Merge pull request #14785 from janlazo/vim-8.1.1838

vim-patch:8.1.{1838,1865},8.2.{38,39,46,945,948,2896}
This commit is contained in:
Jan Edmund Lazo 2021-06-12 15:07:11 -04:00 committed by GitHub
commit 12d8ff7ccd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 555 additions and 187 deletions

View File

@ -8230,9 +8230,8 @@ spellbadword([{sentence}])
echo spellbadword("the quik brown fox") echo spellbadword("the quik brown fox")
< ['quik', 'bad'] ~ < ['quik', 'bad'] ~
The spelling information for the current window is used. The The spelling information for the current window and the value
'spell' option must be set and the value of 'spelllang' is of 'spelllang' are used.
used.
*spellsuggest()* *spellsuggest()*
spellsuggest({word} [, {max} [, {capital}]]) spellsuggest({word} [, {max} [, {capital}]])
@ -8254,8 +8253,7 @@ spellsuggest({word} [, {max} [, {capital}]])
although it may appear capitalized. although it may appear capitalized.
The spelling information for the current window is used. The The spelling information for the current window is used. The
'spell' option must be set and the values of 'spelllang' and values of 'spelllang' and 'spellsuggest' are used.
'spellsuggest' are used.
split({expr} [, {pattern} [, {keepempty}]]) *split()* split({expr} [, {pattern} [, {keepempty}]]) *split()*

View File

@ -110,6 +110,23 @@ zuG Undo |zW| and |zG|, remove the word from the internal
:spellw[rong]! {word} Add {word} as a wrong (bad) word to the internal word :spellw[rong]! {word} Add {word} as a wrong (bad) word to the internal word
list, like with |zW|. list, like with |zW|.
*:spellra* *:spellrare*
:[count]spellr[are] {word}
Add {word} as a rare word to 'spellfile', similar to
|zw|. Without count the first name is used, with
a count of two the second entry, etc.
There are no normal mode commands to mark words as
rare as this is a fairly uncommon command and all
intuitive commands for this are already taken. If you
want you can add mappings with e.g.: >
nnoremap z? :exe ':spellrare ' . expand('<cWORD>')<CR>
nnoremap z/ :exe ':spellrare! ' . expand('<cWORD>')<CR>
< |:spellundo|, |zuw|, or |zuW| can be used to undo this.
:spellr[rare]! {word} Add {word} as a rare word to the internal word
list, similar to |zW|.
:[count]spellu[ndo] {word} *:spellu* *:spellundo* :[count]spellu[ndo] {word} *:spellu* *:spellundo*
Like |zuw|. [count] used as with |:spellgood|. Like |zuw|. [count] used as with |:spellgood|.

Binary file not shown.

View File

@ -9661,6 +9661,18 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *word = ""; const char *word = "";
hlf_T attr = HLF_COUNT; hlf_T attr = HLF_COUNT;
size_t len = 0; 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) { if (argvars[0].v_type == VAR_UNKNOWN) {
// Find the start and length of the badly spelled word. // 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(); word = (char *)get_cursor_pos_ptr();
curwin->w_set_curswant = true; 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]); const char *str = tv_get_string_chk(&argvars[0]);
int capcol = -1; 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); assert(len <= INT_MAX);
tv_list_alloc_ret(rettv, 2); tv_list_alloc_ret(rettv, 2);
@ -9708,8 +9721,20 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int maxcount; int maxcount;
garray_T ga = GA_EMPTY_INIT_VALUE; garray_T ga = GA_EMPTY_INIT_VALUE;
bool need_capital = false; bool need_capital = false;
const int wo_spell_save = curwin->w_p_spell;
if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { 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_s->b_p_spl != NUL) {
const char *const str = tv_get_string(&argvars[0]); const char *const str = tv_get_string(&argvars[0]);
if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[1].v_type != VAR_UNKNOWN) {
maxcount = tv_get_number_chk(&argvars[1], &typeerr); 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); tv_list_append_allocated_string(rettv->vval.v_list, p);
} }
ga_clear(&ga); ga_clear(&ga);
curwin->w_p_spell = wo_spell_save;
} }
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)

View File

@ -2567,6 +2567,12 @@ module.cmds = {
addr_type='ADDR_NONE', addr_type='ADDR_NONE',
func='ex_spellrepall', func='ex_spellrepall',
}, },
{
command='spellrare',
flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR),
addr_type='ADDR_OTHER',
func='ex_spell',
},
{ {
command='spellundo', command='spellundo',
flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR),

View File

@ -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_invrange[] INIT(= N_("E16: Invalid range"));
EXTERN char_u e_invcmd[] INIT(= N_("E476: Invalid command")); 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_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_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_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job"));
EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full")); EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full"));

