aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c58
-rw-r--r--src/nvim/api/private/defs.h43
-rw-r--r--src/nvim/api/private/helpers.c125
-rw-r--r--src/nvim/api/private/helpers.h44
-rw-r--r--src/nvim/api/tabpage.c8
-rw-r--r--src/nvim/api/vim.c70
-rw-r--r--src/nvim/api/window.c38
-rw-r--r--src/nvim/buffer.c64
-rw-r--r--src/nvim/buffer_defs.h26
-rw-r--r--src/nvim/diff.c27
-rw-r--r--src/nvim/edit.c7
-rw-r--r--src/nvim/eval.c590
-rw-r--r--src/nvim/ex_cmds.c18
-rw-r--r--src/nvim/ex_cmds2.c51
-rw-r--r--src/nvim/ex_docmd.c17
-rw-r--r--src/nvim/ex_getln.c8
-rw-r--r--src/nvim/file_search.c4
-rw-r--r--src/nvim/fileio.c66
-rw-r--r--src/nvim/fold.c12
-rw-r--r--src/nvim/getchar.c7
-rw-r--r--src/nvim/globals.h4
-rw-r--r--src/nvim/if_cscope.c8
-rw-r--r--src/nvim/indent.c6
-rw-r--r--src/nvim/indent_c.c10
-rw-r--r--src/nvim/main.c36
-rw-r--r--src/nvim/map.c18
-rw-r--r--src/nvim/map.h3
-rw-r--r--src/nvim/mark.c31
-rw-r--r--src/nvim/memfile.c12
-rw-r--r--src/nvim/memline.c26
-rw-r--r--src/nvim/memory.c14
-rw-r--r--src/nvim/misc1.c19
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/ops.c15
-rw-r--r--src/nvim/option.c20
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/os/channel.c60
-rw-r--r--src/nvim/os/fs.c59
-rw-r--r--src/nvim/os/job.c12
-rw-r--r--src/nvim/os/msgpack_rpc.c101
-rw-r--r--src/nvim/os/msgpack_rpc.h1
-rw-r--r--src/nvim/os/msgpack_rpc_helpers.c229
-rw-r--r--src/nvim/os/msgpack_rpc_helpers.h114
-rw-r--r--src/nvim/os/provider.c173
-rw-r--r--src/nvim/os/server.c7
-rw-r--r--src/nvim/os/wstream.c13
-rw-r--r--src/nvim/os_unix.c8
-rw-r--r--src/nvim/path.c18
-rw-r--r--src/nvim/quickfix.c81
-rw-r--r--src/nvim/screen.c280
-rw-r--r--src/nvim/spell.c4
-rw-r--r--src/nvim/syntax.c17
-rw-r--r--src/nvim/testdir/Makefile3
-rw-r--r--src/nvim/testdir/test55.in6
-rw-r--r--src/nvim/testdir/test55.ok4
-rw-r--r--src/nvim/testdir/test63.in25
-rw-r--r--src/nvim/testdir/test63.ok3
-rw-r--r--src/nvim/testdir/test86.in2
-rw-r--r--src/nvim/testdir/test_insertcount.in14
-rw-r--r--src/nvim/testdir/test_insertcount.ok3
-rw-r--r--src/nvim/undo.c16
-rw-r--r--src/nvim/version.c72
-rw-r--r--src/nvim/vim.h2
-rw-r--r--src/nvim/window.c207
64 files changed, 1711 insertions, 1335 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index a268e04559..8355bfe868 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -51,10 +51,10 @@ Integer buffer_get_length(Buffer buffer, Error *err)
String buffer_get_line(Buffer buffer, Integer index, Error *err)
{
String rv = {.size = 0};
- StringArray slice = buffer_get_slice(buffer, index, index, true, true, err);
+ Array slice = buffer_get_slice(buffer, index, index, true, true, err);
if (!err->set && slice.size) {
- rv = slice.items[0];
+ rv = slice.items[0].data.string;
}
free(slice.items);
@@ -70,7 +70,8 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// @param[out] err Details of an error that may have occurred
void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
{
- StringArray array = {.items = &line, .size = 1};
+ Object l = STRING_OBJ(line);
+ Array array = {.items = &l, .size = 1};
buffer_set_slice(buffer, index, index, true, true, array, err);
}
@@ -81,7 +82,7 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
/// @param[out] err Details of an error that may have occurred
void buffer_del_line(Buffer buffer, Integer index, Error *err)
{
- StringArray array = ARRAY_DICT_INIT;
+ Array array = ARRAY_DICT_INIT;
buffer_set_slice(buffer, index, index, true, true, array, err);
}
@@ -94,14 +95,14 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err)
/// @param include_end True if the slice includes the `end` parameter
/// @param[out] err Details of an error that may have occurred
/// @return An array of lines
-StringArray buffer_get_slice(Buffer buffer,
- Integer start,
- Integer end,
- Boolean include_start,
- Boolean include_end,
- Error *err)
+ArrayOf(String) buffer_get_slice(Buffer buffer,
+ Integer start,
+ Integer end,
+ Boolean include_start,
+ Boolean include_end,
+ Error *err)
{
- StringArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
@@ -118,7 +119,7 @@ StringArray buffer_get_slice(Buffer buffer,
}
rv.size = (size_t)(end - start);
- rv.items = xcalloc(sizeof(String), rv.size);
+ rv.items = xcalloc(sizeof(Object), rv.size);
for (size_t i = 0; i < rv.size; i++) {
int64_t lnum = start + (int64_t)i;
@@ -129,13 +130,13 @@ StringArray buffer_get_slice(Buffer buffer,
}
const char *bufstr = (char *) ml_get_buf(buf, (linenr_T) lnum, false);
- rv.items[i] = cstr_to_string(bufstr);
+ rv.items[i] = STRING_OBJ(cstr_to_string(bufstr));
}
end:
if (err->set) {
for (size_t i = 0; i < rv.size; i++) {
- free(rv.items[i].data);
+ free(rv.items[i].data.string.data);
}
free(rv.items);
@@ -152,15 +153,15 @@ end:
/// @param end The last line index
/// @param include_start True if the slice includes the `start` parameter
/// @param include_end True if the slice includes the `end` parameter
-/// @param lines An array of lines to use as replacement(A 0-length array
-/// will simply delete the line range)
+/// @param replacement An array of lines to use as replacement(A 0-length
+// array will simply delete the line range)
/// @param[out] err Details of an error that may have occurred
void buffer_set_slice(Buffer buffer,
Integer start,
Integer end,
Boolean include_start,
Boolean include_end,
- StringArray replacement,
+ ArrayOf(String) replacement,
Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -184,10 +185,15 @@ void buffer_set_slice(Buffer buffer,
size_t new_len = replacement.size;
size_t old_len = (size_t)(end - start);
ssize_t extra = 0; // lines added to text, can be negative
- char **lines = (new_len != 0) ? xmalloc(new_len * sizeof(char *)) : NULL;
+ char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL;
for (size_t i = 0; i < new_len; i++) {
- String l = replacement.items[i];
+ if (replacement.items[i].type != kObjectTypeString) {
+ set_api_error("all items in the replacement array must be strings", err);
+ goto end;
+ }
+
+ String l = replacement.items[i].data.string;
lines[i] = xmemdupz(l.data, l.size);
}
@@ -430,7 +436,10 @@ Boolean buffer_is_valid(Buffer buffer)
/// to the end of the buffer.
/// @param lines An array of lines
/// @param[out] err Details of an error that may have occurred
-void buffer_insert(Buffer buffer, Integer lnum, StringArray lines, Error *err)
+void buffer_insert(Buffer buffer,
+ Integer lnum,
+ ArrayOf(String) lines,
+ Error *err)
{
buffer_set_slice(buffer, lnum, lnum, false, true, lines, err);
}
@@ -441,9 +450,9 @@ void buffer_insert(Buffer buffer, Integer lnum, StringArray lines, Error *err)
/// @param name The mark's name
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple
-Position buffer_get_mark(Buffer buffer, String name, Error *err)
+ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err)
{
- Position rv = POSITION_INIT;
+ Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
@@ -473,8 +482,9 @@ Position buffer_get_mark(Buffer buffer, String name, Error *err)
return rv;
}
- rv.row = posp->lnum;
- rv.col = posp->col;
+ ADD(rv, INTEGER_OBJ(posp->lnum));
+ ADD(rv, INTEGER_OBJ(posp->col));
+
return rv;
}
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index b049412014..2dd229ec5f 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -5,17 +5,15 @@
#include <stdbool.h>
#include <string.h>
-#define ARRAY_DICT_INIT {.size = 0, .items = NULL}
+#define ARRAY_DICT_INIT {.size = 0, .capacity = 0, .items = NULL}
#define STRING_INIT {.data = NULL, .size = 0}
#define OBJECT_INIT { .type = kObjectTypeNil }
-#define POSITION_INIT { .row = 0, .col = 0 }
#define REMOTE_TYPE(type) typedef uint64_t type
-#define TYPED_ARRAY_OF(type) \
- typedef struct { \
- type *items; \
- size_t size; \
- } type##Array
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+ #define ArrayOf(...) Array
+ #define DictionaryOf(...) Dictionary
+#endif
// Basic types
typedef struct {
@@ -38,15 +36,6 @@ REMOTE_TYPE(Tabpage);
typedef struct object Object;
-TYPED_ARRAY_OF(Buffer);
-TYPED_ARRAY_OF(Window);
-TYPED_ARRAY_OF(Tabpage);
-TYPED_ARRAY_OF(String);
-
-typedef struct {
- Integer row, col;
-} Position;
-
typedef struct {
Object *items;
size_t size, capacity;
@@ -60,40 +49,30 @@ typedef struct {
} Dictionary;
typedef enum {
+ kObjectTypeBuffer,
+ kObjectTypeWindow,
+ kObjectTypeTabpage,
kObjectTypeNil,
kObjectTypeBoolean,
kObjectTypeInteger,
kObjectTypeFloat,
kObjectTypeString,
- kObjectTypeBuffer,
- kObjectTypeWindow,
- kObjectTypeTabpage,
kObjectTypeArray,
kObjectTypeDictionary,
- kObjectTypePosition,
- kObjectTypeStringArray,
- kObjectTypeBufferArray,
- kObjectTypeWindowArray,
- kObjectTypeTabpageArray,
} ObjectType;
struct object {
ObjectType type;
union {
+ Buffer buffer;
+ Window window;
+ Tabpage tabpage;
Boolean boolean;
Integer integer;
Float floating;
String string;
- Buffer buffer;
- Window window;
- Tabpage tabpage;
Array array;
Dictionary dictionary;
- Position position;
- StringArray stringarray;
- BufferArray bufferarray;
- WindowArray windowarray;
- TabpageArray tabpagearray;
} data;
};
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index f6fb46e1d1..14a820aa1b 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -6,6 +6,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/handle.h"
+#include "nvim/os/provider.h"
#include "nvim/ascii.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
@@ -449,6 +450,130 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
return true;
}
+void api_free_string(String value)
+{
+ if (!value.data) {
+ return;
+ }
+
+ free(value.data);
+}
+
+void api_free_object(Object value)
+{
+ switch (value.type) {
+ case kObjectTypeNil:
+ case kObjectTypeBoolean:
+ case kObjectTypeInteger:
+ case kObjectTypeFloat:
+ case kObjectTypeBuffer:
+ case kObjectTypeWindow:
+ case kObjectTypeTabpage:
+ break;
+
+ case kObjectTypeString:
+ api_free_string(value.data.string);
+ break;
+
+ case kObjectTypeArray:
+ api_free_array(value.data.array);
+ break;
+
+ case kObjectTypeDictionary:
+ api_free_dictionary(value.data.dictionary);
+ break;
+
+ default:
+ abort();
+ }
+}
+
+void api_free_array(Array value)
+{
+ for (size_t i = 0; i < value.size; i++) {
+ api_free_object(value.items[i]);
+ }
+
+ free(value.items);
+}
+
+void api_free_dictionary(Dictionary value)
+{
+ for (size_t i = 0; i < value.size; i++) {
+ api_free_string(value.items[i].key);
+ api_free_object(value.items[i].value);
+ }
+
+ free(value.items);
+}
+
+Dictionary api_metadata(void)
+{
+ static Dictionary metadata = ARRAY_DICT_INIT;
+
+ if (!metadata.size) {
+ msgpack_rpc_init_function_metadata(&metadata);
+ init_type_metadata(&metadata);
+ provider_init_feature_metadata(&metadata);
+ }
+
+ return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary;
+}
+
+static void init_type_metadata(Dictionary *metadata)
+{
+ Dictionary types = ARRAY_DICT_INIT;
+
+ Dictionary buffer_metadata = ARRAY_DICT_INIT;
+ PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer));
+
+ Dictionary window_metadata = ARRAY_DICT_INIT;
+ PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow));
+
+ Dictionary tabpage_metadata = ARRAY_DICT_INIT;
+ PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage));
+
+ PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata));
+ PUT(types, "Window", DICTIONARY_OBJ(window_metadata));
+ PUT(types, "Tabpage", DICTIONARY_OBJ(tabpage_metadata));
+
+ PUT(*metadata, "types", DICTIONARY_OBJ(types));
+}
+
+/// Creates a deep clone of an object
+static Object copy_object(Object obj)
+{
+ switch (obj.type) {
+ case kObjectTypeNil:
+ case kObjectTypeBoolean:
+ case kObjectTypeInteger:
+ case kObjectTypeFloat:
+ return obj;
+
+ case kObjectTypeString:
+ return STRING_OBJ(cstr_to_string(obj.data.string.data));
+
+ case kObjectTypeArray: {
+ Array rv = ARRAY_DICT_INIT;
+ for (size_t i = 0; i < obj.data.array.size; i++) {
+ ADD(rv, copy_object(obj.data.array.items[i]));
+ }
+ return ARRAY_OBJ(rv);
+ }
+
+ case kObjectTypeDictionary: {
+ Dictionary rv = ARRAY_DICT_INIT;
+ for (size_t i = 0; i < obj.data.dictionary.size; i++) {
+ KeyValuePair item = obj.data.dictionary.items[i];
+ PUT(rv, item.key.data, copy_object(item.value));
+ }
+ return DICTIONARY_OBJ(rv);
+ }
+ default:
+ abort();
+ }
+}
+
/// Recursion helper for the `vim_to_object`. This uses a pointer table
/// to avoid infinite recursion due to cyclic references
///
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index f1b9dc3bc8..f3ecdaacc4 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -51,36 +51,11 @@
.data.array = a \
})
-#define STRINGARRAY_OBJ(a) ((Object) { \
- .type = kObjectTypeStringArray, \
- .data.stringarray = a \
- })
-
-#define BUFFERARRAY_OBJ(a) ((Object) { \
- .type = kObjectTypeBufferArray, \
- .data.bufferarray = a \
- })
-
-#define WINDOWARRAY_OBJ(a) ((Object) { \
- .type = kObjectTypeWindowArray, \
- .data.windowarray = a \
- })
-
-#define TABPAGEARRAY_OBJ(a) ((Object) { \
- .type = kObjectTypeTabpageArray, \
- .data.tabpagearray = a \
- })
-
#define DICTIONARY_OBJ(d) ((Object) { \
.type = kObjectTypeDictionary, \
.data.dictionary = d \
})
-#define POSITION_OBJ(p) ((Object) { \
- .type = kObjectTypePosition, \
- .data.position = p \
- })
-
#define NIL ((Object) {.type = kObjectTypeNil})
#define PUT(dict, k, v) \
@@ -91,6 +66,25 @@
#define ADD(array, item) \
kv_push(Object, array, item)
+// Helpers used by the generated msgpack-rpc api wrappers
+#define api_init_boolean
+#define api_init_integer
+#define api_init_float
+#define api_init_string = STRING_INIT
+#define api_init_buffer
+#define api_init_window
+#define api_init_tabpage
+#define api_init_object = NIL
+#define api_init_array = ARRAY_DICT_INIT
+#define api_init_dictionary = ARRAY_DICT_INIT
+
+#define api_free_boolean(value)
+#define api_free_integer(value)
+#define api_free_float(value)
+#define api_free_buffer(value)
+#define api_free_window(value)
+#define api_free_tabpage(value)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/helpers.h.generated.h"
#endif
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 535722c087..91020d6850 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -13,9 +13,9 @@
/// @param tabpage The tabpage
/// @param[out] err Details of an error that may have occurred
/// @return The number of windows in `tabpage`
-WindowArray tabpage_get_windows(Tabpage tabpage, Error *err)
+ArrayOf(Window) tabpage_get_windows(Tabpage tabpage, Error *err)
{
- WindowArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
@@ -32,14 +32,14 @@ WindowArray tabpage_get_windows(Tabpage tabpage, Error *err)
rv.size++;
}
- rv.items = xmalloc(sizeof(Window) * rv.size);
+ rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (tp != tab) {
break;
}
- rv.items[i++] = wp->handle;
+ rv.items[i++] = WINDOW_OBJ(wp->handle);
}
return rv;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a2c50b4c81..43f2aafdc8 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -149,9 +149,9 @@ Integer vim_strwidth(String str, Error *err)
/// Returns a list of paths contained in 'runtimepath'
///
/// @return The list of paths
-StringArray vim_list_runtime_paths(void)
+ArrayOf(String) vim_list_runtime_paths(void)
{
- StringArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
uint8_t *rtp = p_rtp;
if (*rtp == NUL) {
@@ -168,19 +168,20 @@ StringArray vim_list_runtime_paths(void)
}
// Allocate memory for the copies
- rv.items = xmalloc(sizeof(String) * rv.size);
+ rv.items = xmalloc(sizeof(Object) * rv.size);
// reset the position
rtp = p_rtp;
// Start copying
for (size_t i = 0; i < rv.size && *rtp != NUL; i++) {
- rv.items[i].data = xmalloc(MAXPATHL);
+ rv.items[i].type = kObjectTypeString;
+ rv.items[i].data.string.data = xmalloc(MAXPATHL);
// Copy the path from 'runtimepath' to rv.items[i]
int length = copy_option_part(&rtp,
- (char_u *)rv.items[i].data,
+ (char_u *)rv.items[i].data.string.data,
MAXPATHL,
",");
assert(length >= 0);
- rv.items[i].size = (size_t)length;
+ rv.items[i].data.string.size = (size_t)length;
}
return rv;
@@ -307,12 +308,22 @@ void vim_err_write(String str)
write_msg(str, true);
}
+/// Higher level error reporting function that ensures all str contents
+/// are written by sending a trailing linefeed to `vim_wrr_write`
+///
+/// @param str The message
+void vim_report_error(String str)
+{
+ vim_err_write(str);
+ vim_err_write((String) {.data = "\n", .size = 1});
+}
+
/// Gets the current list of buffer handles
///
/// @return The number of buffers
-BufferArray vim_get_buffers(void)
+ArrayOf(Buffer) vim_get_buffers(void)
{
- BufferArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
buf_T *b = firstbuf;
while (b) {
@@ -320,12 +331,12 @@ BufferArray vim_get_buffers(void)
b = b->b_next;
}
- rv.items = xmalloc(sizeof(Buffer) * rv.size);
+ rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
b = firstbuf;
while (b) {
- rv.items[i++] = b->handle;
+ rv.items[i++] = BUFFER_OBJ(b->handle);
b = b->b_next;
}
@@ -370,9 +381,9 @@ void vim_set_current_buffer(Buffer buffer, Error *err)
/// Gets the current list of window handles
///
/// @return The number of windows
-WindowArray vim_get_windows(void)
+ArrayOf(Window) vim_get_windows(void)
{
- WindowArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
tabpage_T *tp;
win_T *wp;
@@ -380,11 +391,11 @@ WindowArray vim_get_windows(void)
rv.size++;
}
- rv.items = xmalloc(sizeof(Window) * rv.size);
+ rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
FOR_ALL_TAB_WINDOWS(tp, wp) {
- rv.items[i++] = wp->handle;
+ rv.items[i++] = WINDOW_OBJ(wp->handle);
}
return rv;
@@ -426,9 +437,9 @@ void vim_set_current_window(Window window, Error *err)
/// Gets the current list of tabpage handles
///
/// @return The number of tab pages
-TabpageArray vim_get_tabpages(void)
+ArrayOf(Tabpage) vim_get_tabpages(void)
{
- TabpageArray rv = ARRAY_DICT_INIT;
+ Array rv = ARRAY_DICT_INIT;
tabpage_T *tp = first_tabpage;
while (tp) {
@@ -436,12 +447,12 @@ TabpageArray vim_get_tabpages(void)
tp = tp->tp_next;
}
- rv.items = xmalloc(sizeof(Tabpage) * rv.size);
+ rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
tp = first_tabpage;
while (tp) {
- rv.items[i++] = tp->handle;
+ rv.items[i++] = TABPAGE_OBJ(tp->handle);
tp = tp->tp_next;
}
@@ -501,22 +512,33 @@ void vim_unsubscribe(uint64_t channel_id, String event)
channel_unsubscribe(channel_id, e);
}
-/// Registers the channel as the provider for `method`. This fails if
-/// a provider for `method` is already registered.
+/// Registers the channel as the provider for `feature`. This fails if
+/// a provider for `feature` is already provided by another channel.
///
/// @param channel_id The channel id
-/// @param method The method name
+/// @param feature The feature name
/// @param[out] err Details of an error that may have occurred
-void vim_register_provider(uint64_t channel_id, String method, Error *err)
+void vim_register_provider(uint64_t channel_id, String feature, Error *err)
{
char buf[METHOD_MAXLEN];
- xstrlcpy(buf, method.data, sizeof(buf));
+ xstrlcpy(buf, feature.data, sizeof(buf));
if (!provider_register(buf, channel_id)) {
- set_api_error("Provider already registered", err);
+ set_api_error("Feature doesn't exist", err);
}
}
+Array vim_get_api_info(uint64_t channel_id)
+{
+ Array rv = ARRAY_DICT_INIT;
+
+ assert(channel_id <= INT64_MAX);
+ ADD(rv, INTEGER_OBJ((int64_t)channel_id));
+ ADD(rv, DICTIONARY_OBJ(api_metadata()));
+
+ return rv;
+}
+
/// Writes a message to vim output or error buffer. The string is split
/// and flushed after each newline. Incomplete lines are kept for writing
/// later.
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 1ab441bed3..dd256f2b6d 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -33,14 +33,14 @@ Buffer window_get_buffer(Window window, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the (row, col) tuple
-Position window_get_cursor(Window window, Error *err)
+ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err)
{
- Position rv = POSITION_INIT;
+ Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
if (win) {
- rv.row = win->w_cursor.lnum;
- rv.col = win->w_cursor.col;
+ ADD(rv, INTEGER_OBJ(win->w_cursor.lnum));
+ ADD(rv, INTEGER_OBJ(win->w_cursor.col));
}
return rv;
@@ -51,31 +51,35 @@ Position window_get_cursor(Window window, Error *err)
/// @param window The window handle
/// @param pos the (row, col) tuple representing the new position
/// @param[out] err Details of an error that may have occurred
-void window_set_cursor(Window window, Position pos, Error *err)
+void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
{
win_T *win = find_window_by_handle(window, err);
- if (!win) {
+ if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger ||
+ pos.items[1].type != kObjectTypeInteger) {
+ set_api_error("\"pos\" argument must be a [row, col] array", err);
return;
}
- if (pos.row <= 0 || pos.row > win->w_buffer->b_ml.ml_line_count) {
- set_api_error("cursor position outside buffer", err);
+ if (!win) {
return;
}
- if (pos.row > LONG_MAX || pos.row < LONG_MIN) {
- set_api_error("Row value outside range", err);
+ int64_t row = pos.items[0].data.integer;
+ int64_t col = pos.items[1].data.integer;
+
+ if (row <= 0 || row > win->w_buffer->b_ml.ml_line_count) {
+ set_api_error("cursor position outside buffer", err);
return;
}
- if (pos.col > INT_MAX || pos.col < INT_MIN) {
+ if (col > MAXCOL || col < 0) {
set_api_error("Column value outside range", err);
return;
}
- win->w_cursor.lnum = (linenr_T)pos.row;
- win->w_cursor.col = (colnr_T)pos.col;
+ win->w_cursor.lnum = (linenr_T)row;
+ win->w_cursor.col = (colnr_T)col;
win->w_cursor.coladd = 0;
// When column is out of range silently correct it.
check_cursor_col_win(win);
@@ -243,14 +247,14 @@ void window_set_option(Window window, String name, Object value, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple with the window position
-Position window_get_position(Window window, Error *err)
+ArrayOf(Integer, 2) window_get_position(Window window, Error *err)
{
- Position rv = POSITION_INIT;
+ Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
if (win) {
- rv.col = win->w_wincol;
- rv.row = win->w_winrow;
+ ADD(rv, INTEGER_OBJ(win->w_winrow));
+ ADD(rv, INTEGER_OBJ(win->w_wincol));
}
return rv;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 77bed67d5f..11171617ef 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1314,7 +1314,7 @@ buflist_new (
* for hard links. */
FileID file_id;
bool file_id_valid = (sfname != NULL &&
- os_get_file_id((char *)sfname, &file_id));
+ os_fileid((char *)sfname, &file_id));
if (ffname != NULL && !(flags & BLN_DUMMY)
&& (buf = buflist_findname_file_id(ffname, &file_id,
file_id_valid)) != NULL) {
@@ -1671,7 +1671,7 @@ buf_T *buflist_findname_exp(char_u *fname)
buf_T *buflist_findname(char_u *ffname)
{
FileID file_id;
- bool file_id_valid = os_get_file_id((char *)ffname, &file_id);
+ bool file_id_valid = os_fileid((char *)ffname, &file_id);
return buflist_findname_file_id(ffname, &file_id, file_id_valid);
}
@@ -1763,13 +1763,16 @@ buflist_findpat (
if (curtab_only) {
/* Ignore the match if the buffer is not open in
* the current tab. */
- win_T *wp;
-
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_buffer == buf)
+ bool found_window = false;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == buf) {
+ found_window = true;
break;
- if (wp == NULL)
+ }
+ }
+ if (!found_window) {
continue;
+ }
}
if (match >= 0) { /* already found a match */
match = -2;
@@ -2020,22 +2023,22 @@ static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col,
/*
- * Return TRUE when "wip" has 'diff' set and the diff is only for another tab
+ * Return true when "wip" has 'diff' set and the diff is only for another tab
* page. That's because a diff is local to a tab page.
*/
-static int wininfo_other_tab_diff(wininfo_T *wip)
+static bool wininfo_other_tab_diff(wininfo_T *wip)
{
- win_T *wp;
-
if (wip->wi_opt.wo_diff) {
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- /* return FALSE when it's a window in the current tab page, thus
+ FOR_ALL_WINDOWS(wp) {
+ /* return false when it's a window in the current tab page, thus
* the buffer was in diff mode here */
- if (wip->wi_win == wp)
- return FALSE;
- return TRUE;
+ if (wip->wi_win == wp) {
+ return false;
+ }
+ }
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -2221,7 +2224,7 @@ setfname (
* - if the buffer is loaded, fail
* - if the buffer is not loaded, delete it from the list
*/
- file_id_valid = os_get_file_id((char *)ffname, &file_id);
+ file_id_valid = os_fileid((char *)ffname, &file_id);
if (!(buf->b_flags & BF_DUMMY)) {
obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid);
}
@@ -2399,7 +2402,7 @@ static int otherfile_buf(buf_T *buf, char_u *ffname,
/* If no struct stat given, get it now */
if (file_id_p == NULL) {
file_id_p = &file_id;
- file_id_valid = os_get_file_id((char *)ffname, file_id_p);
+ file_id_valid = os_fileid((char *)ffname, file_id_p);
}
if (!file_id_valid) {
// file_id not valid, assume files are different.
@@ -2429,7 +2432,7 @@ void buf_set_file_id(buf_T *buf)
{
FileID file_id;
if (buf->b_fname != NULL
- && os_get_file_id((char *)buf->b_fname, &file_id)) {
+ && os_fileid((char *)buf->b_fname, &file_id)) {
buf->file_id_valid = true;
buf->file_id = file_id;
} else {
@@ -2441,7 +2444,7 @@ void buf_set_file_id(buf_T *buf)
static bool buf_same_file_id(buf_T *buf, FileID *file_id)
{
return buf->file_id_valid
- && os_file_id_equal(&(buf->file_id), file_id);
+ && os_fileid_equal(&(buf->file_id), file_id);
}
/*
@@ -3601,7 +3604,6 @@ do_arg_all (
)
{
int i;
- win_T *wp, *wpnext;
char_u *opened; /* Array of weight for which args are open:
* 0: not opened
* 1: opened in other tab
@@ -3651,8 +3653,9 @@ do_arg_all (
if (had_tab > 0)
goto_tabpage_tp(first_tabpage, TRUE, TRUE);
for (;; ) {
+ win_T *wpnext = NULL;
tpnext = curtab->tp_next;
- for (wp = firstwin; wp != NULL; wp = wpnext) {
+ for (win_T *wp = firstwin; wp != NULL; wp = wpnext) {
wpnext = wp->w_next;
buf = wp->w_buffer;
if (buf->b_ffname == NULL
@@ -3762,13 +3765,14 @@ do_arg_all (
if (opened[i] > 0) {
/* Move the already present window to below the current window */
if (curwin->w_arg_idx != i) {
- for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next) {
- if (wpnext->w_arg_idx == i) {
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_arg_idx == i) {
if (keep_tabs) {
- new_curwin = wpnext;
+ new_curwin = wp;
new_curtab = curtab;
- } else
- win_move_after(wpnext, curwin);
+ } else {
+ win_move_after(wp, curwin);
+ }
break;
}
}
@@ -4421,8 +4425,8 @@ linenr_T buf_delsign(
}
/* When deleted the last sign needs to redraw the windows to remove the
- * sign column. */
- if (buf->b_signlist == NULL) {
+ * sign column. Not when curwin is NULL (this means we're exiting). */
+ if (buf->b_signlist != NULL && curwin != NULL) {
redraw_buf_later(buf, NOT_VALID);
changed_cline_bef_curs();
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 4162df63ab..84d55fb730 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -255,6 +255,7 @@ struct wininfo_S {
typedef struct arglist {
garray_T al_ga; /* growarray with the array of file names */
int al_refcount; /* number of windows using this arglist */
+ int id; ///< id of this arglist
} alist_T;
/*
@@ -512,7 +513,7 @@ struct file_buffer {
long b_mtime; /* last change time of original file */
long b_mtime_read; /* last change time when reading */
- off_t b_orig_size; /* size of original file in bytes */
+ uint64_t b_orig_size; /* size of original file in bytes */
int b_orig_mode; /* mode of original file */
pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */
@@ -880,6 +881,28 @@ typedef struct {
proftime_T tm; /* for a time limit */
} match_T;
+/// number of positions supported by matchaddpos()
+#define MAXPOSMATCH 8
+
+/// Same as lpos_T, but with additional field len.
+typedef struct
+{
+ linenr_T lnum; ///< line number
+ colnr_T col; ///< column number
+ int len; ///< length: 0 - to the end of line
+} llpos_T;
+
+/// posmatch_T provides an array for storing match items for matchaddpos()
+/// function.
+typedef struct posmatch posmatch_T;
+struct posmatch
+{
+ llpos_T pos[MAXPOSMATCH]; ///< array of positions
+ int cur; ///< internal position counter
+ linenr_T toplnum; ///< top buffer line
+ linenr_T botlnum; ///< bottom buffer line
+};
+
/*
* matchitem_T provides a linked list for storing match items for ":match" and
* the match functions.
@@ -892,6 +915,7 @@ struct matchitem {
char_u *pattern; /* pattern to highlight */
int hlg_id; /* highlight group ID */
regmmatch_T match; /* regexp program for pattern */
+ posmatch_T pos; // position matches
match_T hl; /* struct for doing the actual highlighting */
};
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index ab0c80112f..8f540fbe09 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -87,14 +87,14 @@ void diff_buf_adjust(win_T *win)
if (!win->w_p_diff) {
// When there is no window showing a diff for this buffer, remove
// it from the diffs.
- win_T *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ bool found_win = false;
+ FOR_ALL_WINDOWS(wp) {
if ((wp->w_buffer == win->w_buffer) && wp->w_p_diff) {
- break;
+ found_win = true;
}
}
- if (wp == NULL) {
+ if (!found_win) {
int i = diff_buf_idx(win->w_buffer);
if (i != DB_COUNT) {
curtab->tp_diffbuf[i] = NULL;
@@ -581,8 +581,7 @@ static int diff_check_sanity(tabpage_T *tp, diff_T *dp)
/// @param dofold Also recompute the folds
static void diff_redraw(int dofold)
{
- win_T *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_p_diff) {
redraw_win_later(wp, SOME_VALID);
if (dofold && foldmethodIsDiff(wp)) {
@@ -947,9 +946,10 @@ void ex_diffpatch(exarg_T *eap)
os_remove((char *)buf);
// Only continue if the output file was created.
- off_t file_size;
- bool file_size_success = os_get_file_size((char *)tmp_new, &file_size);
- if (!file_size_success || file_size == 0) {
+ FileInfo file_info;
+ bool info_ok = os_fileinfo((char *)tmp_new, &file_info);
+ uint64_t filesize = os_fileinfo_size(&file_info);
+ if (!info_ok || filesize == 0) {
EMSG(_("E816: Cannot read patch output"));
} else {
if (curbuf->b_fname != NULL) {
@@ -1110,8 +1110,7 @@ void ex_diffoff(exarg_T *eap)
win_T *old_curwin = curwin;
int diffwin = FALSE;
- win_T *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
if (eap->forceit ? wp->w_p_diff : (wp == curwin)) {
// Set 'diff', 'scrollbind' off and 'wrap' on. If option values
// were saved in diff_win_options() restore them.
@@ -2363,10 +2362,8 @@ void ex_diffgetput(exarg_T *eap)
/// @param skip_idx
static void diff_fold_update(diff_T *dp, int skip_idx)
{
- win_T *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
- int i;
- for (i = 0; i < DB_COUNT; ++i) {
+ FOR_ALL_WINDOWS(wp) {
+ for (int i = 0; i < DB_COUNT; ++i) {
if ((curtab->tp_diffbuf[i] == wp->w_buffer) && (i != skip_idx)) {
foldUpdate(wp, dp->df_lnum[i], dp->df_lnum[i] + dp->df_count[i]);
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 6158176e56..b3f4e4d449 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -3798,6 +3798,8 @@ static void ins_compl_delete(void)
*/
i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
backspace_until_column(i);
+ // TODO: is this sufficient for redrawing? Redrawing everything causes
+ // flicker, thus we can't do that.
changed_cline_bef_curs();
}
@@ -6917,8 +6919,9 @@ ins_esc (
State &= ~REPLACE_FLAG;
(void)start_redo_ins();
- if (cmdchar == 'r' || cmdchar == 'v')
- stuffReadbuff(ESC_STR); /* no ESC in redo buffer */
+ if (cmdchar == 'r' || cmdchar == 'v') {
+ stuffRedoReadbuff(ESC_STR); // No ESC in redo buffer
+ }
++RedrawingDisabled;
disabled_redraw = TRUE;
return FALSE; /* repeat the insert */
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 34af143446..7793f5040c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -84,7 +84,6 @@
#include "nvim/os/channel.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
-#include "nvim/os/msgpack_rpc_helpers.h"
#include "nvim/os/dl.h"
#include "nvim/os/provider.h"
@@ -4758,7 +4757,7 @@ void listitem_free(listitem_T *item)
*/
void listitem_remove(list_T *l, listitem_T *item)
{
- list_remove(l, item, item);
+ vim_list_remove(l, item, item);
listitem_free(item);
}
@@ -5231,30 +5230,29 @@ static list_T *list_copy(list_T *orig, int deep, int copyID)
return copy;
}
-/*
- * Remove items "item" to "item2" from list "l".
- * Does not free the listitem or the value!
- */
-void list_remove(list_T *l, listitem_T *item, listitem_T *item2)
+/// Remove items "item" to "item2" from list "l".
+/// @warning Does not free the listitem or the value!
+void vim_list_remove(list_T *l, listitem_T *item, listitem_T *item2)
{
- listitem_T *ip;
-
- /* notify watchers */
- for (ip = item; ip != NULL; ip = ip->li_next) {
+ // notify watchers
+ for (listitem_T *ip = item; ip != NULL; ip = ip->li_next) {
--l->lv_len;
list_fix_watch(l, ip);
- if (ip == item2)
+ if (ip == item2) {
break;
+ }
}
- if (item2->li_next == NULL)
+ if (item2->li_next == NULL) {
l->lv_last = item->li_prev;
- else
+ } else {
item2->li_next->li_prev = item->li_prev;
- if (item->li_prev == NULL)
+ }
+ if (item->li_prev == NULL) {
l->lv_first = item2->li_next;
- else
+ } else {
item->li_prev->li_next = item2->li_next;
+ }
l->lv_idx_item = NULL;
}
@@ -6311,6 +6309,7 @@ static struct fst {
{"append", 2, 2, f_append},
{"argc", 0, 0, f_argc},
{"argidx", 0, 0, f_argidx},
+ {"arglistid", 0, 2, f_arglistid},
{"argv", 0, 1, f_argv},
{"asin", 1, 1, f_asin}, /* WJMc */
{"atan", 1, 1, f_atan},
@@ -6436,9 +6435,9 @@ static struct fst {
{"isdirectory", 1, 1, f_isdirectory},
{"islocked", 1, 1, f_islocked},
{"items", 1, 1, f_items},
- {"jobstart", 2, 3, f_job_start},
- {"jobstop", 1, 1, f_job_stop},
- {"jobwrite", 2, 2, f_job_write},
+ {"jobsend", 2, 2, f_jobsend},
+ {"jobstart", 2, 3, f_jobstart},
+ {"jobstop", 1, 1, f_jobstop},
{"join", 1, 2, f_join},
{"keys", 1, 1, f_keys},
{"last_buffer_nr", 0, 0, f_last_buffer_nr}, /* obsolete */
@@ -6456,6 +6455,7 @@ static struct fst {
{"mapcheck", 1, 3, f_mapcheck},
{"match", 2, 4, f_match},
{"matchadd", 2, 4, f_matchadd},
+ {"matchaddpos", 2, 4, f_matchaddpos},
{"matcharg", 1, 1, f_matcharg},
{"matchdelete", 1, 1, f_matchdelete},
{"matchend", 2, 4, f_matchend},
@@ -6484,6 +6484,10 @@ static struct fst {
{"resolve", 1, 1, f_resolve},
{"reverse", 1, 1, f_reverse},
{"round", 1, 1, f_round},
+ {"rpcnotify", 2, 64, f_rpcnotify},
+ {"rpcrequest", 2, 64, f_rpcrequest},
+ {"rpcstart", 1, 2, f_rpcstart},
+ {"rpcstop", 1, 1, f_rpcstop},
{"screenattr", 2, 2, f_screenattr},
{"screenchar", 2, 2, f_screenchar},
{"screencol", 0, 0, f_screencol},
@@ -6493,8 +6497,6 @@ static struct fst {
{"searchpair", 3, 7, f_searchpair},
{"searchpairpos", 3, 7, f_searchpairpos},
{"searchpos", 1, 4, f_searchpos},
- {"send_call", 2, 64, f_send_call},
- {"send_event", 2, 64, f_send_event},
{"setbufvar", 3, 3, f_setbufvar},
{"setcmdpos", 1, 1, f_setcmdpos},
{"setline", 2, 2, f_setline},
@@ -7125,6 +7127,32 @@ static void f_argidx(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = curwin->w_arg_idx;
}
+/// "arglistid" function
+static void f_arglistid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = -1;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ tabpage_T *tp = NULL;
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ long n = get_tv_number(&argvars[1]);
+ if (n >= 0) {
+ tp = find_tabpage(n);
+ }
+ } else {
+ tp = curtab;
+ }
+
+ if (tp != NULL) {
+ win_T *wp = find_win_by_nr(&argvars[0], tp);
+ if (wp != NULL) {
+ rettv->vval.v_number = wp->w_alist->id;
+ }
+ }
+ } else {
+ rettv->vval.v_number = curwin->w_alist->id;
+ }
+}
+
/*
* "argv(nr)" function
*/
@@ -7360,19 +7388,20 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv)
*/
static void f_bufwinnr(typval_T *argvars, typval_T *rettv)
{
- win_T *wp;
- int winnr = 0;
- buf_T *buf;
-
(void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
++emsg_off;
- buf = get_buf_tv(&argvars[0], TRUE);
- for (wp = firstwin; wp; wp = wp->w_next) {
+
+ buf_T *buf = get_buf_tv(&argvars[0], TRUE);
+ int winnr = 0;
+ bool found_buf = false;
+ FOR_ALL_WINDOWS(wp) {
++winnr;
- if (wp->w_buffer == buf)
+ if (wp->w_buffer == buf) {
+ found_buf = true;
break;
+ }
}
- rettv->vval.v_number = (wp != NULL ? winnr : -1);
+ rettv->vval.v_number = (found_buf ? winnr : -1);
--emsg_off;
}
@@ -9165,15 +9194,16 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_NUMBER;
- off_t file_size;
- if (os_get_file_size(fname, &file_size)) {
+ FileInfo file_info;
+ if (os_fileinfo(fname, &file_info)) {
+ uint64_t filesize = os_fileinfo_size(&file_info);
if (os_isdir((char_u *)fname))
rettv->vval.v_number = 0;
else {
- rettv->vval.v_number = (varnumber_T)file_size;
+ rettv->vval.v_number = (varnumber_T)filesize;
/* non-perfect check for overflow */
- if ((off_t)rettv->vval.v_number != file_size) {
+ if ((uint64_t)rettv->vval.v_number != filesize) {
rettv->vval.v_number = -2;
}
}
@@ -9190,7 +9220,7 @@ static void f_getftime(typval_T *argvars, typval_T *rettv)
char *fname = (char *)get_tv_string(&argvars[0]);
FileInfo file_info;
- if (os_get_file_info(fname, &file_info)) {
+ if (os_fileinfo(fname, &file_info)) {
rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec;
} else {
rettv->vval.v_number = -1;
@@ -9210,7 +9240,7 @@ static void f_getftype(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_STRING;
FileInfo file_info;
- if (os_get_file_info_link((char *)fname, &file_info)) {
+ if (os_fileinfo_link((char *)fname, &file_info)) {
uint64_t mode = file_info.stat.st_mode;
#ifdef S_ISREG
if (S_ISREG(mode))
@@ -9300,12 +9330,34 @@ static void f_getline(typval_T *argvars, typval_T *rettv)
static void f_getmatches(typval_T *argvars, typval_T *rettv)
{
matchitem_T *cur = curwin->w_match_head;
+ int i;
rettv_list_alloc(rettv);
while (cur != NULL) {
dict_T *dict = dict_alloc();
+ if (cur->match.regprog == NULL) {
+ // match added with matchaddpos()
+ for (i = 0; i < MAXPOSMATCH; ++i) {
+ llpos_T *llpos;
+ char buf[6];
+
+ llpos = &cur->pos.pos[i];
+ if (llpos->lnum == 0) {
+ break;
+ }
+ list_T *l = list_alloc();
+ list_append_number(l, (varnumber_T)llpos->lnum);
+ if (llpos->col > 0) {
+ list_append_number(l, (varnumber_T)llpos->col);
+ list_append_number(l, (varnumber_T)llpos->len);
+ }
+ sprintf(buf, "pos%d", i + 1);
+ dict_add_list(dict, buf, l);
+ }
+ } else {
+ dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
+ }
dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
- dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
dict_add_nr_str(dict, "id", (long)cur->id, NULL);
list_append_dict(rettv->vval.v_list, dict);
@@ -9790,7 +9842,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"windows",
"winaltkeys",
"writebackup",
- "neovim",
+ "nvim",
NULL
};
@@ -10456,8 +10508,40 @@ static void f_items(typval_T *argvars, typval_T *rettv)
dict_list(argvars, rettv, 2);
}
+// "jobsend()" function
+static void f_jobsend(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER || argvars[1].v_type != VAR_STRING) {
+ // First argument is the job id and second is the string to write to
+ // the job's stdin
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ Job *job = job_find(argvars[0].vval.v_number);
+
+ if (!job) {
+ // Invalid job id
+ EMSG(_(e_invjob));
+ return;
+ }
+
+ WBuffer *buf = wstream_new_buffer(xstrdup((char *)argvars[1].vval.v_string),
+ strlen((char *)argvars[1].vval.v_string),
+ 1,
+ free);
+ rettv->vval.v_number = job_write(job, buf);
+}
+
// "jobstart()" function
-static void f_job_start(typval_T *argvars, typval_T *rettv)
+static void f_jobstart(typval_T *argvars, typval_T *rettv)
{
list_T *args = NULL;
listitem_T *arg;
@@ -10535,7 +10619,7 @@ static void f_job_start(typval_T *argvars, typval_T *rettv)
}
// "jobstop()" function
-static void f_job_stop(typval_T *argvars, typval_T *rettv)
+static void f_jobstop(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -10562,38 +10646,6 @@ static void f_job_stop(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1;
}
-// "jobwrite()" function
-static void f_job_write(typval_T *argvars, typval_T *rettv)
-{
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = 0;
-
- if (check_restricted() || check_secure()) {
- return;
- }
-
- if (argvars[0].v_type != VAR_NUMBER || argvars[1].v_type != VAR_STRING) {
- // First argument is the job id and second is the string to write to
- // the job's stdin
- EMSG(_(e_invarg));
- return;
- }
-
- Job *job = job_find(argvars[0].vval.v_number);
-
- if (!job) {
- // Invalid job id
- EMSG(_(e_invjob));
- return;
- }
-
- WBuffer *buf = wstream_new_buffer(xstrdup((char *)argvars[1].vval.v_string),
- strlen((char *)argvars[1].vval.v_string),
- 1,
- free);
- rettv->vval.v_number = job_write(job, buf);
-}
-
/*
* "join()" function
*/
@@ -11104,7 +11156,52 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv)
return;
}
- rettv->vval.v_number = match_add(curwin, grp, pat, prio, id);
+ rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+}
+
+static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL
+{
+ rettv->vval.v_number = -1;
+
+ char_u buf[NUMBUFLEN];
+ char_u *group;
+ group = get_tv_string_buf_chk(&argvars[0], buf);
+ if (group == NULL) {
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_LIST) {
+ EMSG2(_(e_listarg), "matchaddpos()");
+ return;
+ }
+
+ list_T *l;
+ l = argvars[1].vval.v_list;
+ if (l == NULL) {
+ return;
+ }
+
+ int error = false;
+ int prio = 10;
+ int id = -1;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ prio = get_tv_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ id = get_tv_number_chk(&argvars[3], &error);
+ }
+ }
+ if (error == true) {
+ return;
+ }
+
+ // id == 3 is ok because matchaddpos() is supposed to substitute :3match
+ if (id == 1 || id == 2) {
+ EMSGN("E798: ID is reserved for \"match\": %" PRId64, id);
+ return;
+ }
+
+ rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l);
}
/*
@@ -11832,8 +11929,8 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
EMSGN(_(e_listidx), idx);
else {
if (argvars[2].v_type == VAR_UNKNOWN) {
- /* Remove one item, return its value. */
- list_remove(l, item, item);
+ // Remove one item, return its value.
+ vim_list_remove(l, item, item);
*rettv = item->li_tv;
free(item);
} else {
@@ -11854,7 +11951,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
if (li == NULL) /* didn't find "item2" after "item" */
EMSG(_(e_invrange));
else {
- list_remove(l, item, item2);
+ vim_list_remove(l, item, item2);
rettv_list_alloc(rettv);
l = rettv->vval.v_list;
l->lv_first = item;
@@ -12273,6 +12370,169 @@ static void f_round(typval_T *argvars, typval_T *rettv)
rettv->vval.v_float = 0.0;
}
+// "rpcnotify()" function
+static void f_rpcnotify(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number < 0) {
+ EMSG2(_(e_invarg2), "Channel id must be a positive integer");
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_STRING) {
+ EMSG2(_(e_invarg2), "Event type must be a string");
+ return;
+ }
+
+ Array args = ARRAY_DICT_INIT;
+
+ for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
+ ADD(args, vim_to_object(tv));
+ }
+
+ if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
+ (char *)argvars[1].vval.v_string,
+ args)) {
+ EMSG2(_(e_invarg2), "Channel doesn't exist");
+ return;
+ }
+
+ rettv->vval.v_number = 1;
+}
+
+// "rpcrequest()" function
+static void f_rpcrequest(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number <= 0) {
+ EMSG2(_(e_invarg2), "Channel id must be a positive integer");
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_STRING) {
+ EMSG2(_(e_invarg2), "Method name must be a string");
+ return;
+ }
+
+ Array args = ARRAY_DICT_INIT;
+
+ for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
+ ADD(args, vim_to_object(tv));
+ }
+
+ bool errored;
+ Object result;
+ if (!channel_send_call((uint64_t)argvars[0].vval.v_number,
+ (char *)argvars[1].vval.v_string,
+ args,
+ &result,
+ &errored)) {
+ EMSG2(_(e_invarg2), "Channel doesn't exist");
+ return;
+ }
+
+ if (errored) {
+ vim_report_error(result.data.string);
+ goto end;
+ }
+
+ Error conversion_error = {.set = false};
+ if (!object_to_vim(result, rettv, &conversion_error)) {
+ EMSG(_("Error converting the call result"));
+ }
+
+end:
+ api_free_object(result);
+}
+
+// "rpcstart()" function
+static void f_rpcstart(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_STRING
+ || (argvars[1].v_type != VAR_LIST && argvars[1].v_type != VAR_UNKNOWN)) {
+ // Wrong argument types
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ list_T *args = NULL;
+ int argsl = 0;
+ if (argvars[1].v_type == VAR_LIST) {
+ args = argvars[1].vval.v_list;
+ argsl = args->lv_len;
+ // Assert that all list items are strings
+ for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
+ if (arg->li_tv.v_type != VAR_STRING) {
+ EMSG(_(e_invarg));
+ return;
+ }
+ }
+ }
+
+ // Allocate extra memory for the argument vector and the NULL pointer
+ int argvl = argsl + 2;
+ char **argv = xmalloc(sizeof(char_u *) * argvl);
+
+ // Copy program name
+ argv[0] = xstrdup((char *)argvars[0].vval.v_string);
+
+ int i = 1;
+ // Copy arguments to the vector
+ if (argsl > 0) {
+ for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
+ argv[i++] = xstrdup((char *)arg->li_tv.vval.v_string);
+ }
+ }
+
+ // The last item of argv must be NULL
+ argv[i] = NULL;
+ uint64_t channel_id = channel_from_job(argv);
+
+ if (!channel_id) {
+ EMSG(_(e_api_spawn_failed));
+ }
+
+ rettv->vval.v_number = (varnumber_T)channel_id;
+}
+
+// "rpcstop()" function
+static void f_rpcstop(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER) {
+ // Wrong argument types
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ rettv->vval.v_number = channel_close(argvars[0].vval.v_number);
+}
+
/*
* "screenattr()" function
*/
@@ -12612,89 +12872,6 @@ do_searchpair (
return retval;
}
-// "send_call()" function
-static void f_send_call(typval_T *argvars, typval_T *rettv)
-{
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = 0;
-
- if (check_restricted() || check_secure()) {
- return;
- }
-
- if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number <= 0) {
- EMSG2(_(e_invarg2), "Channel id must be a positive integer");
- return;
- }
-
- if (argvars[1].v_type != VAR_STRING) {
- EMSG2(_(e_invarg2), "Method name must be a string");
- return;
- }
-
- Array args = ARRAY_DICT_INIT;
-
- for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
- }
-
- bool errored;
- Object result;
- if (!channel_send_call((uint64_t)argvars[0].vval.v_number,
- (char *)argvars[1].vval.v_string,
- args,
- &result,
- &errored)) {
- EMSG2(_(e_invarg2), "Channel doesn't exist");
- return;
- }
-
- Error conversion_error = {.set = false};
- if (errored || !object_to_vim(result, rettv, &conversion_error)) {
- EMSG(errored ?
- result.data.string.data :
- _("Error converting the call result"));
- }
-
- msgpack_rpc_free_object(result);
-}
-
-// "send_event()" function
-static void f_send_event(typval_T *argvars, typval_T *rettv)
-{
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = 0;
-
- if (check_restricted() || check_secure()) {
- return;
- }
-
- if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number < 0) {
- EMSG2(_(e_invarg2), "Channel id must be a positive integer");
- return;
- }
-
- if (argvars[1].v_type != VAR_STRING) {
- EMSG2(_(e_invarg2), "Event type must be a string");
- return;
- }
-
- Array args = ARRAY_DICT_INIT;
-
- for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
- ADD(args, vim_to_object(tv));
- }
-
- if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
- (char *)argvars[1].vval.v_string,
- args)) {
- EMSG2(_(e_invarg2), "Channel doesn't exist");
- return;
- }
-
- rettv->vval.v_number = 1;
-}
-
/*
* "searchpos()" function
*/
@@ -12926,7 +13103,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
get_dict_string(d, (char_u *)"pattern", FALSE),
(int)get_dict_number(d, (char_u *)"priority"),
- (int)get_dict_number(d, (char_u *)"id"));
+ (int)get_dict_number(d, (char_u *)"id"), NULL);
li = li->li_next;
}
rettv->vval.v_number = 0;
@@ -13209,11 +13386,18 @@ static void f_sinh(typval_T *argvars, typval_T *rettv)
rettv->vval.v_float = 0.0;
}
+/// struct used in the array that's given to qsort()
+typedef struct {
+ listitem_T *item;
+ int idx;
+} sortItem_T;
static int item_compare_ic;
+static bool item_compare_numeric;
static char_u *item_compare_func;
static dict_T *item_compare_selfdict;
static int item_compare_func_err;
+static bool item_compare_keep_zero;
#define ITEM_COMPARE_FAIL 999
/*
@@ -13221,22 +13405,40 @@ static int item_compare_func_err;
*/
static int item_compare(const void *s1, const void *s2)
{
+ sortItem_T *si1, *si2;
char_u *p1, *p2;
char_u *tofree1, *tofree2;
int res;
char_u numbuf1[NUMBUFLEN];
char_u numbuf2[NUMBUFLEN];
- p1 = tv2string(&(*(listitem_T **)s1)->li_tv, &tofree1, numbuf1, 0);
- p2 = tv2string(&(*(listitem_T **)s2)->li_tv, &tofree2, numbuf2, 0);
+ si1 = (sortItem_T *)s1;
+ si2 = (sortItem_T *)s2;
+ p1 = tv2string(&si1->item->li_tv, &tofree1, numbuf1, 0);
+ p2 = tv2string(&si2->item->li_tv, &tofree2, numbuf2, 0);
if (p1 == NULL)
p1 = (char_u *)"";
if (p2 == NULL)
p2 = (char_u *)"";
- if (item_compare_ic)
- res = STRICMP(p1, p2);
- else
- res = STRCMP(p1, p2);
+ if (!item_compare_numeric) {
+ if (item_compare_ic) {
+ res = STRICMP(p1, p2);
+ } else {
+ res = STRCMP(p1, p2);
+ }
+ } else {
+ double n1, n2;
+ n1 = strtod((char *)p1, (char **)&p1);
+ n2 = strtod((char *)p2, (char **)&p2);
+ res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
+ }
+
+ // When the result would be zero, compare the pointers themselves. Makes
+ // the sort stable.
+ if (res == 0 && !item_compare_keep_zero) {
+ res = si1->idx > si2->idx ? 1 : -1;
+ }
+
free(tofree1);
free(tofree2);
return res;
@@ -13244,6 +13446,7 @@ static int item_compare(const void *s1, const void *s2)
static int item_compare2(const void *s1, const void *s2)
{
+ sortItem_T *si1, *si2;
int res;
typval_T rettv;
typval_T argv[3];
@@ -13253,10 +13456,13 @@ static int item_compare2(const void *s1, const void *s2)
if (item_compare_func_err)
return 0;
- /* copy the values. This is needed to be able to set v_lock to VAR_FIXED
- * in the copy without changing the original list items. */
- copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]);
- copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);
+ si1 = (sortItem_T *)s1;
+ si2 = (sortItem_T *)s2;
+
+ // Copy the values. This is needed to be able to set v_lock to VAR_FIXED
+ // in the copy without changing the original list items.
+ copy_tv(&si1->item->li_tv, &argv[0]);
+ copy_tv(&si2->item->li_tv, &argv[1]);
rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
@@ -13272,6 +13478,13 @@ static int item_compare2(const void *s1, const void *s2)
if (item_compare_func_err)
res = ITEM_COMPARE_FAIL; /* return value has wrong type */
clear_tv(&rettv);
+
+ // When the result would be zero, compare the pointers themselves. Makes
+ // the sort stable.
+ if (res == 0 && !item_compare_keep_zero) {
+ res = si1->idx > si2->idx ? 1 : -1;
+ }
+
return res;
}
@@ -13282,7 +13495,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
{
list_T *l;
listitem_T *li;
- listitem_T **ptrs;
+ sortItem_T *ptrs;
long len;
long i;
@@ -13303,6 +13516,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
return; /* short list sorts pretty quickly */
item_compare_ic = FALSE;
+ item_compare_numeric = false;
item_compare_func = NULL;
item_compare_selfdict = NULL;
@@ -13320,6 +13534,15 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
item_compare_ic = TRUE;
else
item_compare_func = get_tv_string(&argvars[1]);
+ if (item_compare_func != NULL) {
+ if (STRCMP(item_compare_func, "n") == 0) {
+ item_compare_func = NULL;
+ item_compare_numeric = true;
+ } else if (STRCMP(item_compare_func, "i") == 0) {
+ item_compare_func = NULL;
+ item_compare_ic = TRUE;
+ }
+ }
}
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -13333,23 +13556,26 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
}
/* Make an array with each entry pointing to an item in the List. */
- ptrs = xmalloc((size_t)(len * sizeof (listitem_T *)));
+ ptrs = xmalloc((size_t)(len * sizeof (sortItem_T)));
i = 0;
if (sort) {
// sort(): ptrs will be the list to sort.
for (li = l->lv_first; li != NULL; li = li->li_next) {
- ptrs[i++] = li;
+ ptrs[i].item = li;
+ ptrs[i].idx = i;
+ i++;
}
item_compare_func_err = FALSE;
+ item_compare_keep_zero = false;
// Test the compare function.
if (item_compare_func != NULL
&& item_compare2(&ptrs[0], &ptrs[1]) == ITEM_COMPARE_FAIL) {
EMSG(_("E702: Sort compare function failed"));
} else {
// Sort the array with item pointers.
- qsort(ptrs, (size_t)len, sizeof (listitem_T *),
+ qsort(ptrs, (size_t)len, sizeof (sortItem_T),
item_compare_func == NULL ? item_compare : item_compare2);
if (!item_compare_func_err) {
@@ -13360,7 +13586,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
l->lv_len = 0;
for (i = 0; i < len; i++) {
- list_append(l, ptrs[i]);
+ list_append(l, ptrs[i].item);
}
}
}
@@ -13369,11 +13595,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
// f_uniq(): ptrs will be a stack of items to remove.
item_compare_func_err = FALSE;
+ item_compare_keep_zero = true;
item_compare_func_ptr = item_compare_func ? item_compare2 : item_compare;
for (li = l->lv_first; li != NULL && li->li_next != NULL; li = li->li_next) {
if (item_compare_func_ptr(&li, &li->li_next) == 0) {
- ptrs[i++] = li;
+ ptrs[i++].item = li;
}
if (item_compare_func_err) {
EMSG(_("E882: Uniq compare function failed"));
@@ -13383,12 +13610,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (!item_compare_func_err) {
while (--i >= 0) {
- li = ptrs[i]->li_next;
- ptrs[i]->li_next = li->li_next;
+ li = ptrs[i].item->li_next;
+ ptrs[i].item->li_next = li->li_next;
if (li->li_next != NULL) {
- li->li_next->li_prev = ptrs[i];
+ li->li_next->li_prev = ptrs[i].item;
} else {
- l->lv_last = ptrs[i];
+ l->lv_last = ptrs[i].item;
}
list_fix_watch(l, li);
listitem_free(li);
@@ -14681,13 +14908,12 @@ static void f_winnr(typval_T *argvars, typval_T *rettv)
*/
static void f_winrestcmd(typval_T *argvars, typval_T *rettv)
{
- win_T *wp;
int winnr = 1;
garray_T ga;
char_u buf[50];
ga_init(&ga, (int)sizeof(char), 70);
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
ga_concat(&ga, buf);
sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
@@ -19171,7 +19397,7 @@ static void script_host_eval(char *method, typval_T *argvars, typval_T *rettv)
Error err = {.set = false};
object_to_vim(result, rettv, &err);
- msgpack_rpc_free_object(result);
+ api_free_object(result);
if (err.set) {
EMSG("Error converting value back to vim");
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 5b6604fc93..b72d1941ec 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1533,7 +1533,7 @@ void write_viminfo(char_u *file, int forceit)
*/
FileInfo old_info; // FileInfo of existing viminfo file
- if (os_get_file_info((char *)fname, &old_info)
+ if (os_fileinfo((char *)fname, &old_info)
&& getuid() != ROOT_UID
&& !(old_info.stat.st_uid == getuid()
? (old_info.stat.st_mode & 0200)
@@ -4610,19 +4610,19 @@ prepare_tagpreview (
bool undo_sync /* sync undo when leaving the window */
)
{
- win_T *wp;
-
-
/*
* If there is already a preview window open, use that one.
*/
if (!curwin->w_p_pvw) {
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_p_pvw)
+ bool found_win = false;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_p_pvw) {
+ win_enter(wp, undo_sync);
+ found_win = true;
break;
- if (wp != NULL)
- win_enter(wp, undo_sync);
- else {
+ }
+ }
+ if (!found_win) {
/*
* There is no preview window open yet. Create one.
*/
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 3809858875..c3d34e9991 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -55,7 +55,6 @@
#include "nvim/os/shell.h"
#include "nvim/os/fs_defs.h"
#include "nvim/os/provider.h"
-#include "nvim/os/msgpack_rpc_helpers.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
@@ -1206,7 +1205,6 @@ check_changed_any (
int bufcount = 0;
int *bufnrs;
tabpage_T *tp;
- win_T *wp;
FOR_ALL_BUFFERS(buf) {
++bufcount;
@@ -1220,15 +1218,21 @@ check_changed_any (
/* curbuf */
bufnrs[bufnum++] = curbuf->b_fnum;
/* buf in curtab */
- FOR_ALL_WINDOWS(wp)
- if (wp->w_buffer != curbuf)
- add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer != curbuf) {
+ add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
+ }
+ }
/* buf in other tab */
- for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
- if (tp != curtab)
- for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
+ if (tp != curtab) {
+ for (win_T *wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next) {
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
+ }
+ }
+ }
+
/* any other buf */
FOR_ALL_BUFFERS(buf) {
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
@@ -1277,16 +1281,19 @@ check_changed_any (
}
/* Try to find a window that contains the buffer. */
- if (buf != curbuf)
- FOR_ALL_TAB_WINDOWS(tp, wp)
- if (wp->w_buffer == buf) {
- goto_tabpage_win(tp, wp);
- /* Paranoia: did autocms wipe out the buffer with changes? */
- if (!buf_valid(buf)) {
- goto theend;
+ if (buf != curbuf) {
+ win_T *wp;
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ goto_tabpage_win(tp, wp);
+ /* Paranoia: did autocms wipe out the buffer with changes? */
+ if (!buf_valid(buf)) {
+ goto theend;
+ }
+ goto buf_found;
}
- goto buf_found;
}
+ }
buf_found:
/* Open the changed buffer in the current window. */
@@ -1907,7 +1914,7 @@ void ex_listdo(exarg_T *eap)
break;
}
}
- if (buf_still_exists) {
+ if (!buf_still_exists) {
break;
}
@@ -2417,13 +2424,13 @@ do_source (
*/
save_current_SID = current_SID;
FileID file_id;
- bool file_id_ok = os_get_file_id((char *)fname_exp, &file_id);
+ bool file_id_ok = os_fileid((char *)fname_exp, &file_id);
for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) {
si = &SCRIPT_ITEM(current_SID);
// Compare dev/ino when possible, it catches symbolic links.
// Also compare file names, the inode may change when the file was edited.
bool file_id_equal = file_id_ok && si->file_id_valid
- && os_file_id_equal(&(si->file_id), &file_id);
+ && os_fileid_equal(&(si->file_id), &file_id);
if (si->sn_name != NULL
&& (file_id_equal || fnamecmp(si->sn_name, fname_exp) == 0)) {
break;
@@ -3256,7 +3263,7 @@ static void script_host_execute(char *method, exarg_T *eap)
Object result = provider_call(method, args);
// We don't care about the result, so free it just in case a bad provider
// returned something
- msgpack_rpc_free_object(result);
+ api_free_object(result);
}
free(script);
@@ -3270,7 +3277,7 @@ static void script_host_execute_file(char *method, exarg_T *eap)
Array args = ARRAY_DICT_INIT;
ADD(args, STRING_OBJ(cstr_to_string(buffer)));
Object result = provider_call(method, args);
- msgpack_rpc_free_object(result);
+ api_free_object(result);
}
static void script_host_do_range(char *method, exarg_T *eap)
@@ -3280,6 +3287,6 @@ static void script_host_do_range(char *method, exarg_T *eap)
ADD(args, INTEGER_OBJ(eap->line2));
ADD(args, STRING_OBJ(cstr_to_string((char *)eap->arg)));
Object result = provider_call(method, args);
- msgpack_rpc_free_object(result);
+ api_free_object(result);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index ab7add1c5b..1117b6fbcf 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5188,13 +5188,12 @@ static void ex_close(exarg_T *eap)
*/
static void ex_pclose(exarg_T *eap)
{
- win_T *win;
-
- for (win = firstwin; win != NULL; win = win->w_next)
+ FOR_ALL_WINDOWS(win) {
if (win->w_p_pvw) {
ex_win_close(eap->forceit, win, NULL);
break;
}
+ }
}
/*
@@ -5505,6 +5504,7 @@ void alist_new(void)
{
curwin->w_alist = xmalloc(sizeof(*curwin->w_alist));
curwin->w_alist->al_refcount = 1;
+ curwin->w_alist->id = ++max_alist_id;
alist_init(curwin->w_alist);
}
@@ -6119,7 +6119,6 @@ static void ex_swapname(exarg_T *eap)
*/
static void ex_syncbind(exarg_T *eap)
{
- win_T *wp;
win_T *save_curwin = curwin;
buf_T *save_curbuf = curbuf;
long topline;
@@ -6133,15 +6132,17 @@ static void ex_syncbind(exarg_T *eap)
*/
if (curwin->w_p_scb) {
topline = curwin->w_topline;
- for (wp = firstwin; wp; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_p_scb && wp->w_buffer) {
y = wp->w_buffer->b_ml.ml_line_count - p_so;
- if (topline > y)
+ if (topline > y) {
topline = y;
+ }
}
}
- if (topline < 1)
+ if (topline < 1) {
topline = 1;
+ }
} else {
topline = 1;
}
@@ -8859,7 +8860,7 @@ static void ex_match(exarg_T *eap)
c = *end;
*end = NUL;
- match_add(curwin, g, p + 1, 10, id);
+ match_add(curwin, g, p + 1, 10, id, NULL);
free(g);
*end = c;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 69fb1d344a..810df627c1 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -287,6 +287,14 @@ getcmdline (
do_digraph(-1); /* init digraph typeahead */
+ // If something above caused an error, reset the flags, we do want to type
+ // and execute commands. Display may be messed up a bit.
+ if (did_emsg) {
+ redrawcmd();
+ }
+ did_emsg = FALSE;
+ got_int = FALSE;
+
/*
* Collect the command string, handling editing keys.
*/
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index c7e1f5cbbc..955b0b0a68 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1097,7 +1097,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
url = true;
} else {
ff_expand_buffer[0] = NUL;
- if (!os_get_file_id((char *)fname, &file_id)) {
+ if (!os_fileid((char *)fname, &file_id)) {
return FAIL;
}
}
@@ -1106,7 +1106,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
|| (!url && vp->file_id_valid
- && os_file_id_equal(&(vp->file_id), &file_id))) {
+ && os_fileid_equal(&(vp->file_id), &file_id))) {
/* are the wildcard parts equal */
if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
/* already visited */
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 2e932e9695..97daa035f8 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -472,7 +472,7 @@ readfile (
if (newfile && !read_stdin && !read_buffer) {
/* Remember time of file. */
FileInfo file_info;
- if (os_get_file_info((char *)fname, &file_info)) {
+ if (os_fileinfo((char *)fname, &file_info)) {
buf_store_file_info(curbuf, &file_info);
curbuf->b_mtime_read = curbuf->b_mtime;
#ifdef UNIX
@@ -2583,7 +2583,7 @@ buf_write (
#if defined(UNIX)
perm = -1;
FileInfo file_info_old;
- if (!os_get_file_info((char *)fname, &file_info_old)) {
+ if (!os_fileinfo((char *)fname, &file_info_old)) {
newfile = TRUE;
} else {
perm = file_info_old.stat.st_mode;
@@ -2629,7 +2629,7 @@ buf_write (
goto fail;
}
if (overwriting) {
- os_get_file_info((char *)fname, &file_info_old);
+ os_fileinfo((char *)fname, &file_info_old);
}
}
@@ -2712,9 +2712,9 @@ buf_write (
* - it's a symbolic link
* - we don't have write permission in the directory
*/
- if (file_info_old.stat.st_nlink > 1
- || !os_get_file_info_link((char *)fname, &file_info)
- || !os_file_info_id_equal(&file_info, &file_info_old)) {
+ if (os_fileinfo_hardlinks(&file_info_old) > 1
+ || !os_fileinfo_link((char *)fname, &file_info)
+ || !os_fileinfo_id_equal(&file_info, &file_info_old)) {
backup_copy = TRUE;
} else
# endif
@@ -2728,7 +2728,7 @@ buf_write (
STRCPY(IObuff, fname);
for (i = 4913;; i += 123) {
sprintf((char *)path_tail(IObuff), "%d", i);
- if (!os_get_file_info_link((char *)IObuff, &file_info)) {
+ if (!os_fileinfo_link((char *)IObuff, &file_info)) {
break;
}
}
@@ -2739,7 +2739,7 @@ buf_write (
else {
# ifdef UNIX
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
- if (!os_get_file_info((char *)IObuff, &file_info)
+ if (!os_fileinfo((char *)IObuff, &file_info)
|| file_info.stat.st_uid != file_info_old.stat.st_uid
|| file_info.stat.st_gid != file_info_old.stat.st_gid
|| (long)file_info.stat.st_mode != perm) {
@@ -2759,20 +2759,20 @@ buf_write (
*/
if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) {
# ifdef UNIX
- bool file_info_link_ok = os_get_file_info_link((char *)fname, &file_info);
+ bool file_info_link_ok = os_fileinfo_link((char *)fname, &file_info);
/* Symlinks. */
if ((bkc_flags & BKC_BREAKSYMLINK)
&& file_info_link_ok
- && !os_file_info_id_equal(&file_info, &file_info_old)) {
+ && !os_fileinfo_id_equal(&file_info, &file_info_old)) {
backup_copy = FALSE;
}
/* Hardlinks. */
if ((bkc_flags & BKC_BREAKHARDLINK)
- && file_info_old.stat.st_nlink > 1
+ && os_fileinfo_hardlinks(&file_info_old) > 1
&& (!file_info_link_ok
- || os_file_info_id_equal(&file_info, &file_info_old))) {
+ || os_fileinfo_id_equal(&file_info, &file_info_old))) {
backup_copy = FALSE;
}
# endif
@@ -2837,14 +2837,14 @@ buf_write (
/*
* Check if backup file already exists.
*/
- if (os_get_file_info((char *)backup, &file_info_new)) {
+ if (os_fileinfo((char *)backup, &file_info_new)) {
/*
* Check if backup file is same as original file.
* May happen when modname() gave the same file back (e.g. silly
* link). If we don't check here, we either ruin the file when
* copying or erase it after writing.
*/
- if (os_file_info_id_equal(&file_info_new, &file_info_old)) {
+ if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) {
free(backup);
backup = NULL; /* no backup file to delete */
}
@@ -2861,7 +2861,7 @@ buf_write (
wp = backup;
*wp = 'z';
while (*wp > 'a'
- && os_get_file_info((char *)backup, &file_info_new)) {
+ && os_fileinfo((char *)backup, &file_info_new)) {
--*wp;
}
/* They all exist??? Must be something wrong. */
@@ -3201,9 +3201,9 @@ nobackup:
FileInfo file_info;
/* Don't delete the file when it's a hard or symbolic link. */
- if ((!newfile && file_info_old.stat.st_nlink > 1)
- || (os_get_file_info_link((char *)fname, &file_info)
- && !os_file_info_id_equal(&file_info, &file_info_old))) {
+ if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1)
+ || (os_fileinfo_link((char *)fname, &file_info)
+ && !os_fileinfo_id_equal(&file_info, &file_info_old))) {
errmsg = (char_u *)_("E166: Can't open linked file for writing");
} else
#endif
@@ -3416,7 +3416,7 @@ restore_backup:
/* don't change the owner when it's already OK, some systems remove
* permission or ACL stuff */
FileInfo file_info;
- if (!os_get_file_info((char *)wfname, &file_info)
+ if (!os_fileinfo((char *)wfname, &file_info)
|| file_info.stat.st_uid != file_info_old.stat.st_uid
|| file_info.stat.st_gid != file_info_old.stat.st_gid) {
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
@@ -3713,7 +3713,7 @@ nofail:
/* Update the timestamp to avoid an "overwrite changed file"
* prompt when writing again. */
- if (os_get_file_info((char *)fname, &file_info_old)) {
+ if (os_fileinfo((char *)fname, &file_info_old)) {
buf_store_file_info(buf, &file_info_old);
buf->b_mtime_read = buf->b_mtime;
}
@@ -4536,7 +4536,7 @@ int vim_rename(char_u *from, char_u *to)
// Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
FileInfo from_info;
- if (!os_get_file_info((char *)from, &from_info)) {
+ if (!os_fileinfo((char *)from, &from_info)) {
return -1;
}
@@ -4544,8 +4544,8 @@ int vim_rename(char_u *from, char_u *to)
// This happens when "from" and "to" differ in case and are on a FAT32
// filesystem. In that case go through a temp file name.
FileInfo to_info;
- if (os_get_file_info((char *)to, &to_info)
- && os_file_info_id_equal(&from_info, &to_info)) {
+ if (os_fileinfo((char *)to, &to_info)
+ && os_fileinfo_id_equal(&from_info, &to_info)) {
use_tmp_file = true;
}
@@ -4790,7 +4790,7 @@ buf_check_timestamp (
int helpmesg = FALSE;
int reload = FALSE;
int can_reload = FALSE;
- off_t orig_size = buf->b_orig_size;
+ uint64_t orig_size = buf->b_orig_size;
int orig_mode = buf->b_orig_mode;
static int busy = FALSE;
int n;
@@ -4812,7 +4812,7 @@ buf_check_timestamp (
bool file_info_ok;
if (!(buf->b_flags & BF_NOTEDITED)
&& buf->b_mtime != 0
- && (!(file_info_ok = os_get_file_info((char *)buf->b_ffname, &file_info))
+ && (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info))
|| time_differs((long)file_info.stat.st_mtim.tv_sec, buf->b_mtime)
|| (int)file_info.stat.st_mode != buf->b_orig_mode
)) {
@@ -5127,9 +5127,10 @@ void buf_reload(buf_T *buf, int orig_mode)
}
void buf_store_file_info(buf_T *buf, FileInfo *file_info)
+ FUNC_ATTR_NONNULL_ALL
{
buf->b_mtime = (long)file_info->stat.st_mtim.tv_sec;
- buf->b_orig_size = file_info->stat.st_size;
+ buf->b_orig_size = os_fileinfo_size(file_info);
buf->b_orig_mode = (int)file_info->stat.st_mode;
}
@@ -6176,12 +6177,17 @@ aucmd_prepbuf (
int save_acd;
/* Find a window that is for the new buffer */
- if (buf == curbuf) /* be quick when buf is curbuf */
+ if (buf == curbuf) { /* be quick when buf is curbuf */
win = curwin;
- else
- for (win = firstwin; win != NULL; win = win->w_next)
- if (win->w_buffer == buf)
+ } else {
+ win = NULL;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == buf) {
+ win = wp;
break;
+ }
+ }
+ }
/* Allocate "aucmd_win" when needed. If this fails (out of memory) fall
* back to using the current window. */
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index f65bbc0875..186e75981e 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -460,13 +460,10 @@ void newFoldLevel(void)
newFoldLevelWin(curwin);
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
- win_T *wp;
-
/*
* Set the same foldlevel in other windows in diff mode.
*/
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) {
wp->w_p_fdl = curwin->w_p_fdl;
newFoldLevelWin(wp);
@@ -1140,19 +1137,18 @@ setManualFold (
)
{
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
- win_T *wp;
linenr_T dlnum;
/*
* Do the same operation in other windows in diff mode. Calculate the
* line number from the diffs.
*/
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) {
dlnum = diff_lnum_win(curwin->w_cursor.lnum, wp);
- if (dlnum != 0)
+ if (dlnum != 0) {
(void)setManualFoldWin(wp, dlnum, opening, recurse, NULL);
+ }
}
}
}
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 6c772a8a66..0d61172d69 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -601,6 +601,13 @@ void stuffReadbuff(char_u *s)
add_buff(&readbuf1, s, -1L);
}
+/// Append string "s" to the redo stuff buffer.
+/// @remark CSI and K_SPECIAL must already have been escaped.
+void stuffRedoReadbuff(char_u *s)
+{
+ add_buff(&readbuf2, s, -1L);
+}
+
void stuffReadbuffLen(char_u *s, long len)
{
add_buff(&readbuf1, s, len);
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 1ff8887598..674786ff08 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -519,7 +519,7 @@ EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */
EXTERN win_T *prevwin INIT(= NULL); /* previous window */
# define W_NEXT(wp) ((wp)->w_next)
-# define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next)
+# define FOR_ALL_WINDOWS(wp) for (win_T *wp = firstwin; wp != NULL; wp = wp->w_next)
/*
* When using this macro "break" only breaks out of the inner loop. Use "goto"
* to break out of the tabpage loop.
@@ -568,6 +568,7 @@ EXTERN int mf_dont_release INIT(= FALSE); /* don't release blocks */
* to this when the window is using the global argument list.
*/
EXTERN alist_T global_alist; /* global argument list */
+EXTERN int max_alist_id INIT(= 0); ///< the previous argument list id
EXTERN int arg_had_last INIT(= FALSE); /* accessed last file in
global_alist */
@@ -1098,6 +1099,7 @@ EXTERN garray_T error_ga
* Excluded are errors that are only used once and debugging messages.
*/
EXTERN char_u e_abort[] INIT(= N_("E470: Command aborted"));
+EXTERN char_u e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
EXTERN char_u e_argreq[] INIT(= N_("E471: Argument required"));
EXTERN char_u e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
EXTERN char_u e_cmdwin[] INIT(= N_(
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 9e07a60ee1..667e6512f3 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -473,7 +473,7 @@ cs_add_common (
fname = (char *)vim_strnsave((char_u *)fname, len);
free(fbuf);
FileInfo file_info;
- bool file_info_ok = os_get_file_info(fname, &file_info);
+ bool file_info_ok = os_fileinfo(fname, &file_info);
if (!file_info_ok) {
staterr:
if (p_csverbose)
@@ -504,7 +504,7 @@ staterr:
else
(void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
- file_info_ok = os_get_file_info(fname2, &file_info);
+ file_info_ok = os_fileinfo(fname2, &file_info);
if (!file_info_ok) {
if (p_csverbose)
cs_stat_emsg(fname2);
@@ -1181,7 +1181,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
i = -1; /* can be set to the index of an empty item in csinfo */
for (j = 0; j < csinfo_size; j++) {
if (csinfo[j].fname != NULL
- && os_file_id_equal_file_info(&(csinfo[j].file_id), file_info)) {
+ && os_fileid_equal_fileinfo(&(csinfo[j].file_id), file_info)) {
if (p_csverbose)
(void)EMSG(_("E568: duplicate cscope database not added"));
return -1;
@@ -1224,7 +1224,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
} else
csinfo[i].flags = NULL;
- os_file_info_get_id(file_info, &(csinfo[i].file_id));
+ os_fileinfo_id(file_info, &(csinfo[i].file_id));
return i;
} /* cs_insert_filelist */
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 9258ee93b6..7090e007bf 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -451,6 +451,7 @@ int get_breakindent_win(win_T *wp, char_u *line) {
static int prev_indent = 0; /* cached indent value */
static int prev_ts = 0L; /* cached tabstop value */
static char_u *prev_line = NULL; /* cached pointer to line */
+ static int prev_tick = 0; // changedtick of cached value
int bri = 0;
/* window width minus window margin space, i.e. what rests for text */
const int eff_wwidth = wp->w_width
@@ -459,10 +460,11 @@ int get_breakindent_win(win_T *wp, char_u *line) {
? number_width(wp) + 1 : 0);
/* used cached indent, unless pointer or 'tabstop' changed */
- if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts)
- {
+ if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
+ || prev_tick != wp->w_buffer->b_changedtick) {
prev_line = line;
prev_ts = wp->w_buffer->b_p_ts;
+ prev_tick = wp->w_buffer->b_changedtick;
prev_indent = get_indent_str(line,
(int)wp->w_buffer->b_p_ts, wp->w_p_list);
}
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 6e12194b63..509f94dbf2 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -2009,12 +2009,14 @@ int get_c_indent(void)
* ldfd) {
* }
*/
- if (curbuf->b_ind_js || (curbuf->b_ind_keep_case_label
- && cin_iscase(skipwhite(get_cursor_line_ptr()),
- FALSE)))
+ if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
+ && cin_iscase(skipwhite(get_cursor_line_ptr()), FALSE)) {
amount = get_indent();
- else
+ } else if (curbuf->b_ind_js) {
+ amount = get_indent_lnum(lnum);
+ } else {
amount = skip_label(lnum, &l);
+ }
start_brace = BRACE_AT_END;
}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 2f06a2cbf2..7dc299e73b 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -12,6 +12,8 @@
#include <string.h>
#include <stdbool.h>
+#include <msgpack.h>
+
#include "nvim/ascii.h"
#include "nvim/vim.h"
#include "nvim/main.h"
@@ -57,6 +59,9 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/signal.h"
+#include "nvim/os/msgpack_rpc_helpers.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
/* Maximum number of commands from + or -c arguments. */
#define MAX_ARG_CMDS 10
@@ -116,9 +121,6 @@ static void init_locale(void);
# endif
#endif /* NO_VIM_MAIN */
-extern const uint8_t msgpack_metadata[];
-extern const unsigned int msgpack_metadata_size;
-
/*
* Different types of error messages.
*/
@@ -190,6 +192,7 @@ int main(int argc, char **argv)
init_yank(); /* init yank buffers */
alist_init(&global_alist); /* Init the argument list to empty. */
+ global_alist.id = 0;
/*
* Set the default values for the options.
@@ -471,11 +474,10 @@ int main(int argc, char **argv)
edit_buffers(&params);
if (params.diff_mode) {
- win_T *wp;
-
/* set options in each window for "vimdiff". */
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
diff_win_options(wp, TRUE);
+ }
}
/*
@@ -1027,12 +1029,18 @@ static void command_line_scan(mparm_T *parmp)
msg_putchar('\n');
msg_didout = FALSE;
mch_exit(0);
- } else if (STRICMP(argv[0] + argv_idx, "api-msgpack-metadata") == 0) {
- for (unsigned int i = 0; i<msgpack_metadata_size; i++) {
- putchar(msgpack_metadata[i]);
+ } else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
+ msgpack_sbuffer* b = msgpack_sbuffer_new();
+ msgpack_packer* p = msgpack_packer_new(b, msgpack_sbuffer_write);
+ Object md = DICTIONARY_OBJ(api_metadata());
+ msgpack_rpc_from_object(md, p);
+
+ for (size_t i = 0; i < b->size; i++) {
+ putchar(b->data[i]);
}
+
mch_exit(0);
- } else if (STRICMP(argv[0] + argv_idx, "embedded-mode") == 0) {
+ } else if (STRICMP(argv[0] + argv_idx, "embed") == 0) {
embedded_mode = true;
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
#if !defined(UNIX)
@@ -2094,9 +2102,9 @@ static int file_owned(char *fname)
{
uid_t uid = getuid();
FileInfo file_info;
- bool file_owned = os_get_file_info(fname, &file_info)
+ bool file_owned = os_fileinfo(fname, &file_info)
&& file_info.stat.st_uid == uid;
- bool link_owned = os_get_file_info_link(fname, &file_info)
+ bool link_owned = os_fileinfo_link(fname, &file_info)
&& file_info.stat.st_uid == uid;
return file_owned && link_owned;
}
@@ -2213,8 +2221,8 @@ static void usage(void)
main_msg(_("-W <scriptout>\tWrite all typed commands to file <scriptout>"));
main_msg(_("--startuptime <file>\tWrite startup timing messages to <file>"));
main_msg(_("-i <viminfo>\t\tUse <viminfo> instead of .viminfo"));
- main_msg(_("--api-msgpack-metadata\tDump API metadata information and exit"));
- main_msg(_("--embedded-mode\tUse stdin/stdout as a msgpack-rpc channel. "
+ main_msg(_("--api-info\t\tDump API metadata serialized to msgpack and exit"));
+ main_msg(_("--embed\t\tUse stdin/stdout as a msgpack-rpc channel. "
"This can be used for embedding Neovim into other programs"));
main_msg(_("-h or --help\tPrint Help (this message) and exit"));
main_msg(_("--version\t\tPrint version information and exit"));
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 2e47e8b249..24aa38d67d 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -1,10 +1,12 @@
#include <stdlib.h>
#include <stdbool.h>
+#include <string.h>
#include "nvim/map.h"
#include "nvim/map_defs.h"
#include "nvim/vim.h"
#include "nvim/memory.h"
+#include "nvim/os/msgpack_rpc.h"
#include "nvim/lib/khash.h"
@@ -87,7 +89,23 @@
return rv; \
}
+static inline khint_t String_hash(String s)
+{
+ khint_t h = 0;
+ for (size_t i = 0; i < s.size && s.data[i]; i++) {
+ h = (h << 5) - h + (uint8_t)s.data[i];
+ }
+ return h;
+}
+
+static inline bool String_eq(String a, String b)
+{
+ return strncmp(a.data, b.data, min(a.size, b.size)) == 0;
+}
+
+
MAP_IMPL(cstr_t, uint64_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
+MAP_IMPL(String, rpc_method_handler_fn, DEFAULT_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 73698cba22..616516c3e1 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -4,6 +4,8 @@
#include <stdbool.h>
#include "nvim/map_defs.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/os/msgpack_rpc.h"
#define MAP_DECLS(T, U) \
KHASH_DECLARE(T##_##U##_map, T, U) \
@@ -23,6 +25,7 @@ MAP_DECLS(cstr_t, uint64_t)
MAP_DECLS(cstr_t, ptr_t)
MAP_DECLS(ptr_t, ptr_t)
MAP_DECLS(uint64_t, ptr_t)
+MAP_DECLS(String, rpc_method_handler_fn)
#define map_new(T, U) map_##T##_##U##_new
#define map_free(T, U) map_##T##_##U##_free
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 43469cab45..6339cf8275 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -500,7 +500,6 @@ void fmarks_check_names(buf_T *buf)
{
char_u *name;
int i;
- win_T *wp;
if (buf->b_ffname == NULL)
return;
@@ -512,10 +511,10 @@ void fmarks_check_names(buf_T *buf)
for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
fmarks_check_one(&namedfm[i], name, buf);
- FOR_ALL_WINDOWS(wp)
- {
- for (i = 0; i < wp->w_jumplistlen; ++i)
+ FOR_ALL_WINDOWS(wp) {
+ for (i = 0; i < wp->w_jumplistlen; ++i) {
fmarks_check_one(&wp->w_jumplist[i], name, buf);
+ }
}
free(name);
@@ -1042,7 +1041,6 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_a
{
int i;
int fnum = curbuf->b_fnum;
- win_T *win;
pos_T *posp;
if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks)
@@ -1085,22 +1083,26 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_a
/*
* Adjust items in all windows related to the current buffer.
*/
- FOR_ALL_WINDOWS(win)
- {
+ FOR_ALL_WINDOWS(win) {
/* marks in the jumplist */
- for (i = 0; i < win->w_jumplistlen; ++i)
- if (win->w_jumplist[i].fmark.fnum == fnum)
+ for (i = 0; i < win->w_jumplistlen; ++i) {
+ if (win->w_jumplist[i].fmark.fnum == fnum) {
col_adjust(&(win->w_jumplist[i].fmark.mark));
+ }
+ }
if (win->w_buffer == curbuf) {
/* marks in the tag stack */
- for (i = 0; i < win->w_tagstacklen; i++)
- if (win->w_tagstack[i].fmark.fnum == fnum)
+ for (i = 0; i < win->w_tagstacklen; i++) {
+ if (win->w_tagstack[i].fmark.fnum == fnum) {
col_adjust(&(win->w_tagstack[i].fmark.mark));
+ }
+ }
/* cursor position for other windows with the same buffer */
- if (win != curwin)
+ if (win != curwin) {
col_adjust(&win->w_cursor);
+ }
}
}
}
@@ -1526,10 +1528,7 @@ void copy_viminfo_marks(vir_T *virp, FILE *fp_out, int count, int eof, int flags
fputs((char *)line, fp_out);
}
if (load_marks) {
- win_T *wp;
-
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_buffer == curbuf)
wp->w_changelistidx = curbuf->b_changelistlen;
}
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 82369b739a..827cff2299 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -122,11 +122,11 @@ memfile_T *mf_open(char_u *fname, int flags)
* mf_blocknr_max must be rounded up.
*/
FileInfo file_info;
- if (mfp->mf_fd >= 0
- && os_get_file_info_fd(mfp->mf_fd, &file_info)
- && file_info.stat.st_blksize >= MIN_SWAP_PAGE_SIZE
- && file_info.stat.st_blksize <= MAX_SWAP_PAGE_SIZE) {
- mfp->mf_page_size = file_info.stat.st_blksize;
+ if (mfp->mf_fd >= 0 && os_fileinfo_fd(mfp->mf_fd, &file_info)) {
+ uint64_t blocksize = os_fileinfo_blocksize(&file_info);
+ if (blocksize >= MIN_SWAP_PAGE_SIZE && blocksize <= MAX_SWAP_PAGE_SIZE) {
+ mfp->mf_page_size = blocksize;
+ }
}
if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
@@ -1017,7 +1017,7 @@ mf_do_open (
*/
FileInfo file_info;
if ((flags & O_CREAT)
- && os_get_file_info_link((char *)mfp->mf_fname, &file_info)) {
+ && os_fileinfo_link((char *)mfp->mf_fname, &file_info)) {
mfp->mf_fd = -1;
EMSG(_("E300: Swap file already exists (symlink attack?)"));
} else {
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 229de4ae1c..04ee0d7f55 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -686,9 +686,9 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
}
}
FileInfo file_info;
- if (os_get_file_info((char *)buf->b_ffname, &file_info)) {
+ if (os_fileinfo((char *)buf->b_ffname, &file_info)) {
long_to_char((long)file_info.stat.st_mtim.tv_sec, b0p->b0_mtime);
- long_to_char((long)os_file_info_get_inode(&file_info), b0p->b0_ino);
+ long_to_char((long)os_fileinfo_inode(&file_info), b0p->b0_ino);
buf_store_file_info(buf, &file_info);
buf->b_mtime_read = buf->b_mtime;
} else {
@@ -961,8 +961,8 @@ void ml_recover(void)
FileInfo swp_file_info;
mtime = char_to_long(b0p->b0_mtime);
if (curbuf->b_ffname != NULL
- && os_get_file_info((char *)curbuf->b_ffname, &org_file_info)
- && ((os_get_file_info((char *)mfp->mf_fname, &swp_file_info)
+ && os_fileinfo((char *)curbuf->b_ffname, &org_file_info)
+ && ((os_fileinfo((char *)mfp->mf_fname, &swp_file_info)
&& org_file_info.stat.st_mtim.tv_sec
> swp_file_info.stat.st_mtim.tv_sec)
|| org_file_info.stat.st_mtim.tv_sec != mtime)) {
@@ -1494,7 +1494,7 @@ static time_t swapfile_info(char_u *fname)
/* print the swap file date */
FileInfo file_info;
- if (os_get_file_info((char *)fname, &file_info)) {
+ if (os_fileinfo((char *)fname, &file_info)) {
#ifdef UNIX
/* print name of owner of the file */
if (os_get_uname(file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) {
@@ -1630,9 +1630,9 @@ void ml_sync_all(int check_file, int check_char)
* call ml_preserve() to get rid of all negative numbered blocks.
*/
FileInfo file_info;
- if (!os_get_file_info((char *)buf->b_ffname, &file_info)
+ if (!os_fileinfo((char *)buf->b_ffname, &file_info)
|| file_info.stat.st_mtim.tv_sec != buf->b_mtime_read
- || (off_t)file_info.stat.st_size != buf->b_orig_size) {
+ || os_fileinfo_size(&file_info) != buf->b_orig_size) {
ml_preserve(buf, FALSE);
did_check_timestamps = FALSE;
need_check_timestamps = TRUE; /* give message later */
@@ -3180,7 +3180,7 @@ attention_message (
msg_outtrans(buf->b_fname);
MSG_PUTS("\"\n");
FileInfo file_info;
- if (os_get_file_info((char *)buf->b_fname, &file_info)) {
+ if (os_fileinfo((char *)buf->b_fname, &file_info)) {
MSG_PUTS(_(" dated: "));
x = file_info.stat.st_mtim.tv_sec;
p = ctime(&x); // includes '\n'
@@ -3294,7 +3294,7 @@ findswapname (
// Extra security check: When a swap file is a symbolic link, this
// is most likely a symlink attack.
FileInfo file_info;
- bool file_or_link_found = os_get_file_info_link((char *)fname, &file_info);
+ bool file_or_link_found = os_fileinfo_link((char *)fname, &file_info);
if (!file_or_link_found) {
break;
}
@@ -3558,8 +3558,8 @@ fnamecmp_ino (
int retval_s; /* flag: buf_s valid */
FileInfo file_info;
- if (os_get_file_info((char *)fname_c, &file_info)) {
- ino_c = os_file_info_get_inode(&file_info);
+ if (os_fileinfo((char *)fname_c, &file_info)) {
+ ino_c = os_fileinfo_inode(&file_info);
}
/*
@@ -3567,8 +3567,8 @@ fnamecmp_ino (
* the swap file may be outdated. If that fails (e.g. this path is not
* valid on this machine), use the inode from block 0.
*/
- if (os_get_file_info((char *)fname_s, &file_info)) {
- ino_s = os_file_info_get_inode(&file_info);
+ if (os_fileinfo((char *)fname_s, &file_info)) {
+ ino_s = os_fileinfo_inode(&file_info);
} else {
ino_s = (uint64_t)ino_block0;
}
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 50dcca3c84..1c3d6e372c 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -121,7 +121,8 @@ void *xmalloc(size_t size)
void *ret = try_malloc(size);
if (!ret) {
- OUT_STR("Vim: Error: Out of memory.\n");
+ OUT_STR(e_outofmem);
+ out_char('\n');
preserve_exit();
}
return ret;
@@ -147,7 +148,8 @@ void *xcalloc(size_t count, size_t size)
if (!ret && (!count || !size))
ret = calloc(1, 1);
if (!ret) {
- OUT_STR("Vim: Error: Out of memory.\n");
+ OUT_STR(e_outofmem);
+ out_char('\n');
preserve_exit();
}
}
@@ -174,7 +176,8 @@ void *xrealloc(void *ptr, size_t size)
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) {
- OUT_STR("Vim: Error: Out of memory.\n");
+ OUT_STR(e_outofmem);
+ out_char('\n');
preserve_exit();
}
}
@@ -194,7 +197,7 @@ void *xmallocz(size_t size)
void *ret;
if (total_size < size) {
- OUT_STR("Vim: Data too large to fit into virtual memory space\n");
+ OUT_STR(_("Vim: Data too large to fit into virtual memory space\n"));
preserve_exit();
}
@@ -316,7 +319,8 @@ char *xstrdup(const char *str)
try_to_free_memory();
ret = strdup(str);
if (!ret) {
- OUT_STR("Vim: Error: Out of memory.\n");
+ OUT_STR(e_outofmem);
+ out_char('\n');
preserve_exit();
}
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index d31bd44493..d7e9618639 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -1877,16 +1877,16 @@ void changed_bytes(linenr_T lnum, colnr_T col)
/* Diff highlighting in other diff windows may need to be updated too. */
if (curwin->w_p_diff) {
- win_T *wp;
linenr_T wlnum;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_p_diff && wp != curwin) {
redraw_win_later(wp, VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0)
changedOneline(wp->w_buffer, wlnum);
}
+ }
}
}
@@ -1973,17 +1973,18 @@ changed_lines (
/* When the number of lines doesn't change then mark_adjust() isn't
* called and other diff buffers still need to be marked for
* displaying. */
- win_T *wp;
linenr_T wlnum;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_p_diff && wp != curwin) {
redraw_win_later(wp, VALID);
wlnum = diff_lnum_win(lnum, wp);
- if (wlnum > 0)
+ if (wlnum > 0) {
changed_lines_buf(wp->w_buffer, wlnum,
lnume - lnum + wlnum, 0L);
+ }
}
+ }
}
changed_common(lnum, col, lnume, xtra);
@@ -2214,14 +2215,14 @@ unchanged (
*/
void check_status(buf_T *buf)
{
- win_T *wp;
-
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_buffer == buf && wp->w_status_height) {
wp->w_redr_status = TRUE;
- if (must_redraw < VALID)
+ if (must_redraw < VALID) {
must_redraw = VALID;
+ }
}
+ }
}
/*
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 55b86f61dd..cc82630548 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -4008,12 +4008,9 @@ dozet:
/* Redraw when 'foldenable' changed */
if (old_fen != curwin->w_p_fen) {
- win_T *wp;
-
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
/* Adjust 'foldenable' in diff-synced windows. */
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) {
wp->w_p_fen = curwin->w_p_fen;
changed_window_setting_win(wp);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index f1cb34577b..9b98c84be4 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -48,7 +48,6 @@
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/os/provider.h"
-#include "nvim/os/msgpack_rpc_helpers.h"
#include "nvim/api/private/helpers.h"
/*
@@ -3698,17 +3697,15 @@ op_format (
}
if (oap->is_VIsual) {
- win_T *wp;
-
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_old_cursor_lnum != 0) {
/* When lines have been inserted or deleted, adjust the end of
* the Visual area to be redrawn. */
- if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum)
+ if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) {
wp->w_old_cursor_lnum += old_line_count;
- else
+ } else {
wp->w_old_visual_lnum += old_line_count;
+ }
}
}
}
@@ -5258,7 +5255,7 @@ static void get_clipboard(int name)
return;
err:
- msgpack_rpc_free_object(result);
+ api_free_object(result);
free(reg->y_array);
reg->y_array = NULL;
reg->y_size = 0;
@@ -5289,5 +5286,5 @@ static void set_clipboard(int name)
ADD(args, ARRAY_OBJ(lines));
Object result = provider_call("clipboard_set", args);
- msgpack_rpc_free_object(result);
+ api_free_object(result);
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 6eac1033c4..b26b6ed4cc 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -974,12 +974,6 @@ static struct vimoption
{"infercase", "inf", P_BOOL|P_VI_DEF,
(char_u *)&p_inf, PV_INF,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
- {"initclipboard","icpb",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_icpb, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
- {"initpython","ipy",P_STRING|P_VI_DEF|P_SECURE,
- (char_u *)&p_ipy, PV_NONE,
- {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
{"insertmode", "im", P_BOOL|P_VI_DEF|P_VIM,
(char_u *)&p_im, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
@@ -4306,7 +4300,6 @@ did_set_string_option (
/* When 'spelllang' or 'spellfile' is set and there is a window for this
* buffer in which 'spell' is set load the wordlists. */
else if (varp == &(curbuf->b_s.b_p_spl) || varp == &(curbuf->b_s.b_p_spf)) {
- win_T *wp;
int l;
if (varp == &(curbuf->b_s.b_p_spf)) {
@@ -4317,10 +4310,11 @@ did_set_string_option (
}
if (errmsg == NULL) {
- FOR_ALL_WINDOWS(wp)
- if (wp->w_buffer == curbuf && wp->w_p_spell) {
- errmsg = did_set_spelllang(wp);
- break;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == curbuf && wp->w_p_spell) {
+ errmsg = did_set_spelllang(wp);
+ break;
+ }
}
}
}
@@ -5075,9 +5069,7 @@ set_bool_option (
/* There can be only one window with 'previewwindow' set. */
else if ((int *)varp == &curwin->w_p_pvw) {
if (curwin->w_p_pvw) {
- win_T *win;
-
- for (win = firstwin; win != NULL; win = win->w_next) {
+ FOR_ALL_WINDOWS(win) {
if (win->w_p_pvw && win != curwin) {
curwin->w_p_pvw = FALSE;
return (char_u *)N_("E590: A preview window already exists");
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 555e9166d6..cd61b6427c 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -631,8 +631,6 @@ EXTERN int p_write; /* 'write' */
EXTERN int p_wa; /* 'writeany' */
EXTERN int p_wb; /* 'writebackup' */
EXTERN long p_wd; /* 'writedelay' */
-EXTERN char *p_ipy; // 'initpython'
-EXTERN char *p_icpb; // 'initclipboard'
/*
* "indir" values for buffer-local opions.
diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c
index 39455df862..1670424e4e 100644
--- a/src/nvim/os/channel.c
+++ b/src/nvim/os/channel.c
@@ -22,8 +22,10 @@
#include "nvim/memory.h"
#include "nvim/os_unix.h"
#include "nvim/message.h"
+#include "nvim/term.h"
#include "nvim/map.h"
#include "nvim/log.h"
+#include "nvim/misc1.h"
#include "nvim/lib/kvec.h"
#define CHANNEL_BUFFER_SIZE 0xffff
@@ -156,7 +158,7 @@ bool channel_send_event(uint64_t id, char *name, Array args)
if (id > 0) {
if (!(channel = pmap_get(uint64_t)(channels, id)) || !channel->enabled) {
- msgpack_rpc_free_array(args);
+ api_free_array(args);
return false;
}
send_event(channel, name, args);
@@ -184,7 +186,7 @@ bool channel_send_call(uint64_t id,
Channel *channel = NULL;
if (!(channel = pmap_get(uint64_t)(channels, id)) || !channel->enabled) {
- msgpack_rpc_free_array(args);
+ api_free_array(args);
return false;
}
@@ -194,11 +196,10 @@ bool channel_send_call(uint64_t id,
char buf[256];
snprintf(buf,
sizeof(buf),
- "Channel %" PRIu64 " was closed due to a high stack depth "
- "while processing a RPC call",
+ "Channel %" PRIu64 " crossed maximum stack depth",
channel->id);
*result = STRING_OBJ(cstr_to_string(buf));
- msgpack_rpc_free_array(args);
+ api_free_array(args);
return false;
}
@@ -223,14 +224,6 @@ bool channel_send_call(uint64_t id,
channel->enabled && // the channel is still enabled
kv_size(channel->call_stack) >= size); // the call didn't return
- if (!(kv_size(channel->call_stack)
- || channel->enabled
- || channel->rpc_call_level)) {
- // Close the channel if it has been disabled and we have not been called
- // by `parse_msgpack`(It would be unsafe to close the channel otherwise)
- close_channel(channel);
- }
-
*errored = frame.errored;
*result = frame.result;
@@ -274,6 +267,23 @@ void channel_unsubscribe(uint64_t id, char *event)
unsubscribe(channel, event);
}
+/// Closes a channel
+///
+/// @param id The channel id
+/// @return true if successful, false otherwise
+bool channel_close(uint64_t id)
+{
+ Channel *channel;
+
+ if (!(channel = pmap_get(uint64_t)(channels, id)) || !channel->enabled) {
+ return false;
+ }
+
+ channel_kill(channel);
+ channel->enabled = false;
+ return true;
+}
+
/// Creates an API channel from stdin/stdout. This is used when embedding
/// Neovim
static void channel_from_stdio(void)
@@ -340,11 +350,11 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
- UnpackResult result;
+ msgpack_unpack_return result;
// Deserialize everything we can.
- while ((result = msgpack_rpc_unpack(channel->unpacker, &unpacked))
- == kUnpackResultOk) {
+ while ((result = msgpack_unpacker_next(channel->unpacker, &unpacked)) ==
+ MSGPACK_UNPACK_SUCCESS) {
if (kv_size(channel->call_stack) && is_rpc_response(&unpacked.data)) {
if (is_valid_rpc_response(&unpacked.data, channel)) {
call_stack_pop(&unpacked.data, channel);
@@ -371,7 +381,13 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
}
}
- if (result == kUnpackResultFail) {
+ if (result == MSGPACK_UNPACK_NOMEM_ERROR) {
+ OUT_STR(e_outofmem);
+ out_char('\n');
+ preserve_exit();
+ }
+
+ if (result == MSGPACK_UNPACK_PARSE_ERROR) {
// See src/msgpack/unpack_template.h in msgpack source tree for
// causes for this error(search for 'goto _failed')
//
@@ -450,7 +466,7 @@ static void broadcast_event(char *name, Array args)
});
if (!kv_size(subscribed)) {
- msgpack_rpc_free_array(args);
+ api_free_array(args);
goto end;
}
@@ -498,7 +514,13 @@ static void close_channel(Channel *channel)
pmap_free(cstr_t)(channel->subscribed_events);
kv_destroy(channel->call_stack);
+ channel_kill(channel);
+ free(channel);
+}
+
+static void channel_kill(Channel *channel)
+{
if (channel->is_job) {
if (channel->data.job) {
job_stop(channel->data.job);
@@ -513,8 +535,6 @@ static void close_channel(Channel *channel)
mch_exit(0);
}
}
-
- free(channel);
}
static void close_cb(uv_handle_t *handle)
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index aca7005064..bb4e897887 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -258,20 +258,6 @@ int os_file_is_writable(const char *name)
return 0;
}
-/// Get the size of a file in bytes.
-///
-/// @param[out] size pointer to an off_t to put the size into.
-/// @return `true` for success, `false` for failure.
-bool os_get_file_size(const char *name, off_t *size)
-{
- uv_stat_t statbuf;
- if (os_stat(name, &statbuf)) {
- *size = statbuf.st_size;
- return true;
- }
- return false;
-}
-
/// Rename a file or directory.
///
/// @return `OK` for success, `FAIL` for failure.
@@ -345,7 +331,7 @@ int os_remove(const char *path)
/// @param path Path to the file.
/// @param[out] file_info Pointer to a FileInfo to put the information in.
/// @return `true` on success, `false` for failure.
-bool os_get_file_info(const char *path, FileInfo *file_info)
+bool os_fileinfo(const char *path, FileInfo *file_info)
{
return os_stat(path, &(file_info->stat));
}
@@ -355,7 +341,7 @@ bool os_get_file_info(const char *path, FileInfo *file_info)
/// @param path Path to the file.
/// @param[out] file_info Pointer to a FileInfo to put the information in.
/// @return `true` on success, `false` for failure.
-bool os_get_file_info_link(const char *path, FileInfo *file_info)
+bool os_fileinfo_link(const char *path, FileInfo *file_info)
{
uv_fs_t request;
int result = uv_fs_lstat(uv_default_loop(), &request, path, NULL);
@@ -369,7 +355,7 @@ bool os_get_file_info_link(const char *path, FileInfo *file_info)
/// @param file_descriptor File descriptor of the file.
/// @param[out] file_info Pointer to a FileInfo to put the information in.
/// @return `true` on success, `false` for failure.
-bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info)
+bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
{
uv_fs_t request;
int result = uv_fs_fstat(uv_default_loop(), &request, file_descriptor, NULL);
@@ -381,7 +367,7 @@ bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info)
/// Compare the inodes of two FileInfos
///
/// @return `true` if the two FileInfos represent the same file.
-bool os_file_info_id_equal(const FileInfo *file_info_1,
+bool os_fileinfo_id_equal(const FileInfo *file_info_1,
const FileInfo *file_info_2)
{
return file_info_1->stat.st_ino == file_info_2->stat.st_ino
@@ -392,7 +378,7 @@ bool os_file_info_id_equal(const FileInfo *file_info_1,
///
/// @param file_info Pointer to the `FileInfo`
/// @param[out] file_id Pointer to a `FileID`
-void os_file_info_get_id(const FileInfo *file_info, FileID *file_id)
+void os_fileinfo_id(const FileInfo *file_info, FileID *file_id)
{
file_id->inode = file_info->stat.st_ino;
file_id->device_id = file_info->stat.st_dev;
@@ -403,17 +389,44 @@ void os_file_info_get_id(const FileInfo *file_info, FileID *file_id)
/// @deprecated Use `FileID` instead, this function is only needed in memline.c
/// @param file_info Pointer to the `FileInfo`
/// @return the inode number
-uint64_t os_file_info_get_inode(const FileInfo *file_info)
+uint64_t os_fileinfo_inode(const FileInfo *file_info)
{
return file_info->stat.st_ino;
}
+/// Get the size of a file from a `FileInfo`.
+///
+/// @return filesize in bytes.
+uint64_t os_fileinfo_size(const FileInfo *file_info)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return file_info->stat.st_size;
+}
+
+/// Get the number of hardlinks from a `FileInfo`.
+///
+/// @return number of hardlinks.
+uint64_t os_fileinfo_hardlinks(const FileInfo *file_info)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return file_info->stat.st_nlink;
+}
+
+/// Get the blocksize from a `FileInfo`.
+///
+/// @return blocksize in bytes.
+uint64_t os_fileinfo_blocksize(const FileInfo *file_info)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return file_info->stat.st_blksize;
+}
+
/// Get the `FileID` for a given path
///
/// @param path Path to the file.
/// @param[out] file_info Pointer to a `FileID` to fill in.
/// @return `true` on sucess, `false` for failure.
-bool os_get_file_id(const char *path, FileID *file_id)
+bool os_fileid(const char *path, FileID *file_id)
{
uv_stat_t statbuf;
if (os_stat(path, &statbuf)) {
@@ -429,7 +442,7 @@ bool os_get_file_id(const char *path, FileID *file_id)
/// @param file_id_1 Pointer to first `FileID`
/// @param file_id_2 Pointer to second `FileID`
/// @return `true` if the two `FileID`s represent te same file.
-bool os_file_id_equal(const FileID *file_id_1, const FileID *file_id_2)
+bool os_fileid_equal(const FileID *file_id_1, const FileID *file_id_2)
{
return file_id_1->inode == file_id_2->inode
&& file_id_1->device_id == file_id_2->device_id;
@@ -440,7 +453,7 @@ bool os_file_id_equal(const FileID *file_id_1, const FileID *file_id_2)
/// @param file_id Pointer to a `FileID`
/// @param file_info Pointer to a `FileInfo`
/// @return `true` if the `FileID` and the `FileInfo` represent te same file.
-bool os_file_id_equal_file_info(const FileID *file_id,
+bool os_fileid_equal_fileinfo(const FileID *file_id,
const FileInfo *file_info)
{
return file_id->inode == file_info->stat.st_ino
diff --git a/src/nvim/os/job.c b/src/nvim/os/job.c
index 9deca9de74..9fb2a49e50 100644
--- a/src/nvim/os/job.c
+++ b/src/nvim/os/job.c
@@ -197,6 +197,12 @@ Job *job_start(char **argv,
job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr;
+ // Give all handles a reference to the job
+ handle_set_job((uv_handle_t *)&job->proc, job);
+ handle_set_job((uv_handle_t *)&job->proc_stdin, job);
+ handle_set_job((uv_handle_t *)&job->proc_stdout, job);
+ handle_set_job((uv_handle_t *)&job->proc_stderr, job);
+
// Spawn the job
if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) {
free_job(job);
@@ -204,12 +210,6 @@ Job *job_start(char **argv,
return NULL;
}
- // Give all handles a reference to the job
- handle_set_job((uv_handle_t *)&job->proc, job);
- handle_set_job((uv_handle_t *)&job->proc_stdin, job);
- handle_set_job((uv_handle_t *)&job->proc_stdout, job);
- handle_set_job((uv_handle_t *)&job->proc_stderr, job);
-
job->in = wstream_new(maxmem);
wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin);
// Start the readable streams
diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c
index c6e2af2f1c..d7e3d33c4b 100644
--- a/src/nvim/os/msgpack_rpc.c
+++ b/src/nvim/os/msgpack_rpc.c
@@ -17,9 +17,6 @@
# include "os/msgpack_rpc.c.generated.h"
#endif
-extern const uint8_t msgpack_metadata[];
-extern const unsigned int msgpack_metadata_size;
-
/// Validates the basic structure of the msgpack-rpc call and fills `res`
/// with the basic response structure.
///
@@ -39,11 +36,6 @@ WBuffer *msgpack_rpc_call(uint64_t channel_id,
return serialize_response(response_id, err, NIL, sbuffer);
}
- if (req->via.array.ptr[2].type == MSGPACK_OBJECT_POSITIVE_INTEGER
- && req->via.array.ptr[2].via.u64 == 0) {
- return serialize_metadata(response_id, channel_id, sbuffer);
- }
-
// dispatch the call
Error error = { .set = false };
Object rv = msgpack_rpc_dispatch(channel_id, req, &error);
@@ -63,42 +55,6 @@ WBuffer *msgpack_rpc_call(uint64_t channel_id,
return serialize_response(response_id, NULL, rv, sbuffer);
}
-/// Try to unpack a msgpack document from the data in the unpacker buffer. This
-/// function is a replacement to msgpack.h `msgpack_unpack_next` that lets
-/// the called know if the unpacking failed due to bad input or due to missing
-/// data.
-///
-/// @param unpacker The unpacker containing the parse buffer
-/// @param result The result which will contain the parsed object
-/// @return kUnpackResultOk : An object was parsed
-/// kUnpackResultFail : Got bad input
-/// kUnpackResultNeedMore: Need more data
-UnpackResult msgpack_rpc_unpack(msgpack_unpacker* unpacker,
- msgpack_unpacked* result)
- FUNC_ATTR_NONNULL_ALL
-{
- if (result->zone != NULL) {
- msgpack_zone_free(result->zone);
- }
-
- int res = msgpack_unpacker_execute(unpacker);
-
- if (res > 0) {
- result->zone = msgpack_unpacker_release_zone(unpacker);
- result->data = msgpack_unpacker_data(unpacker);
- msgpack_unpacker_reset(unpacker);
- return kUnpackResultOk;
- }
-
- if (res < 0) {
- // Since we couldn't parse it, destroy the data consumed so far
- msgpack_unpacker_reset(unpacker);
- return kUnpackResultFail;
- }
-
- return kUnpackResultNeedMore;
-}
-
/// Finishes the msgpack-rpc call with an error message.
///
/// @param msg The error message
@@ -109,12 +65,22 @@ void msgpack_rpc_error(char *msg, msgpack_packer *res)
size_t len = strlen(msg);
// error message
- msgpack_pack_raw(res, len);
- msgpack_pack_raw_body(res, msg, len);
+ msgpack_pack_bin(res, len);
+ msgpack_pack_bin_body(res, msg, len);
// Nil result
msgpack_pack_nil(res);
}
+/// Handler executed when an invalid method name is passed
+Object msgpack_rpc_handle_missing_method(uint64_t channel_id,
+ msgpack_object *req,
+ Error *error)
+{
+ snprintf(error->msg, sizeof(error->msg), "Invalid method name");
+ error->set = true;
+ return NIL;
+}
+
/// Serializes a msgpack-rpc request or notification(id == 0)
WBuffer *serialize_request(uint64_t request_id,
String method,
@@ -132,14 +98,14 @@ WBuffer *serialize_request(uint64_t request_id,
msgpack_pack_uint64(&pac, request_id);
}
- msgpack_pack_raw(&pac, method.size);
- msgpack_pack_raw_body(&pac, method.data, method.size);
+ msgpack_pack_bin(&pac, method.size);
+ msgpack_pack_bin_body(&pac, method.data, method.size);
msgpack_rpc_from_array(args, &pac);
WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size),
sbuffer->size,
refcount,
free);
- msgpack_rpc_free_array(args);
+ api_free_array(args);
msgpack_sbuffer_clear(sbuffer);
return rv;
}
@@ -160,8 +126,8 @@ WBuffer *serialize_response(uint64_t response_id,
if (err_msg) {
String err = {.size = strlen(err_msg), .data = err_msg};
// error message
- msgpack_pack_raw(&pac, err.size);
- msgpack_pack_raw_body(&pac, err.data, err.size);
+ msgpack_pack_bin(&pac, err.size);
+ msgpack_pack_bin_body(&pac, err.data, err.size);
// Nil result
msgpack_pack_nil(&pac);
} else {
@@ -175,32 +141,7 @@ WBuffer *serialize_response(uint64_t response_id,
sbuffer->size,
1, // responses only go though 1 channel
free);
- msgpack_rpc_free_object(arg);
- msgpack_sbuffer_clear(sbuffer);
- return rv;
-}
-
-WBuffer *serialize_metadata(uint64_t id,
- uint64_t channel_id,
- msgpack_sbuffer *sbuffer)
- FUNC_ATTR_NONNULL_ALL
-{
- msgpack_packer pac;
- msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
- msgpack_pack_array(&pac, 4);
- msgpack_pack_int(&pac, 1);
- msgpack_pack_uint64(&pac, id);
- // Nil error
- msgpack_pack_nil(&pac);
- // The result is the [channel_id, metadata] array
- msgpack_pack_array(&pac, 2);
- msgpack_pack_uint64(&pac, channel_id);
- msgpack_pack_raw(&pac, msgpack_metadata_size);
- msgpack_pack_raw_body(&pac, msgpack_metadata, msgpack_metadata_size);
- WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size),
- sbuffer->size,
- 1,
- free);
+ api_free_object(arg);
msgpack_sbuffer_clear(sbuffer);
return rv;
}
@@ -234,9 +175,9 @@ static char *msgpack_rpc_validate(uint64_t *response_id, msgpack_object *req)
return "Message type must be 0";
}
- if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER
- && req->via.array.ptr[2].type != MSGPACK_OBJECT_RAW) {
- return "Method must be a positive integer or a string";
+ if (req->via.array.ptr[2].type != MSGPACK_OBJECT_BIN
+ && req->via.array.ptr[2].type != MSGPACK_OBJECT_STR) {
+ return "Method must be a string";
}
if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) {
diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h
index 35f175d2a0..3476d791ea 100644
--- a/src/nvim/os/msgpack_rpc.h
+++ b/src/nvim/os/msgpack_rpc.h
@@ -25,6 +25,7 @@ typedef Object (*rpc_method_handler_fn)(uint64_t channel_id,
/// Initializes the msgpack-rpc method table
void msgpack_rpc_init(void);
+void msgpack_rpc_init_function_metadata(Dictionary *metadata);
/// Dispatches to the actual API function after basic payload validation by
/// `msgpack_rpc_call`. It is responsible for validating/converting arguments
diff --git a/src/nvim/os/msgpack_rpc_helpers.c b/src/nvim/os/msgpack_rpc_helpers.c
index e2c277abe4..b14de8245c 100644
--- a/src/nvim/os/msgpack_rpc_helpers.c
+++ b/src/nvim/os/msgpack_rpc_helpers.c
@@ -7,61 +7,67 @@
#include "nvim/vim.h"
#include "nvim/memory.h"
-#define REMOTE_FUNCS_IMPL(t, lt) \
- bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \
- { \
- *arg = obj->via.u64; \
- return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER; \
- } \
- \
- void msgpack_rpc_from_##lt(t result, msgpack_packer *res) \
- { \
- msgpack_pack_uint64(res, result); \
- }
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/msgpack_rpc_helpers.c.generated.h"
+#endif
-#define TYPED_ARRAY_IMPL(t, lt) \
- bool msgpack_rpc_to_##lt##array(msgpack_object *obj, t##Array *arg) \
+static msgpack_zone zone;
+static msgpack_sbuffer sbuffer;
+
+#define HANDLE_TYPE_CONVERSION_IMPL(t, lt) \
+ bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \
+ FUNC_ATTR_NONNULL_ALL \
{ \
- if (obj->type != MSGPACK_OBJECT_ARRAY) { \
+ if (obj->type != MSGPACK_OBJECT_EXT \
+ || obj->via.ext.type != kObjectType##t) { \
return false; \
} \
\
- arg->size = obj->via.array.size; \
- arg->items = xcalloc(obj->via.array.size, sizeof(t)); \
+ msgpack_object data; \
+ msgpack_unpack_return ret = msgpack_unpack(obj->via.ext.ptr, \
+ obj->via.ext.size, \
+ NULL, \
+ &zone, \
+ &data); \
\
- for (size_t i = 0; i < obj->via.array.size; i++) { \
- if (!msgpack_rpc_to_##lt(obj->via.array.ptr + i, &arg->items[i])) { \
- return false; \
- } \
+ if (ret != MSGPACK_UNPACK_SUCCESS) { \
+ return false; \
} \
\
+ *arg = data.via.u64; \
return true; \
} \
\
- void msgpack_rpc_from_##lt##array(t##Array result, msgpack_packer *res) \
+ void msgpack_rpc_from_##lt(t o, msgpack_packer *res) \
+ FUNC_ATTR_NONNULL_ARG(2) \
{ \
- msgpack_pack_array(res, result.size); \
- \
- for (size_t i = 0; i < result.size; i++) { \
- msgpack_rpc_from_##lt(result.items[i], res); \
- } \
- } \
- \
- void msgpack_rpc_free_##lt##array(t##Array value) { \
- for (size_t i = 0; i < value.size; i++) { \
- msgpack_rpc_free_##lt(value.items[i]); \
- } \
- \
- free(value.items); \
+ msgpack_packer pac; \
+ msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \
+ msgpack_pack_uint64(&pac, o); \
+ msgpack_pack_ext(res, sbuffer.size, kObjectType##t); \
+ msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \
+ msgpack_sbuffer_clear(&sbuffer); \
}
+void msgpack_rpc_helpers_init(void)
+{
+ msgpack_zone_init(&zone, 0xfff);
+ msgpack_sbuffer_init(&sbuffer);
+}
+
+HANDLE_TYPE_CONVERSION_IMPL(Buffer, buffer)
+HANDLE_TYPE_CONVERSION_IMPL(Window, window)
+HANDLE_TYPE_CONVERSION_IMPL(Tabpage, tabpage)
+
bool msgpack_rpc_to_boolean(msgpack_object *obj, Boolean *arg)
+ FUNC_ATTR_NONNULL_ALL
{
*arg = obj->via.boolean;
return obj->type == MSGPACK_OBJECT_BOOLEAN;
}
bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg)
+ FUNC_ATTR_NONNULL_ALL
{
if (obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER
&& obj->via.u64 <= INT64_MAX) {
@@ -74,23 +80,27 @@ bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg)
}
bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg)
+ FUNC_ATTR_NONNULL_ALL
{
*arg = obj->via.dec;
return obj->type == MSGPACK_OBJECT_DOUBLE;
}
bool msgpack_rpc_to_string(msgpack_object *obj, String *arg)
+ FUNC_ATTR_NONNULL_ALL
{
- if (obj->type != MSGPACK_OBJECT_RAW) {
+ if (obj->type == MSGPACK_OBJECT_BIN || obj->type == MSGPACK_OBJECT_STR) {
+ arg->data = xmemdupz(obj->via.bin.ptr, obj->via.bin.size);
+ arg->size = obj->via.bin.size;
+ } else {
return false;
}
- arg->data = xmemdupz(obj->via.raw.ptr, obj->via.raw.size);
- arg->size = obj->via.raw.size;
return true;
}
bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg)
+ FUNC_ATTR_NONNULL_ALL
{
switch (obj->type) {
case MSGPACK_OBJECT_NIL:
@@ -110,7 +120,8 @@ bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg)
arg->type = kObjectTypeFloat;
return msgpack_rpc_to_float(obj, &arg->data.floating);
- case MSGPACK_OBJECT_RAW:
+ case MSGPACK_OBJECT_BIN:
+ case MSGPACK_OBJECT_STR:
arg->type = kObjectTypeString;
return msgpack_rpc_to_string(obj, &arg->data.string);
@@ -122,21 +133,22 @@ bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg)
arg->type = kObjectTypeDictionary;
return msgpack_rpc_to_dictionary(obj, &arg->data.dictionary);
+ case MSGPACK_OBJECT_EXT:
+ switch (obj->via.ext.type) {
+ case kObjectTypeBuffer:
+ return msgpack_rpc_to_buffer(obj, &arg->data.buffer);
+ case kObjectTypeWindow:
+ return msgpack_rpc_to_window(obj, &arg->data.window);
+ case kObjectTypeTabpage:
+ return msgpack_rpc_to_tabpage(obj, &arg->data.tabpage);
+ }
default:
return false;
}
}
-bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg)
-{
- return obj->type == MSGPACK_OBJECT_ARRAY
- && obj->via.array.size == 2
- && msgpack_rpc_to_integer(obj->via.array.ptr, &arg->row)
- && msgpack_rpc_to_integer(obj->via.array.ptr + 1, &arg->col);
-}
-
-
bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg)
+ FUNC_ATTR_NONNULL_ALL
{
if (obj->type != MSGPACK_OBJECT_ARRAY) {
return false;
@@ -155,6 +167,7 @@ bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg)
}
bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg)
+ FUNC_ATTR_NONNULL_ALL
{
if (obj->type != MSGPACK_OBJECT_MAP) {
return false;
@@ -180,6 +193,7 @@ bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg)
}
void msgpack_rpc_from_boolean(Boolean result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
if (result) {
msgpack_pack_true(res);
@@ -189,22 +203,26 @@ void msgpack_rpc_from_boolean(Boolean result, msgpack_packer *res)
}
void msgpack_rpc_from_integer(Integer result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
msgpack_pack_int64(res, result);
}
void msgpack_rpc_from_float(Float result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
msgpack_pack_double(res, result);
}
void msgpack_rpc_from_string(String result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
- msgpack_pack_raw(res, result.size);
- msgpack_pack_raw_body(res, result.data, result.size);
+ msgpack_pack_bin(res, result.size);
+ msgpack_pack_bin_body(res, result.data, result.size);
}
void msgpack_rpc_from_object(Object result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
switch (result.type) {
case kObjectTypeNil:
@@ -231,10 +249,6 @@ void msgpack_rpc_from_object(Object result, msgpack_packer *res)
msgpack_rpc_from_array(result.data.array, res);
break;
- case kObjectTypePosition:
- msgpack_rpc_from_position(result.data.position, res);
- break;
-
case kObjectTypeBuffer:
msgpack_rpc_from_buffer(result.data.buffer, res);
break;
@@ -247,36 +261,14 @@ void msgpack_rpc_from_object(Object result, msgpack_packer *res)
msgpack_rpc_from_tabpage(result.data.tabpage, res);
break;
- case kObjectTypeStringArray:
- msgpack_rpc_from_stringarray(result.data.stringarray, res);
- break;
-
- case kObjectTypeBufferArray:
- msgpack_rpc_from_bufferarray(result.data.bufferarray, res);
- break;
-
- case kObjectTypeWindowArray:
- msgpack_rpc_from_windowarray(result.data.windowarray, res);
- break;
-
- case kObjectTypeTabpageArray:
- msgpack_rpc_from_tabpagearray(result.data.tabpagearray, res);
- break;
-
case kObjectTypeDictionary:
msgpack_rpc_from_dictionary(result.data.dictionary, res);
break;
}
}
-void msgpack_rpc_from_position(Position result, msgpack_packer *res)
-{
- msgpack_pack_array(res, 2);;
- msgpack_pack_int64(res, result.row);
- msgpack_pack_int64(res, result.col);
-}
-
void msgpack_rpc_from_array(Array result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
msgpack_pack_array(res, result.size);
@@ -286,6 +278,7 @@ void msgpack_rpc_from_array(Array result, msgpack_packer *res)
}
void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
+ FUNC_ATTR_NONNULL_ARG(2)
{
msgpack_pack_map(res, result.size);
@@ -294,87 +287,3 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
msgpack_rpc_from_object(result.items[i].value, res);
}
}
-
-void msgpack_rpc_free_string(String value)
-{
- if (!value.data) {
- return;
- }
-
- free(value.data);
-}
-
-void msgpack_rpc_free_object(Object value)
-{
- switch (value.type) {
- case kObjectTypeNil:
- case kObjectTypeBoolean:
- case kObjectTypeInteger:
- case kObjectTypeFloat:
- case kObjectTypePosition:
- case kObjectTypeBuffer:
- case kObjectTypeWindow:
- case kObjectTypeTabpage:
- break;
-
- case kObjectTypeString:
- msgpack_rpc_free_string(value.data.string);
- break;
-
- case kObjectTypeArray:
- msgpack_rpc_free_array(value.data.array);
- break;
-
- case kObjectTypeStringArray:
- msgpack_rpc_free_stringarray(value.data.stringarray);
- break;
-
- case kObjectTypeBufferArray:
- msgpack_rpc_free_bufferarray(value.data.bufferarray);
- break;
-
- case kObjectTypeWindowArray:
- msgpack_rpc_free_windowarray(value.data.windowarray);
- break;
-
- case kObjectTypeTabpageArray:
- msgpack_rpc_free_tabpagearray(value.data.tabpagearray);
- break;
-
- case kObjectTypeDictionary:
- msgpack_rpc_free_dictionary(value.data.dictionary);
- break;
-
- default:
- abort();
- }
-}
-
-void msgpack_rpc_free_array(Array value)
-{
- for (uint32_t i = 0; i < value.size; i++) {
- msgpack_rpc_free_object(value.items[i]);
- }
-
- free(value.items);
-}
-
-void msgpack_rpc_free_dictionary(Dictionary value)
-{
- for (uint32_t i = 0; i < value.size; i++) {
- msgpack_rpc_free_string(value.items[i].key);
- msgpack_rpc_free_object(value.items[i].value);
- }
-
- free(value.items);
-}
-
-REMOTE_FUNCS_IMPL(Buffer, buffer)
-REMOTE_FUNCS_IMPL(Window, window)
-REMOTE_FUNCS_IMPL(Tabpage, tabpage)
-
-TYPED_ARRAY_IMPL(Buffer, buffer)
-TYPED_ARRAY_IMPL(Window, window)
-TYPED_ARRAY_IMPL(Tabpage, tabpage)
-TYPED_ARRAY_IMPL(String, string)
-
diff --git a/src/nvim/os/msgpack_rpc_helpers.h b/src/nvim/os/msgpack_rpc_helpers.h
index e3d1e756ef..aede6b1587 100644
--- a/src/nvim/os/msgpack_rpc_helpers.h
+++ b/src/nvim/os/msgpack_rpc_helpers.h
@@ -6,119 +6,11 @@
#include <msgpack.h>
-#include "nvim/func_attr.h"
#include "nvim/api/private/defs.h"
-/// Functions for validating and converting from msgpack types to C types.
-/// These are used by `msgpack_rpc_dispatch` to validate and convert each
-/// argument.
-///
-/// @param obj The object to convert
-/// @param[out] arg A pointer to the avalue
-/// @return true if the conversion succeeded, false otherwise
-bool msgpack_rpc_to_boolean(msgpack_object *obj, Boolean *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_string(msgpack_object *obj, String *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_buffer(msgpack_object *obj, Buffer *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_bufferarray(msgpack_object *obj, BufferArray *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_windowarray(msgpack_object *obj, WindowArray *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_tabpagearray(msgpack_object *obj, TabpageArray *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg)
- FUNC_ATTR_NONNULL_ALL;
-bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg)
- FUNC_ATTR_NONNULL_ALL;
-
-/// Functions for converting from C types to msgpack types.
-/// These are used by `msgpack_rpc_dispatch` to convert return values
-/// from the API
-///
-/// @param result A pointer to the result
-/// @param res A packer that contains the response
-void msgpack_rpc_from_boolean(Boolean result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_integer(Integer result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_float(Float result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_position(Position result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_string(String result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_buffer(Buffer result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_window(Window result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_object(Object result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_bufferarray(BufferArray result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_windowarray(WindowArray result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_tabpagearray(TabpageArray result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_array(Array result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2);
-
-/// Helpers for initializing types that may be freed later
-#define msgpack_rpc_init_boolean
-#define msgpack_rpc_init_integer
-#define msgpack_rpc_init_float
-#define msgpack_rpc_init_position
-#define msgpack_rpc_init_string = STRING_INIT
-#define msgpack_rpc_init_buffer
-#define msgpack_rpc_init_window
-#define msgpack_rpc_init_tabpage
-#define msgpack_rpc_init_object = {.type = kObjectTypeNil}
-#define msgpack_rpc_init_stringarray = ARRAY_DICT_INIT
-#define msgpack_rpc_init_bufferarray = ARRAY_DICT_INIT
-#define msgpack_rpc_init_windowarray = ARRAY_DICT_INIT
-#define msgpack_rpc_init_tabpagearray = ARRAY_DICT_INIT
-#define msgpack_rpc_init_array = ARRAY_DICT_INIT
-#define msgpack_rpc_init_dictionary = ARRAY_DICT_INIT
-
-/// Helpers for freeing arguments/return value
-///
-/// @param value The value to be freed
-#define msgpack_rpc_free_boolean(value)
-#define msgpack_rpc_free_integer(value)
-#define msgpack_rpc_free_float(value)
-#define msgpack_rpc_free_position(value)
-void msgpack_rpc_free_string(String value);
-#define msgpack_rpc_free_buffer(value)
-#define msgpack_rpc_free_window(value)
-#define msgpack_rpc_free_tabpage(value)
-void msgpack_rpc_free_object(Object value);
-void msgpack_rpc_free_stringarray(StringArray value);
-void msgpack_rpc_free_bufferarray(BufferArray value);
-void msgpack_rpc_free_windowarray(WindowArray value);
-void msgpack_rpc_free_tabpagearray(TabpageArray value);
-void msgpack_rpc_free_array(Array value);
-void msgpack_rpc_free_dictionary(Dictionary value);
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/msgpack_rpc_helpers.h.generated.h"
+#endif
#endif // NVIM_OS_MSGPACK_RPC_HELPERS_H
diff --git a/src/nvim/os/provider.c b/src/nvim/os/provider.c
index 07e757fe0e..2e7a677793 100644
--- a/src/nvim/os/provider.c
+++ b/src/nvim/os/provider.c
@@ -14,37 +14,34 @@
#include "nvim/log.h"
#include "nvim/map.h"
#include "nvim/message.h"
-#include "nvim/os/msgpack_rpc_helpers.h"
#define FEATURE_COUNT (sizeof(features) / sizeof(features[0]))
-#define FEATURE(feature_name, provider_bootstrap_command, ...) { \
+#define FEATURE(feature_name, ...) { \
.name = feature_name, \
- .bootstrap_command = provider_bootstrap_command, \
- .argv = NULL, \
.channel_id = 0, \
.methods = (char *[]){__VA_ARGS__, NULL} \
}
-static struct feature {
- char *name, **bootstrap_command, **argv, **methods;
+typedef struct {
+ char *name, **methods;
size_t name_length;
uint64_t channel_id;
-} features[] = {
+} Feature;
+
+static Feature features[] = {
FEATURE("python",
- &p_ipy,
"python_execute",
"python_execute_file",
"python_do_range",
"python_eval"),
FEATURE("clipboard",
- &p_icpb,
"clipboard_get",
"clipboard_set")
};
-static Map(cstr_t, uint64_t) *registered_providers = NULL;
+static PMap(cstr_t) *registered_providers = NULL;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/provider.c.generated.h"
@@ -53,163 +50,101 @@ static Map(cstr_t, uint64_t) *registered_providers = NULL;
void provider_init(void)
{
- registered_providers = map_new(cstr_t, uint64_t)();
+ registered_providers = pmap_new(cstr_t)();
}
bool provider_has_feature(char *name)
{
- for (size_t i = 0; i < FEATURE_COUNT; i++) {
- struct feature *f = &features[i];
- if (!STRICMP(name, f->name)) {
- return f->channel_id || can_execute(f);
- }
- }
-
- return false;
+ Feature *f = find_feature(name);
+ return f != NULL && channel_exists(f->channel_id);
}
-bool provider_available(char *method)
+bool provider_register(char *name, uint64_t channel_id)
{
- return map_has(cstr_t, uint64_t)(registered_providers, method);
-}
+ Feature *f = find_feature(name);
-bool provider_register(char *method, uint64_t channel_id)
-{
- if (map_has(cstr_t, uint64_t)(registered_providers, method)) {
+ if (!f) {
return false;
}
- // First check if this method is part of a feature, and if so, update
- // the feature structure with the channel id
- struct feature *f = get_feature_for(method);
- if (f) {
- DLOG("Registering provider for \"%s\" "
- "which is part of the \"%s\" feature",
- method,
- f->name);
- f->channel_id = channel_id;
+ if (f->channel_id && channel_exists(f->channel_id)) {
+ ILOG("Feature \"%s\" is already provided by another channel"
+ "(will be replaced)", name);
+ }
+
+ DLOG("Registering provider for \"%s\"", name);
+ f->channel_id = channel_id;
+
+ // Associate all method names with the feature struct
+ size_t i;
+ char *method;
+ for (method = f->methods[i = 0]; method; method = f->methods[++i]) {
+ pmap_put(cstr_t)(registered_providers, method, f);
+ DLOG("Channel \"%" PRIu64 "\" will be sent requests for \"%s\"",
+ channel_id,
+ method);
}
- map_put(cstr_t, uint64_t)(registered_providers, xstrdup(method), channel_id);
- ILOG("Registered channel %" PRIu64 " as the provider for \"%s\"",
+ ILOG("Registered channel %" PRIu64 " as the provider for the \"%s\" feature",
channel_id,
- method);
+ name);
return true;
}
Object provider_call(char *method, Array args)
{
- uint64_t channel_id = get_provider_for(method);
+ Feature *f = pmap_get(cstr_t)(registered_providers, method);
- if (!channel_id) {
+ if (!f || !channel_exists(f->channel_id)) {
char buf[256];
snprintf(buf,
sizeof(buf),
- "Provider for \"%s\" is not available",
+ "Provider for method \"%s\" is not available",
method);
- report_error(buf);
- msgpack_rpc_free_array(args);
+ vim_report_error(cstr_as_string(buf));
+ api_free_array(args);
return NIL;
}
bool error = false;
Object result = NIL;
- channel_send_call(channel_id, method, args, &result, &error);
+ channel_send_call(f->channel_id, method, args, &result, &error);
if (error) {
- report_error(result.data.string.data);
- msgpack_rpc_free_object(result);
+ vim_report_error(result.data.string);
+ api_free_object(result);
return NIL;
}
return result;
}
-static uint64_t get_provider_for(char *method)
+void provider_init_feature_metadata(Dictionary *metadata)
{
- uint64_t channel_id = map_get(cstr_t, uint64_t)(registered_providers, method);
+ Dictionary md = ARRAY_DICT_INIT;
- if (channel_id) {
- return channel_id;
- }
-
- // Try to bootstrap if the method is part of a feature
- struct feature *f = get_feature_for(method);
-
- if (!f || !can_execute(f)) {
- ELOG("Cannot bootstrap provider for \"%s\"", method);
- goto err;
- }
-
- if (f->channel_id) {
- ELOG("Already bootstrapped provider for \"%s\"", f->name);
- goto err;
- }
-
- f->channel_id = channel_from_job(f->argv);
-
- if (!f->channel_id) {
- ELOG("The provider for \"%s\" failed to bootstrap", f->name);
- goto err;
- }
-
- return f->channel_id;
-
-err:
- // Ensure we won't try to restart the provider
- if (f) {
- f->bootstrap_command = NULL;
- f->channel_id = 0;
- }
- return 0;
-}
-
-static bool can_execute(struct feature *f)
-{
- if (!f->bootstrap_command) {
- return false;
- }
-
- char *cmd = *f->bootstrap_command;
-
- if (!cmd || !strlen(cmd)) {
- return false;
- }
-
- if (!f->argv) {
- f->argv = shell_build_argv((uint8_t *)cmd, NULL);
- }
-
- return os_can_exe((uint8_t *)f->argv[0]);
-}
-
-static void report_error(char *str)
-{
- vim_err_write((String) {.data = str, .size = strlen(str)});
- vim_err_write((String) {.data = "\n", .size = 1});
-}
-
-static bool feature_has_method(struct feature *f, char *method)
-{
- size_t i;
- char *m;
+ for (size_t i = 0; i < FEATURE_COUNT; i++) {
+ Array methods = ARRAY_DICT_INIT;
+ Feature *f = &features[i];
- for (m = f->methods[i = 0]; m; m = f->methods[++i]) {
- if (!STRCMP(method, m)) {
- return true;
+ size_t j;
+ char *method;
+ for (method = f->methods[j = 0]; method; method = f->methods[++j]) {
+ ADD(methods, STRING_OBJ(cstr_to_string(method)));
}
+
+ PUT(md, f->name, ARRAY_OBJ(methods));
}
- return false;
+ PUT(*metadata, "features", DICTIONARY_OBJ(md));
}
-
-static struct feature *get_feature_for(char *method)
+static Feature * find_feature(char *name)
{
for (size_t i = 0; i < FEATURE_COUNT; i++) {
- struct feature *f = &features[i];
- if (feature_has_method(f, method)) {
+ Feature *f = &features[i];
+ if (!STRICMP(name, f->name)) {
return f;
}
}
diff --git a/src/nvim/os/server.c b/src/nvim/os/server.c
index 2e8934ecfb..66dd0ecd88 100644
--- a/src/nvim/os/server.c
+++ b/src/nvim/os/server.c
@@ -17,6 +17,7 @@
#define MAX_CONNECTIONS 32
#define ADDRESS_MAX_SIZE 256
#define NEOVIM_DEFAULT_TCP_PORT 7450
+#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
typedef enum {
kServerTypeTcp,
@@ -51,13 +52,13 @@ void server_init(void)
{
servers = pmap_new(cstr_t)();
- if (!os_getenv("NEOVIM_LISTEN_ADDRESS")) {
+ if (!os_getenv(LISTEN_ADDRESS_ENV_VAR)) {
char *listen_address = (char *)vim_tempname();
- os_setenv("NEOVIM_LISTEN_ADDRESS", listen_address, 1);
+ os_setenv(LISTEN_ADDRESS_ENV_VAR, listen_address, 1);
free(listen_address);
}
- server_start((char *)os_getenv("NEOVIM_LISTEN_ADDRESS"));
+ server_start((char *)os_getenv(LISTEN_ADDRESS_ENV_VAR));
}
/// Teardown the server module
diff --git a/src/nvim/os/wstream.c b/src/nvim/os/wstream.c
index 44463c7c88..00a53d1628 100644
--- a/src/nvim/os/wstream.c
+++ b/src/nvim/os/wstream.c
@@ -72,12 +72,12 @@ WStream * wstream_new(size_t maxmem)
/// @param wstream The `WStream` instance
void wstream_free(WStream *wstream) {
if (!wstream->pending_reqs) {
- handle_set_wstream((uv_handle_t *)wstream->stream, NULL);
if (wstream->free_handle) {
uv_close((uv_handle_t *)wstream->stream, close_cb);
+ } else {
+ handle_set_wstream((uv_handle_t *)wstream->stream, NULL);
+ free(wstream);
}
-
- free(wstream);
} else {
wstream->freed = true;
}
@@ -238,12 +238,7 @@ static void release_wbuffer(WBuffer *buffer)
static void close_cb(uv_handle_t *handle)
{
- WStream *wstream = handle_get_wstream(handle);
-
- if (wstream) {
- free(wstream);
- }
-
+ free(handle_get_wstream(handle));
free(handle->data);
free(handle);
}
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 33b08d7df6..6c79fbd479 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -55,6 +55,7 @@
#include "nvim/os/signal.h"
#include "nvim/os/job.h"
#include "nvim/os/msgpack_rpc.h"
+#include "nvim/os/msgpack_rpc_helpers.h"
#if defined(HAVE_SYS_IOCTL_H)
# include <sys/ioctl.h>
@@ -166,6 +167,7 @@ void mch_init(void)
#endif
msgpack_rpc_init();
+ msgpack_rpc_helpers_init();
event_init();
}
@@ -328,7 +330,7 @@ int len /* buffer size, only used when name gets longer */
struct dirent *dp;
FileInfo file_info;
- if (os_get_file_info_link((char *)name, &file_info)) {
+ if (os_fileinfo_link((char *)name, &file_info)) {
/* Open the directory where the file is located. */
slash = vim_strrchr(name, '/');
if (slash == NULL) {
@@ -354,8 +356,8 @@ int len /* buffer size, only used when name gets longer */
STRLCPY(newname + (tail - name), dp->d_name,
MAXPATHL - (tail - name) + 1);
FileInfo file_info_new;
- if (os_get_file_info_link((char *)newname, &file_info_new)
- && os_file_info_id_equal(&file_info, &file_info_new)) {
+ if (os_fileinfo_link((char *)newname, &file_info_new)
+ && os_fileinfo_id_equal(&file_info, &file_info_new)) {
STRCPY(tail, dp->d_name);
break;
}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 0c18ab7bd4..4e05c506f8 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -61,10 +61,10 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
FileID file_id_1, file_id_2;
expand_env(s1, exp1, MAXPATHL);
- bool id_ok_1 = os_get_file_id((char *)exp1, &file_id_1);
- bool id_ok_2 = os_get_file_id((char *)s2, &file_id_2);
+ bool id_ok_1 = os_fileid((char *)exp1, &file_id_1);
+ bool id_ok_2 = os_fileid((char *)s2, &file_id_2);
if (!id_ok_1 && !id_ok_2) {
- // If os_get_file_id() doesn't work, may compare the names.
+ // If os_fileid() doesn't work, may compare the names.
if (checkname) {
vim_FullName(exp1, full1, MAXPATHL, FALSE);
vim_FullName(s2, full2, MAXPATHL, FALSE);
@@ -77,7 +77,7 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
if (!id_ok_1 || !id_ok_2) {
return kOneFileMissing;
}
- if (os_file_id_equal(&file_id_1, &file_id_2)) {
+ if (os_fileid_equal(&file_id_1, &file_id_2)) {
return kEqualFiles;
}
return kDifferentFiles;
@@ -1304,7 +1304,7 @@ void simplify_filename(char_u *filename)
saved_char = p[-1];
p[-1] = NUL;
FileInfo file_info;
- if (!os_get_file_info_link((char *)filename, &file_info)) {
+ if (!os_fileinfo_link((char *)filename, &file_info)) {
do_strip = TRUE;
}
p[-1] = saved_char;
@@ -1327,7 +1327,7 @@ void simplify_filename(char_u *filename)
* components. */
saved_char = *tail;
*tail = NUL;
- if (os_get_file_info((char *)filename, &file_info)) {
+ if (os_fileinfo((char *)filename, &file_info)) {
do_strip = TRUE;
}
else
@@ -1343,15 +1343,15 @@ void simplify_filename(char_u *filename)
* component's parent directory.) */
FileInfo new_file_info;
if (p == start && relative) {
- os_get_file_info(".", &new_file_info);
+ os_fileinfo(".", &new_file_info);
} else {
saved_char = *p;
*p = NUL;
- os_get_file_info((char *)filename, &new_file_info);
+ os_fileinfo((char *)filename, &new_file_info);
*p = saved_char;
}
- if (!os_file_info_id_equal(&file_info, &new_file_info)) {
+ if (!os_fileinfo_id_equal(&file_info, &new_file_info)) {
do_strip = FALSE;
/* We don't disable stripping of later
* components since the unstripped path name is
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2415858e0f..ce2a80adaa 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1294,7 +1294,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
int len;
int old_KeyTyped = KeyTyped; /* getting file may reset it */
int ok = OK;
- int usable_win;
+ bool usable_win;
if (qi == NULL)
qi = &ql_info;
@@ -1379,14 +1379,16 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
* For ":helpgrep" find a help window or open one.
*/
if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0)) {
- win_T *wp;
+ win_T *wp = NULL;
- if (cmdmod.tab != 0)
- wp = NULL;
- else
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_buffer != NULL && wp->w_buffer->b_help)
+ if (cmdmod.tab == 0) {
+ FOR_ALL_WINDOWS(wp2) {
+ if (wp2->w_buffer != NULL && wp2->w_buffer->b_help) {
+ wp = wp2;
break;
+ }
+ }
+ }
if (wp != NULL && wp->w_buffer->b_nwindows > 0)
win_enter(wp, true);
else {
@@ -1433,26 +1435,29 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
if (qf_ptr->qf_fnum == 0)
goto theend;
- usable_win = 0;
+ usable_win = false;
ll_ref = curwin->w_llist_ref;
if (ll_ref != NULL) {
/* Find a window using the same location list that is not a
* quickfix window. */
- FOR_ALL_WINDOWS(usable_win_ptr)
- if (usable_win_ptr->w_llist == ll_ref
- && usable_win_ptr->w_buffer->b_p_bt[0] != 'q') {
- usable_win = 1;
- break;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_llist == ll_ref
+ && wp->w_buffer->b_p_bt[0] != 'q') {
+ usable_win = true;
+ usable_win_ptr = wp;
+ break;
+ }
}
}
if (!usable_win) {
/* Locate a window showing a normal buffer */
- FOR_ALL_WINDOWS(win)
- if (win->w_buffer->b_p_bt[0] == NUL) {
- usable_win = 1;
- break;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer->b_p_bt[0] == NUL) {
+ usable_win = true;
+ break;
+ }
}
}
@@ -1468,7 +1473,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
{
if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) {
goto_tabpage_win(tp, wp);
- usable_win = 1;
+ usable_win = true;
goto win_found;
}
}
@@ -1501,9 +1506,12 @@ win_found:
win = usable_win_ptr;
if (win == NULL) {
/* Find the window showing the selected file */
- FOR_ALL_WINDOWS(win)
- if (win->w_buffer->b_fnum == qf_ptr->qf_fnum)
- break;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) {
+ win = wp;
+ break;
+ }
+ }
if (win == NULL) {
/* Find a previous usable window */
win = curwin;
@@ -2212,13 +2220,13 @@ static int is_qf_win(win_T *win, qf_info_T *qi)
*/
static win_T *qf_find_win(qf_info_T *qi)
{
- win_T *win;
-
- FOR_ALL_WINDOWS(win)
- if (is_qf_win(win, qi))
- break;
+ FOR_ALL_WINDOWS(win) {
+ if (is_qf_win(win, qi)) {
+ return win;
+ }
+ }
- return win;
+ return NULL;
}
/*
@@ -2564,7 +2572,7 @@ static char_u *get_mef_name(void)
STRCAT(name, p + 2);
// Don't accept a symbolic link, its a security risk.
FileInfo file_info;
- bool file_or_link_found = os_get_file_info_link((char *)name, &file_info);
+ bool file_or_link_found = os_fileinfo_link((char *)name, &file_info);
if (!file_or_link_found) {
break;
}
@@ -3478,7 +3486,6 @@ void ex_helpgrep(exarg_T *eap)
char_u *lang;
qf_info_T *qi = &ql_info;
int new_qi = FALSE;
- win_T *wp;
char_u *au_name = NULL;
/* Check for a specified language */
@@ -3501,16 +3508,16 @@ void ex_helpgrep(exarg_T *eap)
p_cpo = empty_option;
if (eap->cmdidx == CMD_lhelpgrep) {
- /* Find an existing help window */
- FOR_ALL_WINDOWS(wp)
- if (wp->w_buffer != NULL && wp->w_buffer->b_help)
- break;
+ qi = NULL;
- if (wp == NULL) /* Help window not found */
- qi = NULL;
- else
- qi = wp->w_llist;
+ /* Find an existing help window */
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer != NULL && wp->w_buffer->b_help) {
+ qi = wp->w_llist;
+ }
+ }
+ /* Help window not found */
if (qi == NULL) {
/* Allocate a new location list for help text matches */
qi = ll_new_list();
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 811f265902..122c23ed84 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -206,10 +206,7 @@ void redraw_later_clear(void)
*/
void redraw_all_later(int type)
{
- win_T *wp;
-
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
redraw_win_later(wp, type);
}
}
@@ -224,12 +221,10 @@ void redraw_curbuf_later(int type)
void redraw_buf_later(buf_T *buf, int type)
{
- win_T *wp;
-
- FOR_ALL_WINDOWS(wp)
- {
- if (wp->w_buffer == buf)
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == buf) {
redraw_win_later(wp, type);
+ }
}
}
@@ -390,7 +385,6 @@ void update_curbuf(int type)
*/
void update_screen(int type)
{
- win_T *wp;
static int did_intro = FALSE;
int did_one;
@@ -438,8 +432,7 @@ void update_screen(int type)
check_for_delay(FALSE);
if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
type = CLEAR;
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_winrow < msg_scrolled) {
if (wp->w_winrow + wp->w_height > msg_scrolled
&& wp->w_redr_type < REDRAW_TOP
@@ -450,8 +443,9 @@ void update_screen(int type)
} else {
wp->w_redr_type = NOT_VALID;
if (wp->w_winrow + wp->w_height + wp->w_status_height
- <= msg_scrolled)
+ <= msg_scrolled) {
wp->w_redr_status = TRUE;
+ }
}
}
}
@@ -512,8 +506,7 @@ void update_screen(int type)
* Correct stored syntax highlighting info for changes in each displayed
* buffer. Each buffer must only be done once.
*/
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_buffer->b_mod_set) {
win_T *wwp;
@@ -534,8 +527,7 @@ void update_screen(int type)
*/
did_one = FALSE;
search_hl.rm.regprog = NULL;
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_redr_type != 0) {
cursor_off();
if (!did_one) {
@@ -558,8 +550,9 @@ void update_screen(int type)
/* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
wp->w_buffer->b_mod_set = FALSE;
+ }
updating_screen = FALSE;
@@ -662,31 +655,28 @@ static void update_finish(void)
void update_debug_sign(buf_T *buf, linenr_T lnum)
{
- win_T *wp;
int doit = FALSE;
win_foldinfo.fi_level = 0;
/* update/delete a specific mark */
- FOR_ALL_WINDOWS(wp)
- {
- if (buf != NULL && lnum > 0) {
- if (wp->w_buffer == buf && lnum >= wp->w_topline
- && lnum < wp->w_botline)
- {
- if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) {
- wp->w_redraw_top = lnum;
- }
- if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) {
- wp->w_redraw_bot = lnum;
- }
- redraw_win_later(wp, VALID);
- }
- } else {
- redraw_win_later(wp, VALID);
- }
- if (wp->w_redr_type != 0) {
- doit = TRUE;
+ FOR_ALL_WINDOWS(wp) {
+ if (buf != NULL && lnum > 0) {
+ if (wp->w_buffer == buf && lnum >= wp->w_topline
+ && lnum < wp->w_botline) {
+ if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) {
+ wp->w_redraw_top = lnum;
+ }
+ if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) {
+ wp->w_redraw_bot = lnum;
+ }
+ redraw_win_later(wp, VALID);
}
+ } else {
+ redraw_win_later(wp, VALID);
+ }
+ if (wp->w_redr_type != 0) {
+ doit = TRUE;
+ }
}
/* Return when there is nothing to do, screen updating is already
@@ -698,13 +688,13 @@ void update_debug_sign(buf_T *buf, linenr_T lnum)
/* update all windows that need updating */
update_prepare();
- for (wp = firstwin; wp; wp = wp->w_next) {
- if (wp->w_redr_type != 0) {
- win_update(wp);
- }
- if (wp->w_redr_status) {
- win_redr_status(wp);
- }
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_redr_type != 0) {
+ win_update(wp);
+ }
+ if (wp->w_redr_status) {
+ win_redr_status(wp);
+ }
}
update_finish();
@@ -1366,8 +1356,9 @@ static void win_update(win_T *wp)
(foldmethodIsSyntax(wp)
&& hasAnyFolding(wp)) ||
syntax_check_changed(lnum)))
- /* match in fixed position might need redraw */
- || wp->w_match_head != NULL
+ // match in fixed position might need redraw
+ // if lines were inserted or deleted
+ || (wp->w_match_head != NULL && buf->b_mod_xlines != 0)
))))) {
if (lnum == mod_top)
top_to_mod = FALSE;
@@ -2658,38 +2649,42 @@ win_line (
shl->startcol = MAXCOL;
shl->endcol = MAXCOL;
shl->attr_cur = 0;
- if (shl->rm.regprog != NULL) {
- v = (long)(ptr - line);
- next_search_hl(wp, shl, lnum, (colnr_T)v);
+ v = (long)(ptr - line);
+ if (cur != NULL) {
+ cur->pos.cur = 0;
+ }
+ next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
- /* Need to get the line again, a multi-line regexp may have made it
- * invalid. */
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
- ptr = line + v;
+ // Need to get the line again, a multi-line regexp may have made it
+ // invalid.
+ line = ml_get_buf(wp->w_buffer, lnum, false);
+ ptr = line + v;
- if (shl->lnum != 0 && shl->lnum <= lnum) {
- if (shl->lnum == lnum)
- shl->startcol = shl->rm.startpos[0].col;
- else
- shl->startcol = 0;
- if (lnum == shl->lnum + shl->rm.endpos[0].lnum
- - shl->rm.startpos[0].lnum)
+ if (shl->lnum != 0 && shl->lnum <= lnum) {
+ if (shl->lnum == lnum) {
+ shl->startcol = shl->rm.startpos[0].col;
+ } else {
+ shl->startcol = 0;
+ }
+ if (lnum == shl->lnum + shl->rm.endpos[0].lnum
+ - shl->rm.startpos[0].lnum) {
shl->endcol = shl->rm.endpos[0].col;
- else
+ } else {
shl->endcol = MAXCOL;
- /* Highlight one character for an empty match. */
- if (shl->startcol == shl->endcol) {
- if (has_mbyte && line[shl->endcol] != NUL)
- shl->endcol += (*mb_ptr2len)(line + shl->endcol);
- else
- ++shl->endcol;
- }
- if ((long)shl->startcol < v) { /* match at leftcol */
- shl->attr_cur = shl->attr;
- search_attr = shl->attr;
- }
- area_highlighting = TRUE;
}
+ // Highlight one character for an empty match.
+ if (shl->startcol == shl->endcol) {
+ if (has_mbyte && line[shl->endcol] != NUL) {
+ shl->endcol += (*mb_ptr2len)(line + shl->endcol);
+ } else {
+ ++shl->endcol;
+ }
+ }
+ if ((long)shl->startcol < v) { // match at leftcol
+ shl->attr_cur = shl->attr;
+ search_attr = shl->attr;
+ }
+ area_highlighting = true;
}
if (shl != &search_hl && cur != NULL)
cur = cur->next;
@@ -2699,9 +2694,9 @@ win_line (
* when Visual mode is active, because it's not clear what is selected
* then. */
if (wp->w_p_cul && lnum == wp->w_cursor.lnum
- && !(wp == curwin && VIsual_active)) {
+ && !(wp == curwin && VIsual_active)) {
line_attr = hl_attr(HLF_CUL);
- area_highlighting = TRUE;
+ area_highlighting = true;
}
off = (unsigned)(current_ScreenLine - ScreenLines);
@@ -2942,15 +2937,22 @@ win_line (
shl_flag = TRUE;
} else
shl = &cur->hl;
- while (shl->rm.regprog != NULL) {
+ if (cur != NULL) {
+ cur->pos.cur = 0;
+ }
+ bool pos_inprogress = true; // mark that a position match search is
+ // in progress
+ while (shl->rm.regprog != NULL
+ || (cur != NULL && pos_inprogress)) {
if (shl->startcol != MAXCOL
&& v >= (long)shl->startcol
&& v < (long)shl->endcol) {
shl->attr_cur = shl->attr;
- } else if (v == (long)shl->endcol) {
+ } else if (v >= (long)shl->endcol) {
shl->attr_cur = 0;
- next_search_hl(wp, shl, lnum, (colnr_T)v);
+ next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
+ pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
/* Need to get the line again, a multi-line regexp
* may have made it invalid. */
@@ -3563,7 +3565,7 @@ win_line (
} else if (c != NUL) {
p_extra = transchar(c);
if (n_extra == 0) {
- n_extra = byte2cells(c);
+ n_extra = byte2cells(c) - 1;
}
if ((dy_flags & DY_UHEX) && wp->w_p_rl)
rl_mirror(p_extra); /* reverse "<12>" */
@@ -4552,13 +4554,13 @@ void rl_mirror(char_u *str)
*/
void status_redraw_all(void)
{
- win_T *wp;
- for (wp = firstwin; wp; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_status_height) {
wp->w_redr_status = TRUE;
redraw_later(VALID);
}
+ }
}
/*
@@ -4566,13 +4568,12 @@ void status_redraw_all(void)
*/
void status_redraw_curbuf(void)
{
- win_T *wp;
-
- for (wp = firstwin; wp; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_status_height != 0 && wp->w_buffer == curbuf) {
wp->w_redr_status = TRUE;
redraw_later(VALID);
}
+ }
}
/*
@@ -4580,11 +4581,11 @@ void status_redraw_curbuf(void)
*/
void redraw_statuslines(void)
{
- win_T *wp;
-
- for (wp = firstwin; wp; wp = wp->w_next)
- if (wp->w_redr_status)
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_redr_status) {
win_redr_status(wp);
+ }
+ }
if (redraw_tabline)
draw_tabline();
}
@@ -5602,9 +5603,16 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum)
NULL, NULL, TRUE, NULL))
break;
}
+ if (cur != NULL) {
+ cur->pos.cur = 0;
+ }
+ bool pos_inprogress = true; // mark that a position match search is
+ // in progress
n = 0;
- while (shl->first_lnum < lnum && shl->rm.regprog != NULL) {
- next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
+ while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
+ || (cur != NULL && pos_inprogress))) {
+ next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, cur);
+ pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
if (shl->lnum != 0) {
shl->first_lnum = shl->lnum
+ shl->rm.endpos[0].lnum
@@ -5634,12 +5642,13 @@ next_search_hl (
win_T *win,
match_T *shl, /* points to search_hl or a match */
linenr_T lnum,
- colnr_T mincol /* minimal column for a match */
+ colnr_T mincol, /* minimal column for a match */
+ matchitem_T *cur /* to retrieve match positions if any */
)
{
linenr_T l;
colnr_T matchcol;
- long nmatched;
+ long nmatched = 0;
if (shl->lnum != 0) {
/* Check for three situations:
@@ -5674,8 +5683,8 @@ next_search_hl (
if (shl->lnum == 0)
matchcol = 0;
else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
- || (shl->rm.endpos[0].lnum == 0
- && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
+ || (shl->rm.endpos[0].lnum == 0
+ && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
char_u *ml;
matchcol = shl->rm.startpos[0].col;
@@ -5693,20 +5702,22 @@ next_search_hl (
matchcol = shl->rm.endpos[0].col;
shl->lnum = lnum;
- nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol,
- &(shl->tm)
- );
- if (called_emsg || got_int) {
- /* Error while handling regexp: stop using this regexp. */
- if (shl == &search_hl) {
- /* don't free regprog in the match list, it's a copy */
- vim_regfree(shl->rm.regprog);
- SET_NO_HLSEARCH(TRUE);
+ if (shl->rm.regprog != NULL) {
+ nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, &(shl->tm));
+ if (called_emsg || got_int) {
+ // Error while handling regexp: stop using this regexp.
+ if (shl == &search_hl) {
+ // don't free regprog in the match list, it's a copy
+ vim_regfree(shl->rm.regprog);
+ SET_NO_HLSEARCH(TRUE);
+ }
+ shl->rm.regprog = NULL;
+ shl->lnum = 0;
+ got_int = FALSE; // avoid the "Type :quit to exit Vim" message
+ break;
}
- shl->rm.regprog = NULL;
- shl->lnum = 0;
- got_int = FALSE; /* avoid the "Type :quit to exit Vim" message */
- break;
+ } else if (cur != NULL) {
+ nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
}
if (nmatched == 0) {
shl->lnum = 0; /* no match found */
@@ -5722,6 +5733,59 @@ next_search_hl (
}
}
+static int
+next_search_hl_pos(
+ match_T *shl, // points to a match
+ linenr_T lnum,
+ posmatch_T *posmatch, // match positions
+ colnr_T mincol // minimal column for a match
+)
+{
+ int i;
+ int bot = -1;
+
+ shl->lnum = 0;
+ for (i = posmatch->cur; i < MAXPOSMATCH; i++) {
+ if (posmatch->pos[i].lnum == 0) {
+ break;
+ }
+ if (posmatch->pos[i].col < mincol) {
+ continue;
+ }
+ if (posmatch->pos[i].lnum == lnum) {
+ if (shl->lnum == lnum) {
+ // partially sort positions by column numbers
+ // on the same line
+ if (posmatch->pos[i].col < posmatch->pos[bot].col) {
+ llpos_T tmp = posmatch->pos[i];
+
+ posmatch->pos[i] = posmatch->pos[bot];
+ posmatch->pos[bot] = tmp;
+ }
+ } else {
+ bot = i;
+ shl->lnum = lnum;
+ }
+ }
+ }
+ posmatch->cur = 0;
+ if (shl->lnum == lnum) {
+ colnr_T start = posmatch->pos[bot].col == 0
+ ? 0: posmatch->pos[bot].col - 1;
+ colnr_T end = posmatch->pos[bot].col == 0
+ ? MAXCOL : start + posmatch->pos[bot].len;
+
+ shl->rm.startpos[0].lnum = 0;
+ shl->rm.startpos[0].col = start;
+ shl->rm.endpos[0].lnum = 0;
+ shl->rm.endpos[0].col = end;
+ posmatch->cur = bot + 1;
+ return true;
+ }
+ return false;
+}
+
+
static void screen_start_highlight(int attr)
{
attrentry_T *aep = NULL;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index d277d71d99..5e40ae7708 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -4155,8 +4155,6 @@ void spell_free_all(void)
// Used after 'encoding' is set and when ":mkspell" was used.
void spell_reload(void)
{
- win_T *wp;
-
// Initialize the table for spell_iswordp().
init_spell_chartab();
@@ -4164,7 +4162,7 @@ void spell_reload(void)
spell_free_all();
// Go through all buffers and handle 'spelllang'.
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
// Only load the wordlists when 'spelllang' is set and there is a
// window for this buffer in which 'spell' is set.
if (*wp->w_s->b_p_spl != NUL) {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 5f6e09925e..5001d6498e 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -984,16 +984,13 @@ static void syn_stack_free_block(synblock_T *block)
*/
void syn_stack_free_all(synblock_T *block)
{
- win_T *wp;
-
syn_stack_free_block(block);
-
/* When using "syntax" fold method, must update all folds. */
- FOR_ALL_WINDOWS(wp)
- {
- if (wp->w_s == block && foldmethodIsSyntax(wp))
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_s == block && foldmethodIsSyntax(wp)) {
foldUpdateAll(wp);
+ }
}
}
@@ -1075,14 +1072,12 @@ static void syn_stack_alloc(void)
*/
void syn_stack_apply_changes(buf_T *buf)
{
- win_T *wp;
-
syn_stack_apply_changes_block(&buf->b_s, buf);
- FOR_ALL_WINDOWS(wp)
- {
- if ((wp->w_buffer == buf) && (wp->w_s != &buf->b_s))
+ FOR_ALL_WINDOWS(wp) {
+ if ((wp->w_buffer == buf) && (wp->w_s != &buf->b_s)) {
syn_stack_apply_changes_block(wp->w_s, buf);
+ }
}
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 92fd47ff6b..81dc49e800 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -33,7 +33,8 @@ SCRIPTS := test_autoformat_join.out \
test106.out test107.out \
test_options.out \
test_listlbr.out test_listlbr_utf8.out \
- test_breakindent.out
+ test_breakindent.out \
+ test_insertcount.out
SCRIPTS_GUI := test16.out
diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in
index 85a8063774..8e073f30f2 100644
--- a/src/nvim/testdir/test55.in
+++ b/src/nvim/testdir/test55.in
@@ -332,6 +332,12 @@ let l = [0, 1, 2, 3]
:$put =string(reverse(sort(l)))
:$put =string(sort(reverse(sort(l))))
:$put =string(uniq(sort(l)))
+:let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
+:$put =string(sort(copy(l), 'n'))
+:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
+:$put =string(sort(copy(l), 1))
+:$put =string(sort(copy(l), 'i'))
+:$put =string(sort(copy(l)))
:"
:" splitting a string to a List
:$put =string(split(' aa bb '))
diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok
index be476e8e93..dfd8060db7 100644
--- a/src/nvim/testdir/test55.ok
+++ b/src/nvim/testdir/test55.ok
@@ -101,6 +101,10 @@ caught a:000[3]
[[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0']
['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]]
['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]]
+[-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255]
+['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}]
+['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}]
+['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}]
['aa', 'bb']
['aa', 'bb']
['', 'aa', 'bb', '']
diff --git a/src/nvim/testdir/test63.in b/src/nvim/testdir/test63.in
index 74339c3e35..ea66ee6dea 100644
--- a/src/nvim/testdir/test63.in
+++ b/src/nvim/testdir/test63.in
@@ -1,5 +1,5 @@
Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()",
-"matchadd()", "matcharg()", "matchdelete()", and "setmatches()".
+"matchadd()", "matchaddpos()", "matcharg()", "matchdelete()", and "setmatches()".
STARTTEST
:so small.vim
@@ -147,9 +147,26 @@ STARTTEST
:unlet rf1
:unlet rf2
:unlet rf3
-:highlight clear MyGroup1
-:highlight clear MyGroup2
-:highlight clear MyGroup3
+:" --- Check that "matchaddpos()" positions matches correctly
+:let @r .= "*** Test 11:\n"
+:set nolazyredraw
+:call setline(1, 'abcdefghijklmnopq')
+:call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3)
+:1
+:redraw!
+:let v1 = screenattr(1, 1)
+:let v5 = screenattr(1, 5)
+:let v6 = screenattr(1, 6)
+:let v8 = screenattr(1, 8)
+:let v10 = screenattr(1, 10)
+:let v11 = screenattr(1, 11)
+:let @r .= string(getmatches())."\n"
+:if v1 != v5 && v6 == v1 && v8 == v5 && v10 == v5 && v11 == v1
+: let @r .= "OK\n"
+:else
+: let @r .= "FAILED\n"
+:endif
+:call clearmatches()
G"rp
:/^Results/,$wq! test.out
ENDTEST
diff --git a/src/nvim/testdir/test63.ok b/src/nvim/testdir/test63.ok
index 14973985eb..f804b693ac 100644
--- a/src/nvim/testdir/test63.ok
+++ b/src/nvim/testdir/test63.ok
@@ -9,3 +9,6 @@ Results of test63:
*** Test 8: OK
*** Test 9: OK
*** Test 10: OK
+*** Test 11:
+[{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}]
+OK
diff --git a/src/nvim/testdir/test86.in b/src/nvim/testdir/test86.in
index ecb06bafd3..11ff35cfd3 100644
--- a/src/nvim/testdir/test86.in
+++ b/src/nvim/testdir/test86.in
@@ -9,7 +9,7 @@ STARTTEST
:so small.vim
:set encoding=latin1
:set noswapfile
-:if !has('python') || has('neovim') | e! test.ok | wq! test.out | endif
+:if !has('python') || has('nvim') | e! test.ok | wq! test.out | endif
:lang C
:fun Test()
:py import vim
diff --git a/src/nvim/testdir/test_insertcount.in b/src/nvim/testdir/test_insertcount.in
new file mode 100644
index 0000000000..7a40573e63
--- /dev/null
+++ b/src/nvim/testdir/test_insertcount.in
@@ -0,0 +1,14 @@
+Tests for repeating insert and replace.
+
+STARTTEST
+:so small.vim
+:/Second
+4gro
+:/^First/,$wq! test.out
+:" get here when failed and in Insert mode
+:.wq! test.out
+ENDTEST
+
+First line
+Second line
+Last line
diff --git a/src/nvim/testdir/test_insertcount.ok b/src/nvim/testdir/test_insertcount.ok
new file mode 100644
index 0000000000..57afab00ff
--- /dev/null
+++ b/src/nvim/testdir/test_insertcount.ok
@@ -0,0 +1,3 @@
+First line
+ooooecond line
+Last line
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 8c7b5b38e9..9fbe21aeb0 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -1116,8 +1116,8 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
*/
FileInfo file_info_old;
FileInfo file_info_new;
- if (os_get_file_info((char *)buf->b_ffname, &file_info_old)
- && os_get_file_info((char *)file_name, &file_info_new)
+ if (os_fileinfo((char *)buf->b_ffname, &file_info_old)
+ && os_fileinfo((char *)file_name, &file_info_new)
&& file_info_old.stat.st_gid != file_info_new.stat.st_gid
&& os_fchown(fd, -1, file_info_old.stat.st_gid) != 0) {
os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
@@ -1249,8 +1249,8 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
* owner of the text file or equal to the current user. */
FileInfo file_info_orig;
FileInfo file_info_undo;
- if (os_get_file_info((char *)orig_name, &file_info_orig)
- && os_get_file_info((char *)file_name, &file_info_undo)
+ if (os_fileinfo((char *)orig_name, &file_info_orig)
+ && os_fileinfo((char *)file_name, &file_info_undo)
&& file_info_orig.stat.st_uid != file_info_undo.stat.st_uid
&& file_info_undo.stat.st_uid != getuid()) {
if (p_verbose > 0) {
@@ -2191,12 +2191,10 @@ u_undo_end (
u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
{
- win_T *wp;
-
- FOR_ALL_WINDOWS(wp)
- {
- if (wp->w_buffer == curbuf && wp->w_p_cole > 0)
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == curbuf && wp->w_p_cole > 0) {
redraw_win_later(wp, NOT_VALID);
+ }
}
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index b164f94bb1..bf0dace6ef 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -186,17 +186,17 @@ static char *(features[]) = {
static int included_patches[] = {
// Add new patch number below this line
//410,
- //409,
+ //409 NA
//408,
//407,
//406,
//405,
- //404,
- //403,
+ //404 NA
+ //403 NA
//402,
- //401,
- //400,
- //399,
+ //401 NA
+ //400 NA
+ //399 NA
//398,
//397,
//396,
@@ -208,10 +208,10 @@ static int included_patches[] = {
//390,
//389,
388,
- //387,
+ 387,
//386,
//385,
- //384,
+ //384 NA
//383,
//382,
//381,
@@ -219,53 +219,53 @@ static int included_patches[] = {
//379,
//378,
//377,
- //376,
+ 376,
//375,
//374,
- //373,
+ //373 NA
//372,
371,
370,
- //369,
- //368,
- //367,
+ 369,
+ 368,
+ 367,
//366,
//365,
//364,
//363,
- //362,
+ 362,
//361,
//360,
//359,
- //358,
- //357,
+ 358,
+ 357,
//356 NA
//355,
- //354,
+ //354 NA
353,
352,
- //351,
+ 351,
//350,
- //349,
- //348,
- //347,
+ 349,
+ 348,
+ 347,
346,
- //345,
- //344,
- //343,
+ 345,
+ 344,
+ 343,
//342 NA
- //341,
+ 341,
//340 NA
339,
338,
- //337,
+ 337,
//336,
335,
- //334,
+ 334,
//333 NA
//332 NA
331,
- //330,
+ 330,
329,
328,
327,
@@ -283,7 +283,7 @@ static int included_patches[] = {
315,
314,
//313,
- //312,
+ 312,
//311,
//310,
309,
@@ -298,7 +298,7 @@ static int included_patches[] = {
//300 NA
//299 NA
298,
- //297,
+ 297,
296,
295,
294,
@@ -312,19 +312,19 @@ static int included_patches[] = {
286,
285,
284,
- //283,
+ //283 NA
282,
281,
280,
279,
- //278,
+ 278,
277,
276,
275,
274,
//273 NA
272,
- //271,
+ //271 NA
//270 NA
269,
268,
@@ -332,11 +332,11 @@ static int included_patches[] = {
266,
265,
264,
- //263,
+ //263 NA
262,
261,
260,
- //259,
+ //259 NA
//258 NA
//257 NA
//256,
@@ -345,7 +345,7 @@ static int included_patches[] = {
253,
//252 NA
251,
- //250,
+ //250 NA
//249,
//248,
//247,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 6479aeaafb..3ef291ef7c 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -8,6 +8,8 @@
#ifndef NVIM_VIM_H
# define NVIM_VIM_H
+#define min(X, Y) (X < Y ? X : Y)
+
#include "nvim/types.h"
#include "nvim/pos.h" // for linenr_T, MAXCOL, etc...
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 3499b14688..27fb160035 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -982,13 +982,13 @@ static void win_init_some(win_T *newp, win_T *oldp)
*/
int win_valid(win_T *win)
{
- win_T *wp;
-
if (win == NULL)
return FALSE;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp == win)
+ FOR_ALL_WINDOWS(wp) {
+ if (wp == win) {
return TRUE;
+ }
+ }
return FALSE;
}
@@ -997,11 +997,11 @@ int win_valid(win_T *win)
*/
int win_count(void)
{
- win_T *wp;
int count = 0;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
++count;
+ }
return count;
}
@@ -1677,20 +1677,19 @@ static int last_window(void)
* Return TRUE if there is only one window other than "aucmd_win" in the
* current tab page.
*/
-int one_window(void)
+bool one_window(void)
{
- win_T *wp;
- int seen_one = FALSE;
+ bool seen_one = false;
- FOR_ALL_WINDOWS(wp)
- {
+ FOR_ALL_WINDOWS(wp) {
if (wp != aucmd_win) {
- if (seen_one)
- return FALSE;
- seen_one = TRUE;
+ if (seen_one) {
+ return false;
+ }
+ seen_one = true;
}
}
- return TRUE;
+ return true;
}
/*
@@ -2002,6 +2001,10 @@ void win_free_all(void)
while (firstwin != NULL)
(void)win_free_mem(firstwin, &dummy, NULL);
+
+ // No window should be used after this. Set curwin to NULL to crash
+ // instead of using freed memory.
+ curwin = NULL;
}
#endif
@@ -3476,14 +3479,14 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
*/
win_T *buf_jump_open_win(buf_T *buf)
{
- win_T *wp;
+ FOR_ALL_WINDOWS(wp) {
+ if (wp->w_buffer == buf) {
+ win_enter(wp, false);
+ return wp;
+ }
+ }
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp->w_buffer == buf)
- break;
- if (wp != NULL)
- win_enter(wp, false);
- return wp;
+ return NULL;
}
/*
@@ -3785,11 +3788,9 @@ void shell_new_columns(void)
void win_size_save(garray_T *gap)
{
- win_T *wp;
-
ga_init(gap, (int)sizeof(int), 1);
ga_grow(gap, win_count() * 2);
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
+ FOR_ALL_WINDOWS(wp) {
((int *)gap->ga_data)[gap->ga_len++] =
wp->w_width + wp->w_vsep_width;
((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
@@ -3802,13 +3803,16 @@ void win_size_save(garray_T *gap)
*/
void win_size_restore(garray_T *gap)
{
- win_T *wp;
-
if (win_count() * 2 == gap->ga_len) {
- int i = 0;
- for (wp = firstwin; wp != NULL; wp = wp->w_next) {
- frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
- win_setheight_win(((int *)gap->ga_data)[i++], wp);
+ /* The order matters, because frames contain other frames, but it's
+ * difficult to get right. The easy way out is to do it twice. */
+ for (int j = 0; j < 2; ++j)
+ {
+ int i = 0;
+ FOR_ALL_WINDOWS(wp) {
+ frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
+ win_setheight_win(((int *)gap->ga_data)[i++], wp);
+ }
}
/* recompute the window positions */
(void)win_comp_pos();
@@ -4234,14 +4238,14 @@ void win_setminheight(void)
{
int room;
int first = TRUE;
- win_T *wp;
/* loop until there is a 'winminheight' that is possible */
while (p_wmh > 0) {
/* TODO: handle vertical splits */
room = -p_wh;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
room += wp->w_height - p_wmh;
+ }
if (room >= 0)
break;
--p_wmh;
@@ -4932,20 +4936,21 @@ int min_rows(void)
int only_one_window(void)
{
int count = 0;
- win_T *wp;
/* If there is another tab page there always is another window. */
if (first_tabpage->tp_next != NULL)
return FALSE;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
+ FOR_ALL_WINDOWS(wp) {
if (wp->w_buffer != NULL
&& (!((wp->w_buffer->b_help && !curbuf->b_help)
|| wp->w_p_pvw
) || wp == curwin)
&& wp != aucmd_win
- )
+ ) {
++count;
+ }
+ }
return count <= 1;
}
@@ -5190,16 +5195,18 @@ void restore_buffer(buf_T *save_curbuf)
* If no particular ID is desired, -1 must be specified for 'id'.
* Return ID of added match, -1 on failure.
*/
-int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id)
+int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list)
{
matchitem_T *cur;
matchitem_T *prev;
matchitem_T *m;
int hlg_id;
- regprog_T *regprog;
+ regprog_T *regprog = NULL;
+ int rtype = SOME_VALID;
- if (*grp == NUL || *pat == NUL)
+ if (*grp == NUL || (pat != NULL && *pat == NUL)) {
return -1;
+ }
if (id < -1 || id == 0) {
EMSGN("E799: Invalid ID: %" PRId64
" (must be greater than or equal to 1)",
@@ -5220,7 +5227,7 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id)
EMSG2(_(e_nogroup), grp);
return -1;
}
- if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) {
+ if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) {
EMSG2(_(e_invarg2), pat);
return -1;
}
@@ -5236,15 +5243,106 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id)
}
/* Build new match. */
- m = xmalloc(sizeof(matchitem_T));
+ m = xcalloc(1, sizeof(matchitem_T));
m->id = id;
m->priority = prio;
- m->pattern = vim_strsave(pat);
+ m->pattern = pat == NULL ? NULL: vim_strsave(pat);
m->hlg_id = hlg_id;
m->match.regprog = regprog;
m->match.rmm_ic = FALSE;
m->match.rmm_maxcol = 0;
+ // Set up position matches
+ if (pos_list != NULL)
+ {
+ linenr_T toplnum = 0;
+ linenr_T botlnum = 0;
+ listitem_T *li;
+ int i;
+
+ for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
+ i++, li = li->li_next) {
+ linenr_T lnum = 0;
+ colnr_T col = 0;
+ int len = 1;
+ list_T *subl;
+ listitem_T *subli;
+ int error = false;
+
+ if (li->li_tv.v_type == VAR_LIST) {
+ subl = li->li_tv.vval.v_list;
+ if (subl == NULL) {
+ goto fail;
+ }
+ subli = subl->lv_first;
+ if (subli == NULL) {
+ goto fail;
+ }
+ lnum = get_tv_number_chk(&subli->li_tv, &error);
+ if (error == true) {
+ goto fail;
+ }
+ if (lnum == 0) {
+ --i;
+ continue;
+ }
+ m->pos.pos[i].lnum = lnum;
+ subli = subli->li_next;
+ if (subli != NULL) {
+ col = get_tv_number_chk(&subli->li_tv, &error);
+ if (error == true)
+ goto fail;
+ subli = subli->li_next;
+ if (subli != NULL) {
+ len = get_tv_number_chk(&subli->li_tv, &error);
+ if (error == true) {
+ goto fail;
+ }
+ }
+ }
+ m->pos.pos[i].col = col;
+ m->pos.pos[i].len = len;
+ } else if (li->li_tv.v_type == VAR_NUMBER) {
+ if (li->li_tv.vval.v_number == 0) {
+ --i;
+ continue;
+ }
+ m->pos.pos[i].lnum = li->li_tv.vval.v_number;
+ m->pos.pos[i].col = 0;
+ m->pos.pos[i].len = 0;
+ } else {
+ EMSG(_("List or number required"));
+ goto fail;
+ }
+ if (toplnum == 0 || lnum < toplnum) {
+ toplnum = lnum;
+ }
+ if (botlnum == 0 || lnum >= botlnum) {
+ botlnum = lnum + 1;
+ }
+ }
+
+ // Calculate top and bottom lines for redrawing area
+ if (toplnum != 0){
+ if (wp->w_buffer->b_mod_set) {
+ if (wp->w_buffer->b_mod_top > toplnum) {
+ wp->w_buffer->b_mod_top = toplnum;
+ }
+ if (wp->w_buffer->b_mod_bot < botlnum) {
+ wp->w_buffer->b_mod_bot = botlnum;
+ }
+ } else {
+ wp->w_buffer->b_mod_set = TRUE;
+ wp->w_buffer->b_mod_top = toplnum;
+ wp->w_buffer->b_mod_bot = botlnum;
+ wp->w_buffer->b_mod_xlines = 0;
+ }
+ m->pos.toplnum = toplnum;
+ m->pos.botlnum = botlnum;
+ rtype = VALID;
+ }
+ }
+
/* Insert new match. The match list is in ascending order with regard to
* the match priorities. */
cur = wp->w_match_head;
@@ -5259,8 +5357,12 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id)
prev->next = m;
m->next = cur;
- redraw_later(SOME_VALID);
+ redraw_later(rtype);
return id;
+
+fail:
+ free(m);
+ return -1;
}
/*
@@ -5271,6 +5373,7 @@ int match_delete(win_T *wp, int id, int perr)
{
matchitem_T *cur = wp->w_match_head;
matchitem_T *prev = cur;
+ int rtype = SOME_VALID;
if (id < 1) {
if (perr == TRUE)
@@ -5294,8 +5397,24 @@ int match_delete(win_T *wp, int id, int perr)
prev->next = cur->next;
vim_regfree(cur->match.regprog);
free(cur->pattern);
+ if (cur->pos.toplnum != 0) {
+ if (wp->w_buffer->b_mod_set) {
+ if (wp->w_buffer->b_mod_top > cur->pos.toplnum) {
+ wp->w_buffer->b_mod_top = cur->pos.toplnum;
+ }
+ if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) {
+ wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+ }
+ } else {
+ wp->w_buffer->b_mod_set = TRUE;
+ wp->w_buffer->b_mod_top = cur->pos.toplnum;
+ wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+ wp->w_buffer->b_mod_xlines = 0;
+ }
+ rtype = VALID;
+ }
free(cur);
- redraw_later(SOME_VALID);
+ redraw_later(rtype);
return 0;
}