Merge pull request #23744 from luukvbaal/spell

vim-patch:9.0.{0175,0590,0608,0664}
This commit is contained in:
zeertzjq
2023-05-25 18:01:06 +08:00
committed by GitHub
7 changed files with 224 additions and 62 deletions

View File

@@ -43,6 +43,7 @@
#include "nvim/plines.h" #include "nvim/plines.h"
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/search.h" #include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h" #include "nvim/state.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/textformat.h" #include "nvim/textformat.h"
@@ -393,6 +394,15 @@ void changed_bytes(linenr_T lnum, colnr_T col)
{ {
changedOneline(curbuf, lnum); changedOneline(curbuf, lnum);
changed_common(lnum, col, lnum + 1, 0); changed_common(lnum, col, lnum + 1, 0);
// When text has been changed at the end of the line, possibly the start of
// the next line may have SpellCap that should be removed or it needs to be
// displayed. Schedule the next line for redrawing just in case.
// Don't do this when displaying '$' at the end of changed text.
if (spell_check_window(curwin)
&& lnum < curbuf->b_ml.ml_line_count
&& vim_strchr(p_cpo, CPO_DOLLAR) == NULL) {
redrawWinline(curwin, lnum + 1);
}
// notify any channels that are watching // notify any channels that are watching
buf_updates_send_changes(curbuf, lnum, 1, 1); buf_updates_send_changes(curbuf, lnum, 1, 1);

View File

@@ -1203,12 +1203,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
draw_color_col = advance_color_col(VCOL_HLC, &color_cols); draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
} }
if (wp->w_p_spell if (!has_fold && !end_fill && spell_check_window(wp)) {
&& !has_fold
&& !end_fill
&& *wp->w_s->b_p_spl != NUL
&& !GA_EMPTY(&wp->w_s->b_langp)
&& *(char **)(wp->w_s->b_langp.ga_data) != NULL) {
// Prepare for spell checking. // Prepare for spell checking.
has_spell = true; has_spell = true;
extra_check = true; extra_check = true;
@@ -2188,12 +2183,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
v = (ptr - line); v = (ptr - line);
if (has_spell && v >= word_end && v > cur_checked_col) { if (has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0; spell_attr = 0;
if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) { char *prev_ptr = ptr - mb_l;
char *prev_ptr; // do not calculate cap_col at the end of the line or when
// only white space is following
if (c != 0 && (*skipwhite(prev_ptr) != NUL)
&& ((!has_syntax && !no_plain_buffer) || can_spell)) {
char *p; char *p;
int len;
hlf_T spell_hlf = HLF_COUNT; hlf_T spell_hlf = HLF_COUNT;
prev_ptr = ptr - mb_l;
v -= mb_l - 1; v -= mb_l - 1;
// Use nextline[] if possible, it has the start of the // Use nextline[] if possible, it has the start of the
@@ -2206,7 +2202,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
cap_col -= (int)(prev_ptr - line); cap_col -= (int)(prev_ptr - line);
size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange); size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange);
assert(tmplen <= INT_MAX); assert(tmplen <= INT_MAX);
len = (int)tmplen; int len = (int)tmplen;
word_end = (int)v + len; word_end = (int)v + len;
// In Insert mode only highlight a word that // In Insert mode only highlight a word that

View File

@@ -53,6 +53,7 @@
#include "nvim/popupmenu.h" #include "nvim/popupmenu.h"
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/search.h" #include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h" #include "nvim/state.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/syntax.h" #include "nvim/syntax.h"
@@ -1526,8 +1527,8 @@ void edit_unputchar(void)
} }
} }
// Called when p_dollar is set: display a '$' at the end of the changed text /// Called when "$" is in 'cpoptions': display a '$' at the end of the changed
// Only works when cursor is in the line that changes. /// text. Only works when cursor is in the line that changes.
void display_dollar(colnr_T col_arg) void display_dollar(colnr_T col_arg)
{ {
colnr_T col = col_arg < 0 ? 0 : col_arg; colnr_T col = col_arg < 0 ? 0 : col_arg;

View File

@@ -1189,11 +1189,19 @@ bool spell_valid_case(int wordflags, int treeflags)
|| (wordflags & WF_ONECAP) != 0)); || (wordflags & WF_ONECAP) != 0));
} }
// Returns true if spell checking is not enabled. /// Return true if spell checking is enabled for "wp".
bool spell_check_window(win_T *wp)
{
return wp->w_p_spell
&& *wp->w_s->b_p_spl != NUL
&& wp->w_s->b_langp.ga_len > 0
&& *(char **)(wp->w_s->b_langp.ga_data) != NULL;
}
/// Return true and give an error if spell checking is not enabled.
bool no_spell_checking(win_T *wp) bool no_spell_checking(win_T *wp)
{ {
if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL || GA_EMPTY(&wp->w_s->b_langp)) {
|| GA_EMPTY(&wp->w_s->b_langp)) {
emsg(_(e_no_spell)); emsg(_(e_no_spell));
return true; return true;
} }