View File

@ -4604,7 +4604,9 @@ dozet:
if (ptr == NULL && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) if (ptr == NULL && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
return; return;
assert(len <= INT_MAX); 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, (nchar == 'G' || nchar == 'W') ? 0 : (int)cap->count1,
undo); undo);
} }

View File

@ -1343,7 +1343,7 @@ static bool no_spell_checking(win_T *wp)
{ {
if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL
|| GA_EMPTY(&wp->w_s->b_langp)) { || GA_EMPTY(&wp->w_s->b_langp)) {
EMSG(_("E756: Spell checking is not enabled")); EMSG(_(e_no_spell));
return true; return true;
} }
return false; return false;
@ -2771,9 +2771,17 @@ void spell_suggest(int count)
int selected = count; int selected = count;
int badlen = 0; int badlen = 0;
int msg_scroll_save = msg_scroll; 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; return;
}
if (VIsual_active) { if (VIsual_active) {
// Use the Visually selected text as the bad word. But reject // Use the Visually selected text as the bad word. But reject
@ -2966,6 +2974,7 @@ void spell_suggest(int count)
spell_find_cleanup(&sug); spell_find_cleanup(&sug);
xfree(line); xfree(line);
curwin->w_p_spell = wo_spell_save;
} }
// Check if the word at line "lnum" column "col" is required to start with a // 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); xfree(stp[i].st_word);
} }
gap->ga_len = keep; gap->ga_len = keep;
return stp[keep - 1].st_score; if (keep >= 1) {
return stp[keep - 1].st_score;
}
} }
} }
return maxscore; return maxscore;

View File

@ -284,4 +284,11 @@ extern int did_set_spelltab;
extern char *e_format; 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 #endif // NVIM_SPELL_DEFS_H

View File

@ -5290,13 +5290,16 @@ static void spell_message(const spellinfo_T *spin, char_u *str)
} }
// ":[count]spellgood {word}" // ":[count]spellgood {word}"
// ":[count]spellwrong {word}" // ":[count]spellwrong {word}"
// ":[count]spellundo {word}" // ":[count]spellundo {word}"
// ":[count]spellrare {word}"
void ex_spell(exarg_T *eap) void ex_spell(exarg_T *eap)
{ {
spell_add_word(eap->arg, (int)STRLEN(eap->arg), eap->cmdidx == CMD_spellwrong, spell_add_word(eap->arg, (int)STRLEN(eap->arg),
eap->forceit ? 0 : (int)eap->line2, eap->cmdidx == CMD_spellwrong ? SPELL_ADD_BAD :
eap->cmdidx == CMD_spellundo); 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. // Add "word[len]" to 'spellfile' as a good or bad word.
@ -5304,10 +5307,10 @@ void
spell_add_word ( spell_add_word (
char_u *word, char_u *word,
int len, int len,
int bad, SpellAddType what, // SPELL_ADD_ values
int idx, // "zG" and "zW": zero, otherwise index in int idx, // "zG" and "zW": zero, otherwise index in
// 'spellfile' // 'spellfile'
bool undo // true for "zug", "zuG", "zuw" and "zuW" bool undo // true for "zug", "zuG", "zuw" and "zuW"
) )
{ {
FILE *fd = NULL; FILE *fd = NULL;
@ -5364,7 +5367,7 @@ spell_add_word (
fname = fnamebuf; fname = fnamebuf;
} }
if (bad || undo) { if (what == SPELL_ADD_BAD || undo) {
// When the word appears as good word we need to remove that one, // When the word appears as good word we need to remove that one,
// since its flags sort before the one with WF_BANNED. // since its flags sort before the one with WF_BANNED.
fd = os_fopen((char *)fname, "r"); fd = os_fopen((char *)fname, "r");
@ -5422,13 +5425,16 @@ spell_add_word (
} }
} }
if (fd == NULL) if (fd == NULL) {
EMSG2(_(e_notopen), fname); EMSG2(_(e_notopen), fname);
else { } else {
if (bad) if (what == SPELL_ADD_BAD) {
fprintf(fd, "%.*s/!\n", len, word); 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); fprintf(fd, "%.*s\n", len, word);
}
fclose(fd); fclose(fd);
home_replace(NULL, fname, NameBuff, MAXPATHL, TRUE); home_replace(NULL, fname, NameBuff, MAXPATHL, TRUE);

View File

@ -1111,161 +1111,6 @@ func Test_normal18_z_fold()
bw! bw!
endfunc 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() func Test_normal20_exmode()
if !has("unix") if !has("unix")
" Reading from redirected file doesn't work on MS-Windows " Reading from redirected file doesn't work on MS-Windows

View File

@ -106,11 +106,14 @@ foobar/?
set spelllang=Xwords.spl set spelllang=Xwords.spl
call assert_equal(['foobar', 'rare'], spellbadword('foo foobar')) 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 set spelllang=en_gb nospell
call assert_equal(['', ''], spellbadword('centre')) call assert_equal(['', ''], spellbadword('centre'))
call assert_equal(['', ''], spellbadword('My bycycle.')) call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
call assert_equal(['', ''], spellbadword('A sentence. another sentence')) 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.spl')
call delete('Xwords') call delete('Xwords')
@ -172,6 +175,183 @@ func Test_spellreall()
bwipe! bwipe!
endfunc 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() func Test_spellinfo()
throw 'skipped: Nvim does not support enc=latin1' throw 'skipped: Nvim does not support enc=latin1'
new new
@ -227,7 +407,7 @@ func Test_zz_basic()
\ ) \ )
call assert_equal("gebletegek", soundfold('goobledygoook')) 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')) call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
endfunc endfunc
@ -408,7 +588,7 @@ func Test_zz_sal_and_addition()
mkspell! Xtest Xtest mkspell! Xtest Xtest
set spl=Xtest.latin1.spl spell set spl=Xtest.latin1.spl spell
call assert_equal('kbltykk', soundfold('goobledygoook')) 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')) call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale'))
"also use an addition file "also use an addition file
@ -461,6 +641,34 @@ func Test_zeq_crash()
bwipe! bwipe!
endfunc 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. " Check handling a word longer than MAXWLEN.
func Test_spell_long_word() func Test_spell_long_word()
set enc=utf-8 set enc=utf-8

