aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/buffer.c60
-rw-r--r--src/nvim/api/private/helpers.c61
-rw-r--r--src/nvim/api/vim.c40
-rw-r--r--src/nvim/api/window.c35
4 files changed, 131 insertions, 65 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");
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d2b787a6f5..24ba6110c4 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1708,33 +1708,6 @@ const char *describe_ns(NS ns_id)
return "(UNKNOWN PLUGIN)";
}
-DecorProvider *get_provider(NS ns_id, bool force)
-{
- ssize_t i;
- for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) {
- DecorProvider *item = &kv_A(decor_providers, i);
- if (item->ns_id == ns_id) {
- return item;
- } else if (item->ns_id > ns_id) {
- break;
- }
- }
-
- if (!force) {
- return NULL;
- }
-
- for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) {
- // allocates if needed:
- (void)kv_a(decor_providers, (size_t)j+1);
- kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j);
- }
- DecorProvider *item = &kv_a(decor_providers, (size_t)i);
- *item = DECORATION_PROVIDER_INIT(ns_id);
-
- return item;
-}
-
static bool parse_float_anchor(String anchor, FloatAnchor *out)
{
if (anchor.size == 0) {
@@ -1787,10 +1760,13 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
struct {
const char *name;
schar_T chars[8];
+ bool shadow_color;
} defaults[] = {
- { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" } },
- { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" } },
- { NULL, { { NUL } } },
+ { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false },
+ { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" }, false },
+ { "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true },
+ { "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false },
+ { NULL, { { NUL } } , false },
};
schar_T *chars = fconfig->border_chars;
@@ -1834,13 +1810,16 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
api_set_error(err, kErrorTypeValidation, "invalid border char");
return;
}
- if (!string.size
- || mb_string2cells_len((char_u *)string.data, string.size) != 1) {
+ if (string.size
+ && mb_string2cells_len((char_u *)string.data, string.size) > 1) {
api_set_error(err, kErrorTypeValidation,
"border chars must be one cell");
+ return;
}
size_t len = MIN(string.size, sizeof(*chars)-1);
- memcpy(chars[i], string.data, len);
+ if (len) {
+ memcpy(chars[i], string.data, len);
+ }
chars[i][len] = NUL;
hl_ids[i] = hl_id;
}
@@ -1849,6 +1828,13 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
memcpy(hl_ids+size, hl_ids, sizeof(*hl_ids) * size);
size <<= 1;
}
+ if ((chars[7][0] && chars[1][0] && !chars[0][0])
+ || (chars[1][0] && chars[3][0] && !chars[2][0])
+ || (chars[3][0] && chars[5][0] && !chars[4][0])
+ || (chars[5][0] && chars[7][0] && !chars[6][0])) {
+ api_set_error(err, kErrorTypeValidation,
+ "corner between used edges must be specified");
+ }
} else if (style.type == kObjectTypeString) {
String str = style.data.string;
if (str.size == 0 || strequal(str.data, "none")) {
@@ -1859,6 +1845,15 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
if (strequal(str.data, defaults[i].name)) {
memcpy(chars, defaults[i].chars, sizeof(defaults[i].chars));
memset(hl_ids, 0, 8 * sizeof(*hl_ids));
+ if (defaults[i].shadow_color) {
+ int hl_blend = SYN_GROUP_STATIC("FloatShadow");
+ int hl_through = SYN_GROUP_STATIC("FloatShadowThrough");
+ hl_ids[2] = hl_through;
+ hl_ids[3] = hl_blend;
+ hl_ids[4] = hl_blend;
+ hl_ids[5] = hl_blend;
+ hl_ids[6] = hl_through;
+ }
return;
}
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index d93be55ee8..e0eebd079f 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -104,10 +104,14 @@ String nvim_exec(String src, Boolean output, Error *err)
}
try_start();
- msg_silent++;
+ if (output) {
+ msg_silent++;
+ }
do_source_str(src.data, "nvim_exec()");
- capture_ga = save_capture_ga;
- msg_silent = save_msg_silent;
+ if (output) {
+ capture_ga = save_capture_ga;
+ msg_silent = save_msg_silent;
+ }
try_end(err);
if (ERROR_SET(err)) {
@@ -1269,6 +1273,7 @@ fail:
/// @param buffer the buffer to use (expected to be empty)
/// @param opts Optional parameters. Reserved for future use.
/// @param[out] err Error details, if any
+/// @return Channel id, or 0 on error
Integer nvim_open_term(Buffer buffer, Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
@@ -1339,7 +1344,8 @@ void nvim_chan_send(Integer chan, String data, Error *err)
return;
}
- channel_send((uint64_t)chan, data.data, data.size, &error);
+ channel_send((uint64_t)chan, data.data, data.size,
+ false, &error);
if (error) {
api_set_error(err, kErrorTypeValidation, "%s", error);
}
@@ -1427,6 +1433,7 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// - "none" No border. This is the default
/// - "single" a single line box
/// - "double" a double line box
+/// - "shadow" a drop shadow effect by blending with the background.
/// If it is an array it should be an array of eight items or any divisor of
/// eight. The array will specifify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As, an
@@ -1437,6 +1444,9 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// [ "/", "-", "\\", "|" ]
/// or all chars the same as:
/// [ "x" ]
+/// An empty string can be used to turn off a specific border, for instance:
+/// [ "", "", "", ">", "", "", "", "<" ]
+/// will only make vertical borders but not horizontal ones.
/// By default `FloatBorder` highlight is used which links to `VertSplit`
/// when not defined. It could also be specified by character:
/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ]
@@ -2714,6 +2724,7 @@ Dictionary nvim__stats(void)
Dictionary rv = ARRAY_DICT_INIT;
PUT(rv, "fsync", INTEGER_OBJ(g_stats.fsync));
PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
+ PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_refcount));
return rv;
}
@@ -2886,19 +2897,6 @@ void nvim__screenshot(String path)
ui_call_screenshot(path);
}
-static void clear_provider(DecorProvider *p)
-{
- if (p == NULL) {
- return;
- }
- NLUA_CLEAR_REF(p->redraw_start);
- NLUA_CLEAR_REF(p->redraw_buf);
- NLUA_CLEAR_REF(p->redraw_win);
- NLUA_CLEAR_REF(p->redraw_line);
- NLUA_CLEAR_REF(p->redraw_end);
- p->active = false;
-}
-
/// Set or change decoration provider for a namespace
///
/// This is a very general purpose interface for having lua callbacks
@@ -2943,8 +2941,8 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
Error *err)
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
{
- DecorProvider *p = get_provider((NS)ns_id, true);
- clear_provider(p);
+ DecorProvider *p = get_decor_provider((NS)ns_id, true);
+ decor_provider_clear(p);
// regardless of what happens, it seems good idea to redraw
redraw_all_later(NOT_VALID); // TODO(bfredl): too soon?
@@ -2966,7 +2964,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
size_t j;
- for (j = 0; cbs[j].name; j++) {
+ for (j = 0; cbs[j].name && cbs[j].dest; j++) {
if (strequal(cbs[j].name, k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation,
@@ -2987,5 +2985,5 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
p->active = true;
return;
error:
- clear_provider(p);
+ decor_provider_clear(p);
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index f4af1632ec..158e149628 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -54,7 +54,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
return;
}
- if (switch_win(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
+ if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
api_set_error(err,
kErrorTypeException,
"Failed to switch to window %d",
@@ -74,7 +74,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
// So do it now.
validate_cursor();
- restore_win(save_curwin, save_curtab, false);
+ restore_win_noblock(save_curwin, save_curtab, false);
}
/// Gets the (1,0)-indexed cursor position in the window. |api-indexing|
@@ -381,7 +381,7 @@ Integer nvim_win_get_number(Window window, Error *err)
}
int tabnr;
- win_get_tabwin(window, &tabnr, &rv);
+ win_get_tabwin(win->handle, &tabnr, &rv);
return rv;
}
@@ -492,6 +492,35 @@ Dictionary nvim_win_get_config(Window window, Error *err)
return rv;
}
+/// Closes the window and hide the buffer it contains (like |:hide| with a
+/// |window-ID|).
+///
+/// Like |:hide| the buffer becomes hidden unless another window is editing it,
+/// or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to |:close| or
+/// |nvim_win_close|, which will close the buffer.
+///
+/// @param window Window handle, or 0 for current window
+/// @param[out] err Error details, if any
+void nvim_win_hide(Window window, Error *err)
+ FUNC_API_SINCE(7)
+ FUNC_API_CHECK_TEXTLOCK
+{
+ win_T *win = find_window_by_handle(window, err);
+ if (!win) {
+ return;
+ }
+
+ tabpage_T *tabpage = win_find_tabpage(win);
+ TryState tstate;
+ try_enter(&tstate);
+ if (tabpage == curtab) {
+ win_close(win, false);
+ } else {
+ win_close_othertab(win, false, tabpage);
+ }
+ vim_ignored = try_leave(&tstate, err);
+}
+
/// Closes the window (like |:close| with a |window-ID|).
///
/// @param window Window handle, or 0 for current window