fix(marks): ineffective conceal_line callback optimization (#32662)

Problem:  _on_conceal_line callbacks are not invoked if callback has not
          let Nvim know it wants to receive them. But this may change on
          factors other than what is currently checked (changed buffer).
Solution: Forego this optimization, callback is still guarded behind
          'conceallevel'.
This commit is contained in:
luukvbaal
2025-02-28 13:36:25 +01:00
committed by GitHub
parent 77626ed7fd
commit 86046c5a31
6 changed files with 27 additions and 39 deletions

View File

@ -431,7 +431,7 @@ end
function TSHighlighter._on_conceal_line(_, _, buf, row)
local self = TSHighlighter.active[buf]
if not self or not self._conceal_line or self._conceal_checked[row] then
return self and self._conceal_line
return
end
-- Do not affect potentially populated highlight state.
@ -440,7 +440,6 @@ function TSHighlighter._on_conceal_line(_, _, buf, row)
self:prepare_highlight_states(row, row)
on_line_impl(self, buf, row, false, true)
self._highlight_states = highlight_states
return true
end
---@private

View File

@ -413,8 +413,7 @@ struct file_buffer {
// negative when lines were deleted
kvec_t(WinInfo *) b_wininfo; // list of last used info for each window
disptick_T b_mod_tick_syn; // last display tick syntax was updated
disptick_T b_mod_tick_decor; // last display tick decoration providers
// where invoked
disptick_T b_mod_tick_decor; // last display tick decoration providers were invoked
int64_t b_mtime; // last change time of original file
int64_t b_mtime_ns; // nanoseconds of last change time
@ -1324,7 +1323,4 @@ struct window_S {
size_t w_winbar_click_defs_size; // Size of the w_winbar_click_defs array
StlClickDefinition *w_statuscol_click_defs; // Status column click definitions
size_t w_statuscol_click_defs_size; // Size of the w_statuscol_click_defs array
buf_T *w_conceal_line_buf; // buffer in win when first invoked
bool w_conceal_line_provider; // whether conceal_line provider is active
};

View File

@ -862,15 +862,7 @@ bool decor_conceal_line(win_T *wp, int row, bool check_cursor)
// No need to scan the marktree if there are no conceal_line marks.
if (!buf_meta_total(wp->w_buffer, kMTMetaConcealLines)) {
// Only invoke callback when a decor provider has indicated that it may
// conceal lines in a certain buffer (the callback's return value).
if (wp->w_conceal_line_buf != wp->w_buffer) {
wp->w_conceal_line_provider = false;
}
if (wp->w_conceal_line_provider || wp->w_conceal_line_buf != wp->w_buffer) {
goto invoke;
}
return false;
return decor_providers_invoke_conceal_line(wp, row);
}
// Scan the marktree for any conceal_line marks on this row.
@ -896,19 +888,13 @@ bool decor_conceal_line(win_T *wp, int row, bool check_cursor)
marktree_itr_next_filter(wp->w_buffer->b_marktree, itr, row + 1, 0, conceal_filter);
}
invoke:;
// Interpret increase in keys to mean this row is concealed by a callback.
size_t keys = wp->w_buffer->b_marktree->n_keys;
decor_providers_invoke_conceal_line(wp, row);
return wp->w_buffer->b_marktree->n_keys > keys;
return decor_providers_invoke_conceal_line(wp, row);
}
/// @return whether a window may have folded or concealed lines
bool win_lines_concealed(win_T *wp)
{
return hasAnyFolding(wp)
|| (wp->w_p_cole >= 2
&& (wp->w_conceal_line_provider || buf_meta_total(wp->w_buffer, kMTMetaConcealLines)));
return hasAnyFolding(wp) || wp->w_p_cole >= 2;
}
int sign_item_cmp(const void *p1, const void *p2)

View File

@ -47,9 +47,7 @@ static bool decor_provider_invoke(int provider_idx, const char *name, LuaRef ref
Error err = ERROR_INIT;
textlock++;
provider_active = true;
Object ret = nlua_call_ref(ref, name, args, kRetNilBool, NULL, &err);
provider_active = false;
textlock--;
// We get the provider here via an index in case the above call to nlua_call_ref causes
@ -92,9 +90,10 @@ void decor_providers_invoke_spell(win_T *wp, int start_row, int start_col, int e
}
}
void decor_providers_invoke_conceal_line(win_T *wp, int row)
/// @return whether a provider placed any marks in the callback.
bool decor_providers_invoke_conceal_line(win_T *wp, int row)
{
wp->w_conceal_line_buf = wp->w_buffer;
size_t keys = wp->w_buffer->b_marktree->n_keys;
for (size_t i = 0; i < kv_size(decor_providers); i++) {
DecorProvider *p = &kv_A(decor_providers, i);
if (p->state != kDecorProviderDisabled && p->conceal_line != LUA_NOREF) {
@ -102,11 +101,10 @@ void decor_providers_invoke_conceal_line(win_T *wp, int row)
ADD_C(args, INTEGER_OBJ(wp->handle));
ADD_C(args, INTEGER_OBJ(wp->w_buffer->handle));
ADD_C(args, INTEGER_OBJ(row));
if (decor_provider_invoke((int)i, "conceal_line", p->conceal_line, args, false)) {
wp->w_conceal_line_provider = true;
}
decor_provider_invoke((int)i, "conceal_line", p->conceal_line, args, true);
}
}
return wp->w_buffer->b_marktree->n_keys > keys;
}
/// For each provider invoke the 'start' callback
@ -279,12 +277,7 @@ void decor_provider_clear(DecorProvider *p)
NLUA_CLEAR_REF(p->redraw_line);
NLUA_CLEAR_REF(p->redraw_end);
NLUA_CLEAR_REF(p->spell_nav);
if (p->conceal_line != LUA_NOREF) {
NLUA_CLEAR_REF(p->conceal_line);
FOR_ALL_TAB_WINDOWS(tp, wp) {
wp->w_conceal_line_buf = NULL; // invoke at least once
}
}
NLUA_CLEAR_REF(p->conceal_line);
p->state = kDecorProviderDisabled;
}

View File

@ -6,8 +6,6 @@
#include "nvim/macros_defs.h"
#include "nvim/types_defs.h" // IWYU pragma: keep
EXTERN bool provider_active INIT( = false);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "decoration_provider.h.generated.h"
#endif

View File

@ -366,5 +366,21 @@ describe('vim.lsp.util', function()
{1:~ }|*9
|
]])
-- Correct height when float inherits 'conceallevel' >= 2 #32639
command('close | set conceallevel=2')
exec_lua([[
vim.lsp.util.open_floating_preview({ '```lua', 'local foo', '```' }, 'markdown', {
border = 'single',
focus = false,
})
]])
screen:expect([[
^ |
┌─────────┐{1: }|
│{100:local}{101: }{102:foo}│{1: }|
└─────────┘{1: }|
{1:~ }|*9
|
]])
end)
end)