# HG changeset patch # User Christian Brabandt # Date 1715965204 -7200 # Node ID ffa6ed03a9f2718c1c898c53de7dfe0860986ae3 # Parent 4f1c68ef216ce1bb7835c441313417015830c694 patch 9.1.0418: Cannot move to previous/next rare word Commit: https://github.com/vim/vim/commit/8e4c4c7d87def2b100a5d64dc518ef85d9de8765 Author: Christ van Willegen - van Noort Date: Fri May 17 18:49:27 2024 +0200 patch 9.1.0418: Cannot move to previous/next rare word Problem: Cannot move to previous/next rare word (Colin Kennedy) Solution: Add the ]r and [r motions (Christ van Willegen) fixes: #14773 closes: #14780 Signed-off-by: Christ van Willegen - van Noort Signed-off-by: Christian Brabandt diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -1,4 +1,4 @@ -*spell.txt* For Vim version 9.1. Last change: 2024 May 11 +*spell.txt* For Vim version 9.1. Last change: 2024 May 17 VIM REFERENCE MANUAL by Bram Moolenaar @@ -62,6 +62,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/runtime/doc/tags b/runtime/doc/tags --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -5876,6 +5876,7 @@ ZZ editing.txt /*ZZ* [p change.txt /*[p* [pattern] pattern.txt /*[pattern]* [quotex] intro.txt /*[quotex]* +[r spell.txt /*[r* [range] cmdline.txt /*[range]* [s spell.txt /*[s* [star motion.txt /*[star* @@ -5904,6 +5905,7 @@ ZZ editing.txt /*ZZ* ]i tagsrch.txt /*]i* ]m motion.txt /*]m* ]p change.txt /*]p* +]r spell.txt /*]r* ]s spell.txt /*]s* ]star motion.txt /*]star* ]z fold.txt /*]z* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2024 May 05 +*version9.txt* For Vim version 9.1. Last change: 2024 May 17 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41587,15 +41587,17 @@ Autocommands: ~ Highlighting: ~ -|hl-MsgArea| highlighting of the Command-line and messages area. +|hl-MsgArea| highlighting of the Command-line and messages area Commands: ~ +|[r| and |]r| to move the cursor to previous/next rare word + Options: ~ 'winfixbuf' Keep buffer focused in a window -'t_xo' Terminal uses XON/XOFF handshaking (e.g. vt420). +'t_xo' Terminal uses XON/XOFF handshaking (e.g. vt420) ============================================================================== INCOMPATIBLE CHANGES *incompatible-9.2* diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -1801,7 +1801,7 @@ win_line( pos = wp->w_cursor; wp->w_cursor.lnum = lnum; wp->w_cursor.col = linecol; - len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); + 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, FALSE); diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -10959,7 +10959,7 @@ f_spellbadword(typval_T *argvars UNUSED, 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 = ml_get_cursor(); diff --git a/src/insexpand.c b/src/insexpand.c --- a/src/insexpand.c +++ b/src/insexpand.c @@ -5195,7 +5195,7 @@ 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/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -2593,7 +2593,7 @@ 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); @@ -4529,13 +4529,15 @@ nv_brackets(cmdarg_T *cap) #endif #ifdef FEAT_SPELL - // "[s", "[S", "]s" and "]S": move to next spell error. - else if (cap->nchar == 's' || cap->nchar == 'S') + // "[r", "[s", "[S", "]r", "]s" and "]S": move to next spell error. + else if (cap->nchar == 'r' || cap->nchar == 's' || cap->nchar == 'S') { setpcmark(); for (n = 0; n < cap->count1; ++n) if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD, - cap->nchar == 's' ? TRUE : FALSE, 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/proto/spell.pro b/src/proto/spell.pro --- a/src/proto/spell.pro +++ b/src/proto/spell.pro @@ -6,7 +6,7 @@ int match_compoundrule(slang_T *slang, c int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req); int spell_valid_case(int wordflags, int treeflags); int spell_check_window(win_T *wp); -int spell_move_to(win_T *wp, int dir, int allwords, int curline, hlf_T *attrp); +int spell_move_to(win_T *wp, int dir, smt_T behaviour, int curline, hlf_T *attrp); void spell_cat_line(char_u *buf, char_u *line, int maxlen); char_u *spell_enc(void); slang_T *slang_alloc(char_u *lang); diff --git a/src/spell.c b/src/spell.c --- a/src/spell.c +++ b/src/spell.c @@ -1336,7 +1336,7 @@ no_spell_checking(win_T *wp) spell_move_to( win_T *wp, int dir, // FORWARD or BACKWARD - int allwords, // TRUE for "[s"/"]s", FALSE for "[S"/"]S" + smt_T behaviour, // Behaviour of the function int curline, hlf_T *attrp) // return: attributes of bad word or NULL // (only when "dir" is FORWARD) @@ -1441,7 +1441,9 @@ spell_move_to( 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. diff --git a/src/spellsuggest.c b/src/spellsuggest.c --- a/src/spellsuggest.c +++ b/src/spellsuggest.c @@ -512,7 +512,7 @@ spell_suggest(int count) badlen = ml_get_curline_len() - (int)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 diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -278,6 +278,7 @@ NEW_TESTS = \ test_spell \ test_spell_utf8 \ test_spellfile \ + test_spellrare \ test_startup \ test_startup_utf8 \ test_stat \ @@ -521,6 +522,7 @@ NEW_TESTS_RES = \ test_spell.res \ test_spell_utf8.res \ test_spellfile.res \ + test_spellrare.res \ test_startup.res \ test_stat.res \ test_statusline.res \ diff --git a/src/testdir/test_spellrare.vim b/src/testdir/test_spellrare.vim new file mode 100644 --- /dev/null +++ b/src/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('')) + normal ]s + call assert_equal('bar', expand('')) + + normal ]r + call assert_equal('foobara', expand('')) + normal ]r + call assert_equal('foobar', expand('')) + normal ]r + call assert_equal('foobara', expand('')) + normal 2]r + call assert_equal('foobara', expand('')) + + normal [r + call assert_equal('foobar', expand('')) + normal [r + call assert_equal('foobara', expand('')) + normal [r + call assert_equal('foobar', expand('')) + normal 2[r + call assert_equal('foobar', expand('')) + + 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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 418, +/**/ 417, /**/ 416, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -1530,6 +1530,15 @@ typedef enum 'z', 'Z', 'g'} /* + * 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; +/* * Boolean constants */ #ifndef TRUE