aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
22 files changed, 669 insertions, 342 deletions
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.