diff options
author | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2021-06-12 15:07:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-12 15:07:11 -0400 |
commit | 12d8ff7ccdad4d5873347e8d318a47ac552941d7 (patch) | |
tree | f7167b901cd2fa667a4a835fe9153d5411b678ab /src | |
parent | d3bdde0bad12458128fae817aa348ac1d07b6f35 (diff) | |
parent | 6a4685fb0e62dbd7955f8698e3aa82f885026036 (diff) | |
download | rneovim-12d8ff7ccdad4d5873347e8d318a47ac552941d7.tar.gz rneovim-12d8ff7ccdad4d5873347e8d318a47ac552941d7.tar.bz2 rneovim-12d8ff7ccdad4d5873347e8d318a47ac552941d7.zip |
Merge pull request #14785 from janlazo/vim-8.1.1838
vim-patch:8.1.{1838,1865},8.2.{38,39,46,945,948,2896}
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval/funcs.c | 30 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 6 | ||||
-rw-r--r-- | src/nvim/globals.h | 1 | ||||
-rw-r--r-- | src/nvim/normal.c | 4 | ||||
-rw-r--r-- | src/nvim/spell.c | 17 | ||||
-rw-r--r-- | src/nvim/spell_defs.h | 7 | ||||
-rw-r--r-- | src/nvim/spellfile.c | 32 | ||||
-rw-r--r-- | src/nvim/testdir/test_normal.vim | 155 | ||||
-rw-r--r-- | src/nvim/testdir/test_spell.vim | 218 | ||||
-rw-r--r-- | src/nvim/testdir/test_spellfile.vim | 240 |
10 files changed, 531 insertions, 179 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ce09d268ea..4f9a9fcd68 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -9661,6 +9661,18 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *word = ""; hlf_T attr = HLF_COUNT; size_t len = 0; + const int wo_spell_save = curwin->w_p_spell; + + if (!curwin->w_p_spell) { + did_set_spelllang(curwin); + curwin->w_p_spell = true; + } + + if (*curwin->w_s->b_p_spl == NUL) { + EMSG(_(e_no_spell)); + curwin->w_p_spell = wo_spell_save; + return; + } if (argvars[0].v_type == VAR_UNKNOWN) { // Find the start and length of the badly spelled word. @@ -9669,7 +9681,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) word = (char *)get_cursor_pos_ptr(); curwin->w_set_curswant = true; } - } else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) { + } else if (*curbuf->b_s.b_p_spl != NUL) { const char *str = tv_get_string_chk(&argvars[0]); int capcol = -1; @@ -9687,6 +9699,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } } + curwin->w_p_spell = wo_spell_save; assert(len <= INT_MAX); tv_list_alloc_ret(rettv, 2); @@ -9708,8 +9721,20 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr) int maxcount; garray_T ga = GA_EMPTY_INIT_VALUE; bool need_capital = false; + const int wo_spell_save = curwin->w_p_spell; + + if (!curwin->w_p_spell) { + did_set_spelllang(curwin); + curwin->w_p_spell = true; + } + + if (*curwin->w_s->b_p_spl == NUL) { + EMSG(_(e_no_spell)); + curwin->w_p_spell = wo_spell_save; + return; + } - if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { + if (*curwin->w_s->b_p_spl != NUL) { const char *const str = tv_get_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { maxcount = tv_get_number_chk(&argvars[1], &typeerr); @@ -9736,6 +9761,7 @@ f_spellsuggest_return: tv_list_append_allocated_string(rettv->vval.v_list, p); } ga_clear(&ga); + curwin->w_p_spell = wo_spell_save; } static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index d99383303b..7b971f464f 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -2568,6 +2568,12 @@ module.cmds = { func='ex_spellrepall', }, { + command='spellrare', + flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), + addr_type='ADDR_OTHER', + func='ex_spell', + }, + { command='spellundo', flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), addr_type='ADDR_OTHER', diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 0ce2b586e3..7c7ce5e65f 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -878,6 +878,7 @@ EXTERN char_u e_invexpr2[] INIT(= N_("E15: Invalid expression: %s")); EXTERN char_u e_invrange[] INIT(= N_("E16: Invalid range")); EXTERN char_u e_invcmd[] INIT(= N_("E476: Invalid command")); EXTERN char_u e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); +EXTERN char_u e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); EXTERN char_u e_invchan[] INIT(= N_("E900: Invalid channel id")); EXTERN char_u e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full")); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index e8ab8da744..44cdc09c0b 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -4604,7 +4604,9 @@ dozet: if (ptr == NULL && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) return; assert(len <= INT_MAX); - spell_add_word(ptr, (int)len, nchar == 'w' || nchar == 'W', + spell_add_word(ptr, (int)len, + nchar == 'w' || nchar == 'W' + ? SPELL_ADD_BAD : SPELL_ADD_GOOD, (nchar == 'G' || nchar == 'W') ? 0 : (int)cap->count1, undo); } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 10cc410e81..771c2106db 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1343,7 +1343,7 @@ static bool no_spell_checking(win_T *wp) { if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL || GA_EMPTY(&wp->w_s->b_langp)) { - EMSG(_("E756: Spell checking is not enabled")); + EMSG(_(e_no_spell)); return true; } return false; @@ -2771,9 +2771,17 @@ void spell_suggest(int count) int selected = count; int badlen = 0; int msg_scroll_save = msg_scroll; + const int wo_spell_save = curwin->w_p_spell; - if (no_spell_checking(curwin)) + if (!curwin->w_p_spell) { + did_set_spelllang(curwin); + curwin->w_p_spell = true; + } + + if (*curwin->w_s->b_p_spl == NUL) { + EMSG(_(e_no_spell)); return; + } if (VIsual_active) { // Use the Visually selected text as the bad word. But reject @@ -2966,6 +2974,7 @@ void spell_suggest(int count) spell_find_cleanup(&sug); xfree(line); + curwin->w_p_spell = wo_spell_save; } // Check if the word at line "lnum" column "col" is required to start with a @@ -5761,7 +5770,9 @@ cleanup_suggestions ( xfree(stp[i].st_word); } gap->ga_len = keep; - return stp[keep - 1].st_score; + if (keep >= 1) { + return stp[keep - 1].st_score; + } } } return maxscore; diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index e2c9ab7ae8..f07f5673f9 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -284,4 +284,11 @@ extern int did_set_spelltab; extern char *e_format; +// Values for "what" argument of spell_add_word() +typedef enum { + SPELL_ADD_GOOD = 0, + SPELL_ADD_BAD = 1, + SPELL_ADD_RARE = 2, +} SpellAddType; + #endif // NVIM_SPELL_DEFS_H diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 145cfe4fc6..0597f392e7 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -5290,13 +5290,16 @@ static void spell_message(const spellinfo_T *spin, char_u *str) } // ":[count]spellgood {word}" -// ":[count]spellwrong {word}" +// ":[count]spellwrong {word}" // ":[count]spellundo {word}" +// ":[count]spellrare {word}" void ex_spell(exarg_T *eap) { - spell_add_word(eap->arg, (int)STRLEN(eap->arg), eap->cmdidx == CMD_spellwrong, - eap->forceit ? 0 : (int)eap->line2, - eap->cmdidx == CMD_spellundo); + spell_add_word(eap->arg, (int)STRLEN(eap->arg), + eap->cmdidx == CMD_spellwrong ? SPELL_ADD_BAD : + eap->cmdidx == CMD_spellrare ? SPELL_ADD_RARE : SPELL_ADD_GOOD, + eap->forceit ? 0 : (int)eap->line2, + eap->cmdidx == CMD_spellundo); } // Add "word[len]" to 'spellfile' as a good or bad word. @@ -5304,10 +5307,10 @@ void spell_add_word ( char_u *word, int len, - int bad, - int idx, // "zG" and "zW": zero, otherwise index in - // 'spellfile' - bool undo // true for "zug", "zuG", "zuw" and "zuW" + SpellAddType what, // SPELL_ADD_ values + int idx, // "zG" and "zW": zero, otherwise index in + // 'spellfile' + bool undo // true for "zug", "zuG", "zuw" and "zuW" ) { FILE *fd = NULL; @@ -5364,7 +5367,7 @@ spell_add_word ( fname = fnamebuf; } - if (bad || undo) { + if (what == SPELL_ADD_BAD || undo) { // When the word appears as good word we need to remove that one, // since its flags sort before the one with WF_BANNED. fd = os_fopen((char *)fname, "r"); @@ -5422,13 +5425,16 @@ spell_add_word ( } } - if (fd == NULL) + if (fd == NULL) { EMSG2(_(e_notopen), fname); - else { - if (bad) + } else { + if (what == SPELL_ADD_BAD) { fprintf(fd, "%.*s/!\n", len, word); - else + } else if (what == SPELL_ADD_RARE) { + fprintf(fd, "%.*s/?\n", len, word); + } else { fprintf(fd, "%.*s\n", len, word); + } fclose(fd); home_replace(NULL, fname, NameBuff, MAXPATHL, TRUE); diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 4a00999c45..5c413d1e16 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -1111,161 +1111,6 @@ func Test_normal18_z_fold() bw! endfunc -func Test_normal19_z_spell() - if !has("spell") || !has('syntax') - return - endif - new - call append(0, ['1 good', '2 goood', '3 goood']) - set spell spellfile=./Xspellfile.add spelllang=en - let oldlang=v:lang - lang C - - " Test for zg - 1 - norm! ]s - call assert_equal('2 goood', getline('.')) - norm! zg - 1 - let a=execute('unsilent :norm! ]s') - call assert_equal('1 good', getline('.')) - call assert_equal('search hit BOTTOM, continuing at TOP', a[1:]) - let cnt=readfile('./Xspellfile.add') - call assert_equal('goood', cnt[0]) - - " Test for zw - 2 - norm! $zw - 1 - norm! ]s - call assert_equal('2 goood', getline('.')) - let cnt=readfile('./Xspellfile.add') - call assert_equal('#oood', cnt[0]) - call assert_equal('goood/!', cnt[1]) - - " Test for zg in visual mode - let a=execute('unsilent :norm! V$zg') - call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:]) - 1 - norm! ]s - call assert_equal('3 goood', getline('.')) - let cnt=readfile('./Xspellfile.add') - call assert_equal('2 goood', cnt[2]) - " Remove "2 good" from spellfile - 2 - let a=execute('unsilent norm! V$zw') - call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:]) - let cnt=readfile('./Xspellfile.add') - call assert_equal('2 goood/!', cnt[3]) - - " Test for zG - let a=execute('unsilent norm! V$zG') - call assert_match("Word '2 goood' added to .*", a) - let fname=matchstr(a, 'to\s\+\zs\f\+$') - let fname=Fix_truncated_tmpfile(fname) - let cnt=readfile(fname) - call assert_equal('2 goood', cnt[0]) - - " Test for zW - let a=execute('unsilent norm! V$zW') - call assert_match("Word '2 goood' added to .*", a) - let cnt=readfile(fname) - call assert_equal('# goood', cnt[0]) - call assert_equal('2 goood/!', cnt[1]) - - " Test for zuW - let a=execute('unsilent norm! V$zuW') - call assert_match("Word '2 goood' removed from .*", a) - let cnt=readfile(fname) - call assert_equal('# goood', cnt[0]) - call assert_equal('# goood/!', cnt[1]) - - " Test for zuG - let a=execute('unsilent norm! $zG') - call assert_match("Word 'goood' added to .*", a) - let cnt=readfile(fname) - call assert_equal('# goood', cnt[0]) - call assert_equal('# goood/!', cnt[1]) - call assert_equal('goood', cnt[2]) - let a=execute('unsilent norm! $zuG') - let cnt=readfile(fname) - call assert_match("Word 'goood' removed from .*", a) - call assert_equal('# goood', cnt[0]) - call assert_equal('# goood/!', cnt[1]) - call assert_equal('#oood', cnt[2]) - " word not found in wordlist - let a=execute('unsilent norm! V$zuG') - let cnt=readfile(fname) - call assert_match("", a) - call assert_equal('# goood', cnt[0]) - call assert_equal('# goood/!', cnt[1]) - call assert_equal('#oood', cnt[2]) - - " Test for zug - call delete('./Xspellfile.add') - 2 - let a=execute('unsilent norm! $zg') - let cnt=readfile('./Xspellfile.add') - call assert_equal('goood', cnt[0]) - let a=execute('unsilent norm! $zug') - call assert_match("Word 'goood' removed from \./Xspellfile.add", a) - let cnt=readfile('./Xspellfile.add') - call assert_equal('#oood', cnt[0]) - " word not in wordlist - let a=execute('unsilent norm! V$zug') - call assert_match('', a) - let cnt=readfile('./Xspellfile.add') - call assert_equal('#oood', cnt[0]) - - " Test for zuw - call delete('./Xspellfile.add') - 2 - let a=execute('unsilent norm! Vzw') - let cnt=readfile('./Xspellfile.add') - call assert_equal('2 goood/!', cnt[0]) - let a=execute('unsilent norm! Vzuw') - call assert_match("Word '2 goood' removed from \./Xspellfile.add", a) - let cnt=readfile('./Xspellfile.add') - call assert_equal('# goood/!', cnt[0]) - " word not in wordlist - let a=execute('unsilent norm! $zug') - call assert_match('', a) - let cnt=readfile('./Xspellfile.add') - call assert_equal('# goood/!', cnt[0]) - - " add second entry to spellfile setting - set spellfile=./Xspellfile.add,./Xspellfile2.add - call delete('./Xspellfile.add') - 2 - let a=execute('unsilent norm! $2zg') - let cnt=readfile('./Xspellfile2.add') - call assert_match("Word 'goood' added to ./Xspellfile2.add", a) - call assert_equal('goood', cnt[0]) - - " Test for :spellgood! - let temp = execute(':spe!0/0') - call assert_match('Invalid region', temp) - let spellfile = matchstr(temp, 'Invalid region nr in \zs.*\ze line \d: 0') - call assert_equal(['# goood', '# goood/!', '#oood', '0/0'], readfile(spellfile)) - call delete(spellfile) - - " clean up - exe "lang" oldlang - call delete("./Xspellfile.add") - call delete("./Xspellfile2.add") - call delete("./Xspellfile.add.spl") - call delete("./Xspellfile2.add.spl") - - " zux -> no-op - 2 - norm! $zux - call assert_equal([], glob('Xspellfile.add',0,1)) - call assert_equal([], glob('Xspellfile2.add',0,1)) - - set spellfile= - bw! -endfunc - func Test_normal20_exmode() if !has("unix") " Reading from redirected file doesn't work on MS-Windows diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index ab8a998bb8..e525d06ea2 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -106,11 +106,14 @@ foobar/? set spelllang=Xwords.spl call assert_equal(['foobar', 'rare'], spellbadword('foo foobar')) - " Typo should not be detected without the 'spell' option. + " Typo should be detected even without the 'spell' option. set spelllang=en_gb nospell call assert_equal(['', ''], spellbadword('centre')) - call assert_equal(['', ''], spellbadword('My bycycle.')) - call assert_equal(['', ''], spellbadword('A sentence. another sentence')) + call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.')) + call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence')) + + set spelllang= + call assert_fails("call spellbadword('maxch')", 'E756:') call delete('Xwords.spl') call delete('Xwords') @@ -172,6 +175,183 @@ func Test_spellreall() bwipe! endfunc +" Test spellsuggest({word} [, {max} [, {capital}]]) +func Test_spellsuggest() + " Verify suggestions are given even when spell checking is not enabled. + set nospell + call assert_equal(['march', 'March'], spellsuggest('marrch', 2)) + + set spell + + " With 1 argument. + call assert_equal(['march', 'March'], spellsuggest('marrch')[0:1]) + + " With 2 arguments. + call assert_equal(['march', 'March'], spellsuggest('marrch', 2)) + + " With 3 arguments. + call assert_equal(['march'], spellsuggest('marrch', 1, 0)) + call assert_equal(['March'], spellsuggest('marrch', 1, 1)) + + " Test with digits and hyphen. + call assert_equal('Carbon-14', spellsuggest('Carbon-15')[0]) + + " Comment taken from spellsuggest.c explains the following test cases: + " + " If there are more UPPER than lower case letters suggest an + " ALLCAP word. Otherwise, if the first letter is UPPER then + " suggest ONECAP. Exception: "ALl" most likely should be "All", + " require three upper case letters. + call assert_equal(['THIRD', 'third'], spellsuggest('thIRD', 2)) + call assert_equal(['third', 'THIRD'], spellsuggest('tHIrd', 2)) + call assert_equal(['Third'], spellsuggest('THird', 1)) + call assert_equal(['All'], spellsuggest('ALl', 1)) + + call assert_fails("call spellsuggest('maxch', [])", 'E745:') + call assert_fails("call spellsuggest('maxch', 2, [])", 'E745:') + + set spelllang= + call assert_fails("call spellsuggest('maxch')", 'E756:') + set spelllang& + + set spell& +endfunc + +" Test 'spellsuggest' option with methods fast, best and double. +func Test_spellsuggest_option_methods() + set spell + + for e in ['utf-8'] + exe 'set encoding=' .. e + + set spellsuggest=fast + call assert_equal(['Stick', 'Stitch'], spellsuggest('Stich', 2), e) + + " With best or double option, "Stitch" should become the top suggestion + " because of better phonetic matching. + set spellsuggest=best + call assert_equal(['Stitch', 'Stick'], spellsuggest('Stich', 2), e) + + set spellsuggest=double + call assert_equal(['Stitch', 'Stick'], spellsuggest('Stich', 2), e) + endfor + + set spell& spellsuggest& encoding& +endfunc + +" Test 'spellsuggest' option with value file:{filename} +func Test_spellsuggest_option_file() + set spell spellsuggest=file:Xspellsuggest + call writefile(['emacs/vim', + \ 'theribal/terrible', + \ 'teribal/terrrible', + \ 'terribal'], + \ 'Xspellsuggest') + + call assert_equal(['vim'], spellsuggest('emacs', 2)) + call assert_equal(['terrible'], spellsuggest('theribal',2)) + + " If the suggestion is misspelled (*terrrible* with 3 r), + " it should not be proposed. + " The entry for "terribal" should be ignored because of missing slash. + call assert_equal([], spellsuggest('teribal', 2)) + call assert_equal([], spellsuggest('terribal', 2)) + + set spell spellsuggest=best,file:Xspellsuggest + call assert_equal(['vim', 'Emacs'], spellsuggest('emacs', 2)) + call assert_equal(['terrible', 'tribal'], spellsuggest('theribal', 2)) + call assert_equal(['tribal'], spellsuggest('teribal', 1)) + call assert_equal(['tribal'], spellsuggest('terribal', 1)) + + call delete('Xspellsuggest') + call assert_fails("call spellsuggest('vim')", "E484: Can't open file Xspellsuggest") + + set spellsuggest& spell& +endfunc + +" Test 'spellsuggest' option with value {number} +" to limit the number of suggestions +func Test_spellsuggest_option_number() + set spell spellsuggest=2,best + new + + " We limited the number of suggestions to 2, so selecting + " the 1st and 2nd suggestion should correct the word, but + " selecting a 3rd suggestion should do nothing. + call setline(1, 'A baord') + norm $1z= + call assert_equal('A board', getline(1)) + + call setline(1, 'A baord') + norm $2z= + call assert_equal('A bard', getline(1)) + + call setline(1, 'A baord') + norm $3z= + call assert_equal('A baord', getline(1)) + + let a = execute('norm $z=') + call assert_equal( + \ "\n" + \ .. "Change \"baord\" to:\n" + \ .. " 1 \"board\"\n" + \ .. " 2 \"bard\"\n" + \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a) + + set spell spellsuggest=0 + call assert_equal("\nSorry, no suggestions", execute('norm $z=')) + + " Unlike z=, function spellsuggest(...) should not be affected by the + " max number of suggestions (2) set by the 'spellsuggest' option. + call assert_equal(['board', 'bard', 'broad'], spellsuggest('baord', 3)) + + set spellsuggest& spell& + bwipe! +endfunc + +" Test 'spellsuggest' option with value expr:{expr} +func Test_spellsuggest_option_expr() + " A silly 'spellsuggest' function which makes suggestions all uppercase + " and makes the score of each suggestion the length of the suggested word. + " So shorter suggestions are preferred. + func MySuggest() + let spellsuggest_save = &spellsuggest + set spellsuggest=3,best + let result = map(spellsuggest(v:val, 3), "[toupper(v:val), len(v:val)]") + let &spellsuggest = spellsuggest_save + return result + endfunc + + set spell spellsuggest=expr:MySuggest() + call assert_equal(['BARD', 'BOARD', 'BROAD'], spellsuggest('baord', 3)) + + new + call setline(1, 'baord') + let a = execute('norm z=') + call assert_equal( + \ "\n" + \ .. "Change \"baord\" to:\n" + \ .. " 1 \"BARD\"\n" + \ .. " 2 \"BOARD\"\n" + \ .. " 3 \"BROAD\"\n" + \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a) + + " With verbose, z= should show the score i.e. word length with + " our SpellSuggest() function. + set verbose=1 + let a = execute('norm z=') + call assert_equal( + \ "\n" + \ .. "Change \"baord\" to:\n" + \ .. " 1 \"BARD\" (4 - 0)\n" + \ .. " 2 \"BOARD\" (5 - 0)\n" + \ .. " 3 \"BROAD\" (5 - 0)\n" + \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a) + + set spell& spellsuggest& verbose& + bwipe! +endfunc + func Test_spellinfo() throw 'skipped: Nvim does not support enc=latin1' new @@ -227,7 +407,7 @@ func Test_zz_basic() \ ) call assert_equal("gebletegek", soundfold('goobledygoook')) - call assert_equal("kepereneven", soundfold('kóopërÿnôven')) + call assert_equal("kepereneven", soundfold('kóopërÿnôven')) call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale')) endfunc @@ -408,7 +588,7 @@ func Test_zz_sal_and_addition() mkspell! Xtest Xtest set spl=Xtest.latin1.spl spell call assert_equal('kbltykk', soundfold('goobledygoook')) - call assert_equal('kprnfn', soundfold('kóopërÿnôven')) + call assert_equal('kprnfn', soundfold('kóopërÿnôven')) call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale')) "also use an addition file @@ -461,6 +641,34 @@ func Test_zeq_crash() bwipe! endfunc +" Check that z= works even when 'nospell' is set. This test uses one of the +" tests in Test_spellsuggest_option_number() just to verify that z= basically +" works and that "E756: Spell checking is not enabled" is not generated. +func Test_zeq_nospell() + new + set nospell spellsuggest=1,best + call setline(1, 'A baord') + try + norm $1z= + call assert_equal('A board', getline(1)) + catch + call assert_report("Caught exception: " . v:exception) + endtry + set spell& spellsuggest& + bwipe! +endfunc + +" Check that "E756: Spell checking is not possible" is reported when z= is +" executed and 'spelllang' is empty. +func Test_zeq_no_spelllang() + new + set spelllang= spellsuggest=1,best + call setline(1, 'A baord') + call assert_fails('normal $1z=', 'E756:') + set spelllang& spellsuggest& + bwipe! +endfunc + " Check handling a word longer than MAXWLEN. func Test_spell_long_word() set enc=utf-8 diff --git a/src/nvim/testdir/test_spellfile.vim b/src/nvim/testdir/test_spellfile.vim new file mode 100644 index 0000000000..729467b556 --- /dev/null +++ b/src/nvim/testdir/test_spellfile.vim @@ -0,0 +1,240 @@ +" Test for commands that operate on the spellfile. + +source shared.vim +source check.vim + +CheckFeature spell +CheckFeature syntax + +func Test_spell_normal() + new + call append(0, ['1 good', '2 goood', '3 goood']) + set spell spellfile=./Xspellfile.add spelllang=en + let oldlang=v:lang + lang C + + " Test for zg + 1 + norm! ]s + call assert_equal('2 goood', getline('.')) + norm! zg + 1 + let a=execute('unsilent :norm! ]s') + call assert_equal('1 good', getline('.')) + call assert_equal('search hit BOTTOM, continuing at TOP', a[1:]) + let cnt=readfile('./Xspellfile.add') + call assert_equal('goood', cnt[0]) + + " Test for zw + 2 + norm! $zw + 1 + norm! ]s + call assert_equal('2 goood', getline('.')) + let cnt=readfile('./Xspellfile.add') + call assert_equal('#oood', cnt[0]) + call assert_equal('goood/!', cnt[1]) + + " Test for :spellrare + spellrare rare + let cnt=readfile('./Xspellfile.add') + call assert_equal(['#oood', 'goood/!', 'rare/?'], cnt) + + " Make sure :spellundo works for rare words. + spellundo rare + let cnt=readfile('./Xspellfile.add') + call assert_equal(['#oood', 'goood/!', '#are/?'], cnt) + + " Test for zg in visual mode + let a=execute('unsilent :norm! V$zg') + call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:]) + 1 + norm! ]s + call assert_equal('3 goood', getline('.')) + let cnt=readfile('./Xspellfile.add') + call assert_equal('2 goood', cnt[3]) + " Remove "2 good" from spellfile + 2 + let a=execute('unsilent norm! V$zw') + call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:]) + let cnt=readfile('./Xspellfile.add') + call assert_equal('2 goood/!', cnt[4]) + + " Test for zG + let a=execute('unsilent norm! V$zG') + call assert_match("Word '2 goood' added to .*", a) + let fname=matchstr(a, 'to\s\+\zs\f\+$') + let cnt=readfile(fname) + call assert_equal('2 goood', cnt[0]) + + " Test for zW + let a=execute('unsilent norm! V$zW') + call assert_match("Word '2 goood' added to .*", a) + let cnt=readfile(fname) + call assert_equal('# goood', cnt[0]) + call assert_equal('2 goood/!', cnt[1]) + + " Test for zuW + let a=execute('unsilent norm! V$zuW') + call assert_match("Word '2 goood' removed from .*", a) + let cnt=readfile(fname) + call assert_equal('# goood', cnt[0]) + call assert_equal('# goood/!', cnt[1]) + + " Test for zuG + let a=execute('unsilent norm! $zG') + call assert_match("Word 'goood' added to .*", a) + let cnt=readfile(fname) + call assert_equal('# goood', cnt[0]) + call assert_equal('# goood/!', cnt[1]) + call assert_equal('goood', cnt[2]) + let a=execute('unsilent norm! $zuG') + let cnt=readfile(fname) + call assert_match("Word 'goood' removed from .*", a) + call assert_equal('# goood', cnt[0]) + call assert_equal('# goood/!', cnt[1]) + call assert_equal('#oood', cnt[2]) + " word not found in wordlist + let a=execute('unsilent norm! V$zuG') + let cnt=readfile(fname) + call assert_match("", a) + call assert_equal('# goood', cnt[0]) + call assert_equal('# goood/!', cnt[1]) + call assert_equal('#oood', cnt[2]) + + " Test for zug + call delete('./Xspellfile.add') + 2 + let a=execute('unsilent norm! $zg') + let cnt=readfile('./Xspellfile.add') + call assert_equal('goood', cnt[0]) + let a=execute('unsilent norm! $zug') + call assert_match("Word 'goood' removed from \./Xspellfile.add", a) + let cnt=readfile('./Xspellfile.add') + call assert_equal('#oood', cnt[0]) + " word not in wordlist + let a=execute('unsilent norm! V$zug') + call assert_match('', a) + let cnt=readfile('./Xspellfile.add') + call assert_equal('#oood', cnt[0]) + + " Test for zuw + call delete('./Xspellfile.add') + 2 + let a=execute('unsilent norm! Vzw') + let cnt=readfile('./Xspellfile.add') + call assert_equal('2 goood/!', cnt[0]) + let a=execute('unsilent norm! Vzuw') + call assert_match("Word '2 goood' removed from \./Xspellfile.add", a) + let cnt=readfile('./Xspellfile.add') + call assert_equal('# goood/!', cnt[0]) + " word not in wordlist + let a=execute('unsilent norm! $zug') + call assert_match('', a) + let cnt=readfile('./Xspellfile.add') + call assert_equal('# goood/!', cnt[0]) + + " add second entry to spellfile setting + set spellfile=./Xspellfile.add,./Xspellfile2.add + call delete('./Xspellfile.add') + 2 + let a=execute('unsilent norm! $2zg') + let cnt=readfile('./Xspellfile2.add') + call assert_match("Word 'goood' added to ./Xspellfile2.add", a) + call assert_equal('goood', cnt[0]) + + " Test for :spellgood! + let temp = execute(':spe!0/0') + call assert_match('Invalid region', temp) + let spellfile = matchstr(temp, 'Invalid region nr in \zs.*\ze line \d: 0') + call assert_equal(['# goood', '# goood/!', '#oood', '0/0'], readfile(spellfile)) + + " Test for :spellrare! + :spellrare! raare + call assert_equal(['# goood', '# goood/!', '#oood', '0/0', 'raare/?'], readfile(spellfile)) + call delete(spellfile) + + " clean up + exe "lang" oldlang + call delete("./Xspellfile.add") + call delete("./Xspellfile2.add") + call delete("./Xspellfile.add.spl") + call delete("./Xspellfile2.add.spl") + + " zux -> no-op + 2 + norm! $zux + call assert_equal([], glob('Xspellfile.add',0,1)) + call assert_equal([], glob('Xspellfile2.add',0,1)) + + set spellfile= + bw! +endfunc + +" Test CHECKCOMPOUNDPATTERN (see :help spell-CHECKCOMPOUNDPATTERN) +func Test_spellfile_CHECKCOMPOUNDPATTERN() + call writefile(['4', + \ 'one/c', + \ 'two/c', + \ 'three/c', + \ 'four'], 'XtestCHECKCOMPOUNDPATTERN.dic') + " Forbid compound words where first word ends with 'wo' and second starts with 'on'. + call writefile(['CHECKCOMPOUNDPATTERN 1', + \ 'CHECKCOMPOUNDPATTERN wo on', + \ 'COMPOUNDFLAG c'], 'XtestCHECKCOMPOUNDPATTERN.aff') + + let output = execute('mkspell! XtestCHECKCOMPOUNDPATTERN-utf8.spl XtestCHECKCOMPOUNDPATTERN') + set spell spelllang=XtestCHECKCOMPOUNDPATTERN-utf8.spl + + " Check valid words with and without valid compounds. + for goodword in ['one', 'two', 'three', 'four', + \ 'oneone', 'onetwo', 'onethree', + \ 'twotwo', 'twothree', + \ 'threeone', 'threetwo', 'threethree', + \ 'onetwothree', 'onethreetwo', 'twothreeone', 'oneoneone'] + call assert_equal(['', ''], spellbadword(goodword), goodword) + endfor + + " Compounds 'twoone' or 'threetwoone' should be forbidden by CHECKCOMPOUNPATTERN. + " 'four' does not have the 'c' flag in *.aff file so no compound. + " 'five' is not in the *.dic file. + for badword in ['five', 'onetwox', + \ 'twoone', 'threetwoone', + \ 'fourone', 'onefour'] + call assert_equal([badword, 'bad'], spellbadword(badword)) + endfor + + set spell& spelllang& + call delete('XtestCHECKCOMPOUNDPATTERN.dic') + call delete('XtestCHECKCOMPOUNDPATTERN.aff') + call delete('XtestCHECKCOMPOUNDPATTERN-utf8.spl') +endfunc + +" Test COMMON (better suggestions with common words, see :help spell-COMMON) +func Test_spellfile_COMMON() + call writefile(['7', + \ 'and', + \ 'ant', + \ 'end', + \ 'any', + \ 'tee', + \ 'the', + \ 'ted'], 'XtestCOMMON.dic') + call writefile(['COMMON the and'], 'XtestCOMMON.aff') + + let output = execute('mkspell! XtestCOMMON-utf8.spl XtestCOMMON') + set spell spelllang=XtestCOMMON-utf8.spl + + " COMMON words 'and' and 'the' should be the top suggestions. + call assert_equal(['and', 'ant'], spellsuggest('anr', 2)) + call assert_equal(['and', 'end'], spellsuggest('ond', 2)) + call assert_equal(['the', 'ted'], spellsuggest('tha', 2)) + call assert_equal(['the', 'tee'], spellsuggest('dhe', 2)) + + set spell& spelllang& + call delete('XtestCOMMON.dic') + call delete('XtestCOMMON.aff') + call delete('XtestCOMMON-utf8.spl') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab |