aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/terminal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/terminal.c')
-rw-r--r--src/nvim/terminal.c131
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;
}