aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt25
-rw-r--r--runtime/plugin/netrwPlugin.vim8
-rw-r--r--src/nvim/api/vim.c6
-rw-r--r--src/nvim/api/window.c32
-rw-r--r--src/nvim/buffer.c10
-rw-r--r--src/nvim/buffer_defs.h4
-rw-r--r--src/nvim/change.c12
-rw-r--r--src/nvim/eval.c28
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/ex_cmds2.c4
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/fileio.c12
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/message.c6
-rw-r--r--src/nvim/move.c75
-rw-r--r--src/nvim/option_defs.h15
-rw-r--r--src/nvim/os/signal.c2
-rw-r--r--src/nvim/quickfix.c216
-rw-r--r--src/nvim/testdir/test_changedtick.vim38
-rw-r--r--src/nvim/testdir/test_cursor_func.vim28
-rw-r--r--src/nvim/testdir/test_quickfix.vim32
-rw-r--r--src/nvim/undo.c2
-rw-r--r--src/nvim/version.c406
-rw-r--r--src/nvim/window.c78
-rw-r--r--test/functional/api/server_requests_spec.lua4
-rw-r--r--test/functional/api/vim_spec.lua4
-rw-r--r--test/functional/core/channels_spec.lua4
-rw-r--r--test/functional/core/job_spec.lua2
-rw-r--r--test/functional/helpers.lua21
-rw-r--r--test/functional/legacy/file_perm_spec.lua2
-rw-r--r--test/functional/plugin/shada_spec.lua509
-rw-r--r--test/functional/terminal/scrollback_spec.lua29
-rw-r--r--test/functional/ui/float_spec.lua329
-rw-r--r--test/functional/ui/messages_spec.lua34
-rw-r--r--test/functional/ui/mode_spec.lua2
-rw-r--r--test/functional/ui/wildmode_spec.lua27
-rw-r--r--test/helpers.lua9
37 files changed, 1345 insertions, 675 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index d8c1132906..93bc7f868d 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1313,8 +1313,10 @@ One local buffer variable is predefined:
*b:changedtick* *changetick*
b:changedtick The total number of changes to the current buffer. It is
incremented for each change. An undo command is also a change
- in this case. This can be used to perform an action only when
- the buffer has changed. Example: >
+ in this case. Resetting 'modified' when writing the buffer is
+ also counted.
+ This can be used to perform an action only when the buffer has
+ changed. Example: >
:if my_changedtick != b:changedtick
: let my_changedtick = b:changedtick
: call My_Update()
@@ -2297,6 +2299,7 @@ rpcrequest({channel}, {method}[, {args}...])
screenattr({row}, {col}) Number attribute at screen position
screenchar({row}, {col}) Number character at screen position
screencol() Number current cursor column
+screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
screenrow() Number current cursor row
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
Number search for {pattern}
@@ -6798,7 +6801,25 @@ screencol() *screencol()*
the following mappings: >
nnoremap <expr> GG ":echom ".screencol()."\n"
nnoremap <silent> GG :echom screencol()<CR>
+ noremap GG <Cmd>echom screencol()<Cr>
<
+screenpos({winid}, {lnum}, {col}) *screenpos()*
+ The result is a Dict with the screen position of the text
+ character in window {winid} at buffer line {lnum} and column
+ {col}. {col} is a one-based byte index.
+ The Dict has these members:
+ row screen row
+ col first screen column
+ endcol last screen column
+ curscol cursor screen column
+ If the specified position is not visible, all values are zero.
+ The "endcol" value differs from "col" when the character
+ occupies more than one screen cell. E.g. for a Tab "col" can
+ be 1 and "endcol" can be 8.
+ The "curscol" value is where the cursor would be placed. For
+ a Tab it would be the same as "endcol", while for a double
+ width character it would be the same as "col".
+
screenrow() *screenrow()*
The result is a Number, which is the current screen row of the
cursor. The top line has number one.
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index e39bde88a7..2d67f6a4e4 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -47,9 +47,9 @@ augroup Network
au FileReadCmd ftp://*,rcp://*,scp://*,http://*,file://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau FileReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(1,expand("<amatch>"))|exe "sil doau FileReadPost ".fnameescape(expand("<amatch>"))
au BufWriteCmd ftp://*,rcp://*,scp://*,http://*,file://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau BufWritePre ".fnameescape(expand("<amatch>"))|exe 'Nwrite '.fnameescape(expand("<amatch>"))|exe "sil doau BufWritePost ".fnameescape(expand("<amatch>"))
au FileWriteCmd ftp://*,rcp://*,scp://*,http://*,file://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau FileWritePre ".fnameescape(expand("<amatch>"))|exe "'[,']".'Nwrite '.fnameescape(expand("<amatch>"))|exe "sil doau FileWritePost ".fnameescape(expand("<amatch>"))
- try
+ try
au SourceCmd ftp://*,rcp://*,scp://*,http://*,file://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe 'Nsource '.fnameescape(expand("<amatch>"))
- catch /^Vim\%((\a\+)\)\=:E216/
+ catch /^Vim\%((\a\+)\)\=:E216/
au SourcePre ftp://*,rcp://*,scp://*,http://*,file://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe 'Nsource '.fnameescape(expand("<amatch>"))
endtry
augroup END
@@ -81,7 +81,7 @@ if !exists("g:netrw_nogx")
if !hasmapto('<Plug>NetrwBrowseX')
nmap <unique> gx <Plug>NetrwBrowseX
endif
- nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(netrw#GX(),netrw#CheckIfRemote(netrw#GX()))<cr>
+ nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(expand((exists("g:netrw_gx")? g:netrw_gx : '<cfile>')),netrw#CheckIfRemote())<cr>
endif
if maparg('gx','v') == ""
if !hasmapto('<Plug>NetrwBrowseXVis')
@@ -103,7 +103,7 @@ fun! s:LocalBrowse(dirname)
" Unfortunate interaction -- only DechoMsg debugging calls can be safely used here.
" Otherwise, the BufEnter event gets triggered when attempts to write to
" the DBG buffer are made.
-
+
if !exists("s:vimentered")
" If s:vimentered doesn't exist, then the VimEnter event hasn't fired. It will,
" and so s:VimEnter() will then be calling this routine, but this time with s:vimentered defined.
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 2034fea770..27344fc093 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1059,6 +1059,12 @@ fail:
/// - "SE" south-east
/// - `height`: window height (in character cells). Minimum of 1.
/// - `width`: window width (in character cells). Minimum of 1.
+/// - 'bufpos': position float relative text inside the window `win` (only
+/// when relative="win"). Takes a tuple of [line, column] where
+/// both are zero-index. Note: `row` and `col` if present, still
+/// applies relative this positio. By default `row=1` and `col=0`
+/// is used (with default NW anchor), to make the float
+/// behave like a tooltip under the buffer text.
/// - `row`: row position. Screen cell height are used as unit. Can be
/// floating point.
/// - `col`: column position. Screen cell width is used as unit. Can be
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index e279edebde..02670c0513 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -503,25 +503,33 @@ Dictionary nvim_win_get_config(Window window, Error *err)
return rv;
}
- PUT(rv, "focusable", BOOLEAN_OBJ(wp->w_float_config.focusable));
- PUT(rv, "external", BOOLEAN_OBJ(wp->w_float_config.external));
+ FloatConfig *config = &wp->w_float_config;
+
+ PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable));
+ PUT(rv, "external", BOOLEAN_OBJ(config->external));
if (wp->w_floating) {
- PUT(rv, "width", INTEGER_OBJ(wp->w_float_config.width));
- PUT(rv, "height", INTEGER_OBJ(wp->w_float_config.height));
- if (!wp->w_float_config.external) {
- if (wp->w_float_config.relative == kFloatRelativeWindow) {
- PUT(rv, "win", INTEGER_OBJ(wp->w_float_config.window));
+ PUT(rv, "width", INTEGER_OBJ(config->width));
+ PUT(rv, "height", INTEGER_OBJ(config->height));
+ if (!config->external) {
+ if (config->relative == kFloatRelativeWindow) {
+ PUT(rv, "win", INTEGER_OBJ(config->window));
+ if (config->bufpos.lnum >= 0) {
+ Array pos = ARRAY_DICT_INIT;
+ ADD(pos, INTEGER_OBJ(config->bufpos.lnum));
+ ADD(pos, INTEGER_OBJ(config->bufpos.col));
+ PUT(rv, "bufpos", ARRAY_OBJ(pos));
+ }
}
PUT(rv, "anchor", STRING_OBJ(cstr_to_string(
- float_anchor_str[wp->w_float_config.anchor])));
- PUT(rv, "row", FLOAT_OBJ(wp->w_float_config.row));
- PUT(rv, "col", FLOAT_OBJ(wp->w_float_config.col));
+ float_anchor_str[config->anchor])));
+ PUT(rv, "row", FLOAT_OBJ(config->row));
+ PUT(rv, "col", FLOAT_OBJ(config->col));
}
}
- const char *rel = (wp->w_floating && !wp->w_float_config.external
- ? float_relative_str[wp->w_float_config.relative] : "");
+ const char *rel = (wp->w_floating && !config->external
+ ? float_relative_str[config->relative] : "");
PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel)));
return rv;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index f8e07a471f..8fd4360aed 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -144,7 +144,7 @@ read_buffer(
if (!readonlymode && !BUFEMPTY()) {
changed();
} else if (retval != FAIL) {
- unchanged(curbuf, false);
+ unchanged(curbuf, false, true);
}
apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, false,
@@ -299,7 +299,7 @@ int open_buffer(
|| (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) {
changed();
} else if (retval != FAIL && !read_stdin && !read_fifo) {
- unchanged(curbuf, false);
+ unchanged(curbuf, false, true);
}
save_file_ff(curbuf); // keep this fileformat
@@ -641,13 +641,11 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
}
}
-/*
- * Make buffer not contain a file.
- */
+/// Make buffer not contain a file.
void buf_clear_file(buf_T *buf)
{
buf->b_ml.ml_line_count = 1;
- unchanged(buf, true);
+ unchanged(buf, true, true);
buf->b_p_eol = true;
buf->b_start_eol = true;
buf->b_p_bomb = false;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 117e3f42fe..16c7804be0 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1006,7 +1006,7 @@ typedef enum {
kFloatRelativeCursor = 2,
} FloatRelative;
-EXTERN const char *const float_relative_str[] INIT(= { "editor", "window",
+EXTERN const char *const float_relative_str[] INIT(= { "editor", "win",
"cursor" });
typedef enum {
@@ -1016,6 +1016,7 @@ typedef enum {
typedef struct {
Window window;
+ lpos_T bufpos;
int height, width;
double row, col;
FloatAnchor anchor;
@@ -1026,6 +1027,7 @@ typedef struct {
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
+ .bufpos = { -1, 0 }, \
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
.focusable = true, \
diff --git a/src/nvim/change.c b/src/nvim/change.c
index f8a4cf4282..3401f8a0a8 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -478,9 +478,11 @@ changed_lines(
}
}
-/// Called when the changed flag must be reset for buffer "buf".
-/// When "ff" is true also reset 'fileformat'.
-void unchanged(buf_T *buf, int ff)
+/// Called when the changed flag must be reset for buffer `buf`.
+/// When `ff` is true also reset 'fileformat'.
+/// When `always_inc_changedtick` is true b:changedtick is incremented even
+/// when the changed flag was off.
+void unchanged(buf_T *buf, int ff, bool always_inc_changedtick)
{
if (buf->b_changed || (ff && file_ff_differs(buf, false))) {
buf->b_changed = false;
@@ -491,8 +493,10 @@ void unchanged(buf_T *buf, int ff)
check_status(buf);
redraw_tabline = true;
need_maketitle = true; // set window title later
+ buf_inc_changedtick(buf);
+ } else if (always_inc_changedtick) {
+ buf_inc_changedtick(buf);
}
- buf_inc_changedtick(buf);
}
/// Insert string "p" at the cursor position. Stops at a NUL byte.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 98448ff1f9..8e848483a7 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -14781,6 +14781,32 @@ static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = ui_current_col() + 1;
}
+/// "screenpos({winid}, {lnum}, {col})" function
+static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ pos_T pos;
+ int row = 0;
+ int scol = 0, ccol = 0, ecol = 0;
+
+ tv_dict_alloc_ret(rettv);
+ dict_T *dict = rettv->vval.v_dict;
+
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
+ }
+
+ pos.lnum = tv_get_number(&argvars[1]);
+ pos.col = tv_get_number(&argvars[2]) - 1;
+ pos.coladd = 0;
+ textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol, false);
+
+ tv_dict_add_nr(dict, S_LEN("row"), row);
+ tv_dict_add_nr(dict, S_LEN("col"), scol);
+ tv_dict_add_nr(dict, S_LEN("curscol"), ccol);
+ tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
+}
+
/*
* "screenrow()" function
*/
@@ -20895,7 +20921,7 @@ void ex_echo(exarg_T *eap)
char *tofree = encode_tv2echo(&rettv, NULL);
if (*tofree != NUL) {
msg_ext_set_kind("echo");
- msg_multiline_attr(tofree, echo_attr);
+ msg_multiline_attr(tofree, echo_attr, true);
}
xfree(tofree);
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 0ad9ef5dac..ab5ff57c2f 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -266,6 +266,7 @@ return {
screenattr={args=2},
screenchar={args=2},
screencol={},
+ screenpos={args=3},
screenrow={},
search={args={1, 4}},
searchdecl={args={1, 3}},
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 964b884460..affdda0386 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1323,7 +1323,7 @@ void dialog_changed(buf_T *buf, bool checkall)
(void)buf_write_all(buf, false);
}
} else if (ret == VIM_NO) {
- unchanged(buf, true);
+ unchanged(buf, true, false);
} else if (ret == VIM_ALL) {
// Write all modified files that can be written.
// Skip readonly buffers, these need to be confirmed
@@ -1348,7 +1348,7 @@ void dialog_changed(buf_T *buf, bool checkall)
} else if (ret == VIM_DISCARDALL) {
// mark all buffers as unchanged
FOR_ALL_BUFFERS(buf2) {
- unchanged(buf2, true);
+ unchanged(buf2, true, false);
}
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 34717b631e..b97c886094 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1527,7 +1527,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
//
// where 'addr' is:
//
- // % (entire file)
+ // % (entire file)
// $ [+-NUM]
// 'x [+-NUM] (where x denotes a currently defined mark)
// . [+-NUM]
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 517325a2cd..4cf42b41e9 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3485,10 +3485,10 @@ restore_backup:
if (reset_changed && whole && !append
&& !write_info.bw_conv_error
&& (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) {
- unchanged(buf, true);
+ unchanged(buf, true, false);
const varnumber_T changedtick = buf_get_changedtick(buf);
if (buf->b_last_changedtick + 1 == changedtick) {
- // changedtick is always incremented in unchanged() but that
+ // b:changedtick may be incremented in unchanged() but that
// should not trigger a TextChanged event.
buf->b_last_changedtick = changedtick;
}
@@ -5107,14 +5107,14 @@ void buf_reload(buf_T *buf, int orig_mode)
}
(void)move_lines(savebuf, buf);
}
- } else if (buf == curbuf) { /* "buf" still valid */
- /* Mark the buffer as unmodified and free undo info. */
- unchanged(buf, TRUE);
+ } else if (buf == curbuf) { // "buf" still valid.
+ // Mark the buffer as unmodified and free undo info.
+ unchanged(buf, true, true);
if ((flags & READ_KEEP_UNDO) == 0) {
u_blockfree(buf);
u_clearall(buf);
} else {
- /* Mark all undo states as changed. */
+ // Mark all undo states as changed.
u_unchanged(curbuf);
}
}
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index b69812a389..15dd2767a2 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1003,7 +1003,7 @@ void ml_recover(void)
set_option_value("fenc", 0L, (char *)b0_fenc, OPT_LOCAL);
xfree(b0_fenc);
}
- unchanged(curbuf, TRUE);
+ unchanged(curbuf, true, true);
bnum = 1; /* start with block 1 */
page_count = 1; /* which is 1 page */
diff --git a/src/nvim/message.c b/src/nvim/message.c
index ac731210d7..b5a5f656a0 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -222,12 +222,12 @@ int msg_attr(const char *s, const int attr)
}
/// similar to msg_outtrans_attr, but support newlines and tabs.
-void msg_multiline_attr(const char *s, int attr)
+void msg_multiline_attr(const char *s, int attr, bool check_int)
FUNC_ATTR_NONNULL_ALL
{
const char *next_spec = s;
- while (next_spec != NULL) {
+ while (next_spec != NULL && (!check_int || !got_int)) {
next_spec = strpbrk(s, "\t\n\r");
if (next_spec != NULL) {
@@ -306,7 +306,7 @@ bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline)
s = buf;
if (multiline) {
- msg_multiline_attr((char *)s, attr);
+ msg_multiline_attr((char *)s, attr, false);
} else {
msg_outtrans_attr(s, attr);
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 4a87f82eb7..e6fee9999f 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -95,6 +95,8 @@ static void comp_botline(win_T *wp)
wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
set_empty_rows(wp, done);
+
+ win_check_anchored_floats(wp);
}
void reset_cursorline(void)
@@ -310,6 +312,7 @@ void update_topline(void)
}
}
curwin->w_valid |= VALID_TOPLINE;
+ win_check_anchored_floats(curwin);
/*
* Need to redraw when topline changed.
@@ -827,7 +830,8 @@ void curs_columns(
new_leftcol = 0;
if (new_leftcol != (int)curwin->w_leftcol) {
curwin->w_leftcol = new_leftcol;
- /* screen has to be redrawn with new curwin->w_leftcol */
+ win_check_anchored_floats(curwin);
+ // screen has to be redrawn with new curwin->w_leftcol
redraw_later(NOT_VALID);
}
}
@@ -943,6 +947,74 @@ void curs_columns(
curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}
+/// Compute the screen position of text character at "pos" in window "wp"
+/// The resulting values are one-based, zero when character is not visible.
+///
+/// @param[out] rowp screen row
+/// @param[out] scolp start screen column
+/// @param[out] ccolp cursor screen column
+/// @param[out] ecolp end screen column
+void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp,
+ int *ccolp, int *ecolp, bool local)
+{
+ colnr_T scol = 0, ccol = 0, ecol = 0;
+ int row = 0;
+ int rowoff = 0;
+ colnr_T coloff = 0;
+ bool visible_row = false;
+
+ if (pos->lnum >= wp->w_topline && pos->lnum < wp->w_botline) {
+ row = plines_m_win(wp, wp->w_topline, pos->lnum - 1) + 1;
+ visible_row = true;
+ } else if (pos->lnum < wp->w_topline) {
+ row = 0;
+ } else {
+ row = wp->w_height_inner;
+ }
+
+ bool existing_row = (pos->lnum > 0
+ && pos->lnum <= wp->w_buffer->b_ml.ml_line_count);
+
+ if ((local && existing_row) || visible_row) {
+ colnr_T off;
+ colnr_T col;
+ int width;
+
+ getvcol(wp, pos, &scol, &ccol, &ecol);
+
+ // similar to what is done in validate_cursor_col()
+ col = scol;
+ off = win_col_off(wp);
+ col += off;
+ width = wp->w_width - off + win_col_off2(wp);
+
+ // long line wrapping, adjust row
+ if (wp->w_p_wrap && col >= (colnr_T)wp->w_width && width > 0) {
+ // use same formula as what is used in curs_columns()
+ rowoff = visible_row ? ((col - wp->w_width) / width + 1) : 0;
+ col -= rowoff * width;
+ }
+
+ col -= wp->w_leftcol;
+
+ if (col >= 0 && col < width) {
+ coloff = col - scol + (local ? 0 : wp->w_wincol) + 1;
+ } else {
+ scol = ccol = ecol = 0;
+ // character is left or right of the window
+ if (local) {
+ coloff = col < 0 ? -1 : wp->w_width_inner + 1;
+ } else {
+ row = 0;
+ }
+ }
+ }
+ *rowp = (local ? 0 : wp->w_winrow) + row + rowoff;
+ *scolp = scol + coloff;
+ *ccolp = ccol + coloff;
+ *ecolp = ecol + coloff;
+}
+
/*
* Scroll the current window down by "line_count" logical lines. "CTRL-Y"
*/
@@ -1099,6 +1171,7 @@ check_topfill (
}
}
}
+ win_check_anchored_floats(curwin);
}
/*
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 3aa2f47907..d846bd0ae0 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -21,13 +21,14 @@
#define SREQ_WIN 1 // Request window-local option value
#define SREQ_BUF 2 // Request buffer-local option value
-/*
- * Default values for 'errorformat'.
- * The "%f|%l| %m" one is used for when the contents of the quickfix window is
- * written to a file.
- */
-#define DFLT_EFM \
- "%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%D%*\\a: Entering directory %*[`']%f',%X%*\\a: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m"
+// Default values for 'errorformat'.
+// The "%f|%l| %m" one is used for when the contents of the quickfix window is
+// written to a file.
+#ifdef WIN32
+# define DFLT_EFM "%f(%l) \\=: %t%*\\D%n: %m,%*[^\"]\"%f\"%*\\D%l: %m,%f(%l) \\=: %m,%*[^ ] %f %l: %m,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,%f|%l| %m"
+#else
+# define DFLT_EFM "%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%D%*\\a: Entering directory %*[`']%f',%X%*\\a: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m"
+#endif
#define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m"
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 20f68233e7..ba6226ef9d 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -145,6 +145,8 @@ static void deadly_signal(int signum)
// Set the v:dying variable.
set_vim_var_nr(VV_DYING, 1);
+ WLOG("got signal %d (%s)", signum, signal_name(signum));
+
snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\n",
signal_name(signum));
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 80477c6947..26687f14f0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1016,7 +1016,8 @@ qf_init_end:
/// Set the title of the specified quickfix list. Frees the previous title.
/// Prepends ':' to the title.
-static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
+static void qf_store_title(qf_info_T *qi, int qf_idx, const char_u *title)
+ FUNC_ATTR_NONNULL_ARG(1)
{
XFREE_CLEAR(qi->qf_lists[qf_idx].qf_title);
@@ -1025,7 +1026,7 @@ static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
char_u *p = xmallocz(len);
qi->qf_lists[qf_idx].qf_title = p;
- xstrlcpy((char *)p, (char *)title, len + 1);
+ xstrlcpy((char *)p, (const char *)title, len + 1);
}
}
@@ -4693,7 +4694,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
if (di->di_tv.vval.v_number != 0) {
qf_idx = (int)di->di_tv.vval.v_number - 1;
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
- qf_idx = -1;
+ qf_idx = INVALID_QFIDX;
}
}
} else if (di->di_tv.v_type == VAR_STRING
@@ -4701,7 +4702,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
// Get the last quickfix list number
qf_idx = qi->qf_listcount - 1;
} else {
- qf_idx = -1;
+ qf_idx = INVALID_QFIDX;
}
}
@@ -4713,7 +4714,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
qf_idx = qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
}
} else {
- qf_idx = -1;
+ qf_idx = INVALID_QFIDX;
}
}
@@ -4829,7 +4830,7 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
// List is not present or is empty
- if (qi == NULL || qi->qf_listcount == 0 || qf_idx == -1) {
+ if (qi == NULL || qi->qf_listcount == 0 || qf_idx == INVALID_QFIDX) {
return qf_getprop_defaults(qi, flags, retdict);
}
@@ -4978,18 +4979,17 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
return retval;
}
-static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
- char_u *title)
+// Get the quickfix list index from 'nr' or 'id'
+static int qf_setprop_get_qfidx(
+ const qf_info_T *qi,
+ const dict_T *what,
+ int action,
+ bool *newlist)
+ FUNC_ATTR_NONNULL_ALL
{
dictitem_T *di;
- int retval = FAIL;
- int newlist = false;
- char_u *errorformat = p_efm;
-
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
- newlist = true;
- }
int qf_idx = qi->qf_curlist; // default is the current list
+
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
@@ -5002,37 +5002,140 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
// When creating a new list, accept qf_idx pointing to the next
// non-available list and add the new list at the end of the
// stack.
- newlist = true;
- qf_idx = qi->qf_listcount - 1;
+ *newlist = true;
+ qf_idx = qi->qf_listcount > 0 ? qi->qf_listcount - 1 : 0;
} else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
- return FAIL;
+ return INVALID_QFIDX;
} else if (action != ' ') {
- newlist = false; // use the specified list
+ *newlist = false; // use the specified list
}
} else if (di->di_tv.v_type == VAR_STRING
&& strequal((const char *)di->di_tv.vval.v_string, "$")) {
if (qi->qf_listcount > 0) {
qf_idx = qi->qf_listcount - 1;
- } else if (newlist) {
+ } else if (*newlist) {
qf_idx = 0;
} else {
- return FAIL;
+ return INVALID_QFIDX;
}
} else {
- return FAIL;
+ return INVALID_QFIDX;
}
}
- if (!newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) {
+ if (!*newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) {
// Use the quickfix/location list with the specified id
- if (di->di_tv.v_type == VAR_NUMBER) {
- qf_idx = qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
- if (qf_idx == -1) {
- return FAIL; // List not found
- }
- } else {
+ if (di->di_tv.v_type != VAR_NUMBER) {
+ return INVALID_QFIDX;
+ }
+ return qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
+ }
+
+ return qf_idx;
+}
+
+// Set the quickfix list title.
+static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what,
+ const dictitem_T *di)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (di->di_tv.v_type != VAR_STRING) {
+ return FAIL;
+ }
+
+ xfree(qi->qf_lists[qf_idx].qf_title);
+ qi->qf_lists[qf_idx].qf_title =
+ (char_u *)tv_dict_get_string(what, "title", true);
+ if (qf_idx == qi->qf_curlist) {
+ qf_update_win_titlevar(qi);
+ }
+
+ return OK;
+}
+
+// Set quickfix list items/entries.
+static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di,
+ int action)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (di->di_tv.v_type != VAR_LIST) {
+ return FAIL;
+ }
+
+ char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
+ const int retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
+ title_save,
+ action == ' ' ? 'a' : action);
+ xfree(title_save);
+
+ return retval;
+}
+
+// Set quickfix list items/entries from a list of lines.
+static int qf_setprop_items_from_lines(
+ qf_info_T *qi,
+ int qf_idx,
+ const dict_T *what,
+ dictitem_T *di,
+ int action)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *errorformat = p_efm;
+ dictitem_T *efm_di;
+ int retval = FAIL;
+
+ // Use the user supplied errorformat settings (if present)
+ if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
+ if (efm_di->di_tv.v_type != VAR_STRING
+ || efm_di->di_tv.vval.v_string == NULL) {
return FAIL;
}
+ errorformat = efm_di->di_tv.vval.v_string;
+ }
+
+ // Only a List value is supported
+ if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL) {
+ return FAIL;
+ }
+
+ if (action == 'r') {
+ qf_free_items(qi, qf_idx);
+ }
+ if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
+ false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
+ retval = OK;
+ }
+
+ return retval;
+}
+
+// Set quickfix list context.
+static int qf_setprop_context(qf_info_T *qi, int qf_idx, dictitem_T *di)
+ FUNC_ATTR_NONNULL_ALL
+{
+ tv_free(qi->qf_lists[qf_idx].qf_ctx);
+ typval_T *ctx = xcalloc(1, sizeof(typval_T));
+ if (ctx != NULL) {
+ tv_copy(&di->di_tv, ctx);
+ }
+ qi->qf_lists[qf_idx].qf_ctx = ctx;
+
+ return OK;
+}
+
+// Set quickfix/location list properties (title, items, context).
+// Also used to add items from parsing a list of lines.
+// Used by the setqflist() and setloclist() VimL functions.
+static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
+ char_u *title)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dictitem_T *di;
+ int retval = FAIL;
+ bool newlist = action == ' ' || qi->qf_curlist == qi->qf_listcount;
+ int qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
+ if (qf_idx == INVALID_QFIDX) { // List not found
+ return FAIL;
}
if (newlist) {
@@ -5042,63 +5145,16 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
}
if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) {
- if (di->di_tv.v_type == VAR_STRING) {
- xfree(qi->qf_lists[qf_idx].qf_title);
- qi->qf_lists[qf_idx].qf_title = (char_u *)tv_dict_get_string(
- what, "title", true);
- if (qf_idx == qi->qf_curlist) {
- qf_update_win_titlevar(qi);
- }
- retval = OK;
- }
+ retval = qf_setprop_title(qi, qf_idx, what, di);
}
if ((di = tv_dict_find(what, S_LEN("items"))) != NULL) {
- if (di->di_tv.v_type == VAR_LIST) {
- assert(qi->qf_lists[qf_idx].qf_title != NULL);
- char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
-
- retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
- title_save, action == ' ' ? 'a' : action);
- if (action == 'r') {
- // When replacing the quickfix list entries using
- // qf_add_entries(), the title is set with a ':' prefix.
- // Restore the title with the saved title.
- xfree(qi->qf_lists[qf_idx].qf_title);
- qi->qf_lists[qf_idx].qf_title = vim_strsave(title_save);
- }
- xfree(title_save);
- }
+ retval = qf_setprop_items(qi, qf_idx, di, action);
}
-
- if ((di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
- if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) {
- return FAIL;
- }
- errorformat = di->di_tv.vval.v_string;
- }
-
if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
- // Only a List value is supported
- if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
- if (action == 'r') {
- qf_free_items(qi, qf_idx);
- }
- if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
- false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
- retval = OK;
- }
- } else {
- return FAIL;
- }
+ retval = qf_setprop_items_from_lines(qi, qf_idx, what, di, action);
}
-
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
- tv_free(qi->qf_lists[qf_idx].qf_ctx);
-
- typval_T *ctx = xcalloc(1, sizeof(typval_T));
- tv_copy(&di->di_tv, ctx);
- qi->qf_lists[qf_idx].qf_ctx = ctx;
- retval = OK;
+ retval = qf_setprop_context(qi, qf_idx, di);
}
if (retval == OK) {
diff --git a/src/nvim/testdir/test_changedtick.vim b/src/nvim/testdir/test_changedtick.vim
index 3a91bb54aa..c789cdc1bc 100644
--- a/src/nvim/testdir/test_changedtick.vim
+++ b/src/nvim/testdir/test_changedtick.vim
@@ -55,3 +55,41 @@ func Test_changedtick_fixed()
call assert_fails('unlet d["changedtick"]', 'E46:')
endfunc
+
+func Test_changedtick_not_incremented_with_write()
+ new
+ let fname = "XChangeTick"
+ exe 'w ' .. fname
+
+ " :write when the buffer is not changed does not increment changedtick
+ let expected = b:changedtick
+ w
+ call assert_equal(expected, b:changedtick)
+
+ " :write when the buffer IS changed DOES increment changedtick
+ let expected = b:changedtick + 1
+ setlocal modified
+ w
+ call assert_equal(expected, b:changedtick)
+
+ " Two ticks: change + write
+ let expected = b:changedtick + 2
+ call setline(1, 'hello')
+ w
+ call assert_equal(expected, b:changedtick)
+
+ " Two ticks: start insert + write
+ let expected = b:changedtick + 2
+ normal! o
+ w
+ call assert_equal(expected, b:changedtick)
+
+ " Three ticks: start insert + change + write
+ let expected = b:changedtick + 3
+ normal! ochanged
+ w
+ call assert_equal(expected, b:changedtick)
+
+ bwipe
+ call delete(fname)
+endfunc
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 6bc9535aaf..037918fa31 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -64,3 +64,31 @@ func Test_curswant_with_cursorline()
call assert_equal(6, winsaveview().curswant)
quit!
endfunc
+
+func Test_screenpos()
+ rightbelow new
+ rightbelow 20vsplit
+ call setline(1, ["\tsome text", "long wrapping line here", "next line"])
+ redraw
+ let winid = win_getid()
+ let [winrow, wincol] = win_screenpos(winid)
+ call assert_equal({'row': winrow,
+ \ 'col': wincol + 0,
+ \ 'curscol': wincol + 7,
+ \ 'endcol': wincol + 7}, screenpos(winid, 1, 1))
+ call assert_equal({'row': winrow,
+ \ 'col': wincol + 13,
+ \ 'curscol': wincol + 13,
+ \ 'endcol': wincol + 13}, screenpos(winid, 1, 7))
+ call assert_equal({'row': winrow + 2,
+ \ 'col': wincol + 1,
+ \ 'curscol': wincol + 1,
+ \ 'endcol': wincol + 1}, screenpos(winid, 2, 22))
+ setlocal number
+ call assert_equal({'row': winrow + 3,
+ \ 'col': wincol + 9,
+ \ 'curscol': wincol + 9,
+ \ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
+ close
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 90abb30da1..440bf47f4b 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1167,6 +1167,13 @@ func Test_efm2()
call assert_equal(1, len(l), string(l))
call assert_equal('|| msg2', l[0].text)
+ " When matching error lines, case should be ignored. Test for this.
+ set noignorecase
+ let l=getqflist({'lines' : ['Xtest:FOO10:Line 20'], 'efm':'%f:foo%l:%m'})
+ call assert_equal(10, l.items[0].lnum)
+ call assert_equal('Line 20', l.items[0].text)
+ set ignorecase&
+
new | only
let &efm = save_efm
endfunc
@@ -1802,6 +1809,9 @@ func Xproperty_tests(cchar)
call assert_equal(0, s)
let d = g:Xgetlist({"title":1})
call assert_equal('Sample', d.title)
+ " Try setting title to a non-string value
+ call assert_equal(-1, g:Xsetlist([], 'a', {'title' : ['Test']}))
+ call assert_equal('Sample', g:Xgetlist({"title":1}).title)
Xopen
call assert_equal('Sample', w:quickfix_title)
@@ -1950,6 +1960,9 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum)
+ " Try setting the items using a string
+ call assert_equal(-1, g:Xsetlist([], ' ', {'items' : 'Test'}))
+
" Save and restore the quickfix stack
call g:Xsetlist([], 'f')
call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
@@ -3481,14 +3494,17 @@ func Xautocmd_changelist(cchar)
call assert_equal(4, line('.'))
autocmd! QuickFixCmdPost
- " Test for grep/lgrep
- call g:Xsetlist([], 'f')
- Xexpr 'Xtestfile1:2:Line2'
- autocmd QuickFixCmdPost * Xolder
- silent Xgrep Line5 Xtestfile2
- call assert_equal('Xtestfile2', bufname(''))
- call assert_equal(5, line('.'))
- autocmd! QuickFixCmdPost
+ " The grepprg may not be set on non-Unix systems
+ if has('unix')
+ " Test for grep/lgrep
+ call g:Xsetlist([], 'f')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ silent Xgrep Line5 Xtestfile2
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(5, line('.'))
+ autocmd! QuickFixCmdPost
+ endif
" Test for vimgrep/lvimgrep
call g:Xsetlist([], 'f')
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index c8343941d2..8ec36a8fe3 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2294,7 +2294,7 @@ static void u_undoredo(int undo, bool do_buf_event)
if (old_flags & UH_CHANGED) {
changed();
} else {
- unchanged(curbuf, FALSE);
+ unchanged(curbuf, false, true);
}
// because the calls to changed()/unchanged() above will bump changedtick
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 74a4852def..0eb005d5df 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,17 +69,17 @@ NULL
// clang-format off
static const int included_patches[] = {
1849,
- // 1848,
+ 1848,
1847,
- // 1846,
+ 1846,
1845,
// 1844,
1843,
// 1842,
- // 1841,
+ 1841,
1840,
1839,
- // 1838,
+ 1838,
1837,
1836,
// 1835,
@@ -87,23 +87,23 @@ static const int included_patches[] = {
1833,
1832,
1831,
- // 1830,
+ 1830,
1829,
1828,
1827,
1826,
1825,
1824,
- // 1823,
+ 1823,
1822,
- // 1821,
- // 1820,
+ 1821,
+ 1820,
1819,
- // 1818,
+ 1818,
// 1817,
1816,
// 1815,
- // 1814,
+ 1814,
1813,
// 1812,
1811,
@@ -111,18 +111,18 @@ static const int included_patches[] = {
1809,
1808,
1807,
- // 1806,
+ 1806,
1805,
// 1804,
1803,
- // 1802,
- // 1801,
+ 1802,
+ 1801,
1800,
1799,
// 1798,
// 1797,
- // 1796,
- // 1795,
+ 1796,
+ 1795,
// 1794,
// 1793,
1792,
@@ -137,26 +137,26 @@ static const int included_patches[] = {
// 1783,
1782,
1781,
- // 1780,
+ 1780,
1779,
1778,
1777,
// 1776,
- // 1775,
+ 1775,
// 1774,
1773,
// 1772,
// 1771,
// 1770,
// 1769,
- // 1768,
+ 1768,
// 1767,
1766,
1765,
1764,
1763,
- // 1762,
- // 1761,
+ 1762,
+ 1761,
1760,
// 1759,
1758,
@@ -164,22 +164,22 @@ static const int included_patches[] = {
1756,
1755,
// 1754,
- // 1753,
+ 1753,
// 1752,
1751,
1750,
1749,
1748,
// 1747,
- // 1746,
+ 1746,
// 1745,
// 1744,
// 1743,
// 1742,
1741,
- // 1740,
+ 1740,
1739,
- // 1738,
+ 1738,
1737,
1736,
1735,
@@ -188,113 +188,113 @@ static const int included_patches[] = {
// 1732,
1731,
1730,
- // 1729,
- // 1728,
+ 1729,
+ 1728,
1727,
1726,
// 1725,
- // 1724,
+ 1724,
1723,
// 1722,
- // 1721,
- // 1720,
+ 1721,
+ 1720,
1719,
- // 1718,
+ 1718,
1717,
- // 1716,
- // 1715,
- // 1714,
+ 1716,
+ 1715,
+ 1714,
// 1713,
// 1712,
// 1711,
1710,
- // 1709,
+ 1709,
1708,
1707,
// 1706,
1705,
1704,
- // 1703,
+ 1703,
1702,
1701,
1700,
1699,
1698,
- // 1697,
+ 1697,
1696,
- // 1695,
- // 1694,
+ 1695,
+ 1694,
1693,
1692,
- // 1691,
- // 1690,
+ 1691,
+ 1690,
1689,
- // 1688,
+ 1688,
1687,
1686,
// 1685,
- // 1684,
+ 1684,
1683,
1682,
- // 1681,
- // 1680,
+ 1681,
+ 1680,
1679,
1678,
1677,
1676,
1675,
1674,
- // 1673,
+ 1673,
1672,
// 1671,
- // 1670,
+ 1670,
1669,
// 1668,
- // 1667,
+ 1667,
// 1666,
// 1665,
- // 1664,
+ 1664,
1663,
- // 1662,
+ 1662,
1661,
// 1660,
1659,
1658,
- // 1657,
- // 1656,
+ 1657,
+ 1656,
// 1655,
1654,
- // 1653,
- // 1652,
+ 1653,
+ 1652,
// 1651,
1650,
1649,
- // 1648,
+ 1648,
// 1647,
1646,
- // 1645,
- // 1644,
- // 1643,
- // 1642,
+ 1645,
+ 1644,
+ 1643,
+ 1642,
// 1641,
- // 1640,
+ 1640,
1639,
- // 1638,
- // 1637,
- // 1636,
+ 1638,
+ 1637,
+ 1636,
1635,
1634,
1633,
- // 1632,
- // 1631,
+ 1632,
+ 1631,
1630,
- // 1629,
- // 1628,
+ 1629,
+ 1628,
1627,
1626,
1625,
// 1624,
- // 1623,
+ 1623,
1622,
// 1621,
1620,
@@ -302,28 +302,28 @@ static const int included_patches[] = {
1618,
// 1617,
// 1616,
- // 1615,
+ 1615,
1614,
1613,
// 1612,
- // 1611,
+ 1611,
1610,
// 1609,
1608,
1607,
1606,
- // 1605,
+ 1605,
// 1604,
1603,
1602,
1601,
1600,
// 1599,
- // 1598,
+ 1598,
1597,
// 1596,
1595,
- // 1594,
+ 1594,
// 1593,
// 1592,
// 1591,
@@ -341,7 +341,7 @@ static const int included_patches[] = {
1579,
// 1578,
1577,
- // 1576,
+ 1576,
1575,
// 1574,
1573,
@@ -365,44 +365,44 @@ static const int included_patches[] = {
1555,
// 1554,
1553,
- // 1552,
+ 1552,
// 1551,
// 1550,
1549,
1548,
1547,
- // 1546,
+ 1546,
1545,
// 1544,
// 1543,
- // 1542,
+ 1542,
1541,
// 1540,
// 1539,
// 1538,
- // 1537,
+ 1537,
1536,
- // 1535,
- // 1534,
- // 1533,
+ 1535,
+ 1534,
+ 1533,
1532,
// 1531,
1530,
// 1529,
1528,
// 1527,
- // 1526,
+ 1526,
// 1525,
1524,
// 1523,
// 1522,
- // 1521,
+ 1521,
// 1520,
1519,
1518,
1517,
1516,
- // 1515,
+ 1515,
1514,
1513,
1512,
@@ -433,15 +433,15 @@ static const int included_patches[] = {
1487,
1486,
1485,
- // 1484,
+ 1484,
1483,
- // 1482,
+ 1482,
1481,
- // 1480,
- // 1479,
+ 1480,
+ 1479,
1478,
- // 1477,
- // 1476,
+ 1477,
+ 1476,
1475,
1474,
1473,
@@ -455,7 +455,7 @@ static const int included_patches[] = {
1465,
1464,
// 1463,
- // 1462,
+ 1462,
// 1461,
// 1460,
// 1459,
@@ -487,8 +487,8 @@ static const int included_patches[] = {
1433,
1432,
1431,
- // 1430,
- // 1429,
+ 1430,
+ 1429,
1428,
1427,
1426,
@@ -531,17 +531,17 @@ static const int included_patches[] = {
1389,
// 1388,
1387,
- // 1386,
+ 1386,
1385,
1384,
1383,
// 1382,
- // 1381,
+ 1381,
1380,
1379,
1378,
1377,
- // 1376,
+ 1376,
// 1375,
1374,
1373,
@@ -549,16 +549,16 @@ static const int included_patches[] = {
// 1371,
1370,
1369,
- // 1368,
+ 1368,
// 1367,
// 1366,
1365,
1364,
1363,
- // 1362,
+ 1362,
1361,
- // 1360,
- // 1359,
+ 1360,
+ 1359,
// 1358,
1357,
// 1356,
@@ -570,14 +570,14 @@ static const int included_patches[] = {
1350,
// 1349,
1348,
- // 1347,
+ 1347,
// 1346,
// 1345,
// 1344,
1343,
- // 1342,
+ 1342,
// 1341,
- // 1340,
+ 1340,
// 1339,
1338,
1337,
@@ -589,20 +589,20 @@ static const int included_patches[] = {
1331,
// 1330,
1329,
- // 1328,
+ 1328,
1327,
1326,
1325,
1324,
- // 1323,
+ 1323,
1322,
// 1321,
// 1320,
// 1319,
// 1318,
- // 1317,
- // 1316,
- // 1315,
+ 1317,
+ 1316,
+ 1315,
1314,
1313,
// 1312,
@@ -621,7 +621,7 @@ static const int included_patches[] = {
1299,
1298,
// 1297,
- // 1296,
+ 1296,
// 1295,
1294,
// 1293,
@@ -631,7 +631,7 @@ static const int included_patches[] = {
1289,
1288,
// 1287,
- // 1286,
+ 1286,
1285,
1284,
1283,
@@ -640,10 +640,10 @@ static const int included_patches[] = {
1280,
1279,
1278,
- // 1277,
+ 1277,
// 1276,
1275,
- // 1274,
+ 1274,
1273,
1272,
1271,
@@ -656,9 +656,9 @@ static const int included_patches[] = {
// 1264,
1263,
1262,
- // 1261,
- // 1260,
- // 1259,
+ 1261,
+ 1260,
+ 1259,
1258,
1257,
1256,
@@ -671,17 +671,17 @@ static const int included_patches[] = {
1249,
1248,
1247,
- // 1246,
+ 1246,
1245,
// 1244,
1243,
1242,
- // 1241,
+ 1241,
// 1240,
- // 1239,
+ 1239,
1238,
1237,
- // 1236,
+ 1236,
1235,
1234,
1233,
@@ -700,11 +700,11 @@ static const int included_patches[] = {
1220,
1219,
1218,
- // 1217,
+ 1217,
1216,
1215,
1214,
- // 1213,
+ 1213,
1212,
1211,
1210,
@@ -715,7 +715,7 @@ static const int included_patches[] = {
1205,
1204,
// 1203,
- // 1202,
+ 1202,
1201,
1200,
1199,
@@ -724,7 +724,7 @@ static const int included_patches[] = {
1196,
1195,
// 1194,
- // 1193,
+ 1193,
1192,
1191,
1190,
@@ -738,24 +738,24 @@ static const int included_patches[] = {
1182,
1181,
1180,
- // 1179,
+ 1179,
1178,
- // 1177,
+ 1177,
// 1176,
1175,
// 1174,
- // 1173,
+ 1173,
1172,
1171,
// 1170,
1169,
1168,
- // 1167,
+ 1167,
1166,
1165,
- // 1164,
+ 1164,
1163,
- // 1162,
+ 1162,
1161,
1160,
1159,
@@ -768,10 +768,10 @@ static const int included_patches[] = {
1152,
1151,
1150,
- // 1149,
+ 1149,
1148,
1147,
- // 1146,
+ 1146,
1145,
1144,
1143,
@@ -786,22 +786,22 @@ static const int included_patches[] = {
// 1134,
1133,
1132,
- // 1131,
+ 1131,
1130,
// 1129,
1128,
// 1127,
- // 1126,
+ 1126,
// 1125,
1124,
// 1123,
1122,
1121,
- // 1120,
+ 1120,
// 1119,
1118,
- // 1117,
- // 1116,
+ 1117,
+ 1116,
1115,
1114,
// 1113,
@@ -811,18 +811,18 @@ static const int included_patches[] = {
// 1109,
1108,
1107,
- // 1106,
+ 1106,
1105,
1104,
- // 1103,
+ 1103,
// 1102,
- // 1101,
- // 1100,
+ 1101,
+ 1100,
1099,
1098,
// 1097,
// 1096,
- // 1095,
+ 1095,
1094,
1093,
1092,
@@ -830,24 +830,24 @@ static const int included_patches[] = {
1090,
1089,
1088,
- // 1087,
+ 1087,
1086,
1085,
1084,
- // 1083,
+ 1083,
1082,
- // 1081,
- // 1080,
+ 1081,
+ 1080,
1079,
1078,
1077,
- // 1076,
- // 1075,
+ 1076,
+ 1075,
// 1074,
1073,
1072,
1071,
- // 1070,
+ 1070,
1069,
1068,
1067,
@@ -859,16 +859,16 @@ static const int included_patches[] = {
1061,
// 1060,
1059,
- // 1058,
- // 1057,
+ 1058,
+ 1057,
1056,
- // 1055,
- // 1054,
- // 1053,
- // 1052,
+ 1055,
+ 1054,
+ 1053,
+ 1052,
// 1051,
1050,
- // 1049,
+ 1049,
1048,
1047,
1046,
@@ -878,12 +878,12 @@ static const int included_patches[] = {
1042,
1041,
1040,
- // 1039,
+ 1039,
// 1038,
1037,
- // 1036,
+ 1036,
// 1035,
- // 1034,
+ 1034,
1033,
1032,
1031,
@@ -902,13 +902,13 @@ static const int included_patches[] = {
1018,
1017,
1016,
- // 1015,
+ 1015,
1014,
- // 1013,
+ 1013,
1012,
- // 1011,
+ 1011,
1010,
- // 1009,
+ 1009,
1008,
1007,
1006,
@@ -922,45 +922,45 @@ static const int included_patches[] = {
998,
997,
996,
- // 995,
- // 994,
+ 995,
+ 994,
993,
- // 992,
- // 991,
- // 990,
+ 992,
+ 991,
+ 990,
989,
988,
- // 987,
+ 987,
986,
- // 985,
- // 984,
+ 985,
+ 984,
983,
- // 982,
- // 981,
+ 982,
+ 981,
980,
- // 979,
- // 978,
- // 977,
+ 979,
+ 978,
+ 977,
// 976,
975,
974,
- // 973,
+ 973,
972,
971,
// 970,
969,
- // 968,
+ 968,
967,
966,
- // 965,
- // 964,
- // 963,
+ 965,
+ 964,
+ 963,
962,
961,
// 960,
- // 959,
- // 958,
- // 957,
+ 959,
+ 958,
+ 957,
// 956,
955,
954,
@@ -970,34 +970,34 @@ static const int included_patches[] = {
950,
949,
948,
- // 947,
+ 947,
946,
945,
944,
- // 943,
- // 942,
+ 943,
+ 942,
// 941,
- // 940,
- // 939,
- // 938,
+ 940,
+ 939,
+ 938,
// 937,
- // 936,
- // 935,
+ 936,
+ 935,
// 934,
933,
// 932,
931,
- // 930,
- // 929,
+ 930,
+ 929,
928,
- // 927,
- // 926,
+ 927,
+ 926,
925,
- // 924,
- // 923,
+ 924,
+ 923,
922,
921,
- // 920,
+ 920,
919,
// 918,
// 917,
@@ -1008,8 +1008,8 @@ static const int included_patches[] = {
// 912,
911,
// 910,
- // 909,
- // 908,
+ 909,
+ 908,
907,
906,
905,
@@ -1614,14 +1614,14 @@ static const int included_patches[] = {
306,
305,
304,
- // 303,
+ 303,
302,
301,
300,
299,
298,
297,
- // 296,
+ 296,
295,
294,
293,
@@ -1679,14 +1679,14 @@ static const int included_patches[] = {
241,
240,
239,
- // 238,
+ 238,
237,
236,
235,
234,
// 233,
232,
- // 231,
+ 231,
230,
229,
228,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 6861e19ca7..315b5ef759 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -652,6 +652,17 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
}
}
+void win_check_anchored_floats(win_T *win)
+{
+ for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
+ // float might be anchored to moved window
+ if (wp->w_float_config.relative == kFloatRelativeWindow
+ && wp->w_float_config.window == win->handle) {
+ wp->w_pos_changed = true;
+ }
+ }
+}
+
static void ui_ext_win_position(win_T *wp)
{
if (!wp->w_floating) {
@@ -673,6 +684,13 @@ static void ui_ext_win_position(win_T *wp)
screen_adjust_grid(&grid, &row_off, &col_off);
row += row_off;
col += col_off;
+ if (c.bufpos.lnum >= 0) {
+ pos_T pos = { c.bufpos.lnum+1, c.bufpos.col, 0 };
+ int trow, tcol, tcolc, tcole;
+ textpos2screenpos(win, &pos, &trow, &tcol, &tcolc, &tcole, true);
+ row += trow-1;
+ col += tcol-1;
+ }
}
api_clear_error(&dummy);
}
@@ -745,6 +763,18 @@ static bool parse_float_relative(String relative, FloatRelative *out)
return true;
}
+static bool parse_float_bufpos(Array bufpos, lpos_T *out)
+{
+ if (bufpos.size != 2
+ || bufpos.items[0].type != kObjectTypeInteger
+ || bufpos.items[1].type != kObjectTypeInteger) {
+ return false;
+ }
+ out->lnum = bufpos.items[0].data.integer;
+ out->col = bufpos.items[1].data.integer;
+ return true;
+}
+
bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
Error *err)
{
@@ -753,6 +783,7 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
bool has_row = false, has_col = false, has_relative = false;
bool has_external = false, has_window = false;
bool has_width = false, has_height = false;
+ bool has_bufpos = false;
for (size_t i = 0; i < config.size; i++) {
char *key = config.items[i].key.data;
@@ -832,6 +863,18 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
return false;
}
fconfig->window = val.data.integer;
+ } else if (!strcmp(key, "bufpos")) {
+ if (val.type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation,
+ "'bufpos' key must be Array");
+ return false;
+ }
+ if (!parse_float_bufpos(val.data.array, &fconfig->bufpos)) {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'bufpos' key");
+ return false;
+ }
+ has_bufpos = true;
} else if (!strcmp(key, "external")) {
if (val.type == kObjectTypeInteger) {
fconfig->external = val.data.integer;
@@ -886,6 +929,21 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
fconfig->window = curwin->handle;
}
+ if (has_window && !has_bufpos) {
+ fconfig->bufpos.lnum = -1;
+ }
+
+ if (has_bufpos) {
+ if (!has_row) {
+ fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1;
+ has_row = true;
+ }
+ if (!has_col) {
+ fconfig->col = 0;
+ has_col = true;
+ }
+ }
+
if (has_relative && has_external) {
api_set_error(err, kErrorTypeValidation,
"Only one of 'relative' and 'external' must be used");
@@ -4732,7 +4790,8 @@ void shell_new_rows(void)
if (!frame_check_height(topframe, h))
frame_new_height(topframe, h, FALSE, FALSE);
- (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
+ (void)win_comp_pos(); // recompute w_winrow and w_wincol
+ win_reconfig_floats(); // The size of floats might change
compute_cmdrow();
curtab->tp_ch_used = p_ch;
@@ -4753,7 +4812,8 @@ void shell_new_columns(void)
frame_new_width(topframe, Columns, false, false);
}
- (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
+ (void)win_comp_pos(); // recompute w_winrow and w_wincol
+ win_reconfig_floats(); // The size of floats might change
}
/*
@@ -4809,15 +4869,23 @@ int win_comp_pos(void)
frame_comp_pos(topframe, &row, &col);
- // Too often, but when we support anchoring floats to split windows,
- // this will be needed
for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
- win_config_float(wp, wp->w_float_config);
+ // float might be anchored to moved window
+ if (wp->w_float_config.relative == kFloatRelativeWindow) {
+ wp->w_pos_changed = true;
+ }
}
return row;
}
+void win_reconfig_floats(void)
+{
+ for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) {
+ win_config_float(wp, wp->w_float_config);
+ }
+}
+
/*
* Update the position of the windows in frame "topfrp", using the width and
* height of the frames.
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index ddd044a10f..a20667de40 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -180,7 +180,7 @@ describe('server -> client', function()
end)
describe('recursive (child) nvim client', function()
- if helpers.isCI('travis') and helpers.os_name() == 'osx' then
+ if helpers.isCI('travis') and helpers.is_os('mac') then
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
pending("[Hangs on Travis macOS. #5002]", function() end)
return
@@ -339,7 +339,7 @@ describe('server -> client', function()
describe('connecting to its own pipe address', function()
it('does not deadlock', function()
- if not helpers.isCI('travis') and helpers.os_name() == 'osx' then
+ if not helpers.isCI('travis') and helpers.is_os('mac') then
-- It does, in fact, deadlock on QuickBuild. #6851
pending("deadlocks on QuickBuild", function() end)
return
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 07c0c5c8f3..b80b1c87af 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -11,7 +11,7 @@ local iswin = helpers.iswin
local meth_pcall = helpers.meth_pcall
local meths = helpers.meths
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
-local os_name = helpers.os_name
+local is_os = helpers.is_os
local parse_context = helpers.parse_context
local request = helpers.request
local source = helpers.source
@@ -83,7 +83,7 @@ describe('API', function()
nvim('command', 'w')
local f = io.open(fname)
ok(f ~= nil)
- if os_name() == 'windows' then
+ if is_os('win') then
eq('testing\r\napi\r\n', f:read('*a'))
else
eq('testing\napi\n', f:read('*a'))
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index 852d9808f5..1ef34c7318 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -7,7 +7,7 @@ local sleep = helpers.sleep
local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
local set_session = helpers.set_session
local nvim_prog = helpers.nvim_prog
-local os_name = helpers.os_name
+local is_os = helpers.is_os
local retry = helpers.retry
local expect_twostreams = helpers.expect_twostreams
@@ -140,7 +140,7 @@ describe('channels', function()
command("call chansend(id, 'incomplet\004')")
local is_bsd = not not string.find(uname(), 'bsd')
- local bsdlike = is_bsd or (os_name() == "osx")
+ local bsdlike = is_bsd or is_os('mac')
local extra = bsdlike and "^D\008\008" or ""
expect_twoline(id, "stdout",
"incomplet"..extra, "[1, ['incomplet'], 'stdin']", true)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 88951e5b51..94b34ef05b 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -206,7 +206,7 @@ describe('jobs', function()
it("will not buffer data if it doesn't end in newlines", function()
if helpers.isCI('travis') and os.getenv('CC') == 'gcc-4.9'
- and helpers.os_name() == "osx" then
+ and helpers.is_os('mac') then
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
pending("[Hangs on Travis macOS. #5002]", function() end)
return
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index c34849b439..cf9f5f9858 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -15,6 +15,7 @@ local check_logs = global_helpers.check_logs
local dedent = global_helpers.dedent
local eq = global_helpers.eq
local filter = global_helpers.filter
+local is_os = global_helpers.is_os
local map = global_helpers.map
local ok = global_helpers.ok
local sleep = global_helpers.sleep
@@ -271,22 +272,6 @@ function module.eval(expr)
return module.request('nvim_eval', expr)
end
-module.os_name = (function()
- local name = nil
- return (function()
- if not name then
- if module.eval('has("win32")') == 1 then
- name = 'windows'
- elseif module.eval('has("macunix")') == 1 then
- name = 'osx'
- else
- name = 'unix'
- end
- end
- return name
- end)
-end)()
-
-- Executes a VimL function.
-- Fails on VimL error, but does not update v:errmsg.
function module.call(name, ...)
@@ -609,7 +594,7 @@ local function do_rmdir(path)
-- Try Nvim delete(): it handles `readonly` attribute on Windows,
-- and avoids Lua cross-version/platform incompatibilities.
if -1 == module.call('delete', abspath) then
- local hint = (module.os_name() == 'windows'
+ local hint = (is_os('win')
and ' (hint: try :%bwipeout! before rmdir())' or '')
error('delete() failed'..hint..': '..abspath)
end
@@ -626,7 +611,7 @@ end
function module.rmdir(path)
local ret, _ = pcall(do_rmdir, path)
- if not ret and module.os_name() == "windows" then
+ if not ret and is_os('win') then
-- Maybe "Permission denied"; try again after changing the nvim
-- process to the top-level directory.
module.command([[exe 'cd '.fnameescape(']]..start_dir.."')")
diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua
index d61fdc9b83..8fdee95e91 100644
--- a/test/functional/legacy/file_perm_spec.lua
+++ b/test/functional/legacy/file_perm_spec.lua
@@ -21,7 +21,7 @@ describe('Test getting and setting file permissions', function()
eq(9, call('len', call('getfperm', tempfile)))
eq(1, call('setfperm', tempfile, 'rwx------'))
- if helpers.os_name() == 'windows' then
+ if helpers.is_os('win') then
eq('rw-rw-rw-', call('getfperm', tempfile))
else
eq('rwx------', call('getfperm', tempfile))
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index d96b479a62..5663f248bf 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -12,9 +12,7 @@ local shada_helpers = require('test.functional.shada.helpers')
local get_shada_rw = shada_helpers.get_shada_rw
local function reset(shada_file)
- clear{ args={'-u', 'NORC',
- '-i', shada_file or 'NONE',
- }}
+ clear{ args={'-u', 'NORC', '-i', shada_file or 'NONE', }}
end
local mpack_eq = function(expected, mpack_result)
@@ -2143,7 +2141,7 @@ describe('plugin/shada.vim', function()
local epoch = os.date('%Y-%m-%dT%H:%M:%S', 0)
local eol = helpers.iswin() and '\r\n' or '\n'
before_each(function()
- reset()
+ -- Note: reset() is called explicitly in each test.
os.remove(fname)
os.remove(fname .. '.tst')
os.remove(fname_tmp)
@@ -2159,272 +2157,263 @@ describe('plugin/shada.vim', function()
mpack_eq(expected, mpack_result)
end
- describe('event BufReadCmd', function()
- it('works', function()
- wshada('\004\000\009\147\000\196\002ab\196\001a')
- wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
- nvim_command('edit ' .. fname)
- eq({
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "a"',
- }, nvim_eval('getline(1, "$")'))
- eq(false, curbuf('get_option', 'modified'))
- eq('shada', curbuf('get_option', 'filetype'))
- nvim_command('edit ' .. fname_tmp)
- eq({
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "b"',
- }, nvim_eval('getline(1, "$")'))
- eq(false, curbuf('get_option', 'modified'))
- eq('shada', curbuf('get_option', 'filetype'))
- eq('++opt not supported', exc_exec('edit ++enc=latin1 ' .. fname))
- neq({
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "a"',
- }, nvim_eval('getline(1, "$")'))
- neq(true, curbuf('get_option', 'modified'))
- end)
+ it('event BufReadCmd', function()
+ reset()
+ wshada('\004\000\009\147\000\196\002ab\196\001a')
+ wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+ nvim_command('edit ' .. fname)
+ eq({
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "a"',
+ }, nvim_eval('getline(1, "$")'))
+ eq(false, curbuf('get_option', 'modified'))
+ eq('shada', curbuf('get_option', 'filetype'))
+ nvim_command('edit ' .. fname_tmp)
+ eq({
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "b"',
+ }, nvim_eval('getline(1, "$")'))
+ eq(false, curbuf('get_option', 'modified'))
+ eq('shada', curbuf('get_option', 'filetype'))
+ eq('++opt not supported', exc_exec('edit ++enc=latin1 ' .. fname))
+ neq({
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "a"',
+ }, nvim_eval('getline(1, "$")'))
+ neq(true, curbuf('get_option', 'modified'))
end)
- describe('event FileReadCmd', function()
- it('works', function()
- wshada('\004\000\009\147\000\196\002ab\196\001a')
- wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
- nvim_command('$read ' .. fname)
- eq({
- '',
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "a"',
- }, nvim_eval('getline(1, "$")'))
- eq(true, curbuf('get_option', 'modified'))
- neq('shada', curbuf('get_option', 'filetype'))
- nvim_command('1,$read ' .. fname_tmp)
- eq({
- '',
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "a"',
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "b"',
- }, nvim_eval('getline(1, "$")'))
- eq(true, curbuf('get_option', 'modified'))
- neq('shada', curbuf('get_option', 'filetype'))
- curbuf('set_option', 'modified', false)
- eq('++opt not supported', exc_exec('$read ++enc=latin1 ' .. fname))
- eq({
- '',
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "a"',
- 'History entry with timestamp ' .. epoch .. ':',
- ' @ Description_ Value',
- ' - history type CMD',
- ' - contents "ab"',
- ' - "b"',
- }, nvim_eval('getline(1, "$")'))
- neq(true, curbuf('get_option', 'modified'))
- end)
+ it('event FileReadCmd', function()
+ reset()
+ wshada('\004\000\009\147\000\196\002ab\196\001a')
+ wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+ nvim_command('$read ' .. fname)
+ eq({
+ '',
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "a"',
+ }, nvim_eval('getline(1, "$")'))
+ eq(true, curbuf('get_option', 'modified'))
+ neq('shada', curbuf('get_option', 'filetype'))
+ nvim_command('1,$read ' .. fname_tmp)
+ eq({
+ '',
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "a"',
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "b"',
+ }, nvim_eval('getline(1, "$")'))
+ eq(true, curbuf('get_option', 'modified'))
+ neq('shada', curbuf('get_option', 'filetype'))
+ curbuf('set_option', 'modified', false)
+ eq('++opt not supported', exc_exec('$read ++enc=latin1 ' .. fname))
+ eq({
+ '',
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "a"',
+ 'History entry with timestamp ' .. epoch .. ':',
+ ' @ Description_ Value',
+ ' - history type CMD',
+ ' - contents "ab"',
+ ' - "b"',
+ }, nvim_eval('getline(1, "$")'))
+ neq(true, curbuf('get_option', 'modified'))
end)
- describe('event BufWriteCmd', function()
- it('works', function()
- nvim('set_var', 'shada#add_own_header', 0)
- curbuf('set_lines', 0, 1, true, {
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- })
- nvim_command('w ' .. fname .. '.tst')
- nvim_command('w ' .. fname)
- nvim_command('w ' .. fname_tmp)
- eq('++opt not supported', exc_exec('w! ++enc=latin1 ' .. fname))
- eq(table.concat({
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- }, eol) .. eol, read_file(fname .. '.tst'))
- shada_eq({{
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }}, fname)
- shada_eq({{
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }}, fname_tmp)
- end)
+ it('event BufWriteCmd', function()
+ reset()
+ nvim('set_var', 'shada#add_own_header', 0)
+ curbuf('set_lines', 0, 1, true, {
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ })
+ nvim_command('w ' .. fname .. '.tst')
+ nvim_command('w ' .. fname)
+ nvim_command('w ' .. fname_tmp)
+ eq('++opt not supported', exc_exec('w! ++enc=latin1 ' .. fname))
+ eq(table.concat({
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ }, eol) .. eol, read_file(fname .. '.tst'))
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }}, fname)
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }}, fname_tmp)
end)
- describe('event FileWriteCmd', function()
- it('works', function()
- nvim('set_var', 'shada#add_own_header', 0)
- curbuf('set_lines', 0, 1, true, {
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- })
- nvim_command('1,3w ' .. fname .. '.tst')
- nvim_command('1,3w ' .. fname)
- nvim_command('1,3w ' .. fname_tmp)
- eq('++opt not supported', exc_exec('1,3w! ++enc=latin1 ' .. fname))
- eq(table.concat({
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- }, eol) .. eol, read_file(fname .. '.tst'))
- shada_eq({{
- timestamp=0,
- type=8,
- value={n=('A'):byte()},
- }}, fname)
- shada_eq({{
- timestamp=0,
- type=8,
- value={n=('A'):byte()},
- }}, fname_tmp)
- end)
+ it('event FileWriteCmd', function()
+ reset()
+ nvim('set_var', 'shada#add_own_header', 0)
+ curbuf('set_lines', 0, 1, true, {
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ })
+ nvim_command('1,3w ' .. fname .. '.tst')
+ nvim_command('1,3w ' .. fname)
+ nvim_command('1,3w ' .. fname_tmp)
+ eq('++opt not supported', exc_exec('1,3w! ++enc=latin1 ' .. fname))
+ eq(table.concat({
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ }, eol) .. eol, read_file(fname .. '.tst'))
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={n=('A'):byte()},
+ }}, fname)
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={n=('A'):byte()},
+ }}, fname_tmp)
end)
- describe('event FileAppendCmd', function()
- it('works', function()
- nvim('set_var', 'shada#add_own_header', 0)
- curbuf('set_lines', 0, 1, true, {
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- })
- funcs.writefile({''}, fname .. '.tst', 'b')
- funcs.writefile({''}, fname, 'b')
- funcs.writefile({''}, fname_tmp, 'b')
- nvim_command('1,3w >> ' .. fname .. '.tst')
- nvim_command('1,3w >> ' .. fname)
- nvim_command('1,3w >> ' .. fname_tmp)
- nvim_command('w >> ' .. fname .. '.tst')
- nvim_command('w >> ' .. fname)
- nvim_command('w >> ' .. fname_tmp)
- eq('++opt not supported', exc_exec('1,3w! ++enc=latin1 >> ' .. fname))
- eq(table.concat({
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- 'Jump with timestamp ' .. epoch .. ':',
- ' % Key________ Description Value',
- ' + n name \'A\'',
- ' + f file name ["foo"]',
- ' + l line number 2',
- ' + c column -200',
- }, eol) .. eol, read_file(fname .. '.tst'))
- shada_eq({{
- timestamp=0,
- type=8,
- value={n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }}, fname)
- shada_eq({{
- timestamp=0,
- type=8,
- value={n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }, {
- timestamp=0,
- type=8,
- value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
- }}, fname_tmp)
- end)
+ it('event FileAppendCmd', function()
+ reset()
+ nvim('set_var', 'shada#add_own_header', 0)
+ curbuf('set_lines', 0, 1, true, {
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ })
+ funcs.writefile({''}, fname .. '.tst', 'b')
+ funcs.writefile({''}, fname, 'b')
+ funcs.writefile({''}, fname_tmp, 'b')
+ nvim_command('1,3w >> ' .. fname .. '.tst')
+ nvim_command('1,3w >> ' .. fname)
+ nvim_command('1,3w >> ' .. fname_tmp)
+ nvim_command('w >> ' .. fname .. '.tst')
+ nvim_command('w >> ' .. fname)
+ nvim_command('w >> ' .. fname_tmp)
+ eq('++opt not supported', exc_exec('1,3w! ++enc=latin1 >> ' .. fname))
+ eq(table.concat({
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ 'Jump with timestamp ' .. epoch .. ':',
+ ' % Key________ Description Value',
+ ' + n name \'A\'',
+ ' + f file name ["foo"]',
+ ' + l line number 2',
+ ' + c column -200',
+ }, eol) .. eol, read_file(fname .. '.tst'))
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }}, fname)
+ shada_eq({{
+ timestamp=0,
+ type=8,
+ value={n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }, {
+ timestamp=0,
+ type=8,
+ value={c=-200, f={'foo'}, l=2, n=('A'):byte()},
+ }}, fname_tmp)
end)
- describe('event SourceCmd', function()
- before_each(function()
- reset(fname)
- end)
- it('works', function()
- wshada('\004\000\006\146\000\196\002ab')
- wshada_tmp('\004\001\006\146\000\196\002bc')
- eq(0, exc_exec('source ' .. fname))
- eq(0, exc_exec('source ' .. fname_tmp))
- eq('bc', funcs.histget(':', -1))
- eq('ab', funcs.histget(':', -2))
- end)
+ it('event SourceCmd', function()
+ reset(fname)
+ wshada('\004\000\006\146\000\196\002ab')
+ wshada_tmp('\004\001\006\146\000\196\002bc')
+ eq(0, exc_exec('source ' .. fname))
+ eq(0, exc_exec('source ' .. fname_tmp))
+ eq('bc', funcs.histget(':', -1))
+ eq('ab', funcs.histget(':', -2))
end)
end)
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 065cb98e69..f4441a5396 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -403,12 +403,8 @@ describe("'scrollback' option", function()
end
curbufmeths.set_option('scrollback', 0)
- if iswin() then
- feed_data('for /L %I in (1,1,30) do @(echo line%I)\r')
- else
- feed_data('awk "BEGIN{for(n=1;n<=30;n++) print \\\"line\\\" n}"\n')
- end
- screen:expect{any='line30 '}
+ feed_data(nvim_dir..'/shell-test REP 31 line'..(iswin() and '\r' or '\n'))
+ screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(7) end)
screen:detach()
@@ -428,13 +424,8 @@ describe("'scrollback' option", function()
-- Wait for prompt.
screen:expect{any='%$'}
- if iswin() then
- feed_data('for /L %I in (1,1,30) do @(echo line%I)\r')
- else
- feed_data('awk "BEGIN{for(n=1;n<=30;n++) print \\\"line\\\" n}"\n')
- end
-
- screen:expect{any='line30 '}
+ feed_data(nvim_dir.."/shell-test REP 31 line"..(iswin() and '\r' or '\n'))
+ screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(33, 2) end)
curbufmeths.set_option('scrollback', 10)
@@ -445,18 +436,14 @@ describe("'scrollback' option", function()
-- Terminal job data is received asynchronously, may happen before the
-- 'scrollback' option is synchronized with the internal sb_buffer.
command('sleep 100m')
- if iswin() then
- feed_data('for /L %I in (1,1,40) do @(echo line%I)\r')
- else
- feed_data('awk "BEGIN{for(n=1;n<=40;n++) print \\\"line\\\" n}"\n')
- end
- screen:expect{any='line40 '}
+ feed_data(nvim_dir.."/shell-test REP 41 line"..(iswin() and '\r' or '\n'))
+ screen:expect{any='40: line '}
retry(nil, nil, function() expect_lines(58) end)
-- Verify off-screen state
- eq((iswin() and 'line36' or 'line35'), eval("getline(line('w0') - 1)"))
- eq((iswin() and 'line27' or 'line26'), eval("getline(line('w0') - 10)"))
+ eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)"))
+ eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)"))
screen:detach()
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 958c56334a..c8cf9d830e 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -963,6 +963,335 @@ describe('floating windows', function()
end
end)
+ it('can be placed relative text in a window', function()
+ screen:try_resize(30,5)
+ local firstwin = meths.get_current_win().id
+ meths.buf_set_lines(0, 0, -1, true, {'just some', 'example text that is wider than the window', '', '', 'more text'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [3:------------------------------]|
+ ## grid 2
+ ^just some |
+ example text that is wider tha|
+ n the window |
+ |
+ ## grid 3
+ |
+ ]]}
+ else
+ screen:expect{grid=[[
+ ^just some |
+ example text that is wider tha|
+ n the window |
+ |
+ |
+ ]]}
+ end
+
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'some info!'})
+
+ local win = meths.open_win(buf, false, {relative='win', width=12, height=1, bufpos={1,32}})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [3:------------------------------]|
+ ## grid 2
+ ^just some |
+ example text that is wider tha|
+ n the window |
+ |
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 3, 2, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^just some |
+ example text that is wider tha|
+ n the window |
+ {1:some info! } |
+ |
+ ]]}
+ end
+ eq({relative='win', width=12, height=1, bufpos={1,32}, anchor='NW',
+ external=false, col=0, row=1, win=firstwin, focusable=true}, meths.win_get_config(win))
+
+ feed('<c-e>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [2:------------------------------]|
+ [3:------------------------------]|
+ ## grid 2
+ ^example text that is wider tha|
+ n the window |
+ |
+ |
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 2, 2, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^example text that is wider tha|
+ n the window |
+ {1:some info! } |
+ |
+ |
+ ]]}
+ end
+
+
+ screen:try_resize(45,5)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ ^example text that is wider than the window |
+ |
+ |
+ more text |
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 1, 32, true }
+ }}
+ else
+ -- note: appears misalinged due to cursor
+ screen:expect{grid=[[
+ ^example text that is wider than the window |
+ {1:some info! } |
+ |
+ more text |
+ |
+ ]]}
+ end
+
+ screen:try_resize(25,10)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ ^example text that is wide|
+ r than the window |
+ |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 2, 7, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^example text that is wide|
+ r than the window |
+ {1:some info! } |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {relative='win', bufpos={1,32}, anchor='SW'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ ^example text that is wide|
+ r than the window |
+ |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "SW", 2, 1, 7, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^example{1:some info! }s wide|
+ r than the window |
+ |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {relative='win', bufpos={1,32}, anchor='NW', col=-2})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ ^example text that is wide|
+ r than the window |
+ |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 2, 5, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^example text that is wide|
+ r than the window |
+ {1:some info! } |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {relative='win', bufpos={1,32}, row=2})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ ^example text that is wide|
+ r than the window |
+ |
+ |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 3, 7, true }
+ }}
+ else
+ screen:expect{grid=[[
+ ^example text that is wide|
+ r than the window |
+ |
+ {1:some info! } |
+ more text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+ end)
+
it('validates cursor even when window is not entered', function()
screen:try_resize(30,5)
command("set nowrap")
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index ed65c4526f..a6b9ef9387 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1052,3 +1052,37 @@ describe('ui/msg_puts_printf', function()
os.execute('cmake -E remove_directory '..test_build_dir..'/share')
end)
end)
+
+describe('pager', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ })
+ end)
+
+ it('can be quit', function()
+ command("set more")
+ feed(':echon join(map(range(0, &lines*2), "v:val"), "\\n")<cr>')
+ screen:expect{grid=[[
+ 0 |
+ 1 |
+ 2 |
+ 3 |
+ {4:-- More --}^ |
+ ]]}
+ feed('q')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+end)
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index a09df075aa..200f6eecdb 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -62,7 +62,7 @@ describe('ui mode_change event', function()
]], mode="normal"}
command("set showmatch")
- command("set matchtime=1") -- tenths of seconds
+ command("set matchtime=2") -- tenths of seconds
feed('a(stuff')
screen:expect{grid=[[
word(stuff^ |
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 2215c0c7d9..f3fa711fb1 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,6 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local shallowcopy = helpers.shallowcopy
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local iswin = helpers.iswin
local funcs = helpers.funcs
@@ -17,14 +16,6 @@ describe("'wildmenu'", function()
screen:attach()
end)
- -- expect the screen stayed unchanged some time after first seen success
- local function expect_stay_unchanged(args)
- screen:expect(args)
- args = shallowcopy(args)
- args.unchanged = true
- screen:expect(args)
- end
-
it(':sign <tab> shows wildmenu completions', function()
command('set wildmenu wildmode=full')
feed(':sign <tab>')
@@ -89,24 +80,20 @@ describe("'wildmenu'", function()
feed([[:sign <Tab>]]) -- Invoke wildmenu.
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
-- For now just assert that the screen remains unchanged.
- expect_stay_unchanged{grid=[[
- |
- |
- |
- define jump list > |
- :sign define^ |
- ]]}
+ screen:expect{any='define jump list > |\n:sign define^ |'}
+ screen:expect_unchanged()
-- cmdline CTRL-D display should also be preserved.
feed([[<C-U>]])
feed([[sign <C-D>]]) -- Invoke cmdline CTRL-D.
- expect_stay_unchanged{grid=[[
+ screen:expect{grid=[[
:sign |
define place |
jump undefine |
list unplace |
:sign ^ |
]]}
+ screen:expect_unchanged()
-- Exiting cmdline should show the buffer.
feed([[<C-\><C-N>]])
@@ -118,13 +105,14 @@ describe("'wildmenu'", function()
command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
feed([[<C-\><C-N>]])
feed([[:sign <Tab>]]) -- Invoke wildmenu.
- expect_stay_unchanged{grid=[[
+ screen:expect{grid=[[
|
~ |
~ |
define jump list > |
:sign define^ |
]]}
+ screen:expect_unchanged()
end)
it('with laststatus=0, :vsplit, :term #2255', function()
@@ -152,7 +140,8 @@ describe("'wildmenu'", function()
feed([[:<Tab>]]) -- Invoke wildmenu.
-- Check only the last 2 lines, because the shell output is
-- system-dependent.
- expect_stay_unchanged{any='! # & < = > @ > |\n:!^'}
+ screen:expect{any='! # & < = > @ > |\n:!^'}
+ screen:expect_unchanged()
end)
it('wildmode=list,full and display+=msgsep interaction #10092', function()
diff --git a/test/helpers.lua b/test/helpers.lua
index 779d33e3b1..c2a708197f 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -190,6 +190,15 @@ module.uname = (function()
end)
end)()
+function module.is_os(s)
+ if not (s == 'win' or s == 'mac' or s == 'unix') then
+ error('unknown platform: '..tostring(s))
+ end
+ return ((s == 'win' and module.iswin())
+ or (s == 'mac' and module.uname() == 'darwin')
+ or (s == 'unix'))
+end
+
local function tmpdir_get()
return os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP')
end