summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/spell.txt17
-rw-r--r--src/ex_cmdidxs.h18
-rw-r--r--src/ex_cmds.h3
-rw-r--r--src/normal.c3
-rw-r--r--src/proto/spellfile.pro2
-rw-r--r--src/spell.h4
-rw-r--r--src/spellfile.c23
-rw-r--r--src/testdir/Make_all.mak2
-rw-r--r--src/testdir/test_normal.vim154
-rw-r--r--src/testdir/test_spellfile.vim172
-rw-r--r--src/version.c2
11 files changed, 226 insertions, 174 deletions
diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt
index 4a28cdc0c..ff6feb60f 100644
--- a/runtime/doc/spell.txt
+++ b/runtime/doc/spell.txt
@@ -121,6 +121,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
list, like with |zW|.
+ *:spellr* *: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*
Like |zuw|. [count] used as with |:spellgood|.
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 1c301ba83..c43e1f2d0 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -24,13 +24,13 @@ static const unsigned short cmdidxs1[26] =
/* q */ 358,
/* r */ 361,
/* s */ 381,
- /* t */ 449,
- /* u */ 494,
- /* v */ 505,
- /* w */ 523,
- /* x */ 537,
- /* y */ 547,
- /* z */ 548
+ /* t */ 450,
+ /* u */ 495,
+ /* v */ 506,
+ /* w */ 524,
+ /* x */ 538,
+ /* y */ 548,
+ /* z */ 549
};
/*
@@ -59,7 +59,7 @@ static const unsigned char cmdidxs2[26][26] =
/* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 },
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
- /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 49, 0, 50, 0, 62, 63, 0, 64, 0 },
+ /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 63, 64, 0, 65, 0 },
/* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 0, 0 },
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
-static const int command_count = 561;
+static const int command_count = 562;
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 196cdcfef..c124a1ee6 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1378,6 +1378,9 @@ EXCMD(CMD_split, "split", ex_splitview,
EXCMD(CMD_spellgood, "spellgood", ex_spell,
EX_BANG|EX_RANGE|EX_NEEDARG|EX_EXTRA|EX_TRLBAR,
ADDR_OTHER),
+EXCMD(CMD_spellrare, "spellrare", ex_spell,
+ EX_BANG|EX_RANGE|EX_NEEDARG|EX_EXTRA|EX_TRLBAR,
+ ADDR_OTHER),
EXCMD(CMD_spelldump, "spelldump", ex_spelldump,
EX_BANG|EX_TRLBAR,
ADDR_NONE),
diff --git a/src/normal.c b/src/normal.c
index f717e8cd5..2067542d3 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -5127,7 +5127,8 @@ dozet:
if (ptr == NULL && (len = find_ident_under_cursor(&ptr,
FIND_IDENT)) == 0)
return;
- spell_add_word(ptr, len, nchar == 'w' || nchar == 'W',
+ spell_add_word(ptr, len, nchar == 'w' || nchar == 'W'
+ ? SPELL_ADD_BAD : SPELL_ADD_GOOD,
(nchar == 'G' || nchar == 'W')
? 0 : (int)cap->count1,
undo);
diff --git a/src/proto/spellfile.pro b/src/proto/spellfile.pro
index 70e993aae..552582afe 100644
--- a/src/proto/spellfile.pro
+++ b/src/proto/spellfile.pro
@@ -5,5 +5,5 @@ int spell_check_msm(void);
void ex_mkspell(exarg_T *eap);
void mkspell(int fcount, char_u **fnames, int ascii, int over_write, int added_word);
void ex_spell(exarg_T *eap);
-void spell_add_word(char_u *word, int len, int bad, int idx, int undo);
+void spell_add_word(char_u *word, int len, int what, int idx, int undo);
/* vim: set ft=c : */
diff --git a/src/spell.h b/src/spell.h
index 085f18c21..380e5ecc0 100644
--- a/src/spell.h
+++ b/src/spell.h
@@ -298,4 +298,8 @@ SPELL_EXTERN char e_format[] SPELL_INIT(= N_("E759: Format error in spell file")
SPELL_EXTERN spelltab_T spelltab;
SPELL_EXTERN int did_set_spelltab;
+// Values for "what" argument of spell_add_word()
+#define SPELL_ADD_GOOD 0
+#define SPELL_ADD_BAD 1
+#define SPELL_ADD_RARE 2
#endif
diff --git a/src/spellfile.c b/src/spellfile.c
index 778a4b27e..f34d9badb 100644
--- a/src/spellfile.c
+++ b/src/spellfile.c
@@ -6125,28 +6125,31 @@ spell_message(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,
+ 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.
+ * Add "word[len]" to 'spellfile' as a good, rare or bad word.
*/
void
spell_add_word(
char_u *word,
int len,
- int bad,
- int idx, /* "zG" and "zW": zero, otherwise index in
- 'spellfile' */
- int undo) /* TRUE for "zug", "zuG", "zuw" and "zuW" */
+ int what, // SPELL_ADD_ values
+ int idx, // "zG" and "zW": zero, otherwise index in
+ // 'spellfile'
+ int undo) // TRUE for "zug", "zuG", "zuw" and "zuW"
{
FILE *fd = NULL;
buf_T *buf = NULL;
@@ -6213,7 +6216,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. */
@@ -6280,8 +6283,10 @@ spell_add_word(
semsg(_(e_notopen), fname);
else
{
- if (bad)
+ if (what == SPELL_ADD_BAD)
fprintf(fd, "%.*s/!\n", len, word);
+ else if (what == SPELL_ADD_RARE)
+ fprintf(fd, "%.*s/?\n", len, word);
else
fprintf(fd, "%.*s\n", len, word);
fclose(fd);
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index b3abcbae0..131ba01f0 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -236,6 +236,7 @@ NEW_TESTS = \
test_source \
test_source_utf8 \
test_spell \
+ test_spellfile \
test_startup \
test_startup_utf8 \
test_stat \
@@ -411,6 +412,7 @@ NEW_TESTS_RES = \
test_sound.res \
test_source.res \
test_spell.res \
+ test_spellfile.res \
test_startup.res \
test_stat.res \
test_substitute.res \
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index f48eaa0f3..2df0fe590 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -1089,160 +1089,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 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/testdir/test_spellfile.vim b/src/testdir/test_spellfile.vim
new file mode 100644
index 000000000..53eca84e4
--- /dev/null
+++ b/src/testdir/test_spellfile.vim
@@ -0,0 +1,172 @@
+" 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
diff --git a/src/version.c b/src/version.c
index 77d940622..fbc1db9e9 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1838,
+/**/
1837,
/**/
1836,