mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #21042 from neovim/backport-20178-to-release-0.8
[Backport release-0.8] feat(extmarks): allow preventing spellchecking with spell = false
This commit is contained in:
@@ -432,6 +432,9 @@ capture marks comments as to be checked: >
|
|||||||
|
|
||||||
(comment) @spell
|
(comment) @spell
|
||||||
<
|
<
|
||||||
|
|
||||||
|
There is also `@nospell` which disables spellchecking regions with `@spell`.
|
||||||
|
|
||||||
*treesitter-highlight-conceal*
|
*treesitter-highlight-conceal*
|
||||||
Treesitter highlighting supports |conceal| via the `conceal` metadata. By
|
Treesitter highlighting supports |conceal| via the `conceal` metadata. By
|
||||||
convention, nodes to be concealed are captured as `@conceal`, but any capture
|
convention, nodes to be concealed are captured as `@conceal`, but any capture
|
||||||
|
@@ -164,7 +164,7 @@ function TSHighlighter:get_query(lang)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@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)
|
self.tree:for_each_tree(function(tstree, tree)
|
||||||
if not tstree then
|
if not tstree then
|
||||||
return
|
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 start_row, start_col, end_row, end_col = node:range()
|
||||||
local hl = highlighter_query.hl_cache[capture]
|
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
|
||||||
|
|
||||||
if hl and end_row >= line and (not spell or is_spell) then
|
-- 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 is_spell_nav or spell ~= nil) then
|
||||||
a.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
|
a.nvim_buf_set_extmark(buf, ns, start_row, start_col, {
|
||||||
end_line = end_row,
|
end_line = end_row,
|
||||||
end_col = end_col,
|
end_col = end_col,
|
||||||
hl_group = hl,
|
hl_group = hl,
|
||||||
ephemeral = true,
|
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,
|
conceal = metadata.conceal,
|
||||||
spell = is_spell,
|
spell = spell,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if start_row > line then
|
if start_row > line then
|
||||||
|
@@ -721,8 +721,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
bool ephemeral = false;
|
bool ephemeral = false;
|
||||||
OPTION_TO_BOOL(ephemeral, ephemeral, false);
|
OPTION_TO_BOOL(ephemeral, ephemeral, false);
|
||||||
|
|
||||||
OPTION_TO_BOOL(decor.spell, spell, false);
|
if (opts->spell.type == kObjectTypeNil) {
|
||||||
if (decor.spell) {
|
decor.spell = kNone;
|
||||||
|
} else {
|
||||||
|
bool spell = false;
|
||||||
|
OPTION_TO_BOOL(spell, spell, false);
|
||||||
|
decor.spell = spell ? kTrue : kFalse;
|
||||||
has_decor = true;
|
has_decor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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)
|
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||||
{
|
{
|
||||||
if (row2 >= row1) {
|
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);
|
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +314,7 @@ next_mark:
|
|||||||
bool conceal = 0;
|
bool conceal = 0;
|
||||||
int conceal_char = 0;
|
int conceal_char = 0;
|
||||||
int conceal_attr = 0;
|
int conceal_attr = 0;
|
||||||
bool spell = false;
|
TriState spell = kNone;
|
||||||
|
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
DecorRange item = kv_A(state->active, i);
|
DecorRange item = kv_A(state->active, i);
|
||||||
@@ -344,8 +348,8 @@ next_mark:
|
|||||||
conceal_attr = item.attr_id;
|
conceal_attr = item.attr_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (active && item.decor.spell) {
|
if (active && item.decor.spell != kNone) {
|
||||||
spell = true;
|
spell = item.decor.spell;
|
||||||
}
|
}
|
||||||
if ((item.start_row == state->row && item.start_col <= col)
|
if ((item.start_row == state->row && item.start_col <= col)
|
||||||
&& decor_virt_pos(item.decor)
|
&& decor_virt_pos(item.decor)
|
||||||
|
@@ -46,7 +46,7 @@ struct Decoration {
|
|||||||
bool hl_eol;
|
bool hl_eol;
|
||||||
bool virt_lines_above;
|
bool virt_lines_above;
|
||||||
bool conceal;
|
bool conceal;
|
||||||
bool spell;
|
TriState spell;
|
||||||
// TODO(bfredl): style, etc
|
// TODO(bfredl): style, etc
|
||||||
DecorPriority priority;
|
DecorPriority priority;
|
||||||
int col; // fixed col value, like win_col
|
int col; // fixed col value, like win_col
|
||||||
@@ -62,7 +62,7 @@ struct Decoration {
|
|||||||
bool ui_watched; // watched for win_extmark
|
bool ui_watched; // watched for win_extmark
|
||||||
};
|
};
|
||||||
#define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, \
|
#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 }
|
DECOR_PRIORITY_BASE, 0, 0, NULL, 0, 0, 0, 0, 0, false }
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -92,7 +92,7 @@ typedef struct {
|
|||||||
int conceal_char;
|
int conceal_char;
|
||||||
int conceal_attr;
|
int conceal_attr;
|
||||||
|
|
||||||
bool spell;
|
TriState spell;
|
||||||
} DecorState;
|
} DecorState;
|
||||||
|
|
||||||
EXTERN DecorState decor_state INIT(= { 0 });
|
EXTERN DecorState decor_state INIT(= { 0 });
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "nvim/spell.h"
|
#include "nvim/spell.h"
|
||||||
#include "nvim/state.h"
|
#include "nvim/state.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
|
#include "nvim/types.h"
|
||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
|
||||||
@@ -1719,9 +1720,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
decor_conceal = 2; // really??
|
decor_conceal = 2; // really??
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decor_state.spell) {
|
can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell);
|
||||||
can_spell = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check spelling (unless at the end of the line).
|
// Check spelling (unless at the end of the line).
|
||||||
|
@@ -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->conceal
|
||||||
|| decor_has_sign(decor)
|
|| decor_has_sign(decor)
|
||||||
|| decor->ui_watched
|
|| decor->ui_watched
|
||||||
|| decor->spell) {
|
|| decor->spell != kNone) {
|
||||||
decor_full = true;
|
decor_full = true;
|
||||||
decor = xmemdup(decor, sizeof *decor);
|
decor = xmemdup(decor, sizeof *decor);
|
||||||
}
|
}
|
||||||
|
@@ -1214,7 +1214,14 @@ static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum,
|
|||||||
*decor_lnum = lnum;
|
*decor_lnum = lnum;
|
||||||
}
|
}
|
||||||
decor_redraw_col(wp->w_buffer, col, col, false, &decor_state);
|
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.
|
/// Moves to the next spell error.
|
||||||
@@ -1344,15 +1351,9 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
: p - buf) > wp->w_cursor.col)) {
|
: p - buf) > wp->w_cursor.col)) {
|
||||||
col = (colnr_T)(p - buf);
|
col = (colnr_T)(p - buf);
|
||||||
|
|
||||||
bool can_spell = decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error);
|
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)
|
||||||
if (!can_spell) {
|
|| (has_syntax && can_syn_spell(wp, lnum, col));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!can_spell) {
|
if (!can_spell) {
|
||||||
attr = HLF_COUNT;
|
attr = HLF_COUNT;
|
||||||
|
@@ -45,6 +45,9 @@ typedef enum {
|
|||||||
kTrue = 1,
|
kTrue = 1,
|
||||||
} TriState;
|
} TriState;
|
||||||
|
|
||||||
|
#define TRISTATE_TO_BOOL(val, \
|
||||||
|
default) ((val) == kTrue ? true : ((val) == kFalse ? false : (default)))
|
||||||
|
|
||||||
typedef struct Decoration Decoration;
|
typedef struct Decoration Decoration;
|
||||||
|
|
||||||
#endif // NVIM_TYPES_H
|
#endif // NVIM_TYPES_H
|
||||||
|
@@ -176,7 +176,13 @@ describe('decorations providers', function()
|
|||||||
beamtrace = {}
|
beamtrace = {}
|
||||||
local function on_do(kind, ...)
|
local function on_do(kind, ...)
|
||||||
if kind == 'win' or kind == 'spell' then
|
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
|
end
|
||||||
table.insert(beamtrace, {kind, ...})
|
table.insert(beamtrace, {kind, ...})
|
||||||
end
|
end
|
||||||
@@ -234,6 +240,36 @@ describe('decorations providers', function()
|
|||||||
{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:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
-- 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)
|
end)
|
||||||
|
|
||||||
it('can predefine highlights', function()
|
it('can predefine highlights', function()
|
||||||
|
Reference in New Issue
Block a user