updated for version 7.0131
diff --git a/src/eval.c b/src/eval.c
index cd706b4..2dbbb22 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -11959,18 +11959,24 @@
 	char_u	*s;
 	int	saved_did_emsg = did_emsg;
 	char	*fmt;
+	va_list	ap; /* dummy */
+
+# ifdef LINT
+	/* avoid warning for "ap" used before set; it is unused. */
+	va_start(ap, rettv);
+# endif
 
 	/* Get the required length, allocate the buffer and do it for real. */
 	did_emsg = FALSE;
 	fmt = (char *)get_tv_string_buf(&argvars[0], buf);
-	len = vim_vsnprintf(NULL, 0, fmt, NULL, argvars + 1);
+	len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
 	if (!did_emsg)
 	{
 	    s = alloc(len + 1);
 	    if (s != NULL)
 	    {
 		rettv->vval.v_string = s;
-		(void)vim_vsnprintf((char *)s, len + 1, fmt, NULL, argvars + 1);
+		(void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
 	    }
 	}
 	did_emsg |= saved_did_emsg;
@@ -17482,6 +17488,10 @@
 	MSG_PUTS("...");
     }
     msg_putchar(')');
+#ifdef FEAT_EVAL
+    if (p_verbose > 0)
+	last_set_msg(fp->uf_script_ID);
+#endif
 }
 
 /*
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 0f5360f..6e6e297 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -5117,6 +5117,10 @@
 	    msg_outtrans(IObuff);
 
 	    msg_outtrans_special(cmd->uc_rep, FALSE);
+#ifdef FEAT_EVAL
+	    if (p_verbose > 0)
+		last_set_msg(cmd->uc_scriptID);
+#endif
 	    out_flush();
 	    ui_breakcheck();
 	    if (got_int)
diff --git a/src/gui.c b/src/gui.c
index f0d65ee..c7f872e 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -4590,6 +4590,7 @@
     int		type = (flags & FRD_TYPE_MASK);
     char_u	*p;
     regmatch_T	regmatch;
+    int		save_did_emsg = did_emsg;
 
     ga_init2(&ga, 1, 100);
     if (type == FRD_REPLACEALL)
@@ -4666,6 +4667,10 @@
 	msg_scroll = i;	    /* don't let an error message set msg_scroll */
     }
 
