4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=ISO-8859-1
7 Content-Transfer-Encoding: 8bit
11 Problem: When a spell files has many compound rules it may take a very long
12 time making the list of suggestions. Displaying also can be slow
13 when there are misspelled words.
14 Can't parse some Hunspell .aff files.
15 Solution: Check if a compounding can possibly work before trying a
16 combination, if the compound rules don't contain wildcards.
17 Implement using CHECKCOMPOUNDPATTERN.
18 Ignore COMPOUNDRULES. Ignore a comment after most items.
19 Accept ONLYINCOMPOUND as an alias for NEEDCOMPOUND.
20 Accept FORBIDDENWORD as an alias for BAD.
21 Files: runtime/doc/spell.txt, src/spell.c
24 *** ../vim-7.2.059/runtime/doc/spell.txt Sat Aug 9 19:36:52 2008
25 --- runtime/doc/spell.txt Sun Nov 30 16:30:02 2008
28 ! *spell.txt* For Vim version 7.2. Last change: 2008 Jun 21
31 VIM REFERENCE MANUAL by Bram Moolenaar
33 ! *spell.txt* For Vim version 7.2. Last change: 2008 Nov 30
36 VIM REFERENCE MANUAL by Bram Moolenaar
42 ! With some items it's also possible to put a comment after it, but this isn't
43 ! supported in general.
51 ! Items with a fixed number of arguments can be followed by a comment. But only
52 ! if none of the arguments can contain white space. The comment must start with
53 ! a "#" character. Example:
55 ! KEEPCASE = # fix case for words with this flag ~
63 Note: When using utf-8 only characters up to 65000 may be used for flags.
65 + Note: even when using "num" or "long" the number of flags available to
66 + compounding and prefixes is limited to about 250.
70 *spell-PFX* *spell-SFX*
74 The flag also applies to the word with affixes, thus this can be used to mark
75 a whole bunch of related words as bad.
77 + *spell-FORBIDDENWORD*
78 + FORBIDDENWORD can be used just like BAD. For compatibility with Hunspell.
81 The NEEDAFFIX flag is used to require that a word is used with an affix. The
82 word itself is not a good word (unless there is an empty affix). Example:
89 + *spell-ONLYINCOMPOUND*
90 + The ONLYINCOMPOUND does exactly the same as NEEDCOMPOUND. Supported for
91 + compatiblity with Hunspell.
94 The minimal character length of a word used for compounding is specified with
99 rules. Can also be used for an affix to count the affix as a compounding
102 + *spell-CHECKCOMPOUNDPATTERN*
103 + CHECKCOMPOUNDPATTERN is used to define patterns that, when matching at the
104 + position where two words are compounded together forbids the compound.
106 + CHECKCOMPOUNDPATTERN o e ~
108 + This forbids compounding if the first word ends in "o" and the second word
111 + The arguments must be plain text, no patterns are actually supported, despite
112 + the item name. Case is always ignored.
114 + The Hunspell feature to use three arguments and flags is not supported.
117 The SYLLABLE item defines characters or character sequences that are used to
118 count the number of syllables in a word. Example:
122 ACCENT (Hunspell) *spell-ACCENT*
123 Use MAP instead. |spell-MAP|
125 + BREAK (Hunspell) *spell-BREAK*
126 + Define break points. Unclear how it works exactly.
129 CHECKCOMPOUNDCASE (Hunspell) *spell-CHECKCOMPOUNDCASE*
130 Disallow uppercase letters at compound word boundaries.
134 Forbid three identical characters when compounding. Not
137 - CHECKCOMPOUNDPATTERN (Hunspell) *spell-CHECKCOMPOUNDPATTERN*
138 - Forbid compounding when patterns match. Not supported.
140 COMPLEXPREFIXES (Hunspell) *spell-COMPLEXPREFIXES*
141 Enables using two prefixes. Not supported.
146 COMPOUNDMIDDLE (Hunspell) *spell-COMPOUNDMIDDLE*
147 Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
149 COMPOUNDSYLLABLE (Hunspell) *spell-COMPOUNDSYLLABLE*
150 Use SYLLABLE and COMPOUNDSYLMAX instead. |spell-SYLLABLE|
151 |spell-COMPOUNDSYLMAX|
153 ! FORBIDDENWORD (Hunspell) *spell-FORBIDDENWORD*
154 ! Use BAD instead. |spell-BAD|
156 LANG (Hunspell) *spell-LANG*
157 This specifies language-specific behavior. This actually
158 moves part of the language knowledge into the program,
160 COMPOUNDMIDDLE (Hunspell) *spell-COMPOUNDMIDDLE*
161 Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
163 + COMPOUNDRULES (Hunspell) *spell-COMPOUNDRULES*
164 + Number of COMPOUNDRULE lines following. Ignored, but the
165 + argument must be a number.
167 COMPOUNDSYLLABLE (Hunspell) *spell-COMPOUNDSYLLABLE*
168 Use SYLLABLE and COMPOUNDSYLMAX instead. |spell-SYLLABLE|
169 |spell-COMPOUNDSYLMAX|
171 ! KEY (Hunspell) *spell-KEY*
172 ! Define characters that are close together on the keyboard.
173 ! Used to give better suggestions. Not supported.
175 LANG (Hunspell) *spell-LANG*
176 This specifies language-specific behavior. This actually
177 moves part of the language knowledge into the program,
180 Only needed for morphological analysis.
182 MAXNGRAMSUGS (Hunspell) *spell-MAXNGRAMSUGS*
185 ! ONLYINCOMPOUND (Hunspell) *spell-ONLYINCOMPOUND*
186 ! Use NEEDCOMPOUND instead. |spell-NEEDCOMPOUND|
188 PSEUDOROOT (Hunspell) *spell-PSEUDOROOT*
189 Use NEEDAFFIX instead. |spell-NEEDAFFIX|
191 Only needed for morphological analysis.
193 MAXNGRAMSUGS (Hunspell) *spell-MAXNGRAMSUGS*
194 ! Set number of n-gram suggestions. Not supported.
196 PSEUDOROOT (Hunspell) *spell-PSEUDOROOT*
197 Use NEEDAFFIX instead. |spell-NEEDAFFIX|
198 *** ../vim-7.2.059/src/spell.c Sat Nov 29 20:18:44 2008
199 --- src/spell.c Sun Nov 30 20:59:13 2008
203 garray_T sl_comppat; /* CHECKCOMPOUNDPATTERN items */
204 regprog_T *sl_compprog; /* COMPOUNDRULE turned into a regexp progrm
205 * (NULL when no compounding) */
206 + char_u *sl_comprules; /* all COMPOUNDRULE concatenated (or NULL) */
207 char_u *sl_compstartflags; /* flags for first compound word */
208 char_u *sl_compallflags; /* all flags for compound words */
209 char_u sl_nobreak; /* When TRUE: no spaces between words */
213 static void slang_clear __ARGS((slang_T *lp));
214 static void slang_clear_sug __ARGS((slang_T *lp));
215 static void find_word __ARGS((matchinf_T *mip, int mode));
216 + static int match_checkcompoundpattern __ARGS((char_u *ptr, int wlen, garray_T *gap));
217 static int can_compound __ARGS((slang_T *slang, char_u *word, char_u *flags));
218 + static int can_be_compound __ARGS((trystate_T *sp, slang_T *slang, char_u *compflags, int flag));
219 + static int match_compoundrule __ARGS((slang_T *slang, char_u *compflags));
220 static int valid_word_prefix __ARGS((int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req));
221 static void find_prefix __ARGS((matchinf_T *mip, int mode));
222 static int fold_more __ARGS((matchinf_T *mip));
226 ((unsigned)flags >> 24)))
229 + /* If there is a match with a CHECKCOMPOUNDPATTERN rule
230 + * discard the compound word. */
231 + if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat))
234 if (mode == FIND_COMPOUND)
240 if (!can_compound(slang, fword, mip->mi_compflags))
243 + else if (slang->sl_comprules != NULL
244 + && !match_compoundrule(slang, mip->mi_compflags))
245 + /* The compound flags collected so far do not match any
246 + * COMPOUNDRULE, discard the compounded word. */
250 /* Check NEEDCOMPOUND: can't use word without compounding. */
257 + * Return TRUE if there is a match between the word ptr[wlen] and
258 + * CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
260 + * A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
261 + * end of ptr[wlen] and the second part matches after it.
264 + match_checkcompoundpattern(ptr, wlen, gap)
267 + garray_T *gap; /* &sl_comppat */
273 + for (i = 0; i + 1 < gap->ga_len; i += 2)
275 + p = ((char_u **)gap->ga_data)[i + 1];
276 + if (STRNCMP(ptr + wlen, p, STRLEN(p)) == 0)
278 + /* Second part matches at start of following compound word, now
279 + * check if first part matches at end of previous word. */
280 + p = ((char_u **)gap->ga_data)[i];
282 + if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0)
290 * Return TRUE if "flags" is a valid sequence of compound flags and "word"
291 * does not have too many syllables.
299 + * Return TRUE when the sequence of flags in "compflags" plus "flag" can
300 + * possibly form a valid compounded word. This also checks the COMPOUNDRULE
301 + * lines if they don't contain wildcards.
304 + can_be_compound(sp, slang, compflags, flag)
310 + /* If the flag doesn't appear in sl_compstartflags or sl_compallflags
311 + * then it can't possibly compound. */
312 + if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
313 + ? slang->sl_compstartflags : slang->sl_compallflags, flag))
316 + /* If there are no wildcards, we can check if the flags collected so far
317 + * possibly can form a match with COMPOUNDRULE patterns. This only
318 + * makes sense when we have two or more words. */
319 + if (slang->sl_comprules != NULL && sp->ts_complen > sp->ts_compsplit)
323 + compflags[sp->ts_complen] = flag;
324 + compflags[sp->ts_complen + 1] = NUL;
325 + v = match_compoundrule(slang, compflags + sp->ts_compsplit);
326 + compflags[sp->ts_complen] = NUL;
335 + * Return TRUE if the compound flags in compflags[] match the start of any
336 + * compound rule. This is used to stop trying a compound if the flags
337 + * collected so far can't possibly match any compound rule.
338 + * Caller must check that slang->sl_comprules is not NULL.
341 + match_compoundrule(slang, compflags)
349 + /* loop over all the COMPOUNDRULE entries */
350 + for (p = slang->sl_comprules; *p != NUL; ++p)
352 + /* loop over the flags in the compound word we have made, match
353 + * them against the current rule entry */
358 + /* found a rule that matches for the flags we have so far */
360 + if (*p == '/' || *p == NUL)
361 + break; /* end of rule, it's too short */
366 + /* compare against all the flags in [] */
368 + while (*p != ']' && *p != NUL)
372 + break; /* none matches */
375 + break; /* flag of word doesn't match flag in pattern */
379 + /* Skip to the next "/", where the next pattern starts. */
380 + p = vim_strchr(p, '/');
385 + /* Checked all the rules and none of them match the flags, so there
386 + * can't possibly be a compound starting with these flags. */
391 * Return non-zero if the prefix indicated by "arridx" matches with the prefix
392 * ID in "flags" for the word "word".
393 * The WF_RAREPFX flag is included in the return value for a rare prefix.
397 lp->sl_midword = NULL;
399 vim_free(lp->sl_compprog);
400 + vim_free(lp->sl_comprules);
401 vim_free(lp->sl_compstartflags);
402 vim_free(lp->sl_compallflags);
403 lp->sl_compprog = NULL;
404 + lp->sl_comprules = NULL;
405 lp->sl_compstartflags = NULL;
406 lp->sl_compallflags = NULL;
421 slang->sl_compallflags = ap;
424 + /* And a list of all patterns in their original form, for checking whether
425 + * compounding may work in match_compoundrule(). This is freed when we
426 + * encounter a wildcard, the check doesn't work then. */
427 + crp = alloc(todo + 1);
428 + slang->sl_comprules = crp;
440 + /* Copy flag to "sl_comprules", unless we run into a wildcard. */
443 + if (c == '+' || c == '*')
445 + vim_free(slang->sl_comprules);
446 + slang->sl_comprules = NULL;
453 if (c == '/') /* slash separates two items */
465 slang->sl_compprog = vim_regcomp(pat, RE_MAGIC + RE_STRING + RE_STRICT);
467 if (slang->sl_compprog == NULL)
473 static afffile_T *spell_read_aff __ARGS((spellinfo_T *spin, char_u *fname));
474 + static int is_aff_rule __ARGS((char_u **items, int itemcnt, char *rulename, int mincount));
475 static void aff_process_flags __ARGS((afffile_T *affile, affentry_T *entry));
476 static int spell_info_item __ARGS((char_u *s));
477 static unsigned affitem2flag __ARGS((int flagtype, char_u *item, char_u *fname, int lnum));
480 /* Handle non-empty lines. */
483 ! if (STRCMP(items[0], "SET") == 0 && itemcnt == 2
484 ! && aff->af_enc == NULL)
487 /* Setup for conversion from "ENC" to 'encoding'. */
489 /* Handle non-empty lines. */
492 ! if (is_aff_rule(items, itemcnt, "SET", 2) && aff->af_enc == NULL)
495 /* Setup for conversion from "ENC" to 'encoding'. */
498 smsg((char_u *)_("Conversion in %s not supported"), fname);
501 ! else if (STRCMP(items[0], "FLAG") == 0 && itemcnt == 2
502 && aff->af_flagtype == AFT_CHAR)
504 if (STRCMP(items[1], "long") == 0)
506 smsg((char_u *)_("Conversion in %s not supported"), fname);
509 ! else if (is_aff_rule(items, itemcnt, "FLAG", 2)
510 && aff->af_flagtype == AFT_CHAR)
512 if (STRCMP(items[1], "long") == 0)
518 ! else if (STRCMP(items[0], "MIDWORD") == 0 && itemcnt == 2
521 midword = getroom_save(spin, items[1]);
523 ! else if (STRCMP(items[0], "TRY") == 0 && itemcnt == 2)
525 /* ignored, we look in the tree for what chars may appear */
527 /* TODO: remove "RAR" later */
528 ! else if ((STRCMP(items[0], "RAR") == 0
529 ! || STRCMP(items[0], "RARE") == 0) && itemcnt == 2
530 ! && aff->af_rare == 0)
532 aff->af_rare = affitem2flag(aff->af_flagtype, items[1],
535 /* TODO: remove "KEP" later */
536 ! else if ((STRCMP(items[0], "KEP") == 0
537 ! || STRCMP(items[0], "KEEPCASE") == 0) && itemcnt == 2
538 && aff->af_keepcase == 0)
540 aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1],
543 ! else if (STRCMP(items[0], "BAD") == 0 && itemcnt == 2
544 ! && aff->af_bad == 0)
546 aff->af_bad = affitem2flag(aff->af_flagtype, items[1],
549 ! else if (STRCMP(items[0], "NEEDAFFIX") == 0 && itemcnt == 2
550 && aff->af_needaffix == 0)
552 aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1],
555 ! else if (STRCMP(items[0], "CIRCUMFIX") == 0 && itemcnt == 2
556 && aff->af_circumfix == 0)
558 aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1],
561 ! else if (STRCMP(items[0], "NOSUGGEST") == 0 && itemcnt == 2
562 && aff->af_nosuggest == 0)
564 aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1],
567 ! else if (STRCMP(items[0], "NEEDCOMPOUND") == 0 && itemcnt == 2
568 && aff->af_needcomp == 0)
570 aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1],
573 ! else if (STRCMP(items[0], "COMPOUNDROOT") == 0 && itemcnt == 2
574 && aff->af_comproot == 0)
576 aff->af_comproot = affitem2flag(aff->af_flagtype, items[1],
579 ! else if (STRCMP(items[0], "COMPOUNDFORBIDFLAG") == 0
580 ! && itemcnt == 2 && aff->af_compforbid == 0)
582 aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
588 ! else if (is_aff_rule(items, itemcnt, "MIDWORD", 2)
591 midword = getroom_save(spin, items[1]);
593 ! else if (is_aff_rule(items, itemcnt, "TRY", 2))
595 /* ignored, we look in the tree for what chars may appear */
597 /* TODO: remove "RAR" later */
598 ! else if ((is_aff_rule(items, itemcnt, "RAR", 2)
599 ! || is_aff_rule(items, itemcnt, "RARE", 2))
600 ! && aff->af_rare == 0)
602 aff->af_rare = affitem2flag(aff->af_flagtype, items[1],
605 /* TODO: remove "KEP" later */
606 ! else if ((is_aff_rule(items, itemcnt, "KEP", 2)
607 ! || is_aff_rule(items, itemcnt, "KEEPCASE", 2))
608 && aff->af_keepcase == 0)
610 aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1],
613 ! else if ((is_aff_rule(items, itemcnt, "BAD", 2)
614 ! || is_aff_rule(items, itemcnt, "FORBIDDENWORD", 2))
615 ! && aff->af_bad == 0)
617 aff->af_bad = affitem2flag(aff->af_flagtype, items[1],
620 ! else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2)
621 && aff->af_needaffix == 0)
623 aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1],
626 ! else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2)
627 && aff->af_circumfix == 0)
629 aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1],
632 ! else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2)
633 && aff->af_nosuggest == 0)
635 aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1],
638 ! else if ((is_aff_rule(items, itemcnt, "NEEDCOMPOUND", 2)
639 ! || is_aff_rule(items, itemcnt, "ONLYINCOMPOUND", 2))
640 && aff->af_needcomp == 0)
642 aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1],
645 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2)
646 && aff->af_comproot == 0)
648 aff->af_comproot = affitem2flag(aff->af_flagtype, items[1],
651 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2)
652 ! && aff->af_compforbid == 0)
654 aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
658 smsg((char_u *)_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
661 ! else if (STRCMP(items[0], "COMPOUNDPERMITFLAG") == 0
662 ! && itemcnt == 2 && aff->af_comppermit == 0)
664 aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
667 smsg((char_u *)_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
670 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2)
671 ! && aff->af_comppermit == 0)
673 aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
677 smsg((char_u *)_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
680 ! else if (STRCMP(items[0], "COMPOUNDFLAG") == 0 && itemcnt == 2
681 && compflags == NULL)
683 /* Turn flag "c" into COMPOUNDRULE compatible string "c+",
685 smsg((char_u *)_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
688 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDFLAG", 2)
689 && compflags == NULL)
691 /* Turn flag "c" into COMPOUNDRULE compatible string "c+",
697 ! else if (STRCMP(items[0], "COMPOUNDRULE") == 0 && itemcnt == 2)
699 /* Concatenate this string to previously defined ones, using a
700 * slash to separate them. */
705 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2))
707 ! /* We don't use the count, but do check that it's a number and
708 ! * not COMPOUNDRULE mistyped. */
709 ! if (atoi((char *)items[1]) == 0)
710 ! smsg((char_u *)_("Wrong COMPOUNDRULES value in %s line %d: %s"),
711 ! fname, lnum, items[1]);
713 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2))
715 /* Concatenate this string to previously defined ones, using a
716 * slash to separate them. */
722 ! else if (STRCMP(items[0], "COMPOUNDWORDMAX") == 0 && itemcnt == 2
725 compmax = atoi((char *)items[1]);
730 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
733 compmax = atoi((char *)items[1]);
736 smsg((char_u *)_("Wrong COMPOUNDWORDMAX value in %s line %d: %s"),
737 fname, lnum, items[1]);
739 ! else if (STRCMP(items[0], "COMPOUNDMIN") == 0 && itemcnt == 2
742 compminlen = atoi((char *)items[1]);
744 smsg((char_u *)_("Wrong COMPOUNDWORDMAX value in %s line %d: %s"),
745 fname, lnum, items[1]);
747 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDMIN", 2)
750 compminlen = atoi((char *)items[1]);
753 smsg((char_u *)_("Wrong COMPOUNDMIN value in %s line %d: %s"),
754 fname, lnum, items[1]);
756 ! else if (STRCMP(items[0], "COMPOUNDSYLMAX") == 0 && itemcnt == 2
759 compsylmax = atoi((char *)items[1]);
761 smsg((char_u *)_("Wrong COMPOUNDMIN value in %s line %d: %s"),
762 fname, lnum, items[1]);
764 ! else if (is_aff_rule(items, itemcnt, "COMPOUNDSYLMAX", 2)
767 compsylmax = atoi((char *)items[1]);
770 smsg((char_u *)_("Wrong COMPOUNDSYLMAX value in %s line %d: %s"),
771 fname, lnum, items[1]);
773 ! else if (STRCMP(items[0], "CHECKCOMPOUNDDUP") == 0 && itemcnt == 1)
775 compoptions |= COMP_CHECKDUP;
777 ! else if (STRCMP(items[0], "CHECKCOMPOUNDREP") == 0 && itemcnt == 1)
779 compoptions |= COMP_CHECKREP;
781 ! else if (STRCMP(items[0], "CHECKCOMPOUNDCASE") == 0 && itemcnt == 1)
783 compoptions |= COMP_CHECKCASE;
785 ! else if (STRCMP(items[0], "CHECKCOMPOUNDTRIPLE") == 0
788 compoptions |= COMP_CHECKTRIPLE;
790 ! else if (STRCMP(items[0], "CHECKCOMPOUNDPATTERN") == 0
793 if (atoi((char *)items[1]) == 0)
794 smsg((char_u *)_("Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"),
795 fname, lnum, items[1]);
797 ! else if (STRCMP(items[0], "CHECKCOMPOUNDPATTERN") == 0
800 garray_T *gap = &spin->si_comppat;
803 smsg((char_u *)_("Wrong COMPOUNDSYLMAX value in %s line %d: %s"),
804 fname, lnum, items[1]);
806 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1))
808 compoptions |= COMP_CHECKDUP;
810 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1))
812 compoptions |= COMP_CHECKREP;
814 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1))
816 compoptions |= COMP_CHECKCASE;
818 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1))
820 compoptions |= COMP_CHECKTRIPLE;
822 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2))
824 if (atoi((char *)items[1]) == 0)
825 smsg((char_u *)_("Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"),
826 fname, lnum, items[1]);
828 ! else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3))
830 garray_T *gap = &spin->si_comppat;
834 = getroom_save(spin, items[2]);
837 ! else if (STRCMP(items[0], "SYLLABLE") == 0 && itemcnt == 2
840 syllable = getroom_save(spin, items[1]);
842 ! else if (STRCMP(items[0], "NOBREAK") == 0 && itemcnt == 1)
844 spin->si_nobreak = TRUE;
846 ! else if (STRCMP(items[0], "NOSPLITSUGS") == 0 && itemcnt == 1)
848 spin->si_nosplitsugs = TRUE;
850 ! else if (STRCMP(items[0], "NOSUGFILE") == 0 && itemcnt == 1)
852 spin->si_nosugfile = TRUE;
854 ! else if (STRCMP(items[0], "PFXPOSTPONE") == 0 && itemcnt == 1)
856 aff->af_pfxpostpone = TRUE;
859 = getroom_save(spin, items[2]);
862 ! else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2)
865 syllable = getroom_save(spin, items[1]);
867 ! else if (is_aff_rule(items, itemcnt, "NOBREAK", 1))
869 spin->si_nobreak = TRUE;
871 ! else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1))
873 spin->si_nosplitsugs = TRUE;
875 ! else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1))
877 spin->si_nosugfile = TRUE;
879 ! else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1))
881 aff->af_pfxpostpone = TRUE;
888 ! else if (STRCMP(items[0], "FOL") == 0 && itemcnt == 2
891 fol = vim_strsave(items[1]);
893 ! else if (STRCMP(items[0], "LOW") == 0 && itemcnt == 2
896 low = vim_strsave(items[1]);
898 ! else if (STRCMP(items[0], "UPP") == 0 && itemcnt == 2
901 upp = vim_strsave(items[1]);
903 ! else if ((STRCMP(items[0], "REP") == 0
904 ! || STRCMP(items[0], "REPSAL") == 0)
907 /* Ignore REP/REPSAL count */;
908 if (!isdigit(*items[1]))
913 ! else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL)
915 fol = vim_strsave(items[1]);
917 ! else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL)
919 low = vim_strsave(items[1]);
921 ! else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL)
923 upp = vim_strsave(items[1]);
925 ! else if (is_aff_rule(items, itemcnt, "REP", 2)
926 ! || is_aff_rule(items, itemcnt, "REPSAL", 2))
928 /* Ignore REP/REPSAL count */;
929 if (!isdigit(*items[1]))
932 : &spin->si_rep, items[1], items[2]);
935 ! else if (STRCMP(items[0], "MAP") == 0 && itemcnt == 2)
937 /* MAP item or count */
940 : &spin->si_rep, items[1], items[2]);
943 ! else if (is_aff_rule(items, itemcnt, "MAP", 2))
945 /* MAP item or count */
949 ga_append(&spin->si_map, '/');
952 ! /* Accept "SAL from to" and "SAL from to # comment". */
953 ! else if (STRCMP(items[0], "SAL") == 0
954 ! && (itemcnt == 3 || (itemcnt > 3 && items[3][0] == '#')))
959 ga_append(&spin->si_map, '/');
962 ! /* Accept "SAL from to" and "SAL from to #comment". */
963 ! else if (is_aff_rule(items, itemcnt, "SAL", 3))
972 ! else if (STRCMP(items[0], "SOFOFROM") == 0 && itemcnt == 2
975 sofofrom = getroom_save(spin, items[1]);
977 ! else if (STRCMP(items[0], "SOFOTO") == 0 && itemcnt == 2
980 sofoto = getroom_save(spin, items[1]);
985 ! else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2)
988 sofofrom = getroom_save(spin, items[1]);
990 ! else if (is_aff_rule(items, itemcnt, "SOFOTO", 2)
993 sofoto = getroom_save(spin, items[1]);
1000 + * Return TRUE when items[0] equals "rulename", there are "mincount" items or
1001 + * a comment is following after item "mincount".
1004 + is_aff_rule(items, itemcnt, rulename, mincount)
1010 + return (STRCMP(items[0], rulename) == 0
1011 + && (itemcnt == mincount
1012 + || (itemcnt > mincount && items[mincount][0] == '#')));
1016 * For affix "entry" move COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG from
1017 * ae_flags to ae_comppermit and ae_compforbid.
1020 *** 11492,11506 ****
1021 vim_strncpy(preword + sp->ts_prewordlen,
1022 tword + sp->ts_splitoff,
1023 sp->ts_twordlen - sp->ts_splitoff);
1025 ! while (*skiptowhite(p) != NUL)
1026 ! p = skipwhite(skiptowhite(p));
1027 ! if (fword_ends && !can_compound(slang, p,
1028 ! compflags + sp->ts_compsplit))
1029 ! /* Compound is not allowed. But it may still be
1030 ! * possible if we add another (short) word. */
1031 compound_ok = FALSE;
1033 /* Get pointer to last char of previous word. */
1034 p = preword + sp->ts_prewordlen;
1035 mb_ptr_back(preword, p);
1036 --- 11675,11698 ----
1037 vim_strncpy(preword + sp->ts_prewordlen,
1038 tword + sp->ts_splitoff,
1039 sp->ts_twordlen - sp->ts_splitoff);
1041 ! /* Verify CHECKCOMPOUNDPATTERN rules. */
1042 ! if (match_checkcompoundpattern(preword, sp->ts_prewordlen,
1043 ! &slang->sl_comppat))
1044 compound_ok = FALSE;
1049 + while (*skiptowhite(p) != NUL)
1050 + p = skipwhite(skiptowhite(p));
1051 + if (fword_ends && !can_compound(slang, p,
1052 + compflags + sp->ts_compsplit))
1053 + /* Compound is not allowed. But it may still be
1054 + * possible if we add another (short) word. */
1055 + compound_ok = FALSE;
1058 /* Get pointer to last char of previous word. */
1059 p = preword + sp->ts_prewordlen;
1060 mb_ptr_back(preword, p);
1062 *** 11697,11706 ****
1063 && (slang->sl_compsylmax < MAXWLEN
1064 || sp->ts_complen + 1 - sp->ts_compsplit
1065 < slang->sl_compmax)
1066 ! && (byte_in_str(sp->ts_complen == sp->ts_compsplit
1067 ! ? slang->sl_compstartflags
1068 ! : slang->sl_compallflags,
1069 ! ((unsigned)flags >> 24))))
1071 try_compound = TRUE;
1072 compflags[sp->ts_complen] = ((unsigned)flags >> 24);
1073 --- 11889,11897 ----
1074 && (slang->sl_compsylmax < MAXWLEN
1075 || sp->ts_complen + 1 - sp->ts_compsplit
1076 < slang->sl_compmax)
1077 ! && (can_be_compound(sp, slang,
1078 ! compflags, ((unsigned)flags >> 24))))
1081 try_compound = TRUE;
1082 compflags[sp->ts_complen] = ((unsigned)flags >> 24);
1083 *** ../vim-7.2.059/src/version.c Sun Nov 30 15:15:56 2008
1084 --- src/version.c Sun Nov 30 21:09:23 2008
1088 { /* Add new patch number below this line */
1094 DEAD PERSON: I'm getting better!
1095 CUSTOMER: No, you're not -- you'll be stone dead in a moment.
1096 MORTICIAN: Oh, I can't take him like that -- it's against regulations.
1097 The Quest for the Holy Grail (Monty Python)
1099 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
1100 /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
1101 \\\ download, build and distribute -- http://www.A-A-P.org ///
1102 \\\ help me help AIDS victims -- http://ICCF-Holland.org ///