aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/getchar.c8
-rw-r--r--src/nvim/mapping.c19
-rw-r--r--src/nvim/testdir/test_mapping.vim14
3 files changed, 31 insertions, 10 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index db4d640f46..b0dac7aea6 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -2191,12 +2191,12 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
// Copy the values from *mp that are used, because evaluating the
// expression may invoke a function that redefines the mapping, thereby
// making *mp invalid.
- char save_m_expr = mp->m_expr;
- int save_m_noremap = mp->m_noremap;
- char save_m_silent = mp->m_silent;
+ const bool save_m_expr = mp->m_expr;
+ const int save_m_noremap = mp->m_noremap;
+ const bool save_m_silent = mp->m_silent;
char *save_m_keys = NULL; // only saved when needed
char *save_m_str = NULL; // only saved when needed
- LuaRef save_m_luaref = mp->m_luaref;
+ const LuaRef save_m_luaref = mp->m_luaref;
// Handle ":map <expr>": evaluate the {rhs} as an
// expression. Also save and restore the command line
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 3522e0de36..a412fd05b2 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -1517,17 +1517,23 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
// insert the last typed char
(void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
}
- if (mp->m_expr) {
+
+ // copy values here, calling eval_map_expr() may make "mp" invalid!
+ const int noremap = mp->m_noremap;
+ const bool silent = mp->m_silent;
+ const bool expr = mp->m_expr;
+
+ if (expr) {
s = eval_map_expr(mp, c);
} else {
s = mp->m_str;
}
if (s != NULL) {
// insert the to string
- (void)ins_typebuf(s, mp->m_noremap, 0, true, mp->m_silent);
+ (void)ins_typebuf(s, noremap, 0, true, silent);
// no abbrev. for these chars
typebuf.tb_no_abbr_cnt += (int)strlen(s) + j + 1;
- if (mp->m_expr) {
+ if (expr) {
xfree(s);
}
}
@@ -1536,7 +1542,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
tb[1] = NUL;
len = clen; // Delete characters instead of bytes
while (len-- > 0) { // delete the from string
- (void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
+ (void)ins_typebuf((char *)tb, 1, 0, true, silent);
}
return true;
}
@@ -1546,6 +1552,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
/// Evaluate the RHS of a mapping or abbreviations and take care of escaping
/// special characters.
+/// Careful: after this "mp" will be invalid if the mapping was deleted.
///
/// @param c NUL or typed character for abbreviation
char *eval_map_expr(mapblock_T *mp, int c)
@@ -1560,6 +1567,8 @@ char *eval_map_expr(mapblock_T *mp, int c)
vim_unescape_ks((char_u *)expr);
}
+ const bool replace_keycodes = mp->m_replace_keycodes;
+
// Forbid changing text or using ":normal" to avoid most of the bad side
// effects. Also restore the cursor position.
textlock++;
@@ -1596,7 +1605,7 @@ char *eval_map_expr(mapblock_T *mp, int c)
char *res = NULL;
- if (mp->m_replace_keycodes) {
+ if (replace_keycodes) {
replace_termcodes(p, strlen(p), &res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
} else {
// Escape K_SPECIAL in the result to be able to use the string as typeahead.
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 522a51589f..5c5a65d4ca 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -767,6 +767,11 @@ func Test_mapcomplete()
mapclear
endfunc
+func GetAbbrText()
+ unabbr hola
+ return 'hello'
+endfunc
+
" Test for <expr> in abbreviation
func Test_expr_abbr()
new
@@ -782,7 +787,14 @@ func Test_expr_abbr()
call assert_equal('', getline(1))
unabbr <expr> hte
- close!
+ " evaluating the expression deletes the abbreviation
+ abbr <expr> hola GetAbbrText()
+ call assert_equal('GetAbbrText()', maparg('hola', 'i', '1'))
+ call feedkeys("ahola \<Esc>", 'xt')
+ call assert_equal('hello ', getline('.'))
+ call assert_equal('', maparg('hola', 'i', '1'))
+
+ bwipe!
endfunc
" Test for storing mappings in different modes in a vimrc file