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.c181
1 files changed, 115 insertions, 66 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 67f4f92bf6..2c2e8a024f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -111,6 +111,24 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// - byte count of previous contents
/// - deleted_codepoints (if `utf_sizes` is true)
/// - deleted_codeunits (if `utf_sizes` is true)
+/// - on_bytes: lua callback invoked on change.
+/// This callback receives more granular information about the
+/// change compared to on_lines.
+/// Return `true` to detach.
+/// Args:
+/// - the string "bytes"
+/// - buffer handle
+/// - b:changedtick
+/// - start row of the changed text (zero-indexed)
+/// - start column of the changed text
+/// - byte offset of the changed text (from the start of
+/// the buffer)
+/// - old end row of the changed text
+/// - old end column of the changed text
+/// - old end byte length of the changed text
+/// - new end row of the changed text
+/// - new end column of the changed text
+/// - new end byte length of the changed text
/// - on_changedtick: Lua callback invoked on changedtick
/// increment without text change. Args:
/// - the string "changedtick"
@@ -119,6 +137,10 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// - on_detach: Lua callback invoked on detach. Args:
/// - the string "detach"
/// - buffer handle
+/// - on_reload: Lua callback invoked on reload. The entire buffer
+/// content should be considered changed. Args:
+/// - the string "detach"
+/// - buffer handle
/// - utf_sizes: include UTF-32 and UTF-16 size of the replaced
/// region, as args to `on_lines`.
/// - preview: also attach to command preview (i.e. 'inccommand')
@@ -141,50 +163,57 @@ Boolean nvim_buf_attach(uint64_t channel_id,
bool is_lua = (channel_id == LUA_INTERNAL_CALL);
BufUpdateCallbacks cb = BUF_UPDATE_CALLBACKS_INIT;
+ struct {
+ const char *name;
+ LuaRef *dest;
+ } cbs[] = {
+ { "on_lines", &cb.on_lines },
+ { "on_bytes", &cb.on_bytes },
+ { "on_changedtick", &cb.on_changedtick },
+ { "on_detach", &cb.on_detach },
+ { "on_reload", &cb.on_reload },
+ { NULL, NULL },
+ };
+
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
- if (is_lua && strequal("on_lines", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- cb.on_lines = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (is_lua && strequal("on_bytes", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- cb.on_bytes = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (is_lua && strequal("on_changedtick", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- cb.on_changedtick = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (is_lua && strequal("on_detach", k.data)) {
- if (v->type != kObjectTypeLuaRef) {
- api_set_error(err, kErrorTypeValidation, "callback is not a function");
- goto error;
- }
- cb.on_detach = v->data.luaref;
- v->data.luaref = LUA_NOREF;
- } else if (is_lua && strequal("utf_sizes", k.data)) {
- if (v->type != kObjectTypeBoolean) {
- api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
- goto error;
+ bool key_used = false;
+ if (is_lua) {
+ for (size_t j = 0; cbs[j].name; j++) {
+ if (strequal(cbs[j].name, k.data)) {
+ if (v->type != kObjectTypeLuaRef) {
+ api_set_error(err, kErrorTypeValidation,
+ "%s is not a function", cbs[j].name);
+ goto error;
+ }
+ *(cbs[j].dest) = v->data.luaref;
+ v->data.luaref = LUA_NOREF;
+ key_used = true;
+ break;
+ }
}
- cb.utf_sizes = v->data.boolean;
- } else if (is_lua && strequal("preview", k.data)) {
- if (v->type != kObjectTypeBoolean) {
- api_set_error(err, kErrorTypeValidation, "preview must be boolean");
- goto error;
+
+ if (key_used) {
+ continue;
+ } else if (strequal("utf_sizes", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
+ goto error;
+ }
+ cb.utf_sizes = v->data.boolean;
+ key_used = true;
+ } else if (strequal("preview", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation, "preview must be boolean");
+ goto error;
+ }
+ cb.preview = v->data.boolean;
+ key_used = true;
}
- cb.preview = v->data.boolean;
- } else {
+ }
+
+ if (!key_used) {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
}
@@ -722,7 +751,8 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer,
kExtmarkUndo);
- changed_lines((linenr_T)start_row, 0, (linenr_T)end_row, (long)extra, true);
+ changed_lines((linenr_T)start_row, 0, (linenr_T)end_row + 1,
+ (long)extra, true);
// adjust cursor like an extmark ( i e it was inside last_part_len)
if (curwin->w_cursor.lnum == end_row && curwin->w_cursor.col > end_col) {
@@ -1395,6 +1425,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - hl_group : name of the highlight group used to highlight
/// this mark.
/// - virt_text : virtual text to link to this mark.
+/// - virt_text_pos : positioning of virtual text. Possible
+/// values:
+/// - "eol": right after eol character (default)
+/// - "overlay": display over the specified column, without
+/// shifting the underlying text.
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
/// redraw cycle, and not be permantently stored in the
@@ -1444,8 +1479,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
uint64_t id = 0;
int line2 = -1, hl_id = 0;
DecorPriority priority = DECOR_PRIORITY_BASE;
- colnr_T col2 = 0;
+ colnr_T col2 = -1;
VirtText virt_text = KV_INITIAL_VALUE;
+ VirtTextPos virt_text_pos = kVTEndOfLine;
bool right_gravity = true;
bool end_right_gravity = false;
bool end_gravity_set = false;
@@ -1514,6 +1550,22 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (ERROR_SET(err)) {
goto error;
}
+ } else if (strequal("virt_text_pos", k.data)) {
+ if (v->type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos is not a String");
+ goto error;
+ }
+ String str = v->data.string;
+ if (strequal("eol", str.data)) {
+ virt_text_pos = kVTEndOfLine;
+ } else if (strequal("overlay", str.data)) {
+ virt_text_pos = kVTOverlay;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos: invalid value");
+ goto error;
+ }
} else if (strequal("ephemeral", k.data)) {
ephemeral = api_object_to_bool(*v, "ephemeral", false, err);
if (ERROR_SET(err)) {
@@ -1555,7 +1607,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
// Only error out if they try to set end_right_gravity without
// setting end_col or end_line
- if (line2 == -1 && col2 == 0 && end_gravity_set) {
+ if (line2 == -1 && col2 == -1 && end_gravity_set) {
api_set_error(err, kErrorTypeValidation,
"cannot set end_right_gravity "
"without setting end_line or end_col");
@@ -1579,30 +1631,28 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0;
}
+ Decoration *decor = NULL, tmp = { 0 };
+
+ if (kv_size(virt_text) || priority != DECOR_PRIORITY_BASE) {
+ // TODO(bfredl): this is a bit sketchy. eventually we should
+ // have predefined decorations for both marks/ephemerals
+ decor = ephemeral ? &tmp : xcalloc(1, sizeof(*decor));
+ decor->hl_id = hl_id;
+ decor->virt_text = virt_text;
+ decor->priority = priority;
+ decor->virt_text_pos = virt_text_pos;
+ } else if (hl_id) {
+ decor = decor_hl(hl_id);
+ }
+
// TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.buf == buf) {
- int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- VirtText *vt_allocated = NULL;
- if (kv_size(virt_text)) {
- vt_allocated = xmalloc(sizeof *vt_allocated);
- *vt_allocated = virt_text;
- }
- decor_add_ephemeral(attr_id, (int)line, (colnr_T)col,
- (int)line2, (colnr_T)col2, priority, vt_allocated);
+ decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0);
} else {
if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
goto error;
}
- Decoration *decor = NULL;
- if (kv_size(virt_text)) {
- decor = xcalloc(1, sizeof(*decor));
- decor->hl_id = hl_id;
- decor->virt_text = virt_text;
- } else if (hl_id) {
- decor = decor_hl(hl_id);
- decor->priority = priority;
- }
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
line2, col2, decor, right_gravity,
@@ -1673,7 +1723,7 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
/// @param[out] err Error details, if any
/// @return The ns_id that was used
Integer nvim_buf_add_highlight(Buffer buffer,
- Integer src_id,
+ Integer ns_id,
String hl_group,
Integer line,
Integer col_start,
@@ -1698,18 +1748,18 @@ Integer nvim_buf_add_highlight(Buffer buffer,
col_end = MAXCOL;
}
- uint64_t ns_id = src2ns(&src_id);
+ uint64_t ns = src2ns(&ns_id);
if (!(line < buf->b_ml.ml_line_count)) {
// safety check, we can't add marks outside the range
- return src_id;
+ return ns_id;
}
int hl_id = 0;
if (hl_group.size > 0) {
hl_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
} else {
- return src_id;
+ return ns_id;
}
int end_line = (int)line;
@@ -1718,11 +1768,11 @@ Integer nvim_buf_add_highlight(Buffer buffer,
end_line++;
}
- extmark_set(buf, ns_id, 0,
+ extmark_set(buf, ns, 0,
(int)line, (colnr_T)col_start,
end_line, (colnr_T)col_end,
decor_hl(hl_id), true, false, kExtmarkNoUndo);
- return src_id;
+ return ns_id;
}
/// Clears namespaced objects (highlights, extmarks, virtual text) from
@@ -1918,7 +1968,6 @@ static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
curwin->w_cursor.lnum += extra;
check_cursor_col();
} else if (extra < 0) {
- curwin->w_cursor.lnum = lo;
check_cursor();
} else {
check_cursor_col();