diff options
Diffstat (limited to 'src/nvim/terminal.c')
-rw-r--r-- | src/nvim/terminal.c | 115 |
1 files changed, 93 insertions, 22 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 90966bcfad..106e92d43c 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -37,45 +37,57 @@ // Some code from pangoterm http://www.leonerd.org.uk/code/pangoterm #include <assert.h> +#include <limits.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <vterm.h> +#include <vterm_keycodes.h> +#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/change.h" +#include "nvim/channel.h" #include "nvim/cursor.h" +#include "nvim/drawline.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/event/loop.h" +#include "nvim/event/multiqueue.h" #include "nvim/event/time.h" -#include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/getchar.h" +#include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/keycodes.h" -#include "nvim/log.h" #include "nvim/macros.h" #include "nvim/main.h" #include "nvim/map.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" +#include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/optionstr.h" -#include "nvim/os/input.h" +#include "nvim/pos.h" +#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/terminal.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/vim.h" -#include "nvim/window.h" typedef struct terminal_state { VimState state; @@ -111,15 +123,19 @@ struct terminal { // - receive data from libvterm as a result of key presses. char textbuf[0x1fff]; - ScrollbackLine **sb_buffer; // Scrollback buffer storage for libvterm - size_t sb_current; // number of rows pushed to sb_buffer - size_t sb_size; // sb_buffer size + ScrollbackLine **sb_buffer; // Scrollback storage. + size_t sb_current; // Lines stored in sb_buffer. + size_t sb_size; // Capacity of sb_buffer. // "virtual index" that points to the first sb_buffer row that we need to // push to the terminal buffer when refreshing the scrollback. When negative, // it actually points to entries that are no longer in sb_buffer (because the // window height has increased) and must be deleted from the terminal buffer int sb_pending; + char *title; // VTermStringFragment buffer + size_t title_len; // number of rows pushed to sb_buffer + size_t title_size; // sb_buffer size + // buf_T instance that acts as a "drawing surface" for libvterm // we can't store a direct reference to the buffer because the // refresh_timer_cb may be called after the buffer was freed, and there's @@ -150,7 +166,7 @@ static VTermScreenCallbacks vterm_screen_callbacks = { .movecursor = term_movecursor, .settermprop = term_settermprop, .bell = term_bell, - .sb_pushline = term_sb_push, + .sb_pushline = term_sb_push, // Called before a line goes offscreen. .sb_popline = term_sb_pop, }; @@ -230,7 +246,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts) set_option_value("wrap", false, NULL, OPT_LOCAL); set_option_value("list", false, NULL, OPT_LOCAL); if (buf->b_ffname != NULL) { - buf_set_term_title(buf, buf->b_ffname); + buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname)); } RESET_BINDING(curwin); // Reset cursor in current window. @@ -371,7 +387,7 @@ void terminal_check_size(Terminal *term) // Check if there is a window that displays the terminal and find the maximum width and height. // Skip the autocommand window which isn't actually displayed. FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp == aucmd_win) { + if (is_aucmd_win(wp)) { continue; } if (wp->w_buffer && wp->w_buffer->terminal == term) { @@ -424,7 +440,7 @@ bool terminal_enter(void) long save_w_p_so = curwin->w_p_so; long save_w_p_siso = curwin->w_p_siso; if (curwin->w_p_cul && curwin->w_p_culopt_flags & CULOPT_NBR) { - if (STRCMP(curwin->w_p_culopt, "number")) { + if (strcmp(curwin->w_p_culopt, "number") != 0) { save_w_p_culopt = curwin->w_p_culopt; curwin->w_p_culopt = xstrdup("number"); } @@ -518,7 +534,19 @@ static int terminal_check(VimState *state) terminal_check_cursor(); if (must_redraw) { - update_screen(0); + update_screen(); + + // Make sure an invoked autocmd doesn't delete the buffer (and the + // terminal) under our fingers. + curbuf->b_locked++; + + // save and restore curwin and curbuf, in case the autocmd changes them + aco_save_T aco; + aucmd_prepbuf(&aco, curbuf); + apply_autocmds(EVENT_TEXTCHANGEDT, NULL, NULL, false, curbuf); + aucmd_restbuf(&aco); + + curbuf->b_locked--; } if (need_maketitle) { // Update title in terminal-mode. #7248 @@ -636,6 +664,7 @@ void terminal_destroy(Terminal **termpp) xfree(term->sb_buffer[i]); } xfree(term->sb_buffer); + xfree(term->title); vterm_free(term->vt); xfree(term); *termpp = NULL; // coverity[dead-store] @@ -688,7 +717,7 @@ void terminal_paste(long count, char **y_array, size_t y_size) return; } vterm_keyboard_start_paste(curbuf->terminal->vt); - size_t buff_len = STRLEN(y_array[0]); + size_t buff_len = strlen(y_array[0]); char_u *buff = xmalloc(buff_len); for (int i = 0; i < count; i++) { // -V756 // feed the lines to the terminal @@ -697,7 +726,7 @@ void terminal_paste(long count, char **y_array, size_t y_size) // terminate the previous line terminal_send(curbuf->terminal, "\n", 1); } - size_t len = STRLEN(y_array[j]); + size_t len = strlen(y_array[j]); if (len > buff_len) { buff = xrealloc(buff, len); buff_len = len; @@ -754,6 +783,22 @@ static int get_rgb(VTermState *state, VTermColor color) return RGB_(color.rgb.red, color.rgb.green, color.rgb.blue); } +static int get_underline_hl_flag(VTermScreenCellAttrs attrs) +{ + switch (attrs.underline) { + case VTERM_UNDERLINE_OFF: + return 0; + case VTERM_UNDERLINE_SINGLE: + return HL_UNDERLINE; + case VTERM_UNDERLINE_DOUBLE: + return HL_UNDERDOUBLE; + case VTERM_UNDERLINE_CURLY: + return HL_UNDERCURL; + default: + return HL_UNDERLINE; + } +} + void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *term_attrs) { int height, width; @@ -790,7 +835,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0) | (cell.attrs.italic ? HL_ITALIC : 0) | (cell.attrs.reverse ? HL_INVERSE : 0) - | (cell.attrs.underline ? HL_UNDERLINE : 0) + | get_underline_hl_flag(cell.attrs) | (cell.attrs.strike ? HL_STRIKETHROUGH: 0) | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0) | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0); @@ -858,13 +903,13 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data) return 1; } -static void buf_set_term_title(buf_T *buf, char *title) +static void buf_set_term_title(buf_T *buf, const char *title, size_t len) FUNC_ATTR_NONNULL_ALL { Error err = ERROR_INIT; dict_set_var(buf->b_vars, STATIC_CSTR_AS_STRING("term_title"), - STRING_OBJ(cstr_as_string(title)), + STRING_OBJ(((String){ .data = (char *)title, .size = len })), false, false, &err); @@ -887,7 +932,30 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) case VTERM_PROP_TITLE: { buf_T *buf = handle_get_buffer(term->buf_handle); - buf_set_term_title(buf, val->string); + VTermStringFragment frag = val->string; + + if (frag.initial && frag.final) { + buf_set_term_title(buf, frag.str, frag.len); + break; + } + + if (frag.initial) { + term->title_len = 0; + term->title_size = MAX(frag.len, 1024); + term->title = xmalloc(sizeof(char *) * term->title_size); + } else if (term->title_len + frag.len > term->title_size) { + term->title_size *= 2; + term->title = xrealloc(term->title, sizeof(char *) * term->title_size); + } + + memcpy(term->title + term->title_len, frag.str, frag.len); + term->title_len += frag.len; + + if (frag.final) { + buf_set_term_title(buf, term->title, term->title_len); + xfree(term->title); + term->title = NULL; + } break; } @@ -908,7 +976,10 @@ static int term_bell(void *data) return 1; } -// Scrollback push handler (from pangoterm). +/// Scrollback push handler: called just before a line goes offscreen (and libvterm will forget it), +/// giving us a chance to store it. +/// +/// Code adapted from pangoterm. static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) { Terminal *term = data; @@ -1368,8 +1439,8 @@ static bool send_mouse_event(Terminal *term, int c) int direction = c == K_MOUSEDOWN ? MSCR_DOWN : MSCR_UP; if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) { scroll_redraw(direction, curwin->w_botline - curwin->w_topline); - } else { - scroll_redraw(direction, 3L); + } else if (p_mousescroll_vert > 0) { + scroll_redraw(direction, p_mousescroll_vert); } curwin->w_redr_status = true; |