View File

@@ -120,6 +120,7 @@
#include "nvim/path.h" #include "nvim/path.h"
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/sha256.h" #include "nvim/sha256.h"
#include "nvim/spell.h"
#include "nvim/state.h" #include "nvim/state.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/types.h" #include "nvim/types.h"
@@ -2372,6 +2373,12 @@ static void u_undoredo(int undo, bool do_buf_event)
} }
changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event); changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event);
// When text has been changed, possibly the start of the next line
// may have SpellCap that should be removed or it needs to be
// displayed. Schedule the next line for redrawing just in case.
if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) {
redrawWinline(curwin, bot);
}
// Set the '[ mark. // Set the '[ mark.
if (top + 1 < curbuf->b_op_start.lnum) { if (top + 1 < curbuf->b_op_start.lnum) {

View File

@@ -3,9 +3,9 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local clear = helpers.clear local clear = helpers.clear
local exec = helpers.exec
local feed = helpers.feed local feed = helpers.feed
local insert = helpers.insert local insert = helpers.insert
local command = helpers.command
local meths = helpers.meths local meths = helpers.meths
local curbufmeths = helpers.curbufmeths local curbufmeths = helpers.curbufmeths
local is_os = helpers.is_os local is_os = helpers.is_os
@@ -27,12 +27,13 @@ describe("'spell'", function()
[6] = {foreground = Screen.colors.Red}, [6] = {foreground = Screen.colors.Red},
[7] = {foreground = Screen.colors.Blue}, [7] = {foreground = Screen.colors.Blue},
[8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true}, [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
[9] = {bold = true},
}) })
end) end)
it('joins long lines #7937', function() it('joins long lines #7937', function()
if is_os('openbsd') then pending('FIXME #12104', function() end) return end if is_os('openbsd') then pending('FIXME #12104', function() end) return end
command('set spell') exec('set spell')
insert([[ insert([[
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
@@ -57,31 +58,128 @@ describe("'spell'", function()
-- oldtest: Test_spell_screendump() -- oldtest: Test_spell_screendump()
it('has correct highlight at start of line', function() it('has correct highlight at start of line', function()
insert([[ exec([=[
"This is some text without any spell errors. Everything", call setline(1, [
"should just be black, nothing wrong here.", \"This is some text without any spell errors. Everything",
"", \"should just be black, nothing wrong here.",
"This line has a sepll error. and missing caps.", \"",
"And and this is the the duplication.", \"This line has a sepll error. and missing caps.",
"with missing caps here.", \"And and this is the the duplication.",
]]) \"with missing caps here.",
command('set spell spelllang=en_nz') \])
set spell spelllang=en_nz
]=])
screen:expect([[ screen:expect([[
"This is some text without any spell errors. Everything", | ^This is some text without any spell errors. Everything |
"should just be black, nothing wrong here.", | should just be black, nothing wrong here. |
"", | |
"This line has a {1:sepll} error. {2:and} missing caps.", | This line has a {1:sepll} error. {2:and} missing caps. |
"{1:And and} this is {1:the the} duplication.", | {1:And and} this is {1:the the} duplication. |
"with missing caps here.", | {2:with} missing caps here. |
^ | {0:~ }|
| |
]]) ]])
end) end)
-- oldtest: Test_spell_screendump_spellcap()
it('has correct highlight at start of line with trailing space', function()
exec([=[
call setline(1, [
\" This line has a sepll error. and missing caps and trailing spaces. ",
\"another missing cap here.",
\"",
\"and here.",
\" ",
\"and here."
\])
set spell spelllang=en
]=])
screen:expect([[
^ This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
{2:another} missing cap here. |
|
{2:and} here. |
|
{2:and} here. |
{0:~ }|
|
]])
-- After adding word missing Cap in next line is updated
feed('3GANot<Esc>')
screen:expect([[
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
{2:another} missing cap here. |
No^t |
and here. |
|
{2:and} here. |
{0:~ }|
|
]])
-- Deleting a full stop removes missing Cap in next line
feed('5Gddk$x')
screen:expect([[
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
{2:another} missing cap here. |
Not |
and her^e |
and here. |
{0:~ }|
{0:~ }|
|
]])
-- Undo also updates the next line (go to command line to remove message)
feed('u:<Esc>')
screen:expect([[
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
{2:another} missing cap here. |
Not |
and here^. |
{2:and} here. |
{0:~ }|
{0:~ }|
|
]])
end)
-- oldtest: Test_spell_compatible()
it([[redraws properly when using "C" and "$" is in 'cpo']], function()
exec([=[
call setline(1, [
\ "test "->repeat(20),
\ "",
\ "end",
\ ])
set spell cpo+=$
]=])
feed('51|C')
screen:expect([[
{2:test} test test test test test test test test test ^test test test test test test |
test test test test$ |
|
{2:end} |
{0:~ }|
{0:~ }|
{0:~ }|
{9:-- INSERT --} |
]])
feed('x')
screen:expect([[
{2:test} test test test test test test test test test x^est test test test test test |
test test test test$ |
|
{2:end} |
{0:~ }|
{0:~ }|
{0:~ }|
{9:-- INSERT --} |
]])
end)
it('extmarks, "noplainbuffer" and syntax #20385 #23398', function() it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
command('set filetype=c') exec('set filetype=c')
command('syntax on') exec('syntax on')
command('set spell') exec('set spell')
insert([[ insert([[
#include <stdbool.h> #include <stdbool.h>
bool func(void); bool func(void);
@@ -119,7 +217,7 @@ describe("'spell'", function()
{0:~ }| {0:~ }|
{6:search hit BOTTOM, continuing at TOP} | {6:search hit BOTTOM, continuing at TOP} |
]]) ]])
command('echo ""') exec('echo ""')
local ns = meths.create_namespace("spell") local ns = meths.create_namespace("spell")
-- extmark with spell=true enables spell -- extmark with spell=true enables spell
local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true }) local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true })
@@ -168,7 +266,7 @@ describe("'spell'", function()
{0:~ }| {0:~ }|
{6:search hit TOP, continuing at BOTTOM} | {6:search hit TOP, continuing at BOTTOM} |
]]) ]])
command('echo ""') exec('echo ""')
curbufmeths.del_extmark(ns, id) curbufmeths.del_extmark(ns, id)
screen:expect([[ screen:expect([[
{3:#include }{4:<stdbool.h>} | {3:#include }{4:<stdbool.h>} |
@@ -192,7 +290,7 @@ describe("'spell'", function()
| |
]]) ]])
-- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled
command('set spelloptions+=noplainbuffer') exec('set spelloptions+=noplainbuffer')
screen:expect_unchanged() screen:expect_unchanged()
feed('[s') feed('[s')
screen:expect([[ screen:expect([[
@@ -206,7 +304,7 @@ describe("'spell'", function()
| |
]]) ]])
-- no spellchecking with "noplainbuffer" and syntax disabled -- no spellchecking with "noplainbuffer" and syntax disabled
command('syntax off') exec('syntax off')
screen:expect([[ screen:expect([[
#include <stdbool.h> | #include <stdbool.h> |
bool func(void); | bool func(void); |
@@ -228,9 +326,9 @@ describe("'spell'", function()
{0:~ }| {0:~ }|
{6:search hit BOTTOM, continuing at TOP} | {6:search hit BOTTOM, continuing at TOP} |
]]) ]])
command('echo ""') exec('echo ""')
-- everything is spellchecked without "noplainbuffer" with syntax disabled -- everything is spellchecked without "noplainbuffer" with syntax disabled
command('set spelloptions&') exec('set spelloptions&')
screen:expect([[ screen:expect([[
#include <{1:stdbool}.h> | #include <{1:stdbool}.h> |
{1:bool} {1:func}(void); | {1:bool} {1:func}(void); |
@@ -256,7 +354,7 @@ describe("'spell'", function()
it('and syntax does not clear extmark highlighting at the start of a word', function() it('and syntax does not clear extmark highlighting at the start of a word', function()
screen:try_resize(43, 3) screen:try_resize(43, 3)
command([[ exec([[
set spell set spell
syntax match Constant "^.*$" syntax match Constant "^.*$"
call setline(1, "This is some text without any spell errors.") call setline(1, "This is some text without any spell errors.")

View File

@@ -972,28 +972,70 @@ func Test_spell_screendump()
\ ]) \ ])
set spell spelllang=en_nz set spell spelllang=en_nz
END END
call writefile(lines, 'XtestSpell') call writefile(lines, 'XtestSpell', 'D')
let buf = RunVimInTerminal('-S XtestSpell', {'rows': 8})
call VerifyScreenDump(buf, 'Test_spell_1', {})
let lines =<< trim END
call setline(1, [
\ "This is some text without any spell errors. Everything",
\ "should just be black, nothing wrong here.",
\ "",
\ "This line has a sepll error. and missing caps.",
\ "And and this is the the duplication.",
\ "with missing caps here.",
\ ])
set spell spelllang=en_nz
END
call writefile(lines, 'XtestSpell')
let buf = RunVimInTerminal('-S XtestSpell', {'rows': 8}) let buf = RunVimInTerminal('-S XtestSpell', {'rows': 8})
call VerifyScreenDump(buf, 'Test_spell_1', {}) call VerifyScreenDump(buf, 'Test_spell_1', {})
" clean up " clean up
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
call delete('XtestSpell') endfunc
func Test_spell_screendump_spellcap()
CheckScreendump
let lines =<< trim END
call setline(1, [
\ " This line has a sepll error. and missing caps and trailing spaces. ",
\ "another missing cap here.",
\ "",
\ "and here.",
\ " ",
\ "and here."
\ ])
set spell spelllang=en
END
call writefile(lines, 'XtestSpellCap', 'D')
let buf = RunVimInTerminal('-S XtestSpellCap', {'rows': 8})
call VerifyScreenDump(buf, 'Test_spell_2', {})
" After adding word missing Cap in next line is updated
call term_sendkeys(buf, "3GANot\<Esc>")
call VerifyScreenDump(buf, 'Test_spell_3', {})
" Deleting a full stop removes missing Cap in next line
call term_sendkeys(buf, "5Gddk$x")
call VerifyScreenDump(buf, 'Test_spell_4', {})
" Undo also updates the next line (go to command line to remove message)
call term_sendkeys(buf, "u:\<Esc>")
call VerifyScreenDump(buf, 'Test_spell_5', {})
" clean up
call StopVimInTerminal(buf)
endfunc
func Test_spell_compatible()
CheckScreendump
let lines =<< trim END
call setline(1, [
\ "test "->repeat(20),
\ "",
\ "end",
\ ])
set spell cpo+=$
END
call writefile(lines, 'XtestSpellComp', 'D')
let buf = RunVimInTerminal('-S XtestSpellComp', {'rows': 8})
call term_sendkeys(buf, "51|C")
call VerifyScreenDump(buf, 'Test_spell_compatible_1', {})
call term_sendkeys(buf, "x")
call VerifyScreenDump(buf, 'Test_spell_compatible_2', {})
" clean up
call StopVimInTerminal(buf)
endfunc endfunc
let g:test_data_aff1 = [ let g:test_data_aff1 = [