aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c23
-rw-r--r--src/nvim/decoration.c26
-rw-r--r--src/nvim/decoration.h7
-rw-r--r--src/nvim/screen.c106
4 files changed, 108 insertions, 54 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index e79a7a2de2..cc5a62a170 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1426,6 +1426,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - "eol": right after eol character (default)
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
+/// - "right_align": display right aligned in the window.
+/// - virt_text_win_col : position the virtual text at a fixed
+/// window column (starting from the first
+/// text column)
/// - virt_text_hide : hide the virtual text when the background
/// text is selected or hidden due to
/// horizontal scroll 'nowrap'
@@ -1574,11 +1578,22 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) {
decor.virt_text_pos = kVTOverlay;
+ } else if (strequal("right_align", str.data)) {
+ decor.virt_text_pos = kVTRightAlign;
} else {
api_set_error(err, kErrorTypeValidation,
"virt_text_pos: invalid value");
goto error;
}
+ } else if (strequal("virt_text_win_col", k.data)) {
+ if (v->type != kObjectTypeInteger) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_win_col is not a Number of the correct size");
+ goto error;
+ }
+
+ decor.col = (int)v->data.integer;
+ decor.virt_text_pos = kVTWinCol;
} else if (strequal("virt_text_hide", k.data)) {
decor.virt_text_hide = api_object_to_bool(*v,
"virt_text_hide", false, err);
@@ -1673,6 +1688,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0;
}
+ if (decor.virt_text_pos == kVTRightAlign) {
+ decor.col = 0;
+ for (size_t i = 0; i < kv_size(decor.virt_text); i++) {
+ decor.col += mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
+ }
+ }
+
+
Decoration *d = NULL;
if (ephemeral) {
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index e39d2328f5..ca1d141dd8 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -230,6 +230,10 @@ static void decor_add(DecorState *state, int start_row, int start_col,
*decor, attr_id,
kv_size(decor->virt_text) && owned, -1 };
+ if (decor->virt_text_pos == kVTEndOfLine) {
+ range.win_col = -2; // handled separately
+ }
+
kv_pushp(state->active);
size_t index;
for (index = kv_size(state->active)-1; index > 0; index--) {
@@ -242,7 +246,7 @@ static void decor_add(DecorState *state, int start_row, int start_col,
kv_A(state->active, index) = range;
}
-int decor_redraw_col(buf_T *buf, int col, int virt_col, bool hidden,
+int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden,
DecorState *state)
{
if (col <= state->col_until) {
@@ -321,8 +325,9 @@ next_mark:
attr = hl_combine_attr(attr, item.attr_id);
}
if ((item.start_row == state->row && item.start_col <= col)
- && kv_size(item.decor.virt_text) && item.virt_col == -1) {
- item.virt_col = (item.decor.virt_text_hide && hidden) ? -2 : virt_col;
+ && kv_size(item.decor.virt_text)
+ && item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) {
+ item.win_col = (item.decor.virt_text_hide && hidden) ? -2 : win_col;
}
if (keep) {
kv_A(state->active, j++) = item;
@@ -340,18 +345,23 @@ void decor_redraw_end(DecorState *state)
state->buf = NULL;
}
-VirtText decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr)
+VirtText decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr,
+ bool *aligned)
{
decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
VirtText text = VIRTTEXT_EMPTY;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange item = kv_A(state->active, i);
- if (!kv_size(text)
- && item.start_row == state->row && kv_size(item.decor.virt_text)
- && item.decor.virt_text_pos == kVTEndOfLine) {
- text = item.decor.virt_text;
+ if (item.start_row == state->row && kv_size(item.decor.virt_text)) {
+ if (!kv_size(text) && item.decor.virt_text_pos == kVTEndOfLine) {
+ text = item.decor.virt_text;
+ } else if (item.decor.virt_text_pos == kVTRightAlign
+ || item.decor.virt_text_pos == kVTWinCol) {
+ *aligned = true;
+ }
}
+
if (item.decor.hl_eol && item.start_row <= state->row) {
*eol_attr = hl_combine_attr(*eol_attr, item.attr_id);
}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 08d69060f0..4cebc0b731 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -21,6 +21,8 @@ typedef uint16_t DecorPriority;
typedef enum {
kVTEndOfLine,
kVTOverlay,
+ kVTWinCol,
+ kVTRightAlign,
} VirtTextPos;
typedef enum {
@@ -41,9 +43,10 @@ struct Decoration
// TODO(bfredl): style, signs, etc
DecorPriority priority;
bool shared; // shared decoration, don't free
+ int col; // fixed col value, like win_col
};
#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \
- kHlModeUnknown, false, DECOR_PRIORITY_BASE, false }
+ kHlModeUnknown, false, DECOR_PRIORITY_BASE, false, 0 }
typedef struct {
int start_row;
@@ -53,7 +56,7 @@ typedef struct {
Decoration decor;
int attr_id; // cached lookup of decor.hl_id
bool virt_text_owned;
- int virt_col;
+ int win_col;
} DecorRange;
typedef struct {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 6be3b6fb60..5151d82c1b 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2101,6 +2101,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
bool search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
bool do_virttext = false; // draw virtual text for this line
+ int win_col_offset; // offsett for window columns
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
@@ -2790,6 +2791,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
+ if (draw_state == WL_NR && n_extra == 0) {
+ win_col_offset = off;
+ }
+
if (wp->w_briopt_sbr && draw_state == WL_BRI - 1
&& n_extra == 0 && *p_sbr != NUL) {
// draw indent after showbreak value
@@ -2904,7 +2909,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
&& filler_todo <= 0) {
- draw_virt_text(buf, &col, grid->Columns);
+ draw_virt_text(buf, win_col_offset, &col, grid->Columns);
grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
@@ -3945,13 +3950,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
VirtText virt_text = KV_INITIAL_VALUE;
+ bool has_aligned = false;
if (err_text) {
int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg"));
kv_push(virt_text, ((VirtTextChunk){ .text = err_text,
.hl_id = hl_err }));
do_virttext = true;
} else if (has_decor) {
- virt_text = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr);
+ virt_text = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr,
+ &has_aligned);
if (kv_size(virt_text)) {
do_virttext = true;
}
@@ -3963,7 +3970,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
grid->Columns * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
|| draw_color_col || line_attr_lowprio || line_attr
- || diff_hlf != (hlf_T)0 || do_virttext)) {
+ || diff_hlf != (hlf_T)0 || do_virttext
+ || has_aligned)) {
int rightmost_vcol = 0;
int i;
@@ -4001,7 +4009,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr);
- if (base_attr || line_attr) {
+ if (base_attr || line_attr || has_aligned) {
rightmost_vcol = INT_MAX;
}
@@ -4079,7 +4087,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- draw_virt_text(buf, &col, grid->Columns);
+ draw_virt_text(buf, win_col_offset, &col, grid->Columns);
grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
row++;
@@ -4300,7 +4308,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& !wp->w_p_rl; // Not right-to-left.
int draw_col = col - boguscols;
- draw_virt_text(buf, &draw_col, grid->Columns);
+ draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
@@ -4377,52 +4385,62 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
return row;
}
-void draw_virt_text(buf_T *buf, int *end_col, int max_col)
+void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
{
DecorState *state = &decor_state;
+ int right_pos = max_col;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
- if (item->start_row == state->row && kv_size(item->decor.virt_text)
- && item->decor.virt_text_pos == kVTOverlay
- && item->virt_col >= 0) {
- VirtText vt = item->decor.virt_text;
- HlMode hl_mode = item->decor.hl_mode;
- LineState s = LINE_STATE("");
- int virt_attr = 0;
- int col = item->virt_col;
- size_t virt_pos = 0;
- item->virt_col = -2; // deactivate
+ if (item->start_row == state->row && kv_size(item->decor.virt_text)) {
+ if (item->win_col == -1) {
+ if (item->decor.virt_text_pos == kVTRightAlign) {
+ right_pos -= item->decor.col;
+ item->win_col = right_pos;
+ } else if (item->decor.virt_text_pos == kVTWinCol) {
+ item->win_col = MAX(item->decor.col+col_off, 0);
+ }
+ }
+ if (item->win_col < 0) {
+ continue;
+ }
+ VirtText vt = item->decor.virt_text;
+ HlMode hl_mode = item->decor.hl_mode;
+ LineState s = LINE_STATE("");
+ int virt_attr = 0;
+ int col = item->win_col;
+ size_t virt_pos = 0;
+ item->win_col = -2; // deactivate
- while (col < max_col) {
- if (!*s.p) {
- if (virt_pos == kv_size(vt)) {
- break;
- }
- s.p = kv_A(vt, virt_pos).text;
- int hl_id = kv_A(vt, virt_pos).hl_id;
- virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- virt_pos++;
- continue;
- }
- int attr;
- bool through = false;
- if (hl_mode == kHlModeCombine) {
- attr = hl_combine_attr(linebuf_attr[col], virt_attr);
- } else if (hl_mode == kHlModeBlend) {
- through = (*s.p == ' ');
- attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
- } else {
- attr = virt_attr;
+ while (col < max_col) {
+ if (!*s.p) {
+ if (virt_pos == kv_size(vt)) {
+ break;
}
- schar_T dummy[2];
- int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
- max_col-col, false);
+ s.p = kv_A(vt, virt_pos).text;
+ int hl_id = kv_A(vt, virt_pos).hl_id;
+ virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
+ virt_pos++;
+ continue;
+ }
+ int attr;
+ bool through = false;
+ if (hl_mode == kHlModeCombine) {
+ attr = hl_combine_attr(linebuf_attr[col], virt_attr);
+ } else if (hl_mode == kHlModeBlend) {
+ through = (*s.p == ' ');
+ attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
+ } else {
+ attr = virt_attr;
+ }
+ schar_T dummy[2];
+ int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
+ max_col-col, false);
+ linebuf_attr[col++] = attr;
+ if (cells > 1) {
linebuf_attr[col++] = attr;
- if (cells > 1) {
- linebuf_attr[col++] = attr;
- }
}
- *end_col = MAX(*end_col, col);
+ }
+ *end_col = MAX(*end_col, col);
}
}
}