mirror of
https://github.com/neovim/neovim.git
synced 2026-05-03 12:35:00 +00:00
Merge #6185 from justinmk/term-cursor
terminal: Keep cursor position; Disable 'cursorline'
This commit is contained in:
@@ -16,14 +16,12 @@ Normal commands ~
|
||||
*]f*
|
||||
*[f* Same as "gf".
|
||||
|
||||
|
||||
Commands ~
|
||||
*:rv*
|
||||
*:rviminfo* Deprecated alias to |:rshada| command.
|
||||
*:wv*
|
||||
*:wviminfo* Deprecated alias to |:wshada| command.
|
||||
|
||||
|
||||
Events ~
|
||||
*EncodingChanged* Never fired; 'encoding' is always "utf-8".
|
||||
*FileEncoding* Never fired; equivalent to |EncodingChanged|.
|
||||
@@ -31,6 +29,10 @@ Events ~
|
||||
Highlight groups ~
|
||||
*hl-VisualNOS* Obsolete. |vim-differences| {Nvim}
|
||||
|
||||
Keycodes ~
|
||||
*<MouseDown>* Use <ScrollWheelUp> instead.
|
||||
*<MouseUp>* Use <ScrollWheelDown> instead.
|
||||
|
||||
Functions ~
|
||||
*buffer_exists()* Obsolete name for |bufexists()|.
|
||||
*buffer_name()* Obsolete name for |bufname()|.
|
||||
|
||||
@@ -235,15 +235,9 @@ This allows quick adjustment of the relative offset of 'scrollbind' windows.
|
||||
==============================================================================
|
||||
6. Scrolling with a mouse wheel *scroll-mouse-wheel*
|
||||
|
||||
When your mouse has a scroll wheel, it should work with Vim in the GUI. How
|
||||
it works depends on your system. It might also work in an xterm
|
||||
|xterm-mouse-wheel|. By default only vertical scroll wheels are supported,
|
||||
but some GUIs also support horizontal scroll wheels.
|
||||
|
||||
For the Win32 GUI the scroll action is hard coded. It works just like
|
||||
dragging the scrollbar of the current window. How many lines are scrolled
|
||||
depends on your mouse driver. If the scroll action causes input focus
|
||||
problems, see |intellimouse-wheel-problems|.
|
||||
When your mouse has a scroll wheel, it should work with Nvim in the GUI and
|
||||
any terminal that has mouse support. By default only vertical scroll wheels
|
||||
are supported, but some GUIs also support horizontal scroll wheels.
|
||||
|
||||
Note that horizontal scrolling only works if 'nowrap' is set. Also, unless
|
||||
the "h" flag in 'guioptions' is set, the cursor moves to the longest visible
|
||||
@@ -258,43 +252,4 @@ the scroll wheel move one line or half a page in Normal mode: >
|
||||
:map <S-ScrollWheelDown> <C-D>
|
||||
You can also use Alt and Ctrl modifiers.
|
||||
|
||||
This only works when Vim gets the scroll wheel events, of course. You can
|
||||
check if this works with the "xev" program.
|
||||
|
||||
*<MouseDown>* *<MouseUp>*
|
||||
The keys <MouseDown> and <MouseUp> have been deprecated. Use <ScrollWheelUp>
|
||||
instead of <MouseDown> and use <ScrollWheelDown> instead of <MouseUp>.
|
||||
|
||||
*xterm-mouse-wheel*
|
||||
To use the mouse wheel in a new xterm you only have to make the scroll wheel
|
||||
work in your Xserver, as mentioned above.
|
||||
|
||||
To use the mouse wheel in an older xterm you must do this:
|
||||
1. Make it work in your Xserver, as mentioned above.
|
||||
2. Add translations for the xterm, so that the xterm will pass a scroll event
|
||||
to Vim as an escape sequence.
|
||||
3. Add mappings in Vim, to interpret the escape sequences as <ScrollWheelDown>
|
||||
or <ScrollWheelUp> keys.
|
||||
|
||||
You can do the translations by adding this to your ~.Xdefaults file (or other
|
||||
file where your X resources are kept): >
|
||||
|
||||
XTerm*VT100.Translations: #override \n\
|
||||
s<Btn4Down>: string("0x9b") string("[64~") \n\
|
||||
s<Btn5Down>: string("0x9b") string("[65~") \n\
|
||||
<Btn4Down>: string("0x9b") string("[62~") \n\
|
||||
<Btn5Down>: string("0x9b") string("[63~") \n\
|
||||
<Btn4Up>: \n\
|
||||
<Btn5Up>:
|
||||
|
||||
Add these mappings to your vimrc file: >
|
||||
:map <M-Esc>[62~ <ScrollWheelUp>
|
||||
:map! <M-Esc>[62~ <ScrollWheelUp>
|
||||
:map <M-Esc>[63~ <ScrollWheelDown>
|
||||
:map! <M-Esc>[63~ <ScrollWheelDown>
|
||||
:map <M-Esc>[64~ <S-ScrollWheelUp>
|
||||
:map! <M-Esc>[64~ <S-ScrollWheelUp>
|
||||
:map <M-Esc>[65~ <S-ScrollWheelDown>
|
||||
:map! <M-Esc>[65~ <S-ScrollWheelDown>
|
||||
<
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
||||
|
||||
@@ -322,7 +322,7 @@ static void parse_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data,
|
||||
if (eof) {
|
||||
close_channel(channel);
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "channel %" PRIu64 " was closed by the client",
|
||||
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
|
||||
channel->id);
|
||||
call_set_error(channel, buf);
|
||||
goto end;
|
||||
@@ -352,8 +352,8 @@ static void parse_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data,
|
||||
} else {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"channel %" PRIu64 " sent a response without a matching "
|
||||
"request id. Ensure the client is properly synchronized",
|
||||
"ch %" PRIu64 " returned a response with an unknown request "
|
||||
"id. Ensure the client is properly synchronized",
|
||||
channel->id);
|
||||
call_set_error(channel, buf);
|
||||
}
|
||||
@@ -405,7 +405,7 @@ static void handle_request(Channel *channel, msgpack_object *request)
|
||||
&out_buffer))) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"channel %" PRIu64 " sent an invalid message, closed.",
|
||||
"ch %" PRIu64 " sent an invalid message, closed.",
|
||||
channel->id);
|
||||
call_set_error(channel, buf);
|
||||
}
|
||||
@@ -497,7 +497,7 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
|
||||
char buf[256];
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
"Before returning from a RPC call, channel %" PRIu64 " was "
|
||||
"Before returning from a RPC call, ch %" PRIu64 " was "
|
||||
"closed due to a failed write",
|
||||
channel->id);
|
||||
call_set_error(channel, buf);
|
||||
|
||||
@@ -232,8 +232,9 @@ Terminal *terminal_open(TerminalOptions opts)
|
||||
|
||||
// Default settings for terminal buffers
|
||||
curbuf->b_p_ma = false; // 'nomodifiable'
|
||||
curbuf->b_p_ul = -1; // disable undo
|
||||
curbuf->b_p_ul = -1; // 'undolevels'
|
||||
curbuf->b_p_scbk = 1000; // 'scrollback'
|
||||
curbuf->b_p_tw = 0; // 'textwidth'
|
||||
set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL);
|
||||
set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL);
|
||||
set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL);
|
||||
@@ -370,6 +371,16 @@ void terminal_enter(void)
|
||||
State = TERM_FOCUS;
|
||||
mapped_ctrl_c |= TERM_FOCUS; // Always map CTRL-C to avoid interrupt.
|
||||
RedrawingDisabled = false;
|
||||
|
||||
// Disable these options in terminal-mode. They are nonsense because cursor is
|
||||
// placed at end of buffer to "follow" output.
|
||||
int save_w_p_cul = curwin->w_p_cul;
|
||||
int save_w_p_cuc = curwin->w_p_cuc;
|
||||
int save_w_p_rnu = curwin->w_p_rnu;
|
||||
curwin->w_p_cul = false;
|
||||
curwin->w_p_cuc = false;
|
||||
curwin->w_p_rnu = false;
|
||||
|
||||
adjust_topline(s->term, buf, 0); // scroll to end
|
||||
// erase the unfocused cursor
|
||||
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
|
||||
@@ -383,6 +394,10 @@ void terminal_enter(void)
|
||||
restart_edit = 0;
|
||||
State = save_state;
|
||||
RedrawingDisabled = s->save_rd;
|
||||
curwin->w_p_cul = save_w_p_cul;
|
||||
curwin->w_p_cuc = save_w_p_cuc;
|
||||
curwin->w_p_rnu = save_w_p_rnu;
|
||||
|
||||
// draw the unfocused cursor
|
||||
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
|
||||
unshowmode(true);
|
||||
@@ -988,9 +1003,12 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
|
||||
map_foreach(invalidated_terminals, term, stub, {
|
||||
refresh_terminal(term);
|
||||
});
|
||||
bool any_visible = is_term_visible();
|
||||
pmap_clear(ptr_t)(invalidated_terminals);
|
||||
unblock_autocmds();
|
||||
redraw(true);
|
||||
if (any_visible) {
|
||||
redraw(true);
|
||||
}
|
||||
end:
|
||||
refresh_pending = false;
|
||||
}
|
||||
@@ -1104,6 +1122,18 @@ static void refresh_screen(Terminal *term, buf_T *buf)
|
||||
term->invalid_end = -1;
|
||||
}
|
||||
|
||||
/// @return true if any invalidated terminal buffer is visible to the user
|
||||
static bool is_term_visible(void)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_buffer->terminal
|
||||
&& pmap_has(ptr_t)(invalidated_terminals, wp->w_buffer->terminal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void redraw(bool restore_cursor)
|
||||
{
|
||||
Terminal *term = curbuf->terminal;
|
||||
@@ -1126,18 +1156,17 @@ static void redraw(bool restore_cursor)
|
||||
update_screen(0);
|
||||
}
|
||||
|
||||
if (term && is_focused(term)) {
|
||||
curwin->w_wrow = term->cursor.row;
|
||||
curwin->w_wcol = term->cursor.col + win_col_off(curwin);
|
||||
setcursor();
|
||||
} else if (restore_cursor) {
|
||||
if (restore_cursor) {
|
||||
ui_cursor_goto(save_row, save_col);
|
||||
} else if (term) {
|
||||
// exiting terminal focus, put the window cursor in a valid position
|
||||
int height, width;
|
||||
vterm_get_size(term->vt, &height, &width);
|
||||
curwin->w_wrow = height - 1;
|
||||
curwin->w_wcol = 0;
|
||||
curwin->w_wrow = term->cursor.row;
|
||||
curwin->w_wcol = term->cursor.col + win_col_off(curwin);
|
||||
curwin->w_cursor.lnum = MIN(curbuf->b_ml.ml_line_count,
|
||||
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;
|
||||
setcursor();
|
||||
}
|
||||
|
||||
@@ -1153,6 +1182,7 @@ static void adjust_topline(Terminal *term, buf_T *buf, long added)
|
||||
if (wp->w_buffer == buf) {
|
||||
linenr_T ml_end = buf->b_ml.ml_line_count;
|
||||
bool following = ml_end == wp->w_cursor.lnum + added; // cursor at end?
|
||||
|
||||
if (following || (wp == curwin && is_focused(term))) {
|
||||
// "Follow" the terminal output
|
||||
wp->w_cursor.lnum = ml_end;
|
||||
|
||||
@@ -12,5 +12,9 @@ self = false
|
||||
-- Rerun tests only if their modification time changed.
|
||||
cache = true
|
||||
|
||||
ignore = {
|
||||
"631", -- max_line_length
|
||||
}
|
||||
|
||||
-- Ignore whitespace issues in converted Vim legacy tests.
|
||||
files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
|
||||
|
||||
@@ -22,9 +22,9 @@ describe('TermClose event', function()
|
||||
execute('terminal')
|
||||
feed('<c-\\><c-n>')
|
||||
screen:expect([[
|
||||
ready $ |
|
||||
^ready $ |
|
||||
[Process exited 0] |
|
||||
^ |
|
||||
|
|
||||
TermClose works! |
|
||||
]])
|
||||
end)
|
||||
|
||||
@@ -40,7 +40,7 @@ describe(':ball', function()
|
||||
-- Write contents of this file
|
||||
execute('%yank A')
|
||||
|
||||
-- Append contents of second window (Xxx1)
|
||||
-- Append contents of second window (Xxx1)
|
||||
feed('')
|
||||
execute('%yank A')
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('BufLeave <buffer>', function()
|
||||
execute('au BufLeave <buffer> update')
|
||||
|
||||
-- Here, autocommand for xx shall append a line
|
||||
-- But autocommand shall not apply to buffer named <buffer>
|
||||
-- But autocommand shall not apply to buffer named <buffer>
|
||||
execute('e somefile')
|
||||
|
||||
-- Here, autocommand shall be auto-deleted
|
||||
|
||||
@@ -31,8 +31,8 @@ describe('storing global variables in ShaDa files', function()
|
||||
'set visualbell',
|
||||
'set shada+=!',
|
||||
"let MY_GLOBAL_DICT={'foo': 1, 'bar': 0, 'longvarible': 1000}",
|
||||
-- Store a really long list. Initially this was testing line wrapping in
|
||||
-- viminfo, but shada files has no line wrapping, no matter how long the
|
||||
-- Store a really long list. Initially this was testing line wrapping in
|
||||
-- viminfo, but shada files has no line wrapping, no matter how long the
|
||||
-- list is.
|
||||
'let MY_GLOBAL_LIST=range(1,100)'
|
||||
)
|
||||
|
||||
@@ -50,11 +50,11 @@ describe('terminal buffer', function()
|
||||
feed('<c-\\><c-n>')
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
@@ -74,11 +74,11 @@ describe('terminal buffer', function()
|
||||
feed('<c-\\><c-n>dd')
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
{8:E21: Cannot make changes, 'modifiable' is off} |
|
||||
]])
|
||||
end)
|
||||
|
||||
@@ -34,11 +34,11 @@ describe('terminal cursor', function()
|
||||
feed('<c-\\><c-n>')
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
@@ -51,11 +51,11 @@ describe('terminal cursor', function()
|
||||
it('is positioned correctly when unfocused', function()
|
||||
screen:expect([[
|
||||
{7: 1 }tty ready |
|
||||
{7: 2 }{2: } |
|
||||
{7: 2 }{2:^ } |
|
||||
{7: 3 } |
|
||||
{7: 4 } |
|
||||
{7: 5 } |
|
||||
{7: 6 }^ |
|
||||
{7: 6 } |
|
||||
:set number |
|
||||
]])
|
||||
end)
|
||||
@@ -101,21 +101,21 @@ describe('terminal cursor', function()
|
||||
hide_cursor()
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
]])
|
||||
show_cursor()
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
@@ -153,11 +153,11 @@ describe('cursor with customized highlighting', function()
|
||||
feed('<c-\\><c-n>')
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local thelpers = require('test.functional.terminal.helpers')
|
||||
local clear = helpers.clear
|
||||
local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval
|
||||
local feed, nvim = helpers.feed, helpers.nvim
|
||||
local feed_data = thelpers.feed_data
|
||||
|
||||
@@ -38,31 +38,17 @@ describe('terminal mouse', function()
|
||||
end)
|
||||
|
||||
describe('when the terminal has focus', function()
|
||||
it('will exit focus when scrolled', function()
|
||||
feed('<MouseDown><0,0>')
|
||||
screen:expect([[
|
||||
line23 |
|
||||
line24 |
|
||||
line25 |
|
||||
line26 |
|
||||
line27 |
|
||||
^line28 |
|
||||
|
|
||||
]])
|
||||
it('will exit focus on mouse-scroll', function()
|
||||
eq('t', eval('mode()'))
|
||||
feed('<ScrollWheelUp><0,0>')
|
||||
eq('n', eval('mode()'))
|
||||
end)
|
||||
|
||||
it('will exit focus after <C-\\>, then scrolled', function()
|
||||
it('will exit focus on <C-\\> + mouse-scroll', function()
|
||||
eq('t', eval('mode()'))
|
||||
feed('<C-\\>')
|
||||
feed('<MouseDown><0,0>')
|
||||
screen:expect([[
|
||||
line23 |
|
||||
line24 |
|
||||
line25 |
|
||||
line26 |
|
||||
line27 |
|
||||
^line28 |
|
||||
|
|
||||
]])
|
||||
feed('<ScrollWheelUp><0,0>')
|
||||
eq('n', eval('mode()'))
|
||||
end)
|
||||
|
||||
describe('with mouse events enabled by the program', function()
|
||||
@@ -94,7 +80,7 @@ describe('terminal mouse', function()
|
||||
end)
|
||||
|
||||
it('will forward mouse scroll to the program', function()
|
||||
feed('<MouseDown><0,0>')
|
||||
feed('<ScrollWheelUp><0,0>')
|
||||
screen:expect([[
|
||||
line27 |
|
||||
line28 |
|
||||
@@ -164,7 +150,7 @@ describe('terminal mouse', function()
|
||||
end)
|
||||
|
||||
it('wont lose focus if another window is scrolled', function()
|
||||
feed('<MouseDown><0,0><MouseDown><0,0>')
|
||||
feed('<ScrollWheelUp><0,0><ScrollWheelUp><0,0>')
|
||||
screen:expect([[
|
||||
{7: 21 }line |line30 |
|
||||
{7: 22 }line |rows: 5, cols: 25 |
|
||||
@@ -174,7 +160,7 @@ describe('terminal mouse', function()
|
||||
========== ========== |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
feed('<S-MouseUp><0,0>')
|
||||
feed('<S-ScrollWheelDown><0,0>')
|
||||
screen:expect([[
|
||||
{7: 26 }line |line30 |
|
||||
{7: 27 }line |rows: 5, cols: 25 |
|
||||
|
||||
@@ -18,11 +18,11 @@ describe('terminal window', function()
|
||||
feed('<c-\\><c-n>')
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
{2: } |
|
||||
{2:^ } |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
]])
|
||||
feed(':set colorcolumn=20<cr>i')
|
||||
|
||||
@@ -658,7 +658,7 @@ describe('Mouse input', function()
|
||||
{4:[No Name] [+] }|
|
||||
:vsp |
|
||||
]])
|
||||
feed('<MouseUp><0,0>')
|
||||
feed('<ScrollWheelDown><0,0>')
|
||||
screen:expect([[
|
||||
mouse scrolling {4:|}lines |
|
||||
^ {4:|}to |
|
||||
@@ -675,7 +675,7 @@ describe('Mouse input', function()
|
||||
{4:[No Name] [+] }|
|
||||
|
|
||||
]])
|
||||
feed('<MouseDown><27,0>')
|
||||
feed('<ScrollWheelUp><27,0>')
|
||||
screen:expect([[
|
||||
mouse scrolling {4:|}text |
|
||||
^ {4:|}with |
|
||||
@@ -692,7 +692,7 @@ describe('Mouse input', function()
|
||||
{4:[No Name] [+] }|
|
||||
|
|
||||
]])
|
||||
feed('<MouseDown><27,7><MouseDown>')
|
||||
feed('<ScrollWheelUp><27,7><ScrollWheelUp>')
|
||||
screen:expect([[
|
||||
mouse scrolling {4:|}text |
|
||||
^ {4:|}with |
|
||||
|
||||
@@ -106,7 +106,8 @@ local lua2obj_type_tab = {
|
||||
api.xmalloc(len * ffi.sizeof('KeyValuePair'))),
|
||||
}})
|
||||
for i = 1, len do
|
||||
local key, val = table.unpack(kvs[i])
|
||||
local table_unpack = table.unpack or unpack -- luacheck: compat
|
||||
local key, val = table_unpack(kvs[i])
|
||||
dct.data.dictionary.items[i - 1] = ffi.new(
|
||||
'KeyValuePair', {key=ffi.gc(lua2obj(key), nil).data.string,
|
||||
value=ffi.gc(lua2obj(val), nil)})
|
||||
|
||||
Reference in New Issue
Block a user