Skip to content

Commit

Permalink
Restore cursor position after expr mapping
Browse files Browse the repository at this point in the history
Fix issue (#12707) where cursor is not restored after an expression
mapping. Save the cursor position before evaluating the mapped
expression, restore it after.

Also, redraw command line after expression mappings. Evaluating an
expression can wreak all sorts of havoc on the command line, to avoid
drawing glitches such as those in #12707, it's best to redraw it.

Add tests for:
 - Cursor position restored after :map expr
 - Cursor position restored after :imap expr
 - Command line restored after :cmap expr
 - Error in :cmap expr handled correctly
  • Loading branch information
JaySandhu committed Sep 9, 2020
1 parent 59712f6 commit 379eb23
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 6 deletions.
17 changes: 15 additions & 2 deletions src/nvim/getchar.c
Expand Up @@ -2044,14 +2044,27 @@ static int vgetorpeek(bool advance)
*/
if (mp->m_expr) {
int save_vgetc_busy = vgetc_busy;
int save_cursor_row = ui_current_row();
int save_cursor_col = ui_current_col();

vgetc_busy = 0;
save_m_keys = vim_strsave(mp->m_keys);
save_m_str = vim_strsave(mp->m_str);
s = eval_map_expr(save_m_str, NUL);
vgetc_busy = save_vgetc_busy;
} else

if (State & CMDLINE) {
redrawcmdline();
} else {
if (must_redraw) {
update_screen(0);
}

ui_cursor_goto(save_cursor_row, save_cursor_col);
}
} else {
s = mp->m_str;
}

/*
* Insert the 'to' part in the typebuf.tb_buf.
Expand Down Expand Up @@ -2382,7 +2395,7 @@ static int vgetorpeek(bool advance)
--vgetc_busy;

return c;
}
} // NOLINT(readability/fn_size)

/*
* inchar() - get one character from
Expand Down
130 changes: 130 additions & 0 deletions test/functional/ex_cmds/map_spec.lua
@@ -1,4 +1,5 @@
local helpers = require("test.functional.helpers")(after_each)
local Screen = require('test.functional.ui.screen')

local eq = helpers.eq
local feed = helpers.feed
Expand Down Expand Up @@ -26,3 +27,132 @@ describe(':*map', function()
expect('-foo-')
end)
end)

describe(':*map <expr>', function()
local screen
before_each(function()
clear()
screen = Screen.new(20, 5)
screen:attach()
end)

it('cursor is restored after :map <expr>', function()
command(':map <expr> x input("> ")')
screen:expect([[
^ |
~ |
~ |
~ |
|
]])
feed('x')
screen:expect([[
|
~ |
~ |
~ |
> ^ |
]])
feed('\n')
screen:expect([[
^ |
~ |
~ |
~ |
> |
]])
end)

it('cursor is restored after :imap <expr>', function()
command(':imap <expr> x input("> ")')
feed('i')
screen:expect([[
^ |
~ |
~ |
~ |
-- INSERT -- |
]])
feed('x')
screen:expect([[
|
~ |
~ |
~ |
> ^ |
]])
feed('\n')
screen:expect([[
^ |
~ |
~ |
~ |
> |
]])
end)

it('command line is restored after :cmap <expr>', function()
command(':cmap <expr> x input("> ")')
feed(':foo')
screen:expect([[
|
~ |
~ |
~ |
:foo^ |
]])
feed('x')
screen:expect([[
|
~ |
~ |
~ |
> ^ |
]])
feed('\n')
screen:expect([[
|
~ |
~ |
~ |
:foo^ |
]])
end)

it('error in :cmap <expr> handled correctly', function()
screen:try_resize(40, 5)
command(':cmap <expr> x execute("throw 42")')
feed(':echo "foo')
screen:expect([[
|
~ |
~ |
~ |
:echo "foo^ |
]])
feed('x')
screen:expect([[
|
:echo "foo |
Error detected while processing : |
E605: Exception not caught: 42 |
:echo "foo^ |
]])
feed('"')
screen:expect([[
|
:echo "foo |
Error detected while processing : |
E605: Exception not caught: 42 |
:echo "foo"^ |
]])
feed('\n')
screen:expect([[
:echo "foo |
Error detected while processing : |
E605: Exception not caught: 42 |
foo |
Press ENTER or type command to continue^ |
]])
end)
end)
9 changes: 5 additions & 4 deletions test/functional/ui/cmdline_highlight_spec.lua
Expand Up @@ -410,7 +410,7 @@ describe('Command-line coloring', function()
end)
it('stops executing callback after a number of errors', function()
set_color_cb('SplittedMultibyteStart')
start_prompt('let x = "«»«»«»«»«»"\n')
start_prompt('let x = "«»«»«»«»«»"')
screen:expect([[
{EOB:~ }|
{EOB:~ }|
Expand All @@ -419,7 +419,7 @@ describe('Command-line coloring', function()
:let x = " |
{ERR:E5405: Chunk 0 start 10 splits multibyte}|
{ERR: character} |
^:let x = "«»«»«»«»«»" |
:let x = "«»«»«»«»«»"^ |
]])
feed('\n')
screen:expect([[
Expand All @@ -432,6 +432,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
|
]])
feed('\n')
eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
eq(msg:rep(1), funcs.execute('messages'))
Expand Down Expand Up @@ -474,14 +475,14 @@ describe('Command-line coloring', function()
]])
feed('\n')
screen:expect([[
|
^ |
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
^:echo 42 |
:echo 42 |
]])
feed('\n')
eq('echo 42', meths.get_var('out'))
Expand Down

0 comments on commit 379eb23

Please sign in to comment.