aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ci/build.ps12
-rw-r--r--runtime/doc/starting.txt3
-rw-r--r--src/nvim/api/private/dispatch.c3
-rw-r--r--src/nvim/api/private/helpers.c47
-rw-r--r--src/nvim/api/vim.c8
-rw-r--r--src/nvim/ex_cmds.c114
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/screen.c21
-rw-r--r--src/nvim/testdir/test_help.vim36
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim28
-rw-r--r--src/nvim/testdir/test_hlsearch.vim14
-rw-r--r--test/functional/api/buffer_spec.lua2
-rw-r--r--test/functional/api/tabpage_spec.lua2
-rw-r--r--test/functional/api/vim_spec.lua58
-rw-r--r--test/functional/api/window_spec.lua2
-rw-r--r--test/functional/ui/cmdline_spec.lua5
-rw-r--r--test/functional/ui/screen.lua231
-rw-r--r--test/functional/ui/searchhl_spec.lua54
-rw-r--r--third-party/CMakeLists.txt8
-rw-r--r--third-party/cmake/BuildLibvterm.cmake3
-rw-r--r--third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch53
23 files changed, 406 insertions, 295 deletions
diff --git a/ci/build.ps1 b/ci/build.ps1
index 7e686f3464..bb4d3a9b23 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -14,7 +14,7 @@ $nvimCmakeVars = @{
}
# For pull requests, skip some build configurations to save time.
-if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32)$') {
+if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32|MINGW_64-gcov)$') {
exit 0
}
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index c9ce2b9dc1..3440131642 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -76,7 +76,8 @@ The option arguments may be given in any order. Single-letter options can be
combined after one dash. There can be no option arguments after the "--"
argument.
---help *-h* *--help*
+--help *-h* *--help* *-?*
+-?
-h Give usage (help) message and exit.
See |info-message| about capturing the text.
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
index dec2b6c185..c08225bbfc 100644
--- a/src/nvim/api/private/dispatch.c
+++ b/src/nvim/api/private/dispatch.c
@@ -40,7 +40,8 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
map_get(String, MsgpackRpcRequestHandler)(methods, m);
if (!rv.fn) {
- api_set_error(error, kErrorTypeException, "Invalid method: %s",
+ api_set_error(error, kErrorTypeException, "Invalid method: %.*s",
+ m.size > 0 ? m.size : sizeof("<empty>"),
m.size > 0 ? m.data : "<empty>");
}
return rv;
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index f3e883de02..ecc0ede4a4 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -162,7 +162,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di == NULL) {
- api_set_error(err, kErrorTypeValidation, "Key '%s' not found", key.data);
+ api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data);
return (Object)OBJECT_INIT;
}
@@ -191,13 +191,12 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
}
if (key.size == 0) {
- api_set_error(err, kErrorTypeValidation,
- "Empty variable names aren't allowed");
+ api_set_error(err, kErrorTypeValidation, "Key name is empty");
return rv;
}
if (key.size > INT_MAX) {
- api_set_error(err, kErrorTypeValidation, "Key length is too high");
+ api_set_error(err, kErrorTypeValidation, "Key name is too long");
return rv;
}
@@ -220,7 +219,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
// Delete the key
if (di == NULL) {
// Doesn't exist, fail
- api_set_error(err, kErrorTypeValidation, "Key does not exist: %s",
+ api_set_error(err, kErrorTypeValidation, "Key not found: %s",
key.data);
} else {
// Return the old value
@@ -284,9 +283,7 @@ Object get_option_from(void *from, int type, String name, Error *err)
type, from);
if (!flags) {
- api_set_error(err,
- kErrorTypeValidation,
- "Invalid option name \"%s\"",
+ api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'",
name.data);
return rv;
}
@@ -303,15 +300,14 @@ Object get_option_from(void *from, int type, String name, Error *err)
rv.data.string.data = stringval;
rv.data.string.size = strlen(stringval);
} else {
- api_set_error(err,
- kErrorTypeException,
- "Unable to get value for option \"%s\"",
+ api_set_error(err, kErrorTypeException,
+ "Failed to get value for option '%s'",
name.data);
}
} else {
api_set_error(err,
kErrorTypeException,
- "Unknown type for option \"%s\"",
+ "Unknown type for option '%s'",
name.data);
}
@@ -336,24 +332,20 @@ void set_option_to(uint64_t channel_id, void *to, int type,
int flags = get_option_value_strict(name.data, NULL, NULL, type, to);
if (flags == 0) {
- api_set_error(err,
- kErrorTypeValidation,
- "Invalid option name \"%s\"",
+ api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'",
name.data);
return;
}
if (value.type == kObjectTypeNil) {
if (type == SREQ_GLOBAL) {
- api_set_error(err,
- kErrorTypeException,
- "Unable to unset option \"%s\"",
+ api_set_error(err, kErrorTypeException, "Cannot unset option '%s'",
name.data);
return;
} else if (!(flags & SOPT_GLOBAL)) {
api_set_error(err,
kErrorTypeException,
- "Cannot unset option \"%s\" "
+ "Cannot unset option '%s' "
"because it doesn't have a global value",
name.data);
return;
@@ -370,7 +362,7 @@ void set_option_to(uint64_t channel_id, void *to, int type,
if (value.type != kObjectTypeBoolean) {
api_set_error(err,
kErrorTypeValidation,
- "Option \"%s\" requires a boolean value",
+ "Option '%s' requires a Boolean value",
name.data);
return;
}
@@ -378,17 +370,15 @@ void set_option_to(uint64_t channel_id, void *to, int type,
numval = value.data.boolean;
} else if (flags & SOPT_NUM) {
if (value.type != kObjectTypeInteger) {
- api_set_error(err,
- kErrorTypeValidation,
- "Option \"%s\" requires an integer value",
+ api_set_error(err, kErrorTypeValidation,
+ "Option '%s' requires an integer value",
name.data);
return;
}
if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) {
- api_set_error(err,
- kErrorTypeValidation,
- "Value for option \"%s\" is outside range",
+ api_set_error(err, kErrorTypeValidation,
+ "Value for option '%s' is out of range",
name.data);
return;
}
@@ -396,9 +386,8 @@ void set_option_to(uint64_t channel_id, void *to, int type,
numval = (int)value.data.integer;
} else {
if (value.type != kObjectTypeString) {
- api_set_error(err,
- kErrorTypeValidation,
- "Option \"%s\" requires a string value",
+ api_set_error(err, kErrorTypeValidation,
+ "Option '%s' requires a string value",
name.data);
return;
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index e78b8c776d..fed20a272a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -502,7 +502,7 @@ Integer nvim_strwidth(String text, Error *err)
FUNC_API_SINCE(1)
{
if (text.size > INT_MAX) {
- api_set_error(err, kErrorTypeValidation, "String length is too high");
+ api_set_error(err, kErrorTypeValidation, "String is too long");
return 0;
}
@@ -559,7 +559,7 @@ void nvim_set_current_dir(String dir, Error *err)
FUNC_API_SINCE(1)
{
if (dir.size >= MAXPATHL) {
- api_set_error(err, kErrorTypeValidation, "Directory string is too long");
+ api_set_error(err, kErrorTypeValidation, "Directory name is too long");
return;
}
@@ -1136,14 +1136,14 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
if (calls.items[i].type != kObjectTypeArray) {
api_set_error(err,
kErrorTypeValidation,
- "All items in calls array must be arrays");
+ "Items in calls array must be arrays");
goto validation_error;
}
Array call = calls.items[i].data.array;
if (call.size != 2) {
api_set_error(err,
kErrorTypeValidation,
- "All items in calls array must be arrays of size 2");
+ "Items in calls array must be arrays of size 2");
goto validation_error;
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index ca975ee02a..a9e9364dc3 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4675,49 +4675,66 @@ static int help_compare(const void *s1, const void *s2)
return strcmp(p1, p2);
}
-/*
- * Find all help tags matching "arg", sort them and return in matches[], with
- * the number of matches in num_matches.
- * The matches will be sorted with a "best" match algorithm.
- * When "keep_lang" is TRUE try keeping the language of the current buffer.
- */
-int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_lang)
+// Find all help tags matching "arg", sort them and return in matches[], with
+// the number of matches in num_matches.
+// The matches will be sorted with a "best" match algorithm.
+// When "keep_lang" is true try keeping the language of the current buffer.
+int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
+ bool keep_lang)
{
- char_u *s, *d;
int i;
- static char *(mtable[]) = {"*", "g*", "[*", "]*",
- "/*", "/\\*", "\"*", "**",
- "/\\(\\)", "/\\%(\\)",
- "?", ":?", "?<CR>", "g?", "g?g?", "g??",
- "/\\?", "/\\z(\\)", "\\=", ":s\\=",
- "[count]", "[quotex]",
- "[range]", ":[range]",
- "[pattern]", "\\|", "\\%$",
- "s/\\~", "s/\\U", "s/\\L",
- "s/\\1", "s/\\2", "s/\\3", "s/\\9"};
- static char *(rtable[]) = {"star", "gstar", "[star", "]star",
- "/star", "/\\\\star", "quotestar", "starstar",
- "/\\\\(\\\\)", "/\\\\%(\\\\)",
- "?", ":?", "?<CR>", "g?", "g?g?", "g??",
- "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
- "\\[count]", "\\[quotex]",
- "\\[range]", ":\\[range]",
- "\\[pattern]", "\\\\bar", "/\\\\%\\$",
- "s/\\\\\\~", "s/\\\\U", "s/\\\\L",
- "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"};
- int flags;
-
- d = IObuff; /* assume IObuff is long enough! */
-
- /*
- * Recognize a few exceptions to the rule. Some strings that contain '*'
- * with "star". Otherwise '*' is recognized as a wildcard.
- */
- for (i = (int)ARRAY_SIZE(mtable); --i >= 0; )
- if (STRCMP(arg, mtable[i]) == 0) {
- STRCPY(d, rtable[i]);
- break;
+ static const char *(mtable[]) = {
+ "*", "g*", "[*", "]*",
+ "/*", "/\\*", "\"*", "**",
+ "/\\(\\)", "/\\%(\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\?", "/\\z(\\)", "\\=", ":s\\=",
+ "[count]", "[quotex]",
+ "[range]", ":[range]",
+ "[pattern]", "\\|", "\\%$",
+ "s/\\~", "s/\\U", "s/\\L",
+ "s/\\1", "s/\\2", "s/\\3", "s/\\9"
+ };
+ static const char *(rtable[]) = {
+ "star", "gstar", "[star", "]star",
+ "/star", "/\\\\star", "quotestar", "starstar",
+ "/\\\\(\\\\)", "/\\\\%(\\\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
+ "\\[count]", "\\[quotex]",
+ "\\[range]", ":\\[range]",
+ "\\[pattern]", "\\\\bar", "/\\\\%\\$",
+ "s/\\\\\\~", "s/\\\\U", "s/\\\\L",
+ "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"
+ };
+ static const char *(expr_table[]) = {
+ "!=?", "!~?", "<=?", "<?", "==?", "=~?",
+ ">=?", ">?", "is?", "isnot?"
+ };
+ char_u *d = IObuff; // assume IObuff is long enough!
+
+ if (STRNICMP(arg, "expr-", 5) == 0) {
+ // When the string starting with "expr-" and containing '?' and matches
+ // the table, it is taken literally. Otherwise '?' is recognized as a
+ // wildcard.
+ for (i = (int)ARRAY_SIZE(expr_table); --i >= 0; ) {
+ if (STRCMP(arg + 5, expr_table[i]) == 0) {
+ STRCPY(d, arg);
+ break;
+ }
+ }
+ } else {
+ // Recognize a few exceptions to the rule. Some strings that contain
+ // '*' with "star". Otherwise '*' is recognized as a wildcard.
+ for (i = (int)ARRAY_SIZE(mtable); --i >= 0; ) {
+ if (STRCMP(arg, mtable[i]) == 0) {
+ STRCPY(d, rtable[i]);
+ break;
+ }
}
+ }
if (i < 0) { /* no match in table */
/* Replace "\S" with "/\\S", etc. Otherwise every tag is matched.
@@ -4749,7 +4766,7 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
if (*arg == '(' && arg[1] == '\'') {
arg++;
}
- for (s = arg; *s; s++) {
+ for (const char_u *s = arg; *s; s++) {
// Replace "|" with "bar" and '"' with "quote" to match the name of
// the tags for these commands.
// Replace "*" with ".*" and "?" with "." to match command line
@@ -4858,9 +4875,10 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
*matches = (char_u **)"";
*num_matches = 0;
- flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
- if (keep_lang)
+ int flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
+ if (keep_lang) {
flags |= TAG_KEEP_LANG;
+ }
if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK
&& *num_matches > 0) {
/* Sort the matches found on the heuristic number that is after the
@@ -5017,11 +5035,9 @@ void fix_help_buffer(void)
const char_u *const f1 = fnames[i1];
const char_u *const f2 = fnames[i2];
const char_u *const t1 = path_tail(f1);
- if (fnamencmp(f1, f2, t1 - f1) != 0) {
- continue;
- }
+ const char_u *const t2 = path_tail(f2);
const char_u *const e1 = STRRCHR(t1, '.');
- const char_u *const e2 = STRRCHR(path_tail(f2), '.');
+ const char_u *const e2 = STRRCHR(t2, '.');
if (e1 == NULL || e2 == NULL) {
continue;
}
@@ -5032,8 +5048,10 @@ void fix_help_buffer(void)
fnames[i1] = NULL;
continue;
}
- if (fnamencmp(f1, f2, e1 - f1) != 0)
+ if (e1 - f1 != e2 - f2
+ || fnamencmp(f1, f2, e1 - f1) != 0) {
continue;
+ }
if (fnamecmp(e1, ".txt") == 0
&& fnamecmp(e2, fname + 4) == 0) {
/* use .abx instead of .txt */
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 786e2cd12c..ff625d6dc9 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -4677,7 +4677,7 @@ ExpandFromContext (
/* With an empty argument we would get all the help tags, which is
* very slow. Get matches for "help" instead. */
if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat,
- num_file, file, FALSE) == OK) {
+ num_file, file, false) == OK) {
cleanup_help_tags(*num_file, *file);
return OK;
}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index af7c194edc..ab8b33aa12 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -892,6 +892,7 @@ static void command_line_scan(mparm_T *parmp)
set_option_value("rl", 1L, NULL, 0);
break;
}
+ case '?': // "-?" give help message (for MS-Windows)
case 'h': { // "-h" give help message
usage();
mch_exit(0);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 0bf93ee001..09444ace0f 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -4771,6 +4771,10 @@ static void nv_ident(cmdarg_T *cap)
assert(*kp != NUL); // option.c:do_set() should default to ":help" if empty.
bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command
bool kp_help = (STRCMP(kp, ":he") == 0 || STRCMP(kp, ":help") == 0);
+ if (kp_help && *skipwhite(ptr) == NUL) {
+ EMSG(_(e_noident)); // found white space only
+ return;
+ }
size_t buf_size = n * 2 + 30 + STRLEN(kp);
char *buf = xmalloc(buf_size);
buf[0] = NUL;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 91840026a5..884fef69d1 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3912,23 +3912,16 @@ win_line (
}
}
- /*
- * At end of the text line.
- */
+ //
+ // At end of the text line.
+ //
if (c == NUL) {
- if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol
- && lnum == wp->w_cursor.lnum) {
- /* highlight last char after line */
- --col;
- --off;
- --vcol;
- }
-
- /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
- if (wp->w_p_wrap)
+ // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line.
+ if (wp->w_p_wrap) {
v = wp->w_skipcol;
- else
+ } else {
v = wp->w_leftcol;
+ }
/* check if line ends before left margin */
if (vcol < v + col - win_col_off(wp))
diff --git a/src/nvim/testdir/test_help.vim b/src/nvim/testdir/test_help.vim
index 26edc16107..ed3181564c 100644
--- a/src/nvim/testdir/test_help.vim
+++ b/src/nvim/testdir/test_help.vim
@@ -13,4 +13,40 @@ endfunc
func Test_help_errors()
call assert_fails('help doesnotexist', 'E149:')
call assert_fails('help!', 'E478:')
+
+ new
+ set keywordprg=:help
+ call setline(1, " ")
+ call assert_fails('normal VK', 'E349:')
+ bwipe!
+endfunc
+
+func Test_help_keyword()
+ new
+ set keywordprg=:help
+ call setline(1, " Visual ")
+ normal VK
+ call assert_match('^Visual mode', getline('.'))
+ call assert_equal('help', &ft)
+ close
+ bwipe!
+endfunc
+
+func Test_help_local_additions()
+ call mkdir('Xruntime/doc', 'p')
+ call writefile(['*mydoc.txt* my awesome doc'], 'Xruntime/doc/mydoc.txt')
+ call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt')
+ let rtp_save = &rtp
+ set rtp+=./Xruntime
+ help
+ 1
+ call search('mydoc.txt')
+ call assert_equal('|mydoc.txt| my awesome doc', getline('.'))
+ 1
+ call search('mydoc-ext.txt')
+ call assert_equal('|mydoc-ext.txt| my extended awesome doc', getline('.'))
+ close
+
+ call delete('Xruntime', 'rf')
+ let &rtp = rtp_save
endfunc
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index 4d4a902031..c873487b92 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -38,6 +38,34 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*:?\*')
helpclose
+ help q?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*q?\*')
+ call assert_true(expand('<cword>') == 'q?')
+ helpclose
+
+ help -?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*-?\*')
+ helpclose
+
+ help v_g?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*v_g?\*')
+ helpclose
+
+ help expr-!=?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*expr-!=?\*')
+ call assert_true(expand('<cword>') == 'expr-!=?')
+ helpclose
+
+ help expr-isnot?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*expr-isnot?\*')
+ call assert_true(expand('<cword>') == 'expr-isnot?')
+ helpclose
+
help FileW*Post
call assert_equal("help", &filetype)
call assert_true(getline('.') =~ '\*FileWritePost\*')
diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim
index 066fdd0250..1fc7b04f88 100644
--- a/src/nvim/testdir/test_hlsearch.vim
+++ b/src/nvim/testdir/test_hlsearch.vim
@@ -4,7 +4,6 @@ function! Test_hlsearch()
new
call setline(1, repeat(['aaa'], 10))
set hlsearch nolazyredraw
- let r=[]
" redraw is needed to make hlsearch highlight the matches
exe "normal! /aaa\<CR>" | redraw
let r1 = screenattr(1, 1)
@@ -32,3 +31,16 @@ function! Test_hlsearch()
call getchar(1)
enew!
endfunction
+
+func Test_hlsearch_eol_highlight()
+ new
+ call append(1, repeat([''], 9))
+ set hlsearch nolazyredraw
+ exe "normal! /$\<CR>" | redraw
+ let attr = screenattr(1, 1)
+ for row in range(2, 10)
+ call assert_equal(attr, screenattr(row, 1), 'in line ' . row)
+ endfor
+ set nohlsearch
+ bwipe!
+endfunc
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 958e2f68fc..271e196103 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -309,7 +309,7 @@ describe('api/buf', function()
eq(1, funcs.exists('b:lua'))
curbufmeths.del_var('lua')
eq(0, funcs.exists('b:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
curbufmeths.set_var('lua', 1)
command('lockvar b:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua
index 260a91a80c..c49091db02 100644
--- a/test/functional/api/tabpage_spec.lua
+++ b/test/functional/api/tabpage_spec.lua
@@ -34,7 +34,7 @@ describe('api/tabpage', function()
eq(1, funcs.exists('t:lua'))
curtabmeths.del_var('lua')
eq(0, funcs.exists('t:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
curtabmeths.set_var('lua', 1)
command('lockvar t:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index ae8a8488d4..5261f57ca7 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -24,13 +24,25 @@ describe('API', function()
before_each(clear)
it('validates requests', function()
- expect_err('Invalid method: bogus',
+ -- RPC
+ expect_err('Invalid method: bogus$',
request, 'bogus')
- expect_err('Invalid method: … の り 。…',
+ expect_err('Invalid method: … の り 。…$',
request, '… の り 。…')
- expect_err('Invalid method: <empty>',
+ expect_err('Invalid method: <empty>$',
request, '')
- expect_err("can't serialize object",
+
+ -- Non-RPC: rpcrequest(v:servername) uses internal channel.
+ expect_err('Invalid method: … の り 。…$',
+ request, 'nvim_eval',
+ [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), '… の り 。…')]=])
+ expect_err('Invalid method: bogus$',
+ request, 'nvim_eval',
+ [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), 'bogus')]=])
+
+ -- XXX: This must be the last one, else next one will fail:
+ -- "Packer instance already working. Use another Packer ..."
+ expect_err("can't serialize object$",
request, nil)
end)
@@ -158,7 +170,7 @@ describe('API', function()
end)
it("VimL error: returns error details, does NOT update v:errmsg", function()
- expect_err('E121: Undefined variable: bogus', request,
+ expect_err('E121: Undefined variable: bogus$', request,
'nvim_eval', 'bogus expression')
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
end)
@@ -173,7 +185,7 @@ describe('API', function()
end)
it("VimL validation error: returns specific error, does NOT update v:errmsg", function()
- expect_err('E117: Unknown function: bogus function', request,
+ expect_err('E117: Unknown function: bogus function$', request,
'nvim_call_function', 'bogus function', {'arg1'})
expect_err('E119: Not enough arguments for function: atan', request,
'nvim_call_function', 'atan', {})
@@ -182,11 +194,11 @@ describe('API', function()
end)
it("VimL error: returns error details, does NOT update v:errmsg", function()
- expect_err('E808: Number or Float required', request,
+ expect_err('E808: Number or Float required$', request,
'nvim_call_function', 'atan', {'foo'})
- expect_err('Invalid channel stream "xxx"', request,
+ expect_err('Invalid channel stream "xxx"$', request,
'nvim_call_function', 'chanclose', {999, 'xxx'})
- expect_err('E900: Invalid channel id', request,
+ expect_err('E900: Invalid channel id$', request,
'nvim_call_function', 'chansend', {999, 'foo'})
eq('', eval('v:exception'))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
@@ -198,7 +210,7 @@ describe('API', function()
throw 'wtf'
endfunction
]])
- expect_err('wtf', request,
+ expect_err('wtf$', request,
'nvim_call_function', 'Foo', {})
eq('', eval('v:exception'))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
@@ -212,7 +224,7 @@ describe('API', function()
endfunction
]])
-- E740
- expect_err('Function called with too many arguments', request,
+ expect_err('Function called with too many arguments$', request,
'nvim_call_function', 'Foo', too_many_args)
end)
end)
@@ -248,23 +260,23 @@ describe('API', function()
it('validates args', function()
command('let g:d={"baz":"zub","meep":[]}')
- expect_err('Not found: bogus', request,
+ expect_err('Not found: bogus$', request,
'nvim_call_dict_function', 'g:d', 'bogus', {1,2})
- expect_err('Not a function: baz', request,
+ expect_err('Not a function: baz$', request,
'nvim_call_dict_function', 'g:d', 'baz', {1,2})
- expect_err('Not a function: meep', request,
+ expect_err('Not a function: meep$', request,
'nvim_call_dict_function', 'g:d', 'meep', {1,2})
- expect_err('E117: Unknown function: f', request,
+ expect_err('E117: Unknown function: f$', request,
'nvim_call_dict_function', { f = '' }, 'f', {1,2})
- expect_err('Not a function: f', request,
+ expect_err('Not a function: f$', request,
'nvim_call_dict_function', "{ 'f': '' }", 'f', {1,2})
- expect_err('dict argument type must be String or Dictionary', request,
+ expect_err('dict argument type must be String or Dictionary$', request,
'nvim_call_dict_function', 42, 'f', {1,2})
- expect_err('Failed to evaluate dict expression', request,
+ expect_err('Failed to evaluate dict expression$', request,
'nvim_call_dict_function', 'foo', 'f', {1,2})
- expect_err('dict not found', request,
+ expect_err('dict not found$', request,
'nvim_call_dict_function', '42', 'f', {1,2})
- expect_err('Invalid %(empty%) function name', request,
+ expect_err('Invalid %(empty%) function name$', request,
'nvim_call_dict_function', "{ 'f': '' }", '', {1,2})
end)
end)
@@ -337,7 +349,7 @@ describe('API', function()
eq(1, funcs.exists('g:lua'))
meths.del_var('lua')
eq(0, funcs.exists('g:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(meths.del_var, 'lua'))
+ eq({false, "Key not found: lua"}, meth_pcall(meths.del_var, 'lua'))
meths.set_var('lua', 1)
command('lockvar lua')
eq({false, 'Key is locked: lua'}, meth_pcall(meths.del_var, 'lua'))
@@ -948,7 +960,7 @@ describe('API', function()
}
local status, err = pcall(meths.call_atomic, req)
eq(false, status)
- ok(err:match(' All items in calls array must be arrays of size 2') ~= nil)
+ ok(err:match('Items in calls array must be arrays of size 2') ~= nil)
-- call before was done, but not after
eq(1, meths.get_var('avar'))
@@ -958,7 +970,7 @@ describe('API', function()
}
status, err = pcall(meths.call_atomic, req)
eq(false, status)
- ok(err:match('All items in calls array must be arrays') ~= nil)
+ ok(err:match('Items in calls array must be arrays') ~= nil)
eq({2,3}, meths.get_var('bvar'))
req = {
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index d404ef5426..27d7aa11b4 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -169,7 +169,7 @@ describe('api/win', function()
eq(1, funcs.exists('w:lua'))
curwinmeths.del_var('lua')
eq(0, funcs.exists('w:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
curwinmeths.set_var('lua', 1)
command('lockvar w:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index bf8cae3a0b..d39b24a00f 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -510,12 +510,7 @@ local function test_cmdline(newgrid)
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{grid=[[
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 18c0fe2c2a..b242fddb78 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -78,6 +78,12 @@ local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
local eq = helpers.eq
local dedent = helpers.dedent
+local inspect = require('inspect')
+
+local function isempty(v)
+ return type(v) == 'table' and next(v) == nil
+end
+
local Screen = {}
Screen.__index = Screen
@@ -200,6 +206,11 @@ function Screen:set_option(option, value)
self._options[option] = value
end
+-- canonical order of ext keys, used to generate asserts
+local ext_keys = {
+ 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos'
+}
+
-- Asserts that the screen state eventually matches an expected state
--
-- This function can either be called with the positional forms
@@ -246,8 +257,10 @@ function Screen:expect(expected, attr_ids, attr_ignore)
if type(expected) == "table" then
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
- any=true, mode=true, popupmenu=true, cmdline=true,
- cmdline_block=true, wildmenu_items=true, wildmenu_pos=true}
+ any=true, mode=true}
+ for _, v in ipairs(ext_keys) do
+ is_key[v] = true
+ end
for k, _ in pairs(expected) do
if not is_key[k] then
error("Screen:expect: Unknown keyword argument '"..k.."'")
@@ -278,11 +291,12 @@ function Screen:expect(expected, attr_ids, attr_ignore)
table.insert(expected_rows, row)
end
end
- local ids = attr_ids or self._default_attr_ids
- local ignore = attr_ignore or self._default_attr_ignore
- local id_to_index
+ local attr_state = {
+ ids = attr_ids or self._default_attr_ids,
+ ignore = attr_ignore or self._default_attr_ignore,
+ }
if self._options.ext_hlstate then
- id_to_index = self:hlstate_check_attrs(ids or {})
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
end
self._new_attrs = false
self:wait(function()
@@ -299,13 +313,12 @@ function Screen:expect(expected, attr_ids, attr_ignore)
end
if self._options.ext_hlstate and self._new_attrs then
- id_to_index = self:hlstate_check_attrs(ids or {})
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
end
- local info = self._options.ext_hlstate and id_to_index or ids
local actual_rows = {}
for i = 1, self._height do
- actual_rows[i] = self:_row_repr(self._rows[i], info, ignore)
+ actual_rows[i] = self:_row_repr(self._rows[i], attr_state)
end
if expected.any ~= nil then
@@ -342,28 +355,18 @@ screen:redraw_debug() to show all intermediate screen states. ]])
-- Extension features. The default expectations should cover the case of
-- the ext_ feature being disabled, or the feature currently not activated
- -- (for instance no external cmdline visible)
- local expected_cmdline = expected.cmdline or {}
- local actual_cmdline = {}
- for i, entry in pairs(self.cmdline) do
- entry = shallowcopy(entry)
- entry.content = self:_chunks_repr(entry.content, info, ignore)
- actual_cmdline[i] = entry
- end
-
- local expected_block = expected.cmdline_block or {}
- local actual_block = {}
- for i, entry in ipairs(self.cmdline_block) do
- actual_block[i] = self:_chunks_repr(entry, info, ignore)
- end
+ -- (for instance no external cmdline visible). Some extensions require
+ -- preprocessing to prepresent highlights in a reproducible way.
+ local extstate = self:_extstate_repr(attr_state)
-- convert assertion errors into invalid screen state descriptions
local status, res = pcall(function()
- eq(expected.popupmenu, self.popupmenu, "popupmenu")
- eq(expected_cmdline, actual_cmdline, "cmdline")
- eq(expected_block, actual_block, "cmdline_block")
- eq(expected.wildmenu_items, self.wildmenu_items, "wildmenu_items")
- eq(expected.wildmenu_pos, self.wildmenu_pos, "wildmenu_pos")
+ for _, k in ipairs(ext_keys) do
+ -- Empty states is considered the default and need not be mentioned
+ if not (expected[k] == nil and isempty(extstate[k])) then
+ eq(expected[k], extstate[k], k)
+ end
+ end
if expected.mode ~= nil then
eq(expected.mode, self.mode, "mode")
end
@@ -438,7 +441,6 @@ function Screen:_redraw(updates)
self._on_event(method, update[i])
end
end
- -- print(self:_current_screen())
end
end
@@ -745,7 +747,7 @@ function Screen:_clear_row_section(rownum, startcol, stopcol)
end
end
-function Screen:_row_repr(row, attr_ids, attr_ignore)
+function Screen:_row_repr(row, attr_state)
local rv = {}
local current_attr_id
for i = 1, self._width do
@@ -753,7 +755,7 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
if self._options.ext_newgrid then
attrs = attrs[(self._options.rgb and 1) or 2]
end
- local attr_id = self:_get_attr_id(attr_ids, attr_ignore, attrs, row[i].hl_id)
+ local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id)
if current_attr_id and attr_id ~= current_attr_id then
-- close current attribute bracket, add it before any whitespace
-- up to the current cell
@@ -779,7 +781,29 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
return table.concat(rv, '')--:gsub('%s+$', '')
end
-function Screen:_chunks_repr(chunks, attr_ids, attr_ignore)
+function Screen:_extstate_repr(attr_state)
+ local cmdline = {}
+ for i, entry in pairs(self.cmdline) do
+ entry = shallowcopy(entry)
+ entry.content = self:_chunks_repr(entry.content, attr_state)
+ cmdline[i] = entry
+ end
+
+ local cmdline_block = {}
+ for i, entry in ipairs(self.cmdline_block) do
+ cmdline_block[i] = self:_chunks_repr(entry, attr_state)
+ end
+
+ return {
+ popupmenu=self.popupmenu,
+ cmdline=cmdline,
+ cmdline_block=cmdline_block,
+ wildmenu_items=self.wildmenu_items,
+ wildmenu_pos=self.wildmenu_pos,
+ }
+end
+
+function Screen:_chunks_repr(chunks, attr_state)
local repr_chunks = {}
for i, chunk in ipairs(chunks) do
local hl, text = unpack(chunk)
@@ -789,21 +813,12 @@ function Screen:_chunks_repr(chunks, attr_ids, attr_ignore)
else
attrs = hl
end
- local attr_id = self:_get_attr_id(attr_ids, attr_ignore, attrs, hl)
+ local attr_id = self:_get_attr_id(attr_state, attrs, hl)
repr_chunks[i] = {text, attr_id}
end
return repr_chunks
end
-function Screen:_current_screen()
- -- get a string that represents the current screen state(debugging helper)
- local rv = {}
- for i = 1, self._height do
- table.insert(rv, "'"..self:_row_repr(self._rows[i]).."'")
- end
- return table.concat(rv, '\n')
-end
-
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
-- dumps the current screen state in the form of Screen:expect().
-- Use snapshot_util({},true) to generate a text-only (no attributes) test.
@@ -832,82 +847,77 @@ function Screen:redraw_debug(attrs, ignore, timeout)
end
function Screen:print_snapshot(attrs, ignore)
+ attrs = attrs or self._default_attr_ids
if ignore == nil then
ignore = self._default_attr_ignore
end
- local id_to_index = {}
- if attrs == nil then
- attrs = {}
- if self._default_attr_ids ~= nil then
- for i, a in pairs(self._default_attr_ids) do
- attrs[i] = a
- end
- if self._options.ext_hlstate then
- id_to_index = self:hlstate_check_attrs(attrs)
- end
- end
+ local attr_state = {
+ ids = {},
+ ignore = ignore,
+ mutable = true, -- allow _row_repr to add missing highlights
+ }
- if ignore ~= true then
- for i = 1, self._height do
- local row = self._rows[i]
- for j = 1, self._width do
- if self._options.ext_hlstate then
- local hl_id = row[j].hl_id
- if hl_id ~= 0 then
- self:_insert_hl_id(attrs, id_to_index, hl_id)
- end
- else
- local attr = row[j].attrs
- if self:_attr_index(attrs, attr) == nil and self:_attr_index(ignore, attr) == nil then
- if not self:_equal_attrs(attr, {}) then
- table.insert(attrs, attr)
- end
- end
- end
- end
- end
+ if attrs ~= nil then
+ for i, a in pairs(attrs) do
+ attr_state.ids[i] = a
end
end
+ if self._options.ext_hlstate then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids)
+ end
- local rv = {}
- local info = self._options.ext_hlstate and id_to_index or attrs
+ local lines = {}
for i = 1, self._height do
- table.insert(rv, " "..self:_row_repr(self._rows[i], info, ignore).."|")
+ table.insert(lines, " "..self:_row_repr(self._rows[i], attr_state).."|")
end
- local attrstrs = {}
- local alldefault = true
- for i, a in ipairs(attrs) do
- if self._default_attr_ids == nil or self._default_attr_ids[i] ~= a then
- alldefault = false
- end
- local dict
- if self._options.ext_hlstate then
- dict = self:_pprint_hlstate(a)
+
+ local ext_state = self:_extstate_repr(attr_state)
+ local keys = false
+ for k, v in pairs(ext_state) do
+ if isempty(v) then
+ ext_state[k] = nil -- deleting keys while iterating is ok
else
- dict = "{"..self:_pprint_attrs(a).."}"
+ keys = true
end
- table.insert(attrstrs, "["..tostring(i).."] = "..dict)
end
- local attrstr = "{"..table.concat(attrstrs, ", ").."}"
- print( "\nscreen:expect([[")
- print( table.concat(rv, '\n'))
- if alldefault then
- print( "]])\n")
- else
- print( "]], "..attrstr..")\n")
+
+ local attrstr = ""
+ if attr_state.modified then
+ local attrstrs = {}
+ for i, a in pairs(attr_state.ids) do
+ local dict
+ if self._options.ext_hlstate then
+ dict = self:_pprint_hlstate(a)
+ else
+ dict = "{"..self:_pprint_attrs(a).."}"
+ end
+ local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
+ table.insert(attrstrs, " "..keyval.." = "..dict..",")
+ end
+ attrstr = (", "..(keys and "attr_ids=" or "")
+ .."{\n"..table.concat(attrstrs, "\n").."\n}")
+ end
+ print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
+ print( table.concat(lines, '\n'))
+ io.stdout:write( "]]"..attrstr)
+ for _, k in ipairs(ext_keys) do
+ if ext_state[k] ~= nil then
+ io.stdout:write(", "..k.."="..inspect(ext_state[k]))
+ end
end
+ print((keys and "}" or ")").."\n")
io.stdout:flush()
end
-function Screen:_insert_hl_id(attrs, id_to_index, hl_id)
- if id_to_index[hl_id] ~= nil then
- return id_to_index[hl_id]
+function Screen:_insert_hl_id(attr_state, hl_id)
+ if attr_state.id_to_index[hl_id] ~= nil then
+ return attr_state.id_to_index[hl_id]
end
local raw_info = self._hl_info[hl_id]
local info = {}
if #raw_info > 1 then
for i, item in ipairs(raw_info) do
- info[i] = self:_insert_hl_id(attrs, id_to_index, item.id)
+ info[i] = self:_insert_hl_id(attr_state, item.id)
end
else
info[1] = {}
@@ -927,9 +937,9 @@ function Screen:_insert_hl_id(attrs, id_to_index, hl_id)
end
- table.insert(attrs, attrval)
- id_to_index[hl_id] = #attrs
- return #attrs
+ table.insert(attr_state.ids, attrval)
+ attr_state.id_to_index[hl_id] = #attr_state.ids
+ return #attr_state.ids
end
function Screen:hlstate_check_attrs(attrs)
@@ -1033,28 +1043,39 @@ local function backward_find_meaningful(tbl, from) -- luacheck: no unused
return from
end
-function Screen:_get_attr_id(attr_ids, ignore, attrs, hl_id)
- if not attr_ids then
+function Screen:_get_attr_id(attr_state, attrs, hl_id)
+ if not attr_state.ids then
return
end
if self._options.ext_hlstate then
- local id = attr_ids[hl_id]
+ local id = attr_state.id_to_index[hl_id]
if id ~= nil or hl_id == 0 then
return id
end
+ if attr_state.mutable then
+ id = self:_insert_hl_id(attr_state, hl_id)
+ attr_state.modified = true
+ return id
+ end
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
else
- for id, a in pairs(attr_ids) do
+ for id, a in pairs(attr_state.ids) do
if self:_equal_attrs(a, attrs) then
return id
end
end
if self:_equal_attrs(attrs, {}) or
- ignore == true or self:_attr_index(ignore, attrs) ~= nil then
+ attr_state.ignore == true or
+ self:_attr_index(attr_state.ignore, attrs) ~= nil then
-- ignore this attrs
return nil
end
+ if attr_state.mutable then
+ table.insert(attr_state.ids, attrs)
+ attr_state.modified = true
+ return #attr_state.ids
+ end
return "UNEXPECTED "..self:_pprint_attrs(attrs)
end
end
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 168080a092..b535092ab9 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
@@ -93,6 +94,59 @@ describe('search highlighting', function()
]])
end)
+ it('highlights after EOL', function()
+ insert("\n\n\n\n\n\n")
+
+ feed("gg/^<cr>")
+ screen:expect([[
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Test that highlights are preserved after moving the cursor.
+ feed("j")
+ screen:expect([[
+ {2: } |
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Repeat the test in rightleft mode.
+ command("nohlsearch")
+ command("set rightleft")
+ feed("gg/^<cr>")
+
+ screen:expect([[
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+
+ feed("j")
+ screen:expect([[
+ {2: }|
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+ end)
+
it('is preserved during :terminal activity', function()
if iswin() then
feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 0905b70be2..f770999c0f 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -138,11 +138,11 @@ set(UNIBILIUM_SHA256 78997d38d4c8177c60d3d0c1aa8c53fd0806eb21825b7b335b1768d7116
set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.20.tar.gz)
set(LIBTERMKEY_SHA256 6c0d87c94ab9915e76ecd313baec08dedf3bd56de83743d9aa923a081935d2f5)
-set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz)
-set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796)
+set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/3f62ac6b7bdffda39d68f723fb1806dfd6d6382d.tar.gz)
+set(LIBVTERM_SHA256 1c8b318370f00f831f43e3ec86a48984250e3ee5c76beb106a421c9a42286ac5)
-set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/4.5.0/jemalloc-4.5.0.tar.bz2)
-set(JEMALLOC_SHA256 9409d85664b4f135b77518b0b118c549009dc10f6cba14557d170476611f6780)
+set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/5.1.0/jemalloc-5.1.0.tar.bz2)
+set(JEMALLOC_SHA256 5396e61cc6103ac393136c309fae09e44d74743c86f90e266948c50f3dbb7268)
set(LUV_URL https://github.com/luvit/luv/archive/1.9.1-1.tar.gz)
set(LUV_SHA256 562b9efaad30aa051a40eac9ade0c3df48bb8186763769abe47ec3fb3edb1268)
diff --git a/third-party/cmake/BuildLibvterm.cmake b/third-party/cmake/BuildLibvterm.cmake
index 4720581e52..e4649986af 100644
--- a/third-party/cmake/BuildLibvterm.cmake
+++ b/third-party/cmake/BuildLibvterm.cmake
@@ -39,8 +39,7 @@ if(WIN32)
set(LIBVTERM_PATCH_COMMAND
${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libvterm init
COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libvterm apply --ignore-whitespace
- ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Remove-VLAs-for-MSVC.patch
- ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Fix-escape-sequences-for-MSVC.patch)
+ ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Remove-VLAs-for-MSVC.patch)
endif()
set(LIBVTERM_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibvtermCMakeLists.txt
diff --git a/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch b/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch
deleted file mode 100644
index b2f0809544..0000000000
--- a/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-diff --git a/src/keyboard.c b/src/keyboard.c
-index bc1299b..5f368f4 100644
---- a/src/keyboard.c
-+++ b/src/keyboard.c
-@@ -48,7 +48,7 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
- if(mod & VTERM_MOD_CTRL)
- c &= 0x1f;
-
-- vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? "\e" : "", c);
-+ vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? "\x1b" : "", c);
- }
-
- typedef struct {
-@@ -73,7 +73,7 @@ static keycodes_s keycodes[] = {
- { KEYCODE_ENTER, '\r' }, // ENTER
- { KEYCODE_TAB, '\t' }, // TAB
- { KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL
-- { KEYCODE_LITERAL, '\e' }, // ESCAPE
-+ { KEYCODE_LITERAL, '\x1b' }, // ESCAPE
-
- { KEYCODE_CSI_CURSOR, 'A' }, // UP
- { KEYCODE_CSI_CURSOR, 'B' }, // DOWN
-@@ -173,7 +173,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
- if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
- vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
- else
-- vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? "\e%c" : "%c", k.literal);
-+ vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? "\x1b%c" : "%c", k.literal);
- break;
-
- case KEYCODE_SS3: case_SS3:
-diff --git a/src/vterm.c b/src/vterm.c
-index 826df93..262b3fc 100644
---- a/src/vterm.c
-+++ b/src/vterm.c
-@@ -158,7 +158,7 @@ INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, cons
- size_t orig_cur = vt->outbuffer_cur;
-
- if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
-- vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40);
-+ vterm_push_output_sprintf(vt, "\x1b%c", ctrl - 0x40);
- else
- vterm_push_output_sprintf(vt, "%c", ctrl);
-
-@@ -176,7 +176,7 @@ INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
- size_t orig_cur = vt->outbuffer_cur;
-
- if(!vt->mode.ctrl8bit)
-- vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40);
-+ vterm_push_output_sprintf(vt, "\x1b%c", C1_DCS - 0x40);
- else
- vterm_push_output_sprintf(vt, "%c", C1_DCS);
-