+    /* Don't want to pass did_emsg to other code, it may cause disabling
+     * syntax HL if we were busy redrawing. */
+    did_emsg = save_did_emsg;
+
     if (State & (NORMAL | INSERT))
     {
 	gui_update_screen();		/* update the screen */
diff --git a/src/message.c b/src/message.c
index 2b3adcf..cca8a52 100644
--- a/src/message.c
+++ b/src/message.c
@@ -3800,7 +3800,7 @@
  * When va_list is not supported we only define vim_snprintf().
  *
  * vim_vsnprintf() can be invoked with either "va_list" or a list of
- * "typval_T".  The other must be NULL.
+ * "typval_T".  When the latter is not used it must be NULL.
  */
 
 /* When generating prototypes all of this is skipped, cproto doesn't
@@ -3937,7 +3937,7 @@
 		    get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-		    ap == NULL ? tv_nr(tvs, &arg_idx) :
+		    tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 			va_arg(ap, int);
 #endif
@@ -3974,7 +3974,7 @@
 			get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-			ap == NULL ? tv_nr(tvs, &arg_idx) :
+			tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 			    va_arg(ap, int);
 #endif
@@ -4050,7 +4050,7 @@
 			    get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-			    ap == NULL ? tv_nr(tvs, &arg_idx) :
+			    tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 				va_arg(ap, int);
 #endif
@@ -4066,7 +4066,7 @@
 				(char *)get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-				ap == NULL ? tv_str(tvs, &arg_idx) :
+				tvs != NULL ? tv_str(tvs, &arg_idx) :
 # endif
 				    va_arg(ap, char *);
 #endif
@@ -4127,10 +4127,10 @@
 			length_modifier = '\0';
 			ptr_arg =
 #ifndef HAVE_STDARG_H
-				    (void *)get_a_arg(arg_idx);
+				 (void *)get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-				    ap == NULL ? (void *)tv_str(tvs, &arg_idx) :
+				 tvs != NULL ? (void *)tv_str(tvs, &arg_idx) :
 # endif
 					va_arg(ap, void *);
 #endif
@@ -4150,7 +4150,7 @@
 					get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-					ap == NULL ? tv_nr(tvs, &arg_idx) :
+					tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 					    va_arg(ap, int);
 #endif
@@ -4165,7 +4165,7 @@
 					get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-					ap == NULL ? tv_nr(tvs, &arg_idx) :
+					tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 					    va_arg(ap, long int);
 #endif
@@ -4188,7 +4188,7 @@
 					    get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-					    ap == NULL ? tv_nr(tvs, &arg_idx) :
+					    tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 						va_arg(ap, unsigned int);
 #endif
@@ -4201,7 +4201,7 @@
 					    get_a_arg(arg_idx);
 #else
 # if defined(FEAT_EVAL)
-					    ap == NULL ? tv_nr(tvs, &arg_idx) :
+					    tvs != NULL ? tv_nr(tvs, &arg_idx) :
 # endif
 						va_arg(ap, unsigned long int);
 #endif
@@ -4484,7 +4484,7 @@
     }
 
 #ifdef HAVE_STDARG_H
-    if (ap == NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
+    if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
 	EMSG(_("E767: Too many arguments to printf()"));
 #endif
 
diff --git a/src/regexp.c b/src/regexp.c
index 1ff5a06..f8b8616 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -3177,7 +3177,7 @@
      * can't go before line 1 */
     if (reg_firstlnum + lnum < 1)
 	return NULL;
-    if (reg_firstlnum + lnum > reg_buf->b_ml.ml_line_count)
+    if (lnum > reg_maxline)
 	/* Must have matched the "\n" in the last line. */
 	return (char_u *)"";
     return ml_get_buf(reg_buf, reg_firstlnum + lnum, FALSE);
diff --git a/src/screen.c b/src/screen.c
index 6562d65..b3dbe01 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -2594,7 +2594,7 @@
     extra_check = 0;
 #endif
 #ifdef FEAT_SYN_HL
-    if (syntax_present(wp->w_buffer))
+    if (syntax_present(wp->w_buffer) && !wp->w_buffer->b_syn_error)
     {
 	/* Prepare for syntax highlighting in this line.  When there is an
 	 * error, stop syntax highlighting. */
@@ -2602,7 +2602,7 @@
 	did_emsg = FALSE;
 	syntax_start(wp, lnum);
 	if (did_emsg)
-	    syntax_clear(wp->w_buffer);
+	    wp->w_buffer->b_syn_error = TRUE;
 	else
 	{
 	    did_emsg = save_did_emsg;
@@ -3643,7 +3643,10 @@
 					       has_spell ? &can_spell : NULL);
 
 		    if (did_emsg)
-			syntax_clear(wp->w_buffer);
+		    {
+			wp->w_buffer->b_syn_error = TRUE;
+			has_syntax = FALSE;
+		    }
 		    else
 			did_emsg = save_did_emsg;
 
diff --git a/src/spell.c b/src/spell.c
index 114e3f2..a3fc24f 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -51,16 +51,21 @@
  */
 
 /* Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word.
- * Only use it for small word lists!
- * SPELL_COMPRESS_CNT is in how many words we compress the tree to limit the
- * amount of memory used (esp. for Italian). */
+ * Only use it for small word lists! */
 #if 0
 # define SPELL_PRINTTREE
-# define SPELL_COMPRESS_CNT 1
-#else
-# define SPELL_COMPRESS_CNT 1000000
 #endif
 
+/* SPELL_COMPRESS_CNT is after how many allocated blocks we compress the tree
+ * to limit the amount of memory used (esp. for Italian and Hungarian).  The
+ * amount of memory used for nodes then is SPELL_COMPRESS_CNT times
+ * SBLOCKSIZE.
+ * Then compress again after allocating SPELL_COMPRESS_INC more blocks or
+ * adding SPELL_COMPRESS_ADDED words and running out of memory again.  */
+#define SPELL_COMPRESS_CNT 30000
+#define SPELL_COMPRESS_INC 100
+#define SPELL_COMPRESS_ADDED 500000
+
 /*
  * Use this to adjust the score after finding suggestions, based on the
  * suggested word sounding like the bad word.  This is much faster than doing
@@ -594,8 +599,9 @@
     char_u	ts_fidx;	/* index in fword[], case-folded bad word */
     char_u	ts_fidxtry;	/* ts_fidx at which bytes may be changed */
     char_u	ts_twordlen;	/* valid length of tword[] */
-    char_u	ts_prefixdepth;	/* stack depth for end of prefix or PREFIXTREE
-				 * or NOPREFIX */
+    char_u	ts_prefixdepth;	/* stack depth for end of prefix or
+				 * PFD_PREFIXTREE or PFD_NOPREFIX or
+				 * PFD_COMPOUND */
 #ifdef FEAT_MBYTE
     char_u	ts_tcharlen;	/* number of bytes in tword character */
     char_u	ts_tcharidx;	/* current byte index in tword character */
@@ -613,8 +619,9 @@
 #define DIFF_INSERT	2	/* inserting character */
 
 /* special values ts_prefixdepth */
-#define PREFIXTREE	0xfe	/* walking through the prefix tree */
-#define NOPREFIX	0xff	/* not using prefixes */
+#define PFD_COMPOUND	0xfd	/* prefixed is a compound word */
+#define PFD_PREFIXTREE	0xfe	/* walking through the prefix tree */
+#define PFD_NOPREFIX	0xff	/* not using prefixes */
 
 /* mode values for find_word */
 #define FIND_FOLDWORD	    0	/* find word case-folded */
@@ -627,6 +634,7 @@
 static void slang_free __ARGS((slang_T *lp));
 static void slang_clear __ARGS((slang_T *lp));
 static void find_word __ARGS((matchinf_T *mip, int mode));
+static int can_compound __ARGS((slang_T *slang, int flags));
 static int valid_word_prefix __ARGS((int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req));
 static void find_prefix __ARGS((matchinf_T *mip));
 static int fold_more __ARGS((matchinf_T *mip));
@@ -740,6 +748,7 @@
 
 static char *e_format = N_("E759: Format error in spell file");
 static char *e_spell_trunc = N_("E758: Truncated spell file");
+static char *e_afftrailing = N_("Trailing text in %s line %d: %s");
 static char *msg_compressing = N_("Compressing word tree...");
 
 /*
@@ -1156,8 +1165,7 @@
 
 		/* The word doesn't end or it comes after another: it must
 		 * have a compound flag. */
-		/* TODO: check more flags */
-		if (*slang->sl_compflags != ((unsigned)flags >> 24))
+		if (!can_compound(slang, flags))
 		    continue;
 	    }
 
@@ -1231,6 +1239,19 @@
 }
 
 /*
+ * Return TRUE if "flags" has a valid compound flag.
+ * TODO: check flags in a more advanced way.
+ */
+    static int
+can_compound(slang, flags)
+    slang_T	*slang;
+    int		flags;
+{
+    return slang->sl_compflags != NULL
+			   && *slang->sl_compflags == ((unsigned)flags >> 24);
+}
+
+/*
  * Return non-zero if the prefix indicated by "arridx" matches with the prefix
  * ID in "flags" for the word "word".
  * The WF_RAREPFX flag is included in the return value for a rare prefix.
@@ -3324,17 +3345,19 @@
 {
     wordnode_T	*si_foldroot;	/* tree with case-folded words */
     long	si_foldwcount;	/* nr of words in si_foldroot */
