diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 28 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 18 | ||||
-rw-r--r-- | src/nvim/main.c | 58 | ||||
-rw-r--r-- | src/nvim/message.c | 7 | ||||
-rw-r--r-- | src/nvim/screen.c | 6 | ||||
-rw-r--r-- | src/nvim/testdir/setup.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_eval_stuff.vim | 21 | ||||
-rw-r--r-- | src/nvim/testdir/test_execute_func.vim | 29 | ||||
-rw-r--r-- | src/nvim/testdir/test_messages.vim | 21 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 46 | ||||
-rw-r--r-- | src/nvim/version.c | 176 |
11 files changed, 248 insertions, 163 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1640729c94..998d0568ce 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8331,6 +8331,8 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) const bool save_emsg_noredir = emsg_noredir; const bool save_redir_off = redir_off; garray_T *const save_capture_ga = capture_ga; + const int save_msg_col = msg_col; + bool echo_output = false; if (check_secure()) { return; @@ -8343,6 +8345,9 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (s == NULL) { return; } + if (*s == NUL) { + echo_output = true; + } if (strncmp(s, "silent", 6) == 0) { msg_silent++; } @@ -8358,6 +8363,9 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) ga_init(&capture_local, (int)sizeof(char), 80); capture_ga = &capture_local; redir_off = false; + if (!echo_output) { + msg_col = 0; // prevent leading spaces + } if (argvars[0].v_type != VAR_LIST) { do_cmdline_cmd(tv_get_string(&argvars[0])); @@ -8376,6 +8384,16 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) emsg_silent = save_emsg_silent; emsg_noredir = save_emsg_noredir; redir_off = save_redir_off; + // "silent reg" or "silent echo x" leaves msg_col somewhere in the line. + if (echo_output) { + // When not working silently: put it in column zero. A following + // "echon" will overwrite the message, unavoidably. + msg_col = 0; + } else { + // When working silently: Put it back where it was, since nothing + // should have been written. + msg_col = save_msg_col; + } ga_append(capture_ga, NUL); rettv->v_type = VAR_STRING; @@ -20064,9 +20082,15 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, // prevent changing the type. if (ht == &vimvarht) { if (v->di_tv.v_type == VAR_STRING) { - xfree(v->di_tv.vval.v_string); + XFREE_CLEAR(v->di_tv.vval.v_string); if (copy || tv->v_type != VAR_STRING) { - v->di_tv.vval.v_string = (char_u *)xstrdup(tv_get_string(tv)); + const char *const val = tv_get_string(tv); + + // Careful: when assigning to v:errmsg and tv_get_string() + // causes an error message the variable will alrady be set. + if (v->di_tv.vval.v_string == NULL) { + v->di_tv.vval.v_string = (char_u *)xstrdup(val); + } } else { // Take over the string to avoid an extra alloc/free. v->di_tv.vval.v_string = tv->vval.v_string; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ec4b16fbb0..7a7b20c35f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2217,11 +2217,19 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.arg = skipwhite(p); } - /* - * 7. Switch on command name. - * - * The "ea" structure holds the arguments that can be used. - */ + // The :try command saves the emsg_silent flag, reset it here when + // ":silent! try" was used, it should only apply to :try itself. + if (ea.cmdidx == CMD_try && did_esilent > 0) { + emsg_silent -= did_esilent; + if (emsg_silent < 0) { + emsg_silent = 0; + } + did_esilent = 0; + } + + // 7. Execute the command. + // + // The "ea" structure holds the arguments that can be used. ea.cmdlinep = cmdlinep; ea.getline = fgetline; ea.cookie = cookie; diff --git a/src/nvim/main.c b/src/nvim/main.c index ed8788af60..8ff873e127 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -316,28 +316,9 @@ int main(int argc, char **argv) // Set the break level after the terminal is initialized. debug_break_level = params.use_debug_break_level; - // - // Read user-input if any TTY is connected. // Read ex-commands if invoked with "-es". - // - bool reading_tty = !headless_mode - && !embedded_mode - && !silent_mode - && (params.input_isatty || params.output_isatty - || params.err_isatty); - bool reading_excmds = !params.input_isatty - && silent_mode - && exmode_active == EXMODE_NORMAL; - if (reading_tty || reading_excmds) { - // One of the startup commands (arguments, sourced scripts or plugins) may - // prompt the user, so start reading from a tty now. - int fd = STDIN_FILENO; - if (!silent_mode - && (!params.input_isatty || params.edit_type == EDIT_STDIN)) { - // Use stderr or stdout since stdin is being used to read commands. - fd = params.err_isatty ? fileno(stderr) : fileno(stdout); - } - input_start(fd); + if (!params.input_isatty && silent_mode && exmode_active == EXMODE_NORMAL) { + input_start(STDIN_FILENO); } // open terminals when opening files that start with term:// @@ -366,16 +347,22 @@ int main(int argc, char **argv) // startup. This allows an external UI to show messages and prompts from // --cmd and buffer loading (e.g. swap files) bool early_ui = false; - if (embedded_mode && !headless_mode) { - TIME_MSG("waiting for embedder to make request"); - remote_ui_wait_for_attach(); - TIME_MSG("done waiting for embedder"); + bool use_remote_ui = (embedded_mode && !headless_mode); + bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode); + if (use_remote_ui || use_builtin_ui) { + TIME_MSG("waiting for UI to make request"); + if (use_remote_ui) { + remote_ui_wait_for_attach(); + } else { + ui_builtin_start(); + } + TIME_MSG("done waiting for UI"); // prepare screen now, so external UIs can display messages starting = NO_BUFFERS; screenclear(); early_ui = true; - TIME_MSG("initialized screen early for embedder"); + TIME_MSG("initialized screen early for UI"); } // Execute --cmd arguments. @@ -469,25 +456,12 @@ int main(int argc, char **argv) read_stdin(); } - if (reading_tty && (need_wait_return || msg_didany)) { - // Because there's no UI yet, error messages would have been printed to - // stdout. Before starting we need confirmation that the user has seen the - // messages and that is done with a call to wait_return. - TIME_MSG("waiting for return"); - wait_return(true); - } - - if (!headless_mode && !embedded_mode && !silent_mode) { - input_stop(); // Stop reading input, let the UI take over. - ui_builtin_start(); - } - setmouse(); // may start using the mouse if (exmode_active || early_ui) { - // Don't clear the screen when starting in Ex mode, or when an - // embedding UI might have displayed messages - must_redraw = CLEAR; + // Don't clear the screen when starting in Ex mode, or when a UI might have + // displayed messages. + redraw_later(VALID); } else { screenclear(); // clear screen TIME_MSG("clearing screen"); diff --git a/src/nvim/message.c b/src/nvim/message.c index a597fb4866..5188824901 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1806,8 +1806,13 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr) // different, e.g. for Win32 console) or we just don't know where the // cursor is. if (msg_use_printf()) { + int saved_msg_col = msg_col; msg_puts_printf(str, len); - } else { + if (headless_mode) { + msg_col = saved_msg_col; + } + } + if (!msg_use_printf() || (headless_mode && default_grid.chars)) { msg_puts_display((const char_u *)str, len, attr, false); } } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 9439869b32..84c3f169ef 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -6595,6 +6595,9 @@ void unshowmode(bool force) // Clear the mode message. void clearmode(void) { + const int save_msg_row = msg_row; + const int save_msg_col = msg_col; + msg_ext_ui_flush(); msg_pos_mode(); if (reg_recording != 0) { @@ -6602,6 +6605,9 @@ void clearmode(void) } msg_clr_eos(); msg_ext_flush_showmode(); + + msg_col = save_msg_col; + msg_row = save_msg_row; } static void recording_mode(int attr) diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim index 011433f19e..c75b00d5de 100644 --- a/src/nvim/testdir/setup.vim +++ b/src/nvim/testdir/setup.vim @@ -16,6 +16,7 @@ set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd set listchars=eol:$ set fillchars=vert:\|,fold:- set shortmess-=F +set laststatus=1 " Prevent Nvim log from writing to stderr. let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log' diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim index 19a15590e5..ff8f2e5fc7 100644 --- a/src/nvim/testdir/test_eval_stuff.vim +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -78,3 +78,24 @@ func Test_string_concatenation() let a..=b call assert_equal('ab', a) endfunc + +func Test_nocatch_restore_silent_emsg() + silent! try + throw 1 + catch + endtry + echoerr 'wrong' + let c1 = nr2char(screenchar(&lines, 1)) + let c2 = nr2char(screenchar(&lines, 2)) + let c3 = nr2char(screenchar(&lines, 3)) + let c4 = nr2char(screenchar(&lines, 4)) + let c5 = nr2char(screenchar(&lines, 5)) + call assert_equal('wrong', c1 . c2 . c3 . c4 . c5) +endfunc + +func Test_let_errmsg() + call assert_fails('let v:errmsg = []', 'E730:') + let v:errmsg = '' + call assert_fails('let v:errmsg = []', 'E730:') + let v:errmsg = '' +endfunc diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index 6f61bede93..eb84a6739d 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -53,3 +53,32 @@ func Test_execute_list() call assert_equal("", execute([])) call assert_equal("", execute(v:_null_list)) endfunc + +func Test_execute_does_not_change_col() + echo '' + echon 'abcd' + let x = execute('silent echo 234343') + echon 'xyz' + let text = '' + for col in range(1, 7) + let text .= nr2char(screenchar(&lines, col)) + endfor + call assert_equal('abcdxyz', text) +endfunc + +func Test_execute_not_silent() + echo '' + echon 'abcd' + let x = execute('echon 234', '') + echo 'xyz' + let text1 = '' + for col in range(1, 8) + let text1 .= nr2char(screenchar(&lines - 1, col)) + endfor + call assert_equal('abcd234 ', text1) + let text2 = '' + for col in range(1, 4) + let text2 .= nr2char(screenchar(&lines, col)) + endfor + call assert_equal('xyz ', text2) +endfunc diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 12101ec1f8..8b71d5f03e 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -39,6 +39,27 @@ function Test_messages() endtry endfunction + " Patch 7.4.1696 defined the "clearmode()" command for clearing the mode +" indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message +" output could then be disturbed when 'cmdheight' was greater than one. +" This test ensures that the bugfix for this issue remains in place. +function! Test_stopinsert_does_not_break_message_output() + set cmdheight=2 + redraw! + + stopinsert | echo 'test echo' + call assert_equal(116, screenchar(&lines - 1, 1)) + call assert_equal(32, screenchar(&lines, 1)) + redraw! + + stopinsert | echomsg 'test echomsg' + call assert_equal(116, screenchar(&lines - 1, 1)) + call assert_equal(32, screenchar(&lines, 1)) + redraw! + + set cmdheight& +endfunction + func Test_message_completion() call feedkeys(":message \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"message clear', @:) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 6d9023bd79..7a725df0a1 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -48,6 +48,26 @@ void tinput_init(TermInput *input, Loop *loop) int curflags = termkey_get_canonflags(input->tk); termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); + + // If stdin is not a pty, switch to stderr. For cases like: + // echo q | nvim -es + // ls *.md | xargs nvim +#ifdef WIN32 + if (!os_isatty(0)) { + const HANDLE conin_handle = CreateFile("CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + (LPSECURITY_ATTRIBUTES)NULL, + OPEN_EXISTING, 0, (HANDLE)NULL); + input->in_fd = _open_osfhandle(conin_handle, _O_RDONLY); + assert(input->in_fd != -1); + } +#else + if (!os_isatty(0) && os_isatty(2)) { + input->in_fd = 2; + } +#endif + // setup input handle rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff); // initialize a timer handle for handling ESC with libtermkey @@ -435,24 +455,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, TermInput *input = data; if (eof) { - if (input->in_fd == 0 && !os_isatty(0) && os_isatty(2)) { - // Started reading from stdin which is not a pty but failed. Switch to - // stderr since it is a pty. - // - // This is how we support commands like: - // - // echo q | nvim -es - // - // and - // - // ls *.md | xargs nvim - input->in_fd = 2; - stream_close(&input->read_stream, NULL, NULL); - multiqueue_put(input->loop->fast_events, tinput_restart_reading, 1, - input); - } else { - loop_schedule(&main_loop, event_create(tinput_done_event, 0)); - } + loop_schedule(&main_loop, event_create(tinput_done_event, 0)); return; } @@ -496,10 +499,3 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, // without wrap around, otherwise it could be misinterpreted. rbuffer_reset(input->read_stream.buffer); } - -static void tinput_restart_reading(void **argv) -{ - TermInput *input = argv[0]; - rstream_init_fd(input->loop, &input->read_stream, input->in_fd, 0xfff); - rstream_start(&input->read_stream, tinput_read_cb, input); -} diff --git a/src/nvim/version.c b/src/nvim/version.c index 43a63095fc..be7a2ffcad 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -94,10 +94,10 @@ static const int included_patches[] = { // 1830, 1829, 1828, - // 1827, + 1827, 1826, 1825, - // 1824, + 1824, // 1823, 1822, // 1821, @@ -118,7 +118,7 @@ static const int included_patches[] = { // 1806, 1805, // 1804, - // 1803, + 1803, // 1802, // 1801, 1800, @@ -148,7 +148,7 @@ static const int included_patches[] = { // 1776, // 1775, // 1774, - // 1773, + 1773, // 1772, // 1771, // 1770, @@ -234,7 +234,7 @@ static const int included_patches[] = { // 1690, // 1689, // 1688, - // 1687, + 1687, 1686, // 1685, // 1684, @@ -244,8 +244,8 @@ static const int included_patches[] = { // 1680, 1679, 1678, - // 1677, - // 1676, + 1677, + 1676, 1675, 1674, // 1673, @@ -260,14 +260,14 @@ static const int included_patches[] = { // 1664, 1663, // 1662, - // 1661, + 1661, // 1660, 1659, 1658, // 1657, // 1656, // 1655, - // 1654, + 1654, // 1653, // 1652, // 1651, @@ -295,7 +295,7 @@ static const int included_patches[] = { // 1629, // 1628, 1627, - // 1626, + 1626, 1625, // 1624, // 1623, @@ -314,7 +314,7 @@ static const int included_patches[] = { 1610, // 1609, 1608, - // 1607, + 1607, 1606, // 1605, // 1604, @@ -397,7 +397,7 @@ static const int included_patches[] = { // 1527, // 1526, // 1525, - // 1524, + 1524, // 1523, // 1522, // 1521, @@ -420,9 +420,9 @@ static const int included_patches[] = { 1504, 1503, 1502, - // 1501, + 1501, 1500, - // 1499, + 1499, 1498, 1497, 1496, @@ -573,7 +573,7 @@ static const int included_patches[] = { 1351, 1350, // 1349, - // 1348, + 1348, // 1347, // 1346, // 1345, @@ -623,7 +623,7 @@ static const int included_patches[] = { 1301, // 1300, 1299, - // 1298, + 1298, // 1297, // 1296, // 1295, @@ -651,11 +651,11 @@ static const int included_patches[] = { 1273, 1272, 1271, - // 1270, + 1270, 1269, 1268, 1267, - // 1266, + 1266, 1265, // 1264, 1263, @@ -783,7 +783,7 @@ static const int included_patches[] = { 1141, 1140, // 1139, - // 1138, + 1138, 1137, 1136, 1135, @@ -857,10 +857,10 @@ static const int included_patches[] = { 1067, 1066, 1065, - // 1064, - // 1063, + 1064, + 1063, 1062, - // 1061, + 1061, // 1060, 1059, // 1058, @@ -893,7 +893,7 @@ static const int included_patches[] = { 1031, 1030, 1029, - // 1028, + 1028, 1027, 1026, 1025, @@ -969,14 +969,14 @@ static const int included_patches[] = { 955, 954, // 953, - // 952, + 952, 951, 950, - // 949, + 949, 948, // 947, 946, - // 945, + 945, 944, // 943, // 942, @@ -993,7 +993,7 @@ static const int included_patches[] = { // 931, // 930, // 929, - // 928, + 928, // 927, // 926, 925, @@ -1010,13 +1010,13 @@ static const int included_patches[] = { // 914, // 913, // 912, - // 911, + 911, // 910, // 909, // 908, - // 907, + 907, 906, - // 905, + 905, 904, 903, // 902, @@ -1024,16 +1024,16 @@ static const int included_patches[] = { 900, // 899, // 898, - // 897, + 897, // 896, 895, 894, // 893, // 892, - // 891, + 891, 890, - // 889, - // 888, + 889, + 888, // 887, 886, // 885, @@ -1048,12 +1048,12 @@ static const int included_patches[] = { 876, 875, // 874, - // 873, + 873, 872, 871, // 870, // 869, - // 868, + 868, // 867, 866, 865, @@ -1061,113 +1061,113 @@ static const int included_patches[] = { // 863, 862, 861, - // 860, - // 859, + 860, + 859, 858, - // 857, - // 856, - // 855, - // 854, + 857, + 856, + 855, + 854, 853, - // 852, + 852, 851, - // 850, - // 849, - // 848, + 850, + 849, + 848, 847, - // 846, - // 845, + 846, + 845, 844, 843, - // 842, - // 841, + 842, + 841, 840, - // 839, - // 838, + 839, + 838, 837, - // 836, + 836, 835, 834, - // 833, - // 832, + 833, + 832, 831, 830, - // 829, + 829, 828, - // 827, - // 826, + 827, + 826, // 825, - // 824, - // 823, + 824, + 823, 822, // 821, - // 820, - // 819, + 820, + 819, // 818, // 817, // 816, - // 815, + 815, 814, - // 813, + 813, 812, 811, 810, 809, 808, - // 807, + 807, 806, 805, 804, // 803, 802, - // 801, - // 800, + 801, + 800, 799, - // 798, + 798, 797, 796, 795, 794, - // 793, + 793, 792, 791, 790, - // 789, - // 788, - // 787, + 789, + 788, + 787, 786, - // 785, - // 784, - // 783, + 785, + 784, + 783, 782, - // 781, + 781, 780, - // 779, + 779, 778, - // 777, + 777, 776, - // 775, + 775, 774, 773, 772, 771, 770, - // 769, + 769, 768, 767, - // 766, + 766, 765, - // 764, + 764, 763, 762, 761, - // 760, + 760, 759, 758, 757, 756, - // 755, - // 754, + 755, + 754, 753, 752, 751, @@ -1189,7 +1189,7 @@ static const int included_patches[] = { 735, 734, 733, - // 732, + 732, 731, 730, 729, @@ -1206,7 +1206,7 @@ static const int included_patches[] = { 718, 717, 716, - // 715, + 715, 714, 713, 712, @@ -1407,7 +1407,7 @@ static const int included_patches[] = { 517, 516, 515, - // 514, + 514, 513, 512, 511, |