changeset 3390:de60f6fa3d8d v7.3.461

updated for version 7.3.461 Problem: The InsertCharPre autocommand event is not triggered during completion and when typing several characters quickly. Solution: Also trigger InsertCharPre during completion. Do not read ahead when an InsertCharPre autocommand is defined. (Yasuhiro Matsumoto)
author Bram Moolenaar <bram@vim.org>
date Wed, 29 Feb 2012 18:22:08 +0100
parents c10cb9f3c366
children e0dcc19788c2
files src/edit.c src/fileio.c src/proto/fileio.pro src/version.c
diffstat 4 files changed, 87 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/edit.c
+++ b/src/edit.c
@@ -259,6 +259,9 @@ static int  ins_ctrl_ey __ARGS((int tc))
 static void ins_try_si __ARGS((int c));
 #endif
 static colnr_T get_nolist_virtcol __ARGS((void));
+#ifdef FEAT_AUTOCMD
+static char_u *do_insert_char_pre __ARGS((int c));
+#endif
 
 static colnr_T	Insstart_textlen;	/* length of line when insert started */
 static colnr_T	Insstart_blank_vcol;	/* vcol for first inserted blank */
@@ -784,7 +787,20 @@ edit(cmdchar, startln, count)
 		 * completion: Add to "compl_leader". */
 		if (ins_compl_accept_char(c))
 		{
-		    ins_compl_addleader(c);
+#ifdef FEAT_AUTOCMD
+		    /* Trigger InsertCharPre. */
+		    char_u *str = do_insert_char_pre(c);
+		    char_u *p;
+
+		    if (str != NULL)
+		    {
+			for (p = str; *p != NUL; mb_ptr_adv(p))
+			    ins_compl_addleader(PTR2CHAR(p));
+			vim_free(str);
+		    }
+		    else
+#endif
+			ins_compl_addleader(c);
 		    continue;
 		}
 
@@ -1393,34 +1409,31 @@ normalchar:
 #ifdef FEAT_AUTOCMD
 	    if (!p_paste)
 	    {
-		/* Trigger the InsertCharPre event.  Lock the text to avoid
-		 * weird things from happening. */
-		set_vim_var_char(c);
-		++textlock;
-		if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL,
-							       FALSE, curbuf))
+		/* Trigger InsertCharPre. */
+		char_u *str = do_insert_char_pre(c);
+		char_u *p;
+
+		if (str != NULL)
 		{
-		    /* Get the new value of v:char.  If it is more than one
-		     * character insert it literally. */
-		    char_u *s = get_vim_var_str(VV_CHAR);
-		    if (MB_CHARLEN(s) > 1)
+		    if (*str != NUL && stop_arrow() != FAIL)
 		    {
-			if (stop_arrow() != FAIL)
+			/* Insert the new value of v:char literally. */
+			for (p = str; *p != NUL; mb_ptr_adv(p))
 			{
-			    ins_str(s);
-			    AppendToRedobuffLit(s, -1);
+			    c = PTR2CHAR(p);
+			    if (c == CAR || c == K_KENTER || c == NL)
+				ins_eol(c);
+			    else
+				ins_char(c);
 			}
-			c = NUL;
+			AppendToRedobuffLit(str, -1);
 		    }
-		    else
-			c = PTR2CHAR(s);
+		    vim_free(str);
+		    c = NUL;
 		}
 
-		set_vim_var_string(VV_CHAR, NULL, -1);
-		--textlock;
-
-		/* If the new value is an empty string then don't insert a
-		 * char. */
+		/* If the new value is already inserted or an empty string
+		 * then don't insert any character. */
 		if (c == NUL)
 		    break;
 	    }
@@ -5883,6 +5896,8 @@ insertchar(c, flags, second_indent)
      * Don't do this when 'cindent' or 'indentexpr' is set, because we might
      * need to re-indent at a ':', or any other character (but not what
      * 'paste' is set)..
+     * Don't do this when there an InsertCharPre autocommand is defined,
+     * because we need to fire the event for every character.
      */
 #ifdef USE_ON_FLY_SCROLL
     dont_scroll = FALSE;		/* allow scrolling here */
@@ -5900,6 +5915,9 @@ insertchar(c, flags, second_indent)
 #ifdef FEAT_RIGHTLEFT
 	    && !p_ri
 #endif
+#ifdef FEAT_AUTOCMD
+	    && !has_insertcharpre()
+#endif
 	       )
     {
 #define INPUT_BUFLEN 100
@@ -10068,3 +10086,38 @@ get_nolist_virtcol()
     validate_virtcol();
     return curwin->w_virtcol;
 }
+
+#ifdef FEAT_AUTOCMD
+/*
+ * Handle the InsertCharPre autocommand.
+ * "c" is the character that was typed.
+ * Return a pointer to allocated memory with the replacement string.
+ * Return NULL to continue inserting "c".
+ */
+    static char_u *
+do_insert_char_pre(c)
+    int c;
+{
+    char_u *res;
+
+    /* Return quickly when there is nothing to do. */
+    if (!has_insertcharpre())
+	return NULL;
+
+    /* Lock the text to avoid weird things from happening. */
+    ++textlock;
+    set_vim_var_char(c);  /* set v:char */
+
+    if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL, FALSE, curbuf))
+	/* Get the new value of v:char.  It may be empty or more than one
+	 * character. */
+	res = vim_strsave(get_vim_var_str(VV_CHAR));
+    else
+	res = NULL;
+
+    set_vim_var_string(VV_CHAR, NULL, -1);  /* clear v:char */
+    --textlock;
+
+    return res;
+}
+#endif
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -9116,6 +9116,15 @@ has_cursormovedI()
     return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
 }
 
+/*
+ * Return TRUE when there is an InsertCharPre autocommand defined.
+ */
+    int
+has_insertcharpre()
+{
+    return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
+}
+
     static int
 apply_autocmds_group(event, fname, fname_io, force, group, buf, eap)
     event_T	event;
--- a/src/proto/fileio.pro
+++ b/src/proto/fileio.pro
@@ -44,6 +44,7 @@ int has_cursorhold __ARGS((void));
 int trigger_cursorhold __ARGS((void));
 int has_cursormoved __ARGS((void));
 int has_cursormovedI __ARGS((void));
+int has_insertcharpre __ARGS((void));
 void block_autocmds __ARGS((void));
 void unblock_autocmds __ARGS((void));
 int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf));
--- a/src/version.c
+++ b/src/version.c
@@ -715,6 +715,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    461,
+/**/
     460,
 /**/
     459,