Last active
March 8, 2023 12:18
-
-
Save shebpamm/5eaa7a43ba6fa5eca6075af67f2d6b60 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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