diff options
Diffstat (limited to 'src/nvim/api/buffer.c')
-rw-r--r-- | src/nvim/api/buffer.c | 181 |
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(); |