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.c164
1 files changed, 117 insertions, 47 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 35c68fa1f6..fd870361c7 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -46,6 +46,7 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
+#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/event/loop.h"
#include "nvim/event/time.h"
@@ -54,6 +55,7 @@
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/keymap.h"
#include "nvim/log.h"
#include "nvim/macros.h"
@@ -63,14 +65,12 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
#include "nvim/screen.h"
#include "nvim/state.h"
-#include "nvim/syntax.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -135,7 +135,6 @@ struct terminal {
int row, col;
bool visible;
} cursor;
- int pressed_button; // which mouse button is pressed
bool pending_resize; // pending width/height
bool color_set[16];
@@ -173,6 +172,11 @@ void terminal_teardown(void)
pmap_init(ptr_t, &invalidated_terminals);
}
+static void term_output_callback(const char *s, size_t len, void *user_data)
+{
+ terminal_send((Terminal *)user_data, (char *)s, len);
+}
+
// public API {{{
Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
@@ -196,6 +200,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
vterm_screen_set_callbacks(rv->vts, &vterm_screen_callbacks, rv);
vterm_screen_set_damage_merge(rv->vts, VTERM_DAMAGE_SCROLL);
vterm_screen_reset(rv->vts, 1);
+ vterm_output_set_callback(rv->vt, term_output_callback, rv);
// force a initial refresh of the screen to ensure the buffer will always
// have as many lines as screen rows when refresh_scrollback is called
rv->invalid_start = 0;
@@ -312,10 +317,14 @@ void terminal_close(Terminal *term, int status)
term->opts.close_cb(term->opts.data);
}
} else if (!only_destroy) {
- // This was called by channel_process_exit_cb() not in process_teardown().
+ // Associated channel has been closed and the editor is not exiting.
// Do not call the close callback now. Wait for the user to press a key.
char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
- snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
+ if (((Channel *)term->opts.data)->streamtype == kChannelStreamInternal) {
+ snprintf(msg, sizeof msg, "\r\n[Terminal closed]");
+ } else {
+ snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
+ }
terminal_receive(term, msg, strlen(msg));
}
@@ -324,10 +333,12 @@ void terminal_close(Terminal *term, int status)
}
if (buf && !is_autocmd_blocked()) {
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
tv_dict_add_nr(dict, S_LEN("status"), status);
+ tv_dict_set_keys_readonly(dict);
apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
}
}
@@ -412,6 +423,7 @@ void terminal_enter(void)
curwin->w_redr_status = true; // For mode() in statusline. #8323
ui_busy_start();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
+ may_trigger_modechanged();
s->state.execute = terminal_execute;
s->state.check = terminal_check;
@@ -462,9 +474,7 @@ static void terminal_check_cursor(void)
row_to_linenr(term, term->cursor.row));
// Nudge cursor when returning to normal-mode.
int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1);
- curwin->w_cursor.col = MAX(0, term->cursor.col + win_col_off(curwin) + off);
- curwin->w_cursor.coladd = 0;
- mb_check_adjust_col(curwin);
+ coladvance(MAX(0, term->cursor.col + off));
}
// Function executed before each iteration of terminal mode.
@@ -529,6 +539,10 @@ static int terminal_execute(VimState *state, int key)
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
break;
+ case K_LUA:
+ map_execute_lua();
+ break;
+
case Ctrl_N:
if (s->got_bsl) {
return 0;
@@ -633,7 +647,6 @@ void terminal_paste(long count, char_u **y_array, size_t y_size)
return;
}
vterm_keyboard_start_paste(curbuf->terminal->vt);
- terminal_flush_output(curbuf->terminal);
size_t buff_len = STRLEN(y_array[0]);
char_u *buff = xmalloc(buff_len);
for (int i = 0; i < count; i++) { // -V756
@@ -664,14 +677,6 @@ void terminal_paste(long count, char_u **y_array, size_t y_size)
}
xfree(buff);
vterm_keyboard_end_paste(curbuf->terminal->vt);
- terminal_flush_output(curbuf->terminal);
-}
-
-void terminal_flush_output(Terminal *term)
-{
- size_t len = vterm_output_read(term->vt, term->textbuf,
- sizeof(term->textbuf));
- terminal_send(term, term->textbuf, len);
}
void terminal_send_key(Terminal *term, int c)
@@ -690,8 +695,6 @@ void terminal_send_key(Terminal *term, int c)
} else {
vterm_keyboard_unichar(term->vt, (uint32_t)c, mod);
}
-
- terminal_flush_output(term);
}
void terminal_receive(Terminal *term, char *data, size_t len)
@@ -1203,27 +1206,70 @@ static VTermKey convert_key(int key, VTermModifier *statep)
return VTERM_KEY_FUNCTION(36);
case K_F37:
return VTERM_KEY_FUNCTION(37);
+ case K_F38:
+ return VTERM_KEY_FUNCTION(38);
+ case K_F39:
+ return VTERM_KEY_FUNCTION(39);
+ case K_F40:
+ return VTERM_KEY_FUNCTION(40);
+ case K_F41:
+ return VTERM_KEY_FUNCTION(41);
+ case K_F42:
+ return VTERM_KEY_FUNCTION(42);
+ case K_F43:
+ return VTERM_KEY_FUNCTION(43);
+ case K_F44:
+ return VTERM_KEY_FUNCTION(44);
+ case K_F45:
+ return VTERM_KEY_FUNCTION(45);
+ case K_F46:
+ return VTERM_KEY_FUNCTION(46);
+ case K_F47:
+ return VTERM_KEY_FUNCTION(47);
+ case K_F48:
+ return VTERM_KEY_FUNCTION(48);
+ case K_F49:
+ return VTERM_KEY_FUNCTION(49);
+ case K_F50:
+ return VTERM_KEY_FUNCTION(50);
+ case K_F51:
+ return VTERM_KEY_FUNCTION(51);
+ case K_F52:
+ return VTERM_KEY_FUNCTION(52);
+ case K_F53:
+ return VTERM_KEY_FUNCTION(53);
+ case K_F54:
+ return VTERM_KEY_FUNCTION(54);
+ case K_F55:
+ return VTERM_KEY_FUNCTION(55);
+ case K_F56:
+ return VTERM_KEY_FUNCTION(56);
+ case K_F57:
+ return VTERM_KEY_FUNCTION(57);
+ case K_F58:
+ return VTERM_KEY_FUNCTION(58);
+ case K_F59:
+ return VTERM_KEY_FUNCTION(59);
+ case K_F60:
+ return VTERM_KEY_FUNCTION(60);
+ case K_F61:
+ return VTERM_KEY_FUNCTION(61);
+ case K_F62:
+ return VTERM_KEY_FUNCTION(62);
+ case K_F63:
+ return VTERM_KEY_FUNCTION(63);
default:
return VTERM_KEY_NONE;
}
}
-static void mouse_action(Terminal *term, int button, int row, int col, bool drag, VTermModifier mod)
+static void mouse_action(Terminal *term, int button, int row, int col, bool pressed,
+ VTermModifier mod)
{
- if (term->pressed_button && (term->pressed_button != button || !drag)) {
- // release the previous button
- vterm_mouse_button(term->vt, term->pressed_button, 0, mod);
- term->pressed_button = 0;
- }
-
- // move the mouse
vterm_mouse_move(term->vt, row, col, mod);
-
- if (!term->pressed_button) {
- // press the button if not already pressed
- vterm_mouse_button(term->vt, button, 1, mod);
- term->pressed_button = button;
+ if (button) {
+ vterm_mouse_button(term->vt, button, pressed, mod);
}
}
@@ -1242,35 +1288,35 @@ static bool send_mouse_event(Terminal *term, int c)
// event in the terminal window and mouse events was enabled by the
// program. translate and forward the event
int button;
- bool drag = false;
+ bool pressed = false;
switch (c) {
case K_LEFTDRAG:
- drag = true; FALLTHROUGH;
case K_LEFTMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_LEFTRELEASE:
button = 1; break;
case K_MOUSEMOVE:
- drag = true; button = 0; break;
+ button = 0; break;
case K_MIDDLEDRAG:
- drag = true; FALLTHROUGH;
case K_MIDDLEMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_MIDDLERELEASE:
button = 2; break;
case K_RIGHTDRAG:
- drag = true; FALLTHROUGH;
case K_RIGHTMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_RIGHTRELEASE:
button = 3; break;
case K_MOUSEDOWN:
- button = 4; break;
+ pressed = true; button = 4; break;
case K_MOUSEUP:
- button = 5; break;
+ pressed = true; button = 5; break;
default:
return false;
}
- mouse_action(term, button, row, col - offset, drag, 0);
- size_t len = vterm_output_read(term->vt, term->textbuf,
- sizeof(term->textbuf));
- terminal_send(term, term->textbuf, len);
+ mouse_action(term, button, row, col - offset, pressed, 0);
return false;
}
@@ -1295,8 +1341,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) {
+ return false;
+ }
+
end:
- ins_char_typebuf(c);
+ ins_char_typebuf(c, mod_mask);
return true;
}
@@ -1466,6 +1518,17 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
int width, height;
vterm_get_size(term->vt, &height, &width);
+ // May still have pending scrollback after increase in terminal height if the
+ // scrollback wasn't refreshed in time; append these to the top of the buffer.
+ int row_offset = term->sb_pending;
+ while (term->sb_pending > 0 && buf->b_ml.ml_line_count < height) {
+ fetch_row(term, term->sb_pending - row_offset - 1, width);
+ ml_append(0, (uint8_t *)term->textbuf, 0, false);
+ appended_lines(0, 1);
+ term->sb_pending--;
+ }
+
+ row_offset -= term->sb_pending;
while (term->sb_pending > 0) {
// This means that either the window height has decreased or the screen
// became full and libvterm had to push all rows up. Convert the first
@@ -1476,7 +1539,7 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
ml_delete(1, false);
deleted_lines(1, 1);
}
- fetch_row(term, -term->sb_pending, width);
+ fetch_row(term, -term->sb_pending - row_offset, width);
int buf_index = (int)buf->b_ml.ml_line_count - height;
ml_append(buf_index, (uint8_t *)term->textbuf, 0, false);
appended_lines(buf_index, 1);
@@ -1506,6 +1569,13 @@ static void refresh_screen(Terminal *term, buf_T *buf)
// Terminal height may have decreased before `invalid_end` reflects it.
term->invalid_end = MIN(term->invalid_end, height);
+ // There are no invalid rows.
+ if (term->invalid_start >= term->invalid_end) {
+ term->invalid_start = INT_MAX;
+ term->invalid_end = -1;
+ return;
+ }
+
for (int r = term->invalid_start, linenr = row_to_linenr(term, r);
r < term->invalid_end; r++, linenr++) {
fetch_row(term, r, width);