diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/extmark.c | 11 | ||||
-rw-r--r-- | src/nvim/decoration.h | 4 | ||||
-rw-r--r-- | src/nvim/decoration_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/drawline.c | 44 |
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); |