mirror of
https://github.com/neovim/neovim.git
synced 2026-06-15 16:23:48 +00:00
fix(float): title/footer shows printable control chars #40047
Problem: Literal tab (or other control char) in a float title/footer is not made printable, so it renders incorrectly instead of as "^I". Solution: Normalize title/footer text for display like 'statusline' tab to "^I", parameterize parse_virt_text() with untab and recompute the width.
This commit is contained in:
@@ -234,7 +234,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
|
||||
uint32_t ns_id = src2ns(&src_id);
|
||||
int width;
|
||||
|
||||
VirtText virt_text = parse_virt_text(chunks, err, &width);
|
||||
VirtText virt_text = parse_virt_text(chunks, err, &width, false);
|
||||
if (ERROR_SET(err)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -669,7 +669,7 @@ Integer nvim_buf_set_extmark(Buffer buf, Integer ns_id, Integer line, Integer co
|
||||
}
|
||||
|
||||
if (HAS_KEY(opts, set_extmark, virt_text)) {
|
||||
virt_text.data.virt_text = parse_virt_text(opts->virt_text, err, &virt_text.width);
|
||||
virt_text.data.virt_text = parse_virt_text(opts->virt_text, err, &virt_text.width, false);
|
||||
if (ERROR_SET(err)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -742,7 +742,7 @@ Integer nvim_buf_set_extmark(Buffer buf, Integer ns_id, Integer line, Integer co
|
||||
goto error;
|
||||
});
|
||||
int dummig;
|
||||
VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
|
||||
VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig, false);
|
||||
kv_push(virt_lines.data.virt_lines, ((struct virt_line){ jtem, virt_lines_flags }));
|
||||
if (ERROR_SET(err)) {
|
||||
goto error;
|
||||
@@ -1192,7 +1192,7 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in
|
||||
}
|
||||
}
|
||||
|
||||
VirtText parse_virt_text(Array chunks, Error *err, int *width)
|
||||
VirtText parse_virt_text(Array chunks, Error *err, int *width, bool untab)
|
||||
{
|
||||
VirtText virt_text = KV_INITIAL_VALUE;
|
||||
int w = 0;
|
||||
@@ -1230,7 +1230,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width)
|
||||
}
|
||||
}
|
||||
|
||||
char *text = transstr(str.size > 0 ? str.data : "", false); // allocates
|
||||
char *text = transstr(str.size > 0 ? str.data : "", untab); // allocates
|
||||
w += (int)mb_string2cells(text);
|
||||
|
||||
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "nvim/autocmd_defs.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/decoration_defs.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/errors.h"
|
||||
@@ -1021,38 +1022,27 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type,
|
||||
return;
|
||||
});
|
||||
|
||||
bool *is_present;
|
||||
VirtText *chunks;
|
||||
int *width;
|
||||
switch (bordertext_type) {
|
||||
case kBorderTextTitle:
|
||||
is_present = &fconfig->title;
|
||||
chunks = &fconfig->title_chunks;
|
||||
width = &fconfig->title_width;
|
||||
break;
|
||||
case kBorderTextFooter:
|
||||
is_present = &fconfig->footer;
|
||||
chunks = &fconfig->footer_chunks;
|
||||
width = &fconfig->footer_width;
|
||||
break;
|
||||
}
|
||||
bool is_title = bordertext_type == kBorderTextTitle;
|
||||
bool *is_present = is_title ? &fconfig->title : &fconfig->footer;
|
||||
VirtText *chunks = is_title ? &fconfig->title_chunks : &fconfig->footer_chunks;
|
||||
int *width = is_title ? &fconfig->title_width : &fconfig->footer_width;
|
||||
|
||||
if (bordertext.type == kObjectTypeString) {
|
||||
if (bordertext.data.string.size == 0) {
|
||||
*is_present = false;
|
||||
return;
|
||||
}
|
||||
char *text = transstr(bordertext.data.string.data, true);
|
||||
kv_init(*chunks);
|
||||
kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data),
|
||||
.hl_id = -1 }));
|
||||
*width = (int)mb_string2cells(bordertext.data.string.data);
|
||||
*is_present = true;
|
||||
return;
|
||||
kv_push(*chunks, ((VirtTextChunk){ .text = text, .hl_id = -1 }));
|
||||
*width = (int)mb_string2cells(text);
|
||||
} else {
|
||||
*chunks = parse_virt_text(bordertext.data.array, err, width, true);
|
||||
if (ERROR_SET(err)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*width = 0;
|
||||
*chunks = parse_virt_text(bordertext.data.array, err, width);
|
||||
|
||||
*is_present = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1737,7 +1737,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo
|
||||
Object obj = eval_foldtext(wp);
|
||||
if (obj.type == kObjectTypeArray) {
|
||||
Error err = ERROR_INIT;
|
||||
*vt = parse_virt_text(obj.data.array, &err, NULL);
|
||||
*vt = parse_virt_text(obj.data.array, &err, NULL, false);
|
||||
if (!ERROR_SET(&err)) {
|
||||
*buf = NUL;
|
||||
text = buf;
|
||||
|
||||
@@ -3056,6 +3056,45 @@ describe('float window', function()
|
||||
eq({ { '🦄', '' }, { 'BB', { 'B0', 'B1', '' } } }, api.nvim_win_get_config(win).title)
|
||||
eq({ { '🦄', '' }, { 'BB', { 'B0', 'B1', '' } } }, api.nvim_win_get_config(win).footer)
|
||||
|
||||
api.nvim_win_set_config(win, { border = 'single', title = 'a\tb', footer = 'A\tB' })
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*6
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
^ |
|
||||
{0:~ }|*5
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
{5:┌}{11:a^Ib}{5:─────┐}|
|
||||
{5:│}{1: halloj! }{5:│}|
|
||||
{5:│}{1: BORDAA }{5:│}|
|
||||
{5:└}{11:A^IB}{5:─────┘}|
|
||||
]],
|
||||
float_pos = { [4] = { 1001, 'NW', 1, 2, 5, true, 50, 1, 2, 5 } },
|
||||
win_viewport = {
|
||||
[2] = { win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0 },
|
||||
[4] = { win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
^ |
|
||||
{0:~ }|
|
||||
{0:~ }{5:┌}{11:a^Ib}{5:─────┐}{0: }|
|
||||
{0:~ }{5:│}{1: halloj! }{5:│}{0: }|
|
||||
{0:~ }{5:│}{1: BORDAA }{5:│}{0: }|
|
||||
{0:~ }{5:└}{11:A^IB}{5:─────┘}{0: }|
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
api.nvim_win_set_config(win, { title = { { 'a\tb' } }, footer = { { 'A\tB' } } })
|
||||
screen:expect_unchanged()
|
||||
|
||||
-- making it a split should not leak memory
|
||||
api.nvim_win_set_config(win, { vertical = true })
|
||||
if multigrid then
|
||||
|
||||
Reference in New Issue
Block a user