diff options
-rw-r--r-- | config/CMakeLists.txt | 1 | ||||
-rw-r--r-- | config/config.h.in | 1 | ||||
-rw-r--r-- | runtime/autoload/health/nvim.vim | 22 | ||||
-rwxr-xr-x | scripts/vim-patch.sh | 10 | ||||
-rw-r--r-- | src/nvim/os/input.c | 4 | ||||
-rw-r--r-- | src/nvim/tag.c | 7 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test47.in | 102 | ||||
-rw-r--r-- | src/nvim/testdir/test47.ok | 44 | ||||
-rw-r--r-- | src/nvim/testdir/test_diffmode.vim | 165 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 7 | ||||
-rw-r--r-- | src/nvim/tui/input.h | 3 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 58 | ||||
-rw-r--r-- | src/nvim/version.c | 4 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 29 | ||||
-rw-r--r-- | third-party/CMakeLists.txt | 4 |
16 files changed, 268 insertions, 195 deletions
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index a16000aba8..c3643db205 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -26,6 +26,7 @@ if(NOT HAVE_SYS_WAIT_H AND UNIX) message(SEND_ERROR "header sys/wait.h is required for Unix") endif() check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H) +check_include_files(termios.h HAVE_TERMIOS_H) check_include_files(utime.h HAVE_UTIME_H) check_include_files(sys/uio.h HAVE_SYS_UIO_H) diff --git a/config/config.h.in b/config/config.h.in index 4c35b3b1cb..f26b5a50a8 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -43,6 +43,7 @@ #cmakedefine HAVE_STRNCASECMP #cmakedefine HAVE_SYS_UTSNAME_H #cmakedefine HAVE_SYS_WAIT_H +#cmakedefine HAVE_TERMIOS_H #cmakedefine HAVE_UTIME #cmakedefine HAVE_UTIME_H #cmakedefine HAVE_UTIMES diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim index 85c17fa660..f5dacfebcc 100644 --- a/runtime/autoload/health/nvim.vim +++ b/runtime/autoload/health/nvim.vim @@ -123,29 +123,23 @@ function! s:check_tmux() abort endif endfunction -function! s:check_terminfo() abort +function! s:check_terminal() abort if !executable('infocmp') return endif - call health#report_start('terminfo') - let suggestions = [ - \ "Set key_backspace to \\177 (ASCII BACKSPACE). Run these commands:\n" - \ .'infocmp $TERM | sed ''s/kbs=^[hH]/kbs=\\177/'' > $TERM.ti' - \ ."\n" - \ .'tic $TERM.ti', - \ s:suggest_faq] + call health#report_start('terminal') let cmd = 'infocmp -L' let out = system(cmd) - let kbs_entry = matchstr(out, 'key_backspace=\S*') + let kbs_entry = matchstr(out, 'key_backspace=[^,[:space:]]*') + let kdch1_entry = matchstr(out, 'key_dc=[^,[:space:]]*') if v:shell_error call health#report_error('command failed: '.cmd."\n".out) - elseif !empty(matchstr(out, '\Vkey_backspace=^H')) - call health#report_error('key_backspace (kbs) entry is ^H (ASCII DELETE): ' - \ .kbs_entry, suggestions) else - call health#report_info('key_backspace terminfo entry: ' + call health#report_info('key_backspace (kbs) terminfo entry: ' \ .(empty(kbs_entry) ? '? (not found)' : kbs_entry)) + call health#report_info('key_dc (kdch1) terminfo entry: ' + \ .(empty(kbs_entry) ? '? (not found)' : kdch1_entry)) endif endfunction @@ -153,6 +147,6 @@ function! health#nvim#check() abort call s:check_config() call s:check_performance() call s:check_rplugin_manifest() - call s:check_terminfo() + call s:check_terminal() call s:check_tmux() endfunction diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index b5d795424b..88fb3cae04 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -61,10 +61,10 @@ clean_files() { read -p "Delete these files (Y/n)? " -n 1 -r reply echo - if [[ "${reply}" =~ ^[Yy]$ ]]; then - rm -- "${CREATED_FILES[@]}" - else + if [[ "${reply}" == n ]]; then echo "You can use 'git clean' to remove these files when you're done." + else + rm -- "${CREATED_FILES[@]}" fi } @@ -370,7 +370,7 @@ review_commit() { printf -- "$(head -n 4 <<< "${nvim_patch}")\n\n" local reply read -p "Continue reviewing (y/N)? " -n 1 -r reply - if [[ ! "${reply}" =~ ^[Nn]$ ]]; then + if [[ "${reply}" == y ]]; then echo return fi @@ -436,7 +436,7 @@ review_pr() { if [[ "${pr_commit_url}" != "${pr_commit_urls[-1]}" ]]; then read -p "Continue with next commit (Y/n)? " -n 1 -r reply echo - if [[ ! "${reply}" =~ ^[Yy]$ ]]; then + if [[ "${reply}" == n ]]; then break fi fi diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 1307ab5e5a..b60a7eed36 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -39,8 +39,6 @@ static int events_enabled = 0; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.c.generated.h" #endif -// Helper function used to push bytes from the 'event' key sequence partially -// between calls to os_inchar when maxlen < 3 void input_init(void) { @@ -389,6 +387,8 @@ static void process_interrupts(void) } } +// Helper function used to push bytes from the 'event' key sequence partially +// between calls to os_inchar when maxlen < 3 static int push_event_key(uint8_t *buf, int maxlen) { static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT }; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index f83154afbf..0b76e36a6b 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1297,7 +1297,12 @@ find_tags ( * Read and parse the lines in the file one by one */ for (;; ) { - line_breakcheck(); /* check for CTRL-C typed */ + // check for CTRL-C typed, more often when jumping around + if (state == TS_BINARY || state == TS_SKIP_BACK) { + line_breakcheck(); + } else { + fast_breakcheck(); + } if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */ ins_compl_check_keys(30, false); if (got_int || compl_interrupted) { diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index dba8a8a877..0118597eb8 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -17,7 +17,6 @@ SCRIPTS := \ test37.out \ test40.out \ test42.out \ - test47.out \ test48.out \ test49.out \ test52.out \ @@ -33,6 +32,7 @@ SCRIPTS := \ NEW_TESTS = \ test_cscope.res \ test_cmdline.res \ + test_diffmode.res \ test_hardcopy.res \ test_help_tagjump.res \ test_history.res \ diff --git a/src/nvim/testdir/test47.in b/src/nvim/testdir/test47.in deleted file mode 100644 index c95c6a6850..0000000000 --- a/src/nvim/testdir/test47.in +++ /dev/null @@ -1,102 +0,0 @@ -Tests for vertical splits and filler lines in diff mode - -Also tests restoration of saved options by :diffoff. - -STARTTEST -:" Disable the title to avoid xterm keeping the wrong one. -:set notitle noicon -/^1 -yG:new -pkdd:w! Xtest -ddGpkkrXoxxx:w! Xtest2 -:file Nop -ggoyyyjjjozzzz -:set foldmethod=marker foldcolumn=4 -:redir => nodiffsettings -:silent! :set diff? fdm? fdc? scb? crb? wrap? -:redir END -:vert diffsplit Xtest -:vert diffsplit Xtest2 -:redir => diffsettings -:silent! :set diff? fdm? fdc? scb? crb? wrap? -:redir END -:let diff_fdm = &fdm -:let diff_fdc = &fdc -:" repeat entering diff mode here to see if this saves the wrong settings -:diffthis -:" jump to second window for a moment to have filler line appear at start of -:" first window -ggpgg:let one = winline() -j:let one = one . "-" . winline() -j:let one = one . "-" . winline() -j:let one = one . "-" . winline() -j:let one = one . "-" . winline() -j:let one = one . "-" . winline() -gg:let two = winline() -j:let two = two . "-" . winline() -j:let two = two . "-" . winline() -j:let two = two . "-" . winline() -j:let two = two . "-" . winline() -gg:let three = winline() -j:let three = three . "-" . winline() -j:let three = three . "-" . winline() -j:let three = three . "-" . winline() -j:let three = three . "-" . winline() -j:let three = three . "-" . winline() -j:let three = three . "-" . winline() -:call append("$", one) -:call append("$", two) -:call append("$", three) -:$-2,$w! test.out -:" -:" Test diffoff -:diffoff! -1 -:let &diff = 1 -:let &fdm = diff_fdm -:let &fdc = diff_fdc -4 -:diffoff! -:$put =nodiffsettings -:$put =diffsettings -1 -:redir => nd1 -:silent! :set diff? fdm? fdc? scb? crb? wrap? -:redir END - -:redir => nd2 -:silent! :set diff? fdm? fdc? scb? crb? wrap? -:redir END - -:redir => nd3 -:silent! :set diff? fdm? fdc? scb? crb? wrap? -:redir END - -:$put =nd1 -:$put =nd2 -:$put =nd3 -:$-39,$w >> test.out -:" -:" Test that diffing shows correct filler lines -:windo :bw! -:enew -:put =range(4,10) -:1d _ -:vnew -:put =range(1,10) -:1d _ -:windo :diffthis -:wincmd h -:let w0=line('w0') -:enew -:put =w0 -:.w >> test.out -:unlet! one two three nodiffsettings diffsettings diff_fdm diff_fdc nd1 nd2 nd3 w0 -:qa! -ENDTEST - -1 aa -2 bb -3 cc -4 dd -5 ee diff --git a/src/nvim/testdir/test47.ok b/src/nvim/testdir/test47.ok deleted file mode 100644 index 83e96571ad..0000000000 --- a/src/nvim/testdir/test47.ok +++ /dev/null @@ -1,44 +0,0 @@ -2-4-5-6-8-9 -1-2-4-5-8 -2-3-4-5-6-7-8 - - -nodiff - foldmethod=marker - foldcolumn=4 -noscrollbind -nocursorbind - wrap - - - diff - foldmethod=diff - foldcolumn=2 - scrollbind - cursorbind -nowrap - - -nodiff - foldmethod=marker - foldcolumn=4 -noscrollbind -nocursorbind - wrap - - -nodiff - foldmethod=marker - foldcolumn=4 -noscrollbind -nocursorbind - wrap - - -nodiff - foldmethod=marker - foldcolumn=4 -noscrollbind -nocursorbind - wrap -1 diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim new file mode 100644 index 0000000000..e5d9ff94d9 --- /dev/null +++ b/src/nvim/testdir/test_diffmode.vim @@ -0,0 +1,165 @@ +" Tests for diff mode + +func Test_diff_fold_sync() + enew! + let l = range(50) + call setline(1, l) + diffthis + let winone = win_getid() + new + let l[25] = 'diff' + call setline(1, l) + diffthis + let wintwo = win_getid() + " line 15 is inside the closed fold + call assert_equal(19, foldclosedend(10)) + call win_gotoid(winone) + call assert_equal(19, foldclosedend(10)) + " open the fold + normal zv + call assert_equal(-1, foldclosedend(10)) + " fold in other window must have opened too + call win_gotoid(wintwo) + call assert_equal(-1, foldclosedend(10)) + + " cursor position is in sync + normal 23G + call win_gotoid(winone) + call assert_equal(23, getcurpos()[1]) + + windo diffoff + close! + set nomodified +endfunc + +func Test_vert_split() + " Disable the title to avoid xterm keeping the wrong one. + set notitle noicon + new + let l = ['1 aa', '2 bb', '3 cc', '4 dd', '5 ee'] + call setline(1, l) + w! Xtest + normal dd + $ + put + normal kkrXoxxx + w! Xtest2 + file Nop + normal ggoyyyjjjozzzz + set foldmethod=marker foldcolumn=4 + call assert_equal(0, &diff) + call assert_equal('marker', &foldmethod) + call assert_equal(4, &foldcolumn) + call assert_equal(0, &scrollbind) + call assert_equal(0, &cursorbind) + call assert_equal(1, &wrap) + + vert diffsplit Xtest + vert diffsplit Xtest2 + call assert_equal(1, &diff) + call assert_equal('diff', &foldmethod) + call assert_equal(2, &foldcolumn) + call assert_equal(1, &scrollbind) + call assert_equal(1, &cursorbind) + call assert_equal(0, &wrap) + + let diff_fdm = &fdm + let diff_fdc = &fdc + " repeat entering diff mode here to see if this saves the wrong settings + diffthis + " jump to second window for a moment to have filler line appear at start of + " first window + wincmd w + normal gg + wincmd p + normal gg + call assert_equal(2, winline()) + normal j + call assert_equal(4, winline()) + normal j + call assert_equal(5, winline()) + normal j + call assert_equal(6, winline()) + normal j + call assert_equal(8, winline()) + normal j + call assert_equal(9, winline()) + + wincmd w + normal gg + call assert_equal(1, winline()) + normal j + call assert_equal(2, winline()) + normal j + call assert_equal(4, winline()) + normal j + call assert_equal(5, winline()) + normal j + call assert_equal(8, winline()) + + wincmd w + normal gg + call assert_equal(2, winline()) + normal j + call assert_equal(3, winline()) + normal j + call assert_equal(4, winline()) + normal j + call assert_equal(5, winline()) + normal j + call assert_equal(6, winline()) + normal j + call assert_equal(7, winline()) + normal j + call assert_equal(8, winline()) + + " Test diffoff + diffoff! + 1wincmd 2 + let &diff = 1 + let &fdm = diff_fdm + let &fdc = diff_fdc + 4wincmd w + diffoff! + 1wincmd w + call assert_equal(0, &diff) + call assert_equal('marker', &foldmethod) + call assert_equal(4, &foldcolumn) + call assert_equal(0, &scrollbind) + call assert_equal(0, &cursorbind) + call assert_equal(1, &wrap) + + wincmd w + call assert_equal(0, &diff) + call assert_equal('marker', &foldmethod) + call assert_equal(4, &foldcolumn) + call assert_equal(0, &scrollbind) + call assert_equal(0, &cursorbind) + call assert_equal(1, &wrap) + + wincmd w + call assert_equal(0, &diff) + call assert_equal('marker', &foldmethod) + call assert_equal(4, &foldcolumn) + call assert_equal(0, &scrollbind) + call assert_equal(0, &cursorbind) + call assert_equal(1, &wrap) + + windo bw! +endfunc + +func Test_filler_lines() + " Test that diffing shows correct filler lines + enew! + put =range(4,10) + 1d _ + vnew + put =range(1,10) + 1d _ + windo diffthis + wincmd h + call assert_equal(1, line('w0')) + unlet! diff_fdm diff_fdc + + windo bw! +endfunc diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 70d87a7ab2..8e5adb14f9 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -32,7 +32,14 @@ void term_input_init(TermInput *input, Loop *loop) term = ""; // termkey_new_abstract assumes non-null (#2745) } +#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 + input->tk = termkey_new_abstract(term, + TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART); + termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL); + termkey_start(input->tk); +#else input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8); +#endif int curflags = termkey_get_canonflags(input->tk); termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index d7ee2b9e52..7d59cf5c6a 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -12,6 +12,9 @@ typedef struct term_input { bool paste_enabled; bool waiting; TermKey *tk; +#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 + TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook +#endif TimeWatcher timer_handle; Loop *loop; Stream read_stream; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index bceb4ca4ff..74187e07c0 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -7,9 +7,13 @@ #include <uv.h> #include <unibilium.h> +#if defined(HAVE_TERMIOS_H) +# include <termios.h> +#endif #include "nvim/lib/kvec.h" +#include "nvim/ascii.h" #include "nvim/vim.h" #include "nvim/log.h" #include "nvim/ui.h" @@ -195,6 +199,11 @@ static void tui_terminal_start(UI *ui) terminfo_start(ui); update_size(ui); signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH); + +#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 + data->input.tk_ti_hook_fn = tui_tk_ti_getstr; +#endif + term_input_init(&data->input, data->loop); term_input_start(&data->input); } @@ -227,8 +236,6 @@ static void tui_main(UIBridgeData *bridge, UI *ui) signal_watcher_init(data->loop, &data->winch_handle, ui); signal_watcher_init(data->loop, &data->cont_handle, data); signal_watcher_start(&data->cont_handle, sigcont_cb, SIGCONT); - // initialize input reading structures - term_input_init(&data->input, &tui_loop); tui_terminal_start(ui); data->stop = false; // allow the main thread to continue, we are ready to start handling UI @@ -957,3 +964,50 @@ static void flush_buf(UI *ui, bool toggle_cursor) unibi_out(ui, unibi_cursor_invisible); } } + +#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 +/// Try to get "kbs" code from stty because "the terminfo kbs entry is extremely +/// unreliable." (Vim, Bash, and tmux also do this.) +/// +/// @see tmux/tty-keys.c fe4e9470bb504357d073320f5d305b22663ee3fd +/// @see https://bugzilla.redhat.com/show_bug.cgi?id=142659 +static const char *tui_get_stty_erase(void) +{ + static char stty_erase[2] = { 0 }; +#if defined(ECHOE) && defined(ICANON) && defined(HAVE_TERMIOS_H) + struct termios t; + if (tcgetattr(input_global_fd(), &t) != -1) { + stty_erase[0] = (char)t.c_cc[VERASE]; + stty_erase[1] = '\0'; + ILOG("stty/termios:erase=%s", stty_erase); + } +#endif + return stty_erase; +} + +/// libtermkey hook to override terminfo entries. +/// @see TermInput.tk_ti_hook_fn +static const char *tui_tk_ti_getstr(const char *name, const char *value, + void *data) +{ + static const char *stty_erase = NULL; + if (stty_erase == NULL) { + stty_erase = tui_get_stty_erase(); + } + + if (strcmp(name, "key_backspace") == 0) { + ILOG("libtermkey:kbs=%s", value); + if (stty_erase != NULL && stty_erase[0] != 0) { + return stty_erase; + } + } else if (strcmp(name, "key_dc") == 0) { + ILOG("libtermkey:kdch1=%s", value); + // Vim: "If <BS> and <DEL> are now the same, redefine <DEL>." + if (stty_erase != NULL && strcmp(stty_erase, value) == 0) { + return stty_erase[0] == DEL ? (char *)CTRL_H_STR : (char *)DEL_STR; + } + } + + return value; +} +#endif diff --git a/src/nvim/version.c b/src/nvim/version.c index 8e7ad2199f..ce103ec7dd 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -105,7 +105,7 @@ static int included_patches[] = { // 2338 NA 2337, // 2336, - // 2335, + 2335, // 2334, // 2333, // 2332 NA @@ -317,7 +317,7 @@ static int included_patches[] = { // 2126, // 2125, // 2124, - // 2123, + 2123, // 2122 NA // 2121, // 2120, diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e27adc1a51..e4b6621ff9 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -6,6 +6,7 @@ local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim, helpers.nvim_dir, helpers.ok, helpers.source, helpers.write_file, helpers.mkdir, helpers.rmdir local command = helpers.command +local wait = helpers.wait local Screen = require('test.functional.ui.screen') if helpers.pending_win32(pending) then return end @@ -271,7 +272,7 @@ describe('jobs', function() screen:set_default_attr_ids({ [1] = {bold=true, foreground=Screen.colors.Blue}, }) - local script = [[ + source([[ function! g:JobHandler(job_id, data, event) endfunction @@ -281,26 +282,14 @@ describe('jobs', function() \ 'on_exit': function('g:JobHandler') \ } let job = jobstart('cat -', g:callbacks) - ]] - source(script) - feed(':function! g:JobHandler(job_id, data, event)<cr>') - feed(':endfunction<cr>') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | ]]) + wait() + source([[ + function! g:JobHandler(job_id, data, event) + endfunction + ]]) + + eq("", eval("v:errmsg")) end) it('requires funcrefs for script-local (s:) functions', function() diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index f746b88276..f7e2a9510b 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -105,8 +105,8 @@ set(LUAROCKS_SHA256 cae709111c5701235770047dfd7169f66b82ae1c7b9b79207f9df0afb722 set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v1.2.0.tar.gz) set(UNIBILIUM_SHA256 623af1099515e673abfd3cae5f2fa808a09ca55dda1c65a7b5c9424eb304ead8) -set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.18.tar.gz) -set(LIBTERMKEY_SHA256 239746de41c845af52bb3c14055558f743292dd6c24ac26c2d6567a5a6093926) +set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.19.tar.gz) +set(LIBTERMKEY_SHA256 c505aa4cb48c8fa59c526265576b97a19e6ebe7b7da20f4ecaae898b727b48b7) set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz) set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796) |