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.c197
1 files changed, 156 insertions, 41 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 85c4950b42..d006477c80 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1,3 +1,6 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
// VT220/xterm-like terminal emulator.
// Powered by libvterm http://www.leonerd.org.uk/code/libvterm
//
@@ -40,6 +43,7 @@
#include <vterm.h>
+#include "nvim/log.h"
#include "nvim/vim.h"
#include "nvim/terminal.h"
#include "nvim/message.h"
@@ -57,7 +61,6 @@
#include "nvim/edit.h"
#include "nvim/mouse.h"
#include "nvim/memline.h"
-#include "nvim/mark.h"
#include "nvim/map.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
@@ -177,13 +180,14 @@ void terminal_init(void)
vterm_state_get_palette_color(state, color_index, &color);
}
map_put(int, int)(color_indexes,
- RGB(color.red, color.green, color.blue), color_index + 1);
+ RGB_(color.red, color.green, color.blue),
+ color_index + 1);
}
VTermColor fg, bg;
vterm_state_get_default_colors(state, &fg, &bg);
- default_vt_fg = RGB(fg.red, fg.green, fg.blue);
- default_vt_bg = RGB(bg.red, bg.green, bg.blue);
+ default_vt_fg = RGB_(fg.red, fg.green, fg.blue);
+ default_vt_bg = RGB_(bg.red, bg.green, bg.blue);
default_vt_bg_rgb = bg;
vterm_free(vt);
}
@@ -226,7 +230,7 @@ Terminal *terminal_open(TerminalOptions opts)
rv->invalid_start = 0;
rv->invalid_end = opts.height;
refresh_screen(rv, curbuf);
- set_option_value("buftype", 0, "terminal", OPT_LOCAL);
+ set_option_value("buftype", 0, "terminal", OPT_LOCAL); // -V666
// Default settings for terminal buffers
curbuf->b_p_ma = false; // 'nomodifiable'
@@ -234,8 +238,6 @@ Terminal *terminal_open(TerminalOptions opts)
curbuf->b_p_scbk = p_scbk; // 'scrollback'
curbuf->b_p_tw = 0; // 'textwidth'
set_option_value("wrap", false, NULL, OPT_LOCAL);
- set_option_value("number", false, NULL, OPT_LOCAL);
- set_option_value("relativenumber", false, NULL, OPT_LOCAL);
set_option_value("list", false, NULL, OPT_LOCAL);
buf_set_term_title(curbuf, (char *)curbuf->b_ffname);
RESET_BINDING(curwin);
@@ -299,8 +301,16 @@ void terminal_close(Terminal *term, char *msg)
}
term->forward_mouse = false;
- term->closed = true;
+
+ // flush any pending changes to the buffer
+ if (!exiting) {
+ block_autocmds();
+ refresh_terminal(term);
+ unblock_autocmds();
+ }
+
buf_T *buf = handle_get_buffer(term->buf_handle);
+ term->closed = true;
if (!msg || exiting) {
// If no msg was given, this was called by close_buffer(buffer.c). Or if
@@ -349,6 +359,15 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
return;
}
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer && wp->w_buffer->terminal == term) {
+ const uint16_t win_width =
+ (uint16_t)(MAX(0, wp->w_width - win_col_off(wp)));
+ width = MAX(width, win_width);
+ height = (uint16_t)MAX(height, wp->w_height);
+ }
+ }
+
vterm_set_size(term->vt, height, width);
vterm_screen_flush_damage(term->vts);
term->pending_resize = true;
@@ -366,8 +385,6 @@ void terminal_enter(void)
// Ensure the terminal is properly sized.
terminal_resize(s->term, 0, 0);
- checkpcmark();
- setpcmark();
int save_state = State;
s->save_rd = RedrawingDisabled;
State = TERM_FOCUS;
@@ -422,14 +439,6 @@ static int terminal_execute(VimState *state, int key)
TerminalState *s = (TerminalState *)state;
switch (key) {
- case K_FOCUSGAINED: // nvim has been given focus
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
- break;
-
- case K_FOCUSLOST: // nvim has lost focus
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
- break;
-
// Temporary fix until paste events gets implemented
case K_PASTE:
break;
@@ -461,6 +470,10 @@ static int terminal_execute(VimState *state, int key)
}
break;
+ case K_COMMAND:
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
+
case Ctrl_N:
if (s->got_bsl) {
return 0;
@@ -520,6 +533,12 @@ void terminal_send(Terminal *term, char *data, size_t size)
void terminal_send_key(Terminal *term, int c)
{
VTermModifier mod = VTERM_MOD_NONE;
+
+ // Convert K_ZERO back to ASCII
+ if (c == K_ZERO) {
+ c = Ctrl_AT;
+ }
+
VTermKey key = convert_key(c, &mod);
if (key) {
@@ -544,7 +563,7 @@ void terminal_receive(Terminal *term, char *data, size_t len)
}
void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
- int *term_attrs)
+ int *term_attrs)
{
int height, width;
vterm_get_size(term->vt, &height, &width);
@@ -560,8 +579,8 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
VTermScreenCell cell;
fetch_cell(term, row, col, &cell);
// Get the rgb value set by libvterm.
- int vt_fg = RGB(cell.fg.red, cell.fg.green, cell.fg.blue);
- int vt_bg = RGB(cell.bg.red, cell.bg.green, cell.bg.blue);
+ int vt_fg = RGB_(cell.fg.red, cell.fg.green, cell.fg.blue);
+ int vt_bg = RGB_(cell.bg.red, cell.bg.green, cell.bg.blue);
vt_fg = vt_fg != default_vt_fg ? vt_fg : - 1;
vt_bg = vt_bg != default_vt_bg ? vt_bg : - 1;
// Since libvterm does not expose the color index used by the program, we
@@ -580,7 +599,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,
@@ -592,8 +611,10 @@ 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 ?
- hl_attr(HLF_TERM) : hl_attr(HLF_TERMNC));
+ attr_id = hl_combine_attr(attr_id,
+ is_focused(term) && wp == curwin
+ ? win_hl_attr(wp, HLF_TERM)
+ : win_hl_attr(wp, HLF_TERMNC));
}
term_attrs[col] = attr_id;
@@ -628,15 +649,16 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible,
}
static void buf_set_term_title(buf_T *buf, char *title)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL
{
- Error err;
+ Error err = ERROR_INIT;
dict_set_var(buf->b_vars,
STATIC_CSTR_AS_STRING("term_title"),
STRING_OBJ(cstr_as_string(title)),
false,
false,
&err);
+ api_clear_error(&err);
}
static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
@@ -671,7 +693,7 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
static int term_bell(void *data)
{
- ui_putc('\x07');
+ ui_call_bell();
return 1;
}
@@ -770,26 +792,60 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
// }}}
// input handling {{{
-static void convert_modifiers(VTermModifier *statep)
+static void convert_modifiers(int key, VTermModifier *statep)
{
if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; }
if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; }
if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; }
+
+ switch (key) {
+ case K_S_TAB:
+ case K_S_UP:
+ case K_S_DOWN:
+ case K_S_LEFT:
+ case K_S_RIGHT:
+ case K_S_F1:
+ case K_S_F2:
+ case K_S_F3:
+ case K_S_F4:
+ case K_S_F5:
+ case K_S_F6:
+ case K_S_F7:
+ case K_S_F8:
+ case K_S_F9:
+ case K_S_F10:
+ case K_S_F11:
+ case K_S_F12:
+ *statep |= VTERM_MOD_SHIFT;
+ break;
+
+ case K_C_LEFT:
+ case K_C_RIGHT:
+ *statep |= VTERM_MOD_CTRL;
+ break;
+ }
}
static VTermKey convert_key(int key, VTermModifier *statep)
{
- convert_modifiers(statep);
+ convert_modifiers(key, statep);
switch (key) {
case K_BS: return VTERM_KEY_BACKSPACE;
+ case K_S_TAB: // FALLTHROUGH
case TAB: return VTERM_KEY_TAB;
case Ctrl_M: return VTERM_KEY_ENTER;
case ESC: return VTERM_KEY_ESCAPE;
+ case K_S_UP: // FALLTHROUGH
case K_UP: return VTERM_KEY_UP;
+ case K_S_DOWN: // FALLTHROUGH
case K_DOWN: return VTERM_KEY_DOWN;
+ case K_S_LEFT: // FALLTHROUGH
+ case K_C_LEFT: // FALLTHROUGH
case K_LEFT: return VTERM_KEY_LEFT;
+ case K_S_RIGHT: // FALLTHROUGH
+ case K_C_RIGHT: // FALLTHROUGH
case K_RIGHT: return VTERM_KEY_RIGHT;
case K_INS: return VTERM_KEY_INS;
@@ -799,22 +855,22 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_PAGEUP: return VTERM_KEY_PAGEUP;
case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN;
- case K_K0:
+ case K_K0: // FALLTHROUGH
case K_KINS: return VTERM_KEY_KP_0;
- case K_K1:
+ case K_K1: // FALLTHROUGH
case K_KEND: return VTERM_KEY_KP_1;
case K_K2: return VTERM_KEY_KP_2;
- case K_K3:
+ case K_K3: // FALLTHROUGH
case K_KPAGEDOWN: return VTERM_KEY_KP_3;
case K_K4: return VTERM_KEY_KP_4;
case K_K5: return VTERM_KEY_KP_5;
case K_K6: return VTERM_KEY_KP_6;
- case K_K7:
+ case K_K7: // FALLTHROUGH
case K_KHOME: return VTERM_KEY_KP_7;
case K_K8: return VTERM_KEY_KP_8;
- case K_K9:
+ case K_K9: // FALLTHROUGH
case K_KPAGEUP: return VTERM_KEY_KP_9;
- case K_KDEL:
+ case K_KDEL: // FALLTHROUGH
case K_KPOINT: return VTERM_KEY_KP_PERIOD;
case K_KENTER: return VTERM_KEY_KP_ENTER;
case K_KPLUS: return VTERM_KEY_KP_PLUS;
@@ -822,6 +878,57 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_KMULTIPLY: return VTERM_KEY_KP_MULT;
case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE;
+ case K_S_F1: // FALLTHROUGH
+ case K_F1: return VTERM_KEY_FUNCTION(1);
+ case K_S_F2: // FALLTHROUGH
+ case K_F2: return VTERM_KEY_FUNCTION(2);
+ case K_S_F3: // FALLTHROUGH
+ case K_F3: return VTERM_KEY_FUNCTION(3);
+ case K_S_F4: // FALLTHROUGH
+ case K_F4: return VTERM_KEY_FUNCTION(4);
+ case K_S_F5: // FALLTHROUGH
+ case K_F5: return VTERM_KEY_FUNCTION(5);
+ case K_S_F6: // FALLTHROUGH
+ case K_F6: return VTERM_KEY_FUNCTION(6);
+ case K_S_F7: // FALLTHROUGH
+ case K_F7: return VTERM_KEY_FUNCTION(7);
+ case K_S_F8: // FALLTHROUGH
+ case K_F8: return VTERM_KEY_FUNCTION(8);
+ case K_S_F9: // FALLTHROUGH
+ case K_F9: return VTERM_KEY_FUNCTION(9);
+ case K_S_F10: // FALLTHROUGH
+ case K_F10: return VTERM_KEY_FUNCTION(10);
+ case K_S_F11: // FALLTHROUGH
+ case K_F11: return VTERM_KEY_FUNCTION(11);
+ case K_S_F12: // FALLTHROUGH
+ case K_F12: return VTERM_KEY_FUNCTION(12);
+
+ case K_F13: return VTERM_KEY_FUNCTION(13);
+ case K_F14: return VTERM_KEY_FUNCTION(14);
+ case K_F15: return VTERM_KEY_FUNCTION(15);
+ case K_F16: return VTERM_KEY_FUNCTION(16);
+ case K_F17: return VTERM_KEY_FUNCTION(17);
+ case K_F18: return VTERM_KEY_FUNCTION(18);
+ case K_F19: return VTERM_KEY_FUNCTION(19);
+ case K_F20: return VTERM_KEY_FUNCTION(20);
+ case K_F21: return VTERM_KEY_FUNCTION(21);
+ case K_F22: return VTERM_KEY_FUNCTION(22);
+ case K_F23: return VTERM_KEY_FUNCTION(23);
+ case K_F24: return VTERM_KEY_FUNCTION(24);
+ case K_F25: return VTERM_KEY_FUNCTION(25);
+ case K_F26: return VTERM_KEY_FUNCTION(26);
+ case K_F27: return VTERM_KEY_FUNCTION(27);
+ case K_F28: return VTERM_KEY_FUNCTION(28);
+ case K_F29: return VTERM_KEY_FUNCTION(29);
+ case K_F30: return VTERM_KEY_FUNCTION(30);
+ case K_F31: return VTERM_KEY_FUNCTION(31);
+ case K_F32: return VTERM_KEY_FUNCTION(32);
+ case K_F33: return VTERM_KEY_FUNCTION(33);
+ case K_F34: return VTERM_KEY_FUNCTION(34);
+ case K_F35: return VTERM_KEY_FUNCTION(35);
+ case K_F36: return VTERM_KEY_FUNCTION(36);
+ case K_F37: return VTERM_KEY_FUNCTION(37);
+
default: return VTERM_KEY_NONE;
}
}
@@ -990,7 +1097,6 @@ static void refresh_terminal(Terminal *term)
refresh_size(term, buf);
refresh_scrollback(term, buf);
refresh_screen(term, buf);
- redraw_buf_later(buf, NOT_VALID);
});
long ml_added = buf->b_ml.ml_line_count - ml_before;
adjust_topline(term, buf, ml_added);
@@ -998,8 +1104,13 @@ static void refresh_terminal(Terminal *term)
// Calls refresh_terminal() on all invalidated_terminals.
static void refresh_timer_cb(TimeWatcher *watcher, void *data)
{
- if (exiting) { // Cannot redraw (requires event loop) during teardown/exit.
- goto end;
+ refresh_pending = false;
+ if (exiting // Cannot redraw (requires event loop) during teardown/exit.
+ || (State & CMDPREVIEW)
+ // WM_LIST (^D) is not redrawn, unlike the normal wildmenu. So we must
+ // skip redraws to keep it visible.
+ || wild_menu_showing == WM_LIST) {
+ return;
}
Terminal *term;
void *stub; (void)(stub);
@@ -1014,8 +1125,6 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
if (any_visible) {
redraw(true);
}
-end:
- refresh_pending = false;
}
static void refresh_size(Terminal *term, buf_T *buf)
@@ -1160,6 +1269,10 @@ static void redraw(bool restore_cursor)
update_screen(0);
}
+ if (need_maketitle) { // Update title in terminal-mode. #7248
+ maketitle();
+ }
+
if (restore_cursor) {
ui_cursor_goto(save_row, save_col);
} else if (term) {
@@ -1217,12 +1330,14 @@ static bool is_focused(Terminal *term)
#define GET_CONFIG_VALUE(k, o) \
do { \
- Error err; \
+ Error err = ERROR_INIT; \
/* Only called from terminal_open where curbuf->terminal is the */ \
/* context */ \
o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \
+ api_clear_error(&err); \
if (o.type == kObjectTypeNil) { \
o = dict_get_value(&globvardict, cstr_as_string(k), &err); \
+ api_clear_error(&err); \
} \
} while (0)