aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c28
-rw-r--r--src/nvim/ex_docmd.c18
-rw-r--r--src/nvim/main.c58
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/screen.c6
-rw-r--r--src/nvim/testdir/setup.vim1
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim21
-rw-r--r--src/nvim/testdir/test_execute_func.vim29
-rw-r--r--src/nvim/testdir/test_messages.vim21
-rw-r--r--src/nvim/tui/input.c46
-rw-r--r--src/nvim/version.c176
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,