View File

@ -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

View File

@ -811,7 +811,7 @@ describe('ui/ext_messages', function()
{1:~ }| {1:~ }|
{1:^~ }| {1:^~ }|
]], messages={ ]], messages={
{content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""} {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""}
}} }}
feed('1') feed('1')
@ -822,7 +822,7 @@ describe('ui/ext_messages', function()
{1:~ }| {1:~ }|
{1:^~ }| {1:^~ }|
]], messages={ ]], messages={
{content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""}, {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""},
{ content = { { "1" } }, kind = "" } { content = { { "1" } }, kind = "" }
}} }}

View File

@ -36,7 +36,7 @@ describe("'spell'", function()
feed('ggJJJJJJ0') feed('ggJJJJJJ0')
screen:expect([[ screen:expect([[
{1:^Lorem} {1:ipsum} dolor sit {1:amet}, {1:consectetur} {1:adipiscing} {1:elit}, {1:sed} do {1:eiusmod} {1:tempor} {1:i}| {1:^Lorem} {1:ipsum} dolor sit {1:amet}, {1:consectetur} {1:adipiscing} {1:elit}, {1:sed} do {1:eiusmod} {1:tempor} {1:i}|
{1:ncididunt} {1:ut} {1:labore} {1:et} {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}| {1:ncididunt} {1:ut} {1:labore} et {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}|
{1:d} {1:exercitation} {1:ullamco} {1:laboris} {1:nisi} {1:ut} {1:aliquip} ex ea {1:commodo} {1:consequat}. {1:Duis} {1:aut}| {1:d} {1:exercitation} {1:ullamco} {1:laboris} {1:nisi} {1:ut} {1:aliquip} ex ea {1:commodo} {1:consequat}. {1:Duis} {1:aut}|
{1:e} {1:irure} dolor in {1:reprehenderit} in {1:voluptate} {1:velit} {1:esse} {1:cillum} {1:dolore} {1:eu} {1:fugiat} {1:n}| {1:e} {1:irure} dolor in {1:reprehenderit} in {1:voluptate} {1:velit} {1:esse} {1:cillum} {1:dolore} {1:eu} {1:fugiat} {1:n}|
{1:ulla} {1:pariatur}. {1:Excepteur} {1:sint} {1:occaecat} {1:cupidatat} non {1:proident}, {1:sunt} in culpa {1:qui}| {1:ulla} {1:pariatur}. {1:Excepteur} {1:sint} {1:occaecat} {1:cupidatat} non {1:proident}, {1:sunt} in culpa {1:qui}|
@ -44,6 +44,7 @@ describe("'spell'", function()
{0:~ }| {0:~ }|
| |
]]) ]])
end) end)
it('has correct highlight at start of line', function() it('has correct highlight at start of line', function()