aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/terminal.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
commit21cb7d04c387e4198ca8098a884c78b56ffcf4c2 (patch)
tree84fe5690df1551f0bb2bdfe1a13aacd29ebc1de7 /src/nvim/terminal.c
parentd9c904f85a23a496df4eb6be42aa43f007b22d50 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-colorcolchar.tar.gz
rneovim-colorcolchar.tar.bz2
rneovim-colorcolchar.zip
Merge remote-tracking branch 'upstream/master' into colorcolcharcolorcolchar
Diffstat (limited to 'src/nvim/terminal.c')
-rw-r--r--src/nvim/terminal.c196
1 files changed, 125 insertions, 71 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index a52a34cd66..1527738165 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1,6 +1,3 @@
-// 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
//
@@ -48,7 +45,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
@@ -59,19 +56,18 @@
#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_docmd.h"
+#include "nvim/func_attr.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/keycodes.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/main.h"
-#include "nvim/map.h"
+#include "nvim/map_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -79,15 +75,16 @@
#include "nvim/move.h"
#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/normal.h"
+#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/option_vars.h"
#include "nvim/optionstr.h"
-#include "nvim/pos.h"
-#include "nvim/screen.h"
+#include "nvim/pos_defs.h"
#include "nvim/state.h"
#include "nvim/terminal.h"
-#include "nvim/types.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
typedef struct terminal_state {
VimState state;
@@ -161,16 +158,16 @@ struct terminal {
};
static VTermScreenCallbacks vterm_screen_callbacks = {
- .damage = term_damage,
- .moverect = term_moverect,
- .movecursor = term_movecursor,
+ .damage = term_damage,
+ .moverect = term_moverect,
+ .movecursor = term_movecursor,
.settermprop = term_settermprop,
- .bell = term_bell,
+ .bell = term_bell,
.sb_pushline = term_sb_push, // Called before a line goes offscreen.
- .sb_popline = term_sb_pop,
+ .sb_popline = term_sb_pop,
};
-static PMap(ptr_t) invalidated_terminals = MAP_INIT;
+static Set(ptr_t) invalidated_terminals = SET_INIT;
void terminal_init(void)
{
@@ -184,10 +181,10 @@ void terminal_teardown(void)
time_watcher_stop(&refresh_timer);
multiqueue_free(refresh_timer.events);
time_watcher_close(&refresh_timer, NULL);
- pmap_destroy(ptr_t)(&invalidated_terminals);
+ set_destroy(ptr_t, &invalidated_terminals);
// terminal_destroy might be called after terminal_teardown is invoked
// make sure it is in an empty, valid state
- pmap_init(ptr_t, &invalidated_terminals);
+ invalidated_terminals = (Set(ptr_t)) SET_INIT;
}
static void term_output_callback(const char *s, size_t len, void *user_data)
@@ -204,10 +201,11 @@ static void term_output_callback(const char *s, size_t len, void *user_data)
///
/// @param buf Buffer used for presentation of the terminal.
/// @param opts PTY process channel, various terminal properties and callbacks.
-Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
+void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
+ FUNC_ATTR_NONNULL_ALL
{
// Create a new terminal instance and configure it
- Terminal *rv = xcalloc(1, sizeof(Terminal));
+ Terminal *rv = *termpp = xcalloc(1, sizeof(Terminal));
rv->opts = opts;
rv->cursor.visible = true;
// Associate the terminal instance with the new buffer
@@ -221,6 +219,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
// Set up screen
rv->vts = vterm_obtain_screen(rv->vt);
vterm_screen_enable_altscreen(rv->vts, true);
+ vterm_screen_enable_reflow(rv->vts, true);
// delete empty lines at the end of the buffer
vterm_screen_set_callbacks(rv->vts, &vterm_screen_callbacks, rv);
vterm_screen_set_damage_merge(rv->vts, VTERM_DAMAGE_SCROLL);
@@ -235,7 +234,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
aucmd_prepbuf(&aco, buf);
refresh_screen(rv, buf);
- set_option_value("buftype", 0, "terminal", OPT_LOCAL); // -V666
+ set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL);
// Default settings for terminal buffers
buf->b_p_ma = false; // 'nomodifiable'
@@ -243,26 +242,34 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
buf->b_p_scbk = // 'scrollback' (initialize local from global)
(p_scbk < 0) ? 10000 : MAX(1, p_scbk);
buf->b_p_tw = 0; // 'textwidth'
- set_option_value("wrap", false, NULL, OPT_LOCAL);
- set_option_value("list", false, NULL, OPT_LOCAL);
+ set_option_value("wrap", BOOLEAN_OPTVAL(false), OPT_LOCAL);
+ set_option_value("list", BOOLEAN_OPTVAL(false), OPT_LOCAL);
if (buf->b_ffname != NULL) {
buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname));
}
RESET_BINDING(curwin);
// Reset cursor in current window.
curwin->w_cursor = (pos_T){ .lnum = 1, .col = 0, .coladd = 0 };
- // Initialize to check if the scrollback buffer has been allocated inside a TermOpen autocmd
+ // Initialize to check if the scrollback buffer has been allocated in a TermOpen autocmd.
rv->sb_buffer = NULL;
// Apply TermOpen autocmds _before_ configuring the scrollback buffer.
apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, buf);
- // Local 'scrollback' _after_ autocmds.
- buf->b_p_scbk = (buf->b_p_scbk < 1) ? SB_MAX : buf->b_p_scbk;
aucmd_restbuf(&aco);
- // Configure the scrollback buffer.
- rv->sb_size = (size_t)buf->b_p_scbk;
- rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
+ if (*termpp == NULL) {
+ return; // Terminal has already been destroyed.
+ }
+
+ if (rv->sb_buffer == NULL) {
+ // Local 'scrollback' _after_ autocmds.
+ if (buf->b_p_scbk < 1) {
+ buf->b_p_scbk = SB_MAX;
+ }
+ // Configure the scrollback buffer.
+ rv->sb_size = (size_t)buf->b_p_scbk;
+ rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
+ }
// Configure the color palette. Try to get the color from:
//
@@ -290,14 +297,13 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
}
}
}
-
- return rv;
}
/// Closes the Terminal buffer.
///
/// May call terminal_destroy, which sets caller storage to NULL.
void terminal_close(Terminal **termpp, int status)
+ FUNC_ATTR_NONNULL_ALL
{
Terminal *term = *termpp;
if (term->destroy) {
@@ -437,8 +443,8 @@ bool terminal_enter(void)
char *save_w_p_culopt = NULL;
uint8_t save_w_p_culopt_flags = curwin->w_p_culopt_flags;
int save_w_p_cuc = curwin->w_p_cuc;
- long save_w_p_so = curwin->w_p_so;
- long save_w_p_siso = curwin->w_p_siso;
+ OptInt save_w_p_so = curwin->w_p_so;
+ OptInt 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") != 0) {
save_w_p_culopt = curwin->w_p_culopt;
@@ -532,6 +538,7 @@ static int terminal_check(VimState *state)
}
terminal_check_cursor();
+ validate_cursor();
if (must_redraw) {
update_screen();
@@ -576,6 +583,8 @@ static int terminal_execute(VimState *state, int key)
case K_RIGHTRELEASE:
case K_MOUSEDOWN:
case K_MOUSEUP:
+ case K_MOUSELEFT:
+ case K_MOUSERIGHT:
if (send_mouse_event(s->term, key)) {
return 0;
}
@@ -597,7 +606,7 @@ static int terminal_execute(VimState *state, int key)
break;
case K_LUA:
- map_execute_lua();
+ map_execute_lua(false);
break;
case Ctrl_N:
@@ -644,6 +653,7 @@ static int terminal_execute(VimState *state, int key)
/// Frees the given Terminal structure and sets the caller storage to NULL (in the spirit of
/// XFREE_CLEAR).
void terminal_destroy(Terminal **termpp)
+ FUNC_ATTR_NONNULL_ALL
{
Terminal *term = *termpp;
buf_T *buf = handle_get_buffer(term->buf_handle);
@@ -653,12 +663,12 @@ void terminal_destroy(Terminal **termpp)
}
if (!term->refcount) {
- if (pmap_has(ptr_t)(&invalidated_terminals, term)) {
+ if (set_has(ptr_t, &invalidated_terminals, term)) {
// flush any pending changes to the buffer
block_autocmds();
refresh_terminal(term);
unblock_autocmds();
- pmap_del(ptr_t)(&invalidated_terminals, term);
+ set_del(ptr_t, &invalidated_terminals, term);
}
for (size_t i = 0; i < term->sb_current; i++) {
xfree(term->sb_buffer[i]);
@@ -681,7 +691,7 @@ void terminal_send(Terminal *term, char *data, size_t size)
static bool is_filter_char(int c)
{
- unsigned int flag = 0;
+ unsigned flag = 0;
switch (c) {
case 0x08:
flag = TPF_BS;
@@ -711,7 +721,7 @@ static bool is_filter_char(int c)
return !!(tpf_flags & flag);
}
-void terminal_paste(long count, char **y_array, size_t y_size)
+void terminal_paste(int count, char **y_array, size_t y_size)
{
if (y_size == 0) {
return;
@@ -719,12 +729,16 @@ void terminal_paste(long count, char **y_array, size_t y_size)
vterm_keyboard_start_paste(curbuf->terminal->vt);
size_t buff_len = strlen(y_array[0]);
char *buff = xmalloc(buff_len);
- for (int i = 0; i < count; i++) { // -V756
+ for (int i = 0; i < count; i++) {
// feed the lines to the terminal
for (size_t j = 0; j < y_size; j++) {
if (j) {
// terminate the previous line
+#ifdef MSWIN
+ terminal_send(curbuf->terminal, "\r\n", 2);
+#else
terminal_send(curbuf->terminal, "\n", 1);
+#endif
}
size_t len = strlen(y_array[j]);
if (len > buff_len) {
@@ -762,7 +776,7 @@ void terminal_send_key(Terminal *term, int c)
if (key) {
vterm_keyboard_key(term->vt, key, mod);
- } else {
+ } else if (!IS_SPECIAL(c)) {
vterm_keyboard_unichar(term->vt, (uint32_t)c, mod);
}
}
@@ -836,7 +850,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te
| (cell.attrs.italic ? HL_ITALIC : 0)
| (cell.attrs.reverse ? HL_INVERSE : 0)
| get_underline_hl_flag(cell.attrs)
- | (cell.attrs.strike ? HL_STRIKETHROUGH: 0)
+ | (cell.attrs.strike ? HL_STRIKETHROUGH : 0)
| ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0)
| ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0);
@@ -893,13 +907,13 @@ static int term_moverect(VTermRect dest, VTermRect src, void *data)
return 1;
}
-static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data)
+static int term_movecursor(VTermPos new_pos, VTermPos old_pos, int visible, void *data)
{
Terminal *term = data;
- term->cursor.row = new.row;
- term->cursor.col = new.col;
- invalidate_terminal(term, old.row, old.row + 1);
- invalidate_terminal(term, new.row, new.row + 1);
+ term->cursor.row = new_pos.row;
+ term->cursor.col = new_pos.col;
+ invalidate_terminal(term, old_pos.row, old_pos.row + 1);
+ invalidate_terminal(term, new_pos.row, new_pos.row + 1);
return 1;
}
@@ -1024,7 +1038,7 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data)
}
memcpy(sbrow->cells, cells, sizeof(cells[0]) * c);
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
return 1;
}
@@ -1065,7 +1079,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
}
xfree(sbrow);
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
return 1;
}
@@ -1091,6 +1105,8 @@ static void convert_modifiers(int key, VTermModifier *statep)
case K_S_DOWN:
case K_S_LEFT:
case K_S_RIGHT:
+ case K_S_HOME:
+ case K_S_END:
case K_S_F1:
case K_S_F2:
case K_S_F3:
@@ -1108,6 +1124,8 @@ static void convert_modifiers(int key, VTermModifier *statep)
case K_C_LEFT:
case K_C_RIGHT:
+ case K_C_HOME:
+ case K_C_END:
*statep |= VTERM_MOD_CTRL;
break;
}
@@ -1154,8 +1172,16 @@ static VTermKey convert_key(int key, VTermModifier *statep)
return VTERM_KEY_INS;
case K_DEL:
return VTERM_KEY_DEL;
+ case K_S_HOME:
+ FALLTHROUGH;
+ case K_C_HOME:
+ FALLTHROUGH;
case K_HOME:
return VTERM_KEY_HOME;
+ case K_S_END:
+ FALLTHROUGH;
+ case K_C_END:
+ FALLTHROUGH;
case K_END:
return VTERM_KEY_END;
case K_PAGEUP:
@@ -1389,13 +1415,14 @@ static void mouse_action(Terminal *term, int button, int row, int col, bool pres
static bool send_mouse_event(Terminal *term, int c)
{
int row = mouse_row, col = mouse_col, grid = mouse_grid;
- int offset;
win_T *mouse_win = mouse_find_win(&grid, &row, &col);
- if (mouse_win == NULL || (offset = win_col_off(mouse_win)) > col) {
+ if (mouse_win == NULL) {
goto end;
}
- if (term->forward_mouse && mouse_win->w_buffer->terminal == term) {
+ int offset;
+ if (term->forward_mouse && mouse_win->w_buffer->terminal == term
+ && col >= (offset = win_col_off(mouse_win))) {
// event in the terminal window and mouse events was enabled by the
// program. translate and forward the event
int button;
@@ -1423,26 +1450,52 @@ static bool send_mouse_event(Terminal *term, int c)
pressed = true; button = 4; break;
case K_MOUSEUP:
pressed = true; button = 5; break;
+ case K_MOUSELEFT:
+ pressed = true; button = 7; break;
+ case K_MOUSERIGHT:
+ pressed = true; button = 6; break;
default:
return false;
}
- mouse_action(term, button, row, col - offset, pressed, 0);
+ VTermModifier mod = VTERM_MOD_NONE;
+ convert_modifiers(c, &mod);
+ mouse_action(term, button, row, col - offset, pressed, mod);
return false;
}
- if (c == K_MOUSEDOWN || c == K_MOUSEUP) {
+ if (c == K_MOUSEUP || c == K_MOUSEDOWN || c == K_MOUSELEFT || c == K_MOUSERIGHT) {
win_T *save_curwin = curwin;
// switch window/buffer to perform the scroll
curwin = mouse_win;
curbuf = curwin->w_buffer;
- 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 if (p_mousescroll_vert > 0) {
- scroll_redraw(direction, p_mousescroll_vert);
+
+ cmdarg_T cap;
+ oparg_T oa;
+ CLEAR_FIELD(cap);
+ clear_oparg(&oa);
+ cap.oap = &oa;
+
+ switch (cap.cmdchar = c) {
+ case K_MOUSEUP:
+ cap.arg = MSCR_UP;
+ break;
+ case K_MOUSEDOWN:
+ cap.arg = MSCR_DOWN;
+ break;
+ case K_MOUSELEFT:
+ cap.arg = MSCR_LEFT;
+ break;
+ case K_MOUSERIGHT:
+ cap.arg = MSCR_RIGHT;
+ break;
+ default:
+ abort();
}
+ // Call the common mouse scroll function shared with other modes.
+ do_mousescroll(&cap);
+
curwin->w_redr_status = true;
curwin = save_curwin;
curbuf = curwin->w_buffer;
@@ -1452,13 +1505,14 @@ static bool send_mouse_event(Terminal *term, int c)
return mouse_win == curwin;
}
- // ignore left release action if it was not processed above
- // to prevent leaving Terminal mode after entering to it using a mouse
- if (c == K_LEFTRELEASE && mouse_win->w_buffer->terminal == term) {
+end:
+ // Ignore left release action if it was not forwarded to prevent
+ // leaving Terminal mode after entering to it using a mouse.
+ if ((c == K_LEFTRELEASE && mouse_win != NULL && mouse_win->w_buffer->terminal == term)
+ || c == K_MOUSEMOVE) {
return false;
}
-end:
ins_char_typebuf(vgetc_char, vgetc_mod_mask);
return true;
}
@@ -1521,7 +1575,7 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
term->invalid_end = MAX(term->invalid_end, end_row);
}
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
if (!refresh_pending) {
time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0);
refresh_pending = true;
@@ -1539,7 +1593,7 @@ static void refresh_terminal(Terminal *term)
}
return;
}
- long ml_before = buf->b_ml.ml_line_count;
+ linenr_T ml_before = buf->b_ml.ml_line_count;
// refresh_ functions assume the terminal buffer is current
aco_save_T aco;
@@ -1549,7 +1603,7 @@ static void refresh_terminal(Terminal *term)
refresh_screen(term, buf);
aucmd_restbuf(&aco);
- long ml_added = buf->b_ml.ml_line_count - ml_before;
+ int ml_added = buf->b_ml.ml_line_count - ml_before;
adjust_topline(term, buf, ml_added);
}
@@ -1564,10 +1618,10 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
void *stub; (void)(stub);
// don't process autocommands while updating terminal buffers
block_autocmds();
- map_foreach(&invalidated_terminals, term, stub, {
+ set_foreach(&invalidated_terminals, term, {
refresh_terminal(term);
});
- pmap_clear(ptr_t)(&invalidated_terminals);
+ set_clear(ptr_t, &invalidated_terminals);
unblock_autocmds();
}
@@ -1704,12 +1758,12 @@ static void refresh_screen(Terminal *term, buf_T *buf)
int change_start = row_to_linenr(term, term->invalid_start);
int change_end = change_start + changed;
- changed_lines(change_start, 0, change_end, added, true);
+ changed_lines(buf, change_start, 0, change_end, added, true);
term->invalid_start = INT_MAX;
term->invalid_end = -1;
}
-static void adjust_topline(Terminal *term, buf_T *buf, long added)
+static void adjust_topline(Terminal *term, buf_T *buf, int added)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {