feat(extmarks): virtual text can be right-aligned, truncated #31921

Problem: Right aligned virtual text can cover up buffer text if virtual
text is too long

Solution: An additional option for `virt_text_pos` called
`eol_right_align` has been added to truncate virtual text if it would
have otherwise covered up buffer text. This ensures the virtual text
extends no further left than EOL.
This commit is contained in:
georgev93
2025-01-24 22:57:45 -05:00
committed by GitHub
parent c6d2cbf8f5
commit 931ee5591f
10 changed files with 143 additions and 10 deletions

View File

@@ -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);