aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/extmark.c11
-rw-r--r--src/nvim/decoration.h4
-rw-r--r--src/nvim/decoration_defs.h5
-rw-r--r--src/nvim/drawline.c44
4 files changed, 58 insertions, 6 deletions
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index e66140da5a..778e857057 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -400,6 +400,15 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// (highest priority last).
/// - virt_text_pos : position of virtual text. Possible values:
/// - "eol": right after eol character (default).
+/// - "eol_right_align": display right aligned in the window
+/// unless the virtual text is longer than
+/// the space available. If the virtual
+/// text is too long, it is truncated to
+/// fit in the window after the EOL
+/// character. If the line is wrapped, the
+/// virtual text is shown after the end of
+/// the line rather than the previous
+/// screen line.
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
/// - "right_align": display right aligned in the window.
@@ -620,6 +629,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
virt_text.pos = kVPosOverlay;
} else if (strequal("right_align", str.data)) {
virt_text.pos = kVPosRightAlign;
+ } else if (strequal("eol_right_align", str.data)) {
+ virt_text.pos = kVPosEndOfLineRightAlign;
} else if (strequal("inline", str.data)) {
virt_text.pos = kVPosInline;
} else {
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index a2f4fefd45..bdbb1795cb 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -15,8 +15,8 @@
// actual Decor* data is in decoration_defs.h
/// Keep in sync with VirtTextPos in decoration_defs.h
-EXTERN const char *const virt_text_pos_str[]
-INIT( = { "eol", "overlay", "win_col", "right_align", "inline" });
+EXTERN const char *const virt_text_pos_str[] INIT( = { "eol", "eol_right_align", "inline",
+ "overlay", "right_align", "win_col" });
/// Keep in sync with HlMode in decoration_defs.h
EXTERN const char *const hl_mode_str[] INIT( = { "", "replace", "combine", "blend" });
diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h
index 58ba93a7ba..36ad6df7a0 100644
--- a/src/nvim/decoration_defs.h
+++ b/src/nvim/decoration_defs.h
@@ -19,10 +19,11 @@ typedef kvec_t(VirtTextChunk) VirtText;
/// Keep in sync with virt_text_pos_str[] in decoration.h
typedef enum {
kVPosEndOfLine,
+ kVPosEndOfLineRightAlign,
+ kVPosInline,
kVPosOverlay,
- kVPosWinCol,
kVPosRightAlign,
- kVPosInline,
+ kVPosWinCol,
} VirtTextPos;
typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 4a7bc9170a..37a42917b0 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -263,6 +263,9 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
int *const indices = state->ranges_i.items;
DecorRangeSlot *const slots = state->slots.items;
+ /// Total width of all virtual text with "eol_right_align" alignment
+ int totalWidthOfEolRightAlignedVirtText = 0;
+
for (int i = 0; i < end; i++) {
DecorRange *item = &slots[indices[i]].range;
if (!(item->start_row == state->row && decor_virt_pos(item))) {
@@ -277,7 +280,44 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
if (decor_virt_pos(item) && item->draw_col == -1) {
bool updated = true;
VirtTextPos pos = decor_virt_pos_kind(item);
- if (pos == kVPosRightAlign) {
+
+ if (do_eol && pos == kVPosEndOfLineRightAlign) {
+ int eolOffset = 0;
+ if (totalWidthOfEolRightAlignedVirtText == 0) {
+ // Look ahead to the remaining decor items
+ for (int j = i; j < end; j++) {
+ /// A future decor to be handled in this function's call
+ DecorRange *lookaheadItem = &slots[indices[j]].range;
+
+ if (lookaheadItem->start_row != state->row
+ || !decor_virt_pos(lookaheadItem)
+ || lookaheadItem->draw_col != -1) {
+ continue;
+ }
+
+ /// The Virtual Text of the decor item we're looking ahead to
+ DecorVirtText *lookaheadVt = NULL;
+ if (item->kind == kDecorKindVirtText) {
+ assert(item->data.vt);
+ lookaheadVt = item->data.vt;
+ }
+
+ if (decor_virt_pos_kind(lookaheadItem) == kVPosEndOfLineRightAlign) {
+ // An extra space is added for single character spacing in EOL alignment
+ totalWidthOfEolRightAlignedVirtText += (lookaheadVt->width + 1);
+ }
+ }
+
+ // Remove one space from the total width since there's no single space after the last entry
+ totalWidthOfEolRightAlignedVirtText--;
+
+ if (totalWidthOfEolRightAlignedVirtText <= (right_pos - state->eol_col)) {
+ eolOffset = right_pos - totalWidthOfEolRightAlignedVirtText - state->eol_col;
+ }
+ }
+
+ item->draw_col = state->eol_col + eolOffset;
+ } else if (pos == kVPosRightAlign) {
right_pos -= vt->width;
item->draw_col = right_pos;
} else if (pos == kVPosEndOfLine && do_eol) {
@@ -304,7 +344,7 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
int vcol = item->draw_col - col_off;
int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text,
vt->hl_mode, max_col, vcol);
- if (vt->pos == kVPosEndOfLine && do_eol) {
+ if (do_eol && ((vt->pos == kVPosEndOfLine) || (vt->pos == kVPosEndOfLineRightAlign))) {
state->eol_col = col + 1;
}
*end_col = MAX(*end_col, col);