aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/buffer.c')
-rw-r--r--src/nvim/buffer.c697
1 files changed, 256 insertions, 441 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b50c764ac3..b3bbdce9d9 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -53,6 +53,7 @@
#include "nvim/indent_c.h"
#include "nvim/main.h"
#include "nvim/mark.h"
+#include "nvim/extmark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -80,12 +81,6 @@
#include "nvim/os/input.h"
#include "nvim/buffer_updates.h"
-typedef enum {
- kBLSUnchanged = 0,
- kBLSChanged = 1,
- kBLSDeleted = 2,
-} BufhlLineStatus;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.c.generated.h"
#endif
@@ -191,14 +186,17 @@ int open_buffer(
}
}
- /*
- * if there is no memfile at all, exit
- * This is OK, since there are no changes to lose.
- */
+ // If there is no memfile at all, exit.
+ // This is OK, since there are no changes to lose.
if (curbuf == NULL) {
EMSG(_("E82: Cannot allocate any buffer, exiting..."));
+
+ // Don't try to do any saving, with "curbuf" NULL almost nothing
+ // will work.
+ v_dying = 2;
getout(2);
}
+
EMSG(_("E83: Cannot allocate buffer, using other one..."));
enter_buffer(curbuf);
if (old_tw != curbuf->b_p_tw) {
@@ -410,11 +408,11 @@ bool buf_valid(buf_T *buf)
/// caller should get a new buffer very soon!
/// The 'bufhidden' option can force freeing and deleting.
/// @param abort_if_last
-/// If TRUE, do not close the buffer if autocommands cause
+/// If true, do not close the buffer if autocommands cause
/// there to be only one window with this buffer. e.g. when
/// ":quit" is supposed to close the window but autocommands
/// close all other windows.
-void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
+void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
{
bool unload_buf = (action != 0);
bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
@@ -768,6 +766,9 @@ static void free_buffer(buf_T *buf)
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
tv_dict_unref(buf->additional_data);
+ xfree(buf->b_prompt_text);
+ callback_free(&buf->b_prompt_callback);
+ callback_free(&buf->b_prompt_interrupt);
clear_fmark(&buf->b_last_cursor);
clear_fmark(&buf->b_last_insert);
clear_fmark(&buf->b_last_change);
@@ -816,7 +817,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
}
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
- bufhl_clear_all(buf); // delete any highligts
+ extmark_free_all(buf); // delete any extmarks
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
@@ -929,7 +930,7 @@ void handle_swap_exists(bufref_T *old_curbuf)
// User selected Recover at ATTENTION prompt.
msg_scroll = true;
- ml_recover();
+ ml_recover(false);
MSG_PUTS("\n"); // don't overwrite the last message
cmdline_row = msg_row;
do_modelines(0);
@@ -1236,7 +1237,7 @@ do_buffer(
return FAIL;
}
} else {
- EMSG2(_("E89: %s will be killed(add ! to override)"),
+ EMSG2(_("E89: %s will be killed (add ! to override)"),
(char *)buf->b_fname);
return FAIL;
}
@@ -1583,10 +1584,12 @@ void enter_buffer(buf_T *buf)
open_buffer(false, NULL, 0);
} else {
- if (!msg_silent) {
+ if (!msg_silent && !shortmess(SHM_FILEINFO)) {
need_fileinfo = true; // display file info after redraw
}
- (void)buf_check_timestamp(curbuf, false); // check if file changed
+ // check if file changed
+ (void)buf_check_timestamp(curbuf, false);
+
curwin->w_topline = 1;
curwin->w_topfill = 0;
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
@@ -1618,6 +1621,7 @@ void enter_buffer(buf_T *buf)
if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
(void)did_set_spelllang(curwin);
}
+ curbuf->b_last_used = time(NULL);
redraw_later(NOT_VALID);
}
@@ -1750,6 +1754,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf);
}
if (aborting()) { // autocmds may abort script processing
+ xfree(ffname);
return NULL;
}
if (buf == curbuf) {
@@ -1879,6 +1884,10 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
}
}
+ buf->b_prompt_callback.type = kCallbackNone;
+ buf->b_prompt_interrupt.type = kCallbackNone;
+ buf->b_prompt_text = NULL;
+
return buf;
}
@@ -1947,6 +1956,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_path);
clear_string_option(&buf->b_p_tags);
clear_string_option(&buf->b_p_tc);
+ clear_string_option(&buf->b_p_tfu);
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);
clear_string_option(&buf->b_p_qe);
@@ -2244,6 +2254,23 @@ int buflist_findpat(
return match;
}
+typedef struct {
+ buf_T *buf;
+ char_u *match;
+} bufmatch_T;
+
+/// Compare functions for qsort() below, that compares b_last_used.
+static int
+buf_time_compare(const void *s1, const void *s2)
+{
+ buf_T *buf1 = *(buf_T **)s1;
+ buf_T *buf2 = *(buf_T **)s2;
+
+ if (buf1->b_last_used == buf2->b_last_used) {
+ return 0;
+ }
+ return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
+}
/*
* Find all buffer names that match.
@@ -2257,6 +2284,7 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
char_u *p;
int attempt;
char_u *patc;
+ bufmatch_T *matches = NULL;
*num_file = 0; // return values in case of FAIL
*file = NULL;
@@ -2307,7 +2335,13 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
} else {
p = vim_strsave(p);
}
- (*file)[count++] = p;
+ if (matches != NULL) {
+ matches[count].buf = buf;
+ matches[count].match = p;
+ count++;
+ } else {
+ (*file)[count++] = p;
+ }
}
}
}
@@ -2316,6 +2350,10 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
}
if (round == 1) {
*file = xmalloc((size_t)count * sizeof(**file));
+
+ if (options & WILD_BUFLASTUSED) {
+ matches = xmalloc((size_t)count * sizeof(*matches));
+ }
}
}
vim_regfree(regmatch.regprog);
@@ -2328,6 +2366,25 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
xfree(patc);
}
+ if (matches != NULL) {
+ if (count > 1) {
+ qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare);
+ }
+
+ // if the current buffer is first in the list, place it at the end
+ if (matches[0].buf == curbuf) {
+ for (int i = 1; i < count; i++) {
+ (*file)[i-1] = matches[i].match;
+ }
+ (*file)[count-1] = matches[0].match;
+ } else {
+ for (int i = 0; i < count; i++) {
+ (*file)[i] = matches[i].match;
+ }
+ }
+ xfree(matches);
+ }
+
*num_file = count;
return count == 0 ? FAIL : OK;
}
@@ -2588,11 +2645,35 @@ linenr_T buflist_findlnum(buf_T *buf)
// List all known file names (for :files and :buffers command).
void buflist_list(exarg_T *eap)
{
- buf_T *buf;
+ buf_T *buf = firstbuf;
int len;
int i;
- for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next) {
+ garray_T buflist;
+ buf_T **buflist_data = NULL, **p;
+
+ if (vim_strchr(eap->arg, 't')) {
+ ga_init(&buflist, sizeof(buf_T *), 50);
+ for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
+ ga_grow(&buflist, 1);
+ ((buf_T **)buflist.ga_data)[buflist.ga_len++] = buf;
+ }
+
+ qsort(buflist.ga_data, (size_t)buflist.ga_len,
+ sizeof(buf_T *), buf_time_compare);
+
+ p = buflist_data = (buf_T **)buflist.ga_data;
+ buf = *p;
+ }
+
+ for (;
+ buf != NULL && !got_int;
+ buf = buflist_data
+ ? (++p < buflist_data + buflist.ga_len ? *p : NULL)
+ : buf->b_next) {
+ const bool is_terminal = buf->terminal;
+ const bool job_running = buf->terminal && terminal_running(buf->terminal);
+
// skip unspecified buffers
if ((!buf->b_p_bl && !eap->forceit && !strchr((char *)eap->arg, 'u'))
|| (strchr((char *)eap->arg, 'u') && buf->b_p_bl)
@@ -2602,6 +2683,8 @@ void buflist_list(exarg_T *eap)
&& (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0))
|| (strchr((char *)eap->arg, 'h')
&& (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0))
+ || (strchr((char *)eap->arg, 'R') && (!is_terminal || !job_running))
+ || (strchr((char *)eap->arg, 'F') && (!is_terminal || job_running))
|| (strchr((char *)eap->arg, '-') && buf->b_p_ma)
|| (strchr((char *)eap->arg, '=') && !buf->b_p_ro)
|| (strchr((char *)eap->arg, 'x') && !(buf->b_flags & BF_READERR))
@@ -2648,13 +2731,22 @@ void buflist_list(exarg_T *eap)
do {
IObuff[len++] = ' ';
} while (--i > 0 && len < IOSIZE - 18);
- vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
- _("line %" PRId64),
- buf == curbuf ? (int64_t)curwin->w_cursor.lnum
- : (int64_t)buflist_findlnum(buf));
+ if (vim_strchr(eap->arg, 't') && buf->b_last_used) {
+ add_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used);
+ } else {
+ vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
+ _("line %" PRId64),
+ buf == curbuf ? (int64_t)curwin->w_cursor.lnum
+ : (int64_t)buflist_findlnum(buf));
+ }
+
msg_outtrans(IObuff);
line_breakcheck();
}
+
+ if (buflist_data) {
+ ga_clear(&buflist);
+ }
}
/*
@@ -2689,7 +2781,7 @@ setfname(
buf_T *buf,
char_u *ffname,
char_u *sfname,
- int message // give message when buffer already exists
+ bool message // give message when buffer already exists
)
{
buf_T *obuf = NULL;
@@ -2992,28 +3084,29 @@ fileinfo(
}
vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
- curbufIsChanged() ? (shortmess(SHM_MOD)
- ? " [+]" : _(" [Modified]")) : " ",
- (curbuf->b_flags & BF_NOTEDITED)
- && !bt_dontwrite(curbuf)
- ? _("[Not edited]") : "",
- (curbuf->b_flags & BF_NEW)
- && !bt_dontwrite(curbuf)
- ? _("[New file]") : "",
- (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
- curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
- : _("[readonly]")) : "",
- (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
- || curbuf->b_p_ro) ?
- " " : "");
- /* 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 > 1000000L)
+ curbufIsChanged()
+ ? (shortmess(SHM_MOD) ? " [+]" : _(" [Modified]")) : " ",
+ (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf)
+ ? _("[Not edited]") : "",
+ (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf)
+ ? new_file_message() : "",
+ (curbuf->b_flags & BF_READERR)
+ ? _("[Read errors]") : "",
+ curbuf->b_p_ro
+ ? (shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")) : "",
+ (curbufIsChanged()
+ || (curbuf->b_flags & BF_WRITE_MASK)
+ || curbuf->b_p_ro)
+ ? " " : "");
+ // 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 > 1000000L) {
n = (int)(((long)curwin->w_cursor.lnum) /
((long)curbuf->b_ml.ml_line_count / 100L));
- else
+ } else {
n = (int)(((long)curwin->w_cursor.lnum * 100L) /
(long)curbuf->b_ml.ml_line_count);
+ }
if (curbuf->b_ml.ml_flags & ML_EMPTY) {
vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
} else if (p_ru) {
@@ -3070,18 +3163,15 @@ void col_print(char_u *buf, size_t buflen, int col, int vcol)
}
}
-/*
- * put file name in title bar of window and in icon title
- */
-
static char_u *lasttitle = NULL;
static char_u *lasticon = NULL;
+
+// Put the title name in the title bar and icon of the window.
void maketitle(void)
{
- char_u *t_str = NULL;
- char_u *i_name;
- char_u *i_str = NULL;
+ char_u *title_str = NULL;
+ char_u *icon_str = NULL;
int maxlen = 0;
int len;
int mustset;
@@ -3095,7 +3185,7 @@ void maketitle(void)
need_maketitle = false;
if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL) {
- return;
+ return; // nothing to do
}
if (p_title) {
@@ -3116,14 +3206,14 @@ void maketitle(void)
build_stl_str_hl(curwin, (char_u *)buf, sizeof(buf),
p_titlestring, use_sandbox,
0, maxlen, NULL, NULL);
- t_str = (char_u *)buf;
+ title_str = (char_u *)buf;
if (called_emsg) {
set_string_option_direct((char_u *)"titlestring", -1, (char_u *)"",
OPT_FREE, SID_ERROR);
}
called_emsg |= save_called_emsg;
} else {
- t_str = p_titlestring;
+ title_str = p_titlestring;
}
} else {
// Format: "fname + (path) (1 of 2) - VIM".
@@ -3207,16 +3297,16 @@ void maketitle(void)
trunc_string((char_u *)buf, (char_u *)buf, maxlen, sizeof(buf));
}
}
- t_str = (char_u *)buf;
+ title_str = (char_u *)buf;
#undef SPACE_FOR_FNAME
#undef SPACE_FOR_DIR
#undef SPACE_FOR_ARGNR
}
}
- mustset = ti_change(t_str, &lasttitle);
+ mustset = value_change(title_str, &lasttitle);
if (p_icon) {
- i_str = (char_u *)buf;
+ icon_str = (char_u *)buf;
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
int use_sandbox = false;
@@ -3224,37 +3314,40 @@ void maketitle(void)
use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
called_emsg = false;
- build_stl_str_hl(curwin, i_str, sizeof(buf),
- p_iconstring, use_sandbox,
- 0, 0, NULL, NULL);
- if (called_emsg)
+ build_stl_str_hl(curwin, icon_str, sizeof(buf),
+ p_iconstring, use_sandbox,
+ 0, 0, NULL, NULL);
+ if (called_emsg) {
set_string_option_direct((char_u *)"iconstring", -1,
- (char_u *)"", OPT_FREE, SID_ERROR);
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ }
called_emsg |= save_called_emsg;
- } else
- i_str = p_iconstring;
+ } else {
+ icon_str = p_iconstring;
+ }
} else {
+ char_u *buf_p;
if (buf_spname(curbuf) != NULL) {
- i_name = buf_spname(curbuf);
+ buf_p = buf_spname(curbuf);
} else { // use file name only in icon
- i_name = path_tail(curbuf->b_ffname);
+ buf_p = path_tail(curbuf->b_ffname);
}
- *i_str = NUL;
+ *icon_str = NUL;
// Truncate name at 100 bytes.
- len = (int)STRLEN(i_name);
+ len = (int)STRLEN(buf_p);
if (len > 100) {
len -= 100;
if (has_mbyte) {
- len += (*mb_tail_off)(i_name, i_name + len) + 1;
+ len += (*mb_tail_off)(buf_p, buf_p + len) + 1;
}
- i_name += len;
+ buf_p += len;
}
- STRCPY(i_str, i_name);
- trans_characters(i_str, IOSIZE);
+ STRCPY(icon_str, buf_p);
+ trans_characters(icon_str, IOSIZE);
}
}
- mustset |= ti_change(i_str, &lasticon);
+ mustset |= value_change(icon_str, &lasticon);
if (mustset) {
resettitle();
@@ -3268,8 +3361,8 @@ void maketitle(void)
/// @param str desired title string
/// @param[in,out] last current title string
//
-/// @return true when "*last" changed.
-static bool ti_change(char_u *str, char_u **last)
+/// @return true if resettitle() is to be called.
+static bool value_change(char_u *str, char_u **last)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if ((str == NULL) != (*last == NULL)
@@ -3277,10 +3370,11 @@ static bool ti_change(char_u *str, char_u **last)
xfree(*last);
if (str == NULL) {
*last = NULL;
+ resettitle();
} else {
*last = vim_strsave(str);
+ return true;
}
- return true;
}
return false;
}
@@ -3370,7 +3464,8 @@ int build_stl_str_hl(
} type;
} items[STL_MAX_ITEM];
#define TMPLEN 70
- char_u tmp[TMPLEN];
+ char_u buf_tmp[TMPLEN];
+ char_u win_tmp[TMPLEN];
char_u *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
@@ -3378,10 +3473,18 @@ int build_stl_str_hl(
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
if (fmt[0] == '%' && fmt[1] == '!') {
+ typval_T tv = {
+ .v_type = VAR_NUMBER,
+ .vval.v_number = wp->handle,
+ };
+ set_var(S_LEN("g:statusline_winid"), &tv, false);
+
usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
if (usefmt == NULL) {
usefmt = fmt;
}
+
+ do_unlet(S_LEN("g:statusline_winid"), true);
}
if (fillchar == 0) {
@@ -3391,14 +3494,27 @@ int build_stl_str_hl(
fillchar = '-';
}
+ // The cursor in windows other than the current one isn't always
+ // up-to-date, esp. because of autocommands and timers.
+ linenr_T lnum = wp->w_cursor.lnum;
+ if (lnum > wp->w_buffer->b_ml.ml_line_count) {
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+ wp->w_cursor.lnum = lnum;
+ }
+
// Get line & check if empty (cursorpos will show "0-1").
- char_u *line_ptr = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, false);
+ const char_u *line_ptr = ml_get_buf(wp->w_buffer, lnum, false);
bool empty_line = (*line_ptr == NUL);
// Get the byte value now, in case we need it below. This is more
// efficient than making a copy of the line.
int byteval;
- if (wp->w_cursor.col > (colnr_T)STRLEN(line_ptr)) {
+ const size_t len = STRLEN(line_ptr);
+ if (wp->w_cursor.col > (colnr_T)len) {
+ // Line may have changed since checking the cursor column, or the lnum
+ // was adjusted above.
+ wp->w_cursor.col = (colnr_T)len;
+ wp->w_cursor.coladd = 0;
byteval = 0;
} else {
byteval = utf_ptr2char(line_ptr + wp->w_cursor.col);
@@ -3530,8 +3646,20 @@ int build_stl_str_hl(
}
}
if (n == curitem && group_start_userhl == group_end_userhl) {
+ // empty group
out_p = t;
group_len = 0;
+ for (n = groupitems[groupdepth] + 1; n < curitem; n++) {
+ // do not use the highlighting from the removed group
+ if (items[n].type == Highlight) {
+ items[n].type = Empty;
+ }
+ // adjust the start position of TabPage to the next
+ // item position
+ if (items[n].type == TabPage) {
+ items[n].start = out_p;
+ }
+ }
}
}
@@ -3791,22 +3919,31 @@ int build_stl_str_hl(
// { Evaluate the expression
// Store the current buffer number as a string variable
- vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
- set_internal_string_var((char_u *)"g:actual_curbuf", tmp);
+ vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum);
+ set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp);
+ vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->handle);
+ set_internal_string_var((char_u *)"g:actual_curwin", win_tmp);
buf_T *const save_curbuf = curbuf;
win_T *const save_curwin = curwin;
+ const int save_VIsual_active = VIsual_active;
curwin = wp;
curbuf = wp->w_buffer;
+ // Visual mode is only valid in the current window.
+ if (curwin != save_curwin) {
+ VIsual_active = false;
+ }
// Note: The result stored in `t` is unused.
str = eval_to_string_safe(out_p, &t, use_sandbox);
curwin = save_curwin;
curbuf = save_curbuf;
+ VIsual_active = save_VIsual_active;
// Remove the variable we just stored
do_unlet(S_LEN("g:actual_curbuf"), true);
+ do_unlet(S_LEN("g:actual_curwin"), true);
// }
@@ -3865,8 +4002,8 @@ int build_stl_str_hl(
// Store the position percentage in our temporary buffer.
// Note: We cannot store the value in `num` because
// `get_rel_pos` can return a named position. Ex: "Top"
- get_rel_pos(wp, tmp, TMPLEN);
- str = tmp;
+ get_rel_pos(wp, buf_tmp, TMPLEN);
+ str = buf_tmp;
break;
case STL_ARGLISTSTAT:
@@ -3876,19 +4013,19 @@ int build_stl_str_hl(
// at the end of the null-terminated string.
// Setting the first byte to null means it will place the argument
// number string at the beginning of the buffer.
- tmp[0] = 0;
+ buf_tmp[0] = 0;
// Note: The call will only return true if it actually
- // appended data to the `tmp` buffer.
- if (append_arg_number(wp, tmp, (int)sizeof(tmp), false)) {
- str = tmp;
+ // appended data to the `buf_tmp` buffer.
+ if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), false)) {
+ str = buf_tmp;
}
break;
case STL_KEYMAP:
fillable = false;
- if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN)) {
- str = tmp;
+ if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN)) {
+ str = buf_tmp;
}
break;
case STL_PAGENUM:
@@ -3945,9 +4082,9 @@ int build_stl_str_hl(
// (including the brackets and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) {
- vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
- wp->w_buffer->b_p_ft);
- str = tmp;
+ vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]",
+ wp->w_buffer->b_p_ft);
+ str = buf_tmp;
}
break;
@@ -3959,13 +4096,13 @@ int build_stl_str_hl(
// (including the comma and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) {
- vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
- wp->w_buffer->b_p_ft);
+ vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s",
+ wp->w_buffer->b_p_ft);
// Uppercase the file extension
- for (char_u *t = tmp; *t != 0; t++) {
+ for (char_u *t = buf_tmp; *t != 0; t++) {
*t = (char_u)TOUPPER_LOC(*t);
}
- str = tmp;
+ str = buf_tmp;
}
break;
}
@@ -4629,7 +4766,8 @@ do_arg_all(
if (i < alist->al_ga.ga_len
&& (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
|| path_full_compare(alist_name(&AARGLIST(alist)[i]),
- buf->b_ffname, true) & kEqualFiles)) {
+ buf->b_ffname,
+ true, true) & kEqualFiles)) {
int weight = 1;
if (old_curtab == curtab) {
@@ -4812,6 +4950,12 @@ do_arg_all(
xfree(opened);
}
+// Return TRUE if "buf" is a prompt buffer.
+int bt_prompt(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == 'p';
+}
+
/*
* Open a window for a number of buffers.
*/
@@ -5179,6 +5323,13 @@ bool bt_help(const buf_T *const buf)
return buf != NULL && buf->b_help;
}
+// Return true if "buf" is a normal buffer, 'buftype' is empty.
+bool bt_normal(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return buf != NULL && buf->b_p_bt[0] == NUL;
+}
+
// Return true if "buf" is the quickfix buffer.
bool bt_quickfix(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
@@ -5199,14 +5350,18 @@ bool bt_nofile(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
- || buf->b_p_bt[0] == 'a' || buf->terminal);
+ || buf->b_p_bt[0] == 'a'
+ || buf->terminal
+ || buf->b_p_bt[0] == 'p');
}
// Return true if "buf" is a "nowrite", "nofile" or "terminal" buffer.
bool bt_dontwrite(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return buf != NULL && (buf->b_p_bt[0] == 'n' || buf->terminal);
+ return buf != NULL && (buf->b_p_bt[0] == 'n'
+ || buf->terminal
+ || buf->b_p_bt[0] == 'p');
}
bool bt_dontwrite_msg(const buf_T *const buf)
@@ -5259,6 +5414,9 @@ char_u *buf_spname(buf_T *buf)
if (buf->b_fname != NULL) {
return buf->b_fname;
}
+ if (bt_prompt(buf)) {
+ return (char_u *)_("[Prompt]");
+ }
return (char_u *)_("[Scratch]");
}
if (buf->b_fname == NULL) {
@@ -5323,349 +5481,6 @@ int buf_signcols(buf_T *buf)
return buf->b_signcols;
}
-// bufhl: plugin highlights associated with a buffer
-
-/// Get reference to line in kbtree_t
-///
-/// @param b the three
-/// @param line the linenumber to lookup
-/// @param put if true, put a new line when not found
-/// if false, return NULL when not found
-BufhlLine *bufhl_tree_ref(BufhlInfo *b, linenr_T line, bool put)
-{
- BufhlLine t = BUFHLLINE_INIT(line);
-
- // kp_put() only works if key is absent, try get first
- BufhlLine **pp = kb_get(bufhl, b, &t);
- if (pp) {
- return *pp;
- } else if (!put) {
- return NULL;
- }
-
- BufhlLine *p = xmalloc(sizeof(*p));
- *p = (BufhlLine)BUFHLLINE_INIT(line);
- kb_put(bufhl, b, p);
- return p;
-}
-
-/// Adds a highlight to buffer.
-///
-/// Unlike matchaddpos() highlights follow changes to line numbering (as lines
-/// are inserted/removed above the highlighted line), like signs and marks do.
-///
-/// When called with "src_id" set to 0, a unique source id is generated and
-/// returned. Succesive calls can pass it in as "src_id" to add new highlights
-/// to the same source group. All highlights in the same group can be cleared
-/// at once. If the highlight never will be manually deleted pass in -1 for
-/// "src_id"
-///
-/// if "hl_id" or "lnum" is invalid no highlight is added, but a new src_id
-/// is still returned.
-///
-/// @param buf The buffer to add highlights to
-/// @param src_id src_id to use or 0 to use a new src_id group,
-/// or -1 for ungrouped highlight.
-/// @param hl_id Id of the highlight group to use
-/// @param lnum The line to highlight
-/// @param col_start First column to highlight
-/// @param col_end The last column to highlight,
-/// or -1 to highlight to end of line
-/// @return The src_id that was used
-int bufhl_add_hl(buf_T *buf,
- int src_id,
- int hl_id,
- linenr_T lnum,
- colnr_T col_start,
- colnr_T col_end)
-{
- if (src_id == 0) {
- src_id = (int)nvim_create_namespace((String)STRING_INIT);
- }
- if (hl_id <= 0) {
- // no highlight group or invalid line, just return src_id
- return src_id;
- }
-
- BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, true);
-
- BufhlItem *hlentry = kv_pushp(lineinfo->items);
- hlentry->src_id = src_id;
- hlentry->hl_id = hl_id;
- hlentry->start = col_start;
- hlentry->stop = col_end;
-
- if (0 < lnum && lnum <= buf->b_ml.ml_line_count) {
- redraw_buf_line_later(buf, lnum);
- }
- return src_id;
-}
-
-/// Add highlighting to a buffer, bounded by two cursor positions,
-/// with an offset.
-///
-/// @param buf Buffer to add highlights to
-/// @param src_id src_id to use or 0 to use a new src_id group,
-/// or -1 for ungrouped highlight.
-/// @param hl_id Highlight group id
-/// @param pos_start Cursor position to start the hightlighting at
-/// @param pos_end Cursor position to end the highlighting at
-/// @param offset Move the whole highlighting this many columns to the right
-void bufhl_add_hl_pos_offset(buf_T *buf,
- int src_id,
- int hl_id,
- lpos_T pos_start,
- lpos_T pos_end,
- colnr_T offset)
-{
- colnr_T hl_start = 0;
- colnr_T hl_end = 0;
-
- for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
- if (pos_start.lnum < lnum && lnum < pos_end.lnum) {
- hl_start = offset;
- hl_end = MAXCOL;
- } else if (lnum == pos_start.lnum && lnum < pos_end.lnum) {
- hl_start = pos_start.col + offset + 1;
- hl_end = MAXCOL;
- } else if (pos_start.lnum < lnum && lnum == pos_end.lnum) {
- hl_start = offset;
- hl_end = pos_end.col + offset;
- } else if (pos_start.lnum == lnum && pos_end.lnum == lnum) {
- hl_start = pos_start.col + offset + 1;
- hl_end = pos_end.col + offset;
- }
- (void)bufhl_add_hl(buf, src_id, hl_id, lnum, hl_start, hl_end);
- }
-}
-
-int bufhl_add_virt_text(buf_T *buf,
- int src_id,
- linenr_T lnum,
- VirtText virt_text)
-{
- if (src_id == 0) {
- src_id = (int)nvim_create_namespace((String)STRING_INIT);
- }
-
- BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, true);
-
- bufhl_clear_virttext(&lineinfo->virt_text);
- if (kv_size(virt_text) > 0) {
- lineinfo->virt_text_src = src_id;
- lineinfo->virt_text = virt_text;
- } else {
- lineinfo->virt_text_src = 0;
- // currently not needed, but allow a future caller with
- // 0 size and non-zero capacity
- kv_destroy(virt_text);
- }
-
- if (0 < lnum && lnum <= buf->b_ml.ml_line_count) {
- redraw_buf_line_later(buf, lnum);
- }
- return src_id;
-}
-
-static void bufhl_clear_virttext(VirtText *text)
-{
- for (size_t i = 0; i < kv_size(*text); i++) {
- xfree(kv_A(*text, i).text);
- }
- kv_destroy(*text);
- *text = (VirtText)KV_INITIAL_VALUE;
-}
-
-/// Clear bufhl highlights from a given source group and range of lines.
-///
-/// @param buf The buffer to remove highlights from
-/// @param src_id highlight source group to clear, or -1 to clear all groups.
-/// @param line_start first line to clear
-/// @param line_end last line to clear or MAXLNUM to clear to end of file.
-void bufhl_clear_line_range(buf_T *buf,
- int src_id,
- linenr_T line_start,
- linenr_T line_end)
-{
- kbitr_t(bufhl) itr;
- BufhlLine *l, t = BUFHLLINE_INIT(line_start);
- if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
- kb_itr_next(bufhl, &buf->b_bufhl_info, &itr);
- }
- for (; kb_itr_valid(&itr); kb_itr_next(bufhl, &buf->b_bufhl_info, &itr)) {
- l = kb_itr_key(&itr);
- linenr_T line = l->line;
- if (line > line_end) {
- break;
- }
- if (line_start <= line) {
- BufhlLineStatus status = bufhl_clear_line(l, src_id, line);
- if (status != kBLSUnchanged) {
- redraw_buf_line_later(buf, line);
- }
- if (status == kBLSDeleted) {
- kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
- xfree(l);
- }
- }
- }
-}
-
-/// Clear bufhl highlights from a given source group and given line
-///
-/// @param bufhl_info The highlight info for the buffer
-/// @param src_id Highlight source group to clear, or -1 to clear all groups.
-/// @param lnum Linenr where the highlight should be cleared
-static BufhlLineStatus bufhl_clear_line(BufhlLine *lineinfo, int src_id,
- linenr_T lnum)
-{
- BufhlLineStatus changed = kBLSUnchanged;
- size_t oldsize = kv_size(lineinfo->items);
- if (src_id < 0) {
- kv_size(lineinfo->items) = 0;
- } else {
- size_t newidx = 0;
- for (size_t i = 0; i < kv_size(lineinfo->items); i++) {
- if (kv_A(lineinfo->items, i).src_id != src_id) {
- if (i != newidx) {
- kv_A(lineinfo->items, newidx) = kv_A(lineinfo->items, i);
- }
- newidx++;
- }
- }
- kv_size(lineinfo->items) = newidx;
- }
- if (kv_size(lineinfo->items) != oldsize) {
- changed = kBLSChanged;
- }
-
- if (kv_size(lineinfo->virt_text) != 0
- && (src_id < 0 || src_id == lineinfo->virt_text_src)) {
- bufhl_clear_virttext(&lineinfo->virt_text);
- lineinfo->virt_text_src = 0;
- changed = kBLSChanged;
- }
-
- if (kv_size(lineinfo->items) == 0 && kv_size(lineinfo->virt_text) == 0) {
- kv_destroy(lineinfo->items);
- return kBLSDeleted;
- }
- return changed;
-}
-
-
-/// Remove all highlights and free the highlight data
-void bufhl_clear_all(buf_T *buf)
-{
- bufhl_clear_line_range(buf, -1, 1, MAXLNUM);
- kb_destroy(bufhl, (&buf->b_bufhl_info));
- kb_init(&buf->b_bufhl_info);
- kv_destroy(buf->b_bufhl_move_space);
- kv_init(buf->b_bufhl_move_space);
-}
-
-/// Adjust a placed highlight for inserted/deleted lines.
-void bufhl_mark_adjust(buf_T* buf,
- linenr_T line1,
- linenr_T line2,
- long amount,
- long amount_after,
- bool end_temp)
-{
- kbitr_t(bufhl) itr;
- BufhlLine *l, t = BUFHLLINE_INIT(line1);
- if (end_temp && amount < 0) {
- // Move all items from b_bufhl_move_space to the btree.
- for (size_t i = 0; i < kv_size(buf->b_bufhl_move_space); i++) {
- l = kv_A(buf->b_bufhl_move_space, i);
- l->line += amount;
- kb_put(bufhl, &buf->b_bufhl_info, l);
- }
- kv_size(buf->b_bufhl_move_space) = 0;
- return;
- }
-
- if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
- kb_itr_next(bufhl, &buf->b_bufhl_info, &itr);
- }
- for (; kb_itr_valid(&itr); kb_itr_next(bufhl, &buf->b_bufhl_info, &itr)) {
- l = kb_itr_key(&itr);
- if (l->line >= line1 && l->line <= line2) {
- if (end_temp && amount > 0) {
- kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
- kv_push(buf->b_bufhl_move_space, l);
- }
- if (amount == MAXLNUM) {
- if (bufhl_clear_line(l, -1, l->line) == kBLSDeleted) {
- kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
- xfree(l);
- } else {
- assert(false);
- }
- } else {
- l->line += amount;
- }
- } else if (l->line > line2) {
- if (amount_after == 0) {
- break;
- }
- l->line += amount_after;
- }
- }
-}
-
-
-/// Get highlights to display at a specific line
-///
-/// @param buf The buffer handle
-/// @param lnum The line number
-/// @param[out] info The highligts for the line
-/// @return true if there was highlights to display
-bool bufhl_start_line(buf_T *buf, linenr_T lnum, BufhlLineInfo *info)
-{
- BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, false);
- if (!lineinfo) {
- return false;
- }
- info->valid_to = -1;
- info->line = lineinfo;
- return true;
-}
-
-/// get highlighting at column col
-///
-/// It is is assumed this will be called with
-/// non-decreasing column nrs, so that it is
-/// possible to only recalculate highlights
-/// at endpoints.
-///
-/// @param info The info returned by bufhl_start_line
-/// @param col The column to get the attr for
-/// @return The highilight attr to display at the column
-int bufhl_get_attr(BufhlLineInfo *info, colnr_T col)
-{
- if (col <= info->valid_to) {
- return info->current;
- }
- int attr = 0;
- info->valid_to = MAXCOL;
- for (size_t i = 0; i < kv_size(info->line->items); i++) {
- BufhlItem entry = kv_A(info->line->items, i);
- if (entry.start <= col && col <= entry.stop) {
- int entry_attr = syn_id2attr(entry.hl_id);
- attr = hl_combine_attr(attr, entry_attr);
- if (entry.stop < info->valid_to) {
- info->valid_to = entry.stop;
- }
- } else if (col < entry.start && entry.start-1 < info->valid_to) {
- info->valid_to = entry.start-1;
- }
- }
- info->current = attr;
- return attr;
-}
-
-
/*
* Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
*/