aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2018-02-06 19:46:45 +0100
committerBjörn Linse <bjorn.linse@gmail.com>2018-02-11 10:29:32 +0100
commit5d8da126d0b5ab7f550a74264ba434a2ad04280e (patch)
treec260eec7838c37eae30b0aa6b866993afd7649c7
parentc205360f00e5be3847c22738260237bcc9f3ca1e (diff)
downloadrneovim-5d8da126d0b5ab7f550a74264ba434a2ad04280e.tar.gz
rneovim-5d8da126d0b5ab7f550a74264ba434a2ad04280e.tar.bz2
rneovim-5d8da126d0b5ab7f550a74264ba434a2ad04280e.zip
ui/tui: highlighting refactor
Make HlAttr contain highlighting state for both color modes (cterm and rgb). This allows us to implement termguicolors completely in the TUI. Simplify some logic duplicated between ui.c and screen.c. Also avoid some superfluous highlighting reset events.
-rw-r--r--src/nvim/api/ui.c3
-rw-r--r--src/nvim/api/ui_events.in.h11
-rw-r--r--src/nvim/ex_getln.c6
-rw-r--r--src/nvim/highlight_defs.h29
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/screen.c43
-rw-r--r--src/nvim/syntax.c47
-rw-r--r--src/nvim/syntax.h13
-rw-r--r--src/nvim/syntax_defs.h17
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/tui/tui.c113
-rw-r--r--src/nvim/ugrid.c7
-rw-r--r--src/nvim/ugrid.h6
-rw-r--r--src/nvim/ui.c143
-rw-r--r--src/nvim/ui.h8
-rw-r--r--src/nvim/ui_bridge.c27
-rw-r--r--test/functional/terminal/tui_spec.lua4
-rw-r--r--test/functional/ui/screen.lua3
18 files changed, 195 insertions, 289 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 760c95eb5b..e53a45bd93 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -86,6 +86,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->put = remote_ui_put;
ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell;
+ ui->default_colors_set = remote_ui_default_colors_set;
ui->update_fg = remote_ui_update_fg;
ui->update_bg = remote_ui_update_bg;
ui->update_sp = remote_ui_update_sp;
@@ -243,7 +244,7 @@ static void push_call(UI *ui, char *name, Array args)
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{
Array args = ARRAY_DICT_INIT;
- Dictionary hl = hlattrs2dict(attrs);
+ Dictionary hl = hlattrs2dict(&attrs, ui->rgb);
ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args);
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 3d2253e918..c599b0ce72 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -47,11 +47,14 @@ void visual_bell(void)
void flush(void)
FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
void update_fg(Integer fg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_bg(Integer bg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_sp(Integer sp)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
+void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
+ Integer cterm_fg, Integer cterm_bg)
+ FUNC_API_SINCE(4);
void suspend(void)
FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void set_title(String title)
@@ -59,7 +62,7 @@ void set_title(String title)
void set_icon(String icon)
FUNC_API_SINCE(3);
void option_set(String name, Object value)
- FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL;
+ FUNC_API_SINCE(4);
void popupmenu_show(Array items, Integer selected, Integer row, Integer col)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index ba51f18518..40b4cc6d79 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2929,11 +2929,11 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
Array item = ARRAY_DICT_INIT;
if (chunk.attr) {
- attrentry_T *aep = syn_cterm_attr2entry(chunk.attr);
+ HlAttrs *aep = syn_cterm_attr2entry(chunk.attr);
// TODO(bfredl): this desicion could be delayed by making attr_code a
// recognized type
- HlAttrs rgb_attrs = attrentry2hlattrs(aep, true);
- ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs)));
+ Dictionary rgb_attrs = hlattrs2dict(aep, true);
+ ADD(item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 927fc94bbe..08157935f5 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -7,6 +7,34 @@
typedef int32_t RgbValue;
+/// Highlighting attribute bits.
+typedef enum {
+ HL_INVERSE = 0x01,
+ HL_BOLD = 0x02,
+ HL_ITALIC = 0x04,
+ HL_UNDERLINE = 0x08,
+ HL_UNDERCURL = 0x10,
+ HL_STANDOUT = 0x20,
+} HlAttrFlags;
+
+/// Stores a complete highlighting entry, including colors and attributes
+/// for both TUI and GUI.
+typedef struct attr_entry {
+ int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
+ RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
+ int cterm_fg_color, cterm_bg_color;
+} HlAttrs;
+
+#define HLATTRS_INIT (HlAttrs) { \
+ .rgb_ae_attr = 0, \
+ .cterm_ae_attr = 0, \
+ .rgb_fg_color = -1, \
+ .rgb_bg_color = -1, \
+ .rgb_sp_color = -1, \
+ .cterm_fg_color = 0, \
+ .cterm_bg_color = 0, \
+}
+
/// Values for index in highlight_attr[].
/// When making changes, also update hlf_names below!
typedef enum {
@@ -117,7 +145,6 @@ EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
EXTERN int cterm_normal_fg_color INIT(= 0);
-EXTERN int cterm_normal_fg_bold INIT(= 0);
EXTERN int cterm_normal_bg_color INIT(= 0);
EXTERN RgbValue normal_fg INIT(= -1);
EXTERN RgbValue normal_bg INIT(= -1);
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index dac5c0ee16..6e8100594d 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2447,7 +2447,7 @@ return {
full_name='termguicolors', abbreviation='tgc',
type='bool', scope={'global'},
vi_def=false,
- redraw={'everything', 'ui_option'},
+ redraw={'ui_option'},
varname='p_tgc',
defaults={if_true={vi=false}}
},
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 8a29734025..122f760c51 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -139,11 +139,6 @@
* doesn't fit. */
#define W_ENDCOL(wp) (wp->w_wincol + wp->w_width)
-/*
- * The attributes that are actually active for writing to the screen.
- */
-static int screen_attr = 0;
-
static match_T search_hl; /* used for 'hlsearch' highlight matching */
static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
@@ -189,8 +184,6 @@ void redraw_win_later(win_T *wp, int type)
void redraw_later_clear(void)
{
redraw_all_later(CLEAR);
- /* Use attributes that is very unlikely to appear in text. */
- screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE;
}
/*
@@ -5847,30 +5840,16 @@ next_search_hl_pos(
return 0;
}
-static void screen_start_highlight(int attr)
-{
- screen_attr = attr;
- ui_start_highlight(attr);
-}
-
-static void screen_stop_highlight(void)
-{
- ui_stop_highlight();
- screen_attr = 0;
-}
-
/*
* Put character ScreenLines["off"] on the screen at position "row" and "col",
* using the attributes from ScreenAttrs["off"].
*/
static void screen_char(unsigned off, int row, int col)
{
- int attr;
-
- /* Check for illegal values, just in case (could happen just after
- * resizing). */
- if (row >= screen_Rows || col >= screen_Columns)
+ // Check for illegal values, just in case (could happen just after resizing).
+ if (row >= screen_Rows || col >= screen_Columns) {
return;
+ }
// Outputting the last character on the screen may scrollup the screen.
// Don't to it! Mark the character invalid (update it when scrolled up)
@@ -5882,17 +5861,8 @@ static void screen_char(unsigned off, int row, int col)
return;
}
- /*
- * Stop highlighting first, so it's easier to move the cursor.
- */
- attr = ScreenAttrs[off];
- if (screen_attr != attr)
- screen_stop_highlight();
-
ui_cursor_goto(row, col);
-
- if (screen_attr != attr)
- screen_start_highlight(attr);
+ ui_set_highlight(ScreenAttrs[off]);
if (enc_utf8 && ScreenLinesUC[off] != 0) {
char_u buf[MB_MAXBYTES + 1];
@@ -6001,7 +5971,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
++off;
if (off < end_off) { /* something to be cleared */
col = off - LineOffset[row];
- screen_stop_highlight();
+ ui_clear_highlight();
ui_cursor_goto(row, col); // clear rest of this screen line
ui_call_eol_clear();
col = end_col - col;
@@ -6383,8 +6353,7 @@ static void screenclear2(void)
return;
}
- screen_stop_highlight(); /* don't want highlighting here */
-
+ ui_clear_highlight(); // don't want highlighting here
/* blank out ScreenLines */
for (i = 0; i < Rows; ++i) {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 40479e05dd..0a7f703461 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -64,7 +64,7 @@ struct hl_group {
int sg_cterm_bold; ///< bold attr was set for light color
// for RGB UIs
int sg_gui; ///< "gui=" highlighting attributes
- ///< (combination of \ref HL_ATTRIBUTES)
+ ///< (combination of \ref HlAttrFlags)
RgbValue sg_rgb_fg; ///< RGB foreground color
RgbValue sg_rgb_bg; ///< RGB background color
RgbValue sg_rgb_sp; ///< RGB special color
@@ -6796,7 +6796,6 @@ void do_highlight(const char *line, const bool forceit, const bool init)
HL_TABLE()[idx].sg_cterm_fg = color + 1;
if (is_normal_group) {
cterm_normal_fg_color = color + 1;
- cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
must_redraw = CLEAR;
}
} else {
@@ -6940,7 +6939,6 @@ void restore_cterm_colors(void)
normal_bg = -1;
normal_sp = -1;
cterm_normal_fg_color = 0;
- cterm_normal_fg_bold = 0;
cterm_normal_bg_color = 0;
}
@@ -6994,9 +6992,9 @@ static void highlight_clear(int idx)
/// GUI can redraw at any time for any buffer.
static garray_T attr_table = GA_EMPTY_INIT_VALUE;
-static inline attrentry_T * ATTR_ENTRY(int idx)
+static inline HlAttrs * ATTR_ENTRY(int idx)
{
- return &((attrentry_T *)attr_table.ga_data)[idx];
+ return &((HlAttrs *)attr_table.ga_data)[idx];
}
@@ -7004,23 +7002,21 @@ static inline attrentry_T * ATTR_ENTRY(int idx)
/// Add a new entry to the term_attr_table, attr_table or gui_attr_table
/// if the combination is new.
/// @return 0 for error.
-int get_attr_entry(attrentry_T *aep)
+int get_attr_entry(HlAttrs *aep)
{
garray_T *table = &attr_table;
- attrentry_T *taep;
- static int recursive = FALSE;
+ HlAttrs *taep;
+ static int recursive = false;
/*
* Init the table, in case it wasn't done yet.
*/
- table->ga_itemsize = sizeof(attrentry_T);
+ table->ga_itemsize = sizeof(HlAttrs);
ga_set_growsize(table, 7);
- /*
- * Try to find an entry with the same specifications.
- */
- for (int i = 0; i < table->ga_len; ++i) {
- taep = &(((attrentry_T *)table->ga_data)[i]);
+ // Try to find an entry with the same specifications.
+ for (int i = 0; i < table->ga_len; i++) {
+ taep = &(((HlAttrs *)table->ga_data)[i]);
if (aep->cterm_ae_attr == taep->cterm_ae_attr
&& aep->cterm_fg_color == taep->cterm_fg_color
&& aep->cterm_bg_color == taep->cterm_bg_color
@@ -7057,7 +7053,7 @@ int get_attr_entry(attrentry_T *aep)
// This is a new combination of colors and font, add an entry.
- taep = GA_APPEND_VIA_PTR(attrentry_T, table);
+ taep = GA_APPEND_VIA_PTR(HlAttrs, table);
memset(taep, 0, sizeof(*taep));
taep->cterm_ae_attr = aep->cterm_ae_attr;
taep->cterm_fg_color = aep->cterm_fg_color;
@@ -7085,9 +7081,9 @@ void clear_hl_tables(void)
// Return the resulting attributes.
int hl_combine_attr(int char_attr, int prim_attr)
{
- attrentry_T *char_aep = NULL;
- attrentry_T *spell_aep;
- attrentry_T new_en = ATTRENTRY_INIT;
+ HlAttrs *char_aep = NULL;
+ HlAttrs *spell_aep;
+ HlAttrs new_en = HLATTRS_INIT;
if (char_attr == 0) {
return prim_attr;
@@ -7136,7 +7132,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
/// \note this function does not apply exclusively to cterm attr contrary
/// to what its name implies
/// \warn don't call it with attr 0 (i.e., the null attribute)
-attrentry_T *syn_cterm_attr2entry(int attr)
+HlAttrs *syn_cterm_attr2entry(int attr)
{
attr -= ATTR_OFF;
if (attr >= attr_table.ga_len) {
@@ -7385,7 +7381,7 @@ syn_list_header(int did_header, int outlen, int id)
/// @param idx corrected highlight index
static void set_hl_attr(int idx)
{
- attrentry_T at_en = ATTRENTRY_INIT;
+ HlAttrs at_en = HLATTRS_INIT;
struct hl_group *sgp = HL_TABLE() + idx;
@@ -8509,24 +8505,21 @@ RgbValue name_to_color(const char_u *name)
/// Gets highlight description for id `attr_id` as a map.
Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
{
- HlAttrs attrs = HLATTRS_INIT;
+ HlAttrs *aep = NULL;
Dictionary dic = ARRAY_DICT_INIT;
if (attr_id == 0) {
- goto end;
+ return dic;
}
- attrentry_T *aep = syn_cterm_attr2entry((int)attr_id);
+ aep = syn_cterm_attr2entry((int)attr_id);
if (!aep) {
api_set_error(err, kErrorTypeException,
"Invalid attribute id: %" PRId64, attr_id);
return dic;
}
- attrs = attrentry2hlattrs(aep, rgb);
-
-end:
- return hlattrs2dict(attrs);
+ return hlattrs2dict(aep, rgb);
}
diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h
index c9b0665ec8..f8282955a6 100644
--- a/src/nvim/syntax.h
+++ b/src/nvim/syntax.h
@@ -6,19 +6,6 @@
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h"
-/// Terminal highlighting attribute bits.
-/// Attributes above HL_ALL are used for syntax highlighting.
-/// \addtogroup HL_ATTRIBUTES
-/// @{
-#define HL_NORMAL 0x00
-#define HL_INVERSE 0x01
-#define HL_BOLD 0x02
-#define HL_ITALIC 0x04
-#define HL_UNDERLINE 0x08
-#define HL_UNDERCURL 0x10
-#define HL_STANDOUT 0x20
-/// @}
-
#define HL_CONTAINED 0x01 /* not used on toplevel */
#define HL_TRANSP 0x02 /* has no highlighting */
#define HL_ONELINE 0x04 /* match within one line only */
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 7260853703..63089a62af 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -68,21 +68,4 @@ struct syn_state {
* may have made the state invalid */
};
-// Structure shared between syntax.c, screen.c
-typedef struct attr_entry {
- int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
- RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
- int cterm_fg_color, cterm_bg_color;
-} attrentry_T;
-
-#define ATTRENTRY_INIT { \
- .rgb_ae_attr = 0, \
- .cterm_ae_attr = 0, \
- .rgb_fg_color = -1, \
- .rgb_bg_color = -1, \
- .rgb_sp_color = -1, \
- .cterm_fg_color = 0, \
- .cterm_bg_color = 0, \
-}
-
#endif // NVIM_SYNTAX_DEFS_H
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 137855469f..f3eb6883ce 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -585,7 +585,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
int attr_id = 0;
if (hl_attrs || vt_fg != -1 || vt_bg != -1) {
- attr_id = get_attr_entry(&(attrentry_T) {
+ attr_id = get_attr_entry(&(HlAttrs) {
.cterm_ae_attr = (int16_t)hl_attrs,
.cterm_fg_color = vt_fg_idx,
.cterm_bg_color = vt_bg_idx,
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 70e19e1d93..62bdc61a68 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -125,7 +125,6 @@ UI *tui_start(void)
{
UI *ui = xcalloc(1, sizeof(UI)); // Freed by ui_bridge_stop().
ui->stop = tui_stop;
- ui->rgb = p_tgc;
ui->resize = tui_resize;
ui->clear = tui_clear;
ui->eol_clear = tui_eol_clear;
@@ -143,15 +142,12 @@ UI *tui_start(void)
ui->put = tui_put;
ui->bell = tui_bell;
ui->visual_bell = tui_visual_bell;
- ui->update_fg = tui_update_fg;
- ui->update_bg = tui_update_bg;
- ui->update_sp = tui_update_sp;
+ ui->default_colors_set = tui_default_colors_set;
ui->flush = tui_flush;
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon;
ui->option_set= tui_option_set;
- ui->event = tui_event;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
@@ -410,36 +406,58 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
ui_schedule_refresh();
}
-static bool attrs_differ(HlAttrs a1, HlAttrs a2)
+static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)
{
- return a1.foreground != a2.foreground || a1.background != a2.background
- || a1.bold != a2.bold || a1.italic != a2.italic
- || a1.undercurl != a2.undercurl || a1.underline != a2.underline
- || a1.reverse != a2.reverse;
+ if (rgb) {
+ // TODO(bfredl): when we start to support special color,
+ // rgb_sp_color must be added here
+ return a1.rgb_fg_color != a2.rgb_fg_color
+ || a1.rgb_bg_color != a2.rgb_bg_color
+ || a1.rgb_ae_attr != a2.rgb_ae_attr;
+ } else {
+ return a1.cterm_fg_color != a2.cterm_fg_color
+ || a1.cterm_bg_color != a2.cterm_bg_color
+ || a1.cterm_ae_attr != a2.cterm_ae_attr;
+ }
}
static void update_attrs(UI *ui, HlAttrs attrs)
{
TUIData *data = ui->data;
- if (!attrs_differ(attrs, data->print_attrs)) {
+ if (!attrs_differ(attrs, data->print_attrs, ui->rgb)) {
return;
}
data->print_attrs = attrs;
UGrid *grid = &data->grid;
- int fg = attrs.foreground != -1 ? attrs.foreground : grid->fg;
- int bg = attrs.background != -1 ? attrs.background : grid->bg;
+ int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1);
+ if (fg == -1) {
+ fg = ui->rgb ? grid->clear_attrs.rgb_fg_color
+ : (grid->clear_attrs.cterm_fg_color - 1);
+ }
+
+ int bg = ui->rgb ? attrs.rgb_bg_color : (attrs.cterm_bg_color - 1);
+ if (bg == -1) {
+ bg = ui->rgb ? grid->clear_attrs.rgb_bg_color
+ : (grid->clear_attrs.cterm_bg_color - 1);
+ }
+
+ int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
+ bool bold = attr & HL_BOLD;
+ bool italic = attr & HL_ITALIC;
+ bool reverse = attr & (HL_INVERSE | HL_STANDOUT);
+ bool underline = attr & (HL_UNDERLINE), undercurl = attr & (HL_UNDERCURL);
if (unibi_get_str(data->ut, unibi_set_attributes)) {
- if (attrs.bold || attrs.reverse || attrs.underline || attrs.undercurl) {
+ if (bold || reverse || underline || undercurl) {
UNIBI_SET_NUM_VAR(data->params[0], 0); // standout
- UNIBI_SET_NUM_VAR(data->params[1], attrs.underline || attrs.undercurl);
- UNIBI_SET_NUM_VAR(data->params[2], attrs.reverse);
+ UNIBI_SET_NUM_VAR(data->params[1], underline || undercurl);
+ UNIBI_SET_NUM_VAR(data->params[2], reverse);
UNIBI_SET_NUM_VAR(data->params[3], 0); // blink
UNIBI_SET_NUM_VAR(data->params[4], 0); // dim
- UNIBI_SET_NUM_VAR(data->params[5], attrs.bold);
+ UNIBI_SET_NUM_VAR(data->params[5], bold);
UNIBI_SET_NUM_VAR(data->params[6], 0); // blank
UNIBI_SET_NUM_VAR(data->params[7], 0); // protect
UNIBI_SET_NUM_VAR(data->params[8], 0); // alternate character set
@@ -451,17 +469,17 @@ static void update_attrs(UI *ui, HlAttrs attrs)
if (!data->default_attr) {
unibi_out(ui, unibi_exit_attribute_mode);
}
- if (attrs.bold) {
+ if (bold) {
unibi_out(ui, unibi_enter_bold_mode);
}
- if (attrs.underline || attrs.undercurl) {
+ if (underline || undercurl) {
unibi_out(ui, unibi_enter_underline_mode);
}
- if (attrs.reverse) {
+ if (reverse) {
unibi_out(ui, unibi_enter_reverse_mode);
}
}
- if (attrs.italic) {
+ if (italic) {
unibi_out(ui, unibi_enter_italics_mode);
}
if (ui->rgb) {
@@ -491,8 +509,7 @@ static void update_attrs(UI *ui, HlAttrs attrs)
}
data->default_attr = fg == -1 && bg == -1
- && !attrs.bold && !attrs.italic && !attrs.underline && !attrs.undercurl
- && !attrs.reverse;
+ && !bold && !italic && !underline && !undercurl && !reverse;
}
static void final_column_wrap(UI *ui)
@@ -534,7 +551,7 @@ static bool cheap_to_print(UI *ui, int row, int col, int next)
UCell *cell = grid->cells[row] + col;
while (next) {
next--;
- if (attrs_differ(cell->attrs, data->print_attrs)) {
+ if (attrs_differ(cell->attrs, data->print_attrs, ui->rgb)) {
if (data->default_attr) {
return false;
}
@@ -659,13 +676,12 @@ static void clear_region(UI *ui, int top, int bot, int left, int right)
int saved_col = grid->col;
bool cleared = false;
- if (grid->bg == -1 && right == ui->width -1) {
+ bool nobg = ui->rgb ? grid->clear_attrs.rgb_bg_color == -1
+ : grid->clear_attrs.cterm_bg_color == 0;
+ if (nobg && right == ui->width -1) {
// Background is set to the default color and the right edge matches the
// screen end, try to use terminal codes for clearing the requested area.
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
- update_attrs(ui, clear_attrs);
+ update_attrs(ui, grid->clear_attrs);
if (left == 0) {
if (bot == ui->height - 1) {
if (top == 0) {
@@ -788,6 +804,7 @@ static void tui_clear(UI *ui)
TUIData *data = ui->data;
UGrid *grid = &data->grid;
ugrid_clear(grid);
+ kv_size(data->invalid_regions) = 0;
clear_region(ui, grid->top, grid->bot, grid->left, grid->right);
}
@@ -905,7 +922,7 @@ static void tui_set_mode(UI *ui, ModeShape mode)
if (c.id != 0 && ui->rgb) {
int attr = syn_id2attr(c.id);
if (attr > 0) {
- attrentry_T *aep = syn_cterm_attr2entry(attr);
+ HlAttrs *aep = syn_cterm_attr2entry(attr);
UNIBI_SET_NUM_VAR(data->params[0], aep->rgb_bg_color);
unibi_out_ext(ui, data->unibi_ext.set_cursor_color);
}
@@ -960,10 +977,7 @@ static void tui_scroll(UI *ui, Integer count)
cursor_goto(ui, grid->top, grid->left);
// also set default color attributes or some terminals can become funny
if (scroll_clears_to_current_colour) {
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
- update_attrs(ui, clear_attrs);
+ update_attrs(ui, grid->clear_attrs);
}
if (count > 0) {
@@ -1028,19 +1042,16 @@ static void tui_visual_bell(UI *ui)
unibi_out(ui, unibi_flash_screen);
}
-static void tui_update_fg(UI *ui, Integer fg)
-{
- ((TUIData *)ui->data)->grid.fg = (int)fg;
-}
-
-static void tui_update_bg(UI *ui, Integer bg)
-{
- ((TUIData *)ui->data)->grid.bg = (int)bg;
-}
-
-static void tui_update_sp(UI *ui, Integer sp)
+static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
+ Integer rgb_sp,
+ Integer cterm_fg, Integer cterm_bg)
{
- // Do nothing; 'special' color is for GUI only
+ UGrid *grid = &((TUIData *)ui->data)->grid;
+ grid->clear_attrs.rgb_fg_color = (int)rgb_fg;
+ grid->clear_attrs.rgb_bg_color = (int)rgb_bg;
+ grid->clear_attrs.rgb_sp_color = (int)rgb_sp;
+ grid->clear_attrs.cterm_fg_color = (int)cterm_fg;
+ grid->clear_attrs.cterm_bg_color = (int)cterm_bg;
}
static void tui_flush(UI *ui)
@@ -1065,6 +1076,7 @@ static void tui_flush(UI *ui)
while (kv_size(data->invalid_regions)) {
Rect r = kv_pop(data->invalid_regions);
+ assert(r.bot < grid->height && r.right < grid->width);
UGRID_FOREACH_CELL(grid, r.top, r.bot, r.left, r.right, {
cursor_goto(ui, row, col);
print_cell(ui, cell);
@@ -1149,18 +1161,13 @@ static void tui_set_icon(UI *ui, String icon)
static void tui_option_set(UI *ui, String name, Object value)
{
+ TUIData *data = ui->data;
if (strequal(name.data, "termguicolors")) {
- // NB: value for bridge is set in ui_bridge.c
ui->rgb = value.data.boolean;
+ invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1);
}
}
-// NB: if we start to use this, the ui_bridge must be updated
-// to make a copy for the tui thread
-static void tui_event(UI *ui, char *name, Array args, bool *args_consumed)
-{
-}
-
static void invalidate(UI *ui, int top, int bot, int left, int right)
{
TUIData *data = ui->data;
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index e0880b4c76..6d420ef2f8 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -17,7 +17,7 @@
void ugrid_init(UGrid *grid)
{
grid->attrs = HLATTRS_INIT;
- grid->fg = grid->bg = -1;
+ grid->clear_attrs = HLATTRS_INIT;
grid->cells = NULL;
}
@@ -107,6 +107,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
UCell *cell = grid->cells[grid->row] + grid->col;
cell->data[size] = 0;
cell->attrs = grid->attrs;
+ assert(size <= CELLBYTES);
if (text) {
memcpy(cell->data, text, size);
@@ -118,9 +119,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
static void clear_region(UGrid *grid, int top, int bot, int left, int right)
{
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
+ HlAttrs clear_attrs = grid->clear_attrs;
UGRID_FOREACH_CELL(grid, top, bot, left, right, {
cell->data[0] = ' ';
cell->data[1] = 0;
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index 1cf047502d..60c9068eb1 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -7,15 +7,17 @@
typedef struct ucell UCell;
typedef struct ugrid UGrid;
+#define CELLBYTES (4 * (MAX_MCO+1))
+
struct ucell {
- char data[6 * MAX_MCO + 1];
+ char data[CELLBYTES + 1];
HlAttrs attrs;
};
struct ugrid {
int top, bot, left, right;
int row, col;
- int bg, fg;
+ HlAttrs clear_attrs;
int width, height;
HlAttrs attrs;
UCell **cells;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 709a172449..e8f5477db0 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -55,7 +55,7 @@ static int row = 0, col = 0;
static struct {
int top, bot, left, right;
} sr;
-static int current_attr_code = 0;
+static int current_attr_code = -1;
static bool pending_cursor_update = false;
static int busy = 0;
static int height, width;
@@ -107,8 +107,9 @@ static char uilog_last_event[1024] = { 0 };
} \
} while (0)
#endif
-#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore)
-#define SELECT_NTH(a1, a2, a3, a4, a5, a6, ...) a6
+#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, \
+ MORE, MORE, ZERO, ignore)
+#define SELECT_NTH(a1, a2, a3, a4, a5, a6, a7, ...) a7
#define UI_CALL_HELPER(c, ...) UI_CALL_HELPER2(c, __VA_ARGS__)
// Resolves to UI_CALL_MORE or UI_CALL_ZERO.
#define UI_CALL_HELPER2(c, ...) UI_CALL_##c(__VA_ARGS__)
@@ -151,6 +152,9 @@ bool ui_is_stopped(UI *ui)
bool ui_rgb_attached(void)
{
+ if (!headless_mode && p_tgc) {
+ return true;
+ }
for (size_t i = 0; i < ui_count; i++) {
if (uis[i]->rgb) {
return true;
@@ -174,84 +178,57 @@ void ui_event(char *name, Array args)
}
-/// Converts an attrentry_T into an HlAttrs
+/// Converts an HlAttrs into Dictionary
///
/// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
-HlAttrs attrentry2hlattrs(const attrentry_T *aep, bool use_rgb)
+Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
{
assert(aep);
-
- HlAttrs attrs = HLATTRS_INIT;
- int mask = 0;
-
- mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
-
- attrs.bold = mask & HL_BOLD;
- attrs.underline = mask & HL_UNDERLINE;
- attrs.undercurl = mask & HL_UNDERCURL;
- attrs.italic = mask & HL_ITALIC;
- attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT);
-
- if (use_rgb) {
- if (aep->rgb_fg_color != -1) {
- attrs.foreground = aep->rgb_fg_color;
- }
-
- if (aep->rgb_bg_color != -1) {
- attrs.background = aep->rgb_bg_color;
- }
-
- if (aep->rgb_sp_color != -1) {
- attrs.special = aep->rgb_sp_color;
- }
- } else {
- if (cterm_normal_fg_color != aep->cterm_fg_color) {
- attrs.foreground = aep->cterm_fg_color - 1;
- }
-
- if (cterm_normal_bg_color != aep->cterm_bg_color) {
- attrs.background = aep->cterm_bg_color - 1;
- }
- }
-
- return attrs;
-}
-
-Dictionary hlattrs2dict(HlAttrs attrs)
-{
Dictionary hl = ARRAY_DICT_INIT;
+ int mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
- if (attrs.bold) {
+ if (mask & HL_BOLD) {
PUT(hl, "bold", BOOLEAN_OBJ(true));
}
- if (attrs.underline) {
+ if (mask & HL_UNDERLINE) {
PUT(hl, "underline", BOOLEAN_OBJ(true));
}
- if (attrs.undercurl) {
+ if (mask & HL_UNDERCURL) {
PUT(hl, "undercurl", BOOLEAN_OBJ(true));
}
- if (attrs.italic) {
+ if (mask & HL_ITALIC) {
PUT(hl, "italic", BOOLEAN_OBJ(true));
}
- if (attrs.reverse) {
+ if (mask & (HL_INVERSE | HL_STANDOUT)) {
PUT(hl, "reverse", BOOLEAN_OBJ(true));
}
- if (attrs.foreground != -1) {
- PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
- }
- if (attrs.background != -1) {
- PUT(hl, "background", INTEGER_OBJ(attrs.background));
- }
+ if (use_rgb) {
+ if (aep->rgb_fg_color != -1) {
+ PUT(hl, "foreground", INTEGER_OBJ(aep->rgb_fg_color));
+ }
- if (attrs.special != -1) {
- PUT(hl, "special", INTEGER_OBJ(attrs.special));
+ if (aep->rgb_bg_color != -1) {
+ PUT(hl, "background", INTEGER_OBJ(aep->rgb_bg_color));
+ }
+
+ if (aep->rgb_sp_color != -1) {
+ PUT(hl, "special", INTEGER_OBJ(aep->rgb_sp_color));
+ }
+ } else {
+ if (cterm_normal_fg_color != aep->cterm_fg_color) {
+ PUT(hl, "foreground", INTEGER_OBJ(aep->cterm_fg_color - 1));
+ }
+
+ if (cterm_normal_bg_color != aep->cterm_bg_color) {
+ PUT(hl, "background", INTEGER_OBJ(aep->cterm_bg_color - 1));
+ }
}
return hl;
@@ -296,6 +273,7 @@ void ui_refresh(void)
ui_mode_info_set();
old_mode_idx = -1;
ui_cursor_shape();
+ current_attr_code = -1;
}
static void ui_refresh_event(void **argv)
@@ -313,6 +291,11 @@ void ui_resize(int new_width, int new_height)
width = new_width;
height = new_height;
+ // TODO(bfredl): update default colors when they changed, NOT on resize.
+ ui_call_default_colors_set(normal_fg, normal_bg, normal_sp,
+ cterm_normal_fg_color, cterm_normal_bg_color);
+
+ // Deprecated:
UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1));
UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1));
UI_CALL(update_sp, (ui->rgb ? normal_sp : -1));
@@ -406,26 +389,28 @@ void ui_reset_scroll_region(void)
ui_call_set_scroll_region(sr.top, sr.bot, sr.left, sr.right);
}
-void ui_start_highlight(int attr_code)
+void ui_set_highlight(int attr_code)
{
+ if (current_attr_code == attr_code) {
+ return;
+ }
current_attr_code = attr_code;
- if (!ui_active()) {
- return;
+ HlAttrs attrs = HLATTRS_INIT;
+
+ if (attr_code != 0) {
+ HlAttrs *aep = syn_cterm_attr2entry(attr_code);
+ if (aep) {
+ attrs = *aep;
+ }
}
- set_highlight_args(current_attr_code);
+ UI_CALL(highlight_set, attrs);
}
-void ui_stop_highlight(void)
+void ui_clear_highlight(void)
{
- current_attr_code = HL_NORMAL;
-
- if (!ui_active()) {
- return;
- }
-
- set_highlight_args(current_attr_code);
+ ui_set_highlight(0);
}
void ui_puts(uint8_t *str)
@@ -503,26 +488,6 @@ void ui_flush(void)
ui_call_flush();
}
-static void set_highlight_args(int attr_code)
-{
- HlAttrs rgb_attrs = HLATTRS_INIT;
- HlAttrs cterm_attrs = rgb_attrs;
-
- if (attr_code == HL_NORMAL) {
- goto end;
- }
- attrentry_T *aep = syn_cterm_attr2entry(attr_code);
-
- if (!aep) {
- goto end;
- }
-
- rgb_attrs = attrentry2hlattrs(aep, true);
- cterm_attrs = attrentry2hlattrs(aep, false);
-
-end:
- UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs));
-}
void ui_linefeed(void)
{
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 0e40a1a215..60adcb974f 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -16,14 +16,6 @@ typedef enum {
} UIWidget;
#define UI_WIDGETS (kUIWildmenu + 1)
-typedef struct {
- bool bold, underline, undercurl, italic, reverse;
- int foreground, background, special;
-} HlAttrs;
-
-#define HLATTRS_INIT \
- ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
-
typedef struct ui_t UI;
struct ui_t {
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 16dd42ebaa..b0f8905771 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -59,9 +59,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.put = ui_bridge_put;
rv->bridge.bell = ui_bridge_bell;
rv->bridge.visual_bell = ui_bridge_visual_bell;
- rv->bridge.update_fg = ui_bridge_update_fg;
- rv->bridge.update_bg = ui_bridge_update_bg;
- rv->bridge.update_sp = ui_bridge_update_sp;
+ rv->bridge.default_colors_set = ui_bridge_default_colors_set;
rv->bridge.flush = ui_bridge_flush;
rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title;
@@ -146,29 +144,6 @@ static void ui_bridge_highlight_set_event(void **argv)
xfree(argv[1]);
}
-static void ui_bridge_option_set(UI *ui, String name, Object value)
-{
- // Assumes bridge is only used by TUI
- if (strequal(name.data, "termguicolors")) {
- ui->rgb = value.data.boolean;
- }
- String copy_name = copy_string(name);
- Object *copy_value = xmalloc(sizeof(Object));
- *copy_value = copy_object(value);
- UI_BRIDGE_CALL(ui, option_set, 4, ui,
- copy_name.data, INT2PTR(copy_name.size), copy_value);
-}
-static void ui_bridge_option_set_event(void **argv)
-{
- UI *ui = UI(argv[0]);
- String name = (String){ .data = argv[1], .size = (size_t)argv[2] };
- Object value = *(Object *)argv[3];
- ui->option_set(ui, name, value);
- api_free_string(name);
- api_free_object(value);
- xfree(argv[3]);
-}
-
static void ui_bridge_suspend(UI *b)
{
UIBridgeData *data = (UIBridgeData *)b;
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index a62c03b70f..171745eb57 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -242,7 +242,7 @@ describe('tui', function()
{9:~ }|
{9:~ }|
{3:[No Name] [+] }|
- |
+ :set termguicolors |
{4:-- TERMINAL --} |
]])
@@ -253,7 +253,7 @@ describe('tui', function()
{2:~ }|
{2:~ }|
{3:[No Name] [+] }|
- |
+ :set notermguicolors |
{4:-- TERMINAL --} |
]])
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 696feabeed..52e108f389 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -455,6 +455,9 @@ function Screen:_handle_visual_bell()
self.visual_bell = true
end
+function Screen:_handle_default_colors_set()
+end
+
function Screen:_handle_update_fg(fg)
self._fg = fg
end