-    int		si_fold_added;	/* nr of words added since compressing */
 
     wordnode_T	*si_keeproot;	/* tree with keep-case words */
     long	si_keepwcount;	/* nr of words in si_keeproot */
-    int		si_keep_added;	/* nr of words added since compressing */
 
     wordnode_T	*si_prefroot;	/* tree with postponed prefixes */
 
     sblock_T	*si_blocks;	/* memory blocks used */
+    long	si_blocks_cnt;	/* memory blocks allocated */
+    long	si_compress_cnt;    /* words to add before lowering
+				       compression limit */
     wordnode_T	*si_first_free; /* List of nodes that have been freed during
 				   compression, linked by "wn_child" field. */
+    long	si_free_count;	/* number of nodes in si_first_free */
 #ifdef SPELL_PRINTTREE
     int		si_wordnode_nr;	/* sequence nr for nodes */
 #endif
@@ -3801,8 +3824,7 @@
 		/* Myspell allows extra text after the item, but that might
 		 * mean mistakes go unnoticed.  Require a comment-starter. */
 		if (itemcnt > lasti && *items[lasti] != '#')
-		    smsg((char_u *)_("Trailing text in %s line %d: %s"),
-						   fname, lnum, items[lasti]);
+		    smsg((char_u *)_(e_afftrailing), fname, lnum, items[lasti]);
 
 		/* New item for an affix letter. */
 		--aff_todo;
