aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/extmark.c20
-rw-r--r--src/nvim/api/keysets_defs.h2
-rw-r--r--src/nvim/api/tabpage.c31
-rw-r--r--src/nvim/buffer.c117
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/decoration.c19
-rw-r--r--src/nvim/decoration.h2
-rw-r--r--src/nvim/ex_cmds2.c2
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/lua/treesitter.c4
-rw-r--r--src/nvim/normal.c6
-rw-r--r--src/nvim/window.c17
12 files changed, 175 insertions, 59 deletions
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 27a4b7854f..4e84b41a02 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -748,20 +748,32 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
col2 = c;
}
+ DecorPriority subpriority = DECOR_PRIORITY_BASE;
+ if (HAS_KEY(opts, set_extmark, _subpriority)) {
+ VALIDATE_RANGE((opts->_subpriority >= 0 && opts->_subpriority <= UINT16_MAX),
+ "_subpriority", {
+ goto error;
+ });
+ subpriority = (DecorPriority)opts->_subpriority;
+ }
+
if (kv_size(virt_text.data.virt_text)) {
- decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true);
+ decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true,
+ subpriority);
}
if (kv_size(virt_lines.data.virt_lines)) {
- decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true);
+ decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true,
+ subpriority);
}
if (url != NULL) {
DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT;
sh.url = url;
- decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0);
+ decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0, subpriority);
}
if (has_hl) {
DecorSignHighlight sh = decor_sh_from_inline(hl);
- decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id);
+ decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id,
+ subpriority);
}
} else {
if (opts->ephemeral) {
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 811f60f4d6..85896c1fa7 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -55,6 +55,8 @@ typedef struct {
Boolean ui_watched;
Boolean undo_restore;
String url;
+
+ Integer _subpriority;
} Dict(set_extmark);
typedef struct {
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 303f2ca817..fadc03b3e5 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -122,6 +122,37 @@ Window nvim_tabpage_get_win(Tabpage tabpage, Error *err)
abort();
}
+/// Sets the current window in a tabpage
+///
+/// @param tabpage Tabpage handle, or 0 for current tabpage
+/// @param win Window handle, must already belong to {tabpage}
+/// @param[out] err Error details, if any
+void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err)
+ FUNC_API_SINCE(12)
+{
+ tabpage_T *tp = find_tab_by_handle(tabpage, err);
+ if (!tp) {
+ return;
+ }
+
+ win_T *wp = find_window_by_handle(win, err);
+ if (!wp) {
+ return;
+ }
+
+ if (!tabpage_win_valid(tp, wp)) {
+ api_set_error(err, kErrorTypeException, "Window does not belong to tabpage %d", tp->handle);
+ return;
+ }
+
+ if (tp == curtab) {
+ win_enter(wp, true);
+ } else if (tp->tp_curwin != wp) {
+ tp->tp_prevwin = tp->tp_curwin;
+ tp->tp_curwin = wp;
+ }
+}
+
/// Gets the tabpage number
///
/// @param tabpage Tabpage handle, or 0 for current tabpage
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index d597d82ee2..00cb7272c0 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1183,6 +1183,32 @@ static int empty_curbuf(bool close_others, int forceit, int action)
return retval;
}
+/// Remove every jump list entry referring to a given buffer.
+/// This function will also adjust the current jump list index.
+void buf_remove_from_jumplist(buf_T *deleted_buf)
+{
+ // Remove all jump list entries that match the deleted buffer.
+ for (int i = curwin->w_jumplistlen - 1; i >= 0; i--) {
+ buf_T *buf = buflist_findnr(curwin->w_jumplist[i].fmark.fnum);
+
+ if (buf == deleted_buf) {
+ // Found an entry that we want to delete.
+ curwin->w_jumplistlen -= 1;
+
+ // If the current jump list index behind the entry we want to
+ // delete, move it back by one.
+ if (curwin->w_jumplistidx > i && curwin->w_jumplistidx > 0) {
+ curwin->w_jumplistidx -= 1;
+ }
+
+ // Actually remove the entry from the jump list.
+ for (int d = i; d < curwin->w_jumplistlen; d++) {
+ curwin->w_jumplist[d] = curwin->w_jumplist[d + 1];
+ }
+ }
+ }
+}
+
/// Implementation of the commands for the buffer list.
///
/// action == DOBUF_GOTO go to specified buffer
@@ -1205,6 +1231,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
{
buf_T *buf;
buf_T *bp;
+ bool update_jumplist = true;
bool unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|| action == DOBUF_WIPE);
@@ -1362,7 +1389,11 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
// If the buffer to be deleted is not the current one, delete it here.
if (buf != curbuf) {
+ // Remove the buffer to be deleted from the jump list.
+ buf_remove_from_jumplist(buf);
+
close_windows(buf, false);
+
if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) {
close_buffer(NULL, buf, action, false, false);
}
@@ -1382,40 +1413,53 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) {
buf = au_new_curbuf.br_buf;
} else if (curwin->w_jumplistlen > 0) {
- int jumpidx = curwin->w_jumplistidx - 1;
- if (jumpidx < 0) {
- jumpidx = curwin->w_jumplistlen - 1;
- }
+ // Remove the current buffer from the jump list.
+ buf_remove_from_jumplist(curbuf);
+
+ // It's possible that we removed all jump list entries, in that case we need to try another
+ // approach
+ if (curwin->w_jumplistlen > 0) {
+ // If the index is the same as the length, the current position was not yet added to the jump
+ // list. So we can safely go back to the last entry and search from there.
+ if (curwin->w_jumplistidx == curwin->w_jumplistlen) {
+ curwin->w_jumplistidx = curwin->w_jumplistlen - 1;
+ }
- forward = jumpidx;
- while (jumpidx != curwin->w_jumplistidx) {
- buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
- if (buf != NULL) {
- // Skip current and unlisted bufs. Also skip a quickfix
- // buffer, it might be deleted soon.
- if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) {
- buf = NULL;
- } else if (buf->b_ml.ml_mfp == NULL) {
- // skip unloaded buf, but may keep it for later
- if (bp == NULL) {
- bp = buf;
+ int jumpidx = curwin->w_jumplistidx;
+
+ forward = jumpidx;
+ do {
+ buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
+
+ if (buf != NULL) {
+ // Skip unlisted bufs. Also skip a quickfix
+ // buffer, it might be deleted soon.
+ if (!buf->b_p_bl || bt_quickfix(buf)) {
+ buf = NULL;
+ } else if (buf->b_ml.ml_mfp == NULL) {
+ // skip unloaded buf, but may keep it for later
+ if (bp == NULL) {
+ bp = buf;
+ }
+ buf = NULL;
}
- buf = NULL;
}
- }
- if (buf != NULL) { // found a valid buffer: stop searching
- break;
- }
- // advance to older entry in jump list
- if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) {
- break;
- }
- if (--jumpidx < 0) {
- jumpidx = curwin->w_jumplistlen - 1;
- }
- if (jumpidx == forward) { // List exhausted for sure
- break;
- }
+ if (buf != NULL) { // found a valid buffer: stop searching
+ curwin->w_jumplistidx = jumpidx;
+ update_jumplist = false;
+ break;
+ }
+ // advance to older entry in jump list
+ if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) {
+ break;
+ }
+ if (--jumpidx < 0) {
+ jumpidx = curwin->w_jumplistlen - 1;
+ }
+ if (jumpidx == forward) { // List exhausted for sure
+ break;
+ }
+ } while (jumpidx != curwin->w_jumplistidx);
}
}
@@ -1511,7 +1555,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
}
// Go to the other buffer.
- set_curbuf(buf, action);
+ set_curbuf(buf, action, update_jumplist);
if (action == DOBUF_SPLIT) {
RESET_BINDING(curwin); // reset 'scrollbind' and 'cursorbind'
@@ -1533,14 +1577,17 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
/// DOBUF_UNLOAD unload it
/// DOBUF_DEL delete it
/// DOBUF_WIPE wipe it out
-void set_curbuf(buf_T *buf, int action)
+void set_curbuf(buf_T *buf, int action, bool update_jumplist)
{
buf_T *prevbuf;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|| action == DOBUF_WIPE);
OptInt old_tw = curbuf->b_p_tw;
- setpcmark();
+ if (update_jumplist) {
+ setpcmark();
+ }
+
if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) {
curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file
}
@@ -3675,7 +3722,7 @@ void ex_buffer_all(exarg_T *eap)
// Open the buffer in this window.
swap_exists_action = SEA_DIALOG;
- set_curbuf(buf, DOBUF_GOTO);
+ set_curbuf(buf, DOBUF_GOTO, false);
if (!bufref_valid(&bufref)) {
// Autocommands deleted the buffer.
swap_exists_action = SEA_NONE;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 79527176ab..24f97dd92c 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -713,7 +713,7 @@ struct file_buffer {
// Measurements of the deleted or replaced region since the last update
// event. Some consumers of buffer changes need to know the byte size (like
- // tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
+ // treesitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
// deleted text.
size_t deleted_bytes;
size_t deleted_bytes2;
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 755655856d..5358241644 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -449,18 +449,21 @@ static void decor_range_add_from_inline(DecorState *state, int start_row, int st
if (decor.ext) {
DecorVirtText *vt = decor.data.ext.vt;
while (vt) {
- decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned);
+ decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned,
+ DECOR_PRIORITY_BASE);
vt = vt->next;
}
uint32_t idx = decor.data.ext.sh_idx;
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
- decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id);
+ decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id,
+ DECOR_PRIORITY_BASE);
idx = sh->next;
}
} else {
DecorSignHighlight sh = decor_sh_from_inline(decor.data.hl);
- decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id);
+ decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id,
+ DECOR_PRIORITY_BASE);
}
}
@@ -470,7 +473,8 @@ static void decor_range_insert(DecorState *state, DecorRange range)
size_t index;
for (index = kv_size(state->active) - 1; index > 0; index--) {
DecorRange item = kv_A(state->active, index - 1);
- if (item.priority <= range.priority) {
+ if ((item.priority < range.priority)
+ || ((item.priority == range.priority) && (item.subpriority <= range.subpriority))) {
break;
}
kv_A(state->active, index) = kv_A(state->active, index - 1);
@@ -479,7 +483,7 @@ static void decor_range_insert(DecorState *state, DecorRange range)
}
void decor_range_add_virt(DecorState *state, int start_row, int start_col, int end_row, int end_col,
- DecorVirtText *vt, bool owned)
+ DecorVirtText *vt, bool owned, DecorPriority subpriority)
{
bool is_lines = vt->flags & kVTIsLines;
DecorRange range = {
@@ -489,13 +493,15 @@ void decor_range_add_virt(DecorState *state, int start_row, int start_col, int e
.attr_id = 0,
.owned = owned,
.priority = vt->priority,
+ .subpriority = subpriority,
.draw_col = -10,
};
decor_range_insert(state, range);
}
void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end_row, int end_col,
- DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id)
+ DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id,
+ DecorPriority subpriority)
{
if (sh->flags & kSHIsSign) {
return;
@@ -508,6 +514,7 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end
.attr_id = 0,
.owned = owned,
.priority = sh->priority,
+ .subpriority = subpriority,
.draw_col = -10,
};
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index b3ff737123..e70c588806 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -48,6 +48,8 @@ typedef struct {
int attr_id; ///< cached lookup of inl.hl_id if it was a highlight
bool owned; ///< ephemeral decoration, free memory immediately
DecorPriority priority;
+ DecorPriority subpriority; ///< Secondary priority value used for ordering (#27131).
+ ///< Reflects the order of patterns/captures in the query file.
DecorRangeKind kind;
/// Screen column to draw the virtual text.
/// When -1, the virtual text may be drawn after deciding where.
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 842f8a4297..484b3572ab 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -405,7 +405,7 @@ buf_found:
// Open the changed buffer in the current window.
if (buf != curbuf) {
- set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
+ set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO, true);
}
theend:
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 03bc953368..d3411850fd 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1146,10 +1146,10 @@ static void gotchars(const uint8_t *chars, size_t len)
maptick++;
}
-/// Record a <Nop> key.
-void gotchars_nop(void)
+/// Record an <Ignore> key.
+void gotchars_ignore(void)
{
- uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_NOP };
+ uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE };
gotchars(nop_buf, 3);
}
@@ -2746,9 +2746,9 @@ static int vgetorpeek(bool advance)
}
if (timedout && c == ESC) {
- // When recording there will be no timeout. Add a <Nop> after the ESC
- // to avoid that it forms a key code with following characters.
- gotchars_nop();
+ // When recording there will be no timeout. Add an <Ignore> after the
+ // ESC to avoid that it forms a key code with following characters.
+ gotchars_ignore();
}
vgetc_busy--;
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 8b62bff496..de17aabca2 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -1,5 +1,5 @@
-// lua bindings for tree-sitter.
-// NB: this file mostly contains a generic lua interface for tree-sitter
+// lua bindings for treesitter.
+// NB: this file mostly contains a generic lua interface for treesitter
// trees and nodes, and could be broken out as a reusable lua package
#include <assert.h>
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index ed2b1437ec..8c388b4318 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -845,10 +845,10 @@ static void normal_get_additional_char(NormalState *s)
no_mapping++;
// Vim may be in a different mode when the user types the next key,
// but when replaying a recording the next key is already in the
- // typeahead buffer, so record a <Nop> before that to prevent the
- // vpeekc() above from applying wrong mappings when replaying.
+ // typeahead buffer, so record an <Ignore> before that to prevent
+ // the vpeekc() above from applying wrong mappings when replaying.
no_u_sync++;
- gotchars_nop();
+ gotchars_ignore();
no_u_sync--;
}
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 112ac8bf3b..66169bcb74 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1557,7 +1557,7 @@ bool win_valid(const win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
/// Check if "win" is a pointer to an existing window in tabpage "tp".
///
/// @param win window to check
-static bool tabpage_win_valid(const tabpage_T *tp, const win_T *win)
+bool tabpage_win_valid(const tabpage_T *tp, const win_T *win)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (win == NULL) {
@@ -2553,6 +2553,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
/// "abort_if_last" is passed to close_buffer(): abort closing if all other
/// windows are closed.
static void win_close_buffer(win_T *win, int action, bool abort_if_last)
+ FUNC_ATTR_NONNULL_ALL
{
// Free independent synblock before the buffer is freed.
if (win->w_buffer != NULL) {
@@ -2590,6 +2591,7 @@ static void win_close_buffer(win_T *win, int action, bool abort_if_last)
// Called by :quit, :close, :xit, :wq and findtag().
// Returns FAIL when the window was not closed.
int win_close(win_T *win, bool free_buf, bool force)
+ FUNC_ATTR_NONNULL_ALL
{
tabpage_T *prev_curtab = curtab;
frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent;
@@ -2888,6 +2890,7 @@ static void do_autocmd_winclosed(win_T *win)
// Caller must check if buffer is hidden and whether the tabline needs to be
// updated.
void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ALL
{
// Get here with win->w_buffer == NULL when win_close() detects the tab page
// changed.
@@ -2989,6 +2992,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
///
/// @return a pointer to the window that got the freed up space.
static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
win_T *wp;
tabpage_T *win_tp = tp == NULL ? curtab : tp;
@@ -3007,6 +3011,7 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
wp = firstwin;
}
} else {
+ assert(tp != curtab);
if (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) {
wp = tp->tp_prevwin;
} else {
@@ -3079,7 +3084,10 @@ void win_free_all(void)
///
/// @return a pointer to the window that got the freed up space.
win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
+ assert(tp == NULL || tp != curtab);
+
// If there is only one window there is nothing to remove.
if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
return NULL;
@@ -3226,7 +3234,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp)
/// @return a pointer to the frame that will receive the empty screen space that
/// is left over after "win" is closed.
static frame_T *win_altframe(win_T *win, tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
+ assert(tp == NULL || tp != curtab);
+
if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
return alt_tabpage()->tp_curwin->w_frame;
}
@@ -3290,6 +3301,7 @@ static tabpage_T *alt_tabpage(void)
// Find the left-upper window in frame "frp".
win_T *frame2win(frame_T *frp)
+ FUNC_ATTR_NONNULL_ALL
{
while (frp->fr_win == NULL) {
frp = frp->fr_child;
@@ -5142,7 +5154,10 @@ void win_append(win_T *after, win_T *wp)
///
/// @param tp tab page "win" is in, NULL for current
void win_remove(win_T *wp, tabpage_T *tp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
+ assert(tp == NULL || tp != curtab);
+
if (wp->w_prev != NULL) {
wp->w_prev->w_next = wp->w_next;
} else if (tp == NULL) {