aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-05-18 07:09:05 +0800
committerGitHub <noreply@github.com>2024-05-18 07:09:05 +0800
commit62eb7e79a5f9b5f476f034b5446d2972c840ef87 (patch)
tree7d4ad0a263d658fb04c5f461e8f2a1b72bdd71df
parent5947f249f838eb56f8d186e69f4f58e9dee009ed (diff)
downloadrneovim-62eb7e79a5f9b5f476f034b5446d2972c840ef87.tar.gz
rneovim-62eb7e79a5f9b5f476f034b5446d2972c840ef87.tar.bz2
rneovim-62eb7e79a5f9b5f476f034b5446d2972c840ef87.zip
vim-patch:9.1.0418: Cannot move to previous/next rare word (#28822)
Problem: Cannot move to previous/next rare word (Colin Kennedy) Solution: Add the ]r and [r motions (Christ van Willegen) fixes: vim/vim#14773 closes: vim/vim#14780 https://github.com/vim/vim/commit/8e4c4c7d87def2b100a5d64dc518ef85d9de8765 Co-authored-by: Christ van Willegen - van Noort <github.com@vanwillegen-vannoort.nl>
-rw-r--r--runtime/doc/spell.txt11
-rw-r--r--src/nvim/drawline.c2
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/insexpand.c2
-rw-r--r--src/nvim/normal.c11
-rw-r--r--src/nvim/spell.c8
-rw-r--r--src/nvim/spell.h7
-rw-r--r--src/nvim/spellsuggest.c2
-rw-r--r--test/old/testdir/test_spellrare.vim61
9 files changed, 95 insertions, 11 deletions
diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt
index 29e4a7b0aa..269d52352d 100644
--- a/runtime/doc/spell.txt
+++ b/runtime/doc/spell.txt
@@ -51,6 +51,17 @@ To search for the next misspelled word:
*[S*
[S Like "]S" but search backwards.
+ *]r*
+]r Move to next "rare" word after the cursor.
+ A count before the command can be used to repeat.
+ 'wrapscan' applies.
+
+ *[r*
+[r Like "]r" but search backwards, find the "rare"
+ word before the cursor. Doesn't recognize words
+ split over two lines, thus may stop at words that are
+ not highlighted as rare.
+
To add words to your own word list:
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 283f7d9d61..07944081da 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -1415,7 +1415,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
pos_T pos = wp->w_cursor;
wp->w_cursor.lnum = lnum;
wp->w_cursor.col = linecol;
- size_t len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
+ size_t len = spell_move_to(wp, FORWARD, SMT_ALL, true, &spell_hlf);
// spell_move_to() may call ml_get() and make "line" invalid
line = ml_get_buf(wp->w_buffer, lnum);
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1fc80e88c4..0b4b79c6ca 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -8308,7 +8308,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
size_t len = 0;
if (argvars[0].v_type == VAR_UNKNOWN) {
// Find the start and length of the badly spelled word.
- len = spell_move_to(curwin, FORWARD, true, true, &attr);
+ len = spell_move_to(curwin, FORWARD, SMT_ALL, true, &attr);
if (len != 0) {
word = get_cursor_pos_ptr();
curwin->w_set_curswant = true;
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 15ec0ab08d..c51b3b916d 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -4570,7 +4570,7 @@ void free_insexpand_stuff(void)
static void spell_back_to_badword(void)
{
pos_T tpos = curwin->w_cursor;
- spell_bad_len = spell_move_to(curwin, BACKWARD, true, true, NULL);
+ spell_bad_len = spell_move_to(curwin, BACKWARD, SMT_ALL, true, NULL);
if (curwin->w_cursor.col != tpos.col) {
start_arrow(&tpos);
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2f1477b9d5..02bd3d05c1 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2710,7 +2710,7 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar)
// off this fails and find_ident_under_cursor() is
// used below.
emsg_off++;
- len = spell_move_to(curwin, FORWARD, true, true, NULL);
+ len = spell_move_to(curwin, FORWARD, SMT_ALL, true, NULL);
emsg_off--;
if (len != 0 && curwin->w_cursor.col <= pos.col) {
ptr = ml_get_pos(&curwin->w_cursor);
@@ -4272,12 +4272,15 @@ static void nv_brackets(cmdarg_T *cap)
cap->count1) == false) {
clearopbeep(cap->oap);
}
- } else if (cap->nchar == 's' || cap->nchar == 'S') {
- // "[s", "[S", "]s" and "]S": move to next spell error.
+ } else if (cap->nchar == 'r' || cap->nchar == 's' || cap->nchar == 'S') {
+ // "[r", "[s", "[S", "]r", "]s" and "]S": move to next spell error.
setpcmark();
for (n = 0; n < cap->count1; n++) {
if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD,
- cap->nchar == 's', false, NULL) == 0) {
+ cap->nchar == 's'
+ ? SMT_ALL
+ : cap->nchar == 'r' ? SMT_RARE : SMT_BAD,
+ false, NULL) == 0) {
clearopbeep(cap->oap);
break;
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 190501028e..6f0c7bab8e 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1290,11 +1290,11 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col)
/// to after badly spelled word before the cursor.
///
/// @param dir FORWARD or BACKWARD
-/// @param allwords true for "[s"/"]s", false for "[S"/"]S"
+/// @param behaviour Behaviour of the function
/// @param attrp return: attributes of bad word or NULL (only when "dir" is FORWARD)
///
/// @return 0 if not found, length of the badly spelled word otherwise.
-size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp)
+size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp)
{
pos_T found_pos;
size_t found_len = 0;
@@ -1398,7 +1398,9 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
if (attr != HLF_COUNT) {
// We found a bad word. Check the attribute.
- if (allwords || attr == HLF_SPB) {
+ if (behaviour == SMT_ALL
+ || (behaviour == SMT_BAD && attr == HLF_SPB)
+ || (behaviour == SMT_RARE && attr == HLF_SPR)) {
// When searching forward only accept a bad word after
// the cursor.
if (dir == BACKWARD
diff --git a/src/nvim/spell.h b/src/nvim/spell.h
index adbdd3705e..85e16d7f6c 100644
--- a/src/nvim/spell.h
+++ b/src/nvim/spell.h
@@ -21,6 +21,13 @@ extern char *e_format;
extern char *repl_from;
extern char *repl_to;
+/// Values for behaviour in spell_move_to
+typedef enum {
+ SMT_ALL = 0, ///< Move to "all" words
+ SMT_BAD, ///< Move to "bad" words only
+ SMT_RARE, ///< Move to "rare" words only
+} smt_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "spell.h.generated.h"
#endif
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index 32480443c4..a7de20d14e 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -484,7 +484,7 @@ void spell_suggest(int count)
badlen = get_cursor_line_len() - curwin->w_cursor.col;
}
// Find the start of the badly spelled word.
- } else if (spell_move_to(curwin, FORWARD, true, true, NULL) == 0
+ } else if (spell_move_to(curwin, FORWARD, SMT_ALL, true, NULL) == 0
|| curwin->w_cursor.col > prev_cursor.col) {
// No bad word or it starts after the cursor: use the word under the
// cursor.
diff --git a/test/old/testdir/test_spellrare.vim b/test/old/testdir/test_spellrare.vim
new file mode 100644
index 0000000000..bbb13c27c2
--- /dev/null
+++ b/test/old/testdir/test_spellrare.vim
@@ -0,0 +1,61 @@
+" Test spell checking
+
+source check.vim
+CheckFeature spell
+
+" Test spellbadword() with argument, specifically to move to "rare" words
+" in normal mode.
+func Test_spellrareword()
+ set spell
+
+ " Create a small word list to test that spellbadword('...')
+ " can return ['...', 'rare'].
+ let lines =<< trim END
+ foo
+ foobar/?
+ foobara/?
+END
+ call writefile(lines, 'Xwords', 'D')
+
+ mkspell! Xwords.spl Xwords
+ set spelllang=Xwords.spl
+ call assert_equal(['foobar', 'rare'], spellbadword('foo foobar'))
+
+ new
+ call setline(1, ['foo', '', 'foo bar foo bar foobara foo foo foo foobar', '', 'End'])
+ set spell wrapscan
+ normal ]s
+ call assert_equal('foo', expand('<cword>'))
+ normal ]s
+ call assert_equal('bar', expand('<cword>'))
+
+ normal ]r
+ call assert_equal('foobara', expand('<cword>'))
+ normal ]r
+ call assert_equal('foobar', expand('<cword>'))
+ normal ]r
+ call assert_equal('foobara', expand('<cword>'))
+ normal 2]r
+ call assert_equal('foobara', expand('<cword>'))
+
+ normal [r
+ call assert_equal('foobar', expand('<cword>'))
+ normal [r
+ call assert_equal('foobara', expand('<cword>'))
+ normal [r
+ call assert_equal('foobar', expand('<cword>'))
+ normal 2[r
+ call assert_equal('foobar', expand('<cword>'))
+
+ bwipe!
+ set nospell
+
+ call delete('Xwords.spl')
+ set spelllang&
+ set spell&
+
+ " set 'encoding' to clear the word list
+ set encoding=utf-8
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab