diff options
Diffstat (limited to 'src/screen.c')
-rw-r--r-- | src/screen.c | 92 |
1 files changed, 88 insertions, 4 deletions
diff --git a/src/screen.c b/src/screen.c index b1fbedfa2..6fb5931db 100644 --- a/src/screen.c +++ b/src/screen.c @@ -2502,8 +2502,17 @@ win_line(wp, lnum, startrow, endrow) int has_syntax = FALSE; /* this buffer has syntax highl. */ int save_did_emsg; int has_spell = FALSE; /* this buffer has spell checking */ +# define SPWORDLEN 150 + char_u nextline[SPWORDLEN * 2];/* text with start of the next line */ + int nextlinecol; /* column where nextline[] starts */ + int nextline_idx; /* index in nextline[] where next line + starts */ int spell_attr = 0; /* attributes desired by spelling */ int word_end = 0; /* last byte with same spell_attr */ + static linenr_T checked_lnum = 0; /* line number for checked_col */ + static int checked_col = 0; /* column in checked_lnum up to which + * there are no spell errors */ + int cur_checked_col = 0; /* checked column for current line */ #endif int extra_check; /* has syntax or linebreak */ #ifdef FEAT_MBYTE @@ -2609,6 +2618,22 @@ win_line(wp, lnum, startrow, endrow) /* Prepare for spell checking. */ has_spell = TRUE; extra_check = TRUE; + + /* Get the start of the next line, so that words that wrap to the next + * line are found too: "et<line-break>al.". + * Trick: skip a few chars for C/shell/Vim comments */ + nextline[SPWORDLEN] = NUL; + if (lnum < wp->w_buffer->b_ml.ml_line_count) + { + line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); + spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); + } + + /* When a word wrapped from the previous line the start of the current + * line is valid. */ + if (lnum == checked_lnum) + cur_checked_col = checked_col; + checked_lnum = 0; } #endif @@ -2774,6 +2799,42 @@ win_line(wp, lnum, startrow, endrow) line = ml_get_buf(wp->w_buffer, lnum, FALSE); ptr = line; +#ifdef FEAT_SYN_HL + if (has_spell) + { + /* To be able to spell-check over line boundaries copy the end of the + * current line into nextline[]. Above the start of the next line was + * copied to nextline[SPWORDLEN]. */ + if (nextline[SPWORDLEN] == NUL) + { + /* No next line or it is empty. */ + nextlinecol = MAXCOL; + nextline_idx = 0; + } + else + { + v = STRLEN(line); + if (v < SPWORDLEN) + { + /* Short line, use it completely and append the start of the + * next line. */ + nextlinecol = 0; + mch_memmove(nextline, line, (size_t)v); + mch_memmove(nextline + v, nextline + SPWORDLEN, + STRLEN(nextline + SPWORDLEN) + 1); + nextline_idx = v + 1; + } + else + { + /* Long line, use only the last SPWORDLEN bytes. */ + nextlinecol = v - SPWORDLEN; + mch_memmove(nextline, line + nextlinecol, SPWORDLEN); + nextline_idx = SPWORDLEN + 1; + } + } + } +#endif + /* find start of trailing whitespace */ if (wp->w_p_list && lcs_trail) { @@ -3587,14 +3648,15 @@ win_line(wp, lnum, startrow, endrow) * Only do this when there is no syntax highlighting, the * @Spell cluster is not used or the current syntax item * contains the @Spell cluster. */ - if (has_spell && v >= word_end) + if (has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; if (area_attr == 0 && search_attr == 0) char_attr = syntax_attr; if (c != 0 && (!has_syntax || can_spell)) { - char_u *prev_ptr; + char_u *prev_ptr, *p; + int len; # ifdef FEAT_MBYTE if (has_mbyte) { @@ -3604,7 +3666,15 @@ win_line(wp, lnum, startrow, endrow) else # endif prev_ptr = ptr - 1; - word_end = v + spell_check(wp, prev_ptr, &spell_attr); + + /* Use nextline[] if possible, it has the start of the + * next line concatenated. */ + if ((prev_ptr - line) - nextlinecol >= 0) + p = nextline + (prev_ptr - line) - nextlinecol; + else + p = prev_ptr; + len = spell_check(wp, p, &spell_attr); + word_end = v + len; /* In Insert mode only highlight a word that * doesn't touch the cursor. */ @@ -3618,10 +3688,24 @@ win_line(wp, lnum, startrow, endrow) spell_attr = 0; spell_redraw_lnum = lnum; } + + if (spell_attr == 0 && p != prev_ptr + && (p - nextline) + len > nextline_idx) + { + /* Remember that the good word continues at the + * start of the next line. */ + checked_lnum = lnum + 1; + checked_col = (p - nextline) + len - nextline_idx; + } } } if (spell_attr != 0) - char_attr = hl_combine_attr(char_attr, spell_attr); + { + if (area_attr == 0 && search_attr == 0) + char_attr = hl_combine_attr(char_attr, spell_attr); + else + char_attr = hl_combine_attr(spell_attr, char_attr); + } #endif #ifdef FEAT_LINEBREAK /* |