Skip to content

Instantly share code, notes, and snippets.

@qRoC
Created November 2, 2022 19:00
Show Gist options
  • Save qRoC/31ffa9b9431e63dd4cddd82b82d5813d to your computer and use it in GitHub Desktop.
Save qRoC/31ffa9b9431e63dd4cddd82b82d5813d to your computer and use it in GitHub Desktop.
From 26641de736600618efbb99ee31c4ffec522433d2 Mon Sep 17 00:00:00 2001
From: Andrii Savytskyi <contact@qroc.pro>
Date: Wed, 2 Nov 2022 20:58:03 +0200
Subject: [PATCH] 20130
---
src/nvim/api/extmark.c | 4 ++++
src/nvim/decoration.h | 3 ++-
src/nvim/drawline.c | 48 +++++++++++++++++++++++++++++++++++++-----
src/nvim/plines.c | 27 ++++++++++++++++++++++--
src/nvim/plines.h | 2 ++
5 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 3b1b47062..f5806c043 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -399,6 +399,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
/// - "right_align": display right aligned in the window.
+/// - "inline": display at the specified column, and
+/// shift the buffer text to the right as needed
/// - virt_text_win_col : position the virtual text at a fixed
/// window column (starting from the first
/// text column)
@@ -613,6 +615,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
decor.virt_text_pos = kVTOverlay;
} else if (strequal("right_align", str.data)) {
decor.virt_text_pos = kVTRightAlign;
+ } else if (strequal("inline", str.data)) {
+ decor.virt_text_pos = kVTInline;
} else {
api_set_error(err, kErrorTypeValidation, "virt_text_pos: invalid value");
goto error;
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index bdbfd72a8..2dd7912a3 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -15,9 +15,10 @@ typedef enum {
kVTOverlay,
kVTWinCol,
kVTRightAlign,
+ kVTInline,
} VirtTextPos;
-EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align" });
+EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align", "inline" });
typedef enum {
kHlModeUnknown,
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 08b6fd89a..c8d52c105 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -590,6 +590,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
int left_curline_col = 0;
int right_curline_col = 0;
+ VirtText virt_inline = KV_INITIAL_VALUE;
+ size_t virt_inline_i = 0;
+
// draw_state: items that are drawn in sequence:
#define WL_START 0 // nothing done yet
#define WL_CMDLINE (WL_START + 1) // cmdline window column
@@ -1384,7 +1387,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
n_extra = 0;
}
- if (draw_state == WL_LINE && (area_highlighting || has_spell)) {
+ int extmark_attr = 0;
+ if (draw_state == WL_LINE && (area_highlighting || has_spell || extra_check)) {
// handle Visual or match highlighting in this line
if (vcol == fromcol
|| (vcol + 1 == fromcol && n_extra == 0
@@ -1439,6 +1443,44 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
+ if (has_decor && v >= 0) {
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && (colnr_T)vcol == wp->w_virtcol));
+ extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v, off,
+ selected, &decor_state);
+
+ // we could already be inside an existing virt_line with multiple chunks
+ if (!(virt_inline_i < kv_size(virt_inline))) {
+ DecorState *state = &decor_state;
+ 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 == kVTInline)) {
+ continue;
+ }
+ if (item->win_col >= -1 && item->start_col <= v) {
+ virt_inline = item->decor.virt_text;
+ virt_inline_i = 0;
+ item->win_col = -2;
+ break;
+ }
+ }
+ }
+
+ if (n_extra <= 0 && virt_inline_i < kv_size(virt_inline)) {
+ VirtTextChunk vtc = kv_A(virt_inline, virt_inline_i);
+ p_extra = (char_u *)vtc.text;
+ n_extra = (int)STRLEN(p_extra);
+ c_extra = NUL;
+ c_final = NUL;
+ extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
+ n_attr = n_extra;
+ extmark_attr = 0;
+ virt_inline_i++;
+ }
+ }
+
// Decide which of the highlight attributes to use.
attr_pri = true;
@@ -1702,10 +1744,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
if (has_decor && v > 0) {
- bool selected = (area_active || (area_highlighting && noinvcur
- && (colnr_T)vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off,
- selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
char_attr = hl_combine_attr(char_attr, extmark_attr);
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 42218ac84..0c8b69395 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -302,8 +302,16 @@ void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum FUNC_ATTR
cts->cts_line = line;
cts->cts_ptr = ptr;
cts->cts_cur_text_width = 0;
- // TODO(bfredl): actually lookup inline virtual text here
cts->cts_has_virt_text = false;
+ cts->cts_row = lnum - 1;
+
+ if (cts->cts_row >= 0) {
+ marktree_itr_get(wp->w_buffer->b_marktree, cts->cts_row, 0, cts->cts_iter);
+ mtkey_t mark = marktree_itr_current(cts->cts_iter);
+ if (mark.pos.row == lnum - 1) {
+ cts->cts_has_virt_text = true;
+ }
+ }
}
/// Free any allocated item in "cts".
@@ -385,7 +393,22 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// First get normal size, without 'linebreak' or virtual text
int size = win_chartabsize(wp, (char *)s, vcol);
if (cts->cts_has_virt_text) {
- // TODO(bfredl): inline virtual text
+ int col = (int)((char *)s - line);
+ while (true) {
+ mtkey_t mark = marktree_itr_current(cts->cts_iter);
+ if (mark.pos.row != cts->cts_row || mark.pos.col > col) {
+ break;
+ } else if (mark.pos.col == col) { // TODO: or maybe unconditionally, what if byte-misaligned?
+ if (!mt_end(mark)) {
+ Decoration decor = get_decor(mark);
+ if (decor.virt_text_pos == kVTInline) {
+ cts->cts_cur_text_width = decor.virt_text_width;
+ size += cts->cts_cur_text_width;
+ }
+ }
+ }
+ marktree_itr_next(wp->w_buffer->b_marktree, cts->cts_iter);
+ }
}
int c = *s;
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
index f463d82f1..05f91fc07 100644
--- a/src/nvim/plines.h
+++ b/src/nvim/plines.h
@@ -8,9 +8,11 @@ typedef struct {
win_T *cts_win;
char *cts_line; // start of the line
char *cts_ptr; // current position in line
+ int cts_row;
bool cts_has_virt_text; // true if if a property inserts text
int cts_cur_text_width; // width of current inserted text
+ MarkTreeIter cts_iter[1];
// TODO(bfredl): iterator in to the marktree for scanning virt text
int cts_vcol; // virtual column at current position
--
2.38.1
@qRoC
Copy link
Author

qRoC commented Nov 2, 2022

brew edit nvim

+    patch do
+          url "https://gist.githubusercontent.com/qRoC/31ffa9b9431e63dd4cddd82b82d5813d/raw/984529e36077bc211c6fc430e4bac8c880cba838/20130.patch"
+          sha256 "ef4eaad807860190d546f32ce798053936a658e187dc2e62aa5116fa52467ada"
+    end

    def install

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment