According to the help, using getchar() in an <expr> map should be avoided:

  - You can use getchar(), but the existing typeahead isn't seen and new
    typeahead is discarded.

I'm not sure this limitation is warranted.

A while back, a user in #vim requested the ability to bracket i_Ctrl-r
with i_Ctrl-g_u so they could more easily undo their changes.  My
immediate suggestion was:

  inoremap <expr> <C-r> "\<C-g>u\<C-r>".nr2char(getchar())."\<C-g>u"

This actually works fine, unless you have another mapping that starts
with the same {lhs}.  Using the following mappings (simplified for
testing):

  inoremap <expr> <C-r> nr2char(getchar())
  inoremap <expr> <C-r>xl "foo"

If I press <C-r>xa, I would expect to have xa inserted into the buffer.
Instead after <C-r>xa, getchar() is waiting for me to type a character.
So I type y and yxa gets inserted into the buffer.

The xa that I typed to disambiguate the mapping was part of the existing
typeahead, so when the mapping finally gets triggered it is cached, I'm
prompted for a character (y) which is pushed onto the typeahead, and
then the previous typeahead is restored.

If I instead wait for the mapping to timeout, everything works fine, but
having to wait for the timeout gets pretty annoying.

This same behavior is what was causing the problem ZyX posted[0] about
some time ago and resulted in this TODO entry:

  Cannot use getchar() inside :normal and using an expression mapping.  Is this
  supposed to work?  (XyX, 2010 Sep 22)

So, I'm not really sure what stashing/restoring the typeahead is
supposed to protect against.  I haven't seen a way to workaround that
stashing with my map disambiguation example and it seems to cause other
uses to break even when there aren't ambiguous maps involved.  Based on
that, I propose the attached patch to remove that restriction.

Thanks,
James

[0]: http://mid.gmane.org/201009222031.13720@-zyx
-- 
James
GPG Key: 1024D/61326D40 2003-09-02 James Vega <james...@jamessan.com>
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -237,8 +237,6 @@
 - Editing another buffer.
 - The |:normal| command.
 - Moving the cursor is allowed, but it is restored afterwards.
-- You can use getchar(), but the existing typeahead isn't seen and new
-  typeahead is discarded.
 If you want the mapping to do any of these let the returned characters do
 that.
 
diff --git a/src/getchar.c b/src/getchar.c
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -2460,27 +2460,17 @@
 
 			/*
 			 * Handle ":map <expr>": evaluate the {rhs} as an
-			 * expression.  Save and restore the typeahead so that
-			 * getchar() can be used.  Also save and restore the
-			 * command line for "normal :".
+			 * expression.  Also save and restore the command line
+			 * for "normal :".
 			 */
 			if (mp->m_expr)
 			{
-			    tasave_T	tabuf;
 			    int		save_vgetc_busy = vgetc_busy;
-
-			    save_typeahead(&tabuf);
-			    if (tabuf.typebuf_valid)
-			    {
-				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
-				s = NULL;
-			    restore_typeahead(&tabuf);
+			    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
 #endif

Attachment: signature.asc
Description: Digital signature

Raspunde prin e-mail lui