aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/CMakeLists.txt1
-rw-r--r--config/config.h.in1
-rw-r--r--runtime/doc/eval.txt37
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/doc/vim_diff.txt2
-rw-r--r--runtime/lua/vim/lsp/handlers.lua6
-rw-r--r--runtime/lua/vim/treesitter/query.lua15
-rw-r--r--runtime/syntax/vim.vim2
-rw-r--r--src/nvim/decoration.c22
-rw-r--r--src/nvim/decoration.h2
-rw-r--r--src/nvim/edit.c9
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c32
-rw-r--r--src/nvim/ops.c7
-rw-r--r--src/nvim/option.c94
-rw-r--r--src/nvim/os/time.c16
-rw-r--r--src/nvim/popupmnu.c4
-rw-r--r--src/nvim/screen.c14
-rw-r--r--src/nvim/testdir/Makefile6
-rw-r--r--src/nvim/testdir/runtest.vim8
-rw-r--r--src/nvim/testdir/test_autochdir.vim8
-rw-r--r--src/nvim/testdir/test_autocmd.vim22
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim2
-rw-r--r--src/nvim/testdir/test_functions.vim34
-rw-r--r--src/nvim/testdir/test_listlbr.vim6
-rw-r--r--src/nvim/testdir/test_messages.vim3
-rw-r--r--src/nvim/testdir/test_options.vim30
-rw-r--r--src/nvim/testdir/test_popup.vim2
-rw-r--r--src/nvim/testdir/test_quickfix.vim2
-rw-r--r--src/nvim/testdir/test_search.vim73
-rw-r--r--src/nvim/testdir/test_signs.vim7
-rw-r--r--src/nvim/testdir/test_startup.vim28
-rw-r--r--src/nvim/testdir/test_system.vim4
-rw-r--r--src/nvim/testdir/test_timers.vim4
-rw-r--r--src/nvim/testdir/test_undo.vim6
-rw-r--r--src/nvim/ui.c1
-rw-r--r--src/nvim/ui_compositor.c15
-rw-r--r--test/functional/lua/buffer_updates_spec.lua84
-rw-r--r--test/functional/ui/decorations_spec.lua29
-rw-r--r--test/functional/ui/diff_spec.lua20
-rw-r--r--test/functional/ui/float_spec.lua125
-rw-r--r--test/functional/ui/screen_basic_spec.lua44
42 files changed, 685 insertions, 144 deletions
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 8a70d864c4..6b88c92cf0 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -52,6 +52,7 @@ check_function_exists(setsid HAVE_SETSID)
check_function_exists(sigaction HAVE_SIGACTION)
check_function_exists(strcasecmp HAVE_STRCASECMP)
check_function_exists(strncasecmp HAVE_STRNCASECMP)
+check_function_exists(strptime HAVE_STRPTIME)
# Symbols
check_symbol_exists(FD_CLOEXEC "fcntl.h" HAVE_FD_CLOEXEC)
diff --git a/config/config.h.in b/config/config.h.in
index 275bff79a0..502f84bbcf 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -33,6 +33,7 @@
#cmakedefine HAVE_STRCASECMP
#cmakedefine HAVE_STRINGS_H
#cmakedefine HAVE_STRNCASECMP
+#cmakedefine HAVE_STRPTIME
#cmakedefine HAVE_SYS_SDT_H
#cmakedefine HAVE_SYS_UTSNAME_H
#cmakedefine HAVE_SYS_WAIT_H
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 1832e2443f..112958f78b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -444,7 +444,7 @@ as a key.
To avoid having to put quotes around every key the #{} form can be used. This
does require the key to consist only of ASCII letters, digits, '-' and '_'.
Example: >
- let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}
+ :let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}
Note that 333 here is the string "333". Empty keys are not possible with #{}.
A value can be any expression. Using a Dictionary for a value creates a
@@ -2430,7 +2430,7 @@ strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at
character {start}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
-strftime({format} [, {time}]) String time in specified format
+strftime({format} [, {time}]) String format time with a specified format
strgetchar({str}, {index}) Number get char {index} from {str}
stridx({haystack}, {needle} [, {start}])
Number index of {needle} in {haystack}
@@ -2439,6 +2439,8 @@ strlen({expr}) Number length of the String {expr}
strpart({str}, {start} [, {len} [, {chars}]])
String {len} bytes/chars of {str} at
byte {start}
+strptime({format}, {timestring})
+ Number Convert {timestring} to unix timestamp
strridx({haystack}, {needle} [, {start}])
Number last index of {needle} in {haystack}
strtrans({expr}) String translate string to make it printable
@@ -4983,7 +4985,7 @@ getwininfo([{winid}]) *getwininfo()*
getwinpos([{timeout}]) *getwinpos()*
The result is a list with two numbers, the result of
- getwinposx() and getwinposy() combined:
+ |getwinposx()| and |getwinposy()| combined:
[x-pos, y-pos]
{timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used.
@@ -5853,7 +5855,7 @@ list2str({list} [, {utf8}]) *list2str()*
<
localtime() *localtime()*
Return the current time, measured as seconds since 1st Jan
- 1970. See also |strftime()| and |getftime()|.
+ 1970. See also |strftime()|, |strptime()| and |getftime()|.
log({expr}) *log()*
@@ -8488,7 +8490,7 @@ strftime({format} [, {time}]) *strftime()*
{format} depends on your system, thus this is not portable!
See the manual page of the C function strftime() for the
format. The maximum length of the result is 80 characters.
- See also |localtime()| and |getftime()|.
+ See also |localtime()|, |getftime()| and |strptime()|.
The language can be changed with the |:language| command.
Examples: >
:echo strftime("%c") Sun Apr 27 11:49:23 1997
@@ -8578,6 +8580,31 @@ strpart({src}, {start} [, {len} [, {chars}]]) *strpart()*
example, to get the character under the cursor: >
strpart(getline("."), col(".") - 1, 1, v:true)
<
+strptime({format}, {timestring}) *strptime()*
+ The result is a Number, which is a unix timestamp representing
+ the date and time in {timestring}, which is expected to match
+ the format specified in {format}.
+
+ The accepted {format} depends on your system, thus this is not
+ portable! See the manual page of the C function strptime()
+ for the format. Especially avoid "%c". The value of $TZ also
+ matters.
+
+ If the {timestring} cannot be parsed with {format} zero is
+ returned. If you do not know the format of {timestring} you
+ can try different {format} values until you get a non-zero
+ result.
+
+ See also |strftime()|.
+ Examples: >
+ :echo strptime("%Y %b %d %X", "1997 Apr 27 11:49:23")
+< 862156163 >
+ :echo strftime("%c", strptime("%y%m%d %T", "970427 11:53:55"))
+< Sun Apr 27 11:53:55 1997 >
+ :echo strftime("%c", strptime("%Y%m%d%H%M%S", "19970427115355") + 3600)
+< Sun Apr 27 12:53:55 1997
+
+
strridx({haystack}, {needle} [, {start}]) *strridx()*
The result is a Number, which gives the byte index in
{haystack} of the last occurrence of the String {needle}.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 63c899da0c..97aacc1403 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -788,6 +788,7 @@ Date and Time: *date-functions* *time-functions*
getftime() get last modification time of a file
localtime() get current time in seconds
strftime() convert time to a string
+ strptime() convert a date/time string to time
reltime() get the current or elapsed time accurately
reltimestr() convert reltime() result to a string
reltimefloat() convert reltime() result to a Float
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 0c1e216164..eadc1c04a0 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -70,6 +70,8 @@ the differences.
- |matchit| plugin is enabled. To disable it in your config: >
:let loaded_matchit = 1
+- |g:vimsyn_embed| defaults to "l" to enable Lua highlighting
+
==============================================================================
3. New Features *nvim-features*
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 0cf80e1443..eacbd90077 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -304,7 +304,7 @@ M['textDocument/typeDefinition'] = location_handler
M['textDocument/implementation'] = location_handler
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
-M['textDocument/signatureHelp'] = function(_, method, result)
+M['textDocument/signatureHelp'] = function(_, method, result, _, bufnr)
-- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler
-- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
if not (result and result.signatures and result.signatures[1]) then
@@ -317,9 +317,11 @@ M['textDocument/signatureHelp'] = function(_, method, result)
print('No signature help available')
return
end
- util.focusable_preview(method, function()
+ local syntax = api.nvim_buf_get_option(bufnr, 'syntax')
+ local p_bufnr, _ = util.focusable_preview(method, function()
return lines, util.try_trim_markdown_code_blocks(lines)
end)
+ api.nvim_buf_set_option(p_bufnr, 'syntax', syntax)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 8b94348994..1b29618997 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -8,10 +8,23 @@ Query.__index = Query
local M = {}
+local function dedupe_files(files)
+ local result = {}
+ local seen = {}
+
+ for _, path in ipairs(files) do
+ if not seen[path] then
+ table.insert(result, path)
+ seen[path] = true
+ end
+ end
+
+ return result
+end
function M.get_query_files(lang, query_name, is_included)
local query_path = string.format('queries/%s/%s.scm', lang, query_name)
- local lang_files = a.nvim_get_runtime_file(query_path, true)
+ local lang_files = dedupe_files(a.nvim_get_runtime_file(query_path, true))
if #lang_files == 0 then return {} end
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 1a37af1c8a..92348d57ec 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -616,7 +616,7 @@ syn region vimGlobal matchgroup=Statement start='\<v\%[global]!\=/' skip='\\.' e
" g:vimsyn_embed =~# 'r' : embed ruby
" g:vimsyn_embed =~# 't' : embed tcl
if !exists("g:vimsyn_embed")
- let g:vimsyn_embed= 0
+ let g:vimsyn_embed = 'l'
endif
" [-- lua --] {{{3
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 9a20b06660..e16598e7d2 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -145,8 +145,7 @@ bool decor_redraw_reset(buf_T *buf, DecorState *state)
for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange item = kv_A(state->active, i);
if (item.virt_text_owned) {
- clear_virttext(item.virt_text);
- xfree(item.virt_text);
+ clear_virttext(&item.virt_text);
}
}
kv_size(state->active) = 0;
@@ -229,7 +228,7 @@ static void decor_add(DecorState *state, int start_row, int start_col,
HlRange range = { start_row, start_col, end_row, end_col,
attr_id, MAX(priority, decor->priority),
- kv_size(decor->virt_text) ? &decor->virt_text : NULL,
+ decor->virt_text,
decor->virt_text_pos, decor->virt_text_hide, decor->hl_mode,
kv_size(decor->virt_text) && owned, -1 };
@@ -304,7 +303,7 @@ next_mark:
bool active = false, keep = true;
if (item.end_row < state->row
|| (item.end_row == state->row && item.end_col <= col)) {
- if (!(item.start_row >= state->row && item.virt_text)) {
+ if (!(item.start_row >= state->row && kv_size(item.virt_text))) {
keep = false;
}
} else {
@@ -324,14 +323,13 @@ next_mark:
attr = hl_combine_attr(attr, item.attr_id);
}
if ((item.start_row == state->row && item.start_col <= col)
- && item.virt_text && item.virt_col == -1) {
+ && kv_size(item.virt_text) && item.virt_col == -1) {
item.virt_col = (item.virt_text_hide && hidden) ? -2 : virt_col;
}
if (keep) {
kv_A(state->active, j++) = item;
} else if (item.virt_text_owned) {
- clear_virttext(item.virt_text);
- xfree(item.virt_text);
+ clear_virttext(&item.virt_text);
}
}
kv_size(state->active) = j;
@@ -344,22 +342,26 @@ void decor_redraw_end(DecorState *state)
state->buf = NULL;
}
-VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
+VirtText decor_redraw_virt_text(buf_T *buf, DecorState *state)
{
decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange item = kv_A(state->active, i);
- if (item.start_row == state->row && item.virt_text
+ if (item.start_row == state->row && kv_size(item.virt_text)
&& item.virt_text_pos == kVTEndOfLine) {
return item.virt_text;
}
}
- return NULL;
+ return VIRTTEXT_EMPTY;
}
void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,
Decoration *decor, DecorPriority priority)
{
+ if (end_row == -1) {
+ end_row = start_row;
+ end_col = start_col;
+ }
decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true,
priority);
}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 264e8a4a82..c5424a1642 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -53,7 +53,7 @@ typedef struct {
// TODO(bfredl): embed decoration instead, perhaps using an arena
// for ephemerals?
DecorPriority priority;
- VirtText *virt_text;
+ VirtText virt_text;
VirtTextPos virt_text_pos;
bool virt_text_hide;
HlMode hl_mode;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index cffa46fa77..b5d5d67e90 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -8764,6 +8764,10 @@ static bool ins_tab(void)
getvcol(curwin, &fpos, &vcol, NULL, NULL);
getvcol(curwin, cursor, &want_vcol, NULL, NULL);
+ // save start of changed region for extmark_splice
+ int start_row = fpos.lnum;
+ colnr_T start_col = fpos.col;
+
// Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
// and 'linebreak' adding extra virtual columns.
while (ascii_iswhite(*ptr)) {
@@ -8813,6 +8817,11 @@ static bool ins_tab(void)
replace_join(repl_off);
}
}
+ if (!(State & VREPLACE_FLAG)) {
+ extmark_splice_cols(curbuf, start_row - 1, start_col,
+ cursor->col - start_col, fpos.col - start_col,
+ kExtmarkUndo);
+ }
}
cursor->col -= i;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index e94d7831b0..d1a3ae3ff8 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -341,6 +341,7 @@ return {
string={args=1},
strlen={args=1},
strpart={args={2, 4}},
+ strptime={args=2},
strridx={args={2, 3}},
strtrans={args=1},
strwidth={args=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 01d23654de..650b4e3882 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -10189,6 +10189,38 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
}
+// "strptime({format}, {timestring})" function
+static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char fmt_buf[NUMBUFLEN];
+ char str_buf[NUMBUFLEN];
+
+ struct tm tmval = {
+ .tm_isdst = -1,
+ };
+ char *fmt = (char *)tv_get_string_buf(&argvars[0], fmt_buf);
+ char *str = (char *)tv_get_string_buf(&argvars[1], str_buf);
+
+ vimconv_T conv = {
+ .vc_type = CONV_NONE,
+ };
+ char_u *enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE) {
+ fmt = (char *)string_convert(&conv, (char_u *)fmt, NULL);
+ }
+ if (fmt == NULL
+ || os_strptime(str, fmt, &tmval) == NULL
+ || (rettv->vval.v_number = mktime(&tmval)) == -1) {
+ rettv->vval.v_number = 0;
+ }
+ if (conv.vc_type != CONV_NONE) {
+ xfree(fmt);
+ }
+ convert_setup(&conv, NULL, NULL);
+ xfree(enc);
+}
+
/*
* "strridx()" function
*/
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 3038fad894..0ff427c261 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3177,7 +3177,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// insert the new text
totlen = (size_t)(count * (yanklen + spaces)
+ bd.startspaces + bd.endspaces);
- newp = (char_u *) xmalloc(totlen + oldlen + 1);
+ int addcount = (int)totlen + lines_appended;
+ newp = (char_u *)xmalloc(totlen + oldlen + 1);
// copy part up to cursor to new line
ptr = newp;
memmove(ptr, oldp, (size_t)bd.textcol);
@@ -3194,6 +3195,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if ((j < count - 1 || !shortline) && spaces) {
memset(ptr, ' ', (size_t)spaces);
ptr += spaces;
+ } else {
+ addcount -= spaces;
}
}
// may insert some spaces after the new text
@@ -3205,7 +3208,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
ml_replace(curwin->w_cursor.lnum, newp, false);
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum-1, bd.textcol,
- delcount, (int)totlen + lines_appended, kExtmarkUndo);
+ delcount, addcount, kExtmarkUndo);
++curwin->w_cursor.lnum;
if (i == 0)
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d04329e104..949558894f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -379,8 +379,8 @@ void set_init_1(bool clean_arg)
# else
static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
# endif
- int len;
garray_T ga;
+ opt_idx = findoption("backupskip");
ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
@@ -401,15 +401,23 @@ void set_init_1(bool clean_arg)
}
if (p != NULL && *p != NUL) {
// First time count the NUL, otherwise count the ','.
- len = (int)strlen(p) + 3;
- ga_grow(&ga, len);
- if (!GA_EMPTY(&ga)) {
- STRCAT(ga.ga_data, ",");
+ const size_t len = strlen(p) + 3;
+ char *item = xmalloc(len);
+ xstrlcpy(item, p, len);
+ add_pathsep(item);
+ xstrlcat(item, "*", len);
+ if (find_dup_item(ga.ga_data, (char_u *)item, options[opt_idx].flags)
+ == NULL) {
+ ga_grow(&ga, (int)len);
+ if (!GA_EMPTY(&ga)) {
+ STRCAT(ga.ga_data, ",");
+ }
+ STRCAT(ga.ga_data, p);
+ add_pathsep(ga.ga_data);
+ STRCAT(ga.ga_data, "*");
+ ga.ga_len += (int)len;
}
- STRCAT(ga.ga_data, p);
- add_pathsep(ga.ga_data);
- STRCAT(ga.ga_data, "*");
- ga.ga_len += len;
+ xfree(item);
}
if(mustfree) {
xfree(p);
@@ -713,6 +721,38 @@ static void set_string_default(const char *name, char *val, bool allocated)
}
}
+// For an option value that contains comma separated items, find "newval" in
+// "origval". Return NULL if not found.
+static char_u *find_dup_item(char_u *origval, const char_u *newval,
+ uint32_t flags)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ int bs = 0;
+
+ if (origval == NULL) {
+ return NULL;
+ }
+
+ const size_t newlen = STRLEN(newval);
+ for (char_u *s = origval; *s != NUL; s++) {
+ if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
+ && STRNCMP(s, newval, newlen) == 0
+ && (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
+ return s;
+ }
+ // Count backslashes. Only a comma with an even number of backslashes
+ // or a single backslash preceded by a comma before it is recognized as
+ // a separator.
+ if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
+ || (s == origval + 1 && s[-1] == '\\')) {
+ bs++;
+ } else {
+ bs = 0;
+ }
+ }
+ return NULL;
+}
+
/// Set the Vi-default value of a number option.
/// Used for 'lines' and 'columns'.
void set_number_default(char *name, long val)
@@ -1285,9 +1325,7 @@ int do_set(
char *saved_newval = NULL;
unsigned newlen;
int comma;
- int bs;
- int new_value_alloced; /* new string option
- was allocated */
+ bool new_value_alloced = false; // new string option was allocated
/* When using ":set opt=val" for a global option
* with a local value the local value will be
@@ -1486,34 +1524,20 @@ int do_set(
i = 0; // init for GCC
if (removing || (flags & P_NODUP)) {
i = (int)STRLEN(newval);
- bs = 0;
- for (s = origval; *s; s++) {
- if ((!(flags & P_COMMA)
- || s == origval
- || (s[-1] == ',' && !(bs & 1)))
- && STRNCMP(s, newval, i) == 0
- && (!(flags & P_COMMA)
- || s[i] == ','
- || s[i] == NUL)) {
- break;
- }
- // Count backslashes. Only a comma with an even number of
- // backslashes or a single backslash preceded by a comma
- // before it is recognized as a separator
- if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
- || (s == origval + 1 && s[-1] == '\\')) {
- bs++;
- } else {
- bs = 0;
- }
- }
+ s = find_dup_item(origval, newval, flags);
// do not add if already there
- if ((adding || prepending) && *s) {
+ if ((adding || prepending) && s != NULL) {
prepending = false;
adding = false;
STRCPY(newval, origval);
}
+
+ // if no duplicate, move pointer to end of
+ // original value
+ if (s == NULL) {
+ s = origval + (int)STRLEN(origval);
+ }
}
/* concatenate the two strings; add a ',' if
@@ -2310,7 +2334,7 @@ static char_u *
did_set_string_option(
int opt_idx, // index in options[] table
char_u **varp, // pointer to the option variable
- int new_value_alloced, // new value was allocated
+ bool new_value_alloced, // new value was allocated
char_u *oldval, // previous value of the option
char_u *errbuf, // buffer for errors, or NULL
size_t errbuflen, // length of errors buffer
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 5cf628935f..e7e0dc4013 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -196,6 +196,22 @@ char *os_ctime(char *result, size_t result_len)
return os_ctime_r(&rawtime, result, result_len);
}
+/// Portable version of POSIX strptime()
+///
+/// @param str[in] string to convert
+/// @param format[in] format to parse "str"
+/// @param tm[out] time representation of "str"
+/// @return Pointer to first unprocessed character or NULL
+char *os_strptime(const char *str, const char *format, struct tm *tm)
+ FUNC_ATTR_NONNULL_ALL
+{
+#ifdef HAVE_STRPTIME
+ return strptime(str, format, tm);
+#else
+ return NULL;
+#endif
+}
+
/// Obtains the current Unix timestamp.
///
/// @return Seconds since epoch.
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 69c614fff9..68abf57413 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -140,7 +140,9 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
}
pum_anchor_grid = (int)curwin->w_grid.target->handle;
- if (!ui_has(kUIMultigrid)) {
+ pum_win_row += curwin->w_grid.row_offset;
+ cursor_col += curwin->w_grid.col_offset;
+ if (!ui_has(kUIMultigrid) && curwin->w_grid.target != &default_grid) {
pum_anchor_grid = (int)default_grid.handle;
pum_win_row += curwin->w_winrow;
cursor_col += curwin->w_wincol;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index d50520f49e..749627de80 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2322,7 +2322,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
}
// do at least one character; happens when past end of line
- if (fromcol == tocol) {
+ if (fromcol == tocol && search_match_endcol) {
tocol = fromcol + 1;
}
area_highlighting = true;
@@ -2758,7 +2758,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// :sign defined with "numhl" highlight.
char_attr = sign_get_attr(num_sign, SIGN_NUMHL);
} else if ((wp->w_p_cul || wp->w_p_rnu)
- && lnum == wp->w_cursor.lnum) {
+ && lnum == wp->w_cursor.lnum
+ && filler_todo == 0) {
// When 'cursorline' is set highlight the line number of
// the current line differently.
// TODO(vim): Can we use CursorLine instead of CursorLineNr
@@ -3921,9 +3922,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
.hl_id = hl_err }));
do_virttext = true;
} else if (has_decor) {
- VirtText *vp = decor_redraw_virt_text(wp->w_buffer, &decor_state);
- if (vp) {
- virt_text = *vp;
+ virt_text = decor_redraw_virt_text(wp->w_buffer, &decor_state);
+ if (kv_size(virt_text)) {
do_virttext = true;
}
}
@@ -4353,10 +4353,10 @@ void draw_virt_text(buf_T *buf, int *end_col, int max_col)
DecorState *state = &decor_state;
for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange *item = &kv_A(state->active, i);
- if (item->start_row == state->row && item->virt_text
+ if (item->start_row == state->row && kv_size(item->virt_text)
&& item->virt_text_pos == kVTOverlay
&& item->virt_col >= 0) {
- VirtText vt = *item->virt_text;
+ VirtText vt = item->virt_text;
LineState s = LINE_STATE("");
int virt_attr = 0;
int col = item->virt_col;
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index e52fd888bd..b760828458 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -36,15 +36,9 @@ NEW_TESTS_IN_ALOT := $(shell sed -n '/^source/ s/^source //; s/\.vim$$//p' $(add
NEW_TESTS_IN_ALOT_LATIN := $(shell sed -n '/^source/ s/^source //; s/\.vim$$//p' test_alot_latin.vim)
# Ignored tests.
# test_alot_latin: Nvim does not allow setting encoding.
-# test_autochdir: ported to Lua, but kept for easier merging.
-# test_eval_func: used as include in old-style test (test_eval.in).
-# test_listlbr: Nvim does not allow setting encoding.
# test_largefile: uses too much resources to run on CI.
NEW_TESTS_IGNORE := \
test_alot_latin $(NEW_TESTS_IN_ALOT_LATIN) \
- test_autochdir \
- test_eval_func \
- test_listlbr \
test_largefile \
NEW_TESTS := $(sort $(basename $(notdir $(wildcard test_*.vim))))
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 275edece1e..2d94b637e0 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -373,9 +373,6 @@ let s:flaky_tests = [
\ 'Test_with_partial_callback()',
\ ]
-" Pattern indicating a common flaky test failure.
-let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
-
" Locate Test_ functions and execute them.
redir @q
silent function /^Test_
@@ -410,6 +407,9 @@ for s:test in sort(s:tests)
let total_errors = []
let run_nr = 1
+ " A test can set g:test_is_flaky to retry running the test.
+ let g:test_is_flaky = 0
+
call RunTheTest(s:test)
" Repeat a flaky test. Give up when:
@@ -417,7 +417,7 @@ for s:test in sort(s:tests)
" - it fails five times (with a different message)
if len(v:errors) > 0
\ && (index(s:flaky_tests, s:test) >= 0
- \ || v:errors[0] =~ s:flaky_errors_re)
+ \ || g:test_is_flaky)
while 1
call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors)
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 67c537b407..d071f4b325 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -1,10 +1,10 @@
" Test 'autochdir' behavior
-if !exists("+autochdir")
- throw 'Skipped: autochdir feature missing'
-endif
+source check.vim
+CheckOption autochdir
func Test_set_filename()
+ CheckFunction test_autochdir
let cwd = getcwd()
call test_autochdir()
set acd
@@ -17,3 +17,5 @@ func Test_set_filename()
exe 'cd ' . cwd
call delete('samples/Xtest')
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 7788e09d43..5e99edf233 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -76,7 +76,7 @@ if has('timers')
endfunc
func Test_OptionSet_modeline()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
au! OptionSet
augroup set_tabstop
@@ -507,7 +507,7 @@ func s:AutoCommandOptionSet(match)
endfunc
func Test_OptionSet()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !has("eval") || !exists("+autochdir")
return
endif
@@ -648,7 +648,7 @@ func Test_OptionSet()
endfunc
func Test_OptionSet_diffmode()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
" 18: Changing an option when entering diff mode
new
@@ -682,7 +682,7 @@ func Test_OptionSet_diffmode()
endfunc
func Test_OptionSet_diffmode_close()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
" 19: Try to close the current window when entering diff mode
" should not segfault
@@ -1285,9 +1285,9 @@ func Test_autocommand_all_events()
endfunc
" Test TextChangedI and TextChangedP
+" See test/functional/viml/completion_spec.lua'
func Test_ChangedP()
- " Nvim does not support test_override().
- throw 'skipped: see test/functional/viml/completion_spec.lua'
+ CheckFunction test_override
new
call setline(1, ['foo', 'bar', 'foobar'])
call test_override("char_avail", 1)
@@ -1350,7 +1350,7 @@ func SetLineOne()
endfunc
func Test_TextChangedI_with_setline()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
new
call test_override('char_avail', 1)
autocmd TextChangedI <buffer> call SetLineOne()
@@ -1366,9 +1366,11 @@ func Test_TextChangedI_with_setline()
endfunc
func Test_Changed_FirstTime()
- if !has('terminal') || has('gui_running')
- return
- endif
+ CheckFeature terminal
+ CheckNotGui
+ " Starting a terminal to run Vim is always considered flaky.
+ let g:test_is_flaky = 1
+
" Prepare file for TextChanged event.
call writefile([''], 'Xchanged.txt')
let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index ff50d53d86..73b57f302e 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -24,7 +24,7 @@ endfunc
func Test_for_invalid()
call assert_fails("for x in 99", 'E714:')
- call assert_fails("for x in 'asdf'", 'E714:')
+ call assert_fails("for x in function('winnr')", 'E714:')
call assert_fails("for x in {'a': 9}", 'E714:')
if 0
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 5dae8d681a..555f549743 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1,5 +1,7 @@
" Tests for various functions.
+
source shared.vim
+source check.vim
" Must be done first, since the alternate buffer must be unset.
func Test_00_bufexists()
@@ -171,9 +173,8 @@ func Test_str2nr()
endfunc
func Test_strftime()
- if !exists('*strftime')
- return
- endif
+ CheckFunction strftime
+
" Format of strftime() depends on system. We assume
" that basic formats tested here are available and
" identical on all systems which support strftime().
@@ -214,6 +215,33 @@ func Test_strftime()
endif
endfunc
+func Test_strptime()
+ CheckFunction strptime
+ CheckNotMSWindows
+
+ if exists('$TZ')
+ let tz = $TZ
+ endif
+ let $TZ = 'UTC'
+
+ call assert_equal(1484653763, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23'))
+
+ " Force DST and check that it's considered
+ let $TZ = 'WINTER0SUMMER,J1,J365'
+ call assert_equal(1484653763 - 3600, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23'))
+
+ call assert_fails('call strptime()', 'E119:')
+ call assert_fails('call strptime("xxx")', 'E119:')
+ call assert_equal(0, strptime("%Y", ''))
+ call assert_equal(0, strptime("%Y", "xxx"))
+
+ if exists('tz')
+ let $TZ = tz
+ else
+ unlet $TZ
+ endif
+endfunc
+
func Test_resolve_unix()
if !has('unix')
return
diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim
index d619ac0eb5..e0518de3c2 100644
--- a/src/nvim/testdir/test_listlbr.vim
+++ b/src/nvim/testdir/test_listlbr.vim
@@ -1,9 +1,5 @@
" Test for linebreak and list option (non-utf8)
-" Nvim does not allow setting 'encoding', so skip this test.
-finish
-
-set encoding=latin1
scriptencoding latin1
if !exists("+linebreak") || !has("conceal")
@@ -46,6 +42,7 @@ func Test_set_linebreak()
endfunc
func Test_linebreak_with_list()
+ throw 'skipped: Nvim does not support enc=latin1'
call s:test_windows('setl ts=4 sbr=+ list listchars=')
call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
let lines = s:screen_lines([1, 4], winwidth(0))
@@ -217,6 +214,7 @@ func Test_norm_after_block_visual()
endfunc
func Test_block_replace_after_wrapping()
+ throw 'skipped: Nvim does not support enc=latin1'
call s:test_windows()
call setline(1, repeat("a", 150))
exe "norm! 0yypk147|\<C-V>jr0"
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 3ebd048f46..08586dffe1 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -1,5 +1,6 @@
" Tests for :messages, :echomsg, :echoerr
+source check.vim
source shared.vim
func Test_messages()
@@ -77,7 +78,7 @@ func Test_echomsg()
endfunc
func Test_echoerr()
- throw 'skipped: Nvim does not support test_ignore_error()'
+ CheckFunction test_ignore_error
call test_ignore_error('IgNoRe')
call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"'))
call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"'))
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 07e2481f95..5aef33cb09 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -448,6 +448,36 @@ func Test_backupskip()
endif
endfor
+ " Duplicates from environment variables should be filtered out (option has
+ " P_NODUP). Run this in a separate instance and write v:errors in a file,
+ " so that we see what happens on startup.
+ let after =<< trim [CODE]
+ let bsklist = split(&backupskip, ',')
+ call assert_equal(uniq(copy(bsklist)), bsklist)
+ call writefile(['errors:'] + v:errors, 'Xtestout')
+ qall
+ [CODE]
+ call writefile(after, 'Xafter')
+ " let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
+ let cmd = GetVimProg() . ' -S Xafter --cmd "set enc=utf8"'
+
+ let saveenv = {}
+ for var in ['TMPDIR', 'TMP', 'TEMP']
+ let saveenv[var] = getenv(var)
+ call setenv(var, '/duplicate/path')
+ endfor
+
+ exe 'silent !' . cmd
+ call assert_equal(['errors:'], readfile('Xtestout'))
+
+ " restore environment variables
+ for var in ['TMPDIR', 'TMP', 'TEMP']
+ call setenv(var, saveenv[var])
+ endfor
+
+ call delete('Xtestout')
+ call delete('Xafter')
+
" Duplicates should be filtered out (option has P_NODUP)
let backupskip = &backupskip
set backupskip=
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 4ee16558a0..9443958984 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -871,7 +871,7 @@ func Test_popup_complete_backwards_ctrl_p()
endfunc
fun! Test_complete_o_tab()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
let s:o_char_pressed = 0
fun! s:act_on_text_changed()
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 704fdacdcd..da949f5940 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -2660,7 +2660,7 @@ endfunc
" Test for incsearch highlighting of the :vimgrep pattern
" This test used to cause "E315: ml_get: invalid lnum" errors.
func Test_vimgrep_incsearch()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
enew
set incsearch
call test_override("char_avail", 1)
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 0703a6b141..d4d529e4b9 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -2,10 +2,11 @@
source shared.vim
source screendump.vim
+source check.vim
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -202,9 +203,9 @@ func Test_search_cmdline()
bw!
endfunc
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline2()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -351,7 +352,7 @@ func Test_searchc()
endfunc
func Cmdline3_prep()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
" need to disable char_avail,
" so that expansion of commandline works
call test_override("char_avail", 1)
@@ -361,14 +362,13 @@ func Cmdline3_prep()
endfunc
func Incsearch_cleanup()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
set noincsearch
call test_override("char_avail", 0)
bw!
endfunc
func Test_search_cmdline3()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -382,7 +382,6 @@ func Test_search_cmdline3()
endfunc
func Test_search_cmdline3s()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -409,7 +408,6 @@ func Test_search_cmdline3s()
endfunc
func Test_search_cmdline3g()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -433,7 +431,6 @@ func Test_search_cmdline3g()
endfunc
func Test_search_cmdline3v()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -450,9 +447,9 @@ func Test_search_cmdline3v()
call Incsearch_cleanup()
endfunc
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline4()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -507,7 +504,7 @@ func Test_search_cmdline5()
endfunc
func Test_search_cmdline7()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
" Test that pressing <c-g> in an empty command line
" does not move the cursor
if !exists('+incsearch')
@@ -798,7 +795,7 @@ func Test_incsearch_vimgrep_dump()
endfunc
func Test_keep_last_search_pattern()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -820,7 +817,7 @@ func Test_keep_last_search_pattern()
endfunc
func Test_word_under_cursor_after_match()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -840,7 +837,7 @@ func Test_word_under_cursor_after_match()
endfunc
func Test_subst_word_under_cursor()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -882,7 +879,7 @@ func Test_incsearch_with_change()
endfunc
func Test_incsearch_cmdline_modifier()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -960,7 +957,7 @@ func Test_incsearch_search_dump()
endfunc
func Test_incsearch_substitute()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -982,7 +979,7 @@ func Test_incsearch_substitute()
endfunc
func Test_incsearch_substitute_long_line()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
new
call test_override("char_avail", 1)
set incsearch
@@ -1104,7 +1101,7 @@ func Test_one_error_msg()
endfunc
func Test_incsearch_add_char_under_cursor()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -1192,4 +1189,40 @@ func Test_search_smartcase_utf8()
close!
endfunc
+func Test_zzzz_incsearch_highlighting_newline()
+ CheckRunVimInTerminal
+ CheckOption incsearch
+ CheckScreendump
+ new
+ call test_override("char_avail", 1)
+
+ let commands =<< trim [CODE]
+ set incsearch nohls
+ call setline(1, ['test', 'xxx'])
+ [CODE]
+ call writefile(commands, 'Xincsearch_nl')
+ let buf = RunVimInTerminal('-S Xincsearch_nl', {'rows': 5, 'cols': 10})
+ " Need to send one key at a time to force a redraw
+ call term_sendkeys(buf, '/test')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline1', {})
+ call term_sendkeys(buf, '\n')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline2', {})
+ call term_sendkeys(buf, 'x')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline3', {})
+ call term_sendkeys(buf, 'x')
+ call VerifyScreenDump(buf, 'Test_incsearch_newline4', {})
+ call term_sendkeys(buf, "\<CR>")
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline5', {})
+ call StopVimInTerminal(buf)
+
+ " clean up
+ call delete('Xincsearch_nl')
+ call test_override("char_avail", 0)
+ bw
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 4bbd722fdb..9c3a5636ce 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -1,8 +1,7 @@
" Test for signs
-if !has('signs')
- finish
-endif
+source check.vim
+CheckFeature signs
source screendump.vim
@@ -1541,7 +1540,7 @@ endfunc
" Tests for memory allocation failures in sign functions
func Test_sign_memfailures()
- throw 'skipped: Nvim does not support test_alloc_fail()'
+ CheckFunction test_alloc_fail
call writefile(repeat(["Sun is shining"], 30), "Xsign")
edit Xsign
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 4d1ad10c23..eb9378194f 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -862,6 +862,34 @@ func Test_x_arg()
call delete('Xtest_x_arg')
endfunc
+" Test for --not-a-term avoiding escape codes.
+func Test_not_a_term()
+ CheckUnix
+ CheckNotGui
+
+ if &shellredir =~ '%s'
+ let redir = printf(&shellredir, 'Xvimout')
+ else
+ let redir = &shellredir .. ' Xvimout'
+ endif
+
+ " Without --not-a-term there are a few escape sequences.
+ " This will take 2 seconds because of the missing --not-a-term
+ let cmd = GetVimProg() .. ' --cmd quit ' .. redir
+ exe "silent !" . cmd
+ " call assert_match("\<Esc>", readfile('Xvimout')->join())
+ call assert_match("\<Esc>", join(readfile('Xvimout')))
+ call delete('Xvimout')
+
+ " With --not-a-term there are no escape sequences.
+ let cmd = GetVimProg() .. ' --not-a-term --cmd quit ' .. redir
+ exe "silent !" . cmd
+ " call assert_notmatch("\<Esc>", readfile('Xvimout')->join())
+ call assert_notmatch("\<Esc>", join(readfile('Xvimout')))
+ call delete('Xvimout')
+endfunc
+
+
" Test starting vim with various names: vim, ex, view, evim, etc.
func Test_progname()
CheckUnix
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 9cf8690d57..6bbe714d19 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -93,7 +93,6 @@ function! Test_system_exmode()
endfunc
func Test_system_with_shell_quote()
- throw 'skipped: enable after porting method patches'
CheckMSWindows
call mkdir('Xdir with spaces', 'p')
@@ -122,7 +121,8 @@ func Test_system_with_shell_quote()
let msg = printf('shell=%s shellxquote=%s', &shell, &shellxquote)
try
- let out = 'echo 123'->system()
+ " let out = 'echo 123'->system()
+ let out = system('echo 123')
catch
call assert_report(printf('%s: %s', msg, v:exception))
continue
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 13971a918d..ceaa5de92b 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -317,8 +317,8 @@ endfunc
" Test that the garbage collector isn't triggered if a timer callback invokes
" vgetc().
func Test_nocatch_garbage_collect()
- " skipped: Nvim does not support test_garbagecollect_soon(), test_override()
- return
+ CheckFunction test_garbagecollect_soon
+ CheckFunction test_override
" 'uptimetime. must be bigger than the timer timeout
set ut=200
call test_garbagecollect_soon()
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 3b66071d6d..54caed3983 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -3,6 +3,8 @@
" undo-able pieces. Do that by setting 'undolevels'.
" Also tests :earlier and :later.
+source check.vim
+
func Test_undotree()
new
@@ -135,7 +137,7 @@ func BackOne(expected)
endfunc
func Test_undo_del_chars()
- throw 'skipped: Nvim does not support test_settime()'
+ CheckFunction test_settime
" Setup a buffer without creating undo entries
new
@@ -330,7 +332,7 @@ func Test_insert_expr()
endfunc
func Test_undofile_earlier()
- throw 'skipped: Nvim does not support test_settime()'
+ CheckFunction test_settime
let t0 = localtime() - 43200
call test_settime(t0)
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index c6c09c80d7..94b6e9e39d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -110,6 +110,7 @@ static char uilog_last_event[1024] = { 0 };
void ui_init(void)
{
default_grid.handle = 1;
+ msg_grid_adj.target = &default_grid;
ui_comp_init();
}
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 946215d957..a2e9266fbb 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -184,14 +184,12 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
insert_at--;
}
// not found: new grid
- kv_push(layers, grid);
- if (insert_at < kv_size(layers)-1) {
- for (size_t i = kv_size(layers)-1; i > insert_at; i--) {
- kv_A(layers, i) = kv_A(layers, i-1);
- kv_A(layers, i)->comp_index = i;
- }
- kv_A(layers, insert_at) = grid;
+ kv_pushp(layers);
+ for (size_t i = kv_size(layers)-1; i > insert_at; i--) {
+ kv_A(layers, i) = kv_A(layers, i-1);
+ kv_A(layers, i)->comp_index = i;
}
+ kv_A(layers, insert_at) = grid;
grid->comp_row = row;
grid->comp_col = col;
@@ -280,6 +278,9 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
// should configure all grids before entering win_update()
if (curgrid != &default_grid) {
size_t new_index = kv_size(layers)-1;
+ if (kv_A(layers, new_index) == &msg_grid) {
+ new_index--;
+ }
if (kv_A(layers, new_index) == &pum_grid) {
new_index--;
}
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 7a6b5be8bc..6d7d9b4d8b 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -666,6 +666,70 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it("tab with noexpandtab and softtabstop", function()
+ command("set noet")
+ command("set ts=4")
+ command("set sw=2")
+ command("set sts=2")
+
+ local check_events = setup_eventcheck(verify, {'asdfasdf'})
+
+ feed("gg0i<tab>")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ }
+ feed("<tab>")
+
+ -- when spaces are merged into a tabstop
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
+ }
+
+ feed("<esc>u")
+ check_events {
+ { "test1", "bytes", 1, 8, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 8, 0, 0, 0, 0, 4, 4, 0, 0, 0 }
+ }
+
+ -- in REPLACE mode
+ feed("R<tab><tab>")
+ check_events {
+ { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 10, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 11, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 12, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 13, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
+ }
+ feed("<esc>u")
+ check_events {
+ { "test1", "bytes", 1, 14, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 14, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
+ { "test1", "bytes", 1, 14, 0, 0, 0, 0, 2, 2, 0, 1, 1 }
+ }
+
+ -- in VISUALREPLACE mode
+ feed("gR<tab><tab>")
+ check_events {
+ { "test1", "bytes", 1, 15, 0, 0, 0, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 16, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 17, 0, 2, 2, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 18, 0, 3, 3, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 19, 0, 3, 3, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 20, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 22, 0, 2, 2, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 23, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 25, 0, 1, 1, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 26, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 28, 0, 0, 0, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 29, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 31, 0, 0, 0, 0, 4, 4, 0, 1, 1 };
+ }
+ end)
+
it("sends events when undoing with undofile", function()
write_file("Xtest-undofile", dedent([[
12345
@@ -717,6 +781,26 @@ describe('lua: nvim_buf_attach on_bytes', function()
command("bw!")
end)
+ it("blockwise paste with uneven line lengths", function()
+ local check_events = setup_eventcheck(verify, {'aaaa', 'aaa', 'aaa'})
+
+ -- eq({}, meths.buf_get_lines(0, 0, -1, true))
+ feed("gg0<c-v>jj$d")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
+ { "test1", "bytes", 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 },
+ { "test1", "bytes", 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 },
+ }
+
+ feed("p")
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 },
+ { "test1", "bytes", 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 },
+ { "test1", "bytes", 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 },
+ }
+
+ end)
teardown(function()
os.remove "Xtest-reload"
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 7f4ab3ee5d..295a54aec8 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -302,6 +302,35 @@ describe('decorations providers', function()
|
]]}
end)
+
+ it('can have virtual text', function()
+ insert(mulholland)
+ setup_provider [[
+ local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
+ local test_ns = a.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ virt_text = {{'+', 'ErrorMsg'}};
+ virt_text_pos='overlay';
+ ephemeral = true;
+ })
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ {2:+}/ just to see if there was an accident |
+ {2:+}/ on Mulholland Drive |
+ {2:+}ry_start(); |
+ {2:+}ufref_T save_buf; |
+ {2:+}witch_buffer(&save_buf, buf); |
+ {2:+}osp = getmark(mark, false); |
+ {2:+}estore_buffer(&save_buf);^ |
+ |
+ ]]}
+ end)
end)
describe('extmark decorations', function()
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 69b6ab8cf0..a8d9fb02fc 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1049,6 +1049,8 @@ it('diff updates line numbers below filler lines', function()
[9] = {background = Screen.colors.LightMagenta},
[10] = {bold = true, foreground = Screen.colors.Brown},
[11] = {foreground = Screen.colors.Brown},
+ [12] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
+ [13] = {background = Screen.colors.Gray90};
})
source([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
@@ -1107,4 +1109,22 @@ it('diff updates line numbers below filler lines', function()
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
+ command("set signcolumn number tgc cursorline")
+ command("hi CursorLineNr guibg=red")
+ screen:expect{grid=[[
+ {1: }a {3:│}{11: 2 }a |
+ {1: }a {3:│}{11: 1 }a |
+ {1: }a {3:│}{12:3 }{13:^a }|
+ {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
+ {1: }{4:x }{3:│}{11: }{2:----------------}|
+ {1: }{4:x }{3:│}{11: }{2:----------------}|
+ {1: }b {3:│}{11: 2 }b |
+ {1: }b {3:│}{11: 3 }b |
+ {1: }b {3:│}{11: 4 }b |
+ {1: }b {3:│}{11: 5 }b |
+ {1: }b {3:│}{11: 6 }b |
+ {6:~ }{3:│}{6:~ }|
+ {3:[No Name] [+] }{7:[No Name] [+] }|
+ signcolumn=auto |
+ ]]}
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index e4824521b0..664b8e7ab7 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -774,6 +774,131 @@ describe('float window', function()
end
end)
+ it('with border show popupmenu', function()
+ screen:try_resize(40,10)
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {'aaa aab ',
+ 'abb acc ', ''})
+ meths.open_win(buf, true, {relative='editor', width=9, height=3, row=0, col=5, border="double"})
+ feed 'G'
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔═════════╗}|
+ {5:║}{1:aaa aab }{5:║}|
+ {5:║}{1:abb acc }{5:║}|
+ {5:║}{1:^ }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 0, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:╔═════════╗} |
+ {0:~ }{5:║}{1:aaa aab }{5:║}{0: }|
+ {0:~ }{5:║}{1:abb acc }{5:║}{0: }|
+ {0:~ }{5:║}{1:^ }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ feed 'i<c-x><c-p>'
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- }{8:match 1 of 4} |
+ ## grid 5
+ {5:╔═════════╗}|
+ {5:║}{1:aaa aab }{5:║}|
+ {5:║}{1:abb acc }{5:║}|
+ {5:║}{1:acc^ }{5:║}|
+ {5:╚═════════╝}|
+ ## grid 6
+ {1: aaa }|
+ {1: aab }|
+ {1: abb }|
+ {13: acc }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 1, 0, 5, true },
+ [6] = { {
+ id = -1
+ }, "NW", 5, 4, 0, false }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:╔═════════╗} |
+ {0:~ }{5:║}{1:aaa aab }{5:║}{0: }|
+ {0:~ }{5:║}{1:abb acc }{5:║}{0: }|
+ {0:~ }{5:║}{1:acc^ }{5:║}{0: }|
+ {0:~ }{1: aaa }{0: }|
+ {0:~ }{1: aab }{0: }|
+ {0:~ }{1: abb }{0: }|
+ {0:~ }{13: acc }{0: }|
+ {0:~ }|
+ {3:-- }{8:match 1 of 4} |
+ ]]}
+ end
+ end)
+
it('can have minimum size', function()
insert("the background text")
local buf = meths.create_buf(false, true)
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index ff9f30d0a1..958e137f65 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -24,10 +24,6 @@ describe('screen', function()
} )
end)
- after_each(function()
- screen:detach()
- end)
-
it('default initial screen', function()
screen:expect([[
^ |
@@ -67,10 +63,6 @@ local function screen_tests(linegrid)
} )
end)
- after_each(function()
- screen:detach()
- end)
-
describe(':suspend', function()
it('is forwarded to the UI', function()
local function check()
@@ -1004,3 +996,39 @@ describe('Screen default colors', function()
end}
end)
end)
+
+
+describe('screen with msgsep deactivated on startup', function()
+ local screen
+
+ before_each(function()
+ clear('--cmd', 'set display-=msgsep')
+ screen = Screen.new()
+ screen:attach()
+ screen:set_default_attr_ids {
+ [0] = {bold=true, foreground=255};
+ [7] = {bold = true, foreground = Screen.colors.SeaGreen};
+ }
+ end)
+
+ it('execute command with multi-line output', function()
+ feed ':ls<cr>'
+ screen:expect([[
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+ feed '<cr>' -- skip the "Press ENTER..." state or tests will hang
+ end)
+end)