@@ -3983,9 +4005,13 @@
 		    smsg((char_u *)_("Expected REP count in %s line %d"),
 								 fname, lnum);
 	    }
-	    else if (STRCMP(items[0], "REP") == 0 && itemcnt == 3)
+	    else if (STRCMP(items[0], "REP") == 0 && itemcnt >= 3)
 	    {
 		/* REP item */
+		/* Myspell ignores extra arguments, we require it starts with
+		 * # to detect mistakes. */
+		if (itemcnt > 3 && items[3][0] != '#')
+		    smsg((char_u *)_(e_afftrailing), fname, lnum, items[3]);
 		if (do_rep)
 		    add_fromto(spin, &spin->si_rep, items[1], items[2]);
 	    }
@@ -4119,9 +4145,6 @@
 	    smsg((char_u *)_("COMPOUNDFLAG(S) value differs from what is used in another .aff file"));
 	else
 	    spin->si_compflags = aff->af_compflags;
-
-	if (aff->af_pfxpostpone)
-	    smsg((char_u *)_("Cannot use both PFXPOSTPONE and COMPOUNDFLAG(S)"));
     }
 
     vim_free(pc);
@@ -4412,10 +4435,32 @@
 	    if (affile->af_pfxpostpone)
 		/* Need to store the list of prefix IDs with the word. */
 		store_afflist = get_pfxlist(spin, affile, afflist);
-	    else if (spin->si_compflags)
-		/* Need to store the list of affix IDs for compounding with
-		 * the word. */
-		store_afflist = get_compflags(spin, afflist);
+
+	    if (spin->si_compflags)
+	    {
+		/* Need to store the list of compound flags with the word. */
+		p = get_compflags(spin, afflist);
+		if (p != NULL)
+		{
+		    if (store_afflist != NULL)
+		    {
+			char_u *s;
+
+			/* Concatenate the prefix IDs with the compound flags.
+			 */
+			s = getroom(spin, STRLEN(store_afflist)
+						      + STRLEN(p) + 1, FALSE);
+			if (s != NULL)
+			{
+			    STRCPY(s, store_afflist);
+			    STRCAT(s, p);
+			    store_afflist = s;
+			}
+		    }
+		    else
+			store_afflist = p;
+		}
+	    }
 	}
 
 	/* Add the word to the word tree(s). */
@@ -4938,6 +4983,7 @@
 	bl->sb_next = spin->si_blocks;
 	spin->si_blocks = bl;
 	bl->sb_used = 0;
+	++spin->si_blocks_cnt;
     }
 
     p = bl->sb_data + bl->sb_used;
@@ -4996,7 +5042,8 @@
  * useful when the word can also be used with all caps (no WF_FIXCAP flag) and
  * used to find suggestions.
  * For a keep-case word also store it in the keep-case tree.
- * When "pfxlist" is not NULL store the word for each postponed prefix ID.
+ * When "pfxlist" is not NULL store the word for each postponed prefix ID and
+ * compound flag.
  */
     static int
 store_word(spin, word, flags, region, pfxlist)
@@ -5158,29 +5205,38 @@
     /* count nr of words added since last message */
     ++spin->si_msg_count;
 
+    if (spin->si_compress_cnt > 1)
+    {
+	if (--spin->si_compress_cnt == 1)
+	    /* Did enough words to lower the block count limit. */
+	    spin->si_blocks_cnt += SPELL_COMPRESS_INC;
+    }
+
     /*
-     * Every so many words compress the tree, so that we don't use too much
-     * memory.
+     * When we have allocated lots of memory we need to compress the word tree
+     * to free up some room.  But compression is slow, and we might actually
+     * need that room, thus only compress in the following situations:
+     * 1. When not compressed before (si_compress_cnt == 0): when using
+     *    SPELL_COMPRESS_CNT blocks.
+     * 2. When compressed before and used SPELL_COMPRESS_INC blocks before
+     *    adding SPELL_COMPRESS_ADDED words (si_compress_cnt > 1).
+     * 3. When compressed before, added SPELL_COMPRESS_ADDED words
+     *    (si_compress_cnt == 1) and the number of free nodes drops below the
+     *    maximum word length.
      */
