aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt5
-rw-r--r--runtime/doc/job_control.txt4
-rw-r--r--runtime/doc/options.txt1
-rw-r--r--runtime/doc/starting.txt10
-rw-r--r--runtime/doc/vim_diff.txt12
-rw-r--r--src/nvim/README.md35
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/ex_docmd.c13
-rw-r--r--src/nvim/ex_getln.c6
-rw-r--r--src/nvim/message.c45
-rw-r--r--src/nvim/option.c11
-rw-r--r--src/nvim/testdir/test_cmdline.vim25
-rw-r--r--src/nvim/testdir/test_functions.vim34
-rw-r--r--src/nvim/tui/terminfo.c87
-rw-r--r--src/nvim/tui/tui.c72
-rw-r--r--src/nvim/ui_bridge.c3
-rw-r--r--src/nvim/version.c4
-rw-r--r--test/functional/eval/null_spec.lua16
-rw-r--r--test/functional/helpers.lua7
-rw-r--r--test/functional/terminal/tui_spec.lua65
-rw-r--r--test/functional/ui/cmdline_spec.lua363
-rw-r--r--test/functional/ui/screen.lua4
-rw-r--r--third-party/cmake/BuildLuarocks.cmake13
23 files changed, 623 insertions, 216 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index d2a3a962e6..71551e38e9 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -8889,11 +8889,6 @@ This does NOT work: >
value and the global value are changed.
Example: >
:let &path = &path . ',/usr/local/include'
-< This also works for terminal codes in the form t_xx.
- But only for alphanumerical names. Example: >
- :let &t_k1 = "\<Esc>[234;"
-< When the code does not exist yet it will be created as
- a terminal key code, there is no error.
:let &{option-name} .= {expr1}
For a string option: Append {expr1} to the value.
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt
index 7df43d6793..ed5f16902a 100644
--- a/runtime/doc/job_control.txt
+++ b/runtime/doc/job_control.txt
@@ -30,7 +30,7 @@ To control jobs, use the "job…" family of functions: |jobstart()|,
Example: >
- function! s:JobHandler(job_id, data, event) dict
+ function! s:OnEvent(job_id, data, event) dict
if a:event == 'stdout'
let str = self.shell.' stdout: '.join(a:data)
elseif a:event == 'stderr'
@@ -58,7 +58,7 @@ Description of what happens:
- The first shell is idle, waiting to read commands from its stdin.
- The second shell is started with -c which executes the command (a for-loop
printing 0 through 9) and then exits.
- - `JobHandler()` callback is passed to |jobstart()| to handle various job
+ - `OnEvent()` callback is passed to |jobstart()| to handle various job
events. It displays stdout/stderr data received from the shells.
For |on_stdout| and |on_stderr| see |channel-callback|.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 4fe2e07909..4180ca21f2 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6424,6 +6424,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Currently, these messages are given:
>= 1 When the shada file is read or written.
>= 2 When a file is ":source"'ed.
+ >= 3 UI info, terminal capabilities
>= 5 Every searched tags file and include file.
>= 8 Files for which a group of autocommands is executed.
>= 9 Every executed autocommand.
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 9b33926d04..30c0641ef7 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -249,14 +249,14 @@ argument.
for reading or writing a ShaDa file. Can be used to find
out what is happening upon startup and exit.
Example: >
- vim -V8 foobar
+ nvim -V8
-V[N]{filename}
- Like -V and set 'verbosefile' to {filename}. The result is
- that messages are not displayed but written to the file
- {filename}. {filename} must not start with a digit.
+ Like -V and set 'verbosefile' to {filename}. Messages are not
+ displayed; instead they are written to the file {filename}.
+ {filename} must not start with a digit.
Example: >
- vim -V20vimlog foobar
+ nvim -V20vimlog
<
*-D*
-D Debugging. Go to debugging mode when executing the first
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index c8155f7a68..45c88f6fe9 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -327,22 +327,26 @@ Ed-compatible mode:
":set noedcompatible" is ignored
":set edcompatible" is an error
- *t_xx* *:set-termcap* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*
+ *t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*
Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure
terminal capabilities. Instead Nvim treats the terminal as any other UI. For
example, 'guicursor' sets the terminal cursor style if possible.
- *'term'* *E529* *E530* *E531*
+ *:set-termcap*
+Start Nvim with 'verbose' level 3 to see the terminal capabilities. >
+ nvim -V3
+<
+ *'term'* *E529* *E530* *E531*
'term' reflects the terminal type derived from |$TERM| and other environment
checks. For debugging only; not reliable during startup. >
:echo &term
"builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system.
- *termcap*
+ *termcap*
Nvim never uses the termcap database, only |terminfo| and |builtin-terms|.
- *xterm-8bit* *xterm-8-bit*
+ *xterm-8bit* *xterm-8-bit*
Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this
requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8
mode, as the 8-bit CSI character has to be written differently in each case.
diff --git a/src/nvim/README.md b/src/nvim/README.md
index 0caf71e2c5..da87a0208e 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -32,6 +32,39 @@ The source files use extensions to hint about their purpose.
- `*.h.generated.h` - exported functions’ declarations.
- `*.c.generated.h` - static functions’ declarations.
+TUI debugging
+-------------
+
+### TUI troubleshoot
+
+Nvim logs its internal terminfo state at 'verbose' level 3. This makes it
+possible to see exactly what terminfo values Nvim is using on any system.
+
+ nvim -V3log
+
+### TUI trace
+
+The ancient `script` command is still the "state of the art" for tracing
+terminal behavior. The libvterm `vterm-dump` utility formats the result for
+human-readability.
+
+Record a Nvim terminal session and format it with `vterm-dump`:
+
+ script foo
+ ./build/bin/nvim -u NONE
+ # Exit the script session with CTRL-d
+
+ # Use `vterm-dump` utility to format the result.
+ ./.deps/usr/bin/vterm-dump foo > bar
+
+Then you can compare `bar` with another session, to debug TUI behavior.
+
+### Terminal reference
+
+- `man terminfo`
+- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt
+- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+
Nvim lifecycle
--------------
@@ -39,7 +72,7 @@ Following describes how Nvim processes input.
Consider a typical Vim-like editing session:
-01. Vim dispays the welcome screen
+01. Vim displays the welcome screen
02. User types: `:`
03. Vim enters command-line mode
04. User types: `edit README.txt<CR>`
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 577aa67c60..56aedb1b4e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8457,11 +8457,13 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
int idx = 0;
if (argvars[0].v_type == VAR_LIST) {
+ tv_copy(&argvars[0], rettv);
if ((l = argvars[0].vval.v_list) == NULL
|| (!map && tv_check_lock(l->lv_lock, arg_errmsg, TV_TRANSLATE))) {
return;
}
} else if (argvars[0].v_type == VAR_DICT) {
+ tv_copy(&argvars[0], rettv);
if ((d = argvars[0].vval.v_dict) == NULL
|| (!map && tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) {
return;
@@ -8542,8 +8544,6 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
did_emsg |= save_did_emsg;
}
-
- tv_copy(&argvars[0], rettv);
}
static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 5180420eff..e11788531b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -3484,10 +3484,17 @@ char_u *skip_range(
{
unsigned delim;
- while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;", *cmd) != NULL) {
- if (*cmd == '\'') {
- if (*++cmd == NUL && ctx != NULL)
+ while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;\\", *cmd) != NULL) {
+ if (*cmd == '\\') {
+ if (cmd[1] == '?' || cmd[1] == '/' || cmd[1] == '&') {
+ cmd++;
+ } else {
+ break;
+ }
+ } else if (*cmd == '\'') {
+ if (*++cmd == NUL && ctx != NULL) {
*ctx = EXPAND_NOTHING;
+ }
} else if (*cmd == '/' || *cmd == '?') {
delim = *cmd++;
while (*cmd != NUL && *cmd != delim)
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index c1500e3121..99330c177c 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -3455,8 +3455,10 @@ nextwild (
return FAIL;
}
- MSG_PUTS("..."); /* show that we are busy */
- ui_flush();
+ if (!ui_is_external(kUIWildmenu)) {
+ MSG_PUTS("..."); // show that we are busy
+ ui_flush();
+ }
i = (int)(xp->xp_pattern - ccline.cmdbuff);
xp->xp_pattern_len = ccline.cmdpos - i;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index b90c475ede..5c8f0655bf 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1237,31 +1237,30 @@ void msg_make(char_u *arg)
}
}
-/*
- * Output the string 'str' upto a NUL character.
- * Return the number of characters it takes on the screen.
- *
- * If K_SPECIAL is encountered, then it is taken in conjunction with the
- * following character and shown as <F1>, <S-Up> etc. Any other character
- * which is not printable shown in <> form.
- * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
- * If a character is displayed in one of these special ways, is also
- * highlighted (its highlight name is '8' in the p_hl variable).
- * Otherwise characters are not highlighted.
- * This function is used to show mappings, where we want to see how to type
- * the character/string -- webb
- */
-int
-msg_outtrans_special (
- char_u *strstart,
- int from /* TRUE for lhs of a mapping */
+/// Output the string 'str' upto a NUL character.
+/// Return the number of characters it takes on the screen.
+///
+/// If K_SPECIAL is encountered, then it is taken in conjunction with the
+/// following character and shown as <F1>, <S-Up> etc. Any other character
+/// which is not printable shown in <> form.
+/// If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
+/// If a character is displayed in one of these special ways, is also
+/// highlighted (its highlight name is '8' in the p_hl variable).
+/// Otherwise characters are not highlighted.
+/// This function is used to show mappings, where we want to see how to type
+/// the character/string -- webb
+int msg_outtrans_special(
+ const char_u *strstart,
+ int from ///< true for LHS of a mapping
)
{
- char_u *str = strstart;
+ if (strstart == NULL) {
+ return 0; // Do nothing.
+ }
+ const char_u *str = strstart;
int retval = 0;
- int attr;
+ int attr = hl_attr(HLF_8);
- attr = hl_attr(HLF_8);
while (*str != NUL) {
const char *string;
// Leading and trailing spaces need to be displayed in <> form.
@@ -1307,7 +1306,7 @@ char *str2special_save(const char *const str, const bool replace_spaces,
return (char *)ga.ga_data;
}
-/// Convert character, replacing key one key code with printable representation
+/// Convert character, replacing key with printable representation.
///
/// @param[in,out] sp String to convert. Is advanced to the next key code.
/// @param[in] replace_spaces Convert spaces into <Space>, normally used for
@@ -1392,7 +1391,7 @@ void str2specialbuf(const char *sp, char *buf, size_t len)
while (*sp) {
const char *s = str2special(&sp, false, false);
const size_t s_len = strlen(s);
- if (s_len <= len) {
+ if (len <= s_len) {
break;
}
memcpy(buf, s, s_len);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 913d27d508..37c4233142 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4906,15 +4906,14 @@ showoptions (
vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT);
- /* Highlight title */
- if (all == 2)
- MSG_PUTS_TITLE(_("\n--- Terminal codes ---"));
- else if (opt_flags & OPT_GLOBAL)
+ // Highlight title
+ if (opt_flags & OPT_GLOBAL) {
MSG_PUTS_TITLE(_("\n--- Global option values ---"));
- else if (opt_flags & OPT_LOCAL)
+ } else if (opt_flags & OPT_LOCAL) {
MSG_PUTS_TITLE(_("\n--- Local option values ---"));
- else
+ } else {
MSG_PUTS_TITLE(_("\n--- Options ---"));
+ }
/*
* do the loop two times:
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 5fc519f822..ac44e09a5a 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -306,3 +306,28 @@ func Test_cmdline_complete_wildoptions()
call assert_equal(a, b)
bw!
endfunc
+
+" using a leading backslash here
+set cpo+=C
+
+func Test_cmdline_search_range()
+ new
+ call setline(1, ['a', 'b', 'c', 'd'])
+ /d
+ 1,\/s/b/B/
+ call assert_equal('B', getline(2))
+
+ /a
+ $
+ \?,4s/c/C/
+ call assert_equal('C', getline(3))
+
+ call setline(1, ['a', 'b', 'c', 'd'])
+ %s/c/c/
+ 1,\&s/b/B/
+ call assert_equal('B', getline(2))
+
+ bwipe!
+endfunc
+
+set cpo&
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 59807ca946..0ce034b63e 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -207,39 +207,73 @@ func! Test_mode()
normal! 3G
exe "normal i\<F2>\<Esc>"
call assert_equal('i-i', g:current_modes)
+ " i_CTRL-P: Multiple matches
exe "normal i\<C-G>uBa\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-P: Single match
exe "normal iBro\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X
exe "normal iBa\<C-X>\<F2>\<Esc>u"
call assert_equal('i-ix', g:current_modes)
+ " i_CTRL-X CTRL-P: Multiple matches
exe "normal iBa\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P: Single match
exe "normal iBro\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P + CTRL-P: Single match
exe "normal iBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: Multiple matches
+ exe "normal i\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: Single match
+ exe "normal iBlu\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-P: No match
exe "normal iCom\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P: No match
exe "normal iCom\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: No match
+ exe "normal iabc\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " R_CTRL-P: Multiple matches
exe "normal RBa\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-P: Single match
exe "normal RBro\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X
exe "normal RBa\<C-X>\<F2>\<Esc>u"
call assert_equal('R-Rx', g:current_modes)
+ " R_CTRL-X CTRL-P: Multiple matches
exe "normal RBa\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P: Single match
exe "normal RBro\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P + CTRL-P: Single match
exe "normal RBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: Multiple matches
+ exe "normal R\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: Single match
+ exe "normal RBlu\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-P: No match
exe "normal RCom\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P: No match
exe "normal RCom\<C-X>\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: No match
+ exe "normal Rabc\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
call assert_equal('n', mode(0))
call assert_equal('n', mode(1))
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index fdc33f0a77..492c1c5e9c 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -9,7 +9,10 @@
#include <unibilium.h>
#include "nvim/log.h"
+#include "nvim/globals.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/option.h"
#include "nvim/tui/terminfo.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -166,3 +169,87 @@ unibi_term *terminfo_from_builtin(const char *term, char **termname)
unibi_set_bool(ut, unibi_back_color_erase, false);
return ut;
}
+
+/// Dumps termcap info to the messages area.
+/// Serves a similar purpose as Vim `:set termcap` (removed in Nvim).
+///
+/// @note adapted from unibilium unibi-dump.c
+void terminfo_info_msg(const unibi_term *const ut)
+{
+ if (exiting) {
+ return;
+ }
+ msg_puts_title("\n\n--- Terminal info --- {{{\n");
+
+ char *term;
+ get_tty_option("term", &term);
+ msg_printf_attr(0, "&term: %s\n", term);
+ msg_printf_attr(0, "Description: %s\n", unibi_get_name(ut));
+ const char **a = unibi_get_aliases(ut);
+ if (*a) {
+ msg_puts("Aliases: ");
+ do {
+ msg_printf_attr(0, "%s%s\n", *a, a[1] ? " | " : "");
+ a++;
+ } while (*a);
+ }
+
+ msg_puts("Boolean capabilities:\n");
+ for (enum unibi_boolean i = unibi_boolean_begin_ + 1;
+ i < unibi_boolean_end_; i++) {
+ msg_printf_attr(0, " %-25s %-10s = %s\n", unibi_name_bool(i),
+ unibi_short_name_bool(i),
+ unibi_get_bool(ut, i) ? "true" : "false");
+ }
+
+ msg_puts("Numeric capabilities:\n");
+ for (enum unibi_numeric i = unibi_numeric_begin_ + 1;
+ i < unibi_numeric_end_; i++) {
+ int n = unibi_get_num(ut, i); // -1 means "empty"
+ msg_printf_attr(0, " %-25s %-10s = %hd\n", unibi_name_num(i),
+ unibi_short_name_num(i), n);
+ }
+
+ msg_puts("String capabilities:\n");
+ for (enum unibi_string i = unibi_string_begin_ + 1;
+ i < unibi_string_end_; i++) {
+ const char *s = unibi_get_str(ut, i);
+ if (s) {
+ msg_printf_attr(0, " %-25s %-10s = ", unibi_name_str(i),
+ unibi_short_name_str(i));
+ // Most of these strings will contain escape sequences.
+ msg_outtrans_special((char_u *)s, false);
+ msg_putchar('\n');
+ }
+ }
+
+ if (unibi_count_ext_bool(ut)) {
+ msg_puts("Extended boolean capabilities:\n");
+ for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) {
+ msg_printf_attr(0, " %-25s = %s\n",
+ unibi_get_ext_bool_name(ut, i),
+ unibi_get_ext_bool(ut, i) ? "true" : "false");
+ }
+ }
+
+ if (unibi_count_ext_num(ut)) {
+ msg_puts("Extended numeric capabilities:\n");
+ for (size_t i = 0; i < unibi_count_ext_num(ut); i++) {
+ msg_printf_attr(0, " %-25s = %hd\n",
+ unibi_get_ext_num_name(ut, i),
+ unibi_get_ext_num(ut, i));
+ }
+ }
+
+ if (unibi_count_ext_str(ut)) {
+ msg_puts("Extended string capabilities:\n");
+ for (size_t i = 0; i < unibi_count_ext_str(ut); i++) {
+ msg_printf_attr(0, " %-25s = ", unibi_get_ext_str_name(ut, i));
+ msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false);
+ msg_putchar('\n');
+ }
+ }
+
+ msg_puts("}}}\n");
+ xfree(term);
+}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 61d3bde450..6e2a5cbe67 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -357,10 +357,12 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
tui_terminal_start(ui);
data->stop = false;
- // allow the main thread to continue, we are ready to start handling UI
- // callbacks
+ // Allow main thread to continue, we are ready to handle UI callbacks.
CONTINUE(bridge);
+ loop_schedule_deferred(&main_loop,
+ event_create(show_termcap_event, 1, data->ut));
+
while (!data->stop) {
loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed
}
@@ -1064,6 +1066,24 @@ static void tui_flush(UI *ui)
flush_buf(ui);
}
+/// Dumps termcap info to the messages area, if 'verbose' >= 3.
+static void show_termcap_event(void **argv)
+{
+ if (p_verbose < 3) {
+ return;
+ }
+ const unibi_term *const ut = argv[0];
+ if (!ut) {
+ abort();
+ }
+ verbose_enter();
+ // XXX: (future) if unibi_term is modified (e.g. after a terminal
+ // query-response) this is a race condition.
+ terminfo_info_msg(ut);
+ verbose_leave();
+ verbose_stop(); // flush now
+}
+
#ifdef UNIX
static void suspend_event(void **argv)
{
@@ -1482,19 +1502,18 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
}
}
- // Some terminals cannot be trusted to report DECSCUSR support. So we keep
- // blacklist for when we should not trust the reported features.
- if (!((vte_version != 0 && vte_version < 3900) || konsole)) {
- // Dickey ncurses terminfo has included the Ss and Se capabilities,
- // pioneered by tmux, since 2011-07-14. So adding them to terminal types,
- // that do actually have such control sequences but lack the correct
- // definitions in terminfo, is a fixup, not an augmentation.
+ // Blacklist of terminals that cannot be trusted to report DECSCUSR support.
+ if (!(st || (vte_version != 0 && vte_version < 3900) || konsole)) {
data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se");
data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
}
+
+ // Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So
+ // adding them to terminal types, that have such control sequences but lack
+ // the correct terminfo entries, is a fixup, not an augmentation.
if (-1 == data->unibi_ext.set_cursor_style) {
- // The DECSCUSR sequence to change the cursor shape is widely supported by
- // several terminal types. https://github.com/gnachman/iTerm2/pull/92
+ // DECSCUSR (cursor shape) sequence is widely supported by several terminal
+ // types. https://github.com/gnachman/iTerm2/pull/92
// xterm extension: vertical bar
if (!konsole && ((xterm && !vte_version) // anything claiming xterm compat
// per MinTTY 0.4.3-1 release notes from 2009
@@ -1504,6 +1523,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| tmux // per tmux manual page
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
|| screen
+ || st // #7641
|| rxvt // per command.C
// per analysis of VT100Terminal.m
|| iterm || iterm_pretending_xterm
@@ -1599,11 +1619,13 @@ static void augment_terminfo(TUIData *data, const char *term,
|| konsole // per commentary in VT102Emulation.cpp
|| teraterm // per TeraTerm "Supported Control Functions" doco
|| rxvt) { // per command.C
- data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
+ "ext.resize_screen",
"\x1b[8;%p1%d;%p2%dt");
}
if (putty || xterm || rxvt) {
- data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut,
+ "ext.reset_scroll_region",
"\x1b[r");
}
@@ -1661,21 +1683,29 @@ static void augment_terminfo(TUIData *data, const char *term,
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
- data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut,
+ "ext.enable_lr_margin",
"\x1b[?69h");
- data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut,
+ "ext.disable_lr_margin",
"\x1b[?69l");
- data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut,
+ "ext.enable_bpaste",
"\x1b[?2004h");
- data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut,
+ "ext.disable_bpaste",
"\x1b[?2004l");
- data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut,
+ "ext.enable_focus",
rxvt ? "\x1b]777;focus;on\x7" : "\x1b[?1004h");
- data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut,
+ "ext.disable_focus",
rxvt ? "\x1b]777;focus;off\x7" : "\x1b[?1004l");
- data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut,
+ "ext.enable_mouse",
"\x1b[?1002h\x1b[?1006h");
- data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, NULL,
+ data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut,
+ "ext.disable_mouse",
"\x1b[?1002l\x1b[?1006l");
}
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 5585886612..7573fa1653 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -82,6 +82,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
abort();
}
+ // Suspend the main thread until CONTINUE is called by the UI thread.
while (!rv->ready) {
uv_cond_wait(&rv->cond, &rv->mutex);
}
@@ -149,7 +150,7 @@ static void ui_bridge_suspend(UI *b)
uv_mutex_lock(&data->mutex);
UI_BRIDGE_CALL(b, suspend, 1, b);
data->ready = false;
- // suspend the main thread until CONTINUE is called by the UI thread
+ // Suspend the main thread until CONTINUE is called by the UI thread.
while (!data->ready) {
uv_cond_wait(&data->cond, &data->mutex);
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 96161c91ff..8d85855c6e 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -950,7 +950,7 @@ static const int included_patches[] = {
// 309,
308,
307,
- // 306,
+ 306,
305,
// 304,
// 303,
@@ -958,7 +958,7 @@ static const int included_patches[] = {
// 301,
300,
// 299,
- // 298,
+ 298,
297,
// 296,
295,
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
index 6fd30caec9..b67158eb22 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/eval/null_spec.lua
@@ -42,14 +42,6 @@ describe('NULL', function()
describe('list', function()
-- Incorrect behaviour
- -- FIXME map() should not return 0 without error
- null_expr_test('does not crash map()', 'map(L, "v:val")', 0, 0)
- -- FIXME map() should not return 0 without error
- null_expr_test('does not crash filter()', 'filter(L, "1")', 0, 0)
- -- FIXME map() should at least return L
- null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 0)
- -- FIXME filter() should at least return L
- null_expr_test('makes filter() return v:_null_list', 'map(L, "1") is# L', 0, 0)
-- FIXME add() should not return 1 at all
null_expr_test('does not crash add()', 'add(L, 0)', 0, 1)
null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0)
@@ -111,6 +103,8 @@ describe('NULL', function()
null_expr_test('does not crash line()', 'line(L)', 0, 0)
null_expr_test('does not crash count()', 'count(L, 1)', 0, 0)
null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1)
+ null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {})
+ null_expr_test('does not crash filter()', 'filter(L, "1")', 0, {})
null_expr_test('is empty', 'empty(L)', 0, 1)
null_expr_test('does not crash get()', 'get(L, 1, 10)', 0, 10)
null_expr_test('has zero length', 'len(L)', 0, 0)
@@ -126,6 +120,8 @@ describe('NULL', function()
null_expr_test('is equal to itself', 'L == L', 0, 1)
null_expr_test('is not not equal to itself', 'L != L', 0, 0)
null_expr_test('counts correctly', 'count([L], L)', 0, 1)
+ null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 1)
+ null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1)
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
@@ -134,5 +130,9 @@ describe('NULL', function()
end)
null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
null_expr_test('makes extend do nothing', 'extend({1: 2}, D)', 0, {['1']=2})
+ null_expr_test('does not crash map()', 'map(D, "v:val")', 0, {})
+ null_expr_test('does not crash filter()', 'filter(D, "1")', 0, {})
+ null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1)
+ null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1)
end)
end)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index da334d4ac6..f939567693 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -261,6 +261,7 @@ local function retry(max, max_ms, fn)
if status then
return result
end
+ luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
if (max and tries >= max) or (luv.now() - start_time > timeout) then
if type(result) == "string" then
result = "\nretry() attempts: "..tostring(tries).."\n"..result
@@ -333,8 +334,8 @@ local function feed_command(...)
end
-- Dedent the given text and write it to the file name.
-local function write_file(name, text, dont_dedent)
- local file = io.open(name, 'w')
+local function write_file(name, text, no_dedent, append)
+ local file = io.open(name, (append and 'a' or 'w'))
if type(text) == 'table' then
-- Byte blob
local bytes = text
@@ -342,7 +343,7 @@ local function write_file(name, text, dont_dedent)
for _, char in ipairs(bytes) do
text = ('%s%c'):format(text, char)
end
- elseif not dont_dedent then
+ elseif not no_dedent then
text = dedent(text)
end
file:write(text)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index d5f6a21d1d..bf3c6bdb3a 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -4,6 +4,7 @@ local global_helpers = require('test.helpers')
local uname = global_helpers.uname
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
+local eq = helpers.eq
local feed_data = thelpers.feed_data
local feed_command = helpers.feed_command
local clear = helpers.clear
@@ -11,6 +12,8 @@ local nvim_dir = helpers.nvim_dir
local retry = helpers.retry
local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
+local ok = helpers.ok
+local read_file = helpers.read_file
if helpers.pending_win32(pending) then return end
@@ -21,9 +24,6 @@ describe('tui', function()
clear()
screen = thelpers.screen_setup(0, '["'..nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler undodir=. directory=. viewdir=. backupdir=."]')
- -- right now pasting can be really slow in the TUI, especially in ASAN.
- -- this will be fixed later but for now we require a high timeout.
- screen.timeout = 60000
screen:expect([[
{1: } |
{4:~ }|
@@ -125,6 +125,9 @@ describe('tui', function()
end)
it('automatically sends <Paste> for bracketed paste sequences', function()
+ -- Pasting can be really slow in the TUI, specially in ASAN.
+ -- This will be fixed later but for now we require a high timeout.
+ screen.timeout = 60000
feed_data('i\027[200~')
screen:expect([[
{1: } |
@@ -158,6 +161,8 @@ describe('tui', function()
end)
it('can handle arbitrarily long bursts of input', function()
+ -- Need extra time for this test, specially in ASAN.
+ screen.timeout = 60000
feed_command('set ruler')
local t = {}
for i = 1, 3000 do
@@ -639,6 +644,7 @@ end)
describe("tui 'term' option", function()
local screen
local is_bsd = not not string.find(string.lower(uname()), 'bsd')
+ local is_macos = not not string.find(string.lower(uname()), 'darwin')
local function assert_term(term_envvar, term_expected)
clear()
@@ -664,11 +670,62 @@ describe("tui 'term' option", function()
end)
it('gets system-provided term if $TERM is valid', function()
- if is_bsd then -- BSD lacks terminfo, we always use builtin there.
+ if is_bsd then -- BSD lacks terminfo, builtin is always used.
assert_term("xterm", "builtin_xterm")
+ elseif is_macos then
+ local status, _ = pcall(assert_term, "xterm", "xterm")
+ if not status then
+ pending("macOS: unibilium could not find terminfo", function() end)
+ end
else
assert_term("xterm", "xterm")
end
end)
end)
+
+-- These tests require `thelpers` because --headless/--embed
+-- does not initialize the TUI.
+describe("tui", function()
+ local screen
+ local logfile = 'Xtest_tui_verbose_log'
+ after_each(function()
+ os.remove(logfile)
+ end)
+
+ -- Runs (child) `nvim` in a TTY (:terminal), to start the builtin TUI.
+ local function nvim_tui(extra_args)
+ clear()
+ -- This is ugly because :term/termopen() forces TERM=xterm-256color.
+ -- TODO: Revisit this after jobstart/termopen accept `env` dict.
+ local cmd = string.format(
+ [=[['sh', '-c', 'LANG=C %s -u NONE -i NONE %s --cmd "%s"']]=],
+ nvim_prog,
+ extra_args or "",
+ nvim_set)
+ screen = thelpers.screen_setup(0, cmd)
+ end
+
+ it('-V3log logs terminfo values', function()
+ nvim_tui('-V3'..logfile)
+
+ -- Wait for TUI to start.
+ feed_data('Gitext')
+ screen:expect([[
+ text{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+
+ retry(nil, 3000, function() -- Wait for log file to be flushed.
+ local log = read_file('Xtest_tui_verbose_log') or ''
+ eq('--- Terminal info --- {{{\n', string.match(log, '--- Terminal.-\n'))
+ ok(#log > 50)
+ end)
+ end)
+
+end)
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 0f8302b036..c9ee61fb1e 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -10,12 +10,19 @@ describe('external cmdline', function()
local last_level = 0
local cmdline = {}
local block = nil
+ local wild_items = nil
+ local wild_selected = nil
before_each(function()
clear()
cmdline, block = {}, nil
screen = Screen.new(25, 5)
screen:attach({rgb=true, ext_cmdline=true})
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {reverse = true},
+ [3] = {bold = true, reverse = true},
+ })
screen:set_on_event_handler(function(name, data)
if name == "cmdline_show" then
local content, pos, firstc, prompt, indent, level = unpack(data)
@@ -38,6 +45,12 @@ describe('external cmdline', function()
block[#block+1] = data[1]
elseif name == "cmdline_block_hide" then
block = nil
+ elseif name == "wildmenu_show" then
+ wild_items = data[1]
+ elseif name == "wildmenu_select" then
+ wild_selected = data[1]
+ elseif name == "wildmenu_hide" then
+ wild_items, wild_selected = nil, nil
end
end)
end)
@@ -66,9 +79,9 @@ describe('external cmdline', function()
feed(':')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq(1, last_level)
@@ -84,9 +97,9 @@ describe('external cmdline', function()
feed('sign')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -101,9 +114,9 @@ describe('external cmdline', function()
feed('<Left>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -118,9 +131,9 @@ describe('external cmdline', function()
feed('<bs>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -135,9 +148,9 @@ describe('external cmdline', function()
feed('<Esc>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({}, cmdline)
@@ -148,9 +161,9 @@ describe('external cmdline', function()
feed(':call input("input", "default")<cr>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -164,9 +177,9 @@ describe('external cmdline', function()
feed('<cr>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({}, cmdline)
@@ -178,9 +191,9 @@ describe('external cmdline', function()
feed(':xx<c-r>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -196,9 +209,9 @@ describe('external cmdline', function()
feed('=')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -234,9 +247,9 @@ describe('external cmdline', function()
}}
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq(expectation, cmdline)
@@ -249,9 +262,9 @@ describe('external cmdline', function()
-- focus is at external cmdline anyway.
screen:expect([[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
^ |
]], nil, nil, function()
eq(expectation, cmdline)
@@ -261,9 +274,9 @@ describe('external cmdline', function()
feed('<cr>')
screen:expect([[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
^ |
]], nil, nil, function()
eq({{
@@ -278,9 +291,9 @@ describe('external cmdline', function()
feed('<esc>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({}, cmdline)
@@ -291,9 +304,9 @@ describe('external cmdline', function()
feed(':function Foo()<cr>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -309,9 +322,9 @@ describe('external cmdline', function()
feed('line1<cr>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{{{}, 'function Foo()'}},
@@ -322,9 +335,9 @@ describe('external cmdline', function()
command("redraw!")
screen:expect([[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
^ |
]], nil, nil, function()
eq({{{{}, 'function Foo()'}},
@@ -335,9 +348,9 @@ describe('external cmdline', function()
feed('endfunction<cr>')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq(nil, block)
@@ -348,9 +361,9 @@ describe('external cmdline', function()
feed(':make')
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -365,9 +378,9 @@ describe('external cmdline', function()
feed('<c-f>')
screen:expect([[
|
- [No Name] |
- :make^ |
- [Command Line] |
+ {2:[No Name] }|
+ {1::}make^ |
+ {3:[Command Line] }|
|
]], nil, nil, function()
eq({}, cmdline)
@@ -377,9 +390,9 @@ describe('external cmdline', function()
feed(':yank')
screen:expect([[
|
- [No Name] |
- :make^ |
- [Command Line] |
+ {2:[No Name] }|
+ {1::}make^ |
+ {3:[Command Line] }|
|
]], nil, nil, function()
eq({nil, {
@@ -395,9 +408,9 @@ describe('external cmdline', function()
command("redraw!")
screen:expect([[
|
- [No Name] |
- :make |
- [Command Line] |
+ {2:[No Name] }|
+ {1::}make |
+ {3:[Command Line] }|
^ |
]], nil, nil, function()
eq({nil, {
@@ -412,9 +425,9 @@ describe('external cmdline', function()
feed("<c-c>")
screen:expect([[
|
- [No Name] |
- :make^ |
- [Command Line] |
+ {2:[No Name] }|
+ {1::}make^ |
+ {3:[Command Line] }|
|
]], nil, nil, function()
eq({}, cmdline)
@@ -423,9 +436,9 @@ describe('external cmdline', function()
feed("<c-c>")
screen:expect([[
|
- [No Name] |
- :make^ |
- [Command Line] |
+ {2:[No Name] }|
+ {1::}make^ |
+ {3:[Command Line] }|
|
]], nil, nil, function()
eq({{
@@ -441,9 +454,9 @@ describe('external cmdline', function()
command("redraw!")
screen:expect([[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
^ |
]], nil, nil, function()
eq({{
@@ -460,9 +473,9 @@ describe('external cmdline', function()
feed(":call inputsecret('secret:')<cr>abc123")
screen:expect([[
^ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
|
]], nil, nil, function()
eq({{
@@ -476,50 +489,160 @@ describe('external cmdline', function()
end)
it('works with highlighted cmdline', function()
- source([[
- highlight RBP1 guibg=Red
- highlight RBP2 guibg=Yellow
- highlight RBP3 guibg=Green
- highlight RBP4 guibg=Blue
- let g:NUM_LVLS = 4
- function RainBowParens(cmdline)
- let ret = []
- let i = 0
- let lvl = 0
- while i < len(a:cmdline)
- if a:cmdline[i] is# '('
- call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
- let lvl += 1
- elseif a:cmdline[i] is# ')'
- let lvl -= 1
- call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
- endif
- let i += 1
- endwhile
- return ret
- endfunction
- map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr>
- "map <f5> :let x = input({'prompt':'>'})<cr>
- ]])
- screen:set_default_attr_ids({
- RBP1={background = Screen.colors.Red},
- RBP2={background = Screen.colors.Yellow},
- RBP3={background = Screen.colors.Green},
- RBP4={background = Screen.colors.Blue},
- EOB={bold = true, foreground = Screen.colors.Blue1},
- ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- SK={foreground = Screen.colors.Blue},
- PE={bold = true, foreground = Screen.colors.SeaGreen4}
- })
- feed('<f5>(a(b)a)')
- screen:expect([[
- ^ |
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- |
- ]], nil, nil, function()
- expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}')
- end)
+ source([[
+ highlight RBP1 guibg=Red
+ highlight RBP2 guibg=Yellow
+ highlight RBP3 guibg=Green
+ highlight RBP4 guibg=Blue
+ let g:NUM_LVLS = 4
+ function RainBowParens(cmdline)
+ let ret = []
+ let i = 0
+ let lvl = 0
+ while i < len(a:cmdline)
+ if a:cmdline[i] is# '('
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ let lvl += 1
+ elseif a:cmdline[i] is# ')'
+ let lvl -= 1
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
+ endif
+ let i += 1
+ endwhile
+ return ret
+ endfunction
+ map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr>
+ "map <f5> :let x = input({'prompt':'>'})<cr>
+ ]])
+ screen:set_default_attr_ids({
+ RBP1={background = Screen.colors.Red},
+ RBP2={background = Screen.colors.Yellow},
+ RBP3={background = Screen.colors.Green},
+ RBP4={background = Screen.colors.Blue},
+ EOB={bold = true, foreground = Screen.colors.Blue1},
+ ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ SK={foreground = Screen.colors.Blue},
+ PE={bold = true, foreground = Screen.colors.SeaGreen4}
+ })
+ feed('<f5>(a(b)a)')
+ screen:expect([[
+ ^ |
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ |
+ ]], nil, nil, function()
+ expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}')
+ end)
+ end)
+
+ it('works together with ext_wildmenu', function()
+ local expected = {
+ 'define',
+ 'jump',
+ 'list',
+ 'place',
+ 'undefine',
+ 'unplace',
+ }
+
+ command('set wildmode=full')
+ command('set wildmenu')
+ screen:set_option('ext_wildmenu', true)
+ feed(':sign <tab>')
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], nil, nil, function()
+ eq({{
+ content = { { {}, "sign define"} },
+ firstc = ":",
+ indent = 0,
+ pos = 11,
+ prompt = ""
+ }}, cmdline)
+ eq(expected, wild_items)
+ eq(0, wild_selected)
+ end)
+
+ feed('<tab>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], nil, nil, function()
+ eq({{
+ content = { { {}, "sign jump"} },
+ firstc = ":",
+ indent = 0,
+ pos = 9,
+ prompt = ""
+ }}, cmdline)
+ eq(expected, wild_items)
+ eq(1, wild_selected)
+ end)
+
+ feed('<left><left>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], nil, nil, function()
+ eq({{
+ content = { { {}, "sign "} },
+ firstc = ":",
+ indent = 0,
+ pos = 5,
+ prompt = ""
+ }}, cmdline)
+ eq(expected, wild_items)
+ eq(-1, wild_selected)
+ end)
+
+ feed('<right>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], nil, nil, function()
+ eq({{
+ content = { { {}, "sign define"} },
+ firstc = ":",
+ indent = 0,
+ pos = 11,
+ prompt = ""
+ }}, cmdline)
+ eq(expected, wild_items)
+ eq(0, wild_selected)
+ end)
+
+ feed('a')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], nil, nil, function()
+ eq({{
+ content = { { {}, "sign definea"} },
+ firstc = ":",
+ indent = 0,
+ pos = 12,
+ prompt = ""
+ }}, cmdline)
+ eq(nil, wild_items)
+ eq(nil, wild_selected)
+ end)
end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index a6b7fb2997..075d8c40d7 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -176,6 +176,10 @@ function Screen:try_resize(columns, rows)
self:sleep(0.1)
end
+function Screen:set_option(option, value)
+ uimeths.set_option(option, value)
+end
+
-- Asserts that `expected` eventually matches the screen state.
--
-- expected: Expected screen state (string). Each line represents a screen
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index ef8a8450f1..c7b7f8d837 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -96,8 +96,7 @@ if(USE_BUNDLED_LUAJIT)
endif()
endif()
-# Each target depends on the previous module, this serializes all calls to
-# luarocks since it is unhappy to be called in parallel.
+# DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack
COMMAND ${LUAROCKS_BINARY}
ARGS build mpack ${LUAROCKS_BUILDARGS}
@@ -106,7 +105,7 @@ add_custom_target(mpack
DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack)
list(APPEND THIRD_PARTY_DEPS mpack)
-
+# DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/lpeg
COMMAND ${LUAROCKS_BINARY}
ARGS build lpeg ${LUAROCKS_BUILDARGS}
@@ -116,16 +115,18 @@ add_custom_target(lpeg
list(APPEND THIRD_PARTY_DEPS lpeg)
+# DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect
COMMAND ${LUAROCKS_BINARY}
ARGS build inspect ${LUAROCKS_BUILDARGS}
- DEPENDS mpack)
+ DEPENDS lpeg)
add_custom_target(inspect
DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect)
list(APPEND THIRD_PARTY_DEPS inspect)
if(USE_BUNDLED_BUSTED)
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight/1.3.2-2
COMMAND ${LUAROCKS_BINARY}
ARGS build penlight 1.3.2-2 ${LUAROCKS_BUILDARGS}
@@ -138,6 +139,7 @@ if(USE_BUNDLED_BUSTED)
else()
set(BUSTED_EXE "${HOSTDEPS_BIN_DIR}/busted")
endif()
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${BUSTED_EXE}
COMMAND ${LUAROCKS_BINARY}
ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc12-1/busted-2.0.rc12-1.rockspec ${LUAROCKS_BUILDARGS}
@@ -145,6 +147,7 @@ if(USE_BUNDLED_BUSTED)
add_custom_target(busted
DEPENDS ${BUSTED_EXE})
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_BIN_DIR}/luacheck
COMMAND ${LUAROCKS_BINARY}
ARGS build https://raw.githubusercontent.com/mpeterv/luacheck/master/luacheck-scm-1.rockspec ${LUAROCKS_BUILDARGS}
@@ -160,6 +163,7 @@ if(USE_BUNDLED_BUSTED)
if(USE_BUNDLED_LIBUV)
list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR})
endif()
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv
COMMAND ${LUAROCKS_BINARY}
ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS}
@@ -168,6 +172,7 @@ if(USE_BUNDLED_BUSTED)
add_custom_target(luv
DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv)
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client
COMMAND ${LUAROCKS_BINARY}
ARGS build https://raw.githubusercontent.com/neovim/lua-client/0.0.1-26/nvim-client-0.0.1-26.rockspec ${LUAROCKS_BUILDARGS}