aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/statusline.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /src/nvim/statusline.c
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'src/nvim/statusline.c')
-rw-r--r--src/nvim/statusline.c900
1 files changed, 634 insertions, 266 deletions
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index e868a79b9a..6ad1f31143 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -5,22 +5,43 @@
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include "nvim/assert.h"
-#include "nvim/autocmd.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
+#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/move.h"
+#include "nvim/normal.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
+#include "nvim/os/os.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
+#include "nvim/screen.h"
+#include "nvim/sign_defs.h"
#include "nvim/statusline.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
@@ -43,11 +64,10 @@ void win_redr_status(win_T *wp)
{
int row;
int col;
- char_u *p;
+ char *p;
int len;
int fillchar;
int attr;
- int width;
int this_ru_col;
bool is_stl_global = global_stl_height() > 0;
static bool busy = false;
@@ -74,53 +94,54 @@ void win_redr_status(win_T *wp)
redraw_custom_statusline(wp);
} else {
fillchar = fillchar_status(&attr, wp);
- width = is_stl_global ? Columns : wp->w_width;
+ const int stl_width = is_stl_global ? Columns : wp->w_width;
get_trans_bufname(wp->w_buffer);
p = NameBuff;
- len = (int)STRLEN(p);
+ len = (int)strlen(p);
- if (bt_help(wp->w_buffer)
- || wp->w_p_pvw
- || bufIsChanged(wp->w_buffer)
- || wp->w_buffer->b_p_ro) {
+ if ((bt_help(wp->w_buffer)
+ || wp->w_p_pvw
+ || bufIsChanged(wp->w_buffer)
+ || wp->w_buffer->b_p_ro)
+ && len < MAXPATHL - 1) {
*(p + len++) = ' ';
}
if (bt_help(wp->w_buffer)) {
- snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[Help]"));
- len += (int)STRLEN(p + len);
+ snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[Help]"));
+ len += (int)strlen(p + len);
}
if (wp->w_p_pvw) {
- snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[Preview]"));
- len += (int)STRLEN(p + len);
+ snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[Preview]"));
+ len += (int)strlen(p + len);
}
if (bufIsChanged(wp->w_buffer)) {
- snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", "[+]");
- len += (int)STRLEN(p + len);
+ snprintf(p + len, MAXPATHL - (size_t)len, "%s", "[+]");
+ len += (int)strlen(p + len);
}
if (wp->w_buffer->b_p_ro) {
- snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[RO]"));
- // len += (int)STRLEN(p + len); // dead assignment
+ snprintf(p + len, MAXPATHL - (size_t)len, "%s", _("[RO]"));
+ // len += (int)strlen(p + len); // dead assignment
}
- this_ru_col = ru_col - (Columns - width);
- if (this_ru_col < (width + 1) / 2) {
- this_ru_col = (width + 1) / 2;
+ this_ru_col = ru_col - (Columns - stl_width);
+ if (this_ru_col < (stl_width + 1) / 2) {
+ this_ru_col = (stl_width + 1) / 2;
}
if (this_ru_col <= 1) {
- p = (char_u *)"<"; // No room for file name!
+ p = "<"; // No room for file name!
len = 1;
} else {
int clen = 0, i;
// Count total number of display cells.
- clen = (int)mb_string2cells((char *)p);
+ clen = (int)mb_string2cells(p);
// Find first character that will fit.
// Going from start to end is much faster for DBCS.
for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
- i += utfc_ptr2len((char *)p + i)) {
- clen -= utf_ptr2cells((char *)p + i);
+ i += utfc_ptr2len(p + i)) {
+ clen -= utf_ptr2cells(p + i);
}
len = clen;
if (i > 0) {
@@ -136,13 +157,23 @@ void win_redr_status(win_T *wp)
grid_fill(&default_grid, row, row + 1, len + col,
this_ru_col + col, fillchar, fillchar, attr);
- if (get_keymap_str(wp, "<%s>", (char *)NameBuff, MAXPATHL)
- && this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
+ if (get_keymap_str(wp, "<%s>", NameBuff, MAXPATHL)
+ && this_ru_col - len > (int)(strlen(NameBuff) + 1)) {
grid_puts(&default_grid, NameBuff, row,
- (int)((size_t)this_ru_col - STRLEN(NameBuff) - 1), attr);
+ (int)((size_t)this_ru_col - strlen(NameBuff) - 1), attr);
}
win_redr_ruler(wp, true);
+
+ // Draw the 'showcmd' information if 'showcmdloc' == "statusline".
+ if (p_sc && *p_sloc == 's') {
+ const int sc_width = MIN(10, this_ru_col - len - 2);
+
+ if (sc_width > 0) {
+ grid_puts_len(&default_grid, showcmd_buf, sc_width, row,
+ wp->w_wincol + this_ru_col - sc_width - 1, attr);
+ }
+ }
}
// May need to draw the character below the vertical separator.
@@ -157,6 +188,252 @@ void win_redr_status(win_T *wp)
busy = false;
}
+/// Clear status line, window bar or tab page line click definition table
+///
+/// @param[out] tpcd Table to clear.
+/// @param[in] tpcd_size Size of the table.
+void stl_clear_click_defs(StlClickDefinition *const click_defs, const size_t click_defs_size)
+{
+ if (click_defs != NULL) {
+ for (size_t i = 0; i < click_defs_size; i++) {
+ if (i == 0 || click_defs[i].func != click_defs[i - 1].func) {
+ xfree(click_defs[i].func);
+ }
+ }
+ memset(click_defs, 0, click_defs_size * sizeof(click_defs[0]));
+ }
+}
+
+/// Allocate or resize the click definitions array if needed.
+StlClickDefinition *stl_alloc_click_defs(StlClickDefinition *cdp, long width, size_t *size)
+{
+ if (*size < (size_t)width) {
+ xfree(cdp);
+ *size = (size_t)width;
+ cdp = xcalloc(*size, sizeof(StlClickDefinition));
+ }
+ return cdp;
+}
+
+/// Fill the click definitions array if needed.
+void stl_fill_click_defs(StlClickDefinition *click_defs, StlClickRecord *click_recs, char *buf,
+ int width, bool tabline)
+{
+ if (click_defs == NULL) {
+ return;
+ }
+
+ int col = 0;
+ int len = 0;
+
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
+ for (int i = 0; click_recs[i].start != NULL; i++) {
+ len += vim_strnsize(buf, (int)(click_recs[i].start - buf));
+ if (col < len) {
+ while (col < len) {
+ click_defs[col++] = cur_click_def;
+ }
+ } else {
+ xfree(cur_click_def.func);
+ }
+ buf = (char *)click_recs[i].start;
+ cur_click_def = click_recs[i].def;
+ if (!tabline && !(cur_click_def.type == kStlClickDisabled
+ || cur_click_def.type == kStlClickFuncRun)) {
+ // window bar and status line only support click functions
+ cur_click_def.type = kStlClickDisabled;
+ }
+ }
+ if (col < width) {
+ while (col < width) {
+ click_defs[col++] = cur_click_def;
+ }
+ } else {
+ xfree(cur_click_def.func);
+ }
+}
+
+/// Redraw the status line, window bar or ruler of window "wp".
+/// When "wp" is NULL redraw the tab pages line from 'tabline'.
+static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
+{
+ static bool entered = false;
+ int attr;
+ int curattr;
+ int row;
+ int col = 0;
+ int maxwidth;
+ int width;
+ int n;
+ int len;
+ int fillchar;
+ char buf[MAXPATHL];
+ char *stl;
+ char *p;
+ char *opt_name;
+ int opt_scope = 0;
+ stl_hlrec_t *hltab;
+ StlClickRecord *tabtab;
+ win_T *ewp;
+ int p_crb_save;
+ bool is_stl_global = global_stl_height() > 0;
+
+ ScreenGrid *grid = &default_grid;
+
+ // There is a tiny chance that this gets called recursively: When
+ // redrawing a status line triggers redrawing the ruler or tabline.
+ // Avoid trouble by not allowing recursion.
+ if (entered) {
+ return;
+ }
+ entered = true;
+
+ // setup environment for the task at hand
+ if (wp == NULL) {
+ // Use 'tabline'. Always at the first line of the screen.
+ stl = p_tal;
+ row = 0;
+ fillchar = ' ';
+ attr = HL_ATTR(HLF_TPF);
+ maxwidth = Columns;
+ opt_name = "tabline";
+ } else if (draw_winbar) {
+ opt_name = "winbar";
+ stl = ((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
+ opt_scope = ((*wp->w_p_wbr != NUL) ? OPT_LOCAL : 0);
+ row = -1; // row zero is first row of text
+ col = 0;
+ grid = &wp->w_grid;
+ grid_adjust(&grid, &row, &col);
+
+ if (row < 0) {
+ return;
+ }
+
+ fillchar = wp->w_p_fcs_chars.wbr;
+ attr = (wp == curwin) ? win_hl_attr(wp, HLF_WBR) : win_hl_attr(wp, HLF_WBRNC);
+ maxwidth = wp->w_width_inner;
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ wp->w_winbar_click_defs = stl_alloc_click_defs(wp->w_winbar_click_defs, maxwidth,
+ &wp->w_winbar_click_defs_size);
+ } else {
+ row = is_stl_global ? (Rows - (int)p_ch - 1) : W_ENDROW(wp);
+ fillchar = fillchar_status(&attr, wp);
+ maxwidth = is_stl_global ? Columns : wp->w_width;
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ wp->w_status_click_defs = stl_alloc_click_defs(wp->w_status_click_defs, maxwidth,
+ &wp->w_status_click_defs_size);
+
+ if (draw_ruler) {
+ stl = p_ruf;
+ opt_name = "rulerformat";
+ // advance past any leading group spec - implicit in ru_col
+ if (*stl == '%') {
+ if (*++stl == '-') {
+ stl++;
+ }
+ if (atoi(stl)) {
+ while (ascii_isdigit(*stl)) {
+ stl++;
+ }
+ }
+ if (*stl++ != '(') {
+ stl = p_ruf;
+ }
+ }
+ col = ru_col - (Columns - maxwidth);
+ if (col < (maxwidth + 1) / 2) {
+ col = (maxwidth + 1) / 2;
+ }
+ maxwidth = maxwidth - col;
+ if (!wp->w_status_height && !is_stl_global) {
+ grid = &msg_grid_adj;
+ row = Rows - 1;
+ maxwidth--; // writing in last column may cause scrolling
+ fillchar = ' ';
+ attr = HL_ATTR(HLF_MSG);
+ }
+ } else {
+ opt_name = "statusline";
+ stl = ((*wp->w_p_stl != NUL) ? wp->w_p_stl : p_stl);
+ opt_scope = ((*wp->w_p_stl != NUL) ? OPT_LOCAL : 0);
+ }
+
+ col += is_stl_global ? 0 : wp->w_wincol;
+ }
+
+ if (maxwidth <= 0) {
+ goto theend;
+ }
+
+ // Temporarily reset 'cursorbind', we don't want a side effect from moving
+ // the cursor away and back.
+ ewp = wp == NULL ? curwin : wp;
+ p_crb_save = ewp->w_p_crb;
+ ewp->w_p_crb = false;
+
+ // Make a copy, because the statusline may include a function call that
+ // might change the option value and free the memory.
+ stl = xstrdup(stl);
+ width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name, opt_scope,
+ fillchar, maxwidth, &hltab, &tabtab, NULL);
+
+ xfree(stl);
+ ewp->w_p_crb = p_crb_save;
+
+ // Make all characters printable.
+ p = transstr(buf, true);
+ len = (int)xstrlcpy(buf, p, sizeof(buf));
+ len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
+ xfree(p);
+
+ // fill up with "fillchar"
+ while (width < maxwidth && len < (int)sizeof(buf) - 1) {
+ len += utf_char2bytes(fillchar, buf + len);
+ width++;
+ }
+ buf[len] = NUL;
+
+ // Draw each snippet with the specified highlighting.
+ grid_puts_line_start(grid, row);
+
+ curattr = attr;
+ p = buf;
+ for (n = 0; hltab[n].start != NULL; n++) {
+ int textlen = (int)(hltab[n].start - p);
+ grid_puts_len(grid, p, textlen, row, col, curattr);
+ col += vim_strnsize(p, textlen);
+ p = hltab[n].start;
+
+ if (hltab[n].userhl == 0) {
+ curattr = attr;
+ } else if (hltab[n].userhl < 0) {
+ curattr = syn_id2attr(-hltab[n].userhl);
+ } else if (wp != NULL && wp != curwin && wp->w_status_height != 0) {
+ curattr = highlight_stlnc[hltab[n].userhl - 1];
+ } else {
+ curattr = highlight_user[hltab[n].userhl - 1];
+ }
+ }
+ // Make sure to use an empty string instead of p, if p is beyond buf + len.
+ grid_puts(grid, p >= buf + len ? "" : p, row, col, curattr);
+
+ grid_puts_line_flush(false);
+
+ // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
+ // in the tab page line, status line or window bar
+ StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
+ : draw_winbar ? wp->w_winbar_click_defs
+ : wp->w_status_click_defs;
+
+ stl_fill_click_defs(click_defs, tabtab, buf, maxwidth, wp == NULL);
+
+theend:
+ entered = false;
+}
+
void win_redr_winbar(win_T *wp)
{
static bool entered = false;
@@ -171,19 +448,7 @@ void win_redr_winbar(win_T *wp)
if (wp->w_winbar_height == 0 || !redrawing()) {
// Do nothing.
} else if (*p_wbr != NUL || *wp->w_p_wbr != NUL) {
- int saved_did_emsg = did_emsg;
-
- did_emsg = false;
win_redr_custom(wp, true, false);
- if (did_emsg) {
- // When there is an error disable the winbar, otherwise the
- // display is messed up with errors and a redraw triggers the problem
- // again and again.
- set_string_option_direct("winbar", -1, "",
- OPT_FREE | (*wp->w_p_stl != NUL
- ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
- }
- did_emsg |= saved_did_emsg;
}
entered = false;
}
@@ -213,11 +478,7 @@ void win_redr_ruler(win_T *wp, bool always)
}
if (*p_ruf && p_ch > 0 && !ui_has(kUIMessages)) {
- const int called_emsg_before = called_emsg;
win_redr_custom(wp, false, true);
- if (called_emsg > called_emsg_before) {
- set_string_option_direct("rulerformat", -1, "", OPT_FREE, SID_ERROR);
- }
return;
}
@@ -266,7 +527,7 @@ void win_redr_ruler(win_T *wp, bool always)
off = 0;
}
- if (!part_of_status && !ui_has_messages()) {
+ if (!part_of_status && p_ch == 0 && !ui_has(kUIMessages)) {
return;
}
@@ -286,7 +547,7 @@ void win_redr_ruler(win_T *wp, bool always)
vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",",
(wp->w_buffer->b_ml.ml_flags &
ML_EMPTY) ? (int64_t)0L : (int64_t)wp->w_cursor.lnum);
- size_t len = STRLEN(buffer);
+ size_t len = strlen(buffer);
col_print(buffer + len, RULER_BUF_LEN - len,
empty_line ? 0 : (int)wp->w_cursor.col + 1,
(int)virtcol + 1);
@@ -294,7 +555,7 @@ void win_redr_ruler(win_T *wp, bool always)
// Add a "50%" if there is room for it.
// On the last line, don't print in the last column (scrolls the
// screen up on some terminals).
- int i = (int)STRLEN(buffer);
+ int i = (int)strlen(buffer);
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
int o = i + vim_strsize(buffer + i + 1);
if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
@@ -342,9 +603,9 @@ void win_redr_ruler(win_T *wp, bool always)
}
ScreenGrid *grid = part_of_status ? &default_grid : &msg_grid_adj;
- grid_puts(grid, (char_u *)buffer, row, this_ru_col + off, attr);
+ grid_puts(grid, buffer, row, this_ru_col + off, attr);
grid_fill(grid, row, row + 1,
- this_ru_col + off + (int)STRLEN(buffer), off + width, fillchar,
+ this_ru_col + off + (int)strlen(buffer), off + width, fillchar,
fillchar, attr);
}
@@ -388,7 +649,6 @@ int fillchar_status(int *attr, win_T *wp)
void redraw_custom_statusline(win_T *wp)
{
static bool entered = false;
- int saved_did_emsg = did_emsg;
// When called recursively return. This can happen when the statusline
// contains an expression that triggers a redraw.
@@ -397,235 +657,262 @@ void redraw_custom_statusline(win_T *wp)
}
entered = true;
- did_emsg = false;
win_redr_custom(wp, false, false);
- if (did_emsg) {
- // When there is an error disable the statusline, otherwise the
- // display is messed up with errors and a redraw triggers the problem
- // again and again.
- set_string_option_direct("statusline", -1, "",
- OPT_FREE | (*wp->w_p_stl != NUL
- ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
- }
- did_emsg |= saved_did_emsg;
entered = false;
}
-/// Redraw the status line, window bar or ruler of window "wp".
-/// When "wp" is NULL redraw the tab pages line from 'tabline'.
-void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
+static void ui_ext_tabline_update(void)
{
- static bool entered = false;
- int attr;
- int curattr;
- int row;
+ Arena arena = ARENA_EMPTY;
+
+ size_t n_tabs = 0;
+ FOR_ALL_TABS(tp) {
+ n_tabs++;
+ }
+
+ Array tabs = arena_array(&arena, n_tabs);
+ FOR_ALL_TABS(tp) {
+ Dictionary tab_info = arena_dict(&arena, 2);
+ PUT_C(tab_info, "tab", TABPAGE_OBJ(tp->handle));
+
+ win_T *cwp = (tp == curtab) ? curwin : tp->tp_curwin;
+ get_trans_bufname(cwp->w_buffer);
+ PUT_C(tab_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string(NameBuff))));
+
+ ADD_C(tabs, DICTIONARY_OBJ(tab_info));
+ }
+
+ size_t n_buffers = 0;
+ FOR_ALL_BUFFERS(buf) {
+ n_buffers += buf->b_p_bl ? 1 : 0;
+ }
+
+ Array buffers = arena_array(&arena, n_buffers);
+ FOR_ALL_BUFFERS(buf) {
+ // Do not include unlisted buffers
+ if (!buf->b_p_bl) {
+ continue;
+ }
+
+ Dictionary buffer_info = arena_dict(&arena, 2);
+ PUT_C(buffer_info, "buffer", BUFFER_OBJ(buf->handle));
+
+ get_trans_bufname(buf);
+ PUT_C(buffer_info, "name", STRING_OBJ(arena_string(&arena, cstr_as_string(NameBuff))));
+
+ ADD_C(buffers, DICTIONARY_OBJ(buffer_info));
+ }
+
+ ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers);
+ arena_mem_free(arena_finish(&arena));
+}
+
+/// Draw the tab pages line at the top of the Vim window.
+void draw_tabline(void)
+{
+ int tabcount = 0;
+ int tabwidth = 0;
int col = 0;
- int maxwidth;
- int width;
- int n;
+ int scol = 0;
+ int attr;
+ win_T *wp;
+ win_T *cwp;
+ int wincount;
+ int modified;
+ int c;
int len;
- int fillchar;
- char buf[MAXPATHL];
- char_u *stl;
+ int attr_nosel = HL_ATTR(HLF_TP);
+ int attr_fill = HL_ATTR(HLF_TPF);
char *p;
- stl_hlrec_t *hltab;
- StlClickRecord *tabtab;
- int use_sandbox = false;
- win_T *ewp;
- int p_crb_save;
- bool is_stl_global = global_stl_height() > 0;
+ int room;
+ int use_sep_chars = (t_colors < 8);
- ScreenGrid *grid = &default_grid;
+ if (default_grid.chars == NULL) {
+ return;
+ }
+ redraw_tabline = false;
- // There is a tiny chance that this gets called recursively: When
- // redrawing a status line triggers redrawing the ruler or tabline.
- // Avoid trouble by not allowing recursion.
- if (entered) {
+ if (ui_has(kUITabline)) {
+ ui_ext_tabline_update();
return;
}
- entered = true;
- // setup environment for the task at hand
- if (wp == NULL) {
- // Use 'tabline'. Always at the first line of the screen.
- stl = p_tal;
- row = 0;
- fillchar = ' ';
- attr = HL_ATTR(HLF_TPF);
- maxwidth = Columns;
- use_sandbox = was_set_insecurely(wp, "tabline", 0);
- } else if (draw_winbar) {
- stl = (char_u *)((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
- row = -1; // row zero is first row of text
- col = 0;
- grid = &wp->w_grid;
- grid_adjust(&grid, &row, &col);
+ if (tabline_height() < 1) {
+ return;
+ }
- if (row < 0) {
- return;
- }
+ // Clear tab_page_click_defs: Clicking outside of tabs has no effect.
+ assert(tab_page_click_defs_size >= (size_t)Columns);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
- fillchar = wp->w_p_fcs_chars.wbr;
- attr = (wp == curwin) ? win_hl_attr(wp, HLF_WBR) : win_hl_attr(wp, HLF_WBRNC);
- maxwidth = wp->w_width_inner;
- use_sandbox = was_set_insecurely(wp, "winbar", 0);
+ // Use the 'tabline' option if it's set.
+ if (*p_tal != NUL) {
+ win_redr_custom(NULL, false, false);
+ } else {
+ FOR_ALL_TABS(tp) {
+ tabcount++;
+ }
- stl_clear_click_defs(wp->w_winbar_click_defs, (long)wp->w_winbar_click_defs_size);
- // Allocate / resize the click definitions array for winbar if needed.
- if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
- xfree(wp->w_winbar_click_defs);
- wp->w_winbar_click_defs_size = (size_t)maxwidth;
- wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
+ if (tabcount > 0) {
+ tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
}
- } else {
- row = is_stl_global ? (Rows - (int)p_ch - 1) : W_ENDROW(wp);
- fillchar = fillchar_status(&attr, wp);
- maxwidth = is_stl_global ? Columns : wp->w_width;
- stl_clear_click_defs(wp->w_status_click_defs, (long)wp->w_status_click_defs_size);
- // Allocate / resize the click definitions array for statusline if needed.
- if (wp->w_status_click_defs_size < (size_t)maxwidth) {
- xfree(wp->w_status_click_defs);
- wp->w_status_click_defs_size = (size_t)maxwidth;
- wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
+ if (tabwidth < 6) {
+ tabwidth = 6;
}
- if (draw_ruler) {
- stl = p_ruf;
- // advance past any leading group spec - implicit in ru_col
- if (*stl == '%') {
- if (*++stl == '-') {
- stl++;
- }
- if (atoi((char *)stl)) {
- while (ascii_isdigit(*stl)) {
- stl++;
- }
- }
- if (*stl++ != '(') {
- stl = p_ruf;
- }
- }
- col = ru_col - (Columns - maxwidth);
- if (col < (maxwidth + 1) / 2) {
- col = (maxwidth + 1) / 2;
- }
- maxwidth = maxwidth - col;
- if (!wp->w_status_height && !is_stl_global) {
- grid = &msg_grid_adj;
- row = Rows - 1;
- maxwidth--; // writing in last column may cause scrolling
- fillchar = ' ';
- attr = HL_ATTR(HLF_MSG);
+ attr = attr_nosel;
+ tabcount = 0;
+
+ FOR_ALL_TABS(tp) {
+ if (col >= Columns - 4) {
+ break;
}
- use_sandbox = was_set_insecurely(wp, "rulerformat", 0);
- } else {
- if (*wp->w_p_stl != NUL) {
- stl = wp->w_p_stl;
+ scol = col;
+
+ if (tp == curtab) {
+ cwp = curwin;
+ wp = firstwin;
} else {
- stl = p_stl;
+ cwp = tp->tp_curwin;
+ wp = tp->tp_firstwin;
}
- use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
- }
- col += is_stl_global ? 0 : wp->w_wincol;
- }
+ if (tp->tp_topframe == topframe) {
+ attr = win_hl_attr(cwp, HLF_TPS);
+ }
+ if (use_sep_chars && col > 0) {
+ grid_putchar(&default_grid, '|', 0, col++, attr);
+ }
- if (maxwidth <= 0) {
- goto theend;
- }
+ if (tp->tp_topframe != topframe) {
+ attr = win_hl_attr(cwp, HLF_TP);
+ }
- // Temporarily reset 'cursorbind', we don't want a side effect from moving
- // the cursor away and back.
- ewp = wp == NULL ? curwin : wp;
- p_crb_save = ewp->w_p_crb;
- ewp->w_p_crb = false;
+ grid_putchar(&default_grid, ' ', 0, col++, attr);
- // Make a copy, because the statusline may include a function call that
- // might change the option value and free the memory.
- stl = vim_strsave(stl);
- width =
- build_stl_str_hl(ewp, buf, sizeof(buf), (char *)stl, use_sandbox,
- fillchar, maxwidth, &hltab, &tabtab);
- xfree(stl);
- ewp->w_p_crb = p_crb_save;
+ modified = false;
- // Make all characters printable.
- p = transstr(buf, true);
- len = (int)STRLCPY(buf, p, sizeof(buf));
- len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
- xfree(p);
+ for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) {
+ if (bufIsChanged(wp->w_buffer)) {
+ modified = true;
+ }
+ }
- // fill up with "fillchar"
- while (width < maxwidth && len < (int)sizeof(buf) - 1) {
- len += utf_char2bytes(fillchar, buf + len);
- width++;
- }
- buf[len] = NUL;
+ if (modified || wincount > 1) {
+ if (wincount > 1) {
+ vim_snprintf(NameBuff, MAXPATHL, "%d", wincount);
+ len = (int)strlen(NameBuff);
+ if (col + len >= Columns - 3) {
+ break;
+ }
+ grid_puts_len(&default_grid, NameBuff, len, 0, col,
+ hl_combine_attr(attr, win_hl_attr(cwp, HLF_T)));
+ col += len;
+ }
+ if (modified) {
+ grid_puts_len(&default_grid, "+", 1, 0, col++, attr);
+ }
+ grid_putchar(&default_grid, ' ', 0, col++, attr);
+ }
- // Draw each snippet with the specified highlighting.
- grid_puts_line_start(grid, row);
+ room = scol - col + tabwidth - 1;
+ if (room > 0) {
+ // Get buffer name in NameBuff[]
+ get_trans_bufname(cwp->w_buffer);
+ shorten_dir(NameBuff);
+ len = vim_strsize(NameBuff);
+ p = NameBuff;
+ while (len > room) {
+ len -= ptr2cells(p);
+ MB_PTR_ADV(p);
+ }
+ if (len > Columns - col - 1) {
+ len = Columns - col - 1;
+ }
- curattr = attr;
- p = buf;
- for (n = 0; hltab[n].start != NULL; n++) {
- int textlen = (int)(hltab[n].start - p);
- grid_puts_len(grid, (char_u *)p, textlen, row, col, curattr);
- col += vim_strnsize((char_u *)p, textlen);
- p = hltab[n].start;
+ grid_puts_len(&default_grid, p, (int)strlen(p), 0, col, attr);
+ col += len;
+ }
+ grid_putchar(&default_grid, ' ', 0, col++, attr);
+
+ // Store the tab page number in tab_page_click_defs[], so that
+ // jump_to_mouse() knows where each one is.
+ tabcount++;
+ while (scol < col) {
+ tab_page_click_defs[scol++] = (StlClickDefinition) {
+ .type = kStlClickTabSwitch,
+ .tabnr = tabcount,
+ .func = NULL,
+ };
+ }
+ }
- if (hltab[n].userhl == 0) {
- curattr = attr;
- } else if (hltab[n].userhl < 0) {
- curattr = syn_id2attr(-hltab[n].userhl);
- } else if (wp != NULL && wp != curwin && wp->w_status_height != 0) {
- curattr = highlight_stlnc[hltab[n].userhl - 1];
+ if (use_sep_chars) {
+ c = '_';
} else {
- curattr = highlight_user[hltab[n].userhl - 1];
+ c = ' ';
}
- }
- // Make sure to use an empty string instead of p, if p is beyond buf + len.
- grid_puts(grid, p >= buf + len ? (char_u *)"" : (char_u *)p, row, col,
- curattr);
+ grid_fill(&default_grid, 0, 1, col, Columns, c, c, attr_fill);
- grid_puts_line_flush(false);
+ // Draw the 'showcmd' information if 'showcmdloc' == "tabline".
+ if (p_sc && *p_sloc == 't') {
+ const int sc_width = MIN(10, (int)Columns - col - (tabcount > 1) * 3);
- // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
- // in the tab page line, status line or window bar
- StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
- : draw_winbar ? wp->w_winbar_click_defs
- : wp->w_status_click_defs;
+ if (sc_width > 0) {
+ grid_puts_len(&default_grid, showcmd_buf, sc_width, 0,
+ Columns - sc_width - (tabcount > 1) * 2, attr_nosel);
+ }
+ }
- if (click_defs == NULL) {
- goto theend;
+ // Put an "X" for closing the current tab if there are several.
+ if (tabcount > 1) {
+ grid_putchar(&default_grid, 'X', 0, Columns - 1, attr_nosel);
+ tab_page_click_defs[Columns - 1] = (StlClickDefinition) {
+ .type = kStlClickTabClose,
+ .tabnr = 999,
+ .func = NULL,
+ };
+ }
}
- col = 0;
- len = 0;
- p = buf;
- StlClickDefinition cur_click_def = {
- .type = kStlClickDisabled,
- };
- for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize((char_u *)p, (int)(tabtab[n].start - p));
- while (col < len) {
- click_defs[col++] = cur_click_def;
- }
- p = (char *)tabtab[n].start;
- cur_click_def = tabtab[n].def;
- if ((wp != NULL) && !(cur_click_def.type == kStlClickDisabled
- || cur_click_def.type == kStlClickFuncRun)) {
- // window bar and status line only support click functions
- cur_click_def.type = kStlClickDisabled;
- }
+ // Reset the flag here again, in case evaluating 'tabline' causes it to be
+ // set.
+ redraw_tabline = false;
+}
+
+/// Build the 'statuscolumn' string for line "lnum". When "relnum" == -1,
+/// the v:lnum and v:relnum variables don't have to be updated.
+///
+/// @param hlrec HL attributes (can be NULL)
+/// @param stcp Status column attributes (can be NULL)
+/// @return The width of the built status column string for line "lnum"
+int build_statuscol_str(win_T *wp, linenr_T lnum, long relnum, int maxwidth, int fillchar,
+ char *buf, stl_hlrec_t **hlrec, statuscol_T *stcp)
+{
+ bool fillclick = relnum >= 0 && lnum == wp->w_topline;
+
+ if (relnum >= 0) {
+ set_vim_var_nr(VV_LNUM, lnum);
+ set_vim_var_nr(VV_RELNUM, relnum);
}
- while (col < maxwidth) {
- click_defs[col++] = cur_click_def;
+
+ StlClickRecord *clickrec;
+ char *stc = xstrdup(wp->w_p_stc);
+ int width = build_stl_str_hl(wp, buf, MAXPATHL, stc, "statuscolumn", OPT_LOCAL, fillchar,
+ maxwidth, hlrec, fillclick ? &clickrec : NULL, stcp);
+ xfree(stc);
+
+ // Only update click definitions once per window per redraw
+ if (fillclick) {
+ stl_clear_click_defs(wp->w_statuscol_click_defs, wp->w_statuscol_click_defs_size);
+ wp->w_statuscol_click_defs = stl_alloc_click_defs(wp->w_statuscol_click_defs, width,
+ &wp->w_statuscol_click_defs_size);
+ stl_fill_click_defs(wp->w_statuscol_click_defs, clickrec, buf, width, false);
}
-theend:
- entered = false;
+ return width;
}
/// Build a string from the status line items in "fmt".
@@ -646,15 +933,18 @@ theend:
/// Note: This should not be NameBuff
/// @param outlen The length of the output buffer
/// @param fmt The statusline format string
-/// @param use_sandbox Use a sandboxed environment when evaluating fmt
+/// @param opt_name The option name corresponding to "fmt"
+/// @param opt_scope The scope corresponding to "opt_name"
/// @param fillchar Character to use when filling empty space in the statusline
/// @param maxwidth The maximum width to make the statusline
/// @param hltab HL attributes (can be NULL)
-/// @param tabtab Tab clicks definition (can be NULL).
+/// @param tabtab Tab clicks definition (can be NULL)
+/// @param stcp Status column attributes (can be NULL)
///
/// @return The final width of the statusline
-int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_sandbox, int fillchar,
- int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
+int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_name, int opt_scope,
+ int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab,
+ statuscol_T *stcp)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@@ -669,6 +959,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
char *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
+ const bool save_KeyTyped = KeyTyped;
+ // TODO(Bram): find out why using called_emsg_before makes tests fail, does it
+ // matter?
+ // const int called_emsg_before = called_emsg;
+ const int did_emsg_before = did_emsg;
if (stl_items == NULL) {
stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len);
@@ -682,6 +977,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
stl_separator_locations = xmalloc(sizeof(int) * stl_items_len);
}
+ // if "fmt" was set insecurely it needs to be evaluated in the sandbox
+ // "opt_name" will be NULL when caller is nvim_eval_statusline()
+ const int use_sandbox = opt_name ? was_set_insecurely(wp, opt_name, opt_scope)
+ : false;
+
// 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] == '!') {
@@ -712,13 +1012,13 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
// Get line & check if empty (cursorpos will show "0-1").
- const char *line_ptr = (char *)ml_get_buf(wp->w_buffer, lnum, false);
+ const char *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;
- const size_t len = 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.
@@ -829,7 +1129,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// so `vim_strsize` will work.
char *t = stl_items[stl_groupitems[groupdepth]].start;
*out_p = NUL;
- long group_len = vim_strsize(t);
+ ptrdiff_t group_len = vim_strsize(t);
// If the group contained internal items
// and the group did not have a minimum width,
@@ -915,7 +1215,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
// If the group is shorter than the minimum width, add padding characters.
} else if (abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) {
- long min_group_width = stl_items[stl_groupitems[groupdepth]].minwid;
+ ptrdiff_t min_group_width = stl_items[stl_groupitems[groupdepth]].minwid;
// If the group is left-aligned, add characters to the right.
if (min_group_width < 0) {
min_group_width = 0 - min_group_width;
@@ -929,7 +1229,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
group_len = (min_group_width - group_len) * utf_char2len(fillchar);
memmove(t + group_len, t, (size_t)(out_p - t));
if (out_p + group_len >= (out_end_p + 1)) {
- group_len = (long)(out_end_p - out_p);
+ group_len = out_end_p - out_p;
}
out_p += group_len;
// }
@@ -1037,7 +1337,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
stl_items[curitem].type = ClickFunc;
stl_items[curitem].start = out_p;
- stl_items[curitem].cmd = xmemdupz(t, (size_t)(fmt_p - t));
+ stl_items[curitem].cmd = tabtab ? xmemdupz(t, (size_t)(fmt_p - t)) : NULL;
stl_items[curitem].minwid = minwid;
fmt_p++;
curitem++;
@@ -1078,7 +1378,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// An invalid item was specified.
// Continue processing on the next character of the format string.
- if (vim_strchr(STL_ALL, *fmt_p) == NULL) {
+ if (vim_strchr(STL_ALL, (uint8_t)(*fmt_p)) == NULL) {
fmt_p++;
continue;
}
@@ -1100,17 +1400,17 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// get replaced with the fillchar
fillable = false;
if (buf_spname(wp->w_buffer) != NULL) {
- STRLCPY(NameBuff, buf_spname(wp->w_buffer), MAXPATHL);
+ xstrlcpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL);
} else {
char *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
: wp->w_buffer->b_fname;
- home_replace(wp->w_buffer, t, (char *)NameBuff, MAXPATHL, true);
+ home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, true);
}
- trans_characters((char *)NameBuff, MAXPATHL);
+ trans_characters(NameBuff, MAXPATHL);
if (opt != STL_FILENAME) {
- str = (char *)NameBuff;
+ str = NameBuff;
} else {
- str = path_tail((char *)NameBuff);
+ str = path_tail(NameBuff);
}
break;
case STL_VIM_EXPR: // '{'
@@ -1191,8 +1491,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
&& strchr((const char *)str, '%') != NULL
&& evaldepth < MAX_STL_EVAL_DEPTH) {
size_t parsed_usefmt = (size_t)(block_start - usefmt);
- size_t str_length = STRLEN(str);
- size_t fmt_length = STRLEN(fmt_p);
+ size_t str_length = strlen(str);
+ size_t fmt_length = strlen(fmt_p);
size_t new_fmt_len = parsed_usefmt + str_length + fmt_length + 3;
char *new_fmt = xmalloc(new_fmt_len * sizeof(char));
char *new_fmt_p = new_fmt;
@@ -1217,8 +1517,14 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
case STL_LINE:
- num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
- ? 0L : (long)(wp->w_cursor.lnum);
+ // Overload %l with v:lnum for 'statuscolumn'
+ if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) {
+ if (wp->w_p_nu && !get_vim_var_nr(VV_VIRTNUM)) {
+ num = get_vim_var_nr(VV_LNUM);
+ }
+ } else {
+ num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum);
+ }
break;
case STL_NUMLINES:
@@ -1255,6 +1561,12 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
str = buf_tmp;
break;
+ case STL_SHOWCMD:
+ if (p_sc && (opt_name == NULL || strcmp(opt_name, p_sloc) == 0)) {
+ str = showcmd_buf;
+ }
+ break;
+
case STL_ARGLISTSTAT:
fillable = false;
@@ -1278,7 +1590,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
break;
case STL_PAGENUM:
- num = printer_page_num;
+ num = 0;
break;
case STL_BUFNO:
@@ -1310,9 +1622,16 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
case STL_ROFLAG:
case STL_ROFLAG_ALT:
- itemisflag = true;
- if (wp->w_buffer->b_p_ro) {
- str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]");
+ // Overload %r with v:relnum for 'statuscolumn'
+ if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) {
+ if (wp->w_p_rnu && !get_vim_var_nr(VV_VIRTNUM)) {
+ num = get_vim_var_nr(VV_RELNUM);
+ }
+ } else {
+ itemisflag = true;
+ if (wp->w_buffer->b_p_ro) {
+ str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]");
+ }
}
break;
@@ -1324,12 +1643,39 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
}
break;
+ case STL_FOLDCOL: // 'C' for 'statuscolumn'
+ case STL_SIGNCOL: { // 's' for 'statuscolumn'
+ if (stcp == NULL) {
+ break;
+ }
+
+ bool fold = opt == STL_FOLDCOL;
+ *buf_tmp = NUL;
+ for (int i = 0; i <= SIGN_SHOW_MAX; i++) {
+ char *p = fold ? stcp->fold_text : stcp->sign_text[i];
+ if ((!p || !*p) && *buf_tmp == NUL) {
+ break;
+ }
+ stl_items[curitem].type = Highlight;
+ stl_items[curitem].start = out_p + strlen(buf_tmp);
+ stl_items[curitem].minwid = !p || (fold && i) ? 0 : fold ? stcp->fold_attr
+ : stcp->sign_attr[i];
+ curitem++;
+ if (!p || (fold && i)) {
+ str = buf_tmp;
+ break;
+ }
+ STRCAT(buf_tmp, p);
+ }
+ break;
+ }
+
case STL_FILETYPE:
// Copy the filetype if it is not null and the formatted string will fit
// in the temporary buffer
// (including the brackets and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
- && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) {
+ && strlen(wp->w_buffer->b_p_ft) < TMPLEN - 3) {
vim_snprintf(buf_tmp, sizeof(buf_tmp), "[%s]",
wp->w_buffer->b_p_ft);
str = buf_tmp;
@@ -1342,11 +1688,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// in the temporary buffer
// (including the comma and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
- && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) {
+ && strlen(wp->w_buffer->b_p_ft) < TMPLEN - 2) {
vim_snprintf(buf_tmp, sizeof(buf_tmp), ",%s", wp->w_buffer->b_p_ft);
// Uppercase the file extension
for (char *t = buf_tmp; *t != 0; t++) {
- *t = (char)TOUPPER_LOC(*t);
+ *t = (char)TOUPPER_LOC((uint8_t)(*t));
}
str = buf_tmp;
}
@@ -1562,7 +1908,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// Advance the output buffer position to the end of the
// number we just printed
- out_p += STRLEN(out_p);
+ out_p += strlen(out_p);
// Otherwise, there was nothing to print so mark the item as empty
} else {
@@ -1595,6 +1941,10 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// What follows is post-processing to handle alignment and highlighting.
int width = vim_strsize(out);
+ // Return truncated width for 'statuscolumn'
+ if (stcp != NULL && width > maxwidth) {
+ stcp->truncate = width - maxwidth;
+ }
if (maxwidth > 0 && width > maxwidth) {
// Result is too long, must truncate somewhere.
int item_idx = 0;
@@ -1642,6 +1992,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// the truncation point
for (int i = 0; i < itemcnt; i++) {
if (stl_items[i].start > trunc_p) {
+ for (int j = i; j < itemcnt; j++) {
+ if (stl_items[j].type == ClickFunc) {
+ XFREE_CLEAR(stl_items[j].cmd);
+ }
+ }
itemcnt = i;
break;
}
@@ -1670,7 +2025,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
if (width + 1 < maxwidth) {
// Advance the pointer to the end of the string
- trunc_p = trunc_p + STRLEN(trunc_p);
+ trunc_p = trunc_p + strlen(trunc_p);
}
// Fill up for half a double-wide character.
@@ -1706,7 +2061,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// add characters at the separate marker (if there is one) to
// fill up the available space.
} else if (width < maxwidth
- && STRLEN(out) + (size_t)(maxwidth - width) + 1 < outlen) {
+ && strlen(out) + (size_t)(maxwidth - width) + 1 < outlen) {
// Find how many separators there are, which we will use when
// figuring out how many groups there are.
int num_separators = 0;
@@ -1804,5 +2159,18 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
curwin->w_redr_type = save_redr_type;
}
+ // Check for an error. If there is one the display will be messed up and
+ // might loop redrawing. Avoid that by making the corresponding option
+ // empty.
+ // TODO(Bram): find out why using called_emsg_before makes tests fail, does it
+ // matter?
+ // if (called_emsg > called_emsg_before)
+ if (opt_name && did_emsg > did_emsg_before) {
+ set_string_option_direct(opt_name, -1, "", OPT_FREE | opt_scope, SID_ERROR);
+ }
+
+ // A user function may reset KeyTyped, restore it.
+ KeyTyped = save_KeyTyped;
+
return width;
}