diff options
113 files changed, 2940 insertions, 1451 deletions
diff --git a/.ci/common/test.sh b/.ci/common/test.sh index 8c32b63ab2..225d88e072 100644 --- a/.ci/common/test.sh +++ b/.ci/common/test.sh @@ -49,11 +49,11 @@ asan_check() { } run_unittests() { - ${MAKE_CMD} -C "${BUILD_DIR}" unittest + ${MAKE_CMD} unittest } run_functionaltests() { - if ! ${MAKE_CMD} -C "${BUILD_DIR}" ${FUNCTIONALTEST}; then + if ! ${MAKE_CMD} ${FUNCTIONALTEST}; then asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" exit 1 @@ -63,7 +63,7 @@ run_functionaltests() { } run_oldtests() { - if ! make -C "${TRAVIS_BUILD_DIR}/src/nvim/testdir"; then + if ! make oldtest; then reset asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" diff --git a/.gitignore b/.gitignore index 94bb54c661..ccb2299582 100644 --- a/.gitignore +++ b/.gitignore @@ -23,9 +23,6 @@ tags # Files generated by the tests /src/nvim/testdir/del -/src/nvim/testdir/mbyte.vim -/src/nvim/testdir/small.vim -/src/nvim/testdir/tiny.vim /src/nvim/testdir/test*.out /src/nvim/testdir/test.log /src/nvim/testdir/messages diff --git a/CMakeLists.txt b/CMakeLists.txt index 98ffc77b15..317d2a1a5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,9 +300,6 @@ include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS}) find_package(Msgpack 1.0.0 REQUIRED) include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS}) -find_package(LuaJit REQUIRED) -include_directories(SYSTEM ${LUAJIT_INCLUDE_DIRS}) - find_package(Unibilium REQUIRED) include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS}) @@ -451,6 +448,14 @@ if(BUSTED_PRG) get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION) endif() + # When running tests from 'ninja' we need to use the + # console pool: to do so we need to use the USES_TERMINAL + # option, but this is only available in CMake 3.2 + set(TEST_TARGET_ARGS) + if(NOT (${CMAKE_VERSION} VERSION_LESS 3.2.0)) + list(APPEND TEST_TARGET_ARGS "USES_TERMINAL") + endif() + configure_file( test/config/paths.lua.in ${CMAKE_BINARY_DIR}/test/config/paths.lua) @@ -469,17 +474,24 @@ if(BUSTED_PRG) add_custom_target(benchmark-prereqs DEPENDS ${BENCHMARK_PREREQS}) - add_custom_target(unittest - COMMAND ${CMAKE_COMMAND} - -DBUSTED_PRG=${BUSTED_PRG} - -DLUA_PRG=${LUA_PRG} - -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} - -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} - -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test - -DBUILD_DIR=${CMAKE_BINARY_DIR} - -DTEST_TYPE=unit - -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${UNITTEST_PREREQS}) + check_lua_module(${LUA_PRG} "ffi" LUA_HAS_FFI) + if(LUA_HAS_FFI) + add_custom_target(unittest + COMMAND ${CMAKE_COMMAND} + -DBUSTED_PRG=${BUSTED_PRG} + -DLUA_PRG=${LUA_PRG} + -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} + -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test + -DBUILD_DIR=${CMAKE_BINARY_DIR} + -DTEST_TYPE=unit + -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake + DEPENDS ${UNITTEST_PREREQS} + ${TEST_TARGET_ARGS}) + else() + message(WARNING "The Luajit ffi is not available in ${LUA_PRG}" + ", disabling unit tests") + endif() add_custom_target(functionaltest COMMAND ${CMAKE_COMMAND} @@ -491,7 +503,8 @@ if(BUSTED_PRG) -DBUILD_DIR=${CMAKE_BINARY_DIR} -DTEST_TYPE=functional -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${FUNCTIONALTEST_PREREQS}) + DEPENDS ${FUNCTIONALTEST_PREREQS} + ${TEST_TARGET_ARGS}) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} @@ -503,7 +516,8 @@ if(BUSTED_PRG) -DBUILD_DIR=${CMAKE_BINARY_DIR} -DTEST_TYPE=benchmark -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${BENCHMARK_PREREQS}) + DEPENDS ${BENCHMARK_PREREQS} + ${TEST_TARGET_ARGS}) endif() if(BUSTED_LUA_PRG) @@ -517,7 +531,8 @@ if(BUSTED_LUA_PRG) -DBUILD_DIR=${CMAKE_BINARY_DIR} -DTEST_TYPE=functional -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${FUNCTIONALTEST_PREREQS}) + DEPENDS ${FUNCTIONALTEST_PREREQS} + ${TEST_TARGET_ARGS}) endif() if(LUACHECK_PRG) @@ -85,16 +85,19 @@ endif mkdir -p build touch $@ -oldtest: | nvim +oldtest: | nvim tags +$(SINGLE_MAKE) -C src/nvim/testdir $(MAKEOVERRIDES) +tags: | nvim + +$(BUILD_CMD) -C build runtime/doc/tags + functionaltest: | nvim +$(BUILD_CMD) -C build functionaltest functionaltest-lua: | nvim +$(BUILD_CMD) -C build functionaltest-lua -testlint: | nvim +testlint: | build/.ran-cmake deps $(BUILD_CMD) -C build testlint unittest: | nvim @@ -115,10 +118,12 @@ distclean: clean install: | nvim +$(BUILD_CMD) -C build install -lint: +clint: cmake -DLINT_PRG=./clint.py \ -DLINT_DIR=src \ -DLINT_SUPPRESS_URL="$(DOC_DOWNLOAD_URL_BASE)$(CLINT_ERRORS_FILE_PATH)" \ -P cmake/RunLint.cmake -.PHONY: test testlint functionaltest unittest lint clean distclean nvim libnvim cmake deps install +lint: clint testlint + +.PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install diff --git a/cmake/LuaHelpers.cmake b/cmake/LuaHelpers.cmake index b1e67e0ca7..32f7e46a57 100644 --- a/cmake/LuaHelpers.cmake +++ b/cmake/LuaHelpers.cmake @@ -8,8 +8,6 @@ function(check_lua_module LUA_PRG_PATH MODULE RESULT_VAR) RESULT_VARIABLE module_missing ERROR_QUIET) if(module_missing) - message(STATUS - "[${LUA_PRG_PATH}] The '${MODULE}' lua package is required for building Neovim") set(${RESULT_VAR} False PARENT_SCOPE) else() set(${RESULT_VAR} True PARENT_SCOPE) @@ -29,6 +27,8 @@ function(check_lua_deps LUA_PRG_PATH MODULES RESULT_VAR) foreach(module ${MODULES}) check_lua_module(${LUA_PRG_PATH} ${module} has_module) if(NOT has_module) + message(STATUS + "[${LUA_PRG_PATH}] The '${module}' lua package is required for building Neovim") set(${RESULT_VAR} False PARENT_SCOPE) return() endif() diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index eaf06ba7f2..e794a8c5b9 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -67,6 +67,14 @@ if(HAVE_LANGINFO_H) check_symbol_exists(CODESET "langinfo.h" HAVE_NL_LANGINFO_CODESET) endif() +check_include_files("endian.h" HAVE_ENDIAN_H) +check_include_files("sys/endian.h" HAVE_SYS_ENDIAN_H) + +set(ENDIAN_INCLUDE_FILE "endian.h") +if(HAVE_SYS_ENDIAN_H AND NOT HAVE_ENDIAN_H) + set(ENDIAN_INCLUDE_FILE "sys/endian.h") +endif() + set(SI "#include <stdint.h>\n") set(MS "int main(int argc,char**argv)\n{\n uint64_t i=0x0102030405060708ULL;") set(ME "}") @@ -74,7 +82,7 @@ check_c_source_compiles(" #define _BSD_SOURCE 1 #define _DEFAULT_SOURCE 1 ${SI} - #include <endian.h> + #include <${ENDIAN_INCLUDE_FILE}> #ifndef be64toh # error No be64toh macros #endif diff --git a/config/config.h.in b/config/config.h.in index d13e7de2e6..5c5b008f7e 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -57,5 +57,6 @@ #cmakedefine HAVE_BE64TOH #cmakedefine ORDER_BIG_ENDIAN +#define ENDIAN_INCLUDE_FILE <@ENDIAN_INCLUDE_FILE@> #endif // AUTO_CONFIG_H diff --git a/man/nvim.1 b/man/nvim.1 index 7e8cd5b809..2fa3ab8ff5 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -391,9 +391,6 @@ See in the .Xr tmux 1 manual page for more information. -.It Ev NVIM_TUI_ENABLE_TRUE_COLOR -If defined, assume the host terminal supports 24 bit colors. -Has no effect in GUIs. .El .Sh FILES .Bl -tag -width "~/.config/nvim/init.vim" diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 9f1737639b..c7cb14ded7 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -52,6 +52,11 @@ elseif executable('lemonade') let s:paste['+'] = 'lemonade paste' let s:copy['*'] = 'lemonade copy' let s:paste['*'] = 'lemonade paste' +elseif executable('doitclient') + let s:copy['+'] = 'doitclient wclip' + let s:paste['+'] = 'doitclient wclip -r' + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] else echom 'clipboard: No clipboard tool available. See :help nvim-clipboard' finish diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim index 8faeaed2ea..a63c6a923b 100644 --- a/runtime/autoload/remote/host.vim +++ b/runtime/autoload/remote/host.vim @@ -140,6 +140,7 @@ function! s:RegistrationCommands(host) abort call remote#host#RegisterClone(host_id, a:host) let pattern = s:plugin_patterns[a:host] let paths = globpath(&rtp, 'rplugin/'.a:host.'/'.pattern, 0, 1) + let paths = map(paths, 'tr(v:val,"\\","/")') " Normalize slashes #4795 if empty(paths) return [] endif diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 580353ea94..c8eb0705f6 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 7.4. Last change: 2015 Oct 17 +*change.txt* For Vim version 7.4. Last change: 2016 Jan 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -423,7 +423,7 @@ This depends on the 'nrformats' option: index. For decimals a leading negative sign is considered for incrementing or -decrementing, for binary and octal and hex values, it won't be considered. To +decrementing, for binary, octal and hex values, it won't be considered. To ignore the sign Visually select the number before using CTRL-A or CTRL-X. For numbers with leading zeros (including all octal and hexadecimal numbers), @@ -966,7 +966,7 @@ inside of strings can change! Also see 'softtabstop' option. > :reg[isters] {arg} Display the contents of the numbered and named registers that are mentioned in {arg}. For example: > - :dis 1a + :reg 1a < to display registers '1' and 'a'. Spaces are allowed in {arg}. diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index b1dd3239ea..c51286a350 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 7.4. Last change: 2015 Aug 25 +*editing.txt* For Vim version 7.4. Last change: 2016 Jan 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1042,10 +1042,10 @@ The names can be in upper- or lowercase. the last file in the argument list has not been edited. See |:confirm| and 'confirm'. -:q[uit]! Quit without writing, also when currently visible - buffers have changes. Does not exit when this is the - last window and there is a changed hidden buffer. - In this case, the first changed hidden buffer becomes +:q[uit]! Quit without writing, also when the current buffer has + changes. If this is the last window and there is a + modified hidden buffer, the current buffer is + abandoned and the first changed hidden buffer becomes the current buffer. Use ":qall!" to exit always. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 6ae137a6ce..eebdabd154 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1776,374 +1776,374 @@ See |function-list| for a list grouped by what the function is used for. USAGE RESULT DESCRIPTION ~ -abs( {expr}) Float or Number absolute value of {expr} -acos( {expr}) Float arc cosine of {expr} -add( {list}, {item}) List append {item} to |List| {list} -and( {expr}, {expr}) Number bitwise AND -append( {lnum}, {string}) Number append {string} below line {lnum} -append( {lnum}, {list}) Number append lines {list} below line {lnum} +abs({expr}) Float or Number absolute value of {expr} +acos({expr}) Float arc cosine of {expr} +add({list}, {item}) List append {item} to |List| {list} +and({expr}, {expr}) Number bitwise AND +append({lnum}, {string}) Number append {string} below line {lnum} +append({lnum}, {list}) Number append lines {list} below line {lnum} argc() Number number of files in the argument list argidx() Number current index in the argument list -arglistid( [{winnr} [, {tabnr}]]) - Number argument list id -argv( {nr}) String {nr} entry of the argument list -argv( ) List the argument list -assert_equal( {exp}, {act} [, {msg}]) none assert {exp} equals {act} +arglistid([{winnr} [, {tabnr}]]) Number argument list id +argv({nr}) String {nr} entry of the argument list +argv() List the argument list +assert_equal({exp}, {act} [, {msg}]) none assert {exp} equals {act} assert_exception({error} [, {msg}]) none assert {error} is in v:exception -assert_false( {actual} [, {msg}]) none assert {actual} is false -assert_true( {actual} [, {msg}]) none assert {actual} is true -asin( {expr}) Float arc sine of {expr} -atan( {expr}) Float arc tangent of {expr} -atan2( {expr}, {expr}) Float arc tangent of {expr1} / {expr2} -browse( {save}, {title}, {initdir}, {default}) +assert_false({actual} [, {msg}]) none assert {actual} is false +assert_true({actual} [, {msg}]) none assert {actual} is true +asin({expr}) Float arc sine of {expr} +atan({expr}) Float arc tangent of {expr} +atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2} +browse({save}, {title}, {initdir}, {default}) String put up a file requester -browsedir( {title}, {initdir}) String put up a directory requester -bufexists( {expr}) Number TRUE if buffer {expr} exists -buflisted( {expr}) Number TRUE if buffer {expr} is listed -bufloaded( {expr}) Number TRUE if buffer {expr} is loaded -bufname( {expr}) String Name of the buffer {expr} -bufnr( {expr} [, {create}]) Number Number of the buffer {expr} -bufwinnr( {expr}) Number window number of buffer {expr} -byte2line( {byte}) Number line number at byte count {byte} -byteidx( {expr}, {nr}) Number byte index of {nr}'th char in {expr} -byteidxcomp( {expr}, {nr}) Number byte index of {nr}'th char in {expr} -call( {func}, {arglist} [, {dict}]) +browsedir({title}, {initdir}) String put up a directory requester +bufexists({expr}) Number TRUE if buffer {expr} exists +buflisted({expr}) Number TRUE if buffer {expr} is listed +bufloaded({expr}) Number TRUE if buffer {expr} is loaded +bufname({expr}) String Name of the buffer {expr} +bufnr({expr} [, {create}]) Number Number of the buffer {expr} +bufwinnr({expr}) Number window number of buffer {expr} +byte2line({byte}) Number line number at byte count {byte} +byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr} +byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr} +call({func}, {arglist} [, {dict}]) any call {func} with arguments {arglist} -ceil( {expr}) Float round {expr} up +ceil({expr}) Float round {expr} up changenr() Number current change number -char2nr( {expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} -cindent( {lnum}) Number C indent for line {lnum} +char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} +cindent({lnum}) Number C indent for line {lnum} clearmatches() none clear all matches -col( {expr}) Number column nr of cursor or mark -complete( {startcol}, {matches}) none set Insert mode completion -complete_add( {expr}) Number add completion match +col({expr}) Number column nr of cursor or mark +complete({startcol}, {matches}) none set Insert mode completion +complete_add({expr}) Number add completion match complete_check() Number check for key typed during completion -confirm( {msg} [, {choices} [, {default} [, {type}]]]) +confirm({msg} [, {choices} [, {default} [, {type}]]]) Number number of choice picked by user -copy( {expr}) any make a shallow copy of {expr} -cos( {expr}) Float cosine of {expr} -cosh( {expr}) Float hyperbolic cosine of {expr} -count( {list}, {expr} [, {ic} [, {start}]]) +copy({expr}) any make a shallow copy of {expr} +cos({expr}) Float cosine of {expr} +cosh({expr}) Float hyperbolic cosine of {expr} +count({list}, {expr} [, {ic} [, {start}]]) Number count how many {expr} are in {list} -cscope_connection( [{num} , {dbpath} [, {prepend}]]) +cscope_connection([{num} , {dbpath} [, {prepend}]]) Number checks existence of cscope connection -cursor( {lnum}, {col} [, {off}]) +cursor({lnum}, {col} [, {off}]) Number move cursor to {lnum}, {col}, {off} -cursor( {list}) Number move cursor to position in {list} -deepcopy( {expr} [, {noref}]) any make a full copy of {expr} -delete( {fname} [, {flags}]) Number delete the file or directory {fname} -dictwatcheradd( {dict}, {pattern}, {callback}) +cursor({list}) Number move cursor to position in {list} +deepcopy({expr} [, {noref}]) any make a full copy of {expr} +delete({fname} [, {flags}]) Number delete the file or directory {fname} +dictwatcheradd({dict}, {pattern}, {callback}) Start watching a dictionary -dictwatcherdel( {dict}, {pattern}, {callback}) +dictwatcherdel({dict}, {pattern}, {callback}) Stop watching a dictionary did_filetype() Number TRUE if FileType autocommand event used -diff_filler( {lnum}) Number diff filler lines about {lnum} -diff_hlID( {lnum}, {col}) Number diff highlighting at {lnum}/{col} -empty( {expr}) Number TRUE if {expr} is empty -escape( {string}, {chars}) String escape {chars} in {string} with '\' -eval( {string}) any evaluate {string} into its value -eventhandler( ) Number TRUE if inside an event handler -executable( {expr}) Number 1 if executable {expr} exists -exepath( {expr}) String full path of the command {expr} -exists( {expr}) Number TRUE if {expr} exists -extend( {expr1}, {expr2} [, {expr3}]) +diff_filler({lnum}) Number diff filler lines about {lnum} +diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col} +empty({expr}) Number TRUE if {expr} is empty +escape({string}, {chars}) String escape {chars} in {string} with '\' +eval({string}) any evaluate {string} into its value +eventhandler() Number TRUE if inside an event handler +executable({expr}) Number 1 if executable {expr} exists +exepath({expr}) String full path of the command {expr} +exists({expr}) Number TRUE if {expr} exists +extend({expr1}, {expr2} [, {expr3}]) List/Dict insert items of {expr2} into {expr1} -exp( {expr}) Float exponential of {expr} -expand( {expr} [, {nosuf} [, {list}]]) +exp({expr}) Float exponential of {expr} +expand({expr} [, {nosuf} [, {list}]]) any expand special keywords in {expr} -feedkeys( {string} [, {mode}]) Number add key sequence to typeahead buffer -filereadable( {file}) Number TRUE if {file} is a readable file -filewritable( {file}) Number TRUE if {file} is a writable file -filter( {expr}, {string}) List/Dict remove items from {expr} where +feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer +filereadable({file}) Number TRUE if {file} is a readable file +filewritable({file}) Number TRUE if {file} is a writable file +filter({expr}, {string}) List/Dict remove items from {expr} where {string} is 0 -finddir( {name}[, {path}[, {count}]]) +finddir({name}[, {path}[, {count}]]) String find directory {name} in {path} -findfile( {name}[, {path}[, {count}]]) +findfile({name}[, {path}[, {count}]]) String find file {name} in {path} -float2nr( {expr}) Number convert Float {expr} to a Number -floor( {expr}) Float round {expr} down -fmod( {expr1}, {expr2}) Float remainder of {expr1} / {expr2} -fnameescape( {fname}) String escape special characters in {fname} -fnamemodify( {fname}, {mods}) String modify file name -foldclosed( {lnum}) Number first line of fold at {lnum} if closed -foldclosedend( {lnum}) Number last line of fold at {lnum} if closed -foldlevel( {lnum}) Number fold level at {lnum} -foldtext( ) String line displayed for closed fold -foldtextresult( {lnum}) String text for closed fold at {lnum} -foreground( ) Number bring the Vim window to the foreground -function( {name}) Funcref reference to function {name} -garbagecollect( [{atexit}]) none free memory, breaking cyclic references -get( {list}, {idx} [, {def}]) any get item {idx} from {list} or {def} -get( {dict}, {key} [, {def}]) any get item {key} from {dict} or {def} -getbufline( {expr}, {lnum} [, {end}]) +float2nr({expr}) Number convert Float {expr} to a Number +floor({expr}) Float round {expr} down +fmod({expr1}, {expr2}) Float remainder of {expr1} / {expr2} +fnameescape({fname}) String escape special characters in {fname} +fnamemodify({fname}, {mods}) String modify file name +foldclosed({lnum}) Number first line of fold at {lnum} if closed +foldclosedend({lnum}) Number last line of fold at {lnum} if closed +foldlevel({lnum}) Number fold level at {lnum} +foldtext() String line displayed for closed fold +foldtextresult({lnum}) String text for closed fold at {lnum} +foreground() Number bring the Vim window to the foreground +function({name}) Funcref reference to function {name} +garbagecollect([{atexit}]) none free memory, breaking cyclic references +get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def} +get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def} +getbufline({expr}, {lnum} [, {end}]) List lines {lnum} to {end} of buffer {expr} -getbufvar( {expr}, {varname} [, {def}]) +getbufvar({expr}, {varname} [, {def}]) any variable {varname} in buffer {expr} -getchar( [expr]) Number get one character from the user -getcharmod( ) Number modifiers for the last typed character +getchar([expr]) Number get one character from the user +getcharmod() Number modifiers for the last typed character getcharsearch() Dict last character search getcmdline() String return the current command-line getcmdpos() Number return cursor position in command-line getcmdtype() String return current command-line type getcmdwintype() String return current command-line window type getcurpos() List position of the cursor -getcwd( [{scope}]) String the current working directory -getfontname( [{name}]) String name of font being used -getfperm( {fname}) String file permissions of file {fname} -getfsize( {fname}) Number size in bytes of file {fname} -getftime( {fname}) Number last modification time of file -getftype( {fname}) String description of type of file {fname} -getline( {lnum}) String line {lnum} of current buffer -getline( {lnum}, {end}) List lines {lnum} to {end} of current buffer -getloclist( {nr}) List list of location list items +getcwd([{scope}]) String the current working directory +getfontname([{name}]) String name of font being used +getfperm({fname}) String file permissions of file {fname} +getfsize({fname}) Number size in bytes of file {fname} +getftime({fname}) Number last modification time of file +getftype({fname}) String description of type of file {fname} +getline({lnum}) String line {lnum} of current buffer +getline({lnum}, {end}) List lines {lnum} to {end} of current buffer +getloclist({nr}) List list of location list items getmatches() List list of current matches getpid() Number process ID of Vim -getpos( {expr}) List position of cursor, mark, etc. +getpos({expr}) List position of cursor, mark, etc. getqflist() List list of quickfix items -getreg( [{regname} [, 1 [, {list}]]]) +getreg([{regname} [, 1 [, {list}]]]) String or List contents of register -getregtype( [{regname}]) String type of register -gettabvar( {nr}, {varname} [, {def}]) +getregtype([{regname}]) String type of register +gettabvar({nr}, {varname} [, {def}]) any variable {varname} in tab {nr} or {def} -gettabwinvar( {tabnr}, {winnr}, {name} [, {def}]) +gettabwinvar({tabnr}, {winnr}, {name} [, {def}]) any {name} in {winnr} in tab page {tabnr} getwinposx() Number X coord in pixels of GUI Vim window getwinposy() Number Y coord in pixels of GUI Vim window -getwinvar( {nr}, {varname} [, {def}]) +getwinvar({nr}, {varname} [, {def}]) any variable {varname} in window {nr} -glob( {expr} [, {nosuf} [, {list} [, {alllinks}]]]) +glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) any expand file wildcards in {expr} -glob2regpat( {expr}) String convert a glob pat into a search pat -globpath( {path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) +glob2regpat({expr}) String convert a glob pat into a search pat +globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) String do glob({expr}) for all dirs in {path} -has( {feature}) Number TRUE if feature {feature} supported -has_key( {dict}, {key}) Number TRUE if {dict} has entry {key} +has({feature}) Number TRUE if feature {feature} supported +has_key({dict}, {key}) Number TRUE if {dict} has entry {key} haslocaldir() Number TRUE if current window executed |:lcd| -hasmapto( {what} [, {mode} [, {abbr}]]) +hasmapto({what} [, {mode} [, {abbr}]]) Number TRUE if mapping to {what} exists -histadd( {history},{item}) String add an item to a history -histdel( {history} [, {item}]) String remove an item from a history -histget( {history} [, {index}]) String get the item {index} from a history -histnr( {history}) Number highest index of a history -hlexists( {name}) Number TRUE if highlight group {name} exists -hlID( {name}) Number syntax ID of highlight group {name} +histadd({history},{item}) String add an item to a history +histdel({history} [, {item}]) String remove an item from a history +histget({history} [, {index}]) String get the item {index} from a history +histnr({history}) Number highest index of a history +hlexists({name}) Number TRUE if highlight group {name} exists +hlID({name}) Number syntax ID of highlight group {name} hostname() String name of the machine Vim is running on -iconv( {expr}, {from}, {to}) String convert encoding of {expr} -indent( {lnum}) Number indent of line {lnum} -index( {list}, {expr} [, {start} [, {ic}]]) +iconv({expr}, {from}, {to}) String convert encoding of {expr} +indent({lnum}) Number indent of line {lnum} +index({list}, {expr} [, {start} [, {ic}]]) Number index in {list} where {expr} appears -input( {prompt} [, {text} [, {completion}]]) +input({prompt} [, {text} [, {completion}]]) String get input from the user -inputdialog( {p} [, {t} [, {c}]]) String like input() but in a GUI dialog -inputlist( {textlist}) Number let the user pick from a choice list +inputdialog({p} [, {t} [, {c}]]) String like input() but in a GUI dialog +inputlist({textlist}) Number let the user pick from a choice list inputrestore() Number restore typeahead inputsave() Number save and clear typeahead -inputsecret( {prompt} [, {text}]) +inputsecret({prompt} [, {text}]) String like input() but hiding the text -insert( {list}, {item} [, {idx}]) +insert({list}, {item} [, {idx}]) List insert {item} in {list} [before {idx}] -invert( {expr}) Number bitwise invert -isdirectory( {directory}) Number TRUE if {directory} is a directory -islocked( {expr}) Number TRUE if {expr} is locked -items( {dict}) List key-value pairs in {dict} -jobclose( {job}[, {stream}]) Number Closes a job stream(s) -jobpid( {job}) Number Returns pid of a job. -jobresize( {job}, {width}, {height}) +invert({expr}) Number bitwise invert +isdirectory({directory}) Number TRUE if {directory} is a directory +islocked({expr}) Number TRUE if {expr} is locked +items({dict}) List key-value pairs in {dict} +jobclose({job}[, {stream}]) Number Closes a job stream(s) +jobpid({job}) Number Returns pid of a job. +jobresize({job}, {width}, {height}) Number Resize {job}'s pseudo terminal window -jobsend( {job}, {data}) Number Writes {data} to {job}'s stdin -jobstart( {cmd}[, {opts}]) Number Spawns {cmd} as a job -jobstop( {job}) Number Stops a job -jobwait( {ids}[, {timeout}]) Number Wait for a set of jobs -join( {list} [, {sep}]) String join {list} items into one String -json_decode( {expr}) any Convert {expr} from JSON -json_encode( {expr}) String Convert {expr} to JSON -keys( {dict}) List keys in {dict} -len( {expr}) Number the length of {expr} -libcall( {lib}, {func}, {arg}) String call {func} in library {lib} with {arg} -libcallnr( {lib}, {func}, {arg}) Number idem, but return a Number -line( {expr}) Number line nr of cursor, last line or mark -line2byte( {lnum}) Number byte count of line {lnum} -lispindent( {lnum}) Number Lisp indent for line {lnum} +jobsend({job}, {data}) Number Writes {data} to {job}'s stdin +jobstart({cmd}[, {opts}]) Number Spawns {cmd} as a job +jobstop({job}) Number Stops a job +jobwait({ids}[, {timeout}]) Number Wait for a set of jobs +join({list} [, {sep}]) String join {list} items into one String +json_decode({expr}) any Convert {expr} from JSON +json_encode({expr}) String Convert {expr} to JSON +keys({dict}) List keys in {dict} +len({expr}) Number the length of {expr} +libcall({lib}, {func}, {arg}) String call {func} in library {lib} with {arg} +libcallnr({lib}, {func}, {arg}) Number idem, but return a Number +line({expr}) Number line nr of cursor, last line or mark +line2byte({lnum}) Number byte count of line {lnum} +lispindent({lnum}) Number Lisp indent for line {lnum} localtime() Number current time -log( {expr}) Float natural logarithm (base e) of {expr} -log10( {expr}) Float logarithm of Float {expr} to base 10 -map( {expr}, {string}) List/Dict change each item in {expr} to {expr} -maparg( {name}[, {mode} [, {abbr} [, {dict}]]]) +log({expr}) Float natural logarithm (base e) of {expr} +log10({expr}) Float logarithm of Float {expr} to base 10 +map({expr}, {string}) List/Dict change each item in {expr} to {expr} +maparg({name}[, {mode} [, {abbr} [, {dict}]]]) String or Dict rhs of mapping {name} in mode {mode} -mapcheck( {name}[, {mode} [, {abbr}]]) +mapcheck({name}[, {mode} [, {abbr}]]) String check for mappings matching {name} -match( {expr}, {pat}[, {start}[, {count}]]) +match({expr}, {pat}[, {start}[, {count}]]) Number position where {pat} matches in {expr} -matchadd( {group}, {pattern}[, {priority}[, {id}]]) +matchadd({group}, {pattern}[, {priority}[, {id}]]) Number highlight {pattern} with {group} -matchaddpos( {group}, {list}[, {priority}[, {id}]]) +matchaddpos({group}, {list}[, {priority}[, {id}]]) Number highlight positions with {group} -matcharg( {nr}) List arguments of |:match| -matchdelete( {id}) Number delete match identified by {id} -matchend( {expr}, {pat}[, {start}[, {count}]]) +matcharg({nr}) List arguments of |:match| +matchdelete({id}) Number delete match identified by {id} +matchend({expr}, {pat}[, {start}[, {count}]]) Number position where {pat} ends in {expr} -matchlist( {expr}, {pat}[, {start}[, {count}]]) +matchlist({expr}, {pat}[, {start}[, {count}]]) List match and submatches of {pat} in {expr} -matchstr( {expr}, {pat}[, {start}[, {count}]]) +matchstr({expr}, {pat}[, {start}[, {count}]]) String {count}'th match of {pat} in {expr} -max( {list}) Number maximum value of items in {list} -min( {list}) Number minimum value of items in {list} -mkdir( {name} [, {path} [, {prot}]]) +max({list}) Number maximum value of items in {list} +min({list}) Number minimum value of items in {list} +mkdir({name} [, {path} [, {prot}]]) Number create directory {name} -mode( [expr]) String current editing mode -msgpackdump( {list}) List dump a list of objects to msgpack -msgpackparse( {list}) List parse msgpack to a list of objects -nextnonblank( {lnum}) Number line nr of non-blank line >= {lnum} -nr2char( {expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} -or( {expr}, {expr}) Number bitwise OR -pathshorten( {expr}) String shorten directory names in a path -pow( {x}, {y}) Float {x} to the power of {y} -prevnonblank( {lnum}) Number line nr of non-blank line <= {lnum} -printf( {fmt}, {expr1}...) String format text +mode([expr]) String current editing mode +msgpackdump({list}) List dump a list of objects to msgpack +msgpackparse({list}) List parse msgpack to a list of objects +nextnonblank({lnum}) Number line nr of non-blank line >= {lnum} +nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} +or({expr}, {expr}) Number bitwise OR +pathshorten({expr}) String shorten directory names in a path +pow({x}, {y}) Float {x} to the power of {y} +prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} +printf({fmt}, {expr1}...) String format text pumvisible() Number whether popup menu is visible -pyeval( {expr}) any evaluate |Python| expression -py3eval( {expr}) any evaluate |python3| expression -range( {expr} [, {max} [, {stride}]]) +pyeval({expr}) any evaluate |Python| expression +py3eval({expr}) any evaluate |python3| expression +range({expr} [, {max} [, {stride}]]) List items from {expr} to {max} -readfile( {fname} [, {binary} [, {max}]]) +readfile({fname} [, {binary} [, {max}]]) List get list of lines from file {fname} -reltime( [{start} [, {end}]]) List get time value -reltimefloat( {time}) Float turn the time value into a Float -reltimestr( {time}) String turn time value into a String -remote_expr( {server}, {string} [, {idvar}]) +reltime([{start} [, {end}]]) List get time value +reltimefloat({time}) Float turn the time value into a Float +reltimestr({time}) String turn time value into a String +remote_expr({server}, {string} [, {idvar}]) String send expression -remote_foreground( {server}) Number bring Vim server to the foreground -remote_peek( {serverid} [, {retvar}]) +remote_foreground({server}) Number bring Vim server to the foreground +remote_peek({serverid} [, {retvar}]) Number check for reply string -remote_read( {serverid}) String read reply string -remote_send( {server}, {string} [, {idvar}]) +remote_read({serverid}) String read reply string +remote_send({server}, {string} [, {idvar}]) String send key sequence -remove( {list}, {idx} [, {end}]) any remove items {idx}-{end} from {list} -remove( {dict}, {key}) any remove entry {key} from {dict} -rename( {from}, {to}) Number rename (move) file from {from} to {to} -repeat( {expr}, {count}) String repeat {expr} {count} times -resolve( {filename}) String get filename a shortcut points to -reverse( {list}) List reverse {list} in-place -round( {expr}) Float round off {expr} -rpcnotify( {channel}, {event}[, {args}...]) +remove({list}, {idx} [, {end}]) any remove items {idx}-{end} from {list} +remove({dict}, {key}) any remove entry {key} from {dict} +rename({from}, {to}) Number rename (move) file from {from} to {to} +repeat({expr}, {count}) String repeat {expr} {count} times +resolve({filename}) String get filename a shortcut points to +reverse({list}) List reverse {list} in-place +round({expr}) Float round off {expr} +rpcnotify({channel}, {event}[, {args}...]) Sends a |msgpack-rpc| notification to {channel} -rpcrequest( {channel}, {method}[, {args}...]) +rpcrequest({channel}, {method}[, {args}...]) Sends a |msgpack-rpc| request to {channel} -rpcstart( {prog}[, {argv}]) Spawns {prog} and opens a |msgpack-rpc| channel -rpcstop( {channel}) Closes a |msgpack-rpc| {channel} -screenattr( {row}, {col}) Number attribute at screen position -screenchar( {row}, {col}) Number character at screen position +rpcstart({prog}[, {argv}]) Spawns {prog} and opens a |msgpack-rpc| channel +rpcstop({channel}) Closes a |msgpack-rpc| {channel} +screenattr({row}, {col}) Number attribute at screen position +screenchar({row}, {col}) Number character at screen position screencol() Number current cursor column screenrow() Number current cursor row -search( {pattern} [, {flags} [, {stopline} [, {timeout}]]]) +search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) Number search for {pattern} -searchdecl( {name} [, {global} [, {thisblock}]]) +searchdecl({name} [, {global} [, {thisblock}]]) Number search for variable declaration -searchpair( {start}, {middle}, {end} [, {flags} [, {skip} [...]]]) +searchpair({start}, {middle}, {end} [, {flags} [, {skip} [...]]]) Number search for other end of start/end pair -searchpairpos( {start}, {middle}, {end} [, {flags} [, {skip} [...]]]) +searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [...]]]) List search for other end of start/end pair -searchpos( {pattern} [, {flags} [, {stopline} [, {timeout}]]]) +searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) List search for {pattern} -server2client( {clientid}, {string}) +server2client({clientid}, {string}) Number send reply string serverlist() String get a list of available servers -setbufvar( {expr}, {varname}, {val}) set {varname} in buffer {expr} to {val} -setcharsearch( {dict}) Dict set character search from {dict} -setcmdpos( {pos}) Number set cursor position in command-line -setline( {lnum}, {line}) Number set line {lnum} to {line} -setloclist( {nr}, {list}[, {action}[, {title}]]) +setbufvar({expr}, {varname}, {val}) set {varname} in buffer {expr} to {val} +setcharsearch({dict}) Dict set character search from {dict} +setcmdpos({pos}) Number set cursor position in command-line +setfperm({fname}, {mode} Number set {fname} file permissions to {mode} +setline({lnum}, {line}) Number set line {lnum} to {line} +setloclist({nr}, {list}[, {action}[, {title}]]) Number modify location list using {list} -setmatches( {list}) Number restore a list of matches -setpos( {expr}, {list}) Number set the {expr} position to {list} -setqflist( {list}[, {action}[, {title}]] +setmatches({list}) Number restore a list of matches +setpos({expr}, {list}) Number set the {expr} position to {list} +setqflist({list}[, {action}[, {title}]] Number modify quickfix list using {list} -setreg( {n}, {v}[, {opt}]) Number set register to value and type -settabvar( {nr}, {varname}, {val}) set {varname} in tab page {nr} to {val} -settabwinvar( {tabnr}, {winnr}, {varname}, {val}) set {varname} in window +setreg({n}, {v}[, {opt}]) Number set register to value and type +settabvar({nr}, {varname}, {val}) set {varname} in tab page {nr} to {val} +settabwinvar({tabnr}, {winnr}, {varname}, {val}) set {varname} in window {winnr} in tab page {tabnr} to {val} -setwinvar( {nr}, {varname}, {val}) set {varname} in window {nr} to {val} -sha256( {string}) String SHA256 checksum of {string} -shellescape( {string} [, {special}]) +setwinvar({nr}, {varname}, {val}) set {varname} in window {nr} to {val} +sha256({string}) String SHA256 checksum of {string} +shellescape({string} [, {special}]) String escape {string} for use as shell command argument shiftwidth() Number effective value of 'shiftwidth' -simplify( {filename}) String simplify filename as much as possible -sin( {expr}) Float sine of {expr} -sinh( {expr}) Float hyperbolic sine of {expr} -sort( {list} [, {func} [, {dict}]]) +simplify({filename}) String simplify filename as much as possible +sin({expr}) Float sine of {expr} +sinh({expr}) Float hyperbolic sine of {expr} +sort({list} [, {func} [, {dict}]]) List sort {list}, using {func} to compare -soundfold( {word}) String sound-fold {word} +soundfold({word}) String sound-fold {word} spellbadword() String badly spelled word at cursor -spellsuggest( {word} [, {max} [, {capital}]]) +spellsuggest({word} [, {max} [, {capital}]]) List spelling suggestions -split( {expr} [, {pat} [, {keepempty}]]) +split({expr} [, {pat} [, {keepempty}]]) List make |List| from {pat} separated {expr} -sqrt( {expr}) Float square root of {expr} -str2float( {expr}) Float convert String to Float -str2nr( {expr} [, {base}]) Number convert String to Number -strchars( {expr} [, {skipcc}]) Number character length of the String {expr} -strdisplaywidth( {expr} [, {col}]) Number display length of the String {expr} -strftime( {format}[, {time}]) String time in specified format -stridx( {haystack}, {needle}[, {start}]) +sqrt({expr}) Float square root of {expr} +str2float({expr}) Float convert String to Float +str2nr({expr} [, {base}]) Number convert String to Number +strchars({expr} [, {skipcc}]) Number character length of the String {expr} +strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} +strftime({format}[, {time}]) String time in specified format +stridx({haystack}, {needle}[, {start}]) Number index of {needle} in {haystack} -string( {expr}) String String representation of {expr} value -strlen( {expr}) Number length of the String {expr} -strpart( {src}, {start}[, {len}]) +string({expr}) String String representation of {expr} value +strlen({expr}) Number length of the String {expr} +strpart({src}, {start}[, {len}]) String {len} characters of {src} at {start} -strridx( {haystack}, {needle} [, {start}]) +strridx({haystack}, {needle} [, {start}]) Number last index of {needle} in {haystack} -strtrans( {expr}) String translate string to make it printable -strwidth( {expr}) Number display cell length of the String {expr} -submatch( {nr}[, {list}]) String or List +strtrans({expr}) String translate string to make it printable +strwidth({expr}) Number display cell length of the String {expr} +submatch({nr}[, {list}]) String or List specific match in ":s" or substitute() -substitute( {expr}, {pat}, {sub}, {flags}) +substitute({expr}, {pat}, {sub}, {flags}) String all {pat} in {expr} replaced with {sub} -synID( {lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col} -synIDattr( {synID}, {what} [, {mode}]) +synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col} +synIDattr({synID}, {what} [, {mode}]) String attribute {what} of syntax ID {synID} -synIDtrans( {synID}) Number translated syntax ID of {synID} -synconcealed( {lnum}, {col}) List info about concealing -synstack( {lnum}, {col}) List stack of syntax IDs at {lnum} and {col} -system( {cmd} [, {input}]) String output of shell command/filter {cmd} -systemlist( {cmd} [, {input}]) List output of shell command/filter {cmd} -tabpagebuflist( [{arg}]) List list of buffer numbers in tab page -tabpagenr( [{arg}]) Number number of current or last tab page -tabpagewinnr( {tabarg}[, {arg}]) +synIDtrans({synID}) Number translated syntax ID of {synID} +synconcealed({lnum}, {col}) List info about concealing +synstack({lnum}, {col}) List stack of syntax IDs at {lnum} and {col} +system({cmd} [, {input}]) String output of shell command/filter {cmd} +systemlist({cmd} [, {input}]) List output of shell command/filter {cmd} +tabpagebuflist([{arg}]) List list of buffer numbers in tab page +tabpagenr([{arg}]) Number number of current or last tab page +tabpagewinnr({tabarg}[, {arg}]) Number number of current window in tab page -taglist( {expr}) List list of tags matching {expr} +taglist({expr}) List list of tags matching {expr} tagfiles() List tags files used tempname() String name for a temporary file -tan( {expr}) Float tangent of {expr} -tanh( {expr}) Float hyperbolic tangent of {expr} -tolower( {expr}) String the String {expr} switched to lowercase -toupper( {expr}) String the String {expr} switched to uppercase -tr( {src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr} +tan({expr}) Float tangent of {expr} +tanh({expr}) Float hyperbolic tangent of {expr} +tolower({expr}) String the String {expr} switched to lowercase +toupper({expr}) String the String {expr} switched to uppercase +tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr} to chars in {tostr} -trunc( {expr}) Float truncate Float {expr} -type( {name}) Number type of variable {name} -undofile( {name}) String undo file name for {name} +trunc({expr}) Float truncate Float {expr} +type({name}) Number type of variable {name} +undofile({name}) String undo file name for {name} undotree() List undo file tree -uniq( {list} [, {func} [, {dict}]]) +uniq({list} [, {func} [, {dict}]]) List remove adjacent duplicates from a list -values( {dict}) List values in {dict} -virtcol( {expr}) Number screen column of cursor or mark -visualmode( [expr]) String last visual mode used +values({dict}) List values in {dict} +virtcol({expr}) Number screen column of cursor or mark +visualmode([expr]) String last visual mode used wildmenumode() Number whether 'wildmenu' mode is active -winbufnr( {nr}) Number buffer number of window {nr} +winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor -winheight( {nr}) Number height of window {nr} +winheight({nr}) Number height of window {nr} winline() Number window line of the cursor -winnr( [{expr}]) Number number of current window +winnr([{expr}]) Number number of current window winrestcmd() String returns command to restore window sizes -winrestview( {dict}) none restore view of current window +winrestview({dict}) none restore view of current window winsaveview() Dict save view of current window -winwidth( {nr}) Number width of window {nr} +winwidth({nr}) Number width of window {nr} wordcount() Dict get byte/char/word statistics -writefile( {list}, {fname} [, {flags}]) +writefile({list}, {fname} [, {flags}]) Number write list of lines to file {fname} -xor( {expr}, {expr}) Number bitwise XOR +xor({expr}, {expr}) Number bitwise XOR abs({expr}) *abs()* Return the absolute value of {expr}. When {expr} evaluates to @@ -3629,6 +3629,8 @@ getfperm({fname}) *getfperm()* < This will hopefully (from a security point of view) display the string "rw-r--r--" or even "rw-------". + For setting permissions use |setfperm()|. + getftime({fname}) *getftime()* The result is a Number, which is the last modification time of the given file {fname}. The value is measured as seconds @@ -5780,7 +5782,7 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()* < In this example "submatch" is 2 when a lowercase letter is found |/\l|, 3 when an uppercase letter is found |/\u|. -server2client( {clientid}, {string}) *server2client()* +server2client({clientid}, {string}) *server2client()* Send a reply string to {clientid}. The most recent {clientid} that sent a string can be retrieved with expand("<client>"). {only available when compiled with the |+clientserver| feature} @@ -5867,6 +5869,23 @@ setcmdpos({pos}) *setcmdpos()* Returns 0 when successful, 1 when not editing the command line. +setfperm({fname}, {mode}) *setfperm()* *chmod* + Set the file permissions for {fname} to {mode}. + {mode} must be a string with 9 characters. It is of the form + "rwxrwxrwx", where each group of "rwx" flags represent, in + turn, the permissions of the owner of the file, the group the + file belongs to, and other users. A '-' character means the + permission is off, any other character means on. Multi-byte + characters are not supported. + + For example "rw-r-----" means read-write for the user, + readable by the group, not accessible by others. "xx-x-----" + would do the same thing. + + Returns non-zero for success, zero for failure. + + To read permissions see |getfperm()|. + setline({lnum}, {text}) *setline()* Set line {lnum} of the current buffer to {text}. To insert lines use |append()|. @@ -6302,7 +6321,7 @@ sqrt({expr}) *sqrt()* "nan" may be different, it depends on system libraries. -str2float( {expr}) *str2float()* +str2float({expr}) *str2float()* Convert String {expr} to a Float. This mostly works the same as when using a floating point number in an expression, see |floating-point-format|. But it's a bit more permissive. @@ -6316,7 +6335,7 @@ str2float( {expr}) *str2float()* let f = str2float(substitute(text, ',', '', 'g')) -str2nr( {expr} [, {base}]) *str2nr()* +str2nr({expr} [, {base}]) *str2nr()* Convert string {expr} to a number. {base} is the conversion base, it can be 2, 8, 10 or 16. When {base} is omitted base 10 is used. This also means that diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index f511b1db6d..e6c1ccc0cf 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 7.4. Last change: 2015 Sep 08 +*index.txt* For Vim version 7.4. Last change: 2016 Jan 03 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/nvim_clipboard.txt b/runtime/doc/nvim_clipboard.txt index 258fc550f8..078382c7a7 100644 --- a/runtime/doc/nvim_clipboard.txt +++ b/runtime/doc/nvim_clipboard.txt @@ -24,6 +24,8 @@ is found in your `$PATH`. - pbcopy/pbpaste (only for Mac OS X) - lemonade (useful for SSH machine) https://github.com/pocke/lemonade +- doitclient (another option for SSH setups from the maintainer of PuTTY) + http://www.chiark.greenend.org.uk/~sgtatham/doit/ The presence of a suitable clipboard tool implicitly enables the '+' and '*' registers. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 84fc2ecfc1..83ae96a651 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.4. Last change: 2015 Nov 23 +*options.txt* For Vim version 7.4. Last change: 2016 Jan 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3785,7 +3785,7 @@ A jump table for the options with a short description can be found at |Q_op|. feature} This option allows switching your keyboard into a special language mode. When you are typing text in Insert mode the characters are - inserted directly. When in command mode the 'langmap' option takes + inserted directly. When in Normal mode the 'langmap' option takes care of translating these special characters to the original meaning of the key. This means you don't have to change the keyboard mode to be able to execute Normal mode commands. @@ -4152,8 +4152,11 @@ A jump table for the options with a short description can be found at |Q_op|. global Maximum amount of memory in Kbyte to use for all buffers together. The maximum usable value is about 2000000 (2 Gbyte). Use this to work - without a limit. On 64 bit machines higher values might work. But - hey, do you really need more than 2 Gbyte for text editing? + without a limit. + On 64 bit machines higher values might work. But hey, do you really + need more than 2 Gbyte for text editing? Keep in mind that text is + stored in the swap file, one can edit files > 2 Gbyte anyway. We do + need the memory to store undo info. Also see 'maxmem'. *'menuitems'* *'mis'* @@ -5823,7 +5826,8 @@ A jump table for the options with a short description can be found at |Q_op|. the two-letter, lower case region name. You can use more than one region by listing them: "en_us,en_ca" supports both US and Canadian English, but not words specific for Australia, New Zealand or Great - Britain. + Britain. (Note: currently en_au and en_nz dictionaries are older than + en_ca, en_gb and en_us). If the name "cjk" is included East Asian characters are excluded from spell checking. This is useful when editing text that also has Asian words. @@ -6420,6 +6424,14 @@ A jump table for the options with a short description can be found at |Q_op|. *'termencoding'* *'tenc'* 'termencoding' 'tenc' Removed. |vim-differences| {Nvim} + *'termguicolors'* *'tgc'* +'termguicolors' 'tgc' boolean (default off) + global + When on, uses |highlight-guifg| and |highlight-guibg| attributes in + the terminal (thus using 24-bit color). Requires a ISO-8613-3 + compatible terminal. + Must be set at startup (in your |init.vim| or |--cmd|). + *'terse'* *'noterse'* 'terse' boolean (default off) global diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index d7b16cc533..5897f756d8 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1,4 +1,4 @@ -*pattern.txt* For Vim version 7.4. Last change: 2015 Dec 26 +*pattern.txt* For Vim version 7.4. Last change: 2016 Jan 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1094,7 +1094,10 @@ x A single character, with no special meaning, matches itself plausible pattern for a Unix filename: "[-./[:alnum:]_~]\+" That is, a list of at least one character, each of which is either '-', '.', '/', alphabetic, numeric, '_' or '~'. - These items only work for 8-bit characters. + These items only work for 8-bit characters, except [:lower:] and + [:upper:] also work for multi-byte characters when using the new + regexp engine. In the future these items may work for multi-byte + characters. */[[=* *[==]* - An equivalence class. This means that characters are matched that have almost the same meaning, e.g., when ignoring accents. This diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index b2e935eb3f..343d3e62cf 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 7.4. Last change: 2015 Apr 13 +*repeat.txt* For Vim version 7.4. Last change: 2016 Jan 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -467,16 +467,44 @@ Additionally, these commands can be used: finish Finish the current script or user function and come back to debug mode for the command after the one that sourced or called it. + *>bt* + *>backtrace* + *>where* + backtrace Show the call stacktrace for current debugging session. + bt + where + *>frame* + frame N Goes to N backtrace level. + and - signs make movement + relative. E.g., ":frame +3" goes three frames up. + *>up* + up Goes one level up from call stacktrace. + *>down* + down Goes one level down from call stacktrace. About the additional commands in debug mode: - There is no command-line completion for them, you get the completion for the normal Ex commands only. -- You can shorten them, up to a single character: "c", "n", "s" and "f". +- You can shorten them, up to a single character, unless more then one command + starts with the same letter. "f" stands for "finish", use "fr" for "frame". - Hitting <CR> will repeat the previous one. When doing another command, this is reset (because it's not clear what you want to repeat). - When you want to use the Ex command with the same name, prepend a colon: ":cont", ":next", ":finish" (or shorter). +The backtrace shows the hierarchy of function calls, e.g.: + >bt ~ + 3 function One[3] ~ + 2 Two[3] ~ + ->1 Three[3] ~ + 0 Four ~ + line 1: let four = 4 ~ + +The "->" points to the current frame. Use "up", "down" and "frame N" to +select another frame. + +In the current frame you can evaluate the local function variables. There is +no way to see the command at the current line yet. + DEFINING BREAKPOINTS *:breaka* *:breakadd* diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index 752444a3bd..c871539fe0 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -1373,6 +1373,14 @@ the item name. Case is always ignored. The Hunspell feature to use three arguments and flags is not supported. + *spell-NOCOMPOUNDSUGS* +This item indicates that using compounding to make suggestions is not a good +idea. Use this when compounding is used with very short or one-character +words. E.g. to make numbers out of digits. Without this flag creating +suggestions would spend most time trying all kind of weird compound words. + + NOCOMPOUNDSUGS ~ + *spell-SYLLABLE* The SYLLABLE item defines characters or character sequences that are used to count the number of syllables in a word. Example: diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 37593aef43..46efe1996a 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -350,7 +350,7 @@ argument. -W {scriptout} Like -w, but do not append, overwrite an existing file. ============================================================================== -3. Initialization *initialization* *startup* +2. Initialization *initialization* *startup* At startup, Vim checks environment variables and files and sets values accordingly. Vim proceeds in this order: @@ -601,7 +601,7 @@ This still won't work for systems where gvim does not use stdout at all though. ============================================================================== -4. $VIM and $VIMRUNTIME +3. $VIM and $VIMRUNTIME *$VIM* The environment variable "$VIM" is used to locate various user files for Vim, such as the user startup script |init.vim|. This depends on the system, see @@ -663,7 +663,7 @@ greps in the help files) you might be able to use this: > VIMRUNTIME="$(nvim -e --cmd 'echo $VIMRUNTIME|quit' 2>&1)" ============================================================================== -5. Suspending *suspend* +4. Suspending *suspend* *iconize* *iconise* *CTRL-Z* *v_CTRL-Z* CTRL-Z Suspend Vim, like ":stop". @@ -696,7 +696,7 @@ can't paste it in another application (since Vim is going to sleep an attempt to get the selection would make the program hang). ============================================================================== -6. Saving settings *save-settings* +5. Saving settings *save-settings* Mostly you will edit your vimrc files manually. This gives you the greatest flexibility. There are a few commands to generate a vimrc file automatically. @@ -753,7 +753,7 @@ these steps: You need to escape special characters, esp. spaces. ============================================================================== -7. Views and Sessions *views-sessions* +6. Views and Sessions *views-sessions* This is introduced in sections |21.4| and |21.5| of the user manual. @@ -897,7 +897,7 @@ To automatically save and restore views for *.c files: > au BufWinEnter *.c silent loadview ============================================================================== -8. The ShaDa file *shada* *shada-file* +7. The ShaDa file *shada* *shada-file* If you exit Vim and later start it again, you would normally lose a lot of information. The ShaDa file can be used to remember that information, which diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 3a2b8115db..af4224993f 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -371,6 +371,7 @@ 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| +B *+termguicolors* 24-bit color in xterm-compatible terminals support *+terminfo* uses |terminfo| instead of termcap N *+termresponse* support for |t_RV| and |v:termresponse| N *+textobjects* |text-objects| selection diff --git a/runtime/indent/lua.vim b/runtime/indent/lua.vim index 5f049d4585..393994c590 100644 --- a/runtime/indent/lua.vim +++ b/runtime/indent/lua.vim @@ -54,7 +54,7 @@ function! GetLuaIndent() " Subtract a 'shiftwidth' on end, else (and elseif), until and '}' " This is the part that requires 'indentkeys'. - let midx = match(getline(v:lnum), '^\s*\%(end\>\|else\>\|until\>\|}\)') + let midx = match(getline(v:lnum), '^\s*\%(end\>\|else\>\|elseif\>\|until\>\|}\)') if midx != -1 && synIDattr(synID(v:lnum, midx + 1, 1), "name") != "luaComment" let ind = ind - &shiftwidth endif diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 7050436aab..68444dde01 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -410,6 +410,10 @@ call append("$", "highlight\twhich highlighting to use for various occasions") call <SID>OptionG("hl", &hl) call append("$", "hlsearch\thighlight all matches for the last used search pattern") call <SID>BinOptionG("hls", &hls) +if has("termguicolors") + call append("$", "termguicolors\tuse GUI colors for the terminal") + call <SID>BinOptionG("tgc", &tgc) +endif if has("syntax") call append("$", "cursorcolumn\thighlight the screen column of the cursor") call append("$", "\t(local to window)") @@ -762,7 +766,7 @@ call append("$", "infercase\tadjust case of a keyword completion match") call append("$", "\t(local to buffer)") call <SID>BinOptionL("inf") if has("digraphs") - call append("$", "digraph\tenable entering digraps with c1 <BS> c2") + call append("$", "digraph\tenable entering digraphs with c1 <BS> c2") call <SID>BinOptionG("dg", &dg) endif call append("$", "tildeop\tthe \"~\" command behaves like an operator") @@ -1138,7 +1142,7 @@ if has("arabic") call <SID>BinOptionG("tbidi", &tbidi) endif if has("keymap") - call append("$", "keymap\tname of a keyboard mappping") + call append("$", "keymap\tname of a keyboard mapping") call <SID>OptionL("kmp") endif if has("langmap") diff --git a/runtime/syntax/dircolors.vim b/runtime/syntax/dircolors.vim index c94d720644..1b598c39b5 100644 --- a/runtime/syntax/dircolors.vim +++ b/runtime/syntax/dircolors.vim @@ -44,24 +44,24 @@ highlight default link dircolorsExtension Identifier highlight default link dircolorsEscape Special function! s:set_guicolors() abort - let s:guicolors = {} - - let s:guicolors[0] = "Black" - let s:guicolors[1] = "DarkRed" - let s:guicolors[2] = "DarkGreen" - let s:guicolors[3] = "DarkYellow" - let s:guicolors[4] = "DarkBlue" - let s:guicolors[5] = "DarkMagenta" - let s:guicolors[6] = "DarkCyan" - let s:guicolors[7] = "Gray" - let s:guicolors[8] = "DarkGray" - let s:guicolors[9] = "Red" - let s:guicolors[10] = "Green" - let s:guicolors[11] = "Yellow" - let s:guicolors[12] = "Blue" - let s:guicolors[13] = "Magenta" - let s:guicolors[14] = "Cyan" - let s:guicolors[15] = "White" + let s:termguicolors = {} + + let s:termguicolors[0] = "Black" + let s:termguicolors[1] = "DarkRed" + let s:termguicolors[2] = "DarkGreen" + let s:termguicolors[3] = "DarkYellow" + let s:termguicolors[4] = "DarkBlue" + let s:termguicolors[5] = "DarkMagenta" + let s:termguicolors[6] = "DarkCyan" + let s:termguicolors[7] = "Gray" + let s:termguicolors[8] = "DarkGray" + let s:termguicolors[9] = "Red" + let s:termguicolors[10] = "Green" + let s:termguicolors[11] = "Yellow" + let s:termguicolors[12] = "Blue" + let s:termguicolors[13] = "Magenta" + let s:termguicolors[14] = "Cyan" + let s:termguicolors[15] = "White" let xterm_palette = ["00", "5f", "87", "af", "d7", "ff"] @@ -70,7 +70,7 @@ function! s:set_guicolors() abort for r in xterm_palette for g in xterm_palette for b in xterm_palette - let s:guicolors[cur_col] = '#' . r . g . b + let s:termguicolors[cur_col] = '#' . r . g . b let cur_col += 1 endfor endfor @@ -78,14 +78,14 @@ function! s:set_guicolors() abort for i in range(24) let g = i * 0xa + 8 - let s:guicolors[i + 232] = '#' . g . g . g + let s:termguicolors[i + 232] = '#' . g . g . g endfor endfunction function! s:get_hi_str(color, place) abort if a:color >= 0 && a:color <= 255 if has('gui_running') - return ' gui' . a:place . '=' . s:guicolors[a:color] + return ' gui' . a:place . '=' . s:termguicolors[a:color] elseif a:color <= 7 || &t_Co == 256 || &t_Co == 88 return ' cterm' . a:place . '=' . a:color endif diff --git a/runtime/syntax/zsh.vim b/runtime/syntax/zsh.vim index 5e588e7d6c..162577669f 100644 --- a/runtime/syntax/zsh.vim +++ b/runtime/syntax/zsh.vim @@ -2,7 +2,7 @@ " Language: Zsh shell script " Maintainer: Christian Brabandt <cb@256bit.org> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2015-05-29 +" Latest Revision: 2015-12-25 " License: Vim (see :h license) " Repository: https://github.com/chrisbra/vim-zsh @@ -125,20 +125,29 @@ syn keyword zshCommands alias autoload bg bindkey break bye cap cd \ zsocket zstyle ztcp " Options, generated by: echo ${(j:\n:)options[(I)*]} | sort +" Create a list of option names from zsh source dir: +" #!/bin/zsh +" topdir=/path/to/zsh-xxx +" grep '^pindex([A-Za-z_]*)$' $topdir/Src/Doc/Zsh/optionsyo | +" while read opt +" do +" echo ${${(L)opt#pindex\(}%\)} +" done + syn case ignore syn keyword zshOptions aliases allexport all_export alwayslastprompt - \ always_lastprompt alwaystoend always_to_end - \ appendhistory append_history autocd autocontinue + \ always_last_prompt always_lastprompt alwaystoend always_to_end appendcreate + \ append_create appendhistory append_history autocd auto_cd autocontinue \ auto_continue autolist auto_list \ automenu auto_menu autonamedirs auto_name_dirs \ autoparamkeys auto_param_keys autoparamslash \ auto_param_slash autopushd auto_pushd autoremoveslash - \ auto_remove_slash autoresume auto_resume badpattern + \ auto_remove_slash autoresume auto_resume badpattern bad_pattern \ banghist bang_hist bareglobqual bare_glob_qual \ bashautolist bash_auto_list bashrematch bash_rematch - \ beep bgnice braceccl brace_ccl braceexpand brace_expand + \ beep bgnice bg_nice braceccl brace_ccl braceexpand brace_expand \ bsdecho bsd_echo caseglob case_glob casematch case_match - \ cbases cdablevars cd_able_vars chasedots chase_dots + \ cbases c_bases cdablevars cdable_vars cd_able_vars chasedots chase_dots \ chaselinks chase_links checkjobs check_jobs \ clobber combiningchars combining_chars completealiases \ complete_aliases completeinword complete_in_word @@ -146,17 +155,17 @@ syn keyword zshOptions aliases allexport all_export alwayslastprompt \ correctall correct_all cprecedences c_precedences \ cshjunkiehistory csh_junkie_history cshjunkieloops \ csh_junkie_loops cshjunkiequotes csh_junkie_quotes - \ cshnullcmd csh_null_cmd cshnullglob csh_null_glob + \ csh_nullcmd csh_null_cmd cshnullcmd csh_null_cmd cshnullglob csh_null_glob \ debugbeforecmd debug_before_cmd dotglob dot_glob dvorak \ emacs equals errexit err_exit errreturn err_return evallineno \ eval_lineno exec extendedglob extended_glob extendedhistory \ extended_history flowcontrol flow_control forcefloat - \ force_float functionargzero function_arg_zero glob globalexport + \ force_float functionargzero function_argzero function_arg_zero glob globalexport \ global_export globalrcs global_rcs globassign glob_assign \ globcomplete glob_complete globdots glob_dots glob_subst - \ globsubst hashall hash_all hashcmds hash_cmds hashdirs - \ hash_dirs hashexecutablesonly hash_executables_only hashlistall - \ hash_list_all histallowclobber hist_allow_clobber histappend + \ globsubst globstarshort glob_star_short hashall hash_all hashcmds + \ hash_cmds hashdirs hash_dirs hashexecutablesonly hash_executables_only + \ hashlistall hash_list_all histallowclobber hist_allow_clobber histappend \ hist_append histbeep hist_beep hist_expand hist_expire_dups_first \ histexpand histexpiredupsfirst histfcntllock hist_fcntl_lock \ histfindnodups hist_find_no_dups histignorealldups @@ -184,7 +193,7 @@ syn keyword zshOptions aliases allexport all_export alwayslastprompt \ numeric_glob_sort octalzeroes octal_zeroes onecmd one_cmd \ overstrike over_strike pathdirs path_dirs pathscript \ path_script physical pipefail pipe_fail posixaliases - \ posix_aliases posixargzero posix_arg_zero posixbuiltins + \ posix_aliases posixargzero posix_arg_zero posix_argzero posixbuiltins \ posix_builtins posixcd posix_cd posixidentifiers posix_identifiers \ posixjobs posix_jobs posixstrings posix_strings posixtraps \ posix_traps printeightbit print_eight_bit printexitvalue @@ -192,8 +201,8 @@ syn keyword zshOptions aliases allexport all_export alwayslastprompt \ prompt_cr promptpercent prompt_percent promptsp prompt_sp \ promptsubst prompt_subst promptvars prompt_vars pushdignoredups \ pushd_ignore_dups pushdminus pushd_minus pushdsilent pushd_silent - \ pushdtohome pushd_to_home rcexpandparam rc_expandparam rcquotes - \ rc_quotes rcs recexact rec_exact rematchpcre re_match_pcre + \ pushdtohome pushd_to_home rcexpandparam rc_expandparam rc_expand_param rcquotes + \ rc_quotes rcs recexact rec_exact rematchpcre re_match_pcre rematch_pcre \ restricted rmstarsilent rm_star_silent rmstarwait rm_star_wait \ sharehistory share_history shfileexpansion sh_file_expansion \ shglob sh_glob shinstdin shin_stdin shnullcmd sh_nullcmd @@ -201,22 +210,22 @@ syn keyword zshOptions aliases allexport all_export alwayslastprompt \ sh_word_split singlecommand single_command singlelinezle single_line_zle \ sourcetrace source_trace stdin sunkeyboardhack sun_keyboard_hack \ trackall track_all transientrprompt transient_rprompt - \ trapsasync trapasync typesetsilent type_set_silent unset verbose vi + \ trapsasync traps_async typesetsilent type_set_silent typeset_silent unset verbose vi \ warncreateglobal warn_create_global xtrace zle syn keyword zshOptions noaliases no_aliases noallexport no_allexport noall_export no_all_export noalwayslastprompt no_alwayslastprompt - \ noalways_lastprompt no_always_lastprompt noalwaystoend no_alwaystoend noalways_to_end no_always_to_end - \ noappendhistory no_appendhistory noappend_history no_append_history noautocd no_autocd noautocontinue no_autocontinue - \ noauto_continue no_auto_continue noautolist no_autolist noauto_list no_auto_list - \ noautomenu no_automenu noauto_menu no_auto_menu noautonamedirs no_autonamedirs noauto_name_dirs no_auto_name_dirs - \ noautoparamkeys no_autoparamkeys noauto_param_keys no_auto_param_keys noautoparamslash no_autoparamslash + \ noalways_lastprompt no_always_lastprompt no_always_last_prompt noalwaystoend no_alwaystoend noalways_to_end no_always_to_end + \ noappendcreate no_appendcreate no_append_create noappendhistory no_appendhistory noappend_history no_append_history noautocd + \ no_autocd no_auto_cd noautocontinue no_autocontinue noauto_continue no_auto_continue noautolist no_autolist noauto_list + \ no_auto_list noautomenu no_automenu noauto_menu no_auto_menu noautonamedirs no_autonamedirs noauto_name_dirs + \ no_auto_name_dirs noautoparamkeys no_autoparamkeys noauto_param_keys no_auto_param_keys noautoparamslash no_autoparamslash \ noauto_param_slash no_auto_param_slash noautopushd no_autopushd noauto_pushd no_auto_pushd noautoremoveslash no_autoremoveslash - \ noauto_remove_slash no_auto_remove_slash noautoresume no_autoresume noauto_resume no_auto_resume nobadpattern no_badpattern + \ noauto_remove_slash no_auto_remove_slash noautoresume no_autoresume noauto_resume no_auto_resume nobadpattern no_badpattern no_bad_pattern \ nobanghist no_banghist nobang_hist no_bang_hist nobareglobqual no_bareglobqual nobare_glob_qual no_bare_glob_qual \ nobashautolist no_bashautolist nobash_auto_list no_bash_auto_list nobashrematch no_bashrematch nobash_rematch no_bash_rematch - \ nobeep no_beep nobgnice no_bgnice nobraceccl no_braceccl nobrace_ccl no_brace_ccl nobraceexpand no_braceexpand nobrace_expand no_brace_expand + \ nobeep no_beep nobgnice no_bgnice no_bg_nice nobraceccl no_braceccl nobrace_ccl no_brace_ccl nobraceexpand no_braceexpand nobrace_expand no_brace_expand \ nobsdecho no_bsdecho nobsd_echo no_bsd_echo nocaseglob no_caseglob nocase_glob no_case_glob nocasematch no_casematch nocase_match no_case_match - \ nocbases no_cbases nocdablevars no_cdablevars nocd_able_vars no_cd_able_vars nochasedots no_chasedots nochase_dots no_chase_dots + \ nocbases no_cbases no_c_bases nocdablevars no_cdablevars no_cdable_vars nocd_able_vars no_cd_able_vars nochasedots no_chasedots nochase_dots no_chase_dots \ nochaselinks no_chaselinks nochase_links no_chase_links nocheckjobs no_checkjobs nocheck_jobs no_check_jobs \ noclobber no_clobber nocombiningchars no_combiningchars nocombining_chars no_combining_chars nocompletealiases no_completealiases \ nocomplete_aliases no_complete_aliases nocompleteinword no_completeinword nocomplete_in_word no_complete_in_word @@ -224,14 +233,15 @@ syn keyword zshOptions noaliases no_aliases noallexport no_allexport no \ nocorrectall no_correctall nocorrect_all no_correct_all nocprecedences no_cprecedences noc_precedences no_c_precedences \ nocshjunkiehistory no_cshjunkiehistory nocsh_junkie_history no_csh_junkie_history nocshjunkieloops no_cshjunkieloops \ nocsh_junkie_loops no_csh_junkie_loops nocshjunkiequotes no_cshjunkiequotes nocsh_junkie_quotes no_csh_junkie_quotes - \ nocshnullcmd no_cshnullcmd nocsh_null_cmd no_csh_null_cmd nocshnullglob no_cshnullglob nocsh_null_glob no_csh_null_glob + \ nocshnullcmd no_cshnullcmd no_csh_nullcmd nocsh_null_cmd no_csh_null_cmd nocshnullglob no_cshnullglob nocsh_null_glob no_csh_null_glob \ nodebugbeforecmd no_debugbeforecmd nodebug_before_cmd no_debug_before_cmd nodotglob no_dotglob nodot_glob no_dot_glob nodvorak no_dvorak \ noemacs no_emacs noequals no_equals noerrexit no_errexit noerr_exit no_err_exit noerrreturn no_errreturn noerr_return no_err_return noevallineno no_evallineno \ noeval_lineno no_eval_lineno noexec no_exec noextendedglob no_extendedglob noextended_glob no_extended_glob noextendedhistory no_extendedhistory \ noextended_history no_extended_history noflowcontrol no_flowcontrol noflow_control no_flow_control noforcefloat no_forcefloat - \ noforce_float no_force_float nofunctionargzero no_functionargzero nofunction_arg_zero no_function_arg_zero noglob no_glob noglobalexport no_globalexport + \ noforce_float no_force_float nofunctionargzero no_functionargzero nofunction_arg_zero no_function_argzero no_function_arg_zero noglob no_glob noglobalexport no_globalexport \ noglobal_export no_global_export noglobalrcs no_globalrcs noglobal_rcs no_global_rcs noglobassign no_globassign noglob_assign no_glob_assign - \ noglobcomplete no_globcomplete noglob_complete no_glob_complete noglobdots no_globdots noglob_dots no_glob_dots noglob_subst no_glob_subst + \ noglobcomplete no_globcomplete noglob_complete no_glob_complete noglobdots no_globdots noglob_dots no_glob_dots + \ noglobstarshort no_glob_star_short noglob_subst no_glob_subst \ noglobsubst no_globsubst nohashall no_hashall nohash_all no_hash_all nohashcmds no_hashcmds nohash_cmds no_hash_cmds nohashdirs no_hashdirs \ nohash_dirs no_hash_dirs nohashexecutablesonly no_hashexecutablesonly nohash_executables_only no_hash_executables_only nohashlistall no_hashlistall \ nohash_list_all no_hash_list_all nohistallowclobber no_histallowclobber nohist_allow_clobber no_hist_allow_clobber nohistappend no_histappend @@ -262,7 +272,7 @@ syn keyword zshOptions noaliases no_aliases noallexport no_allexport no \ nonumeric_glob_sort no_numeric_glob_sort nooctalzeroes no_octalzeroes nooctal_zeroes no_octal_zeroes noonecmd no_onecmd noone_cmd no_one_cmd \ nooverstrike no_overstrike noover_strike no_over_strike nopathdirs no_pathdirs nopath_dirs no_path_dirs nopathscript no_pathscript \ nopath_script no_path_script nophysical no_physical nopipefail no_pipefail nopipe_fail no_pipe_fail noposixaliases no_posixaliases - \ noposix_aliases no_posix_aliases noposixargzero no_posixargzero noposix_arg_zero no_posix_arg_zero noposixbuiltins no_posixbuiltins + \ noposix_aliases no_posix_aliases noposixargzero no_posixargzero no_posix_argzero noposix_arg_zero no_posix_arg_zero noposixbuiltins no_posixbuiltins \ noposix_builtins no_posix_builtins noposixcd no_posixcd noposix_cd no_posix_cd noposixidentifiers no_posixidentifiers noposix_identifiers no_posix_identifiers \ noposixjobs no_posixjobs noposix_jobs no_posix_jobs noposixstrings no_posixstrings noposix_strings no_posix_strings noposixtraps no_posixtraps \ noposix_traps no_posix_traps noprinteightbit no_printeightbit noprint_eight_bit no_print_eight_bit noprintexitvalue no_printexitvalue @@ -270,8 +280,8 @@ syn keyword zshOptions noaliases no_aliases noallexport no_allexport no \ noprompt_cr no_prompt_cr nopromptpercent no_promptpercent noprompt_percent no_prompt_percent nopromptsp no_promptsp noprompt_sp no_prompt_sp \ nopromptsubst no_promptsubst noprompt_subst no_prompt_subst nopromptvars no_promptvars noprompt_vars no_prompt_vars nopushdignoredups no_pushdignoredups \ nopushd_ignore_dups no_pushd_ignore_dups nopushdminus no_pushdminus nopushd_minus no_pushd_minus nopushdsilent no_pushdsilent nopushd_silent no_pushd_silent - \ nopushdtohome no_pushdtohome nopushd_to_home no_pushd_to_home norcexpandparam no_rcexpandparam norc_expandparam no_rc_expandparam norcquotes no_rcquotes - \ norc_quotes no_rc_quotes norcs no_rcs norecexact no_recexact norec_exact no_rec_exact norematchpcre no_rematchpcre nore_match_pcre no_re_match_pcre + \ nopushdtohome no_pushdtohome nopushd_to_home no_pushd_to_home norcexpandparam no_rcexpandparam norc_expandparam no_rc_expandparam no_rc_expand_param norcquotes no_rcquotes + \ norc_quotes no_rc_quotes norcs no_rcs norecexact no_recexact norec_exact no_rec_exact norematchpcre no_rematchpcre nore_match_pcre no_re_match_pcre no_rematch_pcre \ norestricted no_restricted normstarsilent no_rmstarsilent norm_star_silent no_rm_star_silent normstarwait no_rmstarwait norm_star_wait no_rm_star_wait \ nosharehistory no_sharehistory noshare_history no_share_history noshfileexpansion no_shfileexpansion nosh_file_expansion no_sh_file_expansion \ noshglob no_shglob nosh_glob no_sh_glob noshinstdin no_shinstdin noshin_stdin no_shin_stdin noshnullcmd no_shnullcmd nosh_nullcmd no_sh_nullcmd @@ -279,11 +289,11 @@ syn keyword zshOptions noaliases no_aliases noallexport no_allexport no \ nosh_word_split no_sh_word_split nosinglecommand no_singlecommand nosingle_command no_single_command nosinglelinezle no_singlelinezle nosingle_line_zle no_single_line_zle \ nosourcetrace no_sourcetrace nosource_trace no_source_trace nostdin no_stdin nosunkeyboardhack no_sunkeyboardhack nosun_keyboard_hack no_sun_keyboard_hack \ notrackall no_trackall notrack_all no_track_all notransientrprompt no_transientrprompt notransient_rprompt no_transient_rprompt - \ notrapsasync no_trapsasync notrapasync no_trapasync notypesetsilent no_typesetsilent notype_set_silent no_type_set_silent nounset no_unset noverbose no_verbose novi no_vi - \ nowarncreateglobal no_warncreateglobal nowarn_create_global no_warn_create_global noxtrace no_xtrace nozle no_zle + \ notrapsasync no_trapsasync notrapasync no_trapasync no_traps_async notypesetsilent no_typesetsilent notype_set_silent no_type_set_silent no_typeset_silent \nounset no_unset + \ noverbose no_verbose novi no_vi nowarncreateglobal no_warncreateglobal nowarn_create_global no_warn_create_global noxtrace no_xtrace nozle no_zle syn case match -syn keyword zshTypes float integer local typeset declare +syn keyword zshTypes float integer local typeset declare private " XXX: this may be too much " syn match zshSwitches '\s\zs--\=[a-zA-Z0-9-]\+' @@ -303,7 +313,7 @@ syn region zshMathSubst matchgroup=zshSubstDelim transparent \ start='\$((' skip='\\)' \ matchgroup=zshSubstDelim end='))' \ contains=zshParentheses,@zshSubst,zshNumber, - \ @zshDerefs,zshString + \ @zshDerefs,zshString keepend syn region zshBrackets contained transparent start='{' skip='\\}' \ end='}' syn region zshSubst matchgroup=zshSubstDelim start='\${' skip='\\}' diff --git a/scripts/release.sh b/scripts/release.sh index 514e5b380a..67738ccc96 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # Performs steps to tag a release. # @@ -45,11 +45,11 @@ echo "Most recent tag: ${__LAST_TAG}" echo "Release version: ${__VERSION}" sed -i -r 's/(NVIM_VERSION_PRERELEASE) "-dev"/\1 ""/' CMakeLists.txt echo "Building changelog since ${__LAST_TAG}..." -__CHANGELOG="$(./scripts/git-log-pretty-since.sh $__LAST_TAG 'vim-patch:\S')" +__CHANGELOG="$(./scripts/git-log-pretty-since.sh "$__LAST_TAG" 'vim-patch:\S')" git add CMakeLists.txt git commit --edit -m "${__RELEASE_MSG} ${__CHANGELOG}" -git tag -a v${__VERSION} -m "NVIM v${__VERSION}" +git tag -a v"${__VERSION}" -m "NVIM v${__VERSION}" sed -i -r 's/(NVIM_VERSION_PRERELEASE) ""/\1 "-dev"/' CMakeLists.txt nvim -c '/NVIM_VERSION' -c 'echo "Update version numbers"' CMakeLists.txt diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index 70777535cb..7a0001769a 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -33,7 +33,11 @@ usage() { # Checks if a program is in the user's PATH, and is executable. check_executable() { - if [[ ! -x $(command -v "${1}") ]]; then + test -x "$(command -v "${1}")" +} + +require_executable() { + if ! check_executable "${1}"; then >&2 echo "${BASENAME}: '${1}' not found in PATH or not executable." exit 1 fi @@ -47,21 +51,21 @@ clean_files() { echo echo "Created files:" local file - for file in ${CREATED_FILES[@]}; do + for file in "${CREATED_FILES[@]}"; do echo " • ${file}" done read -p "Delete these files (Y/n)? " -n 1 -r reply echo if [[ "${reply}" =~ ^[Yy]$ ]]; then - rm -- ${CREATED_FILES[@]} + rm -- "${CREATED_FILES[@]}" else echo "You can use 'git clean' to remove these files when you're done." fi } get_vim_sources() { - check_executable git + require_executable git if [[ ! -d ${VIM_SOURCE_DIR} ]]; then echo "Cloning Vim sources into '${VIM_SOURCE_DIR}'." @@ -97,13 +101,13 @@ assign_commit_details() { vim_version="${1}" vim_tag="v${1}" vim_commit=$(cd "${VIM_SOURCE_DIR}" \ - && git log -1 --format="%H" ${vim_tag}) + && git log -1 --format="%H" "${vim_tag}") local strip_commit_line=true else # Interpret parameter as commit hash. vim_version="${1:0:7}" vim_commit=$(cd "${VIM_SOURCE_DIR}" \ - && git log -1 --format="%H" ${vim_version}) + && git log -1 --format="%H" "${vim_version}") local strip_commit_line=false fi @@ -132,13 +136,16 @@ get_vim_patch() { # Patch surgery: preprocess the patch. # - transform src/ paths to src/nvim/ - local vim_full="$(git show -1 --pretty=medium "${vim_commit}" \ + local vim_full + vim_full="$(git show -1 --pretty=medium "${vim_commit}" \ | LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g')" local neovim_branch="${BRANCH_PREFIX}${vim_version}" cd "${NEOVIM_SOURCE_DIR}" - local git_remote=$(find_git_remote) - local checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" + local git_remote + git_remote="$(find_git_remote)" + local checked_out_branch + checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then echo "✔ Current branch '${checked_out_branch}' seems to be a vim-patch" @@ -191,41 +198,68 @@ get_vim_patch() { echo " for more information." } +hub_pr() { + hub pull-request -m "$1" +} + +git_hub_pr() { + git hub pull new -m "$1" +} + submit_pr() { - check_executable git - check_executable hub + require_executable git + local push_first + push_first=1 + local submit_fn + if check_executable hub; then + submit_fn="hub_pr" + elif check_executable git-hub; then + push_first=0 + submit_fn="git_hub_pr" + else + >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable." + exit 1 + fi cd "${NEOVIM_SOURCE_DIR}" - local checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" + local checked_out_branch + checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then echo "✘ Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch." exit 1 fi - local git_remote=$(find_git_remote) - local pr_body="$(git log --reverse --format='#### %s%n%n%b%n' ${git_remote}/master..HEAD)" - local patches=("$(git log --reverse --format='%s' ${git_remote}/master..HEAD)") + local git_remote + git_remote="$(find_git_remote)" + local pr_body + pr_body="$(git log --reverse --format='#### %s%n%n%b%n' "${git_remote}"/master..HEAD)" + local patches + patches=("$(git log --reverse --format='%s' "${git_remote}"/master..HEAD)") patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array. - local pr_title="${patches[@]}" # Create space-separated string from array. + local pr_title="${patches[*]}" # Create space-separated string from array. pr_title="${pr_title// /,}" # Replace spaces with commas. - local pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")" + local pr_message + pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")" - echo "Pushing to 'origin/${checked_out_branch}'." - output="$(git push origin "${checked_out_branch}" 2>&1)" && - echo "✔ ${output}" || - (echo "✘ ${output}"; git reset --soft HEAD^1; false) + if [[ $push_first -ne 0 ]]; then + echo "Pushing to 'origin/${checked_out_branch}'." + output="$(git push origin "${checked_out_branch}" 2>&1)" && + echo "✔ ${output}" || + (echo "✘ ${output}"; git reset --soft HEAD^1; false) + + echo + fi - echo echo "Creating pull request." - output="$(hub pull-request -F - 2>&1 <<< "${pr_message}")" && + output="$(${submit_fn} "${pr_message}" 2>&1)" && echo "✔ ${output}" || (echo "✘ ${output}"; false) echo echo "Cleaning up files." local patch_file - for patch_file in ${patches[@]}; do + for patch_file in "${patches[@]}"; do patch_file="vim-${patch_file}.patch" if [[ ! -f "${NEOVIM_SOURCE_DIR}/${patch_file}" ]]; then continue @@ -241,18 +275,24 @@ list_vim_patches() { printf "\nVim patches missing from Neovim:\n" # Get commits since 7.4.602. - local vim_commits=$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v7.4.602..HEAD) + local vim_commits + vim_commits="$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v7.4.602..HEAD)" local vim_commit for vim_commit in ${vim_commits}; do local is_missing - local vim_tag=$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null) + local vim_tag + # This fails for untagged commits (e.g., runtime file updates) so mask the return status + vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true if [[ -n "${vim_tag}" ]]; then local patch_number="${vim_tag:5}" # Remove prefix like "v7.4." # Tagged Vim patch, check version.c: is_missing="$(sed -n '/static int included_patches/,/}/p' "${NEOVIM_SOURCE_DIR}/src/nvim/version.c" | grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA.*" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")" vim_commit="${vim_tag#v}" + if (cd "${VIM_SOURCE_DIR}" && git show --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then + vim_commit="${vim_commit} (+runtime)" + fi else # Untagged Vim patch (e.g. runtime updates), check the Neovim git log: is_missing="$(cd "${NEOVIM_SOURCE_DIR}" && @@ -283,8 +323,10 @@ review_commit() { local neovim_patch_url="${neovim_commit_url}.patch" local git_patch_prefix='Subject: \[PATCH\] ' - local neovim_patch="$(curl -Ssf "${neovim_patch_url}")" - local vim_version="$(head -n 4 <<< "${neovim_patch}" | sed -n "s/${git_patch_prefix}vim-patch:\([a-z0-9.]*\)$/\1/p")" + local neovim_patch + neovim_patch="$(curl -Ssf "${neovim_patch_url}")" + local vim_version + vim_version="$(head -n 4 <<< "${neovim_patch}" | sed -n "s/${git_patch_prefix}vim-patch:\([a-z0-9.]*\)$/\1/p")" echo if [[ -n "${vim_version}" ]]; then @@ -300,9 +342,12 @@ review_commit() { local vim_patch_url="${vim_commit_url}.patch" - local expected_commit_message="$(commit_message)" - local message_length="$(wc -l <<< "${expected_commit_message}")" - local commit_message="$(tail -n +4 <<< "${neovim_patch}" | head -n "${message_length}")" + local expected_commit_message + expected_commit_message="$(commit_message)" + local message_length + message_length="$(wc -l <<< "${expected_commit_message}")" + local commit_message + commit_message="$(tail -n +4 <<< "${neovim_patch}" | head -n "${message_length}")" if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then echo "✔ Found expected commit message." else @@ -330,9 +375,9 @@ review_commit() { } review_pr() { - check_executable curl - check_executable nvim - check_executable jq + require_executable curl + require_executable nvim + require_executable jq get_vim_sources @@ -347,7 +392,7 @@ review_pr() { local pr_commit_url local reply - for pr_commit_url in ${pr_commit_urls[@]}; do + for pr_commit_url in "${pr_commit_urls[@]}"; do review_commit "${pr_commit_url}" if [[ "${pr_commit_url}" != "${pr_commit_urls[-1]}" ]]; then read -p "Continue with next commit (Y/n)? " -n 1 -r reply diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 0711642868..172643091a 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -1,4 +1,5 @@ include(CheckLibraryExists) +include(CheckCCompilerFlag) option(USE_GCOV "Enable gcov support" OFF) @@ -230,7 +231,6 @@ endif() list(APPEND NVIM_LINK_LIBRARIES ${LIBUV_LIBRARIES} ${MSGPACK_LIBRARIES} - ${LUAJIT_LIBRARIES} ${LIBVTERM_LIBRARIES} ${LIBTERMKEY_LIBRARIES} ${UNIBILIUM_LIBRARIES} @@ -258,8 +258,14 @@ install_helper(TARGETS nvim) if(CLANG_ASAN_UBSAN) message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.") + check_c_compiler_flag(-fno-sanitize-recover=all SANITIZE_RECOVER_ALL) + if(SANITIZE_RECOVER_ALL) + set(SANITIZE_RECOVER -fno-sanitize-recover=all) # Clang 3.6+ + else() + set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5- + endif() set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ") - set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-sanitize-recover -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist") + set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist") set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ") elseif(CLANG_MSAN) message(STATUS "Enabling Clang memory sanitizer for nvim.") diff --git a/src/nvim/assert.h b/src/nvim/assert.h index 2c43777858..761636305e 100644 --- a/src/nvim/assert.h +++ b/src/nvim/assert.h @@ -65,9 +65,16 @@ # define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg) # undef STATIC_ASSERT_PRAGMA_START + +#if __GNUC__ >= 6 # define STATIC_ASSERT_PRAGMA_START \ _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-pedantic\"") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") +#else +# define STATIC_ASSERT_PRAGMA_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-pedantic\"") +#endif # undef STATIC_ASSERT_PRAGMA_END # define STATIC_ASSERT_PRAGMA_END \ diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6e9f89bbb5..96c008b0e0 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6877,6 +6877,7 @@ static struct fst { { "setbufvar", 3, 3, f_setbufvar }, { "setcharsearch", 1, 1, f_setcharsearch }, { "setcmdpos", 1, 1, f_setcmdpos }, + { "setfperm", 2, 2, f_setfperm }, { "setline", 2, 2, f_setline }, { "setloclist", 2, 4, f_setloclist }, { "setmatches", 1, 1, f_setmatches }, @@ -10684,6 +10685,7 @@ static void f_has(typval_T *argvars, typval_T *rettv) "tablineat", "tag_binary", "tag_old_static", + "termguicolors", "termresponse", "textobjects", "title", @@ -14445,6 +14447,38 @@ static void f_setcmdpos(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = set_cmdline_pos(pos); } + +/// "setfperm({fname}, {mode})" function +static void f_setfperm(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = 0; + + char_u *fname = get_tv_string_chk(&argvars[0]); + if (fname == NULL) { + return; + } + + char_u modebuf[NUMBUFLEN]; + char_u *mode_str = get_tv_string_buf_chk(&argvars[1], modebuf); + if (mode_str == NULL) { + return; + } + if (STRLEN(mode_str) != 9) { + EMSG2(_(e_invarg2), mode_str); + return; + } + + int mask = 1; + int mode = 0; + for (int i = 8; i >= 0; i--) { + if (mode_str[i] != '-') { + mode |= mask; + } + mask = mask << 1; + } + rettv->vval.v_number = os_setperm(fname, mode) == OK; +} + /* * "setline()" function */ @@ -18122,6 +18156,25 @@ static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, in return HI2DI(hi); } +// Get function call environment based on backtrace debug level +static funccall_T *get_funccal(void) +{ + funccall_T *funccal = current_funccal; + if (debug_backtrace_level > 0) { + for (int i = 0; i < debug_backtrace_level; i++) { + funccall_T *temp_funccal = funccal->caller; + if (temp_funccal) { + funccal = temp_funccal; + } else { + // backtrace level overflow. reset to max + debug_backtrace_level = i; + } + } + } + + return funccal; +} + // Find the dict and hashtable used for a variable name. Set "varname" to the // start of name without ':'. static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) @@ -18146,7 +18199,11 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) return &compat_hashtab; } - *d = current_funccal ? ¤t_funccal->l_vars : &globvardict; + if (current_funccal == NULL) { + *d = &globvardict; + } else { + *d = &get_funccal()->l_vars; // l: variable + } goto end; } @@ -18168,9 +18225,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) } else if (*name == 'v') { // v: variable *d = &vimvardict; } else if (*name == 'a' && current_funccal != NULL) { // function argument - *d = ¤t_funccal->l_avars; + *d = &get_funccal()->l_avars; } else if (*name == 'l' && current_funccal != NULL) { // local variable - *d = ¤t_funccal->l_vars; + *d = &get_funccal()->l_vars; } else if (*name == 's' // script variable && current_SID > 0 && current_SID <= ga_scripts.ga_len) { *d = &SCRIPT_SV(current_SID)->sv_dict; @@ -21700,6 +21757,18 @@ static void term_resize(uint16_t width, uint16_t height, void *d) pty_process_resize(&data->proc.pty, width, height); } +static inline void term_delayed_free(void **argv) +{ + TerminalJobData *j = argv[0]; + if (j->in.pending_reqs || j->out.pending_reqs || j->err.pending_reqs) { + queue_put(j->events, term_delayed_free, 1, j); + return; + } + + terminal_destroy(j->term); + term_job_data_decref(j); +} + static void term_close(void *d) { TerminalJobData *data = d; @@ -21707,8 +21776,7 @@ static void term_close(void *d) data->exited = true; process_stop((Process *)&data->proc); } - terminal_destroy(data->term); - term_job_data_decref(d); + queue_put(data->events, term_delayed_free, 1, data); } static void term_job_data_decref(TerminalJobData *data) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index e8314e02e0..86f1a16216 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3816,16 +3816,17 @@ skip: EMSG2(_(e_patnotf2), get_search_pat()); } - if (do_ask && hasAnyFolding(curwin)) - /* Cursor position may require updating */ + if (do_ask && hasAnyFolding(curwin)) { + // Cursor position may require updating changed_window_setting(); + } - vim_regfree(regmatch.regprog); + vim_regfree(regmatch.regprog); - // Restore the flag values, they can be used for ":&&". - do_all = save_do_all; - do_ask = save_do_ask; - } + // Restore the flag values, they can be used for ":&&". + do_all = save_do_all; + do_ask = save_do_ask; +} /* * Give message for number of substitutions. @@ -4413,17 +4414,20 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la || (arg[0] == '\\' && arg[1] == '{')) *d++ = '\\'; - for (s = arg; *s; ++s) { - /* - * Replace "|" with "bar" and '"' with "quote" to match the name of - * the tags for these commands. - * Replace "*" with ".*" and "?" with "." to match command line - * completion. - * Insert a backslash before '~', '$' and '.' to avoid their - * special meaning. - */ - if (d - IObuff > IOSIZE - 10) /* getting too long!? */ + // If tag starts with "('", skip the "(". Fixes CTRL-] on ('option'. + if (*arg == '(' && arg[1] == '\'') { + arg++; + } + for (s = arg; *s; s++) { + // Replace "|" with "bar" and '"' with "quote" to match the name of + // the tags for these commands. + // Replace "*" with ".*" and "?" with "." to match command line + // completion. + // Insert a backslash before '~', '$' and '.' to avoid their + // special meaning. + if (d - IObuff > IOSIZE - 10) { // getting too long!? break; + } switch (*s) { case '|': STRCPY(d, "bar"); d += 3; @@ -4484,6 +4488,12 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la *d++ = *s; + // If tag contains "({" or "([", tag terminates at the "(". + // This is for help on functions, e.g.: abs({expr}). + if (*s == '(' && (s[1] == '{' || s[1] =='[')) { + break; + } + /* * If tag starts with ', toss everything after a second '. Fixes * CTRL-] on 'option'. (would include the trailing '.'). diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 12efddc205..5fe6209a0a 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -144,6 +144,10 @@ void do_debug(char_u *cmd) #define CMD_FINISH 4 #define CMD_QUIT 5 #define CMD_INTERRUPT 6 +#define CMD_BACKTRACE 7 +#define CMD_FRAME 8 +#define CMD_UP 9 +#define CMD_DOWN 10 ++RedrawingDisabled; /* don't redisplay the window */ @@ -185,6 +189,7 @@ void do_debug(char_u *cmd) ignore_script = TRUE; } + xfree(cmdline); cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL); if (typeahead_saved) { @@ -194,6 +199,7 @@ void do_debug(char_u *cmd) ex_normal_busy = save_ex_normal_busy; cmdline_row = msg_row; + msg_starthere(); if (cmdline != NULL) { /* If this is a debug command, set "last_cmd". * If not, reset "last_cmd". @@ -210,8 +216,15 @@ void do_debug(char_u *cmd) case 's': last_cmd = CMD_STEP; tail = "tep"; break; - case 'f': last_cmd = CMD_FINISH; - tail = "inish"; + case 'f': + last_cmd = 0; + if (p[1] == 'r') { + last_cmd = CMD_FRAME; + tail = "rame"; + } else { + last_cmd = CMD_FINISH; + tail = "inish"; + } break; case 'q': last_cmd = CMD_QUIT; tail = "uit"; @@ -219,6 +232,26 @@ void do_debug(char_u *cmd) case 'i': last_cmd = CMD_INTERRUPT; tail = "nterrupt"; break; + case 'b': + last_cmd = CMD_BACKTRACE; + if (p[1] == 't') { + tail = "t"; + } else { + tail = "acktrace"; + } + break; + case 'w': + last_cmd = CMD_BACKTRACE; + tail = "here"; + break; + case 'u': + last_cmd = CMD_UP; + tail = "p"; + break; + case 'd': + last_cmd = CMD_DOWN; + tail = "own"; + break; default: last_cmd = 0; } if (last_cmd != 0) { @@ -228,8 +261,9 @@ void do_debug(char_u *cmd) ++p; ++tail; } - if (ASCII_ISALPHA(*p)) + if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) { last_cmd = 0; + } } } @@ -259,7 +293,28 @@ void do_debug(char_u *cmd) /* Do not repeat ">interrupt" cmd, continue stepping. */ last_cmd = CMD_STEP; break; + case CMD_BACKTRACE: + do_showbacktrace(cmd); + continue; + case CMD_FRAME: + if (*p == NUL) { + do_showbacktrace(cmd); + } else { + p = skipwhite(p); + do_setdebugtracelevel(p); + } + continue; + case CMD_UP: + debug_backtrace_level++; + do_checkbacktracelevel(); + continue; + case CMD_DOWN: + debug_backtrace_level--; + do_checkbacktracelevel(); + continue; } + // Going out reset backtrace_level + debug_backtrace_level = 0; break; } @@ -269,8 +324,6 @@ void do_debug(char_u *cmd) (void)do_cmdline(cmdline, getexline, NULL, DOCMD_VERBOSE|DOCMD_EXCRESET); debug_break_level = n; - - xfree(cmdline); } lines_left = (int)(Rows - 1); } @@ -294,6 +347,78 @@ void do_debug(char_u *cmd) debug_did_msg = TRUE; } +static int get_maxbacktrace_level(void) +{ + int maxbacktrace = 0; + + if (sourcing_name != NULL) { + char *p = (char *)sourcing_name; + char *q; + while ((q = strstr(p, "..")) != NULL) { + p = q + 2; + maxbacktrace++; + } + } + return maxbacktrace; +} + +static void do_setdebugtracelevel(char_u *arg) +{ + int level = atoi((char *)arg); + if (*arg == '+' || level < 0) { + debug_backtrace_level += level; + } else { + debug_backtrace_level = level; + } + + do_checkbacktracelevel(); +} + +static void do_checkbacktracelevel(void) +{ + if (debug_backtrace_level < 0) { + debug_backtrace_level = 0; + MSG(_("frame is zero")); + } else { + int max = get_maxbacktrace_level(); + if (debug_backtrace_level > max) { + debug_backtrace_level = max; + smsg(_("frame at highest level: %d"), max); + } + } +} + +static void do_showbacktrace(char_u *cmd) +{ + if (sourcing_name != NULL) { + int i = 0; + int max = get_maxbacktrace_level(); + char *cur = (char *)sourcing_name; + while (!got_int) { + char *next = strstr(cur, ".."); + if (next != NULL) { + *next = NUL; + } + if (i == max - debug_backtrace_level) { + smsg("->%d %s", max - i, cur); + } else { + smsg(" %d %s", max - i, cur); + } + i++; + if (next == NULL) { + break; + } + *next = '.'; + cur = next + 2; + } + } + if (sourcing_lnum != 0) { + smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd); + } else { + smsg(_("cmd: %s"), cmd); + } +} + /* * ":debug". */ @@ -1241,16 +1366,18 @@ static void add_bufnum(int *bufnrs, int *bufnump, int nr) *bufnump = *bufnump + 1; } -/* - * Return TRUE if any buffer was changed and cannot be abandoned. - * That changed buffer becomes the current buffer. - */ -int -check_changed_any ( - int hidden /* Only check hidden buffers */ -) +/// Check if any buffer was changed and cannot be abandoned. +/// That changed buffer becomes the current buffer. +/// When "unload" is true the current buffer is unloaded instead of making it +/// hidden. This is used for ":q!". +/// +/// @param[in] hidden specifies whether to check only hidden buffers. +/// @param[in] unload specifies whether to unload, instead of hide, the buffer. +/// +/// @returns true if any buffer is changed and cannot be abandoned +int check_changed_any(bool hidden, bool unload) { - int ret = FALSE; + bool ret = false; int save; int i; int bufnum = 0; @@ -1261,8 +1388,9 @@ check_changed_any ( ++bufcount; } - if (bufcount == 0) - return FALSE; + if (bufcount == 0) { + return false; + } bufnrs = xmalloc(sizeof(*bufnrs) * bufcount); @@ -1346,9 +1474,10 @@ check_changed_any ( } buf_found: - /* Open the changed buffer in the current window. */ - if (buf != curbuf) - set_curbuf(buf, DOBUF_GOTO); + // Open the changed buffer in the current window. + if (buf != curbuf) { + set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO); + } theend: xfree(bufnrs); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 89c35a3c45..870284a0f7 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5671,10 +5671,10 @@ static void ex_quit(exarg_T *eap) exiting = TRUE; if ((!P_HID(curbuf) && check_changed(curbuf, (p_awa ? CCGD_AW : 0) - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) - || check_more(TRUE, eap->forceit) == FAIL - || (only_one_window() && check_changed_any(eap->forceit))) { + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) + || check_more(true, eap->forceit) == FAIL + || (only_one_window() && check_changed_any(eap->forceit, true))) { not_exiting(); } else { // quit last window @@ -5723,9 +5723,10 @@ static void ex_quit_all(exarg_T *eap) if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) return; - exiting = TRUE; - if (eap->forceit || !check_changed_any(FALSE)) + exiting = true; + if (eap->forceit || !check_changed_any(false, false)) { getout(0); + } not_exiting(); } @@ -6010,21 +6011,22 @@ static void ex_exit(exarg_T *eap) if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) return; - /* - * if more files or windows we won't exit - */ - if (check_more(FALSE, eap->forceit) == OK && only_one_window()) - exiting = TRUE; - if ( ((eap->cmdidx == CMD_wq - || curbufIsChanged()) - && do_write(eap) == FAIL) - || check_more(TRUE, eap->forceit) == FAIL - || (only_one_window() && check_changed_any(eap->forceit))) { + // if more files or windows we won't exit + if (check_more(false, eap->forceit) == OK && only_one_window()) { + exiting = true; + } + if (((eap->cmdidx == CMD_wq + || curbufIsChanged()) + && do_write(eap) == FAIL) + || check_more(true, eap->forceit) == FAIL + || (only_one_window() && check_changed_any(eap->forceit, false))) { not_exiting(); } else { - if (only_one_window()) /* quit last window, exit Vim */ + if (only_one_window()) { + // quit last window, exit Vim getout(0); - /* Quit current window, may free the buffer. */ + } + // Quit current window, may free the buffer. win_close(curwin, !P_HID(curwin->w_buffer)); } } @@ -9497,12 +9499,14 @@ static void ex_folddo(exarg_T *eap) static void ex_terminal(exarg_T *eap) { - // We will call termopen() with ['shell'] if not given a {cmd}. - char *name = (char *)p_sh; + char *name = (char *)p_sh; // Default to 'shell' if {cmd} is not given. + bool mustfree = false; char *lquote = "['"; char *rquote = "']"; + if (*eap->arg != NUL) { name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\"); + mustfree = true; lquote = rquote = "\""; } @@ -9512,7 +9516,7 @@ static void ex_terminal(exarg_T *eap) eap->forceit==TRUE ? "!" : "", lquote, name, rquote); do_cmdline_cmd(ex_cmd); - if (name != (char *)p_sh) { + if (mustfree) { xfree(name); } } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 49d1de21d9..dafb75ca87 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -293,10 +293,11 @@ EXTERN int msg_no_more INIT(= FALSE); /* don't use more prompt, truncate EXTERN char_u *sourcing_name INIT( = NULL); /* name of error message source */ EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */ -EXTERN int ex_nesting_level INIT(= 0); /* nesting level */ -EXTERN int debug_break_level INIT(= -1); /* break below this level */ -EXTERN int debug_did_msg INIT(= FALSE); /* did "debug mode" message */ -EXTERN int debug_tick INIT(= 0); /* breakpoint change count */ +EXTERN int ex_nesting_level INIT(= 0); // nesting level +EXTERN int debug_break_level INIT(= -1); // break below this level +EXTERN int debug_did_msg INIT(= false); // did "debug mode" message +EXTERN int debug_tick INIT(= 0); // breakpoint change count +EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level /* Values for "do_profiling". */ #define PROF_NONE 0 /* profiling not started */ @@ -503,6 +504,7 @@ EXTERN int cterm_normal_fg_bold INIT(= 0); EXTERN int cterm_normal_bg_color INIT(= 0); EXTERN RgbValue normal_fg INIT(= -1); EXTERN RgbValue normal_bg INIT(= -1); +EXTERN RgbValue normal_sp INIT(= -1); EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */ EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */ diff --git a/src/nvim/message.c b/src/nvim/message.c index 265f8c00c0..47f246fc76 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1508,51 +1508,44 @@ void msg_puts_attr(char_u *s, int attr) msg_puts_attr_len(s, -1, attr); } -/* - * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes). - * When "maxlen" is -1 there is no maximum length. - * When "maxlen" is >= 0 the message is not put in the history. - */ +/// Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes). +/// When "maxlen" is -1 there is no maximum length. +/// When "maxlen" is >= 0 the message is not put in the history. static void msg_puts_attr_len(char_u *str, int maxlen, int attr) { - /* - * If redirection is on, also write to the redirection file. - */ + // If redirection is on, also write to the redirection file. redir_write(str, maxlen); - /* - * Don't print anything when using ":silent cmd". - */ - if (msg_silent != 0) + // Don't print anything when using ":silent cmd". + if (msg_silent != 0) { return; + } - /* if MSG_HIST flag set, add message to history */ + // if MSG_HIST flag set, add message to history if ((attr & MSG_HIST) && maxlen < 0) { add_msg_hist(str, -1, attr); attr &= ~MSG_HIST; } - /* - * When writing something to the screen after it has scrolled, requires a - * wait-return prompt later. Needed when scrolling, resetting - * need_wait_return after some prompt, and then outputting something - * without scrolling - */ - if (msg_scrolled != 0 && !msg_scrolled_ign) - need_wait_return = TRUE; - msg_didany = TRUE; /* remember that something was outputted */ + // When writing something to the screen after it has scrolled, requires a + // wait-return prompt later. Needed when scrolling, resetting + // need_wait_return after some prompt, and then outputting something + // without scrolling + if (msg_scrolled != 0 && !msg_scrolled_ign) { + need_wait_return = true; + } + msg_didany = true; // remember that something was outputted - /* - * If there is no valid screen, use fprintf so we can see error messages. - * If termcap is not active, we may be writing in an alternate console - * window, cursor positioning may not work correctly (window size may be - * different, e.g. for Win32 console) or we just don't know where the - * cursor is. - */ - if (msg_use_printf()) - msg_puts_printf(str, maxlen); - else - msg_puts_display(str, maxlen, attr, FALSE); + // If there is no valid screen, use fprintf so we can see error messages. + // If termcap is not active, we may be writing in an alternate console + // window, cursor positioning may not work correctly (window size may be + // different, e.g. for Win32 console) or we just don't know where the + // cursor is. + if (msg_use_printf()) { + msg_puts_printf((char *)str, maxlen); + } else { + msg_puts_display(str, maxlen, attr, false); + } } /* @@ -1926,46 +1919,46 @@ int msg_use_printf(void) return !embedded_mode && !ui_active(); } -/* - * Print a message when there is no valid screen. - */ -static void msg_puts_printf(char_u *str, int maxlen) +/// Print a message when there is no valid screen. +static void msg_puts_printf(char *str, int maxlen) { - char_u *s = str; - char_u buf[4]; - char_u *p; + char *s = str; + char buf[4]; + char *p; while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) { if (!(silent_mode && p_verbose == 0)) { - /* NL --> CR NL translation (for Unix, not for "--version") */ - /* NL --> CR translation (for Mac) */ + // NL --> CR NL translation (for Unix, not for "--version") p = &buf[0]; - if (*s == '\n' && !info_message) + if (*s == '\n' && !info_message) { *p++ = '\r'; + } *p++ = *s; *p = '\0'; - if (info_message) /* informative message, not an error */ - mch_msg((char *)buf); - else - mch_errmsg((char *)buf); + if (info_message) { + mch_msg(buf); + } else { + mch_errmsg(buf); + } } - /* primitive way to compute the current column */ + // primitive way to compute the current column if (cmdmsg_rl) { - if (*s == '\r' || *s == '\n') + if (*s == '\r' || *s == '\n') { msg_col = Columns - 1; - else - --msg_col; + } else { + msg_col--; + } } else { - if (*s == '\r' || *s == '\n') + if (*s == '\r' || *s == '\n') { msg_col = 0; - else - ++msg_col; + } else { + msg_col++; + } } - ++s; + s++; } - msg_didout = TRUE; /* assume that line is not empty */ - + msg_didout = true; // assume that line is not empty } /* diff --git a/src/nvim/misc2.c b/src/nvim/misc2.c index 4b64de1be0..368f83cfb5 100644 --- a/src/nvim/misc2.c +++ b/src/nvim/misc2.c @@ -467,11 +467,12 @@ bool put_bytes(FILE *fd, uintmax_t number, size_t len) } /// Writes time_t to file "fd" in 8 bytes. -void put_time(FILE *fd, time_t time_) +/// @returns FAIL when the write failed. +int put_time(FILE *fd, time_t time_) { uint8_t buf[8]; time_to_bytes(time_, buf); - (void)fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd); + return fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd) == 1 ? OK : FAIL; } /// Writes time_t to "buf[8]". diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c index f0d92b52a0..6ffcffe2e1 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/msgpack_rpc/remote_ui.c @@ -96,6 +96,7 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, ui->visual_bell = remote_ui_visual_bell; ui->update_fg = remote_ui_update_fg; ui->update_bg = remote_ui_update_bg; + ui->update_sp = remote_ui_update_sp; ui->flush = remote_ui_flush; ui->suspend = remote_ui_suspend; ui->set_title = remote_ui_set_title; @@ -285,6 +286,10 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) PUT(hl, "background", INTEGER_OBJ(attrs.background)); } + if (attrs.special != -1) { + PUT(hl, "special", INTEGER_OBJ(attrs.special)); + } + ADD(args, DICTIONARY_OBJ(hl)); push_call(ui, "highlight_set", args); } @@ -323,6 +328,13 @@ static void remote_ui_update_bg(UI *ui, int bg) push_call(ui, "update_bg", args); } +static void remote_ui_update_sp(UI *ui, int sp) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(sp)); + push_call(ui, "update_sp", args); +} + static void remote_ui_flush(UI *ui) { UIData *data = ui->data; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index f5607f3676..382c4943ff 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -7648,19 +7648,25 @@ static void nv_halfpage(cmdarg_T *cap) */ static void nv_join(cmdarg_T *cap) { - if (VIsual_active) /* join the visual lines */ + if (VIsual_active) { // join the visual lines nv_operator(cap); - else if (!checkclearop(cap->oap)) { - if (cap->count0 <= 1) - cap->count0 = 2; /* default for join is two lines! */ + } else if (!checkclearop(cap->oap)) { + if (cap->count0 <= 1) { + cap->count0 = 2; // default for join is two lines! + } if (curwin->w_cursor.lnum + cap->count0 - 1 > - curbuf->b_ml.ml_line_count) - clearopbeep(cap->oap); /* beyond last line */ - else { - prep_redo(cap->oap->regname, cap->count0, - NUL, cap->cmdchar, NUL, NUL, cap->nchar); - do_join(cap->count0, cap->nchar == NUL, true, true, true); + curbuf->b_ml.ml_line_count) { + // can't join when on the last line + if (cap->count0 <= 2) { + clearopbeep(cap->oap); + return; + } + cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1; } + + prep_redo(cap->oap->regname, cap->count0, + NUL, cap->cmdchar, NUL, NUL, cap->nchar); + do_join(cap->count0, cap->nchar == NUL, true, true, true); } } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index eda963ff77..adfd0424f0 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5372,11 +5372,10 @@ void cursor_pos_info(dict_T *dict) } } - // Don't shorten this message, the user asked for it. bom_count = bomb_size(); if (bom_count > 0) { vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), - _("(+%" PRId64 " for BOM)"), (int64_t)byte_count); + _("(+%" PRId64 " for BOM)"), (int64_t)bom_count); } if (dict == NULL) { p = p_shm; @@ -5387,20 +5386,18 @@ void cursor_pos_info(dict_T *dict) } if (dict != NULL) { + // Don't shorten this message, the user asked for it. dict_add_nr_str(dict, "words", word_count, NULL); dict_add_nr_str(dict, "chars", char_count, NULL); dict_add_nr_str(dict, "bytes", byte_count + bom_count, NULL); - if (l_VIsual_active) { - dict_add_nr_str(dict, "visual_bytes", byte_count_cursor, NULL); - dict_add_nr_str(dict, "visual_chars", char_count_cursor, NULL); - dict_add_nr_str(dict, "visual_words", word_count_cursor, NULL); - } else { - dict_add_nr_str(dict, "cursor_bytes", byte_count_cursor, NULL); - dict_add_nr_str(dict, "cursor_chars", char_count_cursor, NULL); - dict_add_nr_str(dict, "cursor_words", word_count_cursor, NULL); + dict_add_nr_str(dict, l_VIsual_active ? "visual_bytes" : "cursor_bytes", + byte_count_cursor, NULL); + dict_add_nr_str(dict, l_VIsual_active ? "visual_chars" : "cursor_chars", + char_count_cursor, NULL); + dict_add_nr_str(dict, l_VIsual_active ? "visual_words" : "cursor_words", + word_count_cursor, NULL); } - } } /// Check if the default register (used in an unnamed paste) should be a diff --git a/src/nvim/option.c b/src/nvim/option.c index 2f22c245dd..45ebb4fa4c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1639,18 +1639,21 @@ do_set ( && STRNCMP(s, newval, i) == 0 && (!(flags & P_COMMA) || s[i] == ',' - || s[i] == NUL)) + || s[i] == NUL)) { break; - /* Count backslashes. Only a comma with an - * even number of backslashes before it is - * recognized as a separator */ - if (s > origval && s[-1] == '\\') - ++bs; - else + } + // Count backslashes. Only a comma with an even number of + // backslashes or a single backslash preceded by a comma + // before it is recognized as a separator + if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',') + || (s == origval + 1 && s[-1] == '\\')) { + bs++; + } else { bs = 0; + } } - /* do not add if already there */ + // do not add if already there if ((adding || prepending) && *s) { prepending = FALSE; adding = FALSE; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 87a9a7398c..904e97f8ca 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -619,6 +619,7 @@ EXTERN long p_titlelen; ///< 'titlelen' EXTERN char_u *p_titleold; ///< 'titleold' EXTERN char_u *p_titlestring; ///< 'titlestring' EXTERN char_u *p_tsr; ///< 'thesaurus' +EXTERN bool p_tgc; ///< 'termguicolors' EXTERN int p_ttimeout; ///< 'ttimeout' EXTERN long p_ttm; ///< 'ttimeoutlen' EXTERN char_u *p_udir; ///< 'undodir' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index a743e8c605..218e34f595 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2383,6 +2383,14 @@ return { defaults={if_true={vi=""}} }, { + full_name='termguicolors', abbreviation='tgc', + type='bool', scope={'global'}, + vi_def=false, + redraw={'everything'}, + varname='p_tgc', + defaults={if_true={vi=false}} + }, + { full_name='terse', type='bool', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 384a17004e..edc430410c 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -147,7 +147,7 @@ static char_u *homedir = NULL; void init_homedir(void) { - /* In case we are called a second time (when 'encoding' changes). */ + // In case we are called a second time (when 'encoding' changes). xfree(homedir); homedir = NULL; @@ -176,16 +176,16 @@ void init_homedir(void) if (var != NULL) { #ifdef UNIX - /* - * Change to the directory and get the actual path. This resolves - * links. Don't do it when we can't return. - */ + // Change to the directory and get the actual path. This resolves + // links. Don't do it when we can't return. if (os_dirname(NameBuff, MAXPATHL) == OK && os_chdir((char *)NameBuff) == 0) { - if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK) + if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK) { var = IObuff; - if (os_chdir((char *)NameBuff) != 0) + } + if (os_chdir((char *)NameBuff) != 0) { EMSG(_(e_prev_dir)); + } } #endif homedir = vim_strsave(var); @@ -239,29 +239,29 @@ void expand_env(char_u *src, char_u *dst, int dstlen) /// "~/" is also expanded, using $HOME. For Unix "~user/" is expanded. /// Skips over "\ ", "\~" and "\$" (not for Win32 though). /// If anything fails no expansion is done and dst equals src. -/// startstr recognize the start of a new name, for '~' expansion. +/// prefix recognize the start of a new name, for '~' expansion. /// @param srcp Input string e.g. "$HOME/vim.hlp" /// @param dst Where to put the result /// @param dstlen Maximum length of the result /// @param esc Should we escape spaces in expanded variables? /// @param one Should we expand more than one '~'? -/// @param startstr Common prefix for paths, can be NULL -void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, - char_u *startstr) +/// @param prefix Common prefix for paths, can be NULL +void expand_env_esc(char_u *restrict srcp, + char_u *restrict dst, + int dstlen, + bool esc, + bool one, + char_u *prefix) { - char_u *src; char_u *tail; - int c; char_u *var; bool copy_char; bool mustfree; // var was allocated, need to free it later bool at_start = true; // at start of a name - int startstr_len = 0; - if (startstr != NULL) - startstr_len = (int)STRLEN(startstr); + int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix); - src = skipwhite(srcp); + char_u *src = skipwhite(srcp); dstlen--; // leave one char space for "\," while (*src && dstlen > 0) { // Skip over `=expr`. @@ -281,6 +281,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, dstlen -= (int)len; continue; } + copy_char = true; if ((*src == '$') || (*src == '~' && at_start)) { mustfree = false; @@ -290,14 +291,15 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, if (*src != '~') { // environment var tail = src + 1; var = dst; - c = dstlen - 1; + int c = dstlen - 1; #ifdef UNIX // Unix has ${var-name} type environment vars if (*tail == '{' && !vim_isIDc('{')) { - tail++; /* ignore '{' */ - while (c-- > 0 && *tail && *tail != '}') + tail++; // ignore '{' + while (c-- > 0 && *tail != NUL && *tail != '}') { *var++ = *tail++; + } } else // NOLINT #endif { @@ -321,7 +323,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, #if defined(UNIX) } #endif - } else if ( src[1] == NUL /* home directory */ + } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) { var = homedir; @@ -331,12 +333,13 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, // Copy ~user to dst[], so we can put a NUL after it. tail = src; var = dst; - c = dstlen - 1; - while ( c-- > 0 - && *tail - && vim_isfilec(*tail) - && !vim_ispathsep(*tail)) + int c = dstlen - 1; + while (c-- > 0 + && *tail + && vim_isfilec(*tail) + && !vim_ispathsep(*tail)) { *var++ = *tail++; + } *var = NUL; // Use os_get_user_directory() to get the user directory. // If this function fails, the shell is used to @@ -344,8 +347,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, // does not support ~user (old versions of /bin/sh). var = (char_u *)os_get_user_directory((char *)dst + 1); mustfree = true; - if (var == NULL) - { + if (var == NULL) { expand_T xpc; ExpandInit(&xpc); @@ -381,8 +383,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) { char_u *p = vim_strsave_escaped(var, (char_u *)" \t"); - if (mustfree) + if (mustfree) { xfree(var); + } var = p; mustfree = true; } @@ -391,7 +394,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) { STRCPY(dst, var); dstlen -= (int)STRLEN(var); - c = (int)STRLEN(var); + int c = (int)STRLEN(var); // if var[] ends in a path separator and tail[] starts // with it, skip a character if (*var != NUL && after_pathsep((char *)dst, (char *)dst + c) @@ -404,8 +407,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, src = tail; copy_char = false; } - if (mustfree) + if (mustfree) { xfree(var); + } } if (copy_char) { // copy at least one char @@ -422,9 +426,10 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, *dst++ = *src++; --dstlen; - if (startstr != NULL && src - startstr_len >= srcp - && STRNCMP(src - startstr_len, startstr, startstr_len) == 0) + if (prefix != NULL && src - prefix_len >= srcp + && STRNCMP(src - prefix_len, prefix, prefix_len) == 0) { at_start = true; + } } } *dst = NUL; @@ -451,17 +456,37 @@ static char *vim_version_dir(const char *vimdir) return NULL; } -/// If the string between "p" and "pend" ends in "name/", return "pend" minus -/// the length of "name/". Otherwise return "pend". -static char *remove_tail(char *p, char *pend, char *name) +/// If `dirname + "/"` precedes `pend` in the path, return the pointer to +/// `dirname + "/" + pend`. Otherwise return `pend`. +/// +/// Examples (path = /usr/local/share/nvim/runtime/doc/help.txt): +/// +/// pend = help.txt +/// dirname = doc +/// -> doc/help.txt +/// +/// pend = doc/help.txt +/// dirname = runtime +/// -> runtime/doc/help.txt +/// +/// pend = runtime/doc/help.txt +/// dirname = vim74 +/// -> runtime/doc/help.txt +/// +/// @param path Path to a file +/// @param pend A suffix of the path +/// @param dirname The immediate path fragment before the pend +/// @return The new pend including dirname or just pend +static char *remove_tail(char *path, char *pend, char *dirname) { - size_t len = STRLEN(name) + 1; - char *newend = pend - len; + size_t len = STRLEN(dirname); + char *new_tail = pend - len - 1; - if (newend >= p - && fnamencmp((char_u *)newend, (char_u *)name, len - 1) == 0 - && (newend == p || after_pathsep(p, newend))) - return newend; + if (new_tail >= path + && fnamencmp((char_u *)new_tail, (char_u *)dirname, len) == 0 + && (new_tail == path || after_pathsep(path, new_tail))) { + return new_tail; + } return pend; } @@ -745,9 +770,10 @@ void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one) /// @param src Input file name char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET { - size_t len = 3; /* space for "~/" and trailing NUL */ - if (src != NULL) /* just in case */ + size_t len = 3; // space for "~/" and trailing NUL + if (src != NULL) { // just in case len += STRLEN(src); + } char_u *dst = xmalloc(len); home_replace(buf, src, dst, (int)len, true); return dst; @@ -783,8 +809,7 @@ char_u *get_env_name(expand_T *xp, int idx) STRLCPY(name, envname, ENVNAMELEN); xfree(envname); return name; - } else { - return NULL; } + return NULL; } diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 49a74cf0d1..143a7160b0 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -111,8 +111,8 @@ int os_nodetype(const char *name) #endif uv_stat_t statbuf; - if (os_stat(name, &statbuf) == 0) { - return NODE_NORMAL; + if (0 != os_stat(name, &statbuf)) { + return NODE_NORMAL; // File doesn't exist. } #ifndef WIN32 diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 17cb8a86aa..151b9d3790 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -160,9 +160,6 @@ qf_init ( { qf_info_T *qi = &ql_info; - if (efile == NULL) - return FAIL; - if (wp != NULL) { qi = ll_get_or_alloc_list(wp); } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 10b5b6bba4..34eef83164 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3385,11 +3385,9 @@ win_line ( && lcs_nbsp) || (c == ' ' && lcs_space && ptr - line <= trailcol))) { c = (c == ' ') ? lcs_space : lcs_nbsp; - if (area_attr == 0 && search_attr == 0) { - n_attr = 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; // save current attr - } + n_attr = 1; + extra_attr = hl_attr(HLF_8); + saved_attr2 = char_attr; // save current attr mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { mb_utf8 = true; @@ -3402,11 +3400,9 @@ win_line ( if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') { c = lcs_trail; - if (!attr_pri) { - n_attr = 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; /* save current attr */ - } + n_attr = 1; + extra_attr = hl_attr(HLF_8); + saved_attr2 = char_attr; // save current attr mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { mb_utf8 = TRUE; @@ -3554,11 +3550,9 @@ win_line ( c = ' '; } lcs_eol_one = -1; - --ptr; /* put it back at the NUL */ - if (!attr_pri) { - extra_attr = hl_attr(HLF_AT); - n_attr = 1; - } + ptr--; // put it back at the NUL + extra_attr = hl_attr(HLF_AT); + n_attr = 1; mb_c = c; if (enc_utf8 && (*mb_char2len)(c) > 1) { mb_utf8 = TRUE; @@ -3587,12 +3581,10 @@ win_line ( n_extra = byte2cells(c) - 1; c = *p_extra++; } - if (!attr_pri) { - n_attr = n_extra + 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; /* save current attr */ - } - mb_utf8 = FALSE; /* don't draw as UTF-8 */ + n_attr = n_extra + 1; + extra_attr = hl_attr(HLF_8); + saved_attr2 = char_attr; // save current attr + mb_utf8 = false; // don't draw as UTF-8 } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') @@ -3702,11 +3694,10 @@ win_line ( did_wcol = true; } - /* Don't override visual selection highlighting. */ - if (n_attr > 0 - && draw_state == WL_LINE - && !attr_pri) - char_attr = extra_attr; + // Don't override visual selection highlighting. + if (n_attr > 0 && draw_state == WL_LINE) { + char_attr = hl_combine_attr(char_attr, extra_attr); + } /* * Handle the case where we are in column 0 but not on the first @@ -3734,13 +3725,12 @@ win_line ( mb_utf8 = TRUE; u8cc[0] = 0; c = 0xc0; - } else - mb_utf8 = FALSE; /* don't draw as UTF-8 */ - if (!attr_pri) { - saved_attr3 = char_attr; /* save current attr */ - char_attr = hl_attr(HLF_AT); /* later copied to char_attr */ - n_attr3 = 1; + } else { + mb_utf8 = false; // don't draw as UTF-8 } + saved_attr3 = char_attr; // save current attr + char_attr = hl_attr(HLF_AT); // later copied to char_attr + n_attr3 = 1; } /* diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 3192be1b3c..51c8597d53 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -46,7 +46,7 @@ #ifdef HAVE_BE64TOH # define _BSD_SOURCE 1 # define _DEFAULT_SOURCE 1 -# include <endian.h> +# include ENDIAN_INCLUDE_FILE #endif // Note: when using bufset hash pointers are intentionally casted to uintptr_t diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 0acaa9ae2b..84906a3548 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -45,6 +45,9 @@ // Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word. // Only use it for small word lists! +// Use SPELL_COMPRESS_ALLWAYS for debugging: compress the word tree after +// adding a word. Only use it for small word lists! + // Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a // specific word. @@ -156,6 +159,8 @@ // // sectionID == SN_NOSPLITSUGS: nothing // +// sectionID == SN_NOCOMPOUNDSUGS: nothing +// // sectionID == SN_WORDS: <word> ... // <word> N bytes NUL terminated common word // @@ -482,7 +487,7 @@ struct slang_S { regprog_T **sl_prefprog; // table with regprogs for prefixes garray_T sl_rep; // list of fromto_T entries from REP lines - short sl_rep_first[256]; // indexes where byte first appears, -1 if + int16_t sl_rep_first[256]; // indexes where byte first appears, -1 if // there is none garray_T sl_sal; // list of salitem_T entries from SAL lines salfirst_T sl_sal_first[256]; // indexes where byte first appears, -1 if @@ -494,8 +499,9 @@ struct slang_S { // "sl_sal_first" maps chars, when has_mbyte // "sl_sal" is a list of wide char lists. garray_T sl_repsal; // list of fromto_T entries from REPSAL lines - short sl_repsal_first[256]; // sl_rep_first for REPSAL lines - bool sl_nosplitsugs; // don't suggest splitting a word + int16_t sl_repsal_first[256]; // sl_rep_first for REPSAL lines + bool sl_nosplitsugs; // don't suggest splitting a word + bool sl_nocompoundsugs; // don't suggest compounding // Info from the .sug file. Loaded on demand. time_t sl_sugtime; // timestamp for .sug file @@ -558,6 +564,7 @@ typedef struct langp_S { #define SN_WORDS 13 // common words #define SN_NOSPLITSUGS 14 // don't split word for suggestions #define SN_INFO 15 // info section +#define SN_NOCOMPOUNDSUGS 16 // don't compound for suggestions #define SN_END 255 // end of sections #define SNF_REQUIRED 1 // <sectionflags>: required section @@ -948,6 +955,7 @@ typedef struct spellinfo_S { char_u *si_sofoto; // SOFOTO text int si_nosugfile; // NOSUGFILE item found int si_nosplitsugs; // NOSPLITSUGS item found + int si_nocompoundsugs; // NOCOMPOUNDSUGS item found int si_followup; // soundsalike: ? int si_collapse; // soundsalike: ? hashtab_T si_commonwords; // hashtable for common words @@ -2666,7 +2674,11 @@ spell_load_file ( break; case SN_NOSPLITSUGS: - lp->sl_nosplitsugs = true; // <timestamp> + lp->sl_nosplitsugs = true; + break; + + case SN_NOCOMPOUNDSUGS: + lp->sl_nocompoundsugs = true; break; case SN_COMPOUND: @@ -2868,7 +2880,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp) // Read REP or REPSAL items section from "fd": <repcount> <rep> ... // Return SP_*ERROR flags. -static int read_rep_section(FILE *fd, garray_T *gap, short *first) +static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first) { int cnt; fromto_T *ftp; @@ -4266,9 +4278,9 @@ static void spell_print_node(wordnode_T *node, int depth) PRINTSOME(line1, depth, "(%d)", node->wn_nr, 0); PRINTSOME(line2, depth, " ", 0, 0); PRINTSOME(line3, depth, " ", 0, 0); - msg(line1); - msg(line2); - msg(line3); + msg((char_u *)line1); + msg((char_u *)line2); + msg((char_u *)line3); } else { node->wn_u1.index = TRUE; @@ -4289,9 +4301,9 @@ static void spell_print_node(wordnode_T *node, int depth) PRINTSOME(line3, depth, " ", 0, 0); if (node->wn_byte == NUL) { - msg(line1); - msg(line2); - msg(line3); + msg((char_u *)line1); + msg((char_u *)line2); + msg((char_u *)line3); } // do the children @@ -4633,6 +4645,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) spin->si_nobreak = true; } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) { spin->si_nosplitsugs = true; + } else if (is_aff_rule(items, itemcnt, "NOCOMPOUNDSUGS", 1)) { + spin->si_nocompoundsugs = true; } else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) { spin->si_nosugfile = true; } else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) { @@ -6289,7 +6303,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int node = *prev; } #ifdef SPELL_PRINTTREE - smsg("Added \"%s\"", word); + smsg((char_u *)"Added \"%s\"", word); spell_print_tree(root->wn_sibling); #endif @@ -6312,8 +6326,8 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int // 3. When compressed before, added "compress_added" words // (si_compress_cnt == 1) and the number of free nodes drops below the // maximum word length. -#ifndef SPELL_PRINTTREE - if (spin->si_compress_cnt == 1 +#ifndef SPELL_COMPRESS_ALLWAYS + if (spin->si_compress_cnt == 1 // NOLINT(readability/braces) ? spin->si_free_count < MAXWLEN : spin->si_blocks_cnt >= compress_start) #endif @@ -6857,6 +6871,15 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) put_bytes(fd, 0, 4); // <sectionlen> } + // SN_NOCOMPUNDSUGS: nothing + // This is used to notify that no suggestions with compounds are to be + // made. + if (spin->si_nocompoundsugs) { + putc(SN_NOCOMPOUNDSUGS, fd); // <sectionID> + putc(0, fd); // <sectionflags> + put_bytes(fd, 0, 4); // <sectionlen> + } + // SN_COMPOUND: compound info. // We don't mark it required, when not supported all compound words will // be bad words. @@ -9771,6 +9794,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // be possible to compound another (short) word. try_compound = false; if (!soundfold + && !slang->sl_nocompoundsugs && slang->sl_compprog != NULL && ((unsigned)flags >> 24) != 0 && sp->ts_twordlen - sp->ts_splitoff @@ -9791,21 +9815,21 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // For NOBREAK we never try splitting, it won't make any word // valid. - if (slang->sl_nobreak) + if (slang->sl_nobreak && !slang->sl_nocompoundsugs) { try_compound = true; - - // If we could add a compound word, and it's also possible to - // split at this point, do the split first and set - // TSF_DIDSPLIT to avoid doing it again. - else if (!fword_ends - && try_compound - && (sp->ts_flags & TSF_DIDSPLIT) == 0) { + } else if (!fword_ends + && try_compound + && (sp->ts_flags & TSF_DIDSPLIT) == 0) { + // If we could add a compound word, and it's also possible to + // split at this point, do the split first and set + // TSF_DIDSPLIT to avoid doing it again. try_compound = false; sp->ts_flags |= TSF_DIDSPLIT; --sp->ts_curi; // do the same NUL again compflags[sp->ts_complen] = NUL; - } else + } else { sp->ts_flags &= ~TSF_DIDSPLIT; + } if (try_split || try_compound) { if (!try_compound && (!fword_ends || !goodword_ends)) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 41af7af55c..1f9dbd8228 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -62,8 +62,10 @@ struct hl_group { int sg_gui; // "gui=" highlighting attributes RgbValue sg_rgb_fg; // RGB foreground color RgbValue sg_rgb_bg; // RGB background color + RgbValue sg_rgb_sp; // RGB special color uint8_t *sg_rgb_fg_name; // RGB foreground color name uint8_t *sg_rgb_bg_name; // RGB background color name + uint8_t *sg_rgb_sp_name; // RGB special color name }; #define SG_CTERM 2 // cterm has been set @@ -2615,33 +2617,37 @@ find_endpos ( IF_SYN_TIME(&spp_skip->sp_time)); spp_skip->sp_prog = regmatch.regprog; if (r && regmatch.startpos[0].col <= best_regmatch.startpos[0].col) { - /* Add offset to skip pattern match */ + // Add offset to skip pattern match syn_add_end_off(&pos, ®match, spp_skip, SPO_ME_OFF, 1); - /* If the skip pattern goes on to the next line, there is no - * match with an end pattern in this line. */ - if (pos.lnum > startpos->lnum) + // If the skip pattern goes on to the next line, there is no + // match with an end pattern in this line. + if (pos.lnum > startpos->lnum) { break; + } - line = ml_get_buf(syn_buf, startpos->lnum, FALSE); + line = ml_get_buf(syn_buf, startpos->lnum, false); + int line_len = (int)STRLEN(line); - /* take care of an empty match or negative offset */ - if (pos.col <= matchcol) - ++matchcol; - else if (pos.col <= regmatch.endpos[0].col) + // take care of an empty match or negative offset + if (pos.col <= matchcol) { + matchcol++; + } else if (pos.col <= regmatch.endpos[0].col) { matchcol = pos.col; - else - /* Be careful not to jump over the NUL at the end-of-line */ + } else { + // Be careful not to jump over the NUL at the end-of-line for (matchcol = regmatch.endpos[0].col; - line[matchcol] != NUL && matchcol < pos.col; - ++matchcol) - ; + matchcol < line_len && matchcol < pos.col; + matchcol++) { + } + } - /* if the skip pattern includes end-of-line, break here */ - if (line[matchcol] == NUL) + // if the skip pattern includes end-of-line, break here + if (matchcol >= line_len) { break; + } - continue; /* start with first end pattern again */ + continue; // start with first end pattern again } } @@ -5004,6 +5010,10 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) curwin->w_s->b_syn_sync_maxlines = 0; } } else if (STRCMP(key, "LINECONT") == 0) { + if (*next_arg == NUL) { // missing pattern + illegal = true; + break; + } if (curwin->w_s->b_syn_linecont_pat != NULL) { EMSG(_("E403: syntax sync: line continuations pattern specified twice")); finished = TRUE; @@ -6161,12 +6171,11 @@ do_highlight ( break; } - /* - * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or - * "guibg"). - */ - while (*linep && !ascii_iswhite(*linep) && *linep != '=') - ++linep; + // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg", + // "guibg" or "guisp"). + while (*linep && !ascii_iswhite(*linep) && *linep != '=') { + linep++; + } xfree(key); key = vim_strnsave_up(key_start, (int)(linep - key_start)); linep = skipwhite(linep); @@ -6362,18 +6371,14 @@ do_highlight ( } else HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; } - color &= 7; /* truncate to 8 colors */ - } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) { - switch (t_colors) { - case 16: - color = color_numbers_8[i]; - break; - case 88: - color = color_numbers_88[i]; - break; - case 256: - color = color_numbers_256[i]; - break; + color &= 7; // truncate to 8 colors + } else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) { + if (t_colors == 88) { + color = color_numbers_88[i]; + } else if (t_colors >= 256) { + color = color_numbers_256[i]; + } else { + color = color_numbers_8[i]; } } } @@ -6448,7 +6453,23 @@ do_highlight ( normal_bg = HL_TABLE()[idx].sg_rgb_bg; } } else if (STRCMP(key, "GUISP") == 0) { - // Ignored for now + if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) { + if (!init) + HL_TABLE()[idx].sg_set |= SG_GUI; + + xfree(HL_TABLE()[idx].sg_rgb_sp_name); + if (STRCMP(arg, "NONE") != 0) { + HL_TABLE()[idx].sg_rgb_sp_name = (uint8_t *)xstrdup((char *)arg); + HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg); + } else { + HL_TABLE()[idx].sg_rgb_sp_name = NULL; + HL_TABLE()[idx].sg_rgb_sp = -1; + } + } + + if (is_normal_group) { + normal_sp = HL_TABLE()[idx].sg_rgb_sp; + } } else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) { // Ignored for now } else { @@ -6512,6 +6533,7 @@ void restore_cterm_colors(void) { normal_fg = -1; normal_bg = -1; + normal_sp = -1; cterm_normal_fg_color = 0; cterm_normal_fg_bold = 0; cterm_normal_bg_color = 0; @@ -6528,6 +6550,7 @@ static int hl_has_settings(int idx, int check_link) || HL_TABLE()[idx].sg_cterm_bg != 0 || HL_TABLE()[idx].sg_rgb_fg_name != NULL || HL_TABLE()[idx].sg_rgb_bg_name != NULL + || HL_TABLE()[idx].sg_rgb_sp_name != NULL || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)); } @@ -6544,14 +6567,18 @@ static void highlight_clear(int idx) HL_TABLE()[idx].sg_gui = 0; HL_TABLE()[idx].sg_rgb_fg = -1; HL_TABLE()[idx].sg_rgb_bg = -1; + HL_TABLE()[idx].sg_rgb_sp = -1; xfree(HL_TABLE()[idx].sg_rgb_fg_name); HL_TABLE()[idx].sg_rgb_fg_name = NULL; xfree(HL_TABLE()[idx].sg_rgb_bg_name); HL_TABLE()[idx].sg_rgb_bg_name = NULL; - /* Clear the script ID only when there is no link, since that is not - * cleared. */ - if (HL_TABLE()[idx].sg_link == 0) + xfree(HL_TABLE()[idx].sg_rgb_sp_name); + HL_TABLE()[idx].sg_rgb_sp_name = NULL; + // Clear the script ID only when there is no link, since that is not + // cleared. + if (HL_TABLE()[idx].sg_link == 0) { HL_TABLE()[idx].sg_scriptID = 0; + } } @@ -6593,7 +6620,8 @@ int get_attr_entry(attrentry_T *aep) && aep->cterm_bg_color == taep->cterm_bg_color && aep->rgb_ae_attr == taep->rgb_ae_attr && aep->rgb_fg_color == taep->rgb_fg_color - && aep->rgb_bg_color == taep->rgb_bg_color) { + && aep->rgb_bg_color == taep->rgb_bg_color + && aep->rgb_sp_color == taep->rgb_sp_color) { return i + ATTR_OFF; } } @@ -6631,6 +6659,7 @@ int get_attr_entry(attrentry_T *aep) taep->rgb_ae_attr = aep->rgb_ae_attr; taep->rgb_fg_color = aep->rgb_fg_color; taep->rgb_bg_color = aep->rgb_bg_color; + taep->rgb_sp_color = aep->rgb_sp_color; return table->ga_len - 1 + ATTR_OFF; } @@ -6692,6 +6721,10 @@ int hl_combine_attr(int char_attr, int prim_attr) if (spell_aep->rgb_bg_color >= 0) { new_en.rgb_bg_color = spell_aep->rgb_bg_color; } + + if (spell_aep->rgb_sp_color >= 0) { + new_en.rgb_sp_color = spell_aep->rgb_sp_color; + } } return get_attr_entry(&new_en); } @@ -6729,7 +6762,7 @@ static void highlight_list_one(int id) didh = highlight_list_arg(id, didh, LIST_STRING, 0, sgp->sg_rgb_bg_name, "guibg"); didh = highlight_list_arg(id, didh, LIST_STRING, - 0, NULL, "guisp"); + 0, sgp->sg_rgb_sp_name, "guisp"); if (sgp->sg_link && !got_int) { (void)syn_list_header(didh, 9999, id); @@ -6843,8 +6876,9 @@ highlight_color ( if (modec == 'g') { if (fg) return HL_TABLE()[id - 1].sg_rgb_fg_name; - if (sp) - return NULL; + if (sp) { + return HL_TABLE()[id - 1].sg_rgb_sp_name; + } return HL_TABLE()[id - 1].sg_rgb_bg_name; } if (font || sp) @@ -6931,7 +6965,17 @@ set_hl_attr ( // before setting attr_entry->{f,g}g_color to a other than -1 at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1; at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1; - sgp->sg_attr = get_attr_entry(&at_en); + at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1; + + if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0 + || at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1 + || at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0 + || at_en.rgb_ae_attr != 0) { + sgp->sg_attr = get_attr_entry(&at_en); + } else { + // If all the fields are cleared, clear the attr field back to default value + sgp->sg_attr = 0; + } } /* @@ -7262,6 +7306,10 @@ int highlight_changed(void) hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg; } + if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) { + hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp; + } + highlight_ga.ga_len = hlcnt + i + 1; set_hl_attr(hlcnt + i); /* At long last we can apply */ highlight_stlnc[i] = syn_id2attr(hlcnt + i + 1); diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h index 67cf672ef2..8d207e6286 100644 --- a/src/nvim/syntax_defs.h +++ b/src/nvim/syntax_defs.h @@ -69,8 +69,8 @@ struct syn_state { // Structure shared between syntax.c, screen.c typedef struct attr_entry { - short rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc. - RgbValue rgb_fg_color, rgb_bg_color; + int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc. + RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color; int cterm_fg_color, cterm_bg_color; } attrentry_T; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 82c7cd4de9..2fba6dd563 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -28,20 +28,19 @@ SCRIPTS := \ test53.out \ test55.out \ test64.out \ - test68.out \ test69.out \ test73.out \ test79.out \ test_listlbr.out \ - test_breakindent.out \ - test_close_count.out \ test_marks.out \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ - test_viml.res \ test_cursor_func.res \ + test_help_tagjump.res \ + test_menu.res \ + test_viml.res \ test_alot.res SCRIPTS_GUI := test16.out @@ -98,7 +97,7 @@ test1.out: $(VIMPROG) $(SCRIPTS) $(SCRIPTS_GUI): $(VIMPROG) test1.out RM_ON_RUN := test.out X* viminfo -RM_ON_START := tiny.vim small.vim mbyte.vim test.ok +RM_ON_START := test.ok RUN_VIM := VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(TOOL) $(VIMPROG) -u unix.vim -U NONE -i viminfo --noplugin -s dotest.in clean: diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 6601dcf52f..2712fb9371 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -20,9 +20,6 @@ " If cleanup after each Test_ function is needed, define a TearDown function. " It will be called after each Test_ function. -" Without the +eval feature we can't run these tests, bail out. -so small.vim - " Check that the screen size is at least 24 x 80 characters. if &lines < 24 || &columns < 80 let error = 'Screen size too small! Tests require at least 24 lines with 80 characters' @@ -68,7 +65,8 @@ function /^Test_ redir END let tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) -for test in tests +" Execute the tests in alphabetical order. +for test in sort(tests) if exists("*SetUp") call SetUp() endif diff --git a/src/nvim/testdir/test1.in b/src/nvim/testdir/test1.in index 85ff1b4db2..272500cd25 100644 --- a/src/nvim/testdir/test1.in +++ b/src/nvim/testdir/test1.in @@ -1,20 +1,5 @@ - First a simple test to check if the test script works. -If Vim was not compiled with the +eval feature, the small.vim script will be -set to copy the test.ok file to test.out, so that it looks like the test -succeeded. Otherwise an empty small.vim is written. small.vim is sourced by -tests that require the +eval feature or other features that are missing in the -small version. - -If Vim was not compiled with the +windows feature, the tiny.vim script will be -set like small.vim above. tiny.vim is sourced by tests that require the -+windows feature or other features that are missing in the tiny version. - -If Vim was not compiled with the +multi_byte feature, the mbyte.vim script will -be set like small.vim above. mbyte.vim is sourced by tests that require the -+multi_byte feature. - STARTTEST :" If columns or lines are too small, create wrongtermsize. :" (Some tests will fail. When columns and/or lines are small) @@ -23,25 +8,6 @@ STARTTEST :" Write a single line to test.out to check if testing works at all. :%d athis is a test:w! test.out -:" Create small.vim and tiny.vim empty, create mbyte.vim to skip the test. -0D:w! small.vim -:w! tiny.vim -ae! test.ok -w! test.out -qa! -:w! mbyte.vim -:" -:" If +multi_byte feature supported, make mbyte.vim empty. -:if has("multi_byte") | sp another | w! mbyte.vim | q | endif -:" -:" If +eval feature supported quit here, leaving tiny.vim and small.vim empty. -:" Otherwise write small.vim to skip the test. -:if 1 | q! | endif -:w! small.vim -:" If +windows feature not supported :sp will fail and tiny.vim will be -:" written to skip the test. -:sp another -:wq! tiny.vim :qa! ENDTEST diff --git a/src/nvim/testdir/test10.in b/src/nvim/testdir/test10.in index 769d690acb..2178cf41ce 100644 --- a/src/nvim/testdir/test10.in +++ b/src/nvim/testdir/test10.in @@ -1,9 +1,6 @@ Test for 'errorformat'. This will fail if the quickfix feature was disabled. STARTTEST -:so small.vim -:" Also test a BOM is ignored. -:so mbyte.vim :7/start of errorfile/,/end of errorfile/w! Xerrorfile1 :7/start of errorfile/,/end of errorfile/-1w! Xerrorfile2 :/start of testfile/,/end of testfile/w! Xtestfile diff --git a/src/nvim/testdir/test10a.in b/src/nvim/testdir/test10a.in index 19e8652fe5..99a5a03db8 100644 --- a/src/nvim/testdir/test10a.in +++ b/src/nvim/testdir/test10a.in @@ -1,7 +1,6 @@ Test for 'errorformat'. STARTTEST -:so small.vim :/start of errorfile/,/end of errorfile/w! Xerrorfile :/start of testfile/,/end of testfile/w! Xtestfile :cf Xerrorfile diff --git a/src/nvim/testdir/test12.in b/src/nvim/testdir/test12.in index be3169a625..0c0623e5d4 100644 --- a/src/nvim/testdir/test12.in +++ b/src/nvim/testdir/test12.in @@ -4,7 +4,6 @@ Tests for 'directory' option. - "dir", in directory relative to current dir STARTTEST -:so small.vim :set dir=.,~ :/start of testfile/,/end of testfile/w! Xtest1 :" do an ls of the current dir to find the swap file (should not be there) diff --git a/src/nvim/testdir/test13.in b/src/nvim/testdir/test13.in index 6713f80e88..fa9ba312b7 100644 --- a/src/nvim/testdir/test13.in +++ b/src/nvim/testdir/test13.in @@ -11,7 +11,6 @@ Also test changing buffers in a BufDel autocommand. If this goes wrong there are ml_line errors and/or a Crash. STARTTEST -:so small.vim :/^start of testfile/,/^end of testfile/w! Xtestje1 :/^start of testfile/,/^end of testfile/w! Xtestje2 :/^start of testfile/,/^end of testfile/w! Xtestje3 diff --git a/src/nvim/testdir/test14.in b/src/nvim/testdir/test14.in index 6ebec99af6..bef2e45431 100644 --- a/src/nvim/testdir/test14.in +++ b/src/nvim/testdir/test14.in @@ -5,7 +5,6 @@ Also test "[m", "]m", "[M" and "]M" Also test search() STARTTEST -:so small.vim /Start cursor here vaBiBD:?Bug?,/Piece/-2w! test.out /^- Bug diff --git a/src/nvim/testdir/test17.in b/src/nvim/testdir/test17.in index a8c81b832d..83abe17770 100644 --- a/src/nvim/testdir/test17.in +++ b/src/nvim/testdir/test17.in @@ -3,7 +3,6 @@ Tests for: - ":checkpath!" with various 'include' settings. STARTTEST -:so small.vim :set isfname=@,48-57,/,.,-,_,+,,,$,:,~,{,} :function! DeleteDirectory(dir) : if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32") diff --git a/src/nvim/testdir/test30.in b/src/nvim/testdir/test30.in index 2a89eac73d..56d5d5c6c2 100644 --- a/src/nvim/testdir/test30.in +++ b/src/nvim/testdir/test30.in @@ -3,7 +3,6 @@ Test for a lot of variations of the 'fileformats' option Note: This test will fail if "cat" is not available. STARTTEST -:so small.vim :" first write three test files, one in each format :set fileformat=unix :set fileformats= diff --git a/src/nvim/testdir/test32.in b/src/nvim/testdir/test32.in index 1a73c862d1..76bd9be889 100644 --- a/src/nvim/testdir/test32.in +++ b/src/nvim/testdir/test32.in @@ -21,7 +21,6 @@ Test for insert expansion * t-expansion STARTTEST -:so small.vim :se backspace="" :se cpt=.,w ff=unix | $-2,$w!Xtestfile | set ff& :se cot= diff --git a/src/nvim/testdir/test34.in b/src/nvim/testdir/test34.in index 71ee5f63b2..4cb7e9494a 100644 --- a/src/nvim/testdir/test34.in +++ b/src/nvim/testdir/test34.in @@ -4,7 +4,6 @@ Also test that a builtin function cannot be replaced. Also test for regression when calling arbitrary expression. STARTTEST -:so small.vim :function Table(title, ...) : let ret = a:title : let idx = 1 diff --git a/src/nvim/testdir/test37.in b/src/nvim/testdir/test37.in index 8ca1125793..156bf74a10 100644 --- a/src/nvim/testdir/test37.in +++ b/src/nvim/testdir/test37.in @@ -1,6 +1,6 @@ Test for 'scrollbind'. <eralston@computer.org> Do not add a line below! STARTTEST -:so small.vim +: :set noscrollbind :set scrollopt=ver,jump :set scrolloff=2 diff --git a/src/nvim/testdir/test40.in b/src/nvim/testdir/test40.in index ced4572fb8..b0285709e5 100644 --- a/src/nvim/testdir/test40.in +++ b/src/nvim/testdir/test40.in @@ -1,7 +1,6 @@ Test for "*Cmd" autocommands STARTTEST -:so small.vim :set wildchar=^E :/^start/,$w! Xxx " write lines below to Xxx :au BufReadCmd XtestA 0r Xxx|$del diff --git a/src/nvim/testdir/test42.in b/src/nvim/testdir/test42.in Binary files differindex c35569a76c..0ea0198d12 100644 --- a/src/nvim/testdir/test42.in +++ b/src/nvim/testdir/test42.in diff --git a/src/nvim/testdir/test47.in b/src/nvim/testdir/test47.in index f15eaf0f8f..c95c6a6850 100644 --- a/src/nvim/testdir/test47.in +++ b/src/nvim/testdir/test47.in @@ -3,7 +3,6 @@ Tests for vertical splits and filler lines in diff mode Also tests restoration of saved options by :diffoff. STARTTEST -:so small.vim :" Disable the title to avoid xterm keeping the wrong one. :set notitle noicon /^1 diff --git a/src/nvim/testdir/test48.in b/src/nvim/testdir/test48.in index 998e1bba00..1df5a3c46a 100644 --- a/src/nvim/testdir/test48.in +++ b/src/nvim/testdir/test48.in @@ -1,7 +1,6 @@ This is a test of 'virtualedit'. STARTTEST -:so small.vim :set noswf :set ve=all j-dgg diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in index d95052e14c..435e62765b 100644 --- a/src/nvim/testdir/test49.in +++ b/src/nvim/testdir/test49.in @@ -4,7 +4,6 @@ If after adding a new test, the test output doesn't appear properly in test49.failed, try to add one or more "G"s at the line ending in "test.out" STARTTEST -:so small.vim :se nomore :lang mess C :so test49.vim diff --git a/src/nvim/testdir/test50.in b/src/nvim/testdir/test50.in index 0cbf4bf6d6..392177b808 100644 --- a/src/nvim/testdir/test50.in +++ b/src/nvim/testdir/test50.in @@ -2,7 +2,6 @@ Test for shortpathname ':8' extension. Only for use on Win32 systems! STARTTEST -:so small.vim :fun! TestIt(file, bits, expected) let res=fnamemodify(a:file,a:bits) if a:expected == '' diff --git a/src/nvim/testdir/test52.in b/src/nvim/testdir/test52.in index 206b65a1f9..fa75129193 100644 --- a/src/nvim/testdir/test52.in +++ b/src/nvim/testdir/test52.in @@ -1,7 +1,6 @@ Tests for reading and writing files with conversion for Win32. STARTTEST -:so mbyte.vim :" make this a dummy test for non-Win32 systems :if !has("win32") | e! test.ok | wq! test.out | endif :" diff --git a/src/nvim/testdir/test53.in b/src/nvim/testdir/test53.in index 7c35b2e853..f3778c5192 100644 --- a/src/nvim/testdir/test53.in +++ b/src/nvim/testdir/test53.in @@ -7,7 +7,6 @@ Also test match() and matchstr() Also test the gn command and repeating it. STARTTEST -:so small.vim /^start:/ da" 0va'a'rx diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in index 9e3c1168cc..9a55eac6f6 100644 --- a/src/nvim/testdir/test55.in +++ b/src/nvim/testdir/test55.in @@ -1,7 +1,6 @@ Tests for List and Dictionary types. vim: set ft=vim : STARTTEST -:so small.vim :fun Test(...) :lang C :" Creating List directly with different types diff --git a/src/nvim/testdir/test64.in b/src/nvim/testdir/test64.in index fd19d3af32..c4585ecbce 100644 --- a/src/nvim/testdir/test64.in +++ b/src/nvim/testdir/test64.in @@ -5,7 +5,6 @@ A pattern that gives the expected result produces OK, so that we know it was actually tried. STARTTEST -:so small.vim :" tl is a List of Lists with: :" regexp engine :" regexp pattern diff --git a/src/nvim/testdir/test68.in b/src/nvim/testdir/test68.in deleted file mode 100644 index ca54e942b5..0000000000 --- a/src/nvim/testdir/test68.in +++ /dev/null @@ -1,131 +0,0 @@ -Test for text formatting. - -Results of test68: - -STARTTEST -:so small.vim -/^{/+1 -:set noai tw=2 fo=t -gRa b -ENDTEST - -{ - - -} - -STARTTEST -/^{/+1 -:set ai tw=2 fo=tw -gqgqjjllab -ENDTEST - -{ -a b - -a -} - -STARTTEST -/^{/+1 -:set tw=3 fo=t -gqgqo -a -ENDTEST - -{ -a -} - -STARTTEST -/^{/+1 -:set tw=2 fo=tcq1 comments=:# -gqgqjgqgqo -a b -#a b -ENDTEST - -{ -a b -#a b -} - -STARTTEST -/^{/+1 -:set tw=5 fo=tcn comments=:# -A bjA b -ENDTEST - -{ - 1 a -# 1 a -} - -STARTTEST -/^{/+3 -:set tw=5 fo=t2a si -i A_ -ENDTEST - -{ - - x a - b - c - -} - -STARTTEST -/^{/+1 -:set tw=5 fo=qn comments=:# -gwap -ENDTEST - -{ -# 1 a b -} - -STARTTEST -/^{/+1 -:set tw=5 fo=q2 comments=:# -gwap -ENDTEST - -{ -# x -# a b -} - -STARTTEST -/^{/+2 -:set tw& fo=a -I^^ -ENDTEST - -{ - 1aa - 2bb -} - -STARTTEST -/mno pqr/ -:setl tw=20 fo=an12wcq comments=s1:/*,mb:*,ex:*/ -A vwx yz -ENDTEST - -/* abc def ghi jkl - * mno pqr stu - */ - -STARTTEST -/^#/ -:setl tw=12 fo=tqnc comments=:# -A foobar -ENDTEST - -# 1 xxxxx - -STARTTEST -:g/^STARTTEST/.,/^ENDTEST/d -:1;/^Results/,$wq! test.out -ENDTEST diff --git a/src/nvim/testdir/test68.ok b/src/nvim/testdir/test68.ok deleted file mode 100644 index b3726a0a27..0000000000 --- a/src/nvim/testdir/test68.ok +++ /dev/null @@ -1,77 +0,0 @@ -Results of test68: - - -{ -a -b -} - - -{ -a -b - -a -b -} - - -{ -a - - -a - -} - - -{ -a b -#a b - -a b -#a b -} - - -{ - 1 a - b -# 1 a -# b -} - - -{ - - x a - b_ - c - -} - - -{ -# 1 a -# b -} - - -{ -# x a -# b -} - - -{ 1aa ^^2bb } - - -/* abc def ghi jkl - * mno pqr stu - * vwx yz - */ - - -# 1 xxxxx -# foobar - diff --git a/src/nvim/testdir/test69.in b/src/nvim/testdir/test69.in index f583947dfb..39b360fc81 100644 --- a/src/nvim/testdir/test69.in +++ b/src/nvim/testdir/test69.in @@ -4,7 +4,7 @@ And test "ra" on multi-byte characters. Also test byteidx() and byteidxcomp() STARTTEST -:so mbyte.vim +: ENDTEST Results of test69: diff --git a/src/nvim/testdir/test73.in b/src/nvim/testdir/test73.in index c525e51d28..7d6c7287a5 100644 --- a/src/nvim/testdir/test73.in +++ b/src/nvim/testdir/test73.in @@ -1,7 +1,6 @@ Tests for find completion. STARTTEST -:so small.vim :set wildmode=full :" Do all test in a separate window to avoid E211 when we recursively :" delete the Xfind directory during cleanup diff --git a/src/nvim/testdir/test8.in b/src/nvim/testdir/test8.in index 41e6262e92..a5e6034782 100644 --- a/src/nvim/testdir/test8.in +++ b/src/nvim/testdir/test8.in @@ -2,7 +2,6 @@ Test for BufWritePre autocommand that deletes or unloads the buffer. Test for BufUnload autocommand that unloads all other buffers. STARTTEST -:so small.vim :au BufWritePre Xxx1 bunload :au BufWritePre Xxx2 bwipe /^start of @@ -35,8 +34,6 @@ endfunc :set shada='100 :au BufUnload * call CloseAll() :au VimLeave * call WriteToOut() -:e small.vim -:sp mbyte.vim :q :qa! ENDTEST diff --git a/src/nvim/testdir/test_breakindent.in b/src/nvim/testdir/test_breakindent.in deleted file mode 100644 index 5a8e580c4a..0000000000 --- a/src/nvim/testdir/test_breakindent.in +++ /dev/null @@ -1,123 +0,0 @@ -Test for breakindent - -STARTTEST -:so small.vim -:if !exists("+breakindent") | e! test.ok | w! test.out | qa! | endif -:set wildchar=^E -:10new|:vsp|:vert resize 20 -:put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\" -:set ts=4 sw=4 sts=4 breakindent -:fu! ScreenChar(line, width) -: let c='' -: for i in range(1,a:width) -: let c.=nr2char(screenchar(a:line, i)) -: endfor -: let c.="\n" -: for i in range(1,a:width) -: let c.=nr2char(screenchar(a:line+1, i)) -: endfor -: let c.="\n" -: for i in range(1,a:width) -: let c.=nr2char(screenchar(a:line+2, i)) -: endfor -: return c -:endfu -:fu DoRecordScreen() -: wincmd l -: $put =printf(\"\n%s\", g:test) -: $put =g:line1 -: wincmd p -:endfu -:set briopt=min:0 -:let g:test="Test 1: Simple breakindent" -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test="Test 2: Simple breakindent + sbr=>>" -:set sbr=>> -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test ="Test 3: Simple breakindent + briopt:sbr" -:set briopt=sbr,min:0 sbr=++ -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test ="Test 4: Simple breakindent + min width: 18" -:set sbr= briopt=min:18 -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test =" Test 5: Simple breakindent + shift by 2" -:set briopt=shift:2,min:0 -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test=" Test 6: Simple breakindent + shift by -1" -:set briopt=shift:-1,min:0 -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr" -:set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 -:let line1=ScreenChar(line('.'),10) -:call DoRecordScreen() -:let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr" -:set briopt=shift:1,sbr,min:0 nu sbr=# list lcs&vi -:let line1=ScreenChar(line('.'),10) -:call DoRecordScreen() -:let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list" -:set briopt-=sbr -:let line1=ScreenChar(line('.'),10) -:call DoRecordScreen() -:let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n" -:set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0 -:let line1=ScreenChar(line('.'),10) -:call DoRecordScreen() -:wincmd p -:let g:test="\n Test 11: strdisplaywidth when breakindent is on" -:set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4 -:let text=getline(2) "skip leading tab when calculating text width -:let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3 " text wraps 3 times -:$put =g:test -:$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width) -:let g:str="\t\t\t\t\t{" -:let g:test=" Test 12: breakindent + long indent" -:wincmd p -:set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 -:$put =g:str -zt:let line1=ScreenChar(1,10) -:wincmd p -:call DoRecordScreen() -:" -:" Test, that the string " a\tb\tc\td\te" is correctly -:" displayed in a 20 column wide window (see bug report -:" https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ -:only -:vert 20new -:set all& breakindent briopt=min:10 -:call setline(1, [" a\tb\tc\td\te", " z y x w v"]) -:/^\s*a -fbgjyl:let line1 = @0 -:?^\s*z -fygjyl:let line2 = @0 -:quit! -:$put ='Test 13: breakindent with wrapping Tab' -:$put =line1 -:$put =line2 -:" -:let g:test="Test 14: breakindent + visual blockwise delete #1" -:set all& breakindent shada+=nX-test-breakindent.shada -:30vnew -:normal! 3a1234567890 -:normal! a abcde -:exec "normal! 0\<C-V>tex" -:let line1=ScreenChar(line('.'),8) -:call DoRecordScreen() -:" -:let g:test="Test 15: breakindent + visual blockwise delete #2" -:%d -:normal! 4a1234567890 -:exec "normal! >>\<C-V>3f0x" -:let line1=ScreenChar(line('.'),20) -:call DoRecordScreen() -:quit! -:" -:%w! test.out -:qa! -ENDTEST -dummy text diff --git a/src/nvim/testdir/test_breakindent.ok b/src/nvim/testdir/test_breakindent.ok deleted file mode 100644 index 995bd5f29c..0000000000 --- a/src/nvim/testdir/test_breakindent.ok +++ /dev/null @@ -1,74 +0,0 @@ - - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP - -Test 1: Simple breakindent - abcd - qrst - GHIJ - -Test 2: Simple breakindent + sbr=>> - abcd - >>qr - >>EF - -Test 3: Simple breakindent + briopt:sbr - abcd -++ qrst -++ GHIJ - -Test 4: Simple breakindent + min width: 18 - abcd - qrstuv - IJKLMN - - Test 5: Simple breakindent + shift by 2 - abcd - qr - EF - - Test 6: Simple breakindent + shift by -1 - abcd - qrstu - HIJKL - - Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr - 2 ab - ? m - ? x - - Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr - 2 ^Iabcd - # opq - # BCD - - Test 9: breakindent + shift by +1 + 'nu' + sbr=# list - 2 ^Iabcd - #op - #AB - - Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n - 2 ab -~ mn -~ yz - - Test 11: strdisplaywidth when breakindent is on -strdisplaywidth: 46 == calculated: 64 - { - - Test 12: breakindent + long indent -56 - -~ -Test 13: breakindent with wrapping Tab -d -w - -Test 14: breakindent + visual blockwise delete #1 -e -~ -~ - -Test 15: breakindent + visual blockwise delete #2 - 1234567890 -~ -~ diff --git a/src/nvim/testdir/test_close_count.in b/src/nvim/testdir/test_close_count.in deleted file mode 100644 index 58dfb425ce..0000000000 --- a/src/nvim/testdir/test_close_count.in +++ /dev/null @@ -1,156 +0,0 @@ -Tests for :[count]close! and :[count]hide vim: set ft=vim : - -STARTTEST -:let tests = [] -:so tiny.vim -:for i in range(5) -:new -:endfor -:4wincmd w -:close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:$close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -:2close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -:new -:new -:2wincmd w -:-1close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:2wincmd w -:+1close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:e! test.out -:call append(0, map(copy(tests), 'join(v:val, " ")')) -:w -:only! -:b1 -ENDTEST - -STARTTEST -:let tests = [] -:so tiny.vim -:for i in range(5) -:new -:endfor -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:4wincmd w -:.hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:$hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -:2hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -:new -:new -:3wincmd w -:-hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:2wincmd w -:+hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:e! test.out -:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) -Go -:w -:only! -:b1 -ENDTEST - -STARTTEST -:let tests = [] -:so tiny.vim -:set hidden -:for i in range(5) -:new -:endfor -:1wincmd w -:$ hide -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:$-1 close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -:.+close! -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:e! test.out -:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) -Go -:w -:only! -:b1 -ENDTEST - -STARTTEST -:let tests = [] -:so tiny.vim -:set hidden -:for i in range(5) -:new -:endfor -:4wincmd w -c -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -1c -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -9c -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:1wincmd w -2c -:let buffers = [] -:windo call add(buffers, bufnr('%')) -:call add(tests, buffers) -:only! -:e! test.out -:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) -:w -:qa! -ENDTEST - - diff --git a/src/nvim/testdir/test_close_count.ok b/src/nvim/testdir/test_close_count.ok deleted file mode 100644 index 1cee870487..0000000000 --- a/src/nvim/testdir/test_close_count.ok +++ /dev/null @@ -1,23 +0,0 @@ -6 5 4 2 1 -5 4 2 1 -5 4 2 -5 2 -7 5 2 -7 5 - -13 12 11 10 9 1 -13 12 11 9 1 -12 11 9 1 -12 11 9 -12 9 -15 12 9 -15 12 - -20 19 18 17 16 -20 19 18 16 -20 18 16 - -25 24 23 21 1 -24 23 21 1 -24 23 21 -24 21 diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim new file mode 100644 index 0000000000..9f9207d27d --- /dev/null +++ b/src/nvim/testdir/test_help_tagjump.vim @@ -0,0 +1,40 @@ +" Tests for :help! {subject} + +func SetUp() + " v:progpath is …/build/bin/nvim and we need …/build/runtime + " to be added to &rtp + let builddir = fnamemodify(exepath(v:progpath), ':h:h') + let s:rtp = &rtp + let &rtp .= printf(',%s/runtime', builddir) +endfunc + +func TearDown() + let &rtp = s:rtp +endfunc + +func Test_help_tagjump() + help + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*help.txt\*') + helpclose + + exec "help! ('textwidth'" + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ "\\*'textwidth'\\*") + helpclose + + exec "help! ('buflisted')," + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ "\\*'buflisted'\\*") + helpclose + + exec "help! abs({expr})" + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*abs()\*') + helpclose + + exec "help! arglistid([{winnr})" + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*arglistid()\*') + helpclose +endfunc diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in index 6084711786..b5bac080ee 100644 --- a/src/nvim/testdir/test_listlbr.in +++ b/src/nvim/testdir/test_listlbr.in @@ -1,7 +1,6 @@ Test for linebreak and list option (non-utf8) STARTTEST -:so small.vim :if !exists("+linebreak") | e! test.ok | w! test.out | qa! | endif :set wildchar=^E :10new|:vsp|:vert resize 20 diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim new file mode 100644 index 0000000000..be559467c8 --- /dev/null +++ b/src/nvim/testdir/test_menu.vim @@ -0,0 +1,9 @@ +" Test that the system menu can be loaded. + +func Test_load_menu() + try + source $VIMRUNTIME/menu.vim + catch + call assert_false(1, 'error while loading menus: ' . v:exception) + endtry +endfunc diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index e1c0407b27..62bc81ba64 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -81,7 +81,7 @@ UI *tui_start(void) { UI *ui = xcalloc(1, sizeof(UI)); ui->stop = tui_stop; - ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL; + ui->rgb = p_tgc; ui->resize = tui_resize; ui->clear = tui_clear; ui->eol_clear = tui_eol_clear; @@ -100,6 +100,7 @@ UI *tui_start(void) ui->visual_bell = tui_visual_bell; ui->update_fg = tui_update_fg; ui->update_bg = tui_update_bg; + ui->update_sp = tui_update_sp; ui->flush = tui_flush; ui->suspend = tui_suspend; ui->set_title = tui_set_title; @@ -573,6 +574,11 @@ static void tui_update_bg(UI *ui, int bg) ((TUIData *)ui->data)->grid.bg = bg; } +static void tui_update_sp(UI *ui, int sp) +{ + // Do nothing; 'special' color is for GUI only +} + static void tui_flush(UI *ui) { TUIData *data = ui->data; diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h index df51e1fced..ad6d96a168 100644 --- a/src/nvim/ugrid.h +++ b/src/nvim/ugrid.h @@ -21,7 +21,7 @@ struct ugrid { UCell **cells; }; -#define EMPTY_ATTRS ((HlAttrs){false, false, false, false, false, -1, -1}) +#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 }) #define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \ do { \ diff --git a/src/nvim/ui.c b/src/nvim/ui.c index d32969f149..05322a6f64 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -155,6 +155,7 @@ void ui_resize(int new_width, int new_height) UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1)); UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1)); + UI_CALL(update_sp, (ui->rgb ? normal_sp : -1)); sr.top = 0; sr.bot = height - 1; @@ -388,7 +389,7 @@ static void parse_control_character(uint8_t c) static void set_highlight_args(int attr_code) { - HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 }; + HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 }; HlAttrs cterm_attrs = rgb_attrs; if (attr_code == HL_NORMAL) { @@ -425,6 +426,10 @@ static void set_highlight_args(int attr_code) rgb_attrs.background = aep->rgb_bg_color; } + if (aep->rgb_sp_color != normal_sp) { + rgb_attrs.special = aep->rgb_sp_color; + } + if (cterm_normal_fg_color != aep->cterm_fg_color) { cterm_attrs.foreground = aep->cterm_fg_color - 1; } diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 4c051fcfbf..5934d2fee9 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -7,7 +7,7 @@ typedef struct { bool bold, underline, undercurl, italic, reverse; - int foreground, background; + int foreground, background, special; } HlAttrs; typedef struct ui_t UI; @@ -35,6 +35,7 @@ struct ui_t { void (*flush)(UI *ui); void (*update_fg)(UI *ui, int fg); void (*update_bg)(UI *ui, int bg); + void (*update_sp)(UI *ui, int sp); void (*suspend)(UI *ui); void (*set_title)(UI *ui, char *title); void (*set_icon)(UI *ui, char *icon); diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index 359fffe3bf..fd9d4671e3 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -49,6 +49,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler) rv->bridge.visual_bell = ui_bridge_visual_bell; rv->bridge.update_fg = ui_bridge_update_fg; rv->bridge.update_bg = ui_bridge_update_bg; + rv->bridge.update_sp = ui_bridge_update_sp; rv->bridge.flush = ui_bridge_flush; rv->bridge.suspend = ui_bridge_suspend; rv->bridge.set_title = ui_bridge_set_title; @@ -305,6 +306,16 @@ static void ui_bridge_update_bg_event(void **argv) ui->update_bg(ui, PTR2INT(argv[1])); } +static void ui_bridge_update_sp(UI *b, int sp) +{ + UI_CALL(b, update_sp, 2, b, INT2PTR(sp)); +} +static void ui_bridge_update_sp_event(void **argv) +{ + UI *ui = UI(argv[0]); + ui->update_sp(ui, PTR2INT(argv[1])); +} + static void ui_bridge_flush(UI *b) { UI_CALL(b, flush, 1, b); diff --git a/src/nvim/version.c b/src/nvim/version.c index d7e75ee26e..c19e1b01c2 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -69,9 +69,15 @@ static char *features[] = { // clang-format off static int included_patches[] = { + 1832, + 1809, + 1808, + 1806, + 1799, 1757, 1755, 1753, + 1728, 1654, 1652, 1643, @@ -107,10 +113,10 @@ static int included_patches[] = { 1574, // 1573, // 1572 NA - // 1571, + 1571, 1570, 1569, - // 1568, + 1568, // 1567, // 1566 NA // 1565, @@ -157,15 +163,15 @@ static int included_patches[] = { // 1524 NA // 1523 NA // 1522 NA - // 1521, + 1521, // 1520 NA // 1519 NA // 1518 NA // 1517 NA - // 1516, + 1516, // 1515 NA // 1514 NA - // 1513, + 1513, // 1512 NA 1511, // 1510 NA @@ -419,7 +425,7 @@ static int included_patches[] = { // 1262 NA // 1261 NA // 1260 NA - // 1259, + 1259, // 1258 NA // 1257 NA // 1256 NA @@ -568,7 +574,7 @@ static int included_patches[] = { 1113, 1112, // 1111, - // 1110, + 1110, // 1109 NA // 1108, 1107, @@ -576,7 +582,7 @@ static int included_patches[] = { 1105, // 1104 NA // 1103 NA - // 1102, + 1102, 1101, // 1100 NA // 1099 NA @@ -607,32 +613,32 @@ static int included_patches[] = { // 1074 NA, // 1073, 1072, - // 1071, + 1071, // 1070 NA // 1069 NA // 1068, // 1067 NA // 1066 NA 1065, - // 1064, + 1064, // 1063 NA // 1062 NA - // 1061, + 1061, // 1060 NA - // 1059, + 1059, // 1058, - // 1057, + 1057, // 1056, 1055, - // 1054, - // 1053, - // 1052, + 1054, + 1053, + 1052, // 1051, - // 1050, - // 1049, - // 1048, - // 1047, - // 1046, + 1050, + 1049, + 1048, + 1047, + 1046, // 1045 NA // 1044 NA // 1043 NA @@ -641,10 +647,10 @@ static int included_patches[] = { // 1040 NA // 1039, // 1038 NA - // 1037, - // 1036, + 1037, + 1036, 1035, - // 1034, + 1034, // 1033 NA 1032, // 1031 NA, @@ -660,8 +666,8 @@ static int included_patches[] = { // 1021 NA // 1020 NA // 1019 NA - // 1018, - // 1017, + 1018, + 1017, // 1016 NA 1015, // 1014 NA @@ -807,7 +813,7 @@ static int included_patches[] = { // 874 NA // 873 NA // 872 NA - // 871, + 871, 870, // 869 NA 868, diff --git a/test/benchmark/bench_re_freeze_spec.lua b/test/benchmark/bench_re_freeze_spec.lua index d40d9f9ece..a194b5f44c 100644 --- a/test/benchmark/bench_re_freeze_spec.lua +++ b/test/benchmark/bench_re_freeze_spec.lua @@ -25,8 +25,8 @@ local measure_script = [[ endfunc]] describe('regexp search', function() - -- The test cases rely on a small Vim script, which we source here, and also - -- on a temporary result file, which we prepare and write to disk. + -- The test cases rely on a temporary result file, which we prepare and write + -- to disk. setup(function() clear() source(measure_script) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6ccadda72d..37b7bf664c 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -176,7 +176,7 @@ local function dedent(str) return str end -- create a pattern for the indent - indent = indent:gsub('%s', '%%s') + indent = indent:gsub('%s', '[ \t]') -- strip it from the first line str = str:gsub('^'..indent, '') -- strip it from the remaining lines diff --git a/test/functional/legacy/031_close_commands_spec.lua b/test/functional/legacy/031_close_commands_spec.lua index 3597cba12a..b79b1903ba 100644 --- a/test/functional/legacy/031_close_commands_spec.lua +++ b/test/functional/legacy/031_close_commands_spec.lua @@ -10,7 +10,7 @@ -- :edit local helpers = require('test.functional.helpers') -local feed, insert = helpers.feed, helpers.insert +local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect describe('Commands that close windows and/or buffers', function() @@ -84,6 +84,28 @@ describe('Commands that close windows and/or buffers', function() feed('GA 4<Esc>:all!<CR>') execute('1wincmd w') expect('testtext 2 2 2') + + -- Test ":q!" and hidden buffer. + execute('bw! Xtest1 Xtest2 Xtest3 Xtest4') + execute('sp Xtest1') + execute('wincmd w') + execute('bw!') + execute('set modified') + execute('bot sp Xtest2') + execute('set modified') + execute('bot sp Xtest3') + execute('set modified') + execute('wincmd t') + execute('hide') + execute('q!') + expect('testtext 3') + execute('q!') + feed('<CR>') + expect('testtext 1') + source([[ + q! + " Now nvim should have exited + throw "Oh, Not finished yet."]]) end) teardown(function() diff --git a/test/functional/legacy/068_text_formatting_spec.lua b/test/functional/legacy/068_text_formatting_spec.lua new file mode 100644 index 0000000000..cac8be77f3 --- /dev/null +++ b/test/functional/legacy/068_text_formatting_spec.lua @@ -0,0 +1,207 @@ +local helpers = require('test.functional.helpers') +local feed, insert = helpers.feed, helpers.insert +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('text formatting', function() + setup(clear) + + it('is working', function() + -- The control character <C-A> (byte \x01) needs to be put in the buffer + -- directly. But the insert function sends the text to nvim in insert + -- mode so it has to be escaped with <C-V>. + insert([[ + Results of test68: + + + { + + + } + + + { + a b + + a + } + + + { + a + } + + + { + a b + #a b + } + + + { + 1 a + # 1 a + } + + + { + + x a + b + c + + } + + + { + # 1 a b + } + + + { + # x + # a b + } + + + { + 1aa + 2bb + } + + + /* abc def ghi jkl + * mno pqr stu + */ + + + # 1 xxxxx + ]]) + + execute('/^{/+1') + execute('set noai tw=2 fo=t') + feed('gRa b<esc>') + + execute('/^{/+1') + execute('set ai tw=2 fo=tw') + feed('gqgqjjllab<esc>') + + execute('/^{/+1') + execute('set tw=3 fo=t') + feed('gqgqo<cr>') + feed('a <C-V><C-A><esc><esc>') + + execute('/^{/+1') + execute('set tw=2 fo=tcq1 comments=:#') + feed('gqgqjgqgqo<cr>') + feed('a b<cr>') + feed('#a b<esc>') + + execute('/^{/+1') + execute('set tw=5 fo=tcn comments=:#') + feed('A b<esc>jA b<esc>') + + execute('/^{/+3') + execute('set tw=5 fo=t2a si') + feed('i <esc>A_<esc>') + + execute('/^{/+1') + execute('set tw=5 fo=qn comments=:#') + feed('gwap<cr>') + + execute('/^{/+1') + execute('set tw=5 fo=q2 comments=:#') + feed('gwap<cr>') + + execute('/^{/+2') + execute('set tw& fo=a') + feed('I^^<esc><esc>') + + execute('/mno pqr/') + execute('setl tw=20 fo=an12wcq comments=s1:/*,mb:*,ex:*/') + feed('A vwx yz<esc>') + + execute('/^#/') + execute('setl tw=12 fo=tqnc comments=:#') + feed('A foobar<esc>') + + -- Assert buffer contents. + expect([[ + Results of test68: + + + { + a + b + } + + + { + a + b + + a + b + } + + + { + a + + + a + + } + + + { + a b + #a b + + a b + #a b + } + + + { + 1 a + b + # 1 a + # b + } + + + { + + x a + b_ + c + + } + + + { + # 1 a + # b + } + + + { + # x a + # b + } + + + { 1aa ^^2bb } + + + /* abc def ghi jkl + * mno pqr stu + * vwx yz + */ + + + # 1 xxxxx + # foobar + ]]) + end) +end) diff --git a/test/functional/legacy/108_backtrace_debug_commands_spec.lua b/test/functional/legacy/108_backtrace_debug_commands_spec.lua new file mode 100644 index 0000000000..6df645d255 --- /dev/null +++ b/test/functional/legacy/108_backtrace_debug_commands_spec.lua @@ -0,0 +1,177 @@ +-- Tests for backtrace debug commands. + +local helpers = require('test.functional.helpers') +local feed, clear = helpers.feed, helpers.clear +local execute, expect = helpers.execute, helpers.expect + +describe('108', function() + before_each(clear) + + it('is working', function() + execute('lang mess C') + execute('function! Foo()') + execute(' let var1 = 1') + execute(' let var2 = Bar(var1) + 9') + execute(' return var2') + execute('endfunction') + execute('function! Bar(var)') + execute(' let var1 = 2 + a:var') + execute(' let var2 = Bazz(var1) + 4') + execute(' return var2') + execute('endfunction') + execute('function! Bazz(var)') + execute(' let var1 = 3 + a:var') + execute(' let var3 = "another var"') + execute(' return var1') + execute('endfunction') + execute('new') + execute('debuggreedy') + execute('redir => out') + execute('debug echo Foo()') + feed('step<cr>') + feed('step<cr>') + feed('step<cr>') + feed('step<cr>') + feed('step<cr>') + feed('step<cr>') + feed([[echo "- show backtrace:\n"<cr>]]) + feed('backtrace<cr>') + feed([[echo "\nshow variables on different levels:\n"<cr>]]) + feed('echo var1<cr>') + feed('up<cr>') + feed('back<cr>') + feed('echo var1<cr>') + feed('u<cr>') + feed('bt<cr>') + feed('echo var1<cr>') + feed([[echo "\n- undefined vars:\n"<cr>]]) + feed('step<cr>') + feed('frame 2<cr>') + feed('echo "undefined var3 on former level:"<cr>') + feed('echo var3<cr>') + feed('fr 0<cr>') + feed([[echo "here var3 is defined with \"another var\":"<cr>]]) + feed('echo var3<cr>') + feed('step<cr>') + feed('step<cr>') + feed('step<cr>') + feed('up<cr>') + feed([[echo "\nundefined var2 on former level"<cr>]]) + feed('echo var2<cr>') + feed('down<cr>') + feed('echo "here var2 is defined with 10:"<cr>') + feed('echo var2<cr>') + feed([[echo "\n- backtrace movements:\n"<cr>]]) + feed('b<cr>') + feed([[echo "\nnext command cannot go down, we are on bottom\n"<cr>]]) + feed('down<cr>') + feed('up<cr>') + feed([[echo "\nnext command cannot go up, we are on top\n"<cr>]]) + feed('up<cr>') + feed('b<cr>') + feed('echo "fil is not frame or finish, it is file"<cr>') + feed('fil<cr>') + feed([[echo "\n- relative backtrace movement\n"<cr>]]) + feed('fr -1<cr>') + feed('frame<cr>') + feed('fra +1<cr>') + feed('fram<cr>') + feed([[echo "\n- go beyond limits does not crash\n"<cr>]]) + feed('fr 100<cr>') + feed('fra<cr>') + feed('frame -40<cr>') + feed('fram<cr>') + feed([[echo "\n- final result 19:"<cr>]]) + feed('cont<cr>') + execute('0debuggreedy') + execute('redir END') + execute('$put =out') + + -- Assert buffer contents. + expect([=[ + + + + - show backtrace: + + 2 function Foo[2] + 1 Bar[2] + ->0 Bazz + line 2: let var3 = "another var" + + show variables on different levels: + + 6 + 2 function Foo[2] + ->1 Bar[2] + 0 Bazz + line 2: let var3 = "another var" + 3 + ->2 function Foo[2] + 1 Bar[2] + 0 Bazz + line 2: let var3 = "another var" + 1 + + - undefined vars: + + undefined var3 on former level: + Error detected while processing function Foo[2]..Bar[2]..Bazz: + line 3: + E121: Undefined variable: var3 + E15: Invalid expression: var3 + here var3 is defined with "another var": + another var + + undefined var2 on former level + Error detected while processing function Foo[2]..Bar: + line 3: + E121: Undefined variable: var2 + E15: Invalid expression: var2 + here var2 is defined with 10: + 10 + + - backtrace movements: + + 1 function Foo[2] + ->0 Bar + line 3: End of function + + next command cannot go down, we are on bottom + + frame is zero + + next command cannot go up, we are on top + + frame at highest level: 1 + ->1 function Foo[2] + 0 Bar + line 3: End of function + fil is not frame or finish, it is file + "[No Name]" --No lines in buffer-- + + - relative backtrace movement + + 1 function Foo[2] + ->0 Bar + line 3: End of function + ->1 function Foo[2] + 0 Bar + line 3: End of function + + - go beyond limits does not crash + + frame at highest level: 1 + ->1 function Foo[2] + 0 Bar + line 3: End of function + frame is zero + 1 function Foo[2] + ->0 Bar + line 3: End of function + + - final result 19: + 19 + ]=]) + end) +end) diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua new file mode 100644 index 0000000000..a12d4add10 --- /dev/null +++ b/test/functional/legacy/breakindent_spec.lua @@ -0,0 +1,211 @@ +-- Test for breakindent + +local helpers = require('test.functional.helpers') +local feed, insert = helpers.feed, helpers.insert +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('breakindent', function() + setup(clear) + + it('is working', function() + insert('dummy text') + + execute('set wildchar=^E') + execute('10new') + execute('vsp') + execute('vert resize 20') + execute([[put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"]]) + execute('set ts=4 sw=4 sts=4 breakindent') + execute('fu! ScreenChar(line, width)') + execute(' let c=""') + execute(' for i in range(1,a:width)') + execute(' let c.=nr2char(screenchar(a:line, i))') + execute(' endfor') + execute([[ let c.="\n"]]) + execute(' for i in range(1,a:width)') + execute(' let c.=nr2char(screenchar(a:line+1, i))') + execute(' endfor') + execute([[ let c.="\n"]]) + execute(' for i in range(1,a:width)') + execute(' let c.=nr2char(screenchar(a:line+2, i))') + execute(' endfor') + execute(' return c') + execute('endfu') + execute('fu DoRecordScreen()') + execute(' wincmd l') + execute([[ $put =printf(\"\n%s\", g:test)]]) + execute(' $put =g:line1') + execute(' wincmd p') + execute('endfu') + execute('set briopt=min:0') + execute('let g:test="Test 1: Simple breakindent"') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test="Test 2: Simple breakindent + sbr=>>"') + execute('set sbr=>>') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test ="Test 3: Simple breakindent + briopt:sbr"') + execute('set briopt=sbr,min:0 sbr=++') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test ="Test 4: Simple breakindent + min width: 18"') + execute('set sbr= briopt=min:18') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test =" Test 5: Simple breakindent + shift by 2"') + execute('set briopt=shift:2,min:0') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test=" Test 6: Simple breakindent + shift by -1"') + execute('set briopt=shift:-1,min:0') + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + execute('let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"') + execute('set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4') + execute('let line1=ScreenChar(line("."),10)') + execute('call DoRecordScreen()') + execute('let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"') + execute('set briopt=shift:1,sbr,min:0 nu sbr=# list lcs&vi') + execute('let line1=ScreenChar(line("."),10)') + execute('call DoRecordScreen()') + execute([[let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"]]) + execute('set briopt-=sbr') + execute('let line1=ScreenChar(line("."),10)') + execute('call DoRecordScreen()') + execute([[let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"]]) + execute('set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0') + execute('let line1=ScreenChar(line("."),10)') + execute('call DoRecordScreen()') + execute('wincmd p') + execute([[let g:test="\n Test 11: strdisplaywidth when breakindent is on"]]) + execute('set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4') + -- Skip leading tab when calculating text width. + execute('let text=getline(2)') + -- Text wraps 3 times. + execute('let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3') + execute('$put =g:test') + execute([[$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)]]) + execute([[let g:str="\t\t\t\t\t{"]]) + execute('let g:test=" Test 12: breakindent + long indent"') + execute('wincmd p') + execute('set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4') + execute('$put =g:str') + feed('zt') + execute('let line1=ScreenChar(1,10)') + execute('wincmd p') + execute('call DoRecordScreen()') + + -- Test, that the string " a\tb\tc\td\te" is correctly displayed in a + -- 20 column wide window (see bug report + -- https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ ). + execute('only') + execute('vert 20new') + execute('set all& breakindent briopt=min:10') + execute([[call setline(1, [" a\tb\tc\td\te", " z y x w v"])]]) + execute([[/^\s*a]]) + feed('fbgjyl') + execute('let line1 = @0') + execute([[?^\s*z]]) + feed('fygjyl') + execute('let line2 = @0') + execute('quit!') + execute([[$put ='Test 13: breakindent with wrapping Tab']]) + execute('$put =line1') + execute('$put =line2') + + execute('let g:test="Test 14: breakindent + visual blockwise delete #1"') + execute('set all& breakindent shada+=nX-test-breakindent.shada') + execute('30vnew') + execute('normal! 3a1234567890') + execute('normal! a abcde') + execute([[exec "normal! 0\<C-V>tex"]]) + execute('let line1=ScreenChar(line("."),8)') + execute('call DoRecordScreen()') + + execute('let g:test="Test 15: breakindent + visual blockwise delete #2"') + execute('%d') + execute('normal! 4a1234567890') + execute([[exec "normal! >>\<C-V>3f0x"]]) + execute('let line1=ScreenChar(line("."),20)') + execute('call DoRecordScreen()') + execute('quit!') + + -- Assert buffer contents. + expect([[ + + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP + + Test 1: Simple breakindent + abcd + qrst + GHIJ + + Test 2: Simple breakindent + sbr=>> + abcd + >>qr + >>EF + + Test 3: Simple breakindent + briopt:sbr + abcd + ++ qrst + ++ GHIJ + + Test 4: Simple breakindent + min width: 18 + abcd + qrstuv + IJKLMN + + Test 5: Simple breakindent + shift by 2 + abcd + qr + EF + + Test 6: Simple breakindent + shift by -1 + abcd + qrstu + HIJKL + + Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr + 2 ab + ? m + ? x + + Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr + 2 ^Iabcd + # opq + # BCD + + Test 9: breakindent + shift by +1 + 'nu' + sbr=# list + 2 ^Iabcd + #op + #AB + + Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n + 2 ab + ~ mn + ~ yz + + Test 11: strdisplaywidth when breakindent is on + strdisplaywidth: 46 == calculated: 64 + { + + Test 12: breakindent + long indent + 56 + + ~ + Test 13: breakindent with wrapping Tab + d + w + + Test 14: breakindent + visual blockwise delete #1 + e + ~ + ~ + + Test 15: breakindent + visual blockwise delete #2 + 1234567890 + ~ + ~ ]]) + end) +end) diff --git a/test/functional/legacy/close_count_spec.lua b/test/functional/legacy/close_count_spec.lua new file mode 100644 index 0000000000..ee6b29c618 --- /dev/null +++ b/test/functional/legacy/close_count_spec.lua @@ -0,0 +1,133 @@ +-- Tests for :[count]close! and :[count]hide + +local helpers = require('test.functional.helpers') +local feed, eval, eq, clear, execute = + helpers.feed, helpers.eval, helpers.eq, helpers.clear, helpers.execute + +describe('close_count', function() + setup(clear) + + it('is working', function() + execute('let tests = []') + execute('for i in range(5)') + execute('new') + execute('endfor') + execute('4wincmd w') + execute('close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({6, 5, 4, 2, 1}, eval('buffers')) + execute('1close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({5, 4, 2, 1}, eval('buffers')) + execute('$close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({5, 4, 2}, eval('buffers')) + execute('1wincmd w') + execute('2close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({5, 2}, eval('buffers')) + execute('1wincmd w') + execute('new') + execute('new') + execute('2wincmd w') + execute('-1close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({7, 5, 2}, eval('buffers')) + execute('2wincmd w') + execute('+1close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({7, 5}, eval('buffers')) + execute('only!') + execute('b1') + execute('let tests = []') + execute('for i in range(5)') + execute('new') + execute('endfor') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({13, 12, 11, 10, 9, 1}, eval('buffers')) + execute('4wincmd w') + execute('.hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({13, 12, 11, 9, 1}, eval('buffers')) + execute('1hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({12, 11, 9, 1}, eval('buffers')) + execute('$hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({12, 11, 9}, eval('buffers')) + execute('1wincmd w') + execute('2hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({12, 9}, eval('buffers')) + execute('1wincmd w') + execute('new') + execute('new') + execute('3wincmd w') + execute('-hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({15, 12, 9}, eval('buffers')) + execute('2wincmd w') + execute('+hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({15, 12}, eval('buffers')) + execute('only!') + execute('b1') + execute('let tests = []') + execute('set hidden') + execute('for i in range(5)') + execute('new') + execute('endfor') + execute('1wincmd w') + execute('$ hide') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({20, 19, 18, 17, 16}, eval('buffers')) + execute('$-1 close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({20, 19, 18, 16}, eval('buffers')) + execute('1wincmd w') + execute('.+close!') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({20, 18, 16}, eval('buffers')) + execute('only!') + execute('b1') + execute('let tests = []') + execute('set hidden') + execute('for i in range(5)') + execute('new') + execute('endfor') + execute('4wincmd w') + feed('<C-W>c<cr>') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({25, 24, 23, 21, 1}, eval('buffers')) + feed('1<C-W>c<cr>') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({24, 23, 21, 1}, eval('buffers')) + feed('9<C-W>c<cr>') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({24, 23, 21}, eval('buffers')) + execute('1wincmd w') + feed('2<C-W>c<cr>') + execute('let buffers = []') + execute('windo call add(buffers, bufnr("%"))') + eq({24, 21}, eval('buffers')) + end) +end) diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua new file mode 100644 index 0000000000..cabeecdc9c --- /dev/null +++ b/test/functional/legacy/file_perm_spec.lua @@ -0,0 +1,42 @@ +-- Test getting and setting file permissions. +require('os') + +local helpers = require('test.functional.helpers') +local clear, call, eq = helpers.clear, helpers.call, helpers.eq +local neq, exc_exec = helpers.neq, helpers.exc_exec + +describe('Test getting and setting file permissions', function() + local tempfile = os.tmpname() + + before_each(function() + os.remove(tempfile) + clear() + end) + + it('file permissions', function() + eq('', call('getfperm', tempfile)) + eq(0, call('setfperm', tempfile, 'r------')) + + call('writefile', {'one'}, tempfile) + eq(9, call('len', call('getfperm', tempfile))) + + eq(1, call('setfperm', tempfile, 'rwx------')) + if helpers.os_name == 'windows' then + eq('rw-rw-rw-', call('getfperm', tempfile)) + else + eq('rwx------', call('getfperm', tempfile)) + end + + eq(1, call('setfperm', tempfile, 'r--r--r--')) + eq('r--r--r--', call('getfperm', tempfile)) + + local err = exc_exec(('call setfperm("%s", "---")'):format(tempfile)) + neq(err:find('E475:'), nil) + + eq(1, call('setfperm', tempfile, 'rwx------')) + end) + + after_each(function() + os.remove(tempfile) + end) +end) diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua index 6139ec0b67..4aa24c0d53 100644 --- a/test/functional/legacy/increment_spec.lua +++ b/test/functional/legacy/increment_spec.lua @@ -708,6 +708,25 @@ describe('Ctrl-A/Ctrl-X on visual selections', function() call assert_equal(["20"], getline(1, '$')) call assert_equal([0, 1, 2, 0], getpos('.')) endfunc + + " Test what patch 7.3.414 fixed. Ctrl-A on "000" drops the leading zeros. + func Test_normal_increment_01() + call setline(1, "000") + exec "norm! gg0\<C-A>" + call assert_equal("001", getline(1)) + + call setline(1, "000") + exec "norm! gg$\<C-A>" + call assert_equal("001", getline(1)) + + call setline(1, "001") + exec "norm! gg0\<C-A>" + call assert_equal("002", getline(1)) + + call setline(1, "001") + exec "norm! gg$\<C-A>" + call assert_equal("002", getline(1)) + endfunc ]=]) end) @@ -720,4 +739,10 @@ describe('Ctrl-A/Ctrl-X on visual selections', function() eq({}, nvim.get_vvar('errors')) end) end + + it('does not drop leading zeroes', function() + execute('set nrformats&vi') -- &vi makes Vim compatible + call('Test_normal_increment_01') + eq({}, nvim.get_vvar('errors')) + end) end) diff --git a/test/functional/legacy/join_spec.lua b/test/functional/legacy/join_spec.lua new file mode 100644 index 0000000000..17ff2e71ad --- /dev/null +++ b/test/functional/legacy/join_spec.lua @@ -0,0 +1,20 @@ +-- Test for joining lines + +local helpers = require('test.functional.helpers') +local clear, eq = helpers.clear, helpers.eq +local eval, execute = helpers.eval, helpers.execute + +describe('joining lines', function() + before_each(clear) + + it('is working', function() + execute('new') + execute([[call setline(1, ['one', 'two', 'three', 'four'])]]) + execute('normal J') + eq('one two', eval('getline(1)')) + execute('%del') + execute([[call setline(1, ['one', 'two', 'three', 'four'])]]) + execute('normal 10J') + eq('one two three four', eval('getline(1)')) + end) +end) diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua index 88f86815b3..315b8ca682 100644 --- a/test/functional/legacy/quickfix_spec.lua +++ b/test/functional/legacy/quickfix_spec.lua @@ -2,11 +2,264 @@ local helpers = require('test.functional.helpers') local source, clear = helpers.source, helpers.clear +local eq, nvim, call = helpers.eq, helpers.meths, helpers.call + +local function expected_empty() + eq({}, nvim.get_vvar('errors')) +end describe('helpgrep', function() - before_each(clear) + before_each(function() + clear() - it('works', function() + source([[ + " Tests for the :clist and :llist commands + function XlistTests(cchar) + let Xlist = a:cchar . 'list' + let Xgetexpr = a:cchar . 'getexpr' + + " With an empty list, command should return error + exe Xgetexpr . ' []' + exe 'silent! ' . Xlist + call assert_true(v:errmsg ==# 'E42: No Errors') + + " Populate the list and then try + exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', + \ 'non-error 2', 'Xtestfile2:2:2:Line2', + \ 'non-error 3', 'Xtestfile3:3:1:Line3']" + + " List only valid entries + redir => result + exe 'silent ' . Xlist + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1', + \ ' 4 Xtestfile2:2 col 2: Line2', + \ ' 6 Xtestfile3:3 col 1: Line3'], l) + + " List all the entries + redir => result + exe 'silent ' . Xlist . "!" + redir END + let l = split(result, "\n") + call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1', + \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2', + \ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l) + + " List a range of errors + redir => result + exe 'silent '. Xlist . " 3,6" + redir END + let l = split(result, "\n") + call assert_equal([' 4 Xtestfile2:2 col 2: Line2', + \ ' 6 Xtestfile3:3 col 1: Line3'], l) + + redir => result + exe 'silent ' . Xlist . "! 3,4" + redir END + let l = split(result, "\n") + call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) + + redir => result + exe 'silent ' . Xlist . " -6,-4" + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l) + + redir => result + exe 'silent ' . Xlist . "! -5,-3" + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1', + \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) + endfunction + + " Tests for the :colder, :cnewer, :lolder and :lnewer commands + " Note that this test assumes that a quickfix/location list is + " already set by the caller + function XageTests(cchar) + let Xolder = a:cchar . 'older' + let Xnewer = a:cchar . 'newer' + let Xgetexpr = a:cchar . 'getexpr' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + " Jumping to a non existent list should return error + exe 'silent! ' . Xolder . ' 99' + call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack') + + exe 'silent! ' . Xnewer . ' 99' + call assert_true(v:errmsg ==# 'E381: At top of quickfix stack') + + " Add three quickfix/location lists + exe Xgetexpr . " ['Xtestfile1:1:3:Line1']" + exe Xgetexpr . " ['Xtestfile2:2:2:Line2']" + exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" + + " Go back two lists + exe Xolder + exe 'let l = ' . Xgetlist + call assert_equal('Line2', l[0].text) + + " Go forward two lists + exe Xnewer + exe 'let l = ' . Xgetlist + call assert_equal('Line3', l[0].text) + + " Test for the optional count argument + exe Xolder . ' 2' + exe 'let l = ' . Xgetlist + call assert_equal('Line1', l[0].text) + + exe Xnewer . ' 2' + exe 'let l = ' . Xgetlist + call assert_equal('Line3', l[0].text) + endfunction + + " Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen + " commands + function XwindowTests(cchar) + let Xwindow = a:cchar . 'window' + let Xclose = a:cchar . 'close' + let Xopen = a:cchar . 'open' + let Xgetexpr = a:cchar . 'getexpr' + + " Create a list with no valid entries + exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + + " Quickfix/Location window should not open with no valid errors + exe Xwindow + call assert_true(winnr('$') == 1) + + " Create a list with valid entries + exe Xgetexpr . " ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', + \ 'Xtestfile3:3:1:Line3']" + + " Open the window + exe Xwindow + call assert_true(winnr('$') == 2 && winnr() == 2 && + \ getline('.') ==# 'Xtestfile1|1 col 3| Line1') + + " Close the window + exe Xclose + call assert_true(winnr('$') == 1) + + " Create a list with no valid entries + exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + + " Open the window + exe Xopen . ' 5' + call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1' + \ && winheight('.') == 5) + + " Opening the window again, should move the cursor to that window + wincmd t + exe Xopen . ' 7' + call assert_true(winnr('$') == 2 && winnr() == 2 && + \ winheight('.') == 7 && + \ getline('.') ==# '|| non-error 1') + + + " Calling cwindow should close the quickfix window with no valid errors + exe Xwindow + call assert_true(winnr('$') == 1) + endfunction + + " Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile + " commands. + function XfileTests(cchar) + let Xfile = a:cchar . 'file' + let Xgetfile = a:cchar . 'getfile' + let Xaddfile = a:cchar . 'addfile' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + call writefile(['Xtestfile1:700:10:Line 700', + \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1') + + enew! + exe Xfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && + \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') + + " Run cfile/lfile from a modified buffer + enew! + silent! put ='Quickfix' + exe 'silent! ' . Xfile . ' Xqftestfile1' + call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)') + + call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1') + exe Xaddfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 3 && + \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900') + + call writefile(['Xtestfile1:222:77:Line 222', + \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1') + + enew! + exe Xgetfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' && + \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333') + + call delete('Xqftestfile1') + endfunction + + " Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and + " :lgetbuffer commands. + function XbufferTests(cchar) + let Xbuffer = a:cchar . 'buffer' + let Xgetbuffer = a:cchar . 'getbuffer' + let Xaddbuffer = a:cchar . 'addbuffer' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + enew! + silent! call setline(1, ['Xtestfile7:700:10:Line 700', + \ 'Xtestfile8:800:15:Line 800']) + exe Xbuffer . "!" + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && + \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') + + enew! + silent! call setline(1, ['Xtestfile9:900:55:Line 900', + \ 'Xtestfile10:950:66:Line 950']) + exe Xgetbuffer + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' && + \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950') + + enew! + silent! call setline(1, ['Xtestfile11:700:20:Line 700', + \ 'Xtestfile12:750:25:Line 750']) + exe Xaddbuffer + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 4 && + \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' && + \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' && + \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750') + + endfunction + ]]) + end) + + it('copen/cclose work', function() source([[ helpgrep quickfix copen @@ -14,4 +267,43 @@ describe('helpgrep', function() cclose ]]) end) + + it('clist/llist work', function() + call('XlistTests', 'c') + expected_empty() + call('XlistTests', 'l') + expected_empty() + end) + + it('colder/cnewer and lolder/lnewer work', function() + local list = {{bufnr = 1, lnum = 1}} + call('setqflist', list) + call('XageTests', 'c') + expected_empty() + + call('setloclist', 0, list) + call('XageTests', 'l') + expected_empty() + end) + + it('quickfix/location list window commands work', function() + call('XwindowTests', 'c') + expected_empty() + call('XwindowTests', 'l') + expected_empty() + end) + + it('quickfix/location list file commands work', function() + call('XfileTests', 'c') + expected_empty() + call('XfileTests', 'l') + expected_empty() + end) + + it('quickfix/location list buffer commands work', function() + call('XbufferTests', 'c') + expected_empty() + call('XbufferTests', 'l') + expected_empty() + end) end) diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua index f81fcd3700..f2c907084e 100644 --- a/test/functional/legacy/set_spec.lua +++ b/test/functional/legacy/set_spec.lua @@ -7,6 +7,21 @@ local clear, execute, eval, eq = describe(':set', function() before_each(clear) + it('handles backslash properly', function() + execute('set iskeyword=a,b,c') + execute('set iskeyword+=d') + eq('a,b,c,d', eval('&iskeyword')) + + execute([[set iskeyword+=\\,e]]) + eq([[a,b,c,d,\,e]], eval('&iskeyword')) + + execute('set iskeyword-=e') + eq([[a,b,c,d,\]], eval('&iskeyword')) + + execute([[set iskeyword-=\]]) + eq('a,b,c,d', eval('&iskeyword')) + end) + it('recognizes a trailing comma with +=', function() execute('set wildignore=*.png,') execute('set wildignore+=*.jpg') diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua index 63787a59d3..ba7be8f21b 100644 --- a/test/functional/legacy/wordcount_spec.lua +++ b/test/functional/legacy/wordcount_spec.lua @@ -9,6 +9,10 @@ describe('wordcount', function() before_each(clear) it('is working', function() + execute('set selection=inclusive') + execute('fileformat=unix') + execute('fileformats=unix') + insert([=[ RESULT test:]=]) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 55ef254a63..cefb603a7e 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -158,8 +158,7 @@ describe('terminal buffer', function() end) it('handles loss of focus gracefully', function() - -- Temporarily change the statusline to avoid printing the file name, which - -- varies be where the test is run. + -- Change the statusline to avoid printing the file name, which varies. nvim('set_option', 'statusline', '==========') execute('set laststatus=0') @@ -195,5 +194,15 @@ describe('terminal buffer', function() execute('set laststatus=1') -- Restore laststatus to the default. end) + + it('term_close() use-after-free #4393', function() + if eval("executable('yes')") == 0 then + pending('missing "yes" command') + return + end + execute('terminal yes') + feed([[<C-\><C-n>]]) + execute('bdelete!') + end) end) diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 493539b4d3..d89092ff27 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -1,15 +1,15 @@ local helpers = require('test.functional.helpers') local Screen = require('test.functional.ui.screen') local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim -local nvim_dir = helpers.nvim_dir -local execute = helpers.execute +local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq +local execute, eval = helpers.execute, helpers.eval describe(':terminal', function() local screen before_each(function() clear() - screen = Screen.new(50, 7) + screen = Screen.new(50, 4) screen:attach(false) nvim('set_option', 'shell', nvim_dir..'/shell-test') nvim('set_option', 'shellcmdflag', 'EXE') @@ -23,9 +23,6 @@ describe(':terminal', function() ready $ | [Process exited 0] | | - | - | - | -- TERMINAL -- | ]]) end) @@ -37,9 +34,6 @@ describe(':terminal', function() ready $ echo hi | | [Process exited 0] | - | - | - | -- TERMINAL -- | ]]) end) @@ -51,10 +45,15 @@ describe(':terminal', function() ready $ echo 'hello' \ "world" | | [Process exited 0] | - | - | - | -- TERMINAL -- | ]]) end) + + it('ex_terminal() double-free #4554', function() + source([[ + autocmd BufNew * set shell=foo + terminal]]) + -- Verify that BufNew actually fired (else the test is invalid). + eq('foo', eval('&shell')) + end) end) diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 045f5aa42f..97875c5147 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -25,7 +25,7 @@ describe('terminal window highlighting', function() [5] = {background = 11}, [6] = {foreground = 130}, [7] = {reverse = true}, - [8] = {background = 11} + [8] = {background = 11}, }) screen:attach(false) execute('enew | call termopen(["'..nvim_dir..'/tty-test"]) | startinsert') @@ -121,7 +121,7 @@ describe('terminal window highlighting with custom palette', function() clear() screen = Screen.new(50, 7) screen:set_default_attr_ids({ - [1] = {foreground = 1193046} + [1] = {foreground = 1193046, special = Screen.colors.Black} }) screen:set_default_attr_ignore({ [1] = {bold = true}, @@ -130,7 +130,7 @@ describe('terminal window highlighting with custom palette', function() [5] = {background = 11}, [6] = {foreground = 130}, [7] = {reverse = true}, - [8] = {background = 11} + [8] = {background = 11}, }) screen:attach(true) nvim('set_var', 'terminal_color_3', '#123456') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 48376a344f..364ca327a4 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -154,9 +154,7 @@ describe('tui', function() for i = 1, 3000 do t[i] = 'item ' .. tostring(i) end - feed('i\027[200~') - feed(table.concat(t, '\n')) - feed('\027[201~') + feed('i\027[200~'..table.concat(t, '\n')..'\027[201~') screen:expect([[ item 2997 | item 2998 | diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4b0173fa89..85fca4d7ca 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1,7 +1,7 @@ local helpers = require('test.functional.helpers') local Screen = require('test.functional.ui.screen') local os = require('os') -local clear, feed = helpers.clear, helpers.feed +local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, request, eq = helpers.execute, helpers.request, helpers.eq @@ -262,4 +262,393 @@ describe('Default highlight groups', function() ]], {[1] = {bold = true, foreground = hlgroup_colors.Question}}) feed('<cr>') -- skip the "Press ENTER..." state or tests will hang end) + it('can be cleared and linked to other highlight groups', function() + execute('highlight clear ModeMsg') + feed('i') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + -- INSERT -- | + ]], {}) + feed('<esc>') + execute('highlight CustomHLGroup guifg=red guibg=green') + execute('highlight link ModeMsg CustomHLGroup') + feed('i') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + {1:-- INSERT --} | + ]], {[1] = {foreground = Screen.colors.Red, background = Screen.colors.Green}}) + end) + it('can be cleared by assigning NONE', function() + execute('syn keyword TmpKeyword neovim') + execute('hi link TmpKeyword ErrorMsg') + insert('neovim') + screen:expect([[ + {1:neovi^m} | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]], { + [1] = {foreground = Screen.colors.White, background = Screen.colors.Red} + }) + execute("hi ErrorMsg term=NONE cterm=NONE ctermfg=NONE ctermbg=NONE" + .. " gui=NONE guifg=NONE guibg=NONE guisp=NONE") + screen:expect([[ + neovi^m | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]], {}) + end) +end) + +describe('guisp (special/undercurl)', function() + local screen + + before_each(function() + clear() + screen = Screen.new(25,10) + screen:attach() + screen:set_default_attr_ignore({ + [1] = {bold = true, foreground = Screen.colors.Blue}, + [2] = {bold = true} + }) + end) + + it('can be set and is applied like foreground or background', function() + execute('syntax on') + execute('syn keyword TmpKeyword neovim') + execute('syn keyword TmpKeyword1 special') + execute('syn keyword TmpKeyword2 specialwithbg') + execute('syn keyword TmpKeyword3 specialwithfg') + execute('hi! Awesome guifg=red guibg=yellow guisp=red') + execute('hi! Awesome1 guisp=red') + execute('hi! Awesome2 guibg=yellow guisp=red') + execute('hi! Awesome3 guifg=red guisp=red') + execute('hi link TmpKeyword Awesome') + execute('hi link TmpKeyword1 Awesome1') + execute('hi link TmpKeyword2 Awesome2') + execute('hi link TmpKeyword3 Awesome3') + insert([[ + neovim + awesome neovim + wordcontainingneovim + special + specialwithbg + specialwithfg + ]]) + feed('Go<tab>neovim tabbed') + screen:expect([[ + {1:neovim} | + awesome {1:neovim} | + wordcontainingneovim | + {2:special} | + {3:specialwithbg} | + {4:specialwithfg} | + | + {1:neovim} tabbed^ | + ~ | + -- INSERT -- | + ]],{ + [1] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red, + special = Screen.colors.Red}, + [2] = {special = Screen.colors.Red}, + [3] = {special = Screen.colors.Red, background = Screen.colors.Yellow}, + [4] = {foreground = Screen.colors.Red, special = Screen.colors.Red}, + }) + + end) +end) + +describe("'cursorline' with 'listchars'", function() + local screen + + local hlgroup_colors = { + NonText = Screen.colors.Blue, + Cursorline = Screen.colors.Grey90, + SpecialKey = Screen.colors.Red, + Visual = Screen.colors.LightGrey, + } + + before_each(function() + clear() + screen = Screen.new(20,5) + screen:attach() + end) + + after_each(function() + screen:detach() + end) + + it("'cursorline' and 'cursorcolumn'", function() + screen:set_default_attr_ids({[1] = {background=hlgroup_colors.Cursorline}}) + screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} ) + execute('highlight clear ModeMsg') + execute('set cursorline') + feed('i') + screen:expect([[ + {1:^ }| + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + feed('abcdefg<cr>kkasdf') + screen:expect([[ + abcdefg | + {1:kkasdf^ }| + ~ | + ~ | + -- INSERT -- | + ]]) + feed('<esc>') + screen:expect([[ + abcdefg | + {1:kkasd^f }| + ~ | + ~ | + | + ]]) + execute('set nocursorline') + screen:expect([[ + abcdefg | + kkasd^f | + ~ | + ~ | + :set nocursorline | + ]]) + feed('k') + screen:expect([[ + abcde^fg | + kkasdf | + ~ | + ~ | + :set nocursorline | + ]]) + feed('jjji<cr><cr><cr><esc>') + screen:expect([[ + kkasd | + | + | + ^f | + | + ]]) + execute('set cursorline') + execute('set cursorcolumn') + feed('kkiabcdefghijk<esc>hh') + screen:expect([[ + kkasd {1: } | + {1:abcdefgh^ijk }| + {1: } | + f {1: } | + | + ]]) + feed('khh') + screen:expect([[ + {1:kk^asd }| + ab{1:c}defghijk | + {1: } | + f {1: } | + | + ]]) + end) + + it("'cursorline' and with 'listchar' option: space, eol, tab, and trail", function() + screen:set_default_attr_ids({ + [1] = {background=hlgroup_colors.Cursorline}, + [2] = { + foreground=hlgroup_colors.SpecialKey, + background=hlgroup_colors.Cursorline, + }, + [3] = { + background=hlgroup_colors.Cursorline, + foreground=hlgroup_colors.NonText, + bold=true, + }, + [4] = { + foreground=hlgroup_colors.NonText, + bold=true, + }, + [5] = { + foreground=hlgroup_colors.SpecialKey, + }, + }) + execute('highlight clear ModeMsg') + execute('highlight SpecialKey guifg=#FF0000') + execute('set cursorline') + execute('set tabstop=8') + execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list') + feed('i\t abcd <cr>\t abcd <cr><esc>k') + screen:expect([[ + {5:>-------.}abcd{5:*}{4:¬} | + {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }| + {4:¬} | + {4:~ }| + | + ]]) + feed('k') + screen:expect([[ + {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }| + {5:>-------.}abcd{5:*}{4:¬} | + {4:¬} | + {4:~ }| + | + ]]) + execute('set nocursorline') + screen:expect([[ + {5:^>-------.}abcd{5:*}{4:¬} | + {5:>-------.}abcd{5:*}{4:¬} | + {4:¬} | + {4:~ }| + :set nocursorline | + ]]) + execute('set nowrap') + feed('ALorem ipsum dolor sit amet<ESC>0') + screen:expect([[ + {5:^>-------.}abcd{5:.}Lorem{4:>}| + {5:>-------.}abcd{5:*}{4:¬} | + {4:¬} | + {4:~ }| + | + ]]) + execute('set cursorline') + screen:expect([[ + {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{4:>}| + {5:>-------.}abcd{5:*}{4:¬} | + {4:¬} | + {4:~ }| + :set cursorline | + ]]) + feed('$') + screen:expect([[ + {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| + {4:<} | + {4:<} | + {4:~ }| + :set cursorline | + ]]) + feed('G') + screen:expect([[ + {5:>-------.}abcd{5:.}Lorem{4:>}| + {5:>-------.}abcd{5:*}{4:¬} | + {3:^¬}{1: }| + {4:~ }| + :set cursorline | + ]]) + end) + + it("'listchar' in visual mode", function() + screen:set_default_attr_ids({ + [1] = {background=hlgroup_colors.Cursorline}, + [2] = { + foreground=hlgroup_colors.SpecialKey, + background=hlgroup_colors.Cursorline, + }, + [3] = { + background=hlgroup_colors.Cursorline, + foreground=hlgroup_colors.NonText, + bold=true, + }, + [4] = { + foreground=hlgroup_colors.NonText, + bold=true, + }, + [5] = { + foreground=hlgroup_colors.SpecialKey, + }, + [6] = { + background=hlgroup_colors.Visual, + }, + [7] = { + background=hlgroup_colors.Visual, + foreground=hlgroup_colors.SpecialKey, + }, + [8] = { + background=hlgroup_colors.Visual, + foreground=hlgroup_colors.NonText, + bold=true, + }, + }) + execute('highlight clear ModeMsg') + execute('highlight SpecialKey guifg=#FF0000') + execute('set cursorline') + execute('set tabstop=8') + execute('set nowrap') + execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list') + feed('i\t abcd <cr>\t abcd Lorem ipsum dolor sit amet<cr><esc>kkk0') + screen:expect([[ + {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }| + {5:>-------.}abcd{5:.}Lorem{4:>}| + {4:¬} | + {4:~ }| + | + ]]) + feed('lllvj') + screen:expect([[ + {5:>-------.}a{6:bcd}{7:*}{8:¬} | + {7:>-------.}{6:a}^bcd{5:.}Lorem{4:>}| + {4:¬} | + {4:~ }| + -- VISUAL -- | + ]]) + feed('<esc>V') + screen:expect([[ + {5:>-------.}abcd{5:*}{4:¬} | + {7:>-------.}{6:a}^b{6:cd}{7:.}{6:Lorem}{4:>}| + {4:¬} | + {4:~ }| + -- VISUAL LINE -- | + ]]) + feed('<esc>$') + screen:expect([[ + {4:<} | + {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }| + {4:<} | + {4:~ }| + | + ]]) + end) end) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index d0d791308b..993bbd5b0e 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -23,7 +23,12 @@ describe('Mouse input', function() screen:attach() screen:set_default_attr_ids({ [1] = {background = hlgroup_colors.Visual}, - [2] = {bold = true} + [2] = {bold = true}, + [3] = { + foreground = hlgroup_colors.NonText, + background = hlgroup_colors.Visual, + bold = true, + }, }) screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} ) feed('itesting<cr>mouse<cr>support and selection<esc>') @@ -225,14 +230,14 @@ describe('Mouse input', function() feed('<LeftDrag><2,2>') screen:expect([[ testing | - mo{1:use } | + mo{1:use}{3: } | {1:su}^pport and selection | ~ | {2:-- VISUAL --} | ]]) feed('<LeftDrag><0,0>') screen:expect([[ - ^t{1:esting } | + ^t{1:esting}{3: } | {1:mou}se | support and selection | ~ | @@ -293,7 +298,7 @@ describe('Mouse input', function() screen:expect([[ testing | mouse | - {1:su}^p{1:port and selection } | + {1:su}^p{1:port and selection}{3: } | ~ | {2:-- VISUAL LINE --} | ]]) @@ -321,8 +326,8 @@ describe('Mouse input', function() ]]) feed('<RightMouse><2,2>') screen:expect([[ - {1:testing } | - {1:mouse } | + {1:testing}{3: } | + {1:mouse}{3: } | {1:su}^pport and selection | ~ | {2:-- VISUAL --} | diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index a11fab18a2..6372cbe081 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -425,6 +425,10 @@ function Screen:_handle_update_bg(bg) self._bg = bg end +function Screen:_handle_update_sp(sp) + self._sp = sp +end + function Screen:_handle_suspend() self.suspended = true end @@ -573,7 +577,7 @@ function Screen:_pprint_attrs(attrs) local items = {} for f, v in pairs(attrs) do local desc = tostring(v) - if f == "foreground" or f == "background" then + if f == "foreground" or f == "background" or f == "special" then if Screen.colornames[v] ~= nil then desc = "Screen.colors."..Screen.colornames[v] end @@ -614,7 +618,8 @@ function Screen:_equal_attrs(a, b) a.underline == b.underline and a.undercurl == b.undercurl and a.italic == b.italic and a.reverse == b.reverse and a.foreground == b.foreground and - a.background == b.background + a.background == b.background and + a.special == b.special end function Screen:_attr_index(attrs, attr) diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 0271540fe3..2b3844bf6d 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -2,7 +2,6 @@ local helpers = require('test.functional.helpers') local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq -local insert = helpers.insert local execute, source, expect = helpers.execute, helpers.source, helpers.expect describe('completion', function() diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 71b5e7f576..857a5001f1 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -14,6 +14,8 @@ local to_cstr = helpers.to_cstr local OK = helpers.OK local FAIL = helpers.FAIL local NULL = helpers.NULL +local NODE_NORMAL = 0 +local NODE_WRITABLE = 1 cimport('unistd.h') cimport('./src/nvim/os/shell.h') @@ -357,15 +359,12 @@ describe('fs function', function() local function os_file_exists(filename) return fs.os_file_exists((to_cstr(filename))) end - local function os_rename(path, new_path) return fs.os_rename((to_cstr(path)), (to_cstr(new_path))) end - local function os_remove(path) return fs.os_remove((to_cstr(path))) end - local function os_open(path, flags, mode) return fs.os_open((to_cstr(path)), flags, mode) end @@ -484,6 +483,20 @@ describe('fs function', function() assert.is_true(0 <= (os_open(existing_file, ffi.C.kO_RDWR, 0))) end) end) + + describe('os_nodetype', function() + before_each(function() + os.remove('non-existing-file') + end) + + it('returns NODE_NORMAL for non-existing file', function() + eq(NODE_NORMAL, fs.os_nodetype(to_cstr('non-existing-file'))) + end) + + it('returns NODE_WRITABLE for /dev/stderr', function() + eq(NODE_WRITABLE, fs.os_nodetype(to_cstr('/dev/stderr'))) + end) + end) end) describe('folder operations', function() |