diff options
Diffstat (limited to 'src/nvim/spell.c')
-rw-r--r-- | src/nvim/spell.c | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/src/nvim/spell.c b/src/nvim/spell.c index c0d05eb799..30e256b37a 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -71,6 +71,7 @@ #include "nvim/change.h" // for changed_bytes #include "nvim/charset.h" // for skipwhite, getwhitecols, skipbin #include "nvim/cursor.h" // for get_cursor_line_ptr +#include "nvim/decoration.h" #include "nvim/drawscreen.h" // for NOT_VALID, redraw_later #include "nvim/eval/typval.h" // for semsg #include "nvim/ex_cmds.h" // for do_sub_msg @@ -220,7 +221,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou size_t nrlen = 0; // found a number first size_t wrongcaplen = 0; bool count_word = docount; - bool use_camel_case = *wp->w_s->b_p_spo != NUL; + bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; bool camel_case = false; // A word never starts at a space or a control character. Return quickly @@ -1198,6 +1199,24 @@ bool no_spell_checking(win_T *wp) return false; } +static void decor_spell_nav_start(win_T *wp) +{ + decor_state = (DecorState){ 0 }; + decor_redraw_reset(wp->w_buffer, &decor_state); +} + +static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, int col, + char **decor_error) +{ + if (*decor_lnum != lnum) { + decor_providers_invoke_spell(wp, lnum - 1, col, lnum - 1, -1, decor_error); + decor_redraw_line(wp->w_buffer, lnum - 1, &decor_state); + *decor_lnum = lnum; + } + decor_redraw_col(wp->w_buffer, col, col, false, &decor_state); + return decor_state.spell; +} + /// Moves to the next spell error. /// "curline" is false for "[s", "]s", "[S" and "]S". /// "curline" is true to find word under/after cursor in the same line. @@ -1216,11 +1235,11 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att hlf_T attr = HLF_COUNT; size_t len; int has_syntax = syntax_present(wp); - int col; + colnr_T col; char_u *buf = NULL; size_t buflen = 0; int skip = 0; - int capcol = -1; + colnr_T capcol = -1; bool found_one = false; bool wrapped = false; @@ -1228,6 +1247,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att return 0; } + size_t ret = 0; + // Start looking for bad word at the start of the line, because we can't // start halfway through a word, we don't know where it starts or ends. // @@ -1240,6 +1261,19 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att linenr_T lnum = wp->w_cursor.lnum; clearpos(&found_pos); + char *decor_error = NULL; + // Ephemeral extmarks are currently stored in the global decor_state. + // When looking for spell errors, we need to: + // - temporarily reset decor_state + // - run the _on_spell_nav decor callback for each line we look at + // - detect if any spell marks are present + // - restore decor_state to the value saved here. + // TODO(lewis6991): un-globalize decor_state and allow ephemeral marks to be stored into a + // temporary DecorState. + DecorState saved_decor_start = decor_state; + linenr_T decor_lnum = -1; + decor_spell_nav_start(wp); + while (!got_int) { char_u *line = ml_get_buf(wp->w_buffer, lnum, false); @@ -1258,10 +1292,10 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // For checking first word with a capital skip white space. if (capcol == 0) { - capcol = (int)getwhitecols((char *)line); + capcol = (colnr_T)getwhitecols((char *)line); } else if (curline && wp == curwin) { // For spellbadword(): check if first word needs a capital. - col = (int)getwhitecols((char *)line); + col = (colnr_T)getwhitecols((char *)line); if (check_need_cap(lnum, col)) { capcol = col; } @@ -1308,33 +1342,37 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att || ((colnr_T)(curline ? p - buf + (ptrdiff_t)len : p - buf) > wp->w_cursor.col)) { - bool can_spell; - if (has_syntax) { - col = (int)(p - buf); - (void)syn_get_id(wp, lnum, (colnr_T)col, - false, &can_spell, false); - if (!can_spell) { - attr = HLF_COUNT; - } - } else { - can_spell = true; + col = (colnr_T)(p - buf); + + bool can_spell = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0; + + if (!can_spell) { + can_spell = decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error); + } + + if (!can_spell && has_syntax) { + (void)syn_get_id(wp, lnum, col, false, &can_spell, false); + } + + if (!can_spell) { + attr = HLF_COUNT; } if (can_spell) { found_one = true; found_pos = (pos_T) { .lnum = lnum, - .col = (int)(p - buf), + .col = col, .coladd = 0 }; if (dir == FORWARD) { // No need to search further. wp->w_cursor = found_pos; - xfree(buf); if (attrp != NULL) { *attrp = attr; } - return len; + ret = len; + goto theend; } else if (curline) { // Insert mode completion: put cursor after // the bad word. @@ -1358,8 +1396,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att if (dir == BACKWARD && found_pos.lnum != 0) { // Use the last match in the line (before the cursor). wp->w_cursor = found_pos; - xfree(buf); - return found_len; + ret = found_len; + goto theend; } if (curline) { @@ -1429,8 +1467,12 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att line_breakcheck(); } +theend: + decor_state_free(&decor_state); + xfree(decor_error); + decor_state = saved_decor_start; xfree(buf); - return 0; + return ret; } // For spell checking: concatenate the start of the following line "line" into |