From 7d333a900d260b8e8caa0fb159c85023fc8795bd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 19:13:29 +0200 Subject: [PATCH 01/45] patch 8.2.0481: Travis is still using trusty Problem: Travis is still using trusty. Solution: Adjust config to use bionic. (Ozaki Kiichi, closes #5868) --- .travis.yml | 59 ++++++++++++++++------------------- src/testdir/lsan-suppress.txt | 10 +++++- src/version.c | 2 ++ 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 419aeb1103..b4fe2ebdd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,13 +26,10 @@ _anchors: linux: &linux os: linux - dist: trusty + dist: bionic addons: apt: - sources: - # Need msgfmt 0.19.8 to be able to generate .desktop files - - sourceline: 'ppa:ricotz/toolchain' - packages: &linux-packages + packages: - autoconf - clang - lcov @@ -41,34 +38,33 @@ _anchors: - libperl-dev - python-dev - python3-dev - - liblua5.2-dev - - lua5.2 + - liblua5.3-dev + - lua5.3 - ruby-dev - tcl-dev - cscope - libgtk2.0-dev - desktop-file-utils + - libtool-bin + services: + - xvfb before_install: - rvm reset - # Remove /opt/python/3.x.x/bin from $PATH for using system python3. - # ("pyenv global system" doesn't seem to work.) - - | - if [[ "$(which python3)" =~ ^/opt/python/ ]]; then - export PATH=$(py3=$(which python3); echo ${PATH//${py3%/python3}:/}) - fi # Use llvm-cov instead of gcov when compiler is clang. - | if [[ "${CC}" = "clang" ]]; then - ln -sf "$(which llvm-cov)" /home/travis/bin/gcov + ln -sf "$(command -v llvm-cov)" /home/travis/bin/gcov + fi + # Setup lua5.3 manually since its package doesn't provide alternative. + # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 + - | + if [[ "${CONFOPT}" =~ luainterp ]]; then + sudo update-alternatives --install /usr/bin/lua lua /usr/bin/lua5.3 10 fi before_script: - # Start virtual framebuffer to be able to test the GUI. For dists newer - # than trusty, the "services: xvfb" setting should be used instead - - | - if [[ ${TRAVIS_DIST} = trusty ]]; then - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start && sleep 3 - fi + # On travis bionic-amd64 gethostbyname() resolves "localhost" to 127.0.1.1 + # so that makes various channel tests fail. + - sudo sed -i '/^127\.0\.1\.1\s/s/\blocalhost\b//g' /etc/hosts - sudo bash ci/load-snd-dummy.sh || true - sudo usermod -a -G audio $USER - do_test() { sg audio "sg $(id -gn) '$*'"; } @@ -90,7 +86,7 @@ _anchors: - /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/ before_install: - rvm reset - # Lua is not installed on Travis OSX + # Lua is not installed on macOS - export LUA_PREFIX=/usr/local coverage: &coverage @@ -101,10 +97,10 @@ _anchors: - (cd "${SRCDIR}" && bash <(curl -s https://codecov.io/bash)) asan_symbolize: &asan_symbolize - - | - while read log; do - asan_symbolize < "${log}" - done < <(find . -type f -name 'asan.*' -size +0) + # Update pyenv to fix the error "/opt/pyenv/libexec/pyenv: line 43: cd: asan_symbolize-6.0: Not a directory". + # https://github.com/pyenv/pyenv/issues/580 + - (cd "${PYENV_ROOT}" && git fetch -p origin && git checkout "$(git rev-list --tags -n1)") &>/dev/null || true + - find . -type f -name 'asan.*' -size +0 2>/dev/null | xargs -I{} -n1 -t asan_symbolize -l{} branches: except: @@ -205,15 +201,14 @@ jobs: name: huge/gcc-s390x compiler: gcc env: *linux-huge - addons: - apt: - packages: - - *linux-packages - - libtool-bin + services: [] - <<: *linux name: huge+coverage/clang compiler: clang - env: *linux-huge + env: + - *linux-huge + # Clang cannot compile test_libvterm with "--coverage" flag. + - TEST=scripttests after_success: *coverage - <<: *linux name: huge+coverage/gcc diff --git a/src/testdir/lsan-suppress.txt b/src/testdir/lsan-suppress.txt index 5166fbf5c7..a3008bdce6 100644 --- a/src/testdir/lsan-suppress.txt +++ b/src/testdir/lsan-suppress.txt @@ -1,3 +1,11 @@ -# Suppress leaks from X libraries on Ubuntu trusty. +# Suppress leaks from X libraries on Ubuntu bionic. leak:libX11.so.6 leak:libXt.so.6 +leak:libcairo.so.2 +leak:libfontconfig.so.1 +leak:libglib-2.0.so.0 +leak:libtinfo.so.5 +# Suppress leaks from other language libraries. +leak:libperl.so.* +leak:libpython*.so.* +leak:libruby*.so.* diff --git a/src/version.c b/src/version.c index e09cf4f707..4288be72b2 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 481, /**/ 480, /**/ From ca68ae13114619df3e4c195b41ad0575516f5ff6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 19:32:53 +0200 Subject: [PATCH 02/45] patch 8.2.0482: channel and sandbox code not sufficiently tested Problem: Channel and sandbox code not sufficiently tested. Solution: Add more tests. (Yegappan Lakshmanan, closes #5855) --- src/option.h | 2 +- src/testdir/test_channel.vim | 186 ++++++++++++++++++++++++++--- src/testdir/test_clientserver.vim | 4 + src/testdir/test_cmdline.vim | 9 ++ src/testdir/test_edit.vim | 23 +++- src/testdir/test_excmd.vim | 65 ++++++++++ src/testdir/test_normal.vim | 23 ++++ src/testdir/test_prompt_buffer.vim | 5 + src/testdir/test_restricted.vim | 10 +- src/testdir/test_smartindent.vim | 66 ++++++++-- src/testdir/test_substitute.vim | 4 + src/testdir/test_terminal.vim | 27 +++++ src/testdir/test_textformat.vim | 84 ++++++++++++- src/testdir/test_visual.vim | 9 ++ src/version.c | 2 + 15 files changed, 488 insertions(+), 31 deletions(-) diff --git a/src/option.h b/src/option.h index 47eb151250..52166cf2d2 100644 --- a/src/option.h +++ b/src/option.h @@ -403,7 +403,7 @@ EXTERN char_u *p_bex; // 'backupext' EXTERN char_u *p_bo; // 'belloff' EXTERN unsigned bo_flags; -// values for the 'beepon' option +// values for the 'belloff' option #define BO_ALL 0x0001 #define BO_BS 0x0002 #define BO_CRSR 0x0004 diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index a2dafb5600..dac90aa0e7 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -251,6 +251,7 @@ func Ch_two_channels(port) call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) call ch_close(newhandle) + call assert_fails("call ch_close(newhandle)", 'E906:') endfunc func Test_two_channels() @@ -497,6 +498,11 @@ func Test_raw_pipe() call ch_sendraw(job, "double this\n", {'callback': 'Ch_handler'}) call WaitForAssert({-> assert_equal("this\nAND this\n", substitute(g:Ch_reply, "\r", "", 'g'))}) + call assert_fails("let i = ch_evalraw(job, '2 + 2', {'callback' : 'abc'})", 'E917:') + call assert_fails("let i = ch_evalexpr(job, '2 + 2')", 'E912:') + call assert_fails("let i = ch_evalraw(job, '2 + 2', {'drop' : ''})", 'E475:') + call assert_fails("let i = ch_evalraw(test_null_job(), '2 + 2')", 'E906:') + let reply = job->ch_evalraw("quit\n", {'timeout': 100}) call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) finally @@ -519,6 +525,10 @@ func Test_raw_pipe() endfor call assert_equal(1, found) + call assert_fails("call job_stop('abc')", 'E475:') + call assert_fails("call job_stop(job, [])", 'E474:') + call assert_fails("call job_stop(test_null_job())", 'E916:') + " Try to use the job and channel where a number is expected. This is not " related to testing the raw pipe. This test is here just to reuse the " already created job/channel. @@ -620,6 +630,7 @@ func Test_nl_read_file() call Stop_g_job() call delete('Xinput') endtry + call assert_fails("echo ch_read(test_null_channel(), {'callback' : 'abc'})", 'E475:') endfunc func Test_nl_write_out_file() @@ -1362,9 +1373,23 @@ endfunc """""""""" func Test_open_fail() - silent! let ch = ch_open("noserver") + call assert_fails("let ch = ch_open('noserver')", 'E475:') echo ch let d = ch + call assert_fails("let ch = ch_open('noserver', 10)", 'E474:') + call assert_fails("let ch = ch_open('localhost:-1')", 'E475:') + call assert_fails("let ch = ch_open('localhost:8765', {'timeout' : -1})", + \ 'E474:') + call assert_fails("let ch = ch_open('localhost:8765', {'axby' : 1})", + \ 'E475:') + call assert_fails("let ch = ch_open('localhost:8765', {'mode' : 'abc'})", + \ 'E475:') + call assert_fails("let ch = ch_open('localhost:8765', {'part' : 'out'})", + \ 'E475:') +endfunc + +func Test_ch_info_fail() + call assert_fails("let x = ch_info(10)", 'E475:') endfunc """""""""" @@ -1403,6 +1428,10 @@ function Ch_test_call(port) let g:Ch_call_ret = [] call assert_equal('ok', ch_evalexpr(handle, 'call-func')) call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)}) + + call assert_fails("let i = ch_evalexpr(handle, '2 + 2', {'callback' : 'abc'})", 'E917:') + call assert_fails("let i = ch_evalexpr(handle, '2 + 2', {'drop' : ''})", 'E475:') + call assert_fails("let i = ch_evalexpr(test_null_job(), '2 + 2')", 'E906:') endfunc func Test_call() @@ -1520,9 +1549,68 @@ func Test_close_partial() call s:run_server('Ch_test_close_partial') endfunc -func Test_job_start_invalid() +func Test_job_start_fails() + " this was leaking memory + call assert_fails("call job_start([''])", "E474:") call assert_fails('call job_start($x)', 'E474:') call assert_fails('call job_start("")', 'E474:') + call assert_fails('call job_start("ls", {"out_io" : "abc"})', 'E475:') + call assert_fails('call job_start("ls", {"err_io" : "abc"})', 'E475:') + call assert_fails('call job_start("ls", [])', 'E715:') + call assert_fails("call job_start('ls', {'in_top' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'in_bot' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'channel' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'callback' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'out_cb' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'err_cb' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'close_cb' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'exit_cb' : -1})", 'E475:') + call assert_fails("call job_start('ls', {'term_name' : []})", 'E475:') + call assert_fails("call job_start('ls', {'term_finish' : 'run'})", 'E475:') + call assert_fails("call job_start('ls', {'term_api' : []})", 'E475:') + call assert_fails("call job_start('ls', {'stoponexit' : []})", 'E475:') + call assert_fails("call job_start('ls', {'in_io' : 'file'})", 'E920:') + call assert_fails("call job_start('ls', {'out_io' : 'file'})", 'E920:') + call assert_fails("call job_start('ls', {'err_io' : 'file'})", 'E920:') + call assert_fails("call job_start('ls', {'in_mode' : 'abc'})", 'E475:') + call assert_fails("call job_start('ls', {'out_mode' : 'abc'})", 'E475:') + call assert_fails("call job_start('ls', {'err_mode' : 'abc'})", 'E475:') + call assert_fails("call job_start('ls', + \ {'in_io' : 'buffer', 'in_buf' : 99999})", 'E86:') + call assert_fails("call job_start('ls', + \ {'out_io' : 'buffer', 'out_buf' : 99999})", 'E86:') + call assert_fails("call job_start('ls', + \ {'err_io' : 'buffer', 'err_buf' : 99999})", 'E86:') + + call assert_fails("call job_start('ls', + \ {'in_io' : 'buffer', 'in_buf' : -1})", 'E475:') + call assert_fails("call job_start('ls', + \ {'out_io' : 'buffer', 'out_buf' : -1})", 'E475:') + call assert_fails("call job_start('ls', + \ {'err_io' : 'buffer', 'err_buf' : -1})", 'E475:') + + set nomodifiable + call assert_fails("call job_start('cmd /c dir', + \ {'out_io' : 'buffer', 'out_buf' :" .. bufnr() .. "})", 'E21:') + call assert_fails("call job_start('cmd /c dir', + \ {'err_io' : 'buffer', 'err_buf' :" .. bufnr() .. "})", 'E21:') + set modifiable + + call assert_fails("call job_start('ls', {'in_io' : 'buffer'})", 'E915:') + + edit! XXX + let bnum = bufnr() + enew + call assert_fails("call job_start('ls', + \ {'in_io' : 'buffer', 'in_buf' : bnum})", 'E918:') + + " Empty job tests + " This was crashing on MS-Windows. + call assert_fails('let job = job_start([""])', 'E474:') + call assert_fails('let job = job_start([" "])', 'E474:') + call assert_fails('let job = job_start("")', 'E474:') + call assert_fails('let job = job_start(" ")', 'E474:') + %bw! endfunc func Test_job_stop_immediately() @@ -1986,14 +2074,6 @@ func Test_zz_nl_err_to_out_pipe() endtry endfunc -func Test_empty_job() - " This was crashing on MS-Windows. - call assert_fails('let job = job_start([""])', 'E474:') - call assert_fails('let job = job_start([" "])', 'E474:') - call assert_fails('let job = job_start("")', 'E474:') - call assert_fails('let job = job_start(" ")', 'E474:') -endfunc - " Do this last, it stops any channel log. func Test_zz_ch_log() call ch_logfile('Xlog', 'w') @@ -2003,14 +2083,12 @@ func Test_zz_ch_log() let text = readfile('Xlog') call assert_match("hello there", text[1]) call assert_match("%s%s", text[2]) + call mkdir("Xdir1") + call assert_fails("call ch_logfile('Xdir1')", 'E484:') + cal delete("Xdir1", 'd') call delete('Xlog') endfunc -func Test_job_start_fails() - " this was leaking memory - call assert_fails("call job_start([''])", "E474:") -endfunc - func Test_issue_5150() if has('win32') let cmd = 'cmd /c pause' @@ -2048,4 +2126,82 @@ func Test_job_trailing_space_unix() call assert_equal(0, job_info(job).exitval) endfunc +func Test_ch_getbufnr() + let ch = test_null_channel() + call assert_equal(-1, ch_getbufnr(ch, 'in')) + call assert_equal(-1, ch_getbufnr(ch, 'out')) + call assert_equal(-1, ch_getbufnr(ch, 'err')) + call assert_equal(-1, ch_getbufnr(ch, '')) +endfunc + +" Test for unsupported options passed to ch_status() +func Test_invalid_job_chan_options() + let ch = test_null_channel() + let invalid_opts = [ + \ {'in_io' : 'null'}, + \ {'out_io' : 'null'}, + \ {'err_io' : 'null'}, + \ {'mode' : 'json'}, + \ {'out_mode' : 'json'}, + \ {'err_mode' : 'json'}, + \ {'noblock' : 1}, + \ {'in_name' : '/a/b'}, + \ {'pty' : 1}, + \ {'in_buf' : 1}, + \ {'out_buf' : 1}, + \ {'err_buf' : 1}, + \ {'out_modifiable' : 1}, + \ {'err_modifiable' : 1}, + \ {'out_msg' : 1}, + \ {'err_msg' : 1}, + \ {'in_top' : 1}, + \ {'in_bot' : 1}, + \ {'channel' : ch}, + \ {'callback' : ''}, + \ {'out_cb' : ''}, + \ {'err_cb' : ''}, + \ {'close_cb' : ''}, + \ {'exit_cb' : ''}, + \ {'term_opencmd' : ''}, + \ {'eof_chars' : ''}, + \ {'term_rows' : 10}, + \ {'term_cols' : 10}, + \ {'vertical' : 0}, + \ {'curwin' : 1}, + \ {'bufnr' : 1}, + \ {'hidden' : 0}, + \ {'norestore' : 0}, + \ {'term_kill' : 'kill'}, + \ {'tty_type' : ''}, + \ {'term_highlight' : ''}, + \ {'env' : {}}, + \ {'cwd' : ''}, + \ {'timeout' : 0}, + \ {'out_timeout' : 0}, + \ {'err_timeout' : 0}, + \ {'id' : 0}, + \ {'stoponexit' : ''}, + \ {'block_write' : 1} + \ ] + if has('gui') + call add(invalid_opts, {'ansi_colors' : []}) + endif + + for opt in invalid_opts + call assert_fails("let x = ch_status(ch, opt)", 'E475:') + endfor +endfunc + +" Test for passing the command and the arguments as List on MS-Windows +func Test_job_with_list_args() + CheckMSWindows + + enew! + let bnum = bufnr() + let job = job_start(['cmd', '/c', 'echo', 'Hello', 'World'], {'out_io' : 'buffer', 'out_buf' : bnum}) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + call assert_equal('Hello World', getline(1)) + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_clientserver.vim b/src/testdir/test_clientserver.vim index 1cbcb19f10..00b06b29d6 100644 --- a/src/testdir/test_clientserver.vim +++ b/src/testdir/test_clientserver.vim @@ -39,6 +39,8 @@ func Test_client_server() call remote_send(name, ":let testvar = 'yes'\") call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"') call assert_equal('yes', remote_expr(name, "testvar", "", 2)) + call assert_fails("let x=remote_expr(name, '2+x')", 'E449:') + call assert_fails("let x=remote_expr('[], '2+2')", 'E116:') if has('unix') && has('gui') && !has('gui_running') " Running in a terminal and the GUI is available: Tell the server to open @@ -66,6 +68,7 @@ func Test_client_server() eval 'MYSELF'->remote_startserver() " May get MYSELF1 when running the test again. call assert_match('MYSELF', v:servername) + call assert_fails("call remote_startserver('MYSELF')", 'E941:') endif let g:testvar = 'myself' call assert_equal('myself', remote_expr(v:servername, 'testvar')) @@ -100,6 +103,7 @@ func Test_client_server() endtry call assert_fails("let x=remote_peek([])", 'E730:') + call assert_fails("let x=remote_read('vim10')", 'E277:') endfunc " Uncomment this line to get a debugging log diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 9a2c3a3513..e2b7fc298f 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1459,4 +1459,13 @@ func Test_cmdwin_blocked_commands() call assert_fails('call feedkeys("q:\\", "xt")', 'E11:') endfunc +" Close the Cmd-line window in insert mode using CTRL-C +func Test_cmdwin_insert_mode_close() + %bw! + let s = '' + exe "normal q:a\let s='Hello'\" + call assert_equal('Hello', s) + call assert_equal(1, winnr('$')) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index 32fc92ddb0..9096fcdeb1 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -1542,8 +1542,8 @@ func Test_edit_ctrl_o_invalid_cmd() close! endfunc -" Test for inserting text at the beginning of a line -func Test_insert_before_first_nonblank() +" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions') +func Test_edit_cpo_H() new call setline(1, ' ') normal! Ia @@ -1556,4 +1556,23 @@ func Test_insert_before_first_nonblank() close! endfunc +" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions') +func Test_edit_cpo_L() + new + call setline(1, 'abcdefghijklmnopqr') + exe "normal 0gR\" + call assert_equal("\ijklmnopqr", getline(1)) + set cpo+=L + set list + call setline(1, 'abcdefghijklmnopqr') + exe "normal 0gR\" + call assert_equal("\cdefghijklmnopqr", getline(1)) + set nolist + call setline(1, 'abcdefghijklmnopqr') + exe "normal 0gR\" + call assert_equal("\ijklmnopqr", getline(1)) + set cpo-=L + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 2d4d520532..9369c1b90b 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -409,4 +409,69 @@ func Test_excmd_delete() close! endfunc +" Test for commands that are blocked in a sandbox +func Sandbox_tests() + call assert_fails("call histadd(':', 'ls')", 'E48:') + call assert_fails("call mkdir('Xdir')", 'E48:') + call assert_fails("call rename('a', 'b')", 'E48:') + call assert_fails("call setbufvar(1, 'myvar', 1)", 'E48:') + call assert_fails("call settabvar(1, 'myvar', 1)", 'E48:') + call assert_fails("call settabwinvar(1, 1, 'myvar', 1)", 'E48:') + call assert_fails("call setwinvar(1, 'myvar', 1)", 'E48:') + call assert_fails("call timer_start(100, '')", 'E48:') + if has('channel') + call assert_fails("call prompt_setcallback(1, '')", 'E48:') + call assert_fails("call prompt_setinterrupt(1, '')", 'E48:') + call assert_fails("call prompt_setprompt(1, '')", 'E48:') + endif + call assert_fails("let $TESTVAR=1", 'E48:') + call assert_fails("call feedkeys('ivim')", 'E48:') + call assert_fails("source! Xfile", 'E48:') + call assert_fails("call delete('Xfile')", 'E48:') + call assert_fails("call writefile([], 'Xfile')", 'E48:') + call assert_fails('!ls', 'E48:') + call assert_fails('shell', 'E48:') + call assert_fails('stop', 'E48:') + call assert_fails('exe "normal \"', 'E48:') + set insertmode + call assert_fails('call feedkeys("\", "xt")', 'E48:') + set insertmode& + call assert_fails('suspend', 'E48:') + call assert_fails('call system("ls")', 'E48:') + call assert_fails('call systemlist("ls")', 'E48:') + if has('clientserver') + call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:') + if !has('win32') + " remote_foreground() doesn't thrown an error message on MS-Windows + call assert_fails('call remote_foreground("gvim")', 'E48:') + endif + call assert_fails('let s=remote_peek("gvim")', 'E48:') + call assert_fails('let s=remote_read("gvim")', 'E48:') + call assert_fails('let s=remote_send("gvim", "abc")', 'E48:') + call assert_fails('let s=server2client("gvim", "abc")', 'E48:') + endif + if has('terminal') + call assert_fails('terminal', 'E48:') + call assert_fails('call term_start("vim")', 'E48:') + call assert_fails('call term_dumpwrite(1, "Xfile")', 'E48:') + endif + if has('channel') + call assert_fails("call ch_logfile('chlog')", 'E48:') + call assert_fails("call ch_open('localhost:8765')", 'E48:') + endif + if has('job') + call assert_fails("call job_start('vim')", 'E48:') + endif + if has('unix') && has('libcall') + call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E48:') + endif + if has('unix') + call assert_fails('cd `pwd`', 'E48:') + endif +endfunc + +func Test_sandbox() + sandbox call Sandbox_tests() +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index c2cbc3e1b3..83a95f9f66 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -2,6 +2,7 @@ source shared.vim source check.vim +source view_util.vim func Setup_NewWindow() 10new @@ -2941,6 +2942,28 @@ func Test_normal_cpo_minus() close! endfunc +" Test for displaying dollar when changing text ('$' flag in 'cpoptions') +func Test_normal_cpo_dollar() + new + let g:Line = '' + func SaveFirstLine() + let g:Line = Screenline(1) + return '' + endfunc + inoremap SaveFirstLine() + call test_override('redraw_flag', 1) + set cpo+=$ + call setline(1, 'one two three') + redraw! + exe "normal c2w\vim" + call assert_equal('one tw$ three', g:Line) + call assert_equal('vim three', getline(1)) + set cpo-=$ + call test_override('ALL', 0) + delfunc SaveFirstLine + %bw! +endfunc + " Test for using : to run a multi-line Ex command in operator pending mode func Test_normal_yank_with_excmd() new diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim index fb5d1343a8..39cce247de 100644 --- a/src/testdir/test_prompt_buffer.vim +++ b/src/testdir/test_prompt_buffer.vim @@ -121,6 +121,11 @@ func Test_prompt_garbage_collect() call feedkeys("\\", 'xt') call assert_true(v:true) + call assert_fails("call prompt_setcallback(bufnr(), [])", 'E921:') + call assert_equal(0, prompt_setcallback({}, '')) + call assert_fails("call prompt_setinterrupt(bufnr(), [])", 'E921:') + call assert_equal(0, prompt_setinterrupt({}, '')) + delfunc MyPromptCallback bwipe! endfunc diff --git a/src/testdir/test_restricted.vim b/src/testdir/test_restricted.vim index 46f5e76449..22ca2f80c1 100644 --- a/src/testdir/test_restricted.vim +++ b/src/testdir/test_restricted.vim @@ -78,7 +78,7 @@ func Test_restricted_mode() call assert_fails("call job_start('vim')", 'E145:') endif - if has('libcall') + if has('unix') && has('libcall') call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E145:') endif call assert_fails("call rename('a', 'b')", 'E145:') @@ -87,9 +87,13 @@ func Test_restricted_mode() call assert_fails('!ls', 'E145:') call assert_fails('shell', 'E145:') call assert_fails('stop', 'E145:') + call assert_fails('exe "normal \"', 'E145:') + set insertmode + call assert_fails('call feedkeys("\", "xt")', 'E145:') + set insertmode& call assert_fails('suspend', 'E145:') - call assert_fails('call system("vim")', 'E145:') - call assert_fails('call systemlist("vim")', 'E145:') + call assert_fails('call system("ls")', 'E145:') + call assert_fails('call systemlist("ls")', 'E145:') if has('unix') call assert_fails('cd `pwd`', 'E145:') endif diff --git a/src/testdir/test_smartindent.vim b/src/testdir/test_smartindent.vim index dc0f99e93f..47ded64d0f 100644 --- a/src/testdir/test_smartindent.vim +++ b/src/testdir/test_smartindent.vim @@ -21,9 +21,7 @@ endfunc func Test_smartindent_has_no_effect() new exe "normal! i\one\" - set noautoindent - set smartindent - set indentexpr= + setlocal noautoindent smartindent indentexpr= exe "normal! Gotwo\" call assert_equal("\ttwo", getline("$")) @@ -32,16 +30,13 @@ func Test_smartindent_has_no_effect() call assert_equal("three", getline("$")) delfunction! MyIndent - set autoindent& - set smartindent& - set indentexpr& bwipe! endfunc " Test for inserting '{' and '} with smartindent func Test_smartindent_braces() new - set smartindent shiftwidth=4 + setlocal smartindent shiftwidth=4 call setline(1, [' if (a)', "\tif (b)", "\t return 1"]) normal 2ggO{ normal 3ggA { @@ -57,7 +52,62 @@ func Test_smartindent_braces() \ "\t}", \ ' }' \ ], getline(1, '$')) - set si& sw& ai& + close! +endfunc + +" Test for adding a new line before and after comments with smartindent +func Test_si_add_line_around_comment() + new + setlocal smartindent shiftwidth=4 + call setline(1, [' A', '# comment1', '# comment2']) + exe "normal GoC\2GOB" + call assert_equal([' A', ' B', '# comment1', '# comment2', ' C'], + \ getline(1, '$')) + close! +endfunc + +" After a C style comment, indent for a following line should line up with the +" line containing the start of the comment. +func Test_si_indent_after_c_comment() + new + setlocal smartindent shiftwidth=4 fo+=ro + exe "normal i\/*\ncomment\n/\n#define FOOBAR\n75\ggOabc" + normal 3jOcont + call assert_equal([' abc', ' /*', ' * comment', ' * cont', + \ ' */', '#define FOOBAR', ' 75'], getline(1, '$')) + close! +endfunc + +" Test for indenting a statement after a if condition split across lines +func Test_si_if_cond_split_across_lines() + new + setlocal smartindent shiftwidth=4 + exe "normal i\if (cond1 &&\n\cond2) {\ni = 10;\n}" + call assert_equal([' if (cond1 &&', "\t cond2) {", "\ti = 10;", + \ ' }'], getline(1, '$')) + close! +endfunc + +" Test for inserting lines before and after a one line comment +func Test_si_one_line_comment() + new + setlocal smartindent shiftwidth=4 + exe "normal i\abc;\n\/* comment */" + normal oi = 10; + normal kOj = 1; + call assert_equal([' abc;', "\tj = 1;", "\t/* comment */", "\ti = 10;"], + \ getline(1, '$')) + close! +endfunc + +" Test for smartindent with a comment continued across multiple lines +func Test_si_comment_line_continuation() + new + setlocal smartindent shiftwidth=4 + call setline(1, ['# com1', '# com2 \', ' contd', '# com3', ' xyz']) + normal ggOabc + call assert_equal([' abc', '# com1', '# com2 \', ' contd', '# com3', + \ ' xyz'], getline(1, '$')) close! endfunc diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index b4105fab29..fd00756147 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -840,4 +840,8 @@ func Test_sub_with_no_last_pat() call delete('Xresult') endfunc +func Test_substitute() + call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g')) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 40749c4af5..9e20a77412 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1001,6 +1001,28 @@ func Test_terminal_term_start_empty_command() call assert_fails(cmd, 'E474') let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})" call assert_fails(cmd, 'E474') + let cmd = "call term_start('', {'term_name' : []})" + call assert_fails(cmd, 'E475') + let cmd = "call term_start('', {'term_finish' : 'axby'})" + call assert_fails(cmd, 'E475') + let cmd = "call term_start('', {'eof_chars' : []})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'term_kill' : []})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'tty_type' : []})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'tty_type' : 'abc'})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'term_highlight' : []})" + call assert_fails(cmd, 'E475:') + if has('gui') + let cmd = "call term_start('', {'ansi_colors' : 'abc'})" + call assert_fails(cmd, 'E475:') + let cmd = "call term_start('', {'ansi_colors' : [[]]})" + call assert_fails(cmd, 'E730:') + let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})" + call assert_fails(cmd, 'E475:') + endif endfunc func Test_terminal_response_to_control_sequence() @@ -1285,6 +1307,7 @@ func Test_terminal_dumpdiff_options() call assert_equal(1, winnr('$')) call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1}) call assert_equal(1, winnr('$')) + call assert_fails("call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'bufnr': -1})", 'E475:') bwipe set laststatus& @@ -1486,6 +1509,8 @@ func Test_terminal_api_call() call assert_equal(['hello', 123], g:called_arg2) call StopVimInTerminal(buf) + call assert_fails("call term_start('ls', {'term_api' : []})", 'E475:') + unlet! g:called_bufnum2 unlet! g:called_arg2 @@ -2552,3 +2577,5 @@ func Test_term_nasty_callback() exe g:buf0 .. 'bwipe!' set hidden& endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim index fd27c7b723..bb41e45a28 100644 --- a/src/testdir/test_textformat.vim +++ b/src/testdir/test_textformat.vim @@ -951,8 +951,88 @@ func Test_whichwrap_multi_byte() bwipe! endfunc -func Test_substitute() - call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g')) +" Test for the 'f' flag in 'comments' (only the first line has the comment +" string) +func Test_firstline_comment() + new + setlocal comments=f:- fo+=ro + exe "normal i- B\nD\ggoC\ggOA\" + call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$')) + %d + setlocal comments=:- + exe "normal i- B\nD\ggoC\ggOA\" + call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$')) + %bw! +endfunc + +" Test for the 'r' flag in 'comments' (right align comment) +func Test_comment_rightalign() + new + setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro + exe "normal i=\o\t /***\nD\n/" + exe "normal 2GOA\joB\jOC\joE\GOF\joG" + let expected =<< trim END + = + A + /*** + ** B + ** C + ** D + ** E + ** F + ******/ + G + END + call assert_equal(expected, getline(1, '$')) + %bw! +endfunc + +" Test for the 'b' flag in 'comments' +func Test_comment_blank() + new + setlocal comments=b:* fo+=ro + exe "normal i* E\nF\n\G\nH\ggOC\O\B\OA\2joD" + let expected =<< trim END + A + *B + * C + * D + * E + * F + *G + H + END + call assert_equal(expected, getline(1, '$')) + %bw! +endfunc + +" Test for the 'n' flag in comments +func Test_comment_nested() + new + setlocal comments=n:> fo+=ro + exe "normal i> B\nD\ggOA\joC\Go\>>> F\nH" + exe "normal 5GOE\6GoG" + let expected =<< trim END + > A + > B + > C + > D + >>>> E + >>>> F + >>>> G + >>>> H + END + call assert_equal(expected, getline(1, '$')) + %bw! +endfunc + +" Test for 'a' and 'w' flags in 'formatoptions' +func Test_fo_a_w() + new + setlocal fo+=aw tw=10 + call feedkeys("iabc abc a abc\k0weade", 'xt') + call assert_equal(['abc abcde ', 'a abc'], getline(1, '$')) + %bw! endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index ff4f76096a..143b140bae 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -267,6 +267,15 @@ func Test_virtual_replace2() call assert_equal(['abcd', \ 'efgh', \ 'ijkl'], getline(1, '$')) + + " Test for truncating spaces in a newly added line using 'autoindent' if + " characters are not added to that line. + %d_ + call setline(1, [' app', ' bee', ' cat']) + setlocal autoindent + exe "normal gg$gRt\n\nr" + call assert_equal([' apt', '', ' rat'], getline(1, '$')) + " clean up %d_ set bs&vim diff --git a/src/version.c b/src/version.c index 4288be72b2..2e8420c5ea 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 482, /**/ 481, /**/ From d25ec2cfa0c25c3b00b7f8963b8aea799df1f20a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 21:05:45 +0200 Subject: [PATCH 03/45] patch 8.2.0483: Vim9: "let x = x + 1" does not give an error Problem: Vim9: "let x = x + 1" does not give an error. Solution: Hide the variable when compiling the expression. --- src/testdir/test_vim9_expr.vim | 2 ++ src/version.c | 2 ++ src/vim9compile.c | 12 ++++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index f61ff536ad..770890ec35 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -738,6 +738,8 @@ def Test_expr7_dict() call CheckDefFailure("let x = {'a': xxx}", 'E1001:') call CheckDefFailure("let x = {xxx: 8}", 'E1001:') call CheckDefFailure("let x = #{a: 1, a: 2}", 'E721:') + call CheckDefFailure("let x += 1", 'E1020:') + call CheckDefFailure("let x = x + 1", 'E1001:') call CheckDefExecFailure("let x = g:anint.member", 'E715:') call CheckDefExecFailure("let x = g:dict_empty.member", 'E716:') enddef diff --git a/src/version.c b/src/version.c index 2e8420c5ea..79d50ee42d 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 483, /**/ 482, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 9d66e5ed15..1e8cd03d02 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3685,6 +3685,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } else if (oplen > 0) { + int r; + // for "+=", "*=", "..=" etc. first load the current value if (*op != '=') { @@ -3717,10 +3719,16 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } } - // compile the expression + // Compile the expression. Temporarily hide the new local variable + // here, it is not available to this expression. + if (idx >= 0) + --cctx->ctx_locals.ga_len; instr_count = instr->ga_len; p = skipwhite(p + oplen); - if (compile_expr1(&p, cctx) == FAIL) + r = compile_expr1(&p, cctx); + if (idx >= 0) + ++cctx->ctx_locals.ga_len; + if (r == FAIL) goto theend; if (idx >= 0 && (is_decl || !has_type)) From 92dba36fc8742fdb51b16d9bb967ef184b4babc1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 21:22:56 +0200 Subject: [PATCH 04/45] patch 8.2.0484: Vim9: some error messages not tested Problem: Vim9: some error messages not tested. Solution: Add more tests. --- src/testdir/test_vim9_expr.vim | 9 +++++++++ src/version.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 770890ec35..b1efbf5b8d 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -522,6 +522,7 @@ func Test_expr5_fails() call CheckDefFailure("let x = 33 + 0z1122", 'E1035') call CheckDefFailure("let x = [3] + 0z1122", 'E1035') call CheckDefFailure("let x = 'asdf' + 0z1122", 'E1035') + call CheckDefFailure("let x = 6 + xxx", 'E1001') endfunc " test multiply, divide, modulo @@ -553,6 +554,8 @@ def Test_expr6() assert_equal(5.0, xf[0] + yf[0]) assert_equal(6.0, xf[0] * yf[0]) endif + + call CheckDefFailure("let x = 6 * xxx", 'E1001') enddef def Test_expr6_float() @@ -680,6 +683,8 @@ def Test_expr7_blob() assert_equal(g:blob_empty, 0z) assert_equal(g:blob_one, 0z01) assert_equal(g:blob_long, 0z0102.0304) + + call CheckDefFailure("let x = 0z123", 'E973:') enddef def Test_expr7_string() @@ -691,6 +696,9 @@ def Test_expr7_string() assert_equal(g:string_long, 'abcdefghijklm') assert_equal(g:string_long, "abcdefghijklm") assert_equal(g:string_special, "ab\ncd\ref\ekk") + + call CheckDefFailure('let x = "abc', 'E114:') + call CheckDefFailure("let x = 'abc", 'E115:') enddef def Test_expr7_special() @@ -738,6 +746,7 @@ def Test_expr7_dict() call CheckDefFailure("let x = {'a': xxx}", 'E1001:') call CheckDefFailure("let x = {xxx: 8}", 'E1001:') call CheckDefFailure("let x = #{a: 1, a: 2}", 'E721:') + call CheckDefFailure("let x = #", 'E1015:') call CheckDefFailure("let x += 1", 'E1020:') call CheckDefFailure("let x = x + 1", 'E1001:') call CheckDefExecFailure("let x = g:anint.member", 'E715:') diff --git a/src/version.c b/src/version.c index 79d50ee42d..8a8c45c14f 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 484, /**/ 483, /**/ From 01b3862956260fdb5fb81b81a28f4749a92699c0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 21:28:39 +0200 Subject: [PATCH 05/45] patch 8.2.0485: Vim9 script test fails Problem: Vim9 script test fails. Solution: Stricter condition for adding new local variable. --- src/version.c | 2 ++ src/vim9compile.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/version.c b/src/version.c index 8a8c45c14f..c5f1a85cbb 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 485, /**/ 484, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 1e8cd03d02..18fb549cc8 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3446,6 +3446,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) size_t varlen; garray_T *instr = &cctx->ctx_instr; int idx = -1; + int new_local = FALSE; char_u *op; int opt_type; assign_dest_T dest = dest_local; @@ -3660,6 +3661,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type); if (idx < 0) goto theend; + new_local = TRUE; } if (heredoc) @@ -3721,12 +3723,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) // Compile the expression. Temporarily hide the new local variable // here, it is not available to this expression. - if (idx >= 0) + if (new_local) --cctx->ctx_locals.ga_len; instr_count = instr->ga_len; p = skipwhite(p + oplen); r = compile_expr1(&p, cctx); - if (idx >= 0) + if (new_local) ++cctx->ctx_locals.ga_len; if (r == FAIL) goto theend; From 9be61bbb170ed3df0e408c8ac12516e772dc0b75 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 30 Mar 2020 22:51:24 +0200 Subject: [PATCH 06/45] patch 8.2.0486: Vim9: some code and error messages not tested Problem: Vim9: some code and error messages not tested. Solution: Add more tests. --- src/evalvars.c | 2 +- src/testdir/test_vim9_expr.vim | 8 +++++++ src/testdir/test_vim9_script.vim | 37 +++++++++++++++++++++++++++++++- src/version.c | 2 ++ src/vim9compile.c | 18 +++++++++++----- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 0ffff56863..35d038db37 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -930,7 +930,7 @@ skip_var_list( { if (*semicolon == 1) { - emsg(_("Double ; in list of variables")); + emsg(_("E452: Double ; in list of variables")); return NULL; } *semicolon = 1; diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index b1efbf5b8d..06c200dbf8 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -58,6 +58,7 @@ enddef func Test_expr1_fails() call CheckDefFailure("let x = 1 ? 'one'", "Missing ':' after '?'") + call CheckDefFailure("let x = 1 ? 'one' : xxx", "E1001:") let msg = "white space required before and after '?'" call CheckDefFailure("let x = 1? 'one' : 'two'", msg) @@ -192,11 +193,18 @@ def Test_expr4_equal() assert_equal(true, g:astring == 'asdf') assert_equal(false, 'xyz' == g:astring) + assert_equal(false, 'abc' == 'aBc') + assert_equal(false, 'abc' ==# 'aBc') + assert_equal(true, 'abc' ==? 'aBc') + assert_equal(false, 'abc' == 'ABC') set ignorecase assert_equal(false, 'abc' == 'ABC') + assert_equal(false, 'abc' ==# 'ABC') set noignorecase + call CheckDefFailure("let x = 'a' == xxx", 'E1001:') + assert_equal(true, 0z3f == 0z3f) assert_equal(false, 0z3f == 0z4f) assert_equal(true, g:ablob == 0z01ab) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 5eeb19842f..f6cb15fd4d 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -53,6 +53,9 @@ def Test_assignment() let dict4: dict = #{one: 1, two: '2'} let dict5: dict = #{one: 0z01, tw: 0z02} + let a: number = 6 + assert_equal(6, a) + if has('channel') let chan1: channel let job1: job @@ -101,6 +104,21 @@ func Test_assignment_failure() call CheckDefFailure(['let true = 1'], 'E1034:') call CheckDefFailure(['let false = 1'], 'E1034:') + call CheckDefFailure(['let [a; b; c] = g:list'], 'E452:') + + call CheckDefFailure(['let &option'], 'E1052:') + call CheckDefFailure(['&g:option = 5'], 'E113:') + + call CheckDefFailure(['let $VAR = 5'], 'E1065:') + + call CheckDefFailure(['let @~ = 5'], 'E354:') + call CheckDefFailure(['let @a = 5'], 'E1066:') + + call CheckDefFailure(['let g:var = 5'], 'E1016:') + + call CheckDefFailure(['let anr = 4', 'anr ..= "text"'], 'E1019:') + call CheckDefFailure(['let xnr += 4'], 'E1020:') + call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef'], 'E1050:') call CheckDefFailure(['let var: list = [123]'], 'expected list but got list') @@ -142,6 +160,7 @@ func Test_const() call CheckDefFailure(['const var = 234', 'var = 99'], 'E1018:') call CheckDefFailure(['const one = 234', 'let one = 99'], 'E1017:') call CheckDefFailure(['const two'], 'E1021:') + call CheckDefFailure(['const &option'], 'E996:') endfunc def Test_block() @@ -172,12 +191,26 @@ def ReturnGlobal(): number return g:notNumber enddef -def Test_return_string() +def Test_return_something() assert_equal('string', ReturnString()) assert_equal(123, ReturnNumber()) assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string') enddef +let s:nothing = 0 +def ReturnNothing() + s:nothing = 1 + if true + return + endif + s:nothing = 2 +enddef + +def Test_return_nothing() + ReturnNothing() + assert_equal(1, s:nothing) +enddef + func Increment() let g:counter += 1 endfunc @@ -282,6 +315,8 @@ def Test_return_type_wrong() CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') + CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:') + CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') enddef diff --git a/src/version.c b/src/version.c index c5f1a85cbb..17ef596544 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 486, /**/ 485, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 18fb549cc8..9fdfdb3b64 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3353,9 +3353,9 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx) } else { - if (set_return_type) - cctx->ctx_ufunc->uf_ret_type = &t_void; - else if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID) + // "set_return_type" cannot be TRUE, only used for a lambda which + // always has an argument. + if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID) { emsg(_("E1003: Missing return value")); return NULL; @@ -3416,7 +3416,10 @@ heredoc_getline( cctx_T *cctx = (cctx_T *)cookie; if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len) - NULL; + { + iemsg("Heredoc got to end"); + return NULL; + } ++cctx->ctx_lnum; return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data) [cctx->ctx_lnum]); @@ -3472,6 +3475,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) return NULL; } + // "a: type" is declaring variable "a" with a type, not "a:". + if (is_decl && p == arg + 2 && p[-1] == ':') + --p; + varlen = p - arg; name = vim_strnsave(arg, (int)varlen); if (name == NULL) @@ -3499,6 +3506,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) p = find_option_end(&p, &opt_flags); if (p == NULL) { + // cannot happen? emsg(_(e_letunexp)); return NULL; } @@ -3508,7 +3516,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) *p = cc; if (opt_type == -3) { - semsg(_(e_unknown_option), *arg); + semsg(_(e_unknown_option), arg); return NULL; } if (opt_type == -2 || opt_type == 0) From bd5da371aafe5a2207065643502f4d1ff6b286c7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 31 Mar 2020 23:13:10 +0200 Subject: [PATCH 07/45] patch 8.2.0487: Vim9: compiling not sufficiently tested Problem: Vim9: compiling not sufficiently tested. Solution: Add more tests. Fix bug with PCALL. --- src/testdir/test_vim9_disassemble.vim | 25 +++++++++++++++ src/testdir/test_vim9_script.vim | 11 ++++++- src/version.c | 2 ++ src/vim9.h | 3 +- src/vim9compile.c | 8 ++++- src/vim9execute.c | 45 ++++++++++++++++----------- 6 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 99bec4337b..62602956ba 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -224,6 +224,31 @@ def Test_disassemble_call() enddef +def EchoArg(arg: string): string + return arg +enddef +def RefThis(): func + return function('EchoArg') +enddef +def s:ScriptPCall() + RefThis()("text") +enddef + +def Test_disassemble_pcall() + let res = execute('disass s:ScriptPCall') + assert_match('\d\+_ScriptPCall.*' + \ .. 'RefThis()("text").*' + \ .. '\d DCALL RefThis(argc 0).*' + \ .. '\d PUSHS "text".*' + \ .. '\d PCALL top (argc 1).*' + \ .. '\d PCALL end.*' + \ .. '\d DROP.*' + \ .. '\d PUSHNR 0.*' + \ .. '\d RETURN.*' + \, res) +enddef + + def FuncWithForwardCall(): string return DefinedLater("yes") enddef diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index f6cb15fd4d..19df73c5ef 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -260,9 +260,10 @@ func TakesOneArg(arg) echo a:arg endfunc -def Test_call_wrong_arg_count() +def Test_call_wrong_args() call CheckDefFailure(['TakesOneArg()'], 'E119:') call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') + call CheckDefFailure(['bufnr(xxx)'], 'E1001:') enddef " Default arg and varargs @@ -1029,6 +1030,14 @@ def Test_while_loop() assert_equal('1_3_', result) enddef +def Test_for_loop_fails() + call CheckDefFailure(['for # in range(5)'], 'E690:') + call CheckDefFailure(['for i In range(5)'], 'E690:') + call CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:') + call CheckScriptFailure(['def Func(arg)', 'for arg in range(5)', 'enddef'], 'E1006:') + call CheckDefFailure(['for i in "text"'], 'E1024:') +enddef + def Test_interrupt_loop() let caught = false let x = 0 diff --git a/src/version.c b/src/version.c index 17ef596544..549bf3bed4 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 487, /**/ 486, /**/ diff --git a/src/vim9.h b/src/vim9.h index ffa09a727d..7b95c377ef 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -57,6 +57,7 @@ typedef enum { ISN_DCALL, // call def function isn_arg.dfunc ISN_UCALL, // call user function or funcref/partial isn_arg.ufunc ISN_PCALL, // call partial, use isn_arg.pfunc + ISN_PCALL_END, // cleanup after ISN_PCALL with cpf_top set ISN_RETURN, // return, result is on top of stack ISN_FUNCREF, // push a function ref to dfunc isn_arg.number @@ -256,7 +257,7 @@ struct dfunc_S { // Functions defined with :def are stored in this growarray. // They are never removed, so that they can be found by index. // Deleted functions have the df_deleted flag set. -garray_T def_functions = {0, 0, sizeof(dfunc_T), 50, NULL}; +garray_T def_functions = {0, 0, sizeof(dfunc_T), 200, NULL}; #else extern garray_T def_functions; #endif diff --git a/src/vim9compile.c b/src/vim9compile.c index 9fdfdb3b64..c7f5032644 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1196,6 +1196,11 @@ generate_PCALL(cctx_T *cctx, int argcount, int at_top) // drop the funcref/partial, get back the return value ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_any; + // If partial is above the arguments it must be cleared and replaced with + // the return value. + if (at_top && generate_instr(cctx, ISN_PCALL_END) == NULL) + return FAIL; + return OK; } @@ -5200,7 +5205,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') ? ea.cmd + 1 : ea.cmd; p = to_name_end(p, TRUE); - if ((p > ea.cmd && *p != NUL) || *p == '(') + if (p > ea.cmd && *p != NUL) { int oplen; int heredoc; @@ -5538,6 +5543,7 @@ delete_instr(isn_T *isn) case ISN_OPFLOAT: case ISN_OPANY: case ISN_PCALL: + case ISN_PCALL_END: case ISN_PUSHF: case ISN_PUSHNR: case ISN_PUSHBOOL: diff --git a/src/vim9execute.c b/src/vim9execute.c index 4846c55211..c082384c60 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -345,7 +345,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) static int call_partial(typval_T *tv, int argcount, ectx_T *ectx) { - char_u *name; + char_u *name = NULL; int called_emsg_before = called_emsg; if (tv->v_type == VAR_PARTIAL) @@ -356,9 +356,9 @@ call_partial(typval_T *tv, int argcount, ectx_T *ectx) return call_ufunc(pt->pt_func, argcount, ectx, NULL); name = pt->pt_name; } - else + else if (tv->v_type == VAR_FUNC) name = tv->vval.v_string; - if (call_by_name(name, argcount, ectx, NULL) == FAIL) + if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) semsg(_(e_unknownfunc), name); @@ -421,7 +421,6 @@ call_def_function( typval_T *tv; int idx; int ret = FAIL; - dfunc_T *dfunc; int defcount = ufunc->uf_args.ga_len - argc; // Get pointer to item in the stack. @@ -467,13 +466,17 @@ call_def_function( ++ectx.ec_stack.ga_len; } - // Reserve space for local variables. - dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - for (idx = 0; idx < dfunc->df_varcount; ++idx) - STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; - ectx.ec_stack.ga_len += dfunc->df_varcount; + { + // Reserve space for local variables. + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; - ectx.ec_instr = dfunc->df_instr; + for (idx = 0; idx < dfunc->df_varcount; ++idx) + STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; + ectx.ec_stack.ga_len += dfunc->df_varcount; + + ectx.ec_instr = dfunc->df_instr; + } // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argc, &ectx); @@ -1022,18 +1025,18 @@ call_def_function( clear_tv(&partial); if (r == FAIL) goto failed; - - if (pfunc->cpf_top) - { - // Get the funcref from the stack, overwrite with the - // return value. - clear_tv(tv); - --ectx.ec_stack.ga_len; - *STACK_TV_BOT(-1) = *STACK_TV_BOT(0); - } } break; + case ISN_PCALL_END: + // PCALL finished, arguments have been consumed and replaced by + // the return value. Now clear the funcref from the stack, + // and move the return value in its place. + --ectx.ec_stack.ga_len; + clear_tv(STACK_TV_BOT(-1)); + *STACK_TV_BOT(-1) = *STACK_TV_BOT(0); + break; + // call a user defined function or funcref/partial case ISN_UCALL: { @@ -1078,6 +1081,7 @@ call_def_function( case ISN_FUNCREF: { partial_T *pt = NULL; + dfunc_T *dfunc; pt = ALLOC_CLEAR_ONE(partial_T); if (pt == NULL) @@ -2005,6 +2009,9 @@ ex_disassemble(exarg_T *eap) cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount); } break; + case ISN_PCALL_END: + smsg("%4d PCALL end", current); + break; case ISN_RETURN: smsg("%4d RETURN", current); break; From 05afceeddc4afbbca60e4e6a729a50d33d4b19f7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 31 Mar 2020 23:32:31 +0200 Subject: [PATCH 08/45] patch 8.2.0488: Vim9: compiling can break when using a lambda inside :def Problem: Vim9: Compiling can break when using a lambda inside :def. Solution: Do not keep a pointer to the dfunc_T for longer time. --- src/version.c | 2 ++ src/vim9.h | 2 +- src/vim9compile.c | 55 ++++++++++++++++++++++++++++------------------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/version.c b/src/version.c index 549bf3bed4..58180acc4b 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 488, /**/ 487, /**/ diff --git a/src/vim9.h b/src/vim9.h index 7b95c377ef..a414caa63a 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -257,7 +257,7 @@ struct dfunc_S { // Functions defined with :def are stored in this growarray. // They are never removed, so that they can be found by index. // Deleted functions have the df_deleted flag set. -garray_T def_functions = {0, 0, sizeof(dfunc_T), 200, NULL}; +garray_T def_functions = {0, 0, sizeof(dfunc_T), 50, NULL}; #else extern garray_T def_functions; #endif diff --git a/src/vim9compile.c b/src/vim9compile.c index c7f5032644..3c3f5a1635 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5029,11 +5029,12 @@ compile_execute(char_u *arg, cctx_T *cctx) * Adds the function to "def_functions". * When "set_return_type" is set then set ufunc->uf_ret_type to the type of the * return statement (used for lambda). + * This can be used recursively through compile_lambda(), which may reallocate + * "def_functions". */ void compile_def_function(ufunc_T *ufunc, int set_return_type) { - dfunc_T *dfunc; char_u *line = NULL; char_u *p; exarg_T ea; @@ -5046,25 +5047,29 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) sctx_T save_current_sctx = current_sctx; int emsg_before = called_emsg; - if (ufunc->uf_dfunc_idx >= 0) { - // Redefining a function that was compiled before. - dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + dfunc_T *dfunc; // may be invalidated by compile_lambda() - // Free old instructions. - delete_def_function_contents(dfunc); - } - else - { - // Add the function to "def_functions". - if (ga_grow(&def_functions, 1) == FAIL) - return; - dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; - vim_memset(dfunc, 0, sizeof(dfunc_T)); - dfunc->df_idx = def_functions.ga_len; - ufunc->uf_dfunc_idx = dfunc->df_idx; - dfunc->df_ufunc = ufunc; - ++def_functions.ga_len; + if (ufunc->uf_dfunc_idx >= 0) + { + // Redefining a function that was compiled before. + dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + + // Free old instructions. + delete_def_function_contents(dfunc); + } + else + { + // Add the function to "def_functions". + if (ga_grow(&def_functions, 1) == FAIL) + return; + dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; + vim_memset(dfunc, 0, sizeof(dfunc_T)); + dfunc->df_idx = def_functions.ga_len; + ufunc->uf_dfunc_idx = dfunc->df_idx; + dfunc->df_ufunc = ufunc; + ++def_functions.ga_len; + } } vim_memset(&cctx, 0, sizeof(cctx)); @@ -5414,10 +5419,14 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) generate_instr(&cctx, ISN_RETURN); } - dfunc->df_deleted = FALSE; - dfunc->df_instr = instr->ga_data; - dfunc->df_instr_count = instr->ga_len; - dfunc->df_varcount = cctx.ctx_max_local; + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + dfunc->df_deleted = FALSE; + dfunc->df_instr = instr->ga_data; + dfunc->df_instr_count = instr->ga_len; + dfunc->df_varcount = cctx.ctx_max_local; + } ret = OK; @@ -5425,6 +5434,8 @@ erret: if (ret == FAIL) { int idx; + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; for (idx = 0; idx < instr->ga_len; ++idx) delete_instr(((isn_T *)instr->ga_data) + idx); From 25b70c780a7e6063544e7f93c368fe403076f34e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 1 Apr 2020 16:34:17 +0200 Subject: [PATCH 09/45] patch 8.2.0489: Vim9: memory leaks Problem: Vim9: memory leaks. Solution: Free memory in the right place. Add hints for using asan. --- src/Makefile | 5 ++++- src/testdir/lsan-suppress.txt | 1 + src/version.c | 2 ++ src/vim9compile.c | 38 +++++++++++++++++++++++++++++------ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/Makefile b/src/Makefile index 690ac3f8e0..221b4f0de8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -691,9 +691,12 @@ LINT_OPTIONS = -beprxzF # Uncomment one of the next two lines to compile Vim with the -# address sanitizer or with the undefined sanitizer. Works with gcc and +# address sanitizer (asan) or with the undefined sanitizer. Works with gcc and # clang. May make Vim twice as slow. Errors reported on stderr. # More at: https://code.google.com/p/address-sanitizer/ +# Useful environment variables: +# $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" +# $ export LSAN_OPTIONS="suppressions=$cwd/testdir/lsan-suppress.txt" #SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer #SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer SANITIZER_LIBS = $(SANITIZER_CFLAGS) diff --git a/src/testdir/lsan-suppress.txt b/src/testdir/lsan-suppress.txt index a3008bdce6..f3d62b9826 100644 --- a/src/testdir/lsan-suppress.txt +++ b/src/testdir/lsan-suppress.txt @@ -9,3 +9,4 @@ leak:libtinfo.so.5 leak:libperl.so.* leak:libpython*.so.* leak:libruby*.so.* +leak:libxcb*.so.* diff --git a/src/version.c b/src/version.c index 58180acc4b..43f9e59435 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 489, /**/ 488, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 3c3f5a1635..64ebddfb99 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3500,7 +3500,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (cmdidx == CMD_const) { emsg(_(e_const_option)); - return NULL; + goto theend; } if (is_decl) { @@ -3513,7 +3513,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) { // cannot happen? emsg(_(e_letunexp)); - return NULL; + goto theend; } cc = *p; *p = NUL; @@ -3522,7 +3522,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (opt_type == -3) { semsg(_(e_unknown_option), arg); - return NULL; + goto theend; } if (opt_type == -2 || opt_type == 0) type = &t_string; @@ -3543,7 +3543,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (!valid_yank_reg(arg[1], TRUE)) { emsg_invreg(arg[1]); - return FAIL; + goto theend; } dest = dest_reg; if (is_decl) @@ -3993,6 +3993,23 @@ new_scope(cctx_T *cctx, scopetype_T type) return scope; } +/* + * Free the current scope and go back to the outer scope. + */ + static void +drop_scope(cctx_T *cctx) +{ + scope_T *scope = cctx->ctx_scope; + + if (scope == NULL) + { + iemsg("calling drop_scope() without a scope"); + return; + } + cctx->ctx_scope = scope->se_outer; + vim_free(scope); +} + /* * Evaluate an expression that is a constant: * has(arg) @@ -4412,7 +4429,6 @@ compile_endif(char_u *arg, cctx_T *cctx) return NULL; } ifscope = &scope->se_u.se_if; - cctx->ctx_scope = scope->se_outer; unwind_locals(cctx, scope->se_local_count); if (scope->se_u.se_if.is_if_label >= 0) @@ -4425,7 +4441,7 @@ compile_endif(char_u *arg, cctx_T *cctx) compile_fill_jump_to_end(&ifscope->is_end_label, cctx); cctx->ctx_skip = FALSE; - vim_free(scope); + drop_scope(cctx); return arg; } @@ -4486,25 +4502,35 @@ compile_for(char_u *arg, cctx_T *cctx) // Reserve a variable to store the loop iteration counter. loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); if (loop_idx < 0) + { + drop_scope(cctx); return NULL; + } // Reserve a variable to store "var" var_idx = reserve_local(cctx, arg, varlen, FALSE, &t_any); if (var_idx < 0) + { + drop_scope(cctx); return NULL; + } generate_STORENR(cctx, loop_idx, -1); // compile "expr", it remains on the stack until "endfor" arg = p; if (compile_expr1(&arg, cctx) == FAIL) + { + drop_scope(cctx); return NULL; + } // now we know the type of "var" vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (vartype->tt_type != VAR_LIST) { emsg(_("E1024: need a List to iterate over")); + drop_scope(cctx); return NULL; } if (vartype->tt_member->tt_type != VAR_UNKNOWN) From 0afdcf8601792ee751984265b49fc2ca6f8ea858 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 1 Apr 2020 18:29:10 +0200 Subject: [PATCH 10/45] patch 8.2.0490: Win32: VTP doesn't respect 'restorescreen' Problem: Win32: VTP doesn't respect 'restorescreen'. Solution: Use escape codes to switch to alternate screen. (Nobuhiro Takasaki, closes #5872) --- src/os_win32.c | 6 ++++++ src/version.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/os_win32.c b/src/os_win32.c index 1952b3636b..77e43d5d39 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5431,6 +5431,9 @@ termcap_mode_start(void) if (g_fTermcapMode) return; + if (!p_rs && USE_VTP) + vtp_printf("\033[?1049h"); + SaveConsoleBuffer(&g_cbNonTermcap); if (g_cbTermcap.IsValid) @@ -5530,6 +5533,9 @@ termcap_mode_end(void) SetConsoleCursorPosition(g_hConOut, coord); } + if (!p_rs && USE_VTP) + vtp_printf("\033[?1049l"); + g_fTermcapMode = FALSE; } #endif // FEAT_GUI_MSWIN diff --git a/src/version.c b/src/version.c index 43f9e59435..0353720775 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 490, /**/ 489, /**/ From 2da0f0c445da3c9b35b2a0cd595d10e81ad2a6f9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 1 Apr 2020 19:22:12 +0200 Subject: [PATCH 11/45] patch 8.2.0491: cannot recognize a