mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge PR #3309 'Fixes for 0.1'
This commit is contained in:
commit
e80d7c0df7
@ -254,7 +254,16 @@ edit (
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (curbuf->terminal) {
|
if (curbuf->terminal) {
|
||||||
terminal_enter();
|
if (ex_normal_busy) {
|
||||||
|
// don't enter terminal mode from `ex_normal`, which can result in all
|
||||||
|
// kinds of havoc(such as terminal mode recursiveness). Instead, set a
|
||||||
|
// flag that allow us to force-set the value of `restart_edit` before
|
||||||
|
// `ex_normal` returns
|
||||||
|
restart_edit = 'i';
|
||||||
|
force_restart_edit = true;
|
||||||
|
} else {
|
||||||
|
terminal_enter();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19832,7 +19832,9 @@ void ex_delfunction(exarg_T *eap)
|
|||||||
EMSG2(_("E131: Cannot delete function %s: It is in use"), eap->arg);
|
EMSG2(_("E131: Cannot delete function %s: It is in use"), eap->arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fp->uf_refcount > 1) {
|
// check `uf_refcount > 2` because deleting a function should also reduce
|
||||||
|
// the reference count, and 1 is the initial refcount.
|
||||||
|
if (fp->uf_refcount > 2) {
|
||||||
EMSG2(_("Cannot delete function %s: It is being used internally"),
|
EMSG2(_("Cannot delete function %s: It is being used internally"),
|
||||||
eap->arg);
|
eap->arg);
|
||||||
return;
|
return;
|
||||||
|
@ -7624,6 +7624,10 @@ void update_topline_cursor(void)
|
|||||||
*/
|
*/
|
||||||
static void ex_normal(exarg_T *eap)
|
static void ex_normal(exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
if (curbuf->terminal) {
|
||||||
|
EMSG("Can't re-enter normal mode from terminal mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
int save_msg_scroll = msg_scroll;
|
int save_msg_scroll = msg_scroll;
|
||||||
int save_restart_edit = restart_edit;
|
int save_restart_edit = restart_edit;
|
||||||
int save_msg_didout = msg_didout;
|
int save_msg_didout = msg_didout;
|
||||||
@ -7715,7 +7719,14 @@ static void ex_normal(exarg_T *eap)
|
|||||||
|
|
||||||
--ex_normal_busy;
|
--ex_normal_busy;
|
||||||
msg_scroll = save_msg_scroll;
|
msg_scroll = save_msg_scroll;
|
||||||
restart_edit = save_restart_edit;
|
if (force_restart_edit) {
|
||||||
|
force_restart_edit = false;
|
||||||
|
} else {
|
||||||
|
// some function called was aware of ex_normal and decided to override the
|
||||||
|
// value of restart_edit anyway. So far only used in terminal mode(see
|
||||||
|
// terminal_enter() in edit.c)
|
||||||
|
restart_edit = save_restart_edit;
|
||||||
|
}
|
||||||
p_im = save_insertmode;
|
p_im = save_insertmode;
|
||||||
finish_op = save_finish_op;
|
finish_op = save_finish_op;
|
||||||
opcount = save_opcount;
|
opcount = save_opcount;
|
||||||
|
@ -823,6 +823,8 @@ EXTERN int no_u_sync INIT(= 0); /* Don't call u_sync() */
|
|||||||
EXTERN int u_sync_once INIT(= 0); /* Call u_sync() once when evaluating
|
EXTERN int u_sync_once INIT(= 0); /* Call u_sync() once when evaluating
|
||||||
an expression. */
|
an expression. */
|
||||||
|
|
||||||
|
EXTERN bool force_restart_edit INIT(= false); // force restart_edit after
|
||||||
|
// ex_normal returns
|
||||||
EXTERN int restart_edit INIT(= 0); /* call edit when next cmd finished */
|
EXTERN int restart_edit INIT(= 0); /* call edit when next cmd finished */
|
||||||
EXTERN int arrow_used; /* Normally FALSE, set to TRUE after
|
EXTERN int arrow_used; /* Normally FALSE, set to TRUE after
|
||||||
* hitting cursor key in insert mode.
|
* hitting cursor key in insert mode.
|
||||||
|
@ -2089,8 +2089,15 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf, int len, int
|
|||||||
// expand it if forced or not an absolute path
|
// expand it if forced or not an absolute path
|
||||||
if (force || !path_is_absolute_path(fname)) {
|
if (force || !path_is_absolute_path(fname)) {
|
||||||
if ((p = vim_strrchr(fname, '/')) != NULL) {
|
if ((p = vim_strrchr(fname, '/')) != NULL) {
|
||||||
STRNCPY(relative_directory, fname, p-fname);
|
// relative to root
|
||||||
relative_directory[p-fname] = NUL;
|
if (p == fname) {
|
||||||
|
// only one path component
|
||||||
|
relative_directory[0] = '/';
|
||||||
|
relative_directory[1] = NUL;
|
||||||
|
} else {
|
||||||
|
STRNCPY(relative_directory, fname, p-fname);
|
||||||
|
relative_directory[p-fname] = NUL;
|
||||||
|
}
|
||||||
end_of_path = (char *) (p + 1);
|
end_of_path = (char *) (p + 1);
|
||||||
} else {
|
} else {
|
||||||
relative_directory[0] = NUL;
|
relative_directory[0] = NUL;
|
||||||
|
@ -4781,6 +4781,7 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
|
|||||||
if (match
|
if (match
|
||||||
/* check that no composing char follows */
|
/* check that no composing char follows */
|
||||||
&& !(enc_utf8
|
&& !(enc_utf8
|
||||||
|
&& STRLEN(regline) > (size_t)(col + len2)
|
||||||
&& utf_iscomposing(PTR2CHAR(regline + col + len2)))
|
&& utf_iscomposing(PTR2CHAR(regline + col + len2)))
|
||||||
) {
|
) {
|
||||||
cleanup_subexpr();
|
cleanup_subexpr();
|
||||||
|
@ -653,7 +653,7 @@ int searchit(
|
|||||||
}
|
}
|
||||||
if (matchcol == 0 && (options & SEARCH_START))
|
if (matchcol == 0 && (options & SEARCH_START))
|
||||||
break;
|
break;
|
||||||
if (ptr[matchcol] == NUL
|
if (STRLEN(ptr) <= (size_t)matchcol || ptr[matchcol] == NUL
|
||||||
|| (nmatched = vim_regexec_multi(®match,
|
|| (nmatched = vim_regexec_multi(®match,
|
||||||
win, buf, lnum + matchpos.lnum,
|
win, buf, lnum + matchpos.lnum,
|
||||||
matchcol,
|
matchcol,
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
#include "nvim/event/time.h"
|
#include "nvim/event/time.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
|
#include "nvim/api/private/handle.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "terminal.c.generated.h"
|
# include "terminal.c.generated.h"
|
||||||
@ -113,7 +114,10 @@ struct terminal {
|
|||||||
// window height has increased) and must be deleted from the terminal buffer
|
// window height has increased) and must be deleted from the terminal buffer
|
||||||
int sb_pending;
|
int sb_pending;
|
||||||
// buf_T instance that acts as a "drawing surface" for libvterm
|
// buf_T instance that acts as a "drawing surface" for libvterm
|
||||||
buf_T *buf;
|
// 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
|
||||||
|
// no way to know if the memory was reused.
|
||||||
|
uint64_t buf_handle;
|
||||||
// program exited
|
// program exited
|
||||||
bool closed, destroy;
|
bool closed, destroy;
|
||||||
// some vterm properties
|
// some vterm properties
|
||||||
@ -155,6 +159,8 @@ void terminal_init(void)
|
|||||||
{
|
{
|
||||||
invalidated_terminals = pmap_new(ptr_t)();
|
invalidated_terminals = pmap_new(ptr_t)();
|
||||||
time_watcher_init(&loop, &refresh_timer, NULL);
|
time_watcher_init(&loop, &refresh_timer, NULL);
|
||||||
|
// refresh_timer_cb will redraw the screen which can call vimscript
|
||||||
|
refresh_timer.events = queue_new_child(loop.events);
|
||||||
|
|
||||||
// initialize a rgb->color index map for cterm attributes(VTermScreenCell
|
// initialize a rgb->color index map for cterm attributes(VTermScreenCell
|
||||||
// only has RGB information and we need color indexes for terminal UIs)
|
// only has RGB information and we need color indexes for terminal UIs)
|
||||||
@ -180,6 +186,7 @@ void terminal_init(void)
|
|||||||
void terminal_teardown(void)
|
void terminal_teardown(void)
|
||||||
{
|
{
|
||||||
time_watcher_stop(&refresh_timer);
|
time_watcher_stop(&refresh_timer);
|
||||||
|
queue_free(refresh_timer.events);
|
||||||
time_watcher_close(&refresh_timer, NULL);
|
time_watcher_close(&refresh_timer, NULL);
|
||||||
pmap_free(ptr_t)(invalidated_terminals);
|
pmap_free(ptr_t)(invalidated_terminals);
|
||||||
map_free(int, int)(color_indexes);
|
map_free(int, int)(color_indexes);
|
||||||
@ -194,7 +201,7 @@ Terminal *terminal_open(TerminalOptions opts)
|
|||||||
rv->opts = opts;
|
rv->opts = opts;
|
||||||
rv->cursor.visible = true;
|
rv->cursor.visible = true;
|
||||||
// Associate the terminal instance with the new buffer
|
// Associate the terminal instance with the new buffer
|
||||||
rv->buf = curbuf;
|
rv->buf_handle = curbuf->handle;
|
||||||
curbuf->terminal = rv;
|
curbuf->terminal = rv;
|
||||||
// Create VTerm
|
// Create VTerm
|
||||||
rv->vt = vterm_new(opts.height, opts.width);
|
rv->vt = vterm_new(opts.height, opts.width);
|
||||||
@ -212,7 +219,7 @@ Terminal *terminal_open(TerminalOptions opts)
|
|||||||
// have as many lines as screen rows when refresh_scrollback is called
|
// have as many lines as screen rows when refresh_scrollback is called
|
||||||
rv->invalid_start = 0;
|
rv->invalid_start = 0;
|
||||||
rv->invalid_end = opts.height;
|
rv->invalid_end = opts.height;
|
||||||
refresh_screen(rv);
|
refresh_screen(rv, curbuf);
|
||||||
set_option_value((uint8_t *)"buftype", 0, (uint8_t *)"terminal", OPT_LOCAL);
|
set_option_value((uint8_t *)"buftype", 0, (uint8_t *)"terminal", OPT_LOCAL);
|
||||||
// some sane settings for terminal buffers
|
// some sane settings for terminal buffers
|
||||||
set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL);
|
set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL);
|
||||||
@ -229,7 +236,7 @@ Terminal *terminal_open(TerminalOptions opts)
|
|||||||
// - SCROLLBACK_BUFFER_DEFAULT_SIZE
|
// - SCROLLBACK_BUFFER_DEFAULT_SIZE
|
||||||
//
|
//
|
||||||
// but limit to 100k.
|
// but limit to 100k.
|
||||||
int size = get_config_int(rv, "terminal_scrollback_buffer_size");
|
int size = get_config_int("terminal_scrollback_buffer_size");
|
||||||
rv->sb_size = size > 0 ? (size_t)size : SCROLLBACK_BUFFER_DEFAULT_SIZE;
|
rv->sb_size = size > 0 ? (size_t)size : SCROLLBACK_BUFFER_DEFAULT_SIZE;
|
||||||
rv->sb_size = MIN(rv->sb_size, 100000);
|
rv->sb_size = MIN(rv->sb_size, 100000);
|
||||||
rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
|
rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
|
||||||
@ -243,7 +250,7 @@ Terminal *terminal_open(TerminalOptions opts)
|
|||||||
RgbValue color_val = -1;
|
RgbValue color_val = -1;
|
||||||
char var[64];
|
char var[64];
|
||||||
snprintf(var, sizeof(var), "terminal_color_%d", i);
|
snprintf(var, sizeof(var), "terminal_color_%d", i);
|
||||||
char *name = get_config_string(rv, var);
|
char *name = get_config_string(var);
|
||||||
if (name) {
|
if (name) {
|
||||||
color_val = name_to_color((uint8_t *)name);
|
color_val = name_to_color((uint8_t *)name);
|
||||||
xfree(name);
|
xfree(name);
|
||||||
@ -273,11 +280,14 @@ void terminal_close(Terminal *term, char *msg)
|
|||||||
term->forward_mouse = false;
|
term->forward_mouse = false;
|
||||||
term->closed = true;
|
term->closed = true;
|
||||||
if (!msg || exiting) {
|
if (!msg || exiting) {
|
||||||
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
// If no msg was given, this was called by close_buffer(buffer.c). Or if
|
// 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
|
// exiting, we must inform the buffer the terminal no longer exists so that
|
||||||
// close_buffer() doesn't call this again.
|
// close_buffer() doesn't call this again.
|
||||||
term->buf->terminal = NULL;
|
term->buf_handle = 0;
|
||||||
term->buf = NULL;
|
if (buf) {
|
||||||
|
buf->terminal = NULL;
|
||||||
|
}
|
||||||
if (!term->refcount) {
|
if (!term->refcount) {
|
||||||
// We should not wait for the user to press a key.
|
// We should not wait for the user to press a key.
|
||||||
term->opts.close_cb(term->opts.data);
|
term->opts.close_cb(term->opts.data);
|
||||||
@ -308,7 +318,7 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
|
|||||||
// The new width/height are the minimum for all windows that display the
|
// The new width/height are the minimum for all windows that display the
|
||||||
// terminal in the current tab.
|
// terminal in the current tab.
|
||||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||||
if (!wp->w_closing && wp->w_buffer == term->buf) {
|
if (!wp->w_closing && wp->w_buffer->terminal == term) {
|
||||||
width = (uint16_t)MIN(width, (uint16_t)(wp->w_width - win_col_off(wp)));
|
width = (uint16_t)MIN(width, (uint16_t)(wp->w_width - win_col_off(wp)));
|
||||||
height = (uint16_t)MIN(height, (uint16_t)wp->w_height);
|
height = (uint16_t)MIN(height, (uint16_t)wp->w_height);
|
||||||
}
|
}
|
||||||
@ -330,7 +340,8 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
|
|||||||
|
|
||||||
void terminal_enter(void)
|
void terminal_enter(void)
|
||||||
{
|
{
|
||||||
Terminal *term = curbuf->terminal;
|
buf_T *buf = curbuf;
|
||||||
|
Terminal *term = buf->terminal;
|
||||||
assert(term && "should only be called when curbuf has a terminal");
|
assert(term && "should only be called when curbuf has a terminal");
|
||||||
|
|
||||||
// Ensure the terminal is properly sized.
|
// Ensure the terminal is properly sized.
|
||||||
@ -345,7 +356,7 @@ void terminal_enter(void)
|
|||||||
bool save_mapped_ctrl_c = mapped_ctrl_c;
|
bool save_mapped_ctrl_c = mapped_ctrl_c;
|
||||||
mapped_ctrl_c = true;
|
mapped_ctrl_c = true;
|
||||||
// go to the bottom when the terminal is focused
|
// go to the bottom when the terminal is focused
|
||||||
adjust_topline(term, false);
|
adjust_topline(term, buf, false);
|
||||||
// erase the unfocused cursor
|
// erase the unfocused cursor
|
||||||
invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
|
invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
|
||||||
showmode();
|
showmode();
|
||||||
@ -356,7 +367,7 @@ void terminal_enter(void)
|
|||||||
|
|
||||||
bool got_bs = false; // True if the last input was <C-\>
|
bool got_bs = false; // True if the last input was <C-\>
|
||||||
|
|
||||||
while (term->buf == curbuf) {
|
while (curbuf->handle == term->buf_handle) {
|
||||||
input_enable_events();
|
input_enable_events();
|
||||||
c = safe_vgetc();
|
c = safe_vgetc();
|
||||||
input_disable_events();
|
input_disable_events();
|
||||||
@ -383,7 +394,7 @@ void terminal_enter(void)
|
|||||||
term->refcount++;
|
term->refcount++;
|
||||||
queue_process_events(loop.events);
|
queue_process_events(loop.events);
|
||||||
term->refcount--;
|
term->refcount--;
|
||||||
if (term->buf == NULL) {
|
if (term->buf_handle == 0) {
|
||||||
close = true;
|
close = true;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -418,10 +429,10 @@ end:
|
|||||||
invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
|
invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
|
||||||
mapped_ctrl_c = save_mapped_ctrl_c;
|
mapped_ctrl_c = save_mapped_ctrl_c;
|
||||||
unshowmode(true);
|
unshowmode(true);
|
||||||
redraw(term->buf != curbuf);
|
redraw(buf != curbuf);
|
||||||
ui_busy_stop();
|
ui_busy_stop();
|
||||||
if (close) {
|
if (close) {
|
||||||
bool wipe = term->buf != NULL;
|
bool wipe = term->buf_handle != 0;
|
||||||
term->opts.close_cb(term->opts.data);
|
term->opts.close_cb(term->opts.data);
|
||||||
if (wipe) {
|
if (wipe) {
|
||||||
do_cmdline_cmd("bwipeout!");
|
do_cmdline_cmd("bwipeout!");
|
||||||
@ -431,10 +442,11 @@ end:
|
|||||||
|
|
||||||
void terminal_destroy(Terminal *term)
|
void terminal_destroy(Terminal *term)
|
||||||
{
|
{
|
||||||
if (term->buf) {
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
term->buf->terminal = NULL;
|
if (buf) {
|
||||||
|
term->buf_handle = 0;
|
||||||
|
buf->terminal = NULL;
|
||||||
}
|
}
|
||||||
term->buf = NULL;
|
|
||||||
|
|
||||||
if (!term->refcount) {
|
if (!term->refcount) {
|
||||||
if (pmap_has(ptr_t)(invalidated_terminals, term)) {
|
if (pmap_has(ptr_t)(invalidated_terminals, term)) {
|
||||||
@ -589,8 +601,9 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VTERM_PROP_TITLE: {
|
case VTERM_PROP_TITLE: {
|
||||||
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
Error err;
|
Error err;
|
||||||
api_free_object(dict_set_value(term->buf->b_vars,
|
api_free_object(dict_set_value(buf->b_vars,
|
||||||
cstr_as_string("term_title"),
|
cstr_as_string("term_title"),
|
||||||
STRING_OBJ(cstr_as_string(val->string)),
|
STRING_OBJ(cstr_as_string(val->string)),
|
||||||
&err));
|
&err));
|
||||||
@ -778,7 +791,7 @@ static bool send_mouse_event(Terminal *term, int c)
|
|||||||
int row = mouse_row, col = mouse_col;
|
int row = mouse_row, col = mouse_col;
|
||||||
win_T *mouse_win = mouse_find_win(&row, &col);
|
win_T *mouse_win = mouse_find_win(&row, &col);
|
||||||
|
|
||||||
if (term->forward_mouse && mouse_win->w_buffer == term->buf) {
|
if (term->forward_mouse && mouse_win->w_buffer->terminal == term) {
|
||||||
// event in the terminal window and mouse events was enabled by the
|
// event in the terminal window and mouse events was enabled by the
|
||||||
// program. translate and forward the event
|
// program. translate and forward the event
|
||||||
int button;
|
int button;
|
||||||
@ -903,22 +916,23 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
|
|||||||
static void refresh_terminal(Terminal *term)
|
static void refresh_terminal(Terminal *term)
|
||||||
{
|
{
|
||||||
// TODO(SplinterOfChaos): Find the condition that makes term->buf invalid.
|
// TODO(SplinterOfChaos): Find the condition that makes term->buf invalid.
|
||||||
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
if (!term->buf || !(valid = buf_valid(term->buf))) {
|
if (!buf || !(valid = buf_valid(buf))) {
|
||||||
// destroyed by `close_buffer`. Dont do anything else
|
// destroyed by `close_buffer`. Dont do anything else
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
term->buf = NULL;
|
term->buf_handle = 0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool pending_resize = term->pending_resize;
|
bool pending_resize = term->pending_resize;
|
||||||
WITH_BUFFER(term->buf, {
|
WITH_BUFFER(buf, {
|
||||||
refresh_size(term);
|
refresh_size(term, buf);
|
||||||
refresh_scrollback(term);
|
refresh_scrollback(term, buf);
|
||||||
refresh_screen(term);
|
refresh_screen(term, buf);
|
||||||
redraw_buf_later(term->buf, NOT_VALID);
|
redraw_buf_later(buf, NOT_VALID);
|
||||||
});
|
});
|
||||||
adjust_topline(term, pending_resize);
|
adjust_topline(term, buf, pending_resize);
|
||||||
}
|
}
|
||||||
// libuv timer callback. This will enqueue on_refresh to be processed as an
|
// libuv timer callback. This will enqueue on_refresh to be processed as an
|
||||||
// event.
|
// event.
|
||||||
@ -943,7 +957,7 @@ end:
|
|||||||
refresh_pending = false;
|
refresh_pending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_size(Terminal *term)
|
static void refresh_size(Terminal *term, buf_T *buf)
|
||||||
{
|
{
|
||||||
if (!term->pending_resize || term->closed) {
|
if (!term->pending_resize || term->closed) {
|
||||||
return;
|
return;
|
||||||
@ -958,7 +972,7 @@ static void refresh_size(Terminal *term)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the scrollback of a invalidated terminal
|
// Refresh the scrollback of a invalidated terminal
|
||||||
static void refresh_scrollback(Terminal *term)
|
static void refresh_scrollback(Terminal *term, buf_T *buf)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
vterm_get_size(term->vt, &height, &width);
|
vterm_get_size(term->vt, &height, &width);
|
||||||
@ -968,13 +982,13 @@ static void refresh_scrollback(Terminal *term)
|
|||||||
// became full and libvterm had to push all rows up. Convert the first
|
// became full and libvterm had to push all rows up. Convert the first
|
||||||
// pending scrollback row into a string and append it just above the visible
|
// pending scrollback row into a string and append it just above the visible
|
||||||
// section of the buffer
|
// section of the buffer
|
||||||
if (((int)term->buf->b_ml.ml_line_count - height) >= (int)term->sb_size) {
|
if (((int)buf->b_ml.ml_line_count - height) >= (int)term->sb_size) {
|
||||||
// scrollback full, delete lines at the top
|
// scrollback full, delete lines at the top
|
||||||
ml_delete(1, false);
|
ml_delete(1, false);
|
||||||
deleted_lines(1, 1);
|
deleted_lines(1, 1);
|
||||||
}
|
}
|
||||||
fetch_row(term, -term->sb_pending, width);
|
fetch_row(term, -term->sb_pending, width);
|
||||||
int buf_index = (int)term->buf->b_ml.ml_line_count - height;
|
int buf_index = (int)buf->b_ml.ml_line_count - height;
|
||||||
ml_append(buf_index, (uint8_t *)term->textbuf, 0, false);
|
ml_append(buf_index, (uint8_t *)term->textbuf, 0, false);
|
||||||
appended_lines(buf_index, 1);
|
appended_lines(buf_index, 1);
|
||||||
term->sb_pending--;
|
term->sb_pending--;
|
||||||
@ -982,15 +996,15 @@ static void refresh_scrollback(Terminal *term)
|
|||||||
|
|
||||||
// Remove extra lines at the bottom
|
// Remove extra lines at the bottom
|
||||||
int max_line_count = (int)term->sb_current + height;
|
int max_line_count = (int)term->sb_current + height;
|
||||||
while (term->buf->b_ml.ml_line_count > max_line_count) {
|
while (buf->b_ml.ml_line_count > max_line_count) {
|
||||||
ml_delete(term->buf->b_ml.ml_line_count, false);
|
ml_delete(buf->b_ml.ml_line_count, false);
|
||||||
deleted_lines(term->buf->b_ml.ml_line_count, 1);
|
deleted_lines(buf->b_ml.ml_line_count, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the screen(visible part of the buffer when the terminal is
|
// Refresh the screen(visible part of the buffer when the terminal is
|
||||||
// focused) of a invalidated terminal
|
// focused) of a invalidated terminal
|
||||||
static void refresh_screen(Terminal *term)
|
static void refresh_screen(Terminal *term, buf_T *buf)
|
||||||
{
|
{
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
int added = 0;
|
int added = 0;
|
||||||
@ -1005,7 +1019,7 @@ static void refresh_screen(Terminal *term)
|
|||||||
r < term->invalid_end; r++, linenr++) {
|
r < term->invalid_end; r++, linenr++) {
|
||||||
fetch_row(term, r, width);
|
fetch_row(term, r, width);
|
||||||
|
|
||||||
if (linenr <= term->buf->b_ml.ml_line_count) {
|
if (linenr <= buf->b_ml.ml_line_count) {
|
||||||
ml_replace(linenr, (uint8_t *)term->textbuf, true);
|
ml_replace(linenr, (uint8_t *)term->textbuf, true);
|
||||||
changed++;
|
changed++;
|
||||||
} else {
|
} else {
|
||||||
@ -1069,20 +1083,20 @@ static void redraw(bool restore_cursor)
|
|||||||
ui_flush();
|
ui_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adjust_topline(Terminal *term, bool force)
|
static void adjust_topline(Terminal *term, buf_T *buf, bool force)
|
||||||
{
|
{
|
||||||
int height, width;
|
int height, width;
|
||||||
vterm_get_size(term->vt, &height, &width);
|
vterm_get_size(term->vt, &height, &width);
|
||||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||||
if (wp->w_buffer == term->buf) {
|
if (wp->w_buffer == buf) {
|
||||||
// for every window that displays a terminal, ensure the cursor is in a
|
// for every window that displays a terminal, ensure the cursor is in a
|
||||||
// valid line
|
// valid line
|
||||||
wp->w_cursor.lnum = MIN(wp->w_cursor.lnum, term->buf->b_ml.ml_line_count);
|
wp->w_cursor.lnum = MIN(wp->w_cursor.lnum, buf->b_ml.ml_line_count);
|
||||||
if (force || curbuf != term->buf || is_focused(term)) {
|
if (force || curbuf != buf || is_focused(term)) {
|
||||||
// if the terminal is not in the current window or if it's focused,
|
// if the terminal is not in the current window or if it's focused,
|
||||||
// adjust topline/cursor so the window will "follow" the terminal
|
// adjust topline/cursor so the window will "follow" the terminal
|
||||||
// output
|
// output
|
||||||
wp->w_cursor.lnum = term->buf->b_ml.ml_line_count;
|
wp->w_cursor.lnum = buf->b_ml.ml_line_count;
|
||||||
set_topline(wp, MAX(wp->w_cursor.lnum - height + 1, 1));
|
set_topline(wp, MAX(wp->w_cursor.lnum - height + 1, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1101,22 +1115,24 @@ static int linenr_to_row(Terminal *term, int linenr)
|
|||||||
|
|
||||||
static bool is_focused(Terminal *term)
|
static bool is_focused(Terminal *term)
|
||||||
{
|
{
|
||||||
return State & TERM_FOCUS && curbuf == term->buf;
|
return State & TERM_FOCUS && curbuf->terminal == term;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_CONFIG_VALUE(t, k, o) \
|
#define GET_CONFIG_VALUE(k, o) \
|
||||||
do { \
|
do { \
|
||||||
Error err; \
|
Error err; \
|
||||||
o = dict_get_value(t->buf->b_vars, cstr_as_string(k), &err); \
|
/* Only called from terminal_open where curbuf->terminal is the */ \
|
||||||
|
/* context */ \
|
||||||
|
o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \
|
||||||
if (o.type == kObjectTypeNil) { \
|
if (o.type == kObjectTypeNil) { \
|
||||||
o = dict_get_value(&globvardict, cstr_as_string(k), &err); \
|
o = dict_get_value(&globvardict, cstr_as_string(k), &err); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static char *get_config_string(Terminal *term, char *key)
|
static char *get_config_string(char *key)
|
||||||
{
|
{
|
||||||
Object obj;
|
Object obj;
|
||||||
GET_CONFIG_VALUE(term, key, obj);
|
GET_CONFIG_VALUE(key, obj);
|
||||||
if (obj.type == kObjectTypeString) {
|
if (obj.type == kObjectTypeString) {
|
||||||
return obj.data.string.data;
|
return obj.data.string.data;
|
||||||
}
|
}
|
||||||
@ -1124,10 +1140,10 @@ static char *get_config_string(Terminal *term, char *key)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_config_int(Terminal *term, char *key)
|
static int get_config_int(char *key)
|
||||||
{
|
{
|
||||||
Object obj;
|
Object obj;
|
||||||
GET_CONFIG_VALUE(term, key, obj);
|
GET_CONFIG_VALUE(key, obj);
|
||||||
if (obj.type == kObjectTypeInteger) {
|
if (obj.type == kObjectTypeInteger) {
|
||||||
return (int)obj.data.integer;
|
return (int)obj.data.integer;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
#define NVIM_UGRID_H
|
#define NVIM_UGRID_H
|
||||||
|
|
||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
|
#include "nvim/globals.h"
|
||||||
|
|
||||||
typedef struct ucell UCell;
|
typedef struct ucell UCell;
|
||||||
typedef struct ugrid UGrid;
|
typedef struct ugrid UGrid;
|
||||||
|
|
||||||
struct ucell {
|
struct ucell {
|
||||||
char data[7];
|
char data[6 * MAX_MCO + 1];
|
||||||
HlAttrs attrs;
|
HlAttrs attrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/ui_bridge.h"
|
#include "nvim/ui_bridge.h"
|
||||||
|
#include "nvim/ugrid.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "ui_bridge.c.generated.h"
|
# include "ui_bridge.c.generated.h"
|
||||||
@ -233,8 +234,11 @@ static void ui_bridge_highlight_set_event(void **argv)
|
|||||||
|
|
||||||
static void ui_bridge_put(UI *b, uint8_t *text, size_t size)
|
static void ui_bridge_put(UI *b, uint8_t *text, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *t = xmalloc(8);
|
uint8_t *t = NULL;
|
||||||
memcpy(t, text, size);
|
if (text) {
|
||||||
|
t = xmalloc(sizeof(((UCell *)0)->data));
|
||||||
|
memcpy(t, text, size);
|
||||||
|
}
|
||||||
UI_CALL(b, put, 3, b, t, INT2PTR(size));
|
UI_CALL(b, put, 3, b, t, INT2PTR(size));
|
||||||
}
|
}
|
||||||
static void ui_bridge_put_event(void **argv)
|
static void ui_bridge_put_event(void **argv)
|
||||||
|
@ -27,8 +27,6 @@ describe('terminal cursor', function()
|
|||||||
|
|
|
|
||||||
-- TERMINAL -- |
|
-- TERMINAL -- |
|
||||||
]])
|
]])
|
||||||
eq(2, screen._cursor.row)
|
|
||||||
eq(15, screen._cursor.col)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('is highlighted when not focused', function()
|
it('is highlighted when not focused', function()
|
||||||
|
@ -416,6 +416,14 @@ describe('more path function', function()
|
|||||||
eq('unit-test-directory/test.file', (ffi.string(filename)))
|
eq('unit-test-directory/test.file', (ffi.string(filename)))
|
||||||
eq(OK, result)
|
eq(OK, result)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('works with directories that have one path component', function()
|
||||||
|
local force_expansion = 1
|
||||||
|
local filename = to_cstr('/tmp')
|
||||||
|
local result = path.vim_FullName(filename, buffer, len, force_expansion)
|
||||||
|
eq('/tmp', ffi.string(buffer))
|
||||||
|
eq(OK, result)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('path_fix_case', function()
|
describe('path_fix_case', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user