diff options
Diffstat (limited to 'src/nvim/terminal.c')
-rw-r--r-- | src/nvim/terminal.c | 131 |
1 files changed, 60 insertions, 71 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index daba7b943f..8ee47b2642 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -130,8 +130,6 @@ struct terminal { // the default values are used to obtain the color numbers passed to cterm // colors RgbValue colors[256]; - // attributes for focused/unfocused cursor cells - int focused_cursor_attr_id, unfocused_cursor_attr_id; }; static VTermScreenCallbacks vterm_screen_callbacks = { @@ -245,7 +243,7 @@ Terminal *terminal_open(TerminalOptions opts) char *name = get_config_string(rv, var); if (name) { color_val = name_to_color((uint8_t *)name); - free(name); + xfree(name); if (color_val != -1) { rv->colors[i] = color_val; @@ -260,41 +258,6 @@ Terminal *terminal_open(TerminalOptions opts) } } - // Configure cursor highlighting when focused/unfocused - char *group = get_config_string(rv, "terminal_focused_cursor_highlight"); - if (group) { - int group_id = syn_name2id((uint8_t *)group); - free(group); - - if (group_id) { - rv->focused_cursor_attr_id = syn_id2attr(group_id); - } - } - if (!rv->focused_cursor_attr_id) { - rv->focused_cursor_attr_id = get_attr_entry(&(attrentry_T) { - .rgb_ae_attr = HL_INVERSE, .rgb_fg_color = -1, .rgb_bg_color = -1, - .cterm_ae_attr = HL_INVERSE, .cterm_fg_color = 0, .cterm_bg_color = 0 - }); - } - - group = get_config_string(rv, "terminal_unfocused_cursor_highlight"); - if (group) { - int group_id = syn_name2id((uint8_t *)group); - free(group); - - if (group_id) { - rv->unfocused_cursor_attr_id = syn_id2attr(group_id); - } - } - if (!rv->unfocused_cursor_attr_id) { - int yellow_rgb = RGB(0xfc, 0xe9, 0x4f); - int yellow_term = 12; - rv->unfocused_cursor_attr_id = get_attr_entry(&(attrentry_T) { - .rgb_ae_attr = 0, .rgb_fg_color = -1, .rgb_bg_color = yellow_rgb, - .cterm_ae_attr = 0, .cterm_fg_color = 0, .cterm_bg_color = yellow_term, - }); - } - return rv; } @@ -307,9 +270,12 @@ void terminal_close(Terminal *term, char *msg) term->forward_mouse = false; term->closed = true; if (!msg || exiting) { - // If no msg was given, this was called by close_buffer(buffer.c) so we - // should not wait for the user to press a key. Also cannot wait if - // `exiting == true` + // If no msg was given, this was called by close_buffer(buffer.c). Or if + // exiting, we must inform the buffer the terminal no longer exists so that + // close_buffer() doesn't call this again. + term->buf->terminal = NULL; + term->buf = NULL; + // We should not wait for the user to press a key. term->opts.close_cb(term->opts.data); } else { terminal_receive(term, msg, strlen(msg)); @@ -338,7 +304,7 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height) // terminal in the current tab. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (!wp->w_closing && wp->w_buffer == term->buf) { - width = (uint16_t)MIN(width, (uint16_t)wp->w_width); + width = (uint16_t)MIN(width, (uint16_t)(wp->w_width - win_col_off(wp))); height = (uint16_t)MIN(height, (uint16_t)wp->w_height); } } @@ -353,8 +319,14 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height) invalidate_terminal(term, -1, -1); } -void terminal_enter(Terminal *term, bool process_deferred) +void terminal_enter(bool process_deferred) { + Terminal *term = curbuf->terminal; + assert(term && "should only be called when curbuf has a terminal"); + + // Ensure the terminal is properly sized. + terminal_resize(term, 0, 0); + checkpcmark(); setpcmark(); int save_state = State; @@ -373,7 +345,9 @@ void terminal_enter(Terminal *term, bool process_deferred) int c; bool close = false; - for (;;) { + bool got_bs = false; // True if the last input was <C-\> + + while (term->buf == curbuf) { if (process_deferred) { event_enable_deferred(); } @@ -385,14 +359,6 @@ void terminal_enter(Terminal *term, bool process_deferred) } switch (c) { - case Ctrl_BSL: - c = safe_vgetc(); - if (c == Ctrl_N) { - goto end; - } - terminal_send_key(term, c); - break; - case K_LEFTMOUSE: case K_LEFTDRAG: case K_LEFTRELEASE: @@ -413,12 +379,23 @@ void terminal_enter(Terminal *term, bool process_deferred) event_process(); break; + case Ctrl_N: + if (got_bs) { + goto end; + } + // FALLTHROUGH + default: + if (c == Ctrl_BSL && !got_bs) { + got_bs = true; + break; + } if (term->closed) { close = true; goto end; } + got_bs = false; terminal_send_key(term, c); } } @@ -431,7 +408,7 @@ end: invalidate_terminal(term, term->cursor.row, term->cursor.row + 1); mapped_ctrl_c = save_mapped_ctrl_c; unshowmode(true); - redraw(false); + redraw(term->buf != curbuf); ui_busy_stop(); if (close) { term->opts.close_cb(term->opts.data); @@ -441,15 +418,17 @@ end: void terminal_destroy(Terminal *term) { - term->buf->terminal = NULL; + if (term->buf) { + term->buf->terminal = NULL; + } term->buf = NULL; pmap_del(ptr_t)(invalidated_terminals, term); for (size_t i = 0 ; i < term->sb_current; i++) { - free(term->sb_buffer[i]); + xfree(term->sb_buffer[i]); } - free(term->sb_buffer); + xfree(term->sb_buffer); vterm_free(term->vt); - free(term); + xfree(term); } void terminal_send(Terminal *term, char *data, size_t size) @@ -540,7 +519,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, if (term->cursor.visible && term->cursor.row == row && term->cursor.col == col) { attr_id = hl_combine_attr(attr_id, is_focused(term) && wp == curwin ? - term->focused_cursor_attr_id : term->unfocused_cursor_attr_id); + hl_attr(HLF_TERM) : hl_attr(HLF_TERMNC)); } term_attrs[col] = attr_id; @@ -624,7 +603,7 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) // Recycle old row if it's the right size sbrow = term->sb_buffer[term->sb_current - 1]; } else { - free(term->sb_buffer[term->sb_current - 1]); + xfree(term->sb_buffer[term->sb_current - 1]); } memmove(term->sb_buffer + 1, term->sb_buffer, @@ -685,7 +664,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) cells[col].chars[0] = 0; cells[col].width = 1; } - free(sbrow); + xfree(sbrow); pmap_put(ptr_t)(invalidated_terminals, term, NULL); return 1; @@ -783,11 +762,11 @@ static bool send_mouse_event(Terminal *term, int c) bool drag = false; switch (c) { - case K_LEFTDRAG: drag = true; + case K_LEFTDRAG: drag = true; // FALLTHROUGH case K_LEFTMOUSE: button = 1; break; - case K_MIDDLEDRAG: drag = true; + case K_MIDDLEDRAG: drag = true; // FALLTHROUGH case K_MIDDLEMOUSE: button = 2; break; - case K_RIGHTDRAG: drag = true; + case K_RIGHTDRAG: drag = true; // FALLTHROUGH case K_RIGHTMOUSE: button = 3; break; case K_MOUSEDOWN: button = 4; break; case K_MOUSEUP: button = 5; break; @@ -916,12 +895,16 @@ static void on_refresh(Event event) } Terminal *term; void *stub; (void)(stub); - // dont process autocommands while updating terminal buffers. JobActivity can - // be used act on terminal output. + // don't process autocommands while updating terminal buffers block_autocmds(); map_foreach(invalidated_terminals, term, stub, { - if (!term->buf) { + // TODO(SplinterOfChaos): Find the condition that makes term->buf invalid. + bool valid = true; + if (!term->buf || !(valid = buf_valid(term->buf))) { // destroyed by `close_buffer`. Dont do anything else + if (!valid) { + term->buf = NULL; + } continue; } bool pending_resize = term->pending_resize; @@ -1018,6 +1001,11 @@ static void refresh_screen(Terminal *term) static void redraw(bool restore_cursor) { + Terminal *term = curbuf->terminal; + if (!term) { + restore_cursor = true; + } + int save_row, save_col; if (restore_cursor) { // save the current row/col to restore after updating screen when not @@ -1040,14 +1028,13 @@ static void redraw(bool restore_cursor) showruler(false); - Terminal *term = curbuf->terminal; if (term && is_focused(term)) { curwin->w_wrow = term->cursor.row; curwin->w_wcol = term->cursor.col + win_col_off(curwin); setcursor(); } else if (restore_cursor) { ui_cursor_goto(save_row, save_col); - } else { + } else if (term) { // exiting terminal focus, put the window cursor in a valid position int height, width; vterm_get_size(term->vt, &height, &width); @@ -1099,28 +1086,30 @@ static bool is_focused(Terminal *term) do { \ Error err; \ o = dict_get_value(t->buf->b_vars, cstr_as_string(k), &err); \ - if (obj.type == kObjectTypeNil) { \ + if (o.type == kObjectTypeNil) { \ o = dict_get_value(&globvardict, cstr_as_string(k), &err); \ } \ } while (0) static char *get_config_string(Terminal *term, char *key) { - Object obj = OBJECT_INIT; + Object obj; GET_CONFIG_VALUE(term, key, obj); if (obj.type == kObjectTypeString) { return obj.data.string.data; } + api_free_object(obj); return NULL; } static int get_config_int(Terminal *term, char *key) { - Object obj = OBJECT_INIT; + Object obj; GET_CONFIG_VALUE(term, key, obj); if (obj.type == kObjectTypeInteger) { return (int)obj.data.integer; } + api_free_object(obj); return 0; } |