diff options
Diffstat (limited to 'src/nvim/buffer.c')
-rw-r--r-- | src/nvim/buffer.c | 558 |
1 files changed, 296 insertions, 262 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8a594dea92..f6c7229485 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -32,6 +32,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/autocmd.h" +#include "nvim/autocmd_defs.h" #include "nvim/buffer.h" #include "nvim/buffer_updates.h" #include "nvim/change.h" @@ -39,28 +40,30 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cursor.h" -#include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" -#include "nvim/eval/typval_defs.h" +#include "nvim/eval/typval.h" #include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/ex_eval_defs.h" #include "nvim/ex_getln.h" #include "nvim/extmark.h" #include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" -#include "nvim/gettext.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/hashtab.h" +#include "nvim/hashtab_defs.h" #include "nvim/help.h" #include "nvim/indent.h" #include "nvim/indent_c.h" @@ -68,26 +71,33 @@ #include "nvim/map_defs.h" #include "nvim/mapping.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/mbyte.h" #include "nvim/memfile_defs.h" +#include "nvim/memline.h" #include "nvim/memline_defs.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/move.h" #include "nvim/normal.h" #include "nvim/option.h" +#include "nvim/option_defs.h" #include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/fs.h" +#include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/os/time.h" #include "nvim/path.h" #include "nvim/plines.h" #include "nvim/pos_defs.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/regexp_defs.h" #include "nvim/runtime.h" +#include "nvim/runtime_defs.h" #include "nvim/search.h" #include "nvim/spell.h" #include "nvim/state_defs.h" @@ -95,7 +105,6 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/terminal.h" -#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/usercmd.h" @@ -133,7 +142,7 @@ int get_highest_fnum(void) /// @param read_stdin read file from stdin, otherwise fifo /// @param eap for forced 'ff' and 'fenc' or NULL /// @param flags extra flags for readfile() -static int read_buffer(int read_stdin, exarg_T *eap, int flags) +static int read_buffer(bool read_stdin, exarg_T *eap, int flags) { int retval = OK; bool silent = shortmess(SHM_FILEINFO); @@ -202,13 +211,13 @@ bool buf_ensure_loaded(buf_T *buf) /// @param flags_arg extra flags for readfile() /// /// @return FAIL for failure, OK otherwise. -int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) +int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) { int flags = flags_arg; int retval = OK; bufref_T old_curbuf; OptInt old_tw = curbuf->b_p_tw; - int read_fifo = false; + bool read_fifo = false; bool silent = shortmess(SHM_FILEINFO); // The 'readonly' flag is only set when BF_NEVERLOADED is being reset. @@ -274,16 +283,14 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) if (curbuf->b_ffname != NULL) { #ifdef UNIX int save_bin = curbuf->b_p_bin; - int perm; - - perm = os_getperm(curbuf->b_ffname); + int perm = os_getperm(curbuf->b_ffname); if (perm >= 0 && (0 || S_ISFIFO(perm) || S_ISSOCK(perm) # ifdef OPEN_CHR_FILES || (S_ISCHR(perm) && is_dev_fd_file(curbuf->b_ffname)) # endif - )) { // NOLINT(whitespace/parens) + )) { read_fifo = true; } if (read_fifo) { @@ -303,9 +310,9 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) } #endif - // Help buffer is filtered. + // Help buffer: populate *local-additions* in help.txt if (bt_help(curbuf)) { - fix_help_buffer(); + get_local_additions(); } } else if (read_stdin) { int save_bin = curbuf->b_p_bin; @@ -332,7 +339,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) // if first time loading this buffer, init b_chartab[] if (curbuf->b_flags & BF_NEVERLOADED) { - (void)buf_init_chartab(curbuf, false); + buf_init_chartab(curbuf, false); parse_cino(curbuf); } @@ -836,8 +843,9 @@ void buf_freeall(buf_T *buf, int flags) ml_close(buf, true); // close and delete the memline/memfile buf->b_ml.ml_line_count = 0; // no lines in buffer if ((flags & BFA_KEEP_UNDO) == 0) { - u_blockfree(buf); // free the memory allocated for undo - u_clearall(buf); // reset all undo information + // free the memory allocated for undo + // and reset all undo information + u_clearallandblockfree(buf); } syntax_clear(&buf->b_s); // reset syntax info buf->b_flags &= ~BF_READERR; // a read error is no longer relevant @@ -938,8 +946,8 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) if (swap_exists_action == SEA_NONE) { swap_exists_action = SEA_DIALOG; } - (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, - start, dir, count, eap->forceit); + do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, + start, dir, count, eap->forceit); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { cleanup_T cs; @@ -1047,7 +1055,7 @@ char *do_bufdel(int command, char *arg, int addr_count, int start_bnr, int end_b int bnr; // buffer number if (addr_count == 0) { - (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); + do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); } else { if (addr_count == 2) { if (*arg) { // both range and argument is not allowed @@ -1126,7 +1134,7 @@ char *do_bufdel(int command, char *arg, int addr_count, int start_bnr, int end_b /// Make the current buffer empty. /// Used when it is wiped out and it's the last buffer. -static int empty_curbuf(int close_others, int forceit, int action) +static int empty_curbuf(bool close_others, int forceit, int action) { buf_T *buf = curbuf; @@ -1176,6 +1184,32 @@ static int empty_curbuf(int 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 @@ -1198,8 +1232,9 @@ int do_buffer(int action, int start, int dir, int count, int forceit) { buf_T *buf; buf_T *bp; - int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL - || action == DOBUF_WIPE); + bool update_jumplist = true; + bool unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL + || action == DOBUF_WIPE); switch (start) { case DOBUF_FIRST: @@ -1355,7 +1390,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); } @@ -1375,42 +1414,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; - - 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); } } @@ -1506,7 +1556,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' @@ -1528,14 +1578,18 @@ 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; + const int last_winid = get_last_winid(); + + if (update_jumplist) { + setpcmark(); + } - setpcmark(); if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file } @@ -1559,7 +1613,11 @@ void set_curbuf(buf_T *buf, int action) if (prevbuf == curwin->w_buffer) { reset_synblock(curwin); } - if (unload) { + // autocommands may have opened a new window + // with prevbuf, grr + if (unload + || (last_winid != get_last_winid() + && strchr("wdu", prevbuf->b_p_bh[0]) != NULL)) { close_windows(prevbuf, false); } if (bufref_valid(&prevbufref) && !aborting()) { @@ -1589,6 +1647,11 @@ void set_curbuf(buf_T *buf, int action) // If curwin->w_buffer is null, enter_buffer() will make it valid again bool valid = buf_valid(buf); if ((valid && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) { + // autocommands changed curbuf and we will move to another + // buffer soon, so decrement curbuf->b_nwindows + if (curbuf != NULL && prevbuf != curbuf) { + curbuf->b_nwindows--; + } // 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) { @@ -1666,7 +1729,7 @@ void enter_buffer(buf_T *buf) need_fileinfo = true; // display file info after redraw } // check if file changed - (void)buf_check_timestamp(curbuf); + buf_check_timestamp(curbuf); curwin->w_topline = 1; curwin->w_topfill = 0; @@ -1691,12 +1754,12 @@ void enter_buffer(buf_T *buf) do_autochdir(); if (curbuf->b_kmap_state & KEYMAP_INIT) { - (void)keymap_init(); + keymap_init(); } // May need to set the spell language. Can only do this after the buffer // has been properly setup. if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { - (void)parse_spelllang(curwin); + parse_spelllang(curwin); } curbuf->b_last_used = time(NULL); @@ -1844,7 +1907,6 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags) buf = xcalloc(1, sizeof(buf_T)); // init b: variables buf->b_vars = tv_dict_alloc(); - buf->b_signcols.sentinel = 0; init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); buf_init_changedtick(buf); } @@ -1963,7 +2025,7 @@ bool curbuf_reusable(void) /// Free the memory for the options of a buffer. /// If "free_p_ff" is true also free 'fileformat', 'buftype' and /// 'fileencoding'. -void free_buf_options(buf_T *buf, int free_p_ff) +void free_buf_options(buf_T *buf, bool free_p_ff) { if (free_p_ff) { clear_string_option(&buf->b_p_fenc); @@ -2151,7 +2213,7 @@ buf_T *buflist_findname_exp(char *fname) #else false #endif - ); // NOLINT(whitespace/parens) + ); if (ffname != NULL) { buf = buflist_findname(ffname); xfree(ffname); @@ -2226,7 +2288,7 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, return -1; } char *patend = pat + strlen(pat) - 1; - int toggledollar = (patend > pat && *patend == '$'); + bool toggledollar = (patend > pat && *patend == '$'); // First try finding a listed buffer. If not found and "unlisted" // is true, try finding an unlisted buffer. @@ -2325,10 +2387,8 @@ static int buf_time_compare(const void *s1, const void *s2) /// @return OK if matches found, FAIL otherwise. int ExpandBufnames(char *pat, int *num_file, char ***file, int options) { - int count = 0; - int round; - char *p; bufmatch_T *matches = NULL; + bool to_free = false; *num_file = 0; // return values in case of FAIL *file = NULL; @@ -2340,125 +2400,115 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) const bool fuzzy = cmdline_fuzzy_complete(pat); char *patc = NULL; + fuzmatch_str_T *fuzmatch = NULL; + regmatch_T regmatch; + // Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular // expression matching) if (!fuzzy) { - if (*pat == '^') { - patc = xmalloc(strlen(pat) + 11); - STRCPY(patc, "\\(^\\|[\\/]\\)"); - STRCPY(patc + 11, pat + 1); + if (*pat == '^' && pat[1] != NUL) { + patc = xstrdup(pat + 1); + to_free = true; + } else if (*pat == '^') { + patc = ""; } else { patc = pat; } + regmatch.regprog = vim_regcomp(patc, RE_MAGIC); } - fuzmatch_str_T *fuzmatch = NULL; - // attempt == 0: try match with '\<', match at start of word - // attempt == 1: try match without '\<', match anywhere - for (int attempt = 0; attempt <= (fuzzy ? 0 : 1); attempt++) { - regmatch_T regmatch; - if (!fuzzy) { - if (attempt > 0 && patc == pat) { - break; // there was no anchor, no need to try again + int count = 0; + int score = 0; + // round == 1: Count the matches. + // round == 2: Build the array to keep the matches. + for (int round = 1; round <= 2; round++) { + count = 0; + FOR_ALL_BUFFERS(buf) { + if (!buf->b_p_bl) { // skip unlisted buffers + continue; } - regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC); - } - - int score = 0; - // round == 1: Count the matches. - // round == 2: Build the array to keep the matches. - for (round = 1; round <= 2; round++) { - count = 0; - FOR_ALL_BUFFERS(buf) { - if (!buf->b_p_bl) { // skip unlisted buffers + if (options & BUF_DIFF_FILTER) { + // Skip buffers not suitable for + // :diffget or :diffput completion. + if (buf == curbuf || !diff_mode_buf(buf)) { continue; } - if (options & BUF_DIFF_FILTER) { - // Skip buffers not suitable for - // :diffget or :diffput completion. - if (buf == curbuf || !diff_mode_buf(buf)) { - continue; - } - } + } - if (!fuzzy) { - if (regmatch.regprog == NULL) { - // invalid pattern, possibly after recompiling - if (patc != pat) { - xfree(patc); - } - return FAIL; - } - p = buflist_match(®match, buf, p_wic); - } else { - p = NULL; - // first try matching with the short file name - if ((score = fuzzy_match_str(buf->b_sfname, pat)) != 0) { - p = buf->b_sfname; - } - if (p == NULL) { - // next try matching with the full path file name - if ((score = fuzzy_match_str(buf->b_ffname, pat)) != 0) { - p = buf->b_ffname; - } + char *p = NULL; + if (!fuzzy) { + if (regmatch.regprog == NULL) { + // invalid pattern, possibly after recompiling + if (to_free) { + xfree(patc); } + return FAIL; } - - if (p == NULL) { - continue; - } - - if (round == 1) { - count++; - continue; - } - - if (options & WILD_HOME_REPLACE) { - p = home_replace_save(buf, p); - } else { - p = xstrdup(p); + p = buflist_match(®match, buf, p_wic); + } else { + p = NULL; + // first try matching with the short file name + if ((score = fuzzy_match_str(buf->b_sfname, pat)) != 0) { + p = buf->b_sfname; } - - if (!fuzzy) { - if (matches != NULL) { - matches[count].buf = buf; - matches[count].match = p; - count++; - } else { - (*file)[count++] = p; + if (p == NULL) { + // next try matching with the full path file name + if ((score = fuzzy_match_str(buf->b_ffname, pat)) != 0) { + p = buf->b_ffname; } - } else { - fuzmatch[count].idx = count; - fuzmatch[count].str = p; - fuzmatch[count].score = score; - count++; } } - if (count == 0) { // no match found, break here - break; + + if (p == NULL) { + continue; } + if (round == 1) { - if (!fuzzy) { - *file = xmalloc((size_t)count * sizeof(**file)); - if (options & WILD_BUFLASTUSED) { - matches = xmalloc((size_t)count * sizeof(*matches)); - } + count++; + continue; + } + + if (options & WILD_HOME_REPLACE) { + p = home_replace_save(buf, p); + } else { + p = xstrdup(p); + } + + if (!fuzzy) { + if (matches != NULL) { + matches[count].buf = buf; + matches[count].match = p; + count++; } else { - fuzmatch = xmalloc((size_t)count * sizeof(fuzmatch_str_T)); + (*file)[count++] = p; } + } else { + fuzmatch[count].idx = count; + fuzmatch[count].str = p; + fuzmatch[count].score = score; + count++; } } - - if (!fuzzy) { - vim_regfree(regmatch.regprog); - if (count) { // match(es) found, break here - break; + if (count == 0) { // no match found, break here + break; + } + if (round == 1) { + if (!fuzzy) { + *file = xmalloc((size_t)count * sizeof(**file)); + if (options & WILD_BUFLASTUSED) { + matches = xmalloc((size_t)count * sizeof(*matches)); + } + } else { + fuzmatch = xmalloc((size_t)count * sizeof(fuzmatch_str_T)); } } } - if (!fuzzy && patc != pat) { - xfree(patc); + if (!fuzzy) { + vim_regfree(regmatch.regprog); + if (to_free) { + xfree(patc); + } } if (!fuzzy) { @@ -2722,7 +2772,7 @@ void get_winopts(buf_T *buf) curwin->w_changelistidx = wip->wi_changelistidx; } - if (curwin->w_float_config.style == kWinStyleMinimal) { + if (curwin->w_config.style == kWinStyleMinimal) { didset_window_options(curwin, false); win_set_minimal_style(curwin); } @@ -2757,8 +2807,6 @@ linenr_T buflist_findlnum(buf_T *buf) void buflist_list(exarg_T *eap) { buf_T *buf = firstbuf; - int len; - int i; garray_T buflist; buf_T **buflist_data = NULL; @@ -2823,21 +2871,21 @@ void buflist_list(exarg_T *eap) } msg_putchar('\n'); - len = vim_snprintf(IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", - buf->b_fnum, - buf->b_p_bl ? ' ' : 'u', - buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), - buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'), - ro_char, - changed_char, - NameBuff); + int len = vim_snprintf(IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", + buf->b_fnum, + buf->b_p_bl ? ' ' : 'u', + buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), + buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'), + ro_char, + changed_char, + NameBuff); if (len > IOSIZE - 20) { len = IOSIZE - 20; } // put "line 999" in column 40 or after the file name - i = 40 - vim_strsize(IObuff); + int i = 40 - vim_strsize(IObuff); do { IObuff[len++] = ' '; } while (--i > 0 && len < IOSIZE - 18); @@ -3136,7 +3184,7 @@ static bool buf_same_file_id(buf_T *buf, FileID *file_id) /// Print info about the current buffer. /// /// @param fullname when non-zero print full path -void fileinfo(int fullname, int shorthelp, int dont_truncate) +void fileinfo(int fullname, int shorthelp, bool dont_truncate) { char *name; int n; @@ -3210,7 +3258,7 @@ void fileinfo(int fullname, int shorthelp, int dont_truncate) (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); } - (void)append_arg_number(curwin, buffer, IOSIZE); + append_arg_number(curwin, buffer, IOSIZE); if (dont_truncate) { // Temporarily set msg_scroll to avoid the message being truncated. @@ -3253,7 +3301,6 @@ void maketitle(void) char *title_str = NULL; char *icon_str = NULL; int maxlen = 0; - int len; char buf[IOSIZE]; if (!redrawing()) { @@ -3278,7 +3325,7 @@ void maketitle(void) if (*p_titlestring != NUL) { if (stl_syntax & STL_IN_TITLE) { build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring, - "titlestring", 0, 0, maxlen, NULL, NULL, NULL); + kOptTitlestring, 0, 0, maxlen, NULL, NULL, NULL, NULL); title_str = buf; } else { title_str = p_titlestring; @@ -3376,14 +3423,14 @@ void maketitle(void) #undef SPACE_FOR_ARGNR } } - int mustset = value_change(title_str, &lasttitle); + bool mustset = value_change(title_str, &lasttitle); if (p_icon) { icon_str = buf; if (*p_iconstring != NUL) { if (stl_syntax & STL_IN_ICON) { build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring, - "iconstring", 0, 0, 0, NULL, NULL, NULL); + kOptIconstring, 0, 0, 0, NULL, NULL, NULL, NULL); } else { icon_str = p_iconstring; } @@ -3396,10 +3443,10 @@ void maketitle(void) } *icon_str = NUL; // Truncate name at 100 bytes. - len = (int)strlen(buf_p); + int len = (int)strlen(buf_p); if (len > 100) { len -= 100; - len += utf_cp_tail_off(buf_p, buf_p + len) + 1; + len += utf_cp_bounds(buf_p, buf_p + len).end_off; buf_p += len; } STRCPY(icon_str, buf_p); @@ -3558,16 +3605,12 @@ bool bt_prompt(buf_T *buf) /// Open a window for a number of buffers. void ex_buffer_all(exarg_T *eap) { - buf_T *buf; win_T *wp, *wpnext; int split_ret = OK; - bool p_ea_save; int open_wins = 0; - int r; linenr_T count; // Maximum number of windows to open. int all; // When true also load inactive buffers. int had_tab = cmdmod.cmod_tab; - tabpage_T *tpnext; if (eap->addr_count == 0) { // make as many windows as possible count = 9999; @@ -3592,7 +3635,7 @@ void ex_buffer_all(exarg_T *eap) goto_tabpage_tp(first_tabpage, true, true); } while (true) { - tpnext = curtab->tp_next; + tabpage_T *tpnext = curtab->tp_next; // Try to close floating windows first for (wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { wpnext = wp->w_floating @@ -3637,7 +3680,7 @@ void ex_buffer_all(exarg_T *eap) // lastwin may be aucmd_win win_enter(lastwin_nofloating(), false); autocmd_no_leave++; - for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) { + for (buf_T *buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) { // Check if this buffer needs a window if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl) { continue; @@ -3667,7 +3710,7 @@ void ex_buffer_all(exarg_T *eap) bufref_T bufref; set_bufref(&bufref, buf); // Split the window and put the buffer in it. - p_ea_save = p_ea; + bool p_ea_save = p_ea; p_ea = true; // use space from all windows split_ret = win_split(0, WSP_ROOM | WSP_BELOW); open_wins++; @@ -3678,7 +3721,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; @@ -3708,7 +3751,7 @@ void ex_buffer_all(exarg_T *eap) os_breakcheck(); if (got_int) { - (void)vgetc(); // only break the file loading, not the rest + vgetc(); // only break the file loading, not the rest break; } // Autocommands deleted the buffer or aborted script processing!!! @@ -3726,8 +3769,8 @@ void ex_buffer_all(exarg_T *eap) // Close superfluous windows. for (wp = lastwin; open_wins > count;) { - r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) - || autowrite(wp->w_buffer, false) == OK) && !is_aucmd_win(wp); + 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)) { // BufWrite Autocommands made the window invalid, start over wp = lastwin; @@ -3800,8 +3843,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:", (size_t)3) == 0) - || strncmp(s, "vi:", (size_t)3) == 0) { + if ((prev != -1 && strncmp(s, "ex:", 3) == 0) + || strncmp(s, "vi:", 3) == 0) { break; } // Accept both "vim" and "Vim". @@ -3866,8 +3909,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 ", (size_t)4) == 0 - || strncmp(s, "se ", (size_t)3) == 0) { + if (strncmp(s, "set ", 4) == 0 + || strncmp(s, "se ", 3) == 0) { if (*e != ':') { // no terminating ':'? break; } @@ -4015,6 +4058,9 @@ char *buf_spname(buf_T *buf) if (buf->b_fname != NULL) { return buf->b_fname; } + if (buf == cmdwin_buf) { + return _("[Command Line]"); + } if (bt_prompt(buf)) { return _("[Prompt]"); } @@ -4026,67 +4072,6 @@ char *buf_spname(buf_T *buf) return NULL; } -/// Invalidate the signcolumn if needed after deleting a sign ranging from line1 to line2. -void buf_signcols_del_check(buf_T *buf, linenr_T line1, linenr_T line2) -{ - linenr_T sent = buf->b_signcols.sentinel; - if (sent >= line1 && sent <= line2) { - // When removed sign overlaps the sentinel line, entire buffer needs to be checked. - buf->b_signcols.sentinel = buf->b_signcols.size = 0; - } -} - -/// Invalidate the signcolumn if needed after adding a sign ranging from line1 to line2. -void buf_signcols_add_check(buf_T *buf, linenr_T line1, linenr_T line2) -{ - if (!buf->b_signcols.sentinel) { - return; - } - - linenr_T sent = buf->b_signcols.sentinel; - if (sent >= line1 && sent <= line2) { - // If added sign overlaps sentinel line, increment without invalidating. - if (buf->b_signcols.size == buf->b_signcols.max) { - buf->b_signcols.max++; - } - buf->b_signcols.size++; - return; - } - - if (line1 < buf->b_signcols.invalid_top) { - buf->b_signcols.invalid_top = line1; - } - if (line2 > buf->b_signcols.invalid_bot) { - buf->b_signcols.invalid_bot = line2; - } -} - -int buf_signcols(buf_T *buf, int max) -{ - if (!buf->b_signs_with_text) { - buf->b_signcols.size = 0; - } else if (max <= 1 && buf->b_signs_with_text >= (size_t)max) { - buf->b_signcols.size = max; - } else { - linenr_T sent = buf->b_signcols.sentinel; - if (!sent || max > buf->b_signcols.max) { - // Recheck if the window scoped maximum 'signcolumn' is greater than the - // previous maximum or if there is no sentinel line yet. - buf->b_signcols.invalid_top = sent ? sent : 1; - buf->b_signcols.invalid_bot = sent ? sent : buf->b_ml.ml_line_count; - } - - if (buf->b_signcols.invalid_bot) { - decor_validate_signcols(buf, max); - } - } - - buf->b_signcols.max = max; - buf->b_signcols.invalid_top = MAXLNUM; - buf->b_signcols.invalid_bot = 0; - return buf->b_signcols.size; -} - /// Get "buf->b_fname", use "[No Name]" if it is NULL. char *buf_get_fname(const buf_T *buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL @@ -4193,6 +4178,7 @@ void wipe_buffer(buf_T *buf, bool aucmd) /// - Always considered 'nomodified' /// /// @param bufnr Buffer to switch to, or 0 to create a new buffer. +/// @param bufname Buffer name, or NULL. /// /// @see curbufIsChanged() /// @@ -4202,12 +4188,60 @@ int buf_open_scratch(handle_T bufnr, char *bufname) if (do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL) { return FAIL; } - apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); - (void)setfname(curbuf, bufname, NULL, true); - apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); - set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); - set_option_value_give_err("bt", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); - set_option_value_give_err("swf", BOOLEAN_OPTVAL(false), OPT_LOCAL); + if (bufname != NULL) { + apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); + setfname(curbuf, bufname, NULL, true); + apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); + } + set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); + set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); + set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL); RESET_BINDING(curwin); return OK; } + +bool buf_is_empty(buf_T *buf) +{ + return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0'; +} + +/// Increment b:changedtick value +/// +/// Also checks b: for consistency in case of debug build. +/// +/// @param[in,out] buf Buffer to increment value in. +void buf_inc_changedtick(buf_T *const buf) + FUNC_ATTR_NONNULL_ALL +{ + buf_set_changedtick(buf, buf_get_changedtick(buf) + 1); +} + +/// Set b:changedtick, also checking b: for consistency in debug build +/// +/// @param[out] buf Buffer to set changedtick in. +/// @param[in] changedtick New value. +void buf_set_changedtick(buf_T *const buf, const varnumber_T changedtick) + FUNC_ATTR_NONNULL_ALL +{ + typval_T old_val = buf->changedtick_di.di_tv; + +#ifndef NDEBUG + dictitem_T *const changedtick_di = tv_dict_find(buf->b_vars, S_LEN("changedtick")); + assert(changedtick_di != NULL); + assert(changedtick_di->di_tv.v_type == VAR_NUMBER); + assert(changedtick_di->di_tv.v_lock == VAR_FIXED); + // For some reason formatc does not like the below. +# ifndef UNIT_TESTING_LUA_PREPROCESSING + assert(changedtick_di->di_flags == (DI_FLAGS_RO|DI_FLAGS_FIX)); +# endif + assert(changedtick_di == (dictitem_T *)&buf->changedtick_di); +#endif + buf->changedtick_di.di_tv.vval.v_number = changedtick; + + if (tv_dict_is_watched(buf->b_vars)) { + tv_dict_watcher_notify(buf->b_vars, + (char *)buf->changedtick_di.di_key, + &buf->changedtick_di.di_tv, + &old_val); + } +} |