mirror of
https://github.com/neovim/neovim.git
synced 2026-06-15 16:23:48 +00:00
fix(folds): foldcolumn is interrupted for virtual line above nested fold (#39999)
Problem:
`foldcolumn` is empty for virtual lines above the start of a nested
fold.
Solution:
For virtual lines, compute the outer fold level and display it by
reusing the logic from `fill_foldcolumn`.
(cherry picked from commit fe154f4d45)
This commit is contained in:
committed by
github-actions[bot]
parent
ed7acd1391
commit
a0d7e80368
@@ -486,26 +486,37 @@ static void draw_foldcolumn(win_T *wp, winlinevars_T *wlv)
|
||||
int fdc = compute_foldcolumn(wp, 0);
|
||||
if (fdc > 0) {
|
||||
int attr = win_hl_attr(wp, use_cursor_line_highlight(wp, wlv->lnum) ? HLF_CLF : HLF_FC);
|
||||
// Only draw 'foldcolumn' for filler line if lnum is inside a fold that
|
||||
// starts higher up. We don't want to show 'foldopen' or 'foldclose' twice.
|
||||
foldinfo_T fi;
|
||||
if (wlv->filler_todo <= 0 || wlv->foldinfo.fi_lnum < wlv->lnum) {
|
||||
fi = wlv->foldinfo;
|
||||
} else {
|
||||
fi = (foldinfo_T){ 0 };
|
||||
}
|
||||
fill_foldcolumn(wp, fi, wlv->lnum, attr, fdc, &wlv->off, NULL, NULL);
|
||||
bool is_virt = wlv->filler_todo > 0;
|
||||
fill_foldcolumn(wp, wlv->foldinfo, wlv->lnum, attr, fdc, is_virt, &wlv->off, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get foldcolumn char based on line fold level and column, either `foldsep`, `foldinner`,
|
||||
/// or an overflow indicator. `foldopen` and `foldclosed` are set in `fill_foldcolumn`.
|
||||
/// @param first_level Lowest fold level displayed on line
|
||||
/// @param i Column index
|
||||
static inline schar_T foldcolumn_sep_char(int first_level, int i, win_T *wp)
|
||||
{
|
||||
if (first_level == 1) {
|
||||
return wp->w_p_fcs_chars.foldsep;
|
||||
} else if (wp->w_p_fcs_chars.foldinner != NUL) {
|
||||
return wp->w_p_fcs_chars.foldinner;
|
||||
} else if (first_level + i <= 9) {
|
||||
return schar_from_ascii('0' + first_level + i);
|
||||
} else {
|
||||
return schar_from_ascii('>');
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw the foldcolumn or fill "out_buffer". Assume monocell characters.
|
||||
///
|
||||
/// @param fdc Current width of the foldcolumn
|
||||
/// @param is_virt Whether the line is a filler line (diff or virtual)
|
||||
/// @param[out] wlv_off Pointer to linebuf offset, incremented for default column
|
||||
/// @param[out] out_buffer Char array to fill, only used for 'statuscolumn'
|
||||
/// @param[out] out_vcol vcol array to fill, only used for 'statuscolumn'
|
||||
void fill_foldcolumn(win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int attr, int fdc, int *wlv_off,
|
||||
colnr_T *out_vcol, schar_T *out_buffer)
|
||||
void fill_foldcolumn(win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int attr, int fdc, bool is_virt,
|
||||
int *wlv_off, colnr_T *out_vcol, schar_T *out_buffer)
|
||||
{
|
||||
bool closed = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
|
||||
int level = foldinfo.fi_level;
|
||||
@@ -523,14 +534,20 @@ void fill_foldcolumn(win_T *wp, foldinfo_T foldinfo, linenr_T lnum, int attr, in
|
||||
symbol = wp->w_p_fcs_chars.foldclosed;
|
||||
} else if (foldinfo.fi_lnum == lnum && first_level + i >= foldinfo.fi_low_level) {
|
||||
symbol = wp->w_p_fcs_chars.foldopen;
|
||||
} else if (first_level == 1) {
|
||||
symbol = wp->w_p_fcs_chars.foldsep;
|
||||
} else if (wp->w_p_fcs_chars.foldinner != NUL) {
|
||||
symbol = wp->w_p_fcs_chars.foldinner;
|
||||
} else if (first_level + i <= 9) {
|
||||
symbol = schar_from_ascii('0' + first_level + i);
|
||||
} else {
|
||||
symbol = schar_from_ascii('>');
|
||||
symbol = foldcolumn_sep_char(first_level, i, wp);
|
||||
}
|
||||
|
||||
// We don't want to show `foldopen` or `foldclose` twice, so we compute
|
||||
// the fold level of `lnum - 1` and reuse the logic from above.
|
||||
if (is_virt && foldinfo.fi_level != 0 && foldinfo.fi_lnum == lnum) {
|
||||
int outer_level = MAX(foldinfo.fi_low_level - 1, 0);
|
||||
int outer_first_level = MAX(outer_level - fdc + 1, 1);
|
||||
if (i >= outer_level) {
|
||||
symbol = schar_from_ascii(' ');
|
||||
} else {
|
||||
symbol = foldcolumn_sep_char(outer_first_level, i, wp);
|
||||
}
|
||||
}
|
||||
|
||||
int vcol = i >= level ? -1 : (i == closedcol - 1 && closed) ? -2 : -3;
|
||||
@@ -1354,6 +1371,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
|
||||
// Draw the 'statuscolumn' if option is set.
|
||||
statuscol.draw = true;
|
||||
statuscol.sattrs = wlv.sattrs;
|
||||
statuscol.lnum = lnum;
|
||||
statuscol.foldinfo = foldinfo;
|
||||
statuscol.width = win_col_off(wp) - (wp == cmdwin_win);
|
||||
statuscol.sign_cul_id = use_cursor_line_highlight(wp, lnum) ? wlv.sign_cul_attr : 0;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/eval/vars.h"
|
||||
#include "nvim/eval_defs.h"
|
||||
#include "nvim/gettext_defs.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/grid.h"
|
||||
@@ -1595,7 +1596,8 @@ stcsign:
|
||||
|
||||
if (fdc > 0) {
|
||||
schar_T fold_buf[9];
|
||||
fill_foldcolumn(wp, stcp->foldinfo, lnum, 0, fdc, NULL, stcp->fold_vcol, fold_buf);
|
||||
fill_foldcolumn(wp, stcp->foldinfo, stcp->lnum, 0, fdc, get_vim_var_nr(VV_VIRTNUM) < 0,
|
||||
NULL, stcp->fold_vcol, fold_buf);
|
||||
stl_items[curitem].minwid = -(use_cursor_line_highlight(wp, lnum) ? HLF_CLF : HLF_FC);
|
||||
size_t buflen = 0;
|
||||
// TODO(bfredl): this is very backwards. we must support schar_T
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvim/fold_defs.h"
|
||||
#include "nvim/pos_defs.h"
|
||||
#include "nvim/sign_defs.h"
|
||||
|
||||
/// 'statusline' item flags
|
||||
@@ -101,6 +102,7 @@ struct stl_item {
|
||||
/// Struct to hold info for 'statuscolumn'
|
||||
typedef struct {
|
||||
int width; ///< width of the status column
|
||||
linenr_T lnum; ///< buffer line being drawn
|
||||
int sign_cul_id; ///< cursorline sign highlight id
|
||||
bool draw; ///< whether to draw the statuscolumn
|
||||
stl_hlrec_t *hlrec; ///< highlight groups
|
||||
|
||||
@@ -2304,6 +2304,10 @@ describe('folded lines', function()
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
-- `foldcolumn` in `statuscolumn` should be identical
|
||||
command('set statuscolumn=%C')
|
||||
screen:expect_unchanged()
|
||||
end)
|
||||
|
||||
it('foldcolumn is not interrupted when virt_lines are inside a fold', function()
|
||||
@@ -2353,6 +2357,129 @@ describe('folded lines', function()
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
command('set statuscolumn=%C')
|
||||
screen:expect_unchanged()
|
||||
end)
|
||||
|
||||
it('foldcolumn for a virt_line above a nested fold shows correct fold level', function()
|
||||
fn.setline(1, 'line 1')
|
||||
fn.setline(2, 'line 2')
|
||||
fn.setline(3, 'line 3')
|
||||
fn.setline(4, 'line 4')
|
||||
|
||||
local ns = api.nvim_create_namespace('ns')
|
||||
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines = { { { 'below line 2', '' } } } })
|
||||
api.nvim_buf_set_extmark(
|
||||
0,
|
||||
ns,
|
||||
2,
|
||||
0,
|
||||
{ virt_lines_above = true, virt_lines = { { { 'above line 3', '' } } } }
|
||||
)
|
||||
|
||||
command('1,4fold | 1,4foldopen')
|
||||
command('3,4fold | 3,4foldopen ')
|
||||
command('set foldcolumn=1')
|
||||
if multigrid then
|
||||
screen:expect([[
|
||||
## grid 1
|
||||
[2:---------------------------------------------]|*7
|
||||
[3:---------------------------------------------]|
|
||||
## grid 2
|
||||
{7:-}^line 1 |
|
||||
{7:│}line 2 |
|
||||
{7:│}below line 2 |
|
||||
{7:│}above line 3 |
|
||||
{7:-}line 3 |
|
||||
{7:2}line 4 |
|
||||
{1:~ }|
|
||||
## grid 3
|
||||
|
|
||||
]])
|
||||
else
|
||||
screen:expect([[
|
||||
{7:-}^line 1 |
|
||||
{7:│}line 2 |
|
||||
{7:│}below line 2 |
|
||||
{7:│}above line 3 |
|
||||
{7:-}line 3 |
|
||||
{7:2}line 4 |
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
command('set statuscolumn=%C')
|
||||
screen:expect_unchanged()
|
||||
command('set statuscolumn=')
|
||||
|
||||
command('set foldcolumn=2')
|
||||
if multigrid then
|
||||
screen:expect([[
|
||||
## grid 1
|
||||
[2:---------------------------------------------]|*7
|
||||
[3:---------------------------------------------]|
|
||||
## grid 2
|
||||
{7:- }^line 1 |
|
||||
{7:│ }line 2 |
|
||||
{7:│ }below line 2 |
|
||||
{7:│ }above line 3 |
|
||||
{7:│-}line 3 |
|
||||
{7:││}line 4 |
|
||||
{1:~ }|
|
||||
## grid 3
|
||||
|
|
||||
]])
|
||||
else
|
||||
screen:expect([[
|
||||
{7:- }^line 1 |
|
||||
{7:│ }line 2 |
|
||||
{7:│ }below line 2 |
|
||||
{7:│ }above line 3 |
|
||||
{7:│-}line 3 |
|
||||
{7:││}line 4 |
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
command('set statuscolumn=%C')
|
||||
screen:expect_unchanged()
|
||||
command('set statuscolumn=')
|
||||
|
||||
command('2,4fold | 2,4foldopen')
|
||||
if multigrid then
|
||||
screen:expect([[
|
||||
## grid 1
|
||||
[2:---------------------------------------------]|*7
|
||||
[3:---------------------------------------------]|
|
||||
## grid 2
|
||||
{7:- }^line 1 |
|
||||
{7:│-}line 2 |
|
||||
{7:││}below line 2 |
|
||||
{7:││}above line 3 |
|
||||
{7:2-}line 3 |
|
||||
{7:23}line 4 |
|
||||
{1:~ }|
|
||||
## grid 3
|
||||
|
|
||||
]])
|
||||
else
|
||||
screen:expect([[
|
||||
{7:- }^line 1 |
|
||||
{7:│-}line 2 |
|
||||
{7:││}below line 2 |
|
||||
{7:││}above line 3 |
|
||||
{7:2-}line 3 |
|
||||
{7:23}line 4 |
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
command('set statuscolumn=%C')
|
||||
screen:expect_unchanged()
|
||||
end)
|
||||
|
||||
it('Folded and Visual highlights are combined #19691', function()
|
||||
|
||||
Reference in New Issue
Block a user