Skip to content

Instantly share code, notes, and snippets.

@shebpamm
Last active March 8, 2023 12:18
Show Gist options
  • Save shebpamm/5eaa7a43ba6fa5eca6075af67f2d6b60 to your computer and use it in GitHub Desktop.
Save shebpamm/5eaa7a43ba6fa5eca6075af67f2d6b60 to your computer and use it in GitHub Desktop.
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 9e03cc867..c2782037a 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -408,6 +408,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)
@@ -626,6 +628,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 {
VALIDATE_S(false, "virt_text_pos", "", {
goto error;
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index c9ec8ede7..fc63616c8 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -23,9 +23,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 a46f383f6..ff9f81c1e 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -960,6 +960,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
int match_conc = 0; ///< cchar for match functions
bool on_last_col = false;
+ VirtText virt_inline = KV_INITIAL_VALUE;
+ size_t virt_inline_i = 0;
+
int syntax_flags = 0;
int syntax_seqnr = 0;
int prev_syntax_id = 0;
@@ -1617,7 +1620,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = 0;
}
- if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) {
+ int extmark_attr = 0;
+ if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell || extra_check)) {
// handle Visual or match highlighting in this line
if (wlv.vcol == wlv.fromcol
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
@@ -1671,6 +1675,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)wlv.vcol == wp->w_virtcol));
+ extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v, wlv.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 (wlv.n_extra <= 0 && virt_inline_i < kv_size(virt_inline)) {
+ VirtTextChunk vtc = kv_A(virt_inline, virt_inline_i);
+ wlv.p_extra = vtc.text;
+ wlv.n_extra = (int)strlen(wlv.p_extra);
+ wlv.c_extra = NUL;
+ wlv.c_final = NUL;
+ wlv.extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
+ n_attr = wlv.n_extra;
+ extmark_attr = 0;
+ virt_inline_i++;
+ }
+ }
+
// Decide which of the highlight attributes to use.
attr_pri = true;
@@ -1932,7 +1974,7 @@ 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
&& wlv.vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, wlv.off,
+ extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, wlv.off,
selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index a3e5640b1..f4a8286d0 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -296,8 +296,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".
@@ -374,7 +382,23 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// First get normal size, without 'linebreak' or virtual text
int size = win_chartabsize(wp, 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 = (uint8_t)(*s);
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
index 808f6d284..a15c234bb 100644
--- a/src/nvim/plines.h
+++ b/src/nvim/plines.h
@@ -11,9 +11,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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment