diff options
Diffstat (limited to 'src/nvim/buffer.c')
-rw-r--r-- | src/nvim/buffer.c | 264 |
1 files changed, 129 insertions, 135 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 39d0d24d47..4a87cebfa7 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" @@ -477,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. @@ -698,6 +704,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_TAB_WINDOWS(tp, wp) { + mark_forget_file(wp, buf->b_fnum); + } if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } else { @@ -864,7 +873,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); @@ -938,6 +947,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); @@ -945,8 +969,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; @@ -1183,32 +1208,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 @@ -1224,10 +1223,10 @@ void buf_remove_from_jumplist(buf_T *deleted_buf) /// /// @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; @@ -1268,19 +1267,14 @@ int do_buffer(int action, int start, int dir, int count, int forceit) 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; - } - } - // don't count unlisted buffers - if (unload || buf->b_p_bl) { + 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. + 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 } @@ -1306,7 +1300,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; } @@ -1332,7 +1328,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)) { @@ -1352,7 +1348,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; @@ -1363,6 +1359,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(); @@ -1378,7 +1376,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 @@ -1386,7 +1384,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) // 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; @@ -1395,8 +1393,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_CLEAN) { + // Remove the buffer to be deleted from the jump list. + mark_jumplist_forget_file(curwin, buf_fnum); + } close_windows(buf, false); @@ -1419,28 +1419,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_CLEAN) { + // 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 // 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_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) { + 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_CLEAN) || 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 @@ -1451,8 +1460,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_CLEAN) { + curwin->w_jumplistidx = jumpidx; + update_jumplist = false; + } break; } // advance to older entry in jump list @@ -1465,7 +1476,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); + } } } @@ -1490,11 +1501,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) 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 @@ -1509,11 +1516,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } 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; } @@ -1523,7 +1526,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 @@ -1544,7 +1547,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); @@ -1574,6 +1577,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. /// @@ -1659,11 +1667,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); } @@ -2076,6 +2080,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); @@ -2114,7 +2119,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) { @@ -2135,6 +2139,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) { @@ -2270,11 +2275,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; @@ -2885,9 +2886,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); @@ -2965,7 +2964,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")); } @@ -3191,8 +3200,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); @@ -3208,11 +3215,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); } @@ -3233,6 +3238,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) { @@ -3321,10 +3327,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) { @@ -3340,7 +3343,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]"), @@ -3414,7 +3417,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. @@ -3440,12 +3443,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); @@ -3610,23 +3610,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. @@ -3642,7 +3637,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; @@ -3654,7 +3649,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; @@ -3691,13 +3686,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) { @@ -3726,7 +3720,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_CLEAN)); if (!bufref_valid(&bufref)) { // Autocommands deleted the buffer. swap_exists_action = SEA_NONE; @@ -3773,7 +3767,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)) { @@ -3841,7 +3835,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; @@ -3886,6 +3879,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() @@ -4207,7 +4201,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 |