aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/buffer.c44
-rw-r--r--src/nvim/api/private/helpers.c81
-rw-r--r--src/nvim/api/ui_events.in.h3
-rw-r--r--src/nvim/api/vim.c63
-rw-r--r--src/nvim/api/window.c102
5 files changed, 196 insertions, 97 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index e79a7a2de2..f84e8c99a4 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"
@@ -441,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".
@@ -460,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;
@@ -472,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 += (bcount_t)strlen(lines[i]) + 1;
// Mark lines that haven't been passed to the buffer as they need
// to be freed later
lines[i] = NULL;
@@ -491,6 +497,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
goto end;
}
+ inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
+
// Same as with replacing, but we also need to free lines
xfree(lines[i]);
lines[i] = NULL;
@@ -505,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);
@@ -1412,12 +1424,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param line Line number where to place the mark
-/// @param col Column where to place the mark
+/// @param line Line where to place the mark, 0-based
+/// @param col Column where to place the mark, 0-based
/// @param opts Optional parameters.
/// - id : id of the extmark to edit.
/// - end_line : ending line of the mark, 0-based inclusive.
-/// - end_col : ending col of the mark, 0-based inclusive.
+/// - end_col : ending col of the mark, 0-based exclusive.
/// - hl_group : name of the highlight group used to highlight
/// this mark.
/// - virt_text : virtual text to link to this mark.
@@ -1426,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'
@@ -1574,11 +1590,22 @@ 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);
@@ -1673,6 +1700,15 @@ 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) {
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 24ba6110c4..c7d261ba18 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -177,42 +177,47 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
return vim_to_object(&di->di_tv);
}
-/// Set a value in a scope dict. Objects are recursively expanded into their
-/// vimscript equivalents.
-///
-/// @param dict The vimscript dict
-/// @param key The key
-/// @param value The new value
-/// @param del Delete key in place of setting it. Argument `value` is ignored in
-/// this case.
-/// @param retval If true the old value will be converted and returned.
-/// @param[out] err Details of an error that may have occurred
-/// @return The old value if `retval` is true and the key was present, else NIL
-Object dict_set_var(dict_T *dict, String key, Object value, bool del,
- bool retval, Error *err)
+dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
{
- Object rv = OBJECT_INIT;
dictitem_T *di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di != NULL) {
if (di->di_flags & DI_FLAGS_RO) {
api_set_error(err, kErrorTypeException, "Key is read-only: %s", key.data);
- return rv;
} else if (di->di_flags & DI_FLAGS_LOCK) {
api_set_error(err, kErrorTypeException, "Key is locked: %s", key.data);
- return rv;
} else if (del && (di->di_flags & DI_FLAGS_FIX)) {
api_set_error(err, kErrorTypeException, "Key is fixed: %s", key.data);
- return rv;
}
} else if (dict->dv_lock) {
api_set_error(err, kErrorTypeException, "Dictionary is locked");
- return rv;
} else if (key.size == 0) {
api_set_error(err, kErrorTypeValidation, "Key name is empty");
- return rv;
} else if (key.size > INT_MAX) {
api_set_error(err, kErrorTypeValidation, "Key name is too long");
+ }
+
+ return di;
+}
+
+/// Set a value in a scope dict. Objects are recursively expanded into their
+/// vimscript equivalents.
+///
+/// @param dict The vimscript dict
+/// @param key The key
+/// @param value The new value
+/// @param del Delete key in place of setting it. Argument `value` is ignored in
+/// this case.
+/// @param retval If true the old value will be converted and returned.
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value if `retval` is true and the key was present, else NIL
+Object dict_set_var(dict_T *dict, String key, Object value, bool del,
+ bool retval, Error *err)
+{
+ Object rv = OBJECT_INIT;
+ dictitem_T *di = dict_check_writable(dict, key, del, err);
+
+ if (ERROR_SET(err)) {
return rv;
}
@@ -1640,7 +1645,7 @@ bool api_object_to_bool(Object obj, const char *what,
} else if (obj.type == kObjectTypeNil) {
return nil_value; // caller decides what NIL (missing retval in lua) means
} else {
- api_set_error(err, kErrorTypeValidation, "%s is not an boolean", what);
+ api_set_error(err, kErrorTypeValidation, "%s is not a boolean", what);
return false;
}
}
@@ -1765,6 +1770,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
{ "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false },
{ "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" }, false },
{ "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true },
+ { "rounded", { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, false },
{ "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ NULL, { { NUL } } , false },
};
@@ -1863,7 +1869,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
- Error *err)
+ bool new_win, Error *err)
{
// TODO(bfredl): use a get/has_key interface instead and get rid of extra
// flags
@@ -1909,7 +1915,7 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
} else if (strequal(key, "height")) {
has_height = true;
if (val.type == kObjectTypeInteger && val.data.integer > 0) {
- fconfig->height= (int)val.data.integer;
+ fconfig->height = (int)val.data.integer;
} else {
api_set_error(err, kErrorTypeValidation,
"'height' key must be a positive Integer");
@@ -1963,24 +1969,23 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
}
has_bufpos = true;
} else if (!strcmp(key, "external")) {
- if (val.type == kObjectTypeInteger) {
- fconfig->external = val.data.integer;
- } else if (val.type == kObjectTypeBoolean) {
- fconfig->external = val.data.boolean;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'external' key must be Boolean");
+ has_external = fconfig->external
+ = api_object_to_bool(val, "'external' key", false, err);
+ if (ERROR_SET(err)) {
return false;
}
- has_external = fconfig->external;
} else if (!strcmp(key, "focusable")) {
- if (val.type == kObjectTypeInteger) {
- fconfig->focusable = val.data.integer;
- } else if (val.type == kObjectTypeBoolean) {
- fconfig->focusable = val.data.boolean;
+ fconfig->focusable
+ = api_object_to_bool(val, "'focusable' key", true, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+ } else if (strequal(key, "zindex")) {
+ if (val.type == kObjectTypeInteger && val.data.integer > 0) {
+ fconfig->zindex = (int)val.data.integer;
} else {
api_set_error(err, kErrorTypeValidation,
- "'focusable' key must be Boolean");
+ "'zindex' key must be a positive Integer");
return false;
}
} else if (!strcmp(key, "border")) {
@@ -2002,6 +2007,12 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
api_set_error(err, kErrorTypeValidation,
"Invalid value of 'style' key");
}
+ } else if (strequal(key, "noautocmd") && new_win) {
+ fconfig->noautocmd
+ = api_object_to_bool(val, "'noautocmd' key", false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index e934d5dc92..11e21a88ea 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -106,7 +106,8 @@ void win_pos(Integer grid, Window win, Integer startrow,
Integer startcol, Integer width, Integer height)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_float_pos(Integer grid, Window win, String anchor, Integer anchor_grid,
- Float anchor_row, Float anchor_col, Boolean focusable)
+ Float anchor_row, Float anchor_col, Boolean focusable,
+ Integer zindex)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_external_pos(Integer grid, Window win)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index c363c77afb..349cc0e7da 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -221,6 +221,12 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
/// in addition the following keys are also recognized:
/// `default`: don't override existing definition,
/// like `hi default`
+/// `ctermfg`: sets foreground of cterm color
+/// `ctermbg`: sets background of cterm color
+/// `cterm` : cterm attribute map. sets attributed for
+/// cterm colors. similer to `hi cterm`
+/// Note: by default cterm attributes are
+/// same as attributes of gui color
/// @param[out] err Error details, if any
///
/// TODO: ns_id = 0, should modify :highlight namespace
@@ -978,7 +984,7 @@ Dictionary nvim_get_all_options_info(Error *err)
/// Resulting dictionary has keys:
/// - name: Name of the option (like 'filetype')
/// - shortname: Shortened name of the option (like 'ft')
-/// - type: type of option ("string", "integer" or "boolean")
+/// - type: type of option ("string", "number" or "boolean")
/// - default: The default value for the option
/// - was_set: Whether the option was set.
///
@@ -1411,6 +1417,15 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// - `external`: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
+/// - `zindex`: Stacking order. floats with higher `zindex` go on top on
+/// floats with lower indices. Must be larger than zero. The
+/// following screen elements have hard-coded z-indices:
+/// - 100: insert completion popupmenu
+/// - 200: message scrollback
+/// - 250: cmdline completion popupmenu (when wildoptions+=pum)
+/// The default value for floats are 50. In general, values below 100 are
+/// recommended, unless there is a good reason to overshadow builtin
+/// elements.
/// - `style`: Configure the appearance of the window. Currently only takes
/// one non-empty value:
/// - "minimal" Nvim will display the window with many UI options
@@ -1422,28 +1437,33 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// end-of-buffer region is hidden by setting `eob` flag of
/// 'fillchars' to a space char, and clearing the
/// |EndOfBuffer| region in 'winhighlight'.
-/// - `border`: style of (optional) window border. This can either be a string
-/// or an array. the string values are:
-/// - "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
+/// - `border`: Style of (optional) window border. This can either be a string
+/// or an array. The string values are
+/// - "none": No border (default).
+/// - "single": A single line box.
+/// - "double": A double line box.
+/// - "rounded": Like "single", but with rounded corners ("╭" etc.).
+/// - "solid": Adds padding by a single whitespace cell.
+/// - "shadow": A drop shadow effect by blending with the background.
+/// - If it is an array, it should have a length of eight 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
-/// example, the double box style could be specified as:
-/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]
-/// if the number of chars are less than eight, they will be repeated. Thus
-/// an ASCII border could be specified as:
-/// [ "/", "-", "\\", "|" ]
-/// or all chars the same as:
-/// [ "x" ]
-/// An empty string can be used to turn off a specific border, for instance:
+/// in a clockwise fashion starting with the top-left corner. As an
+/// example, the double box style could be specified as
+/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
+/// If the number of chars are less than eight, they will be repeated. Thus
+/// an ASCII border could be specified as
+/// [ "/", "-", "\\", "|" ],
+/// 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`
+/// By default, `FloatBorder` highlight is used, which links to `VertSplit`
/// when not defined. It could also be specified by character:
-/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ]
+/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ].
+/// - `noautocmd`: If true then no buffer-related autocommand events such as
+/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from
+/// calling this function.
///
/// @param[out] err Error details, if any
///
@@ -1454,7 +1474,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
FUNC_API_CHECK_TEXTLOCK
{
FloatConfig fconfig = FLOAT_CONFIG_INIT;
- if (!parse_float_config(config, &fconfig, false, err)) {
+ if (!parse_float_config(config, &fconfig, false, true, err)) {
return 0;
}
win_T *wp = win_new_float(NULL, fconfig, err);
@@ -1469,7 +1489,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
return 0;
}
if (buffer > 0) {
- nvim_win_set_buf(wp->handle, buffer, err);
+ win_set_buf(wp->handle, buffer, fconfig.noautocmd, err);
}
if (fconfig.style == kWinStyleMinimal) {
@@ -2936,6 +2956,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
{
DecorProvider *p = get_decor_provider((NS)ns_id, true);
+ assert(p != NULL);
decor_provider_clear(p);
// regardless of what happens, it seems good idea to redraw
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 89fa2f86fb..0729024b45 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -6,19 +6,21 @@
#include <stdlib.h>
#include <limits.h>
-#include "nvim/ascii.h"
-#include "nvim/globals.h"
-#include "nvim/api/window.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/lua/executor.h"
#include "nvim/ex_docmd.h"
#include "nvim/vim.h"
+#include "nvim/api/window.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/globals.h"
+#include "nvim/move.h"
#include "nvim/option.h"
-#include "nvim/window.h"
#include "nvim/screen.h"
-#include "nvim/move.h"
+#include "nvim/syntax.h"
+#include "nvim/window.h"
/// Gets the current buffer in a window
///
@@ -46,35 +48,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
FUNC_API_SINCE(5)
FUNC_API_CHECK_TEXTLOCK
{
- win_T *win = find_window_by_handle(window, err), *save_curwin = curwin;
- buf_T *buf = find_buffer_by_handle(buffer, err);
- tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab;
-
- if (!win || !buf) {
- return;
- }
-
- if (switch_win(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
- api_set_error(err,
- kErrorTypeException,
- "Failed to switch to window %d",
- window);
- }
-
- try_start();
- int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
- if (!try_end(err) && result == FAIL) {
- api_set_error(err,
- kErrorTypeException,
- "Failed to set buffer %d",
- buffer);
- }
-
- // If window is not current, state logic will not validate its cursor.
- // So do it now.
- validate_cursor();
-
- restore_win(save_curwin, save_curtab, false);
+ win_set_buf(window, buffer, false, err);
}
/// Gets the (1,0)-indexed cursor position in the window. |api-indexing|
@@ -381,7 +355,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;
}
@@ -423,7 +397,7 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
// reuse old values, if not overriden
FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config;
- if (!parse_float_config(config, &fconfig, !new_float, err)) {
+ if (!parse_float_config(config, &fconfig, !new_float, false, err)) {
return;
}
if (new_float) {
@@ -483,6 +457,26 @@ Dictionary nvim_win_get_config(Window window, Error *err)
PUT(rv, "row", FLOAT_OBJ(config->row));
PUT(rv, "col", FLOAT_OBJ(config->col));
}
+ if (config->border) {
+ Array border = ARRAY_DICT_INIT;
+ for (size_t i = 0; i < 8; i++) {
+ Array tuple = ARRAY_DICT_INIT;
+
+ String s = cstrn_to_string(
+ (const char *)config->border_chars[i], sizeof(schar_T));
+
+ int hi_id = config->border_hl_ids[i];
+ char_u *hi_name = syn_id2name(hi_id);
+ if (hi_name[0]) {
+ ADD(tuple, STRING_OBJ(s));
+ ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name)));
+ ADD(border, ARRAY_OBJ(tuple));
+ } else {
+ ADD(border, STRING_OBJ(s));
+ }
+ }
+ PUT(rv, "border", ARRAY_OBJ(border));
+ }
}
const char *rel = (wp->w_floating && !config->external
@@ -552,3 +546,39 @@ void nvim_win_close(Window window, Boolean force, Error *err)
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
vim_ignored = try_leave(&tstate, err);
}
+
+/// Calls a function with window as temporary current window.
+///
+/// @see |win_execute()|
+/// @see |nvim_buf_call()|
+///
+/// @param window Window handle, or 0 for current window
+/// @param fun Function to call inside the window (currently lua callable
+/// only)
+/// @param[out] err Error details, if any
+/// @return Return value of function. NB: will deepcopy lua values
+/// currently, use upvalues to send lua references in and out.
+Object nvim_win_call(Window window, LuaRef fun, Error *err)
+ FUNC_API_SINCE(7)
+ FUNC_API_LUA_ONLY
+{
+ win_T *win = find_window_by_handle(window, err);
+ if (!win) {
+ return NIL;
+ }
+ tabpage_T *tabpage = win_find_tabpage(win);
+
+ win_T *save_curwin;
+ tabpage_T *save_curtab;
+
+ try_start();
+ Object res = OBJECT_INIT;
+ if (switch_win_noblock(&save_curwin, &save_curtab, win, tabpage, true) ==
+ OK) {
+ Array args = ARRAY_DICT_INIT;
+ res = nlua_call_ref(fun, NULL, args, true, err);
+ }
+ restore_win_noblock(save_curwin, save_curtab, true);
+ try_end(err);
+ return res;
+}