diff options
-rw-r--r-- | runtime/plugin/matchparen.vim | 2 | ||||
-rw-r--r-- | src/nvim/edit.c | 3 | ||||
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 13 | ||||
-rw-r--r-- | src/nvim/globals.h | 3 | ||||
-rw-r--r-- | src/nvim/main.c | 4 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 43 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/remote_ui.c | 96 | ||||
-rw-r--r-- | src/nvim/os/input.c | 10 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 12 | ||||
-rw-r--r-- | src/nvim/screen.c | 13 | ||||
-rw-r--r-- | src/nvim/syntax.c | 28 | ||||
-rw-r--r-- | src/nvim/term.c | 16 | ||||
-rw-r--r-- | src/nvim/ui.c | 120 | ||||
-rw-r--r-- | src/nvim/ui.h | 6 | ||||
-rw-r--r-- | test/functional/legacy/066_visual_block_tab_spec.lua | 10 | ||||
-rw-r--r-- | test/functional/ui/highlight_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 17 |
18 files changed, 240 insertions, 159 deletions
diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim index 3804ab949a..4dc0b7cd61 100644 --- a/runtime/plugin/matchparen.vim +++ b/runtime/plugin/matchparen.vim @@ -45,7 +45,7 @@ function! s:Highlight_Matching_Pair() " Avoid that we remove the popup menu. " Return when there are no colors (looks like the cursor jumps). - if pumvisible() || (&t_Co < 8 && !has("gui_running")) + if pumvisible() || (&term != 'abstract_ui' && &t_Co < 8 && !has("gui_running")) return endif diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e1a1fb18fa..89696410c9 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2294,8 +2294,7 @@ static int pum_wanted(void) return FALSE; /* The display looks bad on a B&W display. */ - if (t_colors < 8 - ) + if (!abstract_ui && t_colors < 8) return FALSE; return TRUE; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d60ce2de73..1dba3cd1e5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14440,7 +14440,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv) if (modec != 't' && modec != 'c' && modec != 'g') modec = 0; /* replace invalid with current */ } else { - if (t_colors > 1) + if (abstract_ui || t_colors > 1) modec = 'c'; else modec = 't'; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 3661a65b11..b794ced428 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -71,6 +71,7 @@ #include "nvim/os/time.h" #include "nvim/ex_cmds_defs.h" #include "nvim/mouse.h" +#include "nvim/msgpack_rpc/channel.h" static int quitmore = 0; static int ex_pressedreturn = FALSE; @@ -5398,10 +5399,16 @@ static void ex_stop(exarg_T *eap) /* * Disallow suspending for "rvim". */ - if (!check_restricted() - ) { - if (!eap->forceit) + if (!check_restricted()) { + if (!eap->forceit) { autowrite_all(); + } + + if (abstract_ui) { + channel_close(last_message_source); + return; + } + windgoto((int)Rows - 1, 0); out_char('\n'); out_flush(); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 11a7e9ecac..854dd33552 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1245,6 +1245,9 @@ EXTERN int curr_tmode INIT(= TMODE_COOK); /* contains current terminal mode */ EXTERN bool embedded_mode INIT(= false); // Using the "abstract_ui" termcap EXTERN bool abstract_ui INIT(= false); +// Id of the last channel sent a message to nvim. Used to determine the target +// of channel-specific actions such as suspending +EXTERN uint64_t last_message_source INIT(= 0); /// Used to track the status of external functions. /// Currently only used for iconv(). diff --git a/src/nvim/main.c b/src/nvim/main.c index 1f6c8ddc81..5e9fde67f5 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -281,9 +281,7 @@ int main(int argc, char **argv) event_init(); - if (abstract_ui) { - t_colors = 256; - } else { + if (!abstract_ui) { // Print a warning if stdout is not a terminal TODO(tarruda): Remove this // check once the new terminal UI is implemented check_tty(¶ms); diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 4c35cce09a..f2db65c605 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -45,6 +45,7 @@ typedef struct { typedef struct { uint64_t id; + size_t pending_requests; PMap(cstr_t) *subscribed_events; bool is_job, closed; msgpack_unpacker *unpacker; @@ -83,7 +84,6 @@ static uint64_t next_id = 1; static PMap(uint64_t) *channels = NULL; static PMap(cstr_t) *event_strings = NULL; static msgpack_sbuffer out_buffer; -static size_t pending_requests = 0; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/channel.c.generated.h" @@ -103,14 +103,7 @@ void channel_init(void) } if (abstract_ui) { - // Add handler for "attach_ui" remote_ui_init(); - String method = cstr_as_string("attach_ui"); - MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .defer = true}; - msgpack_rpc_add_method_handler(method, handler); - method = cstr_as_string("detach_ui"); - handler.fn = remote_ui_detach; - msgpack_rpc_add_method_handler(method, handler); } } @@ -200,20 +193,21 @@ bool channel_send_event(uint64_t id, char *name, Array args) return false; } - if (pending_requests) { - DelayedNotification p = { - .channel = channel, - .method = cstr_to_string(name), - .args = args - }; - // Pending request, queue the notification for sending later - *kl_pushp(DelayedNotification, delayed_notifications) = p; - } else { - if (channel) { - send_event(channel, name, args); + if (channel) { + if (channel->pending_requests) { + DelayedNotification p = { + .channel = channel, + .method = cstr_to_string(name), + .args = args + }; + // Pending request, queue the notification for sending later + *kl_pushp(DelayedNotification, delayed_notifications) = p; } else { - broadcast_event(name, args); + send_event(channel, name, args); } + } else { + // TODO(tarruda): Implement event broadcasting in vimscript + broadcast_event(name, args); } return true; @@ -246,10 +240,10 @@ Object channel_send_call(uint64_t id, // Push the frame ChannelCallFrame frame = {request_id, false, false, NIL}; kv_push(ChannelCallFrame *, channel->call_stack, &frame); - pending_requests++; + channel->pending_requests++; event_poll_until(-1, frame.returned); (void)kv_pop(channel->call_stack); - pending_requests--; + channel->pending_requests--; if (frame.errored) { api_set_error(err, Exception, "%s", frame.result.data.string.data); @@ -261,7 +255,7 @@ Object channel_send_call(uint64_t id, free_channel(channel); } - if (!pending_requests) { + if (!channel->pending_requests) { send_delayed_notifications(); } @@ -492,6 +486,7 @@ static void on_request_event(Event event) { RequestEvent *e = event.data; Channel *channel = e->channel; + last_message_source = channel->id; MsgpackRpcRequestHandler handler = e->handler; Array args = e->args; uint64_t request_id = e->request_id; @@ -644,6 +639,7 @@ static void close_channel(Channel *channel) uv_handle_t *handle = (uv_handle_t *)channel->data.streams.uv; if (handle) { uv_close(handle, close_cb); + free_channel(channel); } else { event_push((Event) { .handler = on_stdio_close }, false); } @@ -687,6 +683,7 @@ static Channel *register_channel(void) rv->closed = false; rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); rv->id = next_id++; + rv->pending_requests = 0; rv->subscribed_events = pmap_new(cstr_t)(); rv->next_request_id = 1; kv_init(rv->call_stack); diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c index f980a77b4c..4db9c71ebb 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/msgpack_rpc/remote_ui.c @@ -26,18 +26,44 @@ static PMap(uint64_t) *connected_uis = NULL; void remote_ui_init(void) { connected_uis = pmap_new(uint64_t)(); + // Add handler for "attach_ui" + String method = cstr_as_string("ui_attach"); + MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .defer = false}; + msgpack_rpc_add_method_handler(method, handler); + method = cstr_as_string("ui_detach"); + handler.fn = remote_ui_detach; + msgpack_rpc_add_method_handler(method, handler); + method = cstr_as_string("ui_try_resize"); + handler.fn = remote_ui_try_resize; + msgpack_rpc_add_method_handler(method, handler); } -Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, - Error *error) +void remote_ui_disconnect(uint64_t channel_id) +{ + UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + if (!ui) { + return; + } + UIData *data = ui->data; + // destroy pending screen updates + api_free_array(data->buffer); + pmap_del(uint64_t)(connected_uis, channel_id); + free(ui->data); + ui_detach(ui); + free(ui); +} + +static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { if (pmap_has(uint64_t)(connected_uis, channel_id)) { api_set_error(error, Exception, _("UI already attached for channel")); return NIL; } - if (args.size != 2 || args.items[0].type != kObjectTypeInteger + if (args.size != 3 || args.items[0].type != kObjectTypeInteger || args.items[1].type != kObjectTypeInteger + || args.items[2].type != kObjectTypeBoolean || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { api_set_error(error, Validation, _("Arguments must be a pair of positive integers " @@ -50,6 +76,7 @@ Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, UI *ui = xcalloc(1, sizeof(UI)); ui->width = (int)args.items[0].data.integer; ui->height = (int)args.items[1].data.integer; + ui->rgb = args.items[2].data.boolean; ui->data = data; ui->resize = remote_ui_resize; ui->clear = remote_ui_clear; @@ -67,16 +94,16 @@ Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, ui->put = remote_ui_put; ui->bell = remote_ui_bell; ui->visual_bell = remote_ui_visual_bell; + ui->update_fg = remote_ui_update_fg; + ui->update_bg = remote_ui_update_bg; ui->flush = remote_ui_flush; - ui->suspend = remote_ui_suspend; pmap_put(uint64_t)(connected_uis, channel_id, ui); ui_attach(ui); - return NIL; } -Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, Array args, - Error *error) +static Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) { api_set_error(error, Exception, _("UI is not attached for channel")); @@ -86,21 +113,30 @@ Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, Array args, return NIL; } -void remote_ui_disconnect(uint64_t channel_id) +static Object remote_ui_try_resize(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); - if (!ui) { - return; + if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + api_set_error(error, Exception, _("UI is not attached for channel")); } - UIData *data = ui->data; - // destroy pending screen updates - api_free_array(data->buffer); - pmap_del(uint64_t)(connected_uis, channel_id); - free(ui->data); - ui_detach(ui); - free(ui); + + if (args.size != 2 || args.items[0].type != kObjectTypeInteger + || args.items[1].type != kObjectTypeInteger + || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { + api_set_error(error, Validation, + _("Arguments must be a pair of positive integers " + "representing the remote screen width/height")); + return NIL; + } + + UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + ui->width = (int)args.items[0].data.integer; + ui->height = (int)args.items[1].data.integer; + ui_refresh(); + return NIL; } + static void push_call(UI *ui, char *name, Array args) { Array call = ARRAY_DICT_INIT; @@ -214,10 +250,6 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) PUT(hl, "bold", BOOLEAN_OBJ(true)); } - if (attrs.standout) { - PUT(hl, "standout", BOOLEAN_OBJ(true)); - } - if (attrs.underline) { PUT(hl, "underline", BOOLEAN_OBJ(true)); } @@ -266,15 +298,23 @@ static void remote_ui_visual_bell(UI *ui) push_call(ui, "visual_bell", args); } -static void remote_ui_flush(UI *ui) +static void remote_ui_update_fg(UI *ui, int fg) { - UIData *data = ui->data; - channel_send_event(data->channel_id, "redraw", data->buffer); - data->buffer = (Array)ARRAY_DICT_INIT; + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(fg)); + push_call(ui, "update_fg", args); } -static void remote_ui_suspend(UI *ui) +static void remote_ui_update_bg(UI *ui, int bg) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(bg)); + push_call(ui, "update_bg", args); +} + +static void remote_ui_flush(UI *ui) { UIData *data = ui->data; - remote_ui_disconnect(data->channel_id); + channel_send_event(data->channel_id, "redraw", data->buffer); + data->buffer = (Array)ARRAY_DICT_INIT; } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index c0d588f4ef..130e239a34 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -187,14 +187,20 @@ size_t input_enqueue(String keys) unsigned int new_size = trans_special((uint8_t **)&ptr, buf, false); if (!new_size) { + if (*ptr == '<') { + // Invalid key sequence, skip until the next '>' or until *end + do { + ptr++; + } while (ptr < end && *ptr != '>'); + ptr++; + continue; + } // copy the character unmodified *buf = (uint8_t)*ptr++; new_size = 1; } new_size = handle_mouse_event(&ptr, buf, new_size); - // TODO(tarruda): Don't produce past unclosed '<' characters, except if - // there's a lot of characters after the '<' rbuffer_write(input_buffer, (char *)buf, new_size); } diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index d0f8442768..d481d6af56 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -24,7 +24,6 @@ #include "nvim/option_defs.h" #include "nvim/charset.h" #include "nvim/strings.h" -#include "nvim/ui.h" #define DYNAMIC_BUFFER_INIT {NULL, 0, 0} @@ -414,6 +413,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, char *start = output; size_t off = 0; + int lastrow = (int)Rows - 1; while (off < remaining) { if (output[off] == NL) { // Insert the line @@ -421,10 +421,8 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, if (to_buffer) { ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); } else { - // pending data from the output buffer has been flushed to the screen, - // safe to call ui_write directly - ui_write((char_u *)output, (int)off); - ui_write((char_u *)"\r\n", 2); + screen_del_lines(0, 0, 1, (int)Rows, true, NULL); + screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0); } size_t skip = off + 1; output += skip; @@ -448,8 +446,8 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, // remember that the NL was missing curbuf->b_no_eol_lnum = curwin->w_cursor.lnum; } else { - ui_write((char_u *)output, (int)remaining); - ui_write((char_u *)"\r\n", 2); + screen_del_lines(0, 0, 1, (int)Rows, true, NULL); + screen_puts_len((char_u *)output, (int)remaining, lastrow, 0, 0); } output += remaining; } else if (to_buffer) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 855c09619e..b593d5a687 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -4548,7 +4548,7 @@ static void screen_line(int row, int coloff, int endcol, int clear_width, int rl int c; c = fillchar_vsep(&hl); - if (ScreenLines[off_to] != c + if (ScreenLines[off_to] != ((schar_T)c) || (enc_utf8 && (int)ScreenLinesUC[off_to] != (c >= 0x80 ? c : 0)) || ScreenAttrs[off_to] != hl) { @@ -6150,8 +6150,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, return; /* it's a "normal" terminal when not in a GUI or cterm */ - norm_term = ( - t_colors <= 1); + norm_term = (!abstract_ui && t_colors <= 1); for (row = start_row; row < end_row; ++row) { if (has_mbyte ) { @@ -6675,7 +6674,7 @@ static void linecopy(int to, int from, win_T *wp) */ int can_clear(char_u *p) { - return *p != NUL && (t_colors <= 1 + return *p != NUL && ((!abstract_ui && t_colors <= 1) || cterm_normal_bg_color == 0 || *T_UT != NUL); } @@ -7702,8 +7701,7 @@ static void draw_tabline(void) int attr_fill = hl_attr(HLF_TPF); char_u *p; int room; - int use_sep_chars = (t_colors < 8 - ); + int use_sep_chars = !abstract_ui && t_colors < 8; redraw_tabline = FALSE; @@ -8188,6 +8186,9 @@ void screen_resize(int width, int height, int mustset) check_shellsize(); if (abstract_ui) { + // Clear the output buffer to ensure UIs don't receive redraw command meant + // for invalid screen sizes. + out_buf_clear(); ui_resize(width, height); } else { mch_set_shellsize(); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 4e2be0cd44..80dc99d6e7 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -45,6 +45,7 @@ #include "nvim/strings.h" #include "nvim/syntax_defs.h" #include "nvim/term.h" +#include "nvim/ui.h" #include "nvim/os/os.h" #include "nvim/os/time.h" @@ -5983,7 +5984,7 @@ init_highlight ( * With 8 colors brown is equal to yellow, need to use black for Search fg * to avoid Statement highlighted text disappears. * Clear the attributes, needed when changing the t_Co value. */ - if (t_colors > 8) + if (abstract_ui || t_colors > 8) do_highlight( (char_u *)(*p_bg == 'l' ? "Visual cterm=NONE ctermbg=LightGrey" @@ -6036,6 +6037,7 @@ int load_colors(char_u *name) apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf); recursive = FALSE; + ui_refresh(); return retval; } @@ -6431,7 +6433,9 @@ do_highlight ( /* Use the _16 table to check if its a valid color name. */ color = color_numbers_16[i]; if (color >= 0) { - if (t_colors == 8) { + if (abstract_ui) { + color = color_numbers_256[i]; + } else if (t_colors == 8) { /* t_Co is 8: use the 8 colors table */ #if defined(__QNXNTO__) color = color_numbers_8_qansi[i]; @@ -6448,8 +6452,7 @@ do_highlight ( HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; } color &= 7; /* truncate to 8 colors */ - } else if (t_colors == 16 || t_colors == 88 - || t_colors == 256) { + } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) { /* * Guess: if the termcap entry ends in 'm', it is * probably an xterm-like terminal. Use the changed @@ -6496,7 +6499,7 @@ do_highlight ( if (color >= 0) { if (termcap_active) term_bg_color(color); - if (t_colors < 16) + if (!abstract_ui && t_colors < 16) i = (color == 0 || color == 4); else i = (color < 7 || color == 8); @@ -6642,6 +6645,10 @@ do_highlight ( if (is_normal_group) { HL_TABLE()[idx].sg_term_attr = 0; HL_TABLE()[idx].sg_cterm_attr = 0; + if (abstract_ui) { + // If the normal group has changed, it is simpler to refresh every UI + ui_refresh(); + } } else set_hl_attr(idx); HL_TABLE()[idx].sg_scriptID = current_SID; @@ -6870,7 +6877,7 @@ int hl_combine_attr(int char_attr, int prim_attr) if (char_attr <= HL_ALL && prim_attr <= HL_ALL) return char_attr | prim_attr; - if (t_colors > 1) { + if (abstract_ui || t_colors > 1) { if (char_attr > HL_ALL) char_aep = syn_cterm_attr2entry(char_attr); if (char_aep != NULL) @@ -6934,7 +6941,7 @@ int syn_attr2attr(int attr) { attrentry_T *aep; - if (t_colors > 1) + if (abstract_ui || t_colors > 1) aep = syn_cterm_attr2entry(attr); else aep = syn_term_attr2entry(attr); @@ -7204,9 +7211,10 @@ set_hl_attr ( * For the color term mode: If there are other than "normal" * highlighting attributes, need to allocate an attr number. */ - if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0) + if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 + && sgp->sg_rgb_fg == -1 && sgp->sg_rgb_bg == -1) { sgp->sg_cterm_attr = sgp->sg_cterm; - else { + } else { at_en.ae_attr = abstract_ui ? sgp->sg_gui : sgp->sg_cterm; at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg; at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg; @@ -7361,7 +7369,7 @@ int syn_id2attr(int hl_id) hl_id = syn_get_final_id(hl_id); sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */ - if (t_colors > 1) + if (abstract_ui || t_colors > 1) attr = sgp->sg_cterm_attr; else attr = sgp->sg_term_attr; diff --git a/src/nvim/term.c b/src/nvim/term.c index b7c30300b0..1169435a4f 100644 --- a/src/nvim/term.c +++ b/src/nvim/term.c @@ -170,6 +170,7 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_DL, "\033|d"}, {(int)KS_CDL, "\033|%p1%dD"}, {(int)KS_CS, "\033|%p1%d;%p2%dR"}, + {(int)KS_CSV, "\033|%p1%d;%p2%dV"}, {(int)KS_CL, "\033|C"}, // attributes switched on with 'h', off with * 'H' {(int)KS_ME, "\033|31H"}, // HL_ALL @@ -1817,17 +1818,20 @@ void term_write(char_u *s, size_t len) static char_u out_buf[OUT_SIZE + 1]; static int out_pos = 0; /* number of chars in out_buf */ +// Clear the output buffer +void out_buf_clear(void) +{ + out_pos = 0; +} + /* * out_flush(): flush the output buffer */ void out_flush(void) { - if (out_pos != 0) { - /* set out_pos to 0 before ui_write, to avoid recursiveness */ - int len = out_pos; - out_pos = 0; - ui_write(out_buf, len); - } + int len = out_pos; + out_pos = 0; + ui_write(out_buf, len); } /* diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 25d6a81960..71960e8a63 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -60,11 +60,8 @@ static struct { int top, bot, left, right; } sr; static int current_highlight_mask = 0; -static HlAttrs current_attrs = { - false, false, false, false, false, false, -1, -1 -}; static bool cursor_enabled = true; -static int height = INT_MAX, width = INT_MAX; +static int height, width; // This set of macros allow us to use UI_CALL to invoke any function on // registered UI instances. The functions can have 0-5 arguments(configurable @@ -98,6 +95,10 @@ void ui_write(uint8_t *s, int len) return; } + if (!len) { + return; + } + char_u *tofree = NULL; if (output_conv.vc_type != CONV_NONE) { @@ -120,9 +121,7 @@ void ui_write(uint8_t *s, int len) */ void ui_suspend(void) { - if (abstract_ui) { - UI_CALL(suspend); - } else { + if (!abstract_ui) { mch_suspend(); } } @@ -165,8 +164,31 @@ void ui_cursor_shape(void) } } -void ui_resize(int width, int height) +void ui_refresh(void) +{ + if (!ui_count) { + return; + } + + int width = INT_MAX, height = INT_MAX; + + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = ui->width < width ? ui->width : width; + height = ui->height < height ? ui->height : height; + } + + screen_resize(width, height, true); +} + +void ui_resize(int new_width, int new_height) { + width = new_width; + height = new_height; + + 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)); + sr.top = 0; sr.bot = height - 1; sr.left = 0; @@ -240,7 +262,7 @@ void ui_attach(UI *ui) } uis[ui_count++] = ui; - resized(ui); + ui_refresh(); } void ui_detach(UI *ui) @@ -267,17 +289,8 @@ void ui_detach(UI *ui) ui_count--; - if (ui->width == width || ui->height == height) { - // It is possible that the UI being detached had the smallest screen, - // so check for the new minimum dimensions - width = height = INT_MAX; - for (size_t i = 0; i < ui_count; i++) { - check_dimensions(uis[i]); - } - } - if (ui_count) { - screen_resize(width, height, true); + ui_refresh(); } } @@ -295,8 +308,7 @@ static void highlight_start(int mask) return; } - set_highlight_args(current_highlight_mask, ¤t_attrs); - UI_CALL(highlight_set, current_attrs); + set_highlight_args(current_highlight_mask); } static void highlight_stop(int mask) @@ -309,12 +321,12 @@ static void highlight_stop(int mask) current_highlight_mask &= ~mask; } - set_highlight_args(current_highlight_mask, ¤t_attrs); - UI_CALL(highlight_set, current_attrs); + set_highlight_args(current_highlight_mask); } -static void set_highlight_args(int mask, HlAttrs *attrs) +static void set_highlight_args(int mask) { + HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 }; attrentry_T *aep = NULL; if (mask > HL_ALL) { @@ -322,18 +334,40 @@ static void set_highlight_args(int mask, HlAttrs *attrs) mask = aep ? aep->ae_attr : 0; } - attrs->bold = mask & HL_BOLD; - attrs->standout = mask & HL_STANDOUT; - attrs->underline = mask & HL_UNDERLINE; - attrs->undercurl = mask & HL_UNDERCURL; - attrs->italic = mask & HL_ITALIC; - attrs->reverse = mask & HL_INVERSE; - attrs->foreground = aep && aep->fg_color >= 0 ? aep->fg_color : normal_fg; - attrs->background = aep && aep->bg_color >= 0 ? aep->bg_color : normal_bg; + rgb_attrs.bold = mask & HL_BOLD; + rgb_attrs.underline = mask & HL_UNDERLINE; + rgb_attrs.undercurl = mask & HL_UNDERCURL; + rgb_attrs.italic = mask & HL_ITALIC; + rgb_attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT); + HlAttrs cterm_attrs = rgb_attrs; + + if (aep) { + if (aep->fg_color != normal_fg) { + rgb_attrs.foreground = aep->fg_color; + } + + if (aep->bg_color != normal_bg) { + rgb_attrs.background = aep->bg_color; + } + + if (cterm_normal_fg_color != aep->ae_u.cterm.fg_color) { + cterm_attrs.foreground = aep->ae_u.cterm.fg_color - 1; + } + + if (cterm_normal_bg_color != aep->ae_u.cterm.bg_color) { + cterm_attrs.background = aep->ae_u.cterm.bg_color - 1; + } + } + + UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs)); } static void parse_abstract_ui_codes(uint8_t *ptr, int len) { + if (!ui_count) { + return; + } + int arg1 = 0, arg2 = 0; uint8_t *end = ptr + len, *p, c; bool update_cursor = false; @@ -444,6 +478,9 @@ static void parse_abstract_ui_codes(uint8_t *ptr, int len) UI_CALL(put, NULL, 0); col++; } + if (col >= width) { + ui_linefeed(); + } p += clen; } ptr = p; @@ -457,25 +494,6 @@ static void parse_abstract_ui_codes(uint8_t *ptr, int len) UI_CALL(flush); } -static void resized(UI *ui) -{ - check_dimensions(ui); - screen_resize(width, height, true); -} - -static void check_dimensions(UI *ui) -{ - // The internal screen dimensions are always the minimum required to fit on - // all connected screens - if (ui->width < width) { - width = ui->width; - } - - if (ui->height < height) { - height = ui->height; - } -} - static void ui_linefeed(void) { int new_col = 0; diff --git a/src/nvim/ui.h b/src/nvim/ui.h index d0933055cc..3d3e2f4ffc 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -6,13 +6,14 @@ #include <stdint.h> typedef struct { - bool bold, standout, underline, undercurl, italic, reverse; + bool bold, underline, undercurl, italic, reverse; int foreground, background; } HlAttrs; typedef struct ui_t UI; struct ui_t { + bool rgb; int width, height; void *data; void (*resize)(UI *ui, int rows, int columns); @@ -32,7 +33,8 @@ struct ui_t { void (*bell)(UI *ui); void (*visual_bell)(UI *ui); void (*flush)(UI *ui); - void (*suspend)(UI *ui); + void (*update_fg)(UI *ui, int fg); + void (*update_bg)(UI *ui, int bg); }; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/test/functional/legacy/066_visual_block_tab_spec.lua b/test/functional/legacy/066_visual_block_tab_spec.lua index cd283e6746..82bb988c67 100644 --- a/test/functional/legacy/066_visual_block_tab_spec.lua +++ b/test/functional/legacy/066_visual_block_tab_spec.lua @@ -23,18 +23,18 @@ describe('visual block shift and tab characters', function() abcdefghijklmnopqrstuvwxyz]]) feed('gg') - feed([[fe<C-v>4jR<esc>ugvr1:'<,'>yank A<cr>]]) + feed([[fe<C-v>4jR<esc>ugvr1:'<lt>,'>yank A<cr>]]) execute('/^abcdefgh') - feed('<C-v>4jI <esc>j<<11|D') + feed('<C-v>4jI <esc>j<lt><lt>11|D') feed('j7|a <esc>') feed('j7|a <esc>') - feed('j7|a <esc>4k13|<C-v>4j<') + feed('j7|a <esc>4k13|<C-v>4j<lt>') execute('$-5,$yank A') execute([[$-4,$s/\s\+//g]]) - feed('<C-v>4kI <esc>j<<') + feed('<C-v>4kI <esc>j<lt><lt>') feed('j7|a <esc>') feed('j7|a <esc>') - feed('j7|a <esc>4k13|<C-v>4j3<') + feed('j7|a <esc>4k13|<C-v>4j3<lt>') execute('$-4,$yank A') -- Put @a and clean empty lines diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 3c55c09f95..9ab86f401f 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -142,7 +142,6 @@ describe('Default highlight groups', function() end) it('end of file markers', function() - nvim('command', 'hi Normal guibg=black') screen:expect([[ ^ | {1:~ }| diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 8e7d1ed798..5d139b367f 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -99,7 +99,6 @@ function Screen.new(width, height) _mouse_enabled = true, _bell = false, _visual_bell = false, - _suspended = true, _attrs = {}, _cursor = { enabled = true, row = 1, col = 1 @@ -115,13 +114,11 @@ function Screen:set_default_attr_ids(attr_ids) end function Screen:attach() - request('attach_ui', self._width, self._height) - self._suspended = false + request('ui_attach', self._width, self._height, true) end function Screen:detach() - request('detach_ui') - self._suspended = true + request('ui_detach') end function Screen:expect(expected, attr_ids) @@ -190,7 +187,7 @@ end function Screen:_handle_eol_clear() local row, col = self._cursor.row, self._cursor.col - self:_clear_block(row, 1, col, self._width - col) + self:_clear_block(row, 1, col, self._scroll_region.right - col) end function Screen:_handle_cursor_goto(row, col) @@ -278,8 +275,12 @@ function Screen:_handle_visual_bell() self._visual_bell = true end -function Screen:_handle_suspend() - self._suspended = true +function Screen:_handle_update_fg(fg) + self._fg = fg +end + +function Screen:_handle_update_bg(bg) + self._bg = bg end function Screen:_clear_block(top, lines, left, columns) |