From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/buffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 39d0d24d47..5d0cd66133 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -43,6 +43,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" -- cgit From a18982cb839d7f05e32b1026bbd99b8aa34ad189 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:00:20 +0700 Subject: refactor: replace '\0' with NUL --- src/nvim/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5d0cd66133..c0fbc36787 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4208,7 +4208,7 @@ int buf_open_scratch(handle_T bufnr, char *bufname) bool buf_is_empty(buf_T *buf) { - return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0'; + return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL; } /// Increment b:changedtick value -- cgit From 1d4e894403638a94ac58766cdcbc7f3128db318b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 6 Jun 2024 05:50:44 +0800 Subject: vim-patch:9.1.0469: Cannot have buffer-local value for 'completeopt' Problem: Cannot have buffer-local value for 'completeopt' (Nick Jensen). Solution: Make 'completeopt' global-local (zeertzjq). Also for some reason test Test_ColonEight_MultiByte seems to be failing sporadically now. Let's mark it as flaky. fixes: vim/vim#5487 closes: vim/vim#14922 https://github.com/vim/vim/commit/529b9ad62a0e843ee56ef609aef7e51b7dc8a4c8 --- src/nvim/buffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index c0fbc36787..57245ce3f5 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2077,6 +2077,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_lop); clear_string_option(&buf->b_p_cinsd); clear_string_option(&buf->b_p_cinw); + clear_string_option(&buf->b_p_cot); clear_string_option(&buf->b_p_cpt); clear_string_option(&buf->b_p_cfu); callback_free(&buf->b_cfu_cb); -- cgit From c37695a5d5f2e8914fff86f3581bed70b4c85d3c Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:40:24 +0700 Subject: refactor: use S_LEN(s) instead of s, n (#29219) --- src/nvim/buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 57245ce3f5..3f4e7047f9 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3850,8 +3850,8 @@ static int chk_modeline(linenr_T lnum, int flags) int prev = -1; for (s = ml_get(lnum); *s != NUL; s++) { if (prev == -1 || ascii_isspace(prev)) { - if ((prev != -1 && strncmp(s, "ex:", 3) == 0) - || strncmp(s, "vi:", 3) == 0) { + if ((prev != -1 && strncmp(s, S_LEN("ex:")) == 0) + || strncmp(s, S_LEN("vi:")) == 0) { break; } // Accept both "vim" and "Vim". @@ -3867,7 +3867,7 @@ static int chk_modeline(linenr_T lnum, int flags) if (*e == ':' && (s[0] != 'V' - || strncmp(skipwhite(e + 1), "set", 3) == 0) + || strncmp(skipwhite(e + 1), S_LEN("set")) == 0) && (s[3] == ':' || (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') @@ -3916,8 +3916,8 @@ static int chk_modeline(linenr_T lnum, int flags) // "vi:set opt opt opt: foo" -- foo not interpreted // "vi:opt opt opt: foo" -- foo interpreted // Accept "se" for compatibility with Elvis. - if (strncmp(s, "set ", 4) == 0 - || strncmp(s, "se ", 3) == 0) { + if (strncmp(s, S_LEN("set ")) == 0 + || strncmp(s, S_LEN("se ")) == 0) { if (*e != ':') { // no terminating ':'? break; } -- cgit From 43d8435cf84468e776e0a6a98d05ae7bd62583b7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jun 2024 22:20:06 +0100 Subject: revert: "refactor: use S_LEN macro" (#29319) revert: "refactor: use S_LEN(s) instead of s, n (#29219)" This reverts commit c37695a5d5f2e8914fff86f3581bed70b4c85d3c. --- src/nvim/buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3f4e7047f9..57245ce3f5 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3850,8 +3850,8 @@ static int chk_modeline(linenr_T lnum, int flags) int prev = -1; for (s = ml_get(lnum); *s != NUL; s++) { if (prev == -1 || ascii_isspace(prev)) { - if ((prev != -1 && strncmp(s, S_LEN("ex:")) == 0) - || strncmp(s, S_LEN("vi:")) == 0) { + if ((prev != -1 && strncmp(s, "ex:", 3) == 0) + || strncmp(s, "vi:", 3) == 0) { break; } // Accept both "vim" and "Vim". @@ -3867,7 +3867,7 @@ static int chk_modeline(linenr_T lnum, int flags) if (*e == ':' && (s[0] != 'V' - || strncmp(skipwhite(e + 1), S_LEN("set")) == 0) + || strncmp(skipwhite(e + 1), "set", 3) == 0) && (s[3] == ':' || (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') @@ -3916,8 +3916,8 @@ static int chk_modeline(linenr_T lnum, int flags) // "vi:set opt opt opt: foo" -- foo not interpreted // "vi:opt opt opt: foo" -- foo interpreted // Accept "se" for compatibility with Elvis. - if (strncmp(s, S_LEN("set ")) == 0 - || strncmp(s, S_LEN("se ")) == 0) { + if (strncmp(s, "set ", 4) == 0 + || strncmp(s, "se ", 3) == 0) { if (*e != ':') { // no terminating ':'? break; } -- cgit From e7020306a19a5211c834966ec067fff3b981bdb9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 30 Jun 2024 06:40:31 +0800 Subject: feat(jumplist): allow opting out of removing unloaded buffers (#29347) Problem: Cannot opt out of removing unloaded buffers from the jumplist. Solution: Only enable that with "unload" flag in 'jumpoptions'. --- src/nvim/buffer.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 57245ce3f5..3812ff6b44 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1396,8 +1396,10 @@ 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); + if (jop_flags & JOP_UNLOAD) { + // Remove the buffer to be deleted from the jump list. + buf_remove_from_jumplist(buf); + } close_windows(buf, false); @@ -1420,28 +1422,37 @@ 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) { - // Remove the current buffer from the jump list. - buf_remove_from_jumplist(curbuf); + if (jop_flags & JOP_UNLOAD) { + // 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; - } - int jumpidx = curwin->w_jumplistidx; + if (jop_flags & JOP_UNLOAD) { + // 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 (jumpidx == curwin->w_jumplistlen) { + jumpidx = curwin->w_jumplistidx = curwin->w_jumplistlen - 1; + } + } else { + jumpidx--; + if (jumpidx < 0) { + jumpidx = curwin->w_jumplistlen - 1; + } + } + forward = jumpidx; - do { + while ((jop_flags & JOP_UNLOAD) || jumpidx != curwin->w_jumplistidx) { buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); if (buf != NULL) { - // Skip unlisted bufs. Also skip a quickfix + // Skip current and unlisted bufs. Also skip a quickfix // buffer, it might be deleted soon. - if (!buf->b_p_bl || bt_quickfix(buf)) { + 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 @@ -1452,8 +1463,10 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } if (buf != NULL) { // found a valid buffer: stop searching - curwin->w_jumplistidx = jumpidx; - update_jumplist = false; + if (jop_flags & JOP_UNLOAD) { + curwin->w_jumplistidx = jumpidx; + update_jumplist = false; + } break; } // advance to older entry in jump list @@ -1466,7 +1479,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (jumpidx == forward) { // List exhausted for sure break; } - } while (jumpidx != curwin->w_jumplistidx); + } } } @@ -3728,7 +3741,7 @@ void ex_buffer_all(exarg_T *eap) // Open the buffer in this window. swap_exists_action = SEA_DIALOG; - set_curbuf(buf, DOBUF_GOTO, false); + set_curbuf(buf, DOBUF_GOTO, !(jop_flags & JOP_UNLOAD)); if (!bufref_valid(&bufref)) { // Autocommands deleted the buffer. swap_exists_action = SEA_NONE; -- cgit From 158ffd646d18eb26ca7e04e9cb9110305577b9c8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 10 Jul 2024 10:35:12 +0800 Subject: vim-patch:9.1.0554: :bw leaves jumplist and tagstack data around (#29639) Problem: :bw leaves jumplist and tagstack data around (Paul "Joey" Clark) Solution: Wipe jumplist and tagstack references to the wiped buffer (LemonBoy) As documented the :bwipeout command brutally deletes all the references to the buffer, so let's make it delete all the entries in the jump list and tag stack referring to the wiped-out buffer. fixes: vim/vim#8201 closes: vim/vim#15185 https://github.com/vim/vim/commit/4ff3a9b1e3ba45f9dbd0ea8c721f27d9315c4d93 Co-authored-by: LemonBoy --- src/nvim/buffer.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3812ff6b44..6878b02a6e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -699,6 +699,9 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i if (buf->b_nwindows > 0) { return false; } + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + mark_forget_file(wp, buf->b_fnum); + } if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } else { @@ -1184,32 +1187,6 @@ 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 @@ -1364,6 +1341,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } + int buf_fnum = buf->b_fnum; + // When closing the current buffer stop Visual mode. if (buf == curbuf && VIsual_active) { end_visual_mode(); @@ -1398,7 +1377,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (buf != curbuf) { if (jop_flags & JOP_UNLOAD) { // Remove the buffer to be deleted from the jump list. - buf_remove_from_jumplist(buf); + mark_jumplist_forget_file(curwin, buf_fnum); } close_windows(buf, false); @@ -1423,8 +1402,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit) buf = au_new_curbuf.br_buf; } else if (curwin->w_jumplistlen > 0) { if (jop_flags & JOP_UNLOAD) { - // Remove the current buffer from the jump list. - buf_remove_from_jumplist(curbuf); + // Remove the buffer from the jump list. + mark_jumplist_forget_file(curwin, buf_fnum); } // It's possible that we removed all jump list entries, in that case we need to try another -- cgit From 07c1996c8ad69bae559406ae17c415e6cbd345e8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 11 Jul 2024 06:26:22 +0800 Subject: vim-patch:9.1.0556: :bwipe doesn't remove file from jumplist of other tabpages (#29651) Problem: :bwipe doesn't remove file from jumplist and tagstack of other tabpages. Time complexity of mark_forget_file() is O(n^2) when removing all entries (after v9.1.0554) Solution: Use FOR_ALL_TAB_WINDOWS(). Start the loops over the arrays from the end instead of the start (zeertzjq) closes: vim/vim#15199 https://github.com/vim/vim/commit/2e7d89b39883b0cfd3e615b02bd55186e00fb7ce --- src/nvim/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 6878b02a6e..d894844c6d 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -699,7 +699,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i if (buf->b_nwindows > 0) { return false; } - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + FOR_ALL_TAB_WINDOWS(tp, wp) { mark_forget_file(wp, buf->b_fnum); } if (buf->b_sfname != buf->b_ffname) { -- cgit From 45b7a2c50335e1943a36715101e40eda5a1423f3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 11 Jul 2024 08:02:59 +0800 Subject: vim-patch:9.1.0557: moving in the buffer list doesn't work as documented (#29653) Problem: moving in the buffer list doesn't work as documented (SenileFelineS) Solution: Skip non-help buffers, when run from normal buffers, else only move from help buffers to the next help buffer (LemonBoy) As explained in the help section for :bnext and :bprev the commands should jump from help buffers to help buffers (and from regular ones to regular ones). fixes: vim/vim#4478 closes: vim/vim#15198 https://github.com/vim/vim/commit/893eeeb44583ca33276e263165b2a6e50fd297d0 Co-authored-by: LemonBoy --- src/nvim/buffer.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index d894844c6d..d1b7c553c3 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -942,6 +942,21 @@ static void free_buffer_stuff(buf_T *buf, int free_flags) void goto_buffer(exarg_T *eap, int start, int dir, int count) { const int save_sea = swap_exists_action; + bool skip_help_buf; + + switch (eap->cmdidx) { + case CMD_bnext: + case CMD_sbnext: + case CMD_bNext: + case CMD_bprevious: + case CMD_sbNext: + case CMD_sbprevious: + skip_help_buf = true; + break; + default: + skip_help_buf = false; + break; + } bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); @@ -949,8 +964,9 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) if (swap_exists_action == SEA_NONE) { swap_exists_action = SEA_DIALOG; } - do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, - start, dir, count, eap->forceit); + (void)do_buffer_ext(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, + (eap->forceit ? DOBUF_FORCEIT : 0) | + (skip_help_buf ? DOBUF_SKIPHELP : 0)); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { cleanup_T cs; @@ -1202,10 +1218,10 @@ static int empty_curbuf(bool close_others, int forceit, int action) /// /// @param dir FORWARD or BACKWARD /// @param count buffer number or number of buffers -/// @param forceit true for :...! +/// @param flags see @ref dobuf_flags_value /// /// @return FAIL or OK. -int do_buffer(int action, int start, int dir, int count, int forceit) +static int do_buffer_ext(int action, int start, int dir, int count, int flags) { buf_T *buf; buf_T *bp; @@ -1257,8 +1273,12 @@ int do_buffer(int action, int start, int dir, int count, int forceit) buf = lastbuf; } } - // don't count unlisted buffers - if (unload || buf->b_p_bl) { + // Don't count unlisted buffers. + // Avoid non-help buffers if the starting point was a non-help buffer and + // vice-versa. + if (unload + || (buf->b_p_bl + && ((flags & DOBUF_SKIPHELP) == 0 || buf->b_help == bp->b_help))) { count--; bp = NULL; // use this buffer as new starting point } @@ -1284,7 +1304,9 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return FAIL; } - if (action == DOBUF_GOTO && buf != curbuf && !check_can_set_curbuf_forceit(forceit)) { + if (action == DOBUF_GOTO + && buf != curbuf + && !check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) ? true : false)) { // disallow navigating to another buffer when 'winfixbuf' is applied return FAIL; } @@ -1310,7 +1332,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return FAIL; } - if (!forceit && bufIsChanged(buf)) { + if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf)) { if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { dialog_changed(buf, false); if (!bufref_valid(&bufref)) { @@ -1330,7 +1352,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } - if (!forceit && buf->terminal && terminal_running(buf->terminal)) { + if (!(flags & DOBUF_FORCEIT) && buf->terminal && terminal_running(buf->terminal)) { if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { if (!dialog_close_terminal(buf)) { return FAIL; @@ -1358,7 +1380,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } if (bp == NULL && buf == curbuf) { - return empty_curbuf(true, forceit, action); + return empty_curbuf(true, (flags & DOBUF_FORCEIT), action); } // If the deleted buffer is the current one, close the current window @@ -1516,7 +1538,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (buf == NULL) { // Autocommands must have wiped out all other buffers. Only option // now is to make the current buffer empty. - return empty_curbuf(false, forceit, action); + return empty_curbuf(false, (flags & DOBUF_FORCEIT), action); } // make "buf" the current buffer @@ -1537,7 +1559,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } // Check if the current buffer may be abandoned. - if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit)) { + if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT))) { if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { bufref_T bufref; set_bufref(&bufref, buf); @@ -1567,6 +1589,11 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return OK; } +int do_buffer(int action, int start, int dir, int count, int forceit) +{ + return do_buffer_ext(action, start, dir, count, forceit ? DOBUF_FORCEIT : 0); +} + /// Set current buffer to "buf". Executes autocommands and closes current /// buffer. /// -- cgit From d1bd3d643e5846eee7343ba1a12bdcbbc8cee7b0 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 19 Jul 2024 11:00:13 +0100 Subject: refactor: collapse statements in single assignments Problem: Variables are often assigned multiple places in common patterns. Solution: Replace these common patterns with different patterns that reduce the number of assignments. Use `MAX` and `MIN`: ```c if (x < y) { x = y; } // --> x = MAX(x, y); ``` ```c if (x > y) { x = y; } // --> x = MIN(x, y); ``` Use ternary: ```c int a; if (cond) { a = b; } els { a = c; } // --> int a = cond ? b : c; ``` --- src/nvim/buffer.c | 104 ++++++++++++++++-------------------------------------- 1 file changed, 31 insertions(+), 73 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index d1b7c553c3..2fc684b412 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1262,17 +1262,8 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) if (bp == NULL) { bp = buf; } - if (dir == FORWARD) { - buf = buf->b_next; - if (buf == NULL) { - buf = firstbuf; - } - } else { - buf = buf->b_prev; - if (buf == NULL) { - buf = lastbuf; - } - } + buf = dir == FORWARD ? (buf->b_next != NULL ? buf->b_next : firstbuf) + : (buf->b_prev != NULL ? buf->b_prev : lastbuf); // Don't count unlisted buffers. // Avoid non-help buffers if the starting point was a non-help buffer and // vice-versa. @@ -1505,11 +1496,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) bp = buf; } } - if (forward) { - buf = buf->b_next; - } else { - buf = buf->b_prev; - } + buf = forward ? buf->b_next : buf->b_prev; } } if (buf == NULL) { // No loaded buffer, use unloaded one @@ -1524,11 +1511,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) } } if (buf == NULL) { // Still no buffer, just take one - if (curbuf->b_next != NULL) { - buf = curbuf->b_next; - } else { - buf = curbuf->b_prev; - } + buf = curbuf->b_next != NULL ? curbuf->b_next : curbuf->b_prev; if (bt_quickfix(buf)) { buf = NULL; } @@ -1679,11 +1662,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist) } // If the buffer is not valid but curwin->w_buffer is NULL we must // enter some buffer. Using the last one is hopefully OK. - if (!valid) { - enter_buffer(lastbuf); - } else { - enter_buffer(buf); - } + enter_buffer(valid ? buf : lastbuf); if (old_tw != curbuf->b_p_tw) { check_colorcolumn(curwin); } @@ -2135,7 +2114,6 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) { win_T *wp = NULL; fmark_T *fm = NULL; - colnr_T col; buf_T *buf = buflist_findnr(n); if (buf == NULL) { @@ -2156,6 +2134,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) return FAIL; } + colnr_T col; bool restore_view = false; // altfpos may be changed by getfile(), get it now if (lnum == 0) { @@ -2291,11 +2270,7 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, int match = -1; if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) { - if (*pattern == '%') { - match = curbuf->b_fnum; - } else { - match = curwin->w_alt_fnum; - } + match = *pattern == '%' ? curbuf->b_fnum : curwin->w_alt_fnum; buf_T *found_buf = buflist_findnr(match); if (diffmode && !(found_buf && diff_mode_buf(found_buf))) { match = -1; @@ -2906,9 +2881,7 @@ void buflist_list(exarg_T *eap) changed_char, NameBuff); - if (len > IOSIZE - 20) { - len = IOSIZE - 20; - } + len = MIN(len, IOSIZE - 20); // put "line 999" in column 40 or after the file name int i = 40 - vim_strsize(IObuff); @@ -3212,8 +3185,6 @@ static bool buf_same_file_id(buf_T *buf, FileID *file_id) /// @param fullname when non-zero print full path void fileinfo(int fullname, int shorthelp, bool dont_truncate) { - char *name; - int n; char *p; char *buffer = xmalloc(IOSIZE); @@ -3229,11 +3200,9 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) if (buf_spname(curbuf) != NULL) { xstrlcpy(p, buf_spname(curbuf), (size_t)(IOSIZE - (p - buffer))); } else { - if (!fullname && curbuf->b_fname != NULL) { - name = curbuf->b_fname; - } else { - name = curbuf->b_ffname; - } + char *name = (!fullname && curbuf->b_fname != NULL) + ? curbuf->b_fname + : curbuf->b_ffname; home_replace(shorthelp ? curbuf : NULL, name, p, (size_t)(IOSIZE - (p - buffer)), true); } @@ -3254,6 +3223,7 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) || (curbuf->b_flags & BF_WRITE_MASK) || curbuf->b_p_ro) ? " " : ""); + int n; // With 32 bit longs and more than 21,474,836 lines multiplying by 100 // causes an overflow, thus for large numbers divide instead. if (curwin->w_cursor.lnum > 1000000) { @@ -3342,10 +3312,7 @@ void maketitle(void) if (p_title) { if (p_titlelen > 0) { - maxlen = (int)(p_titlelen * Columns / 100); - if (maxlen < 10) { - maxlen = 10; - } + maxlen = MAX((int)(p_titlelen * Columns / 100), 10); } if (*p_titlestring != NUL) { @@ -3461,12 +3428,9 @@ void maketitle(void) icon_str = p_iconstring; } } else { - char *buf_p; - if (buf_spname(curbuf) != NULL) { - buf_p = buf_spname(curbuf); - } else { // use file name only in icon - buf_p = path_tail(curbuf->b_ffname); - } + char *buf_p = buf_spname(curbuf) != NULL + ? buf_spname(curbuf) + : path_tail(curbuf->b_ffname); // use file name only in icon *icon_str = NUL; // Truncate name at 100 bytes. int len = (int)strlen(buf_p); @@ -3631,23 +3595,18 @@ bool bt_prompt(buf_T *buf) /// Open a window for a number of buffers. void ex_buffer_all(exarg_T *eap) { - win_T *wp, *wpnext; + win_T *wpnext; int split_ret = OK; int open_wins = 0; - linenr_T count; // Maximum number of windows to open. - int all; // When true also load inactive buffers. int had_tab = cmdmod.cmod_tab; - if (eap->addr_count == 0) { // make as many windows as possible - count = 9999; - } else { - count = eap->line2; // make as many windows as specified - } - if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide) { - all = false; - } else { - all = true; - } + // Maximum number of windows to open. + linenr_T count = eap->addr_count == 0 + ? 9999 // make as many windows as possible + : eap->line2; // make as many windows as specified + + // When true also load inactive buffers. + int all = eap->cmdidx != CMD_unhide && eap->cmdidx != CMD_sunhide; // Stop Visual mode, the cursor and "VIsual" may very well be invalid after // switching to another buffer. @@ -3663,7 +3622,7 @@ void ex_buffer_all(exarg_T *eap) while (true) { tabpage_T *tpnext = curtab->tp_next; // Try to close floating windows first - for (wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { + for (win_T *wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { wpnext = wp->w_floating ? wp->w_prev->w_floating ? wp->w_prev : firstwin : (wp->w_next == NULL || wp->w_next->w_floating) ? NULL : wp->w_next; @@ -3712,13 +3671,12 @@ void ex_buffer_all(exarg_T *eap) continue; } + win_T *wp; if (had_tab != 0) { // With the ":tab" modifier don't move the window. - if (buf->b_nwindows > 0) { - wp = lastwin; // buffer has a window, skip it - } else { - wp = NULL; - } + wp = buf->b_nwindows > 0 + ? lastwin // buffer has a window, skip it + : NULL; } else { // Check if this buffer already has a window for (wp = firstwin; wp != NULL; wp = wp->w_next) { @@ -3794,7 +3752,7 @@ void ex_buffer_all(exarg_T *eap) autocmd_no_leave--; // Close superfluous windows. - for (wp = lastwin; open_wins > count;) { + for (win_T *wp = lastwin; open_wins > count;) { bool r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, false) == OK) && !is_aucmd_win(wp); if (!win_valid(wp)) { @@ -3862,7 +3820,6 @@ static int chk_modeline(linenr_T lnum, int flags) { char *s; char *e; - char *linecopy; // local copy of any modeline found intmax_t vers; int retval = OK; @@ -3907,6 +3864,7 @@ static int chk_modeline(linenr_T lnum, int flags) s++; } while (s[-1] != ':'); + char *linecopy; // local copy of any modeline found s = linecopy = xstrdup(s); // copy the line, it will change // prepare for emsg() -- cgit From f926cc32c9262b6254e2843276b951cef9da1afe Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 2 Jul 2024 13:45:50 +0200 Subject: refactor(shada): rework msgpack decoding without msgpack-c This also makes shada reading slightly faster due to avoiding some copying and allocation. Use keysets to drive decoding of msgpack maps for shada entries. --- src/nvim/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 2fc684b412..0c301bd5e2 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -868,7 +868,7 @@ static void free_buffer(buf_T *buf) } unref_var_dict(buf->b_vars); aubuflocal_remove(buf); - tv_dict_unref(buf->additional_data); + xfree(buf->additional_data); xfree(buf->b_prompt_text); callback_free(&buf->b_prompt_callback); callback_free(&buf->b_prompt_interrupt); -- cgit From 92186be428e84798ac6fa6c69ae575187a0d3da8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 8 Aug 2024 14:51:29 +0800 Subject: vim-patch:8.2.3476: renaming a buffer on startup may cause using freed memory Problem: Renaming a buffer on startup may cause using freed memory. Solution: Check if the buffer is used in a window. (closes vim/vim#8955) https://github.com/vim/vim/commit/d3710cf01ef6ab1b2f233866ff01dab76686f642 Cherry-pick Test_echo_true_in_cmd() from Vim. Co-authored-by: Bram Moolenaar --- src/nvim/buffer.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 0c301bd5e2..ab648708fc 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2959,7 +2959,17 @@ int setfname(buf_T *buf, char *ffname_arg, char *sfname_arg, bool message) obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid); } if (obuf != NULL && obuf != buf) { - if (obuf->b_ml.ml_mfp != NULL) { // it's loaded, fail + bool in_use = false; + + // during startup a window may use a buffer that is not loaded yet + FOR_ALL_TAB_WINDOWS(tab, win) { + if (win->w_buffer == obuf) { + in_use = true; + } + } + + // it's loaded or used in a window, fail + if (obuf->b_ml.ml_mfp != NULL || in_use) { if (message) { emsg(_("E95: Buffer with this name already exists")); } -- cgit From b3d291c5656085189e1ba65357119f16e2f5e9b0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 16 Aug 2024 09:00:50 +0800 Subject: vim-patch:9.1.0678: [security]: use-after-free in alist_add() Problem: [security]: use-after-free in alist_add() (SuyueGuo) Solution: Lock the current window, so that the reference to the argument list remains valid. This fixes CVE-2024-43374 https://github.com/vim/vim/commit/0a6e57b09bc8c76691b367a5babfb79b31b770e8 Co-authored-by: Christian Brabandt --- src/nvim/buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ab648708fc..f986f558a9 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1379,7 +1379,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) // When the autocommand window is involved win_close() may need to print an error message. // Repeat this so long as we end up in a window with this buffer. while (buf == curbuf - && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) + && !(win_locked(curwin) || curwin->w_buffer->b_locked > 0) && (is_aucmd_win(lastwin) || !last_window(curwin))) { if (win_close(curwin, false, false) == FAIL) { break; @@ -3644,7 +3644,7 @@ void ex_buffer_all(exarg_T *eap) : wp->w_width != Columns) || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW - && !(wp->w_closing || wp->w_buffer->b_locked > 0) + && !(win_locked(curwin) || wp->w_buffer->b_locked > 0) && !is_aucmd_win(wp)) { if (win_close(wp, false, false) == FAIL) { break; -- cgit From 98ba65b8be8cb2dde839502357e70916c4a3e37a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:32:08 -0500 Subject: fix: replace NVIM with Nvim in default titlestring (#30348) --- src/nvim/buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f986f558a9..e47db44f68 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3338,7 +3338,7 @@ void maketitle(void) #define SPACE_FOR_FNAME (sizeof(buf) - 100) #define SPACE_FOR_DIR (sizeof(buf) - 20) -#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM". +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim". char *buf_p = buf; if (curbuf->b_fname == NULL) { const size_t size = xstrlcpy(buf_p, _("[No Name]"), @@ -3412,7 +3412,7 @@ void maketitle(void) append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf))); - xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf))); + xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf))); if (maxlen > 0) { // Make it shorter by removing a bit in the middle. -- cgit From 7dbbaaec3fae62667b273c4c2d362bee91316083 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 19 Sep 2024 18:05:27 +0800 Subject: refactor!: rename 'jumpoptions' flag "unload" to "clean" (#30418) Follow-up to #29347 --- src/nvim/buffer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e47db44f68..271f3fa725 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1388,7 +1388,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) // If the buffer to be deleted is not the current one, delete it here. if (buf != curbuf) { - if (jop_flags & JOP_UNLOAD) { + if (jop_flags & JOP_CLEAN) { // Remove the buffer to be deleted from the jump list. mark_jumplist_forget_file(curwin, buf_fnum); } @@ -1414,7 +1414,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) { buf = au_new_curbuf.br_buf; } else if (curwin->w_jumplistlen > 0) { - if (jop_flags & JOP_UNLOAD) { + if (jop_flags & JOP_CLEAN) { // Remove the buffer from the jump list. mark_jumplist_forget_file(curwin, buf_fnum); } @@ -1424,7 +1424,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) if (curwin->w_jumplistlen > 0) { int jumpidx = curwin->w_jumplistidx; - if (jop_flags & JOP_UNLOAD) { + if (jop_flags & JOP_CLEAN) { // 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 (jumpidx == curwin->w_jumplistlen) { @@ -1438,7 +1438,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) } forward = jumpidx; - while ((jop_flags & JOP_UNLOAD) || jumpidx != curwin->w_jumplistidx) { + while ((jop_flags & JOP_CLEAN) || jumpidx != curwin->w_jumplistidx) { buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); if (buf != NULL) { @@ -1455,7 +1455,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) } } if (buf != NULL) { // found a valid buffer: stop searching - if (jop_flags & JOP_UNLOAD) { + if (jop_flags & JOP_CLEAN) { curwin->w_jumplistidx = jumpidx; update_jumplist = false; } @@ -3715,7 +3715,7 @@ void ex_buffer_all(exarg_T *eap) // Open the buffer in this window. swap_exists_action = SEA_DIALOG; - set_curbuf(buf, DOBUF_GOTO, !(jop_flags & JOP_UNLOAD)); + set_curbuf(buf, DOBUF_GOTO, !(jop_flags & JOP_CLEAN)); if (!bufref_valid(&bufref)) { // Autocommands deleted the buffer. swap_exists_action = SEA_NONE; -- cgit From 2377443cd27ac41429d77fc6ba41e21469ed3b5b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 7 Oct 2024 10:40:44 +0800 Subject: vim-patch:9.1.0764: [security]: use-after-free when closing a buffer (#30705) Problem: [security]: use-after-free when closing a buffer Solution: When splitting the window and editing a new buffer, check whether the newly to be edited buffer has been marked for deletion and abort in this case Github Advisory: https://github.com/vim/vim/security/advisories/GHSA-rj48-v4mq-j4vg https://github.com/vim/vim/commit/51b62387be93c65fa56bbabe1c3c1ea5df187641 Co-authored-by: Christian Brabandt --- src/nvim/buffer.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/nvim/buffer.c') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 271f3fa725..4a87cebfa7 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -478,6 +478,11 @@ static bool can_unload_buffer(buf_T *buf) return can_unload; } +bool buf_locked(buf_T *buf) +{ + return buf->b_locked || buf->b_locked_split; +} + /// Close the link to a buffer. /// /// @param win If not NULL, set b_last_cursor. -- cgit