diff options
36 files changed, 392 insertions, 192 deletions
diff --git a/ci/after_success.sh b/ci/after_success.sh deleted file mode 100755 index 388b6eb714..0000000000 --- a/ci/after_success.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -if [[ -n "${GCOV}" ]]; then - coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.' - bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.' -fi diff --git a/ci/build.bat b/ci/build.bat index 9909d102a4..5c7f14ad0a 100644 --- a/ci/build.bat +++ b/ci/build.bat @@ -56,6 +56,10 @@ bin\nvim --version || goto :error :: Functional tests mingw32-make functionaltest VERBOSE=1 || goto :error +if defined USE_GCOV ( + C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F functionaltest || echo 'codecov upload failed.'" +) + :: Old tests setlocal set PATH=%PATH%;C:\msys64\usr\bin @@ -63,7 +67,7 @@ mingw32-make -C "%~dp0\..\src\nvim\testdir" VERBOSE=1 endlocal if defined USE_GCOV ( - C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.'" + C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F oldtest || echo 'codecov upload failed.'" ) :: Build artifacts diff --git a/ci/common/test.sh b/ci/common/test.sh index 1cb3a6224b..bc80dfead7 100644 --- a/ci/common/test.sh +++ b/ci/common/test.sh @@ -1,6 +1,15 @@ . "${CI_DIR}/common/build.sh" . "${CI_DIR}/common/suite.sh" +submit_coverage() { + if [ -n "${GCOV}" ]; then + if curl --fail --output codecov.bash --silent https://codecov.io/bash; then + bash codecov.bash -c -F "$1" || echo "codecov upload failed." + rm -f codecov.bash + fi + fi +} + print_core() { local app="$1" local core="$2" @@ -82,6 +91,7 @@ run_unittests() {( if ! build_make unittest ; then fail 'unittests' F 'Unit tests failed' fi + submit_coverage unittest check_core_dumps "$(which luajit)" exit_suite )} @@ -92,6 +102,7 @@ run_functionaltests() {( if ! build_make ${FUNCTIONALTEST}; then fail 'functionaltests' F 'Functional tests failed' fi + submit_coverage functionaltest asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" check_core_dumps @@ -105,6 +116,7 @@ run_oldtests() {( reset fail 'oldtests' F 'Legacy tests failed' fi + submit_coverage oldtest asan_check "${LOG_DIR}" valgrind_check "${LOG_DIR}" check_core_dumps diff --git a/ci/install.sh b/ci/install.sh index eb7fb14760..60d9507bfb 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -13,8 +13,8 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then fi # Use default CC to avoid compilation problems when installing Python modules. -echo "Install neovim module and coveralls for Python 2." -CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls +echo "Install neovim module for Python 2." +CC=cc pip2.7 -q install --user --upgrade neovim echo "Install neovim module for Python 3." # Allow failure. pyenv pip3 on travis is broken: diff --git a/codecov.yml b/codecov.yml index 0b3de06b97..481eea89ee 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,6 +1,6 @@ codecov: notify: - require_ci_to_pass: yes + require_ci_to_pass: no ci: - appveyor - travis diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim index ae106095f9..073dcf92a8 100644 --- a/runtime/autoload/health/provider.vim +++ b/runtime/autoload/health/provider.vim @@ -126,7 +126,7 @@ endfunction function! s:check_clipboard() abort call health#report_start('Clipboard (optional)') - if !empty($TMUX) && executable('tmux') && executable('pbcopy') && !s:cmd_ok('pbcopy') + if !empty($TMUX) && executable('tmux') && executable('pbpaste') && !s:cmd_ok('pbpaste') let tmux_version = matchstr(system('tmux -V'), '\d\+\.\d\+') call health#report_error('pbcopy does not work with tmux version: '.tmux_version, \ ['Install tmux 2.6+. https://superuser.com/q/231130', diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 9e2e6046f8..87a0315073 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -64,7 +64,7 @@ function! provider#clipboard#Executable() abort let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null }) let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0) return get(g:clipboard, 'name', 'g:clipboard') - elseif has('mac') && executable('pbcopy') && s:cmd_ok('pbcopy') + elseif has('mac') && executable('pbpaste') && s:cmd_ok('pbpaste') let s:copy['+'] = 'pbcopy' let s:paste['+'] = 'pbpaste' let s:copy['*'] = s:copy['+'] diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 6a36202177..a1a361fc85 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5445,14 +5445,13 @@ A jump table for the options with a short description can be found at |Q_op|. See |tab-page| for more information about tab pages. *'sidescroll'* *'ss'* -'sidescroll' 'ss' number (default 0) +'sidescroll' 'ss' number (default 1) global The minimal number of columns to scroll horizontally. Used only when the 'wrap' option is off and the cursor is moved off of the screen. When it is zero the cursor will be put in the middle of the screen. - When using a slow terminal set it to a large number or 0. When using - a fast terminal use a small number or 1. Not used for "zh" and "zl" - commands. + When using a slow terminal set it to a large number or 0. Not used + for "zh" and "zl" commands. *'sidescrolloff'* *'siso'* 'sidescrolloff' 'siso' number (default 0) diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 6cf62f9bb5..075ffdac52 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -232,11 +232,6 @@ correct values. See |:mode|. Slow and fast terminals *slow-fast-terminal* *slow-terminal* -If you have a fast terminal you may like to set the 'ruler' option. The -cursor position is shown in the status line. If you are using horizontal -scrolling ('wrap' option off) consider setting 'sidescroll' to a small -number. - If you have a slow terminal you may want to reset the 'showcmd' and 'ruler' options. The command characters and cursor positions will not be shown in the status line (which involves a lot of cursor motions and attribute changes for diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index c5c558279e..d61c4d0c06 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -48,6 +48,7 @@ a complete and centralized reference of those differences. - 'ruler' is set by default - 'sessionoptions' doesn't include "options" - 'showcmd' is set by default +- 'sidescroll' defaults to 1 - 'smarttab' is set by default - 'tabpagemax' defaults to 50 - 'tags' defaults to "./tags;,tags" diff --git a/src/nvim/README.md b/src/nvim/README.md index 1ece92e44d..d668db0cdc 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -90,6 +90,12 @@ Record a Nvim terminal session and format it with `vterm-dump`: Then you can compare `bar` with another session, to debug TUI behavior. +### TUI redraw + +Set the 'writedelay' option to see where and when the UI is painted. + + :set writedelay=1 + ### Terminal reference - `man terminfo` diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e5da5b835b..a86a908492 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4466,7 +4466,7 @@ do_arg_all ( // leaving an empty tab page when executed locally. if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 && curbuf->b_ffname == NULL && !curbuf->b_changed) { - use_firstwin = TRUE; + use_firstwin = true; } for (i = 0; i < count && i < opened_len && !got_int; ++i) { diff --git a/src/nvim/diff.c b/src/nvim/diff.c index c2ab57a59b..e55cf7bf7e 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -855,7 +855,7 @@ void ex_diffpatch(exarg_T *eap) { char_u *buf = NULL; win_T *old_curwin = curwin; - char_u *newname = NULL; // name of patched file buffer + char_u *newname = NULL; // name of patched file buffer char_u *esc_name = NULL; #ifdef UNIX @@ -886,9 +886,9 @@ void ex_diffpatch(exarg_T *eap) esc_name = vim_strsave_shellescape( #ifdef UNIX - fullname != NULL ? fullname : + fullname != NULL ? fullname : #endif - eap->arg, true, true); + eap->arg, true, true); if (esc_name == NULL) { goto theend; } diff --git a/src/nvim/main.c b/src/nvim/main.c index 3402e2bebc..4fd55f1491 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -577,8 +577,9 @@ int main(int argc, char **argv) return 0; } -/* Exit properly */ +/// Exit properly void getout(int exitval) + FUNC_ATTR_NORETURN { tabpage_T *tp, *next_tp; diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index a498c7f4da..8bd59b5886 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -2610,13 +2610,12 @@ int match_user(char_u *name) return result; } -/* - * Preserve files and exit. - * When called IObuff must contain a message. - * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe - * functions, such as allocating memory. - */ +/// Preserve files and exit. +/// @note IObuff must contain a message. +/// @note This may be called from deadly_signal() in a signal handler, avoid +/// unsafe functions, such as allocating memory. void preserve_exit(void) + FUNC_ATTR_NORETURN { // 'true' when we are sure to exit, e.g., after a deadly signal static bool really_exiting = false; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 47044a6072..bca4a0f93e 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -5031,8 +5031,8 @@ static void nv_right(cmdarg_T *cap) if ((!PAST_LINE && oneright() == false) || (PAST_LINE && *get_cursor_pos_ptr() == NUL) ) { - // <Space> wraps to next line if 'whichwrap' has 's'. - // 'l' wraps to next line if 'whichwrap' has 'l'. + // <Space> wraps to next line if 'whichwrap' has 's'. + // 'l' wraps to next line if 'whichwrap' has 'l'. // CURS_RIGHT wraps to next line if 'whichwrap' has '>'. if (((cap->cmdchar == ' ' && vim_strchr(p_ww, 's') != NULL) || (cap->cmdchar == 'l' && vim_strchr(p_ww, 'l') != NULL) diff --git a/src/nvim/options.lua b/src/nvim/options.lua index db7ed9da45..dac5c0ee16 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2185,7 +2185,7 @@ return { type='number', scope={'global'}, vi_def=true, varname='p_ss', - defaults={if_true={vi=0}} + defaults={if_true={vi=1}} }, { full_name='sidescrolloff', abbreviation='siso', diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 11e6a76939..f650a51fe7 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -422,7 +422,7 @@ static void out_data_ring(char *output, size_t size) } if (output == NULL && size == SIZE_MAX) { // Print mode - out_data_append_to_screen(last_skipped, last_skipped_len, true); + out_data_append_to_screen(last_skipped, &last_skipped_len, true); return; } @@ -450,30 +450,40 @@ static void out_data_ring(char *output, size_t size) /// @param output Data to append to screen lines. /// @param remaining Size of data. /// @param new_line If true, next data output will be on a new line. -static void out_data_append_to_screen(char *output, size_t remaining, - bool new_line) +static void out_data_append_to_screen(char *output, size_t *count, + bool eof) { - char *p = output, *end = output + remaining; + char *p = output, *end = output + *count; while (p < end) { - if (*p == '\n' || *p == '\r' || *p == TAB) { + if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { msg_putchar_attr((uint8_t)(*p), 0); p++; } else { + // Note: this is not 100% precise: + // 1. we don't check if received continuation bytes are already invalid + // and we thus do some buffering that could be avoided + // 2. we don't compose chars over buffer boundaries, even if we see an + // incomplete UTF-8 sequence that could be composing with the last + // complete sequence. + // This will be corrected when we switch to vterm based implementation int i = *p ? mb_ptr2len_len((char_u *)p, (int)(end-p)) : 1; + if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end-p)) { + *count = (size_t)(p - output); + goto end; + } (void)msg_outtrans_len_attr((char_u *)p, i, 0); p += i; } } +end: ui_flush(); } static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { - // We always output the whole buffer, so the buffer can never - // wrap around. size_t cnt; char *ptr = rbuffer_read_ptr(buf, &cnt); @@ -482,12 +492,16 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, // Save the skipped output. If it is the final chunk, we display it later. out_data_ring(ptr, cnt); } else { - out_data_append_to_screen(ptr, cnt, eof); + out_data_append_to_screen(ptr, &cnt, eof); } if (cnt) { rbuffer_consumed(buf, cnt); } + + // Move remaining data to start of buffer, so the buffer can never + // wrap around. + rbuffer_reset(buf); } /// Parses a command string into a sequence of words, taking quotes into @@ -576,14 +590,10 @@ static void read_input(DynamicBuffer *buf) if (len == l) { // Finished a line, add a NL, unless this line should not have one. - // FIXME need to make this more readable if (lnum != curbuf->b_op_end.lnum - || (!curbuf->b_p_bin - && curbuf->b_p_fixeol) + || (!curbuf->b_p_bin && curbuf->b_p_fixeol) || (lnum != curbuf->b_no_eol_lnum - && (lnum != - curbuf->b_ml.ml_line_count - || curbuf->b_p_eol))) { + && (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) { dynamic_buffer_ensure(buf, buf->len + 1); buf->data[buf->len++] = NL; } diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index c471352c02..290d421acc 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -38,33 +38,33 @@ uint64_t os_hrtime(void) return uv_hrtime(); } -/// Sleeps for a certain amount of milliseconds. +/// Sleeps for `ms` milliseconds. /// -/// @param milliseconds Number of milliseconds to sleep +/// @param ms Number of milliseconds to sleep /// @param ignoreinput If true, only SIGINT (CTRL-C) can interrupt. -void os_delay(uint64_t milliseconds, bool ignoreinput) +void os_delay(uint64_t ms, bool ignoreinput) { if (ignoreinput) { - if (milliseconds > INT_MAX) { - milliseconds = INT_MAX; + if (ms > INT_MAX) { + ms = INT_MAX; } - LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)milliseconds, got_int); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)ms, got_int); } else { - os_microdelay(milliseconds * 1000u, ignoreinput); + os_microdelay(ms * 1000u, ignoreinput); } } -/// Sleeps for a certain amount of microseconds. +/// Sleeps for `us` microseconds. /// -/// @param ms Number of microseconds to sleep. +/// @param us Number of microseconds to sleep. /// @param ignoreinput If true, ignore all input (including SIGINT/CTRL-C). /// If false, waiting is aborted on any input. -void os_microdelay(uint64_t ms, bool ignoreinput) +void os_microdelay(uint64_t us, bool ignoreinput) { uint64_t elapsed = 0u; uint64_t base = uv_hrtime(); // Convert microseconds to nanoseconds, or UINT64_MAX on overflow. - const uint64_t ns = (ms < UINT64_MAX / 1000u) ? ms * 1000u : UINT64_MAX; + const uint64_t ns = (us < UINT64_MAX / 1000u) ? us * 1000u : UINT64_MAX; uv_mutex_lock(&delay_mutex); diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index d7ba675b68..a27fee4e90 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -133,7 +133,8 @@ void mch_free_acl(vim_acl_T aclent) } #endif -void mch_exit(int r) FUNC_ATTR_NORETURN +void mch_exit(int r) + FUNC_ATTR_NORETURN { exiting = true; diff --git a/src/nvim/search.c b/src/nvim/search.c index bbcac45369..533a28de35 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -775,12 +775,17 @@ int searchit( } } if (ptr[matchcol] == NUL - || (nmatched = vim_regexec_multi(®match, - win, buf, lnum + matchpos.lnum, - matchcol, - tm - )) == 0) - break; + || (nmatched = vim_regexec_multi( + ®match, win, buf, lnum + matchpos.lnum, matchcol, + tm)) == 0) { + // If the search timed out, we did find a match + // but it might be the wrong one, so that's not + // OK. + if (tm != NULL && profile_passed_limit(*tm)) { + match_ok = false; + } + break; + } /* Need to get the line pointer again, a * multi-line search may have made it invalid. */ diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index dfa758f41e..137855469f 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -61,7 +61,6 @@ #include "nvim/edit.h" #include "nvim/mouse.h" #include "nvim/memline.h" -#include "nvim/mark.h" #include "nvim/map.h" #include "nvim/misc1.h" #include "nvim/move.h" @@ -376,8 +375,6 @@ void terminal_enter(void) // Ensure the terminal is properly sized. terminal_resize(s->term, 0, 0); - checkpcmark(); - setpcmark(); int save_state = State; s->save_rd = RedrawingDisabled; State = TERM_FOCUS; diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 4de1345679..01ba8baf02 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -62,20 +62,9 @@ lang mess C " Always use forward slashes. set shellslash -" Make sure $HOME does not get read or written. -let $HOME = '/does/not/exist' - " Prepare for calling garbagecollect_for_testing(). let v:testing = 1 -" Align Nvim defaults to Vim. -set directory^=. -set backspace= -set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd -set listchars=eol:$ -" Prevent Nvim log from writing to stderr. -let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log' - func RunTheTest(test) echo 'Executing ' . a:test if exists("*SetUp") diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim index 06f2199214..87cf1f6163 100644 --- a/src/nvim/testdir/setup.vim +++ b/src/nvim/testdir/setup.vim @@ -1,8 +1,14 @@ " Common preparations for running tests. -set noruler -set noshowcmd -set belloff= +" Align Nvim defaults to Vim. +set sidescroll=0 +set directory^=. +set backspace= +set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd +set listchars=eol:$ +" Prevent Nvim log from writing to stderr. +let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log' + " Make sure 'runtimepath' and 'packpath' does not include $HOME. set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 8aec923538..709a172449 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -453,6 +453,13 @@ void ui_puts(uint8_t *str) ui_linefeed(); } p += clen; + + if (p_wd) { // 'writedelay': flush & delay each time. + ui_flush(); + assert(p_wd >= 0 + && (sizeof(long) <= sizeof(uint64_t) || p_wd <= UINT64_MAX)); + os_delay((uint64_t)p_wd, false); + } } } diff --git a/src/nvim/version.c b/src/nvim/version.c index c95be072cf..5fd94fcee8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -78,6 +78,22 @@ NULL // clang-format off static const int included_patches[] = { + 1435, + // 1434, + // 1433, + // 1432, + // 1431, + // 1430, + // 1429, + // 1428, + // 1427, + // 1426, + // 1425, + // 1424, + // 1423, + // 1422, + // 1421, + // 1420, 1419, // 1418, // 1417, @@ -1039,7 +1055,7 @@ static const int included_patches[] = { 461, // 460, 459, - // 458, + 458, 457, // 456, // 455, @@ -1063,7 +1079,7 @@ static const int included_patches[] = { 437, // 436, // 435, - // 434, + 434, 433, // 432, 431, @@ -1073,7 +1089,7 @@ static const int included_patches[] = { 427, 426, // 425, - // 424, + 424, 423, // 422, 421, @@ -1312,7 +1328,7 @@ static const int included_patches[] = { 188, 187, 186, - // 185, + 185, // 184, 183, 182, @@ -1322,7 +1338,7 @@ static const int included_patches[] = { 178, 177, 176, - // 175, + 175, 174, 173, 172, diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 0a0cb2e91c..1faed4e9b1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -11,11 +11,11 @@ local funcs = helpers.funcs local request = helpers.request local meth_pcall = helpers.meth_pcall local command = helpers.command +local iswin = helpers.iswin local intchar2lua = global_helpers.intchar2lua local format_string = global_helpers.format_string local mergedicts_copy = global_helpers.mergedicts_copy -local uname = global_helpers.uname describe('api', function() before_each(clear) @@ -101,7 +101,7 @@ describe('api', function() end) it('returns shell |:!| output', function() - local win_lf = (uname() == 'Windows' and '\r') or '' + local win_lf = iswin() and '\r' or '' eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]])) end) diff --git a/test/functional/eval/backtick_expansion_spec.lua b/test/functional/eval/backtick_expansion_spec.lua index 81e8e295fa..b1b44cfa8b 100644 --- a/test/functional/eval/backtick_expansion_spec.lua +++ b/test/functional/eval/backtick_expansion_spec.lua @@ -21,11 +21,19 @@ describe("backtick expansion", function() end) it("with default 'shell'", function() - if helpers.pending_win32(pending) then return end -- Need win32 shell fixes - command(":silent args `echo ***2`") + if helpers.iswin() then + command(":silent args `dir /b *2`") + else + command(":silent args `echo ***2`") + end eq({ "file2", }, eval("argv()")) - command(":silent args `echo */*4`") - eq({ "subdir/file4", }, eval("argv()")) + if helpers.iswin() then + command(":silent args `dir /s/b *4`") + eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')")) + else + command(":silent args `echo */*4`") + eq({ "subdir/file4", }, eval("argv()")) + end end) it("with shell=fish", function() diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua index c866359520..183884a51e 100644 --- a/test/functional/eval/execute_spec.lua +++ b/test/functional/eval/execute_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.functional.helpers')(after_each) -local global_helpers = require('test.helpers') local eq = helpers.eq local eval = helpers.eval local clear = helpers.clear @@ -10,7 +9,7 @@ local funcs = helpers.funcs local Screen = require('test.functional.ui.screen') local command = helpers.command local feed = helpers.feed -local uname = global_helpers.uname +local iswin = helpers.iswin describe('execute()', function() before_each(clear) @@ -123,7 +122,7 @@ describe('execute()', function() -- This deviates from vim behavior, but is consistent -- with how nvim currently displays the output. it('does capture shell-command output', function() - local win_lf = (uname() == 'Windows' and '\13') or '' + local win_lf = iswin() and '\13' or '' eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo')) end) diff --git a/test/functional/ex_cmds/bang_filter_spec.lua b/test/functional/ex_cmds/bang_filter_spec.lua deleted file mode 100644 index 636d732161..0000000000 --- a/test/functional/ex_cmds/bang_filter_spec.lua +++ /dev/null @@ -1,69 +0,0 @@ --- Specs for bang/filter commands - -local helpers = require('test.functional.helpers')(after_each) -local feed, command, clear = helpers.feed, helpers.command, helpers.clear -local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir -local feed_command = helpers.feed_command - -if helpers.pending_win32(pending) then return end - -local Screen = require('test.functional.ui.screen') - - -describe(':! command', function() - local screen - - before_each(function() - clear() - rmdir('bang_filter_spec') - mkdir('bang_filter_spec') - write_file('bang_filter_spec/f1', 'f1') - write_file('bang_filter_spec/f2', 'f2') - write_file('bang_filter_spec/f3', 'f3') - screen = Screen.new(53,10) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {foreground = Screen.colors.Blue1}, - [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) - screen:attach() - end) - - after_each(function() - rmdir('bang_filter_spec') - end) - - it("doesn't truncate Last line of shell output #3269", function() - command([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]]) - feed([[\l]]) - screen:expect([[ - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :!ls bang_filter_spec | - f1 | - f2 | - f3 | - | - {3:Press ENTER or type command to continue}^ | - ]]) - end) - - it('handles binary and multibyte data', function() - feed_command('!cat test/functional/fixtures/shell_data.txt') - screen:expect([[ - {1:~ }| - {1:~ }| - {1:~ }| - :!cat test/functional/fixtures/shell_data.txt | - {2:^@^A^B^C^D^E^F^G^H} | - {2:^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_} | - ö 한글 {2:<a5><c3>} | - t {2:<ff>} | - | - {3:Press ENTER or type command to continue}^ | - ]]) - end) - -end) diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c index 8dbec2aaee..38695ce76b 100644 --- a/test/functional/fixtures/shell-test.c +++ b/test/functional/fixtures/shell-test.c @@ -4,6 +4,13 @@ #include <stdio.h> #include <string.h> #include <stdint.h> +#include <unistd.h> + +static void wait(void) +{ + fflush(stdout); + usleep(10*1000); +} static void help(void) { @@ -61,6 +68,22 @@ int main(int argc, char **argv) for (uint8_t i = 0; i < number; i++) { printf("%d: %s\n", (int) i, argv[3]); } + } else if (strcmp(argv[1], "UTF-8") == 0) { + // test split-up UTF-8 sequence + printf("\xc3"); wait(); + printf("\xa5\n"); wait(); + + // split up a 2+2 grapheme clusters all possible ways + printf("ref: \xc3\xa5\xcc\xb2\n"); wait(); + + printf("1: \xc3"); wait(); + printf("\xa5\xcc\xb2\n"); wait(); + + printf("2: \xc3\xa5"); wait(); + printf("\xcc\xb2\n"); wait(); + + printf("3: \xc3\xa5\xcc"); wait(); + printf("\xb2\n"); wait(); } else { fprintf(stderr, "Unknown first argument\n"); return 3; diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index ee92ba6865..0a30b9bb02 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -2,8 +2,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq +local feed = helpers.feed local feed_command, eval = helpers.feed_command, helpers.eval +local funcs = helpers.funcs local retry = helpers.retry +local ok = helpers.ok local iswin = helpers.iswin describe(':terminal', function() @@ -24,13 +27,16 @@ describe(':terminal', function() ]]) -- Invoke a command that emits frequent terminal activity. if iswin() then - feed_command([[terminal for /L \\%I in (1,0,2) do echo \\%I]]) + feed_command([[terminal for /L \%I in (1,0,2) do echo \%I]]) else feed_command([[terminal while true; do echo X; done]]) end - helpers.feed([[<C-\><C-N>]]) + feed([[<C-\><C-N>]]) wait() - screen:sleep(10) -- Let some terminal activity happen. + -- Wait for some terminal activity. + retry(nil, 4000, function() + ok(funcs.line('$') > 6) + end) feed_command("messages") screen:expect([[ msg1 | @@ -46,7 +52,7 @@ describe(':terminal', function() else feed_command([[terminal while true; do echo foo; sleep .1; done]]) end - helpers.feed([[<C-\><C-N>M]]) -- move cursor away from last line + feed([[<C-\><C-N>M]]) -- move cursor away from last line wait() eq(3, eval("line('$')")) -- window height eq(2, eval("line('.')")) -- cursor is in the middle @@ -56,6 +62,32 @@ describe(':terminal', function() eq(2, eval("line('.')")) -- cursor stays where we put it end) + it('Enter/Leave does not increment jumplist #3723', function() + feed_command('terminal') + local function enter_and_leave() + local lines_before = funcs.line('$') + -- Create a new line (in the shell). For a normal buffer this + -- increments the jumplist; for a terminal-buffer it should not. #3723 + feed('i') + wait() + feed('<CR><CR><CR><CR>') + wait() + feed([[<C-\><C-N>]]) + wait() + -- Wait for >=1 lines to be created. + retry(nil, 4000, function() + ok(funcs.line('$') > lines_before) + end) + end + enter_and_leave() + enter_and_leave() + enter_and_leave() + ok(funcs.line('$') > 6) -- Verify assumption. + local jumps = funcs.split(funcs.execute('jumps'), '\n') + eq(' jump line col file/text', jumps[1]) + eq(3, #jumps) + end) + end) describe(':terminal (with fake shell)', function() @@ -151,12 +183,12 @@ describe(':terminal (with fake shell)', function() it('ignores writes if the backing stream closes', function() terminal_with_fake_shell() - helpers.feed('iiXXXXXXX') + feed('iiXXXXXXX') wait() -- Race: Though the shell exited (and streams were closed by SIGCHLD -- handler), :terminal cleanup is pending on the main-loop. -- This write should be ignored (not crash, #5445). - helpers.feed('iiYYYYYYY') + feed('iiYYYYYYY') eq(2, eval("1+1")) -- Still alive? end) @@ -175,7 +207,7 @@ describe(':terminal (with fake shell)', function() :terminal | ]]) eq('term://', string.match(eval('bufname("%")'), "^term://")) - helpers.feed([[<C-\><C-N>]]) + feed([[<C-\><C-N>]]) feed_command([[find */shadacat.py]]) if iswin() then eq('scripts\\shadacat.py', eval('bufname("%")')) @@ -192,9 +224,9 @@ describe(':terminal (with fake shell)', function() [Process exited 0] | :terminal echo "scripts/shadacat.py" | ]]) - helpers.feed([[<C-\><C-N>]]) + feed([[<C-\><C-N>]]) eq('term://', string.match(eval('bufname("%")'), "^term://")) - helpers.feed([[ggf"lgf]]) + feed([[ggf"lgf]]) eq('scripts/shadacat.py', eval('bufname("%")')) end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 2252e3580f..95fb2ce21c 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -905,6 +905,7 @@ describe("'winhighlight' highlight", function() end) it('background applies also to non-text', function() + command('set sidescroll=0') insert('Lorem ipsum dolor sit amet ') command('set shiftwidth=2') feed('>>') diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 13820af3b8..e5708d51ef 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths local insert, feed_command = helpers.insert, helpers.feed_command local eq, funcs = helpers.eq, helpers.funcs +local command = helpers.command describe('ui/mouse/input', function() local screen @@ -706,6 +707,7 @@ describe('ui/mouse/input', function() end) it('horizontal scrolling', function() + command('set sidescroll=0') feed("<esc>:set nowrap<cr>") feed("a <esc>20Ab<esc>") diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index da3f474e08..4246020fab 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -1,14 +1,24 @@ -local session = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local helpers = require('test.functional.helpers')(after_each) local child_session = require('test.functional.terminal.helpers') - -if session.pending_win32(pending) then return end +local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir +local eq = helpers.eq +local eval = helpers.eval +local feed = helpers.feed +local feed_command = helpers.feed_command +local iswin = helpers.iswin +local clear = helpers.clear +local command = helpers.command +local nvim_dir = helpers.nvim_dir describe("shell command :!", function() + if helpers.pending_win32(pending) then return end + local screen before_each(function() - session.clear() - screen = child_session.screen_setup(0, '["'..session.nvim_prog.. - '", "-u", "NONE", "-i", "NONE", "--cmd", "'..session.nvim_set..'"]') + clear() + screen = child_session.screen_setup(0, '["'..helpers.nvim_prog.. + '", "-u", "NONE", "-i", "NONE", "--cmd", "'..helpers.nvim_set..'"]') screen:expect([[ {1: } | {4:~ }| @@ -41,7 +51,7 @@ describe("shell command :!", function() end) it("throttles shell-command output greater than ~10KB", function() - if os.getenv("TRAVIS") and session.os_name() == "osx" then + if os.getenv("TRAVIS") and helpers.os_name() == "osx" then pending("[Unreliable on Travis macOS.]", function() end) return end @@ -66,3 +76,154 @@ describe("shell command :!", function() ]]) end) end) + +describe("shell command :!", function() + before_each(function() + clear() + end) + + it("cat a binary file #4142", function() + feed(":exe 'silent !cat '.shellescape(v:progpath)<CR>") + eq(2, eval('1+1')) -- Still alive? + end) + + it([[display \x08 char #4142]], function() + feed(":silent !echo \08<CR>") + eq(2, eval('1+1')) -- Still alive? + end) + + it([[handles control codes]], function() + if iswin() then + pending('missing printf', function() end) + return + end + local screen = Screen.new(50, 4) + screen:attach() + -- Print TAB chars. #2958 + feed([[:!printf '1\t2\t3'<CR>]]) + screen:expect([[ + ~ | + :!printf '1\t2\t3' | + 1 2 3 | + Press ENTER or type command to continue^ | + ]]) + feed([[<CR>]]) + -- Print BELL control code. #4338 + screen.bell = false + feed([[:!printf '\x07\x07\x07\x07text'<CR>]]) + screen:expect([[ + ~ | + :!printf '\x07\x07\x07\x07text' | + text | + Press ENTER or type command to continue^ | + ]], nil, nil, function() + eq(true, screen.bell) + end) + feed([[<CR>]]) + -- Print BS control code. + feed([[:echo system('printf ''\x08\n''')<CR>]]) + screen:expect([[ + ~ | + ^H | + | + Press ENTER or type command to continue^ | + ]]) + feed([[<CR>]]) + -- Print LF control code. + feed([[:!printf '\n'<CR>]]) + screen:expect([[ + :!printf '\n' | + | + | + Press ENTER or type command to continue^ | + ]]) + feed([[<CR>]]) + end) + + describe('', function() + local screen + before_each(function() + rmdir('bang_filter_spec') + mkdir('bang_filter_spec') + write_file('bang_filter_spec/f1', 'f1') + write_file('bang_filter_spec/f2', 'f2') + write_file('bang_filter_spec/f3', 'f3') + screen = Screen.new(53,10) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Blue1}, + [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + end) + + after_each(function() + rmdir('bang_filter_spec') + end) + + it("doesn't truncate Last line of shell output #3269", function() + command(helpers.iswin() + and [[nnoremap <silent>\l :!dir /b bang_filter_spec<cr>]] + or [[nnoremap <silent>\l :!ls bang_filter_spec<cr>]]) + local result = (helpers.iswin() + and [[:!dir /b bang_filter_spec]] + or [[:!ls bang_filter_spec ]]) + feed([[\l]]) + screen:expect([[ + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]..result..[[ | + f1 | + f2 | + f3 | + | + {3:Press ENTER or type command to continue}^ | + ]]) + end) + + it('handles binary and multibyte data', function() + feed_command('!cat test/functional/fixtures/shell_data.txt') + screen.bell = false + screen:expect([[ + {1:~ }| + {1:~ }| + {1:~ }| + :!cat test/functional/fixtures/shell_data.txt | + {2:^@^A^B^C^D^E^F^H} | + {2:^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_} | + ö 한글 {2:<a5><c3>} | + t {2:<ff>} | + | + {3:Press ENTER or type command to continue}^ | + ]], nil, nil, function() + eq(true, screen.bell) + end) + end) + + it('handles multibyte sequences split over buffer boundaries', function() + command('cd '..nvim_dir) + local cmd + if iswin() then + cmd = '!shell-test UTF-8 ' + else + cmd = '!./shell-test UTF-8' + end + feed_command(cmd) + -- Note: only the first example of split composed char works + screen:expect([[ + {1:~ }| + {1:~ }| + :]]..cmd..[[ | + å | + ref: å̲ | + 1: å̲ | + 2: å ̲ | + 3: å ̲ | + | + {3:Press ENTER or type command to continue}^ | + ]]) + end) + end) +end) diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index 968547491e..913f1b9bed 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -2,12 +2,16 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local feed = helpers.feed +local feed_command = helpers.feed_command +local insert = helpers.insert -describe('combining long lines', function() +describe("'spell'", function() local screen before_each(function() - helpers.clear() + clear() screen = Screen.new(80, 8) screen:attach() screen:set_default_attr_ids( { @@ -20,9 +24,9 @@ describe('combining long lines', function() screen:detach() end) - it('#7937 successfully joins lines with "set spell"', function() - helpers.feed_command('set spell') - helpers.insert([[ + it('joins long lines #7937', function() + feed_command('set spell') + insert([[ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo @@ -30,7 +34,7 @@ describe('combining long lines', function() cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ]]) - helpers.feed('ggJJJJJJ0') + feed('ggJJJJJJ0') screen:expect([[ {1:^Lorem} {1:ipsum} dolor sit {1:amet}, {1:consectetur} {1:adipiscing} {1:elit}, {1:sed} do {1:eiusmod} {1:tempor} {1:i}| {1:ncididunt} {1:ut} {1:labore} {1:et} {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}| |