-    i = FALSE;
-    if (root == spin->si_foldroot)
+#ifndef SPELL_PRINTTREE
+    if (spin->si_compress_cnt == 1
+	    ? spin->si_free_count < MAXWLEN
+	    : spin->si_blocks_cnt >= SPELL_COMPRESS_CNT)
+#endif
     {
-	if (++spin->si_fold_added >= SPELL_COMPRESS_CNT)
-	{
-	    i = TRUE;
-	    spin->si_fold_added = 0;
-	}
-    }
-    else if (root == spin->si_keeproot)
-    {
-	if (++spin->si_keep_added >= SPELL_COMPRESS_CNT)
-	{
-	    i = TRUE;
-	    spin->si_keep_added = 0;
-	}
-    }
-    if (i)
-    {
+	/* Decrement the block counter.  The effect is that we compress again
+	 * when the freed up room has been used and another SPELL_COMPRESS_INC
+	 * blocks have been allocated.  Unless SPELL_COMPRESS_ADDED words have
+	 * been added, then the limit is put back again. */
+	spin->si_blocks_cnt -= SPELL_COMPRESS_INC;
+	spin->si_compress_cnt = SPELL_COMPRESS_ADDED;
+
 	if (spin->si_verbose)
 	{
 	    msg_start();
@@ -5190,7 +5246,12 @@
 	    msg_col = 0;
 	    out_flush();
 	}
-	wordtree_compress(spin, root);
+
+	/* Compress both trees.  Either they both have many nodes, which makes
+	 * compression useful, or one of them is small, which means
+	 * compression goes fast. */
+	wordtree_compress(spin, spin->si_foldroot);
+	wordtree_compress(spin, spin->si_keeproot);
     }
 
     return OK;
@@ -5213,6 +5274,7 @@
 	n = spin->si_first_free;
 	spin->si_first_free = n->wn_child;
 	vim_memset(n, 0, sizeof(wordnode_T));
+	--spin->si_free_count;
     }
 #ifdef SPELL_PRINTTREE
     n->wn_nr = ++spin->si_wordnode_nr;
@@ -5252,6 +5314,7 @@
 {
     n->wn_child = spin->si_first_free;
     spin->si_first_free = n;
+    ++spin->si_free_count;
 }
 
 /*
@@ -5282,6 +5345,8 @@
 		verbose_enter();
 	    if (tot > 1000000)
 		perc = (tot - n) / (tot / 100);
+	    else if (tot == 0)
+		perc = 0;
 	    else
 		perc = (tot - n) * 100 / tot;
 	    smsg((char_u *)_("Compressed %d of %d nodes; %d%% remaining"),
@@ -5323,7 +5388,7 @@
      * Note that with "child" we mean not just the node that is pointed to,
      * but the whole list of siblings, of which the node is the first.
      */
-    for (np = node; np != NULL; np = np->wn_sibling)
+    for (np = node; np != NULL && !got_int; np = np->wn_sibling)
     {
 	++len;
 	if ((child = np->wn_child) != NULL)
@@ -5398,6 +5463,9 @@
     node->wn_u1.hashkey[4] = n == 0 ? 1 : n;
     node->wn_u1.hashkey[5] = NUL;
 
+    /* Check for CTRL-C pressed now and then. */
+    fast_breakcheck();
+
     return compressed;
 }
 
@@ -7604,6 +7672,8 @@
     fromto_T	*ftp;
     int		fl = 0, tl;
     int		repextra = 0;	    /* extra bytes in fword[] from REP item */
