aboutsummaryrefslogtreecommitdiff
path: root/src/nvim
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim')
-rw-r--r--src/nvim/CMakeLists.txt13
-rw-r--r--src/nvim/api/private/defs.h10
-rw-r--r--src/nvim/api/private/handle.c36
-rw-r--r--src/nvim/api/private/handle.h6
-rw-r--r--src/nvim/api/private/helpers.c318
-rw-r--r--src/nvim/api/private/helpers.h105
-rw-r--r--src/nvim/api/ui.c (renamed from src/nvim/msgpack_rpc/remote_ui.c)78
-rw-r--r--src/nvim/api/ui.h11
-rw-r--r--src/nvim/api/vim.c28
-rw-r--r--src/nvim/buffer.c75
-rw-r--r--src/nvim/buffer.h16
-rw-r--r--src/nvim/buffer_defs.h20
-rw-r--r--src/nvim/charset.c75
-rw-r--r--src/nvim/charset.h8
-rw-r--r--src/nvim/digraph.c4
-rw-r--r--src/nvim/edit.c8
-rw-r--r--src/nvim/eval.c960
-rw-r--r--src/nvim/eval/decode.c18
-rw-r--r--src/nvim/eval/encode.c629
-rw-r--r--src/nvim/eval/typval_encode.h570
-rw-r--r--src/nvim/eval_defs.h14
-rw-r--r--src/nvim/event/defs.h26
-rw-r--r--src/nvim/event/libuv_process.c2
-rw-r--r--src/nvim/event/loop.h64
-rw-r--r--src/nvim/event/process.c100
-rw-r--r--src/nvim/event/process.h2
-rw-r--r--src/nvim/event/rstream.c8
-rw-r--r--src/nvim/event/socket.c2
-rw-r--r--src/nvim/event/stream.c1
-rw-r--r--src/nvim/event/stream.h1
-rw-r--r--src/nvim/event/time.c5
-rw-r--r--src/nvim/event/time.h1
-rw-r--r--src/nvim/ex_cmds.c278
-rw-r--r--src/nvim/ex_cmds.lua20
-rw-r--r--src/nvim/ex_cmds2.c2576
-rw-r--r--src/nvim/ex_docmd.c152
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/ex_getln.c99
-rw-r--r--src/nvim/file_search.c16
-rw-r--r--src/nvim/fileio.c40
-rw-r--r--src/nvim/func_attr.h250
-rw-r--r--src/nvim/garray.h28
-rw-r--r--src/nvim/getchar.c7
-rw-r--r--src/nvim/globals.h21
-rw-r--r--src/nvim/hardcopy.c3
-rw-r--r--src/nvim/if_cscope.c3
-rw-r--r--src/nvim/lib/klist.h154
-rw-r--r--src/nvim/lib/kvec.h260
-rw-r--r--src/nvim/lib/queue.h158
-rw-r--r--src/nvim/lib/ringbuf.h388
-rw-r--r--src/nvim/log.c63
-rw-r--r--src/nvim/macros.h5
-rw-r--r--src/nvim/main.c28
-rw-r--r--src/nvim/main.h3
-rw-r--r--src/nvim/map.c165
-rw-r--r--src/nvim/map.h28
-rw-r--r--src/nvim/mbyte.c2
-rw-r--r--src/nvim/memfile.c2
-rw-r--r--src/nvim/memline.c15
-rw-r--r--src/nvim/message.c111
-rw-r--r--src/nvim/misc1.c13
-rw-r--r--src/nvim/mouse.c76
-rw-r--r--src/nvim/msgpack_rpc/channel.c81
-rw-r--r--src/nvim/msgpack_rpc/helpers.c458
-rw-r--r--src/nvim/msgpack_rpc/remote_ui.h9
-rw-r--r--src/nvim/msgpack_rpc/server.c7
-rw-r--r--src/nvim/normal.c13
-rw-r--r--src/nvim/ops.c535
-rw-r--r--src/nvim/ops.h2
-rw-r--r--src/nvim/option.c132
-rw-r--r--src/nvim/option_defs.h153
-rw-r--r--src/nvim/options.lua10
-rw-r--r--src/nvim/os/fileio.c319
-rw-r--r--src/nvim/os/fileio.h72
-rw-r--r--src/nvim/os/fs.c295
-rw-r--r--src/nvim/os/input.c12
-rw-r--r--src/nvim/os/os_defs.h6
-rw-r--r--src/nvim/os/pty_process.h9
-rw-r--r--src/nvim/os/pty_process_unix.c (renamed from src/nvim/event/pty_process.c)18
-rw-r--r--src/nvim/os/pty_process_unix.h (renamed from src/nvim/event/pty_process.h)9
-rw-r--r--src/nvim/os/pty_process_win.h28
-rw-r--r--src/nvim/os/shell.c78
-rw-r--r--src/nvim/os/signal.c11
-rw-r--r--src/nvim/os/time.c3
-rw-r--r--src/nvim/os_unix.c7
-rw-r--r--src/nvim/path.c9
-rw-r--r--src/nvim/po/eo.po62
-rw-r--r--src/nvim/po/it.po106
-rw-r--r--src/nvim/po/ja.euc-jp.po180
-rw-r--r--src/nvim/po/ja.po181
-rw-r--r--src/nvim/po/ja.sjis.po186
-rw-r--r--src/nvim/quickfix.c57
-rw-r--r--src/nvim/rbuffer.c4
-rw-r--r--src/nvim/rbuffer.h42
-rw-r--r--src/nvim/regexp_nfa.c34
-rw-r--r--src/nvim/screen.c10
-rw-r--r--src/nvim/shada.c276
-rw-r--r--src/nvim/spell.c197
-rw-r--r--src/nvim/state.c5
-rw-r--r--src/nvim/syntax.c202
-rw-r--r--src/nvim/tag.c7
-rw-r--r--src/nvim/terminal.c53
-rw-r--r--src/nvim/testdir/Makefile13
-rw-r--r--src/nvim/testdir/runtest.vim19
-rw-r--r--src/nvim/testdir/test10.in110
-rw-r--r--src/nvim/testdir/test10.ok23
-rw-r--r--src/nvim/testdir/test10a.in72
-rw-r--r--src/nvim/testdir/test10a.ok23
-rw-r--r--src/nvim/testdir/test34.in86
-rw-r--r--src/nvim/testdir/test34.ok10
-rw-r--r--src/nvim/testdir/test55.in600
-rw-r--r--src/nvim/testdir/test55.ok199
-rw-r--r--src/nvim/testdir/test_alot.vim4
-rw-r--r--src/nvim/testdir/test_assign.vim9
-rw-r--r--src/nvim/testdir/test_hardcopy.vim58
-rw-r--r--src/nvim/testdir/test_langmap.vim24
-rw-r--r--src/nvim/testdir/test_listlbr.in119
-rw-r--r--src/nvim/testdir/test_listlbr.ok62
-rw-r--r--src/nvim/testdir/test_syntax.vim63
-rw-r--r--src/nvim/testdir/test_timers.vim32
-rw-r--r--src/nvim/testdir/test_unlet.vim26
-rw-r--r--src/nvim/testdir/test_viml.vim60
-rw-r--r--src/nvim/testdir/test_visual.vim18
-rw-r--r--src/nvim/tui/input.c13
-rw-r--r--src/nvim/tui/tui.c16
-rw-r--r--src/nvim/ugrid.h20
-rw-r--r--src/nvim/ui.c53
-rw-r--r--src/nvim/ui_bridge.c13
-rw-r--r--src/nvim/ui_bridge.h14
-rw-r--r--src/nvim/undo.c4
-rw-r--r--src/nvim/version.c169
-rw-r--r--src/nvim/vim.h9
-rw-r--r--src/nvim/window.c22
133 files changed, 7891 insertions, 6129 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 172643091a..d80add2835 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -1,6 +1,3 @@
-include(CheckLibraryExists)
-include(CheckCCompilerFlag)
-
option(USE_GCOV "Enable gcov support" OFF)
if(NOT CLANG_TSAN)
@@ -55,6 +52,10 @@ foreach(subdir
event
eval
)
+ if(${subdir} MATCHES "tui" AND NOT FEAT_TUI)
+ continue()
+ endif()
+
file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
file(GLOB sources ${subdir}/*.c)
@@ -74,6 +75,9 @@ foreach(sfile ${NEOVIM_SOURCES})
if(${f} MATCHES "^(regexp_nfa.c)$")
list(APPEND to_remove ${sfile})
endif()
+ if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$")
+ list(APPEND to_remove ${sfile})
+ endif()
endforeach()
list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove})
@@ -91,7 +95,6 @@ set(CONV_SOURCES
mbyte.c
memline.c
message.c
- ops.c
regexp.c
screen.c
search.c
@@ -265,7 +268,7 @@ if(CLANG_ASAN_UBSAN)
set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
endif()
set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
+ set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/src/.asan-blacklist")
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ")
elseif(CLANG_MSAN)
message(STATUS "Enabling Clang memory sanitizer for nvim.")
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index fbfa87d5ae..5fb95a163f 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -12,8 +12,8 @@
#define REMOTE_TYPE(type) typedef uint64_t type
#ifdef INCLUDE_GENERATED_DECLARATIONS
- #define ArrayOf(...) Array
- #define DictionaryOf(...) Dictionary
+# define ArrayOf(...) Array
+# define DictionaryOf(...) Dictionary
#endif
// Basic types
@@ -41,6 +41,12 @@ typedef bool Boolean;
typedef int64_t Integer;
typedef double Float;
+/// Maximum value of an Integer
+#define API_INTEGER_MAX INT64_MAX
+
+/// Minimum value of an Integer
+#define API_INTEGER_MIN INT64_MIN
+
typedef struct {
char *data;
size_t size;
diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c
index abbda95073..69df7294ad 100644
--- a/src/nvim/api/private/handle.c
+++ b/src/nvim/api/private/handle.c
@@ -7,24 +7,24 @@
#define HANDLE_INIT(name) name##_handles = pmap_new(uint64_t)()
-#define HANDLE_IMPL(type, name) \
- static PMap(uint64_t) *name##_handles = NULL; \
- \
- type *handle_get_##name(uint64_t handle) \
- { \
- return pmap_get(uint64_t)(name##_handles, handle); \
- } \
- \
- void handle_register_##name(type *name) \
- { \
- assert(!name->handle); \
- name->handle = next_handle++; \
- pmap_put(uint64_t)(name##_handles, name->handle, name); \
- } \
- \
- void handle_unregister_##name(type *name) \
- { \
- pmap_del(uint64_t)(name##_handles, name->handle); \
+#define HANDLE_IMPL(type, name) \
+ static PMap(uint64_t) *name##_handles = NULL; \
+ \
+ type *handle_get_##name(uint64_t handle) \
+ { \
+ return pmap_get(uint64_t)(name##_handles, handle); \
+ } \
+ \
+ void handle_register_##name(type *name) \
+ { \
+ assert(!name->handle); \
+ name->handle = next_handle++; \
+ pmap_put(uint64_t)(name##_handles, name->handle, name); \
+ } \
+ \
+ void handle_unregister_##name(type *name) \
+ { \
+ pmap_del(uint64_t)(name##_handles, name->handle); \
}
static uint64_t next_handle = 1;
diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h
index 1a196f6797..804e266dc3 100644
--- a/src/nvim/api/private/handle.h
+++ b/src/nvim/api/private/handle.h
@@ -4,9 +4,9 @@
#include "nvim/vim.h"
#include "nvim/buffer_defs.h"
-#define HANDLE_DECLS(type, name) \
- type *handle_get_##name(uint64_t handle); \
- void handle_register_##name(type *name); \
+#define HANDLE_DECLS(type, name) \
+ type *handle_get_##name(uint64_t handle); \
+ void handle_register_##name(type *name); \
void handle_unregister_##name(type *name);
HANDLE_DECLS(buf_T, buffer)
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index db3e499427..c88bf2127a 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -17,6 +17,13 @@
#include "nvim/map.h"
#include "nvim/option.h"
#include "nvim/option_defs.h"
+#include "nvim/eval/typval_encode.h"
+#include "nvim/lib/kvec.h"
+
+/// Helper structure for vim_to_object
+typedef struct {
+ kvec_t(Object) stack; ///< Object stack.
+} EncodedData;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/helpers.c.generated.h"
@@ -310,6 +317,179 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
}
}
+#define TYPVAL_ENCODE_ALLOW_SPECIALS false
+
+#define TYPVAL_ENCODE_CONV_NIL() \
+ kv_push(edata->stack, NIL)
+
+#define TYPVAL_ENCODE_CONV_BOOL(num) \
+ kv_push(edata->stack, BOOLEAN_OBJ((Boolean)(num)))
+
+#define TYPVAL_ENCODE_CONV_NUMBER(num) \
+ kv_push(edata->stack, INTEGER_OBJ((Integer)(num)))
+
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER
+
+#define TYPVAL_ENCODE_CONV_FLOAT(flt) \
+ kv_push(edata->stack, FLOATING_OBJ((Float)(flt)))
+
+#define TYPVAL_ENCODE_CONV_STRING(str, len) \
+ do { \
+ const size_t len_ = (size_t)(len); \
+ const char *const str_ = (const char *)(str); \
+ assert(len_ == 0 || str_ != NULL); \
+ kv_push(edata->stack, STRING_OBJ(((String) { \
+ .data = xmemdupz((len_?str_:""), len_), \
+ .size = len_ \
+ }))); \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
+
+#define TYPVAL_ENCODE_CONV_EXT_STRING(str, len, type) \
+ TYPVAL_ENCODE_CONV_NIL()
+
+#define TYPVAL_ENCODE_CONV_FUNC(fun) \
+ TYPVAL_ENCODE_CONV_NIL()
+
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
+ kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
+
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
+ kv_push(edata->stack, \
+ DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
+
+static inline void typval_encode_list_start(EncodedData *const edata,
+ const size_t len)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ const Object obj = OBJECT_INIT;
+ kv_push(edata->stack, ARRAY_OBJ(((Array) {
+ .capacity = len,
+ .size = 0,
+ .items = xmalloc(len * sizeof(*obj.data.array.items)),
+ })));
+}
+
+#define TYPVAL_ENCODE_CONV_LIST_START(len) \
+ typval_encode_list_start(edata, (size_t)(len))
+
+static inline void typval_encode_between_list_items(EncodedData *const edata)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ Object item = kv_pop(edata->stack);
+ Object *const list = &kv_last(edata->stack);
+ assert(list->type == kObjectTypeArray);
+ assert(list->data.array.size < list->data.array.capacity);
+ list->data.array.items[list->data.array.size++] = item;
+}
+
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() \
+ typval_encode_between_list_items(edata)
+
+static inline void typval_encode_list_end(EncodedData *const edata)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ typval_encode_between_list_items(edata);
+#ifndef NDEBUG
+ const Object *const list = &kv_last(edata->stack);
+ assert(list->data.array.size == list->data.array.capacity);
+#endif
+}
+
+#define TYPVAL_ENCODE_CONV_LIST_END() \
+ typval_encode_list_end(edata)
+
+static inline void typval_encode_dict_start(EncodedData *const edata,
+ const size_t len)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ const Object obj = OBJECT_INIT;
+ kv_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
+ .capacity = len,
+ .size = 0,
+ .items = xmalloc(len * sizeof(*obj.data.dictionary.items)),
+ })));
+}
+
+#define TYPVAL_ENCODE_CONV_DICT_START(len) \
+ typval_encode_dict_start(edata, (size_t)(len))
+
+#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair)
+
+static inline void typval_encode_after_key(EncodedData *const edata)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ Object key = kv_pop(edata->stack);
+ Object *const dict = &kv_last(edata->stack);
+ assert(dict->type == kObjectTypeDictionary);
+ assert(dict->data.dictionary.size < dict->data.dictionary.capacity);
+ if (key.type == kObjectTypeString) {
+ dict->data.dictionary.items[dict->data.dictionary.size].key
+ = key.data.string;
+ } else {
+ api_free_object(key);
+ dict->data.dictionary.items[dict->data.dictionary.size].key
+ = STATIC_CSTR_TO_STRING("__INVALID_KEY__");
+ }
+}
+
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() \
+ typval_encode_after_key(edata)
+
+static inline void typval_encode_between_dict_items(EncodedData *const edata)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ Object val = kv_pop(edata->stack);
+ Object *const dict = &kv_last(edata->stack);
+ assert(dict->type == kObjectTypeDictionary);
+ assert(dict->data.dictionary.size < dict->data.dictionary.capacity);
+ dict->data.dictionary.items[dict->data.dictionary.size++].value = val;
+}
+
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \
+ typval_encode_between_dict_items(edata)
+
+static inline void typval_encode_dict_end(EncodedData *const edata)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ typval_encode_between_dict_items(edata);
+#ifndef NDEBUG
+ const Object *const dict = &kv_last(edata->stack);
+ assert(dict->data.dictionary.size == dict->data.dictionary.capacity);
+#endif
+}
+
+#define TYPVAL_ENCODE_CONV_DICT_END() \
+ typval_encode_dict_end(edata)
+
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
+ TYPVAL_ENCODE_CONV_NIL()
+
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, object, EncodedData *const, edata)
+
+#undef TYPVAL_ENCODE_CONV_STRING
+#undef TYPVAL_ENCODE_CONV_STR_STRING
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_NUMBER
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#undef TYPVAL_ENCODE_CONV_FUNC
+#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
+#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CONV_NIL
+#undef TYPVAL_ENCODE_CONV_BOOL
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#undef TYPVAL_ENCODE_CONV_DICT_START
+#undef TYPVAL_ENCODE_CONV_DICT_END
+#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_LIST_END
+#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_RECURSE
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
+
/// Convert a vim object to an `Object` instance, recursively expanding
/// Arrays/Dictionaries.
///
@@ -317,13 +497,12 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
/// @return The converted value
Object vim_to_object(typval_T *obj)
{
- Object rv;
- // We use a lookup table to break out of cyclic references
- PMap(ptr_t) *lookup = pmap_new(ptr_t)();
- rv = vim_to_object_rec(obj, lookup);
- // Free the table
- pmap_free(ptr_t)(lookup);
- return rv;
+ EncodedData edata = { .stack = KV_INITIAL_VALUE };
+ encode_vim_to_object(&edata, obj, "vim_to_object argument");
+ Object ret = kv_A(edata.stack, 0);
+ assert(kv_size(edata.stack) == 1);
+ kv_destroy(edata.stack);
+ return ret;
}
buf_T *find_buffer_by_handle(Buffer buffer, Error *err)
@@ -633,131 +812,6 @@ Object copy_object(Object obj)
}
}
-/// Recursion helper for the `vim_to_object`. This uses a pointer table
-/// to avoid infinite recursion due to cyclic references
-///
-/// @param obj The source object
-/// @param lookup Lookup table containing pointers to all processed objects
-/// @return The converted value
-static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup)
-{
- Object rv = OBJECT_INIT;
-
- if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
- // Container object, add it to the lookup table
- if (pmap_has(ptr_t)(lookup, obj)) {
- // It's already present, meaning we alredy processed it so just return
- // nil instead.
- return rv;
- }
- pmap_put(ptr_t)(lookup, obj, NULL);
- }
-
- switch (obj->v_type) {
- case VAR_SPECIAL:
- switch (obj->vval.v_special) {
- case kSpecialVarTrue:
- case kSpecialVarFalse: {
- rv.type = kObjectTypeBoolean;
- rv.data.boolean = (obj->vval.v_special == kSpecialVarTrue);
- break;
- }
- case kSpecialVarNull: {
- rv.type = kObjectTypeNil;
- break;
- }
- }
- break;
-
- case VAR_STRING:
- rv.type = kObjectTypeString;
- rv.data.string = cstr_to_string((char *) obj->vval.v_string);
- break;
-
- case VAR_NUMBER:
- rv.type = kObjectTypeInteger;
- rv.data.integer = obj->vval.v_number;
- break;
-
- case VAR_FLOAT:
- rv.type = kObjectTypeFloat;
- rv.data.floating = obj->vval.v_float;
- break;
-
- case VAR_LIST:
- {
- list_T *list = obj->vval.v_list;
- listitem_T *item;
-
- if (list != NULL) {
- rv.type = kObjectTypeArray;
- assert(list->lv_len >= 0);
- rv.data.array.size = (size_t)list->lv_len;
- rv.data.array.items = xmalloc(rv.data.array.size * sizeof(Object));
-
- uint32_t i = 0;
- for (item = list->lv_first; item != NULL; item = item->li_next) {
- rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup);
- i++;
- }
- }
- }
- break;
-
- case VAR_DICT:
- {
- dict_T *dict = obj->vval.v_dict;
- hashtab_T *ht;
- uint64_t todo;
- hashitem_T *hi;
- dictitem_T *di;
-
- if (dict != NULL) {
- ht = &obj->vval.v_dict->dv_hashtab;
- todo = ht->ht_used;
- rv.type = kObjectTypeDictionary;
-
- // Count items
- rv.data.dictionary.size = 0;
- for (hi = ht->ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- rv.data.dictionary.size++;
- }
- }
-
- rv.data.dictionary.items =
- xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair));
- todo = ht->ht_used;
- uint32_t i = 0;
-
- // Convert all
- for (hi = ht->ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- di = dict_lookup(hi);
- // Convert key
- rv.data.dictionary.items[i].key =
- cstr_to_string((char *) hi->hi_key);
- // Convert value
- rv.data.dictionary.items[i].value =
- vim_to_object_rec(&di->di_tv, lookup);
- todo--;
- i++;
- }
- }
- }
- }
- break;
-
- case VAR_UNKNOWN:
- case VAR_FUNC:
- break;
- }
-
- return rv;
-}
-
-
static void set_option_value_for(char *key,
int numval,
char *stringval,
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index a0f14ac7a4..a946e35149 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -8,69 +8,70 @@
#include "nvim/memory.h"
#include "nvim/lib/kvec.h"
-#define api_set_error(err, errtype, ...) \
- do { \
- snprintf((err)->msg, \
- sizeof((err)->msg), \
- __VA_ARGS__); \
- (err)->set = true; \
- (err)->type = kErrorType##errtype; \
+#define api_set_error(err, errtype, ...) \
+ do { \
+ snprintf((err)->msg, \
+ sizeof((err)->msg), \
+ __VA_ARGS__); \
+ (err)->set = true; \
+ (err)->type = kErrorType##errtype; \
} while (0)
#define OBJECT_OBJ(o) o
-#define BOOLEAN_OBJ(b) ((Object) { \
- .type = kObjectTypeBoolean, \
- .data.boolean = b \
- })
-
-#define INTEGER_OBJ(i) ((Object) { \
- .type = kObjectTypeInteger, \
- .data.integer = i \
- })
-
-#define STRING_OBJ(s) ((Object) { \
- .type = kObjectTypeString, \
- .data.string = s \
- })
-
-#define BUFFER_OBJ(s) ((Object) { \
- .type = kObjectTypeBuffer, \
- .data.buffer = s \
- })
-
-#define WINDOW_OBJ(s) ((Object) { \
- .type = kObjectTypeWindow, \
- .data.window = s \
- })
-
-#define TABPAGE_OBJ(s) ((Object) { \
- .type = kObjectTypeTabpage, \
- .data.tabpage = s \
- })
-
-#define ARRAY_OBJ(a) ((Object) { \
- .type = kObjectTypeArray, \
- .data.array = a \
- })
-
-#define DICTIONARY_OBJ(d) ((Object) { \
- .type = kObjectTypeDictionary, \
- .data.dictionary = d \
- })
+#define BOOLEAN_OBJ(b) ((Object) { \
+ .type = kObjectTypeBoolean, \
+ .data.boolean = b })
+
+#define INTEGER_OBJ(i) ((Object) { \
+ .type = kObjectTypeInteger, \
+ .data.integer = i })
+
+#define FLOATING_OBJ(f) ((Object) { \
+ .type = kObjectTypeFloat, \
+ .data.floating = f })
+
+#define STRING_OBJ(s) ((Object) { \
+ .type = kObjectTypeString, \
+ .data.string = s })
+
+#define BUFFER_OBJ(s) ((Object) { \
+ .type = kObjectTypeBuffer, \
+ .data.buffer = s })
+
+#define WINDOW_OBJ(s) ((Object) { \
+ .type = kObjectTypeWindow, \
+ .data.window = s })
+
+#define TABPAGE_OBJ(s) ((Object) { \
+ .type = kObjectTypeTabpage, \
+ .data.tabpage = s })
+
+#define ARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeArray, \
+ .data.array = a })
+
+#define DICTIONARY_OBJ(d) ((Object) { \
+ .type = kObjectTypeDictionary, \
+ .data.dictionary = d })
#define NIL ((Object) {.type = kObjectTypeNil})
-#define PUT(dict, k, v) \
- kv_push(KeyValuePair, \
- dict, \
- ((KeyValuePair) {.key = cstr_to_string(k), .value = v}))
+#define PUT(dict, k, v) \
+ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v }))
-#define ADD(array, item) \
- kv_push(Object, array, item)
+#define ADD(array, item) \
+ kv_push(array, item)
#define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1})
+/// Create a new String instance, putting data in allocated memory
+///
+/// @param[in] s String to work with. Must be a string literal.
+#define STATIC_CSTR_TO_STRING(s) ((String){ \
+ .data = xmemdupz(s, sizeof(s) - 1), \
+ .size = sizeof(s) - 1 })
+
// Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean
#define api_init_integer
diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/api/ui.c
index 6ffcffe2e1..1703d49296 100644
--- a/src/nvim/msgpack_rpc/remote_ui.c
+++ b/src/nvim/api/ui.c
@@ -7,13 +7,12 @@
#include "nvim/ui.h"
#include "nvim/memory.h"
#include "nvim/map.h"
-#include "nvim/msgpack_rpc/remote_ui.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "msgpack_rpc/remote_ui.c.generated.h"
+# include "api/ui.c.generated.h"
#endif
typedef struct {
@@ -24,21 +23,13 @@ typedef struct {
static PMap(uint64_t) *connected_uis = NULL;
void remote_ui_init(void)
+ FUNC_API_NOEXPORT
{
connected_uis = pmap_new(uint64_t)();
- // Add handler for "attach_ui"
- String method = cstr_as_string("ui_attach");
- MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .async = false};
- msgpack_rpc_add_method_handler(method, handler);
- method = cstr_as_string("ui_detach");
- handler.fn = remote_ui_detach;
- msgpack_rpc_add_method_handler(method, handler);
- method = cstr_as_string("ui_try_resize");
- handler.fn = remote_ui_try_resize;
- msgpack_rpc_add_method_handler(method, handler);
}
void remote_ui_disconnect(uint64_t channel_id)
+ FUNC_API_NOEXPORT
{
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
if (!ui) {
@@ -49,34 +40,30 @@ void remote_ui_disconnect(uint64_t channel_id)
api_free_array(data->buffer);
pmap_del(uint64_t)(connected_uis, channel_id);
xfree(ui->data);
- ui_detach(ui);
+ ui_detach_impl(ui);
xfree(ui);
}
-static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id,
- Array args, Error *error)
+void ui_attach(uint64_t channel_id, Integer width, Integer height,
+ Boolean enable_rgb, Error *err)
{
if (pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(error, Exception, _("UI already attached for channel"));
- return NIL;
+ api_set_error(err, Exception, _("UI already attached for channel"));
+ return;
}
- if (args.size != 3 || args.items[0].type != kObjectTypeInteger
- || args.items[1].type != kObjectTypeInteger
- || args.items[2].type != kObjectTypeBoolean
- || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) {
- api_set_error(error, Validation,
- _("Invalid arguments. Expected: "
- "(uint width > 0, uint height > 0, bool enable_rgb)"));
- return NIL;
+ if (width <= 0 || height <= 0) {
+ api_set_error(err, Validation,
+ _("Expected width > 0 and height > 0"));
+ return;
}
UIData *data = xmalloc(sizeof(UIData));
data->channel_id = channel_id;
data->buffer = (Array)ARRAY_DICT_INIT;
UI *ui = xcalloc(1, sizeof(UI));
- ui->width = (int)args.items[0].data.integer;
- ui->height = (int)args.items[1].data.integer;
- ui->rgb = args.items[2].data.boolean;
+ ui->width = (int)width;
+ ui->height = (int)height;
+ ui->rgb = enable_rgb;
ui->data = data;
ui->resize = remote_ui_resize;
ui->clear = remote_ui_clear;
@@ -102,45 +89,38 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id,
ui->set_title = remote_ui_set_title;
ui->set_icon = remote_ui_set_icon;
pmap_put(uint64_t)(connected_uis, channel_id, ui);
- ui_attach(ui);
- return NIL;
+ ui_attach_impl(ui);
+ return;
}
-static Object remote_ui_detach(uint64_t channel_id, uint64_t request_id,
- Array args, Error *error)
+void ui_detach(uint64_t channel_id, Error *err)
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(error, Exception, _("UI is not attached for channel"));
+ api_set_error(err, Exception, _("UI is not attached for channel"));
}
remote_ui_disconnect(channel_id);
-
- return NIL;
}
-static Object remote_ui_try_resize(uint64_t channel_id, uint64_t request_id,
- Array args, Error *error)
+Object ui_try_resize(uint64_t channel_id, Integer width,
+ Integer height, Error *err)
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(error, Exception, _("UI is not attached for channel"));
+ api_set_error(err, Exception, _("UI is not attached for channel"));
}
- if (args.size != 2 || args.items[0].type != kObjectTypeInteger
- || args.items[1].type != kObjectTypeInteger
- || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) {
- api_set_error(error, Validation,
- _("Invalid arguments. Expected: "
- "(uint width > 0, uint height > 0)"));
+ if (width <= 0 || height <= 0) {
+ api_set_error(err, Validation,
+ _("Expected width > 0 and height > 0"));
return NIL;
}
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
- ui->width = (int)args.items[0].data.integer;
- ui->height = (int)args.items[1].data.integer;
+ ui->width = (int)width;
+ ui->height = (int)height;
ui_refresh();
return NIL;
}
-
static void push_call(UI *ui, char *name, Array args)
{
Array call = ARRAY_DICT_INIT;
@@ -236,7 +216,7 @@ static void remote_ui_mode_change(UI *ui, int mode)
}
static void remote_ui_set_scroll_region(UI *ui, int top, int bot, int left,
- int right)
+ int right)
{
Array args = ARRAY_DICT_INIT;
ADD(args, INTEGER_OBJ(top));
@@ -297,7 +277,7 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
static void remote_ui_put(UI *ui, uint8_t *data, size_t size)
{
Array args = ARRAY_DICT_INIT;
- String str = {.data = xmemdupz(data, size), .size = size};
+ String str = { .data = xmemdupz(data, size), .size = size };
ADD(args, STRING_OBJ(str));
push_call(ui, "put", args);
}
diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h
new file mode 100644
index 0000000000..b3af14f8a8
--- /dev/null
+++ b/src/nvim/api/ui.h
@@ -0,0 +1,11 @@
+#ifndef NVIM_API_UI_H
+#define NVIM_API_UI_H
+
+#include <stdint.h>
+
+#include "nvim/api/private/defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "api/ui.h.generated.h"
+#endif
+#endif // NVIM_API_UI_H
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 46ac3c9022..ac7cc65ee4 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -57,6 +57,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
bool remap = true;
bool insert = false;
bool typed = false;
+ bool execute = false;
if (keys.size == 0) {
return;
@@ -68,6 +69,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
case 'm': remap = true; break;
case 't': typed = true; break;
case 'i': insert = true; break;
+ case 'x': execute = true; break;
}
}
@@ -86,8 +88,12 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
xfree(keys_esc);
}
- if (vgetc_busy)
+ if (vgetc_busy) {
typebuf_was_filled = true;
+ }
+ if (execute) {
+ exec_normal(true);
+ }
}
/// Passes input keys to Neovim. Unlike `vim_feedkeys`, this will use a
@@ -98,7 +104,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
/// @return The number of bytes actually written, which can be lower than
/// requested if the buffer becomes full.
Integer vim_input(String keys)
- FUNC_ATTR_ASYNC
+ FUNC_API_ASYNC
{
return (Integer)input_enqueue(keys);
}
@@ -618,7 +624,7 @@ Dictionary vim_get_color_map(void)
Array vim_get_api_info(uint64_t channel_id)
- FUNC_ATTR_ASYNC
+ FUNC_API_ASYNC
{
Array rv = ARRAY_DICT_INIT;
@@ -641,14 +647,14 @@ static void write_msg(String message, bool to_err)
static size_t out_pos = 0, err_pos = 0;
static char out_line_buf[LINE_BUFFER_SIZE], err_line_buf[LINE_BUFFER_SIZE];
-#define PUSH_CHAR(i, pos, line_buf, msg) \
- if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \
- line_buf[pos] = NUL; \
- msg((uint8_t *)line_buf); \
- pos = 0; \
- continue; \
- } \
- \
+#define PUSH_CHAR(i, pos, line_buf, msg) \
+ if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \
+ line_buf[pos] = NUL; \
+ msg((uint8_t *)line_buf); \
+ pos = 0; \
+ continue; \
+ } \
+ \
line_buf[pos++] = message.data[i];
++no_wait_return;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 72716daf0e..438a85dd5d 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1249,6 +1249,10 @@ void enter_buffer(buf_T *buf)
/* mark cursor position as being invalid */
curwin->w_valid = 0;
+ if (buf->terminal) {
+ terminal_resize(buf->terminal, curwin->w_width, curwin->w_height);
+ }
+
/* Make sure the buffer is loaded. */
if (curbuf->b_ml.ml_mfp == NULL) { /* need to load the file */
/* If there is no filetype, allow for detecting one. Esp. useful for
@@ -1534,6 +1538,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_cms);
clear_string_option(&buf->b_p_nf);
clear_string_option(&buf->b_p_syn);
+ clear_string_option(&buf->b_s.b_syn_isk);
clear_string_option(&buf->b_s.b_p_spc);
clear_string_option(&buf->b_s.b_p_spf);
vim_regfree(buf->b_s.b_cap_prog);
@@ -2848,7 +2853,7 @@ typedef enum {
/// is "curwin".
///
/// Items are drawn interspersed with the text that surrounds it
-/// Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
+/// Specials: %-<wid>(xxx%) => group, %= => separation marker, %< => truncation
/// Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
///
/// If maxwidth is not zero, the string will be filled at any middle marker
@@ -2892,7 +2897,7 @@ int build_stl_str_hl(
Normal,
Empty,
Group,
- Middle,
+ Separate,
Highlight,
TabPage,
ClickFunc,
@@ -2993,14 +2998,14 @@ int build_stl_str_hl(
continue;
}
- // STL_MIDDLEMARK: Separation place between left and right aligned items.
- if (*fmt_p == STL_MIDDLEMARK) {
+ // STL_SEPARATE: Separation place between left and right aligned items.
+ if (*fmt_p == STL_SEPARATE) {
fmt_p++;
// Ignored when we are inside of a grouping
if (groupdepth > 0) {
continue;
}
- item[curitem].type = Middle;
+ item[curitem].type = Separate;
item[curitem++].start = out_p;
continue;
}
@@ -3839,27 +3844,53 @@ int build_stl_str_hl(
width = maxwidth;
// If there is room left in our statusline, and room left in our buffer,
- // add characters at the middle marker (if there is one) to
+ // add characters at the separate marker (if there is one) to
// fill up the available space.
} else if (width < maxwidth
- && STRLEN(out) + maxwidth - width + 1 < outlen) {
- for (int item_idx = 0; item_idx < itemcnt; item_idx++) {
- if (item[item_idx].type == Middle) {
- // Move the statusline to make room for the middle characters
- char_u *middle_end = item[item_idx].start + (maxwidth - width);
- STRMOVE(middle_end, item[item_idx].start);
-
- // Fill the middle section with our fill character
- for (char_u *s = item[item_idx].start; s < middle_end; s++)
- *s = fillchar;
+ && STRLEN(out) + maxwidth - width + 1 < outlen) {
+ // Find how many separators there are, which we will use when
+ // figuring out how many groups there are.
+ int num_separators = 0;
+ for (int i = 0; i < itemcnt; i++) {
+ if (item[i].type == Separate) {
+ num_separators++;
+ }
+ }
+
+ // If we have separated groups, then we deal with it now
+ if (num_separators) {
+ // Create an array of the start location for each
+ // separator mark.
+ int separator_locations[STL_MAX_ITEM];
+ int index = 0;
+ for (int i = 0; i < itemcnt; i++) {
+ if (item[i].type == Separate) {
+ separator_locations[index] = i;
+ index++;
+ }
+ }
- // Adjust the offset of any items after the middle
- for (item_idx++; item_idx < itemcnt; item_idx++)
- item[item_idx].start += maxwidth - width;
+ int standard_spaces = (maxwidth - width) / num_separators;
+ int final_spaces = (maxwidth - width) -
+ standard_spaces * (num_separators - 1);
- width = maxwidth;
- break;
+ for (int i = 0; i < num_separators; i++) {
+ int dislocation = (i == (num_separators - 1)) ?
+ final_spaces : standard_spaces;
+ char_u *sep_loc = item[separator_locations[i]].start + dislocation;
+ STRMOVE(sep_loc, item[separator_locations[i]].start);
+ for (char_u *s = item[separator_locations[i]].start; s < sep_loc; s++) {
+ *s = fillchar;
+ }
+
+ for (int item_idx = separator_locations[i] + 1;
+ item_idx < itemcnt;
+ item_idx++) {
+ item[item_idx].start += dislocation;
+ }
}
+
+ width = maxwidth;
}
}
@@ -4950,7 +4981,7 @@ int bufhl_add_hl(buf_T *buf,
bufhl_vec_T* lineinfo = map_ref(linenr_T, bufhl_vec_T)(buf->b_bufhl_info,
lnum, true);
- bufhl_hl_item_T *hlentry = kv_pushp(bufhl_hl_item_T, *lineinfo);
+ bufhl_hl_item_T *hlentry = kv_pushp(*lineinfo);
hlentry->src_id = src_id;
hlentry->hl_id = hl_id;
hlentry->start = col_start;
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h
index d51a2f7dae..36cbec7e60 100644
--- a/src/nvim/buffer.h
+++ b/src/nvim/buffer.h
@@ -76,14 +76,14 @@ static inline void restore_win_for_buf(win_T *save_curwin,
}
}
-#define WITH_BUFFER(b, code) \
- do { \
- buf_T *save_curbuf = NULL; \
- win_T *save_curwin = NULL; \
- tabpage_T *save_curtab = NULL; \
- switch_to_win_for_buf(b, &save_curwin, &save_curtab, &save_curbuf); \
- code; \
- restore_win_for_buf(save_curwin, save_curtab, save_curbuf); \
+#define WITH_BUFFER(b, code) \
+ do { \
+ buf_T *save_curbuf = NULL; \
+ win_T *save_curwin = NULL; \
+ tabpage_T *save_curtab = NULL; \
+ switch_to_win_for_buf(b, &save_curwin, &save_curtab, &save_curbuf); \
+ code; \
+ restore_win_for_buf(save_curwin, save_curtab, save_curbuf); \
} while (0)
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 0324f6b88a..b515c4e1e4 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -438,15 +438,17 @@ typedef struct {
linenr_T b_sst_check_lnum;
uint16_t b_sst_lasttick; /* last display tick */
- /* for spell checking */
- garray_T b_langp; /* list of pointers to slang_T, see spell.c */
- bool b_spell_ismw[256]; /* flags: is midword char */
- char_u *b_spell_ismw_mb; /* multi-byte midword chars */
- char_u *b_p_spc; /* 'spellcapcheck' */
- regprog_T *b_cap_prog; /* program for 'spellcapcheck' */
- char_u *b_p_spf; /* 'spellfile' */
- char_u *b_p_spl; /* 'spelllang' */
- int b_cjk; /* all CJK letters as OK */
+ // for spell checking
+ garray_T b_langp; // list of pointers to slang_T, see spell.c
+ bool b_spell_ismw[256]; // flags: is midword char
+ char_u *b_spell_ismw_mb; // multi-byte midword chars
+ char_u *b_p_spc; // 'spellcapcheck'
+ regprog_T *b_cap_prog; // program for 'spellcapcheck'
+ char_u *b_p_spf; // 'spellfile'
+ char_u *b_p_spl; // 'spelllang'
+ int b_cjk; // all CJK letters as OK
+ char_u b_syn_chartab[32]; // syntax iskeyword option
+ char_u *b_syn_isk; // iskeyword option
} synblock_T;
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index d0dc7b66fc..22ca0fb0cc 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -43,20 +43,29 @@ static bool chartab_initialized = false;
#define GET_CHARTAB(buf, c) \
((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
-/// Fill chartab[]. Also fills curbuf->b_chartab[] with flags for keyword
+// Table used below, see init_chartab() for an explanation
+static char_u g_chartab[256];
+
+// Flags for g_chartab[].
+#define CT_CELL_MASK 0x07 ///< mask: nr of display cells (1, 2 or 4)
+#define CT_PRINT_CHAR 0x10 ///< flag: set for printable chars
+#define CT_ID_CHAR 0x20 ///< flag: set for ID chars
+#define CT_FNAME_CHAR 0x40 ///< flag: set for file name chars
+
+/// Fill g_chartab[]. Also fills curbuf->b_chartab[] with flags for keyword
/// characters for current buffer.
///
/// Depends on the option settings 'iskeyword', 'isident', 'isfname',
/// 'isprint' and 'encoding'.
///
-/// The index in chartab[] depends on 'encoding':
+/// The index in g_chartab[] depends on 'encoding':
/// - For non-multi-byte index with the byte (same as the character).
/// - For DBCS index with the first byte.
/// - For UTF-8 index with the character (when first byte is up to 0x80 it is
/// the same as the character, if the first byte is 0x80 and above it depends
/// on further bytes).
///
-/// The contents of chartab[]:
+/// The contents of g_chartab[]:
/// - The lower two bits, masked by CT_CELL_MASK, give the number of display
/// cells the character occupies (1 or 2). Not valid for UTF-8 above 0x80.
/// - CT_PRINT_CHAR bit is set when the character is printable (no need to
@@ -94,32 +103,32 @@ int buf_init_chartab(buf_T *buf, int global)
c = 0;
while (c < ' ') {
- chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
+ g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
}
while (c <= '~') {
- chartab[c++] = 1 + CT_PRINT_CHAR;
+ g_chartab[c++] = 1 + CT_PRINT_CHAR;
}
if (p_altkeymap) {
while (c < YE) {
- chartab[c++] = 1 + CT_PRINT_CHAR;
+ g_chartab[c++] = 1 + CT_PRINT_CHAR;
}
}
while (c < 256) {
if (enc_utf8 && (c >= 0xa0)) {
// UTF-8: bytes 0xa0 - 0xff are printable (latin1)
- chartab[c++] = CT_PRINT_CHAR + 1;
+ g_chartab[c++] = CT_PRINT_CHAR + 1;
} else if ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) {
// euc-jp characters starting with 0x8e are single width
- chartab[c++] = CT_PRINT_CHAR + 1;
+ g_chartab[c++] = CT_PRINT_CHAR + 1;
} else if ((enc_dbcs != 0) && (MB_BYTE2LEN(c) == 2)) {
// other double-byte chars can be printable AND double-width
- chartab[c++] = CT_PRINT_CHAR + 2;
+ g_chartab[c++] = CT_PRINT_CHAR + 2;
} else {
// the rest is unprintable by default
- chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
+ g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
}
}
@@ -128,7 +137,7 @@ int buf_init_chartab(buf_T *buf, int global)
if (((enc_dbcs != 0) && (MB_BYTE2LEN(c) > 1))
|| ((enc_dbcs == DBCS_JPNU) && (c == 0x8e))
|| (enc_utf8 && (c >= 0xa0))) {
- chartab[c] |= CT_FNAME_CHAR;
+ g_chartab[c] |= CT_FNAME_CHAR;
}
}
}
@@ -231,9 +240,9 @@ int buf_init_chartab(buf_T *buf, int global)
if (i == 0) {
// (re)set ID flag
if (tilde) {
- chartab[c] &= (uint8_t)~CT_ID_CHAR;
+ g_chartab[c] &= (uint8_t)~CT_ID_CHAR;
} else {
- chartab[c] |= CT_ID_CHAR;
+ g_chartab[c] |= CT_ID_CHAR;
}
} else if (i == 1) {
// (re)set printable
@@ -244,20 +253,20 @@ int buf_init_chartab(buf_T *buf, int global)
|| (p_altkeymap && (F_isalpha(c) || F_isdigit(c))))
&& !(enc_dbcs && (MB_BYTE2LEN(c) == 2))) {
if (tilde) {
- chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK)
- + ((dy_flags & DY_UHEX) ? 4 : 2));
- chartab[c] &= (uint8_t)~CT_PRINT_CHAR;
+ g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK)
+ + ((dy_flags & DY_UHEX) ? 4 : 2));
+ g_chartab[c] &= (uint8_t)~CT_PRINT_CHAR;
} else {
- chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) + 1);
- chartab[c] |= CT_PRINT_CHAR;
+ g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1);
+ g_chartab[c] |= CT_PRINT_CHAR;
}
}
} else if (i == 2) {
// (re)set fname flag
if (tilde) {
- chartab[c] &= (uint8_t)~CT_FNAME_CHAR;
+ g_chartab[c] &= (uint8_t)~CT_FNAME_CHAR;
} else {
- chartab[c] |= CT_FNAME_CHAR;
+ g_chartab[c] |= CT_FNAME_CHAR;
}
} else { // i == 3
// (re)set keyword flag
@@ -492,9 +501,9 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
return buf;
}
-// Catch 22: chartab[] can't be initialized before the options are
+// Catch 22: g_chartab[] can't be initialized before the options are
// initialized, and initializing options may cause transchar() to be called!
-// When chartab_initialized == false don't use chartab[].
+// When chartab_initialized == false don't use g_chartab[].
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
@@ -633,7 +642,7 @@ int byte2cells(int b)
if (enc_utf8 && (b >= 0x80)) {
return 0;
}
- return chartab[b] & CT_CELL_MASK;
+ return g_chartab[b] & CT_CELL_MASK;
}
/// Return number of display cells occupied by character "c".
@@ -665,7 +674,7 @@ int char2cells(int c)
return 2;
}
}
- return chartab[c & 0xff] & CT_CELL_MASK;
+ return g_chartab[c & 0xff] & CT_CELL_MASK;
}
/// Return number of display cells occupied by character at "*p".
@@ -682,7 +691,7 @@ int ptr2cells(char_u *p)
}
// For DBCS we can tell the cell count from the first byte.
- return chartab[*p] & CT_CELL_MASK;
+ return g_chartab[*p] & CT_CELL_MASK;
}
/// Return the number of character cells string "s" will take on the screen,
@@ -806,7 +815,7 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len)
bool vim_isIDc(int c)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return c > 0 && c < 0x100 && (chartab[c] & CT_ID_CHAR);
+ return c > 0 && c < 0x100 && (g_chartab[c] & CT_ID_CHAR);
}
/// Check that "c" is a keyword character:
@@ -878,7 +887,7 @@ bool vim_iswordp_buf(char_u *p, buf_T *buf)
bool vim_isfilec(int c)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return c >= 0x100 || (c > 0 && (chartab[c] & CT_FNAME_CHAR));
+ return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR));
}
/// Check that "c" is a valid file-name character or a wildcard character
@@ -906,7 +915,7 @@ bool vim_isprintc(int c)
if (enc_utf8 && (c >= 0x100)) {
return utf_printable(c);
}
- return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR));
+ return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR));
}
/// Strict version of vim_isprintc(c), don't return true if "c" is the head
@@ -925,7 +934,7 @@ bool vim_isprintc_strict(int c)
if (enc_utf8 && (c >= 0x100)) {
return utf_printable(c);
}
- return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR));
+ return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR));
}
/// like chartabsize(), but also check for line breaks on the screen
@@ -1247,7 +1256,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
if (enc_utf8 && (c >= 0x80)) {
incr = utf_ptr2cells(ptr);
} else {
- incr = CHARSIZE(c);
+ incr = g_chartab[c] & CT_CELL_MASK;
}
// If a double-cell char doesn't fit at the end of a line
@@ -1261,7 +1270,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
head = 1;
}
} else {
- incr = CHARSIZE(c);
+ incr = g_chartab[c] & CT_CELL_MASK;
}
}
@@ -1582,7 +1591,7 @@ static char_u latin1lower[257] =
///
/// @param c character to check
bool vim_islower(int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c <= '@') {
return false;
@@ -1613,7 +1622,7 @@ bool vim_islower(int c)
///
/// @param c character to check
bool vim_isupper(int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c <= '@') {
return false;
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index 995ad123ae..78d6f2a76c 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -1,14 +1,6 @@
#ifndef NVIM_CHARSET_H
#define NVIM_CHARSET_H
-/*
- * Flags for chartab[].
- */
-#define CT_CELL_MASK 0x07 /* mask: nr of display cells (1, 2 or 4) */
-#define CT_PRINT_CHAR 0x10 /* flag: set for printable chars */
-#define CT_ID_CHAR 0x20 /* flag: set for ID chars */
-#define CT_FNAME_CHAR 0x40 /* flag: set for file name chars */
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.h.generated.h"
#endif
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 9525024c1b..aad145b3e5 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1757,12 +1757,12 @@ char_u* keymap_init(void)
vim_snprintf(buf, buflen, "keymap/%s_%s.vim",
curbuf->b_p_keymap, p_enc);
- if (source_runtime((char_u *)buf, FALSE) == FAIL) {
+ if (source_runtime((char_u *)buf, 0) == FAIL) {
// try finding "keymap/'keymap'.vim" in 'runtimepath'
vim_snprintf(buf, buflen, "keymap/%s.vim",
curbuf->b_p_keymap);
- if (source_runtime((char_u *)buf, FALSE) == FAIL) {
+ if (source_runtime((char_u *)buf, 0) == FAIL) {
xfree(buf);
return (char_u *)N_("E544: Keymap file not found");
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index e131da8fe0..03ef41f849 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -961,7 +961,7 @@ static int insert_handle_key(InsertState *s)
break;
case K_EVENT: // some event
- queue_process_events(loop.events);
+ queue_process_events(main_loop.events);
break;
case K_FOCUSGAINED: // Neovim has been given focus
@@ -6952,8 +6952,8 @@ static void ins_reg(void)
AppendCharToRedobuff(literally);
AppendCharToRedobuff(regname);
- do_put(regname, NULL, BACKWARD, 1L,
- (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
+ do_put(regname, NULL, BACKWARD, 1,
+ (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
} else if (insert_reg(regname, literally) == FAIL) {
vim_beep(BO_REG);
need_redraw = true; // remove the '"'
@@ -7701,7 +7701,7 @@ static void ins_mouse(int c)
undisplay_dollar();
tpos = curwin->w_cursor;
- if (do_mouse(NULL, c, BACKWARD, 1L, 0)) {
+ if (do_mouse(NULL, c, BACKWARD, 1, 0)) {
win_T *new_curwin = curwin;
if (curwin != old_curwin && win_valid(old_curwin)) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 96c008b0e0..7fb7969783 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -67,6 +67,7 @@
#include "nvim/syntax.h"
#include "nvim/tag.h"
#include "nvim/ui.h"
+#include "nvim/main.h"
#include "nvim/mouse.h"
#include "nvim/terminal.h"
#include "nvim/undo.h"
@@ -76,9 +77,10 @@
#include "nvim/eval/decode.h"
#include "nvim/os/os.h"
#include "nvim/event/libuv_process.h"
-#include "nvim/event/pty_process.h"
+#include "nvim/os/pty_process.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
+#include "nvim/event/time.h"
#include "nvim/os/time.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/server.h"
@@ -89,6 +91,7 @@
#include "nvim/os/input.h"
#include "nvim/event/loop.h"
#include "nvim/lib/queue.h"
+#include "nvim/eval/typval_encode.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -428,6 +431,15 @@ typedef struct {
int status;
} JobEvent;
+typedef struct {
+ TimeWatcher tw;
+ int timer_id;
+ int repeat_count;
+ long timeout;
+ bool stopped;
+ ufunc_T *callback;
+} timer_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.c.generated.h"
#endif
@@ -438,6 +450,9 @@ typedef struct {
static uint64_t current_job_id = 1;
static PMap(uint64_t) *jobs = NULL;
+static uint64_t last_timer_id = 0;
+static PMap(uint64_t) *timers = NULL;
+
static const char *const msgpack_type_names[] = {
[kMPNil] = "nil",
[kMPBoolean] = "boolean",
@@ -469,6 +484,7 @@ void eval_init(void)
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
jobs = pmap_new(uint64_t)();
+ timers = pmap_new(uint64_t)();
struct vimvar *p;
init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
@@ -494,6 +510,7 @@ void eval_init(void)
/* add to compat scope dict */
hash_add(&compat_hashtab, p->vv_di.di_key);
}
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
dict_T *const msgpack_types_dict = dict_alloc();
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
@@ -1876,7 +1893,7 @@ ex_let_one (
}
}
if (p != NULL) {
- write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
+ write_reg_contents(*arg == '@' ? '"' : *arg, p, STRLEN(p), false);
arg_end = arg + 1;
}
xfree(ptofree);
@@ -2964,11 +2981,16 @@ int do_unlet(char_u *name, int forceit)
} else if (current_funccal != NULL
&& ht == &current_funccal->l_vars.dv_hashtab) {
d = &current_funccal->l_vars;
+ } else if (ht == &compat_hashtab) {
+ d = &vimvardict;
} else {
di = find_var_in_ht(ht, *name, (char_u *)"", false);
d = di->di_tv.vval.v_dict;
}
-
+ if (d == NULL) {
+ EMSG2(_(e_intern2), "do_unlet()");
+ return FAIL;
+ }
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi)) {
di = HI2DI(hi);
@@ -2977,6 +2999,11 @@ int do_unlet(char_u *name, int forceit)
|| tv_check_lock(d->dv_lock, name, false)) {
return FAIL;
}
+
+ if (d == NULL || tv_check_lock(d->dv_lock, name, false)) {
+ return FAIL;
+ }
+
typval_T oldtv;
bool watched = is_watched(dict);
@@ -3270,6 +3297,26 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
+/// Return TRUE if "pat" matches "text".
+/// Does not use 'cpo' and always uses 'magic'.
+static int pattern_match(char_u *pat, char_u *text, int ic)
+{
+ int matches = 0;
+ regmatch_T regmatch;
+
+ // avoid 'l' flag in 'cpoptions'
+ char_u *save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = ic;
+ matches = vim_regexec_nl(&regmatch, text, (colnr_T)0);
+ vim_regfree(regmatch.regprog);
+ }
+ p_cpo = save_cpo;
+ return matches;
+}
+
/*
* types for expressions.
*/
@@ -3545,9 +3592,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
long n1, n2;
char_u *s1, *s2;
char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
- regmatch_T regmatch;
int ic;
- char_u *save_cpo;
/*
* Get the first variable.
@@ -3756,19 +3801,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
case TYPE_MATCH:
case TYPE_NOMATCH:
- /* avoid 'l' flag in 'cpoptions' */
- save_cpo = p_cpo;
- p_cpo = (char_u *)"";
- regmatch.regprog = vim_regcomp(s2,
- RE_MAGIC + RE_STRING);
- regmatch.rm_ic = ic;
- if (regmatch.regprog != NULL) {
- n1 = vim_regexec_nl(&regmatch, s1, (colnr_T)0);
- vim_regfree(regmatch.regprog);
- if (type == TYPE_NOMATCH)
- n1 = !n1;
+ n1 = pattern_match(s2, s1, ic);
+ if (type == TYPE_NOMATCH) {
+ n1 = !n1;
}
- p_cpo = save_cpo;
break;
case TYPE_UNKNOWN: break; /* avoid gcc warning */
@@ -6659,6 +6695,7 @@ static struct fst {
{ "acos", 1, 1, f_acos }, // WJMc
{ "add", 2, 2, f_add },
{ "and", 2, 2, f_and },
+ { "api_info", 0, 0, f_api_info },
{ "append", 2, 2, f_append },
{ "argc", 0, 0, f_argc },
{ "argidx", 0, 0, f_argidx },
@@ -6667,7 +6704,11 @@ static struct fst {
{ "asin", 1, 1, f_asin }, // WJMc
{ "assert_equal", 2, 3, f_assert_equal },
{ "assert_exception", 1, 2, f_assert_exception },
+ { "assert_fails", 1, 2, f_assert_fails },
{ "assert_false", 1, 2, f_assert_false },
+ { "assert_match", 2, 3, f_assert_match },
+ { "assert_notequal", 2, 3, f_assert_notequal },
+ { "assert_notmatch", 2, 3, f_assert_notmatch },
{ "assert_true", 1, 2, f_assert_true },
{ "atan", 1, 1, f_atan },
{ "atan2", 2, 2, f_atan2 },
@@ -6686,6 +6727,7 @@ static struct fst {
{ "byteidx", 2, 2, f_byteidx },
{ "byteidxcomp", 2, 2, f_byteidxcomp },
{ "call", 2, 3, f_call },
+ { "capture", 1, 1, f_capture },
{ "ceil", 1, 1, f_ceil },
{ "changenr", 0, 0, f_changenr },
{ "char2nr", 1, 2, f_char2nr },
@@ -6930,6 +6972,8 @@ static struct fst {
{ "tempname", 0, 0, f_tempname },
{ "termopen", 1, 2, f_termopen },
{ "test", 1, 1, f_test },
+ { "timer_start", 2, 3, f_timer_start },
+ { "timer_stop", 1, 1, f_timer_stop },
{ "tolower", 1, 1, f_tolower },
{ "toupper", 1, 1, f_toupper },
{ "tr", 3, 3, f_tr },
@@ -7438,6 +7482,15 @@ static void f_and(typval_T *argvars, typval_T *rettv)
& get_tv_number_chk(&argvars[1], NULL);
}
+
+/// "api_info()" function
+static void f_api_info(typval_T *argvars, typval_T *rettv)
+{
+ Dictionary metadata = api_metadata();
+ (void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
+ api_free_dictionary(metadata);
+}
+
/*
* "append(lnum, string/list)" function
*/
@@ -7513,25 +7566,9 @@ static void f_argidx(typval_T *argvars, typval_T *rettv)
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;
+ win_T *wp = find_tabwin(&argvars[0], &argvars[1]);
+ if (wp != NULL) {
+ rettv->vval.v_number = wp->w_alist->id;
}
}
@@ -7581,7 +7618,7 @@ static void prepare_assert_error(garray_T *gap)
// Fill "gap" with information about an assert error.
static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
char_u *exp_str, typval_T *exp_tv,
- typval_T *got_tv)
+ typval_T *got_tv, assert_type_T atype)
{
char_u *tofree;
@@ -7590,7 +7627,11 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
ga_concat(gap, tofree);
xfree(tofree);
} else {
- ga_concat(gap, (char_u *)"Expected ");
+ if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) {
+ ga_concat(gap, (char_u *)"Pattern ");
+ } else {
+ ga_concat(gap, (char_u *)"Expected ");
+ }
if (exp_str == NULL) {
tofree = (char_u *) encode_tv2string(exp_tv, NULL);
ga_concat(gap, tofree);
@@ -7598,8 +7639,16 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
} else {
ga_concat(gap, exp_str);
}
- tofree = (char_u *) encode_tv2string(got_tv, NULL);
- ga_concat(gap, (char_u *)" but got ");
+ tofree = (char_u *)encode_tv2string(got_tv, NULL);
+ if (atype == ASSERT_MATCH) {
+ ga_concat(gap, (char_u *)" does not match ");
+ } else if (atype == ASSERT_NOTMATCH) {
+ ga_concat(gap, (char_u *)" does match ");
+ } else if (atype == ASSERT_NOTEQUAL) {
+ ga_concat(gap, (char_u *)" differs from ");
+ } else {
+ ga_concat(gap, (char_u *)" but got ");
+ }
ga_concat(gap, tofree);
xfree(tofree);
}
@@ -7618,20 +7667,32 @@ static void assert_error(garray_T *gap)
gap->ga_data, gap->ga_len);
}
-// "assert_equal(expected, actual[, msg])" function
-static void f_assert_equal(typval_T *argvars, typval_T *rettv)
+static void assert_equal_common(typval_T *argvars, assert_type_T atype)
{
garray_T ga;
- if (!tv_equal(&argvars[0], &argvars[1], false, false)) {
+ if (tv_equal(&argvars[0], &argvars[1], false, false)
+ != (atype == ASSERT_EQUAL)) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL,
- &argvars[0], &argvars[1]);
+ &argvars[0], &argvars[1], atype);
assert_error(&ga);
ga_clear(&ga);
}
}
+// "assert_equal(expected, actual[, msg])" function
+static void f_assert_equal(typval_T *argvars, typval_T *rettv)
+{
+ assert_equal_common(argvars, ASSERT_EQUAL);
+}
+
+// "assert_notequal(expected, actual[, msg])" function
+static void f_assert_notequal(typval_T *argvars, typval_T *rettv)
+{
+ assert_equal_common(argvars, ASSERT_NOTEQUAL);
+}
+
/// "assert_exception(string[, msg])" function
static void f_assert_exception(typval_T *argvars, typval_T *rettv)
{
@@ -7643,13 +7704,51 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv)
ga_concat(&ga, (char_u *)"v:exception is not set");
assert_error(&ga);
ga_clear(&ga);
- } else if (strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) {
+ } else if (error != NULL
+ && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
- &vimvars[VV_EXCEPTION].vv_tv);
+ &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+}
+
+/// "assert_fails(cmd [, error])" function
+static void f_assert_fails(typval_T *argvars, typval_T *rettv)
+{
+ char_u *cmd = get_tv_string_chk(&argvars[0]);
+ garray_T ga;
+
+ called_emsg = false;
+ suppress_errthrow = true;
+ emsg_silent = true;
+ do_cmdline_cmd((char *)cmd);
+ if (!called_emsg) {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"command did not fail: ");
+ ga_concat(&ga, cmd);
assert_error(&ga);
ga_clear(&ga);
+ } else if (argvars[1].v_type != VAR_UNKNOWN) {
+ char_u buf[NUMBUFLEN];
+ char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf);
+
+ if (error == NULL
+ || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
+ &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
}
+
+ called_emsg = false;
+ suppress_errthrow = false;
+ emsg_silent = false;
+ emsg_on_display = false;
+ set_vim_var_string(VV_ERRMSG, NULL, 0);
}
// Common for assert_true() and assert_false().
@@ -7669,7 +7768,7 @@ static void assert_bool(typval_T *argvars, bool is_true)
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1],
(char_u *)(is_true ? "True" : "False"),
- NULL, &argvars[0]);
+ NULL, &argvars[0], ASSERT_OTHER);
assert_error(&ga);
ga_clear(&ga);
}
@@ -7681,6 +7780,36 @@ static void f_assert_false(typval_T *argvars, typval_T *rettv)
assert_bool(argvars, false);
}
+static void assert_match_common(typval_T *argvars, assert_type_T atype)
+{
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1);
+ char_u *text = get_tv_string_buf_chk(&argvars[1], buf2);
+
+ if (pat == NULL || text == NULL) {
+ EMSG(_(e_invarg));
+ } else if (pattern_match(pat, text, false) != (atype == ASSERT_MATCH)) {
+ garray_T ga;
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+}
+
+/// "assert_match(pattern, actual[, msg])" function
+static void f_assert_match(typval_T *argvars, typval_T *rettv)
+{
+ assert_match_common(argvars, ASSERT_MATCH);
+}
+
+/// "assert_notmatch(pattern, actual[, msg])" function
+static void f_assert_notmatch(typval_T *argvars, typval_T *rettv)
+{
+ assert_match_common(argvars, ASSERT_NOTMATCH);
+}
+
// "assert_true(actual[, msg])" function
static void f_assert_true(typval_T *argvars, typval_T *rettv)
{
@@ -8024,6 +8153,38 @@ static void f_call(typval_T *argvars, typval_T *rettv)
(void)func_call(func, &argvars[1], selfdict, rettv);
}
+// "capture(command)" function
+static void f_capture(typval_T *argvars, typval_T *rettv)
+{
+ int save_msg_silent = msg_silent;
+ garray_T *save_capture_ga = capture_ga;
+
+ if (check_secure()) {
+ return;
+ }
+
+ garray_T capture_local;
+ capture_ga = &capture_local;
+ ga_init(capture_ga, (int)sizeof(char), 80);
+
+ msg_silent++;
+ if (argvars[0].v_type != VAR_LIST) {
+ do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
+ } else if (argvars[0].vval.v_list != NULL) {
+ for (listitem_T *li = argvars[0].vval.v_list->lv_first;
+ li != NULL; li = li->li_next) {
+ do_cmdline_cmd((char *)get_tv_string(&li->li_tv));
+ }
+ }
+ msg_silent = save_msg_silent;
+
+ ga_append(capture_ga, NUL);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = capture_ga->ga_data;
+
+ capture_ga = save_capture_ga;
+}
+
/*
* "ceil({float})" function
*/
@@ -9834,7 +9995,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv)
static void f_getcwd(typval_T *argvars, typval_T *rettv)
{
// Possible scope of working directory to return.
- CdScope scope = MIN_CD_SCOPE;
+ CdScope scope = kCdScopeInvalid;
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
@@ -9863,26 +10024,27 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
return;
}
scope_number[i] = argvars[i].vval.v_number;
- // The scope is the current iteration step.
- scope = i;
// It is an error for the scope number to be less than `-1`.
if (scope_number[i] < -1) {
EMSG(_(e_invarg));
return;
}
+ // Use the narrowest scope the user requested
+ if (scope_number[i] >= 0 && scope == kCdScopeInvalid) {
+ // The scope is the current iteration step.
+ scope = i;
+ } else if (scope_number[i] < 0) {
+ scope = i + 1;
+ }
}
- // Normalize scope, the number of the new scope will be 0.
- if (scope_number[scope] < 0) {
- // Arguments to `getcwd` always end at second-highest scope, so scope will
- // always be <= `MAX_CD_SCOPE`.
- scope++;
+ // If the user didn't specify anything, default to window scope
+ if (scope == kCdScopeInvalid) {
+ scope = MIN_CD_SCOPE;
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] == -1) {
- tp = NULL;
- } else if (scope_number[kCdScopeTab] > 0) {
+ if (scope_number[kCdScopeTab] > 0) {
tp = find_tabpage(scope_number[kCdScopeTab]);
if (!tp) {
EMSG(_("E5000: Cannot find tab number."));
@@ -9891,16 +10053,14 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
}
// Find the window in `tp` by number, `NULL` if none.
- if (scope_number[kCdScopeWindow] == -1) {
- win = NULL;
- } else if (scope_number[kCdScopeWindow] >= 0) {
- if (!tp) {
+ if (scope_number[kCdScopeWindow] >= 0) {
+ if (scope_number[kCdScopeTab] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
if (scope_number[kCdScopeWindow] > 0) {
- win = find_win_by_nr(&argvars[0], curtab);
+ win = find_win_by_nr(&argvars[0], tp);
if (!win) {
EMSG(_("E5002: Cannot find window number."));
return;
@@ -9935,6 +10095,9 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv)
}
}
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
if (from) {
@@ -10406,9 +10569,33 @@ find_win_by_nr (
return NULL;
}
-/*
- * "getwinvar()" function
- */
+/// Find window specified by "wvp" in tabpage "tvp".
+static win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
+{
+ win_T *wp = NULL;
+ tabpage_T *tp = NULL;
+
+ if (wvp->v_type != VAR_UNKNOWN) {
+ if (tvp->v_type != VAR_UNKNOWN) {
+ long n = get_tv_number(tvp);
+ if (n >= 0) {
+ tp = find_tabpage(n);
+ }
+ } else {
+ tp = curtab;
+ }
+
+ if (tp != NULL) {
+ wp = find_win_by_nr(wvp, tp);
+ }
+ } else {
+ wp = curwin;
+ }
+
+ return wp;
+}
+
+/// "getwinvar()" function
static void f_getwinvar(typval_T *argvars, typval_T *rettv)
{
getwinvar(argvars, rettv, 0);
@@ -10661,6 +10848,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"mouse",
"multi_byte",
"multi_lang",
+ "packages",
"path_extra",
"persistent_undo",
"postscript",
@@ -10688,6 +10876,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"termguicolors",
"termresponse",
"textobjects",
+ "timers",
"title",
"user-commands", /* was accidentally included in 5.4 */
"user_commands",
@@ -10781,7 +10970,7 @@ static void f_has_key(typval_T *argvars, typval_T *rettv)
static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
{
// Possible scope of working directory to return.
- CdScope scope = MIN_CD_SCOPE;
+ CdScope scope = kCdScopeInvalid;
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
@@ -10806,25 +10995,26 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
return;
}
scope_number[i] = argvars[i].vval.v_number;
- // The scope is the current iteration step.
- scope = i;
if (scope_number[i] < -1) {
EMSG(_(e_invarg));
return;
}
+ // Use the narrowest scope the user requested
+ if (scope_number[i] >= 0 && scope == kCdScopeInvalid) {
+ // The scope is the current iteration step.
+ scope = i;
+ } else if (scope_number[i] < 0) {
+ scope = i + 1;
+ }
}
- // Normalize scope, the number of the new scope will be 0.
- if (scope_number[scope] < 0) {
- // Arguments to `haslocaldir` always end at second-highest scope, so scope
- // will always be <= `MAX_CD_SCOPE`.
- scope++;
+ // If the user didn't specify anything, default to window scope
+ if (scope == kCdScopeInvalid) {
+ scope = MIN_CD_SCOPE;
}
// Find the tabpage by number
- if (scope_number[kCdScopeTab] == -1) {
- tp = NULL;
- } else if (scope_number[kCdScopeTab] > 0) {
+ if (scope_number[kCdScopeTab] > 0) {
tp = find_tabpage(scope_number[kCdScopeTab]);
if (!tp) {
EMSG(_("5000: Cannot find tab number."));
@@ -10833,16 +11023,14 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
}
// Find the window in `tp` by number, `NULL` if none.
- if (scope_number[kCdScopeWindow] == -1) {
- win = NULL;
- } else if (scope_number[kCdScopeWindow] >= 0) {
- if (!tp) {
+ if (scope_number[kCdScopeWindow] >= 0) {
+ if (scope_number[kCdScopeTab] < 0) {
EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
return;
}
if (scope_number[kCdScopeWindow] > 0) {
- win = find_win_by_nr(&argvars[0], curtab);
+ win = find_win_by_nr(&argvars[0], tp);
if (!win) {
EMSG(_("E5002: Cannot find window number."));
return;
@@ -10863,6 +11051,9 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
// The global scope never has a local directory
rettv->vval.v_number = 0;
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
}
@@ -11672,8 +11863,21 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
dict_T *job_opts = NULL;
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
+ char *cwd = NULL;
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
+
+ char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false);
+ if (new_cwd && strlen(new_cwd) > 0) {
+ cwd = new_cwd;
+ // The new cwd must be a directory.
+ if (!os_isdir((char_u *)cwd)) {
+ EMSG2(_(e_invarg2), "expected valid directory");
+ shell_free_argv(argv);
+ return;
+ }
+ }
+
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
shell_free_argv(argv);
return;
@@ -11683,7 +11887,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, pty, detach);
+ job_opts, pty, detach, cwd);
Process *proc = (Process *)&data->proc;
if (pty) {
@@ -11758,7 +11962,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
list_T *rv = list_alloc();
ui_busy_start();
- Queue *waiting_jobs = queue_new_parent(loop_on_put, &loop);
+ Queue *waiting_jobs = queue_new_parent(loop_on_put, &main_loop);
// For each item in the input list append an integer to the output list. -3
// is used to represent an invalid job id, -2 is for a interrupted job and
// -1 for jobs that were skipped or timed out.
@@ -11836,7 +12040,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
}
// restore the parent queue for the job
queue_process_events(data->events);
- queue_replace_parent(data->events, loop.events);
+ queue_replace_parent(data->events, main_loop.events);
}
queue_free(waiting_jobs);
@@ -14837,7 +15041,8 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
}
*curval++ = NULL;
- write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len);
+ write_reg_contents_lst(regname, lstval, STRLEN(lstval),
+ append, yank_type, block_len);
free_lstval:
while (curallocval > allocval)
@@ -14848,7 +15053,8 @@ free_lstval:
if (strval == NULL) {
return;
}
- write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len);
+ write_reg_contents_ex(regname, strval, STRLEN(strval),
+ append, yank_type, block_len);
}
rettv->vval.v_number = 0;
}
@@ -15024,13 +15230,18 @@ typedef struct {
int idx;
} sortItem_T;
-static int item_compare_ic;
-static bool item_compare_numeric;
-static bool item_compare_numbers;
-static bool item_compare_float;
-static char_u *item_compare_func;
-static dict_T *item_compare_selfdict;
-static int item_compare_func_err;
+/// struct storing information about current sort
+typedef struct {
+ int item_compare_ic;
+ bool item_compare_numeric;
+ bool item_compare_numbers;
+ bool item_compare_float;
+ char_u *item_compare_func;
+ dict_T *item_compare_selfdict;
+ int item_compare_func_err;
+} sortinfo_T;
+static sortinfo_T *sortinfo = NULL;
+
#define ITEM_COMPARE_FAIL 999
/*
@@ -15050,14 +15261,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
typval_T *tv1 = &si1->item->li_tv;
typval_T *tv2 = &si2->item->li_tv;
- if (item_compare_numbers) {
+ if (sortinfo->item_compare_numbers) {
long v1 = get_tv_number(tv1);
long v2 = get_tv_number(tv2);
return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
}
- if (item_compare_float) {
+ if (sortinfo->item_compare_float) {
float_T v1 = get_tv_float(tv1);
float_T v2 = get_tv_float(tv2);
@@ -15068,7 +15279,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
// do that for string variables. Use a single quote when comparing with
// a non-string to do what the docs promise.
if (tv1->v_type == VAR_STRING) {
- if (tv2->v_type != VAR_STRING || item_compare_numeric) {
+ if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
p1 = (char_u *)"'";
} else {
p1 = tv1->vval.v_string;
@@ -15077,7 +15288,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
tofree1 = p1 = (char_u *) encode_tv2string(tv1, NULL);
}
if (tv2->v_type == VAR_STRING) {
- if (tv1->v_type != VAR_STRING || item_compare_numeric) {
+ if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
p2 = (char_u *)"'";
} else {
p2 = tv2->vval.v_string;
@@ -15085,12 +15296,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
} else {
tofree2 = p2 = (char_u *) encode_tv2string(tv2, NULL);
}
- if (p1 == NULL)
+ if (p1 == NULL) {
p1 = (char_u *)"";
- if (p2 == NULL)
+ }
+ if (p2 == NULL) {
p2 = (char_u *)"";
- if (!item_compare_numeric) {
- if (item_compare_ic) {
+ }
+ if (!sortinfo->item_compare_numeric) {
+ if (sortinfo->item_compare_ic) {
res = STRICMP(p1, p2);
} else {
res = STRCMP(p1, p2);
@@ -15131,9 +15344,10 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
typval_T argv[3];
int dummy;
- /* shortcut after failure in previous call; compare all items equal */
- if (item_compare_func_err)
+ // shortcut after failure in previous call; compare all items equal
+ if (sortinfo->item_compare_func_err) {
return 0;
+ }
si1 = (sortItem_T *)s1;
si2 = (sortItem_T *)s2;
@@ -15143,19 +15357,22 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
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),
- &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
- item_compare_selfdict);
+ rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
+ res = call_func(sortinfo->item_compare_func,
+ (int)STRLEN(sortinfo->item_compare_func),
+ &rettv, 2, argv, 0L, 0L, &dummy, true,
+ sortinfo->item_compare_selfdict);
clear_tv(&argv[0]);
clear_tv(&argv[1]);
- if (res == FAIL)
+ if (res == FAIL) {
res = ITEM_COMPARE_FAIL;
- else
- res = get_tv_number_chk(&rettv, &item_compare_func_err);
- if (item_compare_func_err)
- res = ITEM_COMPARE_FAIL; /* return value has wrong type */
+ } else {
+ res = get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ }
+ if (sortinfo->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
@@ -15188,6 +15405,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
long len;
long i;
+ // Pointer to current info struct used in compare function. Save and restore
+ // the current one for nested calls.
+ sortinfo_T info;
+ sortinfo_T *old_sortinfo = sortinfo;
+ sortinfo = &info;
+
if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
@@ -15198,61 +15421,70 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
? N_("sort() argument")
: N_("uniq() argument")),
true)) {
- return;
+ goto theend;
}
rettv->vval.v_list = l;
rettv->v_type = VAR_LIST;
++l->lv_refcount;
len = list_len(l);
- if (len <= 1)
- return; /* short list sorts pretty quickly */
+ if (len <= 1) {
+ goto theend; // short list sorts pretty quickly
+ }
- item_compare_ic = FALSE;
- item_compare_numeric = false;
- item_compare_numbers = false;
- item_compare_float = false;
- item_compare_func = NULL;
- item_compare_selfdict = NULL;
+ info.item_compare_ic = false;
+ info.item_compare_numeric = false;
+ info.item_compare_numbers = false;
+ info.item_compare_float = false;
+ info.item_compare_func = NULL;
+ info.item_compare_selfdict = NULL;
if (argvars[1].v_type != VAR_UNKNOWN) {
/* optional second argument: {func} */
if (argvars[1].v_type == VAR_FUNC) {
- item_compare_func = argvars[1].vval.v_string;
+ info.item_compare_func = argvars[1].vval.v_string;
} else {
int error = FALSE;
i = get_tv_number_chk(&argvars[1], &error);
- if (error)
- return; /* type error; errmsg already given */
- if (i == 1)
- 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, "N") == 0) {
- item_compare_func = NULL;
- item_compare_numbers = true;
- } else if (STRCMP(item_compare_func, "f") == 0) {
- item_compare_func = NULL;
- item_compare_float = true;
- } else if (STRCMP(item_compare_func, "i") == 0) {
- item_compare_func = NULL;
- item_compare_ic = TRUE;
+ if (error) {
+ goto theend; // type error; errmsg already given
+ }
+ if (i == 1) {
+ info.item_compare_ic = true;
+ } else if (argvars[1].v_type != VAR_NUMBER) {
+ info.item_compare_func = get_tv_string(&argvars[1]);
+ } else if (i != 0) {
+ EMSG(_(e_invarg));
+ goto theend;
+ }
+ if (info.item_compare_func != NULL) {
+ if (*info.item_compare_func == NUL) {
+ // empty string means default sort
+ info.item_compare_func = NULL;
+ } else if (STRCMP(info.item_compare_func, "n") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numeric = true;
+ } else if (STRCMP(info.item_compare_func, "N") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numbers = true;
+ } else if (STRCMP(info.item_compare_func, "f") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_float = true;
+ } else if (STRCMP(info.item_compare_func, "i") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_ic = true;
}
}
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- /* optional third argument: {dict} */
+ // optional third argument: {dict}
if (argvars[2].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
- return;
+ goto theend;
}
- item_compare_selfdict = argvars[2].vval.v_dict;
+ info.item_compare_selfdict = argvars[2].vval.v_dict;
}
}
@@ -15268,19 +15500,20 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
i++;
}
- item_compare_func_err = FALSE;
+ info.item_compare_func_err = false;
// Test the compare function.
- if (item_compare_func != NULL
+ if (info.item_compare_func != NULL
&& item_compare2_not_keeping_zero(&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 (sortItem_T),
- item_compare_func == NULL ? item_compare_not_keeping_zero :
- item_compare2_not_keeping_zero);
+ (info.item_compare_func == NULL ?
+ item_compare_not_keeping_zero :
+ item_compare2_not_keeping_zero));
- if (!item_compare_func_err) {
+ if (!info.item_compare_func_err) {
// Clear the list and append the items in the sorted order.
l->lv_first = NULL;
l->lv_last = NULL;
@@ -15296,21 +15529,24 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
int (*item_compare_func_ptr)(const void *, const void *);
// f_uniq(): ptrs will be a stack of items to remove.
- item_compare_func_err = FALSE;
- item_compare_func_ptr = item_compare_func ? item_compare2_keeping_zero :
- item_compare_keeping_zero;
+ info.item_compare_func_err = false;
+ if (info.item_compare_func != NULL) {
+ item_compare_func_ptr = item_compare2_keeping_zero;
+ } else {
+ item_compare_func_ptr = item_compare_keeping_zero;
+ }
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++].item = li;
}
- if (item_compare_func_err) {
+ if (info.item_compare_func_err) {
EMSG(_("E882: Uniq compare function failed"));
break;
}
}
- if (!item_compare_func_err) {
+ if (!info.item_compare_func_err) {
while (--i >= 0) {
assert(ptrs[i].item->li_next);
li = ptrs[i].item->li_next;
@@ -15329,6 +15565,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
xfree(ptrs);
}
+
+theend:
+ sortinfo = old_sortinfo;
}
/// "sort"({list})" function
@@ -16365,8 +16604,21 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
dict_T *job_opts = NULL;
+ char *cwd = ".";
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
+
+ char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false);
+ if (new_cwd && strlen(new_cwd) > 0) {
+ cwd = new_cwd;
+ // The new cwd must be a directory.
+ if (!os_isdir((char_u *)cwd)) {
+ EMSG2(_(e_invarg2), "expected valid directory");
+ shell_free_argv(argv);
+ return;
+ }
+ }
+
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
shell_free_argv(argv);
return;
@@ -16374,7 +16626,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
}
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, true, false);
+ job_opts, true, false, cwd);
data->proc.pty.width = curwin->w_width;
data->proc.pty.height = curwin->w_height;
data->proc.pty.term_name = xstrdup("xterm-256color");
@@ -16389,11 +16641,6 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
topts.resize_cb = term_resize;
topts.close_cb = term_close;
- char *cwd = ".";
- if (argvars[1].v_type == VAR_STRING
- && os_isdir(argvars[1].vval.v_string)) {
- cwd = (char *)argvars[1].vval.v_string;
- }
int pid = data->proc.pty.process.pid;
char buf[1024];
@@ -16441,6 +16688,139 @@ static void f_tanh(typval_T *argvars, typval_T *rettv)
float_op_wrapper(argvars, rettv, &tanh);
}
+
+/// "timer_start(timeout, callback, opts)" function
+static void f_timer_start(typval_T *argvars, typval_T *rettv)
+{
+ long timeout = get_tv_number(&argvars[0]);
+ timer_T *timer;
+ int repeat = 1;
+ dict_T *dict;
+
+ rettv->vval.v_number = -1;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ if (argvars[2].v_type != VAR_DICT
+ || (dict = argvars[2].vval.v_dict) == NULL) {
+ EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
+ return;
+ }
+ if (dict_find(dict, (char_u *)"repeat", -1) != NULL) {
+ repeat = get_dict_number(dict, (char_u *)"repeat");
+ if (repeat == 0) {
+ repeat = 1;
+ }
+ }
+ }
+
+ if (argvars[1].v_type != VAR_FUNC && argvars[1].v_type != VAR_STRING) {
+ EMSG2(e_invarg2, "funcref");
+ return;
+ }
+ ufunc_T *func = find_ufunc(argvars[1].vval.v_string);
+ if (!func) {
+ // Invalid function name. Error already reported by `find_ufunc`.
+ return;
+ }
+ func->uf_refcount++;
+
+ timer = xmalloc(sizeof *timer);
+ timer->stopped = false;
+ timer->repeat_count = repeat;
+ timer->timeout = timeout;
+ timer->timer_id = last_timer_id++;
+ timer->callback = func;
+
+ time_watcher_init(&main_loop, &timer->tw, timer);
+ timer->tw.events = queue_new_child(main_loop.events);
+ // if main loop is blocked, don't queue up multiple events
+ timer->tw.blockable = true;
+ time_watcher_start(&timer->tw, timer_due_cb, timeout,
+ timeout * (repeat != 1));
+
+ pmap_put(uint64_t)(timers, timer->timer_id, timer);
+ rettv->vval.v_number = timer->timer_id;
+}
+
+
+// "timer_stop(timerid)" function
+static void f_timer_stop(typval_T *argvars, typval_T *rettv)
+{
+ if (argvars[0].v_type != VAR_NUMBER) {
+ EMSG(_(e_number_exp));
+ return;
+ }
+
+ timer_T *timer = pmap_get(uint64_t)(timers, get_tv_number(&argvars[0]));
+
+ if (timer == NULL) {
+ return;
+ }
+
+ timer_stop(timer);
+}
+
+// invoked on the main loop
+static void timer_due_cb(TimeWatcher *tw, void *data)
+{
+ timer_T *timer = (timer_T *)data;
+ if (timer->stopped) {
+ return;
+ }
+ // if repeat was negative repeat forever
+ if (timer->repeat_count >= 0 && --timer->repeat_count == 0) {
+ timer_stop(timer);
+ }
+
+ typval_T argv[1];
+ init_tv(argv);
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = timer->timer_id;
+ typval_T rettv;
+
+ init_tv(&rettv);
+ call_user_func(timer->callback, ARRAY_SIZE(argv), argv, &rettv,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum, NULL);
+ clear_tv(&rettv);
+
+ if (!timer->stopped && timer->timeout == 0) {
+ // special case: timeout=0 means the callback will be
+ // invoked again on the next event loop tick.
+ // we don't use uv_idle_t to not spin the event loop
+ // when the main loop is blocked.
+ time_watcher_start(&timer->tw, timer_due_cb, 0, 0);
+ }
+}
+
+static void timer_stop(timer_T *timer)
+{
+ if (timer->stopped) {
+ // avoid double free
+ return;
+ }
+ timer->stopped = true;
+ time_watcher_stop(&timer->tw);
+ time_watcher_close(&timer->tw, timer_free_cb);
+}
+
+// invoked on next event loop tick, so queue is empty
+static void timer_free_cb(TimeWatcher *tw, void *data)
+{
+ timer_T *timer = (timer_T *)data;
+ queue_free(timer->tw.events);
+ user_func_unref(timer->callback);
+ pmap_del(uint64_t)(timers, timer->timer_id);
+ xfree(timer);
+}
+
+void timer_teardown(void)
+{
+ timer_T *timer;
+ map_foreach_value(timers, timer, {
+ timer_stop(timer);
+ })
+}
+
/*
* "tolower(string)" function
*/
@@ -17540,7 +17920,8 @@ void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
void set_vim_var_string(const VimVarIndex idx, const char *const val,
const ptrdiff_t len)
{
- xfree(vimvars[idx].vv_str);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_STRING;
if (val == NULL) {
vimvars[idx].vv_str = NULL;
} else if (len == -1) {
@@ -17556,7 +17937,8 @@ void set_vim_var_string(const VimVarIndex idx, const char *const val,
/// @param[in,out] val Value to set to. Reference count will be incremented.
void set_vim_var_list(const VimVarIndex idx, list_T *const val)
{
- list_unref(vimvars[idx].vv_list);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_LIST;
vimvars[idx].vv_list = val;
if (val != NULL) {
val->lv_refcount++;
@@ -17570,7 +17952,8 @@ void set_vim_var_list(const VimVarIndex idx, list_T *const val)
/// Also keys of the dictionary will be made read-only.
void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
{
- dict_unref(vimvars[idx].vv_dict);
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_DICT;
vimvars[idx].vv_dict = val;
if (val != NULL) {
@@ -17847,45 +18230,147 @@ void free_tv(typval_T *varp)
}
}
-/*
- * Free the memory for a variable value and set the value to NULL or 0.
- */
+#define TYPVAL_ENCODE_ALLOW_SPECIALS false
+
+#define TYPVAL_ENCODE_CONV_NIL() \
+ do { \
+ tv->vval.v_special = kSpecialVarFalse; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_BOOL(ignored) \
+ TYPVAL_ENCODE_CONV_NIL()
+
+#define TYPVAL_ENCODE_CONV_NUMBER(ignored) \
+ do { \
+ (void)ignored; \
+ tv->vval.v_number = 0; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(ignored) \
+ assert(false)
+
+#define TYPVAL_ENCODE_CONV_FLOAT(ignored) \
+ do { \
+ tv->vval.v_float = 0; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_STRING(str, ignored) \
+ do { \
+ xfree(str); \
+ tv->vval.v_string = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_STR_STRING(ignored1, ignored2)
+
+#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3)
+
+#define TYPVAL_ENCODE_CONV_FUNC(fun) \
+ do { \
+ func_unref(fun); \
+ if (fun != empty_string) { \
+ xfree(fun); \
+ } \
+ tv->vval.v_string = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
+ do { \
+ list_unref(tv->vval.v_list); \
+ tv->vval.v_list = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
+ do { \
+ dict_unref(tv->vval.v_dict); \
+ tv->vval.v_dict = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_LIST_START(ignored) \
+ do { \
+ if (tv->vval.v_list->lv_refcount > 1) { \
+ tv->vval.v_list->lv_refcount--; \
+ tv->vval.v_list = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ return OK; \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS()
+
+#define TYPVAL_ENCODE_CONV_LIST_END() \
+ do { \
+ typval_T *const cur_tv = cur_mpsv->tv; \
+ assert(cur_tv->v_type == VAR_LIST); \
+ list_unref(cur_tv->vval.v_list); \
+ cur_tv->vval.v_list = NULL; \
+ cur_tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_DICT_START(ignored) \
+ do { \
+ if (tv->vval.v_dict->dv_refcount > 1) { \
+ tv->vval.v_dict->dv_refcount--; \
+ tv->vval.v_dict = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ return OK; \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(ignored1, ignored2)
+
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY()
+
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
+
+#define TYPVAL_ENCODE_CONV_DICT_END() \
+ do { \
+ typval_T *const cur_tv = cur_mpsv->tv; \
+ assert(cur_tv->v_type == VAR_DICT); \
+ dict_unref(cur_tv->vval.v_dict); \
+ cur_tv->vval.v_dict = NULL; \
+ cur_tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_RECURSE(ignored1, ignored2)
+
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
+
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
+#undef TYPVAL_ENCODE_CONV_NIL
+#undef TYPVAL_ENCODE_CONV_BOOL
+#undef TYPVAL_ENCODE_CONV_NUMBER
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#undef TYPVAL_ENCODE_CONV_STRING
+#undef TYPVAL_ENCODE_CONV_STR_STRING
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_FUNC
+#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
+#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_LIST_END
+#undef TYPVAL_ENCODE_CONV_DICT_START
+#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_DICT_END
+#undef TYPVAL_ENCODE_CONV_RECURSE
+
+/// Free memory for a variable value and set the value to NULL or 0
+///
+/// @param[in,out] varp Value to free.
void clear_tv(typval_T *varp)
{
- if (varp != NULL) {
- switch (varp->v_type) {
- case VAR_FUNC:
- func_unref(varp->vval.v_string);
- if (varp->vval.v_string != empty_string) {
- xfree(varp->vval.v_string);
- }
- varp->vval.v_string = NULL;
- break;
- case VAR_STRING:
- xfree(varp->vval.v_string);
- varp->vval.v_string = NULL;
- break;
- case VAR_LIST:
- list_unref(varp->vval.v_list);
- varp->vval.v_list = NULL;
- break;
- case VAR_DICT:
- dict_unref(varp->vval.v_dict);
- varp->vval.v_dict = NULL;
- break;
- case VAR_NUMBER:
- varp->vval.v_number = 0;
- break;
- case VAR_FLOAT:
- varp->vval.v_float = 0.0;
- break;
- case VAR_SPECIAL:
- varp->vval.v_special = kSpecialVarFalse;
- break;
- case VAR_UNKNOWN:
- break;
- }
- varp->v_lock = 0;
+ if (varp != NULL && varp->v_type != VAR_UNKNOWN) {
+ encode_vim_to_nothing(varp, varp, "clear_tv argument");
}
}
@@ -18467,19 +18952,6 @@ set_var (
|| tv_check_lock(v->di_tv.v_lock, name, false)) {
return;
}
- if (v->di_tv.v_type != tv->v_type
- && !((v->di_tv.v_type == VAR_STRING
- || v->di_tv.v_type == VAR_NUMBER)
- && (tv->v_type == VAR_STRING
- || tv->v_type == VAR_NUMBER))
- && !((v->di_tv.v_type == VAR_NUMBER
- || v->di_tv.v_type == VAR_FLOAT)
- && (tv->v_type == VAR_NUMBER
- || tv->v_type == VAR_FLOAT))
- ) {
- EMSG2(_("E706: Variable type mismatch for: %s"), name);
- return;
- }
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
@@ -18489,7 +18961,7 @@ set_var (
if (copy || tv->v_type != VAR_STRING)
v->di_tv.vval.v_string = vim_strsave(get_tv_string(tv));
else {
- /* Take over the string to avoid an extra alloc/free. */
+ // Take over the string to avoid an extra alloc/free.
v->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
@@ -19750,11 +20222,15 @@ theend:
*/
static int eval_fname_script(char_u *p)
{
- if (p[0] == '<' && (STRNICMP(p + 1, "SID>", 4) == 0
- || STRNICMP(p + 1, "SNR>", 4) == 0))
+ // Use mb_stricmp() because in Turkish comparing the "I" may not work with
+ // the standard library function.
+ if (p[0] == '<' && (mb_strnicmp(p + 1, (char_u *)"SID>", 4) == 0
+ || mb_strnicmp(p + 1, (char_u *)"SNR>", 4) == 0)) {
return 5;
- if (p[0] == 's' && p[1] == ':')
+ }
+ if (p[0] == 's' && p[1] == ':') {
return 2;
+ }
return 0;
}
@@ -20079,9 +20555,10 @@ script_autoload (
tofree = NULL;
}
- /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
- if (source_runtime(scriptname, FALSE) == OK)
- ret = TRUE;
+ // Try loading the package from $VIMRUNTIME/autoload/<name>.vim
+ if (source_runtime(scriptname, 0) == OK) {
+ ret = true;
+ }
}
xfree(tofree);
@@ -21537,7 +22014,8 @@ static inline TerminalJobData *common_job_init(char **argv,
ufunc_T *on_exit,
dict_T *self,
bool pty,
- bool detach)
+ bool detach,
+ char *cwd)
{
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
data->stopped = false;
@@ -21545,11 +22023,11 @@ static inline TerminalJobData *common_job_init(char **argv,
data->on_stderr = on_stderr;
data->on_exit = on_exit;
data->self = self;
- data->events = queue_new_child(loop.events);
+ data->events = queue_new_child(main_loop.events);
if (pty) {
- data->proc.pty = pty_process_init(&loop, data);
+ data->proc.pty = pty_process_init(&main_loop, data);
} else {
- data->proc.uv = libuv_process_init(&loop, data);
+ data->proc.uv = libuv_process_init(&main_loop, data);
}
Process *proc = (Process *)&data->proc;
proc->argv = argv;
@@ -21561,6 +22039,7 @@ static inline TerminalJobData *common_job_init(char **argv,
proc->cb = on_process_exit;
proc->events = data->events;
proc->detach = detach;
+ proc->cwd = cwd;
return data;
}
@@ -21647,7 +22126,7 @@ static inline void free_term_job_data(TerminalJobData *data)
{
// data->queue may still be used after this function returns(process_wait), so
// only free in the next event loop iteration
- queue_put(loop.fast_events, free_term_job_data_event, 1, data);
+ queue_put(main_loop.fast_events, free_term_job_data_event, 1, data);
}
// vimscript job callbacks must be executed on Nvim main loop
@@ -21851,6 +22330,7 @@ static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
if (argvars[0].v_type != VAR_STRING) {
EMSG(_(e_invarg));
+ return;
}
list_T *args = list_alloc();
@@ -21908,17 +22388,19 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
bool eval_has_provider(char *name)
{
-
-#define check_provider(name) \
- if (has_##name == -1) { \
- has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
- if (!has_##name) { \
- script_autoload((uint8_t *)"provider#" #name "#Call", false); \
- has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
- } \
+#define check_provider(name) \
+ if (has_##name == -1) { \
+ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
+ if (!has_##name) { \
+ script_autoload((uint8_t *)"provider#" #name "#Call", false); \
+ has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \
+ } \
}
- static int has_clipboard = -1, has_python = -1, has_python3 = -1;
+ static int has_clipboard = -1;
+ static int has_python = -1;
+ static int has_python3 = -1;
+ static int has_ruby = -1;
if (!strcmp(name, "clipboard")) {
check_provider(clipboard);
@@ -21929,14 +22411,16 @@ bool eval_has_provider(char *name)
} else if (!strcmp(name, "python")) {
check_provider(python);
return has_python;
+ } else if (!strcmp(name, "ruby")) {
+ check_provider(ruby);
+ return has_ruby;
}
return false;
}
-// Compute the `DictWatcher` address from a QUEUE node. This only exists because
-// ASAN doesn't handle `QUEUE_DATA` pointer arithmetic, and we blacklist this
-// function on .asan-blacklist.
+// Compute the `DictWatcher` address from a QUEUE node. This only exists for
+// .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer arithmetic).
static DictWatcher *dictwatcher_node_data(QUEUE *q)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 0774ef515f..43e9f76c0f 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -101,7 +101,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
FUNC_ATTR_NONNULL_ALL
{
if (kv_size(*container_stack) == 0) {
- kv_push(ValuesStackItem, *stack, obj);
+ kv_push(*stack, obj);
return OK;
}
ContainerStackItem last_container = kv_last(*container_stack);
@@ -190,7 +190,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
*next_map_special = true;
return OK;
}
- kv_push(ValuesStackItem, *stack, obj);
+ kv_push(*stack, obj);
}
return OK;
}
@@ -628,10 +628,8 @@ int json_decode_string(const char *const buf, const size_t buf_len,
convert_setup(&conv, (char_u *) "utf-8", p_enc);
conv.vc_fail = true;
int ret = OK;
- ValuesStack stack;
- kv_init(stack);
- ContainerStack container_stack;
- kv_init(container_stack);
+ ValuesStack stack = KV_INITIAL_VALUE;
+ ContainerStack container_stack = KV_INITIAL_VALUE;
rettv->v_type = VAR_UNKNOWN;
bool didcomma = false;
bool didcolon = false;
@@ -815,13 +813,13 @@ json_decode_string_cycle_start:
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
};
- kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) {
+ kv_push(container_stack, ((ContainerStackItem) {
.stack_index = kv_size(stack),
.s = p,
.container = tv,
.special_val = NULL,
}));
- kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon));
+ kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
case '{': {
@@ -845,13 +843,13 @@ json_decode_string_cycle_start:
.vval = { .v_dict = dict },
};
}
- kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) {
+ kv_push(container_stack, ((ContainerStackItem) {
.stack_index = kv_size(stack),
.s = p,
.container = tv,
.special_val = val_list,
}));
- kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon));
+ kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
default: {
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index c651a50be9..670437ceda 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -6,6 +6,7 @@
#include <msgpack.h>
#include <inttypes.h>
+#include <stddef.h>
#include <assert.h>
#include <math.h>
@@ -22,6 +23,7 @@
#include "nvim/ascii.h"
#include "nvim/vim.h" // For _()
#include "nvim/lib/kvec.h"
+#include "nvim/eval/typval_encode.h"
#define ga_concat(a, b) ga_concat(a, (char_u *)b)
#define utf_ptr2char(b) utf_ptr2char((char_u *)b)
@@ -32,29 +34,6 @@
#define convert_setup(vcp, from, to) \
(convert_setup(vcp, (char_u *)from, (char_u *)to))
-/// Structure representing current VimL to messagepack conversion state
-typedef struct {
- enum {
- kMPConvDict, ///< Convert dict_T *dictionary.
- kMPConvList, ///< Convert list_T *list.
- kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
- } type;
- union {
- struct {
- dict_T *dict; ///< Currently converted dictionary.
- hashitem_T *hi; ///< Currently converted dictionary item.
- size_t todo; ///< Amount of items left to process.
- } d; ///< State of dictionary conversion.
- struct {
- list_T *list; ///< Currently converted list.
- listitem_T *li; ///< Currently converted list item.
- } l; ///< State of list or generic mapping conversion.
- } data; ///< Data to convert.
-} MPConvStackVal;
-
-/// Stack used to convert VimL values to messagepack.
-typedef kvec_t(MPConvStackVal) MPConvStack;
-
const char *const encode_special_var_names[] = {
[kSpecialVarNull] = "null",
[kSpecialVarTrue] = "true",
@@ -275,368 +254,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
: OK);
}
-/// Code for checking whether container references itself
-///
-/// @param[in,out] val Container to check.
-/// @param copyID_attr Name of the container attribute that holds copyID.
-/// After checking whether value of this attribute is
-/// copyID (variable) it is set to copyID.
-#define CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \
- do { \
- if ((val)->copyID_attr == copyID) { \
- CONV_RECURSE((val), conv_type); \
- } \
- (val)->copyID_attr = copyID; \
- } while (0)
-
-#define TV_STRLEN(tv) \
- (tv->vval.v_string == NULL ? 0 : STRLEN(tv->vval.v_string))
-
-/// Define functions which convert VimL value to something else
-///
-/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const
-/// tv)` which returns OK or FAIL and helper functions.
-///
-/// @param firstargtype Type of the first argument. It will be used to return
-/// the results.
-/// @param firstargname Name of the first argument.
-/// @param name Name of the target converter.
-#define DEFINE_VIML_CONV_FUNCTIONS(scope, name, firstargtype, firstargname) \
-static int name##_convert_one_value(firstargtype firstargname, \
- MPConvStack *const mpstack, \
- typval_T *const tv, \
- const int copyID, \
- const char *const objname) \
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- switch (tv->v_type) { \
- case VAR_STRING: { \
- CONV_STRING(tv->vval.v_string, TV_STRLEN(tv)); \
- break; \
- } \
- case VAR_NUMBER: { \
- CONV_NUMBER(tv->vval.v_number); \
- break; \
- } \
- case VAR_FLOAT: { \
- CONV_FLOAT(tv->vval.v_float); \
- break; \
- } \
- case VAR_FUNC: { \
- CONV_FUNC(tv->vval.v_string); \
- break; \
- } \
- case VAR_LIST: { \
- if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
- CONV_EMPTY_LIST(); \
- break; \
- } \
- CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, kMPConvList); \
- CONV_LIST_START(tv->vval.v_list); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvList, \
- .data = { \
- .l = { \
- .list = tv->vval.v_list, \
- .li = tv->vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case VAR_SPECIAL: { \
- switch (tv->vval.v_special) { \
- case kSpecialVarNull: { \
- CONV_NIL(); \
- break; \
- } \
- case kSpecialVarTrue: \
- case kSpecialVarFalse: { \
- CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \
- break; \
- } \
- } \
- break; \
- } \
- case VAR_DICT: { \
- if (tv->vval.v_dict == NULL \
- || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \
- CONV_EMPTY_DICT(); \
- break; \
- } \
- const dictitem_T *type_di; \
- const dictitem_T *val_di; \
- if (CONV_ALLOW_SPECIAL \
- && tv->vval.v_dict->dv_hashtab.ht_used == 2 \
- && (type_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_TYPE", -1)) != NULL \
- && type_di->di_tv.v_type == VAR_LIST \
- && (val_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_VAL", -1)) != NULL) { \
- size_t i; \
- for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \
- if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \
- break; \
- } \
- } \
- if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- switch ((MessagePackType) i) { \
- case kMPNil: { \
- CONV_NIL(); \
- break; \
- } \
- case kMPBoolean: { \
- if (val_di->di_tv.v_type != VAR_NUMBER) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_BOOL(val_di->di_tv.vval.v_number); \
- break; \
- } \
- case kMPInteger: { \
- const list_T *val_list; \
- varnumber_T sign; \
- varnumber_T highest_bits; \
- varnumber_T high_bits; \
- varnumber_T low_bits; \
- /* List of 4 integers; first is signed (should be 1 or -1, but */ \
- /* this is not checked), second is unsigned and have at most */ \
- /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \
- /* bits is not checked), other unsigned and have at most 31 */ \
- /* non-zero bits (number of bits is not checked).*/ \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 4 \
- || val_list->lv_first->li_tv.v_type != VAR_NUMBER \
- || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \
- || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \
- || (highest_bits = \
- val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \
- || (high_bits = \
- val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_tv.v_type != VAR_NUMBER \
- || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \
- | (uint64_t) (((uint64_t) high_bits) << 31) \
- | (uint64_t) low_bits); \
- if (sign > 0) { \
- CONV_UNSIGNED_NUMBER(number); \
- } else { \
- CONV_NUMBER(-number); \
- } \
- break; \
- } \
- case kMPFloat: { \
- if (val_di->di_tv.v_type != VAR_FLOAT) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_FLOAT(val_di->di_tv.vval.v_float); \
- break; \
- } \
- case kMPString: \
- case kMPBinary: { \
- const bool is_string = ((MessagePackType) i == kMPString); \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \
- &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- if (is_string) { \
- CONV_STR_STRING(buf, len); \
- } else { \
- CONV_STRING(buf, len); \
- } \
- xfree(buf); \
- break; \
- } \
- case kMPArray: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, \
- kMPConvList); \
- CONV_LIST_START(val_di->di_tv.vval.v_list); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvList, \
- .data = { \
- .l = { \
- .list = val_di->di_tv.vval.v_list, \
- .li = val_di->di_tv.vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPMap: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- list_T *const val_list = val_di->di_tv.vval.v_list; \
- if (val_list == NULL || val_list->lv_len == 0) { \
- CONV_EMPTY_DICT(); \
- break; \
- } \
- for (const listitem_T *li = val_list->lv_first; li != NULL; \
- li = li->li_next) { \
- if (li->li_tv.v_type != VAR_LIST \
- || li->li_tv.vval.v_list->lv_len != 2) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- } \
- CHECK_SELF_REFERENCE(val_list, lv_copyID, kMPConvPairs); \
- CONV_DICT_START(val_list->lv_len); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvPairs, \
- .data = { \
- .l = { \
- .list = val_list, \
- .li = val_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPExt: { \
- const list_T *val_list; \
- varnumber_T type; \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 2 \
- || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \
- || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \
- || type < INT8_MIN \
- || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \
- &len, &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_EXT_STRING(buf, len, type); \
- xfree(buf); \
- break; \
- } \
- } \
- break; \
- } \
-name##_convert_one_value_regular_dict: \
- CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, kMPConvDict); \
- CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvDict, \
- .data = { \
- .d = { \
- .dict = tv->vval.v_dict, \
- .hi = tv->vval.v_dict->dv_hashtab.ht_array, \
- .todo = tv->vval.v_dict->dv_hashtab.ht_used, \
- }, \
- }, \
- })); \
- break; \
- } \
- case VAR_UNKNOWN: { \
- EMSG2(_(e_intern2), #name "_convert_one_value()"); \
- return FAIL; \
- } \
- } \
- return OK; \
-} \
-\
-scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
- const char *const objname) \
- FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- const int copyID = get_copyID(); \
- MPConvStack mpstack; \
- kv_init(mpstack); \
- if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
- == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- while (kv_size(mpstack)) { \
- MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \
- typval_T *cur_tv = NULL; \
- switch (cur_mpsv->type) { \
- case kMPConvDict: { \
- if (!cur_mpsv->data.d.todo) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
- CONV_DICT_END(); \
- continue; \
- } else if (cur_mpsv->data.d.todo \
- != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \
- CONV_DICT_BETWEEN_ITEMS(); \
- } \
- while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \
- cur_mpsv->data.d.hi++; \
- } \
- dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \
- cur_mpsv->data.d.todo--; \
- cur_mpsv->data.d.hi++; \
- CONV_STR_STRING(&di->di_key[0], STRLEN(&di->di_key[0])); \
- CONV_DICT_AFTER_KEY(); \
- cur_tv = &di->di_tv; \
- break; \
- } \
- case kMPConvList: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- CONV_LIST_END(cur_mpsv->data.l.list); \
- continue; \
- } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
- CONV_LIST_BETWEEN_ITEMS(); \
- } \
- cur_tv = &cur_mpsv->data.l.li->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
- } \
- case kMPConvPairs: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- CONV_DICT_END(); \
- continue; \
- } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
- CONV_DICT_BETWEEN_ITEMS(); \
- } \
- const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
- CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair); \
- if (name##_convert_one_value(firstargname, &mpstack, \
- &kv_pair->lv_first->li_tv, copyID, \
- objname) == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- CONV_DICT_AFTER_KEY(); \
- cur_tv = &kv_pair->lv_last->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
- } \
- } \
- assert(cur_tv != NULL); \
- if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
- objname) == FAIL) { \
- goto encode_vim_to_##name##_error_ret; \
- } \
- } \
- kv_destroy(mpstack); \
- return OK; \
-encode_vim_to_##name##_error_ret: \
- kv_destroy(mpstack); \
- return FAIL; \
-}
-
-#define CONV_STRING(buf, len) \
+#define TYPVAL_ENCODE_CONV_STRING(buf, len) \
do { \
const char *const buf_ = (const char *) buf; \
if (buf == NULL) { \
@@ -655,19 +273,19 @@ encode_vim_to_##name##_error_ret: \
} \
} while (0)
-#define CONV_STR_STRING(buf, len) \
- CONV_STRING(buf, len)
+#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \
+ TYPVAL_ENCODE_CONV_STRING(buf, len)
-#define CONV_EXT_STRING(buf, len, type)
+#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type)
-#define CONV_NUMBER(num) \
+#define TYPVAL_ENCODE_CONV_NUMBER(num) \
do { \
char numbuf[NUMBUFLEN]; \
vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t) (num)); \
ga_concat(gap, numbuf); \
} while (0)
-#define CONV_FLOAT(flt) \
+#define TYPVAL_ENCODE_CONV_FLOAT(flt) \
do { \
const float_T flt_ = (flt); \
switch (fpclassify(flt_)) { \
@@ -690,51 +308,51 @@ encode_vim_to_##name##_error_ret: \
} \
} while (0)
-#define CONV_FUNC(fun) \
+#define TYPVAL_ENCODE_CONV_FUNC(fun) \
do { \
ga_concat(gap, "function("); \
- CONV_STRING(fun, STRLEN(fun)); \
+ TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \
ga_append(gap, ')'); \
} while (0)
-#define CONV_EMPTY_LIST() \
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
ga_concat(gap, "[]")
-#define CONV_LIST_START(lst) \
+#define TYPVAL_ENCODE_CONV_LIST_START(len) \
ga_append(gap, '[')
-#define CONV_EMPTY_DICT() \
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
ga_concat(gap, "{}")
-#define CONV_NIL() \
+#define TYPVAL_ENCODE_CONV_NIL() \
ga_concat(gap, "v:null")
-#define CONV_BOOL(num) \
+#define TYPVAL_ENCODE_CONV_BOOL(num) \
ga_concat(gap, ((num)? "v:true": "v:false"))
-#define CONV_UNSIGNED_NUMBER(num)
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num)
-#define CONV_DICT_START(len) \
+#define TYPVAL_ENCODE_CONV_DICT_START(len) \
ga_append(gap, '{')
-#define CONV_DICT_END() \
+#define TYPVAL_ENCODE_CONV_DICT_END() \
ga_append(gap, '}')
-#define CONV_DICT_AFTER_KEY() \
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() \
ga_concat(gap, ": ")
-#define CONV_DICT_BETWEEN_ITEMS() \
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \
ga_concat(gap, ", ")
-#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair)
+#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key)
-#define CONV_LIST_END(lst) \
+#define TYPVAL_ENCODE_CONV_LIST_END() \
ga_append(gap, ']')
-#define CONV_LIST_BETWEEN_ITEMS() \
- CONV_DICT_BETWEEN_ITEMS()
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() \
+ TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
-#define CONV_RECURSE(val, conv_type) \
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
do { \
if (!did_echo_string_emsg) { \
/* Only give this message once for a recursive call to avoid */ \
@@ -761,15 +379,14 @@ encode_vim_to_##name##_error_ret: \
} \
vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{E724@%zu}", backref); \
ga_concat(gap, &ebuf[0]); \
- return OK; \
} while (0)
-#define CONV_ALLOW_SPECIAL false
+#define TYPVAL_ENCODE_ALLOW_SPECIALS false
-DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap)
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, string, garray_T *const, gap)
-#undef CONV_RECURSE
-#define CONV_RECURSE(val, conv_type) \
+#undef TYPVAL_ENCODE_CONV_RECURSE
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
do { \
char ebuf[NUMBUFLEN + 7]; \
size_t backref = 0; \
@@ -796,10 +413,10 @@ DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap)
return OK; \
} while (0)
-DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap)
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, echo, garray_T *const, gap)
-#undef CONV_RECURSE
-#define CONV_RECURSE(val, conv_type) \
+#undef TYPVAL_ENCODE_CONV_RECURSE
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
do { \
if (!did_echo_string_emsg) { \
/* Only give this message once for a recursive call to avoid */ \
@@ -808,30 +425,29 @@ DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap)
EMSG(_("E724: unable to correctly dump variable " \
"with self-referencing container")); \
} \
- return OK; \
} while (0)
-#undef CONV_ALLOW_SPECIAL
-#define CONV_ALLOW_SPECIAL true
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
+#define TYPVAL_ENCODE_ALLOW_SPECIALS true
-#undef CONV_NIL
-#define CONV_NIL() \
+#undef TYPVAL_ENCODE_CONV_NIL
+#define TYPVAL_ENCODE_CONV_NIL() \
ga_concat(gap, "null")
-#undef CONV_BOOL
-#define CONV_BOOL(num) \
+#undef TYPVAL_ENCODE_CONV_BOOL
+#define TYPVAL_ENCODE_CONV_BOOL(num) \
ga_concat(gap, ((num)? "true": "false"))
-#undef CONV_UNSIGNED_NUMBER
-#define CONV_UNSIGNED_NUMBER(num) \
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \
do { \
char numbuf[NUMBUFLEN]; \
vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \
ga_concat(gap, numbuf); \
} while (0)
-#undef CONV_FLOAT
-#define CONV_FLOAT(flt) \
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#define TYPVAL_ENCODE_CONV_FLOAT(flt) \
do { \
const float_T flt_ = (flt); \
switch (fpclassify(flt_)) { \
@@ -1019,24 +635,24 @@ static inline int convert_to_json_string(garray_T *const gap,
return OK;
}
-#undef CONV_STRING
-#define CONV_STRING(buf, len) \
+#undef TYPVAL_ENCODE_CONV_STRING
+#define TYPVAL_ENCODE_CONV_STRING(buf, len) \
do { \
if (convert_to_json_string(gap, (const char *) (buf), (len)) != OK) { \
return FAIL; \
} \
} while (0)
-#undef CONV_EXT_STRING
-#define CONV_EXT_STRING(buf, len, type) \
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \
do { \
xfree(buf); \
EMSG(_("E474: Unable to convert EXT string to JSON")); \
return FAIL; \
} while (0)
-#undef CONV_FUNC
-#define CONV_FUNC(fun) \
+#undef TYPVAL_ENCODE_CONV_FUNC
+#define TYPVAL_ENCODE_CONV_FUNC(fun) \
return conv_error(_("E474: Error while dumping %s, %s: " \
"attempt to dump function reference"), \
mpstack, objname)
@@ -1044,9 +660,8 @@ static inline int convert_to_json_string(garray_T *const gap,
/// Check whether given key can be used in json_encode()
///
/// @param[in] tv Key to check.
-static inline bool check_json_key(const typval_T *const tv)
+bool encode_check_json_key(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
- FUNC_ATTR_ALWAYS_INLINE
{
if (tv->v_type == VAR_STRING) {
return true;
@@ -1080,38 +695,38 @@ static inline bool check_json_key(const typval_T *const tv)
return true;
}
-#undef CONV_SPECIAL_DICT_KEY_CHECK
-#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair) \
+#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key) \
do { \
- if (!check_json_key(&kv_pair->lv_first->li_tv)) { \
+ if (!encode_check_json_key(&key)) { \
EMSG(_("E474: Invalid key in special dictionary")); \
- goto encode_vim_to_##name##_error_ret; \
+ goto label; \
} \
} while (0)
-DEFINE_VIML_CONV_FUNCTIONS(static, json, garray_T *const, gap)
-
-#undef CONV_STRING
-#undef CONV_STR_STRING
-#undef CONV_EXT_STRING
-#undef CONV_NUMBER
-#undef CONV_FLOAT
-#undef CONV_FUNC
-#undef CONV_EMPTY_LIST
-#undef CONV_LIST_START
-#undef CONV_EMPTY_DICT
-#undef CONV_NIL
-#undef CONV_BOOL
-#undef CONV_UNSIGNED_NUMBER
-#undef CONV_DICT_START
-#undef CONV_DICT_END
-#undef CONV_DICT_AFTER_KEY
-#undef CONV_DICT_BETWEEN_ITEMS
-#undef CONV_SPECIAL_DICT_KEY_CHECK
-#undef CONV_LIST_END
-#undef CONV_LIST_BETWEEN_ITEMS
-#undef CONV_RECURSE
-#undef CONV_ALLOW_SPECIAL
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, json, garray_T *const, gap)
+
+#undef TYPVAL_ENCODE_CONV_STRING
+#undef TYPVAL_ENCODE_CONV_STR_STRING
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_NUMBER
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#undef TYPVAL_ENCODE_CONV_FUNC
+#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
+#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CONV_NIL
+#undef TYPVAL_ENCODE_CONV_BOOL
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#undef TYPVAL_ENCODE_CONV_DICT_START
+#undef TYPVAL_ENCODE_CONV_DICT_END
+#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_LIST_END
+#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_RECURSE
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
/// Return a string with the string representation of a variable.
/// Puts quotes around strings, so that they can be parsed back by eval().
@@ -1181,7 +796,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
return (char *) ga.ga_data;
}
-#define CONV_STRING(buf, len) \
+#define TYPVAL_ENCODE_CONV_STRING(buf, len) \
do { \
if (buf == NULL) { \
msgpack_pack_bin(packer, 0); \
@@ -1192,7 +807,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
} \
} while (0)
-#define CONV_STR_STRING(buf, len) \
+#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \
do { \
if (buf == NULL) { \
msgpack_pack_str(packer, 0); \
@@ -1203,7 +818,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
} \
} while (0)
-#define CONV_EXT_STRING(buf, len, type) \
+#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \
do { \
if (buf == NULL) { \
msgpack_pack_ext(packer, 0, (int8_t) type); \
@@ -1214,30 +829,30 @@ char *encode_tv2json(typval_T *tv, size_t *len)
} \
} while (0)
-#define CONV_NUMBER(num) \
+#define TYPVAL_ENCODE_CONV_NUMBER(num) \
msgpack_pack_int64(packer, (int64_t) (num))
-#define CONV_FLOAT(flt) \
+#define TYPVAL_ENCODE_CONV_FLOAT(flt) \
msgpack_pack_double(packer, (double) (flt))
-#define CONV_FUNC(fun) \
+#define TYPVAL_ENCODE_CONV_FUNC(fun) \
return conv_error(_("E951: Error while dumping %s, %s: " \
"attempt to dump function reference"), \
mpstack, objname)
-#define CONV_EMPTY_LIST() \
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
msgpack_pack_array(packer, 0)
-#define CONV_LIST_START(lst) \
- msgpack_pack_array(packer, (size_t) (lst)->lv_len)
+#define TYPVAL_ENCODE_CONV_LIST_START(len) \
+ msgpack_pack_array(packer, (size_t) (len))
-#define CONV_EMPTY_DICT() \
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \
msgpack_pack_map(packer, 0)
-#define CONV_NIL() \
+#define TYPVAL_ENCODE_CONV_NIL() \
msgpack_pack_nil(packer)
-#define CONV_BOOL(num) \
+#define TYPVAL_ENCODE_CONV_BOOL(num) \
do { \
if ((num)) { \
msgpack_pack_true(packer); \
@@ -1246,51 +861,51 @@ char *encode_tv2json(typval_T *tv, size_t *len)
} \
} while (0)
-#define CONV_UNSIGNED_NUMBER(num) \
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \
msgpack_pack_uint64(packer, (num))
-#define CONV_DICT_START(len) \
+#define TYPVAL_ENCODE_CONV_DICT_START(len) \
msgpack_pack_map(packer, (size_t) (len))
-#define CONV_DICT_END()
+#define TYPVAL_ENCODE_CONV_DICT_END()
-#define CONV_DICT_AFTER_KEY()
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY()
-#define CONV_DICT_BETWEEN_ITEMS()
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS()
-#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair)
+#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, key)
-#define CONV_LIST_END(lst)
+#define TYPVAL_ENCODE_CONV_LIST_END()
-#define CONV_LIST_BETWEEN_ITEMS()
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS()
-#define CONV_RECURSE(val, conv_type) \
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
return conv_error(_("E952: Unable to dump %s: " \
"container references itself in %s"), \
mpstack, objname)
-#define CONV_ALLOW_SPECIAL true
-
-DEFINE_VIML_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
-
-#undef CONV_STRING
-#undef CONV_STR_STRING
-#undef CONV_EXT_STRING
-#undef CONV_NUMBER
-#undef CONV_FLOAT
-#undef CONV_FUNC
-#undef CONV_EMPTY_LIST
-#undef CONV_LIST_START
-#undef CONV_EMPTY_DICT
-#undef CONV_NIL
-#undef CONV_BOOL
-#undef CONV_UNSIGNED_NUMBER
-#undef CONV_DICT_START
-#undef CONV_DICT_END
-#undef CONV_DICT_AFTER_KEY
-#undef CONV_DICT_BETWEEN_ITEMS
-#undef CONV_SPECIAL_DICT_KEY_CHECK
-#undef CONV_LIST_END
-#undef CONV_LIST_BETWEEN_ITEMS
-#undef CONV_RECURSE
-#undef CONV_ALLOW_SPECIAL
+#define TYPVAL_ENCODE_ALLOW_SPECIALS true
+
+TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
+
+#undef TYPVAL_ENCODE_CONV_STRING
+#undef TYPVAL_ENCODE_CONV_STR_STRING
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_NUMBER
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#undef TYPVAL_ENCODE_CONV_FUNC
+#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
+#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CONV_NIL
+#undef TYPVAL_ENCODE_CONV_BOOL
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#undef TYPVAL_ENCODE_CONV_DICT_START
+#undef TYPVAL_ENCODE_CONV_DICT_END
+#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_LIST_END
+#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_RECURSE
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
new file mode 100644
index 0000000000..98fa7b26c6
--- /dev/null
+++ b/src/nvim/eval/typval_encode.h
@@ -0,0 +1,570 @@
+/// @file eval/typval_convert.h
+///
+/// Contains set of macros used to convert (possibly recursive) typval_T into
+/// something else. For these macros to work the following macros must be
+/// defined:
+
+/// @def TYPVAL_ENCODE_CONV_NIL
+/// @brief Macros used to convert NIL value
+///
+/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS
+/// is false) and `v:null`. Accepts no arguments, but still must be
+/// a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_BOOL
+/// @brief Macros used to convert boolean value
+///
+/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS
+/// is false) and `v:true`/`v:false`.
+///
+/// @param num Boolean value to convert. Value is an expression which
+/// evaluates to some integer.
+
+/// @def TYPVAL_ENCODE_CONV_NUMBER
+/// @brief Macros used to convert integer
+///
+/// @param num Integer to convert, must accept both varnumber_T and int64_t.
+
+/// @def TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+/// @brief Macros used to convert unsigned integer
+///
+/// Not used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be
+/// defined.
+///
+/// @param num Integer to convert, must accept uint64_t.
+
+/// @def TYPVAL_ENCODE_CONV_FLOAT
+/// @brief Macros used to convert floating-point number
+///
+/// @param flt Number to convert, must accept float_T.
+
+/// @def TYPVAL_ENCODE_CONV_STRING
+/// @brief Macros used to convert plain string
+///
+/// Is used to convert VAR_STRING objects as well as BIN strings represented as
+/// special dictionary.
+///
+/// @param buf String to convert. Is a char[] buffer, not NUL-terminated.
+/// @param len String length.
+
+/// @def TYPVAL_ENCODE_CONV_STR_STRING
+/// @brief Like #TYPVAL_ENCODE_CONV_STRING, but for STR strings
+///
+/// Is used to convert dictionary keys and STR strings represented as special
+/// dictionaries.
+
+/// @def TYPVAL_ENCODE_CONV_EXT_STRING
+/// @brief Macros used to convert EXT string
+///
+/// Is used to convert EXT strings represented as special dictionaries. Never
+/// actually used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be
+/// defined.
+///
+/// @param buf String to convert. Is a char[] buffer, not NUL-terminated.
+/// @param len String length.
+/// @param type EXT type.
+
+/// @def TYPVAL_ENCODE_CONV_FUNC
+/// @brief Macros used to convert a function reference
+///
+/// @param fun Function name.
+
+/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
+/// @brief Macros used to convert an empty list
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_EMPTY_DICT
+/// @brief Macros used to convert an empty dictionary
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_LIST_START
+/// @brief Macros used before starting to convert non-empty list
+///
+/// @param len List length. Is an expression which evaluates to an integer.
+
+/// @def TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+/// @brief Macros used after finishing converting non-last list item
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_LIST_END
+/// @brief Macros used after converting non-empty list
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_DICT_START
+/// @brief Macros used before starting to convert non-empty dictionary
+///
+/// @param len Dictionary length. Is an expression which evaluates to an
+/// integer.
+
+/// @def TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK
+/// @brief Macros used to check special dictionary key
+///
+/// @param label Label for goto in case check was not successfull.
+/// @param key typval_T key to check.
+
+/// @def TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+/// @brief Macros used after finishing converting dictionary key
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+/// @brief Macros used after finishing converting non-last dictionary value
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_DICT_END
+/// @brief Macros used after converting non-empty dictionary
+///
+/// Accepts no arguments, but still must be a function-like macros.
+
+/// @def TYPVAL_ENCODE_CONV_RECURSE
+/// @brief Macros used when self-containing container is detected
+///
+/// @param val Container for which this situation was detected.
+/// @param conv_type Type of the stack entry, @see MPConvStackValType.
+
+/// @def TYPVAL_ENCODE_ALLOW_SPECIALS
+/// @brief Macros that specifies whether special dictionaries are special
+///
+/// Must be something that evaluates to boolean, most likely `true` or `false`.
+/// If it is false then special dictionaries are not treated specially.
+#ifndef NVIM_EVAL_TYPVAL_ENCODE_H
+#define NVIM_EVAL_TYPVAL_ENCODE_H
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "nvim/lib/kvec.h"
+#include "nvim/eval_defs.h"
+#include "nvim/eval/encode.h"
+#include "nvim/func_attr.h"
+
+/// Type of the stack entry
+typedef enum {
+ kMPConvDict, ///< Convert dict_T *dictionary.
+ kMPConvList, ///< Convert list_T *list.
+ kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
+} MPConvStackValType;
+
+/// Structure representing current VimL to messagepack conversion state
+typedef struct {
+ MPConvStackValType type; ///< Type of the stack entry.
+ typval_T *tv; ///< Currently converted typval_T.
+ union {
+ struct {
+ dict_T *dict; ///< Currently converted dictionary.
+ hashitem_T *hi; ///< Currently converted dictionary item.
+ size_t todo; ///< Amount of items left to process.
+ } d; ///< State of dictionary conversion.
+ struct {
+ list_T *list; ///< Currently converted list.
+ listitem_T *li; ///< Currently converted list item.
+ } l; ///< State of list or generic mapping conversion.
+ } data; ///< Data to convert.
+} MPConvStackVal;
+
+/// Stack used to convert VimL values to messagepack.
+typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;
+
+// Defines for MPConvStack
+#define _mp_size kv_size
+#define _mp_init kvi_init
+#define _mp_destroy kvi_destroy
+#define _mp_push kvi_push
+#define _mp_pop kv_pop
+#define _mp_last kv_last
+
+/// Code for checking whether container references itself
+///
+/// @param[in,out] val Container to check.
+/// @param copyID_attr Name of the container attribute that holds copyID.
+/// After checking whether value of this attribute is
+/// copyID (variable) it is set to copyID.
+/// @param conv_type Type of the conversion, @see MPConvStackValType.
+#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \
+ do { \
+ if ((val)->copyID_attr == copyID) { \
+ TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \
+ return OK; \
+ } \
+ (val)->copyID_attr = copyID; \
+ } while (0)
+
+/// Length of the string stored in typval_T
+///
+/// @param[in] tv String for which to compute length for. Must be typval_T
+/// with VAR_STRING.
+///
+/// @return Length of the string stored in typval_T, including 0 for NULL
+/// string.
+static inline size_t tv_strlen(const typval_T *const tv)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(tv->v_type == VAR_STRING);
+ return (tv->vval.v_string == NULL
+ ? 0
+ : strlen((char *) tv->vval.v_string));
+}
+
+/// Define functions which convert VimL value to something else
+///
+/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const
+/// tv)` which returns OK or FAIL and helper functions.
+///
+/// @param scope Scope of the main function: either nothing or `static`.
+/// @param name Name of the target converter.
+/// @param firstargtype Type of the first argument. It will be used to return
+/// the results.
+/// @param firstargname Name of the first argument.
+#define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, firstargtype, \
+ firstargname) \
+static int name##_convert_one_value(firstargtype firstargname, \
+ MPConvStack *const mpstack, \
+ typval_T *const tv, \
+ const int copyID, \
+ const char *const objname) \
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
+{ \
+ switch (tv->v_type) { \
+ case VAR_STRING: { \
+ TYPVAL_ENCODE_CONV_STRING(tv->vval.v_string, tv_strlen(tv)); \
+ break; \
+ } \
+ case VAR_NUMBER: { \
+ TYPVAL_ENCODE_CONV_NUMBER(tv->vval.v_number); \
+ break; \
+ } \
+ case VAR_FLOAT: { \
+ TYPVAL_ENCODE_CONV_FLOAT(tv->vval.v_float); \
+ break; \
+ } \
+ case VAR_FUNC: { \
+ TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \
+ break; \
+ } \
+ case VAR_LIST: { \
+ if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
+ TYPVAL_ENCODE_CONV_EMPTY_LIST(); \
+ break; \
+ } \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, \
+ kMPConvList); \
+ TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \
+ _mp_push(*mpstack, ((MPConvStackVal) { \
+ .type = kMPConvList, \
+ .tv = tv, \
+ .data = { \
+ .l = { \
+ .list = tv->vval.v_list, \
+ .li = tv->vval.v_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case VAR_SPECIAL: { \
+ switch (tv->vval.v_special) { \
+ case kSpecialVarNull: { \
+ TYPVAL_ENCODE_CONV_NIL(); \
+ break; \
+ } \
+ case kSpecialVarTrue: \
+ case kSpecialVarFalse: { \
+ TYPVAL_ENCODE_CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \
+ break; \
+ } \
+ } \
+ break; \
+ } \
+ case VAR_DICT: { \
+ if (tv->vval.v_dict == NULL \
+ || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \
+ TYPVAL_ENCODE_CONV_EMPTY_DICT(); \
+ break; \
+ } \
+ const dictitem_T *type_di; \
+ const dictitem_T *val_di; \
+ if (TYPVAL_ENCODE_ALLOW_SPECIALS \
+ && tv->vval.v_dict->dv_hashtab.ht_used == 2 \
+ && (type_di = dict_find((dict_T *) tv->vval.v_dict, \
+ (char_u *) "_TYPE", -1)) != NULL \
+ && type_di->di_tv.v_type == VAR_LIST \
+ && (val_di = dict_find((dict_T *) tv->vval.v_dict, \
+ (char_u *) "_VAL", -1)) != NULL) { \
+ size_t i; \
+ for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \
+ if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \
+ break; \
+ } \
+ } \
+ if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ switch ((MessagePackType) i) { \
+ case kMPNil: { \
+ TYPVAL_ENCODE_CONV_NIL(); \
+ break; \
+ } \
+ case kMPBoolean: { \
+ if (val_di->di_tv.v_type != VAR_NUMBER) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ TYPVAL_ENCODE_CONV_BOOL(val_di->di_tv.vval.v_number); \
+ break; \
+ } \
+ case kMPInteger: { \
+ const list_T *val_list; \
+ varnumber_T sign; \
+ varnumber_T highest_bits; \
+ varnumber_T high_bits; \
+ varnumber_T low_bits; \
+ /* List of 4 integers; first is signed (should be 1 or -1, but */ \
+ /* this is not checked), second is unsigned and have at most */ \
+ /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \
+ /* bits is not checked), other unsigned and have at most 31 */ \
+ /* non-zero bits (number of bits is not checked).*/ \
+ if (val_di->di_tv.v_type != VAR_LIST \
+ || (val_list = val_di->di_tv.vval.v_list) == NULL \
+ || val_list->lv_len != 4 \
+ || val_list->lv_first->li_tv.v_type != VAR_NUMBER \
+ || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \
+ || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \
+ || (highest_bits = \
+ val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \
+ || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \
+ || (high_bits = \
+ val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \
+ || val_list->lv_last->li_tv.v_type != VAR_NUMBER \
+ || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \
+ | (uint64_t) (((uint64_t) high_bits) << 31) \
+ | (uint64_t) low_bits); \
+ if (sign > 0) { \
+ TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(number); \
+ } else { \
+ TYPVAL_ENCODE_CONV_NUMBER(-number); \
+ } \
+ break; \
+ } \
+ case kMPFloat: { \
+ if (val_di->di_tv.v_type != VAR_FLOAT) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ TYPVAL_ENCODE_CONV_FLOAT(val_di->di_tv.vval.v_float); \
+ break; \
+ } \
+ case kMPString: \
+ case kMPBinary: { \
+ const bool is_string = ((MessagePackType) i == kMPString); \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ size_t len; \
+ char *buf; \
+ if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \
+ &buf)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ if (is_string) { \
+ TYPVAL_ENCODE_CONV_STR_STRING(buf, len); \
+ } else { \
+ TYPVAL_ENCODE_CONV_STRING(buf, len); \
+ } \
+ xfree(buf); \
+ break; \
+ } \
+ case kMPArray: { \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, \
+ lv_copyID, kMPConvList); \
+ TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \
+ _mp_push(*mpstack, ((MPConvStackVal) { \
+ .tv = tv, \
+ .type = kMPConvList, \
+ .data = { \
+ .l = { \
+ .list = val_di->di_tv.vval.v_list, \
+ .li = val_di->di_tv.vval.v_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case kMPMap: { \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ list_T *const val_list = val_di->di_tv.vval.v_list; \
+ if (val_list == NULL || val_list->lv_len == 0) { \
+ TYPVAL_ENCODE_CONV_EMPTY_DICT(); \
+ break; \
+ } \
+ for (const listitem_T *li = val_list->lv_first; li != NULL; \
+ li = li->li_next) { \
+ if (li->li_tv.v_type != VAR_LIST \
+ || li->li_tv.vval.v_list->lv_len != 2) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ } \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \
+ kMPConvPairs); \
+ TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
+ _mp_push(*mpstack, ((MPConvStackVal) { \
+ .tv = tv, \
+ .type = kMPConvPairs, \
+ .data = { \
+ .l = { \
+ .list = val_list, \
+ .li = val_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case kMPExt: { \
+ const list_T *val_list; \
+ varnumber_T type; \
+ if (val_di->di_tv.v_type != VAR_LIST \
+ || (val_list = val_di->di_tv.vval.v_list) == NULL \
+ || val_list->lv_len != 2 \
+ || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \
+ || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \
+ || type < INT8_MIN \
+ || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ size_t len; \
+ char *buf; \
+ if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \
+ &len, &buf)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type); \
+ xfree(buf); \
+ break; \
+ } \
+ } \
+ break; \
+ } \
+name##_convert_one_value_regular_dict: \
+ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \
+ kMPConvDict); \
+ TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
+ _mp_push(*mpstack, ((MPConvStackVal) { \
+ .tv = tv, \
+ .type = kMPConvDict, \
+ .data = { \
+ .d = { \
+ .dict = tv->vval.v_dict, \
+ .hi = tv->vval.v_dict->dv_hashtab.ht_array, \
+ .todo = tv->vval.v_dict->dv_hashtab.ht_used, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case VAR_UNKNOWN: { \
+ EMSG2(_(e_intern2), #name "_convert_one_value()"); \
+ return FAIL; \
+ } \
+ } \
+ return OK; \
+} \
+\
+scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
+ const char *const objname) \
+ FUNC_ATTR_WARN_UNUSED_RESULT \
+{ \
+ const int copyID = get_copyID(); \
+ MPConvStack mpstack; \
+ _mp_init(mpstack); \
+ if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
+ == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ while (_mp_size(mpstack)) { \
+ MPConvStackVal *cur_mpsv = &_mp_last(mpstack); \
+ typval_T *cur_tv = NULL; \
+ switch (cur_mpsv->type) { \
+ case kMPConvDict: { \
+ if (!cur_mpsv->data.d.todo) { \
+ (void) _mp_pop(mpstack); \
+ cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
+ TYPVAL_ENCODE_CONV_DICT_END(); \
+ continue; \
+ } else if (cur_mpsv->data.d.todo \
+ != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \
+ TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \
+ } \
+ while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \
+ cur_mpsv->data.d.hi++; \
+ } \
+ dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \
+ cur_mpsv->data.d.todo--; \
+ cur_mpsv->data.d.hi++; \
+ TYPVAL_ENCODE_CONV_STR_STRING(&di->di_key[0], \
+ strlen((char *) &di->di_key[0])); \
+ TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \
+ cur_tv = &di->di_tv; \
+ break; \
+ } \
+ case kMPConvList: { \
+ if (cur_mpsv->data.l.li == NULL) { \
+ (void) _mp_pop(mpstack); \
+ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
+ TYPVAL_ENCODE_CONV_LIST_END(); \
+ continue; \
+ } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
+ TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); \
+ } \
+ cur_tv = &cur_mpsv->data.l.li->li_tv; \
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
+ break; \
+ } \
+ case kMPConvPairs: { \
+ if (cur_mpsv->data.l.li == NULL) { \
+ (void) _mp_pop(mpstack); \
+ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
+ TYPVAL_ENCODE_CONV_DICT_END(); \
+ continue; \
+ } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
+ TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \
+ } \
+ const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
+ TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK( \
+ encode_vim_to_##name##_error_ret, kv_pair->lv_first->li_tv); \
+ if (name##_convert_one_value(firstargname, &mpstack, \
+ &kv_pair->lv_first->li_tv, copyID, \
+ objname) == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \
+ cur_tv = &kv_pair->lv_last->li_tv; \
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
+ break; \
+ } \
+ } \
+ assert(cur_tv != NULL); \
+ if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
+ objname) == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ } \
+ _mp_destroy(mpstack); \
+ return OK; \
+encode_vim_to_##name##_error_ret: \
+ _mp_destroy(mpstack); \
+ return FAIL; \
+}
+
+#endif // NVIM_EVAL_TYPVAL_ENCODE_H
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index 8ffc0c98ce..884c987f10 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -155,7 +155,21 @@ typedef struct list_stack_S {
/// Convert a hashitem key pointer to a dictitem pointer
#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
+/// Convert a hashitem value pointer to a dictitem pointer
+#define HIVAL2DI(p) \
+ ((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv)))
+
/// Convert a hashitem pointer to a dictitem pointer
#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
+/// Type of assert_* check being performed
+typedef enum
+{
+ ASSERT_EQUAL,
+ ASSERT_NOTEQUAL,
+ ASSERT_MATCH,
+ ASSERT_NOTMATCH,
+ ASSERT_OTHER,
+} assert_type_T;
+
#endif // NVIM_EVAL_DEFS_H
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h
index b802866a3d..e5335d9f25 100644
--- a/src/nvim/event/defs.h
+++ b/src/nvim/event/defs.h
@@ -14,19 +14,19 @@ typedef struct message {
} Event;
typedef void(*event_scheduler)(Event event, void *data);
-#define VA_EVENT_INIT(event, p, h, a) \
- do { \
- assert(a <= EVENT_HANDLER_MAX_ARGC); \
- (event)->priority = p; \
- (event)->handler = h; \
- if (a) { \
- va_list args; \
- va_start(args, a); \
- for (int i = 0; i < a; i++) { \
- (event)->argv[i] = va_arg(args, void *); \
- } \
- va_end(args); \
- } \
+#define VA_EVENT_INIT(event, p, h, a) \
+ do { \
+ assert(a <= EVENT_HANDLER_MAX_ARGC); \
+ (event)->priority = p; \
+ (event)->handler = h; \
+ if (a) { \
+ va_list args; \
+ va_start(args, a); \
+ for (int i = 0; i < a; i++) { \
+ (event)->argv[i] = va_arg(args, void *); \
+ } \
+ va_end(args); \
+ } \
} while (0)
static inline Event event_create(int priority, argv_callback cb, int argc, ...)
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 9ef3468284..a68badcc8f 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -25,7 +25,7 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
}
uvproc->uvopts.exit_cb = exit_cb;
- uvproc->uvopts.cwd = NULL;
+ uvproc->uvopts.cwd = proc->cwd;
uvproc->uvopts.env = NULL;
uvproc->uvopts.stdio = uvproc->uvstdio;
uvproc->uvopts.stdio_count = 3;
diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h
index 0c1fcb5ed9..407aa4245f 100644
--- a/src/nvim/event/loop.h
+++ b/src/nvim/event/loop.h
@@ -26,43 +26,43 @@ typedef struct loop {
int recursive;
} Loop;
-#define CREATE_EVENT(queue, handler, argc, ...) \
- do { \
- if (queue) { \
- queue_put((queue), (handler), argc, __VA_ARGS__); \
- } else { \
- void *argv[argc] = {__VA_ARGS__}; \
- (handler)(argv); \
- } \
+#define CREATE_EVENT(queue, handler, argc, ...) \
+ do { \
+ if (queue) { \
+ queue_put((queue), (handler), argc, __VA_ARGS__); \
+ } else { \
+ void *argv[argc] = { __VA_ARGS__ }; \
+ (handler)(argv); \
+ } \
} while (0)
// Poll for events until a condition or timeout
-#define LOOP_PROCESS_EVENTS_UNTIL(loop, queue, timeout, condition) \
- do { \
- int remaining = timeout; \
- uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
- while (!(condition)) { \
- LOOP_PROCESS_EVENTS(loop, queue, remaining); \
- if (remaining == 0) { \
- break; \
- } else if (remaining > 0) { \
- uint64_t now = os_hrtime(); \
- remaining -= (int) ((now - before) / 1000000); \
- before = now; \
- if (remaining <= 0) { \
- break; \
- } \
- } \
- } \
+#define LOOP_PROCESS_EVENTS_UNTIL(loop, queue, timeout, condition) \
+ do { \
+ int remaining = timeout; \
+ uint64_t before = (remaining > 0) ? os_hrtime() : 0; \
+ while (!(condition)) { \
+ LOOP_PROCESS_EVENTS(loop, queue, remaining); \
+ if (remaining == 0) { \
+ break; \
+ } else if (remaining > 0) { \
+ uint64_t now = os_hrtime(); \
+ remaining -= (int) ((now - before) / 1000000); \
+ before = now; \
+ if (remaining <= 0) { \
+ break; \
+ } \
+ } \
+ } \
} while (0)
-#define LOOP_PROCESS_EVENTS(loop, queue, timeout) \
- do { \
- if (queue && !queue_empty(queue)) { \
- queue_process_events(queue); \
- } else { \
- loop_poll_events(loop, timeout); \
- } \
+#define LOOP_PROCESS_EVENTS(loop, queue, timeout) \
+ do { \
+ if (queue && !queue_empty(queue)) { \
+ queue_process_events(queue); \
+ } else { \
+ loop_poll_events(loop, timeout); \
+ } \
} while (0)
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 9bb62891c7..317e40e43a 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -9,7 +9,7 @@
#include "nvim/event/wstream.h"
#include "nvim/event/process.h"
#include "nvim/event/libuv_process.h"
-#include "nvim/event/pty_process.h"
+#include "nvim/os/pty_process.h"
#include "nvim/globals.h"
#include "nvim/log.h"
@@ -22,11 +22,11 @@
#define TERM_TIMEOUT 1000000000
#define KILL_TIMEOUT (TERM_TIMEOUT * 2)
-#define CLOSE_PROC_STREAM(proc, stream) \
- do { \
- if (proc->stream && !proc->stream->closed) { \
- stream_close(proc->stream, NULL); \
- } \
+#define CLOSE_PROC_STREAM(proc, stream) \
+ do { \
+ if (proc->stream && !proc->stream->closed) { \
+ stream_close(proc->stream, NULL); \
+ } \
} while (0)
static bool process_is_tearing_down = false;
@@ -116,23 +116,20 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
process_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
- if (proc->detach) {
+ if (proc->detach || proc->type == kProcessTypePty) {
// Close handles to process without killing it.
CREATE_EVENT(loop->events, process_close_handles, 1, proc);
} else {
- if (proc->type == kProcessTypeUv) {
- uv_kill(proc->pid, SIGTERM);
- proc->term_sent = true;
- process_stop(proc);
- } else { // kProcessTypePty
- process_close_streams(proc);
- pty_process_close_master((PtyProcess *)proc);
- }
+ uv_kill(proc->pid, SIGTERM);
+ proc->term_sent = true;
+ process_stop(proc);
}
}
- // Wait until all children exit
- LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, kl_empty(loop->children));
+ // Wait until all children exit and all close events are processed.
+ LOOP_PROCESS_EVENTS_UNTIL(
+ loop, loop->events, -1,
+ kl_empty(loop->children) && queue_empty(loop->events));
pty_process_teardown(loop);
}
@@ -315,8 +312,10 @@ static void decref(Process *proc)
static void process_close(Process *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
- if (process_is_tearing_down && proc->detach && proc->closed) {
- // If a detached process dies while tearing down it might get closed twice.
+ if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty)
+ && proc->closed) {
+ // If a detached/pty process dies while tearing down it might get closed
+ // twice.
return;
}
assert(!proc->closed);
@@ -333,9 +332,61 @@ static void process_close(Process *proc)
}
}
+/// Flush output stream.
+///
+/// @param proc Process, for which an output stream should be flushed.
+/// @param stream Stream to flush.
+static void flush_stream(Process *proc, Stream *stream)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (!stream || stream->closed) {
+ return;
+ }
+
+ // Maximal remaining data size of terminated process is system
+ // buffer size.
+ // Also helps with a child process that keeps the output streams open. If it
+ // keeps sending data, we only accept as much data as the system buffer size.
+ // Otherwise this would block cleanup/teardown.
+ int system_buffer_size = 0;
+ int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe,
+ &system_buffer_size);
+ if (err) {
+ system_buffer_size = (int)rbuffer_capacity(stream->buffer);
+ }
+
+ size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size;
+
+ // Read remaining data.
+ while (!stream->closed && stream->num_bytes < max_bytes) {
+ // Remember number of bytes before polling
+ size_t num_bytes = stream->num_bytes;
+
+ // Poll for data and process the generated events.
+ loop_poll_events(proc->loop, 0);
+ if (proc->events) {
+ queue_process_events(proc->events);
+ }
+
+ // Stream can be closed if it is empty.
+ if (num_bytes == stream->num_bytes) {
+ if (stream->read_cb) {
+ // Stream callback could miss EOF handling if a child keeps the stream
+ // open.
+ stream->read_cb(stream, stream->buffer, 0, stream->data, true);
+ }
+ break;
+ }
+ }
+}
+
static void process_close_handles(void **argv)
{
Process *proc = argv[0];
+
+ flush_stream(proc, proc->out);
+ flush_stream(proc, proc->err);
+
process_close_streams(proc);
process_close(proc);
}
@@ -350,11 +401,12 @@ static void on_process_exit(Process *proc)
uv_timer_stop(&loop->children_kill_timer);
}
- // Process handles are closed in the next event loop tick. This is done to
- // give libuv more time to read data from the OS after the process exits(If
- // process_close_streams is called with data still in the OS buffer, we lose
- // it)
- CREATE_EVENT(proc->events, process_close_handles, 1, proc);
+ // Process has terminated, but there could still be data to be read from the
+ // OS. We are still in the libuv loop, so we cannot call code that polls for
+ // more data directly. Instead delay the reading after the libuv loop by
+ // queueing process_close_handles() as an event.
+ Queue *queue = proc->events ? proc->events : loop->events;
+ CREATE_EVENT(queue, process_close_handles, 1, proc);
}
static void on_process_stream_close(Stream *stream, void *data)
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index e23c8ea60f..a4c6e7eeb2 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -21,6 +21,7 @@ struct process {
int pid, status, refcount;
// set to the hrtime of when process_stop was called for the process.
uint64_t stopped_time;
+ char *cwd;
char **argv;
Stream *in, *out, *err;
process_exit_cb cb;
@@ -40,6 +41,7 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.status = 0,
.refcount = 0,
.stopped_time = 0,
+ .cwd = NULL,
.argv = NULL,
.in = NULL,
.out = NULL,
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 9f3fbc25ff..a520143064 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -100,6 +100,10 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
{
Stream *stream = uvstream->data;
+ if (cnt > 0) {
+ stream->num_bytes += (size_t)cnt;
+ }
+
if (cnt <= 0) {
if (cnt != UV_ENOBUFS
// cnt == 0 means libuv asked for a buffer and decided it wasn't needed:
@@ -185,10 +189,6 @@ static void read_event(void **argv)
static void invoke_read_cb(Stream *stream, size_t count, bool eof)
{
- if (stream->closed) {
- return;
- }
-
// Don't let the stream be closed before the event is processed.
stream->pending_reqs++;
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 93cc592683..cdaf40849b 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -103,7 +103,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
// Libuv converts ENOENT to EACCES for Windows compatibility, but if
// the parent directory does not exist, ENOENT would be more accurate.
*path_tail((char_u *)watcher->addr) = NUL;
- if (!os_file_exists((char_u *)watcher->addr)) {
+ if (!os_path_exists((char_u *)watcher->addr)) {
result = -ENOENT;
}
}
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 71582ab357..33404158cf 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -71,6 +71,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream,
stream->closed = false;
stream->buffer = NULL;
stream->events = NULL;
+ stream->num_bytes = 0;
}
void stream_close(Stream *stream, stream_close_cb on_stream_close)
diff --git a/src/nvim/event/stream.h b/src/nvim/event/stream.h
index c6baac0db7..ad4e24775b 100644
--- a/src/nvim/event/stream.h
+++ b/src/nvim/event/stream.h
@@ -49,6 +49,7 @@ struct stream {
size_t curmem;
size_t maxmem;
size_t pending_reqs;
+ size_t num_bytes;
void *data, *internal_data;
bool closed;
Queue *events;
diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c
index 7bf333bcea..f68a66345f 100644
--- a/src/nvim/event/time.c
+++ b/src/nvim/event/time.c
@@ -17,6 +17,7 @@ void time_watcher_init(Loop *loop, TimeWatcher *watcher, void *data)
watcher->uv.data = watcher;
watcher->data = data;
watcher->events = loop->fast_events;
+ watcher->blockable = false;
}
void time_watcher_start(TimeWatcher *watcher, time_cb cb, uint64_t timeout,
@@ -50,6 +51,10 @@ static void time_watcher_cb(uv_timer_t *handle)
FUNC_ATTR_NONNULL_ALL
{
TimeWatcher *watcher = handle->data;
+ if (watcher->blockable && !queue_empty(watcher->events)) {
+ // the timer blocked and there already is an unprocessed event waiting
+ return;
+ }
CREATE_EVENT(watcher->events, time_event, 1, watcher);
}
diff --git a/src/nvim/event/time.h b/src/nvim/event/time.h
index 7882b2b627..14df176ea3 100644
--- a/src/nvim/event/time.h
+++ b/src/nvim/event/time.h
@@ -13,6 +13,7 @@ struct time_watcher {
void *data;
time_cb cb, close_cb;
Queue *events;
+ bool blockable;
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 86f1a16216..5de9ac0523 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1745,14 +1745,14 @@ check_overwrite (
* write to other file or b_flags set or not writing the whole file:
* overwriting only allowed with '!'
*/
- if ( (other
- || (buf->b_flags & BF_NOTEDITED)
- || ((buf->b_flags & BF_NEW)
- && vim_strchr(p_cpo, CPO_OVERNEW) == NULL)
- || (buf->b_flags & BF_READERR))
- && !p_wa
- && !bt_nofile(buf)
- && os_file_exists(ffname)) {
+ if ((other
+ || (buf->b_flags & BF_NOTEDITED)
+ || ((buf->b_flags & BF_NEW)
+ && vim_strchr(p_cpo, CPO_OVERNEW) == NULL)
+ || (buf->b_flags & BF_READERR))
+ && !p_wa
+ && !bt_nofile(buf)
+ && os_path_exists(ffname)) {
if (!eap->forceit && !eap->append) {
#ifdef UNIX
// It is possible to open a directory on Unix.
@@ -1795,7 +1795,7 @@ check_overwrite (
}
swapname = makeswapname(fname, ffname, curbuf, dir);
xfree(dir);
- if (os_file_exists(swapname)) {
+ if (os_path_exists(swapname)) {
if (p_confirm || cmdmod.confirm) {
char_u buff[DIALOG_MSG_SIZE];
@@ -1909,7 +1909,7 @@ static int check_readonly(int *forceit, buf_T *buf)
/* Handle a file being readonly when the 'readonly' option is set or when
* the file exists and permissions are read-only. */
if (!*forceit && (buf->b_p_ro
- || (os_file_exists(buf->b_ffname)
+ || (os_path_exists(buf->b_ffname)
&& !os_file_is_writable((char *)buf->b_ffname)))) {
if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL) {
char_u buff[DIALOG_MSG_SIZE];
@@ -4796,122 +4796,15 @@ void ex_viusage(exarg_T *eap)
}
-/*
- * ":helptags"
- */
-void ex_helptags(exarg_T *eap)
-{
- garray_T ga;
- int len;
- char_u lang[2];
- expand_T xpc;
- char_u *dirname;
- char_u ext[5];
- char_u fname[8];
- int filecount;
- char_u **files;
- int add_help_tags = FALSE;
-
- /* Check for ":helptags ++t {dir}". */
- if (STRNCMP(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) {
- add_help_tags = TRUE;
- eap->arg = skipwhite(eap->arg + 3);
- }
-
- ExpandInit(&xpc);
- xpc.xp_context = EXPAND_DIRECTORIES;
- dirname = ExpandOne(&xpc, eap->arg, NULL,
- WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
- if (dirname == NULL || !os_isdir(dirname)) {
- EMSG2(_("E150: Not a directory: %s"), eap->arg);
- xfree(dirname);
- return;
- }
-
- /* Get a list of all files in the help directory and in subdirectories. */
- STRCPY(NameBuff, dirname);
- add_pathsep((char *)NameBuff);
- STRCAT(NameBuff, "**");
-
- // Note: We cannot just do `&NameBuff` because it is a statically sized array
- // so `NameBuff == &NameBuff` according to C semantics.
- char_u *buff_list[1] = {NameBuff};
- if (gen_expand_wildcards(1, buff_list, &filecount, &files,
- EW_FILE|EW_SILENT) == FAIL
- || filecount == 0) {
- EMSG2("E151: No match: %s", NameBuff);
- xfree(dirname);
- return;
- }
-
- /* Go over all files in the directory to find out what languages are
- * present. */
- ga_init(&ga, 1, 10);
- for (int i = 0; i < filecount; ++i) {
- len = (int)STRLEN(files[i]);
- if (len <= 4) {
- continue;
- }
- if (STRICMP(files[i] + len - 4, ".txt") == 0) {
- /* ".txt" -> language "en" */
- lang[0] = 'e';
- lang[1] = 'n';
- } else if (files[i][len - 4] == '.'
- && ASCII_ISALPHA(files[i][len - 3])
- && ASCII_ISALPHA(files[i][len - 2])
- && TOLOWER_ASC(files[i][len - 1]) == 'x') {
- /* ".abx" -> language "ab" */
- lang[0] = TOLOWER_ASC(files[i][len - 3]);
- lang[1] = TOLOWER_ASC(files[i][len - 2]);
- } else
- continue;
-
- int j;
- /* Did we find this language already? */
- for (j = 0; j < ga.ga_len; j += 2)
- if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0)
- break;
- if (j == ga.ga_len) {
- /* New language, add it. */
- ga_grow(&ga, 2);
- ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
- ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
- }
- }
-
- /*
- * Loop over the found languages to generate a tags file for each one.
- */
- for (int j = 0; j < ga.ga_len; j += 2) {
- STRCPY(fname, "tags-xx");
- fname[5] = ((char_u *)ga.ga_data)[j];
- fname[6] = ((char_u *)ga.ga_data)[j + 1];
- if (fname[5] == 'e' && fname[6] == 'n') {
- /* English is an exception: use ".txt" and "tags". */
- fname[4] = NUL;
- STRCPY(ext, ".txt");
- } else {
- /* Language "ab" uses ".abx" and "tags-ab". */
- STRCPY(ext, ".xxx");
- ext[1] = fname[5];
- ext[2] = fname[6];
- }
- helptags_one(dirname, ext, fname, add_help_tags);
- }
-
- ga_clear(&ga);
- FreeWild(filecount, files);
-
- xfree(dirname);
-}
-
-static void
-helptags_one (
- char_u *dir, /* doc directory */
- char_u *ext, /* suffix, ".txt", ".itx", ".frx", etc. */
- char_u *tagfname, /* "tags" for English, "tags-fr" for French. */
- int add_help_tags /* add "help-tags" tag */
-)
+/// Generate tags in one help directory
+///
+/// @param dir Path to the doc directory
+/// @param ext Suffix of the help files (".txt", ".itx", ".frx", etc.)
+/// @param tagname Name of the tags file ("tags" for English, "tags-fr" for
+/// French)
+/// @param add_help_tags Whether to add the "help-tags" tag
+static void helptags_one(char_u *dir, char_u *ext, char_u *tagfname,
+ bool add_help_tags)
{
FILE *fd_tags;
FILE *fd;
@@ -4928,9 +4821,8 @@ helptags_one (
int mix = FALSE; /* detected mixed encodings */
// Find all *.txt files.
- size_t dirlen = STRLEN(dir);
- STRCPY(NameBuff, dir);
- STRCAT(NameBuff, "/**/*");
+ size_t dirlen = STRLCPY(NameBuff, dir, sizeof(NameBuff));
+ STRCAT(NameBuff, "/**/*"); // NOLINT
STRCAT(NameBuff, ext);
// Note: We cannot just do `&NameBuff` because it is a statically sized array
@@ -4948,7 +4840,7 @@ helptags_one (
* Open the tags file for writing.
* Do this before scanning through all the files.
*/
- STRCPY(NameBuff, dir);
+ STRLCPY(NameBuff, dir, sizeof(NameBuff));
add_pathsep((char *)NameBuff);
STRNCAT(NameBuff, tagfname, sizeof(NameBuff) - dirlen - 2);
fd_tags = mch_fopen((char *)NameBuff, "w");
@@ -5111,6 +5003,132 @@ helptags_one (
fclose(fd_tags); /* there is no check for an error... */
}
+/// Generate tags in one help directory, taking care of translations.
+static void do_helptags(char_u *dirname, bool add_help_tags)
+{
+ int len;
+ garray_T ga;
+ char_u lang[2];
+ char_u ext[5];
+ char_u fname[8];
+ int filecount;
+ char_u **files;
+
+ // Get a list of all files in the help directory and in subdirectories.
+ STRLCPY(NameBuff, dirname, sizeof(NameBuff));
+ add_pathsep((char *)NameBuff);
+ STRCAT(NameBuff, "**");
+
+ // Note: We cannot just do `&NameBuff` because it is a statically sized array
+ // so `NameBuff == &NameBuff` according to C semantics.
+ char_u *buff_list[1] = {NameBuff};
+ if (gen_expand_wildcards(1, buff_list, &filecount, &files,
+ EW_FILE|EW_SILENT) == FAIL
+ || filecount == 0) {
+ EMSG2("E151: No match: %s", NameBuff);
+ xfree(dirname);
+ return;
+ }
+
+ /* Go over all files in the directory to find out what languages are
+ * present. */
+ int j;
+ ga_init(&ga, 1, 10);
+ for (int i = 0; i < filecount; i++) {
+ len = (int)STRLEN(files[i]);
+ if (len <= 4) {
+ continue;
+ }
+ if (STRICMP(files[i] + len - 4, ".txt") == 0) {
+ /* ".txt" -> language "en" */
+ lang[0] = 'e';
+ lang[1] = 'n';
+ } else if (files[i][len - 4] == '.'
+ && ASCII_ISALPHA(files[i][len - 3])
+ && ASCII_ISALPHA(files[i][len - 2])
+ && TOLOWER_ASC(files[i][len - 1]) == 'x') {
+ /* ".abx" -> language "ab" */
+ lang[0] = TOLOWER_ASC(files[i][len - 3]);
+ lang[1] = TOLOWER_ASC(files[i][len - 2]);
+ } else
+ continue;
+
+ // Did we find this language already?
+ for (j = 0; j < ga.ga_len; j += 2) {
+ if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) {
+ break;
+ }
+ }
+ if (j == ga.ga_len) {
+ // New language, add it.
+ ga_grow(&ga, 2);
+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
+ }
+ }
+
+ /*
+ * Loop over the found languages to generate a tags file for each one.
+ */
+ for (j = 0; j < ga.ga_len; j += 2) {
+ STRCPY(fname, "tags-xx");
+ fname[5] = ((char_u *)ga.ga_data)[j];
+ fname[6] = ((char_u *)ga.ga_data)[j + 1];
+ if (fname[5] == 'e' && fname[6] == 'n') {
+ /* English is an exception: use ".txt" and "tags". */
+ fname[4] = NUL;
+ STRCPY(ext, ".txt");
+ } else {
+ /* Language "ab" uses ".abx" and "tags-ab". */
+ STRCPY(ext, ".xxx");
+ ext[1] = fname[5];
+ ext[2] = fname[6];
+ }
+ helptags_one(dirname, ext, fname, add_help_tags);
+ }
+
+ ga_clear(&ga);
+ FreeWild(filecount, files);
+}
+
+ static void
+helptags_cb(char_u *fname, void *cookie)
+{
+ do_helptags(fname, *(bool *)cookie);
+}
+
+/*
+ * ":helptags"
+ */
+void ex_helptags(exarg_T *eap)
+{
+ expand_T xpc;
+ char_u *dirname;
+ bool add_help_tags = false;
+
+ /* Check for ":helptags ++t {dir}". */
+ if (STRNCMP(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) {
+ add_help_tags = true;
+ eap->arg = skipwhite(eap->arg + 3);
+ }
+
+ if (STRCMP(eap->arg, "ALL") == 0) {
+ do_in_path(p_rtp, (char_u *)"doc", DIP_ALL + DIP_DIR,
+ helptags_cb, &add_help_tags);
+ } else {
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_DIRECTORIES;
+ dirname = ExpandOne(&xpc, eap->arg, NULL,
+ WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
+ if (dirname == NULL || !os_isdir(dirname)) {
+ EMSG2(_("E150: Not a directory: %s"), eap->arg);
+ } else {
+ do_helptags(dirname, add_help_tags);
+ }
+ xfree(dirname);
+ }
+}
+
struct sign
{
sign_T *sn_next; /* next sign in list */
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 04fd88cc8d..3f5d9b3244 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -88,7 +88,7 @@ return {
},
{
command='argadd',
- flags=bit.bor(BANG, NEEDARG, RANGE, NOTADR, ZEROR, FILES, TRLBAR),
+ flags=bit.bor(BANG, RANGE, NOTADR, ZEROR, FILES, TRLBAR),
addr_type=ADDR_ARGUMENTS,
func='ex_argadd',
},
@@ -1849,6 +1849,18 @@ return {
func='ex_print',
},
{
+ command='packadd',
+ flags=bit.bor(BANG, FILE1, NEEDARG, TRLBAR, SBOXOK, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_packadd',
+ },
+ {
+ command='packloadall',
+ flags=bit.bor(BANG, TRLBAR, SBOXOK, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_packloadall',
+ },
+ {
command='pclose',
flags=bit.bor(BANG, TRLBAR),
addr_type=ADDR_LINES,
@@ -2158,19 +2170,19 @@ return {
command='ruby',
flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_script_ni',
+ func='ex_ruby',
},
{
command='rubydo',
flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_ni',
+ func='ex_rubydo',
},
{
command='rubyfile',
flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_ni',
+ func='ex_rubyfile',
},
{
command='rviminfo',
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 5fe6209a0a..6d24ba91f2 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1,6 +1,6 @@
-/*
- * ex_cmds2.c: some more functions for command line commands
- */
+/// @file ex_cmds2.c
+///
+/// Some more functions for command line commands
#include <assert.h>
#include <inttypes.h>
@@ -50,15 +50,15 @@
#include "nvim/api/private/defs.h"
-/* Growarray to store info about already sourced scripts.
- * Also store the dev/ino, so that we don't have to stat() each
- * script when going through the list. */
+/// Growarray to store info about already sourced scripts.
+/// Also store the dev/ino, so that we don't have to stat() each
+/// script when going through the list.
typedef struct scriptitem_S {
char_u *sn_name;
bool file_id_valid;
FileID file_id;
bool sn_prof_on; ///< true when script is/was profiled
- int sn_pr_force; ///< forceit: profile functions in this script
+ bool sn_pr_force; ///< forceit: profile functions in this script
proftime_T sn_pr_child; ///< time set when going into first child
int sn_pr_nest; ///< nesting for sn_pr_child
// profiling the script as a whole
@@ -76,29 +76,27 @@ typedef struct scriptitem_S {
int sn_prl_execed; ///< line being timed was executed
} scriptitem_T;
-static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
+static garray_T script_items = { 0, 0, sizeof(scriptitem_T), 4, NULL };
#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
-/* Struct used in sn_prl_ga for every line of a script. */
+// Struct used in sn_prl_ga for every line of a script.
typedef struct sn_prl_S {
int snp_count; ///< nr of times line was executed
proftime_T sn_prl_total; ///< time spent in a line + children
proftime_T sn_prl_self; ///< time spent in a line itself
} sn_prl_T;
-/*
- * Structure used to store info for each sourced file.
- * It is shared between do_source() and getsourceline().
- * This is required, because it needs to be handed to do_cmdline() and
- * sourcing can be done recursively.
- */
+/// Structure used to store info for each sourced file.
+/// It is shared between do_source() and getsourceline().
+/// This is required, because it needs to be handed to do_cmdline() and
+/// sourcing can be done recursively.
struct source_cookie {
FILE *fp; ///< opened file for sourcing
char_u *nextline; ///< if not NULL: line that was read ahead
int finished; ///< ":finish" used
#if defined(USE_CRNL)
int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
- int error; ///< TRUE if LF found after CR-LF
+ bool error; ///< true if LF found after CR-LF
#endif
linenr_T breakpoint; ///< next line with breakpoint or zero
char_u *fname; ///< name of sourced file
@@ -113,13 +111,11 @@ struct source_cookie {
# include "ex_cmds2.c.generated.h"
#endif
-static int debug_greedy = FALSE; /* batch mode debugging: don't save
- and restore typeahead. */
+/// batch mode debugging: don't save and restore typeahead.
+static bool debug_greedy = false;
-/*
- * do_debug(): Debug mode.
- * Repeatedly get Ex commands, until told to continue normal execution.
- */
+/// Debug mode. Repeatedly get Ex commands, until told to continue normal
+/// execution.
void do_debug(char_u *cmd)
{
int save_msg_scroll = msg_scroll;
@@ -130,7 +126,7 @@ void do_debug(char_u *cmd)
int save_emsg_silent = emsg_silent;
int save_redir_off = redir_off;
tasave_T typeaheadbuf;
- int typeahead_saved = FALSE;
+ bool typeahead_saved = false;
int save_ignore_script = 0;
int save_ex_normal_busy;
int n;
@@ -150,43 +146,44 @@ void do_debug(char_u *cmd)
#define CMD_DOWN 10
- ++RedrawingDisabled; /* don't redisplay the window */
- ++no_wait_return; /* don't wait for return */
- did_emsg = FALSE; /* don't use error from debugged stuff */
- cmd_silent = FALSE; /* display commands */
- msg_silent = FALSE; /* display messages */
- emsg_silent = FALSE; /* display error messages */
- redir_off = TRUE; /* don't redirect debug commands */
+ RedrawingDisabled++; // don't redisplay the window
+ no_wait_return++; // don't wait for return
+ did_emsg = false; // don't use error from debugged stuff
+ cmd_silent = false; // display commands
+ msg_silent = false; // display messages
+ emsg_silent = false; // display error messages
+ redir_off = true; // don't redirect debug commands
State = NORMAL;
- if (!debug_did_msg)
+ if (!debug_did_msg) {
MSG(_("Entering Debug mode. Type \"cont\" to continue."));
- if (sourcing_name != NULL)
+ }
+ if (sourcing_name != NULL) {
msg(sourcing_name);
- if (sourcing_lnum != 0)
+ }
+ if (sourcing_lnum != 0) {
smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
- else
+ } else {
smsg(_("cmd: %s"), cmd);
+ }
- /*
- * Repeat getting a command and executing it.
- */
+ // Repeat getting a command and executing it.
for (;; ) {
- msg_scroll = TRUE;
- need_wait_return = FALSE;
- /* Save the current typeahead buffer and replace it with an empty one.
- * This makes sure we get input from the user here and don't interfere
- * with the commands being executed. Reset "ex_normal_busy" to avoid
- * the side effects of using ":normal". Save the stuff buffer and make
- * it empty. Set ignore_script to avoid reading from script input. */
+ msg_scroll = true;
+ need_wait_return = false;
+ // Save the current typeahead buffer and replace it with an empty one.
+ // This makes sure we get input from the user here and don't interfere
+ // with the commands being executed. Reset "ex_normal_busy" to avoid
+ // the side effects of using ":normal". Save the stuff buffer and make
+ // it empty. Set ignore_script to avoid reading from script input.
save_ex_normal_busy = ex_normal_busy;
ex_normal_busy = 0;
if (!debug_greedy) {
save_typeahead(&typeaheadbuf);
- typeahead_saved = TRUE;
+ typeahead_saved = true;
save_ignore_script = ignore_script;
- ignore_script = TRUE;
+ ignore_script = true;
}
xfree(cmdline);
@@ -201,9 +198,9 @@ void do_debug(char_u *cmd)
cmdline_row = msg_row;
msg_starthere();
if (cmdline != NULL) {
- /* If this is a debug command, set "last_cmd".
- * If not, reset "last_cmd".
- * For a blank line use previous command. */
+ // If this is a debug command, set "last_cmd".
+ // If not, reset "last_cmd".
+ // For a blank line use previous command.
p = skipwhite(cmdline);
if (*p != NUL) {
switch (*p) {
@@ -255,11 +252,11 @@ void do_debug(char_u *cmd)
default: last_cmd = 0;
}
if (last_cmd != 0) {
- /* Check that the tail matches. */
- ++p;
+ // Check that the tail matches.
+ p++;
while (*p != NUL && *p == *tail) {
- ++p;
- ++tail;
+ p++;
+ tail++;
}
if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {
last_cmd = 0;
@@ -268,8 +265,7 @@ void do_debug(char_u *cmd)
}
if (last_cmd != 0) {
- /* Execute debug command: decided where to break next and
- * return. */
+ // Execute debug command: decided where to break next and return.
switch (last_cmd) {
case CMD_CONT:
debug_break_level = -1;
@@ -284,13 +280,13 @@ void do_debug(char_u *cmd)
debug_break_level = ex_nesting_level - 1;
break;
case CMD_QUIT:
- got_int = TRUE;
+ got_int = true;
debug_break_level = -1;
break;
case CMD_INTERRUPT:
- got_int = TRUE;
+ got_int = true;
debug_break_level = 9999;
- /* Do not repeat ">interrupt" cmd, continue stepping. */
+ // Do not repeat ">interrupt" cmd, continue stepping.
last_cmd = CMD_STEP;
break;
case CMD_BACKTRACE:
@@ -318,21 +314,21 @@ void do_debug(char_u *cmd)
break;
}
- /* don't debug this command */
+ // don't debug this command
n = debug_break_level;
debug_break_level = -1;
(void)do_cmdline(cmdline, getexline, NULL,
- DOCMD_VERBOSE|DOCMD_EXCRESET);
+ DOCMD_VERBOSE|DOCMD_EXCRESET);
debug_break_level = n;
}
lines_left = (int)(Rows - 1);
}
xfree(cmdline);
- --RedrawingDisabled;
- --no_wait_return;
+ RedrawingDisabled--;
+ no_wait_return--;
redraw_all_later(NOT_VALID);
- need_wait_return = FALSE;
+ need_wait_return = false;
msg_scroll = save_msg_scroll;
lines_left = (int)(Rows - 1);
State = save_State;
@@ -342,9 +338,8 @@ void do_debug(char_u *cmd)
emsg_silent = save_emsg_silent;
redir_off = save_redir_off;
- /* Only print the message again when typing a command before coming back
- * here. */
- debug_did_msg = TRUE;
+ // Only print the message again when typing a command before coming back here.
+ debug_did_msg = true;
}
static int get_maxbacktrace_level(void)
@@ -419,9 +414,8 @@ static void do_showbacktrace(char_u *cmd)
}
}
-/*
- * ":debug".
- */
+
+/// ":debug".
void ex_debug(exarg_T *eap)
{
int debug_break_level_save = debug_break_level;
@@ -434,88 +428,81 @@ void ex_debug(exarg_T *eap)
static char_u *debug_breakpoint_name = NULL;
static linenr_T debug_breakpoint_lnum;
-/*
- * When debugging or a breakpoint is set on a skipped command, no debug prompt
- * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
- * debug_skipped_name is then set to the source name in the breakpoint case. If
- * a skipped command decides itself that a debug prompt should be displayed, it
- * can do so by calling dbg_check_skipped().
- */
+/// When debugging or a breakpoint is set on a skipped command, no debug prompt
+/// is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
+/// debug_skipped_name is then set to the source name in the breakpoint case. If
+/// a skipped command decides itself that a debug prompt should be displayed, it
+/// can do so by calling dbg_check_skipped().
static int debug_skipped;
static char_u *debug_skipped_name;
-/*
- * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
- * at or below the break level. But only when the line is actually
- * executed. Return TRUE and set breakpoint_name for skipped commands that
- * decide to execute something themselves.
- * Called from do_one_cmd() before executing a command.
- */
+/// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
+/// at or below the break level. But only when the line is actually
+/// executed. Return true and set breakpoint_name for skipped commands that
+/// decide to execute something themselves.
+/// Called from do_one_cmd() before executing a command.
void dbg_check_breakpoint(exarg_T *eap)
{
char_u *p;
- debug_skipped = FALSE;
+ debug_skipped = false;
if (debug_breakpoint_name != NULL) {
if (!eap->skip) {
- /* replace K_SNR with "<SNR>" */
+ // replace K_SNR with "<SNR>"
if (debug_breakpoint_name[0] == K_SPECIAL
&& debug_breakpoint_name[1] == KS_EXTRA
- && debug_breakpoint_name[2] == (int)KE_SNR)
+ && debug_breakpoint_name[2] == (int)KE_SNR) {
p = (char_u *)"<SNR>";
- else
+ } else {
p = (char_u *)"";
+ }
smsg(_("Breakpoint in \"%s%s\" line %" PRId64),
- p,
- debug_breakpoint_name + (*p == NUL ? 0 : 3),
- (int64_t)debug_breakpoint_lnum);
+ p,
+ debug_breakpoint_name + (*p == NUL ? 0 : 3),
+ (int64_t)debug_breakpoint_lnum);
debug_breakpoint_name = NULL;
do_debug(eap->cmd);
} else {
- debug_skipped = TRUE;
+ debug_skipped = true;
debug_skipped_name = debug_breakpoint_name;
debug_breakpoint_name = NULL;
}
} else if (ex_nesting_level <= debug_break_level) {
- if (!eap->skip)
+ if (!eap->skip) {
do_debug(eap->cmd);
- else {
- debug_skipped = TRUE;
+ } else {
+ debug_skipped = true;
debug_skipped_name = NULL;
}
}
}
-/*
- * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
- * set. Return TRUE when the debug mode is entered this time.
- */
-int dbg_check_skipped(exarg_T *eap)
+/// Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
+/// set.
+///
+/// @return true when the debug mode is entered this time.
+bool dbg_check_skipped(exarg_T *eap)
{
int prev_got_int;
if (debug_skipped) {
- /*
- * Save the value of got_int and reset it. We don't want a previous
- * interruption cause flushing the input buffer.
- */
+ // Save the value of got_int and reset it. We don't want a previous
+ // interruption cause flushing the input buffer.
prev_got_int = got_int;
- got_int = FALSE;
+ got_int = false;
debug_breakpoint_name = debug_skipped_name;
- /* eap->skip is TRUE */
- eap->skip = FALSE;
+ // eap->skip is true
+ eap->skip = false;
dbg_check_breakpoint(eap);
- eap->skip = TRUE;
+ eap->skip = true;
got_int |= prev_got_int;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-/*
- * The list of breakpoints: dbg_breakp.
- * This is a grow-array of structs.
- */
+/// The list of breakpoints: dbg_breakp.
+/// This is a grow-array of structs.
struct debuggy {
int dbg_nr; ///< breakpoint number
int dbg_type; ///< DBG_FUNC or DBG_FILE
@@ -525,33 +512,30 @@ struct debuggy {
int dbg_forceit; ///< ! used
};
-static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
+static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL };
#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
-static int last_breakp = 0; /* nr of last defined breakpoint */
+static int last_breakp = 0; // nr of last defined breakpoint
-/* Profiling uses file and func names similar to breakpoints. */
-static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
+// Profiling uses file and func names similar to breakpoints.
+static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL };
#define DBG_FUNC 1
#define DBG_FILE 2
-/*
- * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
- * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
- * is allocated.
- * Returns FAIL for failure.
- */
-static int
-dbg_parsearg (
- char_u *arg,
- garray_T *gap /* either &dbg_breakp or &prof_ga */
-)
+/// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
+/// in the entry just after the last one in dbg_breakp. Note that "dbg_name"
+/// is allocated.
+/// Returns FAIL for failure.
+///
+/// @param arg
+/// @param gap either &dbg_breakp or &prof_ga
+static int dbg_parsearg(char_u *arg, garray_T *gap)
{
char_u *p = arg;
char_u *q;
struct debuggy *bp;
- int here = FALSE;
+ bool here = false;
ga_grow(gap, 1);
@@ -568,7 +552,7 @@ dbg_parsearg (
return FAIL;
}
bp->dbg_type = DBG_FILE;
- here = TRUE;
+ here = true;
} else {
EMSG2(_(e_invarg2), p);
return FAIL;
@@ -585,7 +569,7 @@ dbg_parsearg (
bp->dbg_lnum = 0;
}
- /* Find the function or file name. Don't accept a function name with (). */
+ // Find the function or file name. Don't accept a function name with ().
if ((!here && *p == NUL)
|| (here && *p != NUL)
|| (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) {
@@ -593,36 +577,38 @@ dbg_parsearg (
return FAIL;
}
- if (bp->dbg_type == DBG_FUNC)
+ if (bp->dbg_type == DBG_FUNC) {
bp->dbg_name = vim_strsave(p);
- else if (here)
+ } else if (here) {
bp->dbg_name = vim_strsave(curbuf->b_ffname);
- else {
- /* Expand the file name in the same way as do_source(). This means
- * doing it twice, so that $DIR/file gets expanded when $DIR is
- * "~/dir". */
+ } else {
+ // Expand the file name in the same way as do_source(). This means
+ // doing it twice, so that $DIR/file gets expanded when $DIR is
+ // "~/dir".
q = expand_env_save(p);
- if (q == NULL)
+ if (q == NULL) {
return FAIL;
+ }
p = expand_env_save(q);
xfree(q);
- if (p == NULL)
+ if (p == NULL) {
return FAIL;
+ }
if (*p != '*') {
bp->dbg_name = (char_u *)fix_fname((char *)p);
xfree(p);
- } else
+ } else {
bp->dbg_name = p;
+ }
}
- if (bp->dbg_name == NULL)
+ if (bp->dbg_name == NULL) {
return FAIL;
+ }
return OK;
}
-/*
- * ":breakadd".
- */
+/// ":breakadd".
void ex_breakadd(exarg_T *eap)
{
struct debuggy *bp;
@@ -630,52 +616,51 @@ void ex_breakadd(exarg_T *eap)
garray_T *gap;
gap = &dbg_breakp;
- if (eap->cmdidx == CMD_profile)
+ if (eap->cmdidx == CMD_profile) {
gap = &prof_ga;
+ }
if (dbg_parsearg(eap->arg, gap) == OK) {
bp = &DEBUGGY(gap, gap->ga_len);
bp->dbg_forceit = eap->forceit;
- pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
+ pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false);
if (pat != NULL) {
bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
xfree(pat);
}
- if (pat == NULL || bp->dbg_prog == NULL)
+ if (pat == NULL || bp->dbg_prog == NULL) {
xfree(bp->dbg_name);
- else {
- if (bp->dbg_lnum == 0) /* default line number is 1 */
+ } else {
+ if (bp->dbg_lnum == 0) { // default line number is 1
bp->dbg_lnum = 1;
+ }
if (eap->cmdidx != CMD_profile) {
DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
- ++debug_tick;
+ debug_tick++;
}
- ++gap->ga_len;
+ gap->ga_len++;
}
}
}
-/*
- * ":debuggreedy".
- */
+/// ":debuggreedy".
void ex_debuggreedy(exarg_T *eap)
{
- if (eap->addr_count == 0 || eap->line2 != 0)
- debug_greedy = TRUE;
- else
- debug_greedy = FALSE;
+ if (eap->addr_count == 0 || eap->line2 != 0) {
+ debug_greedy = true;
+ } else {
+ debug_greedy = false;
+ }
}
-/*
- * ":breakdel" and ":profdel".
- */
+/// ":breakdel" and ":profdel".
void ex_breakdel(exarg_T *eap)
{
struct debuggy *bp, *bpi;
int nr;
int todel = -1;
- int del_all = FALSE;
+ bool del_all = false;
linenr_T best_lnum = 0;
garray_T *gap;
@@ -687,7 +672,7 @@ void ex_breakdel(exarg_T *eap)
if (ascii_isdigit(*eap->arg)) {
// ":breakdel {nr}"
nr = atoi((char *)eap->arg);
- for (int i = 0; i < gap->ga_len; ++i) {
+ for (int i = 0; i < gap->ga_len; i++) {
if (DEBUGGY(gap, i).dbg_nr == nr) {
todel = i;
break;
@@ -695,13 +680,14 @@ void ex_breakdel(exarg_T *eap)
}
} else if (*eap->arg == '*') {
todel = 0;
- del_all = TRUE;
+ del_all = true;
} else {
- /* ":breakdel {func|file} [lnum] {name}" */
- if (dbg_parsearg(eap->arg, gap) == FAIL)
+ // ":breakdel {func|file} [lnum] {name}"
+ if (dbg_parsearg(eap->arg, gap) == FAIL) {
return;
+ }
bp = &DEBUGGY(gap, gap->ga_len);
- for (int i = 0; i < gap->ga_len; ++i) {
+ for (int i = 0; i < gap->ga_len; i++) {
bpi = &DEBUGGY(gap, i);
if (bp->dbg_type == bpi->dbg_type
&& STRCMP(bp->dbg_name, bpi->dbg_name) == 0
@@ -716,90 +702,85 @@ void ex_breakdel(exarg_T *eap)
xfree(bp->dbg_name);
}
- if (todel < 0)
+ if (todel < 0) {
EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
- else {
+ } else {
while (!GA_EMPTY(gap)) {
xfree(DEBUGGY(gap, todel).dbg_name);
vim_regfree(DEBUGGY(gap, todel).dbg_prog);
- --gap->ga_len;
- if (todel < gap->ga_len)
+ gap->ga_len--;
+ if (todel < gap->ga_len) {
memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
(size_t)(gap->ga_len - todel) * sizeof(struct debuggy));
+ }
if (eap->cmdidx == CMD_breakdel) {
- ++debug_tick;
+ debug_tick++;
}
if (!del_all) {
break;
}
}
- /* If all breakpoints were removed clear the array. */
- if (GA_EMPTY(gap))
+ // If all breakpoints were removed clear the array.
+ if (GA_EMPTY(gap)) {
ga_clear(gap);
+ }
}
}
-/*
- * ":breaklist".
- */
+/// ":breaklist".
void ex_breaklist(exarg_T *eap)
{
struct debuggy *bp;
- if (GA_EMPTY(&dbg_breakp))
+ if (GA_EMPTY(&dbg_breakp)) {
MSG(_("No breakpoints defined"));
- else
- for (int i = 0; i < dbg_breakp.ga_len; ++i) {
+ } else {
+ for (int i = 0; i < dbg_breakp.ga_len; i++) {
bp = &BREAKP(i);
- if (bp->dbg_type == DBG_FILE)
- home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
+ if (bp->dbg_type == DBG_FILE) {
+ home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true);
+ }
smsg(_("%3d %s %s line %" PRId64),
- bp->dbg_nr,
- bp->dbg_type == DBG_FUNC ? "func" : "file",
- bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
- (int64_t)bp->dbg_lnum);
- }
-}
-
-/*
- * Find a breakpoint for a function or sourced file.
- * Returns line number at which to break; zero when no matching breakpoint.
- */
-linenr_T
-dbg_find_breakpoint (
- int file, /* TRUE for a file, FALSE for a function */
- char_u *fname, /* file or function name */
- linenr_T after /* after this line number */
+ bp->dbg_nr,
+ bp->dbg_type == DBG_FUNC ? "func" : "file",
+ bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
+ (int64_t)bp->dbg_lnum);
+ }
+ }
+}
+
+/// Find a breakpoint for a function or sourced file.
+/// Returns line number at which to break; zero when no matching breakpoint.
+linenr_T
+dbg_find_breakpoint(
+ bool file, // true for a file, false for a function
+ char_u *fname, // file or function name
+ linenr_T after // after this line number
)
{
return debuggy_find(file, fname, after, &dbg_breakp, NULL);
}
-/*
- * Return TRUE if profiling is on for a function or sourced file.
- */
-int
-has_profiling (
- int file, /* TRUE for a file, FALSE for a function */
- char_u *fname, /* file or function name */
- int *fp /* return: forceit */
-)
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param fp[out] forceit
+///
+/// @returns true if profiling is on for a function or sourced file.
+bool has_profiling(bool file, char_u *fname, bool *fp)
{
return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
!= (linenr_T)0;
}
-/*
- * Common code for dbg_find_breakpoint() and has_profiling().
- */
-static linenr_T
-debuggy_find (
- int file, /* TRUE for a file, FALSE for a function */
- char_u *fname, /* file or function name */
- linenr_T after, /* after this line number */
- garray_T *gap, /* either &dbg_breakp or &prof_ga */
- int *fp /* if not NULL: return forceit */
+/// Common code for dbg_find_breakpoint() and has_profiling().
+static linenr_T
+debuggy_find(
+ bool file, // true for a file, false for a function
+ char_u *fname, // file or function name
+ linenr_T after, // after this line number
+ garray_T *gap, // either &dbg_breakp or &prof_ga
+ bool *fp // if not NULL: return forceit
)
{
struct debuggy *bp;
@@ -807,59 +788,57 @@ debuggy_find (
char_u *name = fname;
int prev_got_int;
- /* Return quickly when there are no breakpoints. */
- if (GA_EMPTY(gap))
+ // Return quickly when there are no breakpoints.
+ if (GA_EMPTY(gap)) {
return (linenr_T)0;
+ }
- /* Replace K_SNR in function name with "<SNR>". */
+ // Replace K_SNR in function name with "<SNR>".
if (!file && fname[0] == K_SPECIAL) {
name = xmalloc(STRLEN(fname) + 3);
STRCPY(name, "<SNR>");
STRCPY(name + 5, fname + 3);
}
- for (int i = 0; i < gap->ga_len; ++i) {
- /* Skip entries that are not useful or are for a line that is beyond
- * an already found breakpoint. */
+ for (int i = 0; i < gap->ga_len; i++) {
+ // Skip entries that are not useful or are for a line that is beyond
+ // an already found breakpoint.
bp = &DEBUGGY(gap, i);
- if (((bp->dbg_type == DBG_FILE) == file
- && (gap == &prof_ga
- || (bp->dbg_lnum > after
- && (lnum == 0 || bp->dbg_lnum < lnum))))) {
+ if ((bp->dbg_type == DBG_FILE) == file
+ && (gap == &prof_ga
+ || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) {
// Save the value of got_int and reset it. We don't want a
// previous interruption cancel matching, only hitting CTRL-C
// while matching should abort it.
prev_got_int = got_int;
- got_int = FALSE;
+ got_int = false;
if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) {
lnum = bp->dbg_lnum;
- if (fp != NULL)
+ if (fp != NULL) {
*fp = bp->dbg_forceit;
+ }
}
got_int |= prev_got_int;
}
}
- if (name != fname)
+ if (name != fname) {
xfree(name);
+ }
return lnum;
}
-/*
- * Called when a breakpoint was encountered.
- */
+/// Called when a breakpoint was encountered.
void dbg_breakpoint(char_u *name, linenr_T lnum)
{
- /* We need to check if this line is actually executed in do_one_cmd() */
+ // We need to check if this line is actually executed in do_one_cmd()
debug_breakpoint_name = name;
debug_breakpoint_lnum = lnum;
}
static char_u *profile_fname = NULL;
-/*
- * ":profile cmd args"
- */
+/// ":profile cmd args"
void ex_profile(exarg_T *eap)
{
static proftime_T pause_time;
@@ -885,8 +864,9 @@ void ex_profile(exarg_T *eap)
set_vim_var_nr(VV_PROFILING, 0L);
profile_reset();
} else if (STRCMP(eap->arg, "pause") == 0) {
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
pause_time = profile_start();
+ }
do_profiling = PROF_PAUSED;
} else if (STRCMP(eap->arg, "continue") == 0) {
if (do_profiling == PROF_PAUSED) {
@@ -897,7 +877,7 @@ void ex_profile(exarg_T *eap)
} else if (STRCMP(eap->arg, "dump") == 0) {
profile_dump();
} else {
- /* The rest is similar to ":breakadd". */
+ // The rest is similar to ":breakadd".
ex_breakadd(eap);
}
}
@@ -917,6 +897,21 @@ void ex_pydo(exarg_T *eap)
script_host_do_range("python", eap);
}
+void ex_ruby(exarg_T *eap)
+{
+ script_host_execute("ruby", eap);
+}
+
+void ex_rubyfile(exarg_T *eap)
+{
+ script_host_execute_file("ruby", eap);
+}
+
+void ex_rubydo(exarg_T *eap)
+{
+ script_host_do_range("ruby", eap);
+}
+
void ex_python3(exarg_T *eap)
{
script_host_execute("python3", eap);
@@ -932,7 +927,7 @@ void ex_pydo3(exarg_T *eap)
script_host_do_range("python3", eap);
}
-/* Command line expansion for :profile. */
+// Command line expansion for :profile.
static enum {
PEXP_SUBCMD, ///< expand :profile sub-commands
PEXP_FUNC ///< expand :profile func {funcname}
@@ -949,36 +944,33 @@ static char *pexpand_cmds[] = {
NULL
};
-/*
- * Function given to ExpandGeneric() to obtain the profile command
- * specific expansion.
- */
+/// Function given to ExpandGeneric() to obtain the profile command
+/// specific expansion.
char_u *get_profile_name(expand_T *xp, int idx)
{
switch (pexpand_what) {
case PEXP_SUBCMD:
return (char_u *)pexpand_cmds[idx];
- /* case PEXP_FUNC: TODO */
+ // case PEXP_FUNC: TODO
default:
return NULL;
}
}
-/*
- * Handle command line completion for :profile command.
- */
+/// Handle command line completion for :profile command.
void set_context_in_profile_cmd(expand_T *xp, char_u *arg)
{
char_u *end_subcmd;
- /* Default: expand subcommands. */
+ // Default: expand subcommands.
xp->xp_context = EXPAND_PROFILE;
pexpand_what = PEXP_SUBCMD;
xp->xp_pattern = arg;
end_subcmd = skiptowhite(arg);
- if (*end_subcmd == NUL)
+ if (*end_subcmd == NUL) {
return;
+ }
if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) {
xp->xp_context = EXPAND_FILES;
@@ -986,22 +978,20 @@ void set_context_in_profile_cmd(expand_T *xp, char_u *arg)
return;
}
- /* TODO: expand function names after "func" */
+ // TODO(tarruda): expand function names after "func"
xp->xp_context = EXPAND_NOTHING;
}
-/*
- * Dump the profiling info.
- */
+/// Dump the profiling info.
void profile_dump(void)
{
FILE *fd;
if (profile_fname != NULL) {
fd = mch_fopen((char *)profile_fname, "w");
- if (fd == NULL)
+ if (fd == NULL) {
EMSG2(_(e_notopen), profile_fname);
- else {
+ } else {
script_dump_profile(fd);
func_dump_profile(fd);
fclose(fd);
@@ -1017,7 +1007,7 @@ static void profile_reset(void)
scriptitem_T *si = &SCRIPT_ITEM(id);
if (si->sn_prof_on) {
si->sn_prof_on = false;
- si->sn_pr_force = 0;
+ si->sn_pr_force = false;
si->sn_pr_child = profile_zero();
si->sn_pr_nest = 0;
si->sn_pr_count = 0;
@@ -1077,26 +1067,23 @@ static void profile_init(scriptitem_T *si)
si->sn_pr_nest = 0;
}
-/*
- * save time when starting to invoke another script or function.
- */
+/// save time when starting to invoke another script or function.
void script_prof_save(
- proftime_T *tm /* place to store wait time */
- )
+ proftime_T *tm // place to store wait time
+)
{
scriptitem_T *si;
if (current_SID > 0 && current_SID <= script_items.ga_len) {
si = &SCRIPT_ITEM(current_SID);
- if (si->sn_prof_on && si->sn_pr_nest++ == 0)
+ if (si->sn_prof_on && si->sn_pr_nest++ == 0) {
si->sn_pr_child = profile_start();
+ }
}
*tm = profile_get_wait();
}
-/*
- * Count time spent in children after invoking another script or function.
- */
+/// Count time spent in children after invoking another script or function.
void script_prof_restore(proftime_T *tm)
{
scriptitem_T *si;
@@ -1115,62 +1102,60 @@ void script_prof_restore(proftime_T *tm)
static proftime_T inchar_time;
-/*
- * Called when starting to wait for the user to type a character.
- */
+/// Called when starting to wait for the user to type a character.
void prof_inchar_enter(void)
{
inchar_time = profile_start();
}
-/*
- * Called when finished waiting for the user to type a character.
- */
+/// Called when finished waiting for the user to type a character.
void prof_inchar_exit(void)
{
inchar_time = profile_end(inchar_time);
profile_set_wait(profile_add(profile_get_wait(), inchar_time));
}
-/*
- * Dump the profiling results for all scripts in file "fd".
- */
+/// Dump the profiling results for all scripts in file "fd".
static void script_dump_profile(FILE *fd)
{
scriptitem_T *si;
FILE *sfd;
sn_prl_T *pp;
- for (int id = 1; id <= script_items.ga_len; ++id) {
+ for (int id = 1; id <= script_items.ga_len; id++) {
si = &SCRIPT_ITEM(id);
if (si->sn_prof_on) {
fprintf(fd, "SCRIPT %s\n", si->sn_name);
- if (si->sn_pr_count == 1)
+ if (si->sn_pr_count == 1) {
fprintf(fd, "Sourced 1 time\n");
- else
+ } else {
fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
+ }
fprintf(fd, "Total time: %s\n", profile_msg(si->sn_pr_total));
fprintf(fd, " Self time: %s\n", profile_msg(si->sn_pr_self));
fprintf(fd, "\n");
fprintf(fd, "count total (s) self (s)\n");
sfd = mch_fopen((char *)si->sn_name, "r");
- if (sfd == NULL)
+ if (sfd == NULL) {
fprintf(fd, "Cannot open file!\n");
- else {
- for (int i = 0; i < si->sn_prl_ga.ga_len; ++i) {
- if (vim_fgets(IObuff, IOSIZE, sfd))
+ } else {
+ for (int i = 0; i < si->sn_prl_ga.ga_len; i++) {
+ if (vim_fgets(IObuff, IOSIZE, sfd)) {
break;
+ }
pp = &PRL_ITEM(si, i);
if (pp->snp_count > 0) {
fprintf(fd, "%5d ", pp->snp_count);
- if (profile_equal(pp->sn_prl_total, pp->sn_prl_self))
+ if (profile_equal(pp->sn_prl_total, pp->sn_prl_self)) {
fprintf(fd, " ");
- else
+ } else {
fprintf(fd, "%s ", profile_msg(pp->sn_prl_total));
+ }
fprintf(fd, "%s ", profile_msg(pp->sn_prl_self));
- } else
+ } else {
fprintf(fd, " ");
+ }
fprintf(fd, "%s", IObuff);
}
fclose(sfd);
@@ -1180,44 +1165,41 @@ static void script_dump_profile(FILE *fd)
}
}
-/*
- * Return TRUE when a function defined in the current script should be
- * profiled.
- */
-int prof_def_func(void)
+/// Return true when a function defined in the current script should be
+/// profiled.
+bool prof_def_func(void)
{
- if (current_SID > 0)
+ if (current_SID > 0) {
return SCRIPT_ITEM(current_SID).sn_pr_force;
- return FALSE;
+ }
+ return false;
}
-/*
- * If 'autowrite' option set, try to write the file.
- * Careful: autocommands may make "buf" invalid!
- *
- * return FAIL for failure, OK otherwise
- */
+/// If 'autowrite' option set, try to write the file.
+/// Careful: autocommands may make "buf" invalid!
+///
+/// @return FAIL for failure, OK otherwise
int autowrite(buf_T *buf, int forceit)
{
int r;
if (!(p_aw || p_awa) || !p_write
- /* never autowrite a "nofile" or "nowrite" buffer */
+ // never autowrite a "nofile" or "nowrite" buffer
|| bt_dontwrite(buf)
- || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
+ || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) {
return FAIL;
+ }
r = buf_write_all(buf, forceit);
- /* Writing may succeed but the buffer still changed, e.g., when there is a
- * conversion error. We do want to return FAIL then. */
- if (buf_valid(buf) && bufIsChanged(buf))
+ // Writing may succeed but the buffer still changed, e.g., when there is a
+ // conversion error. We do want to return FAIL then.
+ if (buf_valid(buf) && bufIsChanged(buf)) {
r = FAIL;
+ }
return r;
}
-/*
- * flush all buffers, except the ones that are readonly
- */
+/// flush all buffers, except the ones that are readonly
void autowrite_all(void)
{
if (!(p_aw || p_awa) || !p_write) {
@@ -1226,123 +1208,125 @@ void autowrite_all(void)
FOR_ALL_BUFFERS(buf) {
if (bufIsChanged(buf) && !buf->b_p_ro) {
- (void)buf_write_all(buf, FALSE);
- /* an autocommand may have deleted the buffer */
- if (!buf_valid(buf))
+ (void)buf_write_all(buf, false);
+ // an autocommand may have deleted the buffer
+ if (!buf_valid(buf)) {
buf = firstbuf;
+ }
}
}
}
-/*
- * Return TRUE if buffer was changed and cannot be abandoned.
- * For flags use the CCGD_ values.
- */
-int check_changed(buf_T *buf, int flags)
+/// Return true if buffer was changed and cannot be abandoned.
+/// For flags use the CCGD_ values.
+bool check_changed(buf_T *buf, int flags)
{
int forceit = (flags & CCGD_FORCEIT);
- if ( !forceit
- && bufIsChanged(buf)
- && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
- && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) {
+ if (!forceit
+ && bufIsChanged(buf)
+ && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
+ && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) {
if ((p_confirm || cmdmod.confirm) && p_write) {
int count = 0;
- if (flags & CCGD_ALLBUF)
+ if (flags & CCGD_ALLBUF) {
FOR_ALL_BUFFERS(buf2) {
if (bufIsChanged(buf2) && (buf2->b_ffname != NULL)) {
- ++count;
+ count++;
}
}
- if (!buf_valid(buf))
- /* Autocommand deleted buffer, oops! It's not changed now. */
- return FALSE;
+ }
+ if (!buf_valid(buf)) {
+ // Autocommand deleted buffer, oops! It's not changed now.
+ return false;
+ }
dialog_changed(buf, count > 1);
- if (!buf_valid(buf))
- /* Autocommand deleted buffer, oops! It's not changed now. */
- return FALSE;
+ if (!buf_valid(buf)) {
+ // Autocommand deleted buffer, oops! It's not changed now.
+ return false;
+ }
return bufIsChanged(buf);
}
- if (flags & CCGD_EXCMD)
+ if (flags & CCGD_EXCMD) {
EMSG(_(e_nowrtmsg));
- else
+ } else {
EMSG(_(e_nowrtmsg_nobang));
- return TRUE;
+ }
+ return true;
}
- return FALSE;
+ return false;
}
-/*
- * Ask the user what to do when abandoning a changed buffer.
- * Must check 'write' option first!
- */
-void
-dialog_changed (
- buf_T *buf,
- int checkall /* may abandon all changed buffers */
-)
+/// Ask the user what to do when abandoning a changed buffer.
+/// Must check 'write' option first!
+///
+/// @param buf
+/// @param checkall may abandon all changed buffers
+void dialog_changed(buf_T *buf, int checkall)
{
char_u buff[DIALOG_MSG_SIZE];
int ret;
exarg_T ea;
dialog_msg(buff, _("Save changes to \"%s\"?"),
- (buf->b_fname != NULL) ?
- buf->b_fname : (char_u *)_("Untitled"));
- if (checkall)
+ (buf->b_fname != NULL) ?
+ buf->b_fname : (char_u *)_("Untitled"));
+ if (checkall) {
ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
- else
+ } else {
ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
+ }
- /* Init ea pseudo-structure, this is needed for the check_overwrite()
- * function. */
- ea.append = ea.forceit = FALSE;
+ // Init ea pseudo-structure, this is needed for the check_overwrite()
+ // function.
+ ea.append = ea.forceit = false;
if (ret == VIM_YES) {
- if (buf->b_fname != NULL && check_overwrite(&ea, buf,
- buf->b_fname, buf->b_ffname, FALSE) == OK)
- /* didn't hit Cancel */
- (void)buf_write_all(buf, FALSE);
+ if (buf->b_fname != NULL
+ && check_overwrite(&ea,
+ buf,
+ buf->b_fname,
+ buf->b_ffname,
+ false) == OK) {
+ // didn't hit Cancel
+ (void)buf_write_all(buf, false);
+ }
} else if (ret == VIM_NO) {
- unchanged(buf, TRUE);
+ unchanged(buf, true);
} else if (ret == VIM_ALL) {
- /*
- * Write all modified files that can be written.
- * Skip readonly buffers, these need to be confirmed
- * individually.
- */
+ // Write all modified files that can be written.
+ // Skip readonly buffers, these need to be confirmed
+ // individually.
FOR_ALL_BUFFERS(buf2) {
if (bufIsChanged(buf2)
- && (buf2->b_ffname != NULL
- )
+ && (buf2->b_ffname != NULL)
&& !buf2->b_p_ro) {
- if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
- buf2->b_fname, buf2->b_ffname, FALSE) == OK)
- /* didn't hit Cancel */
- (void)buf_write_all(buf2, FALSE);
- /* an autocommand may have deleted the buffer */
- if (!buf_valid(buf2))
+ if (buf2->b_fname != NULL
+ && check_overwrite(&ea, buf2, buf2->b_fname,
+ buf2->b_ffname, false) == OK) {
+ // didn't hit Cancel
+ (void)buf_write_all(buf2, false);
+ }
+ // an autocommand may have deleted the buffer
+ if (!buf_valid(buf2)) {
buf2 = firstbuf;
+ }
}
}
} else if (ret == VIM_DISCARDALL) {
- /*
- * mark all buffers as unchanged
- */
+ // mark all buffers as unchanged
FOR_ALL_BUFFERS(buf2) {
- unchanged(buf2, TRUE);
+ unchanged(buf2, true);
}
}
}
-/*
- * Return TRUE if the buffer "buf" can be abandoned, either by making it
- * hidden, autowriting it or unloading it.
- */
-int can_abandon(buf_T *buf, int forceit)
+/// Return true if the buffer "buf" can be abandoned, either by making it
+/// hidden, autowriting it or unloading it.
+bool can_abandon(buf_T *buf, int forceit)
{
return P_HID(buf)
|| !bufIsChanged(buf)
@@ -1352,16 +1336,16 @@ int can_abandon(buf_T *buf, int forceit)
}
-/*
- * Add a buffer number to "bufnrs", unless it's already there.
- */
+/// Add a buffer number to "bufnrs", unless it's already there.
static void add_bufnum(int *bufnrs, int *bufnump, int nr)
{
int i;
- for (i = 0; i < *bufnump; ++i)
- if (bufnrs[i] == nr)
+ for (i = 0; i < *bufnump; i++) {
+ if (bufnrs[i] == nr) {
return;
+ }
+ }
bufnrs[*bufnump] = nr;
*bufnump = *bufnump + 1;
}
@@ -1375,7 +1359,7 @@ static void add_bufnum(int *bufnrs, int *bufnump, int nr)
/// @param[in] unload specifies whether to unload, instead of hide, the buffer.
///
/// @returns true if any buffer is changed and cannot be abandoned
-int check_changed_any(bool hidden, bool unload)
+bool check_changed_any(bool hidden, bool unload)
{
bool ret = false;
int save;
@@ -1385,7 +1369,7 @@ int check_changed_any(bool hidden, bool unload)
int *bufnrs;
FOR_ALL_BUFFERS(buf) {
- ++bufcount;
+ bufcount++;
}
if (bufcount == 0) {
@@ -1394,16 +1378,16 @@ int check_changed_any(bool hidden, bool unload)
bufnrs = xmalloc(sizeof(*bufnrs) * bufcount);
- /* curbuf */
+ // curbuf
bufnrs[bufnum++] = curbuf->b_fnum;
- /* buf in curtab */
+ // buf in curtab
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer != curbuf) {
add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
}
}
- /* buf in other tab */
+ // buf in other tab
FOR_ALL_TABS(tp) {
if (tp != curtab) {
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
@@ -1412,59 +1396,60 @@ int check_changed_any(bool hidden, bool unload)
}
}
- /* any other buf */
+ // any other buf
FOR_ALL_BUFFERS(buf) {
add_bufnum(bufnrs, &bufnum, buf->b_fnum);
}
buf_T *buf = NULL;
- for (i = 0; i < bufnum; ++i) {
+ for (i = 0; i < bufnum; i++) {
buf = buflist_findnr(bufnrs[i]);
- if (buf == NULL)
+ if (buf == NULL) {
continue;
+ }
if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) {
- /* Try auto-writing the buffer. If this fails but the buffer no
- * longer exists it's not changed, that's OK. */
+ // Try auto-writing the buffer. If this fails but the buffer no
+ // longer exists it's not changed, that's OK.
if (check_changed(buf, (p_awa ? CCGD_AW : 0)
- | CCGD_MULTWIN
- | CCGD_ALLBUF) && buf_valid(buf))
- break; /* didn't save - still changes */
+ | CCGD_MULTWIN
+ | CCGD_ALLBUF) && buf_valid(buf)) {
+ break; // didn't save - still changes
+ }
}
}
- if (i >= bufnum)
+ if (i >= bufnum) {
goto theend;
+ }
- ret = TRUE;
- exiting = FALSE;
- /*
- * When ":confirm" used, don't give an error message.
- */
+ ret = true;
+ exiting = false;
+ // When ":confirm" used, don't give an error message.
if (!(p_confirm || cmdmod.confirm)) {
- /* There must be a wait_return for this message, do_buffer()
- * may cause a redraw. But wait_return() is a no-op when vgetc()
- * is busy (Quit used from window menu), then make sure we don't
- * cause a scroll up. */
+ // There must be a wait_return for this message, do_buffer()
+ // may cause a redraw. But wait_return() is a no-op when vgetc()
+ // is busy (Quit used from window menu), then make sure we don't
+ // cause a scroll up.
if (vgetc_busy > 0) {
msg_row = cmdline_row;
msg_col = 0;
- msg_didout = FALSE;
+ msg_didout = false;
}
if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
- buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) {
+ buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) {
save = no_wait_return;
- no_wait_return = FALSE;
- wait_return(FALSE);
+ no_wait_return = false;
+ wait_return(false);
no_wait_return = save;
}
}
- /* Try to find a window that contains the buffer. */
+ // 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? */
+ // Paranoia: did autocmds wipe out the buffer with changes?
if (!buf_valid(buf)) {
goto theend;
}
@@ -1484,10 +1469,8 @@ theend:
return ret;
}
-/*
- * return FAIL if there is no file name, OK if there is one
- * give error message for FAIL
- */
+/// Return FAIL if there is no file name, OK if there is one.
+/// Give error message for FAIL.
int check_fname(void)
{
if (curbuf->b_ffname == NULL) {
@@ -1497,19 +1480,17 @@ int check_fname(void)
return OK;
}
-/*
- * flush the contents of a buffer, unless it has no file name
- *
- * return FAIL for failure, OK otherwise
- */
+/// Flush the contents of a buffer, unless it has no file name.
+///
+/// @return FAIL for failure, OK otherwise
int buf_write_all(buf_T *buf, int forceit)
{
int retval;
buf_T *old_curbuf = curbuf;
retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
- (linenr_T)1, buf->b_ml.ml_line_count, NULL,
- FALSE, forceit, TRUE, FALSE));
+ (linenr_T)1, buf->b_ml.ml_line_count, NULL,
+ false, forceit, true, false));
if (curbuf != old_curbuf) {
msg_source(hl_attr(HLF_W));
MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
@@ -1517,37 +1498,35 @@ int buf_write_all(buf_T *buf, int forceit)
return retval;
}
-/*
- * Code to handle the argument list.
- */
+/// Code to handle the argument list.
#define AL_SET 1
#define AL_ADD 2
#define AL_DEL 3
-/*
- * Isolate one argument, taking backticks.
- * Changes the argument in-place, puts a NUL after it. Backticks remain.
- * Return a pointer to the start of the next argument.
- */
+/// Isolate one argument, taking backticks.
+/// Changes the argument in-place, puts a NUL after it. Backticks remain.
+/// Return a pointer to the start of the next argument.
static char_u *do_one_arg(char_u *str)
{
char_u *p;
- int inbacktick;
+ bool inbacktick;
- inbacktick = FALSE;
- for (p = str; *str; ++str) {
- /* When the backslash is used for escaping the special meaning of a
- * character we need to keep it until wildcard expansion. */
+ inbacktick = false;
+ for (p = str; *str; str++) {
+ // When the backslash is used for escaping the special meaning of a
+ // character we need to keep it until wildcard expansion.
if (rem_backslash(str)) {
*p++ = *str++;
*p++ = *str;
} else {
- /* An item ends at a space not in backticks */
- if (!inbacktick && ascii_isspace(*str))
+ // An item ends at a space not in backticks
+ if (!inbacktick && ascii_isspace(*str)) {
break;
- if (*str == '`')
- inbacktick ^= TRUE;
+ }
+ if (*str == '`') {
+ inbacktick ^= true;
+ }
*p++ = *str;
}
}
@@ -1557,26 +1536,23 @@ static char_u *do_one_arg(char_u *str)
return str;
}
-/*
- * Separate the arguments in "str" and return a list of pointers in the
- * growarray "gap".
- */
+/// Separate the arguments in "str" and return a list of pointers in the
+/// growarray "gap".
void get_arglist(garray_T *gap, char_u *str)
{
ga_init(gap, (int)sizeof(char_u *), 20);
while (*str != NUL) {
GA_APPEND(char_u *, gap, str);
- /* Isolate one argument, change it in-place, put a NUL after it. */
+ // Isolate one argument, change it in-place, put a NUL after it.
str = do_one_arg(str);
}
}
-/*
- * Parse a list of arguments (file names), expand them and return in
- * "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'.
- * Return FAIL or OK.
- */
+/// Parse a list of arguments (file names), expand them and return in
+/// "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'.
+///
+/// @return FAIL or OK.
int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
{
garray_T ga;
@@ -1584,31 +1560,29 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
get_arglist(&ga, str);
- if (wig)
+ if (wig) {
i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
- fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
- else
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ } else {
i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
- fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ }
ga_clear(&ga);
return i;
}
-/*
- * "what" == AL_SET: Redefine the argument list to 'str'.
- * "what" == AL_ADD: add files in 'str' to the argument list after "after".
- * "what" == AL_DEL: remove files in 'str' from the argument list.
- *
- * Return FAIL for failure, OK otherwise.
- */
-static int
-do_arglist (
- char_u *str,
- int what,
- int after /* 0 means before first one */
-)
+/// @param str
+/// @param what
+/// AL_SET: Redefine the argument list to 'str'.
+/// AL_ADD: add files in 'str' to the argument list after "after".
+/// AL_DEL: remove files in 'str' from the argument list.
+/// @param after
+/// 0 means before first one
+///
+/// @return FAIL for failure, OK otherwise.
+static int do_arglist(char_u *str, int what, int after)
{
garray_T new_ga;
int exp_count;
@@ -1616,54 +1590,63 @@ do_arglist (
char_u *p;
int match;
- /*
- * Collect all file name arguments in "new_ga".
- */
+ // Set default argument for ":argadd" command.
+ if (what == AL_ADD && *str == NUL) {
+ if (curbuf->b_ffname == NULL) {
+ return FAIL;
+ }
+ str = curbuf->b_fname;
+ }
+
+ // Collect all file name arguments in "new_ga".
get_arglist(&new_ga, str);
if (what == AL_DEL) {
regmatch_T regmatch;
- int didone;
-
- /*
- * Delete the items: use each item as a regexp and find a match in the
- * argument list.
- */
- regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
- for (int i = 0; i < new_ga.ga_len && !got_int; ++i) {
+ bool didone;
+
+ // Delete the items: use each item as a regexp and find a match in the
+ // argument list.
+ regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set
+ for (int i = 0; i < new_ga.ga_len && !got_int; i++) {
p = ((char_u **)new_ga.ga_data)[i];
- p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
- if (p == NULL)
+ p = file_pat_to_reg_pat(p, NULL, NULL, false);
+ if (p == NULL) {
break;
+ }
regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
if (regmatch.regprog == NULL) {
xfree(p);
break;
}
- didone = FALSE;
- for (match = 0; match < ARGCOUNT; ++match)
+ didone = false;
+ for (match = 0; match < ARGCOUNT; match++) {
if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
- (colnr_T)0)) {
- didone = TRUE;
+ (colnr_T)0)) {
+ didone = true;
xfree(ARGLIST[match].ae_fname);
memmove(ARGLIST + match, ARGLIST + match + 1,
(size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T));
- --ALIST(curwin)->al_ga.ga_len;
- if (curwin->w_arg_idx > match)
- --curwin->w_arg_idx;
- --match;
+ ALIST(curwin)->al_ga.ga_len--;
+ if (curwin->w_arg_idx > match) {
+ curwin->w_arg_idx--;
+ }
+ match--;
}
+ }
vim_regfree(regmatch.regprog);
xfree(p);
- if (!didone)
+ if (!didone) {
EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
+ }
}
ga_clear(&new_ga);
} else {
int i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
- &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
+ &exp_count, &exp_files,
+ EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
ga_clear(&new_ga);
if (i == FAIL || exp_count == 0) {
EMSG(_(e_nomatch));
@@ -1673,8 +1656,9 @@ do_arglist (
if (what == AL_ADD) {
(void)alist_add_list(exp_count, exp_files, after);
xfree(exp_files);
- } else /* what == AL_SET */
- alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
+ } else { // what == AL_SET
+ alist_set(ALIST(curwin), exp_count, exp_files, false, NULL, 0);
+ }
}
alist_check_arg_idx();
@@ -1682,9 +1666,7 @@ do_arglist (
return OK;
}
-/*
- * Check the validity of the arg_idx for each other window.
- */
+/// Check the validity of the arg_idx for each other window.
static void alist_check_arg_idx(void)
{
FOR_ALL_TAB_WINDOWS(tp, win) {
@@ -1694,136 +1676,123 @@ static void alist_check_arg_idx(void)
}
}
-/*
- * Return TRUE if window "win" is editing the file at the current argument
- * index.
- */
-static int editing_arg_idx(win_T *win)
+/// Return true if window "win" is editing the file at the current argument
+/// index.
+static bool editing_arg_idx(win_T *win)
{
return !(win->w_arg_idx >= WARGCOUNT(win)
|| (win->w_buffer->b_fnum
!= WARGLIST(win)[win->w_arg_idx].ae_fnum
&& (win->w_buffer->b_ffname == NULL
|| !(path_full_compare(
- alist_name(&WARGLIST(win)[win->w_arg_idx]),
- win->w_buffer->b_ffname, TRUE) & kEqualFiles))));
+ alist_name(&WARGLIST(win)[win->w_arg_idx]),
+ win->w_buffer->b_ffname, true) & kEqualFiles))));
}
-/*
- * Check if window "win" is editing the w_arg_idx file in its argument list.
- */
+/// Check if window "win" is editing the w_arg_idx file in its argument list.
void check_arg_idx(win_T *win)
{
if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) {
- /* We are not editing the current entry in the argument list.
- * Set "arg_had_last" if we are editing the last one. */
- win->w_arg_idx_invalid = TRUE;
+ // We are not editing the current entry in the argument list.
+ // Set "arg_had_last" if we are editing the last one.
+ win->w_arg_idx_invalid = true;
if (win->w_arg_idx != WARGCOUNT(win) - 1
- && arg_had_last == FALSE
+ && arg_had_last == false
&& ALIST(win) == &global_alist
&& GARGCOUNT > 0
&& win->w_arg_idx < GARGCOUNT
&& (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
|| (win->w_buffer->b_ffname != NULL
&& (path_full_compare(alist_name(&GARGLIST[GARGCOUNT - 1]),
- win->w_buffer->b_ffname, TRUE) & kEqualFiles))))
- arg_had_last = TRUE;
+ win->w_buffer->b_ffname, true)
+ & kEqualFiles)))) {
+ arg_had_last = true;
+ }
} else {
- /* We are editing the current entry in the argument list.
- * Set "arg_had_last" if it's also the last one */
- win->w_arg_idx_invalid = FALSE;
+ // We are editing the current entry in the argument list.
+ // Set "arg_had_last" if it's also the last one
+ win->w_arg_idx_invalid = false;
if (win->w_arg_idx == WARGCOUNT(win) - 1
- && win->w_alist == &global_alist
- )
- arg_had_last = TRUE;
+ && win->w_alist == &global_alist) {
+ arg_had_last = true;
+ }
}
}
-/*
- * ":args", ":argslocal" and ":argsglobal".
- */
+/// ":args", ":argslocal" and ":argsglobal".
void ex_args(exarg_T *eap)
{
if (eap->cmdidx != CMD_args) {
alist_unlink(ALIST(curwin));
- if (eap->cmdidx == CMD_argglobal)
+ if (eap->cmdidx == CMD_argglobal) {
ALIST(curwin) = &global_alist;
- else /* eap->cmdidx == CMD_arglocal */
+ } else { // eap->cmdidx == CMD_arglocal
alist_new();
+ }
}
if (!ends_excmd(*eap->arg)) {
- /*
- * ":args file ..": define new argument list, handle like ":next"
- * Also for ":argslocal file .." and ":argsglobal file ..".
- */
+ // ":args file ..": define new argument list, handle like ":next"
+ // Also for ":argslocal file .." and ":argsglobal file ..".
ex_next(eap);
- } else if (eap->cmdidx == CMD_args) {
- /*
- * ":args": list arguments.
- */
+ } else if (eap->cmdidx == CMD_args) {
+ // ":args": list arguments.
if (ARGCOUNT > 0) {
- /* Overwrite the command, for a short list there is no scrolling
- * required and no wait_return(). */
- gotocmdline(TRUE);
- for (int i = 0; i < ARGCOUNT; ++i) {
- if (i == curwin->w_arg_idx)
+ // Overwrite the command, for a short list there is no scrolling
+ // required and no wait_return().
+ gotocmdline(true);
+ for (int i = 0; i < ARGCOUNT; i++) {
+ if (i == curwin->w_arg_idx) {
msg_putchar('[');
+ }
msg_outtrans(alist_name(&ARGLIST[i]));
- if (i == curwin->w_arg_idx)
+ if (i == curwin->w_arg_idx) {
msg_putchar(']');
+ }
msg_putchar(' ');
}
}
} else if (eap->cmdidx == CMD_arglocal) {
garray_T *gap = &curwin->w_alist->al_ga;
- /*
- * ":argslocal": make a local copy of the global argument list.
- */
+ // ":argslocal": make a local copy of the global argument list.
ga_grow(gap, GARGCOUNT);
- for (int i = 0; i < GARGCOUNT; ++i)
+ for (int i = 0; i < GARGCOUNT; i++) {
if (GARGLIST[i].ae_fname != NULL) {
AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
vim_strsave(GARGLIST[i].ae_fname);
AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
GARGLIST[i].ae_fnum;
- ++gap->ga_len;
+ gap->ga_len++;
}
+ }
}
}
-/*
- * ":previous", ":sprevious", ":Next" and ":sNext".
- */
+/// ":previous", ":sprevious", ":Next" and ":sNext".
void ex_previous(exarg_T *eap)
{
- /* If past the last one already, go to the last one. */
- if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
+ // If past the last one already, go to the last one.
+ if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) {
do_argfile(eap, ARGCOUNT - 1);
- else
+ } else {
do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
+ }
}
-/*
- * ":rewind", ":first", ":sfirst" and ":srewind".
- */
+/// ":rewind", ":first", ":sfirst" and ":srewind".
void ex_rewind(exarg_T *eap)
{
do_argfile(eap, 0);
}
-/*
- * ":last" and ":slast".
- */
+/// ":last" and ":slast".
void ex_last(exarg_T *eap)
{
do_argfile(eap, ARGCOUNT - 1);
}
-/*
- * ":argument" and ":sargument".
- */
+/// ":argument" and ":sargument".
void ex_argument(exarg_T *eap)
{
int i;
@@ -1836,9 +1805,7 @@ void ex_argument(exarg_T *eap)
do_argfile(eap, i);
}
-/*
- * Edit file "argn" of the argument lists.
- */
+/// Edit file "argn" of the argument lists.
void do_argfile(exarg_T *eap, int argn)
{
int other;
@@ -1846,26 +1813,26 @@ void do_argfile(exarg_T *eap, int argn)
int old_arg_idx = curwin->w_arg_idx;
if (argn < 0 || argn >= ARGCOUNT) {
- if (ARGCOUNT <= 1)
+ if (ARGCOUNT <= 1) {
EMSG(_("E163: There is only one file to edit"));
- else if (argn < 0)
+ } else if (argn < 0) {
EMSG(_("E164: Cannot go before first file"));
- else
+ } else {
EMSG(_("E165: Cannot go beyond last file"));
+ }
} else {
setpcmark();
- /* split window or create new tab page first */
+ // split window or create new tab page first
if (*eap->cmd == 's' || cmdmod.tab != 0) {
- if (win_split(0, 0) == FAIL)
+ if (win_split(0, 0) == FAIL) {
return;
+ }
RESET_BINDING(curwin);
} else {
- /*
- * if 'hidden' set, only check for changed file when re-editing
- * the same buffer
- */
- other = TRUE;
+ // if 'hidden' set, only check for changed file when re-editing
+ // the same buffer
+ other = true;
if (P_HID(curbuf)) {
p = (char_u *)fix_fname((char *)alist_name(&ARGLIST[argn]));
other = otherfile(p);
@@ -1873,101 +1840,97 @@ void do_argfile(exarg_T *eap, int argn)
}
if ((!P_HID(curbuf) || !other)
&& check_changed(curbuf, CCGD_AW
- | (other ? 0 : CCGD_MULTWIN)
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD))
+ | (other ? 0 : CCGD_MULTWIN)
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD)) {
return;
+ }
}
curwin->w_arg_idx = argn;
if (argn == ARGCOUNT - 1
- && curwin->w_alist == &global_alist
- )
- arg_had_last = TRUE;
+ && curwin->w_alist == &global_alist) {
+ arg_had_last = true;
+ }
- /* Edit the file; always use the last known line number.
- * When it fails (e.g. Abort for already edited file) restore the
- * argument index. */
+ // Edit the file; always use the last known line number.
+ // When it fails (e.g. Abort for already edited file) restore the
+ // argument index.
if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
- eap, ECMD_LAST,
- (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
- + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
+ eap, ECMD_LAST,
+ (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
+ + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) {
curwin->w_arg_idx = old_arg_idx;
- /* like Vi: set the mark where the cursor is in the file. */
- else if (eap->cmdidx != CMD_argdo)
+ } else if (eap->cmdidx != CMD_argdo) {
+ // like Vi: set the mark where the cursor is in the file.
setmark('\'');
+ }
}
}
-/*
- * ":next", and commands that behave like it.
- */
+/// ":next", and commands that behave like it.
void ex_next(exarg_T *eap)
{
int i;
- /*
- * check for changed buffer now, if this fails the argument list is not
- * redefined.
- */
- if ( P_HID(curbuf)
- || eap->cmdidx == CMD_snext
- || !check_changed(curbuf, CCGD_AW
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD)) {
- if (*eap->arg != NUL) { /* redefine file list */
- if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
+ // check for changed buffer now, if this fails the argument list is not
+ // redefined.
+ if (P_HID(curbuf)
+ || eap->cmdidx == CMD_snext
+ || !check_changed(curbuf, CCGD_AW
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD)) {
+ if (*eap->arg != NUL) { // redefine file list
+ if (do_arglist(eap->arg, AL_SET, 0) == FAIL) {
return;
+ }
i = 0;
- } else
+ } else {
i = curwin->w_arg_idx + (int)eap->line2;
+ }
do_argfile(eap, i);
}
}
-/*
- * ":argedit"
- */
+/// ":argedit"
void ex_argedit(exarg_T *eap)
{
int fnum;
int i;
char_u *s;
- /* Add the argument to the buffer list and get the buffer number. */
+ // Add the argument to the buffer list and get the buffer number.
fnum = buflist_add(eap->arg, BLN_LISTED);
- /* Check if this argument is already in the argument list. */
- for (i = 0; i < ARGCOUNT; ++i)
- if (ARGLIST[i].ae_fnum == fnum)
+ // Check if this argument is already in the argument list.
+ for (i = 0; i < ARGCOUNT; i++) {
+ if (ARGLIST[i].ae_fnum == fnum) {
break;
+ }
+ }
if (i == ARGCOUNT) {
- /* Can't find it, add it to the argument list. */
+ // Can't find it, add it to the argument list.
s = vim_strsave(eap->arg);
- i = alist_add_list(1, &s,
- eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
+ int after = eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1;
+ i = alist_add_list(1, &s, after);
curwin->w_arg_idx = i;
}
alist_check_arg_idx();
- /* Edit the argument. */
+ // Edit the argument.
do_argfile(eap, i);
}
-/*
- * ":argadd"
- */
+/// ":argadd"
void ex_argadd(exarg_T *eap)
{
do_arglist(eap->arg, AL_ADD,
- eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
+ eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
maketitle();
}
-/*
- * ":argdelete"
- */
+/// ":argdelete"
void ex_argdelete(exarg_T *eap)
{
if (eap->addr_count > 0) {
@@ -1979,7 +1942,7 @@ void ex_argdelete(exarg_T *eap)
if (*eap->arg != NUL || n <= 0) {
EMSG(_(e_invarg));
} else {
- for (linenr_T i = eap->line1; i <= eap->line2; ++i) {
+ for (linenr_T i = eap->line1; i <= eap->line2; i++) {
xfree(ARGLIST[i - 1].ae_fname);
}
memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
@@ -1990,17 +1953,21 @@ void ex_argdelete(exarg_T *eap)
} else if (curwin->w_arg_idx > eap->line1) {
curwin->w_arg_idx = (int)eap->line1;
}
+ if (ARGCOUNT == 0) {
+ curwin->w_arg_idx = 0;
+ } else if (curwin->w_arg_idx >= ARGCOUNT) {
+ curwin->w_arg_idx = ARGCOUNT - 1;
+ }
}
- } else if (*eap->arg == NUL)
+ } else if (*eap->arg == NUL) {
EMSG(_(e_argreq));
- else
+ } else {
do_arglist(eap->arg, AL_DEL, 0);
+ }
maketitle();
}
-/*
- * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
- */
+/// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
void ex_listdo(exarg_T *eap)
{
int i;
@@ -2010,10 +1977,11 @@ void ex_listdo(exarg_T *eap)
char_u *save_ei = NULL;
char_u *p_shm_save;
- if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
- /* Don't do syntax HL autocommands. Skipping the syntax file is a
- * great speed improvement. */
+ if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) {
+ // Don't do syntax HL autocommands. Skipping the syntax file is a
+ // great speed improvement.
save_ei = au_event_disable(",Syntax");
+ }
start_global_changes();
@@ -2021,36 +1989,36 @@ void ex_listdo(exarg_T *eap)
|| eap->cmdidx == CMD_tabdo
|| P_HID(curbuf)
|| !check_changed(curbuf, CCGD_AW
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD)) {
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD)) {
i = 0;
- /* start at the eap->line1 argument/window/buffer */
+ // start at the eap->line1 argument/window/buffer
wp = firstwin;
tp = first_tabpage;
switch (eap->cmdidx) {
- case CMD_windo:
- for (; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) {
- i++;
- }
- break;
- case CMD_tabdo:
- for (; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) {
- i++;
- }
- break;
- case CMD_argdo:
- i = (int)eap->line1 - 1;
- break;
- default:
- break;
+ case CMD_windo:
+ for (; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) {
+ i++;
+ }
+ break;
+ case CMD_tabdo:
+ for (; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) {
+ i++;
+ }
+ break;
+ case CMD_argdo:
+ i = (int)eap->line1 - 1;
+ break;
+ default:
+ break;
}
buf_T *buf = curbuf;
size_t qf_size = 0;
- /* set pcmark now */
+ // set pcmark now
if (eap->cmdidx == CMD_bufdo) {
- /* Advance to the first listed buffer after "eap->line1". */
+ // Advance to the first listed buffer after "eap->line1".
for (buf = firstbuf;
buf != NULL && (buf->b_fnum < eap->line1 || !buf->b_p_bl);
buf = buf->b_next) {
@@ -2082,64 +2050,71 @@ void ex_listdo(exarg_T *eap)
} else {
setpcmark();
}
- listcmd_busy = TRUE; /* avoids setting pcmark below */
+ listcmd_busy = true; // avoids setting pcmark below
while (!got_int && buf != NULL) {
if (eap->cmdidx == CMD_argdo) {
- /* go to argument "i" */
- if (i == ARGCOUNT)
+ // go to argument "i"
+ if (i == ARGCOUNT) {
break;
- /* Don't call do_argfile() when already there, it will try
- * reloading the file. */
+ }
+ // Don't call do_argfile() when already there, it will try
+ // reloading the file.
if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) {
- /* Clear 'shm' to avoid that the file message overwrites
- * any output from the command. */
+ // Clear 'shm' to avoid that the file message overwrites
+ // any output from the command.
p_shm_save = vim_strsave(p_shm);
set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
do_argfile(eap, i);
set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
xfree(p_shm_save);
}
- if (curwin->w_arg_idx != i)
+ if (curwin->w_arg_idx != i) {
break;
+ }
} else if (eap->cmdidx == CMD_windo) {
- /* go to window "wp" */
- if (!win_valid(wp))
+ // go to window "wp"
+ if (!win_valid(wp)) {
break;
+ }
assert(wp);
win_goto(wp);
- if (curwin != wp)
- break; /* something must be wrong */
+ if (curwin != wp) {
+ break; // something must be wrong
+ }
wp = curwin->w_next;
} else if (eap->cmdidx == CMD_tabdo) {
- /* go to window "tp" */
- if (!valid_tabpage(tp))
+ // go to window "tp"
+ if (!valid_tabpage(tp)) {
break;
+ }
assert(tp);
- goto_tabpage_tp(tp, TRUE, TRUE);
+ goto_tabpage_tp(tp, true, true);
tp = tp->tp_next;
} else if (eap->cmdidx == CMD_bufdo) {
- /* Remember the number of the next listed buffer, in case
- * ":bwipe" is used or autocommands do something strange. */
+ // Remember the number of the next listed buffer, in case
+ // ":bwipe" is used or autocommands do something strange.
next_fnum = -1;
- for (buf_T *buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
+ for (buf_T *buf = curbuf->b_next; buf != NULL; buf = buf->b_next) {
if (buf->b_p_bl) {
next_fnum = buf->b_fnum;
break;
}
+ }
}
- ++i;
- /* execute the command */
+ i++;
+ // execute the command
do_cmdline(eap->arg, eap->getline, eap->cookie,
- DOCMD_VERBOSE + DOCMD_NOWAIT);
+ DOCMD_VERBOSE + DOCMD_NOWAIT);
if (eap->cmdidx == CMD_bufdo) {
- /* Done? */
- if (next_fnum < 0 || next_fnum > eap->line2)
+ // Done?
+ if (next_fnum < 0 || next_fnum > eap->line2) {
break;
+ }
- /* Check if the buffer still exists. */
+ // Check if the buffer still exists.
bool buf_still_exists = false;
FOR_ALL_BUFFERS(bp) {
if (bp->b_fnum == next_fnum) {
@@ -2151,8 +2126,8 @@ void ex_listdo(exarg_T *eap)
break;
}
- /* Go to the next buffer. Clear 'shm' to avoid that the file
- * message overwrites any output from the command. */
+ // Go to the next buffer. Clear 'shm' to avoid that the file
+ // message overwrites any output from the command.
p_shm_save = vim_strsave(p_shm);
set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
@@ -2178,15 +2153,16 @@ void ex_listdo(exarg_T *eap)
// If jumping to the next quickfix entry fails, quit here.
if (qf_get_cur_idx(eap) == qf_idx) {
- break;
+ break;
}
}
if (eap->cmdidx == CMD_windo) {
- validate_cursor(); /* cursor may have moved */
- /* required when 'scrollbind' has been set */
- if (curwin->w_p_scb)
- do_check_scrollbind(TRUE);
+ validate_cursor(); // cursor may have moved
+ // required when 'scrollbind' has been set
+ if (curwin->w_p_scb) {
+ do_check_scrollbind(true);
+ }
}
if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo) {
if (i + 1 > eap->line2) {
@@ -2197,54 +2173,53 @@ void ex_listdo(exarg_T *eap)
break;
}
}
- listcmd_busy = FALSE;
+ listcmd_busy = false;
}
if (save_ei != NULL) {
au_event_restore(save_ei);
apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
- curbuf->b_fname, TRUE, curbuf);
+ curbuf->b_fname, true, curbuf);
}
end_global_changes();
}
-/*
- * Add files[count] to the arglist of the current window after arg "after".
- * The file names in files[count] must have been allocated and are taken over.
- * Files[] itself is not taken over.
- * Returns index of first added argument.
- */
-static int
-alist_add_list (
- int count,
- char_u **files,
- int after /* where to add: 0 = before first one */
-)
+/// Add files[count] to the arglist of the current window after arg "after".
+/// The file names in files[count] must have been allocated and are taken over.
+/// Files[] itself is not taken over.
+///
+/// @param after: where to add: 0 = before first one
+///
+/// @return index of first added argument
+static int alist_add_list(int count, char_u **files, int after)
{
+ int old_argcount = ARGCOUNT;
ga_grow(&ALIST(curwin)->al_ga, count);
{
- if (after < 0)
+ if (after < 0) {
after = 0;
- if (after > ARGCOUNT)
+ }
+ if (after > ARGCOUNT) {
after = ARGCOUNT;
- if (after < ARGCOUNT)
+ }
+ if (after < ARGCOUNT) {
memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
(size_t)(ARGCOUNT - after) * sizeof(aentry_T));
- for (int i = 0; i < count; ++i) {
+ }
+ for (int i = 0; i < count; i++) {
ARGLIST[after + i].ae_fname = files[i];
ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
}
ALIST(curwin)->al_ga.ga_len += count;
- if (curwin->w_arg_idx >= after)
- ++curwin->w_arg_idx;
+ if (old_argcount > 0 && curwin->w_arg_idx >= after) {
+ curwin->w_arg_idx += count;
+ }
return after;
}
}
-/*
- * ":compiler[!] {name}"
- */
+/// ":compiler[!] {name}"
void ex_compiler(exarg_T *eap)
{
char_u *buf;
@@ -2252,134 +2227,148 @@ void ex_compiler(exarg_T *eap)
char_u *p;
if (*eap->arg == NUL) {
- /* List all compiler scripts. */
- do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')");
- /* ) keep the indenter happy... */
+ // List all compiler scripts.
+ do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')"); // NOLINT
} else {
- buf = xmalloc(STRLEN(eap->arg) + 14);
+ size_t bufsize = STRLEN(eap->arg) + 14;
+ buf = xmalloc(bufsize);
if (eap->forceit) {
- /* ":compiler! {name}" sets global options */
+ // ":compiler! {name}" sets global options
do_cmdline_cmd("command -nargs=* CompilerSet set <args>");
} else {
- /* ":compiler! {name}" sets local options.
- * To remain backwards compatible "current_compiler" is always
- * used. A user's compiler plugin may set it, the distributed
- * plugin will then skip the settings. Afterwards set
- * "b:current_compiler" and restore "current_compiler".
- * Explicitly prepend "g:" to make it work in a function. */
+ // ":compiler! {name}" sets local options.
+ // To remain backwards compatible "current_compiler" is always
+ // used. A user's compiler plugin may set it, the distributed
+ // plugin will then skip the settings. Afterwards set
+ // "b:current_compiler" and restore "current_compiler".
+ // Explicitly prepend "g:" to make it work in a function.
old_cur_comp = get_var_value((char_u *)"g:current_compiler");
- if (old_cur_comp != NULL)
+ if (old_cur_comp != NULL) {
old_cur_comp = vim_strsave(old_cur_comp);
+ }
do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>");
}
- do_unlet((char_u *)"g:current_compiler", TRUE);
- do_unlet((char_u *)"b:current_compiler", TRUE);
+ do_unlet((char_u *)"g:current_compiler", true);
+ do_unlet((char_u *)"b:current_compiler", true);
- sprintf((char *)buf, "compiler/%s.vim", eap->arg);
- if (source_runtime(buf, TRUE) == FAIL)
+ snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
+ if (source_runtime(buf, DIP_ALL) == FAIL) {
EMSG2(_("E666: compiler not supported: %s"), eap->arg);
+ }
xfree(buf);
do_cmdline_cmd(":delcommand CompilerSet");
- /* Set "b:current_compiler" from "current_compiler". */
+ // Set "b:current_compiler" from "current_compiler".
p = get_var_value((char_u *)"g:current_compiler");
- if (p != NULL)
+ if (p != NULL) {
set_internal_string_var((char_u *)"b:current_compiler", p);
+ }
- /* Restore "current_compiler" for ":compiler {name}". */
+ // Restore "current_compiler" for ":compiler {name}".
if (!eap->forceit) {
if (old_cur_comp != NULL) {
set_internal_string_var((char_u *)"g:current_compiler",
- old_cur_comp);
+ old_cur_comp);
xfree(old_cur_comp);
- } else
- do_unlet((char_u *)"g:current_compiler", TRUE);
+ } else {
+ do_unlet((char_u *)"g:current_compiler", true);
+ }
}
}
}
-/*
- * ":runtime {name}"
- */
+/// ":runtime [what] {name}"
void ex_runtime(exarg_T *eap)
{
- source_runtime(eap->arg, eap->forceit);
+ char_u *arg = eap->arg;
+ char_u *p = skiptowhite(arg);
+ ptrdiff_t len = p - arg;
+ int flags = eap->forceit ? DIP_ALL : 0;
+
+ if (STRNCMP(arg, "START", len) == 0) {
+ flags += DIP_START + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ } else if (STRNCMP(arg, "OPT", len) == 0) {
+ flags += DIP_OPT + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ } else if (STRNCMP(arg, "PACK", len) == 0) {
+ flags += DIP_START + DIP_OPT + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ } else if (STRNCMP(arg, "ALL", len) == 0) {
+ flags += DIP_START + DIP_OPT;
+ arg = skipwhite(arg + len);
+ }
+
+ source_runtime(arg, flags);
}
static void source_callback(char_u *fname, void *cookie)
{
- (void)do_source(fname, FALSE, DOSO_NONE);
+ (void)do_source(fname, false, DOSO_NONE);
}
-/*
- * Source the file "name" from all directories in 'runtimepath'.
- * "name" can contain wildcards.
- * When "all" is TRUE, source all files, otherwise only the first one.
- * return FAIL when no file could be sourced, OK otherwise.
- */
-int source_runtime(char_u *name, int all)
+/// Source the file "name" from all directories in 'runtimepath'.
+/// "name" can contain wildcards.
+/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
+///
+/// return FAIL when no file could be sourced, OK otherwise.
+int source_runtime(char_u *name, int flags)
{
- return do_in_runtimepath(name, all, source_callback, NULL);
+ return do_in_runtimepath(name, flags, source_callback, NULL);
}
-/*
- * Find "name" in 'runtimepath'. When found, invoke the callback function for
- * it: callback(fname, "cookie")
- * When "all" is TRUE repeat for all matches, otherwise only the first one is
- * used.
- * Returns OK when at least one match found, FAIL otherwise.
- *
- * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
- * passed by reference in this case, setting it to NULL indicates that callback
- * has done its job.
- */
-int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback,
- void *cookie)
+/// Find the file "name" in all directories in "path" and invoke
+/// "callback(fname, cookie)".
+/// "name" can contain wildcards.
+/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
+/// When "flags" has DIP_DIR: find directories instead of files.
+/// When "flags" has DIP_ERR: give an error message if there is no match.
+///
+/// return FAIL when no file could be sourced, OK otherwise.
+int do_in_path(char_u *path, char_u *name, int flags,
+ DoInRuntimepathCB callback, void *cookie)
{
- char_u *rtp;
- char_u *np;
- char_u *buf;
- char_u *rtp_copy;
char_u *tail;
int num_files;
char_u **files;
int i;
- int did_one = FALSE;
+ bool did_one = false;
- /* Make a copy of 'runtimepath'. Invoking the callback may change the
- * value. */
- rtp_copy = vim_strsave(p_rtp);
- buf = xmallocz(MAXPATHL);
+ // Make a copy of 'runtimepath'. Invoking the callback may change the
+ // value.
+ char_u *rtp_copy = vim_strsave(path);
+ char_u *buf = xmallocz(MAXPATHL);
{
if (p_verbose > 1 && name != NULL) {
verbose_enter();
smsg(_("Searching for \"%s\" in \"%s\""),
- (char *)name, (char *)p_rtp);
+ (char *)name, (char *)path);
verbose_leave();
}
- /* Loop over all entries in 'runtimepath'. */
- rtp = rtp_copy;
- while (*rtp != NUL && (all || !did_one)) {
- /* Copy the path from 'runtimepath' to buf[]. */
+ // Loop over all entries in 'runtimepath'.
+ char_u *rtp = rtp_copy;
+ while (*rtp != NUL && ((flags & DIP_ALL) || !did_one)) {
+ // Copy the path from 'runtimepath' to buf[].
copy_option_part(&rtp, buf, MAXPATHL, ",");
if (name == NULL) {
- (*callback)(buf, (void *) &cookie);
- if (!did_one)
+ (*callback)(buf, (void *)&cookie);
+ if (!did_one) {
did_one = (cookie == NULL);
+ }
} else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) {
add_pathsep((char *)buf);
tail = buf + STRLEN(buf);
- /* Loop over all patterns in "name" */
- np = name;
- while (*np != NUL && (all || !did_one)) {
- /* Append the pattern from "name" to buf[]. */
+ // Loop over all patterns in "name"
+ char_u *np = name;
+ while (*np != NUL && ((flags & DIP_ALL) || !did_one)) {
+ // Append the pattern from "name" to buf[].
assert(MAXPATHL >= (tail - buf));
copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)),
- "\t ");
+ "\t ");
if (p_verbose > 2) {
verbose_enter();
@@ -2387,14 +2376,16 @@ int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback,
verbose_leave();
}
- /* Expand wildcards, invoke the callback for each match. */
+ // Expand wildcards, invoke the callback for each match.
if (gen_expand_wildcards(1, &buf, &num_files, &files,
- EW_FILE) == OK) {
- for (i = 0; i < num_files; ++i) {
+ (flags & DIP_DIR) ? EW_DIR
+ : EW_FILE) == OK) {
+ for (i = 0; i < num_files; i++) {
(*callback)(files[i], cookie);
- did_one = TRUE;
- if (!all)
+ did_one = true;
+ if (!(flags & DIP_ALL)) {
break;
+ }
}
FreeWild(num_files, files);
}
@@ -2404,27 +2395,235 @@ int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback,
}
xfree(buf);
xfree(rtp_copy);
- if (p_verbose > 0 && !did_one && name != NULL) {
- verbose_enter();
- smsg(_("not found in 'runtimepath': \"%s\""), name);
- verbose_leave();
+ if (!did_one && name != NULL) {
+ char *basepath = path == p_rtp ? "runtimepath" : "packpath";
+
+ if (flags & DIP_ERR) {
+ EMSG3(_(e_dirnotf), basepath, name);
+ } else if (p_verbose > 0) {
+ verbose_enter();
+ smsg(_("not found in '%s': \"%s\""), basepath, name);
+ verbose_leave();
+ }
}
return did_one ? OK : FAIL;
}
-/*
- * ":options"
- */
+/// Find "name" in 'runtimepath'. When found, invoke the callback function for
+/// it: callback(fname, "cookie")
+/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
+/// one is used.
+/// Returns OK when at least one match found, FAIL otherwise.
+/// If "name" is NULL calls callback for each entry in runtimepath. Cookie is
+/// passed by reference in this case, setting it to NULL indicates that callback
+/// has done its job.
+int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
+ void *cookie)
+{
+ int done = FAIL;
+
+ if ((flags & DIP_NORTP) == 0) {
+ done = do_in_path(p_rtp, name, flags, callback, cookie);
+ }
+
+ if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) {
+ char *start_dir = "pack/*/start/*/%s"; // NOLINT
+ size_t len = STRLEN(start_dir) + STRLEN(name);
+ char_u *s = xmallocz(len);
+
+ vim_snprintf((char *)s, len, start_dir, name);
+ done = do_in_path(p_pp, s, flags, callback, cookie);
+
+ xfree(s);
+ }
+
+ if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT)) {
+ char *opt_dir = "pack/*/opt/*/%s"; // NOLINT
+ size_t len = STRLEN(opt_dir) + STRLEN(name);
+ char_u *s = xmallocz(len);
+
+ vim_snprintf((char *)s, len, opt_dir, name);
+ done = do_in_path(p_pp, s, flags, callback, cookie);
+
+ xfree(s);
+ }
+
+ return done;
+}
+
+// Expand wildcards in "pat" and invoke do_source() for each match.
+static void source_all_matches(char_u *pat)
+{
+ int num_files;
+ char_u **files;
+
+ if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK) {
+ for (int i = 0; i < num_files; i++) {
+ (void)do_source(files[i], false, DOSO_NONE);
+ }
+ FreeWild(num_files, files);
+ }
+}
+
+// used for "cookie" of add_pack_plugin()
+static int APP_ADD_DIR;
+static int APP_LOAD;
+static int APP_BOTH;
+
+static void add_pack_plugin(char_u *fname, void *cookie)
+{
+ char_u *p4, *p3, *p2, *p1, *p;
+ char_u *new_rtp;
+ char_u *ffname = (char_u *)fix_fname((char *)fname);
+
+ if (ffname == NULL) {
+ return;
+ }
+
+ if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL) {
+ // directory is not yet in 'runtimepath', add it
+ p4 = p3 = p2 = p1 = get_past_head(ffname);
+ for (p = p1; *p; mb_ptr_adv(p)) {
+ if (vim_ispathsep_nocolon(*p)) {
+ p4 = p3; p3 = p2; p2 = p1; p1 = p;
+ }
+ }
+
+ // now we have:
+ // rtp/pack/name/start/name
+ // p4 p3 p2 p1
+ //
+ // find the part up to "pack" in 'runtimepath'
+ char_u c = *p4;
+ *p4 = NUL;
+
+ // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
+ size_t fname_len = STRLEN(ffname);
+ char_u *insp = p_rtp;
+ for (;;) {
+ if (vim_fnamencmp(insp, ffname, fname_len) == 0) {
+ break;
+ }
+ insp = vim_strchr(insp, ',');
+ if (insp == NULL) {
+ break;
+ }
+ insp++;
+ }
+
+ if (insp == NULL) {
+ // not found, append at the end
+ insp = p_rtp + STRLEN(p_rtp);
+ } else {
+ // append after the matching directory.
+ insp += STRLEN(ffname);
+ while (*insp != NUL && *insp != ',') {
+ insp++;
+ }
+ }
+ *p4 = c;
+
+ // check if rtp/pack/name/start/name/after exists
+ char *afterdir = concat_fnames((char *)ffname, "after", true);
+ size_t afterlen = 0;
+ if (os_isdir((char_u *)afterdir)) {
+ afterlen = STRLEN(afterdir) + 1; // add one for comma
+ }
+
+ size_t oldlen = STRLEN(p_rtp);
+ size_t addlen = STRLEN(ffname) + 1; // add one for comma
+ new_rtp = try_malloc(oldlen + addlen + afterlen + 1); // add one for NUL
+ if (new_rtp == NULL) {
+ goto theend;
+ }
+ uintptr_t keep = (uintptr_t)(insp - p_rtp);
+ memmove(new_rtp, p_rtp, keep);
+ new_rtp[keep] = ',';
+ memmove(new_rtp + keep + 1, ffname, addlen);
+ if (p_rtp[keep] != NUL) {
+ memmove(new_rtp + keep + addlen, p_rtp + keep,
+ oldlen - keep + 1);
+ }
+ if (afterlen > 0) {
+ STRCAT(new_rtp, ",");
+ STRCAT(new_rtp, afterdir);
+ }
+ set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
+ xfree(new_rtp);
+ xfree(afterdir);
+ }
+
+ if (cookie != &APP_ADD_DIR) {
+ static const char *plugpat = "%s/plugin/*.vim"; // NOLINT
+ static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT
+
+ size_t len = STRLEN(ffname) + STRLEN(ftpat);
+ char_u *pat = try_malloc(len + 1);
+ if (pat == NULL) {
+ goto theend;
+ }
+ vim_snprintf((char *)pat, len, plugpat, ffname);
+ source_all_matches(pat);
+
+ char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
+
+ // If runtime/filetype.vim wasn't loaded yet, the scripts will be
+ // found when it loads.
+ if (eval_to_number(cmd) > 0) {
+ do_cmdline_cmd("augroup filetypedetect");
+ vim_snprintf((char *)pat, len, ftpat, ffname);
+ source_all_matches(pat);
+ do_cmdline_cmd("augroup END");
+ }
+ xfree(cmd);
+ xfree(pat);
+ }
+
+theend:
+ xfree(ffname);
+}
+
+static bool did_source_packages = false;
+
+// ":packloadall"
+// Find plugins in the package directories and source them.
+void ex_packloadall(exarg_T *eap)
+{
+ if (!did_source_packages || (eap != NULL && eap->forceit)) {
+ did_source_packages = true;
+
+ // First do a round to add all directories to 'runtimepath', then load
+ // the plugins. This allows for plugins to use an autoload directory
+ // of another plugin.
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
+ add_pack_plugin, &APP_ADD_DIR);
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
+ add_pack_plugin, &APP_LOAD);
+ }
+}
+
+/// ":packadd[!] {name}"
+void ex_packadd(exarg_T *eap)
+{
+ static const char *plugpat = "pack/*/opt/%s"; // NOLINT
+
+ size_t len = STRLEN(plugpat) + STRLEN(eap->arg);
+ char *pat = (char *)xmallocz(len);
+ vim_snprintf(pat, len, plugpat, eap->arg);
+ do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR, add_pack_plugin,
+ eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
+ xfree(pat);
+}
+
+/// ":options"
void ex_options(exarg_T *eap)
{
cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
}
-/*
- * ":source {fname}"
- */
+/// ":source {fname}"
void ex_source(exarg_T *eap)
{
cmd_source(eap->arg, eap);
@@ -2432,96 +2631,82 @@ void ex_source(exarg_T *eap)
static void cmd_source(char_u *fname, exarg_T *eap)
{
- if (*fname == NUL)
+ if (*fname == NUL) {
EMSG(_(e_argreq));
-
- else if (eap != NULL && eap->forceit)
- /* ":source!": read Normal mode commands
- * Need to execute the commands directly. This is required at least
- * for:
- * - ":g" command busy
- * - after ":argdo", ":windo" or ":bufdo"
- * - another command follows
- * - inside a loop
- */
+ } else if (eap != NULL && eap->forceit) {
+ // ":source!": read Normal mode commands
+ // Need to execute the commands directly. This is required at least
+ // for:
+ // - ":g" command busy
+ // - after ":argdo", ":windo" or ":bufdo"
+ // - another command follows
+ // - inside a loop
openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
- || eap->cstack->cs_idx >= 0
- );
+ || eap->cstack->cs_idx >= 0);
- /* ":source" read ex commands */
- else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
+ // ":source" read ex commands
+ } else if (do_source(fname, false, DOSO_NONE) == FAIL) {
EMSG2(_(e_notopen), fname);
+ }
}
-/*
- * ":source" and associated commands.
- */
-
-/*
- * Return the address holding the next breakpoint line for a source cookie.
- */
+/// ":source" and associated commands.
+///
+/// @return address holding the next breakpoint line for a source cookie
linenr_T *source_breakpoint(void *cookie)
{
return &((struct source_cookie *)cookie)->breakpoint;
}
-/*
- * Return the address holding the debug tick for a source cookie.
- */
+/// Return the address holding the debug tick for a source cookie.
int *source_dbg_tick(void *cookie)
{
return &((struct source_cookie *)cookie)->dbg_tick;
}
-/*
- * Return the nesting level for a source cookie.
- */
+/// Return the nesting level for a source cookie.
int source_level(void *cookie)
{
return ((struct source_cookie *)cookie)->level;
}
-
-#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
-# define USE_FOPEN_NOINH
-/*
- * Special function to open a file without handle inheritance.
- * When possible the handle is closed on exec().
- */
+/// Special function to open a file without handle inheritance.
+/// If possible the handle is closed on exec().
static FILE *fopen_noinh_readbin(char *filename)
{
+#ifdef WIN32
+ int fd_tmp = os_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
+#else
int fd_tmp = os_open(filename, O_RDONLY, 0);
+#endif
- if (fd_tmp < 0)
+ if (fd_tmp < 0) {
return NULL;
+ }
-# ifdef HAVE_FD_CLOEXEC
+#ifdef HAVE_FD_CLOEXEC
{
int fdflags = fcntl(fd_tmp, F_GETFD);
if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
(void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
}
}
-# endif
+#endif
return fdopen(fd_tmp, READBIN);
}
-#endif
-/*
- * do_source: Read the file "fname" and execute its lines as EX commands.
- *
- * This function may be called recursively!
- *
- * return FAIL if file could not be opened, OK otherwise
- */
-int
-do_source (
- char_u *fname,
- int check_other, /* check for .vimrc and _vimrc */
- int is_vimrc /* DOSO_ value */
-)
+/// Read the file "fname" and execute its lines as EX commands.
+///
+/// This function may be called recursively!
+///
+/// @param fname
+/// @param check_other check for .vimrc and _vimrc
+/// @param is_vimrc DOSO_ value
+///
+/// @return FAIL if file could not be opened, OK otherwise
+int do_source(char_u *fname, int check_other, int is_vimrc)
{
struct source_cookie cookie;
char_u *save_sourcing_name;
@@ -2538,125 +2723,113 @@ do_source (
proftime_T wait_start;
p = expand_env_save(fname);
- if (p == NULL)
+ if (p == NULL) {
return retval;
+ }
fname_exp = (char_u *)fix_fname((char *)p);
xfree(p);
- if (fname_exp == NULL)
+ if (fname_exp == NULL) {
return retval;
+ }
if (os_isdir(fname_exp)) {
smsg(_("Cannot source a directory: \"%s\""), fname);
goto theend;
}
- /* Apply SourceCmd autocommands, they should get the file and source it. */
+ // Apply SourceCmd autocommands, they should get the file and source it.
if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
- FALSE, curbuf)) {
+ false, curbuf)) {
retval = aborting() ? FAIL : OK;
goto theend;
}
- /* Apply SourcePre autocommands, they may get the file. */
- apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
+ // Apply SourcePre autocommands, they may get the file.
+ apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, false, curbuf);
-#ifdef USE_FOPEN_NOINH
cookie.fp = fopen_noinh_readbin((char *)fname_exp);
-#else
- cookie.fp = mch_fopen((char *)fname_exp, READBIN);
-#endif
if (cookie.fp == NULL && check_other) {
- /*
- * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
- * and ".exrc" by "_exrc" or vice versa.
- */
+ // Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
+ // and ".exrc" by "_exrc" or vice versa.
p = path_tail(fname_exp);
if ((*p == '.' || *p == '_')
&& (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) {
- if (*p == '_')
- *p = '.';
- else
- *p = '_';
-#ifdef USE_FOPEN_NOINH
+ *p = (*p == '_') ? '.' : '_';
cookie.fp = fopen_noinh_readbin((char *)fname_exp);
-#else
- cookie.fp = mch_fopen((char *)fname_exp, READBIN);
-#endif
}
}
if (cookie.fp == NULL) {
if (p_verbose > 0) {
verbose_enter();
- if (sourcing_name == NULL)
+ if (sourcing_name == NULL) {
smsg(_("could not source \"%s\""), fname);
- else
+ } else {
smsg(_("line %" PRId64 ": could not source \"%s\""),
- (int64_t)sourcing_lnum, fname);
+ (int64_t)sourcing_lnum, fname);
+ }
verbose_leave();
}
goto theend;
}
- /*
- * The file exists.
- * - In verbose mode, give a message.
- * - For a vimrc file, may want to call vimrc_found().
- */
+ // The file exists.
+ // - In verbose mode, give a message.
+ // - For a vimrc file, may want to call vimrc_found().
if (p_verbose > 1) {
verbose_enter();
- if (sourcing_name == NULL)
+ if (sourcing_name == NULL) {
smsg(_("sourcing \"%s\""), fname);
- else
+ } else {
smsg(_("line %" PRId64 ": sourcing \"%s\""),
- (int64_t)sourcing_lnum, fname);
+ (int64_t)sourcing_lnum, fname);
+ }
verbose_leave();
}
- if (is_vimrc == DOSO_VIMRC)
+ if (is_vimrc == DOSO_VIMRC) {
vimrc_found(fname_exp, (char_u *)"MYVIMRC");
- else if (is_vimrc == DOSO_GVIMRC)
+ } else if (is_vimrc == DOSO_GVIMRC) {
vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
+ }
#ifdef USE_CRNL
- /* If no automatic file format: Set default to CR-NL. */
- if (*p_ffs == NUL)
+ // If no automatic file format: Set default to CR-NL.
+ if (*p_ffs == NUL) {
cookie.fileformat = EOL_DOS;
- else
+ } else {
cookie.fileformat = EOL_UNKNOWN;
- cookie.error = FALSE;
+ }
+ cookie.error = false;
#endif
cookie.nextline = NULL;
- cookie.finished = FALSE;
+ cookie.finished = false;
- /*
- * Check if this script has a breakpoint.
- */
- cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
+ // Check if this script has a breakpoint.
+ cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, (linenr_T)0);
cookie.fname = fname_exp;
cookie.dbg_tick = debug_tick;
cookie.level = ex_nesting_level;
- /*
- * Keep the sourcing name/lnum, for recursive calls.
- */
+ // Keep the sourcing name/lnum, for recursive calls.
save_sourcing_name = sourcing_name;
sourcing_name = fname_exp;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 0;
- cookie.conv.vc_type = CONV_NONE; /* no conversion */
+ cookie.conv.vc_type = CONV_NONE; // no conversion
- /* Read the first line so we can check for a UTF-8 BOM. */
+ // Read the first line so we can check for a UTF-8 BOM.
firstline = getsourceline(0, (void *)&cookie, 0);
if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
&& firstline[1] == 0xbb && firstline[2] == 0xbf) {
- /* Found BOM; setup conversion, skip over BOM and recode the line. */
+ // Found BOM; setup conversion, skip over BOM and recode the line.
convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
p = string_convert(&cookie.conv, firstline + 3, NULL);
- if (p == NULL)
+ if (p == NULL) {
p = vim_strsave(firstline + 3);
+ }
xfree(firstline);
firstline = p;
}
@@ -2671,22 +2844,21 @@ do_source (
}
const int l_do_profiling = do_profiling;
- if (l_do_profiling == PROF_YES)
- prof_child_enter(&wait_start); /* entering a child now */
+ if (l_do_profiling == PROF_YES) {
+ prof_child_enter(&wait_start); // entering a child now
+ }
- /* Don't use local function variables, if called from a function.
- * Also starts profiling timer for nested script. */
+ // Don't use local function variables, if called from a function.
+ // Also starts profiling timer for nested script.
save_funccalp = save_funccal();
- /*
- * Check if this script was sourced before to finds its SID.
- * If it's new, generate a new SID.
- */
+ // Check if this script was sourced before to finds its SID.
+ // If it's new, generate a new SID.
save_current_SID = current_SID;
FileID file_id;
bool file_id_ok = os_fileid((char *)fname_exp, &file_id);
assert(script_items.ga_len >= 0);
- for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) {
+ 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.
@@ -2701,7 +2873,7 @@ do_source (
current_SID = ++last_current_SID;
ga_grow(&script_items, (int)(current_SID - script_items.ga_len));
while (script_items.ga_len < current_SID) {
- ++script_items.ga_len;
+ script_items.ga_len++;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false;
}
@@ -2715,53 +2887,53 @@ do_source (
si->file_id_valid = false;
}
- /* Allocate the local script variables to use for this script. */
+ // Allocate the local script variables to use for this script.
new_script_vars(current_SID);
}
if (l_do_profiling == PROF_YES) {
- int forceit;
+ bool forceit;
- /* Check if we do profiling for this script. */
+ // Check if we do profiling for this script.
if (!si->sn_prof_on && has_profiling(true, si->sn_name, &forceit)) {
profile_init(si);
si->sn_pr_force = forceit;
}
if (si->sn_prof_on) {
- ++si->sn_pr_count;
+ si->sn_pr_count++;
si->sn_pr_start = profile_start();
si->sn_pr_children = profile_zero();
}
}
- /*
- * Call do_cmdline, which will call getsourceline() to get the lines.
- */
+ // Call do_cmdline, which will call getsourceline() to get the lines.
do_cmdline(firstline, getsourceline, (void *)&cookie,
- DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
retval = OK;
if (l_do_profiling == PROF_YES) {
- /* Get "si" again, "script_items" may have been reallocated. */
+ // Get "si" again, "script_items" may have been reallocated.
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on) {
si->sn_pr_start = profile_end(si->sn_pr_start);
si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start);
si->sn_pr_total = profile_add(si->sn_pr_total, si->sn_pr_start);
si->sn_pr_self = profile_self(si->sn_pr_self, si->sn_pr_start,
- si->sn_pr_children);
+ si->sn_pr_children);
}
}
- if (got_int)
+ if (got_int) {
EMSG(_(e_interr));
+ }
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
if (p_verbose > 1) {
verbose_enter();
smsg(_("finished sourcing %s"), fname);
- if (sourcing_name != NULL)
+ if (sourcing_name != NULL) {
smsg(_("continuing in %s"), sourcing_name);
+ }
verbose_leave();
}
@@ -2771,18 +2943,18 @@ do_source (
time_pop(rel_time);
}
- /*
- * After a "finish" in debug mode, need to break at first command of next
- * sourced file.
- */
+ // After a "finish" in debug mode, need to break at first command of next
+ // sourced file.
if (save_debug_break_level > ex_nesting_level
- && debug_break_level == ex_nesting_level)
- ++debug_break_level;
+ && debug_break_level == ex_nesting_level) {
+ debug_break_level++;
+ }
current_SID = save_current_SID;
restore_funccal(save_funccalp);
- if (l_do_profiling == PROF_YES)
- prof_child_exit(&wait_start); /* leaving a child now */
+ if (l_do_profiling == PROF_YES) {
+ prof_child_exit(&wait_start); // leaving a child now
+ }
fclose(cookie.fp);
xfree(cookie.nextline);
xfree(firstline);
@@ -2794,26 +2966,23 @@ theend:
}
-/*
- * ":scriptnames"
- */
+/// ":scriptnames"
void ex_scriptnames(exarg_T *eap)
{
- for (int i = 1; i <= script_items.ga_len && !got_int; ++i)
+ for (int i = 1; i <= script_items.ga_len && !got_int; i++) {
if (SCRIPT_ITEM(i).sn_name != NULL) {
home_replace(NULL, SCRIPT_ITEM(i).sn_name,
- NameBuff, MAXPATHL, TRUE);
+ NameBuff, MAXPATHL, true);
smsg("%3d: %s", i, NameBuff);
}
+ }
}
# if defined(BACKSLASH_IN_FILENAME)
-/*
- * Fix slashes in the list of script names for 'shellslash'.
- */
+/// Fix slashes in the list of script names for 'shellslash'.
void scriptnames_slash_adjust(void)
{
- for (int i = 1; i <= script_items.ga_len; ++i) {
+ for (int i = 1; i <= script_items.ga_len; i++) {
if (SCRIPT_ITEM(i).sn_name != NULL) {
slash_adjust(SCRIPT_ITEM(i).sn_name);
}
@@ -2822,21 +2991,24 @@ void scriptnames_slash_adjust(void)
# endif
-/*
- * Get a pointer to a script name. Used for ":verbose set".
- */
+/// Get a pointer to a script name. Used for ":verbose set".
char_u *get_scriptname(scid_T id)
{
- if (id == SID_MODELINE)
+ if (id == SID_MODELINE) {
return (char_u *)_("modeline");
- if (id == SID_CMDARG)
+ }
+ if (id == SID_CMDARG) {
return (char_u *)_("--cmd argument");
- if (id == SID_CARG)
+ }
+ if (id == SID_CARG) {
return (char_u *)_("-c argument");
- if (id == SID_ENV)
+ }
+ if (id == SID_ENV) {
return (char_u *)_("environment variable");
- if (id == SID_ERROR)
+ }
+ if (id == SID_ERROR) {
return (char_u *)_("error handler");
+ }
return SCRIPT_ITEM(id).sn_name;
}
@@ -2849,51 +3021,49 @@ void free_scriptnames(void)
# endif
-/*
- * Get one full line from a sourced file.
- * Called by do_cmdline() when it's called from do_source().
- *
- * Return a pointer to the line in allocated memory.
- * Return NULL for end-of-file or some error.
- */
+/// Get one full line from a sourced file.
+/// Called by do_cmdline() when it's called from do_source().
+///
+/// @return pointer to the line in allocated memory, or NULL for end-of-file or
+/// some error.
char_u *getsourceline(int c, void *cookie, int indent)
{
struct source_cookie *sp = (struct source_cookie *)cookie;
- char_u *line;
- char_u *p;
+ char_u *line;
+ char_u *p;
- /* If breakpoints have been added/deleted need to check for it. */
+ // If breakpoints have been added/deleted need to check for it.
if (sp->dbg_tick < debug_tick) {
- sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+ sp->breakpoint = dbg_find_breakpoint(true, sp->fname, sourcing_lnum);
sp->dbg_tick = debug_tick;
}
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
script_line_end();
- /*
- * Get current line. If there is a read-ahead line, use it, otherwise get
- * one now.
- */
- if (sp->finished)
+ }
+ // Get current line. If there is a read-ahead line, use it, otherwise get
+ // one now.
+ if (sp->finished) {
line = NULL;
- else if (sp->nextline == NULL)
+ } else if (sp->nextline == NULL) {
line = get_one_sourceline(sp);
- else {
+ } else {
line = sp->nextline;
sp->nextline = NULL;
- ++sourcing_lnum;
+ sourcing_lnum++;
}
- if (line != NULL && do_profiling == PROF_YES)
+ if (line != NULL && do_profiling == PROF_YES) {
script_line_start();
+ }
- /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
- * contain the 'C' flag. */
+ // Only concatenate lines starting with a \ when 'cpoptions' doesn't
+ // contain the 'C' flag.
if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) {
- /* compensate for the one line read-ahead */
- --sourcing_lnum;
+ // compensate for the one line read-ahead
+ sourcing_lnum--;
- /* Get the next line and concatenate it when it starts with a
- * backslash. We always need to read the next line, keep it in
- * sp->nextline. */
+ // Get the next line and concatenate it when it starts with a
+ // backslash. We always need to read the next line, keep it in
+ // sp->nextline.
sp->nextline = get_one_sourceline(sp);
if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\') {
garray_T ga;
@@ -2904,13 +3074,15 @@ char_u *getsourceline(int c, void *cookie, int indent)
for (;; ) {
xfree(sp->nextline);
sp->nextline = get_one_sourceline(sp);
- if (sp->nextline == NULL)
+ if (sp->nextline == NULL) {
break;
+ }
p = skipwhite(sp->nextline);
- if (*p != '\\')
+ if (*p != '\\') {
break;
- /* Adjust the growsize to the current length to speed up
- * concatenating many lines. */
+ }
+ // Adjust the growsize to the current length to speed up
+ // concatenating many lines.
if (ga.ga_len > 400) {
ga_set_growsize(&ga, (ga.ga_len > 8000) ? 8000 : ga.ga_len);
}
@@ -2925,7 +3097,7 @@ char_u *getsourceline(int c, void *cookie, int indent)
if (line != NULL && sp->conv.vc_type != CONV_NONE) {
char_u *s;
- /* Convert the encoding of the script line. */
+ // Convert the encoding of the script line.
s = string_convert(&sp->conv, line, NULL);
if (s != NULL) {
xfree(line);
@@ -2933,11 +3105,11 @@ char_u *getsourceline(int c, void *cookie, int indent)
}
}
- /* Did we encounter a breakpoint? */
+ // Did we encounter a breakpoint?
if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) {
dbg_breakpoint(sp->fname, sourcing_lnum);
- /* Find next breakpoint. */
- sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+ // Find next breakpoint.
+ sp->breakpoint = dbg_find_breakpoint(true, sp->fname, sourcing_lnum);
sp->dbg_tick = debug_tick;
}
@@ -2951,175 +3123,170 @@ static char_u *get_one_sourceline(struct source_cookie *sp)
int c;
char_u *buf;
#ifdef USE_CRNL
- int has_cr; /* CR-LF found */
+ int has_cr; // CR-LF found
#endif
- int have_read = FALSE;
+ bool have_read = false;
- /* use a growarray to store the sourced line */
+ // use a growarray to store the sourced line
ga_init(&ga, 1, 250);
- /*
- * Loop until there is a finished line (or end-of-file).
- */
+ // Loop until there is a finished line (or end-of-file).
sourcing_lnum++;
for (;; ) {
- /* make room to read at least 120 (more) characters */
+ // make room to read at least 120 (more) characters
ga_grow(&ga, 120);
buf = (char_u *)ga.ga_data;
if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
- sp->fp) == NULL)
+ sp->fp) == NULL) {
break;
+ }
len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
#ifdef USE_CRNL
- /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
- * CTRL-Z by its own, or after a NL. */
- if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
- && sp->fileformat == EOL_DOS
- && buf[len - 1] == Ctrl_Z) {
+ // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
+ // CTRL-Z by its own, or after a NL.
+ if ((len == 1 || (len >= 2 && buf[len - 2] == '\n'))
+ && sp->fileformat == EOL_DOS
+ && buf[len - 1] == Ctrl_Z) {
buf[len - 1] = NUL;
break;
}
#endif
- have_read = TRUE;
+ have_read = true;
ga.ga_len = len;
- /* If the line was longer than the buffer, read more. */
- if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
+ // If the line was longer than the buffer, read more.
+ if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') {
continue;
+ }
- if (len >= 1 && buf[len - 1] == '\n') { /* remove trailing NL */
+ if (len >= 1 && buf[len - 1] == '\n') { // remove trailing NL
#ifdef USE_CRNL
has_cr = (len >= 2 && buf[len - 2] == '\r');
if (sp->fileformat == EOL_UNKNOWN) {
- if (has_cr)
+ if (has_cr) {
sp->fileformat = EOL_DOS;
- else
+ } else {
sp->fileformat = EOL_UNIX;
+ }
}
if (sp->fileformat == EOL_DOS) {
- if (has_cr) { /* replace trailing CR */
+ if (has_cr) { // replace trailing CR
buf[len - 2] = '\n';
- --len;
- --ga.ga_len;
- } else { /* lines like ":map xx yy^M" will have failed */
+ len--;
+ ga.ga_len--;
+ } else { // lines like ":map xx yy^M" will have failed
if (!sp->error) {
msg_source(hl_attr(HLF_W));
EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
}
- sp->error = TRUE;
+ sp->error = true;
sp->fileformat = EOL_UNIX;
}
}
#endif
- /* The '\n' is escaped if there is an odd number of ^V's just
- * before it, first set "c" just before the 'V's and then check
- * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
- for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
- ;
- if ((len & 1) != (c & 1)) { /* escaped NL, read more */
+ // The '\n' is escaped if there is an odd number of ^V's just
+ // before it, first set "c" just before the 'V's and then check
+ // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo
+ for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {}
+ if ((len & 1) != (c & 1)) { // escaped NL, read more
sourcing_lnum++;
continue;
}
- buf[len - 1] = NUL; /* remove the NL */
+ buf[len - 1] = NUL; // remove the NL
}
- /*
- * Check for ^C here now and then, so recursive :so can be broken.
- */
+ // Check for ^C here now and then, so recursive :so can be broken.
line_breakcheck();
break;
}
- if (have_read)
+ if (have_read) {
return (char_u *)ga.ga_data;
+ }
xfree(ga.ga_data);
return NULL;
}
-/*
- * Called when starting to read a script line.
- * "sourcing_lnum" must be correct!
- * When skipping lines it may not actually be executed, but we won't find out
- * until later and we need to store the time now.
- */
+/// Called when starting to read a script line.
+/// "sourcing_lnum" must be correct!
+/// When skipping lines it may not actually be executed, but we won't find out
+/// until later and we need to store the time now.
void script_line_start(void)
{
scriptitem_T *si;
sn_prl_T *pp;
- if (current_SID <= 0 || current_SID > script_items.ga_len)
+ if (current_SID <= 0 || current_SID > script_items.ga_len) {
return;
+ }
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && sourcing_lnum >= 1) {
- /* Grow the array before starting the timer, so that the time spent
- * here isn't counted. */
+ // Grow the array before starting the timer, so that the time spent
+ // here isn't counted.
ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
si->sn_prl_idx = sourcing_lnum - 1;
while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
&& si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen) {
- /* Zero counters for a line that was not used before. */
+ // Zero counters for a line that was not used before.
pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
pp->snp_count = 0;
pp->sn_prl_total = profile_zero();
pp->sn_prl_self = profile_zero();
- ++si->sn_prl_ga.ga_len;
+ si->sn_prl_ga.ga_len++;
}
- si->sn_prl_execed = FALSE;
+ si->sn_prl_execed = false;
si->sn_prl_start = profile_start();
si->sn_prl_children = profile_zero();
si->sn_prl_wait = profile_get_wait();
}
}
-/*
- * Called when actually executing a function line.
- */
+/// Called when actually executing a function line.
void script_line_exec(void)
{
scriptitem_T *si;
- if (current_SID <= 0 || current_SID > script_items.ga_len)
+ if (current_SID <= 0 || current_SID > script_items.ga_len) {
return;
+ }
si = &SCRIPT_ITEM(current_SID);
- if (si->sn_prof_on && si->sn_prl_idx >= 0)
- si->sn_prl_execed = TRUE;
+ if (si->sn_prof_on && si->sn_prl_idx >= 0) {
+ si->sn_prl_execed = true;
+ }
}
-/*
- * Called when done with a function line.
- */
+/// Called when done with a function line.
void script_line_end(void)
{
scriptitem_T *si;
sn_prl_T *pp;
- if (current_SID <= 0 || current_SID > script_items.ga_len)
+ if (current_SID <= 0 || current_SID > script_items.ga_len) {
return;
+ }
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && si->sn_prl_idx >= 0
&& si->sn_prl_idx < si->sn_prl_ga.ga_len) {
if (si->sn_prl_execed) {
pp = &PRL_ITEM(si, si->sn_prl_idx);
- ++pp->snp_count;
+ pp->snp_count++;
si->sn_prl_start = profile_end(si->sn_prl_start);
si->sn_prl_start = profile_sub_wait(si->sn_prl_wait, si->sn_prl_start);
pp->sn_prl_total = profile_add(pp->sn_prl_total, si->sn_prl_start);
pp->sn_prl_self = profile_self(pp->sn_prl_self, si->sn_prl_start,
- si->sn_prl_children);
+ si->sn_prl_children);
}
si->sn_prl_idx = -1;
}
}
-/*
- * ":scriptencoding": Set encoding conversion for a sourced script.
- * Without the multi-byte feature it's simply ignored.
- */
+/// ":scriptencoding": Set encoding conversion for a sourced script.
+/// Without the multi-byte feature it's simply ignored.
void ex_scriptencoding(exarg_T *eap)
{
struct source_cookie *sp;
@@ -3132,84 +3299,80 @@ void ex_scriptencoding(exarg_T *eap)
if (*eap->arg != NUL) {
name = enc_canonize(eap->arg);
- } else
+ } else {
name = eap->arg;
+ }
- /* Setup for conversion from the specified encoding to 'encoding'. */
+ // Setup for conversion from the specified encoding to 'encoding'.
sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
convert_setup(&sp->conv, name, p_enc);
- if (name != eap->arg)
+ if (name != eap->arg) {
xfree(name);
+ }
}
-/*
- * ":finish": Mark a sourced file as finished.
- */
+/// ":finish": Mark a sourced file as finished.
void ex_finish(exarg_T *eap)
{
- if (getline_equal(eap->getline, eap->cookie, getsourceline))
- do_finish(eap, FALSE);
- else
+ if (getline_equal(eap->getline, eap->cookie, getsourceline)) {
+ do_finish(eap, false);
+ } else {
EMSG(_("E168: :finish used outside of a sourced file"));
+ }
}
-/*
- * Mark a sourced file as finished. Possibly makes the ":finish" pending.
- * Also called for a pending finish at the ":endtry" or after returning from
- * an extra do_cmdline(). "reanimate" is used in the latter case.
- */
+/// Mark a sourced file as finished. Possibly makes the ":finish" pending.
+/// Also called for a pending finish at the ":endtry" or after returning from
+/// an extra do_cmdline(). "reanimate" is used in the latter case.
void do_finish(exarg_T *eap, int reanimate)
{
int idx;
- if (reanimate)
+ if (reanimate) {
((struct source_cookie *)getline_cookie(eap->getline,
- eap->cookie))->finished = FALSE;
-
- /*
- * Cleanup (and inactivate) conditionals, but stop when a try conditional
- * not in its finally clause (which then is to be executed next) is found.
- * In this case, make the ":finish" pending for execution at the ":endtry".
- * Otherwise, finish normally.
- */
- idx = cleanup_conditionals(eap->cstack, 0, TRUE);
+ eap->cookie))->finished = false;
+ }
+
+ // Cleanup (and inactivate) conditionals, but stop when a try conditional
+ // not in its finally clause (which then is to be executed next) is found.
+ // In this case, make the ":finish" pending for execution at the ":endtry".
+ // Otherwise, finish normally.
+ idx = cleanup_conditionals(eap->cstack, 0, true);
if (idx >= 0) {
eap->cstack->cs_pending[idx] = CSTP_FINISH;
report_make_pending(CSTP_FINISH, NULL);
- } else
+ } else {
((struct source_cookie *)getline_cookie(eap->getline,
- eap->cookie))->finished = TRUE;
+ eap->cookie))->finished = true;
+ }
}
-/*
- * Return TRUE when a sourced file had the ":finish" command: Don't give error
- * message for missing ":endif".
- * Return FALSE when not sourcing a file.
- */
-int source_finished(LineGetter fgetline, void *cookie)
+/// Return true when a sourced file had the ":finish" command: Don't give error
+/// message for missing ":endif".
+/// Return false when not sourcing a file.
+bool source_finished(LineGetter fgetline, void *cookie)
{
return getline_equal(fgetline, cookie, getsourceline)
&& ((struct source_cookie *)getline_cookie(
- fgetline, cookie))->finished;
+ fgetline, cookie))->finished;
}
-/*
- * ":checktime [buffer]"
- */
+/// ":checktime [buffer]"
void ex_checktime(exarg_T *eap)
{
buf_T *buf;
int save_no_check_timestamps = no_check_timestamps;
no_check_timestamps = 0;
- if (eap->addr_count == 0) /* default is all buffers */
- check_timestamps(FALSE);
- else {
+ if (eap->addr_count == 0) { // default is all buffers
+ check_timestamps(false);
+ } else {
buf = buflist_findnr((int)eap->line2);
- if (buf != NULL) /* cannot happen? */
- (void)buf_check_timestamp(buf, FALSE);
+ if (buf != NULL) { // cannot happen?
+ (void)buf_check_timestamp(buf, false);
+ }
}
no_check_timestamps = save_no_check_timestamps;
}
@@ -3228,10 +3391,8 @@ static char *get_locale_val(int what)
-/*
- * Obtain the current messages language. Used to set the default for
- * 'helplang'. May return NULL or an empty string.
- */
+/// Obtain the current messages language. Used to set the default for
+/// 'helplang'. May return NULL or an empty string.
char *get_mess_lang(void)
{
char *p;
@@ -3240,10 +3401,10 @@ char *get_mess_lang(void)
# if defined(LC_MESSAGES)
p = get_locale_val(LC_MESSAGES);
# else
- /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
- * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
- * and LC_MONETARY may be set differently for a Japanese working in the
- * US. */
+ // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
+ // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
+ // and LC_MONETARY may be set differently for a Japanese working in the
+ // US.
p = get_locale_val(LC_COLLATE);
# endif
# else
@@ -3258,11 +3419,9 @@ char *get_mess_lang(void)
return p;
}
-/* Complicated #if; matches with where get_mess_env() is used below. */
+// Complicated #if; matches with where get_mess_env() is used below.
#ifdef HAVE_WORKING_LIBINTL
-/*
- * Get the language used for messages from the environment.
- */
+/// Get the language used for messages from the environment.
static char_u *get_mess_env(void)
{
char_u *p;
@@ -3273,7 +3432,7 @@ static char_u *get_mess_env(void)
if (p == NULL) {
p = (char_u *)os_getenv("LANG");
if (p != NULL && ascii_isdigit(*p)) {
- p = NULL; /* ignore something like "1043" */
+ p = NULL; // ignore something like "1043"
}
# ifdef HAVE_GET_LOCALE_VAL
if (p == NULL) {
@@ -3288,10 +3447,8 @@ static char_u *get_mess_env(void)
#endif
-/*
- * Set the "v:lang" variable according to the current locale setting.
- * Also do "v:lc_time"and "v:ctype".
- */
+/// Set the "v:lang" variable according to the current locale setting.
+/// Also do "v:lc_time"and "v:ctype".
void set_lang_var(void)
{
const char *loc;
@@ -3304,10 +3461,10 @@ void set_lang_var(void)
# endif
set_vim_var_string(VV_CTYPE, loc, -1);
- /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
- * back to LC_CTYPE if it's empty. */
+ // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
+ // back to LC_CTYPE if it's empty.
# ifdef HAVE_WORKING_LIBINTL
- loc = (char *) get_mess_env();
+ loc = (char *)get_mess_env();
# elif defined(LC_MESSAGES)
loc = get_locale_val(LC_MESSAGES);
# else
@@ -3323,9 +3480,11 @@ void set_lang_var(void)
}
#ifdef HAVE_WORKING_LIBINTL
-/*
- * ":language": Set the language (locale).
- */
+///
+/// ":language": Set the language (locale).
+///
+/// @param eap
+///
void ex_language(exarg_T *eap)
{
char *loc;
@@ -3341,9 +3500,9 @@ void ex_language(exarg_T *eap)
name = eap->arg;
- /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
- * Allow abbreviation, but require at least 3 characters to avoid
- * confusion with a two letter language name "me" or "ct". */
+ // Check for "messages {name}", "ctype {name}" or "time {name}" argument.
+ // Allow abbreviation, but require at least 3 characters to avoid
+ // confusion with a two letter language name "me" or "ct".
p = skiptowhite(eap->arg);
if ((*p == NUL || ascii_iswhite(*p)) && p - eap->arg >= 3) {
if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) {
@@ -3363,47 +3522,52 @@ void ex_language(exarg_T *eap)
if (*name == NUL) {
#ifdef HAVE_WORKING_LIBINTL
- if (what == VIM_LC_MESSAGES)
+ if (what == VIM_LC_MESSAGES) {
p = get_mess_env();
- else
+ } else {
+#endif
+ p = (char_u *)setlocale(what, NULL);
+#ifdef HAVE_WORKING_LIBINTL
+ }
#endif
- p = (char_u *)setlocale(what, NULL);
- if (p == NULL || *p == NUL)
+ if (p == NULL || *p == NUL) {
p = (char_u *)"Unknown";
+ }
smsg(_("Current %slanguage: \"%s\""), whatstr, p);
} else {
#ifndef LC_MESSAGES
- if (what == VIM_LC_MESSAGES)
+ if (what == VIM_LC_MESSAGES) {
loc = "";
- else
+ } else {
#endif
- {
loc = setlocale(what, (char *)name);
#ifdef LC_NUMERIC
- /* Make sure strtod() uses a decimal point, not a comma. */
+ // Make sure strtod() uses a decimal point, not a comma.
setlocale(LC_NUMERIC, "C");
#endif
+#ifndef LC_MESSAGES
}
- if (loc == NULL)
+#endif
+ if (loc == NULL) {
EMSG2(_("E197: Cannot set language to \"%s\""), name);
- else {
+ } else {
#ifdef HAVE_NL_MSG_CAT_CNTR
- /* Need to do this for GNU gettext, otherwise cached translations
- * will be used again. */
+ // Need to do this for GNU gettext, otherwise cached translations
+ // will be used again.
extern int _nl_msg_cat_cntr;
- ++_nl_msg_cat_cntr;
+ _nl_msg_cat_cntr++;
#endif
- /* Reset $LC_ALL, otherwise it would overrule everything. */
+ // Reset $LC_ALL, otherwise it would overrule everything.
vim_setenv("LC_ALL", "");
if (what != LC_TIME) {
- /* Tell gettext() what to translate to. It apparently doesn't
- * use the currently effective locale. */
+ // Tell gettext() what to translate to. It apparently doesn't
+ // use the currently effective locale.
if (what == LC_ALL) {
vim_setenv("LANG", (char *)name);
- /* Clear $LANGUAGE because GNU gettext uses it. */
+ // Clear $LANGUAGE because GNU gettext uses it.
vim_setenv("LANGUAGE", "");
}
if (what != LC_CTYPE) {
@@ -3412,7 +3576,7 @@ void ex_language(exarg_T *eap)
}
}
- /* Set v:lang, v:lc_time and v:ctype to the final result. */
+ // Set v:lang, v:lc_time and v:ctype to the final result.
set_lang_var();
maketitle();
}
@@ -3420,43 +3584,43 @@ void ex_language(exarg_T *eap)
}
-static char_u **locales = NULL; /* Array of all available locales */
-static int did_init_locales = FALSE;
+static char_u **locales = NULL; // Array of all available locales
+static bool did_init_locales = false;
-/*
- * Lazy initialization of all available locales.
- */
+/// Lazy initialization of all available locales.
static void init_locales(void)
{
if (!did_init_locales) {
- did_init_locales = TRUE;
+ did_init_locales = true;
locales = find_locales();
}
}
-/* Return an array of strings for all available locales + NULL for the
- * last element. Return NULL in case of error. */
+// Return an array of strings for all available locales + NULL for the
+/// last element. Return NULL in case of error.
static char_u **find_locales(void)
{
garray_T locales_ga;
char_u *loc;
+ char *saveptr = NULL;
- /* Find all available locales by running command "locale -a". If this
- * doesn't work we won't have completion. */
+ // Find all available locales by running command "locale -a". If this
+ // doesn't work we won't have completion.
char_u *locale_a = get_cmd_output((char_u *)"locale -a", NULL,
kShellOptSilent, NULL);
- if (locale_a == NULL)
+ if (locale_a == NULL) {
return NULL;
+ }
ga_init(&locales_ga, sizeof(char_u *), 20);
- /* Transform locale_a string where each locale is separated by "\n"
- * into an array of locale strings. */
- loc = (char_u *)strtok((char *)locale_a, "\n");
+ // Transform locale_a string where each locale is separated by "\n"
+ // into an array of locale strings.
+ loc = (char_u *)os_strtok((char *)locale_a, "\n", &saveptr);
while (loc != NULL) {
loc = vim_strsave(loc);
GA_APPEND(char_u *, &locales_ga, loc);
- loc = (char_u *)strtok(NULL, "\n");
+ loc = (char_u *)os_strtok(NULL, "\n", &saveptr);
}
xfree(locale_a);
// Guarantee that .ga_data is NULL terminated
@@ -3470,8 +3634,9 @@ void free_locales(void)
{
int i;
if (locales != NULL) {
- for (i = 0; locales[i] != NULL; i++)
+ for (i = 0; locales[i] != NULL; i++) {
xfree(locales[i]);
+ }
xfree(locales);
locales = NULL;
}
@@ -3479,33 +3644,34 @@ void free_locales(void)
# endif
-/*
- * Function given to ExpandGeneric() to obtain the possible arguments of the
- * ":language" command.
- */
+/// Function given to ExpandGeneric() to obtain the possible arguments of the
+/// ":language" command.
char_u *get_lang_arg(expand_T *xp, int idx)
{
- if (idx == 0)
+ if (idx == 0) {
return (char_u *)"messages";
- if (idx == 1)
+ }
+ if (idx == 1) {
return (char_u *)"ctype";
- if (idx == 2)
+ }
+ if (idx == 2) {
return (char_u *)"time";
+ }
init_locales();
- if (locales == NULL)
+ if (locales == NULL) {
return NULL;
+ }
return locales[idx - 3];
}
-/*
- * Function given to ExpandGeneric() to obtain the available locales.
- */
+/// Function given to ExpandGeneric() to obtain the available locales.
char_u *get_locales(expand_T *xp, int idx)
{
init_locales();
- if (locales == NULL)
+ if (locales == NULL) {
return NULL;
+ }
return locales[idx];
}
@@ -3552,79 +3718,65 @@ static void script_host_do_range(char *name, exarg_T *eap)
(void)eval_call_provider(name, "do_range", args);
}
-/*
- * ":drop"
- * Opens the first argument in a window. When there are two or more arguments
- * the argument list is redefined.
- */
+/// ":drop"
+/// Opens the first argument in a window. When there are two or more arguments
+/// the argument list is redefined.
void ex_drop(exarg_T *eap)
{
- int split = FALSE;
- buf_T *buf;
-
- /*
- * Check if the first argument is already being edited in a window. If
- * so, jump to that window.
- * We would actually need to check all arguments, but that's complicated
- * and mostly only one file is dropped.
- * This also ignores wildcards, since it is very unlikely the user is
- * editing a file name with a wildcard character.
- */
- do_arglist(eap->arg, AL_SET, 0);
-
- /*
- * Expanding wildcards may result in an empty argument list. E.g. when
- * editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we
- * already did an error message for this.
- */
- if (ARGCOUNT == 0)
- return;
-
- if (cmdmod.tab)
- {
- /* ":tab drop file ...": open a tab for each argument that isn't
- * edited in a window yet. It's like ":tab all" but without closing
- * windows or tabs. */
- ex_all(eap);
- }
- else
- {
- /* ":drop file ...": Edit the first argument. Jump to an existing
- * window if possible, edit in current window if the current buffer
- * can be abandoned, otherwise open a new window. */
- buf = buflist_findnr(ARGLIST[0].ae_fnum);
-
- FOR_ALL_TAB_WINDOWS(tp, wp)
- {
- if (wp->w_buffer == buf)
- {
- goto_tabpage_win(tp, wp);
- curwin->w_arg_idx = 0;
- return;
- }
- }
-
- /*
- * Check whether the current buffer is changed. If so, we will need
- * to split the current window or data could be lost.
- * Skip the check if the 'hidden' option is set, as in this case the
- * buffer won't be lost.
- */
- if (!P_HID(curbuf))
- {
- ++emsg_off;
- split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD);
- --emsg_off;
- }
-
- /* Fake a ":sfirst" or ":first" command edit the first argument. */
- if (split)
- {
- eap->cmdidx = CMD_sfirst;
- eap->cmd[0] = 's';
- }
- else
- eap->cmdidx = CMD_first;
- ex_rewind(eap);
+ bool split = false;
+ buf_T *buf;
+
+ // Check if the first argument is already being edited in a window. If
+ // so, jump to that window.
+ // We would actually need to check all arguments, but that's complicated
+ // and mostly only one file is dropped.
+ // This also ignores wildcards, since it is very unlikely the user is
+ // editing a file name with a wildcard character.
+ do_arglist(eap->arg, AL_SET, 0);
+
+ // Expanding wildcards may result in an empty argument list. E.g. when
+ // editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we
+ // already did an error message for this.
+ if (ARGCOUNT == 0) {
+ return;
+ }
+
+ if (cmdmod.tab) {
+ // ":tab drop file ...": open a tab for each argument that isn't
+ // edited in a window yet. It's like ":tab all" but without closing
+ // windows or tabs.
+ ex_all(eap);
+ } else {
+ // ":drop file ...": Edit the first argument. Jump to an existing
+ // window if possible, edit in current window if the current buffer
+ // can be abandoned, otherwise open a new window.
+ buf = buflist_findnr(ARGLIST[0].ae_fnum);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ goto_tabpage_win(tp, wp);
+ curwin->w_arg_idx = 0;
+ return;
+ }
}
+
+ // Check whether the current buffer is changed. If so, we will need
+ // to split the current window or data could be lost.
+ // Skip the check if the 'hidden' option is set, as in this case the
+ // buffer won't be lost.
+ if (!P_HID(curbuf)) {
+ emsg_off++;
+ split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD);
+ emsg_off--;
+ }
+
+ // Fake a ":sfirst" or ":first" command edit the first argument.
+ if (split) {
+ eap->cmdidx = CMD_sfirst;
+ eap->cmd[0] = 's';
+ } else {
+ eap->cmdidx = CMD_first;
+ }
+ ex_rewind(eap);
+ }
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 870284a0f7..9bc7ec39da 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1536,8 +1536,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
ea.cmd = skipwhite(ea.cmd);
lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0);
- if (ea.cmd == NULL) /* error detected */
+ if (ea.cmd == NULL) { // error detected
goto doend;
+ }
if (lnum == MAXLNUM) {
if (*ea.cmd == '%') { /* '%' - all lines */
++ea.cmd;
@@ -3315,6 +3316,11 @@ set_one_cmd_context (
xp->xp_pattern = arg;
break;
+ case CMD_packadd:
+ xp->xp_context = EXPAND_PACKADD;
+ xp->xp_pattern = arg;
+ break;
+
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
p = skiptowhite(arg);
@@ -4640,14 +4646,14 @@ static struct {
char *name;
} addr_type_complete[] =
{
- {ADDR_ARGUMENTS, "arguments"},
- {ADDR_LINES, "lines"},
- {ADDR_LOADED_BUFFERS, "loaded_buffers"},
- {ADDR_TABS, "tabs"},
- {ADDR_BUFFERS, "buffers"},
- {ADDR_WINDOWS, "windows"},
- {ADDR_QUICKFIX, "quickfix"},
- {-1, NULL}
+ { ADDR_ARGUMENTS, "arguments" },
+ { ADDR_LINES, "lines" },
+ { ADDR_LOADED_BUFFERS, "loaded_buffers" },
+ { ADDR_TABS, "tabs" },
+ { ADDR_BUFFERS, "buffers" },
+ { ADDR_WINDOWS, "windows" },
+ { ADDR_QUICKFIX, "quickfix" },
+ { -1, NULL }
};
/*
@@ -4659,41 +4665,42 @@ static struct {
char *name;
} command_complete[] =
{
- {EXPAND_AUGROUP, "augroup"},
- {EXPAND_BEHAVE, "behave"},
- {EXPAND_BUFFERS, "buffer"},
- {EXPAND_COLORS, "color"},
- {EXPAND_COMMANDS, "command"},
- {EXPAND_COMPILER, "compiler"},
- {EXPAND_CSCOPE, "cscope"},
- {EXPAND_USER_DEFINED, "custom"},
- {EXPAND_USER_LIST, "customlist"},
- {EXPAND_DIRECTORIES, "dir"},
- {EXPAND_ENV_VARS, "environment"},
- {EXPAND_EVENTS, "event"},
- {EXPAND_EXPRESSION, "expression"},
- {EXPAND_FILES, "file"},
- {EXPAND_FILES_IN_PATH, "file_in_path"},
- {EXPAND_FILETYPE, "filetype"},
- {EXPAND_FUNCTIONS, "function"},
- {EXPAND_HELP, "help"},
- {EXPAND_HIGHLIGHT, "highlight"},
- {EXPAND_HISTORY, "history"},
+ { EXPAND_AUGROUP, "augroup" },
+ { EXPAND_BEHAVE, "behave" },
+ { EXPAND_BUFFERS, "buffer" },
+ { EXPAND_COLORS, "color" },
+ { EXPAND_COMMANDS, "command" },
+ { EXPAND_COMPILER, "compiler" },
+ { EXPAND_CSCOPE, "cscope" },
+ { EXPAND_USER_DEFINED, "custom" },
+ { EXPAND_USER_LIST, "customlist" },
+ { EXPAND_DIRECTORIES, "dir" },
+ { EXPAND_ENV_VARS, "environment" },
+ { EXPAND_EVENTS, "event" },
+ { EXPAND_EXPRESSION, "expression" },
+ { EXPAND_FILES, "file" },
+ { EXPAND_FILES_IN_PATH, "file_in_path" },
+ { EXPAND_FILETYPE, "filetype" },
+ { EXPAND_FUNCTIONS, "function" },
+ { EXPAND_HELP, "help" },
+ { EXPAND_HIGHLIGHT, "highlight" },
+ { EXPAND_HISTORY, "history" },
#ifdef HAVE_WORKING_LIBINTL
- {EXPAND_LOCALES, "locale"},
+ { EXPAND_LOCALES, "locale" },
#endif
- {EXPAND_MAPPINGS, "mapping"},
- {EXPAND_MENUS, "menu"},
- {EXPAND_OWNSYNTAX, "syntax"},
- {EXPAND_SYNTIME, "syntime"},
- {EXPAND_SETTINGS, "option"},
- {EXPAND_SHELLCMD, "shellcmd"},
- {EXPAND_SIGN, "sign"},
- {EXPAND_TAGS, "tag"},
- {EXPAND_TAGS_LISTFILES, "tag_listfiles"},
- {EXPAND_USER, "user"},
- {EXPAND_USER_VARS, "var"},
- {0, NULL}
+ { EXPAND_MAPPINGS, "mapping" },
+ { EXPAND_MENUS, "menu" },
+ { EXPAND_OWNSYNTAX, "syntax" },
+ { EXPAND_SYNTIME, "syntime" },
+ { EXPAND_SETTINGS, "option" },
+ { EXPAND_PACKADD, "packadd" },
+ { EXPAND_SHELLCMD, "shellcmd" },
+ { EXPAND_SIGN, "sign" },
+ { EXPAND_TAGS, "tag" },
+ { EXPAND_TAGS_LISTFILES, "tag_listfiles" },
+ { EXPAND_USER, "user" },
+ { EXPAND_USER_VARS, "var" },
+ { 0, NULL }
};
static void uc_list(char_u *name, size_t name_len)
@@ -6865,6 +6872,9 @@ void post_chdir(CdScope scope)
curwin->w_localdir = vim_strsave(NameBuff);
}
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
shorten_fnames(TRUE);
@@ -6989,10 +6999,10 @@ static void ex_sleep(exarg_T *eap)
*/
void do_sleep(long msec)
{
- long done;
ui_flush(); // flush before waiting
- for (done = 0; !got_int && done < msec; done += 1000L) {
- os_delay(msec - done > 1000L ? 1000L : msec - done, true);
+ for (long left = msec; !got_int && left > 0; left -= 1000L) {
+ int next = left > 1000l ? 1000 : (int)left;
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, (int)next, got_int);
os_breakcheck();
}
}
@@ -7122,8 +7132,8 @@ static void ex_put(exarg_T *eap)
eap->forceit = TRUE;
}
curwin->w_cursor.lnum = eap->line2;
- do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L,
- PUT_LINE|PUT_CURSLINE);
+ do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1,
+ PUT_LINE|PUT_CURSLINE);
}
/*
@@ -7132,7 +7142,7 @@ static void ex_put(exarg_T *eap)
static void ex_copymove(exarg_T *eap)
{
long n = get_address(eap, &eap->arg, eap->addr_type, false, false);
- if (eap->arg == NULL) { /* error detected */
+ if (eap->arg == NULL) { // error detected
eap->nextcmd = NULL;
return;
}
@@ -7351,10 +7361,11 @@ static void ex_redir(exarg_T *eap)
/* Can use both "@a" and "@a>". */
if (*arg == '>')
arg++;
- /* Make register empty when not using @A-@Z and the
- * command is valid. */
- if (*arg == NUL && !isupper(redir_reg))
- write_reg_contents(redir_reg, (char_u *)"", -1, FALSE);
+ // Make register empty when not using @A-@Z and the
+ // command is valid.
+ if (*arg == NUL && !isupper(redir_reg)) {
+ write_reg_contents(redir_reg, (char_u *)"", 0, false);
+ }
}
}
if (*arg != NUL) {
@@ -7645,7 +7656,7 @@ open_exfile (
return NULL;
}
#endif
- if (!forceit && *mode != 'a' && os_file_exists(fname)) {
+ if (!forceit && *mode != 'a' && os_path_exists(fname)) {
EMSG2(_("E189: \"%s\" exists (add ! to override)"), fname);
return NULL;
}
@@ -7855,19 +7866,26 @@ static void ex_stopinsert(exarg_T *eap)
*/
void exec_normal_cmd(char_u *cmd, int remap, bool silent)
{
+ // Stuff the argument into the typeahead buffer.
+ ins_typebuf(cmd, remap, 0, true, silent);
+ exec_normal(false);
+}
+
+/// Execute normal_cmd() until there is no typeahead left.
+///
+/// @param was_typed whether or not something was typed
+void exec_normal(bool was_typed)
+{
oparg_T oa;
- /*
- * Stuff the argument into the typeahead buffer.
- * Execute normal_cmd() until there is no typeahead left.
- */
clear_oparg(&oa);
- finish_op = FALSE;
- ins_typebuf(cmd, remap, 0, TRUE, silent);
- while ((!stuff_empty() || (!typebuf_typed() && typebuf.tb_len > 0))
+ finish_op = false;
+ while ((!stuff_empty()
+ || ((was_typed || !typebuf_typed())
+ && typebuf.tb_len > 0))
&& !got_int) {
update_topline_cursor();
- normal_cmd(&oa, TRUE); /* execute a Normal mode cmd */
+ normal_cmd(&oa, true); // execute a Normal mode cmd
}
}
@@ -9318,14 +9336,14 @@ static void ex_filetype(exarg_T *eap)
}
if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) {
if (*arg == 'o' || !filetype_detect) {
- source_runtime((char_u *)FILETYPE_FILE, true);
+ source_runtime((char_u *)FILETYPE_FILE, DIP_ALL);
filetype_detect = kTrue;
if (plugin) {
- source_runtime((char_u *)FTPLUGIN_FILE, true);
+ source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = kTrue;
}
if (indent) {
- source_runtime((char_u *)INDENT_FILE, true);
+ source_runtime((char_u *)INDENT_FILE, DIP_ALL);
filetype_indent = kTrue;
}
}
@@ -9336,15 +9354,15 @@ static void ex_filetype(exarg_T *eap)
} else if (STRCMP(arg, "off") == 0) {
if (plugin || indent) {
if (plugin) {
- source_runtime((char_u *)FTPLUGOF_FILE, true);
+ source_runtime((char_u *)FTPLUGOF_FILE, DIP_ALL);
filetype_plugin = kFalse;
}
if (indent) {
- source_runtime((char_u *)INDOFF_FILE, true);
+ source_runtime((char_u *)INDOFF_FILE, DIP_ALL);
filetype_indent = kFalse;
}
} else {
- source_runtime((char_u *)FTOFF_FILE, true);
+ source_runtime((char_u *)FTOFF_FILE, DIP_ALL);
filetype_detect = kFalse;
}
} else
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index dbfc64e2f1..bafad20169 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -26,6 +26,7 @@
/// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes
/// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead.
typedef enum {
+ kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page.
kCdScopeGlobal, ///< Affects the entire instance of Neovim.
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index a4e5a4dcd7..cd28554970 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -358,7 +358,8 @@ static int command_line_execute(VimState *state, int key)
s->c = key;
if (s->c == K_EVENT) {
- queue_process_events(loop.events);
+ queue_process_events(main_loop.events);
+ redrawcmdline();
return 1;
}
@@ -3439,6 +3440,7 @@ addstar (
|| context == EXPAND_COMPILER
|| context == EXPAND_OWNSYNTAX
|| context == EXPAND_FILETYPE
+ || context == EXPAND_PACKADD
|| (context == EXPAND_TAGS && fname[0] == '/'))
retval = vim_strnsave(fname, len);
else {
@@ -3793,23 +3795,27 @@ ExpandFromContext (
|| xp->xp_context == EXPAND_TAGS_LISTFILES)
return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
if (xp->xp_context == EXPAND_COLORS) {
- char *directories[] = {"colors", NULL};
- return ExpandRTDir(pat, num_file, file, directories);
+ char *directories[] = { "colors", NULL };
+ return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, directories);
}
if (xp->xp_context == EXPAND_COMPILER) {
- char *directories[] = {"compiler", NULL};
- return ExpandRTDir(pat, num_file, file, directories);
+ char *directories[] = { "compiler", NULL };
+ return ExpandRTDir(pat, 0, num_file, file, directories);
}
if (xp->xp_context == EXPAND_OWNSYNTAX) {
- char *directories[] = {"syntax", NULL};
- return ExpandRTDir(pat, num_file, file, directories);
+ char *directories[] = { "syntax", NULL };
+ return ExpandRTDir(pat, 0, num_file, file, directories);
}
if (xp->xp_context == EXPAND_FILETYPE) {
- char *directories[] = {"syntax", "indent", "ftplugin", NULL};
- return ExpandRTDir(pat, num_file, file, directories);
+ char *directories[] = { "syntax", "indent", "ftplugin", NULL };
+ return ExpandRTDir(pat, 0, num_file, file, directories);
}
- if (xp->xp_context == EXPAND_USER_LIST)
+ if (xp->xp_context == EXPAND_USER_LIST) {
return ExpandUserList(xp, num_file, file);
+ }
+ if (xp->xp_context == EXPAND_PACKADD) {
+ return ExpandPackAddDir(pat, num_file, file);
+ }
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
if (regmatch.regprog == NULL)
@@ -4189,12 +4195,16 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
return OK;
}
-/*
- * Expand color scheme, compiler or filetype names:
- * 'runtimepath'/{dirnames}/{pat}.vim
- * "dirnames" is an array with one or more directory names.
- */
-static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirnames[])
+/// Expand color scheme, compiler or filetype names.
+/// Search from 'runtimepath':
+/// 'runtimepath'/{dirnames}/{pat}.vim
+/// When "flags" has DIP_START: search also from 'start' of 'packpath':
+/// 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim
+/// When "flags" has DIP_OPT: search also from 'opt' of 'packpath':
+/// 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim
+/// "dirnames" is an array with one or more directory names.
+static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file,
+ char *dirnames[])
{
*num_file = 0;
*file = NULL;
@@ -4211,6 +4221,26 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname
xfree(s);
}
+ if (flags & DIP_START) {
+ for (int i = 0; dirnames[i] != NULL; i++) {
+ size_t size = STRLEN(dirnames[i]) + pat_len + 22;
+ char_u *s = xmalloc(size);
+ snprintf((char *)s, size, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT
+ globpath(p_pp, s, &ga, 0);
+ xfree(s);
+ }
+ }
+
+ if (flags & DIP_OPT) {
+ for (int i = 0; dirnames[i] != NULL; i++) {
+ size_t size = STRLEN(dirnames[i]) + pat_len + 20;
+ char_u *s = xmalloc(size);
+ snprintf((char *)s, size, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT
+ globpath(p_pp, s, &ga, 0);
+ xfree(s);
+ }
+ }
+
for (int i = 0; i < ga.ga_len; i++) {
char_u *match = ((char_u **)ga.ga_data)[i];
char_u *s = match;
@@ -4240,6 +4270,43 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname
return OK;
}
+/// Expand loadplugin names:
+/// 'packpath'/pack/ * /opt/{pat}
+static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file)
+{
+ garray_T ga;
+
+ *num_file = 0;
+ *file = NULL;
+ size_t pat_len = STRLEN(pat);
+ ga_init(&ga, (int)sizeof(char *), 10);
+
+ size_t buflen = pat_len + 26;
+ char_u *s = xmalloc(buflen);
+ snprintf((char *)s, buflen, "pack/*/opt/%s*", pat); // NOLINT
+ globpath(p_pp, s, &ga, 0);
+ xfree(s);
+
+ for (int i = 0; i < ga.ga_len; i++) {
+ char_u *match = ((char_u **)ga.ga_data)[i];
+ s = path_tail(match);
+ char_u *e = s + STRLEN(s);
+ memmove(match, s, e - s + 1);
+ }
+
+ if (GA_EMPTY(&ga)) {
+ return FAIL;
+ }
+
+ // Sort and remove duplicates which can happen when specifying multiple
+ // directories in dirnames.
+ ga_remove_duplicate_strings(&ga);
+
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+
/// Expand `file` for all comma-separated directories in `path`.
/// Adds matches to `ga`.
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index beefc4238e..78b224f04c 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -791,7 +791,7 @@ char_u *vim_findfile(void *search_ctx_arg)
for (;; ) {
/* if file exists and we didn't already find it */
if ((path_with_url((char *)file_path)
- || (os_file_exists(file_path)
+ || (os_path_exists(file_path)
&& (search_ctx->ffsc_find_what
== FINDFILE_BOTH
|| ((search_ctx->ffsc_find_what
@@ -1378,7 +1378,7 @@ find_file_in_path_option (
/* copy file name into NameBuff, expanding environment variables */
save_char = ptr[len];
ptr[len] = NUL;
- expand_env(ptr, NameBuff, MAXPATHL);
+ expand_env_esc(ptr, NameBuff, MAXPATHL, false, true, NULL);
ptr[len] = save_char;
xfree(ff_file_to_find);
@@ -1442,12 +1442,12 @@ find_file_in_path_option (
buf = suffixes;
for (;; ) {
if (
- (os_file_exists(NameBuff)
- && (find_what == FINDFILE_BOTH
- || ((find_what == FINDFILE_DIR)
- == os_isdir(NameBuff))))) {
- file_name = vim_strsave(NameBuff);
- goto theend;
+ (os_path_exists(NameBuff)
+ && (find_what == FINDFILE_BOTH
+ || ((find_what == FINDFILE_DIR)
+ == os_isdir(NameBuff))))) {
+ file_name = vim_strsave(NameBuff);
+ goto theend;
}
if (*buf == NUL)
break;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index db1469db97..154558b332 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1749,8 +1749,9 @@ failed:
#ifdef HAVE_FD_CLOEXEC
else {
int fdflags = fcntl(fd, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
- fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
+ (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
}
#endif
xfree(buffer);
@@ -2989,14 +2990,15 @@ nobackup:
* delete an existing one, try to use another name.
* Change one character, just before the extension.
*/
- if (!p_bk && os_file_exists(backup)) {
+ if (!p_bk && os_path_exists(backup)) {
p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
if (p < backup) /* empty file name ??? */
p = backup;
*p = 'z';
- while (*p > 'a' && os_file_exists(backup))
- --*p;
- /* They all exist??? Must be something wrong! */
+ while (*p > 'a' && os_path_exists(backup)) {
+ (*p)--;
+ }
+ // They all exist??? Must be something wrong!
if (*p == 'a') {
xfree(backup);
backup = NULL;
@@ -3223,12 +3225,12 @@ restore_backup:
* This may not work if the vim_rename() fails.
* In that case we leave the copy around.
*/
- /* If file does not exist, put the copy in its place */
- if (!os_file_exists(fname)) {
+ // If file does not exist, put the copy in its place
+ if (!os_path_exists(fname)) {
vim_rename(backup, fname);
}
- /* if original file does exist throw away the copy */
- if (os_file_exists(fname)) {
+ // if original file does exist throw away the copy
+ if (os_path_exists(fname)) {
os_remove((char *)backup);
}
} else {
@@ -3237,8 +3239,8 @@ restore_backup:
}
}
- /* if original file no longer exists give an extra warning */
- if (!newfile && !os_file_exists(fname)) {
+ // if original file no longer exists give an extra warning
+ if (!newfile && !os_path_exists(fname)) {
end = 0;
}
}
@@ -3596,9 +3598,9 @@ restore_backup:
* If the original file does not exist yet
* the current backup file becomes the original file
*/
- if (org == NULL)
+ if (org == NULL) {
EMSG(_("E205: Patchmode: can't save original file"));
- else if (!os_file_exists((char_u *)org)) {
+ } else if (!os_path_exists((char_u *)org)) {
vim_rename(backup, (char_u *)org);
xfree(backup); /* don't delete the file */
backup = NULL;
@@ -4513,9 +4515,11 @@ int vim_rename(char_u *from, char_u *to)
if (STRLEN(from) >= MAXPATHL - 5)
return -1;
STRCPY(tempname, from);
- for (n = 123; n < 99999; ++n) {
- sprintf((char *)path_tail(tempname), "%d", n);
- if (!os_file_exists(tempname)) {
+ for (n = 123; n < 99999; n++) {
+ char * tail = (char *)path_tail(tempname);
+ snprintf(tail, (MAXPATHL + 1) - (tail - (char *)tempname - 1), "%d", n);
+
+ if (!os_path_exists(tempname)) {
if (os_rename(from, tempname) == OK) {
if (os_rename(tempname, to) == OK)
return 0;
@@ -4862,7 +4866,7 @@ buf_check_timestamp (
}
} else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
- && os_file_exists(buf->b_ffname)) {
+ && os_path_exists(buf->b_ffname)) {
retval = 1;
mesg = _("W13: Warning: File \"%s\" has been created after editing started");
buf->b_flags |= BF_NEW_W;
diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h
index c31d21ec6d..ea017ab0c8 100644
--- a/src/nvim/func_attr.h
+++ b/src/nvim/func_attr.h
@@ -41,168 +41,174 @@
// $ gcc -E -dM - </dev/null
// $ echo | clang -dM -E -
+#ifndef NVIM_FUNC_ATTR_H
+#define NVIM_FUNC_ATTR_H
+#undef NVIM_FUNC_ATTR_H
+
#ifdef FUNC_ATTR_MALLOC
- #undef FUNC_ATTR_MALLOC
+# undef FUNC_ATTR_MALLOC
#endif
#ifdef FUNC_ATTR_ALLOC_SIZE
- #undef FUNC_ATTR_ALLOC_SIZE
+# undef FUNC_ATTR_ALLOC_SIZE
#endif
#ifdef FUNC_ATTR_ALLOC_SIZE_PROD
- #undef FUNC_ATTR_ALLOC_SIZE_PROD
+# undef FUNC_ATTR_ALLOC_SIZE_PROD
#endif
#ifdef FUNC_ATTR_ALLOC_ALIGN
- #undef FUNC_ATTR_ALLOC_ALIGN
+# undef FUNC_ATTR_ALLOC_ALIGN
#endif
#ifdef FUNC_ATTR_PURE
- #undef FUNC_ATTR_PURE
+# undef FUNC_ATTR_PURE
#endif
#ifdef FUNC_ATTR_CONST
- #undef FUNC_ATTR_CONST
+# undef FUNC_ATTR_CONST
#endif
#ifdef FUNC_ATTR_WARN_UNUSED_RESULT
- #undef FUNC_ATTR_WARN_UNUSED_RESULT
+# undef FUNC_ATTR_WARN_UNUSED_RESULT
#endif
#ifdef FUNC_ATTR_ALWAYS_INLINE
- #undef FUNC_ATTR_ALWAYS_INLINE
+# undef FUNC_ATTR_ALWAYS_INLINE
#endif
#ifdef FUNC_ATTR_UNUSED
- #undef FUNC_ATTR_UNUSED
+# undef FUNC_ATTR_UNUSED
#endif
#ifdef FUNC_ATTR_NONNULL_ALL
- #undef FUNC_ATTR_NONNULL_ALL
+# undef FUNC_ATTR_NONNULL_ALL
#endif
#ifdef FUNC_ATTR_NONNULL_ARG
- #undef FUNC_ATTR_NONNULL_ARG
+# undef FUNC_ATTR_NONNULL_ARG
#endif
#ifdef FUNC_ATTR_NONNULL_RET
- #undef FUNC_ATTR_NONNULL_RET
+# undef FUNC_ATTR_NONNULL_RET
#endif
#ifndef DID_REAL_ATTR
- #define DID_REAL_ATTR
- #ifdef __GNUC__
- // place defines for all gnulikes here, for now that's gcc, clang and
- // intel.
-
- // place these after the argument list of the function declaration
- // (not definition), like so:
- // void myfunc(void) REAL_FATTR_ALWAYS_INLINE;
- #define REAL_FATTR_MALLOC __attribute__((malloc))
- #define REAL_FATTR_ALLOC_ALIGN(x) __attribute__((alloc_align(x)))
- #define REAL_FATTR_PURE __attribute__ ((pure))
- #define REAL_FATTR_CONST __attribute__((const))
- #define REAL_FATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
- #define REAL_FATTR_ALWAYS_INLINE __attribute__((always_inline))
- #define REAL_FATTR_UNUSED __attribute__((unused))
- #define REAL_FATTR_NONNULL_ALL __attribute__((nonnull))
- #define REAL_FATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__)))
-
- #ifdef __clang__
- // clang only
- #elif defined(__INTEL_COMPILER)
- // intel only
- #else
- #define GCC_VERSION \
+# define DID_REAL_ATTR
+# ifdef __GNUC__
+// place defines for all gnulikes here, for now that's gcc, clang and
+// intel.
+
+// place these after the argument list of the function declaration
+// (not definition), like so:
+// void myfunc(void) REAL_FATTR_ALWAYS_INLINE;
+# define REAL_FATTR_MALLOC __attribute__((malloc))
+# define REAL_FATTR_ALLOC_ALIGN(x) __attribute__((alloc_align(x)))
+# define REAL_FATTR_PURE __attribute__ ((pure))
+# define REAL_FATTR_CONST __attribute__((const))
+# define REAL_FATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+# define REAL_FATTR_ALWAYS_INLINE __attribute__((always_inline))
+# define REAL_FATTR_UNUSED __attribute__((unused))
+# define REAL_FATTR_NONNULL_ALL __attribute__((nonnull))
+# define REAL_FATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__)))
+
+# ifdef __clang__
+// clang only
+# elif defined(__INTEL_COMPILER)
+// intel only
+# else
+# define GCC_VERSION \
(__GNUC__ * 10000 + \
- __GNUC_MINOR__ * 100 + \
- __GNUC_PATCHLEVEL__)
- // gcc only
- #define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
- #define REAL_FATTR_ALLOC_SIZE_PROD(x,y) __attribute__((alloc_size(x,y)))
- #if GCC_VERSION >= 40900
- #define REAL_FATTR_NONNULL_RET __attribute__((returns_nonnull))
- #endif
- #endif
- #endif
-
- // define function attributes that haven't been defined for this specific
- // compiler.
-
- #ifndef REAL_FATTR_MALLOC
- #define REAL_FATTR_MALLOC
- #endif
-
- #ifndef REAL_FATTR_ALLOC_SIZE
- #define REAL_FATTR_ALLOC_SIZE(x)
- #endif
-
- #ifndef REAL_FATTR_ALLOC_SIZE_PROD
- #define REAL_FATTR_ALLOC_SIZE_PROD(x,y)
- #endif
-
- #ifndef REAL_FATTR_ALLOC_ALIGN
- #define REAL_FATTR_ALLOC_ALIGN(x)
- #endif
-
- #ifndef REAL_FATTR_PURE
- #define REAL_FATTR_PURE
- #endif
-
- #ifndef REAL_FATTR_CONST
- #define REAL_FATTR_CONST
- #endif
-
- #ifndef REAL_FATTR_WARN_UNUSED_RESULT
- #define REAL_FATTR_WARN_UNUSED_RESULT
- #endif
-
- #ifndef REAL_FATTR_ALWAYS_INLINE
- #define REAL_FATTR_ALWAYS_INLINE
- #endif
-
- #ifndef REAL_FATTR_UNUSED
- #define REAL_FATTR_UNUSED
- #endif
-
- #ifndef REAL_FATTR_NONNULL_ALL
- #define REAL_FATTR_NONNULL_ALL
- #endif
-
- #ifndef REAL_FATTR_NONNULL_ARG
- #define REAL_FATTR_NONNULL_ARG(...)
- #endif
-
- #ifndef REAL_FATTR_NONNULL_RET
- #define REAL_FATTR_NONNULL_RET
- #endif
+ __GNUC_MINOR__ * 100 + \
+ __GNUC_PATCHLEVEL__)
+// gcc only
+# define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
+# define REAL_FATTR_ALLOC_SIZE_PROD(x, y) __attribute__((alloc_size(x, y)))
+# if GCC_VERSION >= 40900
+# define REAL_FATTR_NONNULL_RET __attribute__((returns_nonnull))
+# endif
+# endif
+# endif
+
+// define function attributes that haven't been defined for this specific
+// compiler.
+
+# ifndef REAL_FATTR_MALLOC
+# define REAL_FATTR_MALLOC
+# endif
+
+# ifndef REAL_FATTR_ALLOC_SIZE
+# define REAL_FATTR_ALLOC_SIZE(x)
+# endif
+
+# ifndef REAL_FATTR_ALLOC_SIZE_PROD
+# define REAL_FATTR_ALLOC_SIZE_PROD(x, y)
+# endif
+
+# ifndef REAL_FATTR_ALLOC_ALIGN
+# define REAL_FATTR_ALLOC_ALIGN(x)
+# endif
+
+# ifndef REAL_FATTR_PURE
+# define REAL_FATTR_PURE
+# endif
+
+# ifndef REAL_FATTR_CONST
+# define REAL_FATTR_CONST
+# endif
+
+# ifndef REAL_FATTR_WARN_UNUSED_RESULT
+# define REAL_FATTR_WARN_UNUSED_RESULT
+# endif
+
+# ifndef REAL_FATTR_ALWAYS_INLINE
+# define REAL_FATTR_ALWAYS_INLINE
+# endif
+
+# ifndef REAL_FATTR_UNUSED
+# define REAL_FATTR_UNUSED
+# endif
+
+# ifndef REAL_FATTR_NONNULL_ALL
+# define REAL_FATTR_NONNULL_ALL
+# endif
+
+# ifndef REAL_FATTR_NONNULL_ARG
+# define REAL_FATTR_NONNULL_ARG(...)
+# endif
+
+# ifndef REAL_FATTR_NONNULL_RET
+# define REAL_FATTR_NONNULL_RET
+# endif
#endif
#ifdef DEFINE_FUNC_ATTRIBUTES
- #define FUNC_ATTR_ASYNC
- #define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC
- #define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x)
- #define FUNC_ATTR_ALLOC_SIZE_PROD(x,y) REAL_FATTR_ALLOC_SIZE_PROD(x,y)
- #define FUNC_ATTR_ALLOC_ALIGN(x) REAL_FATTR_ALLOC_ALIGN(x)
- #define FUNC_ATTR_PURE REAL_FATTR_PURE
- #define FUNC_ATTR_CONST REAL_FATTR_CONST
- #define FUNC_ATTR_WARN_UNUSED_RESULT REAL_FATTR_WARN_UNUSED_RESULT
- #define FUNC_ATTR_ALWAYS_INLINE REAL_FATTR_ALWAYS_INLINE
- #define FUNC_ATTR_UNUSED REAL_FATTR_UNUSED
- #define FUNC_ATTR_NONNULL_ALL REAL_FATTR_NONNULL_ALL
- #define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__)
- #define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET
+# define FUNC_API_ASYNC
+# define FUNC_API_NOEXPORT
+# define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC
+# define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x)
+# define FUNC_ATTR_ALLOC_SIZE_PROD(x, y) REAL_FATTR_ALLOC_SIZE_PROD(x, y)
+# define FUNC_ATTR_ALLOC_ALIGN(x) REAL_FATTR_ALLOC_ALIGN(x)
+# define FUNC_ATTR_PURE REAL_FATTR_PURE
+# define FUNC_ATTR_CONST REAL_FATTR_CONST
+# define FUNC_ATTR_WARN_UNUSED_RESULT REAL_FATTR_WARN_UNUSED_RESULT
+# define FUNC_ATTR_ALWAYS_INLINE REAL_FATTR_ALWAYS_INLINE
+# define FUNC_ATTR_UNUSED REAL_FATTR_UNUSED
+# define FUNC_ATTR_NONNULL_ALL REAL_FATTR_NONNULL_ALL
+# define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__)
+# define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET
#elif !defined(DO_NOT_DEFINE_EMPTY_ATTRIBUTES)
- #define FUNC_ATTR_MALLOC
- #define FUNC_ATTR_ALLOC_SIZE(x)
- #define FUNC_ATTR_ALLOC_SIZE_PROD(x,y)
- #define FUNC_ATTR_ALLOC_ALIGN(x)
- #define FUNC_ATTR_PURE
- #define FUNC_ATTR_CONST
- #define FUNC_ATTR_WARN_UNUSED_RESULT
- #define FUNC_ATTR_ALWAYS_INLINE
- #define FUNC_ATTR_UNUSED
- #define FUNC_ATTR_NONNULL_ALL
- #define FUNC_ATTR_NONNULL_ARG(...)
- #define FUNC_ATTR_NONNULL_RET
+# define FUNC_ATTR_MALLOC
+# define FUNC_ATTR_ALLOC_SIZE(x)
+# define FUNC_ATTR_ALLOC_SIZE_PROD(x, y)
+# define FUNC_ATTR_ALLOC_ALIGN(x)
+# define FUNC_ATTR_PURE
+# define FUNC_ATTR_CONST
+# define FUNC_ATTR_WARN_UNUSED_RESULT
+# define FUNC_ATTR_ALWAYS_INLINE
+# define FUNC_ATTR_UNUSED
+# define FUNC_ATTR_NONNULL_ALL
+# define FUNC_ATTR_NONNULL_ARG(...)
+# define FUNC_ATTR_NONNULL_RET
#endif
+#endif // NVIM_FUNC_ATTR_H
diff --git a/src/nvim/garray.h b/src/nvim/garray.h
index 642eaf54f0..5d7806bbfa 100644
--- a/src/nvim/garray.h
+++ b/src/nvim/garray.h
@@ -21,10 +21,10 @@ typedef struct growarray {
#define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0)
-#define GA_APPEND(item_type, gap, item) \
- do { \
- ga_grow(gap, 1); \
- ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \
+#define GA_APPEND(item_type, gap, item) \
+ do { \
+ ga_grow(gap, 1); \
+ ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \
} while (0)
#define GA_APPEND_VIA_PTR(item_type, gap) \
@@ -49,16 +49,16 @@ static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size)
/// @param gap the garray to be freed
/// @param item_type type of the item in the garray
/// @param free_item_fn free function that takes (*item_type) as parameter
-#define GA_DEEP_CLEAR(gap, item_type, free_item_fn) \
- do { \
- garray_T *_gap = (gap); \
- if (_gap->ga_data != NULL) { \
- for (int i = 0; i < _gap->ga_len; i++) { \
- item_type *_item = &(((item_type *)_gap->ga_data)[i]); \
- free_item_fn(_item); \
- } \
- } \
- ga_clear(_gap); \
+#define GA_DEEP_CLEAR(gap, item_type, free_item_fn) \
+ do { \
+ garray_T *_gap = (gap); \
+ if (_gap->ga_data != NULL) { \
+ for (int i = 0; i < _gap->ga_len; i++) { \
+ item_type *_item = &(((item_type *)_gap->ga_data)[i]); \
+ free_item_fn(_item); \
+ } \
+ } \
+ ga_clear(_gap); \
} while (false)
#define FREE_PTR_PTR(ptr) xfree(*(ptr))
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index dbf0322d78..ae1857f318 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1754,10 +1754,11 @@ static int vgetorpeek(int advance)
|| ((compl_cont_status & CONT_LOCAL)
&& (c1 == Ctrl_N || c1 == Ctrl_P)))
) {
- if (c1 == K_SPECIAL)
+ if (c1 == K_SPECIAL) {
nolmaplen = 2;
- else {
- LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0);
+ } else {
+ LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0
+ && get_real_state() != SELECTMODE);
nolmaplen = 0;
}
/* First try buffer-local mappings. */
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index dafb75ca87..f2610ac868 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -414,7 +414,7 @@ EXTERN int provider_call_nesting INIT(= 0);
EXTERN char_u hash_removed;
-EXTERN int t_colors INIT(= 0); /* int value of T_CCO */
+EXTERN int t_colors INIT(= 256); // int value of T_CCO
/*
* When highlight_match is TRUE, highlight a match, starting at the cursor
@@ -836,8 +836,8 @@ EXTERN int* (*iconv_errno)(void);
EXTERN int State INIT(= NORMAL); /* This is the current state of the
* command interpreter. */
-EXTERN int finish_op INIT(= FALSE); /* TRUE while an operator is pending */
-EXTERN long opcount INIT(= 0); /* count for pending operator */
+EXTERN bool finish_op INIT(= false); // true while an operator is pending
+EXTERN long opcount INIT(= 0); // count for pending operator
/*
* ex mode (Q) state
@@ -914,9 +914,6 @@ EXTERN int KeyTyped; // TRUE if user typed current char
EXTERN int KeyStuffed; // TRUE if current char from stuffbuf
EXTERN int maptick INIT(= 0); // tick for each non-mapped char
-EXTERN uint8_t chartab[256]; // table used in charset.c; See
- // init_chartab() for explanation
-
EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */
EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
@@ -985,10 +982,11 @@ EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */
*/
EXTERN char_u *empty_option INIT(= (char_u *)"");
-EXTERN int redir_off INIT(= FALSE); /* no redirection for a moment */
-EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */
-EXTERN int redir_reg INIT(= 0); /* message redirection register */
-EXTERN int redir_vname INIT(= 0); /* message redirection variable */
+EXTERN int redir_off INIT(= false); // no redirection for a moment
+EXTERN FILE *redir_fd INIT(= NULL); // message redirection file
+EXTERN int redir_reg INIT(= 0); // message redirection register
+EXTERN int redir_vname INIT(= 0); // message redirection variable
+EXTERN garray_T *capture_ga INIT(= NULL); // capture() buffer
EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */
@@ -1222,6 +1220,8 @@ EXTERN char_u e_invalpat[] INIT(= N_(
EXTERN char_u e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
EXTERN char_u e_notset[] INIT(= N_("E764: Option '%s' is not set"));
EXTERN char_u e_invalidreg[] INIT(= N_("E850: Invalid register name"));
+EXTERN char_u e_dirnotf[] INIT(= N_(
+ "E919: Directory not found in '%s': \"%s\""));
EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
@@ -1243,7 +1243,6 @@ EXTERN char *ignoredp;
// If a msgpack-rpc channel should be started over stdin/stdout
EXTERN bool embedded_mode INIT(= false);
-EXTERN Loop loop;
/// Used to track the status of external functions.
/// Currently only used for iconv().
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 916d27a964..1c9b8e18ef 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -1526,8 +1526,7 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource)
vim_strcat(buffer, (char_u *)name, MAXPATHL);
vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
resource->filename[0] = NUL;
- retval = (do_in_runtimepath(buffer, FALSE, prt_resource_name,
- resource->filename)
+ retval = (do_in_runtimepath(buffer, 0, prt_resource_name, resource->filename)
&& resource->filename[0] != NUL);
xfree(buffer);
return retval;
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 2f9ec0b3ff..f2432dd71d 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -480,8 +480,9 @@ staterr:
if (arg2 != NULL) {
ppath = xmalloc(MAXPATHL + 1);
expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
- if (!os_file_exists((char_u *)ppath))
+ if (!os_path_exists((char_u *)ppath)) {
goto staterr;
+ }
}
int i;
diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h
index 1280a927e8..7ee100ab8c 100644
--- a/src/nvim/lib/klist.h
+++ b/src/nvim/lib/klist.h
@@ -33,35 +33,37 @@
#include "nvim/func_attr.h"
-#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \
- typedef struct { \
- size_t cnt, n, max; \
- kmptype_t **buf; \
- } kmp_##name##_t; \
- static inline kmp_##name##_t *kmp_init_##name(void) { \
- return xcalloc(1, sizeof(kmp_##name##_t)); \
- } \
- static inline void kmp_destroy_##name(kmp_##name##_t *mp) \
- REAL_FATTR_UNUSED; \
- static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \
- size_t k; \
- for (k = 0; k < mp->n; ++k) { \
- kmpfree_f(mp->buf[k]); xfree(mp->buf[k]); \
- } \
- xfree(mp->buf); xfree(mp); \
- } \
- static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
- ++mp->cnt; \
- if (mp->n == 0) return xcalloc(1, sizeof(kmptype_t)); \
- return mp->buf[--mp->n]; \
- } \
+#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \
+ typedef struct { \
+ size_t cnt, n, max; \
+ kmptype_t **buf; \
+ } kmp_##name##_t; \
+ static inline kmp_##name##_t *kmp_init_##name(void) { \
+ return xcalloc(1, sizeof(kmp_##name##_t)); \
+ } \
+ static inline void kmp_destroy_##name(kmp_##name##_t *mp) \
+ REAL_FATTR_UNUSED; \
+ static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \
+ size_t k; \
+ for (k = 0; k < mp->n; k++) { \
+ kmpfree_f(mp->buf[k]); xfree(mp->buf[k]); \
+ } \
+ xfree(mp->buf); xfree(mp); \
+ } \
+ static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
+ mp->cnt++; \
+ if (mp->n == 0) { \
+ return xcalloc(1, sizeof(kmptype_t)); \
+ } \
+ return mp->buf[--mp->n]; \
+ } \
static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \
- --mp->cnt; \
- if (mp->n == mp->max) { \
- mp->max = mp->max? mp->max<<1 : 16; \
+ mp->cnt--; \
+ if (mp->n == mp->max) { \
+ mp->max = mp->max ? (mp->max << 1) : 16; \
mp->buf = xrealloc(mp->buf, sizeof(kmptype_t *) * mp->max); \
- } \
- mp->buf[mp->n++] = p; \
+ } \
+ mp->buf[mp->n++] = p; \
}
#define kmempool_t(name) kmp_##name##_t
@@ -70,54 +72,56 @@
#define kmp_alloc(name, mp) kmp_alloc_##name(mp)
#define kmp_free(name, mp, p) kmp_free_##name(mp, p)
-#define KLIST_INIT(name, kltype_t, kmpfree_t) \
- struct __kl1_##name { \
- kltype_t data; \
- struct __kl1_##name *next; \
- }; \
- typedef struct __kl1_##name kl1_##name; \
- KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \
- typedef struct { \
- kl1_##name *head, *tail; \
- kmp_##name##_t *mp; \
- size_t size; \
- } kl_##name##_t; \
- static inline kl_##name##_t *kl_init_##name(void) { \
- kl_##name##_t *kl = xcalloc(1, sizeof(kl_##name##_t)); \
- kl->mp = kmp_init(name); \
- kl->head = kl->tail = kmp_alloc(name, kl->mp); \
- kl->head->next = 0; \
- return kl; \
- } \
- static inline void kl_destroy_##name(kl_##name##_t *kl) \
- REAL_FATTR_UNUSED; \
- static inline void kl_destroy_##name(kl_##name##_t *kl) { \
- kl1_##name *p; \
- for (p = kl->head; p != kl->tail; p = p->next) \
- kmp_free(name, kl->mp, p); \
- kmp_free(name, kl->mp, p); \
- kmp_destroy(name, kl->mp); \
- xfree(kl); \
- } \
- static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \
- kl1_##name *q, *p = kmp_alloc(name, kl->mp); \
- q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \
- ++kl->size; \
- q->data = d; \
- } \
- static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \
- kl1_##name **n) { \
- assert((*n)->next); \
- kl1_##name *p; \
- --kl->size; \
- p = *n; \
- *n = (*n)->next; \
- if (p == kl->head) kl->head = *n; \
- kltype_t d = p->data; \
- kmp_free(name, kl->mp, p); \
- return d; \
- } \
-
+#define KLIST_INIT(name, kltype_t, kmpfree_t) \
+ struct __kl1_##name { \
+ kltype_t data; \
+ struct __kl1_##name *next; \
+ }; \
+ typedef struct __kl1_##name kl1_##name; \
+ KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \
+ typedef struct { \
+ kl1_##name *head, *tail; \
+ kmp_##name##_t *mp; \
+ size_t size; \
+ } kl_##name##_t; \
+ static inline kl_##name##_t *kl_init_##name(void) { \
+ kl_##name##_t *kl = xcalloc(1, sizeof(kl_##name##_t)); \
+ kl->mp = kmp_init(name); \
+ kl->head = kl->tail = kmp_alloc(name, kl->mp); \
+ kl->head->next = 0; \
+ return kl; \
+ } \
+ static inline void kl_destroy_##name(kl_##name##_t *kl) \
+ REAL_FATTR_UNUSED; \
+ static inline void kl_destroy_##name(kl_##name##_t *kl) { \
+ kl1_##name *p; \
+ for (p = kl->head; p != kl->tail; p = p->next) { \
+ kmp_free(name, kl->mp, p); \
+ } \
+ kmp_free(name, kl->mp, p); \
+ kmp_destroy(name, kl->mp); \
+ xfree(kl); \
+ } \
+ static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \
+ kl1_##name *q, *p = kmp_alloc(name, kl->mp); \
+ q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \
+ kl->size++; \
+ q->data = d; \
+ } \
+ static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \
+ kl1_##name **n) { \
+ assert((*n)->next); \
+ kl1_##name *p; \
+ kl->size--; \
+ p = *n; \
+ *n = (*n)->next; \
+ if (p == kl->head) { \
+ kl->head = *n; \
+ } \
+ kltype_t d = p->data; \
+ kmp_free(name, kl->mp, p); \
+ return d; \
+ }
#define kliter_t(name) kl1_##name
#define klist_t(name) kl_##name##_t
diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h
index b41ef0cc9f..584282d773 100644
--- a/src/nvim/lib/kvec.h
+++ b/src/nvim/lib/kvec.h
@@ -1,59 +1,61 @@
-/* The MIT License
-
- Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-*/
-
-/*
- An example:
-
-#include "kvec.h"
-int main() {
- kvec_t(int) array;
- kv_init(array);
- kv_push(int, array, 10); // append
- kv_a(int, array, 20) = 5; // dynamic
- kv_A(array, 20) = 4; // static
- kv_destroy(array);
- return 0;
-}
-*/
-
-/*
- 2008-09-22 (0.1.0):
+// The MIT License
+//
+// Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// An example:
+//
+// #include "kvec.h"
+// int main() {
+// kvec_t(int) array = KV_INITIAL_VALUE;
+// kv_push(array, 10); // append
+// kv_a(array, 20) = 5; // dynamic
+// kv_A(array, 20) = 4; // static
+// kv_destroy(array);
+// return 0;
+// }
+
+#ifndef NVIM_LIB_KVEC_H
+#define NVIM_LIB_KVEC_H
- * The initial version.
+#include <stdlib.h>
+#include <string.h>
-*/
+#include "nvim/memory.h"
-#ifndef AC_KVEC_H
-#define AC_KVEC_H
+#define kv_roundup32(x) \
+ ((--(x)), \
+ ((x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16), \
+ (++(x)))
-#include <stdlib.h>
-#include "nvim/memory.h"
+#define KV_INITIAL_VALUE { .size = 0, .capacity = 0, .items = NULL }
-#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
+#define kvec_t(type) \
+ struct { \
+ size_t size; \
+ size_t capacity; \
+ type *items; \
+ }
-#define kvec_t(type) struct { size_t size, capacity; type *items; }
#define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0)
#define kv_destroy(v) xfree((v).items)
#define kv_A(v, i) ((v).items[(i)])
@@ -62,31 +64,133 @@ int main() {
#define kv_max(v) ((v).capacity)
#define kv_last(v) kv_A(v, kv_size(v) - 1)
-#define kv_resize(type, v, s) ((v).capacity = (s), (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity))
-
-#define kv_copy(type, v1, v0) do { \
- if ((v1).capacity < (v0).size) kv_resize(type, v1, (v0).size); \
- (v1).size = (v0).size; \
- memcpy((v1).items, (v0).items, sizeof(type) * (v0).size); \
- } while (0) \
-
-#define kv_push(type, v, x) do { \
- if ((v).size == (v).capacity) { \
- (v).capacity = (v).capacity? (v).capacity<<1 : 8; \
- (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity); \
- } \
- (v).items[(v).size++] = (x); \
- } while (0)
-
-#define kv_pushp(type, v) ((((v).size == (v).capacity)? \
- ((v).capacity = ((v).capacity? (v).capacity<<1 : 8), \
- (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \
- : 0), ((v).items + ((v).size++)))
-
-#define kv_a(type, v, i) (((v).capacity <= (size_t)(i)? \
- ((v).capacity = (v).size = (i) + 1, kv_roundup32((v).capacity), \
- (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \
- : (v).size <= (size_t)(i)? (v).size = (i) + 1 \
- : 0), (v).items[(i)])
-
-#endif
+#define kv_resize(v, s) \
+ ((v).capacity = (s), \
+ (v).items = xrealloc((v).items, sizeof((v).items[0]) * (v).capacity))
+
+#define kv_resize_full(v) \
+ kv_resize(v, (v).capacity ? (v).capacity << 1 : 8)
+
+#define kv_copy(v1, v0) \
+ do { \
+ if ((v1).capacity < (v0).size) { \
+ kv_resize(v1, (v0).size); \
+ } \
+ (v1).size = (v0).size; \
+ memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \
+ } while (0) \
+
+#define kv_pushp(v) \
+ ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \
+ ((v).items + ((v).size++)))
+
+#define kv_push(v, x) \
+ (*kv_pushp(v) = (x))
+
+#define kv_a(v, i) \
+ (((v).capacity <= (size_t) (i) \
+ ? ((v).capacity = (v).size = (i) + 1, \
+ kv_roundup32((v).capacity), \
+ kv_resize((v), (v).capacity), 0) \
+ : ((v).size <= (size_t) (i) \
+ ? (v).size = (i) + 1 \
+ : 0)), \
+ (v).items[(i)])
+
+/// Type of a vector with a few first members allocated on stack
+///
+/// Is compatible with #kv_A, #kv_pop, #kv_size, #kv_max, #kv_last.
+/// Is not compatible with #kv_resize, #kv_resize_full, #kv_copy, #kv_push,
+/// #kv_pushp, #kv_a, #kv_destroy.
+///
+/// @param[in] type Type of vector elements.
+/// @param[in] init_size Number of the elements in the initial array.
+#define kvec_withinit_t(type, INIT_SIZE) \
+ struct { \
+ size_t size; \
+ size_t capacity; \
+ type *items; \
+ type init_array[INIT_SIZE]; \
+ }
+
+/// Initialize vector with preallocated array
+///
+/// @param[out] v Vector to initialize.
+#define kvi_init(v) \
+ ((v).capacity = ARRAY_SIZE((v).init_array), \
+ (v).size = 0, \
+ (v).items = (v).init_array)
+
+/// Move data to a new destination and free source
+static inline void *_memcpy_free(void *const restrict dest,
+ void *const restrict src,
+ const size_t size)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE
+{
+ memcpy(dest, src, size);
+ xfree(src);
+ return dest;
+}
+
+/// Resize vector with preallocated array
+///
+/// @note May not resize to an array smaller then init_array: if requested,
+/// init_array will be used.
+///
+/// @param[out] v Vector to resize.
+/// @param[in] s New size.
+#define kvi_resize(v, s) \
+ ((v).capacity = ((s) > ARRAY_SIZE((v).init_array) \
+ ? (s) \
+ : ARRAY_SIZE((v).init_array)), \
+ (v).items = ((v).capacity == ARRAY_SIZE((v).init_array) \
+ ? ((v).items == (v).init_array \
+ ? (v).items \
+ : _memcpy_free((v).init_array, (v).items, \
+ (v).size * sizeof((v).items[0]))) \
+ : ((v).items == (v).init_array \
+ ? memcpy(xmalloc((v).capacity * sizeof((v).items[0])), \
+ (v).items, \
+ (v).size * sizeof((v).items[0])) \
+ : xrealloc((v).items, \
+ (v).capacity * sizeof((v).items[0])))))
+
+/// Resize vector with preallocated array when it is full
+///
+/// @param[out] v Vector to resize.
+#define kvi_resize_full(v) \
+ /* ARRAY_SIZE((v).init_array) is the minimal capacity of this vector. */ \
+ /* Thus when vector is full capacity may not be zero and it is safe */ \
+ /* not to bother with checking whether (v).capacity is 0. But now */ \
+ /* capacity is not guaranteed to have size that is a power of 2, it is */ \
+ /* hard to fix this here and is not very necessary if users will use */ \
+ /* 2^x initial array size. */ \
+ kvi_resize(v, (v).capacity << 1)
+
+/// Get location where to store new element to a vector with preallocated array
+///
+/// @param[in,out] v Vector to push to.
+///
+/// @return Pointer to the place where new value should be stored.
+#define kvi_pushp(v) \
+ ((((v).size == (v).capacity) ? (kvi_resize_full(v), 0) : 0), \
+ ((v).items + ((v).size++)))
+
+/// Push value to a vector with preallocated array
+///
+/// @param[out] v Vector to push to.
+/// @param[in] x Value to push.
+#define kvi_push(v, x) \
+ (*kvi_pushp(v) = (x))
+
+/// Free array of elements of a vector with preallocated array if needed
+///
+/// @param[out] v Vector to free.
+#define kvi_destroy(v) \
+ do { \
+ if ((v).items != (v).init_array) { \
+ xfree((v).items); \
+ } \
+ } while (0)
+
+#endif // NVIM_LIB_KVEC_H
diff --git a/src/nvim/lib/queue.h b/src/nvim/lib/queue.h
index fe02b454ea..9fcedf298f 100644
--- a/src/nvim/lib/queue.h
+++ b/src/nvim/lib/queue.h
@@ -1,92 +1,94 @@
-/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
+// Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#ifndef QUEUE_H_
-#define QUEUE_H_
+#ifndef NVIM_LIB_QUEUE_H
+#define NVIM_LIB_QUEUE_H
-typedef void *QUEUE[2];
+#include <stddef.h>
-/* Private macros. */
-#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
-#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
-#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
-#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+#include "nvim/func_attr.h"
-/* Public macros. */
-#define QUEUE_DATA(ptr, type, field) \
- ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+typedef struct _queue {
+ struct _queue *next;
+ struct _queue *prev;
+} QUEUE;
-#define QUEUE_FOREACH(q, h) \
- for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+// Public macros.
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *)((char *)(ptr) - offsetof(type, field)))
-#define QUEUE_EMPTY(q) \
- ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+#define QUEUE_FOREACH(q, h) \
+ for ( /* NOLINT(readability/braces) */ \
+ (q) = (h)->next; (q) != (h); (q) = (q)->next)
-#define QUEUE_HEAD(q) \
- (QUEUE_NEXT(q))
+// ffi.cdef is unable to swallow `bool` in place of `int` here.
+static inline int QUEUE_EMPTY(const QUEUE *const q)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return q == q->next;
+}
-#define QUEUE_INIT(q) \
- do { \
- QUEUE_NEXT(q) = (q); \
- QUEUE_PREV(q) = (q); \
- } \
- while (0)
+#define QUEUE_HEAD(q) (q)->next
-#define QUEUE_ADD(h, n) \
- do { \
- QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
- QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
- QUEUE_PREV(h) = QUEUE_PREV(n); \
- QUEUE_PREV_NEXT(h) = (h); \
- } \
- while (0)
+static inline void QUEUE_INIT(QUEUE *const q) FUNC_ATTR_ALWAYS_INLINE
+{
+ q->next = q;
+ q->prev = q;
+}
-#define QUEUE_SPLIT(h, q, n) \
- do { \
- QUEUE_PREV(n) = QUEUE_PREV(h); \
- QUEUE_PREV_NEXT(n) = (n); \
- QUEUE_NEXT(n) = (q); \
- QUEUE_PREV(h) = QUEUE_PREV(q); \
- QUEUE_PREV_NEXT(h) = (h); \
- QUEUE_PREV(q) = (n); \
- } \
- while (0)
+static inline void QUEUE_ADD(QUEUE *const h, QUEUE *const n)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ h->prev->next = n->next;
+ n->next->prev = h->prev;
+ h->prev = n->prev;
+ h->prev->next = h;
+}
-#define QUEUE_INSERT_HEAD(h, q) \
- do { \
- QUEUE_NEXT(q) = QUEUE_NEXT(h); \
- QUEUE_PREV(q) = (h); \
- QUEUE_NEXT_PREV(q) = (q); \
- QUEUE_NEXT(h) = (q); \
- } \
- while (0)
+static inline void QUEUE_SPLIT(QUEUE *const h, QUEUE *const q, QUEUE *const n)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ n->prev = h->prev;
+ n->prev->next = n;
+ n->next = q;
+ h->prev = q->prev;
+ h->prev->next = h;
+ q->prev = n;
+}
-#define QUEUE_INSERT_TAIL(h, q) \
- do { \
- QUEUE_NEXT(q) = (h); \
- QUEUE_PREV(q) = QUEUE_PREV(h); \
- QUEUE_PREV_NEXT(q) = (q); \
- QUEUE_PREV(h) = (q); \
- } \
- while (0)
+static inline void QUEUE_INSERT_HEAD(QUEUE *const h, QUEUE *const q)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ q->next = h->next;
+ q->prev = h;
+ q->next->prev = q;
+ h->next = q;
+}
-#define QUEUE_REMOVE(q) \
- do { \
- QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
- QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
- } \
- while (0)
+static inline void QUEUE_INSERT_TAIL(QUEUE *const h, QUEUE *const q)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ q->next = h;
+ q->prev = h->prev;
+ q->prev->next = q;
+ h->prev = q;
+}
-#endif /* QUEUE_H_ */
+static inline void QUEUE_REMOVE(QUEUE *const q) FUNC_ATTR_ALWAYS_INLINE
+{
+ q->prev->next = q->next;
+ q->next->prev = q->prev;
+}
+
+#endif // NVIM_LIB_QUEUE_H
diff --git a/src/nvim/lib/ringbuf.h b/src/nvim/lib/ringbuf.h
index cb71500bb7..12b75ec65a 100644
--- a/src/nvim/lib/ringbuf.h
+++ b/src/nvim/lib/ringbuf.h
@@ -65,12 +65,12 @@
/// @param TypeName Ring buffer type name. Actual type name will be
/// `{TypeName}RingBuffer`.
/// @param RBType Type of the single ring buffer element.
-#define RINGBUF_TYPEDEF(TypeName, RBType) \
-typedef struct { \
- RBType *buf; \
- RBType *next; \
- RBType *first; \
- RBType *buf_end; \
+#define RINGBUF_TYPEDEF(TypeName, RBType) \
+typedef struct { \
+ RBType *buf; \
+ RBType *next; \
+ RBType *first; \
+ RBType *buf_end; \
} TypeName##RingBuffer;
/// Initialize a new ring buffer
@@ -84,198 +84,196 @@ typedef struct { \
/// a macros like `#define RBFREE(item)` (to skip freeing).
///
/// Intended function signature: `void *rbfree(RBType *)`;
-#define RINGBUF_INIT(TypeName, funcprefix, RBType, rbfree) \
- \
- \
-static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \
- REAL_FATTR_WARN_UNUSED_RESULT; \
-static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \
-{ \
- assert(size != 0); \
- RBType *buf = xmalloc(size * sizeof(RBType)); \
- return (TypeName##RingBuffer) { \
- .buf = buf, \
- .next = buf, \
- .first = NULL, \
- .buf_end = buf + size - 1, \
- }; \
-} \
- \
-static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \
- REAL_FATTR_UNUSED; \
-static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \
-{ \
- if (rb == NULL) { \
- return; \
- } \
- RINGBUF_FORALL(rb, RBType, rbitem) { \
- rbfree(rbitem); \
- } \
- xfree(rb->buf); \
-} \
- \
-static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
- REAL_FATTR_UNUSED; \
-static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
-{ \
- xfree(rb->buf); \
-} \
- \
-static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \
- RBType item) \
- REAL_FATTR_NONNULL_ARG(1); \
-static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \
- RBType item) \
-{ \
- if (rb->next == rb->first) { \
- rbfree(rb->first); \
- rb->first = _RINGBUF_NEXT(rb, rb->first); \
- } else if (rb->first == NULL) { \
- rb->first = rb->next; \
- } \
- *rb->next = item; \
- rb->next = _RINGBUF_NEXT(rb, rb->next); \
-} \
- \
-static inline ptrdiff_t funcprefix##_rb_find_idx( \
- const TypeName##RingBuffer *const rb, const RBType *const item_p) \
- REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \
-static inline ptrdiff_t funcprefix##_rb_find_idx( \
- const TypeName##RingBuffer *const rb, const RBType *const item_p) \
-{ \
- assert(rb->buf <= item_p); \
- assert(rb->buf_end >= item_p); \
- if (rb->first == NULL) { \
- return -1; \
- } else if (item_p >= rb->first) { \
- return item_p - rb->first; \
- } else { \
- return item_p - rb->buf + rb->buf_end - rb->first + 1; \
- } \
-} \
- \
-static inline size_t funcprefix##_rb_size( \
- const TypeName##RingBuffer *const rb) \
- REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
-static inline size_t funcprefix##_rb_size( \
- const TypeName##RingBuffer *const rb) \
-{ \
- return (size_t) (rb->buf_end - rb->buf) + 1; \
-} \
- \
-static inline size_t funcprefix##_rb_length( \
- const TypeName##RingBuffer *const rb) \
- REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
-static inline size_t funcprefix##_rb_length( \
- const TypeName##RingBuffer *const rb) \
-{ \
- return _RINGBUF_LENGTH(rb); \
-} \
- \
-static inline RBType *funcprefix##_rb_idx_p( \
- const TypeName##RingBuffer *const rb, const size_t idx) \
- REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
-static inline RBType *funcprefix##_rb_idx_p( \
- const TypeName##RingBuffer *const rb, const size_t idx) \
-{ \
- assert(idx <= funcprefix##_rb_size(rb)); \
- assert(idx <= funcprefix##_rb_length(rb)); \
- if (rb->first + idx > rb->buf_end) { \
- return rb->buf + ((rb->first + idx) - (rb->buf_end + 1)); \
- } else { \
- return rb->first + idx; \
- } \
-} \
- \
+#define RINGBUF_INIT(TypeName, funcprefix, RBType, rbfree) \
+static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \
+ REAL_FATTR_WARN_UNUSED_RESULT; \
+static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \
+{ \
+ assert(size != 0); \
+ RBType *buf = xmalloc(size * sizeof(RBType)); \
+ return (TypeName##RingBuffer) { \
+ .buf = buf, \
+ .next = buf, \
+ .first = NULL, \
+ .buf_end = buf + size - 1, \
+ }; \
+} \
+\
+static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \
+ REAL_FATTR_UNUSED; \
+static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \
+{ \
+ if (rb == NULL) { \
+ return; \
+ } \
+ RINGBUF_FORALL(rb, RBType, rbitem) { \
+ rbfree(rbitem); \
+ } \
+ xfree(rb->buf); \
+} \
+\
+static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
+ REAL_FATTR_UNUSED; \
+static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \
+{ \
+ xfree(rb->buf); \
+} \
+\
+static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \
+ RBType item) \
+ REAL_FATTR_NONNULL_ARG(1); \
+static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \
+ RBType item) \
+{ \
+ if (rb->next == rb->first) { \
+ rbfree(rb->first); \
+ rb->first = _RINGBUF_NEXT(rb, rb->first); \
+ } else if (rb->first == NULL) { \
+ rb->first = rb->next; \
+ } \
+ *rb->next = item; \
+ rb->next = _RINGBUF_NEXT(rb, rb->next); \
+} \
+\
+static inline ptrdiff_t funcprefix##_rb_find_idx( \
+ const TypeName##RingBuffer *const rb, const RBType *const item_p) \
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \
+static inline ptrdiff_t funcprefix##_rb_find_idx( \
+ const TypeName##RingBuffer *const rb, const RBType *const item_p) \
+{ \
+ assert(rb->buf <= item_p); \
+ assert(rb->buf_end >= item_p); \
+ if (rb->first == NULL) { \
+ return -1; \
+ } else if (item_p >= rb->first) { \
+ return item_p - rb->first; \
+ } else { \
+ return item_p - rb->buf + rb->buf_end - rb->first + 1; \
+ } \
+} \
+\
+static inline size_t funcprefix##_rb_size( \
+ const TypeName##RingBuffer *const rb) \
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
+static inline size_t funcprefix##_rb_size( \
+ const TypeName##RingBuffer *const rb) \
+{ \
+ return (size_t) (rb->buf_end - rb->buf) + 1; \
+} \
+\
+static inline size_t funcprefix##_rb_length( \
+ const TypeName##RingBuffer *const rb) \
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
+static inline size_t funcprefix##_rb_length( \
+ const TypeName##RingBuffer *const rb) \
+{ \
+ return _RINGBUF_LENGTH(rb); \
+} \
+\
+static inline RBType *funcprefix##_rb_idx_p( \
+ const TypeName##RingBuffer *const rb, const size_t idx) \
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \
+static inline RBType *funcprefix##_rb_idx_p( \
+ const TypeName##RingBuffer *const rb, const size_t idx) \
+{ \
+ assert(idx <= funcprefix##_rb_size(rb)); \
+ assert(idx <= funcprefix##_rb_length(rb)); \
+ if (rb->first + idx > rb->buf_end) { \
+ return rb->buf + ((rb->first + idx) - (rb->buf_end + 1)); \
+ } else { \
+ return rb->first + idx; \
+ } \
+} \
+\
static inline RBType funcprefix##_rb_idx(const TypeName##RingBuffer *const rb, \
- const size_t idx) \
- REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \
+ const size_t idx) \
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \
static inline RBType funcprefix##_rb_idx(const TypeName##RingBuffer *const rb, \
- const size_t idx) \
-{ \
- return *funcprefix##_rb_idx_p(rb, idx); \
-} \
- \
-static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \
- const size_t idx, \
- RBType item) \
- REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \
-static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \
- const size_t idx, \
- RBType item) \
-{ \
- assert(idx <= funcprefix##_rb_size(rb)); \
- assert(idx <= funcprefix##_rb_length(rb)); \
- const size_t length = funcprefix##_rb_length(rb); \
- if (idx == length) { \
- funcprefix##_rb_push(rb, item); \
- return; \
- } \
- RBType *const insertpos = funcprefix##_rb_idx_p(rb, idx); \
- if (insertpos == rb->next) { \
- funcprefix##_rb_push(rb, item); \
- return; \
- } \
- if (length == funcprefix##_rb_size(rb)) { \
- rbfree(rb->first); \
- } \
- if (insertpos < rb->next) { \
- memmove(insertpos + 1, insertpos, \
- (size_t) ((uintptr_t) rb->next - (uintptr_t) insertpos)); \
- } else { \
- assert(insertpos > rb->first); \
- assert(rb->next <= rb->first); \
- memmove(rb->buf + 1, rb->buf, \
- (size_t) ((uintptr_t) rb->next - (uintptr_t) rb->buf)); \
- *rb->buf = *rb->buf_end; \
- memmove(insertpos + 1, insertpos, \
+ const size_t idx) \
+{ \
+ return *funcprefix##_rb_idx_p(rb, idx); \
+} \
+\
+static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \
+ const size_t idx, \
+ RBType item) \
+ REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \
+static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \
+ const size_t idx, \
+ RBType item) \
+{ \
+ assert(idx <= funcprefix##_rb_size(rb)); \
+ assert(idx <= funcprefix##_rb_length(rb)); \
+ const size_t length = funcprefix##_rb_length(rb); \
+ if (idx == length) { \
+ funcprefix##_rb_push(rb, item); \
+ return; \
+ } \
+ RBType *const insertpos = funcprefix##_rb_idx_p(rb, idx); \
+ if (insertpos == rb->next) { \
+ funcprefix##_rb_push(rb, item); \
+ return; \
+ } \
+ if (length == funcprefix##_rb_size(rb)) { \
+ rbfree(rb->first); \
+ } \
+ if (insertpos < rb->next) { \
+ memmove(insertpos + 1, insertpos, \
+ (size_t) ((uintptr_t) rb->next - (uintptr_t) insertpos)); \
+ } else { \
+ assert(insertpos > rb->first); \
+ assert(rb->next <= rb->first); \
+ memmove(rb->buf + 1, rb->buf, \
+ (size_t) ((uintptr_t) rb->next - (uintptr_t) rb->buf)); \
+ *rb->buf = *rb->buf_end; \
+ memmove(insertpos + 1, insertpos, \
(size_t) ((uintptr_t) (rb->buf_end + 1) - (uintptr_t) insertpos)); \
- } \
- *insertpos = item; \
- if (length == funcprefix##_rb_size(rb)) { \
- rb->first = _RINGBUF_NEXT(rb, rb->first); \
- } \
- rb->next = _RINGBUF_NEXT(rb, rb->next); \
-} \
- \
-static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \
- const size_t idx) \
- REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \
-static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \
- const size_t idx) \
-{ \
- assert(idx < funcprefix##_rb_size(rb)); \
- assert(idx < funcprefix##_rb_length(rb)); \
- RBType *const rmpos = funcprefix##_rb_idx_p(rb, idx); \
- rbfree(rmpos); \
- if (rmpos == rb->next - 1) { \
- rb->next--; \
- if (rb->first == rb->next) { \
- rb->first = NULL; \
- rb->next = rb->buf; \
- } \
- } else if (rmpos == rb->first) { \
- rb->first = _RINGBUF_NEXT(rb, rb->first); \
- if (rb->first == rb->next) { \
- rb->first = NULL; \
- rb->next = rb->buf; \
- } \
- } else if (rb->first < rb->next || rb->next == rb->buf) { \
- assert(rmpos > rb->first); \
- assert(rmpos <= _RINGBUF_PREV(rb, rb->next)); \
- memmove(rb->first + 1, rb->first, \
- (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \
- rb->first = _RINGBUF_NEXT(rb, rb->first); \
- } else if (rmpos < rb->next) { \
- memmove(rmpos, rmpos + 1, \
- (size_t) ((uintptr_t) rb->next - (uintptr_t) rmpos)); \
- rb->next = _RINGBUF_PREV(rb, rb->next); \
- } else { \
- assert(rb->first < rb->buf_end); \
- memmove(rb->first + 1, rb->first, \
- (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \
- rb->first = _RINGBUF_NEXT(rb, rb->first); \
- } \
+ } \
+ *insertpos = item; \
+ if (length == funcprefix##_rb_size(rb)) { \
+ rb->first = _RINGBUF_NEXT(rb, rb->first); \
+ } \
+ rb->next = _RINGBUF_NEXT(rb, rb->next); \
+} \
+\
+static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \
+ const size_t idx) \
+ REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \
+static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \
+ const size_t idx) \
+{ \
+ assert(idx < funcprefix##_rb_size(rb)); \
+ assert(idx < funcprefix##_rb_length(rb)); \
+ RBType *const rmpos = funcprefix##_rb_idx_p(rb, idx); \
+ rbfree(rmpos); \
+ if (rmpos == rb->next - 1) { \
+ rb->next--; \
+ if (rb->first == rb->next) { \
+ rb->first = NULL; \
+ rb->next = rb->buf; \
+ } \
+ } else if (rmpos == rb->first) { \
+ rb->first = _RINGBUF_NEXT(rb, rb->first); \
+ if (rb->first == rb->next) { \
+ rb->first = NULL; \
+ rb->next = rb->buf; \
+ } \
+ } else if (rb->first < rb->next || rb->next == rb->buf) { \
+ assert(rmpos > rb->first); \
+ assert(rmpos <= _RINGBUF_PREV(rb, rb->next)); \
+ memmove(rb->first + 1, rb->first, \
+ (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \
+ rb->first = _RINGBUF_NEXT(rb, rb->first); \
+ } else if (rmpos < rb->next) { \
+ memmove(rmpos, rmpos + 1, \
+ (size_t) ((uintptr_t) rb->next - (uintptr_t) rmpos)); \
+ rb->next = _RINGBUF_PREV(rb, rb->next); \
+ } else { \
+ assert(rb->first < rb->buf_end); \
+ memmove(rb->first + 1, rb->first, \
+ (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \
+ rb->first = _RINGBUF_NEXT(rb, rb->first); \
+ } \
}
#endif // NVIM_LIB_RINGBUF_H
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 773d497881..c31af6b287 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -10,7 +10,14 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-#define USR_LOG_FILE "$HOME" _PATHSEPSTR ".nvimlog"
+/// First location of the log file used by log_path_init()
+#define USR_LOG_FILE "$NVIM_LOG_FILE"
+
+/// Fall back location of the log file used by log_path_init()
+#define USR_LOG_FILE_2 "$HOME" _PATHSEPSTR ".nvimlog"
+
+/// Cached location of the log file set by log_path_init()
+static char expanded_log_file_path[MAXPATHL + 1] = { 0 };
static uv_mutex_t mutex;
@@ -18,6 +25,35 @@ static uv_mutex_t mutex;
# include "log.c.generated.h"
#endif
+/// Initialize path to log file
+///
+/// Tries to use #USR_LOG_FILE, then falls back #USR_LOG_FILE_2. Path to log
+/// file is cached, so only the first call has effect, unless first call was not
+/// successful. To make initialization not succeed either a bug in expand_env()
+/// is needed or both `$NVIM_LOG_FILE` and `$HOME` environment variables
+/// undefined.
+///
+/// @return true if path was initialized, false otherwise.
+static bool log_path_init(void)
+{
+ if (expanded_log_file_path[0]) {
+ return true;
+ }
+ expand_env((char_u *)USR_LOG_FILE, (char_u *)expanded_log_file_path,
+ sizeof(expanded_log_file_path) - 1);
+ // if the log file path expansion failed then fall back to stderr
+ if (strcmp(USR_LOG_FILE, expanded_log_file_path) == 0) {
+ memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path));
+ expand_env((char_u *)USR_LOG_FILE_2, (char_u *)expanded_log_file_path,
+ sizeof(expanded_log_file_path) - 1);
+ if (strcmp(USR_LOG_FILE_2, expanded_log_file_path) == 0) {
+ memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path));
+ return false;
+ }
+ }
+ return true;
+}
+
void log_init(void)
{
uv_mutex_init(&mutex);
@@ -73,30 +109,17 @@ FILE *open_log_file(void)
return stderr;
}
- // expand USR_LOG_FILE and open the file
- FILE *log_file;
+ // expand USR_LOG_FILE if needed and open the file
+ FILE *log_file = NULL;
opening_log_file = true;
- {
- static char expanded_log_file_path[MAXPATHL + 1];
-
- expand_env((char_u *)USR_LOG_FILE, (char_u *)expanded_log_file_path,
- MAXPATHL);
- // if the log file path expansion failed then fall back to stderr
- if (strcmp(USR_LOG_FILE, expanded_log_file_path) == 0) {
- goto open_log_file_error;
- }
-
+ if (log_path_init()) {
log_file = fopen(expanded_log_file_path, "a");
- if (log_file == NULL) {
- goto open_log_file_error;
- }
}
opening_log_file = false;
- return log_file;
-
-open_log_file_error:
- opening_log_file = false;
+ if (log_file != NULL) {
+ return log_file;
+ }
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
"Couldn't open USR_LOG_FILE, logging to stderr! This may be "
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 5f69fa2f6a..503daa9648 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -73,11 +73,6 @@
/* Returns empty string if it is NULL. */
#define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"")
-/* macro version of chartab().
- * Only works with values 0-255!
- * Doesn't work for UTF-8 mode with chars >= 0x80. */
-#define CHARSIZE(c) (chartab[c] & CT_CELL_MASK)
-
/*
* Adjust chars in a language according to 'langmap' option.
* NOTE that there is no noticeable overhead if 'langmap' is not set.
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 71a972e8f6..e052d0d315 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -120,6 +120,8 @@ typedef struct {
# include "main.c.generated.h"
#endif
+Loop main_loop;
+
static char *argv0;
// Error messages
@@ -133,7 +135,7 @@ static const char *err_extra_cmd =
void event_init(void)
{
- loop_init(&loop, NULL);
+ loop_init(&main_loop, NULL);
// early msgpack-rpc initialization
msgpack_rpc_init_method_table();
msgpack_rpc_helpers_init();
@@ -151,19 +153,20 @@ void event_init(void)
void event_teardown(void)
{
- if (!loop.events) {
+ if (!main_loop.events) {
return;
}
- queue_process_events(loop.events);
+ queue_process_events(main_loop.events);
input_stop();
channel_teardown();
- process_teardown(&loop);
+ process_teardown(&main_loop);
+ timer_teardown();
server_teardown();
signal_teardown();
terminal_teardown();
- loop_close(&loop);
+ loop_close(&main_loop);
}
/// Performs early initialization.
@@ -273,7 +276,6 @@ int main(int argc, char **argv)
printf(_("%d files to edit\n"), GARGCOUNT);
full_screen = true;
- t_colors = 256;
check_tty(&params);
/*
@@ -504,6 +506,9 @@ int main(int argc, char **argv)
no_wait_return = FALSE;
starting = 0;
+ // 'autochdir' has been postponed.
+ do_autochdir();
+
/* start in insert mode */
if (p_im)
need_start_insertmode = TRUE;
@@ -665,8 +670,8 @@ static void init_locale(void)
{
char_u *p;
- /* expand_env() doesn't work yet, because chartab[] is not initialized
- * yet, call vim_getenv() directly */
+ // expand_env() doesn't work yet, because g_chartab[] is not
+ // initialized yet, call vim_getenv() directly
p = (char_u *)vim_getenv("VIMRUNTIME");
if (p != NULL && *p != NUL) {
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
@@ -1236,8 +1241,11 @@ static void set_window_layout(mparm_T *paramp)
static void load_plugins(void)
{
if (p_lpl) {
- source_runtime((char_u *)"plugin/**/*.vim", TRUE);
+ source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL); // NOLINT
TIME_MSG("loading plugins");
+
+ ex_packloadall(NULL);
+ TIME_MSG("loading packages");
}
}
@@ -1665,8 +1673,6 @@ static bool do_user_initialization(void)
}
/// Source startup scripts
-///
-/// @param[in]
static void source_startup_scripts(const mparm_T *const parmp)
FUNC_ATTR_NONNULL_ALL
{
diff --git a/src/nvim/main.h b/src/nvim/main.h
index 084e247b7e..86d25fe657 100644
--- a/src/nvim/main.h
+++ b/src/nvim/main.h
@@ -2,6 +2,9 @@
#define NVIM_MAIN_H
#include "nvim/normal.h"
+#include "nvim/event/loop.h"
+
+extern Loop main_loop;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "main.h.generated.h"
diff --git a/src/nvim/map.c b/src/nvim/map.c
index d4262ae9a8..398e74268f 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -34,88 +34,88 @@
#define INITIALIZER_DECLARE(T, U, ...) const U INITIALIZER(T, U) = __VA_ARGS__
#define DEFAULT_INITIALIZER {0}
-#define MAP_IMPL(T, U, ...) \
- INITIALIZER_DECLARE(T, U, __VA_ARGS__); \
- __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \
- \
- Map(T, U) *map_##T##_##U##_new() \
- { \
- Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \
- rv->table = kh_init(T##_##U##_map); \
- return rv; \
- } \
- \
- void map_##T##_##U##_free(Map(T, U) *map) \
- { \
- kh_destroy(T##_##U##_map, map->table); \
- xfree(map); \
- } \
- \
- U map_##T##_##U##_get(Map(T, U) *map, T key) \
- { \
- khiter_t k; \
- \
+#define MAP_IMPL(T, U, ...) \
+ INITIALIZER_DECLARE(T, U, __VA_ARGS__); \
+ __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \
+ \
+ Map(T, U) *map_##T##_##U##_new() \
+ { \
+ Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \
+ rv->table = kh_init(T##_##U##_map); \
+ return rv; \
+ } \
+ \
+ void map_##T##_##U##_free(Map(T, U) *map) \
+ { \
+ kh_destroy(T##_##U##_map, map->table); \
+ xfree(map); \
+ } \
+ \
+ U map_##T##_##U##_get(Map(T, U) *map, T key) \
+ { \
+ khiter_t k; \
+ \
if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \
- return INITIALIZER(T, U); \
- } \
- \
- return kh_val(map->table, k); \
- } \
- \
- bool map_##T##_##U##_has(Map(T, U) *map, T key) \
- { \
- return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \
- } \
- \
- U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \
- { \
- int ret; \
- U rv = INITIALIZER(T, U); \
- khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \
- \
- if (!ret) { \
- rv = kh_val(map->table, k); \
- } \
- \
- kh_val(map->table, k) = value; \
- return rv; \
- } \
- \
- U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \
- { \
- int ret; \
- khiter_t k; \
- if (put) { \
- k = kh_put(T##_##U##_map, map->table, key, &ret); \
- if (ret) { \
- kh_val(map->table, k) = INITIALIZER(T, U); \
- } \
- } else { \
- k = kh_get(T##_##U##_map, map->table, key); \
- if (k == kh_end(map->table)) { \
- return NULL; \
- } \
- } \
- \
- return &kh_val(map->table, k); \
- } \
- \
- U map_##T##_##U##_del(Map(T, U) *map, T key) \
- { \
- U rv = INITIALIZER(T, U); \
- khiter_t k; \
- \
+ return INITIALIZER(T, U); \
+ } \
+ \
+ return kh_val(map->table, k); \
+ } \
+ \
+ bool map_##T##_##U##_has(Map(T, U) *map, T key) \
+ { \
+ return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \
+ } \
+ \
+ U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \
+ { \
+ int ret; \
+ U rv = INITIALIZER(T, U); \
+ khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \
+ \
+ if (!ret) { \
+ rv = kh_val(map->table, k); \
+ } \
+ \
+ kh_val(map->table, k) = value; \
+ return rv; \
+ } \
+ \
+ U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \
+ { \
+ int ret; \
+ khiter_t k; \
+ if (put) { \
+ k = kh_put(T##_##U##_map, map->table, key, &ret); \
+ if (ret) { \
+ kh_val(map->table, k) = INITIALIZER(T, U); \
+ } \
+ } else { \
+ k = kh_get(T##_##U##_map, map->table, key); \
+ if (k == kh_end(map->table)) { \
+ return NULL; \
+ } \
+ } \
+ \
+ return &kh_val(map->table, k); \
+ } \
+ \
+ U map_##T##_##U##_del(Map(T, U) *map, T key) \
+ { \
+ U rv = INITIALIZER(T, U); \
+ khiter_t k; \
+ \
if ((k = kh_get(T##_##U##_map, map->table, key)) != kh_end(map->table)) { \
- rv = kh_val(map->table, k); \
- kh_del(T##_##U##_map, map->table, k); \
- } \
- \
- return rv; \
- } \
- \
- void map_##T##_##U##_clear(Map(T, U) *map) \
- { \
- kh_clear(T##_##U##_map, map->table); \
+ rv = kh_val(map->table, k); \
+ kh_del(T##_##U##_map, map->table, k); \
+ } \
+ \
+ return rv; \
+ } \
+ \
+ void map_##T##_##U##_clear(Map(T, U) *map) \
+ { \
+ kh_clear(T##_##U##_map, map->table); \
}
static inline khint_t String_hash(String s)
@@ -129,7 +129,10 @@ static inline khint_t String_hash(String s)
static inline bool String_eq(String a, String b)
{
- return strncmp(a.data, b.data, MIN(a.size, b.size)) == 0;
+ if (a.size != b.size) {
+ return false;
+ }
+ return memcmp(a.data, b.data, a.size) == 0;
}
diff --git a/src/nvim/map.h b/src/nvim/map.h
index e90cc360ce..c7d9894bd1 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -8,20 +8,20 @@
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/bufhl_defs.h"
-#define MAP_DECLS(T, U) \
- KHASH_DECLARE(T##_##U##_map, T, U) \
- \
- typedef struct { \
- khash_t(T##_##U##_map) *table; \
- } Map(T, U); \
- \
- Map(T, U) *map_##T##_##U##_new(void); \
- void map_##T##_##U##_free(Map(T, U) *map); \
- U map_##T##_##U##_get(Map(T, U) *map, T key); \
- bool map_##T##_##U##_has(Map(T, U) *map, T key); \
- U map_##T##_##U##_put(Map(T, U) *map, T key, U value); \
- U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put); \
- U map_##T##_##U##_del(Map(T, U) *map, T key); \
+#define MAP_DECLS(T, U) \
+ KHASH_DECLARE(T##_##U##_map, T, U) \
+ \
+ typedef struct { \
+ khash_t(T##_##U##_map) *table; \
+ } Map(T, U); \
+ \
+ Map(T, U) *map_##T##_##U##_new(void); \
+ void map_##T##_##U##_free(Map(T, U) *map); \
+ U map_##T##_##U##_get(Map(T, U) *map, T key); \
+ bool map_##T##_##U##_has(Map(T, U) *map, T key); \
+ U map_##T##_##U##_put(Map(T, U) *map, T key, U value); \
+ U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put); \
+ U map_##T##_##U##_del(Map(T, U) *map, T key); \
void map_##T##_##U##_clear(Map(T, U) *map);
MAP_DECLS(int, int)
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 3495203c43..0ba9f8b076 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1304,7 +1304,7 @@ int utfc_ptr2char(const char_u *p, int *pcc)
*/
int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen)
{
-#define IS_COMPOSING(s1, s2, s3) \
+#define IS_COMPOSING(s1, s2, s3) \
(i == 0 ? UTF_COMPOSINGLIKE((s1), (s2)) : utf_iscomposing((s3)))
assert(maxlen > 0);
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 6599db787f..9fb03c4ac7 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -913,7 +913,7 @@ static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags)
#ifdef HAVE_FD_CLOEXEC
int fdflags = fcntl(mfp->mf_fd, F_GETFD);
if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
- fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
}
#endif
#ifdef HAVE_SELINUX
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 4e35dd481f..673205f08f 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -443,8 +443,9 @@ void ml_setname(buf_T *buf)
#ifdef HAVE_FD_CLOEXEC
{
int fdflags = fcntl(mfp->mf_fd, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
- fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
+ (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
}
#endif
}
@@ -1358,7 +1359,7 @@ recover_names (
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", TRUE);
if (swapname != NULL) {
- if (os_file_exists(swapname)) {
+ if (os_path_exists(swapname)) {
files = xmalloc(sizeof(char_u *));
files[0] = swapname;
swapname = NULL;
@@ -3425,11 +3426,11 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
break;
}
- /* If the file was deleted this fname can be used. */
- if (!os_file_exists((char_u *) fname))
+ // If the file was deleted this fname can be used.
+ if (!os_path_exists((char_u *)fname)) {
break;
- } else
- {
+ }
+ } else {
MSG_PUTS("\n");
if (msg_silent == 0)
/* call wait_return() later */
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 47f246fc76..77e8f0e4f2 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -493,10 +493,11 @@ int emsg(char_u *s)
* when the message should be ignored completely (used for the
* interrupt message).
*/
- if (cause_errthrow(s, severe, &ignore) == TRUE) {
- if (!ignore)
- did_emsg = TRUE;
- return TRUE;
+ if (cause_errthrow(s, severe, &ignore) == true) {
+ if (!ignore) {
+ did_emsg = true;
+ }
+ return true;
}
// set "v:errmsg", also when using ":silent! cmd"
@@ -511,41 +512,43 @@ int emsg(char_u *s)
p = get_emsg_source();
if (p != NULL) {
STRCAT(p, "\n");
- redir_write(p, -1);
+ redir_write(p, STRLEN(p));
xfree(p);
}
p = get_emsg_lnum();
if (p != NULL) {
STRCAT(p, "\n");
- redir_write(p, -1);
+ redir_write(p, STRLEN(p));
xfree(p);
}
- redir_write(s, -1);
- return TRUE;
+ redir_write(s, STRLEN(s));
+ return true;
}
- /* Reset msg_silent, an error causes messages to be switched back on. */
+ // Reset msg_silent, an error causes messages to be switched back on.
msg_silent = 0;
cmd_silent = FALSE;
- if (global_busy) /* break :global command */
- ++global_busy;
+ if (global_busy) { // break :global command
+ global_busy++;
+ }
- if (p_eb)
- beep_flush(); /* also includes flush_buffers() */
- else
- flush_buffers(FALSE); /* flush internal buffers */
- did_emsg = TRUE; /* flag for DoOneCmd() */
+ if (p_eb) {
+ beep_flush(); // also includes flush_buffers()
+ } else {
+ flush_buffers(false); // flush internal buffers
+ }
+ did_emsg = true; // flag for DoOneCmd()
}
- emsg_on_display = TRUE; /* remember there is an error message */
- ++msg_scroll; /* don't overwrite a previous message */
- attr = hl_attr(HLF_E); /* set highlight mode for error messages */
- if (msg_scrolled != 0)
- need_wait_return = TRUE; /* needed in case emsg() is called after
- * wait_return has reset need_wait_return
- * and a redraw is expected because
- * msg_scrolled is non-zero */
+ emsg_on_display = true; // remember there is an error message
+ msg_scroll++; // don't overwrite a previous message
+ attr = hl_attr(HLF_E); // set highlight mode for error messages
+ if (msg_scrolled != 0) {
+ need_wait_return = true; // needed in case emsg() is called after
+ } // wait_return has reset need_wait_return
+ // and a redraw is expected because
+ // msg_scrolled is non-zero
/*
* Display name and line number for the source of the error.
@@ -785,11 +788,13 @@ void wait_return(int redraw)
State = HITRETURN;
setmouse();
- /* Avoid the sequence that the user types ":" at the hit-return prompt
- * to start an Ex command, but the file-changed dialog gets in the
- * way. */
- if (need_check_timestamps)
- check_timestamps(FALSE);
+ cmdline_row = msg_row;
+ // Avoid the sequence that the user types ":" at the hit-return prompt
+ // to start an Ex command, but the file-changed dialog gets in the
+ // way.
+ if (need_check_timestamps) {
+ check_timestamps(false);
+ }
hit_return_msg();
@@ -1970,6 +1975,7 @@ static void msg_puts_printf(char *str, int maxlen)
*/
static int do_more_prompt(int typed_char)
{
+ static bool entered = false;
int used_typed_char = typed_char;
int oldState = State;
int c;
@@ -1979,6 +1985,13 @@ static int do_more_prompt(int typed_char)
msgchunk_T *mp;
int i;
+ // We get called recursively when a timer callback outputs a message. In
+ // that case don't show another prompt. Also when at the hit-Enter prompt.
+ if (entered || State == HITRETURN) {
+ return false;
+ }
+ entered = true;
+
if (typed_char == 'G') {
/* "g<": Find first line on the last page. */
mp_last = msg_sb_start(last_msgchunk);
@@ -2153,9 +2166,11 @@ static int do_more_prompt(int typed_char)
if (quit_more) {
msg_row = Rows - 1;
msg_col = 0;
- } else if (cmdmsg_rl)
+ } else if (cmdmsg_rl) {
msg_col = Columns - 1;
+ }
+ entered = false;
return retval;
}
@@ -2377,6 +2392,19 @@ static void redir_write(char_u *str, int maxlen)
char_u *s = str;
static int cur_col = 0;
+ if (maxlen == 0) {
+ return;
+ }
+
+ // Append output to capture().
+ if (capture_ga) {
+ size_t len = 0;
+ while (str[len] && (maxlen < 0 ? 1 : (len < (size_t)maxlen))) {
+ len++;
+ }
+ ga_concat_len(capture_ga, (const char *)str, len);
+ }
+
/* Don't do anything for displaying prompts and the like. */
if (redir_off)
return;
@@ -2389,22 +2417,27 @@ static void redir_write(char_u *str, int maxlen)
/* If the string doesn't start with CR or NL, go to msg_col */
if (*s != '\n' && *s != '\r') {
while (cur_col < msg_col) {
- if (redir_reg)
- write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
- else if (redir_vname)
+ if (redir_reg) {
+ write_reg_contents(redir_reg, (char_u *)" ", 1, true);
+ } else if (redir_vname) {
var_redir_str((char_u *)" ", -1);
- else if (redir_fd != NULL)
+ } else if (redir_fd != NULL) {
fputs(" ", redir_fd);
- if (verbose_fd != NULL)
+ }
+ if (verbose_fd != NULL) {
fputs(" ", verbose_fd);
- ++cur_col;
+ }
+ cur_col++;
}
}
- if (redir_reg)
- write_reg_contents(redir_reg, s, maxlen, TRUE);
- if (redir_vname)
+ if (redir_reg) {
+ size_t len = maxlen == -1 ? STRLEN(s) : (size_t)maxlen;
+ write_reg_contents(redir_reg, s, len, true);
+ }
+ if (redir_vname) {
var_redir_str(s, maxlen);
+ }
/* Write and adjust the current column. */
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) {
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 48791384a6..d72d8e8513 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -178,12 +178,11 @@ open_line (
if (curbuf->b_p_ai
|| do_si
) {
- /*
- * count white space on current line
- */
- newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE);
- if (newindent == 0 && !(flags & OPENLINE_COM_LIST))
- newindent = second_line_indent; /* for ^^D command in insert mode */
+ // count white space on current line
+ newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, false);
+ if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) {
+ newindent = second_line_indent; // for ^^D command in insert mode
+ }
/*
* Do smart indenting.
@@ -612,7 +611,7 @@ open_line (
if (curbuf->b_p_ai
|| do_si
)
- newindent = get_indent_str(leader, (int)curbuf->b_p_ts, FALSE);
+ newindent = get_indent_str(leader, (int)curbuf->b_p_ts, false);
/* Add the indent offset */
if (newindent + off < 0) {
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 2f499e477c..5efac2623c 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -6,6 +6,7 @@
#include "nvim/window.h"
#include "nvim/strings.h"
#include "nvim/screen.h"
+#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/os_unix.h"
#include "nvim/fold.h"
@@ -303,6 +304,10 @@ retnomove:
mouse_past_bottom = true;
}
+ if (!(flags & MOUSE_RELEASED) && which_button == MOUSE_LEFT) {
+ col = mouse_adjust_click(curwin, row, col);
+ }
+
// Start Visual mode before coladvance(), for when 'sel' != "old"
if ((flags & MOUSE_MAY_VIS) && !VIsual_active) {
check_visual_highlight();
@@ -597,3 +602,74 @@ bool mouse_scroll_horiz(int dir)
return leftcol_changed();
}
+
+// Adjust the clicked column position if there are concealed characters
+// before the current column. But only when it's absolutely necessary.
+static int mouse_adjust_click(win_T *wp, int row, int col)
+{
+ if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0
+ && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) {
+ return col;
+ }
+
+ int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum));
+ int vend = getviscol2(end, 0);
+
+ if (col >= vend) {
+ return col;
+ }
+
+ int i = wp->w_leftcol;
+
+ if (row > 0) {
+ i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp)
+ - wp->w_leftcol) + wp->w_skipcol;
+ }
+
+ int start_col = i;
+ int matchid;
+ int last_matchid;
+ int bcol = end - (vend - col);
+
+ while (i < bcol) {
+ matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i);
+
+ if (matchid != 0) {
+ if (wp->w_p_cole == 3) {
+ bcol++;
+ } else {
+ if (row > 0 && i == start_col) {
+ // Check if the current concealed character is actually part of
+ // the previous wrapped row's conceal group.
+ last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum,
+ i - 1);
+ if (last_matchid == matchid) {
+ bcol++;
+ }
+ } else if (wp->w_p_cole == 1
+ || (wp->w_p_cole == 2
+ && (lcs_conceal != NUL
+ || syn_get_sub_char() != NUL))) {
+ // At least one placeholder character will be displayed.
+ bcol--;
+ }
+
+ last_matchid = matchid;
+
+ // Adjust for concealed text that spans more than one character.
+ do {
+ i++;
+ bcol++;
+ matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i);
+ } while (last_matchid == matchid);
+
+ continue;
+ }
+ }
+
+ i++;
+ }
+
+ return getviscol2(bcol, 0);
+}
+
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 34ff7c6374..5b249ee1c7 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -7,8 +7,8 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
+#include "nvim/api/ui.h"
#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/remote_ui.h"
#include "nvim/event/loop.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/rstream.h"
@@ -16,6 +16,7 @@
#include "nvim/event/socket.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/vim.h"
+#include "nvim/main.h"
#include "nvim/ascii.h"
#include "nvim/memory.h"
#include "nvim/os_unix.h"
@@ -119,7 +120,7 @@ void channel_teardown(void)
uint64_t channel_from_process(char **argv)
{
Channel *channel = register_channel(kChannelTypeProc);
- channel->data.process.uvproc = libuv_process_init(&loop, channel);
+ channel->data.process.uvproc = libuv_process_init(&main_loop, channel);
Process *proc = &channel->data.process.uvproc.process;
proc->argv = argv;
proc->in = &channel->data.process.in;
@@ -127,7 +128,7 @@ uint64_t channel_from_process(char **argv)
proc->err = &channel->data.process.err;
proc->cb = process_exit;
if (!process_spawn(proc)) {
- loop_poll_events(&loop, 0);
+ loop_poll_events(&main_loop, 0);
decref(channel);
return 0;
}
@@ -179,7 +180,7 @@ bool channel_send_event(uint64_t id, char *name, Array args)
// Pending request, queue the notification for later sending.
String method = cstr_as_string(name);
WBuffer *buffer = serialize_request(id, 0, method, args, &out_buffer, 1);
- kv_push(WBuffer *, channel->delayed_notifications, buffer);
+ kv_push(channel->delayed_notifications, buffer);
} else {
send_event(channel, name, args);
}
@@ -217,10 +218,10 @@ Object channel_send_call(uint64_t id,
send_request(channel, request_id, method_name, args);
// Push the frame
- ChannelCallFrame frame = {request_id, false, false, NIL};
- kv_push(ChannelCallFrame *, channel->call_stack, &frame);
+ ChannelCallFrame frame = { request_id, false, false, NIL };
+ kv_push(channel->call_stack, &frame);
channel->pending_requests++;
- LOOP_PROCESS_EVENTS_UNTIL(&loop, channel->events, -1, frame.returned);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, frame.returned);
(void)kv_pop(channel->call_stack);
channel->pending_requests--;
@@ -316,11 +317,11 @@ void channel_from_stdio(void)
Channel *channel = register_channel(kChannelTypeStdio);
incref(channel); // stdio channels are only closed on exit
// read stream
- rstream_init_fd(&loop, &channel->data.std.in, 0, CHANNEL_BUFFER_SIZE,
- channel);
+ rstream_init_fd(&main_loop, &channel->data.std.in, 0, CHANNEL_BUFFER_SIZE,
+ channel);
rstream_start(&channel->data.std.in, parse_msgpack);
// write stream
- wstream_init_fd(&loop, &channel->data.std.out, 1, 0, NULL);
+ wstream_init_fd(&main_loop, &channel->data.std.out, 1, 0, NULL);
}
static void forward_stderr(Stream *stream, RBuffer *rbuf, size_t count,
@@ -574,13 +575,12 @@ static void send_event(Channel *channel,
static void broadcast_event(char *name, Array args)
{
- kvec_t(Channel *) subscribed;
- kv_init(subscribed);
+ kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
Channel *channel;
map_foreach_value(channels, channel, {
if (pmap_has(cstr_t)(channel->subscribed_events, name)) {
- kv_push(Channel *, subscribed, channel);
+ kv_push(subscribed, channel);
}
});
@@ -600,7 +600,7 @@ static void broadcast_event(char *name, Array args)
for (size_t i = 0; i < kv_size(subscribed); i++) {
Channel *channel = kv_A(subscribed, i);
if (channel->pending_requests) {
- kv_push(WBuffer *, channel->delayed_notifications, buffer);
+ kv_push(channel->delayed_notifications, buffer);
} else {
channel_write(channel, buffer);
}
@@ -647,7 +647,7 @@ static void close_channel(Channel *channel)
case kChannelTypeStdio:
stream_close(&channel->data.std.in, NULL);
stream_close(&channel->data.std.out, NULL);
- queue_put(loop.fast_events, exit_event, 1, channel);
+ queue_put(main_loop.fast_events, exit_event, 1, channel);
return;
default:
abort();
@@ -692,7 +692,7 @@ static void close_cb(Stream *stream, void *data)
static Channel *register_channel(ChannelType type)
{
Channel *rv = xmalloc(sizeof(Channel));
- rv->events = queue_new_child(loop.events);
+ rv->events = queue_new_child(main_loop.events);
rv->type = type;
rv->refcount = 1;
rv->closed = false;
@@ -816,20 +816,55 @@ static void decref(Channel *channel)
#define REQ "[request] "
#define RES "[response] "
#define NOT "[notification] "
+#define ERR "[error] "
+
+// Cannot define array with negative offsets, so this one is needed to be added
+// to MSGPACK_UNPACK_\* values.
+#define MUR_OFF 2
+
+static const char *const msgpack_error_messages[] = {
+ [MSGPACK_UNPACK_EXTRA_BYTES + MUR_OFF] = "extra bytes found",
+ [MSGPACK_UNPACK_CONTINUE + MUR_OFF] = "incomplete string",
+ [MSGPACK_UNPACK_PARSE_ERROR + MUR_OFF] = "parse error",
+ [MSGPACK_UNPACK_NOMEM_ERROR + MUR_OFF] = "not enough memory",
+};
static void log_server_msg(uint64_t channel_id,
msgpack_sbuffer *packed)
{
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
- msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL);
- uint64_t type = unpacked.data.via.array.ptr[0].via.u64;
DLOGN("[msgpack-rpc] nvim -> client(%" PRIu64 ") ", channel_id);
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, type ? (type == 1 ? RES : NOT) : REQ);
- log_msg_close(f, unpacked.data);
- msgpack_unpacked_destroy(&unpacked);
+ const msgpack_unpack_return result =
+ msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL);
+ switch (result) {
+ case MSGPACK_UNPACK_SUCCESS: {
+ uint64_t type = unpacked.data.via.array.ptr[0].via.u64;
+ log_lock();
+ FILE *f = open_log_file();
+ fprintf(f, type ? (type == 1 ? RES : NOT) : REQ);
+ log_msg_close(f, unpacked.data);
+ msgpack_unpacked_destroy(&unpacked);
+ break;
+ }
+ case MSGPACK_UNPACK_EXTRA_BYTES:
+ case MSGPACK_UNPACK_CONTINUE:
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ case MSGPACK_UNPACK_NOMEM_ERROR: {
+ log_lock();
+ FILE *f = open_log_file();
+ fprintf(f, ERR);
+ log_msg_close(f, (msgpack_object) {
+ .type = MSGPACK_OBJECT_STR,
+ .via.str = {
+ .ptr = (char *)msgpack_error_messages[result + MUR_OFF],
+ .size = (uint32_t)strlen(
+ msgpack_error_messages[result + MUR_OFF]),
+ },
+ });
+ break;
+ }
+ }
}
static void log_client_msg(uint64_t channel_id,
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 0049ae6b95..9195b10614 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -7,9 +7,11 @@
#include "nvim/api/private/helpers.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/defs.h"
+#include "nvim/lib/kvec.h"
#include "nvim/vim.h"
#include "nvim/log.h"
#include "nvim/memory.h"
+#include "nvim/assert.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/helpers.c.generated.h"
@@ -18,39 +20,39 @@
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_EXT \
- || obj->via.ext.type != kObjectType##t) { \
- return false; \
- } \
- \
- msgpack_object data; \
- msgpack_unpack_return ret = msgpack_unpack(obj->via.ext.ptr, \
- obj->via.ext.size, \
- NULL, \
- &zone, \
- &data); \
- \
- if (ret != MSGPACK_UNPACK_SUCCESS) { \
- return false; \
- } \
- \
- *arg = data.via.u64; \
- return true; \
- } \
- \
- void msgpack_rpc_from_##lt(t o, msgpack_packer *res) \
- FUNC_ATTR_NONNULL_ARG(2) \
- { \
- 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); \
+#define HANDLE_TYPE_CONVERSION_IMPL(t, lt) \
+ bool msgpack_rpc_to_##lt(const msgpack_object *const obj, t *const arg) \
+ FUNC_ATTR_NONNULL_ALL \
+ { \
+ if (obj->type != MSGPACK_OBJECT_EXT \
+ || obj->via.ext.type != kObjectType##t) { \
+ return false; \
+ } \
+ \
+ msgpack_object data; \
+ msgpack_unpack_return ret = msgpack_unpack(obj->via.ext.ptr, \
+ obj->via.ext.size, \
+ NULL, \
+ &zone, \
+ &data); \
+ \
+ if (ret != MSGPACK_UNPACK_SUCCESS) { \
+ return false; \
+ } \
+ \
+ *arg = data.via.u64; \
+ return true; \
+ } \
+ \
+ void msgpack_rpc_from_##lt(t o, msgpack_packer *res) \
+ FUNC_ATTR_NONNULL_ARG(2) \
+ { \
+ 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)
@@ -63,34 +65,182 @@ 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)
+typedef struct {
+ const msgpack_object *mobj;
+ Object *aobj;
+ bool container;
+ size_t idx;
+} MPToAPIObjectStackItem;
+
+/// Convert type used by msgpack parser to Neovim own API type
+///
+/// @param[in] obj Msgpack value to convert.
+/// @param[out] arg Location where result of conversion will be saved.
+///
+/// @return true in case of success, false otherwise.
+bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const 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) {
- *arg = (int64_t)obj->via.u64;
- return true;
+ bool ret = true;
+ kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE;
+ kv_push(stack, ((MPToAPIObjectStackItem) { obj, arg, false, 0 }));
+ while (ret && kv_size(stack)) {
+ MPToAPIObjectStackItem cur = kv_last(stack);
+ if (!cur.container) {
+ *cur.aobj = NIL;
+ }
+ switch (cur.mobj->type) {
+ case MSGPACK_OBJECT_NIL: {
+ break;
+ }
+ case MSGPACK_OBJECT_BOOLEAN: {
+ *cur.aobj = BOOLEAN_OBJ(cur.mobj->via.boolean);
+ break;
+ }
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
+ STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.i64),
+ "Msgpack integer size does not match API integer");
+ *cur.aobj = INTEGER_OBJ(cur.mobj->via.i64);
+ break;
+ }
+ case MSGPACK_OBJECT_POSITIVE_INTEGER: {
+ STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.u64),
+ "Msgpack integer size does not match API integer");
+ if (cur.mobj->via.u64 > API_INTEGER_MAX) {
+ ret = false;
+ } else {
+ *cur.aobj = INTEGER_OBJ((Integer)cur.mobj->via.u64);
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_FLOAT: {
+ STATIC_ASSERT(sizeof(Float) == sizeof(cur.mobj->via.f64),
+ "Msgpack floating-point size does not match API integer");
+ *cur.aobj = FLOATING_OBJ(cur.mobj->via.f64);
+ break;
+ }
+#define STR_CASE(type, attr, obj, dest, conv) \
+ case type: { \
+ dest = conv(((String) { \
+ .size = obj->via.attr.size, \
+ .data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \
+ ? NULL \
+ : xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), \
+ })); \
+ break; \
+ }
+ STR_CASE(MSGPACK_OBJECT_STR, str, cur.mobj, *cur.aobj, STRING_OBJ)
+ STR_CASE(MSGPACK_OBJECT_BIN, bin, cur.mobj, *cur.aobj, STRING_OBJ)
+ case MSGPACK_OBJECT_ARRAY: {
+ const size_t size = cur.mobj->via.array.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ kv_push(stack, ((MPToAPIObjectStackItem) {
+ .mobj = &cur.mobj->via.array.ptr[idx],
+ .aobj = &cur.aobj->data.array.items[idx],
+ .container = false,
+ }));
+ }
+ } else {
+ *cur.aobj = ARRAY_OBJ(((Array) {
+ .size = size,
+ .capacity = size,
+ .items = (size > 0
+ ? xcalloc(size, sizeof(*cur.aobj->data.array.items))
+ : NULL),
+ }));
+ cur.container = true;
+ kv_last(stack) = cur;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_MAP: {
+ const size_t size = cur.mobj->via.map.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key;
+ switch (key->type) {
+#define ID(x) x
+ STR_CASE(MSGPACK_OBJECT_STR, str, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
+ STR_CASE(MSGPACK_OBJECT_BIN, bin, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
+#undef ID
+ case MSGPACK_OBJECT_NIL:
+ case MSGPACK_OBJECT_BOOLEAN:
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+ case MSGPACK_OBJECT_FLOAT:
+ case MSGPACK_OBJECT_EXT:
+ case MSGPACK_OBJECT_MAP:
+ case MSGPACK_OBJECT_ARRAY: {
+ ret = false;
+ break;
+ }
+ }
+ if (ret) {
+ kv_push(stack, ((MPToAPIObjectStackItem) {
+ .mobj = &cur.mobj->via.map.ptr[idx].val,
+ .aobj = &cur.aobj->data.dictionary.items[idx].value,
+ .container = false,
+ }));
+ }
+ }
+ } else {
+ *cur.aobj = DICTIONARY_OBJ(((Dictionary) {
+ .size = size,
+ .capacity = size,
+ .items = (size > 0
+ ? xcalloc(size, sizeof(*cur.aobj->data.dictionary.items))
+ : NULL),
+ }));
+ cur.container = true;
+ kv_last(stack) = cur;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_EXT: {
+ switch (cur.mobj->via.ext.type) {
+ case kObjectTypeBuffer: {
+ cur.aobj->type = kObjectTypeBuffer;
+ ret = msgpack_rpc_to_buffer(cur.mobj, &cur.aobj->data.buffer);
+ break;
+ }
+ case kObjectTypeWindow: {
+ cur.aobj->type = kObjectTypeWindow;
+ ret = msgpack_rpc_to_window(cur.mobj, &cur.aobj->data.window);
+ break;
+ }
+ case kObjectTypeTabpage: {
+ cur.aobj->type = kObjectTypeTabpage;
+ ret = msgpack_rpc_to_tabpage(cur.mobj, &cur.aobj->data.tabpage);
+ break;
+ }
+ }
+ break;
+ }
+#undef STR_CASE
+ }
+ if (!cur.container) {
+ (void)kv_pop(stack);
+ }
}
-
- *arg = obj->via.i64;
- return obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER;
+ kv_destroy(stack);
+ return ret;
}
-bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg)
- FUNC_ATTR_NONNULL_ALL
-{
- *arg = obj->via.f64;
- return obj->type == MSGPACK_OBJECT_FLOAT;
-}
-
-bool msgpack_rpc_to_string(msgpack_object *obj, String *arg)
+static bool msgpack_rpc_to_string(const msgpack_object *const obj,
+ String *const arg)
FUNC_ATTR_NONNULL_ALL
{
if (obj->type == MSGPACK_OBJECT_BIN || obj->type == MSGPACK_OBJECT_STR) {
@@ -103,58 +253,7 @@ bool msgpack_rpc_to_string(msgpack_object *obj, String *arg)
return false;
}
-bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg)
- FUNC_ATTR_NONNULL_ALL
-{
- switch (obj->type) {
- case MSGPACK_OBJECT_NIL:
- arg->type = kObjectTypeNil;
- return true;
-
- case MSGPACK_OBJECT_BOOLEAN:
- arg->type = kObjectTypeBoolean;
- return msgpack_rpc_to_boolean(obj, &arg->data.boolean);
-
- case MSGPACK_OBJECT_POSITIVE_INTEGER:
- case MSGPACK_OBJECT_NEGATIVE_INTEGER:
- arg->type = kObjectTypeInteger;
- return msgpack_rpc_to_integer(obj, &arg->data.integer);
-
- case MSGPACK_OBJECT_FLOAT:
- arg->type = kObjectTypeFloat;
- return msgpack_rpc_to_float(obj, &arg->data.floating);
-
- case MSGPACK_OBJECT_BIN:
- case MSGPACK_OBJECT_STR:
- arg->type = kObjectTypeString;
- return msgpack_rpc_to_string(obj, &arg->data.string);
-
- case MSGPACK_OBJECT_ARRAY:
- arg->type = kObjectTypeArray;
- return msgpack_rpc_to_array(obj, &arg->data.array);
-
- case MSGPACK_OBJECT_MAP:
- arg->type = kObjectTypeDictionary;
- return msgpack_rpc_to_dictionary(obj, &arg->data.dictionary);
-
- case MSGPACK_OBJECT_EXT:
- switch (obj->via.ext.type) {
- case kObjectTypeBuffer:
- arg->type = kObjectTypeBuffer;
- return msgpack_rpc_to_buffer(obj, &arg->data.buffer);
- case kObjectTypeWindow:
- arg->type = kObjectTypeWindow;
- return msgpack_rpc_to_window(obj, &arg->data.window);
- case kObjectTypeTabpage:
- arg->type = kObjectTypeTabpage;
- return msgpack_rpc_to_tabpage(obj, &arg->data.tabpage);
- }
- default:
- return false;
- }
-}
-
-bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg)
+bool msgpack_rpc_to_array(const msgpack_object *const obj, Array *const arg)
FUNC_ATTR_NONNULL_ALL
{
if (obj->type != MSGPACK_OBJECT_ARRAY) {
@@ -173,7 +272,8 @@ bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg)
return true;
}
-bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg)
+bool msgpack_rpc_to_dictionary(const msgpack_object *const obj,
+ Dictionary *const arg)
FUNC_ATTR_NONNULL_ALL
{
if (obj->type != MSGPACK_OBJECT_MAP) {
@@ -228,50 +328,108 @@ void msgpack_rpc_from_string(String result, msgpack_packer *res)
msgpack_pack_str_body(res, result.data, result.size);
}
-void msgpack_rpc_from_object(Object result, msgpack_packer *res)
+typedef struct {
+ const Object *aobj;
+ bool container;
+ size_t idx;
+} APIToMPObjectStackItem;
+
+/// Convert type used by Neovim API to msgpack
+///
+/// @param[in] result Object to convert.
+/// @param[out] res Structure that defines where conversion results are saved.
+///
+/// @return true in case of success, false otherwise.
+void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
FUNC_ATTR_NONNULL_ARG(2)
{
- switch (result.type) {
- case kObjectTypeNil:
- msgpack_pack_nil(res);
- break;
-
- case kObjectTypeBoolean:
- msgpack_rpc_from_boolean(result.data.boolean, res);
- break;
-
- case kObjectTypeInteger:
- msgpack_rpc_from_integer(result.data.integer, res);
- break;
-
- case kObjectTypeFloat:
- msgpack_rpc_from_float(result.data.floating, res);
- break;
-
- case kObjectTypeString:
- msgpack_rpc_from_string(result.data.string, res);
- break;
-
- case kObjectTypeArray:
- msgpack_rpc_from_array(result.data.array, res);
- break;
-
- case kObjectTypeBuffer:
- msgpack_rpc_from_buffer(result.data.buffer, res);
- break;
-
- case kObjectTypeWindow:
- msgpack_rpc_from_window(result.data.window, res);
- break;
-
- case kObjectTypeTabpage:
- msgpack_rpc_from_tabpage(result.data.tabpage, res);
- break;
-
- case kObjectTypeDictionary:
- msgpack_rpc_from_dictionary(result.data.dictionary, res);
- break;
+ kvec_t(APIToMPObjectStackItem) stack = KV_INITIAL_VALUE;
+ kv_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
+ while (kv_size(stack)) {
+ APIToMPObjectStackItem cur = kv_last(stack);
+ switch (cur.aobj->type) {
+ case kObjectTypeNil: {
+ msgpack_pack_nil(res);
+ break;
+ }
+ case kObjectTypeBoolean: {
+ msgpack_rpc_from_boolean(cur.aobj->data.boolean, res);
+ break;
+ }
+ case kObjectTypeInteger: {
+ msgpack_rpc_from_integer(cur.aobj->data.integer, res);
+ break;
+ }
+ case kObjectTypeFloat: {
+ msgpack_rpc_from_float(cur.aobj->data.floating, res);
+ break;
+ }
+ case kObjectTypeString: {
+ msgpack_rpc_from_string(cur.aobj->data.string, res);
+ break;
+ }
+ case kObjectTypeBuffer: {
+ msgpack_rpc_from_buffer(cur.aobj->data.buffer, res);
+ break;
+ }
+ case kObjectTypeWindow: {
+ msgpack_rpc_from_window(cur.aobj->data.window, res);
+ break;
+ }
+ case kObjectTypeTabpage: {
+ msgpack_rpc_from_tabpage(cur.aobj->data.tabpage, res);
+ break;
+ }
+ case kObjectTypeArray: {
+ const size_t size = cur.aobj->data.array.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ kv_push(stack, ((APIToMPObjectStackItem) {
+ .aobj = &cur.aobj->data.array.items[idx],
+ .container = false,
+ }));
+ }
+ } else {
+ msgpack_pack_array(res, size);
+ cur.container = true;
+ kv_last(stack) = cur;
+ }
+ break;
+ }
+ case kObjectTypeDictionary: {
+ const size_t size = cur.aobj->data.dictionary.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key,
+ res);
+ kv_push(stack, ((APIToMPObjectStackItem) {
+ .aobj = &cur.aobj->data.dictionary.items[idx].value,
+ .container = false,
+ }));
+ }
+ } else {
+ msgpack_pack_map(res, size);
+ cur.container = true;
+ kv_last(stack) = cur;
+ }
+ break;
+ }
+ }
+ if (!cur.container) {
+ (void)kv_pop(stack);
+ }
}
+ kv_destroy(stack);
}
void msgpack_rpc_from_array(Array result, msgpack_packer *res)
diff --git a/src/nvim/msgpack_rpc/remote_ui.h b/src/nvim/msgpack_rpc/remote_ui.h
deleted file mode 100644
index 8af86dc1b8..0000000000
--- a/src/nvim/msgpack_rpc/remote_ui.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef NVIM_MSGPACK_RPC_REMOTE_UI_H
-#define NVIM_MSGPACK_RPC_REMOTE_UI_H
-
-#include "nvim/ui.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "msgpack_rpc/remote_ui.h.generated.h"
-#endif
-#endif // NVIM_MSGPACK_RPC_REMOTE_UI_H
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 6cc56ba3dd..d7c2926a0f 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -12,6 +12,7 @@
#include "nvim/eval.h"
#include "nvim/garray.h"
#include "nvim/vim.h"
+#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/log.h"
#include "nvim/fileio.h"
@@ -39,6 +40,10 @@ bool server_init(void)
listen_address = server_address_new();
}
+ if (!listen_address) {
+ return false;
+ }
+
bool ok = (server_start(listen_address) == 0);
if (must_free) {
xfree((char *) listen_address);
@@ -108,7 +113,7 @@ int server_start(const char *endpoint)
}
SocketWatcher *watcher = xmalloc(sizeof(SocketWatcher));
- socket_watcher_init(&loop, watcher, endpoint, NULL);
+ socket_watcher_init(&main_loop, watcher, endpoint, NULL);
// Check if a watcher for the endpoint already exists
for (int i = 0; i < watchers.ga_len; i++) {
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 382c4943ff..c95e5e1a15 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -974,7 +974,7 @@ static int normal_execute(VimState *state, int key)
s->old_col = curwin->w_curswant;
s->c = key;
- LANGMAP_ADJUST(s->c, true);
+ LANGMAP_ADJUST(s->c, get_real_state() != SELECTMODE);
// If a mapping was started in Visual or Select mode, remember the length
// of the mapping. This is used below to not return to Insert mode for as
@@ -1795,10 +1795,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
if (oap->line_count < 2)
oap->line_count = 2;
if (curwin->w_cursor.lnum + oap->line_count - 1 >
- curbuf->b_ml.ml_line_count)
+ curbuf->b_ml.ml_line_count) {
beep_flush();
- else {
- do_join(oap->line_count, oap->op_type == OP_JOIN, true, true, true);
+ } else {
+ do_join((size_t)oap->line_count, oap->op_type == OP_JOIN,
+ true, true, true);
auto_format(false, true);
}
break;
@@ -7666,7 +7667,7 @@ static void nv_join(cmdarg_T *cap)
prep_redo(cap->oap->regname, cap->count0,
NUL, cap->cmdchar, NUL, NUL, cap->nchar);
- do_join(cap->count0, cap->nchar == NUL, true, true, true);
+ do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true);
}
}
@@ -7879,7 +7880,7 @@ static void nv_event(cmdarg_T *cap)
// not safe to perform garbage collection because there could be unreferenced
// lists or dicts being used.
may_garbage_collect = false;
- queue_process_events(loop.events);
+ queue_process_events(main_loop.events);
cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index adfd0424f0..e8a79fa820 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1,6 +1,6 @@
/*
* ops.c: implementation of various operators: op_shift, op_delete, op_tilde,
- * op_change, op_yank, do_put, do_join
+ * op_change, op_yank, do_put, do_join
*/
#include <assert.h>
@@ -257,8 +257,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
* shift the current line one shiftwidth left (if left != 0) or right
* leaves cursor on first blank in the line
*/
-void
-shift_line (
+void shift_line(
int left,
int round,
int amount,
@@ -340,10 +339,16 @@ static void shift_block(oparg_T *oap, int amount)
total += bd.pre_whitesp; /* all virtual WS up to & incl a split TAB */
ws_vcol = bd.start_vcol - bd.pre_whitesp;
if (bd.startspaces) {
- if (has_mbyte)
- bd.textstart += (*mb_ptr2len)(bd.textstart);
- else
- ++bd.textstart;
+ if (has_mbyte) {
+ if ((*mb_ptr2len)(bd.textstart) == 1) {
+ bd.textstart++;
+ } else {
+ ws_vcol = 0;
+ bd.startspaces = 0;
+ }
+ } else {
+ bd.textstart++;
+ }
}
for (; ascii_iswhite(*bd.textstart); ) {
// TODO: is passing bd.textstart for start of the line OK?
@@ -369,18 +374,18 @@ static void shift_block(oparg_T *oap, int amount)
memset(newp + bd.textcol + i, ' ', (size_t)j);
/* the end */
memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
- } else { /* left */
- colnr_T destination_col; /* column to which text in block will
- be shifted */
- char_u *verbatim_copy_end; /* end of the part of the line which is
- copied verbatim */
- colnr_T verbatim_copy_width; /* the (displayed) width of this part
- of line */
- unsigned fill; /* nr of spaces that replace a TAB */
- unsigned new_line_len; /* the length of the line after the
- block shift */
- size_t block_space_width;
- size_t shift_amount;
+ } else { // left
+ colnr_T destination_col; // column to which text in block will
+ // be shifted
+ char_u *verbatim_copy_end; // end of the part of the line which is
+ // copied verbatim
+ colnr_T verbatim_copy_width; // the (displayed) width of this part
+ // of line
+ size_t fill; // nr of spaces that replace a TAB
+ size_t new_line_len; // the length of the line after the
+ // block shift
+ colnr_T block_space_width;
+ colnr_T shift_amount;
char_u *non_white = bd.textstart;
colnr_T non_white_col;
@@ -409,11 +414,10 @@ static void shift_block(oparg_T *oap, int amount)
block_space_width = non_white_col - oap->start_vcol;
/* We will shift by "total" or "block_space_width", whichever is less.
*/
- shift_amount = (block_space_width < (size_t)total
- ? block_space_width : (size_t)total);
+ shift_amount = (block_space_width < total ? block_space_width : total);
- /* The column to which we will shift the text. */
- destination_col = (colnr_T)(non_white_col - shift_amount);
+ // The column to which we will shift the text.
+ destination_col = non_white_col - shift_amount;
/* Now let's find out how much of the beginning of the line we can
* reuse without modification. */
@@ -439,20 +443,21 @@ static void shift_block(oparg_T *oap, int amount)
/* If "destination_col" is different from the width of the initial
* part of the line that will be copied, it means we encountered a tab
* character, which we will have to partly replace with spaces. */
- fill = destination_col - verbatim_copy_width;
-
- /* The replacement line will consist of:
- * - the beginning of the original line up to "verbatim_copy_end",
- * - "fill" number of spaces,
- * - the rest of the line, pointed to by non_white. */
- new_line_len = (unsigned)(verbatim_copy_end - oldp)
- + fill
- + (unsigned)STRLEN(non_white) + 1;
-
- newp = (char_u *) xmalloc((size_t)(new_line_len));
- memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
- memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill);
- STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
+ assert(destination_col - verbatim_copy_width >= 0);
+ fill = (size_t)(destination_col - verbatim_copy_width);
+
+ assert(verbatim_copy_end - oldp >= 0);
+ size_t verbatim_diff = (size_t)(verbatim_copy_end - oldp);
+ // The replacement line will consist of:
+ // - the beginning of the original line up to "verbatim_copy_end",
+ // - "fill" number of spaces,
+ // - the rest of the line, pointed to by non_white.
+ new_line_len = verbatim_diff + fill + STRLEN(non_white) + 1;
+
+ newp = (char_u *) xmalloc(new_line_len);
+ memmove(newp, oldp, verbatim_diff);
+ memset(newp + verbatim_diff, ' ', fill);
+ STRMOVE(newp + verbatim_diff + fill, non_white);
}
/* replace the line */
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
@@ -469,21 +474,20 @@ static void shift_block(oparg_T *oap, int amount)
static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def *bdp)
{
int p_ts;
- int count = 0; /* extra spaces to replace a cut TAB */
- int spaces = 0; /* non-zero if cutting a TAB */
- colnr_T offset; /* pointer along new line */
- unsigned s_len; /* STRLEN(s) */
- char_u *newp, *oldp; /* new, old lines */
- linenr_T lnum; /* loop var */
+ int count = 0; // extra spaces to replace a cut TAB
+ int spaces = 0; // non-zero if cutting a TAB
+ colnr_T offset; // pointer along new line
+ size_t s_len = STRLEN(s);
+ char_u *newp, *oldp; // new, old lines
+ linenr_T lnum; // loop var
int oldstate = State;
-
- State = INSERT; /* don't want REPLACE for State */
- s_len = (unsigned)STRLEN(s);
+ State = INSERT; // don't want REPLACE for State
for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++) {
- block_prep(oap, bdp, lnum, TRUE);
- if (bdp->is_short && b_insert)
- continue; /* OP_INSERT, line ends before block start */
+ block_prep(oap, bdp, lnum, true);
+ if (bdp->is_short && b_insert) {
+ continue; // OP_INSERT, line ends before block start
+ }
oldp = ml_get(lnum);
@@ -523,25 +527,26 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
count -= off;
}
- newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + s_len + count + 1));
+ assert(count >= 0);
+ newp = (char_u *)xmalloc(STRLEN(oldp) + s_len + (size_t)count + 1);
- /* copy up to shifted part */
- memmove(newp, oldp, (size_t)(offset));
+ // copy up to shifted part
+ memmove(newp, oldp, (size_t)offset);
oldp += offset;
- /* insert pre-padding */
+ // insert pre-padding
memset(newp + offset, ' ', (size_t)spaces);
- /* copy the new text */
- memmove(newp + offset + spaces, s, (size_t)s_len);
- offset += s_len;
+ // copy the new text
+ memmove(newp + offset + spaces, s, s_len);
+ offset += (int)s_len;
if (spaces && !bdp->is_short) {
- /* insert post-padding */
+ // insert post-padding
memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces));
- /* We're splitting a TAB, don't copy it. */
+ // We're splitting a TAB, don't copy it.
oldp++;
- /* We allowed for that TAB, remember this now */
+ // We allowed for that TAB, remember this now
count++;
}
@@ -804,7 +809,7 @@ yankreg_T *copy_register(int name)
copy->y_array = NULL;
} else {
copy->y_array = xcalloc(copy->y_size, sizeof(char_u *));
- for (linenr_T i = 0; i < copy->y_size; i++) {
+ for (size_t i = 0; i < copy->y_size; i++) {
copy->y_array[i] = vim_strsave(reg->y_array[i]);
}
}
@@ -888,7 +893,7 @@ static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data)
/*
* Stuff string "p" into yank register "regname" as a single line (append if
- * uppercase). "p" must have been alloced.
+ * uppercase). "p" must have been alloced.
*
* return FAIL for failure, OK otherwise
*/
@@ -940,10 +945,8 @@ do_execreg (
int silent /* set "silent" flag in typeahead buffer */
)
{
- long i;
- char_u *p;
+ char_u *p;
int retval = OK;
- int remap;
if (regname == '@') { /* repeat previous one */
if (execreg_lastc == NUL) {
@@ -1001,21 +1004,20 @@ do_execreg (
if (reg->y_array == NULL)
return FAIL;
- /* Disallow remaping for ":@r". */
- remap = colon ? REMAP_NONE : REMAP_YES;
+ // Disallow remaping for ":@r".
+ int remap = colon ? REMAP_NONE : REMAP_YES;
/*
* Insert lines into typeahead buffer, from last one to first one.
*/
put_reedit_in_typebuf(silent);
- for (i = reg->y_size - 1; i >= 0; i--) {
- char_u *escaped;
-
+ char_u *escaped;
+ for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included
// insert NL between lines and after last line if type is kMTLineWise
- if (reg->y_type == kMTLineWise || i < reg->y_size - 1
- || addcr) {
- if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
+ if (reg->y_type == kMTLineWise || i < reg->y_size - 1 || addcr) {
+ if (ins_typebuf((char_u *)"\n", remap, 0, true, silent) == FAIL) {
return FAIL;
+ }
}
escaped = vim_strsave_escape_csi(reg->y_array[i]);
retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
@@ -1045,7 +1047,7 @@ static void put_reedit_in_typebuf(int silent)
buf[1] = 'R';
buf[2] = NUL;
} else {
- buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
+ buf[0] = (char_u)(restart_edit == 'I' ? 'i' : restart_edit);
buf[1] = NUL;
}
if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
@@ -1059,8 +1061,7 @@ static void put_reedit_in_typebuf(int silent)
* When "esc" is TRUE it is to be taken literally: Escape CSI characters and
* no remapping.
*/
-static int
-put_in_typebuf (
+static int put_in_typebuf(
char_u *s,
int esc,
int colon, /* add ':' before the line */
@@ -1098,13 +1099,11 @@ put_in_typebuf (
*
* return FAIL for failure, OK otherwise
*/
-int
-insert_reg (
+int insert_reg(
int regname,
int literally /* insert literally, not as if typed */
)
{
- long i;
int retval = OK;
char_u *arg;
int allocated;
@@ -1132,10 +1131,10 @@ insert_reg (
xfree(arg);
} else { /* name or number register */
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
- if (reg->y_array == NULL)
+ if (reg->y_array == NULL) {
retval = FAIL;
- else {
- for (i = 0; i < reg->y_size; i++) {
+ } else {
+ for (size_t i = 0; i < reg->y_size; i++) {
stuffescaped(reg->y_array[i], literally);
// Insert a newline between lines and after last line if
// y_type is kMTLineWise.
@@ -1185,8 +1184,7 @@ static void stuffescaped(char_u *arg, int literally)
* If "regname" is a special register, return TRUE and store a pointer to its
* value in "argp".
*/
-int
-get_spec_reg (
+int get_spec_reg(
int regname,
char_u **argp,
int *allocated, /* return: TRUE when value was allocated */
@@ -1273,13 +1271,11 @@ get_spec_reg (
/// @returns FAIL for failure, OK otherwise
bool cmdline_paste_reg(int regname, bool literally, bool remcr)
{
- long i;
-
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (reg->y_array == NULL)
return FAIL;
- for (i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
cmdline_paste_str(reg->y_array[i], literally);
// Insert ^M between lines and after last line if type is kMTLineWise.
@@ -1311,12 +1307,14 @@ int op_delete(oparg_T *oap)
struct block_def bd;
linenr_T old_lcount = curbuf->b_ml.ml_line_count;
- if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to do
return OK;
+ }
- /* Nothing to delete, return here. Do prepare undo, for op_change(). */
- if (oap->empty)
+ // Nothing to delete, return here. Do prepare undo, for op_change().
+ if (oap->empty) {
return u_save_cursor();
+ }
if (!MODIFIABLE(curbuf)) {
EMSG(_(e_modifiable));
@@ -1431,23 +1429,21 @@ int op_delete(oparg_T *oap)
curwin->w_cursor.coladd = 0;
}
- /* n == number of chars deleted
- * If we delete a TAB, it may be replaced by several characters.
- * Thus the number of characters may increase!
- */
+ // n == number of chars deleted
+ // If we delete a TAB, it may be replaced by several characters.
+ // Thus the number of characters may increase!
n = bd.textlen - bd.startspaces - bd.endspaces;
oldp = ml_get(lnum);
- newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + 1 - n));
- /* copy up to deleted part */
+ newp = (char_u *)xmalloc(STRLEN(oldp) - (size_t)n + 1);
+ // copy up to deleted part
memmove(newp, oldp, (size_t)bd.textcol);
- /* insert spaces */
- memset(newp + bd.textcol, ' ',
- (size_t)(bd.startspaces + bd.endspaces));
- /* copy the part after the deleted part */
+ // insert spaces
+ memset(newp + bd.textcol, ' ', (size_t)(bd.startspaces + bd.endspaces));
+ // copy the part after the deleted part
oldp += bd.textcol + bd.textlen;
STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
- /* replace the line */
- ml_replace(lnum, newp, FALSE);
+ // replace the line
+ ml_replace(lnum, newp, false);
}
check_cursor_col();
@@ -1552,7 +1548,7 @@ int op_delete(oparg_T *oap)
curwin->w_cursor.coladd = 0;
}
- (void)del_bytes((long)n, !virtual_op,
+ (void)del_bytes((colnr_T)n, !virtual_op,
oap->op_type == OP_DELETE && !oap->is_VIsual);
} else {
// delete characters between lines
@@ -1572,7 +1568,7 @@ int op_delete(oparg_T *oap)
// delete from start of line until op_end
n = (oap->end.col + 1 - !oap->inclusive);
curwin->w_cursor.col = 0;
- (void)del_bytes((long)n, !virtual_op,
+ (void)del_bytes((colnr_T)n, !virtual_op,
oap->op_type == OP_DELETE && !oap->is_VIsual);
curwin->w_cursor = curpos; // restore curwin->w_cursor
(void)do_join(2, false, false, false, false);
@@ -1611,7 +1607,8 @@ static void mb_adjust_opend(oparg_T *oap)
*/
static inline void pchar(pos_T lp, int c)
{
- *(ml_get_buf(curbuf, lp.lnum, TRUE) + lp.col) = c;;
+ assert(c <= UCHAR_MAX);
+ *(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c;
}
/*
@@ -1622,7 +1619,7 @@ int op_replace(oparg_T *oap, int c)
int n, numc;
int num_chars;
char_u *newp, *oldp;
- size_t oldlen;
+ colnr_T oldlen;
struct block_def bd;
char_u *after_p = NULL;
int had_ctrl_v_cr = (c == -1 || c == -2);
@@ -1690,42 +1687,56 @@ int op_replace(oparg_T *oap, int c)
/* Compute bytes needed, move character count to num_chars. */
num_chars = numc;
numc *= (*mb_char2len)(c);
- /* oldlen includes textlen, so don't double count */
- n += numc - bd.textlen;
oldp = get_cursor_line_ptr();
- oldlen = STRLEN(oldp);
- newp = (char_u *) xmalloc((size_t)(oldlen + 1 + n));
- memset(newp, NUL, (size_t)(oldlen + 1 + n));
- /* copy up to deleted part */
+ oldlen = (int)STRLEN(oldp);
+
+ size_t newp_size = (size_t)(bd.textcol + bd.startspaces);
+ if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
+ newp_size += (size_t)numc;
+ if (!bd.is_short) {
+ newp_size += (size_t)(bd.endspaces + oldlen
+ - bd.textcol - bd.textlen);
+ }
+ }
+ newp = xmallocz(newp_size);
+ // copy up to deleted part
memmove(newp, oldp, (size_t)bd.textcol);
oldp += bd.textcol + bd.textlen;
- /* insert pre-spaces */
+ // insert pre-spaces
memset(newp + bd.textcol, ' ', (size_t)bd.startspaces);
- /* insert replacement chars CHECK FOR ALLOCATED SPACE */
- /* -1/-2 is used for entering CR literally. */
+ // insert replacement chars CHECK FOR ALLOCATED SPACE
+ // -1/-2 is used for entering CR literally.
+ size_t after_p_len = 0;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
- if (has_mbyte) {
- n = (int)STRLEN(newp);
- while (--num_chars >= 0)
- n += (*mb_char2bytes)(c, newp + n);
- } else
- memset(newp + STRLEN(newp), c, (size_t)numc);
- if (!bd.is_short) {
- /* insert post-spaces */
- memset(newp + STRLEN(newp), ' ', (size_t)bd.endspaces);
- /* copy the part after the changed part */
- STRMOVE(newp + STRLEN(newp), oldp);
+ // strlen(newp) at this point
+ int newp_len = bd.textcol + bd.startspaces;
+ if (has_mbyte) {
+ while (--num_chars >= 0) {
+ newp_len += (*mb_char2bytes)(c, newp + newp_len);
+ }
+ } else {
+ memset(newp + newp_len, c, (size_t)numc);
+ newp_len += numc;
+ }
+ if (!bd.is_short) {
+ // insert post-spaces
+ memset(newp + newp_len, ' ', (size_t)bd.endspaces);
+ newp_len += bd.endspaces;
+ // copy the part after the changed part
+ memmove(newp + newp_len, oldp,
+ (size_t)(oldlen - bd.textcol - bd.textlen + 1));
}
} else {
- /* Replacing with \r or \n means splitting the line. */
- after_p = (char_u *) xmalloc((size_t)(oldlen + 1 + n - STRLEN(newp)));
- STRMOVE(after_p, oldp);
+ // Replacing with \r or \n means splitting the line.
+ after_p_len = (size_t)(oldlen - bd.textcol - bd.textlen + 1);
+ after_p = (char_u *)xmalloc(after_p_len);
+ memmove(after_p, oldp, after_p_len);
}
/* replace the line */
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
if (after_p != NULL) {
- ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE);
+ ml_append(curwin->w_cursor.lnum++, after_p, (int)after_p_len, false);
appended_lines_mark(curwin->w_cursor.lnum, 1L);
oap->end.lnum++;
xfree(after_p);
@@ -1992,7 +2003,7 @@ void op_insert(oparg_T *oap, long count1)
// already disabled, but still need it when calling
// coladvance_force().
if (curwin->w_cursor.coladd > 0) {
- int old_ve_flags = ve_flags;
+ unsigned old_ve_flags = ve_flags;
ve_flags = VE_ALL;
if (u_save_cursor() == FAIL)
@@ -2066,8 +2077,8 @@ void op_insert(oparg_T *oap, long count1)
if (oap->op_type == OP_INSERT
&& oap->start.col + oap->start.coladd
!= curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) {
- size_t t = getviscol2(curbuf->b_op_start_orig.col,
- curbuf->b_op_start_orig.coladd);
+ int t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
pre_textlen -= t - oap->start_vcol;
oap->start_vcol = t;
@@ -2075,8 +2086,8 @@ void op_insert(oparg_T *oap, long count1)
&& oap->end.col + oap->end.coladd
>= curbuf->b_op_start_orig.col
+ curbuf->b_op_start_orig.coladd) {
- size_t t = getviscol2(curbuf->b_op_start_orig.col,
- curbuf->b_op_start_orig.coladd);
+ int t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
/* reset pre_textlen to the value of OP_INSERT */
pre_textlen += bd.textlen;
@@ -2109,14 +2120,13 @@ void op_insert(oparg_T *oap, long count1)
firstline = ml_get(oap->start.lnum) + bd.textcol;
if (oap->op_type == OP_APPEND)
firstline += bd.textlen;
- if (pre_textlen >= 0
- && (ins_len = (long)STRLEN(firstline) - pre_textlen) > 0) {
- ins_text = vim_strnsave(firstline, (int)ins_len);
- /* block handled here */
- if (u_save(oap->start.lnum,
- (linenr_T)(oap->end.lnum + 1)) == OK)
- block_insert(oap, ins_text, (oap->op_type == OP_INSERT),
- &bd);
+ ins_len = (long)STRLEN(firstline) - pre_textlen;
+ if (pre_textlen >= 0 && ins_len > 0) {
+ ins_text = vim_strnsave(firstline, (size_t)ins_len);
+ // block handled here
+ if (u_save(oap->start.lnum, (linenr_T)(oap->end.lnum + 1)) == OK) {
+ block_insert(oap, ins_text, (oap->op_type == OP_INSERT), &bd);
+ }
curwin->w_cursor.col = oap->start.col;
check_cursor();
@@ -2139,8 +2149,10 @@ int op_change(oparg_T *oap)
long ins_len;
long pre_textlen = 0;
long pre_indent = 0;
- char_u *firstline;
- char_u *ins_text, *newp, *oldp;
+ char_u *newp;
+ char_u *firstline;
+ char_u *ins_text;
+ char_u *oldp;
struct block_def bd;
l = oap->start.col;
@@ -2198,14 +2210,14 @@ int op_change(oparg_T *oap)
long new_indent = (long)(skipwhite(firstline) - firstline);
pre_textlen += new_indent - pre_indent;
- bd.textcol += new_indent - pre_indent;
+ bd.textcol += (colnr_T)(new_indent - pre_indent);
}
ins_len = (long)STRLEN(firstline) - pre_textlen;
if (ins_len > 0) {
/* Subsequent calls to ml_get() flush the firstline data - take a
* copy of the inserted text. */
- ins_text = (char_u *) xmalloc((size_t)(ins_len + 1));
+ ins_text = (char_u *)xmalloc((size_t)(ins_len + 1));
STRLCPY(ins_text, firstline + bd.textcol, ins_len + 1);
for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum;
linenr++) {
@@ -2218,11 +2230,13 @@ int op_change(oparg_T *oap)
if (bd.is_short) {
vpos.lnum = linenr;
(void)getvpos(&vpos, oap->start_vcol);
- } else
+ } else {
vpos.coladd = 0;
+ }
oldp = ml_get(linenr);
- newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + vpos.coladd + ins_len + 1));
- /* copy up to block start */
+ newp = xmalloc(STRLEN(oldp) + (size_t)vpos.coladd
+ + (size_t)ins_len + 1);
+ // copy up to block start
memmove(newp, oldp, (size_t)bd.textcol);
offset = bd.textcol;
memset(newp + offset, ' ', (size_t)vpos.coladd);
@@ -2272,9 +2286,7 @@ void free_register(yankreg_T *reg)
{
set_yreg_additional_data(reg, NULL);
if (reg->y_array != NULL) {
- long i;
-
- for (i = reg->y_size - 1; i >= 0; i--) {
+ for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included
xfree(reg->y_array[i]);
}
xfree(reg->y_array);
@@ -2311,30 +2323,27 @@ bool op_yank(oparg_T *oap, bool message)
static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
{
- long y_idx; /* index in y_array[] */
- yankreg_T *curr; /* copy of current register */
- yankreg_T newreg; /* new yank register when appending */
- char_u **new_ptr;
- linenr_T lnum; /* current line number */
- long j;
+ yankreg_T newreg; // new yank register when appending
+ char_u **new_ptr;
+ linenr_T lnum; // current line number
+ size_t j;
MotionType yank_type = oap->motion_type;
- long yanklines = oap->line_count;
+ size_t yanklines = (size_t)oap->line_count;
linenr_T yankendlnum = oap->end.lnum;
- char_u *p;
- char_u *pnew;
+ char_u *p;
+ char_u *pnew;
struct block_def bd;
- curr = reg;
- /* append to existing contents */
- if (append && reg->y_array != NULL)
+ yankreg_T *curr = reg; // copy of current register
+ // append to existing contents
+ if (append && reg->y_array != NULL) {
reg = &newreg;
- else
- free_register(reg); /* free previously yanked lines */
+ } else {
+ free_register(reg); // free previously yanked lines
+ }
- /*
- * If the cursor was in column 1 before and after the movement, and the
- * operator is not inclusive, the yank is always linewise.
- */
+ // If the cursor was in column 1 before and after the movement, and the
+ // operator is not inclusive, the yank is always linewise.
if (oap->motion_type == kMTCharWise
&& oap->start.col == 0
&& !oap->inclusive
@@ -2353,7 +2362,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
reg->additional_data = NULL;
reg->timestamp = os_time();
- y_idx = 0;
+ size_t y_idx = 0; // index in y_array[]
lnum = oap->start.lnum;
if (yank_type == kMTBlockWise) {
@@ -2481,7 +2490,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
yanklines = 0;
}
// Some versions of Vi use ">=" here, some don't...
- if (yanklines > p_report) {
+ if (yanklines > (size_t)p_report) {
// redisplay now, so message is not deleted
update_topline_redraw();
if (yanklines == 1) {
@@ -2512,10 +2521,10 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
return;
}
-static void yank_copy_line(yankreg_T *reg, struct block_def *bd, long y_idx)
+static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx)
{
- char_u *pnew = xmallocz(bd->startspaces + bd->endspaces + bd->textlen);
-
+ char_u *pnew = xmallocz((size_t)(bd->startspaces + bd->endspaces
+ + bd->textlen));
reg->y_array[y_idx] = pnew;
memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces;
@@ -2548,7 +2557,7 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
// the yanked text
list_T *list = list_alloc();
- for (linenr_T i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
list_append_string(list, reg->y_array[i], -1);
}
list->lv_lock = VAR_FIXED;
@@ -2565,7 +2574,7 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
dict_add_nr_str(dict, "regname", 0, (char_u *)buf);
// kind of operation (yank/delete/change)
- buf[0] = get_op_char(oap->op_type);
+ buf[0] = (char)get_op_char(oap->op_type);
buf[1] = NUL;
dict_add_nr_str(dict, "operator", 0, (char_u *)buf);
@@ -2582,23 +2591,24 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
/*
* Put contents of register "regname" into the text.
* Caller must check "regname" to be valid!
- * "flags": PUT_FIXINDENT make indent look nice
- * PUT_CURSEND leave cursor after end of new text
- * PUT_LINE force linewise put (":put")
+ * "flags": PUT_FIXINDENT make indent look nice
+ * PUT_CURSEND leave cursor after end of new text
+ * PUT_LINE force linewise put (":put")
dir: BACKWARD for 'P', FORWARD for 'p' */
void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
{
- char_u *ptr;
- char_u *newp, *oldp;
+ char_u *ptr;
+ char_u *newp;
+ char_u *oldp;
int yanklen;
- int totlen = 0; /* init for gcc */
+ size_t totlen = 0; // init for gcc
linenr_T lnum;
colnr_T col;
- long i; // index in y_array[]
+ size_t i; // index in y_array[]
MotionType y_type;
- long y_size;
- int oldlen;
- long y_width = 0;
+ size_t y_size;
+ size_t oldlen;
+ int y_width = 0;
colnr_T vcol;
int delcount;
int incr = 0;
@@ -2705,7 +2715,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (curbuf->terminal) {
for (int i = 0; i < count; i++) {
// feed the lines to the terminal
- for (int j = 0; j < y_size; j++) {
+ for (size_t j = 0; j < y_size; j++) {
if (j) {
// terminate the previous line
terminal_send(curbuf->terminal, "\n", 1);
@@ -2736,7 +2746,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (dir == FORWARD && *p != NUL) {
mb_ptr_adv(p);
}
- ptr = vim_strnsave(oldp, p - oldp);
+ ptr = vim_strnsave(oldp, (size_t)(p - oldp));
ml_replace(curwin->w_cursor.lnum, ptr, false);
nr_lines++;
dir = FORWARD;
@@ -2761,11 +2771,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
if (y_type == kMTBlockWise) {
- lnum = curwin->w_cursor.lnum + y_size + 1;
- if (lnum > curbuf->b_ml.ml_line_count)
+ lnum = curwin->w_cursor.lnum + (linenr_T)y_size + 1;
+ if (lnum > curbuf->b_ml.ml_line_count) {
lnum = curbuf->b_ml.ml_line_count + 1;
- if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
+ }
+ if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) {
goto end;
+ }
} else if (y_type == kMTLineWise) {
lnum = curwin->w_cursor.lnum;
/* Correct line number for closed fold. Don't move the cursor yet,
@@ -2811,7 +2823,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
* Block mode
*/
if (y_type == kMTBlockWise) {
- char c = gchar_cursor();
+ int c = gchar_cursor();
colnr_T endcol2 = 0;
if (dir == FORWARD && c != NUL) {
@@ -2864,7 +2876,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
/* get the old line and advance to the position to insert at */
oldp = get_cursor_line_ptr();
- oldlen = (int)STRLEN(oldp);
+ oldlen = STRLEN(oldp);
for (ptr = oldp; vcol < col && *ptr; ) {
/* Count a tab for what it's worth (if list mode not on) */
incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
@@ -2901,10 +2913,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (spaces < 0)
spaces = 0;
- /* insert the new text */
- totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
- newp = (char_u *) xmalloc((size_t)(totlen + oldlen + 1));
- /* copy part up to cursor to new line */
+ // insert the new text
+ totlen = (size_t)(count * (yanklen + spaces)
+ + bd.startspaces + bd.endspaces);
+ newp = (char_u *) xmalloc(totlen + oldlen + 1);
+ // copy part up to cursor to new line
ptr = newp;
memmove(ptr, oldp, (size_t)bd.textcol);
ptr += bd.textcol;
@@ -2925,10 +2938,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/* may insert some spaces after the new text */
memset(ptr, ' ', (size_t)bd.endspaces);
ptr += bd.endspaces;
- /* move the text after the cursor to the end of the line. */
+ // move the text after the cursor to the end of the line.
memmove(ptr, oldp + bd.textcol + delcount,
- (size_t)(oldlen - bd.textcol - delcount + 1));
- ml_replace(curwin->w_cursor.lnum, newp, FALSE);
+ (size_t)((int)oldlen - bd.textcol - delcount + 1));
+ ml_replace(curwin->w_cursor.lnum, newp, false);
++curwin->w_cursor.lnum;
if (i == 0)
@@ -2943,7 +2956,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/* adjust '] mark */
curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
- curbuf->b_op_end.col = bd.textcol + totlen - 1;
+ curbuf->b_op_end.col = bd.textcol + (colnr_T)totlen - 1;
curbuf->b_op_end.coladd = 0;
if (flags & PUT_CURSEND) {
colnr_T len;
@@ -2994,13 +3007,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
*/
if (y_type == kMTCharWise && y_size == 1) {
do {
- totlen = count * yanklen;
+ totlen = (size_t)(count * yanklen);
if (totlen > 0) {
oldp = ml_get(lnum);
newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + totlen + 1));
memmove(newp, oldp, (size_t)col);
ptr = newp + col;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < (size_t)count; i++) {
memmove(ptr, y_array[0], (size_t)yanklen);
ptr += yanklen;
}
@@ -3037,7 +3050,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// Then append y_array[0] to first line.
lnum = new_cursor.lnum;
ptr = ml_get(lnum) + col;
- totlen = (int)STRLEN(y_array[y_size - 1]);
+ totlen = STRLEN(y_array[y_size - 1]);
newp = (char_u *) xmalloc((size_t)(STRLEN(ptr) + totlen + 1));
STRCPY(newp, y_array[y_size - 1]);
STRCAT(newp, ptr);
@@ -3217,22 +3230,19 @@ int get_register_name(int num)
*/
void ex_display(exarg_T *eap)
{
- int i, n;
- long j;
- char_u *p;
- yankreg_T *yb;
+ char_u *p;
+ yankreg_T *yb;
int name;
- int attr;
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
int clen;
if (arg != NULL && *arg == NUL)
arg = NULL;
- attr = hl_attr(HLF_8);
+ int attr = hl_attr(HLF_8);
/* Highlight title */
MSG_PUTS_TITLE(_("\n--- Registers ---"));
- for (i = -1; i < NUM_REGISTERS && !got_int; i++) {
+ for (int i = -1; i < NUM_REGISTERS && !got_int; i++) {
name = get_register_name(i);
if (arg != NULL && vim_strchr(arg, name) == NULL) {
@@ -3261,8 +3271,8 @@ void ex_display(exarg_T *eap)
msg_putchar(name);
MSG_PUTS(" ");
- n = (int)Columns - 6;
- for (j = 0; j < yb->y_size && n > 1; ++j) {
+ int n = (int)Columns - 6;
+ for (size_t j = 0; j < yb->y_size && n > 1; j++) {
if (j) {
MSG_PUTS_ATTR("^J", attr);
n -= 2;
@@ -3438,7 +3448,7 @@ static char_u *skip_comment(char_u *line, int process, int include_space, int *i
// to set those marks.
//
// return FAIL for failure, OK otherwise
-int do_join(long count,
+int do_join(size_t count,
int insert_space,
int save_undo,
int use_formatoptions,
@@ -3461,24 +3471,21 @@ int do_join(long count,
&& has_format_option(FO_REMOVE_COMS);
int prev_was_comment;
- assert(count > 1);
- if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
- (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
+ if (save_undo && u_save(curwin->w_cursor.lnum - 1,
+ curwin->w_cursor.lnum + (linenr_T)count) == FAIL) {
return FAIL;
-
- /* Allocate an array to store the number of spaces inserted before each
- * line. We will use it to pre-compute the length of the new line and the
- * proper placement of each original line in the new one. */
+ }
+ // Allocate an array to store the number of spaces inserted before each
+ // line. We will use it to pre-compute the length of the new line and the
+ // proper placement of each original line in the new one.
spaces = xcalloc(count, 1);
if (remove_comments) {
comments = xcalloc(count, sizeof(*comments));
}
- /*
- * Don't move anything, just compute the final line length
- * and setup the array of space strings lengths
- */
- for (t = 0; t < count; ++t) {
+ // Don't move anything, just compute the final line length
+ // and setup the array of space strings lengths
+ for (t = 0; t < (linenr_T)count; t++) {
curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
if (t == 0 && setmark) {
// Set the '[ mark.
@@ -3558,7 +3565,7 @@ int do_join(long count,
* column. This is not Vi compatible, but Vi deletes the marks, thus that
* should not really be a problem.
*/
- for (t = count - 1;; --t) {
+ for (t = (linenr_T)count - 1;; t--) {
cend -= currsize;
memmove(cend, curr, (size_t)currsize);
if (spaces[t] > 0) {
@@ -3595,8 +3602,8 @@ int do_join(long count,
* have moved up (last line deleted), so the current lnum is kept in t.
*/
t = curwin->w_cursor.lnum;
- ++curwin->w_cursor.lnum;
- del_lines(count - 1, FALSE);
+ curwin->w_cursor.lnum++;
+ del_lines((long)count - 1, false);
curwin->w_cursor.lnum = t;
/*
@@ -3778,8 +3785,8 @@ fex_format (
* Set v:lnum to the first line number and v:count to the number of lines.
* Set v:char to the character to be inserted (can be NUL).
*/
- set_vim_var_nr(VV_LNUM, lnum);
- set_vim_var_nr(VV_COUNT, count);
+ set_vim_var_nr(VV_LNUM, (varnumber_T)lnum);
+ set_vim_var_nr(VV_COUNT, (varnumber_T)count);
set_vim_var_char(c);
/*
@@ -4473,7 +4480,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
firstdigit = 'a';
}
} else {
- firstdigit -= Prenum1;
+ firstdigit -= (int)Prenum1;
}
} else {
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
@@ -4483,7 +4490,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
firstdigit = 'z';
}
} else {
- firstdigit += Prenum1;
+ firstdigit += (int)Prenum1;
}
}
curwin->w_cursor.col = col;
@@ -4591,7 +4598,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// Prepare the leading characters in buf1[].
// When there are many leading zeros it could be very long.
// Allocate a bit too much.
- buf1 = xmalloc(length + NUMBUFLEN);
+ buf1 = xmalloc((size_t)length + NUMBUFLEN);
if (buf1 == NULL) {
goto theend;
}
@@ -4604,7 +4611,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
length--;
}
if (pre == 'b' || pre == 'B' || pre == 'x' || pre == 'X') {
- *ptr++ = pre;
+ *ptr++ = (char_u)pre;
length--;
}
@@ -4767,8 +4774,6 @@ static void *get_reg_wrap_one_line(char_u *s, int flags)
/// @returns NULL for error.
void *get_reg_contents(int regname, int flags)
{
- long i;
-
// Don't allow using an expression register inside an expression.
if (regname == '=') {
if (flags & kGRegNoExpr) {
@@ -4804,7 +4809,7 @@ void *get_reg_contents(int regname, int flags)
if (flags & kGRegList) {
list_T *list = list_alloc();
- for (int i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
list_append_string(list, reg->y_array[i], -1);
}
@@ -4815,7 +4820,7 @@ void *get_reg_contents(int regname, int flags)
* Compute length of resulting string.
*/
size_t len = 0;
- for (i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
len += STRLEN(reg->y_array[i]);
/*
* Insert a newline between lines and after last line if
@@ -4832,7 +4837,7 @@ void *get_reg_contents(int regname, int flags)
* Copy the lines of the yank register into the string.
*/
len = 0;
- for (i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
STRCPY(retval + len, reg->y_array[i]);
len += STRLEN(retval + len);
@@ -4888,7 +4893,7 @@ void write_reg_contents(int name, const char_u *str, ssize_t len,
void write_reg_contents_lst(int name, char_u **strings, int maxlen,
bool must_append, MotionType yank_type,
- long block_len)
+ colnr_T block_len)
{
if (name == '/' || name == '=') {
char_u *s = strings[0];
@@ -4913,7 +4918,8 @@ void write_reg_contents_lst(int name, char_u **strings, int maxlen,
return;
}
- str_to_reg(reg, yank_type, (char_u *) strings, -1, block_len, true);
+ str_to_reg(reg, yank_type, (char_u *)strings, STRLEN((char_u *)strings),
+ block_len, true);
finish_write_reg(name, reg, old_y_previous);
}
@@ -4941,7 +4947,7 @@ void write_reg_contents_ex(int name,
ssize_t len,
bool must_append,
MotionType yank_type,
- long block_len)
+ colnr_T block_len)
{
if (len < 0) {
len = (ssize_t) STRLEN(str);
@@ -4991,7 +4997,7 @@ void write_reg_contents_ex(int name,
// Copy the input string into the adjusted memory at the specified
// offset.
expr_line = xrealloc(expr_line, totlen + 1);
- memcpy(expr_line + offset, str, (size_t) len);
+ memcpy(expr_line + offset, str, (size_t)len);
expr_line[totlen] = NUL;
return;
@@ -5005,7 +5011,7 @@ void write_reg_contents_ex(int name,
if (!(reg = init_write_reg(name, &old_y_previous, must_append))) {
return;
}
- str_to_reg(reg, yank_type, str, len, block_len, false);
+ str_to_reg(reg, yank_type, str, (size_t)len, block_len, false);
finish_write_reg(name, reg, old_y_previous);
}
@@ -5061,7 +5067,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
(y_ptr->y_size + newlines) * sizeof(char_u *));
y_ptr->y_array = pp;
- linenr_T lnum = y_ptr->y_size; // The current line number.
+ size_t lnum = y_ptr->y_size; // The current line number.
// If called with `blocklen < 0`, we have to update the yank reg's width.
size_t maxlen = 0;
@@ -5080,7 +5086,9 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
for (const char_u *start = str, *end = str + len;
start < end + extraline;
start += line_len + 1, lnum++) {
- line_len = (const char_u *) xmemscan(start, '\n', end - start) - start;
+ assert(end - start >= 0);
+ line_len = (size_t)((char_u *)xmemscan(start, '\n',
+ (size_t)(end - start)) - start);
if (line_len > maxlen) {
maxlen = line_len;
}
@@ -5090,7 +5098,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
char_u *s = xmallocz(line_len + extra);
memcpy(s, pp[lnum], extra);
memcpy(s + extra, start, line_len);
- ssize_t s_len = extra + line_len;
+ size_t s_len = extra + line_len;
if (append) {
xfree(pp[lnum]);
@@ -5450,7 +5458,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
yankreg_T *target;
if (cb_flags & CB_UNNAMEDPLUS) {
- *name = cb_flags & CB_UNNAMED ? '"': '+';
+ *name = (cb_flags & CB_UNNAMED && writing) ? '"': '+';
target = &y_regs[PLUS_REGISTER];
} else {
*name = '*';
@@ -5474,7 +5482,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
free_register(reg);
list_T *args = list_alloc();
- char_u regname = name;
+ char_u regname = (char_u)name;
list_append_string(args, &regname, 1);
typval_T result = eval_call_provider("clipboard", "get", args);
@@ -5519,8 +5527,8 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
reg->y_type = kMTUnknown;
}
- reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *));
- reg->y_size = lines->lv_len;
+ reg->y_array = xcalloc((size_t)lines->lv_len, sizeof(uint8_t *));
+ reg->y_size = (size_t)lines->lv_len;
reg->additional_data = NULL;
reg->timestamp = 0;
// Timestamp is not saved for clipboard registers because clipboard registers
@@ -5551,14 +5559,15 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
}
if (reg->y_type == kMTBlockWise) {
- int maxlen = 0;
- for (int i = 0; i < reg->y_size; i++) {
- int rowlen = STRLEN(reg->y_array[i]);
+ size_t maxlen = 0;
+ for (size_t i = 0; i < reg->y_size; i++) {
+ size_t rowlen = STRLEN(reg->y_array[i]);
if (rowlen > maxlen) {
maxlen = rowlen;
}
}
- reg->y_width = maxlen-1;
+ assert(maxlen <= INT_MAX);
+ reg->y_width = (int)maxlen - 1;
}
*target = reg;
@@ -5566,7 +5575,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
err:
if (reg->y_array) {
- for (int i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
xfree(reg->y_array[i]);
}
xfree(reg->y_array);
@@ -5590,7 +5599,7 @@ static void set_clipboard(int name, yankreg_T *reg)
list_T *lines = list_alloc();
- for (int i = 0; i < reg->y_size; i++) {
+ for (size_t i = 0; i < reg->y_size; i++) {
list_append_string(lines, reg->y_array[i], -1);
}
@@ -5615,7 +5624,7 @@ static void set_clipboard(int name, yankreg_T *reg)
}
list_append_string(args, &regtype, 1);
- char_u regname = name;
+ char_u regname = (char_u)name;
list_append_string(args, &regname, 1);
(void)eval_call_provider("clipboard", "set", args);
@@ -5678,8 +5687,8 @@ const void *op_register_iter(const void *const iter, char *const name,
if (iter_reg - &(y_regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) {
return NULL;
}
- size_t iter_off = iter_reg - &(y_regs[0]);
- *name = (char) get_register_name(iter_off);
+ int iter_off = (int)(iter_reg - &(y_regs[0]));
+ *name = (char)get_register_name(iter_off);
*reg = *iter_reg;
while (++iter_reg - &(y_regs[0]) < NUM_SAVED_REGISTERS) {
if (!reg_empty(iter_reg)) {
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 8c8a586957..44df2e9e0c 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -79,7 +79,7 @@ enum GRegFlags {
/// Definition of one register
typedef struct yankreg {
char_u **y_array; ///< Pointer to an array of line pointers.
- linenr_T y_size; ///< Number of lines in y_array.
+ size_t y_size; ///< Number of lines in y_array.
MotionType y_type; ///< Register type
colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise).
Timestamp timestamp; ///< Time when register was last modified.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 45ebb4fa4c..de53b0b1f4 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2129,6 +2129,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_nf);
check_string_option(&buf->b_p_qe);
check_string_option(&buf->b_p_syn);
+ check_string_option(&buf->b_s.b_syn_isk);
check_string_option(&buf->b_s.b_p_spc);
check_string_option(&buf->b_s.b_p_spf);
check_string_option(&buf->b_s.b_p_spl);
@@ -2313,50 +2314,46 @@ set_string_option_global (
}
}
-/*
- * Set a string option to a new value, and handle the effects.
- *
- * Returns NULL on success or error message on error.
- */
-static char_u *
-set_string_option (
- int opt_idx,
- char_u *value,
- int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */
-)
+/// Set a string option to a new value, handling the effects
+///
+/// @param[in] opt_idx Option to set.
+/// @param[in] value New value.
+/// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or
+/// #OPT_GLOBAL.
+///
+/// @return NULL on success, error message on error.
+static char *set_string_option(const int opt_idx, const char *const value,
+ const int opt_flags)
+ FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
{
- char_u *s;
- char_u **varp;
- char_u *oldval;
- char *saved_oldval = NULL;
- char_u *r = NULL;
-
- if (options[opt_idx].var == NULL) /* don't set hidden option */
+ if (options[opt_idx].var == NULL) { // don't set hidden option
return NULL;
+ }
- s = vim_strsave(value);
- varp = (char_u **)get_varp_scope(&(options[opt_idx]),
- (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
- ? (((int)options[opt_idx].indir & PV_BOTH)
- ? OPT_GLOBAL : OPT_LOCAL)
- : opt_flags);
- oldval = *varp;
+ char *const s = xstrdup(value);
+ char **const varp = (char **)get_varp_scope(
+ &(options[opt_idx]),
+ ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ ? (((int)options[opt_idx].indir & PV_BOTH)
+ ? OPT_GLOBAL : OPT_LOCAL)
+ : opt_flags));
+ char *const oldval = *varp;
*varp = s;
- if (!starting) {
- saved_oldval = xstrdup((char *) oldval);
- }
+ char *const saved_oldval = (starting ? NULL : xstrdup(oldval));
- if ((r = did_set_string_option(opt_idx, varp, (int)true, oldval, NULL,
- opt_flags)) == NULL)
- did_set_option(opt_idx, opt_flags, TRUE);
+ char *const r = (char *)did_set_string_option(
+ opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags);
+ if (r == NULL) {
+ did_set_option(opt_idx, opt_flags, true);
+ }
// call autocommand after handling side effects
if (saved_oldval != NULL) {
char buf_type[7];
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_NEW, (char *) (*varp), -1);
+ set_vim_var_string(VV_OPTION_NEW, (char *)(*varp), -1);
set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET,
@@ -2442,16 +2439,13 @@ did_set_string_option (
else if (varp == &curwin->w_p_briopt) {
if (briopt_check(curwin) == FAIL)
errmsg = e_invarg;
- }
- /*
- * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[]
- * If the new option is invalid, use old value. 'lisp' option: refill
- * chartab[] for '-' char
- */
- else if ( varp == &p_isi
+ } else if (varp == &p_isi
|| varp == &(curbuf->b_p_isk)
|| varp == &p_isp
|| varp == &p_isf) {
+ // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
+ // If the new option is invalid, use old value. 'lisp' option: refill
+ // g_chartab[] for '-' char
if (init_chartab() == FAIL) {
did_chartab = TRUE; /* need to restore it below */
errmsg = e_invarg; /* error in value */
@@ -3190,8 +3184,9 @@ did_set_string_option (
for (p = q; *p != NUL; ++p)
if (vim_strchr((char_u *)"_.,", *p) != NULL)
break;
- vim_snprintf((char *)fname, 200, "spell/%.*s.vim", (int)(p - q), q);
- source_runtime(fname, TRUE);
+ vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim",
+ (int)(p - q), q);
+ source_runtime(fname, DIP_ALL);
}
}
@@ -3402,9 +3397,10 @@ char_u *check_stl_option(char_u *s)
if (!*s)
break;
s++;
- if (*s != '%' && *s != ')')
- ++itemcnt;
- if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_MIDDLEMARK) {
+ if (*s != '%' && *s != ')') {
+ itemcnt++;
+ }
+ if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) {
s++;
continue;
}
@@ -4029,15 +4025,16 @@ set_num_option (
errmsg = e_invarg;
curwin->w_p_fdc = 12;
}
- }
- /* 'shiftwidth' or 'tabstop' */
- else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) {
- if (foldmethodIsIndent(curwin))
+ // 'shiftwidth' or 'tabstop'
+ } else if (pp == &curbuf->b_p_sw || pp == (long *)&curbuf->b_p_ts) {
+ if (foldmethodIsIndent(curwin)) {
foldUpdateAll(curwin);
- /* When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
- * parse 'cinoptions'. */
- if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
+ }
+ // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
+ // parse 'cinoptions'.
+ if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
parse_cino(curbuf);
+ }
}
/* 'maxcombine' */
else if (pp == &p_mco) {
@@ -4405,6 +4402,7 @@ bool get_tty_option(char *name, char **value)
if (is_tty_option(name)) {
if (value) {
+ // XXX: All other t_* options were removed in 3baba1e7.
*value = xstrdup("");
}
return true;
@@ -4652,26 +4650,28 @@ set_option_value (
EMSG(_(e_sandbox));
return NULL;
}
- if (flags & P_STRING)
- return set_string_option(opt_idx, string, opt_flags);
- else {
+ if (flags & P_STRING) {
+ const char *s = (const char *)string;
+ if (s == NULL) {
+ s = "";
+ }
+ return (char_u *)set_string_option(opt_idx, s, opt_flags);
+ } else {
varp = get_varp_scope(&(options[opt_idx]), opt_flags);
if (varp != NULL) { /* hidden option is not changed */
if (number == 0 && string != NULL) {
int idx;
- /* Either we are given a string or we are setting option
- * to zero. */
- for (idx = 0; string[idx] == '0'; ++idx)
- ;
+ // Either we are given a string or we are setting option
+ // to zero.
+ for (idx = 0; string[idx] == '0'; idx++) {}
if (string[idx] != NUL || idx == 0) {
- /* There's another character after zeros or the string
- * is empty. In both cases, we are trying to set a
- * num option using a string. */
+ // There's another character after zeros or the string
+ // is empty. In both cases, we are trying to set a
+ // num option using a string.
EMSG3(_("E521: Number required: &%s = '%s'"),
- name, string);
- return NULL; /* do nothing as we hit an error */
-
+ name, string);
+ return NULL; // do nothing as we hit an error
}
}
if (flags & P_NUM)
@@ -5606,6 +5606,7 @@ void buf_copy_options(buf_T *buf, int flags)
/* Don't copy 'syntax', it must be set */
buf->b_p_syn = empty_option;
buf->b_p_smc = p_smc;
+ buf->b_s.b_syn_isk = empty_option;
buf->b_s.b_p_spc = vim_strsave(p_spc);
(void)compile_cap_prog(&buf->b_s);
buf->b_s.b_p_spf = vim_strsave(p_spf);
@@ -5655,7 +5656,7 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_isk = save_p_isk;
else {
buf->b_p_isk = vim_strsave(p_isk);
- did_isk = TRUE;
+ did_isk = true;
buf->b_p_ts = p_ts;
buf->b_help = false;
if (buf->b_p_bt[0] == 'h')
@@ -5836,6 +5837,7 @@ set_context_in_set_cmd (
if (p == (char_u *)&p_bdir
|| p == (char_u *)&p_dir
|| p == (char_u *)&p_path
+ || p == (char_u *)&p_pp
|| p == (char_u *)&p_rtp
|| p == (char_u *)&p_cdpath
|| p == (char_u *)&p_vdir
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 904e97f8ca..8d6f42e088 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -258,7 +258,7 @@ enum {
STL_ARGLISTSTAT = 'a', ///< Argument list status as (x of y).
STL_PAGENUM = 'N', ///< Page number (when printing).
STL_VIM_EXPR = '{', ///< Start of expression to substitute.
- STL_MIDDLEMARK = '=', ///< Separation between left and right.
+ STL_SEPARATE = '=', ///< Separation between alignment sections.
STL_TRUNCMARK = '<', ///< Truncation mark if line is too long.
STL_USER_HL = '*', ///< Highlight from (User)1..9 or 0.
STL_HIGHLIGHT = '#', ///< Highlight name.
@@ -274,7 +274,7 @@ enum {
STL_HELPFLAG, STL_HELPFLAG_ALT, STL_FILETYPE, STL_FILETYPE_ALT, \
STL_PREVIEWFLAG, STL_PREVIEWFLAG_ALT, STL_MODIFIED, STL_MODIFIED_ALT, \
STL_QUICKFIX, STL_PERCENTAGE, STL_ALTPERCENT, STL_ARGLISTSTAT, STL_PAGENUM, \
- STL_VIM_EXPR, STL_MIDDLEMARK, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \
+ STL_VIM_EXPR, STL_SEPARATE, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \
STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \
0, \
})
@@ -456,80 +456,81 @@ EXTERN int p_hid; // 'hidden'
// Use P_HID to check if a buffer is to be hidden when it is no longer
// visible in a window.
# define P_HID(buf) (buf_hide(buf))
-EXTERN char_u *p_hl; /* 'highlight' */
-EXTERN int p_hls; /* 'hlsearch' */
-EXTERN long p_hi; /* 'history' */
-EXTERN int p_hkmap; /* 'hkmap' */
-EXTERN int p_hkmapp; /* 'hkmapp' */
-EXTERN int p_fkmap; /* 'fkmap' */
-EXTERN int p_altkeymap; /* 'altkeymap' */
-EXTERN int p_arshape; /* 'arabicshape' */
-EXTERN int p_icon; /* 'icon' */
-EXTERN char_u *p_iconstring; /* 'iconstring' */
-EXTERN int p_ic; /* 'ignorecase' */
-EXTERN int p_is; /* 'incsearch' */
-EXTERN int p_im; /* 'insertmode' */
-EXTERN char_u *p_isf; /* 'isfname' */
-EXTERN char_u *p_isi; /* 'isident' */
-EXTERN char_u *p_isp; /* 'isprint' */
-EXTERN int p_js; /* 'joinspaces' */
-EXTERN char_u *p_kp; /* 'keywordprg' */
-EXTERN char_u *p_km; /* 'keymodel' */
-EXTERN char_u *p_langmap; /* 'langmap'*/
-EXTERN int p_lnr; /* 'langnoremap'*/
-EXTERN char_u *p_lm; /* 'langmenu' */
-EXTERN char_u *p_lispwords; /* 'lispwords' */
-EXTERN long p_ls; /* 'laststatus' */
-EXTERN long p_stal; /* 'showtabline' */
-EXTERN char_u *p_lcs; /* 'listchars' */
-
-EXTERN int p_lz; /* 'lazyredraw' */
-EXTERN int p_lpl; /* 'loadplugins' */
-EXTERN int p_magic; /* 'magic' */
-EXTERN char_u *p_mef; /* 'makeef' */
-EXTERN char_u *p_mp; /* 'makeprg' */
-EXTERN char_u *p_cc; /* 'colorcolumn' */
-EXTERN int p_cc_cols[256]; /* array for 'colorcolumn' columns */
-EXTERN long p_mat; /* 'matchtime' */
-EXTERN long p_mco; /* 'maxcombine' */
-EXTERN long p_mfd; /* 'maxfuncdepth' */
-EXTERN long p_mmd; /* 'maxmapdepth' */
-EXTERN long p_mm; /* 'maxmem' */
-EXTERN long p_mmp; /* 'maxmempattern' */
-EXTERN long p_mmt; /* 'maxmemtot' */
-EXTERN long p_mis; /* 'menuitems' */
-EXTERN char_u *p_msm; /* 'mkspellmem' */
-EXTERN long p_mls; /* 'modelines' */
-EXTERN char_u *p_mouse; /* 'mouse' */
-EXTERN char_u *p_mousem; /* 'mousemodel' */
-EXTERN long p_mouset; /* 'mousetime' */
-EXTERN int p_more; /* 'more' */
-EXTERN char_u *p_opfunc; /* 'operatorfunc' */
-EXTERN char_u *p_para; /* 'paragraphs' */
-EXTERN int p_paste; /* 'paste' */
-EXTERN char_u *p_pt; /* 'pastetoggle' */
-EXTERN char_u *p_pex; /* 'patchexpr' */
-EXTERN char_u *p_pm; /* 'patchmode' */
-EXTERN char_u *p_path; /* 'path' */
-EXTERN char_u *p_cdpath; /* 'cdpath' */
-EXTERN long p_rdt; /* 'redrawtime' */
-EXTERN int p_remap; /* 'remap' */
-EXTERN long p_re; /* 'regexpengine' */
-EXTERN long p_report; /* 'report' */
-EXTERN long p_pvh; /* 'previewheight' */
-EXTERN int p_ari; /* 'allowrevins' */
-EXTERN int p_ri; /* 'revins' */
-EXTERN int p_ru; /* 'ruler' */
-EXTERN char_u *p_ruf; /* 'rulerformat' */
-EXTERN char_u *p_rtp; /* 'runtimepath' */
-EXTERN long p_sj; /* 'scrolljump' */
-EXTERN long p_so; /* 'scrolloff' */
-EXTERN char_u *p_sbo; /* 'scrollopt' */
-EXTERN char_u *p_sections; /* 'sections' */
-EXTERN int p_secure; /* 'secure' */
-EXTERN char_u *p_sel; /* 'selection' */
-EXTERN char_u *p_slm; /* 'selectmode' */
-EXTERN char_u *p_ssop; /* 'sessionoptions' */
+EXTERN char_u *p_hl; // 'highlight'
+EXTERN int p_hls; // 'hlsearch'
+EXTERN long p_hi; // 'history'
+EXTERN int p_hkmap; // 'hkmap'
+EXTERN int p_hkmapp; // 'hkmapp'
+EXTERN int p_fkmap; // 'fkmap'
+EXTERN int p_altkeymap; // 'altkeymap'
+EXTERN int p_arshape; // 'arabicshape'
+EXTERN int p_icon; // 'icon'
+EXTERN char_u *p_iconstring; // 'iconstring'
+EXTERN int p_ic; // 'ignorecase'
+EXTERN int p_is; // 'incsearch'
+EXTERN int p_im; // 'insertmode'
+EXTERN char_u *p_isf; // 'isfname'
+EXTERN char_u *p_isi; // 'isident'
+EXTERN char_u *p_isp; // 'isprint'
+EXTERN int p_js; // 'joinspaces'
+EXTERN char_u *p_kp; // 'keywordprg'
+EXTERN char_u *p_km; // 'keymodel'
+EXTERN char_u *p_langmap; // 'langmap'*/
+EXTERN int p_lnr; // 'langnoremap'*/
+EXTERN char_u *p_lm; // 'langmenu'
+EXTERN char_u *p_lispwords; // 'lispwords'
+EXTERN long p_ls; // 'laststatus'
+EXTERN long p_stal; // 'showtabline'
+EXTERN char_u *p_lcs; // 'listchars'
+
+EXTERN int p_lz; // 'lazyredraw'
+EXTERN int p_lpl; // 'loadplugins'
+EXTERN int p_magic; // 'magic'
+EXTERN char_u *p_mef; // 'makeef'
+EXTERN char_u *p_mp; // 'makeprg'
+EXTERN char_u *p_cc; // 'colorcolumn'
+EXTERN int p_cc_cols[256]; // array for 'colorcolumn' columns
+EXTERN long p_mat; // 'matchtime'
+EXTERN long p_mco; // 'maxcombine'
+EXTERN long p_mfd; // 'maxfuncdepth'
+EXTERN long p_mmd; // 'maxmapdepth'
+EXTERN long p_mm; // 'maxmem'
+EXTERN long p_mmp; // 'maxmempattern'
+EXTERN long p_mmt; // 'maxmemtot'
+EXTERN long p_mis; // 'menuitems'
+EXTERN char_u *p_msm; // 'mkspellmem'
+EXTERN long p_mls; // 'modelines'
+EXTERN char_u *p_mouse; // 'mouse'
+EXTERN char_u *p_mousem; // 'mousemodel'
+EXTERN long p_mouset; // 'mousetime'
+EXTERN int p_more; // 'more'
+EXTERN char_u *p_opfunc; // 'operatorfunc'
+EXTERN char_u *p_para; // 'paragraphs'
+EXTERN int p_paste; // 'paste'
+EXTERN char_u *p_pt; // 'pastetoggle'
+EXTERN char_u *p_pex; // 'patchexpr'
+EXTERN char_u *p_pm; // 'patchmode'
+EXTERN char_u *p_path; // 'path'
+EXTERN char_u *p_cdpath; // 'cdpath'
+EXTERN long p_rdt; // 'redrawtime'
+EXTERN int p_remap; // 'remap'
+EXTERN long p_re; // 'regexpengine'
+EXTERN long p_report; // 'report'
+EXTERN long p_pvh; // 'previewheight'
+EXTERN int p_ari; // 'allowrevins'
+EXTERN int p_ri; // 'revins'
+EXTERN int p_ru; // 'ruler'
+EXTERN char_u *p_ruf; // 'rulerformat'
+EXTERN char_u *p_pp; // 'packpath'
+EXTERN char_u *p_rtp; // 'runtimepath'
+EXTERN long p_sj; // 'scrolljump'
+EXTERN long p_so; // 'scrolloff'
+EXTERN char_u *p_sbo; // 'scrollopt'
+EXTERN char_u *p_sections; // 'sections'
+EXTERN int p_secure; // 'secure'
+EXTERN char_u *p_sel; // 'selection'
+EXTERN char_u *p_slm; // 'selectmode'
+EXTERN char_u *p_ssop; // 'sessionoptions'
EXTERN unsigned ssop_flags;
# ifdef IN_OPTION_C
/* Also used for 'viewoptions'! */
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 218e34f595..d19af4f73f 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1640,6 +1640,16 @@ return {
defaults={if_true={vi=""}}
},
{
+ full_name='packpath', abbreviation='pp',
+ type='string', list='onecomma', scope={'global'},
+ deny_duplicates=true,
+ secure=true,
+ vi_def=true,
+ expand=true,
+ varname='p_pp',
+ defaults={if_true={vi=''}}
+ },
+ {
full_name='paragraphs', abbreviation='para',
type='string', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
new file mode 100644
index 0000000000..6cee102305
--- /dev/null
+++ b/src/nvim/os/fileio.c
@@ -0,0 +1,319 @@
+/// @file fileio.c
+///
+/// Buffered reading/writing to a file. Unlike fileio.c this is not dealing with
+/// Neovim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite
+/// replacement.
+
+#include <unistd.h>
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <fcntl.h>
+
+#include "auto/config.h"
+
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+
+#include <uv.h>
+
+#include "nvim/os/fileio.h"
+#include "nvim/memory.h"
+#include "nvim/os/os.h"
+#include "nvim/globals.h"
+#include "nvim/rbuffer.h"
+#include "nvim/macros.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fileio.c.generated.h"
+#endif
+
+/// Open file
+///
+/// @param[out] ret_fp Address where information needed for reading from or
+/// writing to a file is saved
+/// @param[in] fname File name to open.
+/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and
+/// writing to the file at once is not supported, so either
+/// FILE_WRITE_ONLY or FILE_READ_ONLY is required.
+/// @param[in] mode Permissions for the newly created file (ignored if flags
+/// does not have FILE_CREATE\*).
+///
+/// @return Error code (@see os_strerror()) or 0.
+int file_open(FileDescriptor *const ret_fp, const char *const fname,
+ const int flags, const int mode)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ int os_open_flags = 0;
+ int fd;
+ TriState wr = kNone;
+#define FLAG(flags, flag, fcntl_flags, wrval, cond) \
+ do { \
+ if (flags & flag) { \
+ os_open_flags |= fcntl_flags; \
+ assert(cond); \
+ if (wrval != kNone) { \
+ wr = wrval; \
+ } \
+ } \
+ } while (0)
+ FLAG(flags, kFileWriteOnly, O_WRONLY, kTrue, true);
+ FLAG(flags, kFileCreateOnly, O_CREAT|O_EXCL|O_WRONLY, kTrue, true);
+ FLAG(flags, kFileCreate, O_CREAT|O_WRONLY, kTrue, !(flags & kFileCreateOnly));
+ FLAG(flags, kFileTruncate, O_TRUNC|O_WRONLY, kTrue,
+ !(flags & kFileCreateOnly));
+ FLAG(flags, kFileReadOnly, O_RDONLY, kFalse, wr != kTrue);
+#ifdef O_NOFOLLOW
+ FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true);
+#endif
+#undef FLAG
+
+ fd = os_open(fname, os_open_flags, mode);
+
+ if (fd < 0) {
+ return fd;
+ }
+
+ ret_fp->wr = (wr == kTrue);
+ ret_fp->fd = fd;
+ ret_fp->eof = false;
+ ret_fp->rv = rbuffer_new(kRWBufferSize);
+ ret_fp->_error = 0;
+ if (ret_fp->wr) {
+ ret_fp->rv->data = ret_fp;
+ ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
+ }
+ return 0;
+}
+
+/// Like file_open(), but allocate and return ret_fp
+///
+/// @param[out] error Error code, @see os_strerror(). Is set to zero on
+/// success.
+/// @param[in] fname File name to open.
+/// @param[in] flags Flags, @see FileOpenFlags.
+/// @param[in] mode Permissions for the newly created file (ignored if flags
+/// does not have FILE_CREATE\*).
+///
+/// @return [allocated] Opened file or NULL in case of error.
+FileDescriptor *file_open_new(int *const error, const char *const fname,
+ const int flags, const int mode)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ FileDescriptor *const fp = xmalloc(sizeof(*fp));
+ if ((*error = file_open(fp, fname, flags, mode)) != 0) {
+ xfree(fp);
+ return NULL;
+ }
+ return fp;
+}
+
+/// Close file and free its buffer
+///
+/// @param[in,out] fp File to close.
+///
+/// @return 0 or error code.
+int file_close(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL
+{
+ const int error = file_fsync(fp);
+ const int error2 = os_close(fp->fd);
+ rbuffer_free(fp->rv);
+ if (error2 != 0) {
+ return error2;
+ }
+ return error;
+}
+
+/// Close and free file obtained using file_open_new()
+///
+/// @param[in,out] fp File to close.
+///
+/// @return 0 or error code.
+int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL
+{
+ const int ret = file_close(fp);
+ xfree(fp);
+ return ret;
+}
+
+/// Flush file modifications to disk
+///
+/// @param[in,out] fp File to work with.
+///
+/// @return 0 or error code.
+int file_fsync(FileDescriptor *const fp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (!fp->wr) {
+ return 0;
+ }
+ file_rb_write_full_cb(fp->rv, fp);
+ if (fp->_error != 0) {
+ const int error = fp->_error;
+ fp->_error = 0;
+ return error;
+ }
+ return os_fsync(fp->fd);
+}
+
+/// Buffer used for writing
+///
+/// Like IObuff, but allows file_\* callers not to care about spoiling it.
+static char writebuf[kRWBufferSize];
+
+/// Function run when RBuffer is full when writing to a file
+///
+/// Actually does writing to the file, may also be invoked directly.
+///
+/// @param[in,out] rv RBuffer instance used.
+/// @param[in,out] fp File to work with.
+static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(fp->wr);
+ assert(rv->data == (void *)fp);
+ if (rbuffer_size(rv) == 0) {
+ return;
+ }
+ const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
+ const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes);
+ if (wres != (ptrdiff_t)read_bytes) {
+ if (wres >= 0) {
+ fp->_error = UV_EIO;
+ } else {
+ fp->_error = (int)wres;
+ }
+ }
+}
+
+/// Read from file
+///
+/// @param[in,out] fp File to work with.
+/// @param[out] ret_buf Buffer to read to. Must not be NULL.
+/// @param[in] size Number of bytes to read. Buffer must have at least ret_buf
+/// bytes.
+///
+/// @return error_code (< 0) or number of bytes read.
+ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
+ const size_t size)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ assert(!fp->wr);
+ char *buf = ret_buf;
+ size_t read_remaining = size;
+ RBuffer *const rv = fp->rv;
+ while (read_remaining) {
+ const size_t rv_size = rbuffer_size(rv);
+ if (rv_size > 0) {
+ const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining));
+ buf += rsize;
+ read_remaining -= rsize;
+ }
+ if (fp->eof) {
+ break;
+ }
+ if (read_remaining) {
+ assert(rbuffer_size(rv) == 0);
+ rbuffer_reset(rv);
+#ifdef HAVE_READV
+ // If there is readv() syscall, then take an opportunity to populate
+ // both target buffer and RBuffer at once, …
+ size_t write_count;
+ struct iovec iov[] = {
+ { .iov_base = buf, .iov_len = read_remaining },
+ { .iov_base = rbuffer_write_ptr(rv, &write_count),
+ .iov_len = kRWBufferSize },
+ };
+ assert(write_count == kRWBufferSize);
+ const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
+ ARRAY_SIZE(iov));
+ if (r_ret > 0) {
+ if (r_ret > (ptrdiff_t)read_remaining) {
+ rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining));
+ read_remaining = 0;
+ } else {
+ buf += (size_t)r_ret;
+ read_remaining -= (size_t)r_ret;
+ }
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+#else
+ if (read_remaining >= kRWBufferSize) {
+ // …otherwise leave RBuffer empty and populate only target buffer,
+ // because filtering information through rbuffer will be more syscalls.
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining);
+ if (r_ret >= 0) {
+ read_remaining -= (size_t)r_ret;
+ return (ptrdiff_t)(size - read_remaining);
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ } else {
+ size_t write_count;
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
+ rbuffer_write_ptr(rv, &write_count),
+ kRWBufferSize);
+ assert(write_count == kRWBufferSize);
+ if (r_ret > 0) {
+ rbuffer_produced(rv, (size_t)r_ret);
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ }
+#endif
+ }
+ }
+ return (ptrdiff_t)(size - read_remaining);
+}
+
+/// Write to a file
+///
+/// @param[in] fd File descriptor to write to.
+/// @param[in] buf Data to write. May be NULL if size is zero.
+/// @param[in] size Amount of bytes to write.
+///
+/// @return Number of bytes written or libuv error code (< 0).
+ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf,
+ const size_t size)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
+{
+ assert(fp->wr);
+ const size_t written = rbuffer_write(fp->rv, buf, size);
+ if (fp->_error != 0) {
+ const int error = fp->_error;
+ fp->_error = 0;
+ return error;
+ } else if (written != size) {
+ return UV_EIO;
+ }
+ return (ptrdiff_t)written;
+}
+
+/// Buffer used for skipping. Its contents is undefined and should never be
+/// used.
+static char skipbuf[kRWBufferSize];
+
+/// Skip some bytes
+///
+/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply
+/// reads to a buffer and discards the result.
+ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(!fp->wr);
+ size_t read_bytes = 0;
+ do {
+ const ptrdiff_t new_read_bytes = file_read(
+ fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
+ if (new_read_bytes < 0) {
+ return new_read_bytes;
+ } else if (new_read_bytes == 0) {
+ break;
+ }
+ read_bytes += (size_t)new_read_bytes;
+ } while (read_bytes < size && !file_eof(fp));
+
+ return (ptrdiff_t)read_bytes;
+}
diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h
new file mode 100644
index 0000000000..2cffd5c851
--- /dev/null
+++ b/src/nvim/os/fileio.h
@@ -0,0 +1,72 @@
+#ifndef NVIM_OS_FILEIO_H
+#define NVIM_OS_FILEIO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "nvim/func_attr.h"
+#include "nvim/rbuffer.h"
+
+/// Structure used to read from/write to file
+typedef struct {
+ int fd; ///< File descriptor.
+ int _error; ///< Error code for use with RBuffer callbacks or zero.
+ RBuffer *rv; ///< Read or write buffer.
+ bool wr; ///< True if file is in write mode.
+ bool eof; ///< True if end of file was encountered.
+} FileDescriptor;
+
+/// file_open() flags
+typedef enum {
+ kFileReadOnly = 1, ///< Open file read-only. Default.
+ kFileCreate = 2, ///< Create file if it does not exist yet.
+ ///< Implies kFileWriteOnly.
+ kFileWriteOnly = 4, ///< Open file for writing only.
+ ///< Cannot be used with kFileReadOnly.
+ kFileNoSymlink = 8, ///< Do not allow symbolic links.
+ kFileCreateOnly = 16, ///< Only create the file, failing if it already
+ ///< exists. Implies kFileWriteOnly. Cannot be used
+ ///< with kFileCreate.
+ kFileTruncate = 32, ///< Truncate the file if it exists.
+ ///< Implies kFileWriteOnly. Cannot be used with
+ ///< kFileCreateOnly.
+} FileOpenFlags;
+
+static inline bool file_eof(const FileDescriptor *const fp)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
+
+/// Check whether end of file was encountered
+///
+/// @param[in] fp File to check.
+///
+/// @return true if it was, false if it was not or read operation was never
+/// performed.
+static inline bool file_eof(const FileDescriptor *const fp)
+{
+ return fp->eof && rbuffer_size(fp->rv) == 0;
+}
+
+static inline int file_fd(const FileDescriptor *const fp)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
+
+/// Return the file descriptor associated with the FileDescriptor structure
+///
+/// @param[in] fp File to check.
+///
+/// @return File descriptor.
+static inline int file_fd(const FileDescriptor *const fp)
+{
+ return fp->fd;
+}
+
+enum {
+ /// Read or write buffer size
+ ///
+ /// Currently equal to (IOSIZE - 1), but they do not need to be connected.
+ kRWBufferSize = 1024
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/fileio.h.generated.h"
+#endif
+#endif // NVIM_OS_FILEIO_H
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 143a7160b0..d12d34d595 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -1,14 +1,26 @@
// fs.c -- filesystem access
#include <stdbool.h>
-
+#include <stddef.h>
#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
+
+#include "auto/config.h"
+
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+
+#include <uv.h>
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/ascii.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/assert.h"
#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/path.h"
@@ -18,6 +30,20 @@
# include "os/fs.c.generated.h"
#endif
+#define RUN_UV_FS_FUNC(ret, func, ...) \
+ do { \
+ bool did_try_to_free = false; \
+uv_call_start: {} \
+ uv_fs_t req; \
+ ret = func(&fs_loop, &req, __VA_ARGS__); \
+ uv_fs_req_cleanup(&req); \
+ if (ret == UV_ENOMEM && !did_try_to_free) { \
+ try_to_free_memory(); \
+ did_try_to_free = true; \
+ goto uv_call_start; \
+ } \
+ } while (0)
+
// Many fs functions from libuv return that value on success.
static const int kLibuvSuccess = 0;
static uv_loop_t fs_loop;
@@ -325,13 +351,190 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
int os_open(const char* path, int flags, int mode)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t open_req;
- int r = uv_fs_open(&fs_loop, &open_req, path, flags, mode, NULL);
- uv_fs_req_cleanup(&open_req);
- // r is the same as open_req.result (except for OOM: then only r is set).
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_open, path, flags, mode, NULL);
+ return r;
+}
+
+/// Close a file
+///
+/// @return 0 or libuv error code on failure.
+int os_close(const int fd)
+{
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_close, fd, NULL);
return r;
}
+/// Read from a file
+///
+/// Handles EINTR and ENOMEM, but not other errors.
+///
+/// @param[in] fd File descriptor to read from.
+/// @param[out] ret_eof Is set to true if EOF was encountered, otherwise set
+/// to false. Initial value is ignored.
+/// @param[out] ret_buf Buffer to write to. May be NULL if size is zero.
+/// @param[in] size Amount of bytes to read.
+///
+/// @return Number of bytes read or libuv error code (< 0).
+ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
+ const size_t size)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ *ret_eof = false;
+ if (ret_buf == NULL) {
+ assert(size == 0);
+ return 0;
+ }
+ size_t read_bytes = 0;
+ bool did_try_to_free = false;
+ while (read_bytes != size) {
+ const ptrdiff_t cur_read_bytes = read(fd, ret_buf + read_bytes,
+ size - read_bytes);
+ if (cur_read_bytes > 0) {
+ read_bytes += (size_t)cur_read_bytes;
+ assert(read_bytes <= size);
+ }
+ if (cur_read_bytes < 0) {
+#ifdef HAVE_UV_TRANSLATE_SYS_ERROR
+ const int error = uv_translate_sys_error(errno);
+#else
+ const int error = -errno;
+ STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes");
+ STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes");
+ STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes");
+#endif
+ errno = 0;
+ if (error == UV_EINTR || error == UV_EAGAIN) {
+ continue;
+ } else if (error == UV_ENOMEM && !did_try_to_free) {
+ try_to_free_memory();
+ did_try_to_free = true;
+ continue;
+ } else {
+ return (ptrdiff_t)error;
+ }
+ }
+ if (cur_read_bytes == 0) {
+ *ret_eof = true;
+ break;
+ }
+ }
+ return (ptrdiff_t)read_bytes;
+}
+
+#ifdef HAVE_READV
+/// Read from a file to multiple buffers at once
+///
+/// Wrapper for readv().
+///
+/// @param[in] fd File descriptor to read from.
+/// @param[out] ret_eof Is set to true if EOF was encountered, otherwise set
+/// to false. Initial value is ignored.
+/// @param[out] iov Description of buffers to write to. Note: this description
+/// may change, it is incorrect to use data it points to after
+/// os_readv().
+/// @param[in] iov_size Number of buffers in iov.
+ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
+ FUNC_ATTR_NONNULL_ALL
+{
+ *ret_eof = false;
+ size_t read_bytes = 0;
+ bool did_try_to_free = false;
+ size_t toread = 0;
+ for (size_t i = 0; i < iov_size; i++) {
+ // Overflow, trying to read too much data
+ assert(toread <= SIZE_MAX - iov[i].iov_len);
+ toread += iov[i].iov_len;
+ }
+ while (read_bytes < toread && iov_size && !*ret_eof) {
+ ptrdiff_t cur_read_bytes = readv(fd, iov, (int)iov_size);
+ if (toread && cur_read_bytes == 0) {
+ *ret_eof = true;
+ }
+ if (cur_read_bytes > 0) {
+ read_bytes += (size_t)cur_read_bytes;
+ while (iov_size && cur_read_bytes) {
+ if (cur_read_bytes < (ptrdiff_t)iov->iov_len) {
+ iov->iov_len -= (size_t)cur_read_bytes;
+ iov->iov_base = (char *)iov->iov_base + cur_read_bytes;
+ cur_read_bytes = 0;
+ } else {
+ cur_read_bytes -= (ptrdiff_t)iov->iov_len;
+ iov_size--;
+ iov++;
+ }
+ }
+ } else if (cur_read_bytes < 0) {
+#ifdef HAVE_UV_TRANSLATE_SYS_ERROR
+ const int error = uv_translate_sys_error(errno);
+#else
+ const int error = -errno;
+ STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes");
+ STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes");
+ STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes");
+#endif
+ errno = 0;
+ if (error == UV_EINTR || error == UV_EAGAIN) {
+ continue;
+ } else if (error == UV_ENOMEM && !did_try_to_free) {
+ try_to_free_memory();
+ did_try_to_free = true;
+ continue;
+ } else {
+ return (ptrdiff_t)error;
+ }
+ }
+ }
+ return (ptrdiff_t)read_bytes;
+}
+#endif // HAVE_READV
+
+/// Write to a file
+///
+/// @param[in] fd File descriptor to write to.
+/// @param[in] buf Data to write. May be NULL if size is zero.
+/// @param[in] size Amount of bytes to write.
+///
+/// @return Number of bytes written or libuv error code (< 0).
+ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (buf == NULL) {
+ assert(size == 0);
+ return 0;
+ }
+ size_t written_bytes = 0;
+ while (written_bytes != size) {
+ const ptrdiff_t cur_written_bytes = write(fd, buf + written_bytes,
+ size - written_bytes);
+ if (cur_written_bytes > 0) {
+ written_bytes += (size_t)cur_written_bytes;
+ }
+ if (cur_written_bytes < 0) {
+#ifdef HAVE_UV_TRANSLATE_SYS_ERROR
+ const int error = uv_translate_sys_error(errno);
+#else
+ const int error = -errno;
+ STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes");
+ STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes");
+ // According to the man page open() may fail with ENOMEM, but write()
+ // can’t.
+#endif
+ errno = 0;
+ if (error == UV_EINTR || error == UV_EAGAIN) {
+ continue;
+ } else {
+ return error;
+ }
+ }
+ if (cur_written_bytes == 0) {
+ return UV_UNKNOWN;
+ }
+ }
+ return (ptrdiff_t)written_bytes;
+}
+
/// Flushes file modifications to disk.
///
/// @param fd the file descriptor of the file to flush to disk.
@@ -339,9 +542,8 @@ int os_open(const char* path, int flags, int mode)
/// @return `0` on success, a libuv error code on failure.
int os_fsync(int fd)
{
- uv_fs_t fsync_req;
- int r = uv_fs_fsync(&fs_loop, &fsync_req, fd, NULL);
- uv_fs_req_cleanup(&fsync_req);
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_fsync, fd, NULL);
return r;
}
@@ -379,16 +581,9 @@ int32_t os_getperm(const char_u *name)
int os_setperm(const char_u *name, int perm)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t request;
- int result = uv_fs_chmod(&fs_loop, &request,
- (const char*)name, perm, NULL);
- uv_fs_req_cleanup(&request);
-
- if (result == kLibuvSuccess) {
- return OK;
- }
-
- return FAIL;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_chmod, (const char *)name, perm, NULL);
+ return (r == kLibuvSuccess ? OK : FAIL);
}
/// Changes the ownership of the file referred to by the open file descriptor.
@@ -397,24 +592,21 @@ int os_setperm(const char_u *name, int perm)
///
/// @note If the `owner` or `group` is specified as `-1`, then that ID is not
/// changed.
-int os_fchown(int file_descriptor, uv_uid_t owner, uv_gid_t group)
- FUNC_ATTR_NONNULL_ALL
+int os_fchown(int fd, uv_uid_t owner, uv_gid_t group)
{
- uv_fs_t request;
- int result = uv_fs_fchown(&fs_loop, &request, file_descriptor,
- owner, group, NULL);
- uv_fs_req_cleanup(&request);
- return result;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_fchown, fd, owner, group, NULL);
+ return r;
}
-/// Check if a file exists.
+/// Check if a path exists.
///
-/// @return `true` if `name` exists.
-bool os_file_exists(const char_u *name)
+/// @return `true` if `path` exists
+bool os_path_exists(const char_u *path)
FUNC_ATTR_NONNULL_ALL
{
uv_stat_t statbuf;
- return os_stat((char *)name, &statbuf) == kLibuvSuccess;
+ return os_stat((char *)path, &statbuf) == kLibuvSuccess;
}
/// Check if a file is readable.
@@ -423,9 +615,8 @@ bool os_file_exists(const char_u *name)
bool os_file_is_readable(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- uv_fs_t req;
- int r = uv_fs_access(&fs_loop, &req, name, R_OK, NULL);
- uv_fs_req_cleanup(&req);
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_access, name, R_OK, NULL);
return (r == 0);
}
@@ -437,9 +628,8 @@ bool os_file_is_readable(const char *name)
int os_file_is_writable(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- uv_fs_t req;
- int r = uv_fs_access(&fs_loop, &req, name, W_OK, NULL);
- uv_fs_req_cleanup(&req);
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_access, name, W_OK, NULL);
if (r == 0) {
return os_isdir((char_u *)name) ? 2 : 1;
}
@@ -452,16 +642,10 @@ int os_file_is_writable(const char *name)
int os_rename(const char_u *path, const char_u *new_path)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t request;
- int result = uv_fs_rename(&fs_loop, &request,
- (const char *)path, (const char *)new_path, NULL);
- uv_fs_req_cleanup(&request);
-
- if (result == kLibuvSuccess) {
- return OK;
- }
-
- return FAIL;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_rename, (const char *)path, (const char *)new_path,
+ NULL);
+ return (r == kLibuvSuccess ? OK : FAIL);
}
/// Make a directory.
@@ -470,10 +654,9 @@ int os_rename(const char_u *path, const char_u *new_path)
int os_mkdir(const char *path, int32_t mode)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t request;
- int result = uv_fs_mkdir(&fs_loop, &request, path, mode, NULL);
- uv_fs_req_cleanup(&request);
- return result;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_mkdir, path, mode, NULL);
+ return r;
}
/// Make a directory, with higher levels when needed
@@ -555,10 +738,9 @@ int os_mkdtemp(const char *template, char *path)
int os_rmdir(const char *path)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t request;
- int result = uv_fs_rmdir(&fs_loop, &request, path, NULL);
- uv_fs_req_cleanup(&request);
- return result;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_rmdir, path, NULL);
+ return r;
}
/// Opens a directory.
@@ -600,10 +782,9 @@ void os_closedir(Directory *dir)
int os_remove(const char *path)
FUNC_ATTR_NONNULL_ALL
{
- uv_fs_t request;
- int result = uv_fs_unlink(&fs_loop, &request, path, NULL);
- uv_fs_req_cleanup(&request);
- return result;
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_unlink, path, NULL);
+ return r;
}
/// Get the file information for a given path
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 7687b14f02..0c46dc96ee 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -60,7 +60,7 @@ void input_start(int fd)
}
global_fd = fd;
- rstream_init_fd(&loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
+ rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE, NULL);
rstream_start(&read_stream, read_cb);
}
@@ -87,8 +87,8 @@ static void create_cursorhold_event(void)
// have been called(inbuf_poll would return kInputAvail)
// TODO(tarruda): Cursorhold should be implemented as a timer set during the
// `state_check` callback for the states where it can be triggered.
- assert(!events_enabled || queue_empty(loop.events));
- queue_put(loop.events, cursorhold_event, 0);
+ assert(!events_enabled || queue_empty(main_loop.events));
+ queue_put(main_loop.events, cursorhold_event, 0);
}
// Low level input function
@@ -147,7 +147,7 @@ bool os_char_avail(void)
void os_breakcheck(void)
{
if (!got_int) {
- loop_poll_events(&loop, 0);
+ loop_poll_events(&main_loop, 0);
}
}
@@ -322,7 +322,7 @@ static bool input_poll(int ms)
prof_inchar_enter();
}
- LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, ms, input_ready() || input_eof);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof);
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
@@ -419,5 +419,5 @@ static void read_error_exit(void)
static bool pending_events(void)
{
- return events_enabled && !queue_empty(loop.events);
+ return events_enabled && !queue_empty(main_loop.events);
}
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index eee0cdd10b..5e164b54a5 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -46,4 +46,10 @@
/// negative libuv error codes are returned by a number of os functions.
#define os_strerror uv_strerror
+#ifdef WIN32
+# define os_strtok strtok_s
+#else
+# define os_strtok strtok_r
+#endif
+
#endif // NVIM_OS_OS_DEFS_H
diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h
new file mode 100644
index 0000000000..94923499ca
--- /dev/null
+++ b/src/nvim/os/pty_process.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_OS_PTY_PROCESS_H
+#define NVIM_OS_PTY_PROCESS_H
+
+#ifdef WIN32
+# include "nvim/os/pty_process_win.h"
+#else
+# include "nvim/os/pty_process_unix.h"
+#endif
+#endif // NVIM_OS_PTY_PROCESS_H
diff --git a/src/nvim/event/pty_process.c b/src/nvim/os/pty_process_unix.c
index 8eef72f12f..436de030ba 100644
--- a/src/nvim/event/pty_process.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -26,11 +26,12 @@
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/event/process.h"
-#include "nvim/event/pty_process.h"
+#include "nvim/os/pty_process_unix.h"
#include "nvim/log.h"
+#include "nvim/os/os.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "event/pty_process.c.generated.h"
+# include "os/pty_process_unix.c.generated.h"
#endif
bool pty_process_spawn(PtyProcess *ptyproc)
@@ -44,7 +45,7 @@ bool pty_process_spawn(PtyProcess *ptyproc)
Process *proc = (Process *)ptyproc;
assert(!proc->err);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
- ptyproc->winsize = (struct winsize){ptyproc->height, ptyproc->width, 0, 0};
+ ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
uv_disable_stdio_inheritance();
int master;
int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize);
@@ -86,11 +87,10 @@ error:
return false;
}
-void pty_process_resize(PtyProcess *ptyproc, uint16_t width,
- uint16_t height)
+void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
- ptyproc->winsize = (struct winsize){height, width, 0, 0};
+ ptyproc->winsize = (struct winsize){ height, width, 0, 0 };
ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize);
}
@@ -132,6 +132,12 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
signal(SIGTERM, SIG_DFL);
signal(SIGALRM, SIG_DFL);
+ Process *proc = (Process *)ptyproc;
+ if (proc->cwd && os_chdir(proc->cwd) != 0) {
+ fprintf(stderr, "chdir failed: %s\n", strerror(errno));
+ return;
+ }
+
setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
execvp(ptyproc->process.argv[0], ptyproc->process.argv);
fprintf(stderr, "execvp failed: %s\n", strerror(errno));
diff --git a/src/nvim/event/pty_process.h b/src/nvim/os/pty_process_unix.h
index 446d7fd3c8..f7c57b3839 100644
--- a/src/nvim/event/pty_process.h
+++ b/src/nvim/os/pty_process_unix.h
@@ -1,5 +1,5 @@
-#ifndef NVIM_EVENT_PTY_PROCESS_H
-#define NVIM_EVENT_PTY_PROCESS_H
+#ifndef NVIM_OS_PTY_PROCESS_UNIX_H
+#define NVIM_OS_PTY_PROCESS_UNIX_H
#include <sys/ioctl.h>
@@ -25,6 +25,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data)
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "event/pty_process.h.generated.h"
+# include "os/pty_process_unix.h.generated.h"
#endif
-#endif // NVIM_EVENT_PTY_PROCESS_H
+
+#endif // NVIM_OS_PTY_PROCESS_UNIX_H
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h
new file mode 100644
index 0000000000..20cc589925
--- /dev/null
+++ b/src/nvim/os/pty_process_win.h
@@ -0,0 +1,28 @@
+#ifndef NVIM_OS_PTY_PROCESS_WIN_H
+#define NVIM_OS_PTY_PROCESS_WIN_H
+
+#include "nvim/event/libuv_process.h"
+
+typedef struct pty_process {
+ Process process;
+ char *term_name;
+ uint16_t width, height;
+} PtyProcess;
+
+#define pty_process_spawn(job) libuv_process_spawn((LibuvProcess *)job)
+#define pty_process_close(job) libuv_process_close((LibuvProcess *)job)
+#define pty_process_close_master(job) libuv_process_close((LibuvProcess *)job)
+#define pty_process_resize(job, width, height)
+#define pty_process_teardown(loop)
+
+static inline PtyProcess pty_process_init(Loop *loop, void *data)
+{
+ PtyProcess rv;
+ rv.process = process_init(loop, kProcessTypePty, data);
+ rv.term_name = NULL;
+ rv.width = 80;
+ rv.height = 24;
+ return rv;
+}
+
+#endif // NVIM_OS_PTY_PROCESS_WIN_H
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index f5a1637c94..64c673930a 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -14,6 +14,7 @@
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
#include "nvim/types.h"
+#include "nvim/main.h"
#include "nvim/vim.h"
#include "nvim/message.h"
#include "nvim/memory.h"
@@ -205,16 +206,16 @@ static int do_os_system(char **argv,
xstrlcpy(prog, argv[0], MAXPATHL);
Stream in, out, err;
- LibuvProcess uvproc = libuv_process_init(&loop, &buf);
+ LibuvProcess uvproc = libuv_process_init(&main_loop, &buf);
Process *proc = &uvproc.process;
- Queue *events = queue_new_child(loop.events);
+ Queue *events = queue_new_child(main_loop.events);
proc->events = events;
proc->argv = argv;
proc->in = input != NULL ? &in : NULL;
proc->out = &out;
proc->err = &err;
if (!process_spawn(proc)) {
- loop_poll_events(&loop, 0);
+ loop_poll_events(&main_loop, 0);
// Failed, probably due to `sh` not being executable
if (!silent) {
MSG_PUTS(_("\nCannot execute "));
@@ -309,25 +310,70 @@ static void system_data_cb(Stream *stream, RBuffer *buf, size_t count,
dbuf->len += nread;
}
+/// Continue to append data to last screen line.
+///
+/// @param output Data to append to screen lines.
+/// @param remaining Size of data.
+/// @param new_line If true, next data output will be on a new line.
+static void append_to_screen_end(char *output, size_t remaining, bool new_line)
+{
+ // Column of last row to start appending data to.
+ static colnr_T last_col = 0;
+
+ size_t off = 0;
+ int last_row = (int)Rows - 1;
+
+ while (off < remaining) {
+ // Found end of line?
+ if (output[off] == NL) {
+ // Can we start a new line or do we need to continue the last one?
+ if (last_col == 0) {
+ screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ }
+ screen_puts_len((char_u *)output, (int)off, last_row, last_col, 0);
+ last_col = 0;
+
+ size_t skip = off + 1;
+ output += skip;
+ remaining -= skip;
+ off = 0;
+ continue;
+ }
+
+ // Translate NUL to SOH
+ if (output[off] == NUL) {
+ output[off] = 1;
+ }
+
+ off++;
+ }
+
+ if (remaining) {
+ if (last_col == 0) {
+ screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ }
+ screen_puts_len((char_u *)output, (int)remaining, last_row, last_col, 0);
+ last_col += (colnr_T)remaining;
+ }
+
+ if (new_line) {
+ last_col = 0;
+ }
+
+ ui_flush();
+}
+
static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
bool eof)
{
+ // We always output the whole buffer, so the buffer can never
+ // wrap around.
size_t cnt;
char *ptr = rbuffer_read_ptr(buf, &cnt);
- if (!cnt) {
- return;
- }
-
- size_t written = write_output(ptr, cnt, false, eof);
- // No output written, force emptying the Rbuffer if it is full.
- if (!written && rbuffer_size(buf) == rbuffer_capacity(buf)) {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- screen_puts_len((char_u *)ptr, (int)cnt, (int)Rows - 1, 0, 0);
- written = cnt;
- }
- if (written) {
- rbuffer_consumed(buf, written);
+ append_to_screen_end(ptr, cnt, eof);
+ if (cnt) {
+ rbuffer_consumed(buf, cnt);
}
}
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 0ff6016e32..4abc9cfc36 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -8,6 +8,7 @@
#include "nvim/globals.h"
#include "nvim/memline.h"
#include "nvim/eval.h"
+#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/misc2.h"
@@ -28,10 +29,10 @@ static bool rejecting_deadly;
void signal_init(void)
{
- signal_watcher_init(&loop, &spipe, NULL);
- signal_watcher_init(&loop, &shup, NULL);
- signal_watcher_init(&loop, &squit, NULL);
- signal_watcher_init(&loop, &sterm, NULL);
+ signal_watcher_init(&main_loop, &spipe, NULL);
+ signal_watcher_init(&main_loop, &shup, NULL);
+ signal_watcher_init(&main_loop, &squit, NULL);
+ signal_watcher_init(&main_loop, &sterm, NULL);
#ifdef SIGPIPE
signal_watcher_start(&spipe, on_signal, SIGPIPE);
#endif
@@ -41,7 +42,7 @@ void signal_init(void)
#endif
signal_watcher_start(&sterm, on_signal, SIGTERM);
#ifdef SIGPWR
- signal_watcher_init(&loop, &spwr, NULL);
+ signal_watcher_init(&main_loop, &spwr, NULL);
signal_watcher_start(&spwr, on_signal, SIGPWR);
#endif
}
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 188f0802c9..2205ad0958 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -9,6 +9,7 @@
#include "nvim/os/time.h"
#include "nvim/event/loop.h"
#include "nvim/vim.h"
+#include "nvim/main.h"
static uv_mutex_t delay_mutex;
static uv_cond_t delay_cond;
@@ -43,7 +44,7 @@ void os_delay(uint64_t milliseconds, bool ignoreinput)
if (milliseconds > INT_MAX) {
milliseconds = INT_MAX;
}
- LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, (int)milliseconds, got_int);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)milliseconds, got_int);
} else {
os_microdelay(milliseconds * 1000);
}
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 2ed0c2c856..def7e3b0e5 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -566,10 +566,11 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
/*
* Move the file names to allocated memory.
*/
- for (j = 0, i = 0; i < *num_file; ++i) {
- /* Require the files to exist. Helps when using /bin/sh */
- if (!(flags & EW_NOTFOUND) && !os_file_exists((*file)[i]))
+ for (j = 0, i = 0; i < *num_file; i++) {
+ // Require the files to exist. Helps when using /bin/sh
+ if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) {
continue;
+ }
/* check if this entry should be included */
dir = (os_isdir((*file)[i]));
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 41fd69f238..57499429ec 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -684,7 +684,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
}
// add existing file or symbolic link
if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info)
- : os_file_exists(buf)) {
+ : os_path_exists(buf)) {
addfile(gap, buf, flags);
}
}
@@ -1205,10 +1205,11 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
/* When EW_NOTFOUND is used, always add files and dirs. Makes
* "vim c:/" work. */
- if (flags & EW_NOTFOUND)
+ if (flags & EW_NOTFOUND) {
addfile(&ga, t, flags | EW_DIR | EW_FILE);
- else if (os_file_exists(t))
+ } else if (os_path_exists(t)) {
addfile(&ga, t, flags);
+ }
xfree(t);
}
@@ -1327,7 +1328,7 @@ void addfile(
if (!(flags & EW_NOTFOUND)
&& ((flags & EW_ALLLINKS)
? !os_fileinfo_link((char *)f, &file_info)
- : !os_file_exists(f))) {
+ : !os_path_exists(f))) {
return;
}
diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po
index 5b0cb2260b..6bc76506ae 100644
--- a/src/nvim/po/eo.po
+++ b/src/nvim/po/eo.po
@@ -23,8 +23,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim(Esperanto)\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-07-30 17:54+0200\n"
-"PO-Revision-Date: 2015-07-30 18:00+0200\n"
+"POT-Creation-Date: 2016-02-13 23:42+0100\n"
+"PO-Revision-Date: 2016-02-13 23:45+0100\n"
"Last-Translator: Dominique PELLÉ <dominique.pelle@gmail.com>\n"
"Language-Team: \n"
"Language: eo\n"
@@ -504,10 +504,6 @@ msgstr "E686: Argumento de %s devas esti Listo"
msgid "E712: Argument of %s must be a List or Dictionary"
msgstr "E712: Argumento de %s devas esti Listo aŭ Vortaro"
-#: ../eval.c:144
-msgid "E713: Cannot use empty key for Dictionary"
-msgstr "E713: Ne eblas uzi malplenan ŝlosilon de Vortaro"
-
#: ../eval.c:145
msgid "E714: List required"
msgstr "E714: Listo bezonata"
@@ -657,6 +653,9 @@ msgstr "E110: Mankas ')'"
msgid "E695: Cannot index a Funcref"
msgstr "E695: Ne eblas indeksi Funcref"
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ne eblas indeksi specialan variablon"
+
#: ../eval.c:4839
#, c-format
msgid "E112: Option name missing: %s"
@@ -689,7 +688,7 @@ msgstr "E697: Mankas fino de Listo ']': %s"
#: ../eval.c:5750
msgid "Not enough memory to set references, garbage collection aborted!"
-msgstr "Ne sufiĉa memory por valorigi referencojn, senrubigado ĉesigita!"
+msgstr "Ne sufiĉa memoro por valorigi referencojn, senrubigado ĉesigita!"
#: ../eval.c:6475
#, c-format
@@ -874,6 +873,18 @@ msgstr "E745: Uzo de Listo kiel Nombro"
msgid "E728: Using a Dictionary as a Number"
msgstr "E728: Uzo de Vortaro kiel Nombro"
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Uzo de Funcref kiel Glitpunktnombro"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Uzo de Ĉeno kiel Glitpunktnombro"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Uzo de Listo kiel Glitpunktnombro"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Uzo de Vortaro kiel Glitpunktnombro"
+
#: ../eval.c:16259
msgid "E729: using Funcref as a String"
msgstr "E729: uzo de Funcref kiel Ĉeno"
@@ -886,6 +897,9 @@ msgstr "E730: uzo de Listo kiel Ĉeno"
msgid "E731: using Dictionary as a String"
msgstr "E731: uzo de Vortaro kiel Ĉeno"
+msgid "E908: using an invalid value as a String"
+msgstr "E908: uzo de nevalida valoro kiel Ĉeno"
+
#: ../eval.c:16619
#, c-format
msgid "E706: Variable type mismatch for: %s"
@@ -1391,6 +1405,13 @@ msgstr "linio %<PRId64>: %s"
msgid "cmd: %s"
msgstr "kmd: %s"
+msgid "frame is zero"
+msgstr "kadro estas nul"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "kadro je la plej alta nivelo: %d"
+
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
@@ -2861,6 +2882,9 @@ msgstr "E46: Ne eblas ŝanĝi nurlegeblan variablon \"%s\""
msgid "E794: Cannot set variable in the sandbox: \"%s\""
msgstr "E794: Ne eblas agordi variablon en la sabloludejo: \"%s\""
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ne eblas uzi malplenan ŝlosilon de Vortaro"
+
#: ../globals.h:1076
msgid "E47: Error while reading errorfile"
msgstr "E47: Eraro dum legado de erardosiero"
@@ -4090,12 +4114,12 @@ msgid ""
"\n"
"(1) Another program may be editing the same file. If this is the case,\n"
" be careful not to end up with two different instances of the same\n"
-" file when making changes."
+" file when making changes. Quit, or continue with caution.\n"
msgstr ""
"\n"
-"(1) Alia programo eble redaktas la saman dosieron.\n"
-" Se jes, estu singarda por ne havi du malsamajn\n"
-" aperojn de la sama dosiero, kiam vi faros ŝanĝojn."
+"(1) Alia programo eble redaktas la saman dosieron. Se jes, estu singarda\n"
+" por ne havi du malsamajn aperojn de la sama dosiero, kiam vi faros\n"
+" ŝanĝojn. Eliru aŭ daŭrigu singarde.\n"
#: ../memline.c:3245
msgid " Quit, or continue with caution.\n"
@@ -4792,6 +4816,15 @@ msgstr ""
"\n"
"Ne povis ŝalti kuntekston de sekureco por "
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Ne povis ŝalti kuntekston de sekureco %s por %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr ""
+"Ne povis akiri kuntekston de sekureco %s por %s. Gi nun estas forigata!"
+
#: ../os_unix.c:1558 ../os_unix.c:1647
#, c-format
msgid "dlerror = \"%s\""
@@ -5717,6 +5750,9 @@ msgstr "Neniu sintaksa elemento difinita por tiu bufro"
msgid "E390: Illegal argument: %s"
msgstr "E390: Nevalida argumento: %s"
+msgid "syntax iskeyword "
+msgstr "sintakso iskeyword "
+
#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
@@ -5813,6 +5849,10 @@ msgstr "E847: Tro da sintaksaj inkluzivoj"
msgid "E789: Missing ']': %s"
msgstr "E789: Mankas ']': %s"
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: vosta signo post ']': %s]%s"
+
#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po
index 171e155689..084102da60 100644
--- a/src/nvim/po/it.po
+++ b/src/nvim/po/it.po
@@ -13,13 +13,13 @@ msgid ""
msgstr ""
"Project-Id-Version: vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-08-11 20:58+0200\n"
-"PO-Revision-Date: 2015-08-11 22:02+0200\n"
-"Last-Translator: Vlad Sandrini <vlad.gently@gmail.com>\n"
-"Language-Team: Italian Antonio Colombo <azc100@gmail."
-"com> Vlad Sandrini <vlad.gently@gmail."
-"com> Luciano Montanaro <mikelima@cirulla.net>\n"
-"Language: \n"
+"POT-Creation-Date: 2016-02-11 12:10+0100\n"
+"PO-Revision-Date: 2016-02-11 14:42+0200\n"
+"Last-Translator: Antonio Colombo <azc100@gmail.com>\n"
+"Language-Team: Antonio Colombo <azc100@gmail.com>"
+" Vlad Sandrini <vlad.gently@gmail.com"
+" Luciano Montanaro <mikelima@cirulla.net>\n"
+"Language: Italian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO_8859-1\n"
"Content-Transfer-Encoding: 8-bit\n"
@@ -491,10 +491,6 @@ msgstr "E686: L'argomento di %s deve essere una Lista"
msgid "E712: Argument of %s must be a List or Dictionary"
msgstr "E712: L'argomento di %s deve essere una Lista o un Dizionario"
-#: ../eval.c:144
-msgid "E713: Cannot use empty key for Dictionary"
-msgstr "E713: Non posso usare una chiave nulla per il Dizionario"
-
#: ../eval.c:145
msgid "E714: List required"
msgstr "E714: necessaria una Lista"
@@ -548,7 +544,7 @@ msgstr "E461: Nome di variabile non ammesso: %s"
# nuovo
#: ../eval.c:157
msgid "E806: using Float as a String"
-msgstr "E806: uso di un numero con virgola come stringa"
+msgstr "E806: uso di un Numero-a-virgola-mobile come Stringa"
#: ../eval.c:1830
msgid "E687: Less targets than List items"
@@ -635,7 +631,7 @@ msgstr "E694: Operazione non valida per Funcref"
#: ../eval.c:4277
msgid "E804: Cannot use '%' with Float"
-msgstr "E804: Non si pu usare '%' con un numero con virgola"
+msgstr "E804: Non si pu usare '%' con un Numero-a-virgola-mobile"
#: ../eval.c:4478
msgid "E110: Missing ')'"
@@ -645,6 +641,9 @@ msgstr "E110: Manca ')'"
msgid "E695: Cannot index a Funcref"
msgstr "E695: Non posso indicizzare un Funcref"
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Non posso indicizzare una variabile speciale"
+
#: ../eval.c:4839
#, c-format
msgid "E112: Option name missing: %s"
@@ -736,7 +735,7 @@ msgstr "E725: Chiamata di funzione dict in assenza di Dizionario: %s"
#: ../eval.c:7453
msgid "E808: Number or Float required"
-msgstr "E808: Ci vuole un numero intero o con virgola"
+msgstr "E808: Ci vuole un Numero o un Numero-a-virgola-mobile"
#: ../eval.c:7503
msgid "add() argument"
@@ -847,7 +846,7 @@ msgstr "E677: Errore in scrittura su file temporaneo"
#: ../eval.c:16159
msgid "E805: Using a Float as a Number"
-msgstr "E805: Uso di un numero con virgola come intero"
+msgstr "E805: Uso di un Numero-a-virgola-mobile come Numero"
#: ../eval.c:16162
msgid "E703: Using a Funcref as a Number"
@@ -861,6 +860,18 @@ msgstr "E745: Uso di Lista come Numero"
msgid "E728: Using a Dictionary as a Number"
msgstr "E728: Uso di Dizionario come Numero"
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Uso di Funcref come Numero-a-virgola-mobile"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Uso di Stringa come Numero-a-virgola-mobile"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Uso di Lista come Numero-a-virgola-mobile"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Uso di Dizionario come Numero-a-virgola-mobile"
+
#: ../eval.c:16259
msgid "E729: using Funcref as a String"
msgstr "E729: uso di Funcref come Stringa"
@@ -873,6 +884,10 @@ msgstr "E730: uso di Lista come Stringa"
msgid "E731: using Dictionary as a String"
msgstr "E731: uso di Dizionario come Stringa"
+# nuovo
+msgid "E908: using an invalid value as a String"
+msgstr "E908: uso di un valore non valido come Stringa"
+
#: ../eval.c:16619
#, c-format
msgid "E706: Variable type mismatch for: %s"
@@ -960,12 +975,14 @@ msgid "E129: Function name required"
msgstr "E129: Nome funzione necessario"
#: ../eval.c:17824
+#, c-format
msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: Il nome funzione deve iniziare con una maiuscola o \"s:\": %s"
+msgstr "E128: Il nome funzione deve iniziare con maiuscola o \"s:\": %s"
#: ../eval.c:17833
+#, c-format
msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E884: Il nome funzione non pu contenere una virgola: %s"
+msgstr "E884: Il nome della funzione non pu contenere un due punti: %s"
#: ../eval.c:18336
#, c-format
@@ -1382,6 +1399,13 @@ msgstr "riga %<PRId64>: %s"
msgid "cmd: %s"
msgstr "com: %s"
+msgid "frame is zero"
+msgstr "al livello zero"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "al livello pi alto: %d"
+
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
@@ -1422,8 +1446,7 @@ msgstr "E162: Buffer \"%s\" non salvato dopo modifica"
#: ../ex_cmds2.c:1480
msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
msgstr ""
-"Avviso: Entrato in altro buffer inaspettatamente (controllare "
-"autocomandi)"
+"Avviso: Entrato in altro buffer inaspettatamente (controllare autocomandi)"
#: ../ex_cmds2.c:1826
msgid "E163: There is only one file to edit"
@@ -2301,19 +2324,19 @@ msgstr "[in formato DOS]"
#: ../fileio.c:3801
msgid "[mac]"
-msgstr "[MAC]"
+msgstr "[Mac]"
#: ../fileio.c:3801
msgid "[mac format]"
-msgstr "[in formato MAC]"
+msgstr "[in formato Mac]"
#: ../fileio.c:3807
msgid "[unix]"
-msgstr "[UNIX]"
+msgstr "[Unix]"
#: ../fileio.c:3807
msgid "[unix format]"
-msgstr "[in formato UNIX]"
+msgstr "[in formato Unix]"
#: ../fileio.c:3831
msgid "1 line, "
@@ -2864,6 +2887,9 @@ msgstr "E46: Non posso cambiare la variabile read-only \"%s\""
msgid "E794: Cannot set variable in the sandbox: \"%s\""
msgstr "E794: Non posso impostare la variabile read-only in ambiente protetto: \"%s\""
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Non posso usare una chiave nulla per il Dizionario"
+
#: ../globals.h:1076
msgid "E47: Error while reading errorfile"
msgstr "E47: Errore leggendo il file errori"
@@ -4087,12 +4113,12 @@ msgid ""
"\n"
"(1) Another program may be editing the same file. If this is the case,\n"
" be careful not to end up with two different instances of the same\n"
-" file when making changes."
+" file when making changes. Quit, or continue with caution.\n"
msgstr ""
"\n"
-"(1) Un altro programma pu essere in edit sullo stesso file.\n"
-" Se cos, attenzione a non trovarti con due versioni\n"
-" differenti dello stesso file a cui vengono apportate modifiche."
+"(1) Un altro programma pu essere in edit sullo stesso file. Se cos,\n"
+" attenzione a non finire con due sessioni differenti che modificano lo\n"
+" stesso file. Uscire da Vim, o continuare con cautela.\n"
#: ../memline.c:3245
msgid " Quit, or continue with caution.\n"
@@ -4335,7 +4361,7 @@ msgstr "E766: Argomenti non sufficienti per printf()"
#: ../message.c:3119
msgid "E807: Expected Float argument for printf()"
-msgstr "E807: Numero con virgola atteso come argomento per printf()"
+msgstr "E807: Numero-a-virgola-mobile atteso come argomento per printf()"
#: ../message.c:3873
msgid "E767: Too many arguments to printf()"
@@ -4526,7 +4552,8 @@ msgstr "E574: Tipo di registro sconosciuto: %d"
msgid ""
"E883: search pattern and expression register may not contain two or more "
"lines"
-msgstr "E883: espressione di ricerca e registro dell'espressione non possono "
+msgstr ""
+"E883: espressione di ricerca e registro dell'espressione non possono "
"contenere due o pi righe"
#: ../ops.c:5089
@@ -4794,6 +4821,14 @@ msgstr ""
"\n"
"Non posso impostare il contesto di sicurezza per "
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Non posso impostare il contesto di sicurezza %s per %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Non posso ottenere il contesto di sicurezza %s per %s. Lo rimuovo!"
+
#: ../os_unix.c:1558 ../os_unix.c:1647
#, c-format
msgid "dlerror = \"%s\""
@@ -4890,6 +4925,7 @@ msgid "E777: String or List expected"
msgstr "E777: aspettavo Stringa o Lista"
#: ../regexp.c:359
+#, c-format
msgid "E369: invalid item in %s%%[]"
msgstr "E369: elemento non valido in %s%%[]"
@@ -5005,6 +5041,7 @@ msgid "External submatches:\n"
msgstr "Sotto-corrispondenze esterne:\n"
#: ../regexp.c:2470
+#, c-format
msgid "E888: (NFA regexp) cannot repeat %s"
msgstr "E888: (NFA regexp) non riesco a ripetere %s"
@@ -5399,8 +5436,7 @@ msgstr "Valore errato per CHECKCOMPOUNDPATTERN in %s riga %d: %s"
#: ../spell.c:4847
#, c-format
msgid "Different combining flag in continued affix block in %s line %d: %s"
-msgstr ""
-"Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s"
+msgstr "Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s"
#: ../spell.c:4850
#, c-format
@@ -5639,10 +5675,12 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries"
msgstr "E765: 'spellfile' non ha %<PRId64> elementi"
#: ../spell.c:8074
+#, c-format
msgid "Word '%.*s' removed from %s"
msgstr "Parola '%.*s' rimossa da %s"
#: ../spell.c:8117
+#, c-format
msgid "Word '%.*s' added to %s"
msgstr "Parola '%.*s' aggiunta a %s"
@@ -5720,6 +5758,9 @@ msgstr "Nessun elemento sintattico definito per questo buffer"
msgid "E390: Illegal argument: %s"
msgstr "E390: Argomento non ammesso: %s"
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
@@ -5816,6 +5857,9 @@ msgstr "E847: Troppe inclusioni di sintassi"
msgid "E789: Missing ']': %s"
msgstr "E789: Manca ']': %s"
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Caratteri in pi dopo ']': %s]%s"
+
#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po
index d3061d3c5a..85042e3506 100644
--- a/src/nvim/po/ja.euc-jp.po
+++ b/src/nvim/po/ja.euc-jp.po
@@ -1,11 +1,11 @@
-# Japanese translation for Vim vim:set foldmethod=marker:
+# Japanese translation for Vim
#
# Do ":help uganda" in Vim to read copying and usage conditions.
# Do ":help credits" in Vim to see a list of people who contributed.
#
-# Last Change: 2013 Jul 06
+# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp (http://vim-jp.org/)
#
-# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com>
# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
#
# Generated from ja.po, DO NOT EDIT.
@@ -14,10 +14,10 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-07-06 15:00+0900\n"
+"POT-Creation-Date: 2016-02-01 09:02+0900\n"
+"PO-Revision-Date: 2016-02-01 09:08+0900\n"
"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
-"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: vim-jp (https://github.com/vim-jp/lang-ja)\n"
"Language: Japanese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=euc-jp\n"
@@ -34,7 +34,7 @@ msgstr "顼: ̤ΤΥץ󷿤Ǥ"
#: ../buffer.c:92
msgid "[Location List]"
-msgstr "[ꥹ]"
+msgstr "[ꥹ]"
#: ../buffer.c:93
msgid "[Quickfix List]"
@@ -277,7 +277,7 @@ msgstr "E810: եɹ⤷ϽǤޤ"
#: ../diff.c:755
msgid "E97: Cannot create diffs"
-msgstr "E97: ʬǤޤ "
+msgstr "E97: ʬǤޤ"
#: ../diff.c:966
msgid "E816: Cannot read patch output"
@@ -293,7 +293,7 @@ msgstr "E99: ߤΥХåեϺʬ⡼ɤǤϤޤ"
#: ../diff.c:2100
msgid "E793: No other buffer in diff mode is modifiable"
-msgstr "E793: ʬ⡼ɤǤ¾ΥХåեѹǽǤ"
+msgstr "E793: ʬ⡼ɤǤ¾ΥХåեѹǤޤ"
#: ../diff.c:2102
msgid "E100: No other buffer in diff mode"
@@ -349,7 +349,7 @@ msgstr " ()䴰 (^L^N^P)"
#: ../edit.c:86
msgid " File name completion (^F^N^P)"
-msgstr "ե̾䴰 (^F^N^P)"
+msgstr " ե̾䴰 (^F^N^P)"
#: ../edit.c:87
msgid " Tag completion (^]^N^P)"
@@ -377,7 +377,7 @@ msgstr " ޥɥ饤䴰 (^V^N^P)"
#: ../edit.c:94
msgid " User defined completion (^U^N^P)"
-msgstr " 桼䴰 (^U^N^P)"
+msgstr " 桼䴰 (^U^N^P)"
#: ../edit.c:95
msgid " Omni completion (^O^N^P)"
@@ -679,6 +679,11 @@ msgstr "E696: ꥹȷ˥ޤޤ: %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: ꥹȷκǸ ']' ޤ: %s"
+#: ../eval.c:5807
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"٥å쥯ߤޤ! ȤΤ˥꤬­ޤ"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -721,7 +726,7 @@ msgstr "E117: ̤ΤδؿǤ: %s"
#: ../eval.c:7383
#, c-format
msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: ؿΰʲ᤮ޤ: %s"
+msgstr "E119: ؿΰ­ޤ: %s"
#: ../eval.c:7387
#, c-format
@@ -826,18 +831,16 @@ msgid "sort() argument"
msgstr "sort() ΰ"
#: ../eval.c:13721
-#, fuzzy
msgid "uniq() argument"
-msgstr "add() ΰ"
+msgstr "uniq() ΰ"
#: ../eval.c:13776
msgid "E702: Sort compare function failed"
msgstr "E702: ȤӴؿԤޤ"
#: ../eval.c:13806
-#, fuzzy
msgid "E882: Uniq compare function failed"
-msgstr "E702: ȤӴؿԤޤ"
+msgstr "E882: Uniq ӴؿԤޤ"
#: ../eval.c:14085
msgid "(Invalid)"
@@ -863,6 +866,18 @@ msgstr "E745: ꥹȷͤȤưäƤޤ"
msgid "E728: Using a Dictionary as a Number"
msgstr "E728: 񷿤ͤȤưäƤޤ"
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: ؿȷưȤưäƤޤ"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: ʸưȤưäƤޤ"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: ꥹȷưȤưäƤޤ"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: 񷿤ưȤưäƤޤ"
+
#: ../eval.c:16259
msgid "E729: using Funcref as a String"
msgstr "E729: ؿȷʸȤưäƤޤ"
@@ -961,14 +976,14 @@ msgid "E129: Function name required"
msgstr "E129: ؿ̾׵ᤵޤ"
#: ../eval.c:17824
-#, fuzzy, c-format
+#, c-format
msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: ؿ̾ʸǻϤޤ뤫ޤޤʤФʤޤ: %s"
+msgstr "E128: ؿ̾ʸ \"s:\" ǻϤޤʤФʤޤ: %s"
#: ../eval.c:17833
-#, fuzzy, c-format
+#, c-format
msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E128: ؿ̾ʸǻϤޤ뤫ޤޤʤФʤޤ: %s"
+msgstr "E884: ؿ̾ˤϥϴޤޤ: %s"
#: ../eval.c:18336
#, c-format
@@ -1081,7 +1096,7 @@ msgstr "E136: viminfo: 顼¿᤮Τ, ʹߤϥåפޤ"
#: ../ex_cmds.c:1458
#, c-format
msgid "Reading viminfo file \"%s\"%s%s%s"
-msgstr "viminfoե \"%s\"%s%s%s ɹ "
+msgstr "viminfoե \"%s\"%s%s%s ɹ"
#: ../ex_cmds.c:1460
msgid " info"
@@ -1357,6 +1372,10 @@ msgstr "E158: ̵ʥХåե̾Ǥ: %s"
msgid "E157: Invalid sign ID: %<PRId64>"
msgstr "E157: ̵sign̻ҤǤ: %<PRId64>"
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: ѹǤʤ sign Ǥ: %s"
+
#: ../ex_cmds.c:6066
msgid " (not supported)"
msgstr " (󥵥ݡ)"
@@ -1379,6 +1398,13 @@ msgstr " %<PRId64>: %s"
msgid "cmd: %s"
msgstr "ޥ: %s"
+msgid "frame is zero"
+msgstr "ե졼ब 0 Ǥ"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ǹ٥Υե졼: %d"
+
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
@@ -1528,7 +1554,8 @@ msgstr "E197: \"%s\" Ǥޤ"
#. don't wait for return
#: ../ex_docmd.c:387
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
-msgstr "Ex⡼ɤޤ. Ρޥˤ\"visual\"ϤƤ."
+msgstr ""
+"Ex⡼ɤޤ. Ρޥ⡼ɤˤ\"visual\"ϤƤ."
#: ../ex_docmd.c:428
msgid "E501: At end-of-file"
@@ -1553,7 +1580,7 @@ msgstr "ؿκǸǤ"
#: ../ex_docmd.c:1628
msgid "E464: Ambiguous use of user-defined command"
-msgstr "E464: 桼ޥɤΤޤʻѤǤ"
+msgstr "E464: 桼ޥɤΤޤʻѤǤ"
#: ../ex_docmd.c:1638
msgid "E492: Not an editor command"
@@ -1606,14 +1633,14 @@ msgstr "E174: ޥɤˤޤ: ˤ ! ɲäƤ"
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" ̾ ϰ 䴰 "
+" ̾ ɥ쥹 䴰 "
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
-msgstr "桼ޥɤĤޤǤ"
+msgstr "桼ޥɤĤޤǤ"
#: ../ex_docmd.c:4538
msgid "E175: No attribute specified"
@@ -1633,7 +1660,10 @@ msgstr "E178: Ȥξά̵ͤǤ"
#: ../ex_docmd.c:4625
msgid "E179: argument required for -complete"
-msgstr "E179: -䴰ΤΰɬפǤ"
+msgstr "E179: -complete ˤϰɬפǤ"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr ˤϰɬפǤ"
#: ../ex_docmd.c:4635
#, c-format
@@ -1650,12 +1680,16 @@ msgstr "E183: 桼ޥɤϱʸǻϤޤʤФʤޤ"
#: ../ex_docmd.c:4696
msgid "E841: Reserved name, cannot be used for user defined command"
-msgstr "E841: ͽ̾ʤΤ, 桼ޥɤѤǤޤ"
+msgstr "E841: ͽ̾ʤΤ, 桼ޥɤѤǤޤ"
#: ../ex_docmd.c:4751
#, c-format
msgid "E184: No such user-defined command: %s"
-msgstr "E184: Υ桼ޥɤϤޤ: %s"
+msgstr "E184: Υ桼ޥɤϤޤ: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: ̵ʥɥ쥹ͤǤ: %s"
#: ../ex_docmd.c:5219
#, c-format
@@ -2019,11 +2053,11 @@ msgstr "ʥե̾"
#: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578
msgid "is a directory"
-msgstr " ϥǥ쥯ȥǤ"
+msgstr "ϥǥ쥯ȥǤ"
#: ../fileio.c:397
msgid "is not a file"
-msgstr " ϥեǤϤޤ"
+msgstr "ϥեǤϤޤ"
#: ../fileio.c:508 ../fileio.c:3522
msgid "[New File]"
@@ -2039,7 +2073,7 @@ msgstr "[ե]"
#: ../fileio.c:534
msgid "[Permission Denied]"
-msgstr "[ǧĤޤ]"
+msgstr "[¤ޤ]"
#: ../fileio.c:653
msgid "E200: *ReadPre autocommands made the file unreadable"
@@ -2210,7 +2244,7 @@ msgstr " Ѵ顼"
#: ../fileio.c:3509
#, c-format
msgid " in line %<PRId64>;"
-msgstr " %<PRId64>;"
+msgstr " %<PRId64>;"
#: ../fileio.c:3519
msgid "[Device]"
@@ -2766,9 +2800,8 @@ msgid "E37: No write since last change (add ! to override)"
msgstr "E37: Ǹѹ¸Ƥޤ (! ɲäѹ˴)"
#: ../globals.h:1055
-#, fuzzy
msgid "E37: No write since last change"
-msgstr "[Ǹѹ¸Ƥޤ]\n"
+msgstr "E37: Ǹѹ¸Ƥޤ"
#: ../globals.h:1056
msgid "E38: Null argument"
@@ -2810,7 +2843,7 @@ msgstr "E42: 顼Ϥޤ"
#: ../globals.h:1067
msgid "E776: No location list"
-msgstr "E776: ꥹȤϤޤ"
+msgstr "E776: ꥹȤϤޤ"
#: ../globals.h:1068
msgid "E43: Damaged match string"
@@ -3831,7 +3864,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"줫.swpեƤ\n"
+".swpեϺƤ⹽ޤ\n"
"\n"
#. use msg() to start the scrolling properly
@@ -3845,7 +3878,7 @@ msgstr " ߤΥǥ쥯ȥ:\n"
#: ../memline.c:1448
msgid " Using specified name:\n"
-msgstr " ̾:\n"
+msgstr " ʲ̾:\n"
#: ../memline.c:1450
msgid " In directory "
@@ -3901,7 +3934,7 @@ msgid ""
" user name: "
msgstr ""
"\n"
-" 桼̾: "
+" 桼̾: "
#: ../memline.c:1568
msgid " host name: "
@@ -4050,12 +4083,12 @@ msgid ""
msgstr ""
"\n"
"(1) ̤ΥץबƱեԽƤ뤫⤷ޤ.\n"
-" ξˤ, ѹ򤷤ݤ˺ǽŪ, Ʊեΰۤʤ\n"
-" 2ĤΥ󥹥󥹤ǤƤޤȤդƤ."
+" ξˤ, ѹ򤷤Ƥޤ1ĤΥեФưۤʤ2Ĥ\n"
+" 󥹥󥹤ǤƤޤΤ, ʤ褦˵ĤƤ."
#: ../memline.c:3245
msgid " Quit, or continue with caution.\n"
-msgstr " λ뤫, դʤ³Ƥ.\n"
+msgstr " λ뤫, դʤ³Ƥ.\n"
#: ../memline.c:3246
msgid "(2) An edit session for this file crashed.\n"
@@ -4479,6 +4512,11 @@ msgstr ""
msgid "E574: Unknown register type %d"
msgstr "E574: ̤ΤΥ쥸 %d Ǥ"
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: ѥȼ쥸ˤ2԰ʾޤޤ"
+
#: ../ops.c:5089
#, c-format
msgid "%<PRId64> Cols; "
@@ -4563,6 +4601,10 @@ msgstr "E522: termcap ˸Ĥޤ"
msgid "E539: Illegal character <%s>"
msgstr "E539: ʸǤ <%s>"
+#, c-format
+msgid "For option %s"
+msgstr "ץ: %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: 'term' ˤ϶ʸǤޤ"
@@ -4740,6 +4782,14 @@ msgstr ""
"\n"
"ƥƥȤǤޤ "
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "ƥƥ %s %s Ǥޤ"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "ƥƥ %s %s Ǥޤ. ޤ!"
+
#: ../os_unix.c:1558 ../os_unix.c:1647
#, c-format
msgid "dlerror = \"%s\""
@@ -4960,6 +5010,10 @@ msgstr "E554: %s{...} ʸˡ顼ޤ"
msgid "External submatches:\n"
msgstr "ʬ:\n"
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA ɽ) ֤ޤ %s"
+
#: ../regexp.c:7022
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
@@ -4968,6 +5022,9 @@ msgstr ""
"E864: \\%#= ˤ 0, 1 ⤷ 2 Τߤ³ޤɽ󥸥ϼư"
"򤵤ޤ"
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Υѥ˥Хåȥå RE 󥸥ŬѤޤ: "
+
#: ../regexp_nfa.c:239
msgid "E865: (NFA) Regexp end encountered prematurely"
msgstr "E865: (NFA) Ԥ᤯ɽνüãޤ"
@@ -4980,7 +5037,7 @@ msgstr "E866: (NFA ɽ) ֤äƤޤ: %c"
#: ../regexp_nfa.c:242
#, c-format
msgid "E877: (NFA regexp) Invalid character class: %<PRId64>"
-msgstr ""
+msgstr "E877: (NFA ɽ) ̵ʸ饹: %<PRId64>"
#: ../regexp_nfa.c:1261
#, c-format
@@ -5590,14 +5647,14 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries"
msgstr "E765: 'spellfile' ˤ %<PRId64> ĤΥȥϤޤ"
#: ../spell.c:8074
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' removed from %s"
-msgstr "%s ñ줬ޤ"
+msgstr "ñ '%.*s' %s ޤ"
#: ../spell.c:8117
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' added to %s"
-msgstr "%s ñ줬ɲäޤ"
+msgstr "ñ '%.*s' %s ɲäޤ"
#: ../spell.c:8381
msgid "E763: Word characters differ between spell files"
@@ -5673,6 +5730,9 @@ msgstr "ΥХåե줿ʸǤϤޤ"
msgid "E390: Illegal argument: %s"
msgstr "E390: ʰǤ: %s"
+msgid "syntax iskeyword "
+msgstr "󥿥å iskeyword "
+
#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
@@ -5769,6 +5829,10 @@ msgstr "E847: ʸμ(include)¿᤮ޤ"
msgid "E789: Missing ']': %s"
msgstr "E789: ']' ޤ: %s"
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' θ;ʬʸޤ: %s]%s"
+
#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
@@ -5874,7 +5938,7 @@ msgstr "E415: ͽǤ: %s"
#: ../syntax.c:6395
#, c-format
msgid "E416: missing equal sign: %s"
-msgstr "E416: 椬ޤ: %s"
+msgstr "E416: 椬ޤ: %s"
#: ../syntax.c:6418
#, c-format
@@ -6078,9 +6142,8 @@ msgstr "Vim: ϤɹΥ顼ˤ꽪λޤ...\n"
#. This happens when the FileChangedRO autocommand changes the
#. * file in a way it becomes shorter.
#: ../undo.c:379
-#, fuzzy
msgid "E881: Line count changed unexpectedly"
-msgstr "E834: ͽԥȤѤޤ"
+msgstr "E881: ͽԥȤѤޤ"
#: ../undo.c:627
#, c-format
@@ -6287,23 +6350,23 @@ msgstr " ƥ vimrc: \""
#: ../version.c:672
msgid " user vimrc file: \""
-msgstr " 桼 vimrc: \""
+msgstr " 桼 vimrc: \""
#: ../version.c:677
msgid " 2nd user vimrc file: \""
-msgstr " 2桼 vimrc: \""
+msgstr " 2桼 vimrc: \""
#: ../version.c:682
msgid " 3rd user vimrc file: \""
-msgstr " 3桼 vimrc: \""
+msgstr " 3桼 vimrc: \""
#: ../version.c:687
msgid " user exrc file: \""
-msgstr " 桼 exrc: \""
+msgstr " 桼 exrc: \""
#: ../version.c:692
msgid " 2nd user exrc file: \""
-msgstr " 2桼 exrc: \""
+msgstr " 2桼 exrc: \""
#: ../version.c:699
msgid " fall-back for $VIM: \""
@@ -6379,7 +6442,7 @@ msgstr "Vimγȯ礷Ƥ!"
#: ../version.c:828
msgid "Become a registered Vim user!"
-msgstr "VimϿ桼ˤʤäƤ!"
+msgstr "VimϿ桼ˤʤäƤ!"
#: ../version.c:831
msgid "type :help sponsor<Enter> for information "
@@ -6391,7 +6454,7 @@ msgstr "ܺ٤ʾ :help register<Enter> "
#: ../version.c:834
msgid "menu Help->Sponsor/Register for information "
-msgstr "ܺ٤ϥ˥塼 إעݥ󥵡/Ͽ 򻲾ȤƲ "
+msgstr "ܺ٤ϥ˥塼 إ->ݥ󥵡/Ͽ 򻲾ȤƲ"
#: ../window.c:119
msgid "Already only one window"
@@ -6429,6 +6492,9 @@ msgstr "E445: ¾Υɥˤѹޤ"
msgid "E446: No file name under cursor"
msgstr "E446: β˥ե̾ޤ"
+msgid "List or number required"
+msgstr "ꥹȤͤɬפǤ"
+
#~ msgid "E831: bf_key_init() called with empty password"
#~ msgstr "E831: bf_key_init() ѥɤǸƤӽФޤ"
diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po
index 6bdfcb426f..0326f33bb5 100644
--- a/src/nvim/po/ja.po
+++ b/src/nvim/po/ja.po
@@ -1,11 +1,11 @@
-# Japanese translation for Vim vim:set foldmethod=marker:
+# Japanese translation for Vim
#
# Do ":help uganda" in Vim to read copying and usage conditions.
# Do ":help credits" in Vim to see a list of people who contributed.
#
-# Last Change: 2013 Jul 06
+# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp (http://vim-jp.org/)
#
-# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com>
# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
#
# Original translations.
@@ -14,10 +14,10 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-07-06 15:00+0900\n"
+"POT-Creation-Date: 2016-02-01 09:02+0900\n"
+"PO-Revision-Date: 2013-06-02-01 09:08+09n"
"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
-"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: vim-jp (https://github.com/vim-jp/lang-ja)\n"
"Language: Japanese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
@@ -34,7 +34,7 @@ msgstr "内部エラー: 未知のオプション型です"
#: ../buffer.c:92
msgid "[Location List]"
-msgstr "[場所リスト]"
+msgstr "[ロケーションリスト]"
#: ../buffer.c:93
msgid "[Quickfix List]"
@@ -277,7 +277,7 @@ msgstr "E810: 一時ファイルの読込もしくは書込ができません"
#: ../diff.c:755
msgid "E97: Cannot create diffs"
-msgstr "E97: 差分を作成できません "
+msgstr "E97: 差分を作成できません"
#: ../diff.c:966
msgid "E816: Cannot read patch output"
@@ -293,7 +293,7 @@ msgstr "E99: 現在のバッファは差分モードではありません"
#: ../diff.c:2100
msgid "E793: No other buffer in diff mode is modifiable"
-msgstr "E793: 差分モードである他のバッファは変更可能です"
+msgstr "E793: 差分モードである他のバッファは変更できません"
#: ../diff.c:2102
msgid "E100: No other buffer in diff mode"
@@ -349,7 +349,7 @@ msgstr " 行(全体)補完 (^L^N^P)"
#: ../edit.c:86
msgid " File name completion (^F^N^P)"
-msgstr "ファイル名補完 (^F^N^P)"
+msgstr " ファイル名補完 (^F^N^P)"
#: ../edit.c:87
msgid " Tag completion (^]^N^P)"
@@ -377,7 +377,7 @@ msgstr " コマンドライン補完 (^V^N^P)"
#: ../edit.c:94
msgid " User defined completion (^U^N^P)"
-msgstr " ユーザ定義補完 (^U^N^P)"
+msgstr " ユーザー定義補完 (^U^N^P)"
#: ../edit.c:95
msgid " Omni completion (^O^N^P)"
@@ -679,6 +679,10 @@ msgstr "E696: リスト型にカンマがありません: %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: リスト型の最後に ']' がありません: %s"
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"ガーベッジコレクションを中止しました! 参照を作成するのにメモリが不足しました"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -721,7 +725,7 @@ msgstr "E117: 未知の関数です: %s"
#: ../eval.c:7383
#, c-format
msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: 関数の引数が少な過ぎます: %s"
+msgstr "E119: 関数の引数が足りません: %s"
#: ../eval.c:7387
#, c-format
@@ -826,18 +830,16 @@ msgid "sort() argument"
msgstr "sort() の引数"
#: ../eval.c:13721
-#, fuzzy
msgid "uniq() argument"
-msgstr "add() の引数"
+msgstr "uniq() の引数"
#: ../eval.c:13776
msgid "E702: Sort compare function failed"
msgstr "E702: ソートの比較関数が失敗しました"
#: ../eval.c:13806
-#, fuzzy
msgid "E882: Uniq compare function failed"
-msgstr "E702: ソートの比較関数が失敗しました"
+msgstr "E882: Uniq の比較関数が失敗しました"
#: ../eval.c:14085
msgid "(Invalid)"
@@ -863,6 +865,18 @@ msgstr "E745: リスト型を数値として扱っています"
msgid "E728: Using a Dictionary as a Number"
msgstr "E728: 辞書型を数値として扱っています"
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: 関数参照型を浮動小数点数として扱っています。"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: 文字列を浮動小数点数として扱っています"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: リスト型を浮動小数点数として扱っています"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: 辞書型を浮動小数点数として扱っています"
+
#: ../eval.c:16259
msgid "E729: using Funcref as a String"
msgstr "E729: 関数参照型を文字列として扱っています"
@@ -961,14 +975,14 @@ msgid "E129: Function name required"
msgstr "E129: 関数名が要求されます"
#: ../eval.c:17824
-#, fuzzy, c-format
+#, c-format
msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: 関数名は大文字で始まるかコロンを含まなければなりません: %s"
+msgstr "E128: 関数名は大文字か \"s:\" で始まらなければなりません: %s"
#: ../eval.c:17833
-#, fuzzy, c-format
+#, c-format
msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E128: 関数名は大文字で始まるかコロンを含まなければなりません: %s"
+msgstr "E884: 関数名にはコロンは含められません: %s"
#: ../eval.c:18336
#, c-format
@@ -1081,7 +1095,7 @@ msgstr "E136: viminfo: エラーが多過ぎるので, 以降はスキップし
#: ../ex_cmds.c:1458
#, c-format
msgid "Reading viminfo file \"%s\"%s%s%s"
-msgstr "viminfoファイル \"%s\"%s%s%s を読込み中 "
+msgstr "viminfoファイル \"%s\"%s%s%s を読込み中"
#: ../ex_cmds.c:1460
msgid " info"
@@ -1357,6 +1371,10 @@ msgstr "E158: 無効なバッファ名です: %s"
msgid "E157: Invalid sign ID: %<PRId64>"
msgstr "E157: 無効なsign識別子です: %<PRId64>"
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: 変更できない sign です: %s"
+
#: ../ex_cmds.c:6066
msgid " (not supported)"
msgstr " (非サポート)"
@@ -1379,6 +1397,13 @@ msgstr "行 %<PRId64>: %s"
msgid "cmd: %s"
msgstr "コマンド: %s"
+msgid "frame is zero"
+msgstr "フレームが 0 です"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "最高レベルのフレーム: %d"
+
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
@@ -1528,7 +1553,8 @@ msgstr "E197: 言語を \"%s\" に設定できません"
#. don't wait for return
#: ../ex_docmd.c:387
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
-msgstr "Exモードに入ります. ノーマルに戻るには\"visual\"と入力してください."
+msgstr ""
+"Exモードに入ります. ノーマルモードに戻るには\"visual\"と入力してください."
#: ../ex_docmd.c:428
msgid "E501: At end-of-file"
@@ -1553,7 +1579,7 @@ msgstr "関数の最後です"
#: ../ex_docmd.c:1628
msgid "E464: Ambiguous use of user-defined command"
-msgstr "E464: ユーザ定義コマンドのあいまいな使用です"
+msgstr "E464: ユーザー定義コマンドのあいまいな使用です"
#: ../ex_docmd.c:1638
msgid "E492: Not an editor command"
@@ -1606,14 +1632,14 @@ msgstr "E174: コマンドが既にあります: 再定義するには ! を追
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" 名前 引数 範囲 補完 定義"
+" 名前 引数 アドレス 補完 定義"
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
-msgstr "ユーザ定義コマンドが見つかりませんでした"
+msgstr "ユーザー定義コマンドが見つかりませんでした"
#: ../ex_docmd.c:4538
msgid "E175: No attribute specified"
@@ -1633,7 +1659,10 @@ msgstr "E178: カウントの省略値が無効です"
#: ../ex_docmd.c:4625
msgid "E179: argument required for -complete"
-msgstr "E179: -補完のための引数が必要です"
+msgstr "E179: -complete には引数が必要です"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr には引数が必要です"
#: ../ex_docmd.c:4635
#, c-format
@@ -1646,16 +1675,20 @@ msgstr "E182: 無効なコマンド名です"
#: ../ex_docmd.c:4691
msgid "E183: User defined commands must start with an uppercase letter"
-msgstr "E183: ユーザ定義コマンドは英大文字で始まらなければなりません"
+msgstr "E183: ユーザー定義コマンドは英大文字で始まらなければなりません"
#: ../ex_docmd.c:4696
msgid "E841: Reserved name, cannot be used for user defined command"
-msgstr "E841: 予約名なので, ユーザ定義コマンドに利用できません"
+msgstr "E841: 予約名なので, ユーザー定義コマンドに利用できません"
#: ../ex_docmd.c:4751
#, c-format
msgid "E184: No such user-defined command: %s"
-msgstr "E184: そのユーザ定義コマンドはありません: %s"
+msgstr "E184: そのユーザー定義コマンドはありません: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: 無効なアドレスタイプ値です: %s"
#: ../ex_docmd.c:5219
#, c-format
@@ -2019,11 +2052,11 @@ msgstr "不正なファイル名"
#: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578
msgid "is a directory"
-msgstr " はディレクトリです"
+msgstr "はディレクトリです"
#: ../fileio.c:397
msgid "is not a file"
-msgstr " はファイルではありません"
+msgstr "はファイルではありません"
#: ../fileio.c:508 ../fileio.c:3522
msgid "[New File]"
@@ -2039,7 +2072,7 @@ msgstr "[ファイル過大]"
#: ../fileio.c:534
msgid "[Permission Denied]"
-msgstr "[認可がありません]"
+msgstr "[権限がありません]"
#: ../fileio.c:653
msgid "E200: *ReadPre autocommands made the file unreadable"
@@ -2210,7 +2243,7 @@ msgstr " 変換エラー"
#: ../fileio.c:3509
#, c-format
msgid " in line %<PRId64>;"
-msgstr "行 %<PRId64>;"
+msgstr " 行 %<PRId64>;"
#: ../fileio.c:3519
msgid "[Device]"
@@ -2766,9 +2799,8 @@ msgid "E37: No write since last change (add ! to override)"
msgstr "E37: 最後の変更が保存されていません (! を追加で変更を破棄)"
#: ../globals.h:1055
-#, fuzzy
msgid "E37: No write since last change"
-msgstr "[最後の変更が保存されていません]\n"
+msgstr "E37: 最後の変更が保存されていません"
#: ../globals.h:1056
msgid "E38: Null argument"
@@ -2810,7 +2842,7 @@ msgstr "E42: エラーはありません"
#: ../globals.h:1067
msgid "E776: No location list"
-msgstr "E776: 場所リストはありません"
+msgstr "E776: ロケーションリストはありません"
#: ../globals.h:1068
msgid "E43: Damaged match string"
@@ -3831,7 +3863,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"それから.swpファイルを削除してください\n"
+"元の.swpファイルは削除しても構いません\n"
"\n"
#. use msg() to start the scrolling properly
@@ -3845,7 +3877,7 @@ msgstr " 現在のディレクトリ:\n"
#: ../memline.c:1448
msgid " Using specified name:\n"
-msgstr " ある名前を使用中:\n"
+msgstr " 以下の名前を使用中:\n"
#: ../memline.c:1450
msgid " In directory "
@@ -3901,7 +3933,7 @@ msgid ""
" user name: "
msgstr ""
"\n"
-" ユーザ名: "
+" ユーザー名: "
#: ../memline.c:1568
msgid " host name: "
@@ -4050,12 +4082,12 @@ msgid ""
msgstr ""
"\n"
"(1) 別のプログラムが同じファイルを編集しているかもしれません.\n"
-" この場合には, 変更をした際に最終的に, 同じファイルの異なる\n"
-" 2つのインスタンスができてしまうことに注意してください."
+" この場合には, 変更をしてしまうと1つのファイルに対して異なる2つの\n"
+" インスタンスができてしまうので, そうしないように気をつけてください."
#: ../memline.c:3245
msgid " Quit, or continue with caution.\n"
-msgstr " 終了するか, 注意しながら続けてください.\n"
+msgstr " 終了するか, 注意しながら続けてください.\n"
#: ../memline.c:3246
msgid "(2) An edit session for this file crashed.\n"
@@ -4479,6 +4511,11 @@ msgstr ""
msgid "E574: Unknown register type %d"
msgstr "E574: 未知のレジスタ型 %d です"
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: 検索パターンと式レジスタには2行以上を含められません"
+
#: ../ops.c:5089
#, c-format
msgid "%<PRId64> Cols; "
@@ -4563,6 +4600,10 @@ msgstr "E522: termcap 内に見つかりません"
msgid "E539: Illegal character <%s>"
msgstr "E539: 不正な文字です <%s>"
+#, c-format
+msgid "For option %s"
+msgstr "オプション: %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: 'term' には空文字列を設定できません"
@@ -4740,6 +4781,14 @@ msgstr ""
"\n"
"セキュリティコンテキストを設定できません "
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "セキュリティコンテキスト %s を %s に設定できません"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "セキュリティコンテキスト %s を %s から取得できません. 削除します!"
+
#: ../os_unix.c:1558 ../os_unix.c:1647
#, c-format
msgid "dlerror = \"%s\""
@@ -4960,6 +5009,10 @@ msgstr "E554: %s{...} 内に文法エラーがあります"
msgid "External submatches:\n"
msgstr "外部の部分該当:\n"
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA 正規表現) 繰り返せません %s"
+
#: ../regexp.c:7022
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
@@ -4968,6 +5021,9 @@ msgstr ""
"E864: \\%#= には 0, 1 もしくは 2 のみが続けられます。正規表現エンジンは自動選"
"択されます。"
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "次のパターンにバックトラッキング RE エンジンを適用します: "
+
#: ../regexp_nfa.c:239
msgid "E865: (NFA) Regexp end encountered prematurely"
msgstr "E865: (NFA) 期待より早く正規表現の終端に到達しました"
@@ -4980,7 +5036,7 @@ msgstr "E866: (NFA 正規表現) 位置が誤っています: %c"
#: ../regexp_nfa.c:242
#, c-format
msgid "E877: (NFA regexp) Invalid character class: %<PRId64>"
-msgstr ""
+msgstr "E877: (NFA 正規表現) 無効な文字クラス: %<PRId64>"
#: ../regexp_nfa.c:1261
#, c-format
@@ -5590,14 +5646,14 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries"
msgstr "E765: 'spellfile' には %<PRId64> 個のエントリはありません"
#: ../spell.c:8074
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' removed from %s"
-msgstr "%s から単語が削除されました"
+msgstr "単語 '%.*s' が %s から削除されました"
#: ../spell.c:8117
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' added to %s"
-msgstr "%s に単語が追加されました"
+msgstr "単語 '%.*s' が %s へ追加されました"
#: ../spell.c:8381
msgid "E763: Word characters differ between spell files"
@@ -5673,6 +5729,9 @@ msgstr "このバッファに定義された構文要素はありません"
msgid "E390: Illegal argument: %s"
msgstr "E390: 不正な引数です: %s"
+msgid "syntax iskeyword "
+msgstr "シンタックス用 iskeyword "
+
#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
@@ -5769,6 +5828,10 @@ msgstr "E847: 構文の取り込み(include)が多過ぎます"
msgid "E789: Missing ']': %s"
msgstr "E789: ']' がありません: %s"
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' の後ろに余分な文字があります: %s]%s"
+
#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
@@ -5874,7 +5937,7 @@ msgstr "E415: 予期せぬ等号です: %s"
#: ../syntax.c:6395
#, c-format
msgid "E416: missing equal sign: %s"
-msgstr "E416: 等号ががありません: %s"
+msgstr "E416: 等号がありません: %s"
#: ../syntax.c:6418
#, c-format
@@ -6078,9 +6141,8 @@ msgstr "Vim: 入力を読込み中のエラーにより終了します...\n"
#. This happens when the FileChangedRO autocommand changes the
#. * file in a way it becomes shorter.
#: ../undo.c:379
-#, fuzzy
msgid "E881: Line count changed unexpectedly"
-msgstr "E834: 予期せず行カウントが変わりました"
+msgstr "E881: 予期せず行カウントが変わりました"
#: ../undo.c:627
#, c-format
@@ -6287,23 +6349,23 @@ msgstr " システム vimrc: \""
#: ../version.c:672
msgid " user vimrc file: \""
-msgstr " ユーザ vimrc: \""
+msgstr " ユーザー vimrc: \""
#: ../version.c:677
msgid " 2nd user vimrc file: \""
-msgstr " 第2ユーザ vimrc: \""
+msgstr " 第2ユーザー vimrc: \""
#: ../version.c:682
msgid " 3rd user vimrc file: \""
-msgstr " 第3ユーザ vimrc: \""
+msgstr " 第3ユーザー vimrc: \""
#: ../version.c:687
msgid " user exrc file: \""
-msgstr " ユーザ exrc: \""
+msgstr " ユーザー exrc: \""
#: ../version.c:692
msgid " 2nd user exrc file: \""
-msgstr " 第2ユーザ exrc: \""
+msgstr " 第2ユーザー exrc: \""
#: ../version.c:699
msgid " fall-back for $VIM: \""
@@ -6379,7 +6441,7 @@ msgstr "Vimの開発を応援してください!"
#: ../version.c:828
msgid "Become a registered Vim user!"
-msgstr "Vimの登録ユーザになってください!"
+msgstr "Vimの登録ユーザーになってください!"
#: ../version.c:831
msgid "type :help sponsor<Enter> for information "
@@ -6391,7 +6453,7 @@ msgstr "詳細な情報は :help register<Enter> "
#: ../version.c:834
msgid "menu Help->Sponsor/Register for information "
-msgstr "詳細はメニューの ヘルプ→スポンサー/登録 を参照して下さい "
+msgstr "詳細はメニューの ヘルプ->スポンサー/登録 を参照して下さい"
#: ../window.c:119
msgid "Already only one window"
@@ -6429,6 +6491,9 @@ msgstr "E445: 他のウィンドウには変更があります"
msgid "E446: No file name under cursor"
msgstr "E446: カーソルの下にファイル名がありません"
+msgid "List or number required"
+msgstr "リストか数値が必要です"
+
#~ msgid "E831: bf_key_init() called with empty password"
#~ msgstr "E831: bf_key_init() が空パスワードで呼び出されました"
diff --git a/src/nvim/po/ja.sjis.po b/src/nvim/po/ja.sjis.po
index 7dac89e172..16a5d2ce36 100644
--- a/src/nvim/po/ja.sjis.po
+++ b/src/nvim/po/ja.sjis.po
@@ -1,11 +1,11 @@
-# Japanese translation for Vim vim:set foldmethod=marker:
+# Japanese translation for Vim
#
# Do ":help uganda" in Vim to read copying and usage conditions.
# Do ":help credits" in Vim to see a list of people who contributed.
#
-# Last Change: 2013 Jul 06
+# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp (http://vim-jp.org/)
#
-# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com>
# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
#
# Original translations.
@@ -14,10 +14,10 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-07-06 15:00+0900\n"
+"POT-Creation-Date: 2016-02-01 09:02+0900\n"
+"PO-Revision-Date: 2016-02-01 09:08+0900\n"
"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
-"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: vim-jpj (https://github.com/vim-jp/lang-ja)\n"
"Language: Japanese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=cp932\n"
@@ -34,7 +34,7 @@ msgstr "G[: m̃IvV^ł"
#: ../buffer.c:92
msgid "[Location List]"
-msgstr "[ꏊXg]"
+msgstr "[P[VXg]"
#: ../buffer.c:93
msgid "[Quickfix List]"
@@ -277,7 +277,7 @@ msgstr "E810: ꎞt@C̓Ǎ͏ł܂"
#: ../diff.c:755
msgid "E97: Cannot create diffs"
-msgstr "E97: 쐬ł܂ "
+msgstr "E97: 쐬ł܂"
#: ../diff.c:966
msgid "E816: Cannot read patch output"
@@ -293,7 +293,7 @@ msgstr "E99: ݂̃obt@͍[hł͂܂"
#: ../diff.c:2100
msgid "E793: No other buffer in diff mode is modifiable"
-msgstr "E793: [hł鑼̃obt@͕ύX”\\ł"
+msgstr "E793: [hł鑼̃obt@͕ύXł܂"
#: ../diff.c:2102
msgid "E100: No other buffer in diff mode"
@@ -349,7 +349,7 @@ msgstr " s(S)⊮ (^L^N^P)"
#: ../edit.c:86
msgid " File name completion (^F^N^P)"
-msgstr "t@C⊮ (^F^N^P)"
+msgstr " t@C⊮ (^F^N^P)"
#: ../edit.c:87
msgid " Tag completion (^]^N^P)"
@@ -377,7 +377,7 @@ msgstr " R}hC⊮ (^V^N^P)"
#: ../edit.c:94
msgid " User defined completion (^U^N^P)"
-msgstr " [U`⊮ (^U^N^P)"
+msgstr " [U[`⊮ (^U^N^P)"
#: ../edit.c:95
msgid " Omni completion (^O^N^P)"
@@ -679,6 +679,10 @@ msgstr "E696: Xg^ɃJ}܂: %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: Xg^̍Ō ']' ܂: %s"
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"K[xbWRNV𒆎~܂! QƂ쐬̂Ƀs܂"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -721,7 +725,7 @@ msgstr "E117: m̊֐ł: %s"
#: ../eval.c:7383
#, c-format
msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: ֐̈ȉ߂܂: %s"
+msgstr "E119: ֐̈܂: %s"
#: ../eval.c:7387
#, c-format
@@ -826,18 +830,16 @@ msgid "sort() argument"
msgstr "sort() ̈"
#: ../eval.c:13721
-#, fuzzy
msgid "uniq() argument"
-msgstr "add() ̈"
+msgstr "uniq() ̈"
#: ../eval.c:13776
msgid "E702: Sort compare function failed"
msgstr "E702: \\[g̔r֐s܂"
#: ../eval.c:13806
-#, fuzzy
msgid "E882: Uniq compare function failed"
-msgstr "E702: \\[g̔r֐s܂"
+msgstr "E882: Uniq ̔r֐s܂"
#: ../eval.c:14085
msgid "(Invalid)"
@@ -863,6 +865,18 @@ msgstr "E745: Xg^𐔒lƂĈĂ܂"
msgid "E728: Using a Dictionary as a Number"
msgstr "E728: ^𐔒lƂĈĂ܂"
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: ֐Qƌ^𕂓_ƂĈĂ܂B"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: 𕂓_ƂĈĂ܂"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Xg^𕂓_ƂĈĂ܂"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: ^𕂓_ƂĈĂ܂"
+
#: ../eval.c:16259
msgid "E729: using Funcref as a String"
msgstr "E729: ֐Qƌ^𕶎ƂĈĂ܂"
@@ -961,14 +975,14 @@ msgid "E129: Function name required"
msgstr "E129: ֐v܂"
#: ../eval.c:17824
-#, fuzzy, c-format
+#, c-format
msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: ֐͑啶Ŏn܂邩R܂܂Ȃ΂Ȃ܂: %s"
+msgstr "E128: ֐͑啶 \"s:\" Ŏn܂Ȃ΂Ȃ܂: %s"
#: ../eval.c:17833
-#, fuzzy, c-format
+#, c-format
msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E128: ֐͑啶Ŏn܂邩R܂܂Ȃ΂Ȃ܂: %s"
+msgstr "E884: ֐ɂ̓R͊܂߂܂: %s"
#: ../eval.c:18336
#, c-format
@@ -1081,7 +1095,7 @@ msgstr "E136: viminfo: G[߂̂, ȍ~̓XLbv܂"
#: ../ex_cmds.c:1458
#, c-format
msgid "Reading viminfo file \"%s\"%s%s%s"
-msgstr "viminfot@C \"%s\"%s%s%s Ǎݒ "
+msgstr "viminfot@C \"%s\"%s%s%s Ǎݒ"
#: ../ex_cmds.c:1460
msgid " info"
@@ -1357,6 +1371,10 @@ msgstr "E158: ȃobt@ł: %s"
msgid "E157: Invalid sign ID: %<PRId64>"
msgstr "E157: signʎqł: %<PRId64>"
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: ύXłȂ sign ł: %s"
+
#: ../ex_cmds.c:6066
msgid " (not supported)"
msgstr " (T|[g)"
@@ -1379,6 +1397,13 @@ msgstr "s %<PRId64>: %s"
msgid "cmd: %s"
msgstr "R}h: %s"
+msgid "frame is zero"
+msgstr "t[ 0 ł"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ōx̃t[: %d"
+
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
@@ -1528,7 +1553,8 @@ msgstr "E197: \"%s\" ɐݒł܂"
#. don't wait for return
#: ../ex_docmd.c:387
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
-msgstr "Ex[hɓ܂. m[}ɖ߂ɂ\"visual\"Ɠ͂Ă."
+msgstr ""
+"Ex[hɓ܂. m[}[hɖ߂ɂ\"visual\"Ɠ͂Ă."
#: ../ex_docmd.c:428
msgid "E501: At end-of-file"
@@ -1553,7 +1579,7 @@ msgstr "֐̍Ōł"
#: ../ex_docmd.c:1628
msgid "E464: Ambiguous use of user-defined command"
-msgstr "E464: [U`R}ĥ܂Ȏgpł"
+msgstr "E464: [U[`R}ĥ܂Ȏgpł"
#: ../ex_docmd.c:1638
msgid "E492: Not an editor command"
@@ -1606,14 +1632,14 @@ msgstr "E174: R}hɂ܂: Ē`ɂ ! ljĂ"
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" O ͈ ⊮ `"
+" O AhX ⊮ `"
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
-msgstr "[U`R}h‚܂ł"
+msgstr "[U[`R}h‚܂ł"
#: ../ex_docmd.c:4538
msgid "E175: No attribute specified"
@@ -1633,7 +1659,10 @@ msgstr "E178: JEg̏ȗlł"
#: ../ex_docmd.c:4625
msgid "E179: argument required for -complete"
-msgstr "E179: -⊮̂߂̈Kvł"
+msgstr "E179: -complete ɂ͈Kvł"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr ɂ͈Kvł"
#: ../ex_docmd.c:4635
#, c-format
@@ -1646,16 +1675,20 @@ msgstr "E182: ȃR}hł"
#: ../ex_docmd.c:4691
msgid "E183: User defined commands must start with an uppercase letter"
-msgstr "E183: [U`R}h͉p啶Ŏn܂Ȃ΂Ȃ܂"
+msgstr "E183: [U[`R}h͉p啶Ŏn܂Ȃ΂Ȃ܂"
#: ../ex_docmd.c:4696
msgid "E841: Reserved name, cannot be used for user defined command"
-msgstr "E841: \\񖼂Ȃ̂, [U`R}hɗpł܂"
+msgstr "E841: \\񖼂Ȃ̂, [U[`R}hɗpł܂"
#: ../ex_docmd.c:4751
#, c-format
msgid "E184: No such user-defined command: %s"
-msgstr "E184: ̃[U`R}h͂܂: %s"
+msgstr "E184: ̃[U[`R}h͂܂: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: ȃAhX^Cvlł: %s"
#: ../ex_docmd.c:5219
#, c-format
@@ -2019,11 +2052,11 @@ msgstr "sȃt@C"
#: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578
msgid "is a directory"
-msgstr " ̓fBNgł"
+msgstr "̓fBNgł"
#: ../fileio.c:397
msgid "is not a file"
-msgstr " ̓t@Cł͂܂"
+msgstr "̓t@Cł͂܂"
#: ../fileio.c:508 ../fileio.c:3522
msgid "[New File]"
@@ -2039,7 +2072,7 @@ msgstr "[t@Cߑ]"
#: ../fileio.c:534
msgid "[Permission Denied]"
-msgstr "[F‚܂]"
+msgstr "[܂]"
#: ../fileio.c:653
msgid "E200: *ReadPre autocommands made the file unreadable"
@@ -2210,7 +2243,7 @@ msgstr " ϊG["
#: ../fileio.c:3509
#, c-format
msgid " in line %<PRId64>;"
-msgstr "s %<PRId64>;"
+msgstr " s %<PRId64>;"
#: ../fileio.c:3519
msgid "[Device]"
@@ -2766,9 +2799,8 @@ msgid "E37: No write since last change (add ! to override)"
msgstr "E37: Ō̕ύXۑĂ܂ (! ljŕύXj)"
#: ../globals.h:1055
-#, fuzzy
msgid "E37: No write since last change"
-msgstr "[Ō̕ύXۑĂ܂]\n"
+msgstr "E37: Ō̕ύXۑĂ܂"
#: ../globals.h:1056
msgid "E38: Null argument"
@@ -2810,7 +2842,7 @@ msgstr "E42: G[͂܂"
#: ../globals.h:1067
msgid "E776: No location list"
-msgstr "E776: ꏊXg͂܂"
+msgstr "E776: P[VXg͂܂"
#: ../globals.h:1068
msgid "E43: Damaged match string"
@@ -2931,6 +2963,10 @@ msgstr "E363: p^[ 'maxmempattern' ȏ̃gp܂"
msgid "E749: empty buffer"
msgstr "E749: obt@ł"
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: obt@ %ld ͂܂"
+
#: ../globals.h:1108
msgid "E682: Invalid search pattern or delimiter"
msgstr "E682: p^[؂Lsł"
@@ -3831,7 +3867,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"ꂩ.swpt@C폜Ă\n"
+".swpt@C͍폜Ă\\܂\n"
"\n"
#. use msg() to start the scrolling properly
@@ -3845,7 +3881,7 @@ msgstr " ݂̃fBNg:\n"
#: ../memline.c:1448
msgid " Using specified name:\n"
-msgstr " 閼Ogp:\n"
+msgstr " ȉ̖Ogp:\n"
#: ../memline.c:1450
msgid " In directory "
@@ -3901,7 +3937,7 @@ msgid ""
" user name: "
msgstr ""
"\n"
-" [U: "
+" [U[: "
#: ../memline.c:1568
msgid " host name: "
@@ -4050,12 +4086,12 @@ msgid ""
msgstr ""
"\n"
"(1) ʂ̃vOt@CҏWĂ邩܂.\n"
-" ̏ꍇɂ, ύXۂɍŏII, t@C̈قȂ\n"
-" 2‚̃CX^XłĂ܂ƂɒӂĂ."
+" ̏ꍇɂ, ύXĂ܂1‚̃t@Cɑ΂ĈقȂ2‚\n"
+" CX^XłĂ܂̂, Ȃ悤ɋC‚Ă."
#: ../memline.c:3245
msgid " Quit, or continue with caution.\n"
-msgstr " I邩, ӂȂ瑱Ă.\n"
+msgstr " I邩, ӂȂ瑱Ă.\n"
#: ../memline.c:3246
msgid "(2) An edit session for this file crashed.\n"
@@ -4479,6 +4515,11 @@ msgstr ""
msgid "E574: Unknown register type %d"
msgstr "E574: m̃WX^^ %d ł"
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: p^[ƎWX^ɂ2sȏ܂߂܂"
+
#: ../ops.c:5089
#, c-format
msgid "%<PRId64> Cols; "
@@ -4563,6 +4604,10 @@ msgstr "E522: termcap Ɍ‚܂"
msgid "E539: Illegal character <%s>"
msgstr "E539: sȕł <%s>"
+#, c-format
+msgid "For option %s"
+msgstr "IvV: %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: 'term' ɂ͋󕶎ݒł܂"
@@ -4740,6 +4785,14 @@ msgstr ""
"\n"
"ZLeBReLXgݒł܂ "
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "ZLeBReLXg %s %s ɐݒł܂"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "ZLeBReLXg %s %s 擾ł܂. 폜܂!"
+
#: ../os_unix.c:1558 ../os_unix.c:1647
#, c-format
msgid "dlerror = \"%s\""
@@ -4960,6 +5013,10 @@ msgstr "E554: %s{...} ɕ@G[܂"
msgid "External submatches:\n"
msgstr "O̕Y:\n"
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA K\\) JԂ܂ %s"
+
#: ../regexp.c:7022
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
@@ -4968,7 +5025,9 @@ msgstr ""
"E864: \\%#= ɂ 0, 1 2 ݂̂܂BK\\GW͎I"
"܂B"
-#: ../regexp_nfa.c:239
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "̃p^[ɃobNgbLO RE GWKp܂: "
+
msgid "E865: (NFA) Regexp end encountered prematurely"
msgstr "E865: (NFA) ҂葁K\\̏I[ɓB܂"
@@ -4980,7 +5039,7 @@ msgstr "E866: (NFA K\\) ʒuĂ܂: %c"
#: ../regexp_nfa.c:242
#, c-format
msgid "E877: (NFA regexp) Invalid character class: %<PRId64>"
-msgstr ""
+msgstr "E877: (NFA K\\) ȕNX: %<PRId64>"
#: ../regexp_nfa.c:1261
#, c-format
@@ -5590,14 +5649,14 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries"
msgstr "E765: 'spellfile' ɂ %<PRId64> ‚̃Gg͂܂"
#: ../spell.c:8074
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' removed from %s"
-msgstr "%s Pꂪ폜܂"
+msgstr "P '%.*s' %s 폜܂"
#: ../spell.c:8117
-#, fuzzy, c-format
+#, c-format
msgid "Word '%.*s' added to %s"
-msgstr "%s ɒPꂪlj܂"
+msgstr "P '%.*s' %s ֒lj܂"
#: ../spell.c:8381
msgid "E763: Word characters differ between spell files"
@@ -5673,6 +5732,9 @@ msgstr "̃obt@ɒ`ꂽ\\vf͂܂"
msgid "E390: Illegal argument: %s"
msgstr "E390: sȈł: %s"
+msgid "syntax iskeyword "
+msgstr "V^bNXp iskeyword "
+
#: ../syntax.c:3299
#, c-format
msgid "E391: No such syntax cluster: %s"
@@ -5769,6 +5831,10 @@ msgstr "E847: \\̎荞(include)߂܂"
msgid "E789: Missing ']': %s"
msgstr "E789: ']' ܂: %s"
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' ̌ɗ]ȕ܂: %s]%s"
+
#: ../syntax.c:4531
#, c-format
msgid "E398: Missing '=': %s"
@@ -5874,7 +5940,7 @@ msgstr "E415: \\ʓł: %s"
#: ../syntax.c:6395
#, c-format
msgid "E416: missing equal sign: %s"
-msgstr "E416: ܂: %s"
+msgstr "E416: ܂: %s"
#: ../syntax.c:6418
#, c-format
@@ -6078,9 +6144,8 @@ msgstr "Vim: ͂Ǎݒ̃G[ɂI܂...\n"
#. This happens when the FileChangedRO autocommand changes the
#. * file in a way it becomes shorter.
#: ../undo.c:379
-#, fuzzy
msgid "E881: Line count changed unexpectedly"
-msgstr "E834: \\sJEgς܂"
+msgstr "E881: \\sJEgς܂"
#: ../undo.c:627
#, c-format
@@ -6287,23 +6352,23 @@ msgstr " VXe vimrc: \""
#: ../version.c:672
msgid " user vimrc file: \""
-msgstr " [U vimrc: \""
+msgstr " [U[ vimrc: \""
#: ../version.c:677
msgid " 2nd user vimrc file: \""
-msgstr " 2[U vimrc: \""
+msgstr " 2[U[ vimrc: \""
#: ../version.c:682
msgid " 3rd user vimrc file: \""
-msgstr " 3[U vimrc: \""
+msgstr " 3[U[ vimrc: \""
#: ../version.c:687
msgid " user exrc file: \""
-msgstr " [U exrc: \""
+msgstr " [U[ exrc: \""
#: ../version.c:692
msgid " 2nd user exrc file: \""
-msgstr " 2[U exrc: \""
+msgstr " 2[U[ exrc: \""
#: ../version.c:699
msgid " fall-back for $VIM: \""
@@ -6379,7 +6444,7 @@ msgstr "Vim̊JĂ!"
#: ../version.c:828
msgid "Become a registered Vim user!"
-msgstr "Vim̓o^[UɂȂĂ!"
+msgstr "Vim̓o^[U[ɂȂĂ!"
#: ../version.c:831
msgid "type :help sponsor<Enter> for information "
@@ -6391,7 +6456,7 @@ msgstr "ڍׂȏ :help register<Enter> "
#: ../version.c:834
msgid "menu Help->Sponsor/Register for information "
-msgstr "ڍׂ̓j[ wvX|T[/o^ QƂĉ "
+msgstr "ڍׂ̓j[ wv->X|T[/o^ QƂĉ"
#: ../window.c:119
msgid "Already only one window"
@@ -6429,6 +6494,9 @@ msgstr "E445: ̃EBhEɂ͕ύX܂"
msgid "E446: No file name under cursor"
msgstr "E446: J[\\̉Ƀt@C܂"
+msgid "List or number required"
+msgstr "XglKvł"
+
#~ msgid "E831: bf_key_init() called with empty password"
#~ msgstr "E831: bf_key_init() pX[hŌĂяo܂"
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 151b9d3790..dfd795b0ba 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -571,8 +571,9 @@ restofline:
*regmatch.endp[i] = c;
if (vim_strchr((char_u *)"OPQ", idx) != NULL
- && !os_file_exists(namebuf))
+ && !os_path_exists(namebuf)) {
continue;
+ }
}
if ((i = (int)fmt_ptr->addr[1]) > 0) { /* %n */
if (regmatch.startp[i] == NULL)
@@ -706,11 +707,12 @@ restofline:
} else if (vim_strchr((char_u *)"OPQ", idx) != NULL) {
// global file names
valid = false;
- if (*namebuf == NUL || os_file_exists(namebuf)) {
- if (*namebuf && idx == 'P')
+ if (*namebuf == NUL || os_path_exists(namebuf)) {
+ if (*namebuf && idx == 'P') {
currfile = qf_push_dir(namebuf, &file_stack);
- else if (idx == 'Q')
+ } else if (idx == 'Q') {
currfile = qf_pop_dir(&file_stack);
+ }
*namebuf = NUL;
if (tail && *tail) {
STRMOVE(IObuff, skipwhite(tail));
@@ -1080,7 +1082,7 @@ static int qf_get_fnum(char_u *directory, char_u *fname)
* "leaving directory"-messages we might have missed a
* directory change.
*/
- if (!os_file_exists(ptr)) {
+ if (!os_path_exists(ptr)) {
xfree(ptr);
directory = qf_guess_filepath(fname);
if (directory)
@@ -1232,8 +1234,9 @@ static char_u *qf_guess_filepath(char_u *filename)
xfree(fullname);
fullname = (char_u *)concat_fnames((char *)ds_ptr->dirname, (char *)filename, TRUE);
- if (os_file_exists(fullname))
+ if (os_path_exists(fullname)) {
break;
+ }
ds_ptr = ds_ptr->next;
}
@@ -1576,14 +1579,23 @@ win_found:
* set b_p_ro flag). */
if (!can_abandon(curbuf, forceit)) {
EMSG(_(e_nowrtmsg));
- ok = FALSE;
- } else
+ ok = false;
+ } else {
ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
- ECMD_HIDE + ECMD_SET_HELP,
- oldwin == curwin ? curwin : NULL);
- } else
- ok = buflist_getfile(qf_ptr->qf_fnum,
- (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
+ ECMD_HIDE + ECMD_SET_HELP,
+ oldwin == curwin ? curwin : NULL);
+ }
+ } else {
+ ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
+ GETF_SETMARK | GETF_SWITCH, forceit);
+ if (qi != &ql_info && !win_valid(oldwin)) {
+ EMSG(_("E924: Current window was closed"));
+ ok = false;
+ qi = NULL;
+ qf_ptr = NULL;
+ opened_window = false;
+ }
+ }
}
if (ok == OK) {
@@ -1663,21 +1675,22 @@ win_found:
msg_scroll = (int)i;
}
} else {
- if (opened_window)
- win_close(curwin, TRUE); /* Close opened window */
- if (qf_ptr->qf_fnum != 0) {
- /*
- * Couldn't open file, so put index back where it was. This could
- * happen if the file was readonly and we changed something.
- */
+ if (opened_window) {
+ win_close(curwin, true); // Close opened window
+ }
+ if (qf_ptr != NULL && qf_ptr->qf_fnum != 0) {
+ // Couldn't open file, so put index back where it was. This could
+ // happen if the file was readonly and we changed something.
failed:
qf_ptr = old_qf_ptr;
qf_index = old_qf_index;
}
}
theend:
- qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr;
- qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
+ if (qi != NULL) {
+ qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr;
+ qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
+ }
if (p_swb != old_swb && opened_window) {
/* Restore old 'switchbuf' value, but not when an autocommand or
* modeline has changed the value. */
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
index b3805a3a28..a2cc432eca 100644
--- a/src/nvim/rbuffer.c
+++ b/src/nvim/rbuffer.c
@@ -15,7 +15,7 @@ RBuffer *rbuffer_new(size_t capacity)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
{
if (!capacity) {
- capacity = 0xffff;
+ capacity = 0x10000;
}
RBuffer *rv = xmalloc(sizeof(RBuffer) + capacity);
@@ -153,7 +153,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count)
// Higher level functions for copying from/to RBuffer instances and data
// pointers
-size_t rbuffer_write(RBuffer *buf, char *src, size_t src_size)
+size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size)
FUNC_ATTR_NONNULL_ALL
{
size_t size = src_size;
diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h
index 35fb16508e..454972c69d 100644
--- a/src/nvim/rbuffer.h
+++ b/src/nvim/rbuffer.h
@@ -36,30 +36,36 @@
//
// Note that the rbuffer_{produced,consumed} calls are necessary or these macros
// create infinite loops
-#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \
- for (size_t rcnt = 0, _r = 1; _r; _r = 0) \
- for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \
- buf->size; \
- rptr = rbuffer_read_ptr(buf, &rcnt))
+#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \
+ for (size_t rcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \
+ for ( /* NOLINT(readability/braces) */ \
+ char *rptr = rbuffer_read_ptr(buf, &rcnt); \
+ buf->size; \
+ rptr = rbuffer_read_ptr(buf, &rcnt))
-#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \
- for (size_t wcnt = 0, _r = 1; _r; _r = 0) \
- for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \
- rbuffer_space(buf); \
- wptr = rbuffer_write_ptr(buf, &wcnt))
+#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \
+ for (size_t wcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \
+ for ( /* NOLINT(readability/braces) */ \
+ char *wptr = rbuffer_write_ptr(buf, &wcnt); \
+ rbuffer_space(buf); \
+ wptr = rbuffer_write_ptr(buf, &wcnt))
// Iteration
-#define RBUFFER_EACH(buf, c, i) \
- for (size_t i = 0; i < buf->size; i = buf->size) \
- for (char c = 0; \
- i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
+#define RBUFFER_EACH(buf, c, i) \
+ for (size_t i = 0; /* NOLINT(readability/braces) */ \
+ i < buf->size; \
+ i = buf->size) \
+ for (char c = 0; /* NOLINT(readability/braces) */ \
+ i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
i++)
-#define RBUFFER_EACH_REVERSE(buf, c, i) \
- for (size_t i = buf->size; i != SIZE_MAX; i = SIZE_MAX) \
- for (char c = 0; \
- i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
+#define RBUFFER_EACH_REVERSE(buf, c, i) \
+ for (size_t i = buf->size; /* NOLINT(readability/braces) */ \
+ i != SIZE_MAX; \
+ i = SIZE_MAX) \
+ for (char c = 0; /* NOLINT(readability/braces) */ \
+ i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
)
typedef struct rbuffer RBuffer;
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 7e53b2ccd1..f97dce9e0d 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -357,13 +357,14 @@ static int nfa_ll_index = 0;
# include "regexp_nfa.c.generated.h"
#endif
-/* helper functions used when doing re2post() ... regatom() parsing */
-#define EMIT(c) do { \
- if (post_ptr >= post_end) { \
- realloc_post_list(); \
- } \
- *post_ptr++ = c; \
-} while (0)
+// Helper functions used when doing re2post() ... regatom() parsing
+#define EMIT(c) \
+ do { \
+ if (post_ptr >= post_end) { \
+ realloc_post_list(); \
+ } \
+ *post_ptr++ = c; \
+ } while (0)
/*
* Initialize internal variables before NFA compilation.
@@ -2892,12 +2893,11 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size)
return NULL;
#define PUSH(s) st_push((s), &stackp, stack_end)
-#define POP() st_pop(&stackp, stack); \
- if (stackp < stack) \
- { \
- st_error(postfix, end, p); \
- xfree(stack); \
- return NULL; \
+#define POP() st_pop(&stackp, stack); \
+ if (stackp < stack) { \
+ st_error(postfix, end, p); \
+ xfree(stack); \
+ return NULL; \
}
if (nfa_calc_size == FALSE) {
@@ -4904,10 +4904,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
} else
addstate(thislist, start, m, NULL, 0);
-#define ADD_STATE_IF_MATCH(state) \
- if (result) { \
- add_state = state->out; \
- add_off = clen; \
+#define ADD_STATE_IF_MATCH(state) \
+ if (result) { \
+ add_state = state->out; \
+ add_off = clen; \
}
/*
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 34eef83164..d67142822f 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3416,12 +3416,10 @@ win_line (
/*
* Handling of non-printable characters.
*/
- if (!(chartab[c & 0xff] & CT_PRINT_CHAR)) {
- /*
- * when getting a character from the file, we may have to
- * turn it into something else on the way to putting it
- * into "ScreenLines".
- */
+ if (!vim_isprintc(c)) {
+ // when getting a character from the file, we may have to
+ // turn it into something else on the way to putting it
+ // into "ScreenLines".
if (c == TAB && (!wp->w_p_list || lcs_tab1)) {
int tab_len = 0;
long vcol_adjusted = vcol; // removed showbreak length
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 51c8597d53..b5921eb810 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -5,7 +5,6 @@
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
-#include <fcntl.h>
#include <assert.h>
#include <msgpack.h>
@@ -36,6 +35,7 @@
#include "nvim/version.h"
#include "nvim/path.h"
#include "nvim/fileio.h"
+#include "nvim/os/fileio.h"
#include "nvim/strings.h"
#include "nvim/quickfix.h"
#include "nvim/eval/encode.h"
@@ -409,7 +409,7 @@ typedef struct sd_read_def {
ShaDaFileSkipper skip; ///< Function used to skip some bytes.
void *cookie; ///< Data describing object read from.
bool eof; ///< True if reader reached end of file.
- char *error; ///< Error message in case of error.
+ const char *error; ///< Error message in case of error.
uintmax_t fpos; ///< Current position (amount of bytes read since
///< reader structure initialization). May overflow.
vimconv_T sd_conv; ///< Structure used for converting encodings of some
@@ -433,7 +433,7 @@ typedef struct sd_write_def {
ShaDaFileWriter write; ///< Writer function.
ShaDaWriteCloser close; ///< Close function.
void *cookie; ///< Data describing object written to.
- char *error; ///< Error message in case of error.
+ const char *error; ///< Error message in case of error.
vimconv_T sd_conv; ///< Structure used for converting encodings of some
///< items.
} ShaDaWriteDef;
@@ -666,38 +666,14 @@ static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest,
const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- size_t read_bytes = 0;
- bool did_try_to_free = false;
- const int fd = (int)(intptr_t) sd_reader->cookie;
- while (read_bytes != size) {
- const ptrdiff_t cur_read_bytes = read(fd, ((char *) dest) + read_bytes,
- size - read_bytes);
- if (cur_read_bytes > 0) {
- read_bytes += (size_t) cur_read_bytes;
- sd_reader->fpos += (uintmax_t) cur_read_bytes;
- assert(read_bytes <= size);
- }
- if (cur_read_bytes < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- errno = 0;
- continue;
- } else if (errno == ENOMEM && !did_try_to_free) {
- try_to_free_memory();
- did_try_to_free = true;
- errno = 0;
- continue;
- } else {
- sd_reader->error = strerror(errno);
- errno = 0;
- return -1;
- }
- }
- if (cur_read_bytes == 0) {
- sd_reader->eof = true;
- break;
- }
+ const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size);
+ sd_reader->eof = file_eof(sd_reader->cookie);
+ if (ret < 0) {
+ sd_reader->error = os_strerror((int)ret);
+ return -1;
}
- return (ptrdiff_t) read_bytes;
+ sd_reader->fpos += (size_t)ret;
+ return ret;
}
/// Read one character
@@ -720,50 +696,26 @@ static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer,
const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- size_t written_bytes = 0;
- const int fd = (int)(intptr_t) sd_writer->cookie;
- while (written_bytes != size) {
- const ptrdiff_t cur_written_bytes = write(fd, (char *) dest + written_bytes,
- size - written_bytes);
- if (cur_written_bytes > 0) {
- written_bytes += (size_t) cur_written_bytes;
- }
- if (cur_written_bytes < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- errno = 0;
- continue;
- } else {
- sd_writer->error = strerror(errno);
- errno = 0;
- return -1;
- }
- }
- if (cur_written_bytes == 0) {
- sd_writer->error = "Zero bytes written.";
- return -1;
- }
+ const ptrdiff_t ret = file_write(sd_writer->cookie, dest, size);
+ if (ret < 0) {
+ sd_writer->error = os_strerror((int)ret);
+ return -1;
}
- return (ptrdiff_t) written_bytes;
+ return ret;
}
/// Wrapper for closing file descriptors opened for reading
static void close_sd_reader(ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ALL
{
- close_file((int)(intptr_t) sd_reader->cookie);
+ close_file(sd_reader->cookie);
}
/// Wrapper for closing file descriptors opened for writing
static void close_sd_writer(ShaDaWriteDef *const sd_writer)
FUNC_ATTR_NONNULL_ALL
{
- const int fd = (int)(intptr_t) sd_writer->cookie;
- if (os_fsync(fd) < 0) {
- emsgf(_(SERR "System error while synchronizing ShaDa file: %s"),
- os_strerror(errno));
- errno = 0;
- }
- close_file(fd);
+ close_file(sd_writer->cookie);
}
/// Wrapper for read that reads to IObuff and ignores bytes read
@@ -779,19 +731,20 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
const size_t offset)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- size_t read_bytes = 0;
- do {
- ptrdiff_t new_read_bytes = sd_reader->read(
- sd_reader, IObuff, (size_t) (offset - read_bytes > IOSIZE
- ? IOSIZE
- : offset - read_bytes));
- if (new_read_bytes == -1) {
- return FAIL;
+ const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset);
+ if (skip_bytes < 0) {
+ sd_reader->error = os_strerror((int)skip_bytes);
+ return FAIL;
+ } else if (skip_bytes != (ptrdiff_t)offset) {
+ assert(skip_bytes < (ptrdiff_t)offset);
+ sd_reader->eof = file_eof(sd_reader->cookie);
+ if (!sd_reader->eof) {
+ sd_reader->error = _("too few bytes read");
}
- read_bytes += (size_t) new_read_bytes;
- } while (read_bytes < offset && !sd_reader->eof);
-
- return (read_bytes == offset ? OK : FAIL);
+ return FAIL;
+ }
+ sd_reader->fpos += (size_t)skip_bytes;
+ return OK;
}
/// Wrapper for read that can be used when lseek cannot be used
@@ -824,37 +777,6 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
return kSDReadStatusSuccess;
}
-/// Wrapper for opening file descriptors
-///
-/// All arguments are passed to os_open().
-///
-/// @return file descriptor or libuv error on failure.
-static int open_file(const char *const fname, const int flags, const int mode)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
-{
- bool did_try_to_free = false;
- int fd;
-open_file_start:
- fd = os_open(fname, flags, mode);
-
- if (fd < 0) {
- if (fd == UV_ENOENT) {
- return fd;
- }
- if (fd == UV_ENOMEM && !did_try_to_free) {
- try_to_free_memory();
- did_try_to_free = true;
- goto open_file_start;
- }
- if (fd != UV_EEXIST) {
- emsgf(_(SERR "System error while opening ShaDa file %s: %s"),
- fname, os_strerror(fd));
- }
- return fd;
- }
- return fd;
-}
-
/// Open ShaDa file for reading
///
/// @param[in] fname File name to open.
@@ -865,11 +787,7 @@ static int open_shada_file_for_reading(const char *const fname,
ShaDaReadDef *sd_reader)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- const intptr_t fd = (intptr_t) open_file(fname, O_RDONLY, 0);
-
- if (fd < 0) {
- return (int) fd;
- }
+ int error;
*sd_reader = (ShaDaReadDef) {
.read = &read_file,
@@ -878,8 +796,11 @@ static int open_shada_file_for_reading(const char *const fname,
.error = NULL,
.eof = false,
.fpos = 0,
- .cookie = (void *) fd,
+ .cookie = file_open_new(&error, fname, kFileReadOnly, 0),
};
+ if (sd_reader->cookie == NULL) {
+ return error;
+ }
convert_setup(&sd_reader->sd_conv, "utf-8", p_enc);
@@ -887,18 +808,12 @@ static int open_shada_file_for_reading(const char *const fname,
}
/// Wrapper for closing file descriptors
-static void close_file(int fd)
+static void close_file(void *cookie)
{
-close_file_start:
- if (close(fd) == -1) {
- if (errno == EINTR) {
- errno = 0;
- goto close_file_start;
- } else {
- emsgf(_(SERR "System error while closing ShaDa file: %s"),
- strerror(errno));
- errno = 0;
- }
+ const int error = file_free(cookie);
+ if (error != 0) {
+ emsgf(_(SERR "System error while closing ShaDa file: %s"),
+ os_strerror(error));
}
}
@@ -978,7 +893,7 @@ static int shada_read_file(const char *const file, const int flags)
}
if (of_ret != 0) {
- if (of_ret == UV_ENOENT && (flags & kShaDaMissingError)) {
+ if (of_ret != UV_ENOENT || (flags & kShaDaMissingError)) {
emsgf(_(SERR "System error while opening ShaDa file %s for reading: %s"),
fname, os_strerror(of_ret));
}
@@ -1421,8 +1336,8 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
}
if (!op_register_set(cur_entry.data.reg.name, (yankreg_T) {
- .y_array = (char_u **) cur_entry.data.reg.contents,
- .y_size = (linenr_T) cur_entry.data.reg.contents_size,
+ .y_array = (char_u **)cur_entry.data.reg.contents,
+ .y_size = cur_entry.data.reg.contents_size,
.y_type = cur_entry.data.reg.type,
.y_width = (colnr_T) cur_entry.data.reg.width,
.timestamp = cur_entry.timestamp,
@@ -2745,7 +2660,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (name == NUL) {
break;
}
- if (limit_reg_lines && reg.y_size > max_reg_lines) {
+ if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) {
continue;
}
wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) {
@@ -2968,17 +2883,23 @@ int shada_write_file(const char *const file, bool nomerge)
char *const fname = shada_filename(file);
char *tempname = NULL;
- ShaDaWriteDef sd_writer = (ShaDaWriteDef) {
+ ShaDaWriteDef sd_writer = {
.write = &write_file,
.close = &close_sd_writer,
.error = NULL,
};
- ShaDaReadDef sd_reader;
-
- intptr_t fd;
+ ShaDaReadDef sd_reader = { .close = NULL };
if (!nomerge) {
- if (open_shada_file_for_reading(fname, &sd_reader) != 0) {
+ int error;
+ if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) {
+ if (error != UV_ENOENT) {
+ emsgf(_(SERR "System error while opening ShaDa file %s for reading "
+ "to merge before writing it: %s"),
+ fname, os_strerror(error));
+ // Try writing the file even if opening it emerged any issues besides
+ // file not existing: maybe writing will succeed nevertheless.
+ }
nomerge = true;
goto shada_write_file_nomerge;
}
@@ -2996,15 +2917,11 @@ int shada_write_file(const char *const file, bool nomerge)
// 2: Make sure that user can always read and write the result.
// 3: If somebody happened to delete the file after it was opened for
// reading use u=rw permissions.
-shada_write_file_open:
- fd = (intptr_t) open_file(tempname, O_CREAT|O_WRONLY|O_NOFOLLOW|O_EXCL,
- perm);
- if (fd < 0) {
- if (fd == UV_EEXIST
-#ifdef ELOOP
- || fd == UV_ELOOP
-#endif
- ) {
+shada_write_file_open: {}
+ sd_writer.cookie = file_open_new(
+ &error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
+ if (sd_writer.cookie == NULL) {
+ if (error == UV_EEXIST || error == UV_ELOOP) {
// File already exists, try another name
char *const wp = tempname + strlen(tempname) - 1;
if (*wp == 'z') {
@@ -3014,11 +2931,16 @@ shada_write_file_open:
fname);
xfree(fname);
xfree(tempname);
+ assert(sd_reader.close != NULL);
+ sd_reader.close(&sd_reader);
return FAIL;
} else {
(*wp)++;
goto shada_write_file_open;
}
+ } else {
+ emsgf(_(SERR "System error while opening temporary ShaDa file %s "
+ "for writing: %s"), tempname, os_strerror(error));
}
}
}
@@ -3042,23 +2964,29 @@ shada_write_file_nomerge: {}
}
*tail = tail_save;
}
- fd = (intptr_t) open_file(fname, O_CREAT|O_WRONLY|O_TRUNC,
- 0600);
- }
-
- if (p_verbose > 0) {
- verbose_enter();
- smsg(_("Writing ShaDa file \"%s\""), fname);
- verbose_leave();
+ int error;
+ sd_writer.cookie = file_open_new(&error, fname, kFileCreate|kFileTruncate,
+ 0600);
+ if (sd_writer.cookie == NULL) {
+ emsgf(_(SERR "System error while opening ShaDa file %s for writing: %s"),
+ fname, os_strerror(error));
+ }
}
- if (fd < 0) {
+ if (sd_writer.cookie == NULL) {
xfree(fname);
xfree(tempname);
+ if (sd_reader.close != NULL) {
+ sd_reader.close(&sd_reader);
+ }
return FAIL;
}
- sd_writer.cookie = (void *) fd;
+ if (p_verbose > 0) {
+ verbose_enter();
+ smsg(_("Writing ShaDa file \"%s\""), fname);
+ verbose_leave();
+ }
convert_setup(&sd_writer.sd_conv, p_enc, "utf-8");
@@ -3066,15 +2994,11 @@ shada_write_file_nomerge: {}
? NULL
: &sd_reader));
assert(sw_ret != kSDWriteIgnError);
-#ifndef UNIX
- sd_writer.close(&sd_writer);
-#endif
if (!nomerge) {
sd_reader.close(&sd_reader);
bool did_remove = false;
if (sw_ret == kSDWriteSuccessfull) {
#ifdef UNIX
- bool closed = false;
// For Unix we check the owner of the file. It's not very nice to
// overwrite a user’s viminfo file after a "su root", with a
// viminfo file that the user can't read.
@@ -3083,16 +3007,15 @@ shada_write_file_nomerge: {}
if (getuid() == ROOT_UID) {
if (old_info.stat.st_uid != ROOT_UID
|| old_info.stat.st_gid != getgid()) {
- const uv_uid_t old_uid = (uv_uid_t) old_info.stat.st_uid;
- const uv_gid_t old_gid = (uv_gid_t) old_info.stat.st_gid;
- const int fchown_ret = os_fchown((int) fd, old_uid, old_gid);
- sd_writer.close(&sd_writer);
+ const uv_uid_t old_uid = (uv_uid_t)old_info.stat.st_uid;
+ const uv_gid_t old_gid = (uv_gid_t)old_info.stat.st_gid;
+ const int fchown_ret = os_fchown(file_fd(sd_writer.cookie),
+ old_uid, old_gid);
if (fchown_ret != 0) {
EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"),
tempname, os_strerror(fchown_ret));
goto shada_write_file_did_not_remove;
}
- closed = true;
}
} else if (!(old_info.stat.st_uid == getuid()
? (old_info.stat.st_mode & 0200)
@@ -3100,13 +3023,9 @@ shada_write_file_nomerge: {}
? (old_info.stat.st_mode & 0020)
: (old_info.stat.st_mode & 0002)))) {
EMSG2(_("E137: ShaDa file is not writable: %s"), fname);
- sd_writer.close(&sd_writer);
goto shada_write_file_did_not_remove;
}
}
- if (!closed) {
- sd_writer.close(&sd_writer);
- }
#endif
if (vim_rename(tempname, fname) == -1) {
EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"),
@@ -3133,6 +3052,7 @@ shada_write_file_did_not_remove:
}
xfree(tempname);
}
+ sd_writer.close(&sd_writer);
xfree(fname);
return OK;
@@ -3262,20 +3182,20 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length);
- (void) read_bytes;
- if (sd_reader->error != NULL) {
- emsgf(_(SERR "System error while reading ShaDa file: %s"),
- sd_reader->error);
- return kSDReadStatusReadError;
- } else if (sd_reader->eof) {
- emsgf(_(RCERR "Error while reading ShaDa file: "
- "last entry specified that it occupies %" PRIu64 " bytes, "
- "but file ended earlier"),
- (uint64_t) length);
- return kSDReadStatusNotShaDa;
+ if (read_bytes != (ptrdiff_t)length) {
+ if (sd_reader->error != NULL) {
+ emsgf(_(SERR "System error while reading ShaDa file: %s"),
+ sd_reader->error);
+ return kSDReadStatusReadError;
+ } else {
+ emsgf(_(RCERR "Error while reading ShaDa file: "
+ "last entry specified that it occupies %" PRIu64 " bytes, "
+ "but file ended earlier"),
+ (uint64_t)length);
+ return kSDReadStatusNotShaDa;
+ }
}
- assert(read_bytes >= 0 && (size_t) read_bytes == length);
return kSDReadStatusSuccess;
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 0acaa9ae2b..610fb660e7 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -45,6 +45,9 @@
// Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word.
// Only use it for small word lists!
+// Use SPELL_COMPRESS_ALLWAYS for debugging: compress the word tree after
+// adding a word. Only use it for small word lists!
+
// Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a
// specific word.
@@ -156,6 +159,8 @@
//
// sectionID == SN_NOSPLITSUGS: nothing
//
+// sectionID == SN_NOCOMPOUNDSUGS: nothing
+//
// sectionID == SN_WORDS: <word> ...
// <word> N bytes NUL terminated common word
//
@@ -482,7 +487,7 @@ struct slang_S {
regprog_T **sl_prefprog; // table with regprogs for prefixes
garray_T sl_rep; // list of fromto_T entries from REP lines
- short sl_rep_first[256]; // indexes where byte first appears, -1 if
+ int16_t sl_rep_first[256]; // indexes where byte first appears, -1 if
// there is none
garray_T sl_sal; // list of salitem_T entries from SAL lines
salfirst_T sl_sal_first[256]; // indexes where byte first appears, -1 if
@@ -494,8 +499,9 @@ struct slang_S {
// "sl_sal_first" maps chars, when has_mbyte
// "sl_sal" is a list of wide char lists.
garray_T sl_repsal; // list of fromto_T entries from REPSAL lines
- short sl_repsal_first[256]; // sl_rep_first for REPSAL lines
- bool sl_nosplitsugs; // don't suggest splitting a word
+ int16_t sl_repsal_first[256]; // sl_rep_first for REPSAL lines
+ bool sl_nosplitsugs; // don't suggest splitting a word
+ bool sl_nocompoundsugs; // don't suggest compounding
// Info from the .sug file. Loaded on demand.
time_t sl_sugtime; // timestamp for .sug file
@@ -558,6 +564,7 @@ typedef struct langp_S {
#define SN_WORDS 13 // common words
#define SN_NOSPLITSUGS 14 // don't split word for suggestions
#define SN_INFO 15 // info section
+#define SN_NOCOMPOUNDSUGS 16 // don't compound for suggestions
#define SN_END 255 // end of sections
#define SNF_REQUIRED 1 // <sectionflags>: required section
@@ -948,6 +955,7 @@ typedef struct spellinfo_S {
char_u *si_sofoto; // SOFOTO text
int si_nosugfile; // NOSUGFILE item found
int si_nosplitsugs; // NOSPLITSUGS item found
+ int si_nocompoundsugs; // NOCOMPOUNDSUGS item found
int si_followup; // soundsalike: ?
int si_collapse; // soundsalike: ?
hashtab_T si_commonwords; // hashtable for common words
@@ -2309,16 +2317,14 @@ static void spell_load_lang(char_u *lang)
for (round = 1; round <= 2; ++round) {
// Find the first spell file for "lang" in 'runtimepath' and load it.
vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
- "spell/%s.%s.spl",
- lang, spell_enc());
- r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl);
+ "spell/%s.%s.spl", lang, spell_enc());
+ r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
if (r == FAIL && *sl.sl_lang != NUL) {
// Try loading the ASCII version.
vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
- "spell/%s.ascii.spl",
- lang);
- r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl);
+ "spell/%s.ascii.spl", lang);
+ r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
if (r == FAIL && *sl.sl_lang != NUL && round == 1
&& apply_autocmds(EVENT_SPELLFILEMISSING, lang,
@@ -2346,7 +2352,7 @@ static void spell_load_lang(char_u *lang)
} else if (sl.sl_slang != NULL) {
// At least one file was loaded, now load ALL the additions.
STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl");
- do_in_runtimepath(fname_enc, TRUE, spell_load_cb, &sl);
+ do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl);
}
}
@@ -2666,7 +2672,11 @@ spell_load_file (
break;
case SN_NOSPLITSUGS:
- lp->sl_nosplitsugs = true; // <timestamp>
+ lp->sl_nosplitsugs = true;
+ break;
+
+ case SN_NOCOMPOUNDSUGS:
+ lp->sl_nocompoundsugs = true;
break;
case SN_COMPOUND:
@@ -2868,7 +2878,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
// Read REP or REPSAL items section from "fd": <repcount> <rep> ...
// Return SP_*ERROR flags.
-static int read_rep_section(FILE *fd, garray_T *gap, short *first)
+static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
{
int cnt;
fromto_T *ftp;
@@ -4266,9 +4276,9 @@ static void spell_print_node(wordnode_T *node, int depth)
PRINTSOME(line1, depth, "(%d)", node->wn_nr, 0);
PRINTSOME(line2, depth, " ", 0, 0);
PRINTSOME(line3, depth, " ", 0, 0);
- msg(line1);
- msg(line2);
- msg(line3);
+ msg((char_u *)line1);
+ msg((char_u *)line2);
+ msg((char_u *)line3);
} else {
node->wn_u1.index = TRUE;
@@ -4289,9 +4299,9 @@ static void spell_print_node(wordnode_T *node, int depth)
PRINTSOME(line3, depth, " ", 0, 0);
if (node->wn_byte == NUL) {
- msg(line1);
- msg(line2);
- msg(line3);
+ msg((char_u *)line1);
+ msg((char_u *)line2);
+ msg((char_u *)line3);
}
// do the children
@@ -4633,6 +4643,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
spin->si_nobreak = true;
} else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) {
spin->si_nosplitsugs = true;
+ } else if (is_aff_rule(items, itemcnt, "NOCOMPOUNDSUGS", 1)) {
+ spin->si_nocompoundsugs = true;
} else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) {
spin->si_nosugfile = true;
} else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) {
@@ -6289,7 +6301,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
node = *prev;
}
#ifdef SPELL_PRINTTREE
- smsg("Added \"%s\"", word);
+ smsg((char_u *)"Added \"%s\"", word);
spell_print_tree(root->wn_sibling);
#endif
@@ -6312,8 +6324,8 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
// 3. When compressed before, added "compress_added" words
// (si_compress_cnt == 1) and the number of free nodes drops below the
// maximum word length.
-#ifndef SPELL_PRINTTREE
- if (spin->si_compress_cnt == 1
+#ifndef SPELL_COMPRESS_ALLWAYS
+ if (spin->si_compress_cnt == 1 // NOLINT(readability/braces)
? spin->si_free_count < MAXWLEN
: spin->si_blocks_cnt >= compress_start)
#endif
@@ -6857,6 +6869,15 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
put_bytes(fd, 0, 4); // <sectionlen>
}
+ // SN_NOCOMPUNDSUGS: nothing
+ // This is used to notify that no suggestions with compounds are to be
+ // made.
+ if (spin->si_nocompoundsugs) {
+ putc(SN_NOCOMPOUNDSUGS, fd); // <sectionID>
+ putc(0, fd); // <sectionflags>
+ put_bytes(fd, 0, 4); // <sectionlen>
+ }
+
// SN_COMPOUND: compound info.
// We don't mark it required, when not supported all compound words will
// be bad words.
@@ -7607,7 +7628,7 @@ mkspell (
else {
// Check for overwriting before doing things that may take a lot of
// time.
- if (!over_write && os_file_exists(wfname)) {
+ if (!over_write && os_path_exists(wfname)) {
EMSG(_(e_exists));
goto theend;
}
@@ -7663,7 +7684,7 @@ mkspell (
spin.si_region = 1 << i;
vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[i]);
- if (os_file_exists(fname)) {
+ if (os_path_exists(fname)) {
// Read the .aff file. Will init "spin->si_conv" based on the
// "SET" line.
afile[i] = spell_read_aff(&spin, fname);
@@ -9296,7 +9317,56 @@ static void suggest_try_special(suginfo_T *su)
}
}
+// Measure how much time is spent in each state.
+// Output is dumped in "suggestprof".
+
+#ifdef SUGGEST_PROFILE
+proftime_T current;
+proftime_T total;
+proftime_T times[STATE_FINAL + 1];
+long counts[STATE_FINAL + 1];
+
+ static void
+prof_init(void)
+{
+ for (int i = 0; i <= STATE_FINAL; i++) {
+ profile_zero(&times[i]);
+ counts[i] = 0;
+ }
+ profile_start(&current);
+ profile_start(&total);
+}
+
+// call before changing state
+ static void
+prof_store(state_T state)
+{
+ profile_end(&current);
+ profile_add(&times[state], &current);
+ counts[state]++;
+ profile_start(&current);
+}
+# define PROF_STORE(state) prof_store(state);
+
+ static void
+prof_report(char *name)
+{
+ FILE *fd = fopen("suggestprof", "a");
+
+ profile_end(&total);
+ fprintf(fd, "-----------------------\n");
+ fprintf(fd, "%s: %s\n", name, profile_msg(&total));
+ for (int i = 0; i <= STATE_FINAL; i++) {
+ fprintf(fd, "%d: %s ("%" PRId64)\n", i, profile_msg(&times[i]), counts[i]);
+ }
+ fclose(fd);
+}
+#else
+# define PROF_STORE(state)
+#endif
+
// Try finding suggestions by adding/removing/swapping letters.
+
static void suggest_try_change(suginfo_T *su)
{
char_u fword[MAXWLEN]; // copy of the bad word, case-folded
@@ -9321,7 +9391,14 @@ static void suggest_try_change(suginfo_T *su)
continue;
// Try it for this language. Will add possible suggestions.
+ //
+#ifdef SUGGEST_PROFILE
+ prof_init();
+#endif
suggest_trie_walk(su, lp, fword, false);
+#ifdef SUGGEST_PROFILE
+ prof_report("try_change");
+#endif
}
}
@@ -9455,6 +9532,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Always past NUL bytes now.
n = (int)sp->ts_state;
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_ENDNUL;
sp->ts_save_badflags = su->su_badflags;
@@ -9494,6 +9572,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_curi > len || byts[arridx] != 0) {
// Past bytes in node and/or past NUL bytes.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_ENDNUL;
sp->ts_save_badflags = su->su_badflags;
break;
@@ -9771,6 +9850,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// be possible to compound another (short) word.
try_compound = false;
if (!soundfold
+ && !slang->sl_nocompoundsugs
&& slang->sl_compprog != NULL
&& ((unsigned)flags >> 24) != 0
&& sp->ts_twordlen - sp->ts_splitoff
@@ -9791,21 +9871,21 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// For NOBREAK we never try splitting, it won't make any word
// valid.
- if (slang->sl_nobreak)
+ if (slang->sl_nobreak && !slang->sl_nocompoundsugs) {
try_compound = true;
-
- // If we could add a compound word, and it's also possible to
- // split at this point, do the split first and set
- // TSF_DIDSPLIT to avoid doing it again.
- else if (!fword_ends
- && try_compound
- && (sp->ts_flags & TSF_DIDSPLIT) == 0) {
+ } else if (!fword_ends
+ && try_compound
+ && (sp->ts_flags & TSF_DIDSPLIT) == 0) {
+ // If we could add a compound word, and it's also possible to
+ // split at this point, do the split first and set
+ // TSF_DIDSPLIT to avoid doing it again.
try_compound = false;
sp->ts_flags |= TSF_DIDSPLIT;
--sp->ts_curi; // do the same NUL again
compflags[sp->ts_complen] = NUL;
- } else
+ } else {
sp->ts_flags &= ~TSF_DIDSPLIT;
+ }
if (try_split || try_compound) {
if (!try_compound && (!fword_ends || !goodword_ends)) {
@@ -9846,6 +9926,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#endif
// Save things to be restored at STATE_SPLITUNDO.
sp->ts_save_badflags = su->su_badflags;
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SPLITUNDO;
++depth;
@@ -9912,6 +9993,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
byts = pbyts;
idxs = pidxs;
sp->ts_prefixdepth = PFD_PREFIXTREE;
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_NOPREFIX;
}
}
@@ -9924,6 +10006,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
su->su_badflags = sp->ts_save_badflags;
// Continue looking for NUL bytes.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_START;
// In case we went into the prefix tree.
@@ -9938,9 +10021,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
&& sp->ts_tcharlen == 0
) {
// The badword ends, can't use STATE_PLAIN.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_DEL;
break;
}
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_PLAIN;
// FALLTHROUGH
@@ -9951,10 +10036,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_curi > byts[arridx]) {
// Done all bytes at this node, do next state. When still at
// already changed bytes skip the other tricks.
- if (sp->ts_fidx >= sp->ts_fidxtry)
+ PROF_STORE(sp->ts_state)
+ if (sp->ts_fidx >= sp->ts_fidxtry) {
sp->ts_state = STATE_DEL;
- else
+ } else {
sp->ts_state = STATE_FINAL;
+ }
} else {
arridx += sp->ts_curi++;
c = byts[arridx];
@@ -10086,10 +10173,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// When past the first byte of a multi-byte char don't try
// delete/insert/swap a character.
if (has_mbyte && sp->ts_tcharlen > 0) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
break;
}
// Try skipping one character in the bad word (delete it).
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_INS_PREP;
sp->ts_curi = 1;
if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
@@ -10137,6 +10226,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_flags & TSF_DIDDEL) {
// If we just deleted a byte then inserting won't make sense,
// a substitute is always cheaper.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SWAP;
break;
}
@@ -10146,11 +10236,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
for (;; ) {
if (sp->ts_curi > byts[n]) {
// Only NUL bytes at this node, go to next state.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SWAP;
break;
}
if (byts[n + sp->ts_curi] != NUL) {
// Found a byte to insert.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_INS;
break;
}
@@ -10166,6 +10258,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
n = sp->ts_arridx;
if (sp->ts_curi > byts[n]) {
// Done all bytes at this node, go to next state.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SWAP;
break;
}
@@ -10226,6 +10319,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
c = *p;
if (c == NUL) {
// End of word, can't swap or replace.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
break;
}
@@ -10233,6 +10327,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Don't swap if the first character is not a word character.
// SWAP3 etc. also don't make sense then.
if (!soundfold && !spell_iswordp(p, curwin)) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
break;
}
@@ -10257,6 +10352,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// When the second character is NUL we can't swap.
if (c2 == NUL) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
break;
}
@@ -10264,6 +10360,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// When characters are identical, swap won't do anything.
// Also get here if the second char is not a word character.
if (c == c2) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SWAP3;
break;
}
@@ -10274,6 +10371,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_twordlen, tword, fword + sp->ts_fidx,
c, c2);
#endif
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNSWAP;
++depth;
if (has_mbyte) {
@@ -10288,6 +10386,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
}
} else
// If this swap doesn't work then SWAP3 won't either.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
break;
@@ -10335,6 +10434,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Also get here when the third character is not a word character.
// Second character may any char: "a.b" -> "b.a"
if (c == c3 || c3 == NUL) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
break;
}
@@ -10345,6 +10445,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_twordlen, tword, fword + sp->ts_fidx,
c, c3);
#endif
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNSWAP3;
++depth;
if (has_mbyte) {
@@ -10358,8 +10459,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
p[2] = c;
stack[depth].ts_fidxtry = sp->ts_fidx + 3;
}
- } else
+ } else {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
+ }
break;
case STATE_UNSWAP3:
@@ -10385,6 +10488,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (!soundfold && !spell_iswordp(p, curwin)) {
// Middle char is not a word char, skip the rotate. First and
// third char were already checked at swap and swap3.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
break;
}
@@ -10399,6 +10503,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_twordlen, tword, fword + sp->ts_fidx,
p[0], p[1], p[2]);
#endif
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3L;
++depth;
p = fword + sp->ts_fidx;
@@ -10417,8 +10522,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
p[2] = c;
stack[depth].ts_fidxtry = sp->ts_fidx + 3;
}
- } else
+ } else {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
+ }
break;
case STATE_UNROT3L:
@@ -10448,6 +10555,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_twordlen, tword, fword + sp->ts_fidx,
p[0], p[1], p[2]);
#endif
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3R;
++depth;
p = fword + sp->ts_fidx;
@@ -10466,8 +10574,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
*p = c;
stack[depth].ts_fidxtry = sp->ts_fidx + 3;
}
- } else
+ } else {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
+ }
break;
case STATE_UNROT3R:
@@ -10497,6 +10607,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if ((lp->lp_replang == NULL && !soundfold)
|| sp->ts_score + SCORE_REP >= su->su_maxscore
|| sp->ts_fidx < sp->ts_fidxtry) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
break;
}
@@ -10509,10 +10620,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
if (sp->ts_curi < 0) {
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
break;
}
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP;
// FALLTHROUGH
@@ -10542,6 +10655,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
ftp->ft_from, ftp->ft_to);
#endif
// Need to undo this afterwards.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_UNDO;
// Change the "from" to the "to" string.
@@ -10561,6 +10675,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
// No (more) matches.
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
break;
@@ -10580,6 +10695,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
repextra -= tl - fl;
}
memmove(p, ftp->ft_from, fl);
+ PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP;
break;
@@ -10990,7 +11106,13 @@ static void suggest_try_soundalike(suginfo_T *su)
// try all kinds of inserts/deletes/swaps/etc.
// TODO: also soundfold the next words, so that we can try joining
// and splitting
+#ifdef SUGGEST_PROFILE
+ prof_init();
+#endif
suggest_trie_walk(su, lp, salword, true);
+#ifdef SUGGEST_PROFILE
+ prof_report("soundalike");
+#endif
}
}
}
@@ -13340,3 +13462,4 @@ int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp)
return ga.ga_len;
}
+
diff --git a/src/nvim/state.c b/src/nvim/state.c
index b2f3f0bebe..30133e2201 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -4,6 +4,7 @@
#include "nvim/state.h"
#include "nvim/vim.h"
+#include "nvim/main.h"
#include "nvim/getchar.h"
#include "nvim/ui.h"
#include "nvim/os/input.h"
@@ -32,7 +33,7 @@ getkey:
// processing. Characters can come from mappings, scripts and other
// sources, so this scenario is very common.
key = safe_vgetc();
- } else if (!queue_empty(loop.events)) {
+ } else if (!queue_empty(main_loop.events)) {
// Event was made available after the last queue_process_events call
key = K_EVENT;
} else {
@@ -45,7 +46,7 @@ getkey:
// directly.
(void)os_inchar(NULL, 0, -1, 0);
input_disable_events();
- key = !queue_empty(loop.events) ? K_EVENT : safe_vgetc();
+ key = !queue_empty(main_loop.events) ? K_EVENT : safe_vgetc();
}
if (key == K_EVENT) {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 1f9dbd8228..3215f7ea14 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -812,19 +812,39 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
validate_current_state();
}
+static void save_chartab(char_u *chartab)
+{
+ if (syn_block->b_syn_isk != empty_option) {
+ memmove(chartab, syn_buf->b_chartab, (size_t)32);
+ memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, (size_t)32);
+ }
+}
+
+static void restore_chartab(char_u *chartab)
+{
+ if (syn_win->w_s->b_syn_isk != empty_option) {
+ memmove(syn_buf->b_chartab, chartab, (size_t)32);
+ }
+}
+
/*
* Return TRUE if the line-continuation pattern matches in line "lnum".
*/
static int syn_match_linecont(linenr_T lnum)
{
- regmmatch_T regmatch;
-
if (syn_block->b_syn_linecont_prog != NULL) {
+ regmmatch_T regmatch;
+ // chartab array for syn iskeyword
+ char_u buf_chartab[32];
+ save_chartab(buf_chartab);
+
regmatch.rmm_ic = syn_block->b_syn_linecont_ic;
regmatch.regprog = syn_block->b_syn_linecont_prog;
int r = syn_regexec(&regmatch, lnum, (colnr_T)0,
IF_SYN_TIME(&syn_block->b_syn_linecont_time));
syn_block->b_syn_linecont_prog = regmatch.regprog;
+
+ restore_chartab(buf_chartab);
return r;
}
return FALSE;
@@ -1617,8 +1637,9 @@ syn_current_attr (
lpos_T pos;
int lc_col;
reg_extmatch_T *cur_extmatch = NULL;
- char_u *line; /* current line. NOTE: becomes invalid after
- looking for a pattern match! */
+ char_u buf_chartab[32]; // chartab array for syn iskeyword
+ char_u *line; // current line. NOTE: becomes invalid after
+ // looking for a pattern match!
/* variables for zero-width matches that have a "nextgroup" argument */
int keep_next_list;
@@ -1668,6 +1689,9 @@ syn_current_attr (
* avoid matching the same item in the same position twice. */
ga_init(&zero_width_next_ga, (int)sizeof(int), 10);
+ // use syntax iskeyword option
+ save_chartab(buf_chartab);
+
/*
* Repeat matching keywords and patterns, to find contained items at the
* same column. This stops when there are no extra matches at the current
@@ -1992,6 +2016,8 @@ syn_current_attr (
} while (found_match);
+ restore_chartab(buf_chartab);
+
/*
* Use attributes from the current state, if within its highlighting.
* If not, use attributes from the current-but-one state, etc.
@@ -2522,7 +2548,8 @@ find_endpos (
regmmatch_T best_regmatch; /* startpos/endpos of best match */
lpos_T pos;
char_u *line;
- int had_match = FALSE;
+ int had_match = false;
+ char_u buf_chartab[32]; // chartab array for syn option iskeyword
/* just in case we are invoked for a keyword */
if (idx < 0)
@@ -2562,9 +2589,13 @@ find_endpos (
unref_extmatch(re_extmatch_in);
re_extmatch_in = ref_extmatch(start_ext);
- matchcol = startpos->col; /* start looking for a match at sstart */
- start_idx = idx; /* remember the first END pattern. */
- best_regmatch.startpos[0].col = 0; /* avoid compiler warning */
+ matchcol = startpos->col; // start looking for a match at sstart
+ start_idx = idx; // remember the first END pattern.
+ best_regmatch.startpos[0].col = 0; // avoid compiler warning
+
+ // use syntax iskeyword option
+ save_chartab(buf_chartab);
+
for (;; ) {
/*
* Find end pattern that matches first after "matchcol".
@@ -2707,6 +2738,8 @@ find_endpos (
if (!had_match)
m_endpos->lnum = 0;
+ restore_chartab(buf_chartab);
+
/* Remove external matches. */
unref_extmatch(re_extmatch_in);
re_extmatch_in = NULL;
@@ -3027,6 +3060,46 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
redraw_win_later(curwin, NOT_VALID);
}
+/// Handle ":syntax iskeyword" command.
+static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
+{
+ char_u *arg = eap->arg;
+ char_u save_chartab[32];
+ char_u *save_isk;
+
+ if (eap->skip) {
+ return;
+ }
+
+ arg = skipwhite(arg);
+ if (*arg == NUL) {
+ MSG_PUTS("\n");
+ MSG_PUTS(_("syntax iskeyword "));
+ if (curwin->w_s->b_syn_isk != empty_option) {
+ msg_outtrans(curwin->w_s->b_syn_isk);
+ } else {
+ msg_outtrans((char_u *)"not set");
+ }
+ } else {
+ if (STRNICMP(arg, "clear", 5) == 0) {
+ memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, (size_t)32);
+ clear_string_option(&curwin->w_s->b_syn_isk);
+ } else {
+ memmove(save_chartab, curbuf->b_chartab, (size_t)32);
+ save_isk = curbuf->b_p_isk;
+ curbuf->b_p_isk = vim_strsave(arg);
+
+ buf_init_chartab(curbuf, false);
+ memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, (size_t)32);
+ memmove(curbuf->b_chartab, save_chartab, (size_t)32);
+ clear_string_option(&curwin->w_s->b_syn_isk);
+ curwin->w_s->b_syn_isk = curbuf->b_p_isk;
+ curbuf->b_p_isk = save_isk;
+ }
+ }
+ redraw_win_later(curwin, NOT_VALID);
+}
+
/*
* Clear all syntax info for one buffer.
*/
@@ -3065,6 +3138,7 @@ void syntax_clear(synblock_T *block)
xfree(block->b_syn_linecont_pat);
block->b_syn_linecont_pat = NULL;
block->b_syn_folditems = 0;
+ clear_string_option(&block->b_syn_isk);
/* free the stored states */
syn_stack_free_all(block);
@@ -3107,6 +3181,7 @@ static void syntax_sync_clear(void)
curwin->w_s->b_syn_linecont_prog = NULL;
xfree(curwin->w_s->b_syn_linecont_pat);
curwin->w_s->b_syn_linecont_pat = NULL;
+ clear_string_option(&curwin->w_s->b_syn_isk);
syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
}
@@ -3266,6 +3341,7 @@ static void syn_cmd_enable(exarg_T *eap, int syncing)
/*
* Handle ":syntax reset" command.
+ * It actually resets highlighting, not syntax.
*/
static void syn_cmd_reset(exarg_T *eap, int syncing)
{
@@ -4131,9 +4207,10 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
current_syn_inc_tag = ++running_syn_inc_tag;
prev_toplvl_grp = curwin->w_s->b_syn_topgrp;
curwin->w_s->b_syn_topgrp = sgl_id;
- if (source ? do_source(eap->arg, FALSE, DOSO_NONE) == FAIL
- : source_runtime(eap->arg, TRUE) == FAIL)
+ if (source ? do_source(eap->arg, false, DOSO_NONE) == FAIL
+ : source_runtime(eap->arg, DIP_ALL) == FAIL) {
EMSG2(_(e_notopen), eap->arg);
+ }
curwin->w_s->b_syn_topgrp = prev_toplvl_grp;
current_syn_inc_tag = prev_syn_inc_tag;
}
@@ -5363,24 +5440,25 @@ struct subcommand {
static struct subcommand subcommands[] =
{
- {"case", syn_cmd_case},
- {"clear", syn_cmd_clear},
- {"cluster", syn_cmd_cluster},
- {"conceal", syn_cmd_conceal},
- {"enable", syn_cmd_enable},
- {"include", syn_cmd_include},
- {"keyword", syn_cmd_keyword},
- {"list", syn_cmd_list},
- {"manual", syn_cmd_manual},
- {"match", syn_cmd_match},
- {"on", syn_cmd_on},
- {"off", syn_cmd_off},
- {"region", syn_cmd_region},
- {"reset", syn_cmd_reset},
- {"spell", syn_cmd_spell},
- {"sync", syn_cmd_sync},
- {"", syn_cmd_list},
- {NULL, NULL}
+ { "case", syn_cmd_case },
+ { "clear", syn_cmd_clear },
+ { "cluster", syn_cmd_cluster },
+ { "conceal", syn_cmd_conceal },
+ { "enable", syn_cmd_enable },
+ { "include", syn_cmd_include },
+ { "iskeyword", syn_cmd_iskeyword },
+ { "keyword", syn_cmd_keyword },
+ { "list", syn_cmd_list },
+ { "manual", syn_cmd_manual },
+ { "match", syn_cmd_match },
+ { "on", syn_cmd_on },
+ { "off", syn_cmd_off },
+ { "region", syn_cmd_region },
+ { "reset", syn_cmd_reset },
+ { "spell", syn_cmd_spell },
+ { "sync", syn_cmd_sync },
+ { "", syn_cmd_list },
+ { NULL, NULL }
};
/*
@@ -5434,6 +5512,7 @@ void ex_ownsyntax(exarg_T *eap)
clear_string_option(&curwin->w_s->b_p_spc);
clear_string_option(&curwin->w_s->b_p_spf);
clear_string_option(&curwin->w_s->b_p_spl);
+ clear_string_option(&curwin->w_s->b_syn_isk);
}
/* save value of b:current_syntax */
@@ -5582,6 +5661,24 @@ int get_syntax_info(int *seqnrp)
return current_flags;
}
+
+/// Get the sequence number of the concealed file position.
+///
+/// @return seqnr if the file position is concealed, 0 otherwise.
+int syn_get_concealed_id(win_T *wp, linenr_T lnum, colnr_T col)
+{
+ int seqnr;
+ int syntax_flags;
+
+ (void)syn_get_id(wp, lnum, col, false, NULL, false);
+ syntax_flags = get_syntax_info(&seqnr);
+
+ if (syntax_flags & HL_CONCEAL) {
+ return seqnr;
+ }
+ return 0;
+}
+
/*
* Return conceal substitution character
*/
@@ -5945,12 +6042,12 @@ init_highlight (
if (get_var_value((char_u *)"g:syntax_on") != NULL) {
static int recursive = 0;
- if (recursive >= 5)
+ if (recursive >= 5) {
EMSG(_("E679: recursive loop loading syncolor.vim"));
- else {
- ++recursive;
- (void)source_runtime((char_u *)"syntax/syncolor.vim", TRUE);
- --recursive;
+ } else {
+ recursive++;
+ (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL);
+ recursive--;
}
}
}
@@ -5963,22 +6060,24 @@ int load_colors(char_u *name)
{
char_u *buf;
int retval = FAIL;
- static int recursive = FALSE;
+ static int recursive = false;
- /* When being called recursively, this is probably because setting
- * 'background' caused the highlighting to be reloaded. This means it is
- * working, thus we should return OK. */
- if (recursive)
+ // When being called recursively, this is probably because setting
+ // 'background' caused the highlighting to be reloaded. This means it is
+ // working, thus we should return OK.
+ if (recursive) {
return OK;
+ }
- recursive = TRUE;
- buf = xmalloc(STRLEN(name) + 12);
- sprintf((char *)buf, "colors/%s.vim", name);
- retval = source_runtime(buf, FALSE);
+ recursive = true;
+ size_t buflen = STRLEN(name) + 12;
+ buf = xmalloc(buflen);
+ snprintf((char *)buf, buflen, "colors/%s.vim", name);
+ retval = source_runtime(buf, DIP_START + DIP_OPT);
xfree(buf);
apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
- recursive = FALSE;
+ recursive = false;
ui_refresh();
return retval;
@@ -6874,8 +6973,23 @@ highlight_color (
else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g'))
return NULL;
if (modec == 'g') {
- if (fg)
+ if (what[2] == '#' && ui_rgb_attached()) {
+ if (fg) {
+ n = HL_TABLE()[id - 1].sg_rgb_fg;
+ } else if (sp) {
+ n = HL_TABLE()[id - 1].sg_rgb_sp;
+ } else {
+ n = HL_TABLE()[id - 1].sg_rgb_bg;
+ }
+ if (n < 0 || n > 0xffffff) {
+ return NULL;
+ }
+ snprintf((char *)name, sizeof(name), "#%06x", n);
+ return name;
+ }
+ if (fg) {
return HL_TABLE()[id - 1].sg_rgb_fg_name;
+ }
if (sp) {
return HL_TABLE()[id - 1].sg_rgb_sp_name;
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 7885d467d8..dfecfb776d 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2023,9 +2023,8 @@ get_tagfname (
if (first) {
ga_clear_strings(&tag_fnames);
ga_init(&tag_fnames, (int)sizeof(char_u *), 10);
- do_in_runtimepath((char_u *)
- "doc/tags doc/tags-??"
- , TRUE, found_tagfile_cb, NULL);
+ do_in_runtimepath((char_u *)"doc/tags doc/tags-??", DIP_ALL,
+ found_tagfile_cb, NULL);
}
if (tnp->tn_hf_idx >= tag_fnames.ga_len) {
@@ -2353,7 +2352,7 @@ jumpto_tag (
* file. Also accept a file name for which there is a matching BufReadCmd
* autocommand event (e.g., http://sys/file).
*/
- if (!os_file_exists(fname)
+ if (!os_path_exists(fname)
&& !has_autocmd(EVENT_BUFREADCMD, fname, NULL)
) {
retval = NOTAGFILE;
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 104cc47cda..6f50c03be9 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -63,6 +63,7 @@
#include "nvim/map.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
+#include "nvim/main.h"
#include "nvim/state.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_cmds.h"
@@ -163,9 +164,9 @@ static VTermColor default_vt_bg_rgb;
void terminal_init(void)
{
invalidated_terminals = pmap_new(ptr_t)();
- time_watcher_init(&loop, &refresh_timer, NULL);
+ time_watcher_init(&main_loop, &refresh_timer, NULL);
// refresh_timer_cb will redraw the screen which can call vimscript
- refresh_timer.events = queue_new_child(loop.events);
+ refresh_timer.events = queue_new_child(main_loop.events);
// initialize a rgb->color index map for cterm attributes(VTermScreenCell
// only has RGB information and we need color indexes for terminal UIs)
@@ -240,6 +241,7 @@ Terminal *terminal_open(TerminalOptions opts)
set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL);
set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL);
set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL);
+ buf_set_term_title(curbuf, (char *)curbuf->b_ffname);
RESET_BINDING(curwin);
// Apply TermOpen autocmds so the user can configure the terminal
apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf);
@@ -347,15 +349,6 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
height = (uint16_t)curheight;
}
- // The new width/height are the minimum for all windows that display the
- // terminal in the current tab.
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (!wp->w_closing && wp->w_buffer->terminal == term) {
- width = (uint16_t)MIN(width, (uint16_t)(wp->w_width - win_col_off(wp)));
- height = (uint16_t)MIN(height, (uint16_t)wp->w_height);
- }
- }
-
if (curheight == height && curwidth == width) {
return;
}
@@ -452,7 +445,7 @@ static int terminal_execute(VimState *state, int key)
case K_EVENT:
// We cannot let an event free the terminal yet. It is still needed.
s->term->refcount++;
- queue_process_events(loop.events);
+ queue_process_events(main_loop.events);
s->term->refcount--;
if (s->term->buf_handle == 0) {
s->close = true;
@@ -626,6 +619,17 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible,
return 1;
}
+static void buf_set_term_title(buf_T *buf, char *title)
+ FUNC_ATTR_NONNULL_ALL
+{
+ Error err;
+ api_free_object(dict_set_value(buf->b_vars,
+ cstr_as_string("term_title"),
+ STRING_OBJ(cstr_as_string(title)),
+ false,
+ &err));
+}
+
static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
{
Terminal *term = data;
@@ -641,12 +645,7 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
case VTERM_PROP_TITLE: {
buf_T *buf = handle_get_buffer(term->buf_handle);
- Error err;
- api_free_object(dict_set_value(buf->b_vars,
- cstr_as_string("term_title"),
- STRING_OBJ(cstr_as_string(val->string)),
- false,
- &err));
+ buf_set_term_title(buf, val->string);
break;
}
@@ -1158,15 +1157,15 @@ static bool is_focused(Terminal *term)
return State & TERM_FOCUS && curbuf->terminal == term;
}
-#define GET_CONFIG_VALUE(k, o) \
- do { \
- Error err; \
- /* Only called from terminal_open where curbuf->terminal is the */ \
- /* context */ \
- o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \
- if (o.type == kObjectTypeNil) { \
- o = dict_get_value(&globvardict, cstr_as_string(k), &err); \
- } \
+#define GET_CONFIG_VALUE(k, o) \
+ do { \
+ Error err; \
+ /* Only called from terminal_open where curbuf->terminal is the */ \
+ /* context */ \
+ o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \
+ if (o.type == kObjectTypeNil) { \
+ o = dict_get_value(&globvardict, cstr_as_string(k), &err); \
+ } \
} while (0)
static char *get_config_string(char *key)
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 88cdf19016..9a0bba83fe 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -9,14 +9,12 @@ SCRIPTSOURCE := ../../../runtime
SCRIPTS := \
test8.out \
- test10.out \
test12.out \
test13.out \
test14.out \
test17.out \
test24.out \
test32.out \
- test34.out \
test37.out \
test40.out \
test42.out \
@@ -25,21 +23,22 @@ SCRIPTS := \
test49.out \
test52.out \
test53.out \
- test55.out \
test64.out \
test69.out \
test73.out \
test79.out \
- test_listlbr.out \
test_marks.out \
# Tests using runtest.vim.vim.
# Keep test_alot*.res as the last one, sort the others.
NEW_TESTS = \
- test_cursor_func.res \
+ test_hardcopy.res \
test_help_tagjump.res \
- test_menu.res \
+ test_langmap.res \
+ test_syntax.res \
+ test_timers.res \
test_viml.res \
+ test_visual.res \
test_alot.res
SCRIPTS_GUI := test16.out
@@ -58,7 +57,7 @@ ifdef USE_VALGRIND
TOOL := valgrind -q \
-q \
$(VALGRIND_TOOL) \
- --suppressions=../../../.valgrind.supp \
+ --suppressions=../../.valgrind.supp \
--error-exitcode=123 \
--log-file=valgrind.\%p.$* \
$(VGDB) \
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 5b34b4fc31..74bbf418fa 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -2,6 +2,11 @@
" When the script is successful the .res file will be created.
" Errors are appended to the test.log file.
"
+" To execute only specific test functions, add a second argument. It will be
+" matched against the names of the Test_ function. E.g.:
+" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
+" The output can be found in the "messages" file.
+"
" The test script may contain anything, only functions that start with
" "Test_" are special. These will be invoked and should contain assert
" functions. See test_assert.vim for an example.
@@ -39,6 +44,9 @@ set nomore
" Output all messages in English.
lang mess C
+" Always use forward slashes.
+set shellslash
+
" Source the test script. First grab the file name, in case the script
" navigates away.
let testname = expand('%')
@@ -61,11 +69,18 @@ endif
" Locate Test_ functions and execute them.
set nomore
redir @q
-function /^Test_
+silent function /^Test_
redir END
let tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
-for test in tests
+" If there is an extra argument filter the function names against it.
+if argc() > 1
+ let tests = filter(tests, 'v:val =~ argv(1)')
+endif
+
+" Execute the tests in alphabetical order.
+for test in sort(tests)
+ echo 'Executing ' . test
if exists("*SetUp")
call SetUp()
endif
diff --git a/src/nvim/testdir/test10.in b/src/nvim/testdir/test10.in
deleted file mode 100644
index 2178cf41ce..0000000000
--- a/src/nvim/testdir/test10.in
+++ /dev/null
@@ -1,110 +0,0 @@
-Test for 'errorformat'. This will fail if the quickfix feature was disabled.
-
-STARTTEST
-:7/start of errorfile/,/end of errorfile/w! Xerrorfile1
-:7/start of errorfile/,/end of errorfile/-1w! Xerrorfile2
-:/start of testfile/,/end of testfile/w! Xtestfile
-:set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m
-:set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m
-:cf Xerrorfile2
-:clast
-:copen
-:let a=w:quickfix_title
-:wincmd p
-lgR=a 
-:cf Xerrorfile1
-grA
-:cn
-gRLINE 6, COL 19
-:cn
-gRNO COLUMN SPECIFIED
-:cn
-gRAGAIN NO COLUMN
-:cn
-gRCOL 1
-:cn
-gRCOL 2
-:cn
-gRCOL 10
-:cn
-gRVCOL 10
-:cn
-grI
-:cn
-gR. SPACE POINTER
-:cn
-gR. DOT POINTER
-:cn
-gR. DASH POINTER
-:cn
-gR. TAB-SPACE POINTER
-:clast
-:cprev
-:cprev
-:wincmd w
-:let a=w:quickfix_title
-:wincmd p
-lgR=a 
-:w! test.out " Write contents of this file
-:qa!
-ENDTEST
-
-start of errorfile
-"Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set.
-"Xtestfile", line 6 col 19; this is an error
-gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c
-Xtestfile:9: parse error before `asd'
-make: *** [vim] Error 1
-in file "Xtestfile" linenr 10: there is an error
-
-2 returned
-"Xtestfile", line 11 col 1; this is an error
-"Xtestfile", line 12 col 2; this is another error
-"Xtestfile", line 14:10; this is an error in column 10
-=Xtestfile=, line 15:10; this is another error, but in vcol 10 this time
-"Xtestfile", linenr 16: yet another problem
-Error in "Xtestfile" at line 17:
-x should be a dot
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17
- ^
-Error in "Xtestfile" at line 18:
-x should be a dot
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18
-.............^
-Error in "Xtestfile" at line 19:
-x should be a dot
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19
---------------^
-Error in "Xtestfile" at line 20:
-x should be a dot
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20
- ^
-
-Does anyone know what is the problem and how to correction it?
-"Xtestfile", line 21 col 9: What is the title of the quickfix window?
-"Xtestfile", line 22 col 9: What is the title of the quickfix window?
-end of errorfile
-
-start of testfile
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22
-end of testfile
diff --git a/src/nvim/testdir/test10.ok b/src/nvim/testdir/test10.ok
deleted file mode 100644
index 76a02f40b4..0000000000
--- a/src/nvim/testdir/test10.ok
+++ /dev/null
@@ -1,23 +0,0 @@
-start of testfile
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3
- xxxxxxxxxxAxxxxxxxxxxxxxxxxxxx line 4
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5
- xxxxxxxxxxxxxxxxxLINE 6, COL 19 line 6
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8
- NO COLUMN SPECIFIEDxxxxxxxxxxx line 9
- AGAIN NO COLUMNxxxxxxxxxxxxxxx line 10
-COL 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11
- COL 2xxxxxxxxxxxxxxxxxxxxxxxxx line 12
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13
- xxxxxxxxCOL 10xxxxxxxxxxxxxxxx line 14
- xVCOL 10xxxxxxxxxxxxxxxxxxxxxx line 15
- Ixxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16
- xxxx. SPACE POINTERxxxxxxxxxxx line 17
- xxxxx. DOT POINTERxxxxxxxxxxxx line 18
- xxxxxx. DASH POINTERxxxxxxxxxx line 19
- xxxxxxx. TAB-SPACE POINTERxxxx line 20
- xxxxxxxx:cf Xerrorfile1xxxxxxx line 21
- xxxxxxxx:cf Xerrorfile2xxxxxxx line 22
-end of testfile
diff --git a/src/nvim/testdir/test10a.in b/src/nvim/testdir/test10a.in
deleted file mode 100644
index 99a5a03db8..0000000000
--- a/src/nvim/testdir/test10a.in
+++ /dev/null
@@ -1,72 +0,0 @@
-Test for 'errorformat'.
-
-STARTTEST
-:/start of errorfile/,/end of errorfile/w! Xerrorfile
-:/start of testfile/,/end of testfile/w! Xtestfile
-:cf Xerrorfile
-rA
-:cn
-rB
-:cn
-rC
-:cn
-rD
-:cn
-rE
-:w! test.out " Write contents of this file
-:qa!
-ENDTEST
-
-start of errorfile
-
- printf(" %d \n", (number/other)%10 );
-..................^
-%CC-E-NOSEMI, Missing ";".
-at line number 4 in file SYS$DISK:XTESTFILE
-
- other=10000000;
-.............^
-%CC-E-UNDECLARED, In this statement, "oszt" is not declared.
-at line number 7 in file SYS$DISK:XTESTFILE
-
- for (i = 0; i<7 ; i++ ){
-..................^
-%CC-E-UNDECLARED, In this statement, "i" is not declared.
-at line number 16 in file SYS$DISK:XTESTFILE
-
-some other error somewhere here.
-...........................^
-%CC-W-WARRING, Sorry, but no expalnation for such an warring.
-at line number 19 in file SYS$DISK:XTESTFILE
-
-and finally some other error exactly here.
-.....................................^
-%CC-I-INFORMATIONAL, It should be some informational message.
-at line number 20 in file SYS$DISK:XTESTFILE
-
-Does anyone know what is the problem and how to correct ?? :)
-end of errorfile
-
-start of testfile
-01234567890123456789012345678901234567
-line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 8 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 12 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 13 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 14 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 15 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 16 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 17 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 18 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 19 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 20 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 22 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-end of testfile
diff --git a/src/nvim/testdir/test10a.ok b/src/nvim/testdir/test10a.ok
deleted file mode 100644
index 10e78c9239..0000000000
--- a/src/nvim/testdir/test10a.ok
+++ /dev/null
@@ -1,23 +0,0 @@
-start of testfile
-01234567890123456789012345678901234567
-line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 4 xxxxxxxxxxAxxxxxxxxxxxxxxxxxxx
-line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 7 xxxxxBxxxxxxxxxxxxxxxxxxxxxxxx
-line 8 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 12 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 13 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 14 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 15 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 16 xxxxxxxxxxCxxxxxxxxxxxxxxxxxxx
-line 17 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 18 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 19 xxxxxxxxxxxxxxxxxxxDxxxxxxxxxx
-line 20 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxE
-line 21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 22 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-end of testfile
diff --git a/src/nvim/testdir/test34.in b/src/nvim/testdir/test34.in
deleted file mode 100644
index 4cb7e9494a..0000000000
--- a/src/nvim/testdir/test34.in
+++ /dev/null
@@ -1,86 +0,0 @@
-Test for user functions.
-Also test an <expr> mapping calling a function.
-Also test that a builtin function cannot be replaced.
-Also test for regression when calling arbitrary expression.
-
-STARTTEST
-:function Table(title, ...)
-: let ret = a:title
-: let idx = 1
-: while idx <= a:0
-: exe "let ret = ret . a:" . idx
-: let idx = idx + 1
-: endwhile
-: return ret
-:endfunction
-:function Compute(n1, n2, divname)
-: if a:n2 == 0
-: return "fail"
-: endif
-: exe "let g:" . a:divname . " = ". a:n1 / a:n2
-: return "ok"
-:endfunction
-:func Expr1()
-: normal! v
-: return "111"
-:endfunc
-:func Expr2()
-: call search('XX', 'b')
-: return "222"
-:endfunc
-:func ListItem()
-: let g:counter += 1
-: return g:counter . '. '
-:endfunc
-:func ListReset()
-: let g:counter = 0
-: return ''
-:endfunc
-:func FuncWithRef(a)
-: unlet g:FuncRef
-: return a:a
-:endfunc
-:let g:FuncRef=function("FuncWithRef")
-:let counter = 0
-:inoremap <expr> ( ListItem()
-:inoremap <expr> [ ListReset()
-:imap <expr> + Expr1()
-:imap <expr> * Expr2()
-:let retval = "nop"
-/^here
-C=Table("xxx", 4, "asdf")
- =Compute(45, 0, "retval")
- =retval
- =Compute(45, 5, "retval")
- =retval
- =g:FuncRef(333)
-
-XX+-XX
----*---
-(one
-(two
-[(one again:call append(line('$'), max([1, 2, 3]))
-:call extend(g:, {'max': function('min')})
-:call append(line('$'), max([1, 2, 3]))
-:try
-: " Regression: the first line below used to throw ?E110: Missing ')'?
-: " Second is here just to prove that this line is correct when not skipping
-: " rhs of &&.
-: $put =(0&&(function('tr'))(1, 2, 3))
-: $put =(1&&(function('tr'))(1, 2, 3))
-:catch
-: $put ='!!! Unexpected exception:'
-: $put =v:exception
-:endtry
-:$-9,$w! test.out
-:delfunc Table
-:delfunc Compute
-:delfunc Expr1
-:delfunc Expr2
-:delfunc ListItem
-:delfunc ListReset
-:unlet retval counter
-:q!
-ENDTEST
-
-here
diff --git a/src/nvim/testdir/test34.ok b/src/nvim/testdir/test34.ok
deleted file mode 100644
index 97995de80e..0000000000
--- a/src/nvim/testdir/test34.ok
+++ /dev/null
@@ -1,10 +0,0 @@
-xxx4asdf fail nop ok 9 333
-XX111-XX
----222---
-1. one
-2. two
-1. one again
-3
-3
-0
-1
diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in
deleted file mode 100644
index 9a55eac6f6..0000000000
--- a/src/nvim/testdir/test55.in
+++ /dev/null
@@ -1,600 +0,0 @@
-Tests for List and Dictionary types. vim: set ft=vim :
-
-STARTTEST
-:fun Test(...)
-:lang C
-:" Creating List directly with different types
-:let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
-:$put =string(l)
-:$put =string(l[-1])
-:$put =string(l[-4])
-:try
-: $put =string(l[-5])
-:catch
-: $put =v:exception[:14]
-:endtry
-:" List slices
-:$put =string(l[:])
-:$put =string(l[1:])
-:$put =string(l[:-2])
-:$put =string(l[0:8])
-:$put =string(l[8:-1])
-:"
-:" List identity
-:let ll = l
-:let lx = copy(l)
-:try
-: $put =(l == ll) . (l isnot ll) . (l is ll) . (l == lx) . (l is lx) . (l isnot lx)
-:catch
-: $put =v:exception
-:endtry
-:"
-:" Creating Dictionary directly with different types
-:let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
-:$put =string(d) . d.1
-:$put =string(sort(keys(d)))
-:$put =string (values(d))
-:for [key, val] in items(d)
-: $put =key . ':' . string(val)
-: unlet key val
-:endfor
-:call extend (d, {3:33, 1:99})
-:call extend(d, {'b':'bbb', 'c':'ccc'}, "keep")
-:try
-: call extend(d, {3:333,4:444}, "error")
-:catch
-: $put =v:exception[:15] . v:exception[-1:-1]
-:endtry
-:$put =string(d)
-:call filter(d, 'v:key =~ ''[ac391]''')
-:$put =string(d)
-:"
-:" Dictionary identity
-:let dd = d
-:let dx = copy(d)
-:try
-: $put =(d == dd) . (d isnot dd) . (d is dd) . (d == dx) . (d is dx) . (d isnot dx)
-:catch
-: $put =v:exception
-:endtry
-:"
-:" Changing var type should fail
-:try
-: let d = []
-:catch
-: $put =v:exception[:14] . v:exception[-1:-1]
-:endtry
-:try
-: let l = {}
-:catch
-: $put =v:exception[:14] . v:exception[-1:-1]
-:endtry
-:"
-:" removing items with :unlet
-:unlet l[2]
-:$put =string(l)
-:let l = range(8)
-:try
-:unlet l[:3]
-:unlet l[1:]
-:catch
-:$put =v:exception
-:endtry
-:$put =string(l)
-:"
-:unlet d.c
-:unlet d[-1]
-:$put =string(d)
-:"
-:" removing items out of range: silently skip items that don't exist
-let l = [0, 1, 2, 3]
-:unlet l[2:1]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[2:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[2:3]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[2:4]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[2:5]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-1:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-2:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-3:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-4:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-5:2]
-:$put =string(l)
-let l = [0, 1, 2, 3]
-:unlet l[-6:2]
-:$put =string(l)
-:"
-:" assignment to a list
-:let l = [0, 1, 2, 3]
-:let [va, vb] = l[2:3]
-:$put =va
-:$put =vb
-:try
-: let [va, vb] = l
-:catch
-: $put =v:exception[:14]
-:endtry
-:try
-: let [va, vb] = l[1:1]
-:catch
-: $put =v:exception[:14]
-:endtry
-:"
-:" manipulating a big Dictionary (hashtable.c has a border of 1000 entries)
-:let d = {}
-:for i in range(1500)
-: let d[i] = 3000 - i
-:endfor
-:$put =d[0] . ' ' . d[100] . ' ' . d[999] . ' ' . d[1400] . ' ' . d[1499]
-:try
-: let n = d[1500]
-:catch
-: $put =substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '')
-:endtry
-:" lookup each items
-:for i in range(1500)
-: if d[i] != 3000 - i
-: $put =d[i]
-: endif
-:endfor
-: let i += 1
-:" delete even items
-:while i >= 2
-: let i -= 2
-: unlet d[i]
-:endwhile
-:$put =get(d, 1500 - 100, 'NONE') . ' ' . d[1]
-:" delete odd items, checking value, one intentionally wrong
-:let d[33] = 999
-:let i = 1
-:while i < 1500
-: if d[i] != 3000 - i
-: $put =i . '=' . d[i]
-: else
-: unlet d[i]
-: endif
-: let i += 2
-:endwhile
-:$put =string(d) " must be almost empty now
-:unlet d
-:"
-:" Dictionary function
-:let dict = {}
-:func dict.func(a) dict
-: $put =a:a . len(self.data)
-:endfunc
-:let dict.data = [1,2,3]
-:call dict.func("len: ")
-:let x = dict.func("again: ")
-:try
-: let Fn = dict.func
-: call Fn('xxx')
-:catch
-: $put =v:exception[:15]
-:endtry
-:"
-:" Function in script-local List or Dict
-:let g:dict = {}
-:function g:dict.func() dict
-: $put ='g:dict.func'.self.foo[1].self.foo[0]('asdf')
-:endfunc
-:let g:dict.foo = ['-', 2, 3]
-:call insert(g:dict.foo, function('strlen'))
-:call g:dict.func()
-:"
-:" Nasty: remove func from Dict that's being called (works)
-:let d = {1:1}
-:func d.func(a)
-: return "a:". a:a
-:endfunc
-:$put =d.func(string(remove(d, 'func')))
-:"
-:" Nasty: deepcopy() dict that refers to itself (fails when noref used)
-:let d = {1:1, 2:2}
-:let l = [4, d, 6]
-:let d[3] = l
-:let dc = deepcopy(d)
-:try
-: let dc = deepcopy(d, 1)
-:catch
-: $put =v:exception[:14]
-:endtry
-:let l2 = [0, l, l, 3]
-:let l[1] = l2
-:let l3 = deepcopy(l2)
-:$put ='same list: ' . (l3[1] is l3[2])
-:"
-:" Locked variables
-:for depth in range(5)
-: $put ='depth is ' . depth
-: for u in range(3)
-: unlet l
-: let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
-: exe "lockvar " . depth . " l"
-: if u == 1
-: exe "unlockvar l"
-: elseif u == 2
-: exe "unlockvar " . depth . " l"
-: endif
-: let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
-: $put =ps
-: let ps = ''
-: try
-: let l[1][1][0] = 99
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l[1][1] = [99]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l[1] = [99]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l[2]['6'][7] = 99
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l[2][6] = {99: 99}
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l[2] = {99: 99}
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: let l = [99]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: $put =ps
-: endfor
-:endfor
-:"
-:" Unletting locked variables
-:$put ='Unletting:'
-:for depth in range(5)
-: $put ='depth is ' . depth
-: for u in range(3)
-: unlet l
-: let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
-: exe "lockvar " . depth . " l"
-: if u == 1
-: exe "unlockvar l"
-: elseif u == 2
-: exe "unlockvar " . depth . " l"
-: endif
-: let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
-: $put =ps
-: let ps = ''
-: try
-: unlet l[2]['6'][7]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l[2][6]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l[2]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l[1][1][0]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l[1][1]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l[1]
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: try
-: unlet l
-: let ps .= 'p'
-: catch
-: let ps .= 'F'
-: endtry
-: $put =ps
-: endfor
-:endfor
-:"
-:" Locked variables and :unlet or list / dict functions
-:$put ='Locks and commands or functions:'
-:"
-:$put ='No :unlet after lock on dict:'
-:unlet! d
-:let d = {'a': 99, 'b': 100}
-:lockvar 1 d
-:try
-: unlet d.a
-: $put ='did :unlet'
-:catch
-: $put =v:exception[:16]
-:endtry
-:$put =string(d)
-:"
-:$put =':unlet after lock on dict item:'
-:unlet! d
-:let d = {'a': 99, 'b': 100}
-:lockvar d.a
-:try
-: unlet d.a
-: $put ='did :unlet'
-:catch
-: $put =v:exception[:16]
-:endtry
-:$put =string(d)
-:"
-:$put ='filter() after lock on dict item:'
-:unlet! d
-:let d = {'a': 99, 'b': 100}
-:lockvar d.a
-:try
-: call filter(d, 'v:key != "a"')
-: $put ='did filter()'
-:catch
-: $put =v:exception[:16]
-:endtry
-:$put =string(d)
-:"
-:$put ='map() after lock on dict:'
-:unlet! d
-:let d = {'a': 99, 'b': 100}
-:lockvar 1 d
-:try
-: call map(d, 'v:val + 200')
-: $put ='did map()'
-:catch
-: $put =v:exception[:16]
-:endtry
-:$put =string(d)
-:"
-:$put ='No extend() after lock on dict item:'
-:unlet! d
-:let d = {'a': 99, 'b': 100}
-:lockvar d.a
-:try
-: $put =string(extend(d, {'a': 123}))
-: $put ='did extend()'
-:catch
-: $put =v:exception[:14]
-:endtry
-:$put =string(d)
-:"
-:$put ='No remove() of write-protected scope-level variable:'
-:fun! Tfunc(this_is_a_loooooooooong_parameter_name)
-: try
-: $put =string(remove(a:, 'this_is_a_loooooooooong_parameter_name'))
-: $put ='did remove()'
-: catch
-: $put =v:exception[:14]
-: endtry
-:endfun
-:call Tfunc('testval')
-:"
-:$put ='No extend() of write-protected scope-level variable:'
-:fun! Tfunc(this_is_a_loooooooooong_parameter_name)
-: try
-: $put =string(extend(a:, {'this_is_a_loooooooooong_parameter_name': 1234}))
-: $put ='did extend()'
-: catch
-: $put =v:exception[:14]
-: endtry
-:endfun
-:call Tfunc('testval')
-:"
-:$put ='No :unlet of variable in locked scope:'
-:let b:testvar = 123
-:lockvar 1 b:
-:try
-: unlet b:testvar
-: $put ='b:testvar was :unlet: '. (!exists('b:testvar'))
-:catch
-: $put =v:exception[:16]
-:endtry
-:unlockvar 1 b:
-:unlet! b:testvar
-:"
-:$put ='No :let += of locked list variable:'
-:let l = ['a', 'b', 3]
-:lockvar 1 l
-:try
-: let l += ['x']
-: $put ='did :let +='
-:catch
-: $put =v:exception[:14]
-:endtry
-:$put =string(l)
-:"
-:unlet l
-:let l = [1, 2, 3, 4]
-:lockvar! l
-:$put =string(l)
-:unlockvar l[1]
-:unlet l[0:1]
-:$put =string(l)
-:unlet l[1:2]
-:$put =string(l)
-:unlockvar l[1]
-:let l[0:1] = [0, 1]
-:$put =string(l)
-:let l[1:2] = [0, 1]
-:$put =string(l)
-:unlet l
-:" :lockvar/islocked() triggering script autoloading
-:set rtp+=./sautest
-:lockvar g:footest#x
-:unlockvar g:footest#x
-:$put ='locked g:footest#x:'.islocked('g:footest#x')
-:$put ='exists g:footest#x:'.exists('g:footest#x')
-:$put ='g:footest#x: '.g:footest#x
-:"
-:" a:000 function argument
-:" first the tests that should fail
-:try
-: let a:000 = [1, 2]
-:catch
-: $put ='caught a:000'
-:endtry
-:try
-: let a:000[0] = 9
-:catch
-: $put ='caught a:000[0]'
-:endtry
-:try
-: let a:000[2] = [9, 10]
-:catch
-: $put ='caught a:000[2]'
-:endtry
-:try
-: let a:000[3] = {9: 10}
-:catch
-: $put ='caught a:000[3]'
-:endtry
-:" now the tests that should pass
-:try
-: let a:000[2][1] = 9
-: call extend(a:000[2], [5, 6])
-: let a:000[3][5] = 8
-: let a:000[3]['a'] = 12
-: $put =string(a:000)
-:catch
-: $put ='caught ' . v:exception
-:endtry
-:"
-:" reverse(), sort(), uniq()
-:let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
-:$put =string(uniq(copy(l)))
-:$put =string(reverse(l))
-:$put =string(reverse(reverse(l)))
-:$put =string(sort(l))
-:$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 '))
-:$put =string(split(' aa bb ', '\W\+', 0))
-:$put =string(split(' aa bb ', '\W\+', 1))
-:$put =string(split(' aa bb ', '\W', 1))
-:$put =string(split(':aa::bb:', ':', 0))
-:$put =string(split(':aa::bb:', ':', 1))
-:$put =string(split('aa,,bb, cc,', ',\s*', 1))
-:$put =string(split('abc', '\zs'))
-:$put =string(split('abc', '\zs', 1))
-:"
-:" compare recursively linked list and dict
-:let l = [1, 2, 3, 4]
-:let d = {'1': 1, '2': l, '3': 3}
-:let l[1] = d
-:$put =(l == l)
-:$put =(d == d)
-:$put =(l != deepcopy(l))
-:$put =(d != deepcopy(d))
-:"
-:" compare complex recursively linked list and dict
-:let l = []
-:call add(l, l)
-:let dict4 = {"l": l}
-:call add(dict4.l, dict4)
-:let lcopy = deepcopy(l)
-:let dict4copy = deepcopy(dict4)
-:$put =(l == lcopy)
-:$put =(dict4 == dict4copy)
-:"
-:" Pass the same List to extend()
-:let l = [1, 2, 3, 4, 5]
-:call extend(l, l)
-:$put =string(l)
-:"
-:" Pass the same Dict to extend()
-:let d = { 'a': {'b': 'B'}}
-:call extend(d, d)
-:$put =string(d)
-:"
-:" Pass the same Dict to extend() with "error"
-:try
-: call extend(d, d, "error")
-:catch
-: $put =v:exception[:15] . v:exception[-1:-1]
-:endtry
-:$put =string(d)
-:"
-:" test for range assign
-:let l = [0]
-:let l[:] = [1, 2]
-:$put =string(l)
-:endfun
-:"
-:call Test(1, 2, [3, 4], {5: 6}) " This may take a while
-:"
-:delfunc Test
-:unlet dict
-:call garbagecollect(1)
-:"
-:" test for patch 7.3.637
-:let a = 'No error caught'
-:try|foldopen|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry
-o=a :"
-:lang C
-:redir => a
-:try|foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry
-:redir END
-o=a :"
-:"
-:/^start:/,$wq! test.out
-ENDTEST
-
-start:
diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok
deleted file mode 100644
index 607a95ead9..0000000000
--- a/src/nvim/testdir/test55.ok
+++ /dev/null
@@ -1,199 +0,0 @@
-start:
-[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]
-{'a': 1}
-1
-Vim(put):E684:
-[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]
-['as''d', [1, 2, function('strlen')], {'a': 1}]
-[1, 'as''d', [1, 2, function('strlen')]]
-[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]
-[]
-101101
-{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}asd
-['-1', '1', 'b']
-['asd', [1, 2, function('strlen')], {'a': 1}]
-1:'asd'
-b:[1, 2, function('strlen')]
--1:{'a': 1}
-Vim(call):E737: 3
-{'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}
-{'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}
-101101
-Vim(let):E706: d
-Vim(let):E706: l
-[1, 'as''d', {'a': 1}]
-[4]
-{'1': 99, '3': 33}
-[0, 1, 2, 3]
-[0, 1, 3]
-[0, 1]
-[0, 1]
-[0, 1]
-[0, 1, 2, 3]
-[0, 1, 3]
-[0, 3]
-[3]
-[3]
-[3]
-2
-3
-Vim(let):E687:
-Vim(let):E688:
-3000 2900 2001 1600 1501
-Vim(let):E716: 1500
-NONE 2999
-33=999
-{'33': 999}
-len: 3
-again: 3
-Vim(call):E725:
-g:dict.func-4
-a:function('3')
-Vim(let):E698:
-same list: 1
-depth is 0
-0000-000
-ppppppp
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 1
-1000-000
-ppppppF
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 2
-1100-100
-ppFppFF
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 3
-1110-110
-pFFpFFF
-0010-010
-pFppFpp
-0000-000
-ppppppp
-depth is 4
-1111-111
-FFFFFFF
-0011-011
-FFpFFpp
-0000-000
-ppppppp
-Unletting:
-depth is 0
-0000-000
-ppppppp
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 1
-1000-000
-ppFppFp
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 2
-1100-100
-pFFpFFp
-0000-000
-ppppppp
-0000-000
-ppppppp
-depth is 3
-1110-110
-FFFFFFp
-0010-010
-FppFppp
-0000-000
-ppppppp
-depth is 4
-1111-111
-FFFFFFp
-0011-011
-FppFppp
-0000-000
-ppppppp
-Locks and commands or functions:
-No :unlet after lock on dict:
-Vim(unlet):E741:
-{'a': 99, 'b': 100}
-:unlet after lock on dict item:
-did :unlet
-{'b': 100}
-filter() after lock on dict item:
-did filter()
-{'b': 100}
-map() after lock on dict:
-did map()
-{'a': 299, 'b': 300}
-No extend() after lock on dict item:
-Vim(put):E741:
-{'a': 99, 'b': 100}
-No remove() of write-protected scope-level variable:
-Vim(put):E795:
-No extend() of write-protected scope-level variable:
-Vim(put):E742:
-No :unlet of variable in locked scope:
-Vim(unlet):E741:
-No :let += of locked list variable:
-Vim(let):E741:
-['a', 'b', 3]
-[1, 2, 3, 4]
-[1, 2, 3, 4]
-[1, 2, 3, 4]
-[1, 2, 3, 4]
-[1, 2, 3, 4]
-locked g:footest#x:-1
-exists g:footest#x:0
-g:footest#x: 1
-caught a:000
-caught a:000[0]
-caught a:000[2]
-caught a:000[3]
-[1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}]
-['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
-[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0']
-[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0']
-['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]]
-[[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', '']
-['', '', 'aa', '', 'bb', '', '']
-['aa', '', 'bb']
-['', 'aa', '', 'bb', '']
-['aa', '', 'bb', 'cc', '']
-['a', 'b', 'c']
-['', 'a', '', 'b', '', 'c', '']
-1
-1
-0
-0
-1
-1
-[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
-{'a': {'b': 'B'}}
-Vim(call):E737: a
-{'a': {'b': 'B'}}
-[1, 2]
-Vim(foldopen):E490:
-
-
-Error detected while processing :
-E492: Not an editor command: foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry
-
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 1d1da94bac..ad9b2cce8b 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -1,3 +1,7 @@
" A series of tests that can run in one Vim invocation.
" This makes testing go faster, since Vim doesn't need to restart.
+source test_assign.vim
+source test_cursor_func.vim
+source test_menu.vim
+source test_unlet.vim
diff --git a/src/nvim/testdir/test_assign.vim b/src/nvim/testdir/test_assign.vim
new file mode 100644
index 0000000000..3d2e7a8998
--- /dev/null
+++ b/src/nvim/testdir/test_assign.vim
@@ -0,0 +1,9 @@
+" Test for assignment
+
+func Test_no_type_checking()
+ let v = 1
+ let v = [1,2,3]
+ let v = {'a':1, 'b':2}
+ let v = 3.4
+ let v = 'hello'
+endfunc
diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim
new file mode 100644
index 0000000000..4629d17dd2
--- /dev/null
+++ b/src/nvim/testdir/test_hardcopy.vim
@@ -0,0 +1,58 @@
+" Test :hardcopy
+
+func Test_printoptions_parsing()
+ " Only test that this doesn't throw an error.
+ set printoptions=left:5in,right:10pt,top:8mm,bottom:2pc
+ set printoptions=left:2in,top:30pt,right:16mm,bottom:3pc
+ set printoptions=header:3,syntax:y,number:7,wrap:n
+ set printoptions=duplex:short,collate:n,jobsplit:y,portrait:n
+ set printoptions=paper:10x14
+ set printoptions=paper:A3
+ set printoptions=paper:A4
+ set printoptions=paper:A5
+ set printoptions=paper:B4
+ set printoptions=paper:B5
+ set printoptions=paper:executive
+ set printoptions=paper:folio
+ set printoptions=paper:ledger
+ set printoptions=paper:legal
+ set printoptions=paper:letter
+ set printoptions=paper:quarto
+ set printoptions=paper:statement
+ set printoptions=paper:tabloid
+ set printoptions=formfeed:y
+ set printoptions=
+ set printoptions&
+endfunc
+
+func Test_printmbfont_parsing()
+ " Only test that this doesn't throw an error.
+ set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no
+ set printmbfont=
+ set printmbfont&
+endfunc
+
+func Test_printheader_parsing()
+ " Only test that this doesn't throw an error.
+ set printheader=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+ set printheader=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
+ set printheader=%<%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b'
+ set printheader=...%r%{VarExists('b:gzflag','\ [GZ]')}%h...
+ set printheader=
+ set printheader&
+endfunc
+
+" Test that :hardcopy produces a non-empty file.
+" We don't check much of the contents.
+func Test_with_syntax()
+ if has('postscript')
+ set printoptions=syntax:y
+ syn on
+ hardcopy > Xhardcopy
+ let lines = readfile('Xhardcopy')
+ call assert_true(len(lines) > 20)
+ call assert_true(lines[0] =~ 'PS-Adobe')
+ call delete('Xhardcopy')
+ set printoptions&
+ endif
+endfunc
diff --git a/src/nvim/testdir/test_langmap.vim b/src/nvim/testdir/test_langmap.vim
new file mode 100644
index 0000000000..066c3bf2bd
--- /dev/null
+++ b/src/nvim/testdir/test_langmap.vim
@@ -0,0 +1,24 @@
+" tests for 'langmap'
+
+func Test_langmap()
+ new
+ set langmap=}l,^x,%v
+
+ call setline(1, ['abc'])
+ call feedkeys('gg0}^', 'tx')
+ call assert_equal('ac', getline(1))
+
+ " in Replace mode
+ " need silent! to avoid a delay when entering Insert mode
+ call setline(1, ['abcde'])
+ silent! call feedkeys("gg0lR%{z\<Esc>00", 'tx')
+ call assert_equal('a%{ze', getline(1))
+
+ " in Select mode
+ " need silent! to avoid a delay when entering Insert mode
+ call setline(1, ['abcde'])
+ silent! call feedkeys("gg0}%}\<C-G>}^\<Esc>00", 'tx')
+ call assert_equal('a}^de', getline(1))
+
+ quit!
+endfunc
diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in
deleted file mode 100644
index b5bac080ee..0000000000
--- a/src/nvim/testdir/test_listlbr.in
+++ /dev/null
@@ -1,119 +0,0 @@
-Test for linebreak and list option (non-utf8)
-
-STARTTEST
-:if !exists("+linebreak") | e! test.ok | w! test.out | qa! | endif
-:set wildchar=^E
-:10new|:vsp|:vert resize 20
-:put =\"\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP \"
-:norm! zt
-:set ts=4 sw=4 sts=4 linebreak sbr=+ wrap
-:fu! ScreenChar(width)
-: let c=''
-: for j in range(1,4)
-: for i in range(1,a:width)
-: let c.=nr2char(screenchar(j, i))
-: endfor
-: let c.="\n"
-: endfor
-: return c
-:endfu
-:fu! DoRecordScreen()
-: wincmd l
-: $put =printf(\"\n%s\", g:test)
-: $put =g:line
-: wincmd p
-:endfu
-:"
-:let g:test="Test 1: set linebreak"
-:redraw!
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:"
-:let g:test="Test 2: set linebreak + set list"
-:set linebreak list listchars=
-:redraw!
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:"
-:let g:test ="Test 3: set linebreak nolist"
-:set nolist linebreak
-:redraw!
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:"
-:let g:test ="Test 4: set linebreak with tab and 1 line as long as screen: should break!"
-:set nolist linebreak ts=8
-:let line="1\t".repeat('a', winwidth(0)-2)
-:$put =line
-:$
-:norm! zt
-:redraw!
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:let line="_S_\t bla"
-:$put =line
-:$
-:norm! zt
-:"
-:let g:test ="Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated)"
-:set cpo&vim list linebreak conceallevel=2 concealcursor=nv listchars=tab:ab
-:syn match ConcealVar contained /_/ conceal
-:syn match All /.*/ contains=ConcealVar
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:set cpo&vim linebreak
-:"
-:let g:test ="Test 6: set linebreak with visual block mode"
-:let line="REMOVE: this not"
-:$put =g:test
-:$put =line
-:let line="REMOVE: aaaaaaaaaaaaa"
-:$put =line
-:1/^REMOVE:
-0jf x:$put
-:set cpo&vim linebreak
-:"
-:let g:test ="Test 7: set linebreak with visual block mode and v_b_A"
-:$put =g:test
-Golong line: 40afoobar aTARGET at end
-:exe "norm! $3B\<C-v>eAx\<Esc>"
-:set cpo&vim linebreak sbr=
-:"
-:let g:test ="Test 8: set linebreak with visual char mode and changing block"
-:$put =g:test
-Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj.
-:"
-:let g:test ="Test 9: using redo after block visual mode"
-:$put =g:test
-Go
-aaa
-aaa
-a2k2j~e.
-:"
-:let g:test ="Test 10: using normal commands after block-visual"
-:$put =g:test
-:set linebreak
-Go
-abcd{ef
-ghijklm
-no}pqrs2k0f{c%
-:"
-:let g:test ="Test 11: using block replace mode after wrapping"
-:$put =g:test
-:set linebreak wrap
-Go150aayypk147|jr0
-:"
-:let g:test ="Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$"
-:set list listchars=space:_,trail:-,tab:>-,eol:$
-:$put =g:test
-:let line="a aaaaaaaaaaaaaaaaaaaaaa\ta "
-:$put =line
-:$
-:norm! zt
-:redraw!
-:let line=ScreenChar(winwidth(0))
-:call DoRecordScreen()
-:%w! test.out
-:qa!
-ENDTEST
-dummy text
diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok
deleted file mode 100644
index b32a54969e..0000000000
--- a/src/nvim/testdir/test_listlbr.ok
+++ /dev/null
@@ -1,62 +0,0 @@
-
- abcdef hijklmn pqrstuvwxyz_1060ABCDEFGHIJKLMNOP
-
-Test 1: set linebreak
- abcdef
-+hijklmn
-+pqrstuvwxyz_1060ABC
-+DEFGHIJKLMNOP
-
-Test 2: set linebreak + set list
-^Iabcdef hijklmn^I
-+pqrstuvwxyz_1060ABC
-+DEFGHIJKLMNOP
-
-
-Test 3: set linebreak nolist
- abcdef
-+hijklmn
-+pqrstuvwxyz_1060ABC
-+DEFGHIJKLMNOP
-1 aaaaaaaaaaaaaaaaaa
-
-Test 4: set linebreak with tab and 1 line as long as screen: should break!
-1
-+aaaaaaaaaaaaaaaaaa
-~
-~
-_S_ bla
-
-Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated)
-Sabbbbbb bla
-~
-~
-~
-Test 6: set linebreak with visual block mode
-this not
-aaaaaaaaaaaaa
-REMOVE:
-REMOVE:
-Test 7: set linebreak with visual block mode and v_b_A
-long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end
-Test 8: set linebreak with visual char mode and changing block
-1111-2222-1111-11-1111-2222-1111
-Test 9: using redo after block visual mode
-
-AaA
-AaA
-A
-Test 10: using normal commands after block-visual
-
-abcdpqrs
-Test 11: using block replace mode after wrapping
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa
-Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$
-a aaaaaaaaaaaaaaaaaaaaaa a
-
-Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$
-a_
-aaaaaaaaaaaaaaaaaaaa
-aa>-----a-$
-~
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
new file mode 100644
index 0000000000..309c0f460b
--- /dev/null
+++ b/src/nvim/testdir/test_syntax.vim
@@ -0,0 +1,63 @@
+" Test for syntax and syntax iskeyword option
+
+func GetSyntaxItem(pat)
+ let c = ''
+ let a = ['a', getreg('a'), getregtype('a')]
+ 0
+ redraw!
+ call search(a:pat, 'W')
+ let synid = synID(line('.'), col('.'), 1)
+ while synid == synID(line('.'), col('.'), 1)
+ norm! v"ay
+ " stop at whitespace
+ if @a =~# '\s'
+ break
+ endif
+ let c .= @a
+ norm! l
+ endw
+ call call('setreg', a)
+ 0
+ return c
+endfunc
+
+func Test_syn_iskeyword()
+ new
+ call setline(1, [
+ \ 'CREATE TABLE FOOBAR(',
+ \ ' DLTD_BY VARCHAR2(100)',
+ \ ');',
+ \ ''])
+
+ syntax on
+ set ft=sql
+ syn match SYN /C\k\+\>/
+ hi link SYN ErrorMsg
+ call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
+ /\<D\k\+\>/:norm! ygn
+ call assert_equal('DLTD_BY', @0)
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword not set", @c)
+
+ syn iskeyword @,48-57,_,192-255
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c)
+
+ setlocal isk-=_
+ call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
+ /\<D\k\+\>/:norm! ygn
+ let b2=@0
+ call assert_equal('DLTD', @0)
+
+ syn iskeyword clear
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword not set", @c)
+
+ quit!
+endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
new file mode 100644
index 0000000000..9f58a35909
--- /dev/null
+++ b/src/nvim/testdir/test_timers.vim
@@ -0,0 +1,32 @@
+" Test for timers
+
+if !has('timers')
+ finish
+endif
+
+func MyHandler(timer)
+ let s:val += 1
+endfunc
+
+func Test_oneshot()
+ let s:val = 0
+ let timer = timer_start(50, 'MyHandler')
+ sleep 200m
+ call assert_equal(1, s:val)
+endfunc
+
+func Test_repeat_three()
+ let s:val = 0
+ let timer = timer_start(50, 'MyHandler', {'repeat': 3})
+ sleep 500m
+ call assert_equal(3, s:val)
+endfunc
+
+func Test_repeat_many()
+ let s:val = 0
+ let timer = timer_start(50, 'MyHandler', {'repeat': -1})
+ sleep 200m
+ call timer_stop(timer)
+ call assert_true(s:val > 1)
+ call assert_true(s:val < 5)
+endfunc
diff --git a/src/nvim/testdir/test_unlet.vim b/src/nvim/testdir/test_unlet.vim
new file mode 100644
index 0000000000..f6705997a9
--- /dev/null
+++ b/src/nvim/testdir/test_unlet.vim
@@ -0,0 +1,26 @@
+" Tests for :unlet
+
+func Test_read_only()
+ try
+ " this caused a crash
+ unlet count
+ catch
+ call assert_true(v:exception =~ ':E795:')
+ endtry
+endfunc
+
+func Test_existing()
+ let does_exist = 1
+ call assert_true(exists('does_exist'))
+ unlet does_exist
+ call assert_false(exists('does_exist'))
+endfunc
+
+func Test_not_existing()
+ unlet! does_not_exist
+ try
+ unlet does_not_exist
+ catch
+ call assert_true(v:exception =~ ':E108:')
+ endtry
+endfunc
diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_viml.vim
index 9f0618bd45..c39c5e6b28 100644
--- a/src/nvim/testdir/test_viml.vim
+++ b/src/nvim/testdir/test_viml.vim
@@ -55,16 +55,26 @@ endfunction
" ExecAsScript - Source a temporary script made from a function. {{{2
"
" Make a temporary script file from the function a:funcname, ":source" it, and
-" delete it afterwards.
+" delete it afterwards. However, if an exception is thrown the file may remain,
+" the caller should call DeleteTheScript() afterwards.
+let s:script_name = ''
function! ExecAsScript(funcname)
" Make a script from the function passed as argument.
- let script = MakeScript(a:funcname)
+ let s:script_name = MakeScript(a:funcname)
" Source and delete the script.
- exec "source" script
- call delete(script)
+ exec "source" s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
endfunction
+function! DeleteTheScript()
+ if s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
+ endif
+endfunc
+
com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
@@ -143,6 +153,7 @@ func Test_endwhile_script()
XpathINIT
ExecAsScript T1_F
Xpath 'F'
+ call DeleteTheScript()
try
ExecAsScript T1_G
@@ -152,6 +163,7 @@ func Test_endwhile_script()
Xpath 'x'
endtry
Xpath 'G'
+ call DeleteTheScript()
call assert_equal('abcFhijxG', g:Xpath)
endfunc
@@ -260,6 +272,7 @@ function Test_finish()
XpathINIT
ExecAsScript T4_F
Xpath '5'
+ call DeleteTheScript()
call assert_equal('ab3e3b2c25', g:Xpath)
endfunction
@@ -922,6 +935,45 @@ func Test_curlies()
call assert_equal(77, g:a['t'])
endfunc
+"-------------------------------------------------------------------------------
+" Test 91: using type(). {{{1
+"-------------------------------------------------------------------------------
+
+func Test_type()
+ call assert_equal(0, type(0))
+ call assert_equal(1, type(""))
+ call assert_equal(2, type(function("tr")))
+ call assert_equal(3, type([]))
+ call assert_equal(4, type({}))
+ call assert_equal(5, type(0.0))
+ call assert_equal(6, type(v:false))
+ call assert_equal(6, type(v:true))
+ call assert_equal(7, type(v:null))
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 92: skipping code {{{1
+"-------------------------------------------------------------------------------
+
+func Test_skip()
+ let Fn = function('Test_type')
+ call assert_false(0 && Fn[1])
+ call assert_false(0 && string(Fn))
+ call assert_false(0 && len(Fn))
+ let l = []
+ call assert_false(0 && l[1])
+ call assert_false(0 && string(l))
+ call assert_false(0 && len(l))
+ let f = 1.0
+ call assert_false(0 && f[1])
+ call assert_false(0 && string(f))
+ call assert_false(0 && len(f))
+ let sp = v:null
+ call assert_false(0 && sp[1])
+ call assert_false(0 && string(sp))
+ call assert_false(0 && len(sp))
+
+endfunc
"-------------------------------------------------------------------------------
" Modelines {{{1
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
new file mode 100644
index 0000000000..83bae967e2
--- /dev/null
+++ b/src/nvim/testdir/test_visual.vim
@@ -0,0 +1,18 @@
+" Tests for Visual mode
+if !has('multi_byte')
+ finish
+endif
+scriptencoding utf-8
+
+if !has('visual')
+ finish
+endif
+
+func Test_block_shift_multibyte()
+ split
+ call setline(1, ['xヹxxx', 'ヹxxx'])
+ exe "normal 1G0l\<C-V>jl>"
+ call assert_equal('x ヹxxx', getline(1))
+ call assert_equal(' ヹxxx', getline(2))
+ q!
+endfunc
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 99eb230a88..be256f3ebc 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -4,6 +4,7 @@
#include "nvim/api/vim.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
+#include "nvim/main.h"
#include "nvim/misc2.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
@@ -92,7 +93,7 @@ static void flush_input(TermInput *input, bool wait_until_empty)
size_t drain_boundary = wait_until_empty ? 0 : 0xff;
do {
uv_mutex_lock(&input->key_buffer_mutex);
- loop_schedule(&loop, event_create(1, wait_input_enqueue, 1, input));
+ loop_schedule(&main_loop, event_create(1, wait_input_enqueue, 1, input));
input->waiting = true;
while (input->waiting) {
uv_cond_wait(&input->key_buffer_cond, &input->key_buffer_mutex);
@@ -138,6 +139,9 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
if (key->type == TERMKEY_TYPE_KEYSYM
&& key->code.sym == TERMKEY_SYM_ESCAPE) {
len = (size_t)snprintf(buf, sizeof(buf), "<Esc>");
+ } else if (key->type == TERMKEY_TYPE_KEYSYM
+ && key->code.sym == TERMKEY_SYM_SUSPEND) {
+ len = (size_t)snprintf(buf, sizeof(buf), "<C-Z>");
} else {
len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM);
}
@@ -153,7 +157,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
TermKeyMouseEvent ev;
termkey_interpret_mouse(input->tk, key, &ev, &button, &row, &col);
- if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG) {
+ if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG
+ && ev != TERMKEY_MOUSE_RELEASE) {
return;
}
@@ -190,6 +195,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
}
} else if (ev == TERMKEY_MOUSE_DRAG) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag");
+ } else if (ev == TERMKEY_MOUSE_RELEASE) {
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release");
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
@@ -336,7 +343,7 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
stream_close(&input->read_stream, NULL);
queue_put(input->loop->fast_events, restart_reading, 1, input);
} else {
- loop_schedule(&loop, event_create(1, input_done_event, 0));
+ loop_schedule(&main_loop, event_create(1, input_done_event, 0));
}
return;
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 62bc81ba64..d220df508a 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -11,6 +11,7 @@
#include "nvim/vim.h"
#include "nvim/ui.h"
#include "nvim/map.h"
+#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/api/vim.h"
#include "nvim/api/private/helpers.h"
@@ -134,6 +135,8 @@ static void terminfo_start(UI *ui)
data->ut = unibi_dummy();
}
fix_terminfo(data);
+ // Set 't_Co' from the result of unibilium & fix_terminfo.
+ t_colors = unibi_get_num(data->ut, unibi_max_colors);
// Enter alternate screen and clear
unibi_out(ui, unibi_enter_ca_mode);
unibi_out(ui, unibi_clear_screen);
@@ -261,7 +264,7 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
UI *ui = data;
update_size(ui);
// run refresh_event in nvim main loop
- loop_schedule(&loop, event_create(1, refresh_event, 0));
+ loop_schedule(&main_loop, event_create(1, refresh_event, 0));
}
static bool attrs_differ(HlAttrs a1, HlAttrs a2)
@@ -681,7 +684,7 @@ static void invalidate(UI *ui, int top, int bot, int left, int right)
intersects->right = MAX(right, intersects->right);
} else {
// Else just add a new entry;
- kv_push(Rect, data->invalid_regions, ((Rect){top, bot, left, right}));
+ kv_push(data->invalid_regions, ((Rect) { top, bot, left, right }));
}
}
@@ -785,6 +788,7 @@ static void fix_terminfo(TUIData *data)
unibi_term *ut = data->ut;
const char *term = os_getenv("TERM");
+ const char *colorterm = os_getenv("COLORTERM");
if (!term) {
goto end;
}
@@ -830,10 +834,10 @@ static void fix_terminfo(TUIData *data)
#define XTERM_SETAB \
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"
- if (os_getenv("COLORTERM") != NULL
- && (!strcmp(term, "xterm") || !strcmp(term, "screen"))) {
- // probably every modern terminal that sets TERM=xterm supports 256
- // colors(eg: gnome-terminal). Also do it when TERM=screen.
+ if ((colorterm && strstr(colorterm, "256"))
+ || strstr(term, "256")
+ || strstr(term, "xterm")) {
+ // Assume TERM~=xterm or COLORTERM~=256 supports 256 colors.
unibi_set_num(ut, unibi_max_colors, 256);
unibi_set_str(ut, unibi_set_a_foreground, XTERM_SETAF);
unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB);
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index ad6d96a168..268362bf1b 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -23,16 +23,16 @@ struct ugrid {
#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
-#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
- do { \
- for (int row = top; row <= bot; ++row) { \
- UCell *row_cells = (grid)->cells[row]; \
- for (int col = left; col <= right; ++col) { \
- UCell *cell = row_cells + col; \
- (void)(cell); \
- code; \
- } \
- } \
+#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
+ do { \
+ for (int row = top; row <= bot; row++) { \
+ UCell *row_cells = (grid)->cells[row]; \
+ for (int col = left; col <= right; col++) { \
+ UCell *cell = row_cells + col; \
+ (void)(cell); \
+ code; \
+ } \
+ } \
} while (0)
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 05322a6f64..d968cbc390 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -30,7 +30,11 @@
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/window.h"
-#include "nvim/tui/tui.h"
+#ifdef FEAT_TUI
+# include "nvim/tui/tui.h"
+#else
+# include "nvim/msgpack_rpc/server.h"
+#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui.c.generated.h"
@@ -56,22 +60,22 @@ static int height, width;
// See http://stackoverflow.com/a/11172679 for a better explanation of how it
// works.
#ifdef _MSC_VER
- #define UI_CALL(funname, ...) \
- do { \
- flush_cursor_update(); \
- for (size_t i = 0; i < ui_count; i++) { \
- UI *ui = uis[i]; \
- UI_CALL_MORE(funname, __VA_ARGS__); \
- } \
+# define UI_CALL(funname, ...) \
+ do { \
+ flush_cursor_update(); \
+ for (size_t i = 0; i < ui_count; i++) { \
+ UI *ui = uis[i]; \
+ UI_CALL_MORE(funname, __VA_ARGS__); \
+ } \
} while (0)
#else
- #define UI_CALL(...) \
- do { \
- flush_cursor_update(); \
- for (size_t i = 0; i < ui_count; i++) { \
- UI *ui = uis[i]; \
- UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \
- } \
+# define UI_CALL(...) \
+ do { \
+ flush_cursor_update(); \
+ for (size_t i = 0; i < ui_count; i++) { \
+ UI *ui = uis[i]; \
+ UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \
+ } \
} while (0)
#endif
#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore)
@@ -83,7 +87,22 @@ static int height, width;
void ui_builtin_start(void)
{
+#ifdef FEAT_TUI
tui_start();
+#else
+ fprintf(stderr, "Neovim was built without a Terminal UI," \
+ "press Ctrl+C to exit\n");
+
+ size_t len;
+ char **addrs = server_address_list(&len);
+ if (addrs != NULL) {
+ fprintf(stderr, "currently listening on the following address(es)\n");
+ for (size_t i = 0; i < len; i++) {
+ fprintf(stderr, "\t%s\n", addrs[i]);
+ }
+ xfree(addrs);
+ }
+#endif
}
void ui_builtin_stop(void)
@@ -188,7 +207,7 @@ void ui_mouse_off(void)
UI_CALL(mouse_off);
}
-void ui_attach(UI *ui)
+void ui_attach_impl(UI *ui)
{
if (ui_count == MAX_UI_COUNT) {
abort();
@@ -198,7 +217,7 @@ void ui_attach(UI *ui)
ui_refresh();
}
-void ui_detach(UI *ui)
+void ui_detach_impl(UI *ui)
{
size_t shift_index = MAX_UI_COUNT;
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index fd9d4671e3..6290fb3d87 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <limits.h>
+#include "nvim/main.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
#include "nvim/memory.h"
@@ -18,9 +19,9 @@
#define UI(b) (((UIBridgeData *)b)->ui)
// Call a function in the UI thread
-#define UI_CALL(ui, name, argc, ...) \
- ((UIBridgeData *)ui)->scheduler( \
- event_create(1, ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui))
+#define UI_CALL(ui, name, argc, ...) \
+ ((UIBridgeData *)ui)->scheduler( \
+ event_create(1, ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui))
#define INT2PTR(i) ((void *)(uintptr_t)i)
#define PTR2INT(p) ((int)(uintptr_t)p)
@@ -71,7 +72,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
}
uv_mutex_unlock(&rv->mutex);
- ui_attach(&rv->bridge);
+ ui_attach_impl(&rv->bridge);
return &rv->bridge;
}
@@ -100,12 +101,12 @@ static void ui_bridge_stop(UI *b)
if (stopped) {
break;
}
- loop_poll_events(&loop, 10);
+ loop_poll_events(&main_loop, 10);
}
uv_thread_join(&bridge->ui_thread);
uv_mutex_destroy(&bridge->mutex);
uv_cond_destroy(&bridge->cond);
- ui_detach(b);
+ ui_detach_impl(b);
xfree(b);
}
static void ui_bridge_stop_event(void **argv)
diff --git a/src/nvim/ui_bridge.h b/src/nvim/ui_bridge.h
index 31b9a69216..561ddb6b24 100644
--- a/src/nvim/ui_bridge.h
+++ b/src/nvim/ui_bridge.h
@@ -28,13 +28,13 @@ struct ui_bridge_data {
bool stopped;
};
-#define CONTINUE(b) \
- do { \
- UIBridgeData *d = (UIBridgeData *)b; \
- uv_mutex_lock(&d->mutex); \
- d->ready = true; \
- uv_cond_signal(&d->cond); \
- uv_mutex_unlock(&d->mutex); \
+#define CONTINUE(b) \
+ do { \
+ UIBridgeData *d = (UIBridgeData *)b; \
+ uv_mutex_lock(&d->mutex); \
+ d->ready = true; \
+ uv_cond_signal(&d->cond); \
+ uv_mutex_unlock(&d->mutex); \
} while (0)
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index f16b4264d7..fc5d6acaa4 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -712,7 +712,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
// When reading check if the file exists.
if (undo_file_name != NULL
- && (!reading || os_file_exists((char_u *)undo_file_name))) {
+ && (!reading || os_path_exists((char_u *)undo_file_name))) {
break;
}
xfree(undo_file_name);
@@ -1094,7 +1094,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
/* If the undo file already exists, verify that it actually is an undo
* file, and delete it. */
- if (os_file_exists((char_u *)file_name)) {
+ if (os_path_exists((char_u *)file_name)) {
if (name == NULL || !forceit) {
/* Check we can read it and it's an undo file. */
fd = os_open(file_name, O_RDONLY, 0);
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 23bfca6221..4a17660cd5 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -64,12 +64,22 @@ static char *features[] = {
#else
"-jemalloc",
#endif
+
+#ifdef FEAT_TUI
+ "+tui",
+#else
+ "-tui",
+#endif
NULL
};
// clang-format off
static int included_patches[] = {
+ 1973,
+ 1960,
+ 1840,
1832,
+ 1831,
1809,
1808,
1806,
@@ -78,20 +88,28 @@ static int included_patches[] = {
1755,
1753,
1728,
+ 1716,
+ 1712,
+ 1703,
+ 1695,
+ 1682,
+ 1663,
1654,
1652,
+ 1649,
1643,
1641,
+ // 1624 NA
// 1600 NA
// 1599 NA
// 1598 NA
// 1597 NA
- // 1596,
+ 1596,
// 1595 NA
// 1594 NA
// 1593 NA
- // 1592,
+ 1592,
// 1591,
// 1590,
// 1589,
@@ -105,40 +123,40 @@ static int included_patches[] = {
// 1581,
// 1580,
- // 1579,
- // 1578,
+ // 1579 NA
+ 1578,
// 1577,
1576,
// 1575 NA
1574,
- // 1573,
+ // 1573 NA
// 1572 NA
1571,
1570,
1569,
1568,
- // 1567,
+ 1567,
// 1566 NA
// 1565,
// 1564,
// 1563,
// 1562 NA
// 1561 NA
- // 1560,
+ // 1560 NA
// 1559,
// 1558,
// 1557,
- // 1556,
- // 1555,
- // 1554,
- // 1553,
- // 1552,
- // 1551,
- // 1550,
+ // 1556 NA
+ // 1555 NA
+ 1554,
+ 1553,
+ 1552,
+ 1551,
+ 1550,
// 1549,
- // 1548,
+ 1548,
// 1547,
- // 1546,
+ 1546,
// 1545 NA
// 1544 NA
// 1543 NA
@@ -156,7 +174,7 @@ static int included_patches[] = {
// 1531 NA
// 1530 NA
// 1529 NA
- // 1528,
+ 1528,
// 1527 NA
// 1526 NA
// 1525 NA
@@ -185,28 +203,28 @@ static int included_patches[] = {
// 1502 NA
// 1501 NA
1500,
- // 1499,
+ 1499,
// 1498 NA
// 1497 NA
// 1496 NA
// 1495 NA
// 1494,
// 1493 NA
- // 1492,
- // 1491,
+ 1492,
+ 1491,
// 1490 NA
// 1489 NA
// 1488 NA
// 1487 NA
- // 1486,
+ 1486,
// 1485 NA
// 1484 NA
// 1483 NA
// 1482 NA
// 1481 NA
- // 1480,
- // 1479,
- // 1478,
+ 1480,
+ 1479,
+ 1478,
// 1477,
// 1476 NA
// 1475 NA
@@ -216,11 +234,11 @@ static int included_patches[] = {
// 1471 NA
// 1470 NA
// 1469 NA
- // 1468,
+ 1468,
// 1467 NA
// 1466 NA
// 1465 NA
- // 1464,
+ 1464,
// 1463 NA
// 1462 NA
// 1461 NA
@@ -287,20 +305,20 @@ static int included_patches[] = {
// 1400 NA
// 1399 NA
// 1398 NA
- // 1397,
- // 1396,
+ 1397,
+ 1396,
// 1395 NA
- // 1394,
+ 1394,
// 1393 NA
// 1392 NA
// 1391 NA
// 1390 NA
// 1389 NA
- // 1388,
+ 1388,
// 1387 NA
// 1386 NA
// 1385 NA
- // 1384,
+ 1384,
// 1383 NA
// 1382 NA
// 1381 NA
@@ -319,7 +337,7 @@ static int included_patches[] = {
// 1368 NA
// 1367 NA
1366,
- // 1365,
+ 1365,
// 1364 NA
// 1363 NA
// 1362 NA
@@ -332,7 +350,7 @@ static int included_patches[] = {
// 1355 NA
// 1354 NA
// 1353 NA
- // 1352,
+ 1352,
// 1351 NA
// 1350 NA
// 1349 NA
@@ -403,12 +421,12 @@ static int included_patches[] = {
1284,
// 1283 NA
1282,
- // 1281,
+ 1281,
// 1280 NA
// 1279 NA
// 1278 NA
// 1277 NA
- // 1276,
+ 1276,
// 1275 NA
// 1274 NA
// 1273,
@@ -461,7 +479,7 @@ static int included_patches[] = {
// 1226 NA
// 1225 NA
// 1224 NA
- // 1223,
+ 1223,
// 1222 NA
// 1221 NA
// 1220 NA
@@ -498,14 +516,14 @@ static int included_patches[] = {
// 1189 NA
// 1188 NA
// 1187 NA
- // 1186,
+ // 1186 NA
// 1185 NA
// 1184 NA
// 1183 NA
// 1182 NA
1181,
1180,
- // 1179,
+ 1179,
1178,
// 1177 NA
// 1176 NA
@@ -523,7 +541,7 @@ static int included_patches[] = {
1164,
1163,
// 1162 NA
- // 1161,
+ 1161,
1160,
// 1159 NA
// 1158 NA
@@ -531,41 +549,41 @@ static int included_patches[] = {
// 1156 NA
// 1155 NA
// 1154 NA
- // 1153,
+ 1153,
// 1152 NA
- // 1151,
- // 1150,
+ 1151,
+ 1150,
1149,
// 1148 NA
- // 1147,
+ 1147,
// 1146 NA
// 1145 NA
1144,
1143,
- // 1142,
+ 1142,
1141,
- // 1140,
+ 1140,
// 1139 NA
// 1138 NA
1137,
- // 1136,
+ 1136,
// 1135 NA
// 1134 NA
// 1133 NA
- // 1132,
+ 1132,
// 1131 NA
- // 1130,
+ // 1130 NA
// 1129 NA
// 1128 NA
// 1127 NA
- // 1126,
+ 1126,
// 1125 NA
// 1124 NA
- // 1123,
+ 1123,
// 1122 NA
- // 1121,
+ 1121,
1120,
- // 1119,
+ 1119,
1118,
1117,
1116,
@@ -573,10 +591,10 @@ static int included_patches[] = {
1114,
1113,
1112,
- // 1111,
+ 1111,
1110,
// 1109 NA
- // 1108,
+ 1108,
1107,
// 1106 NA
1105,
@@ -587,14 +605,14 @@ static int included_patches[] = {
// 1100 NA
// 1099 NA
// 1098 NA
- // 1097,
- // 1096,
+ // 1097 NA
+ 1096,
// 1095 NA
- // 1094,
+ 1094,
1093,
1092,
1091,
- // 1090,
+ 1090,
1089,
1088,
1087,
@@ -605,35 +623,35 @@ static int included_patches[] = {
// 1082 NA
1081,
// 1080 NA
- // 1079,
+ // 1079 NA
// 1078 NA
// 1077 NA
1076,
1075,
// 1074 NA,
- // 1073,
+ // 1073 NA
1072,
- // 1071,
+ 1071,
// 1070 NA
// 1069 NA
- // 1068,
+ 1068,
// 1067 NA
// 1066 NA
1065,
- // 1064,
+ 1064,
// 1063 NA
// 1062 NA
1061,
// 1060 NA
1059,
- // 1058,
+ // 1058 NA
1057,
- // 1056,
+ 1056,
1055,
1054,
- // 1053,
+ 1053,
1052,
- // 1051,
+ 1051,
1050,
1049,
1048,
@@ -645,7 +663,7 @@ static int included_patches[] = {
1042,
1041,
// 1040 NA
- // 1039,
+ // 1039 NA
// 1038 NA
1037,
1036,
@@ -1895,21 +1913,15 @@ void intro_message(int colon)
N_("by Bram Moolenaar et al."),
N_("Vim is open source and freely distributable"),
"",
- N_("First time using a vi-like editor?"),
- N_("Type :Tutor<Enter> to get started!"),
+ N_("Type \":Tutor\" or \":help nvim\" to get started!"),
"",
- N_("Already know your way around Vim?"),
- N_("See :help nvim-intro for an introduction to Neovim."),
+ N_("Still have questions? https://neovim.io/community"),
"",
- N_("Still have questions?"),
- N_("Reach out to the Neovim community at neovim.io/community."),
+ N_("type :q<Enter> to exit "),
+ N_("type :help<Enter> or <F1> for on-line help"),
"",
N_("Help poor children in Uganda!"),
N_("type :help iccf<Enter> for information "),
- "",
- N_("type :q<Enter> to exit "),
- N_("type :help<Enter> or <F1> for on-line help"),
- N_("type :help nvim<Enter> for Neovim help "),
};
// blanklines = screen height - # message lines
@@ -2011,3 +2023,4 @@ void ex_intro(exarg_T *eap)
intro_message(TRUE);
wait_return(TRUE);
}
+
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 165a44a148..09e9e850a7 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -174,6 +174,7 @@ enum {
EXPAND_USER,
EXPAND_SYNTIME,
EXPAND_USER_ADDR_TYPE,
+ EXPAND_PACKADD,
};
@@ -307,4 +308,12 @@ enum {
# define SET_NO_HLSEARCH(flag) no_hlsearch = (flag); set_vim_var_nr( \
VV_HLSEARCH, !no_hlsearch && p_hls)
+// Used for flags in do_in_path()
+#define DIP_ALL 0x01 // all matches, not just the first one
+#define DIP_DIR 0x02 // find directories instead of files
+#define DIP_ERR 0x04 // give an error message when none found
+#define DIP_START 0x08 // also use "start" directory in 'packpath'
+#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
+#define DIP_NORTP 0x20 // do not use 'runtimepath'
+
#endif /* NVIM_VIM_H */
diff --git a/src/nvim/window.c b/src/nvim/window.c
index bea55c465f..e267d493bf 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -251,11 +251,14 @@ newwindow:
if (win_new_tabpage((int)Prenum, NULL) == OK
&& valid_tabpage(oldtab)) {
newtab = curtab;
- goto_tabpage_tp(oldtab, TRUE, TRUE);
- if (curwin == wp)
- win_close(curwin, FALSE);
- if (valid_tabpage(newtab))
- goto_tabpage_tp(newtab, TRUE, TRUE);
+ goto_tabpage_tp(oldtab, true, true);
+ if (curwin == wp) {
+ win_close(curwin, false);
+ }
+ if (valid_tabpage(newtab)) {
+ goto_tabpage_tp(newtab, true, true);
+ apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf);
+ }
}
}
break;
@@ -3293,8 +3296,11 @@ void tabpage_move(int nr)
tabpage_T *tp;
tabpage_T *tp_dst;
- if (first_tabpage->tp_next == NULL)
+ assert(curtab != NULL);
+
+ if (first_tabpage->tp_next == NULL) {
return;
+ }
for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) {
++n;
@@ -3613,6 +3619,10 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
/* Change directories when the 'acd' option is set. */
do_autochdir();
+
+ if (curbuf->terminal) {
+ terminal_resize(curbuf->terminal, curwin->w_width, curwin->w_height);
+ }
}