diff options
96 files changed, 3607 insertions, 1201 deletions
diff --git a/.ci/after_success.sh b/.ci/after_success.sh index 580b988061..0215eb139b 100755 --- a/.ci/after_success.sh +++ b/.ci/after_success.sh @@ -3,8 +3,6 @@ set -e set -o pipefail -if [[ -n "${CI_TARGET}" ]]; then - exit +if [[ -n "${GCOV}" ]]; then + coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.' fi - -[ "$USE_GCOV" = on ] && { coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.' ; } diff --git a/.ci/before_script.sh b/.ci/before_script.sh index 6babc582ea..23940ab2e2 100755 --- a/.ci/before_script.sh +++ b/.ci/before_script.sh @@ -29,10 +29,10 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then # That allows to test changing the group of the file by `os_fchown`. sudo dscl . -create /Groups/chown_test sudo dscl . -append /Groups/chown_test GroupMembership "${USER}" -else - # Compile dependencies. - build_deps fi +# Compile dependencies. +build_deps + rm -rf "${LOG_DIR}" mkdir -p "${LOG_DIR}" diff --git a/.ci/common/build.sh b/.ci/common/build.sh index 06bdab707f..c89d4c559b 100644 --- a/.ci/common/build.sh +++ b/.ci/common/build.sh @@ -14,10 +14,15 @@ build_deps() { # If there is a valid cache and we're not forced to recompile, # use cached third-party dependencies. if [[ -f "${CACHE_MARKER}" ]] && [[ "${BUILD_NVIM_DEPS}" != true ]]; then - echo "Using third-party dependencies from Travis's cache (last updated: $(stat -c '%y' "${CACHE_MARKER}"))." + if [[ "${TRAVIS_OS_NAME}" == osx ]]; then + local statcmd="stat -f '%Sm'" + else + local statcmd="stat -c '%y'" + fi + echo "Using third-party dependencies from Travis's cache (last updated: $(${statcmd} "${CACHE_MARKER}"))." mkdir -p "$(dirname "${DEPS_BUILD_DIR}")" - mv -T "${HOME}/.cache/nvim-deps" "${DEPS_BUILD_DIR}" + mv "${HOME}/.cache/nvim-deps" "${DEPS_BUILD_DIR}" else mkdir -p "${DEPS_BUILD_DIR}" fi @@ -26,7 +31,7 @@ build_deps() { # update CMake configuration and update to newer deps versions. cd "${DEPS_BUILD_DIR}" echo "Configuring with '${DEPS_CMAKE_FLAGS}'." - cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/" + CC= cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/" if ! ${MAKE_CMD}; then exit 1 diff --git a/.ci/common/test.sh b/.ci/common/test.sh index 225d88e072..dc59f4f793 100644 --- a/.ci/common/test.sh +++ b/.ci/common/test.sh @@ -49,11 +49,11 @@ asan_check() { } run_unittests() { - ${MAKE_CMD} unittest + ${MAKE_CMD} -C "${BUILD_DIR}" unittest } run_functionaltests() { - if ! ${MAKE_CMD} ${FUNCTIONALTEST}; then + if ! ${MAKE_CMD} -C "${BUILD_DIR}" ${FUNCTIONALTEST}; then asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" exit 1 @@ -63,7 +63,8 @@ run_functionaltests() { } run_oldtests() { - if ! make oldtest; then + ${MAKE_CMD} -C "${BUILD_DIR}" helptags + if ! make -C "${TRAVIS_BUILD_DIR}/src/nvim/testdir"; then reset asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" @@ -83,8 +84,9 @@ install_nvim() { exit 1 } + local genvimsynf=syntax/vim/generated.vim # Check that all runtime files were installed - for file in doc/tags syntax/vim/generated.vim $( + for file in doc/tags $genvimsynf $( cd runtime ; git ls-files | grep -e '.vim$' -e '.ps$' -e '.dict$' -e '.py$' -e '.tutor$' ) ; do if ! test -e "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then @@ -93,6 +95,13 @@ install_nvim() { fi done + # Check that generated syntax file has function names, #5060. + local gpat='syn keyword vimFuncName .*eval' + if ! grep -q "$gpat" "${INSTALL_PREFIX}/share/nvim/runtime/$genvimsynf"; then + echo "It appears that $genvimsynf does not contain $gpat." + exit 1 + fi + for file in $( cd runtime ; git ls-files | grep -e '.awk$' -e '.sh$' -e '.bat$' ) ; do diff --git a/.ci/install.sh b/.ci/install.sh index cb2362a70e..f809bb06ea 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -9,6 +9,7 @@ fi if [[ "${TRAVIS_OS_NAME}" == osx ]]; then brew install gettext + brew reinstall -s libtool elif [[ "${BUILD_MINGW}" == ON ]]; then # TODO: When Travis gets a recent version of Mingw-w64 use packages: # binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-dev mingw-w64-tools @@ -16,7 +17,6 @@ elif [[ "${BUILD_MINGW}" == ON ]]; then echo "Downloading MinGW..." curl -sSL "https://github.com/neovim/deps/raw/master/opt/i686-w64-mingw32-gcc-4.8.0-linux64_rubenvb.tar.xz" \ | tar xJf - -C "${HOME}/.local" - fi # Use default CC to avoid compilation problems when installing Python modules. @@ -29,3 +29,6 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then else CC=cc pip3.3 -q install --user --upgrade neovim fi + +echo "Install neovim RubyGem." +gem install --no-document --version ">= 0.2.0" neovim diff --git a/.ci/script.sh b/.ci/script.sh index c3c7b8dfa9..46c4eecf38 100755 --- a/.ci/script.sh +++ b/.ci/script.sh @@ -12,9 +12,6 @@ fi # as $USER, while retaining the environment variables defined and belonging # to secondary groups given above in usermod. if [[ "${TRAVIS_OS_NAME}" == osx ]]; then - # Set up precompiled third-party dependencies. - eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) deps-x64" - sudo -E su "${USER}" -c ".ci/run_tests.sh" else .ci/run_tests.sh diff --git a/.travis.yml b/.travis.yml index 8334b03cdf..9d529c2632 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,7 @@ matrix: env: CI_TARGET=lint - os: linux compiler: gcc-5 + env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - os: linux compiler: gcc-5 env: FUNCTIONALTEST=functionaltest-lua @@ -72,7 +73,7 @@ matrix: env: BUILD_32BIT=ON - os: linux compiler: clang - env: GCOV=llvm-cov CLANG_SANITIZER=ASAN_UBSAN CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" + env: CLANG_SANITIZER=ASAN_UBSAN - os: linux compiler: clang env: CLANG_SANITIZER=TSAN diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b3e6ec85e..1787f4e306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -501,6 +501,7 @@ if(BUSTED_PRG) add_custom_target(functionaltest COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -514,6 +515,7 @@ if(BUSTED_PRG) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -529,6 +531,7 @@ if(BUSTED_LUA_PRG) add_custom_target(functionaltest-lua COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_LUA_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -89,7 +89,7 @@ oldtest: | nvim helptags +$(SINGLE_MAKE) -C src/nvim/testdir $(MAKEOVERRIDES) helptags: | nvim - +$(BUILD_CMD) -C build runtime/doc/tags + +$(BUILD_CMD) -C build helptags functionaltest: | nvim +$(BUILD_CMD) -C build functionaltest diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake index 0858ea24ac..9fa91ffb5d 100644 --- a/cmake/RunTests.cmake +++ b/cmake/RunTests.cmake @@ -27,7 +27,7 @@ endif() execute_process( COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE} - --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua + --lua=${LUA_PRG} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua --lpath=${BUILD_DIR}/?.lua ${TEST_PATH} WORKING_DIRECTORY ${WORKING_DIR} ERROR_VARIABLE err diff --git a/man/nvim.1 b/man/nvim.1 index 2fa3ab8ff5..70bf480f2b 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -353,7 +353,7 @@ Like but used to store data not generally edited by the user, namely swap, backup, and ShaDa files. Defaults to -.Pa ~/.local/share/nvim +.Pa ~/.local/share if not set. .It Ev VIMINIT A string of Ex commands to be executed at startup. diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 66971eccb2..0dd8b07b7a 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -124,7 +124,7 @@ endforeach() file(GLOB_RECURSE RUNTIME_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - *.vim *.dict *.py *.ps *.tutor) + *.vim *.dict *.py *.rb *.ps *.tutor) foreach(F ${RUNTIME_FILES}) get_filename_component(BASEDIR ${F} PATH) diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim index dc362577a6..0a698e6492 100644 --- a/runtime/autoload/health.vim +++ b/runtime/autoload/health.vim @@ -404,6 +404,39 @@ function! s:diagnose_python(version) abort endfunction +function! s:diagnose_ruby() abort + echo 'Checking: Ruby' + let ruby_vers = systemlist('ruby -v')[0] + let ruby_prog = provider#ruby#Detect() + let notes = [] + + if empty(ruby_prog) + let ruby_prog = 'not found' + let prog_vers = 'not found' + call add(notes, 'Suggestion: Install the neovim RubyGem using ' . + \ '`gem install neovim`.') + else + silent let prog_vers = systemlist(ruby_prog . ' --version')[0] + + if v:shell_error + let prog_vers = 'outdated' + call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' . + \ '`gem install neovim`.') + elseif s:version_cmp(prog_vers, "0.2.0") == -1 + let prog_vers .= ' (outdated)' + call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' . + \ '`gem install neovim`.') + endif + endif + + echo ' Ruby Version: ' . ruby_vers + echo ' Host Executable: ' . ruby_prog + echo ' Host Version: ' . prog_vers + + call s:echo_notes(notes) +endfunction + + function! health#check(bang) abort redir => report try @@ -411,6 +444,8 @@ function! health#check(bang) abort silent echo '' silent call s:diagnose_python(3) silent echo '' + silent call s:diagnose_ruby() + silent echo '' silent call s:diagnose_manifest() silent echo '' finally diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 77bc8c781d..0f4aa78ddd 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -65,11 +65,10 @@ endif let s:clipboard = {} function! s:clipboard.get(reg) - let reg = a:reg == '"' ? '+' : a:reg - if s:selections[reg].owner > 0 - return s:selections[reg].data + if s:selections[a:reg].owner > 0 + return s:selections[a:reg].data end - return s:try_cmd(s:paste[reg]) + return s:try_cmd(s:paste[a:reg]) endfunction function! s:clipboard.set(lines, regtype, reg) diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim index aad8c09d28..e9130b98c1 100644 --- a/runtime/autoload/provider/ruby.vim +++ b/runtime/autoload/provider/ruby.vim @@ -1,12 +1,18 @@ " The Ruby provider helper -if exists('s:loaded_ruby_provider') +if exists('g:loaded_ruby_provider') finish endif +let g:loaded_ruby_provider = 1 -let s:loaded_ruby_provider = 1 +function! provider#ruby#Detect() abort + return exepath('neovim-ruby-host') +endfunction + +function! provider#ruby#Prog() + return s:prog +endfunction function! provider#ruby#Require(host) abort - " Collect registered Ruby plugins into args let args = [] let ruby_plugins = remote#host#PluginsForHost(a:host.name) @@ -16,19 +22,43 @@ function! provider#ruby#Require(host) abort try let channel_id = rpcstart(provider#ruby#Prog(), args) - - if rpcrequest(channel_id, 'poll') == 'ok' + if rpcrequest(channel_id, 'poll') ==# 'ok' return channel_id endif catch echomsg v:throwpoint echomsg v:exception endtry - - throw remote#host#LoadErrorForHost(a:host.orig_name, - \ '$NVIM_RUBY_LOG_FILE') + throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE') endfunction -function! provider#ruby#Prog() abort - return 'neovim-ruby-host' +function! provider#ruby#Call(method, args) + if s:err != '' + echoerr s:err + return + endif + + if !exists('s:host') + try + let s:host = remote#host#Require('legacy-ruby-provider') + catch + let s:err = v:exception + echohl WarningMsg + echomsg v:exception + echohl None + return + endtry + endif + return call('rpcrequest', insert(insert(a:args, 'ruby_'.a:method), s:host)) endfunction + +let s:err = '' +let s:prog = provider#ruby#Detect() +let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb' + +if empty(s:prog) + let s:err = 'Cannot find the neovim RubyGem. Try :CheckHealth' +endif + +call remote#host#RegisterClone('legacy-ruby-provider', 'ruby') +call remote#host#RegisterPlugin('legacy-ruby-provider', s:plugin_path, []) diff --git a/runtime/autoload/provider/script_host.rb b/runtime/autoload/provider/script_host.rb new file mode 100644 index 0000000000..1dade766c7 --- /dev/null +++ b/runtime/autoload/provider/script_host.rb @@ -0,0 +1,8 @@ +begin + require "neovim/ruby_provider" +rescue LoadError + warn( + "Your neovim RubyGem is missing or out of date. " + + "Install the latest version using `gem install neovim`." + ) +end diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim index 4ec2eeb5b7..eb5e87d7e1 100644 --- a/runtime/autoload/remote/host.vim +++ b/runtime/autoload/remote/host.vim @@ -121,7 +121,7 @@ endfunction function! s:GetManifest() abort let prefix = exists('$MYVIMRC') \ ? $MYVIMRC - \ : matchstr(get(split(capture('scriptnames'), '\n'), 0, ''), '\f\+$') + \ : matchstr(get(split(execute('scriptnames'), '\n'), 0, ''), '\f\+$') return fnamemodify(expand(prefix, 1), ':h') \.'/.'.fnamemodify(prefix, ':t').'-rplugin~' endfunction diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 0ca41370e9..3fa5474a7e 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Apr 12 +*eval.txt* For Vim version 7.4. Last change: 2016 Mar 27 VIM REFERENCE MANUAL by Bram Moolenaar @@ -103,18 +103,9 @@ to Float, printf() for Float to String and float2nr() for Float to Number. *E891* *E892* *E893* *E894* When expecting a Float a Number can also be used, but nothing else. - *E706* *sticky-type-checking* -You will get an error if you try to change the type of a variable. You need -to |:unlet| it first to avoid this error. String and Number are considered -equivalent though, as well are Float and Number. Consider this sequence of -commands: > - :let l = "string" - :let l = 44 " changes type from String to Number - :let l = [1, 2, 3] " error! l is still a Number - :let l = 4.4 " changes type from Number to Float - :let l = "string" " error! - - + *no-type-checking* +You will not get an error if you try to change the type of a variable. + 1.2 Function references ~ *Funcref* *E695* *E718* A Funcref variable is obtained with the |function()| function. It can be used @@ -763,13 +754,23 @@ expressions are referring to the same |List| or |Dictionary| instance. A copy of a |List| is different from the original |List|. When using "is" without a |List| or a |Dictionary| it is equivalent to using "equal", using "isnot" equivalent to using "not equal". Except that a different type means the -values are different: "4 == '4'" is true, "4 is '4'" is false and "0 is []" is -false and not an error. "is#"/"isnot#" and "is?"/"isnot?" can be used to match -and ignore case. +values are different: > + echo 4 == '4' + 1 + echo 4 is '4' + 0 + echo 0 is [] + 0 +"is#"/"isnot#" and "is?"/"isnot?" can be used to match and ignore case. When comparing a String with a Number, the String is converted to a Number, -and the comparison is done on Numbers. This means that "0 == 'x'" is TRUE, -because 'x' converted to a Number is zero. +and the comparison is done on Numbers. This means that: > + echo 0 == 'x' + 1 +because 'x' converted to a Number is zero. However: > + echo 0 == 'x' + 0 +Inside a List or Dictionary this conversion is not used. When comparing two Strings, this is done with strcmp() or stricmp(). This results in the mathematical difference (comparing byte values), not @@ -1793,10 +1794,13 @@ 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} +assert_equal({exp}, {act} [, {msg}]) none assert {exp} is equal to {act} assert_exception( {error} [, {msg}]) none assert {error} is in v:exception assert_fails( {cmd} [, {error}]) none assert {cmd} fails assert_false({actual} [, {msg}]) none assert {actual} is false +assert_match( {pat}, {text} [, {msg}]) none assert {pat} matches {text} +assert_notequal( {exp}, {act} [, {msg}]) none assert {exp} is not equal {act} +assert_notmatch( {pat}, {text} [, {msg}]) none assert {pat} not matches {text} assert_true({actual} [, {msg}]) none assert {actual} is true asin({expr}) Float arc sine of {expr} atan({expr}) Float arc tangent of {expr} @@ -1815,7 +1819,6 @@ 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} -capture({command}) String capture output of {command} ceil({expr}) Float round {expr} up changenr() Number current change number char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} @@ -1851,6 +1854,7 @@ 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 +execute({command}) String execute and capture output of {command} exepath({expr}) String full path of the command {expr} exists({expr}) Number TRUE if {expr} exists extend({expr1}, {expr2} [, {expr3}]) @@ -1893,6 +1897,7 @@ 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 +getcompletion({pat}, {type}) List list of cmdline completion matches getcurpos() List position of the cursor getcwd([{winnr} [, {tabnr}]]) String the current working directory getfontname([{name}]) String name of font being used @@ -2143,6 +2148,10 @@ 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 +win_getid( [{win} [, {tab}]]) Number get window ID for {win} in {tab} +win_gotoid( {expr}) Number go to window with ID {expr} +win_id2tabwin( {expr}) List get tab window nr from window ID +win_id2win( {expr}) Number get window nr from window ID winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight({nr}) Number height of window {nr} @@ -2290,6 +2299,36 @@ assert_false({actual} [, {msg}]) *assert_false()* When {msg} is omitted an error in the form "Expected False but got {actual}" is produced. + *assert_match()* +assert_match({pattern}, {actual} [, {msg}]) + When {pattern} does not match {actual} an error message is + added to |v:errors|. + + {pattern} is used as with |=~|: The matching is always done + like 'magic' was set and 'cpoptions' is empty, no matter what + the actual value of 'magic' or 'cpoptions' is. + + {actual} is used as a string, automatic conversion applies. + Use "^" and "$" to match with the start and end of the text. + Use both to match the whole text. + + When {msg} is omitted an error in the form "Pattern {pattern} + does not match {actual}" is produced. + Example: > + assert_match('^f.*o$', 'foobar') +< Will result in a string to be added to |v:errors|: + test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~ + + *assert_notequal()* +assert_notequal({expected}, {actual} [, {msg}]) + The opposite of `assert_equal()`: add an error message to + |v:errors| when {expected} and {actual} are equal. + + *assert_notmatch()* +assert_notmatch({pattern}, {actual} [, {msg}]) + The opposite of `assert_match()`: add an error message to + |v:errors| when {pattern} matches {actual}. + assert_true({actual} [, {msg}]) *assert_true()* When {actual} is not true an error message is added to |v:errors|, like with |assert_equal()|. @@ -2500,21 +2539,6 @@ call({func}, {arglist} [, {dict}]) *call()* *E699* {dict} is for functions with the "dict" attribute. It will be used to set the local variable "self". |Dictionary-function| -capture({command}) *capture()* - Capture output of {command}. - If {command} is a |String|, returns {command} output. - If {command} is a |List|, returns concatenated outputs. - Examples: > - echo capture('echon "foo"') -< foo > - echo capture(['echon "foo"', 'echon "bar"']) -< foobar - This function is not available in the |sandbox|. - Note: {command} executes as if prepended with |:silent| - (output is collected, but not displayed). If nested, an outer - capture() will not observe the output of inner calls. - Note: Text attributes (highlights) are not captured. - ceil({expr}) *ceil()* Return the smallest integral value greater than or equal to {expr} as a |Float| (round up). @@ -2965,6 +2989,21 @@ executable({expr}) *executable()* 0 does not exist -1 not implemented on this system +execute({command}) *execute()* + Execute {command} and capture its output. + If {command} is a |String|, returns {command} output. + If {command} is a |List|, returns concatenated outputs. + Examples: > + echo execute('echon "foo"') +< foo > + echo execute(['echon "foo"', 'echon "bar"']) +< foobar + This function is not available in the |sandbox|. + Note: {command} executes as if prepended with |:silent| + (output is collected but not displayed). If nested, an outer + execute() will not observe output of the inner calls. + Note: Text attributes (highlights) are not captured. + exepath({expr}) *exepath()* If {expr} is an executable and is either an absolute path, a relative path or found in $PATH, return the full path. @@ -3623,6 +3662,49 @@ getcmdwintype() *getcmdwintype()* values are the same as |getcmdtype()|. Returns an empty string when not in the command-line window. +getcompletion({pat}, {type}) *getcompletion()* + Return a list of command-line completion matches. {type} + specifies what for. The following completion types are + supported: + + augroup autocmd groups + buffer buffer names + behave :behave suboptions + color color schemes + command Ex command (and arguments) + compiler compilers + cscope |:cscope| suboptions + dir directory names + environment environment variable names + event autocommand events + expression Vim expression + file file and directory names + file_in_path file and directory names in |'path'| + filetype filetype names |'filetype'| + function function name + help help subjects + highlight highlight groups + history :history suboptions + locale locale names (as output of locale -a) + mapping mapping name + menu menus + option options + shellcmd Shell command + sign |:sign| suboptions + syntax syntax file names |'syntax'| + syntime |:syntime| suboptions + tag tags + tag_listfiles tags, file names + user user names + var user variables + + If {pat} is an empty string, then all the matches are returned. + Otherwise only items matching {pat} are returned. See + |wildcards| for the use of special characters in {pat}. + + If there are no matches, an empty list is returned. An + invalid value for {type} produces an error. + *getcurpos()* getcurpos() Get the position of the cursor. This is like getpos('.'), but includes an extra item in the list: @@ -7124,6 +7206,29 @@ wildmenumode() *wildmenumode()* (Note, this needs the 'wildcharm' option set appropriately). +win_getid([{win} [, {tab}]]) *win_getid()* + Get the window ID for the specified window. + When {win} is missing use the current window. + With {win} this is the window number. The top window has + number 1. + Without {tab} use the current tab, otherwise the tab with + number {tab}. The first tab has number one. + Return zero if the window cannot be found. + +win_gotoid({expr}) *win_gotoid()* + Go to window with ID {expr}. This may also change the current + tabpage. + Return 1 if successful, 0 if the window cannot be found. + +win_id2tabwin({expr} *win_id2tabwin()* + Return a list with the tab number and window number of window + with ID {expr}: [tabnr, winnr]. + Return [0, 0] if the window cannot be found. + +win_id2win({expr}) *win_id2win()* + Return the window number of window with ID {expr}. + Return 0 if the window cannot be found in the current tabpage. + *winbufnr()* winbufnr({nr}) The result is a Number, which is the number of the buffer associated with window {nr}. When {nr} is zero, the number of diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index e2fb501ac5..1e8bb408d9 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -825,13 +825,13 @@ the <CR> key. |<>|) See section |42.4| in the user manual. - *:tmenu* *:tm* + *:tmenu* :tm[enu] {menupath} {rhs} Define a tip for a menu or tool. {only in X11 and Win32 GUI} :tm[enu] [menupath] List menu tips. {only in X11 and Win32 GUI} - *:tunmenu* *:tu* + *:tunmenu* :tu[nmenu] {menupath} Remove a tip for a menu or tool. {only in X11 and Win32 GUI} diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt new file mode 100644 index 0000000000..fdd63501ea --- /dev/null +++ b/runtime/doc/if_ruby.txt @@ -0,0 +1,185 @@ +*if_ruby.txt* + + + VIM REFERENCE MANUAL by Shugo Maeda + +The Ruby Interface to Vim *ruby* *Ruby* + + +1. Commands |ruby-commands| +2. The VIM module |ruby-vim| +3. VIM::Buffer objects |ruby-buffer| +4. VIM::Window objects |ruby-window| +5. Global variables |ruby-globals| + + *E266* *E267* *E268* *E269* *E270* *E271* *E272* *E273* + +The home page for ruby is http://www.ruby-lang.org/. You can find links for +downloading Ruby there. + +============================================================================== +1. Commands *ruby-commands* + + *:ruby* *:rub* +:rub[y] {cmd} Execute Ruby command {cmd}. A command to try it out: > + :ruby print "Hello" + +:rub[y] << {endpattern} +{script} +{endpattern} + Execute Ruby script {script}. + {endpattern} must NOT be preceded by any white space. + If {endpattern} is omitted, it defaults to a dot '.' + like for the |:append| and |:insert| commands. This + form of the |:ruby| command is mainly useful for + including ruby code in vim scripts. + Note: This command doesn't work when the Ruby feature + wasn't compiled in. To avoid errors, see + |script-here|. + +Example Vim script: > + + function! RedGem() + ruby << EOF + class Garnet + def initialize(s) + @buffer = VIM::Buffer.current + vimputs(s) + end + def vimputs(s) + @buffer.append(@buffer.count,s) + end + end + gem = Garnet.new("pretty") + EOF + endfunction +< + + *:rubydo* *:rubyd* *E265* +:[range]rubyd[o] {cmd} Evaluate Ruby command {cmd} for each line in the + [range], with $_ being set to the text of each line in + turn, without a trailing <EOL>. Setting $_ will change + the text, but note that it is not possible to add or + delete lines using this command. + The default for [range] is the whole file: "1,$". + + *:rubyfile* *:rubyf* +:rubyf[ile] {file} Execute the Ruby script in {file}. This is the same as + ":ruby load 'file'", but allows file name completion. + +Executing Ruby commands is not possible in the |sandbox|. + +============================================================================== +2. The VIM module *ruby-vim* + +Ruby code gets all of its access to vim via the "VIM" module. + +Overview > + print "Hello" # displays a message + VIM.command(cmd) # execute an Ex command + num = VIM::Window.count # gets the number of windows + w = VIM::Window[n] # gets window "n" + cw = VIM::Window.current # gets the current window + num = VIM::Buffer.count # gets the number of buffers + b = VIM::Buffer[n] # gets buffer "n" + cb = VIM::Buffer.current # gets the current buffer + w.height = lines # sets the window height + w.cursor = [row, col] # sets the window cursor position + pos = w.cursor # gets an array [row, col] + name = b.name # gets the buffer file name + line = b[n] # gets a line from the buffer + num = b.count # gets the number of lines + b[n] = str # sets a line in the buffer + b.delete(n) # deletes a line + b.append(n, str) # appends a line after n + line = VIM::Buffer.current.line # gets the current line + num = VIM::Buffer.current.line_number # gets the current line number + VIM::Buffer.current.line = "test" # sets the current line number +< + +Module Functions: + + *ruby-message* +VIM::message({msg}) + Displays the message {msg}. + + *ruby-set_option* +VIM::set_option({arg}) + Sets a vim option. {arg} can be any argument that the ":set" command + accepts. Note that this means that no spaces are allowed in the + argument! See |:set|. + + *ruby-command* +VIM::command({cmd}) + Executes Ex command {cmd}. + + *ruby-evaluate* +VIM::evaluate({expr}) + Evaluates {expr} using the vim internal expression evaluator (see + |expression|). Returns the expression result as a string. + A |List| is turned into a string by joining the items and inserting + line breaks. + +============================================================================== +3. VIM::Buffer objects *ruby-buffer* + +VIM::Buffer objects represent vim buffers. + +Class Methods: + +current Returns the current buffer object. +count Returns the number of buffers. +self[{n}] Returns the buffer object for the number {n}. The first number + is 0. + +Methods: + +name Returns the name of the buffer. +number Returns the number of the buffer. +count Returns the number of lines. +length Returns the number of lines. +self[{n}] Returns a line from the buffer. {n} is the line number. +self[{n}] = {str} + Sets a line in the buffer. {n} is the line number. +delete({n}) Deletes a line from the buffer. {n} is the line number. +append({n}, {str}) + Appends a line after the line {n}. +line Returns the current line of the buffer if the buffer is + active. +line = {str} Sets the current line of the buffer if the buffer is active. +line_number Returns the number of the current line if the buffer is + active. + +============================================================================== +4. VIM::Window objects *ruby-window* + +VIM::Window objects represent vim windows. + +Class Methods: + +current Returns the current window object. +count Returns the number of windows. +self[{n}] Returns the window object for the number {n}. The first number + is 0. + +Methods: + +buffer Returns the buffer displayed in the window. +height Returns the height of the window. +height = {n} Sets the window height to {n}. +width Returns the width of the window. +width = {n} Sets the window width to {n}. +cursor Returns a [row, col] array for the cursor position. +cursor = [{row}, {col}] + Sets the cursor position to {row} and {col}. + +============================================================================== +5. Global variables *ruby-globals* + +There are two global variables. + +$curwin The current window object. +$curbuf The current buffer object. + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 31c3198f72..c1eef398e2 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -55,6 +55,7 @@ modes. :im[ap] {lhs} {rhs} |mapmode-i| *:im* *:imap* :lm[ap] {lhs} {rhs} |mapmode-l| *:lm* *:lmap* :cm[ap] {lhs} {rhs} |mapmode-c| *:cm* *:cmap* +:tm[ap] {lhs} {rhs} |mapmode-t| *:tm* *:tmap* Map the key sequence {lhs} to {rhs} for the modes where the map command applies. The result, including {rhs}, is then further scanned for mappings. This @@ -71,6 +72,7 @@ modes. :ino[remap] {lhs} {rhs} |mapmode-i| *:ino* *:inoremap* :ln[oremap] {lhs} {rhs} |mapmode-l| *:ln* *:lnoremap* :cno[remap] {lhs} {rhs} |mapmode-c| *:cno* *:cnoremap* +:tno[remap] {lhs} {rhs} |mapmode-t| *:tno* *:tnoremap* Map the key sequence {lhs} to {rhs} for the modes where the map command applies. Disallow mapping of {rhs}, to avoid nested and recursive mappings. Often @@ -87,6 +89,7 @@ modes. :iu[nmap] {lhs} |mapmode-i| *:iu* *:iunmap* :lu[nmap] {lhs} |mapmode-l| *:lu* *:lunmap* :cu[nmap] {lhs} |mapmode-c| *:cu* *:cunmap* +:tu[nmap] {lhs} |mapmode-t| *:tu* *:tunmap* Remove the mapping of {lhs} for the modes where the map command applies. The mapping may remain defined for other modes where it applies. @@ -105,6 +108,7 @@ modes. :imapc[lear] |mapmode-i| *:imapc* *:imapclear* :lmapc[lear] |mapmode-l| *:lmapc* *:lmapclear* :cmapc[lear] |mapmode-c| *:cmapc* *:cmapclear* +:tmapc[lear] |mapmode-t| *:tmapc* *:tmapclear* Remove ALL mappings for the modes where the map command applies. Use the <buffer> argument to remove buffer-local @@ -121,6 +125,7 @@ modes. :im[ap] |mapmode-i| :lm[ap] |mapmode-l| :cm[ap] |mapmode-c| +:tm[ap] |mapmode-t| List all key mappings for the modes where the map command applies. Note that ":map" and ":map!" are used most often, because they include the other modes. @@ -135,6 +140,7 @@ modes. :im[ap] {lhs} |mapmode-i| *:imap_l* :lm[ap] {lhs} |mapmode-l| *:lmap_l* :cm[ap] {lhs} |mapmode-c| *:cmap_l* +:tm[ap] {lhs} |mapmode-t| *:tmap_l* List the key mappings for the key sequences starting with {lhs} in the modes where the map command applies. @@ -288,9 +294,9 @@ as a special key. 1.3 MAPPING AND MODES *:map-modes* - *mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* + *mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* *mapmode-t* -There are six sets of mappings +There are seven sets of mappings - For Normal mode: When typing commands. - For Visual mode: When typing commands while the Visual area is highlighted. - For Select mode: like Visual mode but typing text replaces the selection. @@ -298,6 +304,7 @@ There are six sets of mappings etc.). See below: |omap-info|. - For Insert mode. These are also used in Replace mode. - For Command-line mode: When entering a ":" or "/" command. +- For Terminal mode: When typing in a |:terminal| buffer. Special case: While typing a count for a command in Normal mode, mapping zero is disabled. This makes it possible to map zero without making it impossible @@ -316,6 +323,7 @@ Overview of which map command works in which mode. More details below. :imap :inoremap :iunmap Insert :lmap :lnoremap :lunmap Insert, Command-line, Lang-Arg :cmap :cnoremap :cunmap Command-line +:tmap :tnoremap :tunmap Terminal COMMANDS MODES ~ diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt index 904fb3c16c..7dfbbd0cf0 100644 --- a/runtime/doc/nvim.txt +++ b/runtime/doc/nvim.txt @@ -18,10 +18,13 @@ Transitioning from Vim *nvim-from-vim* To start the transition, link your previous configuration so Nvim can use it: > - mkdir -p ${XDG_CONFIG_HOME:=$HOME/.config} - ln -s ~/.vim $XDG_CONFIG_HOME/nvim - ln -s ~/.vimrc $XDG_CONFIG_HOME/nvim/init.vim + mkdir ~/.config + ln -s ~/.vim ~/.config/nvim + ln -s ~/.vimrc ~/.config/nvim/init.vim < +Note: If your system sets `$XDG_CONFIG_HOME`, use that instead of `~/.config` +in the code above. Nvim follows the XDG |base-directories| convention. + See |provider-python| and |provider-clipboard| for additional software you might need to use some features. diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 4296ef6490..8f7dc0dbf0 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -10,6 +10,7 @@ Embedded terminal emulator *terminal-emulator* 2. Spawning |terminal-emulator-spawning| 3. Input |terminal-emulator-input| 4. Configuration |terminal-emulator-configuration| +5. Status Variables |terminal-emulator-status| ============================================================================== 1. Introduction *terminal-emulator-intro* @@ -113,4 +114,25 @@ The terminal cursor can be highlighted via |hl-TermCursor| and |hl-TermCursorNC|. ============================================================================== +5. Status Variables *terminal-emulator-status* + +Terminal buffers maintain some information about the terminal in buffer-local +variables: + +- *b:term_title* The settable title of the terminal, typically displayed in + the window title or tab title of a graphical terminal emulator. Programs + running in the terminal can set this title via an escape sequence. +- *b:terminal_job_id* The nvim job ID of the job running in the terminal. See + |job-control| for more information. +- *b:terminal_job_pid* The PID of the top-level process running in the + terminal. + +These variables will have a value by the time the TermOpen autocmd runs, and +will continue to have a value for the lifetime of the terminal buffer, making +them suitable for use in 'statusline'. For example, to show the terminal title +as the status line: +> + :autocmd TermOpen * setlocal statusline=%{b:term_title} +< +============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index db5c61879c..7380fb9346 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -88,6 +88,25 @@ the |:CheckHealth| command to diagnose your setup. save to a file or copy to the clipboard. ============================================================================== +Ruby integration *provider-ruby* + +Nvim supports the Vim legacy |ruby-vim| interface via external Ruby +interpreters connected via |RPC|. + + +RUBY QUICKSTART ~ + +To use Vim Ruby plugins with Nvim, just install the latest `neovim` RubyGem: > + $ gem install neovim + + +RUBY PROVIDER CONFIGURATION ~ + *g:loaded_ruby_provider* +To disable Ruby support: > + let g:loaded_ruby_provider = 1 + + +============================================================================== Clipboard integration *provider-clipboard* *clipboard* Nvim has no direct connection to the system clipboard. Instead it is diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 236ed65f46..8249f8e71f 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -14,6 +14,7 @@ Starting Vim *starting* 6. Saving settings |save-settings| 7. Views and Sessions |views-sessions| 8. The ShaDa file |shada-file| +9. Base Directories |base-directories| ============================================================================== 1. Vim arguments *vim-arguments* @@ -382,7 +383,7 @@ accordingly. Vim proceeds in this order: name, "init.vim" is Neovim specific location for vimrc file. Also see |vimrc-intro|. - Places for your personal initializations: + Places for your personal initializations (see |base-directories|): Unix $XDG_CONFIG_HOME/nvim/init.vim (default for $XDG_CONFIG_HOME is ~/.config) Windows $XDG_CONFIG_HOME/nvim/init.vim @@ -1083,7 +1084,7 @@ even if other entries (with known name/type/etc) are merged. |shada-merging| SHADA FILE NAME *shada-file-name* - The default name of the ShaDa file is "$XDG_DATA_HOME/nvim/shada/main.shada" - for Unix. Default for $XDG_DATA_HOME is ~/.local/share. + for Unix. Default for $XDG_DATA_HOME is ~/.local/share. |base-directories| - The 'n' flag in the 'shada' option can be used to specify another ShaDa file name |'shada'|. - The "-i" Vim argument can be used to set another file name, |-i|. When the @@ -1370,4 +1371,40 @@ file when reading and include: either contains more then one MessagePack object or it does not contain complete MessagePack object. +============================================================================== +9. Base Directories *base-directories* *xdg* + +Nvim conforms to the XDG Base Directory Specification for application +configuration and data file locations. This just means Nvim looks for some +optional settings and uses them if they exist, otherwise defaults are chosen. +https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + +CONFIGURATION DIRECTORY *$XDG_CONFIG_HOME* + + Base directory default: + Unix: ~/.config + Windows: ~/AppData/Local + + Nvim directory: + Unix: ~/.config/nvim/ + Windows: ~/AppData/Local/nvim/ + +DATA DIRECTORY *$XDG_DATA_HOME* + + Base directory default: + Unix: ~/.local/share + Windows: ~/AppData/Local + + Nvim directory: + Unix: ~/.local/share/nvim/ + Windows: ~/AppData/Local/nvim-data/ + +Note on Windows the configuration and data directory defaults are the same +(for lack of an alternative), but the sub-directory for data is named +"nvim-data" to separate it from the configuration sub-directory "nvim". + +Throughout other sections of the user manual, the defaults are used as generic +placeholders, e.g. where "~/.config" is mentioned it should be understood to +mean "$XDG_CONFIG_HOME or ~/.config". + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index eb813866da..a1bf379d86 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -417,7 +417,7 @@ m *+xpm_w32* Win32 GUI only: pixmap support |w32-xpm-support| the screen, put the commands in a function and call it with ":silent call Function()". Alternatives are the 'verbosefile' option or - |capture()| function, these can be used in combination + |execute()| function, these can be used in combination with ":redir". :redi[r] >> {file} Redirect messages to file {file}. Append if {file} diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index e536ea873a..937ed9e8ba 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -98,7 +98,7 @@ Commands: |:CheckHealth| Functions: - |capture()| + |execute()| works with |:redir| Events: |TabNew| @@ -202,13 +202,12 @@ Additional differences: ============================================================================== 5. Missing legacy features *nvim-features-missing* - *if_ruby* *if_lua* *if_perl* *if_mzscheme* *if_tcl* + *if_lua* *if_perl* *if_mzscheme* *if_tcl* These legacy Vim features may be implemented in the future, but they are not planned for the current milestone. - vim.bindeval() (new feature in Vim 7.4 Python interface) -- |if_ruby| - |if_lua| - |if_perl| - |if_mzscheme| diff --git a/runtime/macros/justify.vim b/runtime/macros/justify.vim index 4ef3bf95fa..011a911401 100644 --- a/runtime/macros/justify.vim +++ b/runtime/macros/justify.vim @@ -1,316 +1,3 @@ -" Function to left and right align text. -" -" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk> -" Created: 980806 14:13 (or around that time anyway) -" Revised: 001103 00:36 (See "Revisions" below) - - -" function Justify( [ textwidth [, maxspaces [, indent] ] ] ) -" -" Justify() will left and right align a line by filling in an -" appropriate amount of spaces. Extra spaces are added to existing -" spaces starting from the right side of the line. As an example, the -" following documentation has been justified. -" -" The function takes the following arguments: - -" textwidth argument -" ------------------ -" If not specified, the value of the 'textwidth' option is used. If -" 'textwidth' is zero a value of 80 is used. -" -" Additionally the arguments 'tw' and '' are accepted. The value of -" 'textwidth' will be used. These are handy, if you just want to specify -" the maxspaces argument. - -" maxspaces argument -" ------------------ -" If specified, alignment will only be done, if the longest space run -" after alignment is no longer than maxspaces. -" -" An argument of '' is accepted, should the user like to specify all -" arguments. -" -" To aid user defined commands, negative values are accepted aswell. -" Using a negative value specifies the default behaviour: any length of -" space runs will be used to justify the text. - -" indent argument -" --------------- -" This argument specifies how a line should be indented. The default is -" to keep the current indentation. -" -" Negative values: Keep current amount of leading whitespace. -" Positive values: Indent all lines with leading whitespace using this -" amount of whitespace. -" -" Note that the value 0, needs to be quoted as a string. This value -" leads to a left flushed text. -" -" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be -" added. In this case, if the value of indent is positive, the amount of -" whitespace to be added will be multiplied by the value of the -" 'shiftwidth' and 'tabstop' settings. If these units are used, the -" argument must be given as a string, eg. Justify('','','2sw'). -" -" If the values of 'sw' or 'tw' are negative, they are treated as if -" they were 0, which means that the text is flushed left. There is no -" check if a negative number prefix is used to change the sign of a -" negative 'sw' or 'ts' value. -" -" As with the other arguments, '' may be used to get the default -" behaviour. - - -" Notes: -" -" If the line, adjusted for space runs and leading/trailing whitespace, -" is wider than the used textwidth, the line will be left untouched (no -" whitespace removed). This should be equivalent to the behaviour of -" :left, :right and :center. -" -" If the resulting line is shorter than the used textwidth it is left -" untouched. -" -" All space runs in the line are truncated before the alignment is -" carried out. -" -" If you have set 'noexpandtab', :retab! is used to replace space runs -" with whitespace using the value of 'tabstop'. This should be -" conformant with :left, :right and :center. -" -" If joinspaces is set, an extra space is added after '.', '?' and '!'. -" If 'cpooptions' include 'j', extra space is only added after '.'. -" (This may on occasion conflict with maxspaces.) - - -" Related mappings: -" -" Mappings that will align text using the current text width, using at -" most four spaces in a space run and keeping current indentation. -nmap _j :%call Justify('tw',4)<CR> -vmap _j :call Justify('tw',4)<CR> -" -" Mappings that will remove space runs and format lines (might be useful -" prior to aligning the text). -nmap ,gq :%s/\s\+/ /g<CR>gq1G -vmap ,gq :s/\s\+/ /g<CR>gvgq - - -" User defined command: -" -" The following is an ex command that works as a shortcut to the Justify -" function. Arguments to Justify() can be added after the command. -com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>) -" -" The following commands are all equivalent: -" -" 1. Simplest use of Justify(): -" :call Justify() -" :Justify -" -" 2. The _j mapping above via the ex command: -" :%Justify tw 4 -" -" 3. Justify visualised text at 72nd column while indenting all -" previously indented text two shiftwidths -" :'<,'>call Justify(72,'','2sw') -" :'<,'>Justify 72 -1 2sw -" -" This documentation has been justified using the following command: -":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" / - -" Revisions: -" 001103: If 'joinspaces' was set, calculations could be wrong. -" Tabs at start of line could also lead to errors. -" Use setline() instead of "exec 's/foo/bar/' - safer. -" Cleaned up the code a bit. -" -" Todo: Convert maps to the new script specific form - -" Error function -function! Justify_error(message) - echohl Error - echo "Justify([tw, [maxspaces [, indent]]]): " . a:message - echohl None -endfunction - - -" Now for the real thing -function! Justify(...) range - - if a:0 > 3 - call Justify_error("Too many arguments (max 3)") - return 1 - endif - - " Set textwidth (accept 'tw' and '' as arguments) - if a:0 >= 1 - if a:1 =~ '^\(tw\)\=$' - let tw = &tw - elseif a:1 =~ '^\d\+$' - let tw = a:1 - else - call Justify_error("tw must be a number (>0), '' or 'tw'") - return 2 - endif - else - let tw = &tw - endif - if tw == 0 - let tw = 80 - endif - - " Set maximum number of spaces between WORDs - if a:0 >= 2 - if a:2 == '' - let maxspaces = tw - elseif a:2 =~ '^-\d\+$' - let maxspaces = tw - elseif a:2 =~ '^\d\+$' - let maxspaces = a:2 - else - call Justify_error("maxspaces must be a number or ''") - return 3 - endif - else - let maxspaces = tw - endif - if maxspaces <= 1 - call Justify_error("maxspaces should be larger than 1") - return 4 - endif - - " Set the indentation style (accept sw and ts units) - let indent_fix = '' - if a:0 >= 3 - if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = -1 - elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = 0 - elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$' - let indent = substitute(a:3, '\D', '', 'g') - elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$' - let indent = 1 - else - call Justify_error("indent: a number with 'sw'/'ts' unit") - return 5 - endif - if indent >= 0 - while indent > 0 - let indent_fix = indent_fix . ' ' - let indent = indent - 1 - endwhile - let indent_sw = 0 - if a:3 =~ '\(shiftwidth\|sw\)' - let indent_sw = &sw - elseif a:3 =~ '\(tabstop\|ts\)' - let indent_sw = &ts - endif - let indent_fix2 = '' - while indent_sw > 0 - let indent_fix2 = indent_fix2 . indent_fix - let indent_sw = indent_sw - 1 - endwhile - let indent_fix = indent_fix2 - endif - else - let indent = -1 - endif - - " Avoid substitution reports - let save_report = &report - set report=1000000 - - " Check 'joinspaces' and 'cpo' - if &js == 1 - if &cpo =~ 'j' - let join_str = '\(\. \)' - else - let join_str = '\([.!?!] \)' - endif - endif - - let cur = a:firstline - while cur <= a:lastline - - let str_orig = getline(cur) - let save_et = &et - set et - exec cur . "retab" - let &et = save_et - let str = getline(cur) - - let indent_str = indent_fix - let indent_n = strlen(indent_str) - " Shall we remember the current indentation - if indent < 0 - let indent_orig = matchstr(str_orig, '^\s*') - if strlen(indent_orig) > 0 - let indent_str = indent_orig - let indent_n = strlen(matchstr(str, '^\s*')) - endif - endif - - " Trim trailing, leading and running whitespace - let str = substitute(str, '\s\+$', '', '') - let str = substitute(str, '^\s\+', '', '') - let str = substitute(str, '\s\+', ' ', 'g') - let str_n = strdisplaywidth(str) - - " Possible addition of space after punctuation - if exists("join_str") - let str = substitute(str, join_str, '\1 ', 'g') - endif - let join_n = strdisplaywidth(str) - str_n - - " Can extraspaces be added? - " Note that str_n may be less than strlen(str) [joinspaces above] - if strdisplaywidth(str) <= tw - indent_n && str_n > 0 - " How many spaces should be added - let s_add = tw - str_n - indent_n - join_n - let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n - let s_dup = s_add / s_nr - let s_mod = s_add % s_nr - - " Test if the changed line fits with tw - if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw - - " Duplicate spaces - while s_dup > 0 - let str = substitute(str, '\( \+\)', ' \1', 'g') - let s_dup = s_dup - 1 - endwhile - - " Add extra spaces from the end - while s_mod > 0 - let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '') - let s_mod = s_mod - 1 - endwhile - - " Indent the line - if indent_n > 0 - let str = substitute(str, '^', indent_str, '' ) - endif - - " Replace the line - call setline(cur, str) - - " Convert to whitespace - if &et == 0 - exec cur . 'retab!' - endif - - endif " Change of line - endif " Possible change - - let cur = cur + 1 - endwhile - - norm ^ - - let &report = save_report - -endfunction - -" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai +" Load the justify package. +" For those users who were loading the justify plugin from here. +packadd justify diff --git a/runtime/macros/shellmenu.vim b/runtime/macros/shellmenu.vim index 6175d1d9a6..4eb72a556a 100644 --- a/runtime/macros/shellmenu.vim +++ b/runtime/macros/shellmenu.vim @@ -1,94 +1,3 @@ -" When you're writing shell scripts and you are in doubt which test to use, -" which shell environment variables are defined, what the syntax of the case -" statement is, and you need to invoke 'man sh'? -" -" Your problems are over now! -" -" Attached is a Vim script file for turning gvim into a shell script editor. -" It may also be used as an example how to use menus in Vim. -" -" Written by: Lennart Schultz <les@dmi.min.dk> - -imenu Stmts.for for in
do
doneki kk0elli -imenu Stmts.case case in
) ;;
esacbki k0elli -imenu Stmts.if if
then
fiki kk0elli -imenu Stmts.if-else if
then
else
fiki kki kk0elli -imenu Stmts.elif elif
then
ki kk0elli -imenu Stmts.while while
do
doneki kk0elli -imenu Stmts.break break -imenu Stmts.continue continue -imenu Stmts.function () {
}ki k0i -imenu Stmts.return return -imenu Stmts.return-true return 0 -imenu Stmts.return-false return 1 -imenu Stmts.exit exit -imenu Stmts.shift shift -imenu Stmts.trap trap -imenu Test.existence [ -e ]hi -imenu Test.existence - file [ -f ]hi -imenu Test.existence - file (not empty) [ -s ]hi -imenu Test.existence - directory [ -d ]hi -imenu Test.existence - executable [ -x ]hi -imenu Test.existence - readable [ -r ]hi -imenu Test.existence - writable [ -w ]hi -imenu Test.String is empty [ x = "x$" ]hhi -imenu Test.String is not empty [ x != "x$" ]hhi -imenu Test.Strings is equal [ "" = "" ]hhhhhhhi -imenu Test.Strings is not equal [ "" != "" ]hhhhhhhhi -imenu Test.Values is greater than [ -gt ]hhhhhhi -imenu Test.Values is greater equal [ -ge ]hhhhhhi -imenu Test.Values is equal [ -eq ]hhhhhhi -imenu Test.Values is not equal [ -ne ]hhhhhhi -imenu Test.Values is less than [ -lt ]hhhhhhi -imenu Test.Values is less equal [ -le ]hhhhhhi -imenu ParmSub.Substitute word if parm not set ${:-}hhi -imenu ParmSub.Set parm to word if not set ${:=}hhi -imenu ParmSub.Substitute word if parm set else nothing ${:+}hhi -imenu ParmSub.If parm not set print word and exit ${:?}hhi -imenu SpShVars.Number of positional parameters ${#} -imenu SpShVars.All positional parameters (quoted spaces) ${*} -imenu SpShVars.All positional parameters (unquoted spaces) ${@} -imenu SpShVars.Flags set ${-} -imenu SpShVars.Return code of last command ${?} -imenu SpShVars.Process number of this shell ${$} -imenu SpShVars.Process number of last background command ${!} -imenu Environ.HOME ${HOME} -imenu Environ.PATH ${PATH} -imenu Environ.CDPATH ${CDPATH} -imenu Environ.MAIL ${MAIL} -imenu Environ.MAILCHECK ${MAILCHECK} -imenu Environ.PS1 ${PS1} -imenu Environ.PS2 ${PS2} -imenu Environ.IFS ${IFS} -imenu Environ.SHACCT ${SHACCT} -imenu Environ.SHELL ${SHELL} -imenu Environ.LC_CTYPE ${LC_CTYPE} -imenu Environ.LC_MESSAGES ${LC_MESSAGES} -imenu Builtins.cd cd -imenu Builtins.echo echo -imenu Builtins.eval eval -imenu Builtins.exec exec -imenu Builtins.export export -imenu Builtins.getopts getopts -imenu Builtins.hash hash -imenu Builtins.newgrp newgrp -imenu Builtins.pwd pwd -imenu Builtins.read read -imenu Builtins.readonly readonly -imenu Builtins.return return -imenu Builtins.times times -imenu Builtins.type type -imenu Builtins.umask umask -imenu Builtins.wait wait -imenu Set.set set -imenu Set.unset unset -imenu Set.mark modified or modified variables set -a -imenu Set.exit when command returns non-zero exit code set -e -imenu Set.Disable file name generation set -f -imenu Set.remember function commands set -h -imenu Set.All keyword arguments are placed in the environment set -k -imenu Set.Read commands but do not execute them set -n -imenu Set.Exit after reading and executing one command set -t -imenu Set.Treat unset variables as an error when substituting set -u -imenu Set.Print shell input lines as they are read set -v -imenu Set.Print commands and their arguments as they are executed set -x +" Load the shellmenu package. +" For those users who were loading the shellmenu plugin from here. +packadd shellmenu diff --git a/runtime/macros/swapmous.vim b/runtime/macros/swapmous.vim index 8b85be050b..5884d83473 100644 --- a/runtime/macros/swapmous.vim +++ b/runtime/macros/swapmous.vim @@ -1,22 +1,3 @@ -" These macros swap the left and right mouse buttons (for left handed) -" Don't forget to do ":set mouse=a" or the mouse won't work at all -noremap <LeftMouse> <RightMouse> -noremap <2-LeftMouse> <2-RightMouse> -noremap <3-LeftMouse> <3-RightMouse> -noremap <4-LeftMouse> <4-RightMouse> -noremap <LeftDrag> <RightDrag> -noremap <LeftRelease> <RightRelease> -noremap <RightMouse> <LeftMouse> -noremap <2-RightMouse> <2-LeftMouse> -noremap <3-RightMouse> <3-LeftMouse> -noremap <4-RightMouse> <4-LeftMouse> -noremap <RightDrag> <LeftDrag> -noremap <RightRelease> <LeftRelease> -noremap g<LeftMouse> <C-RightMouse> -noremap g<RightMouse> <C-LeftMouse> -noremap! <LeftMouse> <RightMouse> -noremap! <LeftDrag> <RightDrag> -noremap! <LeftRelease> <RightRelease> -noremap! <RightMouse> <LeftMouse> -noremap! <RightDrag> <LeftDrag> -noremap! <RightRelease> <LeftRelease> +" Load the swapmouse package. +" For those users who were loading the swapmous plugin from here. +packadd swapmouse diff --git a/runtime/pack/dist/opt/justify/plugin/justify.vim b/runtime/pack/dist/opt/justify/plugin/justify.vim new file mode 100644 index 0000000000..4ef3bf95fa --- /dev/null +++ b/runtime/pack/dist/opt/justify/plugin/justify.vim @@ -0,0 +1,316 @@ +" Function to left and right align text. +" +" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk> +" Created: 980806 14:13 (or around that time anyway) +" Revised: 001103 00:36 (See "Revisions" below) + + +" function Justify( [ textwidth [, maxspaces [, indent] ] ] ) +" +" Justify() will left and right align a line by filling in an +" appropriate amount of spaces. Extra spaces are added to existing +" spaces starting from the right side of the line. As an example, the +" following documentation has been justified. +" +" The function takes the following arguments: + +" textwidth argument +" ------------------ +" If not specified, the value of the 'textwidth' option is used. If +" 'textwidth' is zero a value of 80 is used. +" +" Additionally the arguments 'tw' and '' are accepted. The value of +" 'textwidth' will be used. These are handy, if you just want to specify +" the maxspaces argument. + +" maxspaces argument +" ------------------ +" If specified, alignment will only be done, if the longest space run +" after alignment is no longer than maxspaces. +" +" An argument of '' is accepted, should the user like to specify all +" arguments. +" +" To aid user defined commands, negative values are accepted aswell. +" Using a negative value specifies the default behaviour: any length of +" space runs will be used to justify the text. + +" indent argument +" --------------- +" This argument specifies how a line should be indented. The default is +" to keep the current indentation. +" +" Negative values: Keep current amount of leading whitespace. +" Positive values: Indent all lines with leading whitespace using this +" amount of whitespace. +" +" Note that the value 0, needs to be quoted as a string. This value +" leads to a left flushed text. +" +" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be +" added. In this case, if the value of indent is positive, the amount of +" whitespace to be added will be multiplied by the value of the +" 'shiftwidth' and 'tabstop' settings. If these units are used, the +" argument must be given as a string, eg. Justify('','','2sw'). +" +" If the values of 'sw' or 'tw' are negative, they are treated as if +" they were 0, which means that the text is flushed left. There is no +" check if a negative number prefix is used to change the sign of a +" negative 'sw' or 'ts' value. +" +" As with the other arguments, '' may be used to get the default +" behaviour. + + +" Notes: +" +" If the line, adjusted for space runs and leading/trailing whitespace, +" is wider than the used textwidth, the line will be left untouched (no +" whitespace removed). This should be equivalent to the behaviour of +" :left, :right and :center. +" +" If the resulting line is shorter than the used textwidth it is left +" untouched. +" +" All space runs in the line are truncated before the alignment is +" carried out. +" +" If you have set 'noexpandtab', :retab! is used to replace space runs +" with whitespace using the value of 'tabstop'. This should be +" conformant with :left, :right and :center. +" +" If joinspaces is set, an extra space is added after '.', '?' and '!'. +" If 'cpooptions' include 'j', extra space is only added after '.'. +" (This may on occasion conflict with maxspaces.) + + +" Related mappings: +" +" Mappings that will align text using the current text width, using at +" most four spaces in a space run and keeping current indentation. +nmap _j :%call Justify('tw',4)<CR> +vmap _j :call Justify('tw',4)<CR> +" +" Mappings that will remove space runs and format lines (might be useful +" prior to aligning the text). +nmap ,gq :%s/\s\+/ /g<CR>gq1G +vmap ,gq :s/\s\+/ /g<CR>gvgq + + +" User defined command: +" +" The following is an ex command that works as a shortcut to the Justify +" function. Arguments to Justify() can be added after the command. +com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>) +" +" The following commands are all equivalent: +" +" 1. Simplest use of Justify(): +" :call Justify() +" :Justify +" +" 2. The _j mapping above via the ex command: +" :%Justify tw 4 +" +" 3. Justify visualised text at 72nd column while indenting all +" previously indented text two shiftwidths +" :'<,'>call Justify(72,'','2sw') +" :'<,'>Justify 72 -1 2sw +" +" This documentation has been justified using the following command: +":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" / + +" Revisions: +" 001103: If 'joinspaces' was set, calculations could be wrong. +" Tabs at start of line could also lead to errors. +" Use setline() instead of "exec 's/foo/bar/' - safer. +" Cleaned up the code a bit. +" +" Todo: Convert maps to the new script specific form + +" Error function +function! Justify_error(message) + echohl Error + echo "Justify([tw, [maxspaces [, indent]]]): " . a:message + echohl None +endfunction + + +" Now for the real thing +function! Justify(...) range + + if a:0 > 3 + call Justify_error("Too many arguments (max 3)") + return 1 + endif + + " Set textwidth (accept 'tw' and '' as arguments) + if a:0 >= 1 + if a:1 =~ '^\(tw\)\=$' + let tw = &tw + elseif a:1 =~ '^\d\+$' + let tw = a:1 + else + call Justify_error("tw must be a number (>0), '' or 'tw'") + return 2 + endif + else + let tw = &tw + endif + if tw == 0 + let tw = 80 + endif + + " Set maximum number of spaces between WORDs + if a:0 >= 2 + if a:2 == '' + let maxspaces = tw + elseif a:2 =~ '^-\d\+$' + let maxspaces = tw + elseif a:2 =~ '^\d\+$' + let maxspaces = a:2 + else + call Justify_error("maxspaces must be a number or ''") + return 3 + endif + else + let maxspaces = tw + endif + if maxspaces <= 1 + call Justify_error("maxspaces should be larger than 1") + return 4 + endif + + " Set the indentation style (accept sw and ts units) + let indent_fix = '' + if a:0 >= 3 + if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = -1 + elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = 0 + elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$' + let indent = substitute(a:3, '\D', '', 'g') + elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$' + let indent = 1 + else + call Justify_error("indent: a number with 'sw'/'ts' unit") + return 5 + endif + if indent >= 0 + while indent > 0 + let indent_fix = indent_fix . ' ' + let indent = indent - 1 + endwhile + let indent_sw = 0 + if a:3 =~ '\(shiftwidth\|sw\)' + let indent_sw = &sw + elseif a:3 =~ '\(tabstop\|ts\)' + let indent_sw = &ts + endif + let indent_fix2 = '' + while indent_sw > 0 + let indent_fix2 = indent_fix2 . indent_fix + let indent_sw = indent_sw - 1 + endwhile + let indent_fix = indent_fix2 + endif + else + let indent = -1 + endif + + " Avoid substitution reports + let save_report = &report + set report=1000000 + + " Check 'joinspaces' and 'cpo' + if &js == 1 + if &cpo =~ 'j' + let join_str = '\(\. \)' + else + let join_str = '\([.!?!] \)' + endif + endif + + let cur = a:firstline + while cur <= a:lastline + + let str_orig = getline(cur) + let save_et = &et + set et + exec cur . "retab" + let &et = save_et + let str = getline(cur) + + let indent_str = indent_fix + let indent_n = strlen(indent_str) + " Shall we remember the current indentation + if indent < 0 + let indent_orig = matchstr(str_orig, '^\s*') + if strlen(indent_orig) > 0 + let indent_str = indent_orig + let indent_n = strlen(matchstr(str, '^\s*')) + endif + endif + + " Trim trailing, leading and running whitespace + let str = substitute(str, '\s\+$', '', '') + let str = substitute(str, '^\s\+', '', '') + let str = substitute(str, '\s\+', ' ', 'g') + let str_n = strdisplaywidth(str) + + " Possible addition of space after punctuation + if exists("join_str") + let str = substitute(str, join_str, '\1 ', 'g') + endif + let join_n = strdisplaywidth(str) - str_n + + " Can extraspaces be added? + " Note that str_n may be less than strlen(str) [joinspaces above] + if strdisplaywidth(str) <= tw - indent_n && str_n > 0 + " How many spaces should be added + let s_add = tw - str_n - indent_n - join_n + let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n + let s_dup = s_add / s_nr + let s_mod = s_add % s_nr + + " Test if the changed line fits with tw + if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw + + " Duplicate spaces + while s_dup > 0 + let str = substitute(str, '\( \+\)', ' \1', 'g') + let s_dup = s_dup - 1 + endwhile + + " Add extra spaces from the end + while s_mod > 0 + let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '') + let s_mod = s_mod - 1 + endwhile + + " Indent the line + if indent_n > 0 + let str = substitute(str, '^', indent_str, '' ) + endif + + " Replace the line + call setline(cur, str) + + " Convert to whitespace + if &et == 0 + exec cur . 'retab!' + endif + + endif " Change of line + endif " Possible change + + let cur = cur + 1 + endwhile + + norm ^ + + let &report = save_report + +endfunction + +" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai diff --git a/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim b/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim new file mode 100644 index 0000000000..6175d1d9a6 --- /dev/null +++ b/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim @@ -0,0 +1,94 @@ +" When you're writing shell scripts and you are in doubt which test to use, +" which shell environment variables are defined, what the syntax of the case +" statement is, and you need to invoke 'man sh'? +" +" Your problems are over now! +" +" Attached is a Vim script file for turning gvim into a shell script editor. +" It may also be used as an example how to use menus in Vim. +" +" Written by: Lennart Schultz <les@dmi.min.dk> + +imenu Stmts.for for in
do
doneki kk0elli +imenu Stmts.case case in
) ;;
esacbki k0elli +imenu Stmts.if if
then
fiki kk0elli +imenu Stmts.if-else if
then
else
fiki kki kk0elli +imenu Stmts.elif elif
then
ki kk0elli +imenu Stmts.while while
do
doneki kk0elli +imenu Stmts.break break +imenu Stmts.continue continue +imenu Stmts.function () {
}ki k0i +imenu Stmts.return return +imenu Stmts.return-true return 0 +imenu Stmts.return-false return 1 +imenu Stmts.exit exit +imenu Stmts.shift shift +imenu Stmts.trap trap +imenu Test.existence [ -e ]hi +imenu Test.existence - file [ -f ]hi +imenu Test.existence - file (not empty) [ -s ]hi +imenu Test.existence - directory [ -d ]hi +imenu Test.existence - executable [ -x ]hi +imenu Test.existence - readable [ -r ]hi +imenu Test.existence - writable [ -w ]hi +imenu Test.String is empty [ x = "x$" ]hhi +imenu Test.String is not empty [ x != "x$" ]hhi +imenu Test.Strings is equal [ "" = "" ]hhhhhhhi +imenu Test.Strings is not equal [ "" != "" ]hhhhhhhhi +imenu Test.Values is greater than [ -gt ]hhhhhhi +imenu Test.Values is greater equal [ -ge ]hhhhhhi +imenu Test.Values is equal [ -eq ]hhhhhhi +imenu Test.Values is not equal [ -ne ]hhhhhhi +imenu Test.Values is less than [ -lt ]hhhhhhi +imenu Test.Values is less equal [ -le ]hhhhhhi +imenu ParmSub.Substitute word if parm not set ${:-}hhi +imenu ParmSub.Set parm to word if not set ${:=}hhi +imenu ParmSub.Substitute word if parm set else nothing ${:+}hhi +imenu ParmSub.If parm not set print word and exit ${:?}hhi +imenu SpShVars.Number of positional parameters ${#} +imenu SpShVars.All positional parameters (quoted spaces) ${*} +imenu SpShVars.All positional parameters (unquoted spaces) ${@} +imenu SpShVars.Flags set ${-} +imenu SpShVars.Return code of last command ${?} +imenu SpShVars.Process number of this shell ${$} +imenu SpShVars.Process number of last background command ${!} +imenu Environ.HOME ${HOME} +imenu Environ.PATH ${PATH} +imenu Environ.CDPATH ${CDPATH} +imenu Environ.MAIL ${MAIL} +imenu Environ.MAILCHECK ${MAILCHECK} +imenu Environ.PS1 ${PS1} +imenu Environ.PS2 ${PS2} +imenu Environ.IFS ${IFS} +imenu Environ.SHACCT ${SHACCT} +imenu Environ.SHELL ${SHELL} +imenu Environ.LC_CTYPE ${LC_CTYPE} +imenu Environ.LC_MESSAGES ${LC_MESSAGES} +imenu Builtins.cd cd +imenu Builtins.echo echo +imenu Builtins.eval eval +imenu Builtins.exec exec +imenu Builtins.export export +imenu Builtins.getopts getopts +imenu Builtins.hash hash +imenu Builtins.newgrp newgrp +imenu Builtins.pwd pwd +imenu Builtins.read read +imenu Builtins.readonly readonly +imenu Builtins.return return +imenu Builtins.times times +imenu Builtins.type type +imenu Builtins.umask umask +imenu Builtins.wait wait +imenu Set.set set +imenu Set.unset unset +imenu Set.mark modified or modified variables set -a +imenu Set.exit when command returns non-zero exit code set -e +imenu Set.Disable file name generation set -f +imenu Set.remember function commands set -h +imenu Set.All keyword arguments are placed in the environment set -k +imenu Set.Read commands but do not execute them set -n +imenu Set.Exit after reading and executing one command set -t +imenu Set.Treat unset variables as an error when substituting set -u +imenu Set.Print shell input lines as they are read set -v +imenu Set.Print commands and their arguments as they are executed set -x diff --git a/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim b/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim new file mode 100644 index 0000000000..8b85be050b --- /dev/null +++ b/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim @@ -0,0 +1,22 @@ +" These macros swap the left and right mouse buttons (for left handed) +" Don't forget to do ":set mouse=a" or the mouse won't work at all +noremap <LeftMouse> <RightMouse> +noremap <2-LeftMouse> <2-RightMouse> +noremap <3-LeftMouse> <3-RightMouse> +noremap <4-LeftMouse> <4-RightMouse> +noremap <LeftDrag> <RightDrag> +noremap <LeftRelease> <RightRelease> +noremap <RightMouse> <LeftMouse> +noremap <2-RightMouse> <2-LeftMouse> +noremap <3-RightMouse> <3-LeftMouse> +noremap <4-RightMouse> <4-LeftMouse> +noremap <RightDrag> <LeftDrag> +noremap <RightRelease> <LeftRelease> +noremap g<LeftMouse> <C-RightMouse> +noremap g<RightMouse> <C-LeftMouse> +noremap! <LeftMouse> <RightMouse> +noremap! <LeftDrag> <RightDrag> +noremap! <LeftRelease> <RightRelease> +noremap! <RightMouse> <LeftMouse> +noremap! <RightDrag> <LeftDrag> +noremap! <RightRelease> <LeftRelease> diff --git a/runtime/plugin/matchit.vim b/runtime/plugin/matchit.vim index 70867b1f93..8053b080e1 100644 --- a/runtime/plugin/matchit.vim +++ b/runtime/plugin/matchit.vim @@ -1,7 +1,8 @@ " matchit.vim: (global plugin) Extended "%" matching -" Last Change: Fri Jan 25 10:00 AM 2008 EST +" Last Change: Fri Jul 29 01:20 AM 2016 EST " Maintainer: Benji Fisher PhD <benji@member.AMS.org> " Version: 1.13.2, for Vim 6.3+ +" Fix from Tommy Allen included. " URL: http://www.vim.org/script.php?script_id=39 " Documentation: @@ -254,12 +255,7 @@ function! s:Match_wrapper(word, forward, mode) range " Fifth step: actually start moving the cursor and call searchpair(). " Later, :execute restore_cursor to get to the original screen. - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor + let view = winsaveview() call cursor(0, curcol + 1) " normal! 0 " if curcol @@ -273,7 +269,7 @@ function! s:Match_wrapper(word, forward, mode) range let sp_return = searchpair(ini, mid, fin, flag, skip) let final_position = "call cursor(" . line(".") . "," . col(".") . ")" " Restore cursor position and original screen. - execute restore_cursor + call winrestview(view) normal! m' if sp_return > 0 execute final_position @@ -634,7 +630,7 @@ endfun " idea to give it its own matching patterns. fun! s:MultiMatch(spflag, mode) if !exists("b:match_words") || b:match_words == "" - return "" + return {} end let restore_options = (&ic ? "" : "no") . "ignorecase" if exists("b:match_ignorecase") @@ -694,15 +690,7 @@ fun! s:MultiMatch(spflag, mode) let skip = 's:comment\|string' endif let skip = s:ParseSkip(skip) - " let restore_cursor = line(".") . "G" . virtcol(".") . "|" - " normal! H - " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor + let view = winsaveview() " Third step: call searchpair(). " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. @@ -720,14 +708,14 @@ fun! s:MultiMatch(spflag, mode) while level if searchpair(openpat, '', closepat, a:spflag, skip) < 1 call s:CleanUp(restore_options, a:mode, startline, startcol) - return "" + return {} endif let level = level - 1 endwhile - " Restore options and return a string to restore the original position. + " Restore options and return view dict to restore the original position. call s:CleanUp(restore_options, a:mode, startline, startcol) - return restore_cursor + return view endfun " Search backwards for "if" or "while" or "<tag>" or ... diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua index 9135c8e3ab..2a82181841 100644 --- a/scripts/genvimvim.lua +++ b/scripts/genvimvim.lua @@ -123,7 +123,7 @@ for line in eval_fd:lines() do if line == '};' then break end - local func_name = line:match('^ {"(%w+)",') + local func_name = line:match('^ { "([%w_]+)",') if func_name then if lld.line_length > 850 then w('\n' .. vimfun_start) diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index a40090d4c3..3997bd52b1 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -137,7 +137,7 @@ get_vim_patch() { # Patch surgery: preprocess the patch. # - transform src/ paths to src/nvim/ local vim_full - vim_full="$(git show -1 --pretty=medium "${vim_commit}" \ + vim_full="$(git --no-pager show --color=never -1 --pretty=medium "${vim_commit}" \ | LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g')" local neovim_branch="${BRANCH_PREFIX}${vim_version}" @@ -290,7 +290,7 @@ list_vim_patches() { 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 + if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then vim_commit="${vim_commit} (+runtime)" fi else diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 438a85dd5d..c934d44e70 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4030,8 +4030,8 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname) if (!buf->b_p_bin) { char_u *rfname; - /* If the file name is a shortcut file, use the file it links to. */ - rfname = mch_resolve_shortcut(*ffname); + // If the file name is a shortcut file, use the file it links to. + rfname = os_resolve_shortcut(*ffname); if (rfname != NULL) { xfree(*ffname); *ffname = rfname; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index b515c4e1e4..46687f344c 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -937,8 +937,9 @@ struct matchitem { */ struct window_S { uint64_t handle; - buf_T *w_buffer; /* buffer we are a window into (used - often, keep it the first item!) */ + int w_id; ///< unique window ID + buf_T *w_buffer; ///< buffer we are a window into (used + ///< often, keep it the first item!) synblock_T *w_s; /* for :ownsyntax */ diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 5ae4416052..22ca0fb0cc 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -43,20 +43,29 @@ static bool chartab_initialized = false; #define GET_CHARTAB(buf, c) \ ((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f))) -/// Fill chartab[]. Also fills curbuf->b_chartab[] with flags for keyword +// Table used below, see init_chartab() for an explanation +static char_u g_chartab[256]; + +// Flags for g_chartab[]. +#define CT_CELL_MASK 0x07 ///< mask: nr of display cells (1, 2 or 4) +#define CT_PRINT_CHAR 0x10 ///< flag: set for printable chars +#define CT_ID_CHAR 0x20 ///< flag: set for ID chars +#define CT_FNAME_CHAR 0x40 ///< flag: set for file name chars + +/// Fill g_chartab[]. Also fills curbuf->b_chartab[] with flags for keyword /// characters for current buffer. /// /// Depends on the option settings 'iskeyword', 'isident', 'isfname', /// 'isprint' and 'encoding'. /// -/// The index in chartab[] depends on 'encoding': +/// The index in g_chartab[] depends on 'encoding': /// - For non-multi-byte index with the byte (same as the character). /// - For DBCS index with the first byte. /// - For UTF-8 index with the character (when first byte is up to 0x80 it is /// the same as the character, if the first byte is 0x80 and above it depends /// on further bytes). /// -/// The contents of chartab[]: +/// The contents of g_chartab[]: /// - The lower two bits, masked by CT_CELL_MASK, give the number of display /// cells the character occupies (1 or 2). Not valid for UTF-8 above 0x80. /// - CT_PRINT_CHAR bit is set when the character is printable (no need to @@ -94,32 +103,32 @@ int buf_init_chartab(buf_T *buf, int global) c = 0; while (c < ' ') { - chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; } while (c <= '~') { - chartab[c++] = 1 + CT_PRINT_CHAR; + g_chartab[c++] = 1 + CT_PRINT_CHAR; } if (p_altkeymap) { while (c < YE) { - chartab[c++] = 1 + CT_PRINT_CHAR; + g_chartab[c++] = 1 + CT_PRINT_CHAR; } } while (c < 256) { if (enc_utf8 && (c >= 0xa0)) { // UTF-8: bytes 0xa0 - 0xff are printable (latin1) - chartab[c++] = CT_PRINT_CHAR + 1; + g_chartab[c++] = CT_PRINT_CHAR + 1; } else if ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) { // euc-jp characters starting with 0x8e are single width - chartab[c++] = CT_PRINT_CHAR + 1; + g_chartab[c++] = CT_PRINT_CHAR + 1; } else if ((enc_dbcs != 0) && (MB_BYTE2LEN(c) == 2)) { // other double-byte chars can be printable AND double-width - chartab[c++] = CT_PRINT_CHAR + 2; + g_chartab[c++] = CT_PRINT_CHAR + 2; } else { // the rest is unprintable by default - chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; } } @@ -128,7 +137,7 @@ int buf_init_chartab(buf_T *buf, int global) if (((enc_dbcs != 0) && (MB_BYTE2LEN(c) > 1)) || ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) || (enc_utf8 && (c >= 0xa0))) { - chartab[c] |= CT_FNAME_CHAR; + g_chartab[c] |= CT_FNAME_CHAR; } } } @@ -231,9 +240,9 @@ int buf_init_chartab(buf_T *buf, int global) if (i == 0) { // (re)set ID flag if (tilde) { - chartab[c] &= (uint8_t)~CT_ID_CHAR; + g_chartab[c] &= (uint8_t)~CT_ID_CHAR; } else { - chartab[c] |= CT_ID_CHAR; + g_chartab[c] |= CT_ID_CHAR; } } else if (i == 1) { // (re)set printable @@ -244,20 +253,20 @@ int buf_init_chartab(buf_T *buf, int global) || (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))) && !(enc_dbcs && (MB_BYTE2LEN(c) == 2))) { if (tilde) { - chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) - + ((dy_flags & DY_UHEX) ? 4 : 2)); - chartab[c] &= (uint8_t)~CT_PRINT_CHAR; + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + + ((dy_flags & DY_UHEX) ? 4 : 2)); + g_chartab[c] &= (uint8_t)~CT_PRINT_CHAR; } else { - chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) + 1); - chartab[c] |= CT_PRINT_CHAR; + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1); + g_chartab[c] |= CT_PRINT_CHAR; } } } else if (i == 2) { // (re)set fname flag if (tilde) { - chartab[c] &= (uint8_t)~CT_FNAME_CHAR; + g_chartab[c] &= (uint8_t)~CT_FNAME_CHAR; } else { - chartab[c] |= CT_FNAME_CHAR; + g_chartab[c] |= CT_FNAME_CHAR; } } else { // i == 3 // (re)set keyword flag @@ -492,9 +501,9 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) return buf; } -// Catch 22: chartab[] can't be initialized before the options are +// Catch 22: g_chartab[] can't be initialized before the options are // initialized, and initializing options may cause transchar() to be called! -// When chartab_initialized == false don't use chartab[]. +// When chartab_initialized == false don't use g_chartab[]. // Does NOT work for multi-byte characters, c must be <= 255. // Also doesn't work for the first byte of a multi-byte, "c" must be a // character! @@ -633,7 +642,7 @@ int byte2cells(int b) if (enc_utf8 && (b >= 0x80)) { return 0; } - return chartab[b] & CT_CELL_MASK; + return g_chartab[b] & CT_CELL_MASK; } /// Return number of display cells occupied by character "c". @@ -665,7 +674,7 @@ int char2cells(int c) return 2; } } - return chartab[c & 0xff] & CT_CELL_MASK; + return g_chartab[c & 0xff] & CT_CELL_MASK; } /// Return number of display cells occupied by character at "*p". @@ -682,7 +691,7 @@ int ptr2cells(char_u *p) } // For DBCS we can tell the cell count from the first byte. - return chartab[*p] & CT_CELL_MASK; + return g_chartab[*p] & CT_CELL_MASK; } /// Return the number of character cells string "s" will take on the screen, @@ -806,7 +815,7 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) bool vim_isIDc(int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return c > 0 && c < 0x100 && (chartab[c] & CT_ID_CHAR); + return c > 0 && c < 0x100 && (g_chartab[c] & CT_ID_CHAR); } /// Check that "c" is a keyword character: @@ -878,7 +887,7 @@ bool vim_iswordp_buf(char_u *p, buf_T *buf) bool vim_isfilec(int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return c >= 0x100 || (c > 0 && (chartab[c] & CT_FNAME_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR)); } /// Check that "c" is a valid file-name character or a wildcard character @@ -906,7 +915,7 @@ bool vim_isprintc(int c) if (enc_utf8 && (c >= 0x100)) { return utf_printable(c); } - return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)); } /// Strict version of vim_isprintc(c), don't return true if "c" is the head @@ -925,7 +934,7 @@ bool vim_isprintc_strict(int c) if (enc_utf8 && (c >= 0x100)) { return utf_printable(c); } - return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)); } /// like chartabsize(), but also check for line breaks on the screen @@ -1247,7 +1256,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, if (enc_utf8 && (c >= 0x80)) { incr = utf_ptr2cells(ptr); } else { - incr = CHARSIZE(c); + incr = g_chartab[c] & CT_CELL_MASK; } // If a double-cell char doesn't fit at the end of a line @@ -1261,7 +1270,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, head = 1; } } else { - incr = CHARSIZE(c); + incr = g_chartab[c] & CT_CELL_MASK; } } diff --git a/src/nvim/charset.h b/src/nvim/charset.h index 995ad123ae..78d6f2a76c 100644 --- a/src/nvim/charset.h +++ b/src/nvim/charset.h @@ -1,14 +1,6 @@ #ifndef NVIM_CHARSET_H #define NVIM_CHARSET_H -/* - * Flags for chartab[]. - */ -#define CT_CELL_MASK 0x07 /* mask: nr of display cells (1, 2 or 4) */ -#define CT_PRINT_CHAR 0x10 /* flag: set for printable chars */ -#define CT_ID_CHAR 0x20 /* flag: set for ID chars */ -#define CT_FNAME_CHAR 0x40 /* flag: set for file name chars */ - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "charset.h.generated.h" #endif diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 03ef41f849..98ec9ae280 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2385,6 +2385,7 @@ void set_completion(colnr_T startcol, list_T *list) } else { ins_complete(Ctrl_N, false); } + compl_enter_selects = compl_no_insert; // Lazily show the popup menu, unless we got interrupted. if (!compl_interrupted) { @@ -3989,6 +3990,7 @@ static void ins_compl_insert(void) dict_add_nr_str(dict, "info", 0L, EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO])); set_vim_var_dict(VV_COMPLETED_ITEM, dict); + compl_curr_match = compl_shown_match; } /* diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 55fa974797..7839a7f645 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3297,6 +3297,26 @@ char_u *get_user_var_name(expand_T *xp, int idx) } +/// Return TRUE if "pat" matches "text". +/// Does not use 'cpo' and always uses 'magic'. +static int pattern_match(char_u *pat, char_u *text, int ic) +{ + int matches = 0; + regmatch_T regmatch; + + // avoid 'l' flag in 'cpoptions' + char_u *save_cpo = p_cpo; + p_cpo = (char_u *)""; + regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); + if (regmatch.regprog != NULL) { + regmatch.rm_ic = ic; + matches = vim_regexec_nl(®match, text, (colnr_T)0); + vim_regfree(regmatch.regprog); + } + p_cpo = save_cpo; + return matches; +} + /* * types for expressions. */ @@ -3572,9 +3592,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) long n1, n2; char_u *s1, *s2; char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; - regmatch_T regmatch; int ic; - char_u *save_cpo; /* * Get the first variable. @@ -3783,19 +3801,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) case TYPE_MATCH: case TYPE_NOMATCH: - /* avoid 'l' flag in 'cpoptions' */ - save_cpo = p_cpo; - p_cpo = (char_u *)""; - regmatch.regprog = vim_regcomp(s2, - RE_MAGIC + RE_STRING); - regmatch.rm_ic = ic; - if (regmatch.regprog != NULL) { - n1 = vim_regexec_nl(®match, s1, (colnr_T)0); - vim_regfree(regmatch.regprog); - if (type == TYPE_NOMATCH) - n1 = !n1; + n1 = pattern_match(s2, s1, ic); + if (type == TYPE_NOMATCH) { + n1 = !n1; } - p_cpo = save_cpo; break; case TYPE_UNKNOWN: break; /* avoid gcc warning */ @@ -6697,6 +6706,9 @@ static struct fst { { "assert_exception", 1, 2, f_assert_exception }, { "assert_fails", 1, 2, f_assert_fails }, { "assert_false", 1, 2, f_assert_false }, + { "assert_match", 2, 3, f_assert_match }, + { "assert_notequal", 2, 3, f_assert_notequal }, + { "assert_notmatch", 2, 3, f_assert_notmatch }, { "assert_true", 1, 2, f_assert_true }, { "atan", 1, 1, f_atan }, { "atan2", 2, 2, f_atan2 }, @@ -6715,7 +6727,6 @@ static struct fst { { "byteidx", 2, 2, f_byteidx }, { "byteidxcomp", 2, 2, f_byteidxcomp }, { "call", 2, 3, f_call }, - { "capture", 1, 1, f_capture }, { "ceil", 1, 1, f_ceil }, { "changenr", 0, 0, f_changenr }, { "char2nr", 1, 2, f_char2nr }, @@ -6744,6 +6755,7 @@ static struct fst { { "eval", 1, 1, f_eval }, { "eventhandler", 0, 0, f_eventhandler }, { "executable", 1, 1, f_executable }, + { "execute", 1, 1, f_execute }, { "exepath", 1, 1, f_exepath }, { "exists", 1, 1, f_exists }, { "exp", 1, 1, f_exp }, @@ -6779,6 +6791,7 @@ static struct fst { { "getcmdpos", 0, 0, f_getcmdpos }, { "getcmdtype", 0, 0, f_getcmdtype }, { "getcmdwintype", 0, 0, f_getcmdwintype }, + { "getcompletion", 2, 2, f_getcompletion }, { "getcurpos", 0, 0, f_getcurpos }, { "getcwd", 0, 2, f_getcwd }, { "getfontname", 0, 1, f_getfontname }, @@ -6974,6 +6987,10 @@ static struct fst { { "virtcol", 1, 1, f_virtcol }, { "visualmode", 0, 1, f_visualmode }, { "wildmenumode", 0, 0, f_wildmenumode }, + { "win_getid", 0, 2, f_win_getid }, + { "win_gotoid", 1, 1, f_win_gotoid }, + { "win_id2tabwin", 1, 1, f_win_id2tabwin }, + { "win_id2win", 1, 1, f_win_id2win }, { "winbufnr", 1, 1, f_winbufnr }, { "wincol", 0, 0, f_wincol }, { "winheight", 1, 1, f_winheight }, @@ -7606,7 +7623,7 @@ static void prepare_assert_error(garray_T *gap) // Fill "gap" with information about an assert error. static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, - typval_T *got_tv) + typval_T *got_tv, assert_type_T atype) { char_u *tofree; @@ -7615,7 +7632,11 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, ga_concat(gap, tofree); xfree(tofree); } else { - ga_concat(gap, (char_u *)"Expected "); + if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) { + ga_concat(gap, (char_u *)"Pattern "); + } else { + ga_concat(gap, (char_u *)"Expected "); + } if (exp_str == NULL) { tofree = (char_u *) encode_tv2string(exp_tv, NULL); ga_concat(gap, tofree); @@ -7623,8 +7644,16 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, } else { ga_concat(gap, exp_str); } - tofree = (char_u *) encode_tv2string(got_tv, NULL); - ga_concat(gap, (char_u *)" but got "); + tofree = (char_u *)encode_tv2string(got_tv, NULL); + if (atype == ASSERT_MATCH) { + ga_concat(gap, (char_u *)" does not match "); + } else if (atype == ASSERT_NOTMATCH) { + ga_concat(gap, (char_u *)" does match "); + } else if (atype == ASSERT_NOTEQUAL) { + ga_concat(gap, (char_u *)" differs from "); + } else { + ga_concat(gap, (char_u *)" but got "); + } ga_concat(gap, tofree); xfree(tofree); } @@ -7643,20 +7672,32 @@ static void assert_error(garray_T *gap) gap->ga_data, gap->ga_len); } -// "assert_equal(expected, actual[, msg])" function -static void f_assert_equal(typval_T *argvars, typval_T *rettv) +static void assert_equal_common(typval_T *argvars, assert_type_T atype) { garray_T ga; - if (!tv_equal(&argvars[0], &argvars[1], false, false)) { + if (tv_equal(&argvars[0], &argvars[1], false, false) + != (atype == ASSERT_EQUAL)) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, - &argvars[0], &argvars[1]); + &argvars[0], &argvars[1], atype); assert_error(&ga); ga_clear(&ga); } } +// "assert_equal(expected, actual[, msg])" function +static void f_assert_equal(typval_T *argvars, typval_T *rettv) +{ + assert_equal_common(argvars, ASSERT_EQUAL); +} + +// "assert_notequal(expected, actual[, msg])" function +static void f_assert_notequal(typval_T *argvars, typval_T *rettv) +{ + assert_equal_common(argvars, ASSERT_NOTEQUAL); +} + /// "assert_exception(string[, msg])" function static void f_assert_exception(typval_T *argvars, typval_T *rettv) { @@ -7672,7 +7713,7 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv) && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], - &vimvars[VV_EXCEPTION].vv_tv); + &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER); assert_error(&ga); ga_clear(&ga); } @@ -7702,7 +7743,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv) || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], - &vimvars[VV_ERRMSG].vv_tv); + &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); assert_error(&ga); ga_clear(&ga); } @@ -7732,7 +7773,7 @@ static void assert_bool(typval_T *argvars, bool is_true) prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[1], (char_u *)(is_true ? "True" : "False"), - NULL, &argvars[0]); + NULL, &argvars[0], ASSERT_OTHER); assert_error(&ga); ga_clear(&ga); } @@ -7744,6 +7785,36 @@ static void f_assert_false(typval_T *argvars, typval_T *rettv) assert_bool(argvars, false); } +static void assert_match_common(typval_T *argvars, assert_type_T atype) +{ + char_u buf1[NUMBUFLEN]; + char_u buf2[NUMBUFLEN]; + char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1); + char_u *text = get_tv_string_buf_chk(&argvars[1], buf2); + + if (pat == NULL || text == NULL) { + EMSG(_(e_invarg)); + } else if (pattern_match(pat, text, false) != (atype == ASSERT_MATCH)) { + garray_T ga; + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype); + assert_error(&ga); + ga_clear(&ga); + } +} + +/// "assert_match(pattern, actual[, msg])" function +static void f_assert_match(typval_T *argvars, typval_T *rettv) +{ + assert_match_common(argvars, ASSERT_MATCH); +} + +/// "assert_notmatch(pattern, actual[, msg])" function +static void f_assert_notmatch(typval_T *argvars, typval_T *rettv) +{ + assert_match_common(argvars, ASSERT_NOTMATCH); +} + // "assert_true(actual[, msg])" function static void f_assert_true(typval_T *argvars, typval_T *rettv) { @@ -8087,38 +8158,6 @@ static void f_call(typval_T *argvars, typval_T *rettv) (void)func_call(func, &argvars[1], selfdict, rettv); } -// "capture(command)" function -static void f_capture(typval_T *argvars, typval_T *rettv) -{ - int save_msg_silent = msg_silent; - garray_T *save_capture_ga = capture_ga; - - if (check_secure()) { - return; - } - - garray_T capture_local; - capture_ga = &capture_local; - ga_init(capture_ga, (int)sizeof(char), 80); - - msg_silent++; - if (argvars[0].v_type != VAR_LIST) { - do_cmdline_cmd((char *)get_tv_string(&argvars[0])); - } else if (argvars[0].vval.v_list != NULL) { - for (listitem_T *li = argvars[0].vval.v_list->lv_first; - li != NULL; li = li->li_next) { - do_cmdline_cmd((char *)get_tv_string(&li->li_tv)); - } - } - msg_silent = save_msg_silent; - - ga_append(capture_ga, NUL); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = capture_ga->ga_data; - - capture_ga = save_capture_ga; -} - /* * "ceil({float})" function */ @@ -8803,6 +8842,38 @@ static void f_executable(typval_T *argvars, typval_T *rettv) || (gettail_dir(name) != name && os_can_exe(name, NULL, false)); } +// "execute(command)" function +static void f_execute(typval_T *argvars, typval_T *rettv) +{ + int save_msg_silent = msg_silent; + garray_T *save_capture_ga = capture_ga; + + if (check_secure()) { + return; + } + + garray_T capture_local; + capture_ga = &capture_local; + ga_init(capture_ga, (int)sizeof(char), 80); + + msg_silent++; + if (argvars[0].v_type != VAR_LIST) { + do_cmdline_cmd((char *)get_tv_string(&argvars[0])); + } else if (argvars[0].vval.v_list != NULL) { + for (listitem_T *li = argvars[0].vval.v_list->lv_first; + li != NULL; li = li->li_next) { + do_cmdline_cmd((char *)get_tv_string(&li->li_tv)); + } + } + msg_silent = save_msg_silent; + + ga_append(capture_ga, NUL); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = capture_ga->ga_data; + + capture_ga = save_capture_ga; +} + /// "exepath()" function static void f_exepath(typval_T *argvars, typval_T *rettv) { @@ -9917,6 +9988,50 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv) rettv->vval.v_string[0] = cmdwin_type; } +// "getcompletion()" function +static void f_getcompletion(typval_T *argvars, typval_T *rettv) +{ + char_u *pat; + expand_T xpc; + int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL + | WILD_LIST_NOTFOUND | WILD_NO_BEEP; + + if (p_wic) { + options |= WILD_ICASE; + } + + ExpandInit(&xpc); + xpc.xp_pattern = get_tv_string(&argvars[0]); + xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1])); + if (xpc.xp_context == EXPAND_NOTHING) { + if (argvars[1].v_type == VAR_STRING) { + EMSG2(_(e_invarg2), argvars[1].vval.v_string); + } else { + EMSG(_(e_invarg)); + } + return; + } + + if (xpc.xp_context == EXPAND_MENUS) { + set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, false); + xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + } + + pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); + if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) { + int i; + + ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); + + for (i = 0; i < xpc.xp_numfiles; i++) { + list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); + } + } + xfree(pat); + ExpandCleanup(&xpc); +} + /// `getcwd([{win}[, {tab}]])` function /// /// Every scope not specified implies the currently selected scope object. @@ -13526,11 +13641,12 @@ static void f_resolve(typval_T *argvars, typval_T *rettv) { char_u *v = NULL; - v = mch_resolve_shortcut(p); - if (v != NULL) + v = os_resolve_shortcut(p); + if (v != NULL) { rettv->vval.v_string = v; - else + } else { rettv->vval.v_string = vim_strsave(p); + } } #else # ifdef HAVE_READLINK @@ -17038,6 +17154,32 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = 1; } +/// "win_getid()" function +static void f_win_getid(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_getid(argvars); +} + +/// "win_gotoid()" function +static void f_win_gotoid(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_gotoid(argvars); +} + +/// "win_id2tabwin()" function +static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv) +{ + if (rettv_list_alloc(rettv) != FAIL) { + win_id2tabwin(argvars, rettv->vval.v_list); + } +} + +/// "win_id2win()" function +static void f_win_id2win(typval_T *argvars, typval_T *rettv) +{ + rettv->vval.v_number = win_id2win(argvars); +} + /* * "winbufnr(nr)" function */ @@ -18325,7 +18467,7 @@ static void init_tv(typval_T *varp) * caller of incompatible types: it sets *denote to TRUE if "denote" * is not NULL or returns -1 otherwise. */ -static long get_tv_number(typval_T *varp) +long get_tv_number(typval_T *varp) { int error = FALSE; @@ -18886,19 +19028,6 @@ set_var ( || tv_check_lock(v->di_tv.v_lock, name, false)) { return; } - if (v->di_tv.v_type != tv->v_type - && !((v->di_tv.v_type == VAR_STRING - || v->di_tv.v_type == VAR_NUMBER) - && (tv->v_type == VAR_STRING - || tv->v_type == VAR_NUMBER)) - && !((v->di_tv.v_type == VAR_NUMBER - || v->di_tv.v_type == VAR_FLOAT) - && (tv->v_type == VAR_NUMBER - || tv->v_type == VAR_FLOAT)) - ) { - EMSG2(_("E706: Variable type mismatch for: %s"), name); - return; - } // Handle setting internal v: variables separately where needed to // prevent changing the type. @@ -18908,7 +19037,7 @@ set_var ( if (copy || tv->v_type != VAR_STRING) v->di_tv.vval.v_string = vim_strsave(get_tv_string(tv)); else { - /* Take over the string to avoid an extra alloc/free. */ + // Take over the string to avoid an extra alloc/free. v->di_tv.vval.v_string = tv->vval.v_string; tv->vval.v_string = NULL; } @@ -22344,7 +22473,10 @@ bool eval_has_provider(char *name) } \ } - static int has_clipboard = -1, has_python = -1, has_python3 = -1; + static int has_clipboard = -1; + static int has_python = -1; + static int has_python3 = -1; + static int has_ruby = -1; if (!strcmp(name, "clipboard")) { check_provider(clipboard); @@ -22355,6 +22487,9 @@ bool eval_has_provider(char *name) } else if (!strcmp(name, "python")) { check_provider(python); return has_python; + } else if (!strcmp(name, "ruby")) { + check_provider(ruby); + return has_ruby; } return false; diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index d5c9b2c1ec..884c987f10 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -162,4 +162,14 @@ typedef struct list_stack_S { /// Convert a hashitem pointer to a dictitem pointer #define HI2DI(hi) HIKEY2DI((hi)->hi_key) +/// Type of assert_* check being performed +typedef enum +{ + ASSERT_EQUAL, + ASSERT_NOTEQUAL, + ASSERT_MATCH, + ASSERT_NOTMATCH, + ASSERT_OTHER, +} assert_type_T; + #endif // NVIM_EVAL_DEFS_H diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 1c4c9737c3..317e40e43a 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -116,23 +116,20 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL process_is_tearing_down = true; kl_iter(WatcherPtr, loop->children, current) { Process *proc = (*current)->data; - if (proc->detach) { + if (proc->detach || proc->type == kProcessTypePty) { // Close handles to process without killing it. CREATE_EVENT(loop->events, process_close_handles, 1, proc); } else { - if (proc->type == kProcessTypeUv) { - uv_kill(proc->pid, SIGTERM); - proc->term_sent = true; - process_stop(proc); - } else { // kProcessTypePty - process_close_streams(proc); - pty_process_close_master((PtyProcess *)proc); - } + uv_kill(proc->pid, SIGTERM); + proc->term_sent = true; + process_stop(proc); } } - // Wait until all children exit - LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, kl_empty(loop->children)); + // Wait until all children exit and all close events are processed. + LOOP_PROCESS_EVENTS_UNTIL( + loop, loop->events, -1, + kl_empty(loop->children) && queue_empty(loop->events)); pty_process_teardown(loop); } @@ -315,8 +312,10 @@ static void decref(Process *proc) static void process_close(Process *proc) FUNC_ATTR_NONNULL_ARG(1) { - if (process_is_tearing_down && proc->detach && proc->closed) { - // If a detached process dies while tearing down it might get closed twice. + if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty) + && proc->closed) { + // If a detached/pty process dies while tearing down it might get closed + // twice. return; } assert(!proc->closed); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index da64533708..5de9ac0523 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4821,9 +4821,8 @@ static void helptags_one(char_u *dir, char_u *ext, char_u *tagfname, int mix = FALSE; /* detected mixed encodings */ // Find all *.txt files. - size_t dirlen = STRLEN(dir); - STRCPY(NameBuff, dir); - STRCAT(NameBuff, "/**/*"); + size_t dirlen = STRLCPY(NameBuff, dir, sizeof(NameBuff)); + STRCAT(NameBuff, "/**/*"); // NOLINT STRCAT(NameBuff, ext); // Note: We cannot just do `&NameBuff` because it is a statically sized array @@ -4841,7 +4840,7 @@ static void helptags_one(char_u *dir, char_u *ext, char_u *tagfname, * Open the tags file for writing. * Do this before scanning through all the files. */ - STRCPY(NameBuff, dir); + STRLCPY(NameBuff, dir, sizeof(NameBuff)); add_pathsep((char *)NameBuff); STRNCAT(NameBuff, tagfname, sizeof(NameBuff) - dirlen - 2); fd_tags = mch_fopen((char *)NameBuff, "w"); @@ -5016,7 +5015,7 @@ static void do_helptags(char_u *dirname, bool add_help_tags) char_u **files; // Get a list of all files in the help directory and in subdirectories. - STRCPY(NameBuff, dirname); + STRLCPY(NameBuff, dirname, sizeof(NameBuff)); add_pathsep((char *)NameBuff); STRCAT(NameBuff, "**"); diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 76191d5a56..3f5d9b3244 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -2170,19 +2170,19 @@ return { command='ruby', flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_script_ni', + func='ex_ruby', }, { command='rubydo', flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_ni', + func='ex_rubydo', }, { command='rubyfile', flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_ni', + func='ex_rubyfile', }, { command='rviminfo', diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index b56b1cf013..6d24ba91f2 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -897,6 +897,21 @@ void ex_pydo(exarg_T *eap) script_host_do_range("python", eap); } +void ex_ruby(exarg_T *eap) +{ + script_host_execute("ruby", eap); +} + +void ex_rubyfile(exarg_T *eap) +{ + script_host_execute_file("ruby", eap); +} + +void ex_rubydo(exarg_T *eap) +{ + script_host_do_range("ruby", eap); +} + void ex_python3(exarg_T *eap) { script_host_execute("python3", eap); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 9bc7ec39da..8bae817211 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5597,6 +5597,17 @@ int parse_compl_arg(char_u *value, int vallen, int *complp, return OK; } +int cmdcomplete_str_to_type(char_u *complete_str) +{ + for (int i = 0; command_complete[i].expand != 0; i++) { + if (STRCMP(complete_str, command_complete[i].name) == 0) { + return command_complete[i].expand; + } + } + + return EXPAND_NOTHING; +} + static void ex_colorscheme(exarg_T *eap) { if (*eap->arg == NUL) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 154558b332..3b598bd64b 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -493,22 +493,14 @@ readfile ( curbuf->b_flags &= ~(BF_NEW | BF_NEW_W); } - /* - * Check readonly by trying to open the file for writing. - * If this fails, we know that the file is readonly. - */ - file_readonly = FALSE; + // Check readonly. + file_readonly = false; if (!read_buffer && !read_stdin) { - if (!newfile || readonlymode) { - file_readonly = TRUE; - } else if ((fd = os_open((char *)fname, O_RDWR, 0)) < 0) { - // opening in readwrite mode failed => file is readonly - file_readonly = TRUE; - } - if (file_readonly == TRUE) { - // try to open readonly - fd = os_open((char *)fname, O_RDONLY, 0); + if (!newfile || readonlymode || !(perm & 0222) + || !os_file_is_writable((char *)fname)) { + file_readonly = true; } + fd = os_open((char *)fname, O_RDONLY, 0); } if (fd < 0) { /* cannot open at all */ diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ed9862a264..950ceb4c74 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -914,9 +914,6 @@ EXTERN int KeyTyped; // TRUE if user typed current char EXTERN int KeyStuffed; // TRUE if current char from stuffbuf EXTERN int maptick INIT(= 0); // tick for each non-mapped char -EXTERN uint8_t chartab[256]; // table used in charset.c; See - // init_chartab() for explanation - EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */ EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */ EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */ @@ -989,7 +986,7 @@ EXTERN int redir_off INIT(= false); // no redirection for a moment EXTERN FILE *redir_fd INIT(= NULL); // message redirection file EXTERN int redir_reg INIT(= 0); // message redirection register EXTERN int redir_vname INIT(= 0); // message redirection variable -EXTERN garray_T *capture_ga INIT(= NULL); // capture() buffer +EXTERN garray_T *capture_ga INIT(= NULL); // captured output for execute() EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */ diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 5f69fa2f6a..503daa9648 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -73,11 +73,6 @@ /* Returns empty string if it is NULL. */ #define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"") -/* macro version of chartab(). - * Only works with values 0-255! - * Doesn't work for UTF-8 mode with chars >= 0x80. */ -#define CHARSIZE(c) (chartab[c] & CT_CELL_MASK) - /* * Adjust chars in a language according to 'langmap' option. * NOTE that there is no noticeable overhead if 'langmap' is not set. diff --git a/src/nvim/main.c b/src/nvim/main.c index 64b5de8663..e052d0d315 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -670,8 +670,8 @@ static void init_locale(void) { char_u *p; - /* expand_env() doesn't work yet, because chartab[] is not initialized - * yet, call vim_getenv() directly */ + // expand_env() doesn't work yet, because g_chartab[] is not + // initialized yet, call vim_getenv() directly p = (char_u *)vim_getenv("VIMRUNTIME"); if (p != NULL && *p != NUL) { vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); diff --git a/src/nvim/map.c b/src/nvim/map.c index 03439e7a9c..398e74268f 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -129,7 +129,10 @@ static inline khint_t String_hash(String s) static inline bool String_eq(String a, String b) { - return strncmp(a.data, b.data, MIN(a.size, b.size)) == 0; + if (a.size != b.size) { + return false; + } + return memcmp(a.data, b.data, a.size) == 0; } diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 0ba9f8b076..26d94aa6fa 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1885,6 +1885,86 @@ static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2) return n1 == 0 ? -1 : 1; } +#ifdef WIN32 +#ifndef CP_UTF8 +# define CP_UTF8 65001 /* magic number from winnls.h */ +#endif + +int utf8_to_utf16(const char *str, WCHAR **strw) + FUNC_ATTR_NONNULL_ALL +{ + ssize_t wchar_len = 0; + + // Compute the length needed to store the converted widechar string. + wchar_len = MultiByteToWideChar(CP_UTF8, + 0, // dwFlags: must be 0 for utf8 + str, // lpMultiByteStr: string to convert + -1, // -1 => process up to NUL + NULL, // lpWideCharStr: converted string + 0); // 0 => return length, don't convert + if (wchar_len == 0) { + return GetLastError(); + } + + ssize_t buf_sz = wchar_len * sizeof(WCHAR); + + if (buf_sz == 0) { + *strw = NULL; + return 0; + } + + char *buf = xmalloc(buf_sz); + char *pos = buf; + + int r = MultiByteToWideChar(CP_UTF8, + 0, + str, + -1, + (WCHAR *)pos, + wchar_len); + assert(r == wchar_len); + *strw = (WCHAR *)pos; + + return 0; +} + +int utf16_to_utf8(const WCHAR *strw, char **str) + FUNC_ATTR_NONNULL_ALL +{ + // Compute the space required to store the string as UTF-8. + ssize_t utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + strw, + -1, + NULL, + 0, + NULL, + NULL); + if (utf8_len == 0) { + return GetLastError(); + } + + ssize_t buf_sz = utf8_len * sizeof(char); + char *buf = xmalloc(buf_sz); + char *pos = buf; + + // Convert string to UTF-8. + int r = WideCharToMultiByte(CP_UTF8, + 0, + strw, + -1, + (LPSTR *)pos, + utf8_len, + NULL, + NULL); + assert(r == utf8_len); + *str = pos; + + return 0; +} + +#endif + /* * Version of strnicmp() that handles multi-byte characters. * Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 673205f08f..08e82071d7 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -3165,9 +3165,10 @@ attention_message ( } /* Some of these messages are long to allow translation to * other languages. */ - MSG_PUTS(_( - "\n(1) Another program may be editing the same file. If this is the case,\n be careful not to end up with two different instances of the same\n file when making changes.")); - MSG_PUTS(_(" Quit, or continue with caution.\n")); + MSG_PUTS(_("\n(1) Another program may be editing the same file. If this is" + " the case,\n be careful not to end up with two different" + " instances of the same\n file when making changes." + " Quit, or continue with caution.\n")); MSG_PUTS(_("(2) An edit session for this file crashed.\n")); MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r ")); msg_outtrans(buf->b_fname); diff --git a/src/nvim/message.c b/src/nvim/message.c index 77e8f0e4f2..3c310ed309 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2396,7 +2396,7 @@ static void redir_write(char_u *str, int maxlen) return; } - // Append output to capture(). + // Append output for execute(). if (capture_ga) { size_t len = 0; while (str[len] && (maxlen < 0 ? 1 : (len < (size_t)maxlen))) { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 2f499e477c..5efac2623c 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -6,6 +6,7 @@ #include "nvim/window.h" #include "nvim/strings.h" #include "nvim/screen.h" +#include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/os_unix.h" #include "nvim/fold.h" @@ -303,6 +304,10 @@ retnomove: mouse_past_bottom = true; } + if (!(flags & MOUSE_RELEASED) && which_button == MOUSE_LEFT) { + col = mouse_adjust_click(curwin, row, col); + } + // Start Visual mode before coladvance(), for when 'sel' != "old" if ((flags & MOUSE_MAY_VIS) && !VIsual_active) { check_visual_highlight(); @@ -597,3 +602,74 @@ bool mouse_scroll_horiz(int dir) return leftcol_changed(); } + +// Adjust the clicked column position if there are concealed characters +// before the current column. But only when it's absolutely necessary. +static int mouse_adjust_click(win_T *wp, int row, int col) +{ + if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0 + && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) { + return col; + } + + int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum)); + int vend = getviscol2(end, 0); + + if (col >= vend) { + return col; + } + + int i = wp->w_leftcol; + + if (row > 0) { + i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) + - wp->w_leftcol) + wp->w_skipcol; + } + + int start_col = i; + int matchid; + int last_matchid; + int bcol = end - (vend - col); + + while (i < bcol) { + matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); + + if (matchid != 0) { + if (wp->w_p_cole == 3) { + bcol++; + } else { + if (row > 0 && i == start_col) { + // Check if the current concealed character is actually part of + // the previous wrapped row's conceal group. + last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, + i - 1); + if (last_matchid == matchid) { + bcol++; + } + } else if (wp->w_p_cole == 1 + || (wp->w_p_cole == 2 + && (lcs_conceal != NUL + || syn_get_sub_char() != NUL))) { + // At least one placeholder character will be displayed. + bcol--; + } + + last_matchid = matchid; + + // Adjust for concealed text that spans more than one character. + do { + i++; + bcol++; + matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); + } while (last_matchid == matchid); + + continue; + } + } + + i++; + } + + return getviscol2(bcol, 0); +} + diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index abbd3e8aff..d7c2926a0f 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -40,6 +40,10 @@ bool server_init(void) listen_address = server_address_new(); } + if (!listen_address) { + return false; + } + bool ok = (server_start(listen_address) == 0); if (must_free) { xfree((char *) listen_address); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index a498fc481a..e8a79fa820 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -339,10 +339,16 @@ static void shift_block(oparg_T *oap, int amount) total += bd.pre_whitesp; /* all virtual WS up to & incl a split TAB */ ws_vcol = bd.start_vcol - bd.pre_whitesp; if (bd.startspaces) { - if (has_mbyte) - bd.textstart += (*mb_ptr2len)(bd.textstart); - else - ++bd.textstart; + if (has_mbyte) { + if ((*mb_ptr2len)(bd.textstart) == 1) { + bd.textstart++; + } else { + ws_vcol = 0; + bd.startspaces = 0; + } + } else { + bd.textstart++; + } } for (; ascii_iswhite(*bd.textstart); ) { // TODO: is passing bd.textstart for start of the line OK? @@ -5452,7 +5458,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) yankreg_T *target; if (cb_flags & CB_UNNAMEDPLUS) { - *name = cb_flags & CB_UNNAMED ? '"': '+'; + *name = (cb_flags & CB_UNNAMED && writing) ? '"': '+'; target = &y_regs[PLUS_REGISTER]; } else { *name = '*'; diff --git a/src/nvim/option.c b/src/nvim/option.c index a7b44b372c..6baf8c65ce 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2451,16 +2451,13 @@ did_set_string_option ( else if (varp == &curwin->w_p_briopt) { if (briopt_check(curwin) == FAIL) errmsg = e_invarg; - } - /* - * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[] - * If the new option is invalid, use old value. 'lisp' option: refill - * chartab[] for '-' char - */ - else if ( varp == &p_isi + } else if (varp == &p_isi || varp == &(curbuf->b_p_isk) || varp == &p_isp || varp == &p_isf) { + // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // If the new option is invalid, use old value. 'lisp' option: refill + // g_chartab[] for '-' char if (init_chartab() == FAIL) { did_chartab = TRUE; /* need to restore it below */ errmsg = e_invarg; /* error in value */ diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 6cee102305..cf5bfd60ae 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -4,7 +4,6 @@ /// Neovim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite /// replacement. -#include <unistd.h> #include <assert.h> #include <stddef.h> #include <stdbool.h> diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index d12d34d595..cd943c4843 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -3,7 +3,6 @@ #include <stddef.h> #include <assert.h> #include <limits.h> -#include <unistd.h> #include <fcntl.h> #include <errno.h> @@ -26,6 +25,10 @@ #include "nvim/path.h" #include "nvim/strings.h" +#ifdef WIN32 +#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fs.c.generated.h" #endif @@ -923,10 +926,100 @@ bool os_fileid_equal(const FileID *file_id_1, const FileID *file_id_2) /// @param file_info Pointer to a `FileInfo` /// @return `true` if the `FileID` and the `FileInfo` represent te same file. bool os_fileid_equal_fileinfo(const FileID *file_id, - const FileInfo *file_info) + const FileInfo *file_info) FUNC_ATTR_NONNULL_ALL { return file_id->inode == file_info->stat.st_ino && file_id->device_id == file_info->stat.st_dev; } +#ifdef WIN32 +# include <shlobj.h> + +/// When "fname" is the name of a shortcut (*.lnk) resolve the file it points +/// to and return that name in allocated memory. +/// Otherwise NULL is returned. +char_u * os_resolve_shortcut(char_u *fname) +{ + HRESULT hr; + IPersistFile *ppf = NULL; + OLECHAR wsz[MAX_PATH]; + char_u *rfname = NULL; + int len; + int conversion_result; + IShellLinkW *pslw = NULL; + WIN32_FIND_DATAW ffdw; + + // Check if the file name ends in ".lnk". Avoid calling CoCreateInstance(), + // it's quite slow. + if (fname == NULL) { + return rfname; + } + len = (int)STRLEN(fname); + if (len <= 4 || STRNICMP(fname + len - 4, ".lnk", 4) != 0) { + return rfname; + } + + CoInitialize(NULL); + + // create a link manager object and request its interface + hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, (void **)&pslw); + if (hr == S_OK) { + WCHAR *p; + int conversion_result = utf8_to_utf16((char *)fname, &p); + if (conversion_result != 0) { + EMSG2("utf8_to_utf16 failed: %s", uv_strerror(conversion_result)); + } + + if (p != NULL) { + // Get a pointer to the IPersistFile interface. + hr = pslw->lpVtbl->QueryInterface( + pslw, &IID_IPersistFile, (void **)&ppf); + if (hr != S_OK) { + goto shortcut_errorw; + } + + // "load" the name and resolve the link + hr = ppf->lpVtbl->Load(ppf, p, STGM_READ); + if (hr != S_OK) { + goto shortcut_errorw; + } + +# if 0 // This makes Vim wait a long time if the target does not exist. + hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI); + if (hr != S_OK) { + goto shortcut_errorw; + } +# endif + + // Get the path to the link target. + ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR)); + hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0); + if (hr == S_OK && wsz[0] != NUL) { + int conversion_result = utf16_to_utf8(wsz, &rfname); + if (conversion_result != 0) { + EMSG2("utf16_to_utf8 failed: %s", uv_strerror(conversion_result)); + } + } + +shortcut_errorw: + xfree(p); + goto shortcut_end; + } + } + +shortcut_end: + // Release all interface pointers (both belong to the same object) + if (ppf != NULL) { + ppf->lpVtbl->Release(ppf); + } + if (pslw != NULL) { + pslw->lpVtbl->Release(pslw); + } + + CoUninitialize(); + return rfname; +} + +#endif diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 436de030ba..b57a69b82b 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <string.h> -#include <unistd.h> #include <termios.h> #include <sys/types.h> #include <sys/wait.h> diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index 8a3fcb8f78..0326f33bb5 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -5653,7 +5653,7 @@ msgstr "単語 '%.*s' が %s から削除されました" #: ../spell.c:8117 #, c-format msgid "Word '%.*s' added to %s" -msgstr "%s に単語が追加されました" +msgstr "単語 '%.*s' が %s へ追加されました" #: ../spell.c:8381 msgid "E763: Word characters differ between spell files" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 886a48e7c5..f8fd7d4ef8 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -1389,6 +1389,10 @@ int vim_regcomp_had_eol(void) return had_eol; } +// variables for parsing reginput +static int at_start; // True when on the first character +static int prev_at_start; // True when on the second character + /* * Parse regular expression, i.e. main body or parenthesized thing. * @@ -1768,6 +1772,7 @@ static char_u *regatom(int *flagp) int c; char_u *p; int extra = 0; + int save_prev_at_start = prev_at_start; *flagp = WORST; /* Tentatively. */ @@ -2143,17 +2148,21 @@ static char_u *regatom(int *flagp) } break; } else if (c == 'l' || c == 'c' || c == 'v') { - if (c == 'l') + if (c == 'l') { ret = regnode(RE_LNUM); - else if (c == 'c') + if (save_prev_at_start) { + at_start = true; + } + } else if (c == 'c') { ret = regnode(RE_COL); - else + } else { ret = regnode(RE_VCOL); - if (ret == JUST_CALC_SIZE) + } + if (ret == JUST_CALC_SIZE) { regsize += 5; - else { - /* put the number and the optional - * comparator after the opcode */ + } else { + // put the number and the optional + // comparator after the opcode regcode = re_put_uint32(regcode, n); *regcode++ = cmp; } @@ -2679,9 +2688,6 @@ static void regoptail(char_u *p, char_u *val) * Functions for getting characters from the regexp input. */ -static int at_start; /* True when on the first character */ -static int prev_at_start; /* True when on the second character */ - /* * Start parsing at "str". */ diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index f97dce9e0d..92dbd693ea 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -1096,6 +1096,7 @@ static int nfa_regatom(void) int startc = -1; int endc = -1; int oldstartc = -1; + int save_prev_at_start = prev_at_start; c = getchr(); switch (c) { @@ -1412,18 +1413,22 @@ static int nfa_regatom(void) c = getchr(); } if (c == 'l' || c == 'c' || c == 'v') { - if (c == 'l') - /* \%{n}l \%{n}<l \%{n}>l */ + if (c == 'l') { + // \%{n}l \%{n}<l \%{n}>l EMIT(cmp == '<' ? NFA_LNUM_LT : - cmp == '>' ? NFA_LNUM_GT : NFA_LNUM); - else if (c == 'c') - /* \%{n}c \%{n}<c \%{n}>c */ + cmp == '>' ? NFA_LNUM_GT : NFA_LNUM); + if (save_prev_at_start) { + at_start = true; + } + } else if (c == 'c') { + // \%{n}c \%{n}<c \%{n}>c EMIT(cmp == '<' ? NFA_COL_LT : - cmp == '>' ? NFA_COL_GT : NFA_COL); - else - /* \%{n}v \%{n}<v \%{n}>v */ + cmp == '>' ? NFA_COL_GT : NFA_COL); + } else { + // \%{n}v \%{n}<v \%{n}>v EMIT(cmp == '<' ? NFA_VCOL_LT : - cmp == '>' ? NFA_VCOL_GT : NFA_VCOL); + cmp == '>' ? NFA_VCOL_GT : NFA_VCOL); + } EMIT(n); break; } else if (c == '\'' && n == 0) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 34eef83164..d67142822f 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3416,12 +3416,10 @@ win_line ( /* * Handling of non-printable characters. */ - if (!(chartab[c & 0xff] & CT_PRINT_CHAR)) { - /* - * when getting a character from the file, we may have to - * turn it into something else on the way to putting it - * into "ScreenLines". - */ + if (!vim_isprintc(c)) { + // when getting a character from the file, we may have to + // turn it into something else on the way to putting it + // into "ScreenLines". if (c == TAB && (!wp->w_p_list || lcs_tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 27855184df..3215f7ea14 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5661,6 +5661,24 @@ int get_syntax_info(int *seqnrp) return current_flags; } + +/// Get the sequence number of the concealed file position. +/// +/// @return seqnr if the file position is concealed, 0 otherwise. +int syn_get_concealed_id(win_T *wp, linenr_T lnum, colnr_T col) +{ + int seqnr; + int syntax_flags; + + (void)syn_get_id(wp, lnum, col, false, NULL, false); + syntax_flags = get_syntax_info(&seqnr); + + if (syntax_flags & HL_CONCEAL) { + return seqnr; + } + return 0; +} + /* * Return conceal substitution character */ diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index fd416b3dcc..6f50c03be9 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -241,6 +241,7 @@ Terminal *terminal_open(TerminalOptions opts) set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL); + buf_set_term_title(curbuf, (char *)curbuf->b_ffname); RESET_BINDING(curwin); // Apply TermOpen autocmds so the user can configure the terminal apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf); @@ -618,6 +619,17 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible, return 1; } +static void buf_set_term_title(buf_T *buf, char *title) + FUNC_ATTR_NONNULL_ALL +{ + Error err; + api_free_object(dict_set_value(buf->b_vars, + cstr_as_string("term_title"), + STRING_OBJ(cstr_as_string(title)), + false, + &err)); +} + static int term_settermprop(VTermProp prop, VTermValue *val, void *data) { Terminal *term = data; @@ -633,12 +645,7 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) case VTERM_PROP_TITLE: { buf_T *buf = handle_get_buffer(term->buf_handle); - Error err; - api_free_object(dict_set_value(buf->b_vars, - cstr_as_string("term_title"), - STRING_OBJ(cstr_as_string(val->string)), - false, - &err)); + buf_set_term_title(buf, val->string); break; } diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 4b0b5e8d26..4979aae57a 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -14,7 +14,6 @@ SCRIPTS := \ test14.out \ test17.out \ test24.out \ - test30.out \ test32.out \ test37.out \ test40.out \ @@ -33,15 +32,14 @@ SCRIPTS := \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ - test_cursor_func.res \ test_hardcopy.res \ test_help_tagjump.res \ test_langmap.res \ - test_menu.res \ test_syntax.res \ test_timers.res \ - test_unlet.res \ test_viml.res \ + test_visual.res \ + test_window_id.res \ test_alot.res SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 1b1f5d7688..74bbf418fa 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -2,6 +2,11 @@ " When the script is successful the .res file will be created. " Errors are appended to the test.log file. " +" To execute only specific test functions, add a second argument. It will be +" matched against the names of the Test_ function. E.g.: +" ../vim -u NONE -S runtest.vim test_channel.vim open_delay +" The output can be found in the "messages" file. +" " The test script may contain anything, only functions that start with " "Test_" are special. These will be invoked and should contain assert " functions. See test_assert.vim for an example. @@ -68,6 +73,11 @@ silent function /^Test_ redir END let tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) +" If there is an extra argument filter the function names against it. +if argc() > 1 + let tests = filter(tests, 'v:val =~ argv(1)') +endif + " Execute the tests in alphabetical order. for test in sort(tests) echo 'Executing ' . test diff --git a/src/nvim/testdir/test30.in b/src/nvim/testdir/test30.in deleted file mode 100644 index 56d5d5c6c2..0000000000 --- a/src/nvim/testdir/test30.in +++ /dev/null @@ -1,230 +0,0 @@ -Test for a lot of variations of the 'fileformats' option - -Note: This test will fail if "cat" is not available. - -STARTTEST -:" first write three test files, one in each format -:set fileformat=unix -:set fileformats= -:/^unix/;/eof/-1w! XXUnix -:/^dos/;/eof/-1w! XXDos -:set bin noeol -:$w! XXMac -Gonoeol -:$w! XXEol -:set nobin eol -:enew! -:bwipe XXUnix XXDos XXMac -:" create mixed format files -:if has("win32") -: !copy /b XXUnix+XXDos XXUxDs -: !copy /b XXUnix+XXMac XXUxMac -: !copy /b XXDos+XXMac XXDosMac -: !copy /b XXMac+XXEol XXMacEol -: !copy /b XXUnix+XXDos+XXMac XXUxDsMc -:else -: !cat XXUnix XXDos >XXUxDs -: !cat XXUnix XXMac >XXUxMac -: !cat XXDos XXMac >XXDosMac -: !cat XXMac XXEol >XXMacEol -: !cat XXUnix XXDos XXMac >XXUxDsMc -:endif -:" -:" try reading and writing with 'fileformats' empty -:set fileformat=unix -:e! XXUnix -:w! test.out -:e! XXDos -:w! XXtt01 -:e! XXMac -:w! XXtt02 -:bwipe XXUnix XXDos XXMac -:set fileformat=dos -:e! XXUnix -:w! XXtt11 -:e! XXDos -:w! XXtt12 -:e! XXMac -:w! XXtt13 -:bwipe XXUnix XXDos XXMac -:set fileformat=mac -:e! XXUnix -:w! XXtt21 -:e! XXDos -:w! XXtt22 -:e! XXMac -:w! XXtt23 -:bwipe XXUnix XXDos XXMac -:" -:" try reading and writing with 'fileformats' set to one format -:set fileformats=unix -:e! XXUxDsMc -:w! XXtt31 -:bwipe XXUxDsMc -:set fileformats=dos -:e! XXUxDsMc -:w! XXtt32 -:bwipe XXUxDsMc -:set fileformats=mac -:e! XXUxDsMc -:w! XXtt33 -:bwipe XXUxDsMc -:" -:" try reading and writing with 'fileformats' set to two formats -:set fileformats=unix,dos -:e! XXUxDsMc -:w! XXtt41 -:bwipe XXUxDsMc -:e! XXUxMac -:w! XXtt42 -:bwipe XXUxMac -:e! XXDosMac -:w! XXtt43 -:bwipe XXDosMac -:set fileformats=unix,mac -:e! XXUxDs -:w! XXtt51 -:bwipe XXUxDs -:e! XXUxDsMc -:w! XXtt52 -:bwipe XXUxDsMc -:e! XXDosMac -:w! XXtt53 -:bwipe XXDosMac -:e! XXEol -ggO=&ffs -:=&ff -:w! XXtt54 -:bwipe XXEol -:set fileformats=dos,mac -:e! XXUxDs -:w! XXtt61 -:bwipe XXUxDs -:e! XXUxMac -ggO=&ffs -:=&ff -:w! XXtt62 -:bwipe XXUxMac -:e! XXUxDsMc -:w! XXtt63 -:bwipe XXUxDsMc -:e! XXMacEol -ggO=&ffs -:=&ff -:w! XXtt64 -:bwipe XXMacEol -:" -:" try reading and writing with 'fileformats' set to three formats -:set fileformats=unix,dos,mac -:e! XXUxDsMc -:w! XXtt71 -:bwipe XXUxDsMc -:e! XXEol -ggO=&ffs -:=&ff -:w! XXtt72 -:bwipe XXEol -:set fileformats=mac,dos,unix -:e! XXUxDsMc -:w! XXtt81 -:bwipe XXUxDsMc -:e! XXEol -ggO=&ffs -:=&ff -:w! XXtt82 -:bwipe XXEol -:" try with 'binary' set -:set fileformats=mac,unix,dos -:set binary -:e! XXUxDsMc -:w! XXtt91 -:bwipe XXUxDsMc -:set fileformats=mac -:e! XXUxDsMc -:w! XXtt92 -:bwipe XXUxDsMc -:set fileformats=dos -:e! XXUxDsMc -:w! XXtt93 -:" -:" Append "END" to each file so that we can see what the last written char was. -:set fileformat=unix nobin -ggdGaEND:w >>XXtt01 -:w >>XXtt02 -:w >>XXtt11 -:w >>XXtt12 -:w >>XXtt13 -:w >>XXtt21 -:w >>XXtt22 -:w >>XXtt23 -:w >>XXtt31 -:w >>XXtt32 -:w >>XXtt33 -:w >>XXtt41 -:w >>XXtt42 -:w >>XXtt43 -:w >>XXtt51 -:w >>XXtt52 -:w >>XXtt53 -:w >>XXtt54 -:w >>XXtt61 -:w >>XXtt62 -:w >>XXtt63 -:w >>XXtt64 -:w >>XXtt71 -:w >>XXtt72 -:w >>XXtt81 -:w >>XXtt82 -:w >>XXtt91 -:w >>XXtt92 -:w >>XXtt93 -:" -:" Concatenate the results. -:" Make fileformat of test.out the native fileformat. -:" Add a newline at the end. -:set binary -:e! test.out -:$r XXtt01 -:$r XXtt02 -Go1:$r XXtt11 -:$r XXtt12 -:$r XXtt13 -Go2:$r XXtt21 -:$r XXtt22 -:$r XXtt23 -Go3:$r XXtt31 -:$r XXtt32 -:$r XXtt33 -Go4:$r XXtt41 -:$r XXtt42 -:$r XXtt43 -Go5:$r XXtt51 -:$r XXtt52 -:$r XXtt53 -:$r XXtt54 -Go6:$r XXtt61 -:$r XXtt62 -:$r XXtt63 -:$r XXtt64 -Go7:$r XXtt71 -:$r XXtt72 -Go8:$r XXtt81 -:$r XXtt82 -Go9:$r XXtt91 -:$r XXtt92 -:$r XXtt93 -Go10:$r XXUnix -:set nobinary ff& -:w -:qa! -ENDTEST - -unix -unix -eof - -dos
-dos
-eof - -mac
mac
diff --git a/src/nvim/testdir/test30.ok b/src/nvim/testdir/test30.ok deleted file mode 100644 index b35f4f5904..0000000000 --- a/src/nvim/testdir/test30.ok +++ /dev/null @@ -1,130 +0,0 @@ -unix -unix -dos
-dos
-END -mac
mac
-END -1 -unix
-unix
-END -dos
-dos
-END -mac
mac
-END -2 -unix -unix -
END -dos
-dos
-
END -mac
mac
END -3 -unix -unix -dos
-dos
-mac
mac
-END -unix
-unix
-dos
-dos
-mac
mac
-END -unix -unix -dos
-dos
-mac
mac
END -4 -unix -unix -dos
-dos
-mac
mac
-END -unix -unix -mac
mac
-END -dos
-dos
-mac
mac
-END -5 -unix -unix -dos
-dos
-END -unix -unix -dos
-dos
-mac
mac
-END -dos
-dos
-mac
mac
END -unix,mac:unix -noeol -END -6 -unix
-unix
-dos
-dos
-END -dos,mac:dos
-unix
-unix
-mac
mac
-END -unix
-unix
-dos
-dos
-mac
mac
-END -dos,mac:mac
mac
mac
noeol
END -7 -unix -unix -dos
-dos
-mac
mac
-END -unix,dos,mac:unix -noeol -END -8 -unix -unix -dos
-dos
-mac
mac
-END -mac,dos,unix:mac
noeol
END -9 -unix -unix -dos
-dos
-mac
mac
END -unix -unix -dos
-dos
-mac
mac
END -unix -unix -dos
-dos
-mac
mac
END -10 -unix -unix diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 1d1da94bac..30b8a9ceb8 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -1,3 +1,9 @@ " A series of tests that can run in one Vim invocation. " This makes testing go faster, since Vim doesn't need to restart. +source test_assign.vim +source test_cursor_func.vim +source test_cmdline.vim +source test_menu.vim +source test_popup.vim +source test_unlet.vim diff --git a/src/nvim/testdir/test_assign.vim b/src/nvim/testdir/test_assign.vim new file mode 100644 index 0000000000..3d2e7a8998 --- /dev/null +++ b/src/nvim/testdir/test_assign.vim @@ -0,0 +1,9 @@ +" Test for assignment + +func Test_no_type_checking() + let v = 1 + let v = [1,2,3] + let v = {'a':1, 'b':2} + let v = 3.4 + let v = 'hello' +endfunc diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim new file mode 100644 index 0000000000..438b20cc5e --- /dev/null +++ b/src/nvim/testdir/test_cmdline.vim @@ -0,0 +1,120 @@ +" Tests for editing the command line. + +func Test_complete_tab() + call writefile(['testfile'], 'Xtestfile') + call feedkeys(":e Xtest\t\r", "tx") + call assert_equal('testfile', getline(1)) + call delete('Xtestfile') +endfunc + +func Test_complete_list() + " We can't see the output, but at least we check the code runs properly. + call feedkeys(":e test\<C-D>\r", "tx") + call assert_equal('test', expand('%:t')) +endfunc + +func Test_complete_wildmenu() + call writefile(['testfile1'], 'Xtestfile1') + call writefile(['testfile2'], 'Xtestfile2') + set wildmenu + call feedkeys(":e Xtest\t\t\r", "tx") + call assert_equal('testfile2', getline(1)) + + call delete('Xtestfile1') + call delete('Xtestfile2') + set nowildmenu +endfunc + +func Test_getcompletion() + if !has('cmdline_compl') + return + endif + let groupcount = len(getcompletion('', 'event')) + call assert_true(groupcount > 0) + let matchcount = len(getcompletion('File', 'event')) + call assert_true(matchcount > 0) + call assert_true(groupcount > matchcount) + + if has('menu') + source $VIMRUNTIME/menu.vim + let matchcount = len(getcompletion('', 'menu')) + call assert_true(matchcount > 0) + call assert_equal(['File.'], getcompletion('File', 'menu')) + call assert_true(matchcount > 0) + let matchcount = len(getcompletion('File.', 'menu')) + call assert_true(matchcount > 0) + endif + + let l = getcompletion('v:n', 'var') + call assert_true(index(l, 'v:null') >= 0) + + let l = getcompletion('', 'augroup') + call assert_true(index(l, 'END') >= 0) + + let l = getcompletion('', 'behave') + call assert_true(index(l, 'mswin') >= 0) + + let l = getcompletion('', 'color') + call assert_true(index(l, 'default') >= 0) + + let l = getcompletion('', 'command') + call assert_true(index(l, 'sleep') >= 0) + + let l = getcompletion('', 'dir') + call assert_true(index(l, 'sautest') >= 0) + + let l = getcompletion('exe', 'expression') + call assert_true(index(l, 'executable(') >= 0) + + let l = getcompletion('tag', 'function') + call assert_true(index(l, 'taglist(') >= 0) + + let l = getcompletion('run', 'file') + call assert_true(index(l, 'runtest.vim') >= 0) + + let l = getcompletion('ha', 'filetype') + call assert_true(index(l, 'hamster') >= 0) + + let l = getcompletion('z', 'syntax') + call assert_true(index(l, 'zimbu') >= 0) + + let l = getcompletion('jikes', 'compiler') + call assert_true(index(l, 'jikes') >= 0) + + let l = getcompletion('time', 'option') + call assert_true(index(l, 'timeoutlen') >= 0) + + let l = getcompletion('er', 'highlight') + call assert_true(index(l, 'ErrorMsg') >= 0) + + " For others test if the name is recognized. + let names = ['buffer', 'environment', 'file_in_path', + \ 'mapping', 'shellcmd', 'tag', 'tag_listfiles', 'user'] + if has('cscope') + call add(names, 'cscope') + endif + if has('cmdline_hist') + call add(names, 'history') + endif + if has('gettext') + call add(names, 'locale') + endif + if has('profile') + call add(names, 'syntime') + endif + if has('signs') + call add(names, 'sign') + endif + + set tags=Xtags + call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", "word\tfile\tcmd"], 'Xtags') + + for name in names + let matchcount = len(getcompletion('', name)) + call assert_true(matchcount >= 0, 'No matches for ' . name) + endfor + + call delete('Xtags') + + call assert_fails('call getcompletion("", "burp")', 'E475:') +endfunc diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim new file mode 100644 index 0000000000..78fc81e3d2 --- /dev/null +++ b/src/nvim/testdir/test_popup.vim @@ -0,0 +1,30 @@ +" Test for completion menu + +function! ComplTest() abort + call complete(1, ['source', 'soundfold']) + return '' +endfunction + +function! Test() abort + call complete(1, ['source', 'soundfold']) + return '' +endfunction + +func Test_noinsert_complete() + new + set completeopt+=noinsert + inoremap <F5> <C-R>=ComplTest()<CR> + call feedkeys("i\<F5>soun\<CR>\<CR>\<ESC>.", 'tx') + call assert_equal('soundfold', getline(1)) + call assert_equal('soundfold', getline(2)) + bwipe! + + new + inoremap <F5> <C-R>=Test()<CR> + call feedkeys("i\<F5>\<CR>\<ESC>", 'tx') + call assert_equal('source', getline(1)) + bwipe! + + set completeopt-=noinsert + iunmap <F5> +endfunc diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_viml.vim index 2d989cdad9..c39c5e6b28 100644 --- a/src/nvim/testdir/test_viml.vim +++ b/src/nvim/testdir/test_viml.vim @@ -55,16 +55,26 @@ endfunction " ExecAsScript - Source a temporary script made from a function. {{{2 " " Make a temporary script file from the function a:funcname, ":source" it, and -" delete it afterwards. +" delete it afterwards. However, if an exception is thrown the file may remain, +" the caller should call DeleteTheScript() afterwards. +let s:script_name = '' function! ExecAsScript(funcname) " Make a script from the function passed as argument. - let script = MakeScript(a:funcname) + let s:script_name = MakeScript(a:funcname) " Source and delete the script. - exec "source" script - call delete(script) + exec "source" s:script_name + call delete(s:script_name) + let s:script_name = '' endfunction +function! DeleteTheScript() + if s:script_name + call delete(s:script_name) + let s:script_name = '' + endif +endfunc + com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>) @@ -143,6 +153,7 @@ func Test_endwhile_script() XpathINIT ExecAsScript T1_F Xpath 'F' + call DeleteTheScript() try ExecAsScript T1_G @@ -152,6 +163,7 @@ func Test_endwhile_script() Xpath 'x' endtry Xpath 'G' + call DeleteTheScript() call assert_equal('abcFhijxG', g:Xpath) endfunc @@ -260,6 +272,7 @@ function Test_finish() XpathINIT ExecAsScript T4_F Xpath '5' + call DeleteTheScript() call assert_equal('ab3e3b2c25', g:Xpath) endfunction diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim new file mode 100644 index 0000000000..83bae967e2 --- /dev/null +++ b/src/nvim/testdir/test_visual.vim @@ -0,0 +1,18 @@ +" Tests for Visual mode +if !has('multi_byte') + finish +endif +scriptencoding utf-8 + +if !has('visual') + finish +endif + +func Test_block_shift_multibyte() + split + call setline(1, ['xヹxxx', 'ヹxxx']) + exe "normal 1G0l\<C-V>jl>" + call assert_equal('x ヹxxx', getline(1)) + call assert_equal(' ヹxxx', getline(2)) + q! +endfunc diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim new file mode 100644 index 0000000000..b9e9f45c49 --- /dev/null +++ b/src/nvim/testdir/test_window_id.vim @@ -0,0 +1,71 @@ +" Test using the window ID. + +func Test_win_getid() + edit one + let id1 = win_getid() + split two + let id2 = win_getid() + split three + let id3 = win_getid() + tabnew + edit four + let id4 = win_getid() + split five + let id5 = win_getid() + tabnext + + wincmd w + call assert_equal("two", expand("%")) + call assert_equal(id2, win_getid()) + let nr2 = winnr() + wincmd w + call assert_equal("one", expand("%")) + call assert_equal(id1, win_getid()) + let nr1 = winnr() + wincmd w + call assert_equal("three", expand("%")) + call assert_equal(id3, win_getid()) + let nr3 = winnr() + tabnext + call assert_equal("five", expand("%")) + call assert_equal(id5, win_getid()) + let nr5 = winnr() + wincmd w + call assert_equal("four", expand("%")) + call assert_equal(id4, win_getid()) + let nr4 = winnr() + tabnext + + exe nr1 . "wincmd w" + call assert_equal(id1, win_getid()) + exe nr2 . "wincmd w" + call assert_equal(id2, win_getid()) + exe nr3 . "wincmd w" + call assert_equal(id3, win_getid()) + tabnext + exe nr4 . "wincmd w" + call assert_equal(id4, win_getid()) + exe nr5 . "wincmd w" + call assert_equal(id5, win_getid()) + + call win_gotoid(id2) + call assert_equal("two", expand("%")) + call win_gotoid(id4) + call assert_equal("four", expand("%")) + call win_gotoid(id1) + call assert_equal("one", expand("%")) + call win_gotoid(id5) + call assert_equal("five", expand("%")) + + call assert_equal(0, win_id2win(9999)) + call assert_equal(nr5, win_id2win(id5)) + call assert_equal(0, win_id2win(id1)) + tabnext + call assert_equal(nr1, win_id2win(id1)) + + call assert_equal([0, 0], win_id2tabwin(9999)) + call assert_equal([1, nr2], win_id2tabwin(id2)) + call assert_equal([2, nr4], win_id2tabwin(id4)) + + only! +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 53551d81cf..aa337f9fae 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -75,29 +75,608 @@ static char *features[] = { // clang-format off static int included_patches[] = { + // 2200, + // 2199, + // 2198, + // 2197, + // 2196, + // 2195, + // 2194, + // 2193, + // 2192, + // 2191, + // 2190, + // 2189, + // 2188, + // 2187, + // 2186, + // 2185, + // 2184, + // 2183, + // 2182, + // 2181, + // 2180, + // 2179, + // 2178, + // 2177, + // 2176, + // 2175, + // 2174, + // 2173, + // 2172, + // 2171, + // 2170, + // 2169, + // 2168, + // 2167, + // 2166, + // 2165, + // 2164, + // 2163, + // 2162, + // 2161, + // 2160, + // 2159, + // 2158, + // 2157, + // 2156, + // 2155, + // 2154, + // 2153, + // 2152, + // 2151, + // 2150, + // 2149, + // 2148, + // 2147, + // 2146, + // 2145, + // 2144, + // 2143, + // 2142, + // 2141, + // 2140, + // 2139, + // 2138, + // 2137, + // 2136, + // 2135, + // 2134, + // 2133, + // 2132, + // 2131, + // 2130, + // 2129, + // 2128, + // 2127, + // 2126, + // 2125, + // 2124, + // 2123, + // 2122, + // 2121, + // 2120, + // 2119, + // 2118, + // 2117, + // 2116, + // 2115, + // 2114, + // 2113, + // 2112, + // 2111, + // 2110, + // 2109, + // 2108, + // 2107, + // 2106, + // 2105 NA + // 2104, + // 2103, + // 2102 NA + // 2101, + // 2100, + // 2099, + // 2098, + // 2097, + // 2096, + // 2095, + // 2094, + // 2093, + // 2092 NA + // 2091 NA + // 2090, + // 2089 NA + // 2088, + // 2087, + // 2086, + // 2085, + // 2084, + // 2083, + // 2082, + // 2081, + // 2080, + // 2079 NA + // 2078 NA + // 2077, + // 2076, + // 2075, + // 2074, + // 2073, + // 2072, + // 2071, + // 2070 NA + // 2069, + // 2068, + // 2067, + 2066, + // 2065, + // 2064, + // 2063 NA + // 2062, + // 2061, + // 2060 NA + // 2059 NA + // 2058, + // 2057 NA + // 2056 NA + // 2055 NA + // 2054 NA + // 2053 NA + // 2052 NA + // 2051, + // 2050, + // 2049, + // 2048 NA + // 2047, + // 2046, + // 2045 NA + // 2044, + // 2043, + // 2042 NA + // 2041 NA + // 2040 NA + // 2039 NA + // 2038 NA + // 2037 NA + // 2036, + // 2035 NA + // 2034 NA + // 2033, + // 2032 NA + // 2031, + // 2030 NA + // 2029, + // 2028, + // 2027 NA + // 2026 NA + // 2025 NA + // 2024, + // 2023, + // 2022, + // 2021, + // 2020 NA + // 2019, + // 2018, + // 2017, + // 2016 NA + // 2015, + 2014, + 2013, + 2012, + 2011, + // 2010, + // 2009, + // 2008, + // 2007, + // 2006, + // 2005, + // 2004 NA + // 2003 NA + // 2002, + // 2001 NA + // 2000, + // 1999, + // 1998 NA + // 1997, + // 1996, + // 1995 NA + // 1994, + // 1993, + // 1992, + // 1991, + // 1990, + // 1989, + // 1988 NA + // 1987 NA + // 1986, + // 1985 NA + // 1984, + // 1983 NA + // 1982 NA + // 1981, + // 1980, + // 1979, + // 1978, + // 1977, + // 1976, + // 1975, + // 1974 NA 1973, + // 1972, + // 1971, + // 1970, + // 1969 NA + // 1968, + // 1967, + // 1966, + // 1965 NA + // 1964, + // 1963 NA + // 1962, + // 1961, 1960, + // 1959 NA + // 1958 NA + // 1957 NA + // 1956, + // 1955, + // 1954, + // 1953, + // 1952, + // 1951 NA + // 1950, + // 1949, + // 1948, + // 1947 NA + // 1946 NA + // 1945, + // 1944 NA + // 1943 NA + // 1942 NA + // 1941, + // 1940, + // 1939 NA + // 1938 NA + // 1937, + // 1936, + // 1935 NA + // 1934 NA + // 1933 NA + // 1932 NA + // 1931 NA + // 1930 NA + // 1929 NA + // 1928, + // 1927 NA + // 1926 NA + // 1925 NA + // 1924 NA + // 1923, + // 1922 NA + // 1921 NA + // 1920 NA + // 1919 NA + // 1918 NA + // 1917 NA + // 1916 NA + // 1915 NA + // 1914, + // 1913, + // 1912, + // 1911, + // 1910, + // 1909, + // 1908 NA + // 1907, + // 1906 NA + // 1905, + // 1904, + // 1903, + // 1902 NA + // 1901 NA + // 1900, + // 1899 NA + // 1898, + // 1897, + // 1896, + // 1895, + // 1894 NA + // 1893, + // 1892 NA + // 1891 NA + // 1890 NA + // 1889, + // 1888, + // 1887 NA + // 1886 NA + // 1885 NA + // 1884, + // 1883 NA + // 1882, + // 1881, + // 1880 NA + // 1879 NA + // 1878 NA + // 1877 NA + // 1876, + // 1875, + // 1874 NA + // 1873 NA + // 1872 NA + // 1871, + // 1870 NA + // 1869 NA + // 1868, + // 1867, + // 1866, + // 1865 NA + // 1864 NA + // 1863 NA + // 1862, + // 1861, + // 1860 NA + // 1859 NA + // 1858 NA + // 1857 NA + // 1856 NA + // 1855 NA + // 1854 NA + // 1853 NA + // 1852 NA + // 1851, + // 1850 NA + // 1849 NA + // 1848 NA + // 1847, + // 1846 NA + // 1845 NA + // 1844, + // 1843 NA + // 1842, + // 1841, 1840, + // 1839, + // 1838, + // 1837, + // 1836, + // 1835, + // 1834, + // 1833, 1832, 1831, + // 1830 NA + // 1829 NA + // 1828 NA + // 1827 NA + // 1826 NA + // 1825 NA + // 1824 NA + // 1823, + // 1822 NA + // 1821, + // 1820, + // 1819 NA + // 1818, + // 1817 NA + // 1816, + // 1815, + // 1814 NA + // 1813, + // 1812, + // 1811, + // 1810 NA 1809, 1808, + // 1807 NA 1806, + // 1805, + // 1804, + // 1803 NA + // 1802, + // 1801 NA + // 1800 NA 1799, + // 1798 NA + // 1797 NA + // 1796 NA + // 1795 NA + // 1794, + // 1793, + // 1792 NA + // 1791 NA + // 1790 NA + // 1789 NA + // 1789 NA + // 1788 NA + // 1787 NA + // 1786 NA + // 1785, + // 1784 NA + // 1783, + // 1782, + // 1781, + // 1780, + // 1779, + // 1778 NA + // 1777 NA + // 1776 NA + // 1775 NA + // 1774 NA + // 1773 NA + // 1772 NA + // 1771 NA + // 1770, + // 1769, + // 1768, + // 1767 NA + // 1766 NA + // 1765, + // 1764 NA + // 1763, + // 1762, + // 1761, + // 1760 NA + // 1759, + // 1758, 1757, + // 1756 NA 1755, + // 1754, 1753, + // 1753, + // 1752, + // 1751, + // 1750, + // 1749 NA + // 1748, + // 1747 NA + // 1746 NA + // 1745 NA + // 1744 NA + // 1743 NA + // 1742, + // 1741, + // 1740, + // 1739, + // 1738, + // 1737 NA + // 1736 NA + // 1735, + // 1734, + // 1733 NA + 1732, + // 1731, + // 1730, + // 1729 NA 1728, + // 1727, + // 1726 NA + // 1725 NA + // 1724 NA + // 1723, + // 1722 NA + // 1721 NA + // 1720, + // 1719, + // 1718, + // 1717 NA 1716, + // 1715, + // 1714, + // 1713 NA 1712, + // 1711, + // 1710, + // 1709 NA + // 1708, + // 1707, + // 1706 NA + // 1705 NA + // 1704, + 1703, + // 1702, + // 1701, + // 1700, + // 1699, + // 1698 NA + // 1697, + // 1696, 1695, + // 1694 NA + // 1693 NA + // 1692, + // 1691, + // 1690 NA + // 1689 NA + // 1688 NA + // 1687 NA + // 1686, + // 1685, + // 1684 NA + // 1683 NA + 1682, + // 1681, + // 1680 NA + // 1679, + // 1678 NA + // 1677 NA + 1676, + 1675, + // 1674 NA + 1673, + // 1672 NA + // 1671, + // 1670, + // 1669 NA + // 1668 NA + // 1667 NA + // 1666 NA + // 1665 NA + // 1664, + 1663, + // 1662 NA + // 1661 NA + // 1660, + // 1659 NA + // 1658, + // 1657 NA + // 1656, + // 1655 NA 1654, + // 1653, 1652, + // 1651 NA + // 1650, 1649, + // 1648, + // 1647, + // 1646 NA + // 1645, + // 1644, 1643, + // 1642, 1641, + // 1640, + // 1639, + // 1638, + // 1637 NA + // 1636 NA + // 1635 NA + // 1634, + // 1633 NA + // 1632 NA + // 1631 NA + // 1630, + // 1629, + // 1628 NA + // 1627 NA + // 1626 NA + // 1625 NA // 1624 NA - + // 1623 NA + // 1622 NA + // 1621 NA + // 1620, + // 1619, + // 1618 NA + // 1617 NA + // 1616 NA + // 1615 NA + // 1614, + // 1613 NA + // 1612 NA + // 1611 NA + // 1610 NA + // 1609 NA + // 1608, + // 1607, + // 1606, + // 1605, + // 1604, + 1603, + // 1602 NA + // 1601 NA // 1600 NA // 1599 NA // 1598 NA @@ -117,7 +696,6 @@ static int included_patches[] = { // 1584 NA // 1583 NA // 1582, - // 1581, // 1580, // 1579 NA @@ -142,7 +720,7 @@ static int included_patches[] = { // 1560 NA // 1559, // 1558, - // 1557, + 1557, // 1556 NA // 1555 NA 1554, @@ -151,9 +729,9 @@ static int included_patches[] = { 1551, 1550, // 1549, - // 1548, + 1548, // 1547, - // 1546, + 1546, // 1545 NA // 1544 NA // 1543 NA @@ -208,7 +786,7 @@ static int included_patches[] = { // 1494, // 1493 NA 1492, - // 1491, + 1491, // 1490 NA // 1489 NA // 1488 NA @@ -243,7 +821,7 @@ static int included_patches[] = { // 1459 NA // 1458 NA // 1457 NA - // 1456, + // 1456 NA // 1455 NA // 1454 NA // 1453 NA @@ -334,7 +912,7 @@ static int included_patches[] = { // 1368 NA // 1367 NA 1366, - // 1365, + 1365, // 1364 NA // 1363 NA // 1362 NA @@ -394,7 +972,7 @@ static int included_patches[] = { // 1308 NA // 1307 NA // 1306 NA - // 1305, + 1305, 1304, // 1303 NA // 1302 NA @@ -426,7 +1004,7 @@ static int included_patches[] = { 1276, // 1275 NA // 1274 NA - // 1273, + // 1273 NA // 1272 NA 1271, // 1270 NA @@ -462,7 +1040,7 @@ static int included_patches[] = { // 1240 NA // 1239 NA // 1238 NA - // 1237, + 1237, 1236, // 1235 NA // 1234 NA @@ -513,14 +1091,14 @@ static int included_patches[] = { // 1189 NA // 1188 NA // 1187 NA - // 1186, + // 1186 NA // 1185 NA // 1184 NA // 1183 NA // 1182 NA 1181, 1180, - // 1179, + 1179, 1178, // 1177 NA // 1176 NA @@ -552,7 +1130,7 @@ static int included_patches[] = { 1150, 1149, // 1148 NA - // 1147, + 1147, // 1146 NA // 1145 NA 1144, @@ -625,7 +1203,7 @@ static int included_patches[] = { // 1077 NA 1076, 1075, - // 1074 NA, + // 1074 NA // 1073 NA 1072, 1071, @@ -668,7 +1246,7 @@ static int included_patches[] = { 1034, // 1033 NA 1032, - // 1031 NA, + // 1031 NA 1030, 1029, // 1028 NA @@ -689,15 +1267,15 @@ static int included_patches[] = { 1013, // 1012 NA // 1011 NA - // 1010 NA, + // 1010 NA // 1009 NA // 1008 NA 1007, 1006, - // 1005 NA, - // 1004 NA, - // 1003 NA, - // 1002 NA, + // 1005 NA + // 1004 NA + // 1003 NA + // 1002 NA 1001, 1000, // 999 NA diff --git a/src/nvim/window.c b/src/nvim/window.c index 1298248f1e..350b54d595 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3296,8 +3296,11 @@ void tabpage_move(int nr) tabpage_T *tp; tabpage_T *tp_dst; - if (first_tabpage->tp_next == NULL) + assert(curtab != NULL); + + if (first_tabpage->tp_next == NULL) { return; + } for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) { ++n; @@ -3680,6 +3683,8 @@ win_T *buf_jump_open_tab(buf_T *buf) return NULL; } +static int last_win_id = 0; + /* * Allocate a window structure and link it in the window list when "hidden" is * FALSE. @@ -3692,6 +3697,7 @@ static win_T *win_alloc(win_T *after, int hidden) win_T *new_wp = xcalloc(1, sizeof(win_T)); handle_register_window(new_wp); win_alloc_lines(new_wp); + new_wp->w_id = ++last_win_id; /* init w: variables */ new_wp->w_vars = dict_alloc(); @@ -5671,3 +5677,93 @@ static bool frame_check_width(frame_T *topfrp, int width) } return true; } + +int win_getid(typval_T *argvars) +{ + if (argvars[0].v_type == VAR_UNKNOWN) { + return curwin->w_id; + } + int winnr = get_tv_number(&argvars[0]); + win_T *wp; + if (winnr > 0) { + if (argvars[1].v_type == VAR_UNKNOWN) { + wp = firstwin; + } else { + tabpage_T *tp; + int tabnr = get_tv_number(&argvars[1]); + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + if (--tabnr == 0) { + break; + } + } + if (tp == NULL) { + return -1; + } + wp = tp->tp_firstwin; + } + for ( ; wp != NULL; wp = wp->w_next) { + if (--winnr == 0) { + return wp->w_id; + } + } + } + return 0; +} + +int win_gotoid(typval_T *argvars) +{ + win_T *wp; + tabpage_T *tp; + int id = get_tv_number(&argvars[0]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) { + if (wp->w_id == id) { + goto_tabpage_win(tp, wp); + return 1; + } + } + } + return 0; +} + +void win_id2tabwin(typval_T *argvars, list_T *list) +{ + win_T *wp; + tabpage_T *tp; + int winnr = 1; + int tabnr = 1; + int id = get_tv_number(&argvars[0]); + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + for (wp = tp == curtab ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) { + if (wp->w_id == id) { + list_append_number(list, tabnr); + list_append_number(list, winnr); + return; + } + winnr++; + } + tabnr++; + winnr = 1; + } + list_append_number(list, 0); + list_append_number(list, 0); +} + +int win_id2win(typval_T *argvars) +{ + win_T *wp; + int nr = 1; + int id = get_tv_number(&argvars[0]); + + for (wp = firstwin; wp != NULL; wp = wp->w_next) { + if (wp->w_id == id) { + return nr; + } + nr++; + } + return 0; +} diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index b4febe4bfb..15977b9777 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -308,6 +308,7 @@ describe('clipboard usage', function() end) it('links the "+ and unnamed registers', function() + eq('+', eval('v:register')) insert("one two") feed('^"+dwdw"+P') expect('two') @@ -335,6 +336,7 @@ describe('clipboard usage', function() eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['*']")) -- unnamedplus takes predecence when pasting + eq('+', eval('v:register')) execute("let g:test_clip['+'] = ['the plus','']") execute("let g:test_clip['*'] = ['the star','']") feed("p") diff --git a/test/functional/job/job_spec.lua b/test/functional/core/job_spec.lua index b54d5166ac..61ecdd1835 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1,4 +1,3 @@ - local helpers = require('test.functional.helpers')(after_each) local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim, nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear, @@ -120,7 +119,7 @@ describe('jobs', function() {0, {'a', '', 'c', '', '', '', 'b', '', ''}}}, next_msg()) end) - it('can preserve nuls', function() + it('can preserve NULs', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, ["\n123\n", "abc\\nxyz\n", ""])') eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}}, @@ -144,7 +143,7 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it("won't allow jobsend with a job that closed stdin", function() + it("disallows jobsend on a job that closed stdin", function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobclose(j, "stdin")') eq(false, pcall(function() @@ -152,12 +151,12 @@ describe('jobs', function() end)) end) - it('will not allow jobsend/stop on a non-existent job', function() + it('disallows jobsend/stop on a non-existent job', function() eq(false, pcall(eval, "jobsend(-1, 'lol')")) eq(false, pcall(eval, "jobstop(-1)")) end) - it('will not allow jobstop twice on the same job', function() + it('disallows jobstop twice on the same job', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") neq(0, eval('j')) eq(true, pcall(eval, "jobstop(j)")) @@ -244,7 +243,7 @@ describe('jobs', function() eq({'notification', 'exit', {45, 10}}, next_msg()) end) - it('cant redefine callbacks being used by a job', function() + it('cannot redefine callbacks being used by a job', function() local screen = Screen.new() screen:attach() local script = [[ @@ -467,3 +466,41 @@ describe('jobs', function() end) end) end) + +describe("pty process teardown", function() + local screen + before_each(function() + clear() + screen = Screen.new(30, 6) + screen:attach() + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + after_each(function() + screen:detach() + end) + + it("does not prevent/delay exit. #4798 #4900", function() + -- Use a nested nvim (in :term) to test without --headless. + execute(":terminal '"..helpers.nvim_prog + -- Use :term again in the _nested_ nvim to get a PTY process. + -- Use `sleep` to simulate a long-running child of the PTY. + .."' +terminal +'!(sleep 300 &)' +qa") + + -- Exiting should terminate all descendants (PTY, its children, ...). + screen:expect([[ + | + [Process exited 0] | + | + | + | + -- TERMINAL -- | + ]]) + end) +end) diff --git a/test/functional/eval/capture_spec.lua b/test/functional/eval/execute_spec.lua index d9265f1b5b..a91a04341f 100644 --- a/test/functional/eval/capture_spec.lua +++ b/test/functional/eval/execute_spec.lua @@ -9,16 +9,16 @@ local funcs = helpers.funcs local Screen = require('test.functional.ui.screen') local feed = helpers.feed -describe('capture()', function() +describe('execute()', function() before_each(clear) it('returns the same result with :redir', function() - eq(redir_exec('messages'), funcs.capture('messages')) + eq(redir_exec('messages'), funcs.execute('messages')) end) it('returns the output of the commands if the argument is List', function() - eq("foobar", funcs.capture({'echon "foo"', 'echon "bar"'})) - eq("\nfoo\nbar", funcs.capture({'echo "foo"', 'echo "bar"'})) + eq("foobar", funcs.execute({'echon "foo"', 'echon "bar"'})) + eq("\nfoo\nbar", funcs.execute({'echo "foo"', 'echo "bar"'})) end) it('supports the nested redirection', function() @@ -38,34 +38,34 @@ describe('capture()', function() return a endfunction ]]) - eq('foo', funcs.capture('call g:Bar()')) + eq('foo', funcs.execute('call g:Bar()')) - eq('42', funcs.capture([[echon capture("echon capture('echon 42')")]])) + eq('42', funcs.execute([[echon execute("echon execute('echon 42')")]])) end) it('returns the transformed string', function() - eq('^A', funcs.capture('echon "\\<C-a>"')) + eq('^A', funcs.execute('echon "\\<C-a>"')) end) it('returns the empty string if the argument list is empty', function() - eq('', funcs.capture({})) - eq(0, exc_exec('let g:ret = capture(v:_null_list)')) + eq('', funcs.execute({})) + eq(0, exc_exec('let g:ret = execute(v:_null_list)')) eq('', eval('g:ret')) end) it('returns the errors', function() local ret - ret = exc_exec('call capture(0.0)') + ret = exc_exec('call execute(0.0)') eq('Vim(call):E806: using Float as a String', ret) - ret = exc_exec('call capture(v:_null_dict)') + ret = exc_exec('call execute(v:_null_dict)') eq('Vim(call):E731: using Dictionary as a String', ret) - ret = exc_exec('call capture(function("tr"))') + ret = exc_exec('call execute(function("tr"))') eq('Vim(call):E729: using Funcref as a String', ret) - ret = exc_exec('call capture(["echo 42", 0.0, "echo 44"])') + ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])') eq('Vim(call):E806: using Float as a String', ret) - ret = exc_exec('call capture(["echo 42", v:_null_dict, "echo 44"])') + ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])') eq('Vim(call):E731: using Dictionary as a String', ret) - ret = exc_exec('call capture(["echo 42", function("tr"), "echo 44"])') + ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])') eq('Vim(call):E729: using Funcref as a String', ret) end) @@ -73,7 +73,7 @@ describe('capture()', function() local screen = Screen.new(20, 5) screen:attach() screen:set_default_attr_ignore({{bold=true, foreground=255}}) - feed(':let g:mes = capture("echon 42")<CR>') + feed(':let g:mes = execute("echon 42")<CR>') screen:expect([[ ^ | ~ | diff --git a/test/functional/fixtures/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim index 0935ea45ff..411e095c71 100644 --- a/test/functional/fixtures/autoload/provider/clipboard.vim +++ b/test/functional/fixtures/autoload/provider/clipboard.vim @@ -9,13 +9,12 @@ function! s:methods.get(reg) if g:cliperror return 0 end - let reg = a:reg == '"' ? '+' : a:reg if g:cliplossy " behave like pure text clipboard - return g:test_clip[reg][0] + return g:test_clip[a:reg][0] else " behave like VIMENC clipboard - return g:test_clip[reg] + return g:test_clip[a:reg] end endfunction diff --git a/test/functional/legacy/030_fileformats_spec.lua b/test/functional/legacy/030_fileformats_spec.lua new file mode 100644 index 0000000000..9bc62a375e --- /dev/null +++ b/test/functional/legacy/030_fileformats_spec.lua @@ -0,0 +1,375 @@ +-- Test for a lot of variations of the 'fileformats' option + +local helpers = require('test.functional.helpers')(after_each) +local feed, clear, execute = helpers.feed, helpers.clear, helpers.execute +local eq, write_file = helpers.eq, helpers.write_file + +describe('fileformats option', function() + setup(function() + clear() + local dos = 'dos\r\ndos\r\n' + local mac = 'mac\rmac\r' + local unix = 'unix\nunix\n' + local eol = 'noeol' + write_file('XXDos', dos) + write_file('XXMac', mac) + write_file('XXUnix', unix) + write_file('XXEol', eol) + write_file('XXDosMac', dos..mac) + write_file('XXMacEol', mac..eol) + write_file('XXUxDs', unix..dos) + write_file('XXUxDsMc', unix..dos..mac) + write_file('XXUxMac', unix..mac) + end) + + teardown(function() + os.remove('test.out') + os.remove('XXDos') + os.remove('XXMac') + os.remove('XXUnix') + os.remove('XXEol') + os.remove('XXDosMac') + os.remove('XXMacEol') + os.remove('XXUxDs') + os.remove('XXUxDsMc') + os.remove('XXUxMac') + for i = 0, 9 do + for j = 1, 4 do + os.remove('XXtt'..i..j) + end + end + end) + + it('is working', function() + + -- Try reading and writing with 'fileformats' empty. + execute('set fileformats=') + execute('set fileformat=unix') + execute('e! XXUnix') + execute('w! test.out') + execute('e! XXDos') + execute('w! XXtt01') + execute('e! XXMac') + execute('w! XXtt02') + execute('bwipe XXUnix XXDos XXMac') + execute('set fileformat=dos') + execute('e! XXUnix') + execute('w! XXtt11') + execute('e! XXDos') + execute('w! XXtt12') + execute('e! XXMac') + execute('w! XXtt13') + execute('bwipe XXUnix XXDos XXMac') + execute('set fileformat=mac') + execute('e! XXUnix') + execute('w! XXtt21') + execute('e! XXDos') + execute('w! XXtt22') + execute('e! XXMac') + execute('w! XXtt23') + execute('bwipe XXUnix XXDos XXMac') + + -- Try reading and writing with 'fileformats' set to one format. + execute('set fileformats=unix') + execute('e! XXUxDsMc') + execute('w! XXtt31') + execute('bwipe XXUxDsMc') + execute('set fileformats=dos') + execute('e! XXUxDsMc') + execute('w! XXtt32') + execute('bwipe XXUxDsMc') + execute('set fileformats=mac') + execute('e! XXUxDsMc') + execute('w! XXtt33') + execute('bwipe XXUxDsMc') + + -- Try reading and writing with 'fileformats' set to two formats. + execute('set fileformats=unix,dos') + execute('e! XXUxDsMc') + execute('w! XXtt41') + execute('bwipe XXUxDsMc') + execute('e! XXUxMac') + execute('w! XXtt42') + execute('bwipe XXUxMac') + execute('e! XXDosMac') + execute('w! XXtt43') + execute('bwipe XXDosMac') + execute('set fileformats=unix,mac') + execute('e! XXUxDs') + execute('w! XXtt51') + execute('bwipe XXUxDs') + execute('e! XXUxDsMc') + execute('w! XXtt52') + execute('bwipe XXUxDsMc') + execute('e! XXDosMac') + execute('w! XXtt53') + execute('bwipe XXDosMac') + execute('e! XXEol') + feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>') + execute('w! XXtt54') + execute('bwipe XXEol') + execute('set fileformats=dos,mac') + execute('e! XXUxDs') + execute('w! XXtt61') + execute('bwipe XXUxDs') + execute('e! XXUxMac') + feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>') + execute('w! XXtt62') + execute('bwipe XXUxMac') + execute('e! XXUxDsMc') + execute('w! XXtt63') + execute('bwipe XXUxDsMc') + execute('e! XXMacEol') + feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>') + execute('w! XXtt64') + execute('bwipe XXMacEol') + + -- Try reading and writing with 'fileformats' set to three formats. + execute('set fileformats=unix,dos,mac') + execute('e! XXUxDsMc') + execute('w! XXtt71') + execute('bwipe XXUxDsMc') + execute('e! XXEol') + feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>') + execute('w! XXtt72') + execute('bwipe XXEol') + execute('set fileformats=mac,dos,unix') + execute('e! XXUxDsMc') + execute('w! XXtt81') + execute('bwipe XXUxDsMc') + execute('e! XXEol') + feed('ggO<C-R>=&ffs<CR>:<C-R>=&ff<CR><ESC>') + execute('w! XXtt82') + execute('bwipe XXEol') + -- Try with 'binary' set. + execute('set fileformats=mac,unix,dos') + execute('set binary') + execute('e! XXUxDsMc') + execute('w! XXtt91') + execute('bwipe XXUxDsMc') + execute('set fileformats=mac') + execute('e! XXUxDsMc') + execute('w! XXtt92') + execute('bwipe XXUxDsMc') + execute('set fileformats=dos') + execute('e! XXUxDsMc') + execute('w! XXtt93') + + -- Append "END" to each file so that we can see what the last written + -- char was. + execute('set fileformat=unix nobin') + feed('ggdGaEND<esc>') + execute('w >>XXtt01') + execute('w >>XXtt02') + execute('w >>XXtt11') + execute('w >>XXtt12') + execute('w >>XXtt13') + execute('w >>XXtt21') + execute('w >>XXtt22') + execute('w >>XXtt23') + execute('w >>XXtt31') + execute('w >>XXtt32') + execute('w >>XXtt33') + execute('w >>XXtt41') + execute('w >>XXtt42') + execute('w >>XXtt43') + execute('w >>XXtt51') + execute('w >>XXtt52') + execute('w >>XXtt53') + execute('w >>XXtt54') + execute('w >>XXtt61') + execute('w >>XXtt62') + execute('w >>XXtt63') + execute('w >>XXtt64') + execute('w >>XXtt71') + execute('w >>XXtt72') + execute('w >>XXtt81') + execute('w >>XXtt82') + execute('w >>XXtt91') + execute('w >>XXtt92') + execute('w >>XXtt93') + + -- Concatenate the results. + -- Make fileformat of test.out the native fileformat. + -- Add a newline at the end. + execute('set binary') + execute('e! test.out') + execute('$r XXtt01') + execute('$r XXtt02') + feed('Go1<esc>') + execute('$r XXtt11') + execute('$r XXtt12') + execute('$r XXtt13') + feed('Go2<esc>') + execute('$r XXtt21') + execute('$r XXtt22') + execute('$r XXtt23') + feed('Go3<esc>') + execute('$r XXtt31') + execute('$r XXtt32') + execute('$r XXtt33') + feed('Go4<esc>') + execute('$r XXtt41') + execute('$r XXtt42') + execute('$r XXtt43') + feed('Go5<esc>') + execute('$r XXtt51') + execute('$r XXtt52') + execute('$r XXtt53') + execute('$r XXtt54') + feed('Go6<esc>') + execute('$r XXtt61') + execute('$r XXtt62') + execute('$r XXtt63') + execute('$r XXtt64') + feed('Go7<esc>') + execute('$r XXtt71') + execute('$r XXtt72') + feed('Go8<esc>') + execute('$r XXtt81') + execute('$r XXtt82') + feed('Go9<esc>') + execute('$r XXtt91') + execute('$r XXtt92') + execute('$r XXtt93') + feed('Go10<esc>') + execute('$r XXUnix') + execute('set nobinary ff&') + + -- Assert buffer contents. This has to be done manually as + -- helpers.expect() calls helpers.dedent() which messes up the white space + -- and carrige returns. + eq( + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'END\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + '1\n'.. + 'unix\r\n'.. + 'unix\r\n'.. + 'END\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'END\n'.. + 'mac\rmac\r\r\n'.. + 'END\n'.. + '2\n'.. + 'unix\n'.. + 'unix\n'.. + '\rEND\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + '\rEND\n'.. + 'mac\rmac\rEND\n'.. + '3\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'unix\r\n'.. + 'unix\r\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\r\n'.. + 'END\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\rEND\n'.. + '4\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'unix\n'.. + 'unix\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\r\n'.. + 'END\n'.. + '5\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'END\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\rEND\n'.. + 'unix,mac:unix\n'.. + 'noeol\n'.. + 'END\n'.. + '6\n'.. + 'unix\r\n'.. + 'unix\r\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'END\n'.. + 'dos,mac:dos\r\n'.. + 'unix\r\n'.. + 'unix\r\n'.. + 'mac\rmac\r\r\n'.. + 'END\n'.. + 'unix\r\n'.. + 'unix\r\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\r\n'.. + 'END\n'.. + 'dos,mac:mac\rmac\rmac\rnoeol\rEND\n'.. + '7\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'unix,dos,mac:unix\n'.. + 'noeol\n'.. + 'END\n'.. + '8\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\r\n'.. + 'END\n'.. + 'mac,dos,unix:mac\rnoeol\rEND\n'.. + '9\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\rEND\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\rEND\n'.. + 'unix\n'.. + 'unix\n'.. + 'dos\r\n'.. + 'dos\r\n'.. + 'mac\rmac\rEND\n'.. + '10\n'.. + 'unix\n'.. + 'unix', + helpers.curbuf_contents()) + end) +end) diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua index 3d5e69d1e5..9e67bb9429 100644 --- a/test/functional/legacy/036_regexp_character_classes_spec.lua +++ b/test/functional/legacy/036_regexp_character_classes_spec.lua @@ -268,4 +268,15 @@ describe('character classes in regexp', function() ABCDEFGHIXYZ ABCDEFGHIXYZ]]) end) + it([["\%1l^#.*" does not match on a line starting with "#". (vim-patch:7.4.1305)]], function() + source([[ + 1 s/\%#=0\%1l^\t...//g + 2 s/\%#=1\%2l^\t...//g + 3 s/\%#=2\%3l^\t...//g + 4 s/\%#=0\%4l^\t...//g + 5 s/\%#=1\%5l^\t...//g + 6 s/\%#=2\%6l^\t...//g]]) + diff(sixlines(string.sub(punct1, 1)..digits..punct2..upper..punct3.. + lower..punct4..ctrl2..iso_text)) + end) end) diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua index dee138e6d8..b9e5a8bc03 100644 --- a/test/functional/legacy/055_list_and_dict_types_spec.lua +++ b/test/functional/legacy/055_list_and_dict_types_spec.lua @@ -112,29 +112,6 @@ describe('list and dictionary types', function() expect('\n101101') end) - it('changing var type should fail', function() - source([[ - lang C - " The list from the first test repeated after splitting the tests. - let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] - " The dict from the first test repeated after splitting the tests. - let d = {'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}} - try - let d = [] - catch - $put =v:exception[:14] . v:exception[-1:-1] - endtry - try - let l = {} - catch - $put =v:exception[:14] . v:exception[-1:-1] - endtry]]) - expect([[ - - Vim(let):E706: d - Vim(let):E706: l]]) - end) - it('removing items with :unlet', function() source([[ lang C diff --git a/test/functional/legacy/101_hlsearch_spec.lua b/test/functional/legacy/101_hlsearch_spec.lua index 0d88e99278..fa29e5fbe8 100644 --- a/test/functional/legacy/101_hlsearch_spec.lua +++ b/test/functional/legacy/101_hlsearch_spec.lua @@ -61,6 +61,6 @@ describe('v:hlsearch', function() 0:not highlighted 1:highlighted 0:not highlighted - Vim(let):E706:]]) + Vim(let):E745:]]) end) end) diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 8da6ee45d7..42dd25023a 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -64,6 +64,20 @@ describe('assert function:', function() end) end) + -- assert_notequal({expected}, {actual}[, {msg}]) + describe('assert_notequal', function() + it('should not change v:errors when expected differs from actual', function() + call('assert_notequal', 'foo', 4) + call('assert_notequal', {1, 2, 3}, 'foo') + expected_empty() + end) + + it('should change v:errors when expected is equal to actual', function() + call('assert_notequal', 'foo', 'foo') + expected_errors({"Expected 'foo' differs from 'foo'"}) + end) + end) + -- assert_false({actual}, [, {msg}]) describe('assert_false', function() it('should not change v:errors when actual is false', function() @@ -155,10 +169,43 @@ describe('assert function:', function() end) end) + -- assert_match({pat}, {text}[, {msg}]) + describe('assert_match', function() + it('should not change v:errors when pat matches text', function() + call('assert_match', '^f.*b.*r$', 'foobar') + expected_empty() + end) + + it('should change v:errors when pat does not match text', function() + call('assert_match', 'bar.*foo', 'foobar') + expected_errors({"Pattern 'bar.*foo' does not match 'foobar'"}) + end) + + it('should set v:errors to msg when given and match fails', function() + call('assert_match', 'bar.*foo', 'foobar', 'wrong') + expected_errors({"'wrong'"}) + end) + end) + + -- assert_notmatch({pat}, {text}[, {msg}]) + describe('assert_notmatch', function() + it('should not change v:errors when pat does not match text', function() + call('assert_notmatch', 'foo', 'bar') + call('assert_notmatch', '^foobar$', 'foobars') + expected_empty() + end) + + it('should change v:errors when pat matches text', function() + call('assert_notmatch', 'foo', 'foobar') + expected_errors({"Pattern 'foo' does match 'foobar'"}) + end) + end) + -- assert_fails({cmd}, [, {error}]) describe('assert_fails', function() it('should change v:errors when error does not match v:errmsg', function() execute([[call assert_fails('xxx', {})]]) + execute([[call assert_match("Expected {} but got 'E731:", v:errors[0])]]) expected_errors({"Expected {} but got 'E731: using Dictionary as a String'"}) end) diff --git a/test/functional/legacy/writefile_spec.lua b/test/functional/legacy/writefile_spec.lua index f096aa23b9..765d373b82 100644 --- a/test/functional/legacy/writefile_spec.lua +++ b/test/functional/legacy/writefile_spec.lua @@ -17,6 +17,7 @@ describe('writefile', function() execute('bwipeout!') execute('$put =readfile(f)') execute('1 delete _') + execute('call delete(f)') -- Assert buffer contents. expect([[ diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua new file mode 100644 index 0000000000..7b0e17688d --- /dev/null +++ b/test/functional/provider/ruby_spec.lua @@ -0,0 +1,96 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local feed = helpers.feed +local clear = helpers.clear +local funcs = helpers.funcs +local meths = helpers.meths +local insert = helpers.insert +local expect = helpers.expect +local command = helpers.command +local write_file = helpers.write_file +local curbufmeths = helpers.curbufmeths + +do + clear() + command('let g:prog = provider#ruby#Detect()') + local prog = meths.get_var('prog') + + if prog == '' then + pending( + "Cannot find the neovim RubyGem. Try :CheckHealth", + function() end) + return + end +end + +before_each(function() + clear() +end) + +describe('ruby feature test', function() + it('works', function() + eq(1, funcs.has('ruby')) + end) +end) + +describe(':ruby command', function() + it('evaluates ruby', function() + command('ruby VIM.command("let g:set_by_ruby = [100, 0]")') + eq({100, 0}, meths.get_var('set_by_ruby')) + end) + + it('supports nesting', function() + command([[ruby VIM.command('ruby VIM.command("let set_by_nested_ruby = 555")')]]) + eq(555, meths.get_var('set_by_nested_ruby')) + end) +end) + +describe(':rubyfile command', function() + it('evaluates a ruby file', function() + local fname = 'rubyfile.rb' + write_file(fname, 'VIM.command("let set_by_rubyfile = 123")') + command('rubyfile rubyfile.rb') + eq(123, meths.get_var('set_by_rubyfile')) + os.remove(fname) + end) +end) + +describe(':rubydo command', function() + it('exposes the $_ variable for modifying lines', function() + insert('abc\ndef\nghi\njkl') + expect([[ + abc + def + ghi + jkl]]) + + feed('ggjvj:rubydo $_.upcase!<CR>') + expect([[ + abc + DEF + GHI + jkl]]) + end) + + it('operates on all lines when not given a range', function() + insert('abc\ndef\nghi\njkl') + expect([[ + abc + def + ghi + jkl]]) + + feed(':rubydo $_.upcase!<CR>') + expect([[ + ABC + DEF + GHI + JKL]]) + end) + + it('does not modify the buffer if no changes are made', function() + command('normal :rubydo 42') + eq(false, curbufmeths.get_option('modified')) + end) +end) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index a433143266..7b820347ac 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -462,4 +462,321 @@ describe('Mouse input', function() | ]]) end) + + describe('on concealed text', function() + -- Helpful for reading the test expectations: + -- :match Error /\^/ + local concealed = { + c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray } + } + + before_each(function() + screen:try_resize(25, 7) + feed('ggdG') + + execute('set concealcursor=n') + execute('set nowrap') + execute('syntax match NonText "\\<amet\\>" conceal') + execute('syntax match NonText "\\cs\\|g." conceal cchar=X') + execute('syntax match NonText "\\%(lo\\|cl\\)." conceal') + execute('syntax match NonText "Lo" conceal cchar=Y') + + insert([[ + Lorem ipsum dolor sit amet, consetetur sadipscing elitr. + Stet clita kasd gubergren, no sea takimata sanctus est. + ]]) + + feed('gg') + end) + + it('(level 1) click on non-wrapped lines', function() + execute('let &conceallevel=1', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con| + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><1,0>') + screen:expect([[ + {c:Y}^rem ip{c:X}um do{c: } {c:X}it {c: }, con| + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,0>') + screen:expect([[ + {c:Y}rem ip{c:X}um do{c: } {c:^X}it {c: }, con| + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con| + {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en, no| + | + ~ | + ~ | + ~ | + | + ]], concealed) + end) -- level 1 - non wrapped + + it('(level 1) click on wrapped lines', function() + execute('let &conceallevel=1', 'let &wrap=1', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: } | + , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><6,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | + , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | + , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} | + elitr. | + {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,3>') + screen:expect([[ + {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | + , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + end) -- level 1 - wrapped + + + it('(level 2) click on non-wrapped lines', function() + execute('let &conceallevel=2', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + {c:^Y}rem ip{c:X}um do {c:X}it , con{c:X}e| + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><1,0>') + screen:expect([[ + {c:Y}^rem ip{c:X}um do {c:X}it , con{c:X}e| + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,0>') + screen:expect([[ + {c:Y}rem ip{c:X}um do {c:X}^it , con{c:X}e| + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do {c:X}it , con{c:X}e| + {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en, no | + | + ~ | + ~ | + ~ | + | + ]], concealed) + end) -- level 2 - non wrapped + + it('(level 2) click on wrapped lines', function() + execute('let &conceallevel=2', 'let &wrap=1', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + {c:^Y}rem ip{c:X}um do {c:X}it | + , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><6,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do {c:X}it | + , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + {c:Y}rem ip{c:X}um do {c:X}it | + , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} | + elitr. | + {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,3>') + screen:expect([[ + {c:Y}rem ip{c:X}um do {c:X}it | + , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | + elitr. | + {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en | + , no {c:X}ea takimata {c:X}anctu{c:X}| + e{c:X}t. | + | + ]], concealed) + end) -- level 2 - wrapped + + + it('(level 3) click on non-wrapped lines', function() + execute('let &conceallevel=3', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + ^rem ipum do it , conetetu| + tet ta kad beren, no ea t| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><1,0>') + screen:expect([[ + r^em ipum do it , conetetu| + tet ta kad beren, no ea t| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,0>') + screen:expect([[ + rem ipum do it ^, conetetu| + tet ta kad beren, no ea t| + | + ~ | + ~ | + ~ | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + rem ipum do it , conetetu| + tet ta kad bere^n, no ea t| + | + ~ | + ~ | + ~ | + | + ]], concealed) + end) -- level 3 - non wrapped + + it('(level 3) click on wrapped lines', function() + execute('let &conceallevel=3', 'let &wrap=1', 'echo') + + feed('<esc><LeftMouse><0,0>') + screen:expect([[ + ^rem ipum do it | + , conetetur adipcin | + elitr. | + tet ta kad beren | + , no ea takimata anctu | + et. | + | + ]], concealed) + + feed('<esc><LeftMouse><6,1>') + screen:expect([[ + rem ipum do it | + , cone^tetur adipcin | + elitr. | + tet ta kad beren | + , no ea takimata anctu | + et. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,1>') + screen:expect([[ + rem ipum do it | + , conetetur adi^pcin | + elitr. | + tet ta kad beren | + , no ea takimata anctu | + et. | + | + ]], concealed) + + feed('<esc><LeftMouse><15,3>') + screen:expect([[ + rem ipum do it | + , conetetur adipcin | + elitr. | + tet ta kad bere^n | + , no ea takimata anctu | + et. | + | + ]], concealed) + end) -- level 3 - wrapped + end) end) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua new file mode 100644 index 0000000000..c7c8986527 --- /dev/null +++ b/test/functional/ui/output_spec.lua @@ -0,0 +1,39 @@ +local session = require('test.functional.helpers')(after_each) +local child_session = require('test.functional.terminal.helpers') + +describe("shell command :!", function() + local screen + before_each(function() + session.clear() + screen = child_session.screen_setup(0, '["'..session.nvim_prog.. + '", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]') + screen:expect([[ + {1: } | + ~ | + ~ | + ~ | + [No Name] | + | + -- TERMINAL -- | + ]]) + end) + + after_each(function() + screen:detach() + end) + + it("displays output even without LF/EOF. #4646 #4569 #3772", function() + -- NOTE: We use a child nvim (within a :term buffer) + -- to avoid triggering a UI flush. + child_session.feed_data(":!printf foo; sleep 200\n") + screen:expect([[ + ~ | + ~ | + [No Name] | + :!printf foo; sleep 200 | + | + foo | + -- TERMINAL -- | + ]]) + end) +end) diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 2d6df76d02..1bff020691 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -142,9 +142,13 @@ if(USE_BUNDLED_BUSTED) if(MINGW AND CMAKE_CROSSCOMPILING) set(LUV_DEPS ${LUV_DEPS} libuv_host) endif() + set(LUV_ARGS CFLAGS='-O0 -g3 -fPIC') + if(USE_BUNDLED_LIBUV) + set(LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR} CFLAGS='-O0 -g3 -fPIC') + endif() add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv COMMAND ${LUAROCKS_BINARY} - ARGS make ${LUAROCKS_BUILDARGS} LIBUV_DIR=${HOSTDEPS_INSTALL_DIR} CFLAGS='-O0 -g3 -fPIC' + ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} WORKING_DIRECTORY ${DEPS_BUILD_DIR}/src/luv DEPENDS ${LUV_DEPS}) add_custom_target(luv |