+    slang_T	*slang;
+    int		fword_ends;
 
     /* We make a copy of the case-folded bad word, so that we can modify it
      * to find matches (esp. REP items).  Append some more text, changing
@@ -7616,6 +7686,8 @@
     for (lp = LANGP_ENTRY(curwin->w_buffer->b_langp, 0);
 						   lp->lp_slang != NULL; ++lp)
     {
+	slang = lp->lp_slang;
+
 	/*
 	 * Go through the whole case-fold tree, try changes at each node.
 	 * "tword[]" contains the word collected from nodes in the tree.
@@ -7639,22 +7711,22 @@
 	 * When there are postponed prefixes we need to use these first.  At
 	 * the end of the prefix we continue in the case-fold tree.
 	 */
-	fbyts = lp->lp_slang->sl_fbyts;
-	fidxs = lp->lp_slang->sl_fidxs;
-	pbyts = lp->lp_slang->sl_pbyts;
-	pidxs = lp->lp_slang->sl_pidxs;
+	fbyts = slang->sl_fbyts;
+	fidxs = slang->sl_fidxs;
+	pbyts = slang->sl_pbyts;
+	pidxs = slang->sl_pidxs;
 	if (pbyts != NULL)
 	{
 	    byts = pbyts;
 	    idxs = pidxs;
-	    sp->ts_prefixdepth = PREFIXTREE;
+	    sp->ts_prefixdepth = PFD_PREFIXTREE;
 	    sp->ts_state = STATE_NOPREFIX;	/* try without prefix first */
 	}
 	else
 	{
 	    byts = fbyts;
 	    idxs = fidxs;
-	    sp->ts_prefixdepth = NOPREFIX;
+	    sp->ts_prefixdepth = PFD_NOPREFIX;
 	}
 
 	/*
@@ -7679,7 +7751,7 @@
 		len = byts[arridx];	    /* bytes in this node */
 		arridx += sp->ts_curi;	    /* index of current byte */
 
