mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
buffer: add support for virtual text annotations
This commit is contained in:
parent
b2d7b70f4d
commit
45f53b370b
@ -967,6 +967,85 @@ void nvim_buf_clear_highlight(Buffer buffer,
|
|||||||
bufhl_clear_line_range(buf, (int)src_id, (int)line_start+1, (int)line_end);
|
bufhl_clear_line_range(buf, (int)src_id, (int)line_start+1, (int)line_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Set the virtual text (annotation) for a buffer line.
|
||||||
|
///
|
||||||
|
/// By default (and currently the only option) the text will be placed after
|
||||||
|
/// the buffer text. Virtual text will never cause reflow, rather virtual
|
||||||
|
/// text will be truncated at the end of the screen line. The virtual text will
|
||||||
|
/// begin after one cell to the right of the ordinary text, this will contain
|
||||||
|
/// the |lcs-eol| char if set, otherwise just be a space.
|
||||||
|
///
|
||||||
|
/// @param buffer Buffer handle
|
||||||
|
/// @param src_id Source group to use or 0 to use a new group,
|
||||||
|
/// or -1 for a ungrouped annotation
|
||||||
|
/// @param line Line to annotate with virtual text (zero-indexed)
|
||||||
|
/// @param chunks A list of [text, hl_group] arrays, each representing a
|
||||||
|
/// text chunk with specified highlight. `hl_group` element
|
||||||
|
/// can be omitted for no highlight.
|
||||||
|
/// @param opts Optional parameters. Currently not used.
|
||||||
|
/// @param[out] err Error details, if any
|
||||||
|
/// @return The src_id that was used
|
||||||
|
Integer nvim_buf_set_virtual_text(Buffer buffer,
|
||||||
|
Integer src_id,
|
||||||
|
Integer line,
|
||||||
|
Array chunks,
|
||||||
|
Dictionary opts,
|
||||||
|
Error *err)
|
||||||
|
FUNC_API_SINCE(5)
|
||||||
|
{
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
if (!buf) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line < 0 || line >= MAXLNUM) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "Line number outside range");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.size > 0) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtText virt_text = KV_INITIAL_VALUE;
|
||||||
|
for (size_t i = 0; i < chunks.size; i++) {
|
||||||
|
if (chunks.items[i].type != kObjectTypeArray) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
|
||||||
|
goto free_exit;
|
||||||
|
}
|
||||||
|
Array chunk = chunks.items[i].data.array;
|
||||||
|
if (chunk.size == 0 || chunk.size > 2
|
||||||
|
|| chunk.items[0].type != kObjectTypeString
|
||||||
|
|| (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
"Chunk is not an array with one or two strings");
|
||||||
|
goto free_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
String str = chunk.items[0].data.string;
|
||||||
|
char *text = xstrdup(str.size > 0 ? str.data : "");
|
||||||
|
|
||||||
|
int hl_id = 0;
|
||||||
|
if (chunk.size == 2) {
|
||||||
|
String hl = chunk.items[1].data.string;
|
||||||
|
if (hl.size > 0) {
|
||||||
|
hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
|
||||||
|
}
|
||||||
|
|
||||||
|
src_id = bufhl_add_virt_text(buf, (int)src_id, (linenr_T)line+1,
|
||||||
|
virt_text);
|
||||||
|
return src_id;
|
||||||
|
|
||||||
|
free_exit:
|
||||||
|
kv_destroy(virt_text);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if deleting lines made the cursor position invalid.
|
// Check if deleting lines made the cursor position invalid.
|
||||||
// Changed the lines from "lo" to "hi" and added "extra" lines (negative if
|
// Changed the lines from "lo" to "hi" and added "extra" lines (negative if
|
||||||
// deleted).
|
// deleted).
|
||||||
|
@ -5375,6 +5375,45 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bufhl_add_virt_text(buf_T *buf,
|
||||||
|
int src_id,
|
||||||
|
linenr_T lnum,
|
||||||
|
VirtText virt_text)
|
||||||
|
{
|
||||||
|
static int next_src_id = 1;
|
||||||
|
if (src_id == 0) {
|
||||||
|
src_id = next_src_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, true);
|
||||||
|
|
||||||
|
bufhl_clear_virttext(&lineinfo->virt_text);
|
||||||
|
if (kv_size(virt_text) > 0) {
|
||||||
|
lineinfo->virt_text_src = src_id;
|
||||||
|
lineinfo->virt_text = virt_text;
|
||||||
|
} else {
|
||||||
|
lineinfo->virt_text_src = 0;
|
||||||
|
// currently not needed, but allow a future caller with
|
||||||
|
// 0 size and non-zero capacity
|
||||||
|
kv_destroy(virt_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < lnum && lnum <= buf->b_ml.ml_line_count) {
|
||||||
|
changed_lines_buf(buf, lnum, lnum+1, 0);
|
||||||
|
redraw_buf_later(buf, VALID);
|
||||||
|
}
|
||||||
|
return src_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bufhl_clear_virttext(VirtText *text)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < kv_size(*text); i++) {
|
||||||
|
xfree(kv_A(*text, i).text);
|
||||||
|
}
|
||||||
|
kv_destroy(*text);
|
||||||
|
*text = (VirtText)KV_INITIAL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear bufhl highlights from a given source group and range of lines.
|
/// Clear bufhl highlights from a given source group and range of lines.
|
||||||
///
|
///
|
||||||
/// @param buf The buffer to remove highlights from
|
/// @param buf The buffer to remove highlights from
|
||||||
@ -5430,6 +5469,7 @@ void bufhl_clear_line_range(buf_T *buf,
|
|||||||
static BufhlLineStatus bufhl_clear_line(BufhlLine *lineinfo, int src_id,
|
static BufhlLineStatus bufhl_clear_line(BufhlLine *lineinfo, int src_id,
|
||||||
linenr_T lnum)
|
linenr_T lnum)
|
||||||
{
|
{
|
||||||
|
BufhlLineStatus changed = kBLSUnchanged;
|
||||||
size_t oldsize = kv_size(lineinfo->items);
|
size_t oldsize = kv_size(lineinfo->items);
|
||||||
if (src_id < 0) {
|
if (src_id < 0) {
|
||||||
kv_size(lineinfo->items) = 0;
|
kv_size(lineinfo->items) = 0;
|
||||||
@ -5445,14 +5485,25 @@ static BufhlLineStatus bufhl_clear_line(BufhlLine *lineinfo, int src_id,
|
|||||||
}
|
}
|
||||||
kv_size(lineinfo->items) = newidx;
|
kv_size(lineinfo->items) = newidx;
|
||||||
}
|
}
|
||||||
|
if (kv_size(lineinfo->items) != oldsize) {
|
||||||
|
changed = kBLSChanged;
|
||||||
|
}
|
||||||
|
|
||||||
if (kv_size(lineinfo->items) == 0) {
|
if (kv_size(lineinfo->virt_text) != 0
|
||||||
|
&& (src_id < 0 || src_id == lineinfo->virt_text_src)) {
|
||||||
|
bufhl_clear_virttext(&lineinfo->virt_text);
|
||||||
|
lineinfo->virt_text_src = 0;
|
||||||
|
changed = kBLSChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kv_size(lineinfo->items) == 0 && kv_size(lineinfo->virt_text) == 0) {
|
||||||
kv_destroy(lineinfo->items);
|
kv_destroy(lineinfo->items);
|
||||||
return kBLSDeleted;
|
return kBLSDeleted;
|
||||||
}
|
}
|
||||||
return kv_size(lineinfo->items) != oldsize ? kBLSChanged : kBLSUnchanged;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Remove all highlights and free the highlight data
|
/// Remove all highlights and free the highlight data
|
||||||
void bufhl_clear_all(buf_T *buf)
|
void bufhl_clear_all(buf_T *buf)
|
||||||
{
|
{
|
||||||
@ -5527,8 +5578,8 @@ bool bufhl_start_line(buf_T *buf, linenr_T lnum, BufhlLineInfo *info)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info->valid_to = -1;
|
info->valid_to = -1;
|
||||||
info->entries = lineinfo->items;
|
info->line = lineinfo;
|
||||||
return kv_size(info->entries) > 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get highlighting at column col
|
/// get highlighting at column col
|
||||||
@ -5548,8 +5599,8 @@ int bufhl_get_attr(BufhlLineInfo *info, colnr_T col)
|
|||||||
}
|
}
|
||||||
int attr = 0;
|
int attr = 0;
|
||||||
info->valid_to = MAXCOL;
|
info->valid_to = MAXCOL;
|
||||||
for (size_t i = 0; i < kv_size(info->entries); i++) {
|
for (size_t i = 0; i < kv_size(info->line->items); i++) {
|
||||||
BufhlItem entry = kv_A(info->entries, i);
|
BufhlItem entry = kv_A(info->line->items, i);
|
||||||
if (entry.start <= col && col <= entry.stop) {
|
if (entry.start <= col && col <= entry.stop) {
|
||||||
int entry_attr = syn_id2attr(entry.hl_id);
|
int entry_attr = syn_id2attr(entry.hl_id);
|
||||||
attr = hl_combine_attr(attr, entry_attr);
|
attr = hl_combine_attr(attr, entry_attr);
|
||||||
|
@ -14,16 +14,23 @@ typedef struct {
|
|||||||
colnr_T stop; // last column to highlight
|
colnr_T stop; // last column to highlight
|
||||||
} BufhlItem;
|
} BufhlItem;
|
||||||
|
|
||||||
typedef kvec_t(BufhlItem) BufhlItemVec;
|
typedef struct {
|
||||||
|
char *text;
|
||||||
|
int hl_id;
|
||||||
|
} VirtTextChunk;
|
||||||
|
|
||||||
|
typedef kvec_t(VirtTextChunk) VirtText;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
linenr_T line;
|
linenr_T line;
|
||||||
BufhlItemVec items;
|
kvec_t(BufhlItem) items;
|
||||||
|
int virt_text_src;
|
||||||
|
VirtText virt_text;
|
||||||
} BufhlLine;
|
} BufhlLine;
|
||||||
#define BUFHLLINE_INIT(l) { l, KV_INITIAL_VALUE }
|
#define BUFHLLINE_INIT(l) { l, KV_INITIAL_VALUE, 0, KV_INITIAL_VALUE }
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BufhlItemVec entries;
|
BufhlLine *line;
|
||||||
int current;
|
int current;
|
||||||
colnr_T valid_to;
|
colnr_T valid_to;
|
||||||
} BufhlLineInfo;
|
} BufhlLineInfo;
|
||||||
|
@ -132,6 +132,15 @@ static schar_T *current_ScreenLine;
|
|||||||
StlClickDefinition *tab_page_click_defs = NULL;
|
StlClickDefinition *tab_page_click_defs = NULL;
|
||||||
long tab_page_click_defs_size = 0;
|
long tab_page_click_defs_size = 0;
|
||||||
|
|
||||||
|
// for line_putchar. Contains the state that needs to be remembered from
|
||||||
|
// putting one character to the next.
|
||||||
|
typedef struct {
|
||||||
|
const char_u *p;
|
||||||
|
int prev_c; // previous Arabic character
|
||||||
|
int prev_c1; // first composing char for prev_c
|
||||||
|
} LineState;
|
||||||
|
#define LINE_STATE(p) { p, 0, 0 }
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "screen.c.generated.h"
|
# include "screen.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@ -1731,6 +1740,56 @@ static int compute_foldcolumn(win_T *wp, int col)
|
|||||||
return fdc;
|
return fdc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Put a single char from an UTF-8 buffer into a line buffer.
|
||||||
|
///
|
||||||
|
/// Handles composing chars and arabic shaping state.
|
||||||
|
static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
|
||||||
|
{
|
||||||
|
const char_u *p = s->p;
|
||||||
|
int cells = utf_ptr2cells(p);
|
||||||
|
int c_len = utfc_ptr2len(p);
|
||||||
|
int u8c, u8cc[MAX_MCO];
|
||||||
|
if (cells > maxcells) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
u8c = utfc_ptr2char(p, u8cc);
|
||||||
|
if (*p < 0x80 && u8cc[0] == 0) {
|
||||||
|
schar_from_ascii(dest[0], *p);
|
||||||
|
s->prev_c = u8c;
|
||||||
|
} else {
|
||||||
|
if (p_arshape && !p_tbidi && arabic_char(u8c)) {
|
||||||
|
// Do Arabic shaping.
|
||||||
|
int pc, pc1, nc;
|
||||||
|
int pcc[MAX_MCO];
|
||||||
|
int firstbyte = *p;
|
||||||
|
|
||||||
|
// The idea of what is the previous and next
|
||||||
|
// character depends on 'rightleft'.
|
||||||
|
if (rl) {
|
||||||
|
pc = s->prev_c;
|
||||||
|
pc1 = s->prev_c1;
|
||||||
|
nc = utf_ptr2char(p + c_len);
|
||||||
|
s->prev_c1 = u8cc[0];
|
||||||
|
} else {
|
||||||
|
pc = utfc_ptr2char(p + c_len, pcc);
|
||||||
|
nc = s->prev_c;
|
||||||
|
pc1 = pcc[0];
|
||||||
|
}
|
||||||
|
s->prev_c = u8c;
|
||||||
|
|
||||||
|
u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc);
|
||||||
|
} else {
|
||||||
|
s->prev_c = u8c;
|
||||||
|
}
|
||||||
|
schar_from_cc(dest[0], u8c, u8cc);
|
||||||
|
}
|
||||||
|
if (cells > 1) {
|
||||||
|
dest[1][0] = 0;
|
||||||
|
}
|
||||||
|
s->p += c_len;
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display one folded line.
|
* Display one folded line.
|
||||||
*/
|
*/
|
||||||
@ -1863,13 +1922,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
|
|||||||
* Right-left text is put in columns 0 - number-col, normal text is put
|
* Right-left text is put in columns 0 - number-col, normal text is put
|
||||||
* in columns number-col - window-width.
|
* in columns number-col - window-width.
|
||||||
*/
|
*/
|
||||||
int cells;
|
|
||||||
int u8c, u8cc[MAX_MCO];
|
|
||||||
int idx;
|
int idx;
|
||||||
int c_len;
|
|
||||||
char_u *p;
|
|
||||||
int prev_c = 0; // previous Arabic character
|
|
||||||
int prev_c1 = 0; // first composing char for prev_c
|
|
||||||
|
|
||||||
if (wp->w_p_rl) {
|
if (wp->w_p_rl) {
|
||||||
idx = off;
|
idx = off;
|
||||||
@ -1877,50 +1930,20 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
|
|||||||
idx = off + col;
|
idx = off + col;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store multibyte characters in ScreenLines[] et al. correctly.
|
LineState s = LINE_STATE(text);
|
||||||
for (p = text; *p != NUL; ) {
|
|
||||||
cells = utf_ptr2cells(p);
|
while (*s.p != NUL) {
|
||||||
c_len = utfc_ptr2len(p);
|
// TODO(bfredl): cargo-culted from the old Vim code:
|
||||||
if (col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) {
|
// if(col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { break; }
|
||||||
|
// This is obvious wrong. If Vim ever fixes this, solve for "cells" again
|
||||||
|
// in the correct condition.
|
||||||
|
int maxcells = wp->w_width - col - (wp->w_p_rl ? col : 0);
|
||||||
|
int cells = line_putchar(&s, &ScreenLines[idx], maxcells, wp->w_p_rl);
|
||||||
|
if (cells == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u8c = utfc_ptr2char(p, u8cc);
|
|
||||||
if (*p < 0x80 && u8cc[0] == 0) {
|
|
||||||
schar_from_ascii(ScreenLines[idx], *p);
|
|
||||||
prev_c = u8c;
|
|
||||||
} else {
|
|
||||||
if (p_arshape && !p_tbidi && arabic_char(u8c)) {
|
|
||||||
// Do Arabic shaping.
|
|
||||||
int pc, pc1, nc;
|
|
||||||
int pcc[MAX_MCO];
|
|
||||||
int firstbyte = *p;
|
|
||||||
|
|
||||||
// The idea of what is the previous and next
|
|
||||||
// character depends on 'rightleft'.
|
|
||||||
if (wp->w_p_rl) {
|
|
||||||
pc = prev_c;
|
|
||||||
pc1 = prev_c1;
|
|
||||||
nc = utf_ptr2char(p + c_len);
|
|
||||||
prev_c1 = u8cc[0];
|
|
||||||
} else {
|
|
||||||
pc = utfc_ptr2char(p + c_len, pcc);
|
|
||||||
nc = prev_c;
|
|
||||||
pc1 = pcc[0];
|
|
||||||
}
|
|
||||||
prev_c = u8c;
|
|
||||||
|
|
||||||
u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc);
|
|
||||||
} else {
|
|
||||||
prev_c = u8c;
|
|
||||||
}
|
|
||||||
schar_from_cc(ScreenLines[idx], u8c, u8cc);
|
|
||||||
}
|
|
||||||
if (cells > 1) {
|
|
||||||
ScreenLines[idx + 1][0] = 0;
|
|
||||||
}
|
|
||||||
col += cells;
|
col += cells;
|
||||||
idx += cells;
|
idx += cells;
|
||||||
p += c_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill the rest of the line with the fold filler */
|
/* Fill the rest of the line with the fold filler */
|
||||||
@ -2215,9 +2238,9 @@ win_line (
|
|||||||
int did_line_attr = 0;
|
int did_line_attr = 0;
|
||||||
|
|
||||||
bool search_attr_from_match = false; // if search_attr is from :match
|
bool search_attr_from_match = false; // if search_attr is from :match
|
||||||
bool has_bufhl = false; // this buffer has highlight matches
|
|
||||||
int bufhl_attr = 0; // attributes desired by bufhl
|
|
||||||
BufhlLineInfo bufhl_info; // bufhl data for this line
|
BufhlLineInfo bufhl_info; // bufhl data for this line
|
||||||
|
bool has_bufhl = false; // this buffer has highlight matches
|
||||||
|
bool do_virttext = false; // draw virtual text for this line
|
||||||
|
|
||||||
/* draw_state: items that are drawn in sequence: */
|
/* draw_state: items that are drawn in sequence: */
|
||||||
#define WL_START 0 /* nothing done yet */
|
#define WL_START 0 /* nothing done yet */
|
||||||
@ -2279,8 +2302,13 @@ win_line (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bufhl_start_line(wp->w_buffer, lnum, &bufhl_info)) {
|
if (bufhl_start_line(wp->w_buffer, lnum, &bufhl_info)) {
|
||||||
has_bufhl = true;
|
if (kv_size(bufhl_info.line->items)) {
|
||||||
extra_check = true;
|
has_bufhl = true;
|
||||||
|
extra_check = true;
|
||||||
|
}
|
||||||
|
if (kv_size(bufhl_info.line->virt_text)) {
|
||||||
|
do_virttext = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for columns to display for 'colorcolumn'.
|
// Check for columns to display for 'colorcolumn'.
|
||||||
@ -3429,7 +3457,7 @@ win_line (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (has_bufhl && v > 0) {
|
if (has_bufhl && v > 0) {
|
||||||
bufhl_attr = bufhl_get_attr(&bufhl_info, (colnr_T)v);
|
int bufhl_attr = bufhl_get_attr(&bufhl_info, (colnr_T)v);
|
||||||
if (bufhl_attr != 0) {
|
if (bufhl_attr != 0) {
|
||||||
if (!attr_pri) {
|
if (!attr_pri) {
|
||||||
char_attr = hl_combine_attr(char_attr, bufhl_attr);
|
char_attr = hl_combine_attr(char_attr, bufhl_attr);
|
||||||
@ -3949,40 +3977,87 @@ win_line (
|
|||||||
&& (int)wp->w_virtcol <
|
&& (int)wp->w_virtcol <
|
||||||
wp->w_width * (row - startrow + 1) + v
|
wp->w_width * (row - startrow + 1) + v
|
||||||
&& lnum != wp->w_cursor.lnum)
|
&& lnum != wp->w_cursor.lnum)
|
||||||
|| draw_color_col)
|
|| draw_color_col || do_virttext)
|
||||||
&& !wp->w_p_rl
|
&& !wp->w_p_rl) {
|
||||||
) {
|
|
||||||
int rightmost_vcol = 0;
|
int rightmost_vcol = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (wp->w_p_cuc)
|
VirtText virt_text = do_virttext ? bufhl_info.line->virt_text
|
||||||
|
: (VirtText)KV_INITIAL_VALUE;
|
||||||
|
size_t virt_pos = 0;
|
||||||
|
LineState s = LINE_STATE((char_u *)"");
|
||||||
|
int virt_attr = 0;
|
||||||
|
|
||||||
|
// Make sure alignment is the same regardless
|
||||||
|
// if listchars=eol:X is used or not.
|
||||||
|
bool delay_virttext = lcs_eol <= 0;
|
||||||
|
|
||||||
|
if (wp->w_p_cuc) {
|
||||||
rightmost_vcol = wp->w_virtcol;
|
rightmost_vcol = wp->w_virtcol;
|
||||||
if (draw_color_col)
|
}
|
||||||
/* determine rightmost colorcolumn to possibly draw */
|
|
||||||
for (i = 0; color_cols[i] >= 0; ++i)
|
if (draw_color_col) {
|
||||||
if (rightmost_vcol < color_cols[i])
|
// determine rightmost colorcolumn to possibly draw
|
||||||
|
for (i = 0; color_cols[i] >= 0; i++) {
|
||||||
|
if (rightmost_vcol < color_cols[i]) {
|
||||||
rightmost_vcol = color_cols[i];
|
rightmost_vcol = color_cols[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cuc_attr = win_hl_attr(wp, HLF_CUC);
|
int cuc_attr = win_hl_attr(wp, HLF_CUC);
|
||||||
int mc_attr = win_hl_attr(wp, HLF_MC);
|
int mc_attr = win_hl_attr(wp, HLF_MC);
|
||||||
|
|
||||||
while (col < wp->w_width) {
|
while (col < wp->w_width) {
|
||||||
schar_from_ascii(ScreenLines[off], ' ');
|
int cells = -1;
|
||||||
col++;
|
if (do_virttext && !delay_virttext) {
|
||||||
|
if (*s.p == NUL) {
|
||||||
|
if (virt_pos < virt_text.size) {
|
||||||
|
s.p = (char_u *)kv_A(virt_text, virt_pos).text;
|
||||||
|
int hl_id = kv_A(virt_text, virt_pos).hl_id;
|
||||||
|
virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
|
||||||
|
virt_pos++;
|
||||||
|
} else {
|
||||||
|
do_virttext = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*s.p != NUL) {
|
||||||
|
cells = line_putchar(&s, &ScreenLines[off], wp->w_width - col,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay_virttext = false;
|
||||||
|
|
||||||
|
if (cells == -1) {
|
||||||
|
schar_from_ascii(ScreenLines[off], ' ');
|
||||||
|
cells = 1;
|
||||||
|
}
|
||||||
|
col += cells;
|
||||||
if (draw_color_col) {
|
if (draw_color_col) {
|
||||||
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
|
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int attr = 0;
|
||||||
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) {
|
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) {
|
||||||
ScreenAttrs[off++] = cuc_attr;
|
attr = cuc_attr;
|
||||||
} else if (draw_color_col && VCOL_HLC == *color_cols) {
|
} else if (draw_color_col && VCOL_HLC == *color_cols) {
|
||||||
ScreenAttrs[off++] = mc_attr;
|
attr = mc_attr;
|
||||||
} else {
|
|
||||||
ScreenAttrs[off++] = wp->w_hl_attr_normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VCOL_HLC >= rightmost_vcol)
|
if (do_virttext) {
|
||||||
|
attr = hl_combine_attr(attr, virt_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenAttrs[off] = attr;
|
||||||
|
if (cells == 2) {
|
||||||
|
ScreenAttrs[off+1] = attr;
|
||||||
|
}
|
||||||
|
off += cells;
|
||||||
|
|
||||||
|
if (VCOL_HLC >= rightmost_vcol && *s.p == NUL
|
||||||
|
&& virt_pos >= virt_text.size) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
++vcol;
|
++vcol;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,10 @@ describe('Buffer highlighting', function()
|
|||||||
[7] = {bold = true},
|
[7] = {bold = true},
|
||||||
[8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
|
[8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
|
||||||
[9] = {foreground = Screen.colors.SlateBlue, underline = true},
|
[9] = {foreground = Screen.colors.SlateBlue, underline = true},
|
||||||
[10] = {foreground = Screen.colors.Red}
|
[10] = {foreground = Screen.colors.Red},
|
||||||
|
[11] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||||
|
[12] = {foreground = Screen.colors.Blue1},
|
||||||
|
[13] = {background = Screen.colors.LightGrey},
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -77,7 +80,7 @@ describe('Buffer highlighting', function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
|
|
||||||
clear_hl(-1, 0 , -1)
|
clear_hl(-1, 0, -1)
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
these are some lines |
|
these are some lines |
|
||||||
^ |
|
^ |
|
||||||
@ -275,4 +278,140 @@ describe('Buffer highlighting', function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('supports virtual text annotations', function()
|
||||||
|
local set_virtual_text = curbufmeths.set_virtual_text
|
||||||
|
insert([[
|
||||||
|
1 + 2
|
||||||
|
3 +
|
||||||
|
x = 4]])
|
||||||
|
feed('O<esc>20A5, <esc>gg')
|
||||||
|
screen:expect([[
|
||||||
|
^1 + 2 |
|
||||||
|
3 + |
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, |
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
local id1 = set_virtual_text(0, 0, {{"=", "Statement"}, {" 3", "Number"}}, {})
|
||||||
|
set_virtual_text(id1, 1, {{"ERROR:", "ErrorMsg"}, {" invalid syntax"}}, {})
|
||||||
|
local id2 = set_virtual_text(0, 2, {{"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}}, {})
|
||||||
|
neq(id2, id1)
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
^1 + 2 {3:=}{2: 3} |
|
||||||
|
3 + {11:ERROR:} invalid syntax |
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
clear_hl(id1, 0, -1)
|
||||||
|
screen:expect([[
|
||||||
|
^1 + 2 |
|
||||||
|
3 + |
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- Handles doublewidth chars, leaving a space if truncating
|
||||||
|
-- in the middle of a char
|
||||||
|
set_virtual_text(id1, 1, {{"暗x事zz速野谷質結育副住新覚丸活解終事", "Comment"}}, {})
|
||||||
|
screen:expect([[
|
||||||
|
^1 + 2 |
|
||||||
|
3 + {12:暗x事zz速野谷質結育副住新覚丸活解終 }|
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed("2Gx")
|
||||||
|
screen:expect([[
|
||||||
|
1 + 2 |
|
||||||
|
^ + {12:暗x事zz速野谷質結育副住新覚丸活解終事}|
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- visual selection doesn't highlight virtual text
|
||||||
|
feed("ggVG")
|
||||||
|
screen:expect([[
|
||||||
|
{13:1 + 2} |
|
||||||
|
{13: +} {12:暗x事zz速野谷質結育副住新覚丸活解終事}|
|
||||||
|
{13:5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
|
||||||
|
{13:, 5, 5, 5, 5, 5, 5, } Lorem ipsum dolor s|
|
||||||
|
^x{13: = 4} |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{7:-- VISUAL LINE --} |
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed("<esc>")
|
||||||
|
screen:expect([[
|
||||||
|
1 + 2 |
|
||||||
|
+ {12:暗x事zz速野谷質結育副住新覚丸活解終事}|
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
^x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed("2Gdd")
|
||||||
|
screen:expect([[
|
||||||
|
1 + 2 |
|
||||||
|
^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- listchars=eol:- works, and doesn't shift virtual text
|
||||||
|
command("set list")
|
||||||
|
screen:expect([[
|
||||||
|
1 + 2 |
|
||||||
|
^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5,{1:-} Lorem ipsum dolor s|
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
clear_hl(-1, 0, -1)
|
||||||
|
screen:expect([[
|
||||||
|
1 + 2 |
|
||||||
|
^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
|
||||||
|
, 5, 5, 5, 5, 5, 5,{1:-} |
|
||||||
|
x = 4 |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user