diff options
author | Bram Moolenaar <Bram@vim.org> | 2005-04-15 21:00:38 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2005-04-15 21:00:38 +0000 |
commit | 402d2fea7025356c7abcb891017a1b7ddf99cbbf (patch) | |
tree | 83c5973b6316912331d4a4c070996d7888097e5c /src | |
parent | 4499d2ee58db42e4ec59bb2c2dbb5eeca2313e8b (diff) |
updated for version 7.0066
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 25 | ||||
-rw-r--r-- | src/charset.c | 23 | ||||
-rw-r--r-- | src/ex_docmd.c | 20 | ||||
-rw-r--r-- | src/fileio.c | 5 | ||||
-rw-r--r-- | src/gui.c | 13 | ||||
-rw-r--r-- | src/gui_kde_x11.cc | 12 | ||||
-rw-r--r-- | src/gui_w32.c | 4 | ||||
-rw-r--r-- | src/macros.h | 2 | ||||
-rw-r--r-- | src/mbyte.c | 5 | ||||
-rw-r--r-- | src/misc2.c | 3 | ||||
-rw-r--r-- | src/normal.c | 25 | ||||
-rw-r--r-- | src/os_unix.c | 2 | ||||
-rw-r--r-- | src/quickfix.c | 9 | ||||
-rw-r--r-- | src/regexp.c | 92 | ||||
-rw-r--r-- | src/screen.c | 4 | ||||
-rw-r--r-- | src/spell.c | 4025 | ||||
-rw-r--r-- | src/tag.c | 8 | ||||
-rw-r--r-- | src/version.h | 4 |
18 files changed, 4040 insertions, 241 deletions
diff --git a/src/Makefile b/src/Makefile index 366dcddb6c..16d3338ecd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1292,6 +1292,9 @@ DEST_MAN_TOP = $(DESTDIR)$(MANDIR) # directory first. # FreeBSD uses ".../man/xx.ISO8859-1/man1" for latin1, use that one too. DEST_MAN = $(DEST_MAN_TOP)$(MAN1DIR) +DEST_MAN_FR = $(DEST_MAN_TOP)/fr$(MAN1DIR) +DEST_MAN_FR_I = $(DEST_MAN_TOP)/fr.ISO8859-1$(MAN1DIR) +DEST_MAN_FR_U = $(DEST_MAN_TOP)/fr.UTF-8$(MAN1DIR) DEST_MAN_IT = $(DEST_MAN_TOP)/it$(MAN1DIR) DEST_MAN_IT_I = $(DEST_MAN_TOP)/it.ISO8859-1$(MAN1DIR) DEST_MAN_IT_U = $(DEST_MAN_TOP)/it.UTF-8$(MAN1DIR) @@ -1823,6 +1826,9 @@ installtools: $(TOOLS) $(DESTDIR)$(exec_prefix) $(DEST_BIN) \ $(STRIP) $(DEST_BIN)/xxd$(EXEEXT) chmod $(BINMOD) $(DEST_BIN)/xxd$(EXEEXT) -$(SHELL) ./installman.sh xxd $(DEST_MAN) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS) -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT) "-it" $(INSTALLMANARGS) -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS) -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS) @@ -1845,12 +1851,21 @@ installtools: $(TOOLS) $(DESTDIR)$(exec_prefix) $(DEST_BIN) \ # install the language specific files, if they were unpacked install-languages: languages $(DEST_LANG) $(DEST_KMAP) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh install $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS) -$(SHELL) ./installman.sh install $(DEST_MAN_IT) "-it" $(INSTALLMANARGS) -$(SHELL) ./installman.sh install $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS) -$(SHELL) ./installman.sh install $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS) -$(SHELL) ./installman.sh install $(DEST_MAN_RU) "-ru" $(INSTALLMANARGS) -$(SHELL) ./installman.sh install $(DEST_MAN_RU_U) "-ru.UTF-8" $(INSTALLMANARGS) -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ $(DEST_MAN_IT) $(INSTALLMLARGS) -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \ $(DEST_MAN_IT_I) $(INSTALLMLARGS) @@ -2006,6 +2021,9 @@ uninstall: uninstall_runtime # Note: the "rmdir" will fail if any files were added after "make install" uninstall_runtime: -$(SHELL) ./installman.sh uninstall $(DEST_MAN) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_I) "" $(INSTALLMANARGS) + -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_U) "" $(INSTALLMANARGS) -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT) "" $(INSTALLMANARGS) -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_I) "" $(INSTALLMANARGS) -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_U) "" $(INSTALLMANARGS) @@ -2014,6 +2032,12 @@ uninstall_runtime: -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ $(DEST_MAN) $(INSTALLMLARGS) -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_I) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ + $(DEST_MAN_FR_U) $(INSTALLMLARGS) + -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ $(DEST_MAN_IT) $(INSTALLMLARGS) -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ $(DEST_MAN_IT_I) $(INSTALLMLARGS) @@ -2024,6 +2048,7 @@ uninstall_runtime: -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \ $(DEST_MAN_RU_U) $(INSTALLMLARGS) -rm -f $(DEST_MAN)/xxd.1 + -rm -f $(DEST_MAN_FR)/xxd.1 $(DEST_MAN_FR_I)/xxd.1 $(DEST_MAN_FR_U)/xxd.1 -rm -f $(DEST_MAN_IT)/xxd.1 $(DEST_MAN_IT_I)/xxd.1 $(DEST_MAN_IT_U)/xxd.1 -rm -f $(DEST_MAN_RU)/xxd.1 $(DEST_MAN_RU_U)/xxd.1 -rm -f $(DEST_HELP)/*.txt $(DEST_HELP)/tags $(DEST_HELP)/*.pl diff --git a/src/charset.c b/src/charset.c index bd319ffe7c..a82a7264ba 100644 --- a/src/charset.c +++ b/src/charset.c @@ -972,6 +972,19 @@ init_spell_chartab() } #endif #ifdef FEAT_MBYTE + else if (STRCMP(p_enc, "iso-8859-2") == 0) + { + /* latin2 */ + for ( ; i <= 0xa0; ++i) + spell_chartab[i] = FALSE; + for ( ; i <= 255; ++i) + spell_chartab[i] = TRUE; + spell_chartab[0xa4] = FALSE; /* currency sign */ + spell_chartab[0xa7] = FALSE; /* paragraph sign */ + spell_chartab[0xad] = FALSE; /* dash */ + spell_chartab[0xb0] = FALSE; /* degrees */ + spell_chartab[0xf7] = FALSE; /* divide-by */ + } else #endif #if defined(FEAT_MBYTE) || !defined(MSDOS) @@ -1117,6 +1130,7 @@ win_lbr_chartabsize(wp, s, col, headp) int numberextra; char_u *ps; int tab_corr = (*s == TAB); + int n; /* * No 'linebreak' and 'showbreak': return quickly. @@ -1160,9 +1174,12 @@ win_lbr_chartabsize(wp, s, col, headp) col2 = col; colmax = W_WIDTH(wp) - numberextra; if (col >= colmax) - colmax += (((col - colmax) - / (colmax + win_col_off2(wp))) + 1) - * (colmax + win_col_off2(wp)); + { + n = colmax + win_col_off2(wp); + if (n > 0) + colmax += (((col - colmax) / n) + 1) * n; + } + for (;;) { ps = s; diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 5f79af92c7..76fafeff01 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -223,6 +223,9 @@ static void ex_popup __ARGS((exarg_T *eap)); #ifndef FEAT_SYN_HL # define ex_syntax ex_ni #endif +#if !defined(FEAT_SYN_HL) || !defined(FEAT_MBYTE) +# define ex_mkspell ex_ni +#endif #ifndef FEAT_MZSCHEME # define ex_mzscheme ex_script_ni # define ex_mzfile ex_ni @@ -4149,11 +4152,11 @@ expand_filename(eap, cmdlinep, errormsgp) /* For a shell command a '!' must be escaped. */ if ((eap->usefilter || eap->cmdidx == CMD_bang) - && vim_strchr(repl, '!') != NULL) + && vim_strpbrk(repl, "!&;()") != NULL) { char_u *l; - l = vim_strsave_escaped(repl, (char_u *)"!"); + l = vim_strsave_escaped(repl, (char_u *)"!&;()"); if (l != NULL) { vim_free(repl); @@ -7328,7 +7331,8 @@ ex_equal(eap) ex_sleep(eap) exarg_T *eap; { - int n; + int n; + long len; if (cursor_valid()) { @@ -7336,7 +7340,15 @@ ex_sleep(eap) if (n >= 0) windgoto((int)n, curwin->w_wcol); } - do_sleep(eap->line2 * (*eap->arg == 'm' ? 1L : 1000L)); + + len = eap->line2; + switch (*eap->arg) + { + case 'm': break; + case NUL: len *= 1000L; break; + default: EMSG2(_(e_invarg2), eap->arg); return; + } + do_sleep(len); } /* diff --git a/src/fileio.c b/src/fileio.c index a5e888abee..d88111a135 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2649,7 +2649,10 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit, if (reset_changed && whole && buf == curbuf - && curbuf->b_ffname == NULL +#ifdef FEAT_QUICKFIX + && !bt_nofile(buf) +#endif + && buf->b_ffname == NULL && !filtering && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { @@ -4326,17 +4326,18 @@ ex_gui(eap) /* * This is shared between Athena, Motif and GTK. */ -static char_u *gfp_buffer; - -static void gfp_setname __ARGS((char_u *fname)); +static void gfp_setname __ARGS((char_u *fname, void *cookie)); /* * Callback function for do_in_runtimepath(). */ static void -gfp_setname(fname) +gfp_setname(fname, cookie) char_u *fname; + void *cookie; { + char_u *gfp_buffer = cookie; + if (STRLEN(fname) >= MAXPATHL) *gfp_buffer = NUL; else @@ -4356,8 +4357,8 @@ gui_find_bitmap(name, buffer, ext) if (STRLEN(name) > MAXPATHL - 14) return FAIL; sprintf((char *)buffer, "bitmaps/%s.%s", name, ext); - gfp_buffer = buffer; - if (do_in_runtimepath(buffer, FALSE, gfp_setname) == FAIL || *buffer == NUL) + if (do_in_runtimepath(buffer, FALSE, gfp_setname, buffer) == FAIL + || *buffer == NUL) return FAIL; return OK; } diff --git a/src/gui_kde_x11.cc b/src/gui_kde_x11.cc index 3bb80765ac..21969c5861 100644 --- a/src/gui_kde_x11.cc +++ b/src/gui_kde_x11.cc @@ -970,10 +970,20 @@ gui_mch_draw_part_cursor(int w, int h, guicolor_T color)//{{{ QPainter p(gui.w); p.setPen(color); p.fillRect( +#ifdef FEAT_RIGHTLEFT + /* vertical line should be on the right of current point */ + CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : +#endif FILL_X(gui.col), FILL_Y(gui.row) + gui.char_height - h + 1, w, h - 2, QColor( color, color)); - p.drawRect(FILL_X(gui.col), FILL_Y(gui.row) + gui.char_height - h + p.drawRect( +#ifdef FEAT_RIGHTLEFT + /* vertical line should be on the right of current point */ + CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : +#endif + FILL_X(gui.col), + FILL_Y(gui.row) + gui.char_height - h + (int)p_linespace / 2, w, h - (int)p_linespace); }//}}} diff --git a/src/gui_w32.c b/src/gui_w32.c index 50c5e59397..e83ff40602 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -1794,7 +1794,7 @@ gui_mch_draw_string( #ifdef FEAT_MBYTE static WCHAR *unicodebuf = NULL; static int *unicodepdy = NULL; - int unibuflen = 0; + static int unibuflen = 0; int n = 0; #endif HPEN hpen, old_pen; @@ -1923,7 +1923,7 @@ gui_mch_draw_string( break; /* Check if the Unicode buffer exists and is big enough. Create it - * with the same lengt as the multi-byte string, the number of wide + * with the same length as the multi-byte string, the number of wide * characters is always equal or smaller. */ if ((enc_utf8 || (enc_codepage > 0 && (int)GetACP() != enc_codepage) diff --git a/src/macros.h b/src/macros.h index 233df0f25c..f7bb10dca3 100644 --- a/src/macros.h +++ b/src/macros.h @@ -260,8 +260,10 @@ # define mb_ptr_adv(p) p += has_mbyte ? (*mb_ptr2len_check)(p) : 1 # define mb_ptr_back(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1 # define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++ +# define MB_CHARLEN(p) mb_charlen(p) #else # define mb_ptr_adv(p) ++p # define mb_ptr_back(s, p) --p # define MB_COPY_CHAR(f, t) *t++ = *f++ +# define MB_CHARLEN(p) STRLEN(p) #endif diff --git a/src/mbyte.c b/src/mbyte.c index 7f8400d5cd..70bb843892 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -706,6 +706,11 @@ codepage_invalid: gui_mch_update_codec(); #endif +#ifdef FEAT_SYN_HL + /* Need to reload spell dictionaries */ + spell_reload(); +#endif + return NULL; } diff --git a/src/misc2.c b/src/misc2.c index c8952074cd..0735e29636 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -5241,7 +5241,8 @@ qsort(base, elm_count, elm_size, cmp) } #endif -#if defined(FEAT_EX_EXTRA) || defined(FEAT_CMDL_COMPL) || defined(PROTO) +#if defined(FEAT_EX_EXTRA) || defined(FEAT_CMDL_COMPL) \ + || (defined(FEAT_SYN_HL) && defined(FEAT_MBYTE)) || defined(PROTO) /* * Sort an array of strings. */ diff --git a/src/normal.c b/src/normal.c index fb6f8f9819..85d84c45be 100644 --- a/src/normal.c +++ b/src/normal.c @@ -6065,6 +6065,18 @@ nv_brackets(cap) } #endif +#ifdef FEAT_SYN_HL + /* + * "[s", "[S", "]s" and "]S": move to next spell error. + */ + else if (cap->nchar == 's' || cap->nchar == 'S') + { + if (spell_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD, + cap->nchar == 's' ? TRUE : FALSE) == FAIL) + clearopbeep(cap->oap); + } +#endif + /* Not a valid cap->nchar. */ else clearopbeep(cap->oap); @@ -8493,6 +8505,7 @@ nv_put(cap) int regname = 0; void *reg1 = NULL, *reg2 = NULL; int empty = FALSE; + int was_visual = FALSE; #endif int dir; int flags = 0; @@ -8527,6 +8540,7 @@ nv_put(cap) * Need to save and restore the registers that the delete * overwrites if the old contents is being put. */ + was_visual = TRUE; regname = cap->oap->regname; # ifdef FEAT_CLIPBOARD adjust_clip_reg(®name); @@ -8587,8 +8601,17 @@ nv_put(cap) /* If a register was saved, put it back now. */ if (reg2 != NULL) put_register(regname, reg2); + + /* What to reselect with "gv"? Selecting the just put text seems to + * be the most useful, since the original text was removed. */ + if (was_visual) + { + curbuf->b_visual_start = curbuf->b_op_start; + curbuf->b_visual_end = curbuf->b_op_end; + } + /* When all lines were selected and deleted do_put() leaves an empty - * line that needs to delete now. */ + * line that needs to be deleted now. */ if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) ml_delete(curbuf->b_ml.ml_line_count, TRUE); #endif diff --git a/src/os_unix.c b/src/os_unix.c index afe9bfdc06..80735b69a0 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5177,6 +5177,8 @@ mch_expand_wildcards(num_pat, pat, num_file, file, flags) else if (!intick && vim_strchr((char_u *)" '", pat[i][j]) != NULL) { + /* Put quotes around special characters, but not when + * inside ``. */ *p++ = '"'; while (pat[i][j] != NUL && vim_strchr((char_u *)" '", pat[i][j]) != NULL) diff --git a/src/quickfix.c b/src/quickfix.c index a4c016e09a..e022c787a5 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -2338,11 +2338,9 @@ ex_vimgrep(eap) char_u **fnames; char_u *s; char_u *p; - int i; int fi; qfline_T *prevp = NULL; long lnum; - garray_T ga; buf_T *buf; int duplicate_name = FALSE; int using_dummy; @@ -2404,12 +2402,7 @@ ex_vimgrep(eap) ; /* parse the list of arguments */ - if (get_arglist(&ga, p) == FAIL) - goto theend; - i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, - &fcount, &fnames, EW_FILE|EW_NOTFOUND); - ga_clear(&ga); - if (i == FAIL) + if (get_arglist_exp(p, &fcount, &fnames) == FAIL) goto theend; if (fcount == 0) { diff --git a/src/regexp.c b/src/regexp.c index fe20b3a8fb..8a2643dcce 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -738,65 +738,69 @@ reg_equi_class(c) { switch (c) { - case 'A': case 'À': case 'Á': case 'Â': - case 'Ã': case 'Ä': case 'Å': - regmbc('A'); regmbc('À'); regmbc('Á'); regmbc('Â'); - regmbc('Ã'); regmbc('Ä'); regmbc('Å'); + case 'A': case '\300': case '\301': case '\302': + case '\303': case '\304': case '\305': + regmbc('A'); regmbc('\300'); regmbc('\301'); + regmbc('\302'); regmbc('\303'); regmbc('\304'); + regmbc('\305'); return; - case 'C': case 'Ç': - regmbc('C'); regmbc('Ç'); + case 'C': case '\307': + regmbc('C'); regmbc('\307'); return; - case 'E': case 'È': case 'É': case 'Ê': case 'Ë': - regmbc('E'); regmbc('È'); regmbc('É'); regmbc('Ê'); - regmbc('Ë'); + case 'E': case '\310': case '\311': case '\312': case '\313': + regmbc('E'); regmbc('\310'); regmbc('\311'); + regmbc('\312'); regmbc('\313'); return; - case 'I': case 'Ì': case 'Í': case 'Î': case 'Ï': - regmbc('I'); regmbc('Ì'); regmbc('Í'); regmbc('Î'); - regmbc('Ï'); + case 'I': case '\314': case '\315': case '\316': case '\317': + regmbc('I'); regmbc('\314'); regmbc('\315'); + regmbc('\316'); regmbc('\317'); return; - case 'N': case 'Ñ': - regmbc('N'); regmbc('Ñ'); + case 'N': case '\321': + regmbc('N'); regmbc('\321'); return; - case 'O': case 'Ò': case 'Ó': case 'Ô': case 'Õ': case 'Ö': - regmbc('O'); regmbc('Ò'); regmbc('Ó'); regmbc('Ô'); - regmbc('Õ'); regmbc('Ö'); + case 'O': case '\322': case '\323': case '\324': case '\325': + case '\326': + regmbc('O'); regmbc('\322'); regmbc('\323'); + regmbc('\324'); regmbc('\325'); regmbc('\326'); return; - case 'U': case 'Ù': case 'Ú': case 'Û': case 'Ü': - regmbc('U'); regmbc('Ù'); regmbc('Ú'); regmbc('Û'); - regmbc('Ü'); + case 'U': case '\331': case '\332': case '\333': case '\334': + regmbc('U'); regmbc('\331'); regmbc('\332'); + regmbc('\333'); regmbc('\334'); return; - case 'Y': case 'Ý': - regmbc('Y'); regmbc('Ý'); + case 'Y': case '\335': + regmbc('Y'); regmbc('\335'); return; - case 'a': case 'à': case 'á': case 'â': - case 'ã': case 'ä': case 'å': - regmbc('a'); regmbc('à'); regmbc('á'); regmbc('â'); - regmbc('ã'); regmbc('ä'); regmbc('å'); + case 'a': case '\340': case '\341': case '\342': + case '\343': case '\344': case '\345': + regmbc('a'); regmbc('\340'); regmbc('\341'); + regmbc('\342'); regmbc('\343'); regmbc('\344'); + regmbc('\345'); return; - case 'c': case 'ç': - regmbc('c'); regmbc('ç'); + case 'c': case '\347': + regmbc('c'); regmbc('\347'); return; - case 'e': case 'è': case 'é': case 'ê': case 'ë': - regmbc('e'); regmbc('è'); regmbc('é'); regmbc('ê'); - regmbc('ë'); + case 'e': case '\350': case '\351': case '\352': case '\353': + regmbc('e'); regmbc('\350'); regmbc('\351'); + regmbc('\352'); regmbc('\353'); return; - case 'i': case 'ì': case 'í': case 'î': case 'ï': - regmbc('i'); regmbc('ì'); regmbc('í'); regmbc('î'); - regmbc('ï'); + case 'i': case '\354': case '\355': case '\356': case '\357': + regmbc('i'); regmbc('\354'); regmbc('\355'); + regmbc('\356'); regmbc('\357'); return; - case 'n': case 'ñ': - regmbc('n'); regmbc('ñ'); + case 'n': case '\361': + regmbc('n'); regmbc('\361'); return; - case 'o': case 'ò': case 'ó': case 'ô': case 'õ': case 'ö': - regmbc('o'); regmbc('ò'); regmbc('ó'); regmbc('ô'); - regmbc('õ'); regmbc('ö'); + case 'o': case '\362': case '\363': case '\364': case '\365': + case '\366': + regmbc('o'); regmbc('\362'); regmbc('\363'); + regmbc('\364'); regmbc('\365'); regmbc('\366'); return; - case 'u': case 'ù': case 'ú': case 'û': case 'ü': - regmbc('u'); regmbc('ù'); regmbc('ú'); regmbc('û'); - regmbc('ü'); + case 'u': case '\371': case '\372': case '\373': case '\374': + regmbc('u'); regmbc('\371'); regmbc('\372'); + regmbc('\373'); regmbc('\374'); return; - case 'y': case 'ý': case 'ÿ': - regmbc('y'); regmbc('ý'); regmbc('ÿ'); + case 'y': case '\375': case '\377': + regmbc('y'); regmbc('\375'); regmbc('\377'); return; } } diff --git a/src/screen.c b/src/screen.c index 70c7ff1894..b2e1181275 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3605,7 +3605,7 @@ win_line(wp, lnum, startrow, endrow) iswordc = spell_iswordc(prev_ptr); if (iswordc && !prev_iswordc) { - word_end = v + spell_check(wp, prev_ptr, + word_end = v + spell_check(wp, line, prev_ptr, &spell_attr); /* In Insert mode only highlight a word that * doesn't touch the cursor. */ @@ -8002,7 +8002,7 @@ showmode() if (gui.in_use) { if (hangul_input_state_get()) - MSG_PUTS_ATTR(" ÇѱÛ", attr); /* HANGUL */ + MSG_PUTS_ATTR(" \307\321\261\333", attr); /* HANGUL */ } #endif #ifdef FEAT_INS_EXPAND diff --git a/src/spell.c b/src/spell.c index 30a02ab41f..e3a97fc833 100644 --- a/src/spell.c +++ b/src/spell.c @@ -16,6 +16,11 @@ * "word" is either a "dword" or an "nword". */ +/* + * Why doesn't Vim use aspell/ispell/myspell/etc.? + * See ":help develop-spell". + */ + #if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) # include <io.h> /* for lseek(), must be before vim.h */ #endif @@ -32,8 +37,3860 @@ /* * Structure that is used to store the text from the language file. This - * avoids the need to allocate each individual word and copying it. It's - * allocated in big chunks for speed. + * avoids the need to allocate space for each individual word. It's allocated + * in big chunks for speed. + */ +#define SBLOCKSIZE 4096 /* default size of sb_data */ +typedef struct sblock_S sblock_T; +struct sblock_S +{ + sblock_T *sb_next; /* next block in list */ + char_u sb_data[1]; /* data, actually longer */ +}; + +/* Info from "REP" entries in ".aff" file used in af_rep. */ +typedef struct repentry_S +{ + char_u *re_from; + char_u *re_to; +} repentry_T; + +/* + * Structure to store affix info. + */ +typedef struct affitem_S affitem_T; +struct affitem_S +{ + affitem_T *ai_next; /* next affix with same ai_add[] or NULL */ + short_u ai_nr; /* affix number */ + char_u ai_combine; /* prefix combines with suffix */ + char_u ai_choplen; /* length of ai_chop in bytes */ + char_u ai_addlen; /* length of ai_add in bytes */ + char_u *ai_chop; /* text chopped off basic word (can be NULL) */ + char_u ai_add[1]; /* text added to basic word (actually longer) */ +}; + +/* Get affitem_T pointer from hashitem that uses ai_add */ +static affitem_T dumai; +#define HI2AI(hi) ((affitem_T *)((hi)->hi_key - (dumai.ai_add - (char_u *)&dumai))) + +/* + * Structure used to store words and other info for one language. + */ +typedef struct slang_S slang_T; +struct slang_S +{ + slang_T *sl_next; /* next language */ + char_u *sl_name; /* language name "en", "en.rare", "nl", etc. */ + hashtab_T sl_words; /* main word table, fword_T */ + int sl_prefcnt; /* number of prefix NRs */ + garray_T sl_preftab; /* list of hashtables to lookup prefixes */ + affitem_T *sl_prefzero; /* list of prefixes with zero add length */ + int sl_suffcnt; /* number of suffix NRs */ + garray_T sl_sufftab; /* list of hashtables to lookup suffixes */ + affitem_T *sl_suffzero; /* list of suffixes with zero add length */ + char_u *sl_try; /* "TRY" from .aff file */ + garray_T sl_rep; /* list of repentry_T entries from REP lines */ + char_u sl_regions[17]; /* table with up to 8 region names plus NUL */ + sblock_T *sl_block; /* list with allocated memory blocks */ + int sl_error; /* error while loading */ +}; + +static slang_T *first_lang = NULL; + +/* + * Structure to store an addition to a basic word. + */ +typedef struct addword_S addword_T; +struct addword_S +{ + addword_T *aw_next; /* next addition */ + char_u aw_flags; /* ADD_ flags */ + char_u aw_leadlen; /* length of lead in bytes */ + char_u aw_wordlen; /* length of aw_word in bytes */ + char_u aw_region; /* region for word with this addition */ + char_u aw_word[1]; /* text, actually longer: case-folded addition + plus, with ADD_KEEPCAP: keep-case addition */ +}; + +/* + * Structure to store a basic word. + */ +typedef struct fword_S fword_T; +struct fword_S +{ + fword_T *fw_next; /* same basic word with different caps */ + char_u fw_region; /* region bits */ + char_u fw_prefixcnt; /* number of prefix numbers */ + char_u fw_suffixcnt; /* number of suffix numbers */ + short_u fw_flags; /* BWF_ flags */ + void *fw_prefix; /* table with prefix numbers */ + void *fw_suffix; /* table with suffix numbers */ + addword_T *fw_adds; /* first addword_T entry */ + char_u fw_word[1]; /* actually longer: case folded word, or + keep-case word when (flags & BWF_KEEPCAP) */ +}; + +/* Get fword_T pointer from hashitem that uses fw_word */ +static fword_T dumfw; +#define HI2FWORD(hi) ((fword_T *)((hi)->hi_key - (dumfw.fw_word - (char_u *)&dumfw))) + +#define REGION_ALL 0xff + + +/* + * Structure used in "b_langp", filled from 'spelllang'. + */ +typedef struct langp_S +{ + slang_T *lp_slang; /* info for this language (NULL for last one) */ + int lp_region; /* bitmask for region or REGION_ALL */ +} langp_T; + +#define LANGP_ENTRY(ga, i) (((langp_T *)(ga).ga_data) + (i)) + +#define SP_OK 0 +#define SP_BAD 1 +#define SP_RARE 2 +#define SP_LOCAL 3 + +/* flags used for basic words in the spell file */ +#define BWF_VALID 0x01 /* word is valid without additions */ +#define BWF_REGION 0x02 /* region byte follows */ +#define BWF_ONECAP 0x04 /* first letter must be capital */ +#define BWF_SUFFIX 0x08 /* has suffix NR list */ +#define BWF_SECOND 0x10 /* second flags byte follows */ + +#define BWF_ADDS 0x0100 /* there are additions */ +#define BWF_PREFIX 0x0200 /* has prefix NR list */ +#define BWF_ALLCAP 0x0400 /* all letters must be capital (not used + for single-letter words) */ +#define BWF_KEEPCAP 0x0800 /* Keep case as-is */ + +/* flags used for addition in the spell file */ +#define ADD_REGION 0x02 /* region byte follows */ +#define ADD_ONECAP 0x04 /* first letter must be capital */ +#define ADD_ALLCAP 0x40 /* all letters must be capital (not used + for single-letter words) */ +#define ADD_KEEPCAP 0x80 /* fixed case */ + +/* Translate ADD_ flags to BWF_ flags. + * (Needed to keep ADD_ flags in one byte.) */ +#define ADD2BWF(x) (((x) & 0x0f) | (((x) & 0xf0) << 4)) + +#define VIMSPELLMAGIC "VIMspell01" /* string at start of Vim spell file */ +#define VIMSPELLMAGICL 10 + +/* + * Structure to store info for word matching. + */ +typedef struct matchinf_S +{ + langp_T *mi_lp; /* info for language and region */ + slang_T *mi_slang; /* info for the language */ + char_u *mi_line; /* start of line containing word */ + char_u *mi_word; /* start of word being checked */ + char_u *mi_end; /* first non-word char after mi_word */ + char_u *mi_wend; /* end of matching word (is "mi_end" + * or further) */ + char_u *mi_cword; /* word to check, can be "mi_fword" */ + char_u mi_fword[MAXWLEN + 1]; /* "mi_word" to "mi_end" case-folded */ + int mi_faddlen; /* length of valid bytes in "mi_fadd" */ + char_u *mi_faddp; /* next char to be added to "mi_fadd" */ + char_u mi_fadd[MAXWLEN + 1]; /* "mi_end" and further case-folded */ + int mi_result; /* result so far: SP_BAD, SP_OK, etc. */ + int mi_capflags; /* BWF_ONECAP BWF_ALLCAP BWF_KEEPCAP */ +} matchinf_T; + +static int word_match __ARGS((matchinf_T *mip)); +static int check_adds __ARGS((matchinf_T *mip, fword_T *fw, int req_pref, int req_suf)); +static int supports_afffix __ARGS((int cnt, void *afffix, int afffixcnt, int nr)); +static int prefix_match __ARGS((matchinf_T *mip)); +static int suffix_match __ARGS((matchinf_T *mip)); +static int match_caps __ARGS((int flags, char_u *caseword, matchinf_T *mip, char_u *cword, char_u *end)); +static slang_T *slang_alloc __ARGS((char_u *lang)); +static void slang_free __ARGS((slang_T *lp)); +static slang_T *spell_load_lang __ARGS((char_u *lang)); +static void spell_load_file __ARGS((char_u *fname, void *cookie)); +static int spell_load_affixes __ARGS((FILE *fd, slang_T *lp, int *bl_usedp, int affm, void **affp)); +static void *getroom __ARGS((slang_T *lp, int *bl_used, int len)); +static int find_region __ARGS((char_u *rp, char_u *region)); +static int captype __ARGS((char_u *word, char_u *end)); + +/* + * Main spell-checking function. + * "ptr" points to the start of a word. + * "*attrp" is set to the attributes for a badly spelled word. For a non-word + * or when it's OK it remains unchanged. + * This must only be called when 'spelllang' is not empty. + * Returns the length of the word in bytes, also when it's OK, so that the + * caller can skip over the word. + */ + int +spell_check(wp, line, ptr, attrp) + win_T *wp; /* current window */ + char_u *line; /* start of line where "ptr" points into */ + char_u *ptr; + int *attrp; +{ + matchinf_T mi; /* Most things are put in "mi" so that it can + be passed to functions quickly. */ + + /* Find the end of the word. We already know that *ptr is a word char. */ + mi.mi_word = ptr; + mi.mi_end = ptr; + do + { + mb_ptr_adv(mi.mi_end); + } while (*mi.mi_end != NUL && spell_iswordc(mi.mi_end)); + + /* A word starting with a number is always OK. */ + if (*ptr >= '0' && *ptr <= '9') + return (int)(mi.mi_end - ptr); + + /* Make case-folded copy of the Word. Compute its hash value. */ + (void)str_foldcase(ptr, mi.mi_end - ptr, mi.mi_fword, MAXWLEN + 1); + mi.mi_cword = mi.mi_fword; + + /* The word is bad unless we find it in the dictionary. */ + mi.mi_result = SP_BAD; + mi.mi_wend = mi.mi_end; + mi.mi_faddp = mi.mi_end; + mi.mi_faddlen = 0; + mi.mi_capflags = captype(ptr, mi.mi_end); + mi.mi_line = line; + + /* + * Loop over the languages specified in 'spelllang'. + * We check them all, because a matching word may have additions that are + * longer than an already found matching word. + */ + for (mi.mi_lp = LANGP_ENTRY(wp->w_buffer->b_langp, 0); + mi.mi_lp->lp_slang != NULL; ++mi.mi_lp) + { + /* + * Check for a matching word. + * If not found or wrong region try removing prefixes (and then + * suffixes). + * If still not found or wrong region try removing suffixes. + */ + mi.mi_slang = mi.mi_lp->lp_slang; + if (!word_match(&mi) || mi.mi_result != SP_OK) + if (!prefix_match(&mi) || mi.mi_result != SP_OK) + suffix_match(&mi); + } + + if (mi.mi_result != SP_OK) + { + if (mi.mi_result == SP_BAD) + *attrp = highlight_attr[HLF_SPB]; + else if (mi.mi_result == SP_RARE) + *attrp = highlight_attr[HLF_SPR]; + else + *attrp = highlight_attr[HLF_SPL]; + } + + return (int)(mi.mi_wend - ptr); +} + +/* + * Check if the word "mip->mi_cword" matches. + */ + static int +word_match(mip) + matchinf_T *mip; +{ + hash_T fhash = hash_hash(mip->mi_cword); + hashitem_T *hi; + fword_T *fw; + int valid = FALSE; + + hi = hash_lookup(&mip->mi_slang->sl_words, mip->mi_cword, fhash); + if (HASHITEM_EMPTY(hi)) + return FALSE; + + /* + * Find a basic word for which the case of word "cword" is correct. + * If it is, check additions and use the longest one. + */ + for (fw = HI2FWORD(hi); fw != NULL; fw = fw->fw_next) + if (match_caps(fw->fw_flags, fw->fw_word, mip, + mip->mi_word, mip->mi_end)) + valid |= check_adds(mip, fw, -1, -1); + + return valid; +} + +/* + * Check a matching basic word for additions. + * Return TRUE if we have a valid match. + */ + static int +check_adds(mip, fw, req_pref, req_suf) + matchinf_T *mip; + fword_T *fw; + int req_pref; /* required prefix nr, -1 if none */ + int req_suf; /* required suffix nr, -1 if none */ +{ + int valid = FALSE; + addword_T *aw; + char_u *p; + int addlen; + int fl; + + /* A word may be valid without additions. */ + if ((fw->fw_flags & BWF_VALID) + && (req_pref < 0 || supports_afffix(mip->mi_slang->sl_prefcnt, + fw->fw_prefix, fw->fw_prefixcnt, req_pref)) + && |