aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/treesitter.txt3
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua19
-rw-r--r--src/nvim/api/extmark.c8
-rw-r--r--src/nvim/decoration.c12
-rw-r--r--src/nvim/decoration.h6
-rw-r--r--src/nvim/drawline.c5
-rw-r--r--src/nvim/extmark.c2
-rw-r--r--src/nvim/spell.c21
-rw-r--r--src/nvim/types.h3
-rw-r--r--test/functional/ui/decorations_spec.lua38
10 files changed, 88 insertions, 29 deletions
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 992e5ebe69..d6cd370ec7 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -432,6 +432,9 @@ capture marks comments as to be checked: >
(comment) @spell
<
+
+There is also `@nospell` which disables spellchecking regions with `@spell`.
+
*treesitter-highlight-conceal*
Treesitter highlighting supports |conceal| via the `conceal` metadata. By
convention, nodes to be concealed are captured as `@conceal`, but any capture
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 83a26aff13..f5e5ca1988 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -164,7 +164,7 @@ function TSHighlighter:get_query(lang)
end
---@private
-local function on_line_impl(self, buf, line, spell)
+local function on_line_impl(self, buf, line, is_spell_nav)
self.tree:for_each_tree(function(tstree, tree)
if not tstree then
return
@@ -201,17 +201,26 @@ local function on_line_impl(self, buf, line, spell)
local start_row, start_col, end_row, end_col = node:range()
local hl = highlighter_query.hl_cache[capture]
- local is_spell = highlighter_query:query().captures[capture] == 'spell'
+ local capture_name = highlighter_query:query().captures[capture]
+ local spell = nil
+ if capture_name == 'spell' then
+ spell = true
+ elseif capture_name == 'nospell' then
+ spell = false
+ end
+
+ -- Give nospell a higher priority so it always overrides spell captures.
+ local spell_pri_offset = capture_name == 'nospell' and 1 or 0
- if hl and end_row >= line and (not spell or is_spell) then
+ if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then
a.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
end_line = end_row,
end_col = end_col,
hl_group = hl,
ephemeral = true,
- priority = tonumber(metadata.priority) or 100, -- Low but leaves room below
+ priority = (tonumber(metadata.priority) or 100) + spell_pri_offset, -- Low but leaves room below
conceal = metadata.conceal,
- spell = is_spell,
+ spell = spell,
})
end
if start_row > line then
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index fee6876469..54eb7d9b6b 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -721,8 +721,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
bool ephemeral = false;
OPTION_TO_BOOL(ephemeral, ephemeral, false);
- OPTION_TO_BOOL(decor.spell, spell, false);
- if (decor.spell) {
+ if (opts->spell.type == kObjectTypeNil) {
+ decor.spell = kNone;
+ } else {
+ bool spell = false;
+ OPTION_TO_BOOL(spell, spell, false);
+ decor.spell = spell ? kTrue : kFalse;
has_decor = true;
}
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 19e99fa7a6..230d96a15f 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -69,7 +69,11 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
{
if (row2 >= row1) {
- if (!decor || decor->hl_id || decor_has_sign(decor) || decor->conceal || decor->spell) {
+ if (!decor
+ || decor->hl_id
+ || decor_has_sign(decor)
+ || decor->conceal
+ || decor->spell != kNone) {
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
}
}
@@ -309,7 +313,7 @@ next_mark:
bool conceal = 0;
int conceal_char = 0;
int conceal_attr = 0;
- bool spell = false;
+ TriState spell = kNone;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange item = kv_A(state->active, i);
@@ -343,8 +347,8 @@ next_mark:
conceal_attr = item.attr_id;
}
}
- if (active && item.decor.spell) {
- spell = true;
+ if (active && item.decor.spell != kNone) {
+ spell = item.decor.spell;
}
if ((item.start_row == state->row && item.start_col <= col)
&& decor_virt_pos(item.decor)
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 9ba621d7a4..8f016c103b 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -45,7 +45,7 @@ struct Decoration {
bool hl_eol;
bool virt_lines_above;
bool conceal;
- bool spell;
+ TriState spell;
// TODO(bfredl): style, etc
DecorPriority priority;
int col; // fixed col value, like win_col
@@ -61,7 +61,7 @@ struct Decoration {
bool ui_watched; // watched for win_extmark
};
#define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, \
- kHlModeUnknown, false, false, false, false, false, \
+ kHlModeUnknown, false, false, false, false, kNone, \
DECOR_PRIORITY_BASE, 0, 0, NULL, 0, 0, 0, 0, 0, false }
typedef struct {
@@ -91,7 +91,7 @@ typedef struct {
int conceal_char;
int conceal_attr;
- bool spell;
+ TriState spell;
} DecorState;
EXTERN DecorState decor_state INIT(= { 0 });
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index cb7d85a467..6d42b91507 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -33,6 +33,7 @@
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/syntax.h"
+#include "nvim/types.h"
#include "nvim/undo.h"
#include "nvim/window.h"
@@ -1722,9 +1723,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
decor_conceal = 2; // really??
}
- if (decor_state.spell) {
- can_spell = true;
- }
+ can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell);
}
// Check spelling (unless at the end of the line).
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index df87cc8ab6..015799be06 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -71,7 +71,7 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|| decor->conceal
|| decor_has_sign(decor)
|| decor->ui_watched
- || decor->spell) {
+ || decor->spell != kNone) {
decor_full = true;
decor = xmemdup(decor, sizeof *decor);
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index f24af5c3bf..b1daf4ed23 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1216,7 +1216,14 @@ static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum,
*decor_lnum = lnum;
}
decor_redraw_col(wp->w_buffer, col, col, false, &decor_state);
- return decor_state.spell;
+ return decor_state.spell == kTrue;
+}
+
+static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col)
+{
+ bool can_spell;
+ (void)syn_get_id(wp, lnum, col, false, &can_spell, false);
+ return can_spell;
}
/// Moves to the next spell error.
@@ -1346,15 +1353,9 @@ 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 = decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error);
-
- if (!can_spell) {
- if (has_syntax) {
- (void)syn_get_id(wp, lnum, col, false, &can_spell, false);
- } else {
- can_spell = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0;
- }
- }
+ 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));
if (!can_spell) {
attr = HLF_COUNT;
diff --git a/src/nvim/types.h b/src/nvim/types.h
index fb10bf21d9..d90c623955 100644
--- a/src/nvim/types.h
+++ b/src/nvim/types.h
@@ -45,6 +45,9 @@ typedef enum {
kTrue = 1,
} TriState;
+#define TRISTATE_TO_BOOL(val, \
+ default) ((val) == kTrue ? true : ((val) == kFalse ? false : (default)))
+
typedef struct Decoration Decoration;
#endif // NVIM_TYPES_H
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 5b62f5b3e1..489c33d8b1 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -176,7 +176,13 @@ describe('decorations providers', function()
beamtrace = {}
local function on_do(kind, ...)
if kind == 'win' or kind == 'spell' then
- a.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, end_col = 23, spell = true, ephemeral = true })
+ a.nvim_buf_set_extmark(0, ns, 0, 0, {
+ end_row = 2,
+ end_col = 23,
+ spell = true,
+ priority = 20,
+ ephemeral = true
+ })
end
table.insert(beamtrace, {kind, ...})
end
@@ -234,6 +240,36 @@ describe('decorations providers', function()
{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:~ }|
+ |
+ ]]}
+
+ -- 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 })
+
+ screen:expect{grid=[[
+ I am well written text. |
+ {15:i} am not capitalized. |
+ I am a {16:^speling} {16:mistakke}. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
end)
it('can predefine highlights', function()