-		if (sp->ts_prefixdepth == PREFIXTREE)
+		if (sp->ts_prefixdepth == PFD_PREFIXTREE)
 		{
 		    /* Skip over the NUL bytes, we use them later. */
 		    for (n = 0; n < len && byts[arridx + n] == 0; ++n)
@@ -7743,7 +7815,17 @@
 
 		flags = (int)idxs[arridx];
 
-		if (sp->ts_prefixdepth < MAXWLEN)
+		if (sp->ts_prefixdepth == PFD_COMPOUND)
+		{
+		    /* There was a compound word before this word.  If this
+		     * word does not support compounding then give up
+		     * (splitting is tried for the word without compound
+		     * flag). */
+		    if (sp->ts_twordlen - splitoff < slang->sl_compminlen
+					       || !can_compound(slang, flags))
+			break;
+		}
+		else if (sp->ts_prefixdepth < MAXWLEN)
 		{
 		    /* There was a prefix before the word.  Check that the
 		     * prefix can be used with this word. */
@@ -7756,10 +7838,8 @@
 			;
 		    if (c > 0)
 		    {
-			/* The prefix ID is stored three bytes above the
-			 * flags. */
 			c = valid_word_prefix(c, n, flags,
-				       tword + splitoff, lp->lp_slang, FALSE);
+					      tword + splitoff, slang, FALSE);
 			if (c == 0)
 			    break;
 
@@ -7776,7 +7856,7 @@
 		tword[sp->ts_twordlen] = NUL;
 		if (flags & WF_KEEPCAP)
 		    /* Must find the word in the keep-case tree. */
-		    find_keepcap_word(lp->lp_slang, tword + splitoff,
+		    find_keepcap_word(slang, tword + splitoff,
 							preword + prewordlen);
 		else
 		{
@@ -7818,9 +7898,9 @@
 					 captype(preword + prewordlen, NULL)))
 		    newscore += SCORE_ICASE;
 
-		if ((fword[sp->ts_fidx] == NUL
-			       || !spell_iswordp(fword + sp->ts_fidx, curbuf))
-			&& sp->ts_fidx >= sp->ts_fidxtry)
+		fword_ends = (fword[sp->ts_fidx] == NUL
+			       || !spell_iswordp(fword + sp->ts_fidx, curbuf));
+		if (fword_ends && sp->ts_fidx >= sp->ts_fidxtry)
 		{
 		    /* The badword also ends: add suggestions.  Give a penalty
 		     * when changing non-word char to word char, e.g., "thes,"
@@ -7849,17 +7929,38 @@
 			    sp->ts_fidx - repextra,
 					   sp->ts_score + newscore, 0, FALSE);
 		}
-		else if (sp->ts_fidx >= sp->ts_fidxtry
+		else if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
 #ifdef FEAT_MBYTE
 			/* Don't split halfway a character. */
 			&& (!has_mbyte || sp->ts_tcharlen == 0)
 #endif
 			)
 		{
-		    /* The word in the tree ends but the badword
-		     * continues: try inserting a space and check that a valid
-		     * words starts at fword[sp->ts_fidx]. */
-		    if (try_deeper(su, stack, depth, newscore + SCORE_SPLIT))
+		    int	    try_compound;
+
+		    /* Get here in two situations:
+		     * 1. The word in the tree ends but the badword continues:
+		     *    If the word allows compounding try that.  Otherwise
+		     *    try a split by inserting a space.  For both check
+		     *    that a valid words starts at fword[sp->ts_fidx].
+		     * 2. The badword does end, but it was due to a change
+		     *    (e.g., a swap).  No need to split, but do check that
+		     *    the following word is valid.
+		     */
+		    if (!fword_ends
+			    && spell_iswordp(fword + sp->ts_fidx, curbuf)
+			    && sp->ts_twordlen - splitoff
+						      >= slang->sl_compminlen
+			    && can_compound(slang, flags))
+			try_compound = TRUE;
+		    else
+		    {
+			try_compound = FALSE;
+			if (!fword_ends)
+			    newscore += SCORE_SPLIT;
+		    }
+
+		    if (try_deeper(su, stack, depth, newscore))
 		    {
 			/* Save things to be restored at STATE_SPLITUNDO. */
 			sp->ts_save_prewordlen = prewordlen;
@@ -7870,28 +7971,49 @@
 			++depth;
 			sp = &stack[depth];
 
-			/* Append a space to preword. */
-			STRCAT(preword, " ");
+			/* Append a space to preword when splitting. */
+			if (!try_compound && !fword_ends)
+			    STRCAT(preword, " ");
 			prewordlen = STRLEN(preword);
 			splitoff = sp->ts_twordlen;
 
 			/* If the badword has a non-word character at this
 			 * position skip it.  That means replacing the
-			 * non-word character with a space. */
-			if (!spell_iswordp_nmw(fword + sp->ts_fidx))
+			 * non-word character with a space.  Always skip a
+			 * character when the word ends. */
+			if ((!try_compound
+				   && !spell_iswordp_nmw(fword + sp->ts_fidx))
+				|| fword_ends)
 			{
-			    sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
+			    int	    l;
+
 #ifdef FEAT_MBYTE
 			    if (has_mbyte)
-				sp->ts_fidx += MB_BYTE2LEN(fword[sp->ts_fidx]);
+				l = MB_BYTE2LEN(fword[sp->ts_fidx]);
 			    else
 #endif
-				++sp->ts_fidx;
+				l = 1;
+			    if (fword_ends)
+			    {
+				/* Copy the skipped character to preword. */
+				mch_memmove(preword + prewordlen,
+						      fword + sp->ts_fidx, l);
+				prewordlen += l;
+				preword[prewordlen] = NUL;
+			    }
+			    else
+				sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
+			    sp->ts_fidx += l;
 			}
 
+			/* set flag to check compound flag on following word */
+			if (try_compound)
+			    sp->ts_prefixdepth = PFD_COMPOUND;
+			else
+			    sp->ts_prefixdepth = PFD_NOPREFIX;
+
 			/* set su->su_badflags to the caps type at this
 			 * position */
-
 #ifdef FEAT_MBYTE
 			if (has_mbyte)
 			    n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
@@ -7908,10 +8030,10 @@
 		break;
 
 	    case STATE_SPLITUNDO:
-		/* Undo the changes done for word split. */
+		/* Undo the changes done for word split or compound word. */
 		su->su_badflags = sp->ts_save_badflags;
 		splitoff = sp->ts_save_splitoff;
-		prewordlen =  sp->ts_save_prewordlen;
+		prewordlen = sp->ts_save_prewordlen;
 
 		/* Continue looking for NUL bytes. */
 		sp->ts_state = STATE_START;
@@ -8018,8 +8140,8 @@
 
 				    /* For a similar character adjust score
 				     * from SCORE_SUBST to SCORE_SIMILAR. */
-				    else if (lp->lp_slang->sl_has_map
-					    && similar_chars(lp->lp_slang,
+				    else if (slang->sl_has_map
+					    && similar_chars(slang,
 						mb_ptr2char(tword
 						    + sp->ts_twordlen
 							   - sp->ts_tcharlen),
@@ -8064,8 +8186,8 @@
 			     * We do this after calling try_deeper() because
 			     * it's slow. */
 			    if (newscore != 0
-				    && lp->lp_slang->sl_has_map
-				    && similar_chars(lp->lp_slang,
+				    && slang->sl_has_map
+				    && similar_chars(slang,
 						   c, fword[sp->ts_fidx - 1]))
 				sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
 			}
@@ -8432,7 +8554,7 @@
 		/* Check if matching with REP items from the .aff file would
 		 * work.  Quickly skip if there are no REP items or the score
 		 * is going to be too high anyway. */
-		gap = &lp->lp_slang->sl_rep;
+		gap = &slang->sl_rep;
 		if (gap->ga_len == 0
 			       || sp->ts_score + SCORE_REP >= su->su_maxscore)
 		{
@@ -8442,7 +8564,7 @@
 
 		/* Use the first byte to quickly find the first entry that
 		 * may match.  If the index is -1 there is none. */
-		sp->ts_curi = lp->lp_slang->sl_rep_first[fword[sp->ts_fidx]];
+		sp->ts_curi = slang->sl_rep_first[fword[sp->ts_fidx]];
 		if (sp->ts_curi < 0)
 		{
 		    sp->ts_state = STATE_FINAL;
@@ -8458,7 +8580,7 @@
 		 * word is valid. */
 		p = fword + sp->ts_fidx;
 
-		gap = &lp->lp_slang->sl_rep;
+		gap = &slang->sl_rep;
 		while (sp->ts_curi < gap->ga_len)
 		{
 		    ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
@@ -8500,8 +8622,7 @@
 
 	    case STATE_REP_UNDO:
 		/* Undo a REP replacement and continue with the next one. */
-		ftp = (fromto_T *)lp->lp_slang->sl_rep.ga_data
-							    + sp->ts_curi - 1;
+		ftp = (fromto_T *)slang->sl_rep.ga_data + sp->ts_curi - 1;
 		fl = STRLEN(ftp->ft_from);
 		tl = STRLEN(ftp->ft_to);
 		p = fword + sp->ts_fidx;
@@ -8518,7 +8639,7 @@
 		/* Did all possible states at this level, go up one level. */
 		--depth;
 
-		if (depth >= 0 && stack[depth].ts_prefixdepth == PREFIXTREE)
+		if (depth >= 0 && stack[depth].ts_prefixdepth == PFD_PREFIXTREE)
 		{
 		    /* Continue in or go back to the prefix tree. */
 		    byts = pbyts;
diff --git a/src/structs.h b/src/structs.h
index af859bf..5473510 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1432,6 +1432,7 @@
 #ifdef FEAT_SYN_HL
     hashtab_T	b_keywtab;		/* syntax keywords hash table */
     hashtab_T	b_keywtab_ic;		/* idem, ignore case */
+    int		b_syn_error;		/* TRUE when error occured in HL */
     int		b_syn_ic;		/* ignore case for :syn cmds */
     int		b_syn_spell;		/* SYNSPL_ values */
     garray_T	b_syn_patterns;		/* table for syntax patterns */
diff --git a/src/syntax.c b/src/syntax.c
index 4c4cbad..aa393d7 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3182,6 +3182,7 @@
 {
     int i;
 
+    buf->b_syn_error = FALSE;	    /* clear previous error */
     buf->b_syn_ic = FALSE;	    /* Use case, by default */
     buf->b_syn_spell = SYNSPL_DEFAULT; /* default spell checking */
     buf->b_syn_containedin = FALSE;
diff --git a/src/version.h b/src/version.h
index 4b69735..94726c6 100644
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT	"vim70aa"
 #define VIM_VERSION_SHORT	"7.0aa"
 #define VIM_VERSION_MEDIUM	"7.0aa ALPHA"
-#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Aug 15)"
-#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Aug 15, compiled "
+#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2005 Aug 16)"
+#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2005 Aug 16, compiled "