diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/extmark.c | 20 | ||||
-rw-r--r-- | src/nvim/api/keysets_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/api/tabpage.c | 31 | ||||
-rw-r--r-- | src/nvim/buffer.c | 117 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/decoration.c | 19 | ||||
-rw-r--r-- | src/nvim/decoration.h | 2 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 2 | ||||
-rw-r--r-- | src/nvim/getchar.c | 12 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 4 | ||||
-rw-r--r-- | src/nvim/normal.c | 6 | ||||
-rw-r--r-- | src/nvim/window.c | 17 |
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) { |