aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/buffer.c')
-rw-r--r--src/nvim/api/buffer.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 66c4454f7b..ebc9aeb75f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -27,6 +27,7 @@
#include "nvim/map_defs.h"
#include "nvim/map.h"
#include "nvim/mark.h"
+#include "nvim/ops.h"
#include "nvim/extmark.h"
#include "nvim/decoration.h"
#include "nvim/fileio.h"
@@ -222,11 +223,7 @@ Boolean nvim_buf_attach(uint64_t channel_id,
return buf_updates_register(buf, channel_id, cb, send_buffer);
error:
- // TODO(bfredl): ASAN build should check that the ref table is empty?
- api_free_luaref(cb.on_lines);
- api_free_luaref(cb.on_bytes);
- api_free_luaref(cb.on_changedtick);
- api_free_luaref(cb.on_detach);
+ buffer_update_callbacks_free(cb);
return false;
}
@@ -445,6 +442,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
goto end;
}
+ bcount_t deleted_bytes = get_region_bytecount(curbuf, start, end, 0, 0);
+
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
@@ -464,6 +463,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
size_t to_replace = old_len < new_len ? old_len : new_len;
+ bcount_t inserted_bytes = 0;
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start + (int64_t)i;
@@ -476,6 +476,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
+
+ inserted_bytes += STRLEN(lines[i]) + 1;
// Mark lines that haven't been passed to the buffer as they need
// to be freed later
lines[i] = NULL;
@@ -495,6 +497,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
goto end;
}
+ inserted_bytes += STRLEN(lines[i]) + 1;
+
// Same as with replacing, but we also need to free lines
xfree(lines[i]);
lines[i] = NULL;
@@ -509,7 +513,11 @@ void nvim_buf_set_lines(uint64_t channel_id,
(linenr_T)(end - 1),
MAXLNUM,
(long)extra,
- kExtmarkUndo);
+ kExtmarkNOOP);
+
+ extmark_splice(curbuf, (int)start-1, 0, (int)(end-start), 0,
+ deleted_bytes, (int)new_len, 0, inserted_bytes,
+ kExtmarkUndo);
changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true);
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
@@ -1430,6 +1438,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - "eol": right after eol character (default)
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
+/// - "right_align": display right aligned in the window.
+/// - virt_text_win_col : position the virtual text at a fixed
+/// window column (starting from the first
+/// text column)
/// - virt_text_hide : hide the virtual text when the background
/// text is selected or hidden due to
/// horizontal scroll 'nowrap'
@@ -1441,6 +1453,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// default
/// - "combine": combine with background text color
/// - "blend": blend with background text color.
+/// - hl_eol : when true, for a multiline highlight covering the
+/// EOL of a line, continue the highlight for the rest
+/// of the screen line (just like for diff and
+/// cursorline highlight).
///
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
@@ -1453,6 +1469,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// the extmark end position (if it exists) will be shifted
/// in when new text is inserted (true for right, false
/// for left). Defaults to false.
+/// - priority: a priority value for the highlight group. For
+/// example treesitter highlighting uses a value of 100.
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
@@ -1572,17 +1590,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) {
decor.virt_text_pos = kVTOverlay;
+ } else if (strequal("right_align", str.data)) {
+ decor.virt_text_pos = kVTRightAlign;
} else {
api_set_error(err, kErrorTypeValidation,
"virt_text_pos: invalid value");
goto error;
}
+ } else if (strequal("virt_text_win_col", k.data)) {
+ if (v->type != kObjectTypeInteger) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_win_col is not a Number of the correct size");
+ goto error;
+ }
+
+ decor.col = (int)v->data.integer;
+ decor.virt_text_pos = kVTWinCol;
} else if (strequal("virt_text_hide", k.data)) {
decor.virt_text_hide = api_object_to_bool(*v,
"virt_text_hide", false, err);
if (ERROR_SET(err)) {
goto error;
}
+ } else if (strequal("hl_eol", k.data)) {
+ decor.hl_eol = api_object_to_bool(*v, "hl_eol", false, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
} else if (strequal("hl_mode", k.data)) {
if (v->type != kObjectTypeString) {
api_set_error(err, kErrorTypeValidation,
@@ -1666,12 +1700,22 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0;
}
+ if (decor.virt_text_pos == kVTRightAlign) {
+ decor.col = 0;
+ for (size_t i = 0; i < kv_size(decor.virt_text); i++) {
+ decor.col
+ += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
+ }
+ }
+
+
Decoration *d = NULL;
if (ephemeral) {
d = &decor;
} else if (kv_size(decor.virt_text)
- || decor.priority != DECOR_PRIORITY_BASE) {
+ || decor.priority != DECOR_PRIORITY_BASE
+ || decor.hl_eol) {
// TODO(bfredl): this is a bit sketchy. eventually we should
// have predefined decorations for both marks/ephemerals
d = xcalloc(1, sizeof(*d));
@@ -1682,7 +1726,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
// TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.buf == buf) {
- decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, 0);
+ decor_add_ephemeral((int)line, (int)col, line2, col2, &decor);
} else {
if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");