mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #19419 from vigoux/extmark_spell
Co-authored-by: Lewis Russell <lewis6991@gmail.com> Co-authored-by: Björn Linse <bjorn.linse@gmail.com>
This commit is contained in:
commit
84d1094958
@ -2646,6 +2646,8 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
|
|||||||
When a character is supplied it is used as |:syn-cchar|.
|
When a character is supplied it is used as |:syn-cchar|.
|
||||||
"hl_group" is used as highlight for the cchar if provided,
|
"hl_group" is used as highlight for the cchar if provided,
|
||||||
otherwise it defaults to |hl-Conceal|.
|
otherwise it defaults to |hl-Conceal|.
|
||||||
|
• spell: boolean indicating that spell checking should be
|
||||||
|
performed within this extmark
|
||||||
• ui_watched: boolean that indicates the mark should be
|
• ui_watched: boolean that indicates the mark should be
|
||||||
drawn by a UI. When set, the UI will receive win_extmark
|
drawn by a UI. When set, the UI will receive win_extmark
|
||||||
events. Note: the mark is positioned by virt_text
|
events. Note: the mark is positioned by virt_text
|
||||||
@ -2677,7 +2679,7 @@ nvim_get_namespaces() *nvim_get_namespaces()*
|
|||||||
dict that maps from names to namespace ids.
|
dict that maps from names to namespace ids.
|
||||||
|
|
||||||
*nvim_set_decoration_provider()*
|
*nvim_set_decoration_provider()*
|
||||||
nvim_set_decoration_provider({ns_id}, {opts})
|
nvim_set_decoration_provider({ns_id}, {*opts})
|
||||||
Set or change decoration provider for a namespace
|
Set or change decoration provider for a namespace
|
||||||
|
|
||||||
This is a very general purpose interface for having lua callbacks being
|
This is a very general purpose interface for having lua callbacks being
|
||||||
@ -2709,7 +2711,7 @@ nvim_set_decoration_provider({ns_id}, {opts})
|
|||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{ns_id} Namespace id from |nvim_create_namespace()|
|
{ns_id} Namespace id from |nvim_create_namespace()|
|
||||||
{opts} Callbacks invoked during redraw:
|
{opts} Table of callbacks:
|
||||||
• on_start: called first on each screen redraw ["start",
|
• on_start: called first on each screen redraw ["start",
|
||||||
tick]
|
tick]
|
||||||
• on_buf: called for each buffer being redrawn (before window
|
• on_buf: called for each buffer being redrawn (before window
|
||||||
|
@ -5871,10 +5871,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
'spelloptions' 'spo' string (default "")
|
'spelloptions' 'spo' string (default "")
|
||||||
local to buffer
|
local to buffer
|
||||||
A comma-separated list of options for spell checking:
|
A comma-separated list of options for spell checking:
|
||||||
camel When a word is CamelCased, assume "Cased" is a
|
camel When a word is CamelCased, assume "Cased" is a
|
||||||
separate word: every upper-case character in a word
|
separate word: every upper-case character in a word
|
||||||
that comes after a lower case character indicates the
|
that comes after a lower case character indicates the
|
||||||
start of a new word.
|
start of a new word.
|
||||||
|
noplainbuffer Only spellcheck a buffer when 'syntax' is enabled, or
|
||||||
|
or when extmarks are set within the buffer. Only
|
||||||
|
designated regions of the buffer are spellchecked in
|
||||||
|
this case.
|
||||||
|
|
||||||
*'spellsuggest'* *'sps'*
|
*'spellsuggest'* *'sps'*
|
||||||
'spellsuggest' 'sps' string (default "best")
|
'spellsuggest' 'sps' string (default "best")
|
||||||
|
@ -97,6 +97,7 @@ function TSHighlighter.new(tree, opts)
|
|||||||
if vim.g.syntax_on ~= 1 then
|
if vim.g.syntax_on ~= 1 then
|
||||||
vim.api.nvim_command('runtime! syntax/synload.vim')
|
vim.api.nvim_command('runtime! syntax/synload.vim')
|
||||||
end
|
end
|
||||||
|
vim.bo[self.bufnr].spelloptions = 'noplainbuffer'
|
||||||
|
|
||||||
self.tree:parse()
|
self.tree:parse()
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ function TSHighlighter:get_query(lang)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
local function on_line_impl(self, buf, line)
|
local function on_line_impl(self, buf, line, spell)
|
||||||
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
|
||||||
@ -193,7 +194,9 @@ local function on_line_impl(self, buf, line)
|
|||||||
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]
|
||||||
|
|
||||||
if hl and end_row >= line then
|
local is_spell = highlighter_query:query().captures[capture] == 'spell'
|
||||||
|
|
||||||
|
if hl and end_row >= line and (not spell or is_spell) 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,
|
||||||
@ -201,6 +204,7 @@ local function on_line_impl(self, buf, line)
|
|||||||
ephemeral = true,
|
ephemeral = true,
|
||||||
priority = tonumber(metadata.priority) or 100, -- Low but leaves room below
|
priority = tonumber(metadata.priority) or 100, -- Low but leaves room below
|
||||||
conceal = metadata.conceal,
|
conceal = metadata.conceal,
|
||||||
|
spell = is_spell,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if start_row > line then
|
if start_row > line then
|
||||||
@ -217,7 +221,21 @@ function TSHighlighter._on_line(_, _win, buf, line, _)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
on_line_impl(self, buf, line)
|
on_line_impl(self, buf, line, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _)
|
||||||
|
local self = TSHighlighter.active[buf]
|
||||||
|
if not self then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
self:reset_highlight_state()
|
||||||
|
|
||||||
|
for row = srow, erow do
|
||||||
|
on_line_impl(self, buf, row, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
@ -244,6 +262,7 @@ a.nvim_set_decoration_provider(ns, {
|
|||||||
on_buf = TSHighlighter._on_buf,
|
on_buf = TSHighlighter._on_buf,
|
||||||
on_win = TSHighlighter._on_win,
|
on_win = TSHighlighter._on_win,
|
||||||
on_line = TSHighlighter._on_line,
|
on_line = TSHighlighter._on_line,
|
||||||
|
_on_spell_nav = TSHighlighter._on_spell_nav,
|
||||||
})
|
})
|
||||||
|
|
||||||
return TSHighlighter
|
return TSHighlighter
|
||||||
|
@ -101,6 +101,7 @@
|
|||||||
[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket
|
[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket
|
||||||
|
|
||||||
(string_literal) @string
|
(string_literal) @string
|
||||||
|
(string_literal) @spell
|
||||||
(system_lib_string) @string
|
(system_lib_string) @string
|
||||||
|
|
||||||
(null) @constant.builtin
|
(null) @constant.builtin
|
||||||
@ -148,6 +149,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(comment) @comment
|
(comment) @comment
|
||||||
|
(comment) @spell
|
||||||
|
|
||||||
;; Parameters
|
;; Parameters
|
||||||
(parameter_declaration
|
(parameter_declaration
|
||||||
|
@ -181,12 +181,14 @@
|
|||||||
;; Others
|
;; Others
|
||||||
|
|
||||||
(comment) @comment
|
(comment) @comment
|
||||||
|
(comment) @spell
|
||||||
|
|
||||||
(hash_bang_line) @comment
|
(hash_bang_line) @comment
|
||||||
|
|
||||||
(number) @number
|
(number) @number
|
||||||
|
|
||||||
(string) @string
|
(string) @string
|
||||||
|
(string) @spell
|
||||||
|
|
||||||
;; Error
|
;; Error
|
||||||
(ERROR) @error
|
(ERROR) @error
|
||||||
|
@ -162,9 +162,11 @@
|
|||||||
;; Literals
|
;; Literals
|
||||||
|
|
||||||
(string_literal) @string
|
(string_literal) @string
|
||||||
|
(string_literal) @spell
|
||||||
(integer_literal) @number
|
(integer_literal) @number
|
||||||
(float_literal) @float
|
(float_literal) @float
|
||||||
(comment) @comment
|
(comment) @comment
|
||||||
|
(comment) @spell
|
||||||
(pattern) @string.special
|
(pattern) @string.special
|
||||||
(pattern_multi) @string.regex
|
(pattern_multi) @string.regex
|
||||||
(filename) @string
|
(filename) @string
|
||||||
|
@ -473,6 +473,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
/// When a character is supplied it is used as |:syn-cchar|.
|
/// When a character is supplied it is used as |:syn-cchar|.
|
||||||
/// "hl_group" is used as highlight for the cchar if provided,
|
/// "hl_group" is used as highlight for the cchar if provided,
|
||||||
/// otherwise it defaults to |hl-Conceal|.
|
/// otherwise it defaults to |hl-Conceal|.
|
||||||
|
/// - spell: boolean indicating that spell checking should be
|
||||||
|
/// performed within this extmark
|
||||||
/// - ui_watched: boolean that indicates the mark should be drawn
|
/// - ui_watched: boolean that indicates the mark should be drawn
|
||||||
/// by a UI. When set, the UI will receive win_extmark events.
|
/// by a UI. When set, the UI will receive win_extmark events.
|
||||||
/// Note: the mark is positioned by virt_text attributes. Can be
|
/// Note: the mark is positioned by virt_text attributes. Can be
|
||||||
@ -719,6 +721,11 @@ 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 (decor.spell) {
|
||||||
|
has_decor = true;
|
||||||
|
}
|
||||||
|
|
||||||
OPTION_TO_BOOL(decor.ui_watched, ui_watched, false);
|
OPTION_TO_BOOL(decor.ui_watched, ui_watched, false);
|
||||||
if (decor.ui_watched) {
|
if (decor.ui_watched) {
|
||||||
has_decor = true;
|
has_decor = true;
|
||||||
@ -972,20 +979,21 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
|
|||||||
/// for the moment.
|
/// for the moment.
|
||||||
///
|
///
|
||||||
/// @param ns_id Namespace id from |nvim_create_namespace()|
|
/// @param ns_id Namespace id from |nvim_create_namespace()|
|
||||||
/// @param opts Callbacks invoked during redraw:
|
/// @param opts Table of callbacks:
|
||||||
/// - on_start: called first on each screen redraw
|
/// - on_start: called first on each screen redraw
|
||||||
/// ["start", tick]
|
/// ["start", tick]
|
||||||
/// - on_buf: called for each buffer being redrawn (before window
|
/// - on_buf: called for each buffer being redrawn (before
|
||||||
/// callbacks)
|
/// window callbacks)
|
||||||
/// ["buf", bufnr, tick]
|
/// ["buf", bufnr, tick]
|
||||||
/// - on_win: called when starting to redraw a specific window.
|
/// - on_win: called when starting to redraw a
|
||||||
|
/// specific window.
|
||||||
/// ["win", winid, bufnr, topline, botline_guess]
|
/// ["win", winid, bufnr, topline, botline_guess]
|
||||||
/// - on_line: called for each buffer line being redrawn. (The
|
/// - on_line: called for each buffer line being redrawn.
|
||||||
/// interaction with fold lines is subject to change)
|
/// (The interaction with fold lines is subject to change)
|
||||||
/// ["win", winid, bufnr, row]
|
/// ["win", winid, bufnr, row]
|
||||||
/// - on_end: called at the end of a redraw cycle
|
/// - on_end: called at the end of a redraw cycle
|
||||||
/// ["end", tick]
|
/// ["end", tick]
|
||||||
void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Error *err)
|
void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *opts, Error *err)
|
||||||
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
|
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
|
||||||
{
|
{
|
||||||
DecorProvider *p = get_decor_provider((NS)ns_id, true);
|
DecorProvider *p = get_decor_provider((NS)ns_id, true);
|
||||||
@ -997,37 +1005,32 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
Object *source;
|
||||||
LuaRef *dest;
|
LuaRef *dest;
|
||||||
} cbs[] = {
|
} cbs[] = {
|
||||||
{ "on_start", &p->redraw_start },
|
{ "on_start", &opts->on_start, &p->redraw_start },
|
||||||
{ "on_buf", &p->redraw_buf },
|
{ "on_buf", &opts->on_buf, &p->redraw_buf },
|
||||||
{ "on_win", &p->redraw_win },
|
{ "on_win", &opts->on_win, &p->redraw_win },
|
||||||
{ "on_line", &p->redraw_line },
|
{ "on_line", &opts->on_line, &p->redraw_line },
|
||||||
{ "on_end", &p->redraw_end },
|
{ "on_end", &opts->on_end, &p->redraw_end },
|
||||||
{ "_on_hl_def", &p->hl_def },
|
{ "_on_hl_def", &opts->_on_hl_def, &p->hl_def },
|
||||||
{ NULL, NULL },
|
{ "_on_spell_nav", &opts->_on_spell_nav, &p->spell_nav },
|
||||||
|
{ NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < opts.size; i++) {
|
for (size_t i = 0; cbs[i].source && cbs[i].dest && cbs[i].name; i++) {
|
||||||
String k = opts.items[i].key;
|
Object *v = cbs[i].source;
|
||||||
Object *v = &opts.items[i].value;
|
if (v->type == kObjectTypeNil) {
|
||||||
size_t j;
|
continue;
|
||||||
for (j = 0; cbs[j].name && cbs[j].dest; j++) {
|
|
||||||
if (strequal(cbs[j].name, k.data)) {
|
|
||||||
if (v->type != kObjectTypeLuaRef) {
|
|
||||||
api_set_error(err, kErrorTypeValidation,
|
|
||||||
"%s is not a function", cbs[j].name);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
*(cbs[j].dest) = v->data.luaref;
|
|
||||||
v->data.luaref = LUA_NOREF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!cbs[j].name) {
|
|
||||||
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
|
if (v->type != kObjectTypeLuaRef) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
"%s is not a function", cbs[i].name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
*(cbs[i].dest) = v->data.luaref;
|
||||||
|
v->data.luaref = LUA_NOREF;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->active = true;
|
p->active = true;
|
||||||
|
@ -2,6 +2,15 @@ return {
|
|||||||
context = {
|
context = {
|
||||||
"types";
|
"types";
|
||||||
};
|
};
|
||||||
|
set_decoration_provider = {
|
||||||
|
"on_start";
|
||||||
|
"on_buf";
|
||||||
|
"on_win";
|
||||||
|
"on_line";
|
||||||
|
"on_end";
|
||||||
|
"_on_hl_def";
|
||||||
|
"_on_spell_nav";
|
||||||
|
};
|
||||||
set_extmark = {
|
set_extmark = {
|
||||||
"id";
|
"id";
|
||||||
"end_line";
|
"end_line";
|
||||||
@ -28,6 +37,7 @@ return {
|
|||||||
"line_hl_group";
|
"line_hl_group";
|
||||||
"cursorline_hl_group";
|
"cursorline_hl_group";
|
||||||
"conceal";
|
"conceal";
|
||||||
|
"spell";
|
||||||
"ui_watched";
|
"ui_watched";
|
||||||
};
|
};
|
||||||
keymap = {
|
keymap = {
|
||||||
|
@ -462,6 +462,9 @@ typedef struct {
|
|||||||
char *b_p_spf; // 'spellfile'
|
char *b_p_spf; // 'spellfile'
|
||||||
char *b_p_spl; // 'spelllang'
|
char *b_p_spl; // 'spelllang'
|
||||||
char *b_p_spo; // 'spelloptions'
|
char *b_p_spo; // 'spelloptions'
|
||||||
|
#define SPO_CAMEL 0x1
|
||||||
|
#define SPO_NPBUFFER 0x2
|
||||||
|
unsigned b_p_spo_flags; // 'spelloptions' flags
|
||||||
int b_cjk; // all CJK letters as OK
|
int b_cjk; // all CJK letters as OK
|
||||||
uint8_t b_syn_chartab[32]; // syntax iskeyword option
|
uint8_t b_syn_chartab[32]; // syntax iskeyword option
|
||||||
char *b_syn_isk; // iskeyword option
|
char *b_syn_isk; // iskeyword option
|
||||||
|
@ -69,7 +69,7 @@ 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) {
|
if (!decor || decor->hl_id || decor_has_sign(decor) || decor->conceal || decor->spell) {
|
||||||
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
|
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +116,11 @@ void decor_free(Decoration *decor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decor_state_free(DecorState *state)
|
||||||
|
{
|
||||||
|
xfree(state->active.items);
|
||||||
|
}
|
||||||
|
|
||||||
void clear_virttext(VirtText *text)
|
void clear_virttext(VirtText *text)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < kv_size(*text); i++) {
|
for (size_t i = 0; i < kv_size(*text); i++) {
|
||||||
@ -306,6 +311,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;
|
||||||
|
|
||||||
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);
|
||||||
@ -339,6 +345,9 @@ next_mark:
|
|||||||
conceal_attr = item.attr_id;
|
conceal_attr = item.attr_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (active && item.decor.spell) {
|
||||||
|
spell = true;
|
||||||
|
}
|
||||||
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)
|
||||||
&& item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) {
|
&& item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) {
|
||||||
@ -355,6 +364,7 @@ next_mark:
|
|||||||
state->conceal = conceal;
|
state->conceal = conceal;
|
||||||
state->conceal_char = conceal_char;
|
state->conceal_char = conceal_char;
|
||||||
state->conceal_attr = conceal_attr;
|
state->conceal_attr = conceal_attr;
|
||||||
|
state->spell = spell;
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ struct Decoration {
|
|||||||
bool hl_eol;
|
bool hl_eol;
|
||||||
bool virt_lines_above;
|
bool virt_lines_above;
|
||||||
bool conceal;
|
bool conceal;
|
||||||
|
bool 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
|
||||||
@ -61,8 +62,8 @@ 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, DECOR_PRIORITY_BASE, \
|
kHlModeUnknown, false, false, false, false, false, \
|
||||||
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 {
|
||||||
int start_row;
|
int start_row;
|
||||||
@ -90,6 +91,8 @@ typedef struct {
|
|||||||
bool conceal;
|
bool conceal;
|
||||||
int conceal_char;
|
int conceal_char;
|
||||||
int conceal_attr;
|
int conceal_attr;
|
||||||
|
|
||||||
|
bool spell;
|
||||||
} DecorState;
|
} DecorState;
|
||||||
|
|
||||||
EXTERN DecorState decor_state INIT(= { 0 });
|
EXTERN DecorState decor_state INIT(= { 0 });
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/decoration_provider.h"
|
#include "nvim/decoration_provider.h"
|
||||||
#include "nvim/highlight.h"
|
#include "nvim/highlight.h"
|
||||||
|
#include "nvim/lib/kvec.h"
|
||||||
#include "nvim/lua/executor.h"
|
#include "nvim/lua/executor.h"
|
||||||
|
|
||||||
static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
|
static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
|
||||||
@ -14,7 +15,7 @@ static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE;
|
|||||||
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
||||||
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
|
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
|
||||||
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
||||||
LUA_NOREF, -1, false }
|
LUA_NOREF, -1, false, false }
|
||||||
|
|
||||||
static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args,
|
static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args,
|
||||||
bool default_true, char **perr)
|
bool default_true, char **perr)
|
||||||
@ -47,11 +48,33 @@ static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref, Array
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decor_providers_invoke_spell(win_T *wp, int start_row, int start_col, int end_row, int end_col,
|
||||||
|
char **err)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < kv_size(decor_providers); i++) {
|
||||||
|
DecorProvider *p = &kv_A(decor_providers, i);
|
||||||
|
if (!p->active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->spell_nav != LUA_NOREF) {
|
||||||
|
MAXSIZE_TEMP_ARRAY(args, 6);
|
||||||
|
ADD_C(args, INTEGER_OBJ(wp->handle));
|
||||||
|
ADD_C(args, INTEGER_OBJ(wp->w_buffer->handle));
|
||||||
|
ADD_C(args, INTEGER_OBJ(start_row));
|
||||||
|
ADD_C(args, INTEGER_OBJ(start_col));
|
||||||
|
ADD_C(args, INTEGER_OBJ(end_row));
|
||||||
|
ADD_C(args, INTEGER_OBJ(end_col));
|
||||||
|
decor_provider_invoke(p->ns_id, "spell", p->spell_nav, args, true, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// For each provider invoke the 'start' callback
|
/// For each provider invoke the 'start' callback
|
||||||
///
|
///
|
||||||
/// @param[out] providers Decoration providers
|
/// @param[out] providers Decoration providers
|
||||||
/// @param[out] err Provider err
|
/// @param[out] err Provider err
|
||||||
void decor_providers_start(DecorProviders *providers, int type, char **err)
|
void decor_providers_start(DecorProviders *providers, char **err)
|
||||||
{
|
{
|
||||||
kvi_init(*providers);
|
kvi_init(*providers);
|
||||||
|
|
||||||
@ -65,7 +88,6 @@ void decor_providers_start(DecorProviders *providers, int type, char **err)
|
|||||||
if (p->redraw_start != LUA_NOREF) {
|
if (p->redraw_start != LUA_NOREF) {
|
||||||
MAXSIZE_TEMP_ARRAY(args, 2);
|
MAXSIZE_TEMP_ARRAY(args, 2);
|
||||||
ADD_C(args, INTEGER_OBJ((int)display_tick));
|
ADD_C(args, INTEGER_OBJ((int)display_tick));
|
||||||
ADD_C(args, INTEGER_OBJ(type));
|
|
||||||
active = decor_provider_invoke(p->ns_id, "start", p->redraw_start, args, true, err);
|
active = decor_provider_invoke(p->ns_id, "start", p->redraw_start, args, true, err);
|
||||||
} else {
|
} else {
|
||||||
active = true;
|
active = true;
|
||||||
@ -116,8 +138,8 @@ void decor_providers_invoke_win(win_T *wp, DecorProviders *providers,
|
|||||||
/// @param row Row to invoke line callback for
|
/// @param row Row to invoke line callback for
|
||||||
/// @param[out] has_decor Set when at least one provider invokes a line callback
|
/// @param[out] has_decor Set when at least one provider invokes a line callback
|
||||||
/// @param[out] err Provider error
|
/// @param[out] err Provider error
|
||||||
void providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *has_decor,
|
void decor_providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *has_decor,
|
||||||
char **err)
|
char **err)
|
||||||
{
|
{
|
||||||
for (size_t k = 0; k < kv_size(*providers); k++) {
|
for (size_t k = 0; k < kv_size(*providers); k++) {
|
||||||
DecorProvider *p = kv_A(*providers, k);
|
DecorProvider *p = kv_A(*providers, k);
|
||||||
@ -215,6 +237,7 @@ void decor_provider_clear(DecorProvider *p)
|
|||||||
NLUA_CLEAR_REF(p->redraw_win);
|
NLUA_CLEAR_REF(p->redraw_win);
|
||||||
NLUA_CLEAR_REF(p->redraw_line);
|
NLUA_CLEAR_REF(p->redraw_line);
|
||||||
NLUA_CLEAR_REF(p->redraw_end);
|
NLUA_CLEAR_REF(p->redraw_end);
|
||||||
|
NLUA_CLEAR_REF(p->spell_nav);
|
||||||
p->active = false;
|
p->active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ typedef struct {
|
|||||||
LuaRef redraw_line;
|
LuaRef redraw_line;
|
||||||
LuaRef redraw_end;
|
LuaRef redraw_end;
|
||||||
LuaRef hl_def;
|
LuaRef hl_def;
|
||||||
|
LuaRef spell_nav;
|
||||||
int hl_valid;
|
int hl_valid;
|
||||||
bool hl_cached;
|
bool hl_cached;
|
||||||
} DecorProvider;
|
} DecorProvider;
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
|
|
||||||
#include "nvim/arabic.h"
|
#include "nvim/arabic.h"
|
||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
#include "nvim/cursor_shape.h"
|
#include "nvim/cursor_shape.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/diff.h"
|
#include "nvim/diff.h"
|
||||||
#include "nvim/drawline.h"
|
#include "nvim/drawline.h"
|
||||||
#include "nvim/fold.h"
|
#include "nvim/fold.h"
|
||||||
@ -654,7 +656,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
|
|
||||||
has_decor = decor_redraw_line(buf, lnum - 1, &decor_state);
|
has_decor = decor_redraw_line(buf, lnum - 1, &decor_state);
|
||||||
|
|
||||||
providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err);
|
decor_providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err);
|
||||||
|
|
||||||
if (*provider_err) {
|
if (*provider_err) {
|
||||||
provider_err_virt_text(lnum, *provider_err);
|
provider_err_virt_text(lnum, *provider_err);
|
||||||
@ -1646,7 +1648,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
if (extra_check) {
|
if (extra_check) {
|
||||||
bool can_spell = true;
|
bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
|
||||||
|
bool can_spell = !no_plain_buffer;
|
||||||
|
|
||||||
// Get syntax attribute, unless still at the start of the line
|
// Get syntax attribute, unless still at the start of the line
|
||||||
// (double-wide char that doesn't fit).
|
// (double-wide char that doesn't fit).
|
||||||
@ -1698,6 +1701,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
char_attr = 0;
|
char_attr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_decor && v > 0) {
|
||||||
|
bool selected = (area_active || (area_highlighting && noinvcur
|
||||||
|
&& (colnr_T)vcol == wp->w_virtcol));
|
||||||
|
int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off,
|
||||||
|
selected, &decor_state);
|
||||||
|
if (extmark_attr != 0) {
|
||||||
|
if (!attr_pri) {
|
||||||
|
char_attr = hl_combine_attr(char_attr, extmark_attr);
|
||||||
|
} else {
|
||||||
|
char_attr = hl_combine_attr(extmark_attr, char_attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decor_conceal = decor_state.conceal;
|
||||||
|
if (decor_conceal && decor_state.conceal_char) {
|
||||||
|
decor_conceal = 2; // really??
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decor_state.spell) {
|
||||||
|
can_spell = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check spelling (unless at the end of the line).
|
// Check spelling (unless at the end of the line).
|
||||||
// Only do this when there is no syntax highlighting, the
|
// Only do this when there is no syntax highlighting, the
|
||||||
// @Spell cluster is not used or the current syntax item
|
// @Spell cluster is not used or the current syntax item
|
||||||
@ -1706,9 +1732,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
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 (!attr_pri) {
|
if (!attr_pri) {
|
||||||
char_attr = syntax_attr;
|
char_attr = hl_combine_attr(char_attr, syntax_attr);
|
||||||
}
|
}
|
||||||
if (c != 0 && (!has_syntax || can_spell)) {
|
if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) {
|
||||||
char_u *prev_ptr;
|
char_u *prev_ptr;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
int len;
|
int len;
|
||||||
@ -1781,25 +1807,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
|
char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_decor && v > 0) {
|
|
||||||
bool selected = (area_active || (area_highlighting && noinvcur
|
|
||||||
&& (colnr_T)vcol == wp->w_virtcol));
|
|
||||||
int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off,
|
|
||||||
selected, &decor_state);
|
|
||||||
if (extmark_attr != 0) {
|
|
||||||
if (!attr_pri) {
|
|
||||||
char_attr = hl_combine_attr(char_attr, extmark_attr);
|
|
||||||
} else {
|
|
||||||
char_attr = hl_combine_attr(extmark_attr, char_attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decor_conceal = decor_state.conceal;
|
|
||||||
if (decor_conceal && decor_state.conceal_char) {
|
|
||||||
decor_conceal = 2; // really??
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found last space before word: check for line break.
|
// Found last space before word: check for line break.
|
||||||
if (wp->w_p_lbr && c0 == c && vim_isbreak(c)
|
if (wp->w_p_lbr && c0 == c && vim_isbreak(c)
|
||||||
&& !vim_isbreak((int)(*ptr))) {
|
&& !vim_isbreak((int)(*ptr))) {
|
||||||
|
@ -539,7 +539,7 @@ int update_screen(int type)
|
|||||||
ui_comp_set_screen_valid(true);
|
ui_comp_set_screen_valid(true);
|
||||||
|
|
||||||
DecorProviders providers;
|
DecorProviders providers;
|
||||||
decor_providers_start(&providers, type, &provider_err);
|
decor_providers_start(&providers, &provider_err);
|
||||||
|
|
||||||
// "start" callback could have changed highlights for global elements
|
// "start" callback could have changed highlights for global elements
|
||||||
if (win_check_ns_hl(NULL)) {
|
if (win_check_ns_hl(NULL)) {
|
||||||
|
@ -70,7 +70,8 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|
|||||||
|| kv_size(decor->virt_lines)
|
|| kv_size(decor->virt_lines)
|
||||||
|| decor->conceal
|
|| decor->conceal
|
||||||
|| decor_has_sign(decor)
|
|| decor_has_sign(decor)
|
||||||
|| decor->ui_watched) {
|
|| decor->ui_watched
|
||||||
|
|| decor->spell) {
|
||||||
decor_full = true;
|
decor_full = true;
|
||||||
decor = xmemdup(decor, sizeof *decor);
|
decor = xmemdup(decor, sizeof *decor);
|
||||||
}
|
}
|
||||||
|
@ -731,6 +731,7 @@ EXTERN char *p_spc; ///< 'spellcapcheck'
|
|||||||
EXTERN char *p_spf; ///< 'spellfile'
|
EXTERN char *p_spf; ///< 'spellfile'
|
||||||
EXTERN char *p_spl; ///< 'spelllang'
|
EXTERN char *p_spl; ///< 'spelllang'
|
||||||
EXTERN char *p_spo; // 'spelloptions'
|
EXTERN char *p_spo; // 'spelloptions'
|
||||||
|
EXTERN unsigned int spo_flags;
|
||||||
EXTERN char *p_sps; // 'spellsuggest'
|
EXTERN char *p_sps; // 'spellsuggest'
|
||||||
EXTERN int p_spr; // 'splitright'
|
EXTERN int p_spr; // 'splitright'
|
||||||
EXTERN int p_sol; // 'startofline'
|
EXTERN int p_sol; // 'startofline'
|
||||||
|
@ -2355,6 +2355,7 @@ return {
|
|||||||
secure=true,
|
secure=true,
|
||||||
expand=true,
|
expand=true,
|
||||||
varname='p_spo',
|
varname='p_spo',
|
||||||
|
redraw={'current_buffer'},
|
||||||
defaults={if_true=""}
|
defaults={if_true=""}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -107,6 +107,7 @@ static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2", "auto:3", "auto:4"
|
|||||||
"auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4",
|
"auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4",
|
||||||
"5", "6", "7", "8", "9", NULL };
|
"5", "6", "7", "8", "9", NULL };
|
||||||
static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
|
static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
|
||||||
|
static char *(p_spo_values[]) = { "camel", "noplainbuffer", NULL };
|
||||||
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
|
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
|
||||||
static char *(p_jop_values[]) = { "stack", "view", NULL };
|
static char *(p_jop_values[]) = { "stack", "view", NULL };
|
||||||
static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL };
|
static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL };
|
||||||
@ -1125,7 +1126,8 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
|
|||||||
// When 'spellcapcheck' is set compile the regexp program.
|
// When 'spellcapcheck' is set compile the regexp program.
|
||||||
errmsg = compile_cap_prog(curwin->w_s);
|
errmsg = compile_cap_prog(curwin->w_s);
|
||||||
} else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions'
|
} else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions'
|
||||||
if (**varp != NUL && STRCMP("camel", *varp) != 0) {
|
if (opt_strings_flags(curwin->w_s->b_p_spo, p_spo_values, &(curwin->w_s->b_p_spo_flags),
|
||||||
|
true) != OK) {
|
||||||
errmsg = e_invarg;
|
errmsg = e_invarg;
|
||||||
}
|
}
|
||||||
} else if (varp == &p_sps) { // 'spellsuggest'
|
} else if (varp == &p_sps) { // 'spellsuggest'
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
#include "nvim/change.h" // for changed_bytes
|
#include "nvim/change.h" // for changed_bytes
|
||||||
#include "nvim/charset.h" // for skipwhite, getwhitecols, skipbin
|
#include "nvim/charset.h" // for skipwhite, getwhitecols, skipbin
|
||||||
#include "nvim/cursor.h" // for get_cursor_line_ptr
|
#include "nvim/cursor.h" // for get_cursor_line_ptr
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/drawscreen.h" // for NOT_VALID, redraw_later
|
#include "nvim/drawscreen.h" // for NOT_VALID, redraw_later
|
||||||
#include "nvim/eval/typval.h" // for semsg
|
#include "nvim/eval/typval.h" // for semsg
|
||||||
#include "nvim/ex_cmds.h" // for do_sub_msg
|
#include "nvim/ex_cmds.h" // for do_sub_msg
|
||||||
@ -220,7 +221,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou
|
|||||||
size_t nrlen = 0; // found a number first
|
size_t nrlen = 0; // found a number first
|
||||||
size_t wrongcaplen = 0;
|
size_t wrongcaplen = 0;
|
||||||
bool count_word = docount;
|
bool count_word = docount;
|
||||||
bool use_camel_case = *wp->w_s->b_p_spo != NUL;
|
bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0;
|
||||||
bool camel_case = false;
|
bool camel_case = false;
|
||||||
|
|
||||||
// A word never starts at a space or a control character. Return quickly
|
// A word never starts at a space or a control character. Return quickly
|
||||||
@ -1198,6 +1199,24 @@ bool no_spell_checking(win_T *wp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void decor_spell_nav_start(win_T *wp)
|
||||||
|
{
|
||||||
|
decor_state = (DecorState){ 0 };
|
||||||
|
decor_redraw_reset(wp->w_buffer, &decor_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool 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);
|
||||||
|
decor_redraw_line(wp->w_buffer, lnum - 1, &decor_state);
|
||||||
|
*decor_lnum = lnum;
|
||||||
|
}
|
||||||
|
decor_redraw_col(wp->w_buffer, col, col, false, &decor_state);
|
||||||
|
return decor_state.spell;
|
||||||
|
}
|
||||||
|
|
||||||
/// Moves to the next spell error.
|
/// Moves to the next spell error.
|
||||||
/// "curline" is false for "[s", "]s", "[S" and "]S".
|
/// "curline" is false for "[s", "]s", "[S" and "]S".
|
||||||
/// "curline" is true to find word under/after cursor in the same line.
|
/// "curline" is true to find word under/after cursor in the same line.
|
||||||
@ -1216,11 +1235,11 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
hlf_T attr = HLF_COUNT;
|
hlf_T attr = HLF_COUNT;
|
||||||
size_t len;
|
size_t len;
|
||||||
int has_syntax = syntax_present(wp);
|
int has_syntax = syntax_present(wp);
|
||||||
int col;
|
colnr_T col;
|
||||||
char_u *buf = NULL;
|
char_u *buf = NULL;
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
int capcol = -1;
|
colnr_T capcol = -1;
|
||||||
bool found_one = false;
|
bool found_one = false;
|
||||||
bool wrapped = false;
|
bool wrapped = false;
|
||||||
|
|
||||||
@ -1228,6 +1247,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
// Start looking for bad word at the start of the line, because we can't
|
// Start looking for bad word at the start of the line, because we can't
|
||||||
// start halfway through a word, we don't know where it starts or ends.
|
// start halfway through a word, we don't know where it starts or ends.
|
||||||
//
|
//
|
||||||
@ -1240,6 +1261,19 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
linenr_T lnum = wp->w_cursor.lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
clearpos(&found_pos);
|
clearpos(&found_pos);
|
||||||
|
|
||||||
|
char *decor_error = NULL;
|
||||||
|
// Ephemeral extmarks are currently stored in the global decor_state.
|
||||||
|
// When looking for spell errors, we need to:
|
||||||
|
// - temporarily reset decor_state
|
||||||
|
// - run the _on_spell_nav decor callback for each line we look at
|
||||||
|
// - detect if any spell marks are present
|
||||||
|
// - restore decor_state to the value saved here.
|
||||||
|
// TODO(lewis6991): un-globalize decor_state and allow ephemeral marks to be stored into a
|
||||||
|
// temporary DecorState.
|
||||||
|
DecorState saved_decor_start = decor_state;
|
||||||
|
linenr_T decor_lnum = -1;
|
||||||
|
decor_spell_nav_start(wp);
|
||||||
|
|
||||||
while (!got_int) {
|
while (!got_int) {
|
||||||
char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
|
char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
|
||||||
|
|
||||||
@ -1258,10 +1292,10 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
|
|
||||||
// For checking first word with a capital skip white space.
|
// For checking first word with a capital skip white space.
|
||||||
if (capcol == 0) {
|
if (capcol == 0) {
|
||||||
capcol = (int)getwhitecols((char *)line);
|
capcol = (colnr_T)getwhitecols((char *)line);
|
||||||
} else if (curline && wp == curwin) {
|
} else if (curline && wp == curwin) {
|
||||||
// For spellbadword(): check if first word needs a capital.
|
// For spellbadword(): check if first word needs a capital.
|
||||||
col = (int)getwhitecols((char *)line);
|
col = (colnr_T)getwhitecols((char *)line);
|
||||||
if (check_need_cap(lnum, col)) {
|
if (check_need_cap(lnum, col)) {
|
||||||
capcol = col;
|
capcol = col;
|
||||||
}
|
}
|
||||||
@ -1308,33 +1342,37 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
|| ((colnr_T)(curline
|
|| ((colnr_T)(curline
|
||||||
? p - buf + (ptrdiff_t)len
|
? p - buf + (ptrdiff_t)len
|
||||||
: p - buf) > wp->w_cursor.col)) {
|
: p - buf) > wp->w_cursor.col)) {
|
||||||
bool can_spell;
|
col = (colnr_T)(p - buf);
|
||||||
if (has_syntax) {
|
|
||||||
col = (int)(p - buf);
|
bool can_spell = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0;
|
||||||
(void)syn_get_id(wp, lnum, (colnr_T)col,
|
|
||||||
false, &can_spell, false);
|
if (!can_spell) {
|
||||||
if (!can_spell) {
|
can_spell = decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error);
|
||||||
attr = HLF_COUNT;
|
}
|
||||||
}
|
|
||||||
} else {
|
if (!can_spell && has_syntax) {
|
||||||
can_spell = true;
|
(void)syn_get_id(wp, lnum, col, false, &can_spell, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!can_spell) {
|
||||||
|
attr = HLF_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_spell) {
|
if (can_spell) {
|
||||||
found_one = true;
|
found_one = true;
|
||||||
found_pos = (pos_T) {
|
found_pos = (pos_T) {
|
||||||
.lnum = lnum,
|
.lnum = lnum,
|
||||||
.col = (int)(p - buf),
|
.col = col,
|
||||||
.coladd = 0
|
.coladd = 0
|
||||||
};
|
};
|
||||||
if (dir == FORWARD) {
|
if (dir == FORWARD) {
|
||||||
// No need to search further.
|
// No need to search further.
|
||||||
wp->w_cursor = found_pos;
|
wp->w_cursor = found_pos;
|
||||||
xfree(buf);
|
|
||||||
if (attrp != NULL) {
|
if (attrp != NULL) {
|
||||||
*attrp = attr;
|
*attrp = attr;
|
||||||
}
|
}
|
||||||
return len;
|
ret = len;
|
||||||
|
goto theend;
|
||||||
} else if (curline) {
|
} else if (curline) {
|
||||||
// Insert mode completion: put cursor after
|
// Insert mode completion: put cursor after
|
||||||
// the bad word.
|
// the bad word.
|
||||||
@ -1358,8 +1396,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
if (dir == BACKWARD && found_pos.lnum != 0) {
|
if (dir == BACKWARD && found_pos.lnum != 0) {
|
||||||
// Use the last match in the line (before the cursor).
|
// Use the last match in the line (before the cursor).
|
||||||
wp->w_cursor = found_pos;
|
wp->w_cursor = found_pos;
|
||||||
xfree(buf);
|
ret = found_len;
|
||||||
return found_len;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curline) {
|
if (curline) {
|
||||||
@ -1429,8 +1467,12 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
line_breakcheck();
|
line_breakcheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
theend:
|
||||||
|
decor_state_free(&decor_state);
|
||||||
|
xfree(decor_error);
|
||||||
|
decor_state = saved_decor_start;
|
||||||
xfree(buf);
|
xfree(buf);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For spell checking: concatenate the start of the following line "line" into
|
// For spell checking: concatenate the start of the following line "line" into
|
||||||
|
@ -31,6 +31,8 @@ describe('decorations providers', function()
|
|||||||
[12] = {foreground = tonumber('0x990000')};
|
[12] = {foreground = tonumber('0x990000')};
|
||||||
[13] = {background = Screen.colors.LightBlue};
|
[13] = {background = Screen.colors.LightBlue};
|
||||||
[14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
|
[14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
|
||||||
|
[15] = {special = Screen.colors.Blue1, undercurl = true},
|
||||||
|
[16] = {special = Screen.colors.Red, undercurl = true},
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ describe('decorations providers', function()
|
|||||||
a.nvim_set_decoration_provider(_G.ns1, {
|
a.nvim_set_decoration_provider(_G.ns1, {
|
||||||
on_start = on_do; on_buf = on_do;
|
on_start = on_do; on_buf = on_do;
|
||||||
on_win = on_do; on_line = on_do;
|
on_win = on_do; on_line = on_do;
|
||||||
on_end = on_do;
|
on_end = on_do; _on_spell_nav = on_do;
|
||||||
})
|
})
|
||||||
return _G.ns1
|
return _G.ns1
|
||||||
]])
|
]])
|
||||||
@ -95,7 +97,7 @@ describe('decorations providers', function()
|
|||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
check_trace {
|
check_trace {
|
||||||
{ "start", 4, 40 };
|
{ "start", 4 };
|
||||||
{ "win", 1000, 1, 0, 8 };
|
{ "win", 1000, 1, 0, 8 };
|
||||||
{ "line", 1000, 1, 0 };
|
{ "line", 1000, 1, 0 };
|
||||||
{ "line", 1000, 1, 1 };
|
{ "line", 1000, 1, 1 };
|
||||||
@ -119,7 +121,7 @@ describe('decorations providers', function()
|
|||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
check_trace {
|
check_trace {
|
||||||
{ "start", 5, 10 };
|
{ "start", 5 };
|
||||||
{ "buf", 1 };
|
{ "buf", 1 };
|
||||||
{ "win", 1000, 1, 0, 8 };
|
{ "win", 1000, 1, 0, 8 };
|
||||||
{ "line", 1000, 1, 6 };
|
{ "line", 1000, 1, 6 };
|
||||||
@ -156,6 +158,84 @@ describe('decorations providers', function()
|
|||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can indicate spellchecked points', function()
|
||||||
|
exec [[
|
||||||
|
set spell
|
||||||
|
set spelloptions=noplainbuffer
|
||||||
|
syntax off
|
||||||
|
]]
|
||||||
|
|
||||||
|
insert [[
|
||||||
|
I am well written text.
|
||||||
|
i am not capitalized.
|
||||||
|
I am a speling mistakke.
|
||||||
|
]]
|
||||||
|
|
||||||
|
setup_provider [[
|
||||||
|
local ns = a.nvim_create_namespace "spell"
|
||||||
|
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 })
|
||||||
|
end
|
||||||
|
table.insert(beamtrace, {kind, ...})
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
check_trace {
|
||||||
|
{ "start", 5 };
|
||||||
|
{ "win", 1000, 1, 0, 5 };
|
||||||
|
{ "line", 1000, 1, 0 };
|
||||||
|
{ "line", 1000, 1, 1 };
|
||||||
|
{ "line", 1000, 1, 2 };
|
||||||
|
{ "line", 1000, 1, 3 };
|
||||||
|
{ "end", 5 };
|
||||||
|
}
|
||||||
|
|
||||||
|
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:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
feed "]s"
|
||||||
|
check_trace {
|
||||||
|
{ "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:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
feed "]s"
|
||||||
|
check_trace {
|
||||||
|
{ "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:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
|
|
||||||
it('can predefine highlights', function()
|
it('can predefine highlights', function()
|
||||||
screen:try_resize(40, 16)
|
screen:try_resize(40, 16)
|
||||||
insert(mulholland)
|
insert(mulholland)
|
||||||
|
Loading…
Reference in New Issue
Block a user