From a803bff89c89cc63e549a3c791fa07d91d1106c8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 1 May 2023 12:30:55 +0800 Subject: [PATCH] fix(spell): extmark with spell=false should disable spell (#23400) --- src/nvim/spell.c | 21 +++- test/functional/ui/decorations_spec.lua | 125 +++++++++++-------- test/functional/ui/spell_spec.lua | 159 +++++++++++++++++++----- 3 files changed, 216 insertions(+), 89 deletions(-) diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 0784c4c8ff..d1d1b9180f 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1206,8 +1206,8 @@ static void decor_spell_nav_start(win_T *wp) decor_redraw_reset(wp, &decor_state); } -static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, int col, - char **decor_error) +static TriState 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); @@ -1215,7 +1215,7 @@ static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, *decor_lnum = lnum; } decor_redraw_col(wp, col, col, false, &decor_state); - return decor_state.spell == kTrue; + return decor_state.spell; } static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col) @@ -1352,9 +1352,18 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att : p - buf) > wp->w_cursor.col)) { col = (colnr_T)(p - buf); - bool can_spell = (!has_syntax && (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0) - || decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error) - || (has_syntax && can_syn_spell(wp, lnum, col)); + bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0; + bool can_spell = !no_plain_buffer; + switch (decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error)) { + case kTrue: + can_spell = true; break; + case kFalse: + can_spell = false; break; + case kNone: + if (has_syntax) { + can_spell = can_syn_spell(wp, lnum, col); + } + } if (!can_spell) { attr = HLF_COUNT; diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 5792c9703d..f531878bc6 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua local exec = helpers.exec local expect_events = helpers.expect_events local meths = helpers.meths +local curbufmeths = helpers.curbufmeths local command = helpers.command describe('decorations providers', function() @@ -31,8 +32,9 @@ describe('decorations providers', function() [12] = {foreground = tonumber('0x990000')}; [13] = {background = Screen.colors.LightBlue}; [14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue}; - [15] = {special = Screen.colors.Blue1, undercurl = true}, + [15] = {special = Screen.colors.Blue, undercurl = true}, [16] = {special = Screen.colors.Red, undercurl = true}, + [17] = {foreground = Screen.colors.Red}, } end) @@ -201,14 +203,14 @@ describe('decorations providers', function() feed "gg0" screen:expect{grid=[[ - ^I am well written text. | - {15:i} am not capitalized. | - I am a {16:speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + ^I am well written text. | + {15:i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} feed "]s" @@ -216,14 +218,14 @@ describe('decorations providers', function() { "spell", 1000, 1, 1, 0, 1, -1 }; } screen:expect{grid=[[ - I am well written text. | - {15:^i} am not capitalized. | - I am a {16:speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + {15:^i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} feed "]s" @@ -231,43 +233,68 @@ describe('decorations providers', function() { "spell", 1000, 1, 2, 7, 2, -1 }; } screen:expect{grid=[[ - I am well written text. | - {15:i} am not capitalized. | - I am a {16:^speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]} - - -- spell=false with lower priority doesn't disable spell - local ns = meths.create_namespace "spell" - local id = helpers.curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) - - screen:expect{grid=[[ - I am well written text. | - i am not capitalized. | - I am a ^speling mistakke. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} -- spell=false with higher priority does disable spell - helpers.curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) + local ns = meths.create_namespace "spell" + local id = curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) screen:expect{grid=[[ - I am well written text. | - {15:i} am not capitalized. | - I am a {16:^speling} {16:mistakke}. | - | - {1:~ }| - {1:~ }| - {1:~ }| - | + I am well written text. | + i am not capitalized. | + I am a ^speling mistakke. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed "]s" + screen:expect{grid=[[ + I am well written text. | + i am not capitalized. | + I am a ^speling mistakke. | + | + {1:~ }| + {1:~ }| + {1:~ }| + {17:search hit BOTTOM, continuing at TOP} | + ]]} + command('echo ""') + + -- spell=false with lower priority doesn't disable spell + curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) + + screen:expect{grid=[[ + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed "]s" + screen:expect{grid=[[ + I am well written text. | + {15:i} am not capitalized. | + I am a {16:speling} {16:^mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | ]]} end) diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index 361f83d1ce..15819aef40 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -6,6 +6,8 @@ local clear = helpers.clear local feed = helpers.feed local insert = helpers.insert local command = helpers.command +local meths = helpers.meths +local curbufmeths = helpers.curbufmeths local is_os = helpers.is_os describe("'spell'", function() @@ -18,11 +20,13 @@ describe("'spell'", function() screen:set_default_attr_ids( { [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {special = Screen.colors.Red, undercurl = true}, - [2] = {special = Screen.colors.Blue1, undercurl = true}, + [2] = {special = Screen.colors.Blue, undercurl = true}, [3] = {foreground = tonumber('0x6a0dad')}, [4] = {foreground = Screen.colors.Magenta}, [5] = {bold = true, foreground = Screen.colors.SeaGreen}, [6] = {foreground = Screen.colors.Red}, + [7] = {foreground = Screen.colors.Blue}, + [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true}, }) end) @@ -74,19 +78,57 @@ describe("'spell'", function() ]]) end) - it('"noplainbuffer" and syntax #20385', function() + it('extmarks, "noplainbuffer" and syntax #20385 #23398', function() command('set filetype=c') command('syntax on') command('set spell') insert([[ #include - bool func(void);]]) + bool func(void); + // I am a speling mistakke]]) + feed('ge') screen:expect([[ {3:#include }{4:} | - {5:bool} func({5:void})^; | + {5:bool} func({5:void}); | + {7:// I am a }{8:spelin^g}{7: }{8:mistakke} | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| + | + ]]) + feed(']s') + screen:expect([[ + {3:#include }{4:} | + {5:bool} func({5:void}); | + {7:// I am a }{8:speling}{7: }{8:^mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(']s') + screen:expect([[ + {3:#include }{4:} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit BOTTOM, continuing at TOP} | + ]]) + command('echo ""') + local ns = meths.create_namespace("spell") + -- extmark with spell=true enables spell + local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true }) + screen:expect([[ + {3:#include }{4:} | + {5:bool} {1:func}({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| {0:~ }| {0:~ }| | @@ -94,73 +136,122 @@ describe("'spell'", function() feed('[s') screen:expect([[ {3:#include }{4:} | - {5:bool} func({5:void})^; | + {5:bool} {1:^func}({5:void}); | + {7:// I am a }{8:speling}{7: }{8:mistakke} | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| + | + ]]) + curbufmeths.del_extmark(ns, id) + -- extmark with spell=false disables spell + id = curbufmeths.set_extmark(ns, 2, 18, { end_row = 2, end_col = 26, spell = false }) + screen:expect([[ + {3:#include }{4:} | + {5:bool} ^func({5:void}); | + {7:// I am a }{8:speling}{7: mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed('[s') + screen:expect([[ + {3:#include }{4:} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: mistakke} | + {0:~ }| + {0:~ }| {0:~ }| {0:~ }| {6:search hit TOP, continuing at BOTTOM} | ]]) - -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled - command('set spelloptions+=noplainbuffer') - screen:expect_unchanged() + command('echo ""') + curbufmeths.del_extmark(ns, id) + screen:expect([[ + {3:#include }{4:} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) feed(']s') screen:expect([[ {3:#include }{4:} | - {5:bool} func({5:void})^; | + {5:bool} func({5:void}); | + {7:// I am a }{8:speling}{7: }{8:^mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| + | + ]]) + -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled + command('set spelloptions+=noplainbuffer') + screen:expect_unchanged() + feed('[s') + screen:expect([[ + {3:#include }{4:} | + {5:bool} func({5:void}); | + {7:// I am a }{8:^speling}{7: }{8:mistakke} | {0:~ }| - {6:search hit BOTTOM, continuing at TOP} | + {0:~ }| + {0:~ }| + {0:~ }| + | ]]) -- no spellchecking with "noplainbuffer" and syntax disabled command('syntax off') screen:expect([[ #include | - bool func(void)^; | + bool func(void); | + // I am a ^speling mistakke | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| + | + ]]) + feed(']s') + screen:expect([[ + #include | + bool func(void); | + // I am a ^speling mistakke | + {0:~ }| + {0:~ }| {0:~ }| {0:~ }| {6:search hit BOTTOM, continuing at TOP} | ]]) - feed('[s') - screen:expect([[ - #include | - bool func(void)^; | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {6:search hit TOP, continuing at BOTTOM} | - ]]) + command('echo ""') -- everything is spellchecked without "noplainbuffer" with syntax disabled command('set spelloptions&') screen:expect([[ #include <{1:stdbool}.h> | - {1:bool} {1:func}(void)^; | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {6:search hit TOP, continuing at BOTTOM} | - ]]) - feed(']s') - screen:expect([[ - #include <{1:^stdbool}.h> | {1:bool} {1:func}(void); | + // I am a {1:^speling} {1:mistakke} | {0:~ }| {0:~ }| {0:~ }| {0:~ }| + | + ]]) + feed('[s') + screen:expect([[ + #include <{1:stdbool}.h> | + {1:bool} {1:^func}(void); | + // I am a {1:speling} {1:mistakke} | {0:~ }| - {6:search hit BOTTOM, continuing at TOP} | + {0:~ }| + {0:~ }| + {0:~ }| + | ]]) end) + end)