aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py1
-rw-r--r--src/klib/khash.h135
-rw-r--r--src/nvim/CMakeLists.txt38
-rw-r--r--src/nvim/README.md3
-rw-r--r--src/nvim/api/autocmd.c16
-rw-r--r--src/nvim/api/buffer.c2
-rw-r--r--src/nvim/api/command.c5
-rw-r--r--src/nvim/api/deprecated.c220
-rw-r--r--src/nvim/api/extmark.c26
-rw-r--r--src/nvim/api/extmark.h1
-rw-r--r--src/nvim/api/options.c218
-rw-r--r--src/nvim/api/options.h1
-rw-r--r--src/nvim/api/private/converter.h2
-rw-r--r--src/nvim/api/private/helpers.c10
-rw-r--r--src/nvim/api/private/helpers.h16
-rw-r--r--src/nvim/api/ui.c4
-rw-r--r--src/nvim/api/vim.c8
-rw-r--r--src/nvim/api/vimscript.c10
-rw-r--r--src/nvim/api/win_config.c8
-rw-r--r--src/nvim/arglist.h2
-rw-r--r--src/nvim/autocmd.c24
-rw-r--r--src/nvim/buffer.c61
-rw-r--r--src/nvim/buffer_defs.h3
-rw-r--r--src/nvim/bufwrite.c16
-rw-r--r--src/nvim/change.c26
-rw-r--r--src/nvim/channel.c16
-rw-r--r--src/nvim/channel.h2
-rw-r--r--src/nvim/charset.c15
-rw-r--r--src/nvim/charset.h2
-rw-r--r--src/nvim/cmdexpand.h2
-rw-r--r--src/nvim/cmdhist.c7
-rw-r--r--src/nvim/cmdhist.h1
-rw-r--r--src/nvim/cursor_shape.c4
-rw-r--r--src/nvim/decoration.c7
-rw-r--r--src/nvim/decoration.h4
-rw-r--r--src/nvim/drawline.c336
-rw-r--r--src/nvim/drawscreen.c9
-rw-r--r--src/nvim/edit.c17
-rw-r--r--src/nvim/eval.c17
-rw-r--r--src/nvim/eval/decode.h4
-rw-r--r--src/nvim/eval/executor.h2
-rw-r--r--src/nvim/eval/funcs.h1
-rw-r--r--src/nvim/eval/gc.h1
-rw-r--r--src/nvim/eval/typval.c22
-rw-r--r--src/nvim/eval/typval.h4
-rw-r--r--src/nvim/eval/typval_encode.h2
-rw-r--r--src/nvim/eval/userfunc.c18
-rw-r--r--src/nvim/eval/userfunc.h1
-rw-r--r--src/nvim/event/process.h1
-rw-r--r--src/nvim/ex_cmds.c30
-rw-r--r--src/nvim/ex_cmds.h1
-rw-r--r--src/nvim/ex_cmds_defs.h2
-rw-r--r--src/nvim/ex_docmd.c28
-rw-r--r--src/nvim/ex_getln.c20
-rw-r--r--src/nvim/ex_getln.h1
-rw-r--r--src/nvim/extmark.c25
-rw-r--r--src/nvim/fileio.c30
-rw-r--r--src/nvim/fileio.h1
-rw-r--r--src/nvim/generators/gen_ex_cmds.lua1
-rw-r--r--src/nvim/getchar.c51
-rw-r--r--src/nvim/globals.h7
-rw-r--r--src/nvim/grid.c3
-rw-r--r--src/nvim/help.c1
-rw-r--r--src/nvim/highlight.c53
-rw-r--r--src/nvim/highlight_group.c19
-rw-r--r--src/nvim/lua/converter.h2
-rw-r--r--src/nvim/lua/executor.c97
-rw-r--r--src/nvim/lua/executor.h4
-rw-r--r--src/nvim/lua/secure.c118
-rw-r--r--src/nvim/lua/secure.h12
-rw-r--r--src/nvim/lua/treesitter.c123
-rw-r--r--src/nvim/main.c18
-rw-r--r--src/nvim/map.c109
-rw-r--r--src/nvim/map.h104
-rw-r--r--src/nvim/map_defs.h12
-rw-r--r--src/nvim/mapping.c10
-rw-r--r--src/nvim/mark_defs.h2
-rw-r--r--src/nvim/marktree.c6
-rw-r--r--src/nvim/marktree.h1
-rw-r--r--src/nvim/mbyte.c18
-rw-r--r--src/nvim/mbyte.h2
-rw-r--r--src/nvim/memory.c2
-rw-r--r--src/nvim/menu.c4
-rw-r--r--src/nvim/message.c6
-rw-r--r--src/nvim/move.c144
-rw-r--r--src/nvim/msgpack_rpc/channel.c53
-rw-r--r--src/nvim/msgpack_rpc/channel_defs.h2
-rw-r--r--src/nvim/normal.c11
-rw-r--r--src/nvim/ops.c20
-rw-r--r--src/nvim/ops.h5
-rw-r--r--src/nvim/option.c6
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/optionstr.c12
-rw-r--r--src/nvim/os/process.c2
-rw-r--r--src/nvim/os/pty_process_win.c1
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/os/time.c2
-rw-r--r--src/nvim/plines.c85
-rw-r--r--src/nvim/plines.h6
-rw-r--r--src/nvim/popupmenu.c10
-rw-r--r--src/nvim/runtime.c37
-rw-r--r--src/nvim/runtime.h1
-rw-r--r--src/nvim/search.c4
-rw-r--r--src/nvim/search.h1
-rw-r--r--src/nvim/shada.c214
-rw-r--r--src/nvim/spell.c39
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/spellsuggest.c2
-rw-r--r--src/nvim/statusline.c4
-rw-r--r--src/nvim/strings.c37
-rw-r--r--src/nvim/strings.h2
-rw-r--r--src/nvim/tag.c21
-rw-r--r--src/nvim/terminal.c23
-rw-r--r--src/nvim/testing.c4
-rw-r--r--src/nvim/testing.h2
-rw-r--r--src/nvim/textobject.c3
-rw-r--r--src/nvim/tui/input.c21
-rw-r--r--src/nvim/tui/tui.c35
-rw-r--r--src/nvim/ui.c20
-rw-r--r--src/nvim/ui_client.c4
-rw-r--r--src/nvim/undo.c9
-rw-r--r--src/nvim/usercmd.c22
-rw-r--r--src/nvim/viml/parser/expressions.c2
-rw-r--r--src/nvim/viml/parser/expressions.h1
-rw-r--r--src/nvim/window.c63
-rw-r--r--src/nvim/window.h6
-rw-r--r--src/uncrustify.cfg57
127 files changed, 1928 insertions, 1345 deletions
diff --git a/src/clint.py b/src/clint.py
index a6649763c2..ee2d0ecc3c 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -2244,6 +2244,7 @@ def CheckSpacing(filename, clean_lines, linenum, error):
r'(?<!\bkbtree_t)'
r'(?<!\bkbitr_t)'
r'(?<!\bPMap)'
+ r'(?<!\bSet)'
r'(?<!\bArrayOf)'
r'(?<!\bDictionaryOf)'
r'(?<!\bDict)'
diff --git a/src/klib/khash.h b/src/klib/khash.h
index 57a41f9c13..eb1714c471 100644
--- a/src/klib/khash.h
+++ b/src/klib/khash.h
@@ -185,41 +185,46 @@ typedef khint_t khiter_t;
#define __ac_HASH_UPPER 0.77
-#define __KHASH_TYPE(name, khkey_t, khval_t) \
+// This is only used for stack temporaries. Heap allocation is done with precise sizes.
+#define KHASH_MAX_VAL_SIZE 32
+
+#define __KHASH_TYPE(name, khkey_t) \
typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
- khval_t *vals; \
+ char *vals_buf; \
} kh_##name##_t;
-#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
+#define __KHASH_PROTOTYPES(name, khkey_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_dealloc_##name(kh_##name##_t *h); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
- extern void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
- extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
+ extern void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets, size_t val_size); \
+ extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret, size_t val_size); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
-#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \
- __hash_equal) \
+#define kh_bval(h, x) (&(h)->vals_buf[val_size*(x)])
+#define kh_copyval(to, from) memcpy(to, from, val_size)
+
+#define __KHASH_IMPL(name, SCOPE, khkey_t, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_dealloc_##name(kh_##name##_t *h) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE void kh_dealloc_##name(kh_##name##_t *h) \
{ \
kfree(h->keys); \
kfree(h->flags); \
- kfree(h->vals); \
+ kfree(h->vals_buf); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
@@ -228,7 +233,7 @@ typedef khint_t khiter_t;
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
@@ -237,7 +242,7 @@ typedef khint_t khiter_t;
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
@@ -257,9 +262,9 @@ typedef khint_t khiter_t;
return 0; \
} \
} \
- SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
- REAL_FATTR_UNUSED; \
- SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
+ SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets, size_t val_size) \
+ REAL_FATTR_UNUSED; \
+ SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets, size_t val_size) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of */ \
/* [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
@@ -280,23 +285,23 @@ typedef khint_t khiter_t;
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
h->keys = new_keys; \
- if (kh_is_map) { \
- khval_t *new_vals = \
- (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
- h->vals = new_vals; \
+ if (val_size) { \
+ char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size); \
+ h->vals_buf = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
+ char cval[KHASH_MAX_VAL_SIZE]; \
+ char ctmp[KHASH_MAX_VAL_SIZE]; \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
- khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
- if (kh_is_map) { \
- val = h->vals[j]; \
+ if (val_size) { \
+ kh_copyval(cval, kh_bval(h, j)); \
} \
__ac_set_isdel_true(h->flags, j); \
/* kick-out process; sort of like in Cuckoo hashing */ \
@@ -315,17 +320,17 @@ typedef khint_t khiter_t;
h->keys[i] = key; \
key = tmp; \
} \
- if (kh_is_map) { \
- khval_t tmp = h->vals[i]; \
- h->vals[i] = val; \
- val = tmp; \
+ if (val_size) { \
+ kh_copyval(ctmp, kh_bval(h, i)); \
+ kh_copyval(kh_bval(h, i), cval); \
+ kh_copyval(cval, ctmp); \
} \
/* mark it as deleted in the old hash table */ \
__ac_set_isdel_true(h->flags, i); \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
- if (kh_is_map) { \
- h->vals[i] = val; \
+ if (val_size) { \
+ kh_copyval(kh_bval(h, i), cval); \
} \
break; \
} \
@@ -335,9 +340,8 @@ typedef khint_t khiter_t;
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t *)krealloc((void *)h->keys, \
new_n_buckets * sizeof(khkey_t)); \
- if (kh_is_map) { \
- h->vals = (khval_t *)krealloc((void *)h->vals, \
- new_n_buckets * sizeof(khval_t)); \
+ if (val_size) { \
+ h->vals_buf = krealloc((void *)h->vals_buf, new_n_buckets * val_size); \
} \
} \
kfree(h->flags); /* free the working space */ \
@@ -347,16 +351,16 @@ typedef khint_t khiter_t;
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
} \
- SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
- REAL_FATTR_UNUSED; \
- SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
+ SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret, size_t val_size) \
+ REAL_FATTR_UNUSED; \
+ SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret, size_t val_size) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size << 1)) { \
- kh_resize_##name(h, h->n_buckets - 1); /* clear "deleted" elements */ \
+ kh_resize_##name(h, h->n_buckets - 1, val_size); /* clear "deleted" elements */ \
} else { \
- kh_resize_##name(h, h->n_buckets + 1); /* expand the hash table */ \
+ kh_resize_##name(h, h->n_buckets + 1, val_size); /* expand the hash table */ \
} \
} /* TODO: implement automatically shrinking; */ \
/* resize() already support shrinking */ \
@@ -407,7 +411,7 @@ typedef khint_t khiter_t;
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
- REAL_FATTR_UNUSED; \
+ REAL_FATTR_UNUSED; \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
@@ -416,16 +420,16 @@ typedef khint_t khiter_t;
} \
}
-#define KHASH_DECLARE(name, khkey_t, khval_t) \
- __KHASH_TYPE(name, khkey_t, khval_t) \
- __KHASH_PROTOTYPES(name, khkey_t, khval_t)
+#define KHASH_DECLARE(khkey_t) \
+ __KHASH_TYPE(khkey_t, khkey_t) \
+ __KHASH_PROTOTYPES(khkey_t, khkey_t)
-#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
- __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+ __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, __hash_func, __hash_equal)
-#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
- KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+#define KHASH_INIT(name, khkey_t, khval_t, __hash_func, __hash_equal) \
+ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, __hash_func, __hash_equal)
// --- BEGIN OF HASH FUNCTIONS ---
@@ -542,7 +546,7 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
-#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
+#define kh_put(name, h, k, r, vs) kh_put_##name(h, k, r, vs)
/*! @function
@abstract Retrieve a key from the hash table.
@@ -584,12 +588,7 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
-#define kh_val(h, x) ((h)->vals[x])
-
-/*! @function
- @abstract Alias of kh_val()
- */
-#define kh_value(h, x) ((h)->vals[x])
+#define kh_val(type, h, x) (*(type *)(&(h)->vals_buf[(x)*(sizeof (type))]))
/*! @function
@abstract Get the start iterator
@@ -626,13 +625,15 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
-#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
- for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
- if (!kh_exist(h, __i)) continue; \
- (kvar) = kh_key(h, __i); \
- (vvar) = kh_val(h, __i); \
- code; \
- } }
+#define kh_foreach(type, h, kvar, vvar, code) { \
+ khint_t __i; \
+ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
+ if (!kh_exist(h,__i)) continue; \
+ (kvar) = kh_key(h,__i); \
+ (vvar) = kh_val(type, h,__i); \
+ code; \
+ } \
+}
/*! @function
@abstract Iterate over the values in the hash table
@@ -640,12 +641,14 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
-#define kh_foreach_value(h, vvar, code) { khint_t __i; \
- for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
- if (!kh_exist(h, __i)) continue; \
- (vvar) = kh_val(h, __i); \
- code; \
- } }
+#define kh_foreach_value(type, h, vvar, code) { \
+ khint_t __i; \
+ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
+ if (!kh_exist(h,__i)) continue; \
+ (vvar) = kh_val(type, h,__i); \
+ code; \
+ } \
+}
/*! @function
@abstract Iterate over the keys in the hash table
@@ -725,6 +728,6 @@ typedef const char *kh_cstr_t;
.upper_bound = 0, \
.flags = NULL, \
.keys = NULL, \
- .vals = NULL, \
+ .vals_buf = NULL, \
})
#endif // NVIM_LIB_KHASH_H
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index c9a46ecfa1..47f32abc07 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -9,7 +9,7 @@ if(TARGET libuv::uv_a)
else()
# Fall back to find module for older libuv versions that don't provide config file
find_package(Libuv 1.28.0 REQUIRED MODULE)
- target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIRS})
+ target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIR})
target_link_libraries(libuv INTERFACE ${LIBUV_LIBRARIES})
endif()
@@ -21,9 +21,9 @@ elseif(APPLE)
set_target_properties(nlua0 PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
endif()
-find_package(Libluv 1.43.0 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBLUV_INCLUDE_DIR})
-target_link_libraries(main_lib INTERFACE ${LIBLUV_LIBRARY})
+find_package(Luv 1.43.0 REQUIRED)
+target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUV_INCLUDE_DIR})
+target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY})
find_package(Iconv REQUIRED)
find_package(Lpeg REQUIRED)
@@ -61,11 +61,11 @@ if(PREFER_LUA)
find_package(Luajit)
else()
find_package(Luajit REQUIRED)
- target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUAJIT_INCLUDE_DIRS})
- target_link_libraries(main_lib INTERFACE ${LUAJIT_LIBRARIES})
- target_include_directories(nlua0 SYSTEM BEFORE PUBLIC ${LUAJIT_INCLUDE_DIRS})
+ target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUAJIT_INCLUDE_DIR})
+ target_link_libraries(main_lib INTERFACE ${LUAJIT_LIBRARY})
+ target_include_directories(nlua0 SYSTEM BEFORE PUBLIC ${LUAJIT_INCLUDE_DIR})
if(WIN32)
- target_link_libraries(nlua0 PUBLIC ${LUAJIT_LIBRARIES})
+ target_link_libraries(nlua0 PUBLIC ${LUAJIT_LIBRARY})
endif()
endif()
@@ -292,6 +292,7 @@ set(LUA_FILETYPE_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/filetype.lu
set(LUA_INIT_PACKAGES_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_init_packages.lua)
set(LUA_KEYMAP_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/keymap.lua)
set(CHAR_BLOB_GENERATOR ${GENERATOR_DIR}/gen_char_blob.lua)
+set(LUAJIT_RUNTIME_DIR ${DEPS_PREFIX}/share/luajit-2.1.0-beta3/jit)
glob_wrapper(UNICODE_FILES ${UNICODE_DIR}/*.txt)
glob_wrapper(API_HEADERS api/*.h)
@@ -798,6 +799,15 @@ install(DIRECTORY ${BINARY_LIB_DIR}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/nvim/
USE_SOURCE_PERMISSIONS)
+if(NOT PREFER_LUA)
+ # install luajit runtime files if bundled
+ if(EXISTS ${LUAJIT_RUNTIME_DIR})
+ install(DIRECTORY ${LUAJIT_RUNTIME_DIR}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/lua
+ USE_SOURCE_PERMISSIONS)
+ endif()
+endif()
+
add_library(libnvim STATIC EXCLUDE_FROM_ALL)
if(MSVC)
set(LIBNVIM_NAME libnvim)
@@ -826,6 +836,7 @@ if(ENABLE_ASAN_UBSAN)
-fsanitize=address
-fsanitize=undefined)
target_link_libraries(nvim PRIVATE -fsanitize=address -fsanitize=undefined)
+ target_compile_definitions(nvim PRIVATE ENABLE_ASAN_UBSAN)
elseif(ENABLE_MSAN)
message(STATUS "Enabling memory sanitizer for nvim.")
target_compile_options(nvim PRIVATE
@@ -877,18 +888,13 @@ add_glob_target(
EXCLUDE
tui/terminfo_defs.h)
-add_custom_target(uncrustify-version
- COMMAND ${CMAKE_COMMAND}
- -D UNCRUSTIFY_PRG=${UNCRUSTIFY_PRG}
- -D CONFIG_FILE=${PROJECT_SOURCE_DIR}/src/uncrustify.cfg
- -P ${PROJECT_SOURCE_DIR}/cmake/CheckUncrustifyVersion.cmake)
-
+set(UNCRUSTIFY_PRG ${DEPS_BIN_DIR}/uncrustify)
add_glob_target(
TARGET lintc-uncrustify
COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c "${PROJECT_SOURCE_DIR}/src/uncrustify.cfg" -q --check
FILES ${LINT_NVIM_SOURCES})
-add_dependencies(lintc-uncrustify uncrustify-version)
+add_dependencies(lintc-uncrustify uncrustify)
add_custom_target(lintc)
add_dependencies(lintc lintc-clint lintc-uncrustify)
@@ -899,7 +905,7 @@ add_custom_target(formatc
-D LANG=c
-P ${PROJECT_SOURCE_DIR}/cmake/Format.cmake
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
-add_dependencies(formatc uncrustify-version)
+add_dependencies(formatc uncrustify)
add_custom_target(generated-sources DEPENDS
${NVIM_GENERATED_FOR_SOURCES}
diff --git a/src/nvim/README.md b/src/nvim/README.md
index cbd5daba4e..75155fb9c6 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -71,9 +71,8 @@ Create a directory to store logs:
Configure the sanitizer(s) via these environment variables:
# Change to detect_leaks=1 to detect memory leaks (slower, noisier).
- export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan,handle_abort=1,handle_sigill=1"
+ export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
# Show backtraces in the logs.
- export UBSAN_OPTIONS=print_stacktrace=1
export MSAN_OPTIONS="log_path=${HOME}/logs/msan"
export TSAN_OPTIONS="log_path=${HOME}/logs/tsan"
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 6ecbff2606..14937cfd8f 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -293,17 +293,17 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
break;
case kCallbackFuncref:
case kCallbackPartial:
- PUT(autocmd_info, "callback", STRING_OBJ(cstr_as_string(callback_to_string(cb))));
+ PUT(autocmd_info, "callback", CSTR_AS_OBJ(callback_to_string(cb)));
break;
default:
abort();
}
} else {
- PUT(autocmd_info, "command", STRING_OBJ(cstr_as_string(xstrdup(ac->exec.callable.cmd))));
+ PUT(autocmd_info, "command", CSTR_TO_OBJ(ac->exec.callable.cmd));
}
- PUT(autocmd_info, "pattern", STRING_OBJ(cstr_to_string(ap->pat)));
- PUT(autocmd_info, "event", STRING_OBJ(cstr_to_string(event_nr2name(event))));
+ PUT(autocmd_info, "pattern", CSTR_TO_OBJ(ap->pat));
+ PUT(autocmd_info, "event", CSTR_TO_OBJ(event_nr2name(event)));
PUT(autocmd_info, "once", BOOLEAN_OBJ(ac->once));
if (ap->buflocal_nr) {
@@ -475,7 +475,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
}
if (patterns.size == 0) {
- ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*")));
+ ADD(patterns, STATIC_CSTR_TO_OBJ("*"));
}
VALIDATE_R((event_array.size > 0), "event", {
@@ -587,7 +587,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
// When we create the autocmds, we want to say that they are all matched, so that's *
// but when we clear them, we want to say that we didn't pass a pattern, so that's NUL
if (patterns.size == 0) {
- ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("")));
+ ADD(patterns, STATIC_CSTR_TO_OBJ(""));
}
// If we didn't pass any events, that means clear all events.
@@ -763,7 +763,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
}
if (patterns.size == 0) {
- ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("")));
+ ADD(patterns, STATIC_CSTR_TO_OBJ(""));
}
if (HAS_KEY(opts->data)) {
@@ -894,7 +894,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob
}
snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
- ADD(*patterns, STRING_OBJ(cstr_to_string(pattern_buflocal)));
+ ADD(*patterns, CSTR_TO_OBJ(pattern_buflocal));
}
return true;
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 10c684941c..82a62c3192 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -518,7 +518,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
{
MAXSIZE_TEMP_ARRAY(scratch, 1);
if (replacement.size == 0) {
- ADD_C(scratch, STRING_OBJ(STATIC_CSTR_AS_STRING("")));
+ ADD_C(scratch, STATIC_CSTR_AS_OBJ(""));
replacement = scratch;
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 3df80e3fed..6d715bcf46 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -245,7 +245,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
Dictionary filter = ARRAY_DICT_INIT;
PUT(filter, "pattern", cmdinfo.cmdmod.cmod_filter_pat
? CSTR_TO_OBJ(cmdinfo.cmdmod.cmod_filter_pat)
- : STRING_OBJ(STATIC_CSTR_TO_STRING("")));
+ : STATIC_CSTR_TO_OBJ(""));
PUT(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force));
PUT(mods, "filter", DICTIONARY_OBJ(filter));
@@ -438,7 +438,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
break;
}
- ADD(args, STRING_OBJ(cstr_as_string(data_str)));
+ ADD(args, CSTR_AS_OBJ(data_str));
}
bool argc_valid;
@@ -916,6 +916,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin
/// - args: (string) The args passed to the command, if any |<args>|
/// - fargs: (table) The args split by unescaped whitespace (when more than one
/// argument is allowed), if any |<f-args>|
+/// - nargs: (string) Number of arguments |:command-nargs|
/// - bang: (boolean) "true" if the command was executed with a ! modifier |<bang>|
/// - line1: (number) The starting line of the command range |<line1>|
/// - line2: (number) The final line of the command range |<line2>|
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 0ca505e7b2..a7e5b32d49 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -8,6 +8,7 @@
#include "nvim/api/buffer.h"
#include "nvim/api/deprecated.h"
#include "nvim/api/extmark.h"
+#include "nvim/api/options.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
@@ -522,3 +523,222 @@ Dictionary nvim_get_option_info(String name, Error *err)
{
return get_vimoption(name, OPT_GLOBAL, curbuf, curwin, err);
}
+
+/// Sets the global value of an option.
+///
+/// @deprecated
+/// @param channel_id
+/// @param name Option name
+/// @param value New option value
+/// @param[out] err Error details, if any
+void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
+ FUNC_API_SINCE(1)
+{
+ set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
+}
+
+/// Gets the global value of an option.
+///
+/// @deprecated
+/// @param name Option name
+/// @param[out] err Error details, if any
+/// @return Option value (global)
+Object nvim_get_option(String name, Arena *arena, Error *err)
+ FUNC_API_SINCE(1)
+{
+ return get_option_from(NULL, SREQ_GLOBAL, name, err);
+}
+
+/// Gets a buffer option value
+///
+/// @deprecated
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param name Option name
+/// @param[out] err Error details, if any
+/// @return Option value
+Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err)
+ FUNC_API_SINCE(1)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (!buf) {
+ return (Object)OBJECT_INIT;
+ }
+
+ return get_option_from(buf, SREQ_BUF, name, err);
+}
+
+/// Sets a buffer option value. Passing `nil` as value deletes the option (only
+/// works if there's a global fallback)
+///
+/// @deprecated
+/// @param channel_id
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param name Option name
+/// @param value Option value
+/// @param[out] err Error details, if any
+void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err)
+ FUNC_API_SINCE(1)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (!buf) {
+ return;
+ }
+
+ set_option_to(channel_id, buf, SREQ_BUF, name, value, err);
+}
+
+/// Gets a window option value
+///
+/// @deprecated
+/// @param window Window handle, or 0 for current window
+/// @param name Option name
+/// @param[out] err Error details, if any
+/// @return Option value
+Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err)
+ FUNC_API_SINCE(1)
+{
+ win_T *win = find_window_by_handle(window, err);
+
+ if (!win) {
+ return (Object)OBJECT_INIT;
+ }
+
+ return get_option_from(win, SREQ_WIN, name, err);
+}
+
+/// Sets a window option value. Passing `nil` as value deletes the option (only
+/// works if there's a global fallback)
+///
+/// @deprecated
+/// @param channel_id
+/// @param window Window handle, or 0 for current window
+/// @param name Option name
+/// @param value Option value
+/// @param[out] err Error details, if any
+void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err)
+ FUNC_API_SINCE(1)
+{
+ win_T *win = find_window_by_handle(window, err);
+
+ if (!win) {
+ return;
+ }
+
+ set_option_to(channel_id, win, SREQ_WIN, name, value, err);
+}
+
+/// Gets the value of a global or local (buffer, window) option.
+///
+/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
+/// to the window or buffer.
+/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
+/// @param name The option name
+/// @param[out] err Details of an error that may have occurred
+/// @return the option value
+static Object get_option_from(void *from, int type, String name, Error *err)
+{
+ Object rv = OBJECT_INIT;
+
+ VALIDATE_S(name.size > 0, "option name", "<empty>", {
+ return rv;
+ });
+
+ // Return values
+ int64_t numval;
+ char *stringval = NULL;
+
+ int flags = get_option_value_strict(name.data, &numval, &stringval, type, from);
+ VALIDATE_S(flags != 0, "option name", name.data, {
+ return rv;
+ });
+
+ if (flags & SOPT_BOOL) {
+ rv.type = kObjectTypeBoolean;
+ rv.data.boolean = numval ? true : false;
+ } else if (flags & SOPT_NUM) {
+ rv.type = kObjectTypeInteger;
+ rv.data.integer = numval;
+ } else if (flags & SOPT_STRING) {
+ if (!stringval) {
+ api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data);
+ return rv;
+ }
+ rv.type = kObjectTypeString;
+ rv.data.string.data = stringval;
+ rv.data.string.size = strlen(stringval);
+ } else {
+ api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data);
+ }
+
+ return rv;
+}
+
+/// Sets the value of a global or local (buffer, window) option.
+///
+/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
+/// to the window or buffer.
+/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
+/// @param name The option name
+/// @param[out] err Details of an error that may have occurred
+static void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value,
+ Error *err)
+{
+ VALIDATE_S(name.size > 0, "option name", "<empty>", {
+ return;
+ });
+
+ int flags = get_option_value_strict(name.data, NULL, NULL, type, to);
+ VALIDATE_S(flags != 0, "option name", name.data, {
+ return;
+ });
+
+ if (value.type == kObjectTypeNil) {
+ if (type == SREQ_GLOBAL) {
+ api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data);
+ return;
+ } else if (!(flags & SOPT_GLOBAL)) {
+ api_set_error(err, kErrorTypeException,
+ "Cannot unset option '%s' because it doesn't have a global value",
+ name.data);
+ return;
+ } else {
+ unset_global_local_option(name.data, to);
+ return;
+ }
+ }
+
+ long numval = 0;
+ char *stringval = NULL;
+
+ if (flags & SOPT_BOOL) {
+ VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, {
+ return;
+ });
+ numval = value.data.boolean;
+ } else if (flags & SOPT_NUM) {
+ VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, {
+ return;
+ });
+ VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN),
+ "Option '%s' value is out of range", name.data, {
+ return;
+ });
+ numval = (int)value.data.integer;
+ } else {
+ VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, {
+ return;
+ });
+ stringval = value.data.string.data;
+ }
+
+ // For global-win-local options -> setlocal
+ // For win-local options -> setglobal and setlocal (opt_flags == 0)
+ const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 :
+ (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
+
+ WITH_SCRIPT_CONTEXT(channel_id, {
+ access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err);
+ });
+}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 87232a8a93..299413e510 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -33,12 +33,10 @@
void api_extmark_free_all_mem(void)
{
String name;
- handle_T id;
- map_foreach(&namespace_ids, name, id, {
- (void)id;
+ map_foreach_key(&namespace_ids, name, {
xfree(name.data);
})
- map_destroy(String, handle_T)(&namespace_ids);
+ map_destroy(String, &namespace_ids);
}
/// Creates a new namespace or gets an existing one. \*namespace\*
@@ -77,7 +75,7 @@ Dictionary nvim_get_namespaces(void)
String name;
handle_T id;
- map_foreach(&namespace_ids, name, id, {
+ map_foreach(handle_T, &namespace_ids, name, id, {
PUT(retval, name.data, INTEGER_OBJ(id));
})
@@ -88,7 +86,7 @@ const char *describe_ns(NS ns_id)
{
String name;
handle_T id;
- map_foreach(&namespace_ids, name, id, {
+ map_foreach(handle_T, &namespace_ids, name, id, {
if ((NS)id == ns_id && name.size) {
return name.data;
}
@@ -108,7 +106,7 @@ bool ns_initialized(uint32_t ns)
static Object hl_group_name(int hl_id, bool hl_name)
{
if (hl_name) {
- return STRING_OBJ(cstr_to_string(syn_id2name(hl_id)));
+ return CSTR_TO_OBJ(syn_id2name(hl_id));
} else {
return INTEGER_OBJ(hl_id);
}
@@ -142,7 +140,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict
PUT(dict, "hl_eol", BOOLEAN_OBJ(decor->hl_eol));
}
if (decor->hl_mode) {
- PUT(dict, "hl_mode", STRING_OBJ(cstr_to_string(hl_mode_str[decor->hl_mode])));
+ PUT(dict, "hl_mode", CSTR_TO_OBJ(hl_mode_str[decor->hl_mode]));
}
if (kv_size(decor->virt_text)) {
@@ -150,7 +148,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict
for (size_t i = 0; i < decor->virt_text.size; i++) {
Array chunk = ARRAY_DICT_INIT;
VirtTextChunk *vtc = &decor->virt_text.items[i];
- ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
+ ADD(chunk, CSTR_TO_OBJ(vtc->text));
if (vtc->hl_id > 0) {
ADD(chunk, hl_group_name(vtc->hl_id, hl_name));
}
@@ -162,7 +160,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict
PUT(dict, "virt_text_win_col", INTEGER_OBJ(decor->col));
}
PUT(dict, "virt_text_pos",
- STRING_OBJ(cstr_to_string(virt_text_pos_str[decor->virt_text_pos])));
+ CSTR_TO_OBJ(virt_text_pos_str[decor->virt_text_pos]));
}
if (decor->ui_watched) {
@@ -179,7 +177,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict
for (size_t j = 0; j < vt->size; j++) {
Array chunk = ARRAY_DICT_INIT;
VirtTextChunk *vtc = &vt->items[j];
- ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
+ ADD(chunk, CSTR_TO_OBJ(vtc->text));
if (vtc->hl_id > 0) {
ADD(chunk, hl_group_name(vtc->hl_id, hl_name));
}
@@ -193,7 +191,7 @@ static Array extmark_to_array(const ExtmarkInfo *extmark, bool id, bool add_dict
}
if (decor->sign_text) {
- PUT(dict, "sign_text", STRING_OBJ(cstr_to_string(decor->sign_text)));
+ PUT(dict, "sign_text", CSTR_TO_OBJ(decor->sign_text));
}
// uncrustify:off
@@ -479,6 +477,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
/// - "right_align": display right aligned in the window.
+/// - "inline": display at the specified column, and
+/// shift the buffer text to the right as needed
/// - virt_text_win_col : position the virtual text at a fixed
/// window column (starting from the first
/// text column)
@@ -697,6 +697,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
decor.virt_text_pos = kVTOverlay;
} else if (strequal("right_align", str.data)) {
decor.virt_text_pos = kVTRightAlign;
+ } else if (strequal("inline", str.data)) {
+ decor.virt_text_pos = kVTInline;
} else {
VALIDATE_S(false, "virt_text_pos", "", {
goto error;
diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h
index a6586e3031..3c979fa4f6 100644
--- a/src/nvim/api/extmark.h
+++ b/src/nvim/api/extmark.h
@@ -6,7 +6,6 @@
#include "nvim/decoration.h"
#include "nvim/macros.h"
#include "nvim/map.h"
-#include "nvim/map_defs.h"
#include "nvim/types.h"
EXTERN Map(String, handle_T) namespace_ids INIT(= MAP_INIT);
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 2d1b170d2d..e18312a6dc 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -188,7 +188,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
switch (result) {
case gov_string:
- rv = STRING_OBJ(cstr_as_string(stringval));
+ rv = CSTR_AS_OBJ(stringval);
break;
case gov_number:
rv = INTEGER_OBJ(numval);
@@ -341,218 +341,6 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Error *err)
return get_vimoption(name, scope, buf, win, err);
}
-/// Sets the global value of an option.
-///
-/// @param channel_id
-/// @param name Option name
-/// @param value New option value
-/// @param[out] err Error details, if any
-void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
-{
- set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
-}
-
-/// Gets the global value of an option.
-///
-/// @param name Option name
-/// @param[out] err Error details, if any
-/// @return Option value (global)
-Object nvim_get_option(String name, Arena *arena, Error *err)
- FUNC_API_SINCE(1)
-{
- return get_option_from(NULL, SREQ_GLOBAL, name, err);
-}
-
-/// Gets a buffer option value
-///
-/// @param buffer Buffer handle, or 0 for current buffer
-/// @param name Option name
-/// @param[out] err Error details, if any
-/// @return Option value
-Object nvim_buf_get_option(Buffer buffer, String name, Arena *arena, Error *err)
- FUNC_API_SINCE(1)
-{
- buf_T *buf = find_buffer_by_handle(buffer, err);
-
- if (!buf) {
- return (Object)OBJECT_INIT;
- }
-
- return get_option_from(buf, SREQ_BUF, name, err);
-}
-
-/// Sets a buffer option value. Passing `nil` as value deletes the option (only
-/// works if there's a global fallback)
-///
-/// @param channel_id
-/// @param buffer Buffer handle, or 0 for current buffer
-/// @param name Option name
-/// @param value Option value
-/// @param[out] err Error details, if any
-void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
-{
- buf_T *buf = find_buffer_by_handle(buffer, err);
-
- if (!buf) {
- return;
- }
-
- set_option_to(channel_id, buf, SREQ_BUF, name, value, err);
-}
-
-/// Gets a window option value
-///
-/// @param window Window handle, or 0 for current window
-/// @param name Option name
-/// @param[out] err Error details, if any
-/// @return Option value
-Object nvim_win_get_option(Window window, String name, Arena *arena, Error *err)
- FUNC_API_SINCE(1)
-{
- win_T *win = find_window_by_handle(window, err);
-
- if (!win) {
- return (Object)OBJECT_INIT;
- }
-
- return get_option_from(win, SREQ_WIN, name, err);
-}
-
-/// Sets a window option value. Passing `nil` as value deletes the option (only
-/// works if there's a global fallback)
-///
-/// @param channel_id
-/// @param window Window handle, or 0 for current window
-/// @param name Option name
-/// @param value Option value
-/// @param[out] err Error details, if any
-void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
-{
- win_T *win = find_window_by_handle(window, err);
-
- if (!win) {
- return;
- }
-
- set_option_to(channel_id, win, SREQ_WIN, name, value, err);
-}
-
-/// Gets the value of a global or local (buffer, window) option.
-///
-/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
-/// to the window or buffer.
-/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
-/// @param name The option name
-/// @param[out] err Details of an error that may have occurred
-/// @return the option value
-static Object get_option_from(void *from, int type, String name, Error *err)
-{
- Object rv = OBJECT_INIT;
-
- VALIDATE_S(name.size > 0, "option name", "<empty>", {
- return rv;
- });
-
- // Return values
- int64_t numval;
- char *stringval = NULL;
-
- int flags = get_option_value_strict(name.data, &numval, &stringval, type, from);
- VALIDATE_S(flags != 0, "option name", name.data, {
- return rv;
- });
-
- if (flags & SOPT_BOOL) {
- rv.type = kObjectTypeBoolean;
- rv.data.boolean = numval ? true : false;
- } else if (flags & SOPT_NUM) {
- rv.type = kObjectTypeInteger;
- rv.data.integer = numval;
- } else if (flags & SOPT_STRING) {
- if (!stringval) {
- api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data);
- return rv;
- }
- rv.type = kObjectTypeString;
- rv.data.string.data = stringval;
- rv.data.string.size = strlen(stringval);
- } else {
- api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data);
- }
-
- return rv;
-}
-
-/// Sets the value of a global or local (buffer, window) option.
-///
-/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
-/// to the window or buffer.
-/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
-/// @param name The option name
-/// @param[out] err Details of an error that may have occurred
-void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err)
-{
- VALIDATE_S(name.size > 0, "option name", "<empty>", {
- return;
- });
-
- int flags = get_option_value_strict(name.data, NULL, NULL, type, to);
- VALIDATE_S(flags != 0, "option name", name.data, {
- return;
- });
-
- if (value.type == kObjectTypeNil) {
- if (type == SREQ_GLOBAL) {
- api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data);
- return;
- } else if (!(flags & SOPT_GLOBAL)) {
- api_set_error(err, kErrorTypeException,
- "Cannot unset option '%s' because it doesn't have a global value",
- name.data);
- return;
- } else {
- unset_global_local_option(name.data, to);
- return;
- }
- }
-
- long numval = 0;
- char *stringval = NULL;
-
- if (flags & SOPT_BOOL) {
- VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, {
- return;
- });
- numval = value.data.boolean;
- } else if (flags & SOPT_NUM) {
- VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, {
- return;
- });
- VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN),
- "Option '%s' value is out of range", name.data, {
- return;
- });
- numval = (int)value.data.integer;
- } else {
- VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, {
- return;
- });
- stringval = value.data.string.data;
- }
-
- // For global-win-local options -> setlocal
- // For win-local options -> setglobal and setlocal (opt_flags == 0)
- const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) ? 0 :
- (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
-
- WITH_SCRIPT_CONTEXT(channel_id, {
- access_option_value_for(name.data, &numval, &stringval, opt_flags, type, to, false, err);
- });
-}
-
static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags,
bool get, Error *err)
{
@@ -571,8 +359,8 @@ static getoption_T access_option_value(char *key, long *numval, char **stringval
}
}
-static getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
- int opt_type, void *from, bool get, Error *err)
+getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
+ int opt_type, void *from, bool get, Error *err)
{
bool need_switch = false;
switchwin_T switchwin;
diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h
index 869826e443..7be72d3708 100644
--- a/src/nvim/api/options.h
+++ b/src/nvim/api/options.h
@@ -3,6 +3,7 @@
#include "nvim/api/keysets.h"
#include "nvim/api/private/defs.h"
+#include "nvim/option.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/options.h.generated.h"
diff --git a/src/nvim/api/private/converter.h b/src/nvim/api/private/converter.h
index 80ee640295..28ae71983b 100644
--- a/src/nvim/api/private/converter.h
+++ b/src/nvim/api/private/converter.h
@@ -2,7 +2,7 @@
#define NVIM_API_PRIVATE_CONVERTER_H
#include "nvim/api/private/defs.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/converter.h.generated.h"
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 02060a8950..2544809553 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -660,10 +660,10 @@ static void init_ui_event_metadata(Dictionary *metadata)
msgpack_unpacked_destroy(&unpacked);
PUT(*metadata, "ui_events", ui_events);
Array ui_options = ARRAY_DICT_INIT;
- ADD(ui_options, STRING_OBJ(cstr_to_string("rgb")));
+ ADD(ui_options, CSTR_TO_OBJ("rgb"));
for (UIExtension i = 0; i < kUIExtCount; i++) {
if (ui_ext_names[i][0] != '_') {
- ADD(ui_options, STRING_OBJ(cstr_to_string(ui_ext_names[i])));
+ ADD(ui_options, CSTR_TO_OBJ(ui_ext_names[i]));
}
}
PUT(*metadata, "ui_options", ARRAY_OBJ(ui_options));
@@ -692,17 +692,17 @@ static void init_type_metadata(Dictionary *metadata)
Dictionary buffer_metadata = ARRAY_DICT_INIT;
PUT(buffer_metadata, "id",
INTEGER_OBJ(kObjectTypeBuffer - EXT_OBJECT_TYPE_SHIFT));
- PUT(buffer_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_buf_")));
+ PUT(buffer_metadata, "prefix", CSTR_TO_OBJ("nvim_buf_"));
Dictionary window_metadata = ARRAY_DICT_INIT;
PUT(window_metadata, "id",
INTEGER_OBJ(kObjectTypeWindow - EXT_OBJECT_TYPE_SHIFT));
- PUT(window_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_win_")));
+ PUT(window_metadata, "prefix", CSTR_TO_OBJ("nvim_win_"));
Dictionary tabpage_metadata = ARRAY_DICT_INIT;
PUT(tabpage_metadata, "id",
INTEGER_OBJ(kObjectTypeTabpage - EXT_OBJECT_TYPE_SHIFT));
- PUT(tabpage_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_tabpage_")));
+ PUT(tabpage_metadata, "prefix", CSTR_TO_OBJ("nvim_tabpage_"));
PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata));
PUT(types, "Window", DICTIONARY_OBJ(window_metadata));
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 2623c97c9d..a9cfaeae22 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -34,6 +34,7 @@
.type = kObjectTypeString, \
.data.string = s })
+#define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s))
#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s))
#define BUFFER_OBJ(s) ((Object) { \
@@ -103,6 +104,9 @@
.data = xmemdupz(s, sizeof(s) - 1), \
.size = sizeof(s) - 1 })
+#define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s))
+#define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s))
+
// Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean
#define api_init_integer
@@ -122,13 +126,13 @@
#define api_free_window(value)
#define api_free_tabpage(value)
-EXTERN PMap(handle_T) buffer_handles INIT(= MAP_INIT);
-EXTERN PMap(handle_T) window_handles INIT(= MAP_INIT);
-EXTERN PMap(handle_T) tabpage_handles INIT(= MAP_INIT);
+EXTERN PMap(int) buffer_handles INIT(= MAP_INIT);
+EXTERN PMap(int) window_handles INIT(= MAP_INIT);
+EXTERN PMap(int) tabpage_handles INIT(= MAP_INIT);
-#define handle_get_buffer(h) pmap_get(handle_T)(&buffer_handles, (h))
-#define handle_get_window(h) pmap_get(handle_T)(&window_handles, (h))
-#define handle_get_tabpage(h) pmap_get(handle_T)(&tabpage_handles, (h))
+#define handle_get_buffer(h) pmap_get(int)(&buffer_handles, (h))
+#define handle_get_window(h) pmap_get(int)(&window_handles, (h))
+#define handle_get_tabpage(h) pmap_get(int)(&tabpage_handles, (h))
/// Structure used for saving state for :try
///
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index bd3482c85f..e98c589189 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -111,7 +111,7 @@ void remote_ui_disconnect(uint64_t channel_id)
}
UIData *data = ui->data;
kv_destroy(data->call_buf);
- pmap_del(uint64_t)(&connected_uis, channel_id);
+ pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
ui_detach_impl(ui, channel_id);
// Destroy `ui`.
@@ -795,7 +795,7 @@ void remote_ui_put(UI *ui, const char *cell)
UIData *data = ui->data;
data->client_col++;
Array args = data->call_buf;
- ADD_C(args, STRING_OBJ(cstr_as_string((char *)cell)));
+ ADD_C(args, CSTR_AS_OBJ((char *)cell));
push_call(ui, "put", args);
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index d47f47e638..36163859eb 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -531,7 +531,7 @@ static void find_runtime_cb(char *fname, void *cookie)
{
Array *rv = (Array *)cookie;
if (fname != NULL) {
- ADD(*rv, STRING_OBJ(cstr_to_string(fname)));
+ ADD(*rv, CSTR_TO_OBJ(fname));
}
}
@@ -1383,7 +1383,7 @@ Dictionary nvim_get_mode(void)
get_mode(modestr);
bool blocked = input_blocking();
- PUT(rv, "mode", STRING_OBJ(cstr_to_string(modestr)));
+ PUT(rv, "mode", CSTR_TO_OBJ(modestr));
PUT(rv, "blocking", BOOLEAN_OBJ(blocked));
return rv;
@@ -1926,7 +1926,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E
}
ret = arena_array(arena, 3);
size_t off = g->line_offset[(size_t)row] + (size_t)col;
- ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off])));
+ ADD_C(ret, CSTR_AS_OBJ((char *)g->chars[off]));
int attr = g->attrs[off];
ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
// will not work first time
@@ -2035,7 +2035,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
ADD(rv, INTEGER_OBJ(row));
ADD(rv, INTEGER_OBJ(col));
ADD(rv, INTEGER_OBJ(bufnr));
- ADD(rv, STRING_OBJ(cstr_to_string(filename)));
+ ADD(rv, CSTR_TO_OBJ(filename));
if (allocated) {
xfree(filename);
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 208aa165c9..1a67be8860 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -502,7 +502,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
};
err_dict.items[0] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("message"),
- .value = STRING_OBJ(cstr_to_string(east.err.msg)),
+ .value = CSTR_TO_OBJ(east.err.msg),
};
if (east.err.arg == NULL) {
err_dict.items[1] = (KeyValuePair) {
@@ -539,7 +539,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
chunk_arr.items[0] = INTEGER_OBJ((Integer)chunk.start.line);
chunk_arr.items[1] = INTEGER_OBJ((Integer)chunk.start.col);
chunk_arr.items[2] = INTEGER_OBJ((Integer)chunk.end_col);
- chunk_arr.items[3] = STRING_OBJ(cstr_to_string(chunk.group));
+ chunk_arr.items[3] = CSTR_TO_OBJ(chunk.group);
hl.items[i] = ARRAY_OBJ(chunk_arr);
}
ret.items[ret.size++] = (KeyValuePair) {
@@ -616,7 +616,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
kv_drop(ast_conv_stack, 1);
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("type"),
- .value = STRING_OBJ(cstr_to_string(east_node_type_tab[node->type])),
+ .value = CSTR_TO_OBJ(east_node_type_tab[node->type]),
};
Array start_array = {
.items = xmalloc(2 * sizeof(start_array.items[0])),
@@ -701,11 +701,11 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
case kExprNodeComparison:
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("cmp_type"),
- .value = STRING_OBJ(cstr_to_string(eltkn_cmp_type_tab[node->data.cmp.type])),
+ .value = CSTR_TO_OBJ(eltkn_cmp_type_tab[node->data.cmp.type]),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ccs_strategy"),
- .value = STRING_OBJ(cstr_to_string(ccs_tab[node->data.cmp.ccs])),
+ .value = CSTR_TO_OBJ(ccs_tab[node->data.cmp.ccs]),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("invert"),
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index c267fee39a..8e4fbb6779 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -267,7 +267,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
PUT(rv, "bufpos", ARRAY_OBJ(pos));
}
}
- PUT(rv, "anchor", STRING_OBJ(cstr_to_string(float_anchor_str[config->anchor])));
+ PUT(rv, "anchor", CSTR_TO_OBJ(float_anchor_str[config->anchor]));
PUT(rv, "row", FLOAT_OBJ(config->row));
PUT(rv, "col", FLOAT_OBJ(config->col));
PUT(rv, "zindex", INTEGER_OBJ(config->zindex));
@@ -283,7 +283,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
char *hi_name = syn_id2name(hi_id);
if (hi_name[0]) {
ADD(tuple, STRING_OBJ(s));
- ADD(tuple, STRING_OBJ(cstr_to_string(hi_name)));
+ ADD(tuple, CSTR_TO_OBJ(hi_name));
ADD(border, ARRAY_OBJ(tuple));
} else {
ADD(border, STRING_OBJ(s));
@@ -297,7 +297,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
Array tuple = ARRAY_DICT_INIT;
ADD(tuple, CSTR_TO_OBJ(title_datas.items[i].text));
if (title_datas.items[i].hl_id > 0) {
- ADD(tuple, STRING_OBJ(cstr_to_string(syn_id2name(title_datas.items[i].hl_id))));
+ ADD(tuple, CSTR_TO_OBJ(syn_id2name(title_datas.items[i].hl_id)));
}
ADD(titles, ARRAY_OBJ(tuple));
}
@@ -317,7 +317,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
const char *rel = (wp->w_floating && !config->external
? float_relative_str[config->relative] : "");
- PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel)));
+ PUT(rv, "relative", CSTR_TO_OBJ(rel));
return rv;
}
diff --git a/src/nvim/arglist.h b/src/nvim/arglist.h
index b2e0f411d4..cd34ca10c4 100644
--- a/src/nvim/arglist.h
+++ b/src/nvim/arglist.h
@@ -1,7 +1,7 @@
#ifndef NVIM_ARGLIST_H
#define NVIM_ARGLIST_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 2d5d8e262b..17a3fd33f1 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -108,14 +108,13 @@ static Map(int, String) map_augroup_id_to_name = MAP_INIT;
static void augroup_map_del(int id, const char *name)
{
if (name != NULL) {
- String key = map_key(String, int)(&map_augroup_name_to_id, cstr_as_string((char *)name));
- map_del(String, int)(&map_augroup_name_to_id, key);
+ String key;
+ map_del(String, int)(&map_augroup_name_to_id, cstr_as_string((char *)name), &key);
api_free_string(key);
}
if (id > 0) {
- String mapped = map_get(int, String)(&map_augroup_id_to_name, id);
+ String mapped = map_del(int, String)(&map_augroup_id_to_name, id, NULL);
api_free_string(mapped);
- map_del(int, String)(&map_augroup_id_to_name, id);
}
}
@@ -543,7 +542,7 @@ void do_augroup(char *arg, int del_group)
String name;
int value;
- map_foreach(&map_augroup_name_to_id, name, value, {
+ map_foreach(int, &map_augroup_name_to_id, name, value, {
if (value > 0) {
msg_puts(name.data);
} else {
@@ -572,18 +571,15 @@ void free_all_autocmds(void)
// Delete the augroup_map, including free the data
String name;
- int id;
- map_foreach(&map_augroup_name_to_id, name, id, {
- (void)id;
+ map_foreach_key(&map_augroup_name_to_id, name, {
api_free_string(name);
})
- map_destroy(String, int)(&map_augroup_name_to_id);
+ map_destroy(String, &map_augroup_name_to_id);
- map_foreach(&map_augroup_id_to_name, id, name, {
- (void)id;
+ map_foreach_value(String, &map_augroup_id_to_name, name, {
api_free_string(name);
})
- map_destroy(int, String)(&map_augroup_id_to_name);
+ map_destroy(int, &map_augroup_id_to_name);
// aucmd_win[] is freed in win_free_all()
}
@@ -1311,7 +1307,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
if (need_append) {
win_append(lastwin, auc_win);
- pmap_put(handle_T)(&window_handles, auc_win->handle, auc_win);
+ pmap_put(int)(&window_handles, auc_win->handle, auc_win);
win_config_float(auc_win, auc_win->w_float_config);
}
// Prevent chdir() call in win_enter_ext(), through do_autochdir()
@@ -1367,7 +1363,7 @@ win_found:
}
// Remove the window.
win_remove(curwin, NULL);
- pmap_del(handle_T)(&window_handles, curwin->handle);
+ pmap_del(int)(&window_handles, curwin->handle, NULL);
if (curwin->w_grid_alloc.chars != NULL) {
ui_comp_remove_grid(&curwin->w_grid_alloc);
ui_call_win_hide(curwin->w_grid_alloc.handle);
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 8d730733d0..11b79fcede 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -833,7 +833,7 @@ void buf_freeall(buf_T *buf, int flags)
/// itself (not the file, that must have been done already).
static void free_buffer(buf_T *buf)
{
- pmap_del(handle_T)(&buffer_handles, buf->b_fnum);
+ pmap_del(int)(&buffer_handles, buf->b_fnum, NULL);
buf_free_count++;
// b:changedtick uses an item in buf_T.
free_buffer_stuff(buf, kBffClearWinInfo);
@@ -1084,11 +1084,11 @@ char *do_bufdel(int command, char *arg, int addr_count, int start_bnr, int end_b
if (deleted == 0) {
if (command == DOBUF_UNLOAD) {
- STRCPY(IObuff, _("E515: No buffers were unloaded"));
+ xstrlcpy(IObuff, _("E515: No buffers were unloaded"), IOSIZE);
} else if (command == DOBUF_DEL) {
- STRCPY(IObuff, _("E516: No buffers were deleted"));
+ xstrlcpy(IObuff, _("E516: No buffers were deleted"), IOSIZE);
} else {
- STRCPY(IObuff, _("E517: No buffers were wiped out"));
+ xstrlcpy(IObuff, _("E517: No buffers were wiped out"), IOSIZE);
}
errormsg = IObuff;
} else if (deleted >= p_report) {
@@ -1459,16 +1459,11 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
// make "buf" the current buffer
if (action == DOBUF_SPLIT) { // split window first
- // If 'switchbuf' contains "useopen": jump to first window containing
- // "buf" if one exists
- if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf)) {
- return OK;
- }
- // If 'switchbuf' contains "usetab": jump to first window in any tab
- // page containing "buf" if one exists
- if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf)) {
+ // If 'switchbuf' is set jump to the window containing "buf".
+ if (swbuf_goto_win_with_buf(buf) != NULL) {
return OK;
}
+
if (win_split(0, 0) == FAIL) {
return FAIL;
}
@@ -1870,7 +1865,7 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags)
lastbuf = buf;
buf->b_fnum = top_file_num++;
- pmap_put(handle_T)(&buffer_handles, buf->b_fnum, buf);
+ pmap_put(int)(&buffer_handles, buf->b_fnum, buf);
if (top_file_num < 0) { // wrap around (may cause duplicates)
emsg(_("W14: Warning: List of file names overflow"));
if (emsg_silent == 0 && !in_assert_fails) {
@@ -2072,17 +2067,8 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
}
if (options & GETF_SWITCH) {
- // If 'switchbuf' contains "useopen": jump to first window containing
- // "buf" if one exists
- if (swb_flags & SWB_USEOPEN) {
- wp = buf_jump_open_win(buf);
- }
-
- // If 'switchbuf' contains "usetab": jump to first window in any tab
- // page containing "buf" if one exists
- if (wp == NULL && (swb_flags & SWB_USETAB)) {
- wp = buf_jump_open_tab(buf);
- }
+ // If 'switchbuf' is set jump to the window containing "buf".
+ wp = swbuf_goto_win_with_buf(buf);
// If 'switchbuf' contains "split", "vsplit" or "newtab" and the
// current buffer isn't empty: open new tab or window
@@ -3528,23 +3514,20 @@ bool append_arg_number(win_T *wp, char *buf, int buflen, bool add_file)
return false;
}
- char *p = buf + strlen(buf); // go to the end of the buffer
-
- // Early out if the string is getting too long
- if (p - buf + 35 >= buflen) {
- return false;
+ const char *msg;
+ switch ((wp->w_arg_idx_invalid ? 1 : 0) + (add_file ? 2 : 0)) {
+ case 0:
+ msg = _(" (%d of %d)"); break;
+ case 1:
+ msg = _(" ((%d) of %d)"); break;
+ case 2:
+ msg = _(" (file %d of %d)"); break;
+ case 3:
+ msg = _(" (file (%d) of %d)"); break;
}
- *p++ = ' ';
- *p++ = '(';
- if (add_file) {
- STRCPY(p, "file ");
- p += 5;
- }
- vim_snprintf(p, (size_t)(buflen - (p - buf)),
- wp->w_arg_idx_invalid
- ? "(%d) of %d)"
- : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
+ char *p = buf + strlen(buf); // go to the end of the buffer
+ vim_snprintf(p, (size_t)(buflen - (p - buf)), msg, wp->w_arg_idx + 1, ARGCOUNT);
return true;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ce8ee21882..f3f98bbd17 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -17,7 +17,7 @@ typedef struct {
#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/garray.h"
#include "nvim/grid_defs.h"
#include "nvim/hashtab.h"
@@ -808,6 +808,7 @@ struct file_buffer {
MarkTree b_marktree[1];
Map(uint32_t, uint32_t) b_extmark_ns[1]; // extmark namespaces
+ size_t b_virt_text_inline; // number of inline virtual texts
size_t b_virt_line_blocks; // number of virt_line blocks
size_t b_signs; // number of sign extmarks
size_t b_signs_with_text; // number of sign extmarks with text
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c
index 84c1276b8b..cfa3ea5bf3 100644
--- a/src/nvim/bufwrite.c
+++ b/src/nvim/bufwrite.c
@@ -745,7 +745,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o
// the ones from the original file.
// First find a file name that doesn't exist yet (use some
// arbitrary numbers).
- STRCPY(IObuff, fname);
+ xstrlcpy(IObuff, fname, IOSIZE);
for (int i = 4913;; i += 123) {
char *tail = path_tail(IObuff);
size_t size = (size_t)(tail - IObuff);
@@ -1749,24 +1749,24 @@ restore_backup:
add_quoted_fname(IObuff, IOSIZE, buf, fname);
bool insert_space = false;
if (write_info.bw_conv_error) {
- STRCAT(IObuff, _(" CONVERSION ERROR"));
+ xstrlcat(IObuff, _(" CONVERSION ERROR"), IOSIZE);
insert_space = true;
if (write_info.bw_conv_error_lnum != 0) {
vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"),
(int64_t)write_info.bw_conv_error_lnum);
}
} else if (notconverted) {
- STRCAT(IObuff, _("[NOT converted]"));
+ xstrlcat(IObuff, _("[NOT converted]"), IOSIZE);
insert_space = true;
} else if (converted) {
- STRCAT(IObuff, _("[converted]"));
+ xstrlcat(IObuff, _("[converted]"), IOSIZE);
insert_space = true;
}
if (device) {
- STRCAT(IObuff, _("[Device]"));
+ xstrlcat(IObuff, _("[Device]"), IOSIZE);
insert_space = true;
} else if (newfile) {
- STRCAT(IObuff, new_file_message());
+ xstrlcat(IObuff, new_file_message(), IOSIZE);
insert_space = true;
}
if (no_eol) {
@@ -1780,9 +1780,9 @@ restore_backup:
msg_add_lines(insert_space, (long)lnum, nchars); // add line/char count
if (!shortmess(SHM_WRITE)) {
if (append) {
- STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
+ xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"), IOSIZE);
} else {
- STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
+ xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"), IOSIZE);
}
}
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 1d6869990e..9e1767c2f3 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -43,6 +43,7 @@
#include "nvim/plines.h"
#include "nvim/pos.h"
#include "nvim/search.h"
+#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/textformat.h"
@@ -247,11 +248,25 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
wp->w_redr_type = UPD_VALID;
}
+ linenr_T last = lnume + xtra - 1; // last line after the change
+
+ // Reset "w_skipcol" if the topline length has become smaller to
+ // such a degree that nothing will be visible anymore, accounting
+ // for 'smoothscroll' <<< or 'listchars' "precedes" marker.
+ if (wp->w_skipcol > 0
+ && (last < wp->w_topline
+ || (wp->w_topline >= lnum
+ && wp->w_topline < lnume
+ && win_linetabsize(wp, wp->w_topline, ml_get(wp->w_topline), (colnr_T)MAXCOL)
+ <= (unsigned)(wp->w_skipcol + sms_marker_overlap(wp, win_col_off(wp)
+ - win_col_off2(wp)))))) {
+ wp->w_skipcol = 0;
+ }
+
// Check if a change in the buffer has invalidated the cached
// values for the cursor.
// Update the folds for this window. Can't postpone this, because
// a following operator might work on the whole fold: ">>dd".
- linenr_T last = lnume + xtra - 1; // last line after the change
foldUpdate(wp, lnum, last);
// The change may cause lines above or below the change to become
@@ -379,6 +394,15 @@ void changed_bytes(linenr_T lnum, colnr_T col)
{
changedOneline(curbuf, lnum);
changed_common(lnum, col, lnum + 1, 0);
+ // When text has been changed at the end of the line, possibly the start of
+ // the next line may have SpellCap that should be removed or it needs to be
+ // displayed. Schedule the next line for redrawing just in case.
+ // Don't do this when displaying '$' at the end of changed text.
+ if (spell_check_window(curwin)
+ && lnum < curbuf->b_ml.ml_line_count
+ && vim_strchr(p_cpo, CPO_DOLLAR) == NULL) {
+ redrawWinline(curwin, lnum + 1);
+ }
// notify any channels that are watching
buf_updates_send_changes(curbuf, lnum, 1, 1);
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 820ce534e1..569d3f5887 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -57,7 +57,7 @@ void channel_teardown(void)
{
Channel *channel;
- map_foreach_value(&channels, channel, {
+ pmap_foreach_value(&channels, channel, {
channel_close(channel->id, kChannelPartAll, NULL);
});
}
@@ -279,7 +279,7 @@ static void free_channel_event(void **argv)
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
- pmap_del(uint64_t)(&channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
multiqueue_free(chan->events);
xfree(chan);
}
@@ -289,7 +289,7 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
- pmap_del(uint64_t)(&channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
chan->id = 0;
if ((--chan->refcount != 0)) {
@@ -884,14 +884,14 @@ Dictionary channel_info(uint64_t id)
stream_desc = "job";
if (chan->stream.proc.type == kProcessTypePty) {
const char *name = pty_process_tty_name(&chan->stream.pty);
- PUT(info, "pty", STRING_OBJ(cstr_to_string(name)));
+ PUT(info, "pty", CSTR_TO_OBJ(name));
}
char **p = chan->stream.proc.argv;
Array argv = ARRAY_DICT_INIT;
if (p != NULL) {
while (*p != NULL) {
- ADD(argv, STRING_OBJ(cstr_to_string(*p)));
+ ADD(argv, CSTR_TO_OBJ(*p));
p++;
}
}
@@ -918,7 +918,7 @@ Dictionary channel_info(uint64_t id)
default:
abort();
}
- PUT(info, "stream", STRING_OBJ(cstr_to_string(stream_desc)));
+ PUT(info, "stream", CSTR_TO_OBJ(stream_desc));
if (chan->is_rpc) {
mode_desc = "rpc";
@@ -929,7 +929,7 @@ Dictionary channel_info(uint64_t id)
} else {
mode_desc = "bytes";
}
- PUT(info, "mode", STRING_OBJ(cstr_to_string(mode_desc)));
+ PUT(info, "mode", CSTR_TO_OBJ(mode_desc));
return info;
}
@@ -938,7 +938,7 @@ Array channel_all_info(void)
{
Channel *channel;
Array ret = ARRAY_DICT_INIT;
- map_foreach_value(&channels, channel, {
+ pmap_foreach_value(&channels, channel, {
ADD(ret, DICTIONARY_OBJ(channel_info(channel->id)));
});
return ret;
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index ca6c75b411..deb693373c 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -5,7 +5,6 @@
#include <stdint.h>
#include <stdlib.h>
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/multiqueue.h"
@@ -16,7 +15,6 @@
#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/map.h"
-#include "nvim/map_defs.h"
#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/os/pty_process.h"
#include "nvim/terminal.h"
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 8cae831881..49890a460a 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -989,6 +989,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
}
chartabsize_T cts;
+ bool on_NUL = false;
init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
// This function is used very often, do some speed optimizations.
@@ -1052,8 +1053,9 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
// make sure we don't go past the end of the line
if (*cts.cts_ptr == NUL) {
- // NUL at end of line only takes one column
- incr = 1;
+ // NUL at end of line only takes one column, unless there is virtual text
+ incr = MAX(1, cts.cts_cur_text_width_left + cts.cts_cur_text_width_right);
+ on_NUL = true;
break;
}
@@ -1079,8 +1081,6 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
}
if (cursor != NULL) {
- // cursor is after inserted text
- vcol += cts.cts_cur_text_width;
if ((*ptr == TAB)
&& (State & MODE_NORMAL)
&& !wp->w_p_list
@@ -1089,6 +1089,13 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
// cursor at end
*cursor = vcol + incr - 1;
} else {
+ if (!on_NUL) {
+ // cursor is after inserted text, unless on the NUL
+ vcol += cts.cts_cur_text_width_left;
+ if ((State & MODE_INSERT) == 0) {
+ vcol += cts.cts_cur_text_width_right;
+ }
+ }
// cursor at start
*cursor = vcol + head;
}
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index f98ed94b87..258e95bec0 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -4,7 +4,7 @@
#include <stdbool.h>
#include "nvim/buffer_defs.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/option_defs.h"
#include "nvim/pos.h"
#include "nvim/strings.h"
diff --git a/src/nvim/cmdexpand.h b/src/nvim/cmdexpand.h
index 810e289f7c..32c23c5d66 100644
--- a/src/nvim/cmdexpand.h
+++ b/src/nvim/cmdexpand.h
@@ -1,7 +1,7 @@
#ifndef NVIM_CMDEXPAND_H
#define NVIM_CMDEXPAND_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_getln.h"
#include "nvim/garray.h"
#include "nvim/types.h"
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index 81b93e5304..fc84cecc1a 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -641,9 +641,10 @@ void ex_history(exarg_T *eap)
}
for (; !got_int && histype1 <= histype2; histype1++) {
- STRCPY(IObuff, "\n # ");
+ xstrlcpy(IObuff, "\n # ", IOSIZE);
assert(history_names[histype1] != NULL);
- STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
+ xstrlcat(IObuff, history_names[histype1], IOSIZE);
+ xstrlcat(IObuff, " history", IOSIZE);
msg_puts_title(IObuff);
int idx = hisidx[histype1];
histentry_T *hist = history[histype1];
@@ -669,7 +670,7 @@ void ex_history(exarg_T *eap)
trunc_string(hist[i].hisstr, IObuff + strlen(IObuff),
Columns - 10, IOSIZE - (int)strlen(IObuff));
} else {
- STRCAT(IObuff, hist[i].hisstr);
+ xstrlcat(IObuff, hist[i].hisstr, IOSIZE);
}
msg_outtrans(IObuff);
}
diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h
index f86a2f855c..a0f2ab6934 100644
--- a/src/nvim/cmdhist.h
+++ b/src/nvim/cmdhist.h
@@ -1,7 +1,6 @@
#ifndef NVIM_CMDHIST_H
#define NVIM_CMDHIST_H
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index 428f9f28e4..4e5886406a 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -62,8 +62,8 @@ Array mode_style_array(Arena *arena)
for (int i = 0; i < SHAPE_IDX_COUNT; i++) {
cursorentry_T *cur = &shape_table[i];
Dictionary dic = arena_dict(arena, 3 + ((cur->used_for & SHAPE_CURSOR) ? 9 : 0));
- PUT_C(dic, "name", STRING_OBJ(cstr_as_string(cur->full_name)));
- PUT_C(dic, "short_name", STRING_OBJ(cstr_as_string(cur->name)));
+ PUT_C(dic, "name", CSTR_AS_OBJ(cur->full_name));
+ PUT_C(dic, "short_name", CSTR_AS_OBJ(cur->name));
if (cur->used_for & SHAPE_MOUSE) {
PUT_C(dic, "mouse_shape", INTEGER_OBJ(cur->mshape));
}
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 87e4441f32..ce1af290c1 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -83,6 +83,9 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
if (decor && decor_virt_pos(*decor)) {
redraw_buf_line_later(buf, row1 + 1, false);
+ if (decor->virt_text_pos == kVTInline) {
+ changed_line_display_buf(buf);
+ }
}
if (decor && kv_size(decor->virt_lines)) {
@@ -95,6 +98,10 @@ void decor_remove(buf_T *buf, int row, int row2, Decoration *decor)
{
decor_redraw(buf, row, row2, decor);
if (decor) {
+ if (kv_size(decor->virt_text) && decor->virt_text_pos == kVTInline) {
+ assert(buf->b_virt_text_inline > 0);
+ buf->b_virt_text_inline--;
+ }
if (kv_size(decor->virt_lines)) {
assert(buf->b_virt_line_blocks > 0);
buf->b_virt_line_blocks--;
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 92001d496d..95c9655742 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -23,9 +23,11 @@ typedef enum {
kVTOverlay,
kVTWinCol,
kVTRightAlign,
+ kVTInline,
} VirtTextPos;
-EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align" });
+EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align",
+ "inline" });
typedef enum {
kHlModeUnknown,
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index e6cdf3d60d..d2d39e8ca8 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -2,7 +2,7 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// drawline.c: Functions for drawing window lines on the screen.
-// This is the middle level, drawscreen.c is the top and grid.c/screen.c the lower level.
+// This is the middle level, drawscreen.c is the top and grid.c the lower level.
#include <assert.h>
#include <limits.h>
@@ -98,6 +98,7 @@ typedef struct {
int char_attr; ///< attributes for next character
int n_extra; ///< number of extra bytes
+ int n_attr; ///< chars with special attr
char *p_extra; ///< string of extra chars, plus NUL, only used
///< when c_extra and c_final are NUL
char *p_extra_free; ///< p_extra buffer that needs to be freed
@@ -105,9 +106,12 @@ typedef struct {
int c_extra; ///< extra chars, all the same
int c_final; ///< final char, mandatory if set
+ bool extra_for_extmark;
+
// saved "extra" items for when draw_state becomes WL_LINE (again)
int saved_n_extra;
char *saved_p_extra;
+ bool saved_extra_for_extmark;
int saved_c_extra;
int saved_c_final;
int saved_char_attr;
@@ -120,6 +124,14 @@ typedef struct {
int filler_lines; ///< nr of filler lines to be drawn
int filler_todo; ///< nr of filler lines still to do + 1
SignTextAttrs sattrs[SIGN_SHOW_MAX]; ///< sign attributes for the sign column
+
+ VirtText virt_inline;
+ size_t virt_inline_i;
+
+ bool reset_extra_attr;
+
+ int skip_cells; // nr of cells to skip for virtual text
+ int skipped_cells; // nr of skipped virtual text cells
} winlinevars_T;
/// for line_putchar. Contains the state that needs to be remembered from
@@ -342,12 +354,20 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
schar_T dummy[2];
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
max_col - col, false, vcol);
- // if we failed to emit a char, we still need to advance
- cells = MAX(cells, 1);
-
+ // If we failed to emit a char, we still need to put a space and advance.
+ if (cells < 1) {
+ schar_from_ascii(linebuf_char[col], ' ');
+ cells = 1;
+ }
for (int c = 0; c < cells; c++) {
linebuf_attr[col++] = attr;
}
+ if (col < max_col && linebuf_char[col][0] == 0) {
+ // If the left half of a double-width char is overwritten,
+ // change the right half to a space so that grid redraws properly,
+ // but don't advance the current column.
+ schar_from_ascii(linebuf_char[col], ' ');
+ }
vcol += cells;
}
return col;
@@ -843,6 +863,73 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
}
}
+static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v, bool *do_save)
+{
+ while (true) {
+ // we could already be inside an existing inline text with multiple chunks
+ if (!(wlv->virt_inline_i < kv_size(wlv->virt_inline))) {
+ DecorState *state = &decor_state;
+ for (size_t i = 0; i < kv_size(state->active); i++) {
+ DecorRange *item = &kv_A(state->active, i);
+ if (item->start_row != state->row
+ || !kv_size(item->decor.virt_text)
+ || item->decor.virt_text_pos != kVTInline) {
+ continue;
+ }
+ if (item->win_col >= -1 && item->start_col == v) {
+ wlv->virt_inline = item->decor.virt_text;
+ wlv->virt_inline_i = 0;
+ item->win_col = -2;
+ break;
+ }
+ }
+ }
+
+ if (wlv->n_extra == 0 || !wlv->extra_for_extmark) {
+ wlv->reset_extra_attr = false;
+ }
+
+ if (wlv->n_extra <= 0 && wlv->virt_inline_i < kv_size(wlv->virt_inline)) {
+ VirtTextChunk vtc = kv_A(wlv->virt_inline, wlv->virt_inline_i);
+ wlv->p_extra = vtc.text;
+ wlv->n_extra = (int)strlen(wlv->p_extra);
+ wlv->extra_for_extmark = true;
+ wlv->c_extra = NUL;
+ wlv->c_final = NUL;
+ wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
+ wlv->n_attr = mb_charlen(vtc.text);
+ wlv->virt_inline_i++;
+ *do_save = true;
+ // If the text didn't reach until the first window
+ // column we need to skip cells.
+ if (wlv->skip_cells > 0) {
+ int virt_text_len = wlv->n_attr;
+ if (virt_text_len > wlv->skip_cells) {
+ int len = mb_charlen2bytelen(wlv->p_extra, wlv->skip_cells);
+ wlv->n_extra -= len;
+ wlv->p_extra += len;
+ wlv->n_attr -= wlv->skip_cells;
+ // Skipped cells needed to be accounted for in vcol.
+ wlv->skipped_cells += wlv->skip_cells;
+ wlv->skip_cells = 0;
+ } else {
+ // the whole text is left of the window, drop
+ // it and advance to the next one
+ wlv->skip_cells -= virt_text_len;
+ // Skipped cells needed to be accounted for in vcol.
+ wlv->skipped_cells += virt_text_len;
+ wlv->n_attr = 0;
+ wlv->n_extra = 0;
+
+ // go to the start so the next virtual text chunk can be selected.
+ continue;
+ }
+ }
+ }
+ break;
+ }
+}
+
static bool check_mb_utf8(int *c, int *u8cc)
{
if (utf_char2len(*c) > 1) {
@@ -909,6 +996,7 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra)
wlv->draw_state = WL_START;
wlv->saved_n_extra = wlv->n_extra;
wlv->saved_p_extra = wlv->p_extra;
+ wlv->saved_extra_for_extmark = wlv->extra_for_extmark;
wlv->saved_c_extra = wlv->c_extra;
wlv->saved_c_final = wlv->c_final;
wlv->saved_char_attr = wlv->char_attr;
@@ -923,6 +1011,8 @@ static void win_line_continue(winlinevars_T *wlv)
if (wlv->saved_n_extra > 0) {
// Continue item from end of wrapped line.
wlv->n_extra = wlv->saved_n_extra;
+ wlv->saved_n_extra = 0;
+ wlv->extra_for_extmark = wlv->saved_extra_for_extmark;
wlv->c_extra = wlv->saved_c_extra;
wlv->c_final = wlv->saved_c_final;
wlv->p_extra = wlv->saved_p_extra;
@@ -938,7 +1028,7 @@ static void win_line_continue(winlinevars_T *wlv)
/// @param lnum line to display
/// @param startrow first row relative to window grid
/// @param endrow last grid row to be redrawn
-/// @param nochange not updating for changed text
+/// @param mod_top top line updated for changed text
/// @param number_only only update the number column
/// @param foldinfo fold info for this line
/// @param[in, out] providers decoration providers active this line
@@ -946,7 +1036,7 @@ static void win_line_continue(winlinevars_T *wlv)
/// or explicitly return `false`.
///
/// @return the number of last row the line occupies.
-int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool number_only,
+int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bool number_only,
foldinfo_T foldinfo, DecorProviders *providers, char **provider_err)
{
winlinevars_T wlv; // variables passed between functions
@@ -959,14 +1049,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
static char *at_end_str = ""; // used for p_extra when displaying curwin->w_p_lcs_chars.eol
// at end-of-line
- bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
+ const bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
- int n_attr = 0; // chars with special attr
int saved_attr2 = 0; // char_attr saved for n_attr
int n_attr3 = 0; // chars with overruling special attr
int saved_attr3 = 0; // char_attr saved for n_attr3
- int n_skip = 0; // nr of chars to skip for 'nowrap'
+ int n_skip = 0; // nr of chars to skip for 'nowrap' or
+ // concealing
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
@@ -978,10 +1068,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
bool area_highlighting = false; // Visual or incsearch highlighting in this line
int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by highlighting
+ int saved_area_attr = 0; // idem for area_attr
int search_attr = 0; // attributes desired by 'hlsearch'
+ int saved_search_attr = 0; // search_attr to be used when n_extra
+ // goes to zero
int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
int syntax_attr = 0; // attributes desired by syntax
bool has_syntax = false; // this buffer has syntax highl.
+ int folded_attr = 0; // attributes for folded line
int save_did_emsg;
int eol_hl_off = 0; // 1 if highlighted char after EOL
bool draw_color_col = false; // highlight colorcolumn
@@ -1016,6 +1110,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
int prev_c1 = 0; // first composing char for prev_c
bool search_attr_from_match = false; // if search_attr is from :match
+ bool saved_search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
int win_col_offset = 0; // offset for window columns
@@ -1065,7 +1160,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.vcol_sbr = -1;
buf_T *buf = wp->w_buffer;
- bool end_fill = (lnum == buf->b_ml.ml_line_count + 1);
+ const bool end_fill = (lnum == buf->b_ml.ml_line_count + 1);
if (!number_only) {
// To speed up the loop below, set extra_check when there is linebreak,
@@ -1109,12 +1204,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
}
- if (wp->w_p_spell
- && !has_fold
- && !end_fill
- && *wp->w_s->b_p_spl != NUL
- && !GA_EMPTY(&wp->w_s->b_langp)
- && *(char **)(wp->w_s->b_langp.ga_data) != NULL) {
+ if (!has_fold && !end_fill && spell_check_window(wp)) {
// Prepare for spell checking.
has_spell = true;
extra_check = true;
@@ -1137,12 +1227,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// When there was a sentence end in the previous line may require a
// word starting with capital in this line. In line 1 always check
- // the first word.
- if (lnum != capcol_lnum) {
- cap_col = -1;
- }
- if (lnum == 1) {
+ // the first word. Also check for sentence end in the line above
+ // when updating the first row in a window, the top line with
+ // changed text in a window, or if the previous line is folded.
+ if (lnum == 1
+ || ((startrow == 0 || mod_top == lnum
+ || hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL))
+ && check_need_cap(wp, lnum, 0))) {
cap_col = 0;
+ } else if (lnum != capcol_lnum) {
+ cap_col = -1;
}
capcol_lnum = 0;
}
@@ -1428,6 +1522,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
+ // If there the text doesn't reach to the desired column, need to skip
+ // "skip_cells" cells when virtual text follows.
+ if (!wp->w_p_wrap && v > wlv.vcol) {
+ wlv.skip_cells = (int)(v - wlv.vcol);
+ }
+
// Adjust for when the inverted text is before the screen,
// and when the start of the inverted text is before the screen.
if (wlv.tocol <= wlv.vcol) {
@@ -1594,6 +1694,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// Draw the 'statuscolumn' if option is set.
if (statuscol.draw) {
if (statuscol.textp == NULL) {
+ v = (ptr - line);
get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol);
if (!end_fill) {
// Get the line again as evaluating 'statuscolumn' may free it.
@@ -1628,7 +1729,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.draw_state = WL_LINE;
if (has_decor && wlv.row == startrow + wlv.filler_lines) {
// hide virt_text on text hidden by 'nowrap'
- decor_redraw_col(wp, wlv.vcol, wlv.off, true, &decor_state);
+ decor_redraw_col(wp, (colnr_T)(ptr - line), wlv.off, true, &decor_state);
}
win_line_continue(&wlv); // use wlv.saved_ values
}
@@ -1664,7 +1765,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& wlv.col == win_col_offset
&& wlv.n_extra == 0
&& wlv.row == startrow + wlv.filler_lines) {
- wlv.char_attr = win_hl_attr(wp, HLF_FL);
+ wlv.char_attr = folded_attr = win_hl_attr(wp, HLF_FL);
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
memset(buf_fold, ' ', FOLD_TEXT_LEN);
@@ -1705,7 +1806,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = 0;
}
- if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) {
+ int extmark_attr = 0;
+ if (wlv.draw_state == WL_LINE
+ && (area_highlighting || has_spell || extra_check)) {
// handle Visual or match highlighting in this line
if (wlv.vcol == wlv.fromcol
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
@@ -1723,39 +1826,65 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
area_active = false;
}
- if (!wlv.n_extra) {
- // Check for start/end of 'hlsearch' and other matches.
- // After end, check for start/end of next match.
- // When another match, have to check for start again.
- v = (ptr - line);
- search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
- &has_match_conc, &match_conc, lcs_eol_one,
- &on_last_col, &search_attr_from_match);
- ptr = line + v; // "line" may have been changed
-
- // Do not allow a conceal over EOL otherwise EOL will be missed
- // and bad things happen.
- if (*ptr == NUL) {
- has_match_conc = 0;
+ if (!has_fold) {
+ if (has_decor && v >= 0) {
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && wlv.vcol == wp->w_virtcol));
+ extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off,
+ selected, &decor_state);
+
+ bool do_save = false;
+ handle_inline_virtual_text(wp, &wlv, v, &do_save);
+ if (do_save) {
+ // restore search_attr and area_attr when n_extra is down to zero
+ // TODO(bfredl): this is ugly as fuck. look if we can do this some other way.
+ saved_search_attr = search_attr;
+ saved_area_attr = area_attr;
+ saved_search_attr_from_match = search_attr_from_match;
+ search_attr_from_match = false;
+ search_attr = 0;
+ area_attr = 0;
+ extmark_attr = 0;
+ n_skip = 0;
+ }
}
- }
- if (wlv.diff_hlf != (hlf_T)0) {
- if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start
- && wlv.n_extra == 0) {
- wlv.diff_hlf = HLF_TXD; // changed text
- }
- if (wlv.diff_hlf == HLF_TXD && ptr - line > change_end
- && wlv.n_extra == 0) {
- wlv.diff_hlf = HLF_CHD; // changed line
+ if (wlv.n_extra == 0) {
+ // Check for start/end of 'hlsearch' and other matches.
+ // After end, check for start/end of next match.
+ // When another match, have to check for start again.
+ v = (ptr - line);
+ search_attr = update_search_hl(wp, lnum, (colnr_T)v, &line, &screen_search_hl,
+ &has_match_conc, &match_conc, lcs_eol_one,
+ &on_last_col, &search_attr_from_match);
+ ptr = line + v; // "line" may have been changed
+
+ // Do not allow a conceal over EOL otherwise EOL will be missed
+ // and bad things happen.
+ if (*ptr == NUL) {
+ has_match_conc = 0;
+ }
}
- wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
- // Overlay CursorLine onto diff-mode highlight.
- if (wlv.cul_attr) {
- wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine
- ? hl_combine_attr(hl_combine_attr(wlv.cul_attr, wlv.line_attr),
- hl_get_underline())
- : hl_combine_attr(wlv.line_attr, wlv.cul_attr);
+
+ if (wlv.diff_hlf != (hlf_T)0) {
+ // When there is extra text (eg: virtual text) it gets the
+ // diff highlighting for the line, but not for changed text.
+ if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start
+ && wlv.n_extra == 0) {
+ wlv.diff_hlf = HLF_TXD; // changed text
+ }
+ if (wlv.diff_hlf == HLF_TXD && ((ptr - line > change_end && wlv.n_extra == 0)
+ || (wlv.n_extra > 0 && wlv.extra_for_extmark))) {
+ wlv.diff_hlf = HLF_CHD; // changed line
+ }
+ wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf);
+ // Overlay CursorLine onto diff-mode highlight.
+ if (wlv.cul_attr) {
+ wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine
+ ? hl_combine_attr(hl_combine_attr(wlv.cul_attr, wlv.line_attr),
+ hl_get_underline())
+ : hl_combine_attr(wlv.line_attr, wlv.cul_attr);
+ }
}
}
@@ -1786,6 +1915,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.char_attr = 0;
}
}
+
+ if (folded_attr != 0) {
+ wlv.char_attr = hl_combine_attr(folded_attr, wlv.char_attr);
+ }
}
// Get the next character to put on the screen.
@@ -1847,6 +1980,26 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.p_extra++;
}
wlv.n_extra--;
+
+ // Only restore search_attr and area_attr after "n_extra" in
+ // the next screen line is also done.
+ if (wlv.n_extra <= 0) {
+ if (wlv.saved_n_extra <= 0) {
+ if (search_attr == 0) {
+ search_attr = saved_search_attr;
+ }
+ if (area_attr == 0 && *ptr != NUL) {
+ area_attr = saved_area_attr;
+ }
+
+ if (wlv.extra_for_extmark) {
+ // wlv.extra_attr should be used at this position but not
+ // any further.
+ wlv.reset_extra_attr = true;
+ }
+ }
+ wlv.extra_for_extmark = false;
+ }
} else if (foldinfo.fi_lines > 0) {
// skip writing the buffer line itself
c = NUL;
@@ -1898,7 +2051,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = NUL;
wlv.c_final = NUL;
if (area_attr == 0 && search_attr == 0) {
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_8);
saved_attr2 = wlv.char_attr; // save current attr
}
@@ -1953,7 +2106,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_final = NUL;
c = ' ';
if (area_attr == 0 && search_attr == 0) {
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
saved_attr2 = wlv.char_attr; // save current attr
}
@@ -2018,10 +2171,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
if (has_decor && v > 0) {
- bool selected = (area_active || (area_highlighting && noinvcur
- && wlv.vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp, (colnr_T)v - 1, wlv.off,
- selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr);
@@ -2045,15 +2194,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
v = (ptr - line);
if (has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0;
- if (!attr_pri) {
- wlv.char_attr = hl_combine_attr(wlv.char_attr, syntax_attr);
- }
- if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) {
- char *prev_ptr;
+ char *prev_ptr = ptr - mb_l;
+ // do not calculate cap_col at the end of the line or when
+ // only white space is following
+ if (c != 0 && (*skipwhite(prev_ptr) != NUL)
+ && ((!has_syntax && !no_plain_buffer) || can_spell)) {
char *p;
- int len;
hlf_T spell_hlf = HLF_COUNT;
- prev_ptr = ptr - mb_l;
v -= mb_l - 1;
// Use nextline[] if possible, it has the start of the
@@ -2064,9 +2211,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
p = prev_ptr;
}
cap_col -= (int)(prev_ptr - line);
- size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange);
+ size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, mod_top == 0);
assert(tmplen <= INT_MAX);
- len = (int)tmplen;
+ int len = (int)tmplen;
word_end = (int)v + len;
// In Insert mode only highlight a word that
@@ -2129,7 +2276,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
chartabsize_T cts;
init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p);
+ // do not want virtual text to be counted here
+ cts.cts_has_virt_text = false;
wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
+ clear_chartabsize_arg(&cts);
// We have just drawn the showbreak value, no need to add
// space for it again.
@@ -2161,7 +2311,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
c = ' ';
}
}
- clear_chartabsize_arg(&cts);
}
in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' ');
@@ -2192,7 +2341,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
} else {
c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
}
- n_attr = 1;
+ wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2215,7 +2364,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
c = wp->w_p_lcs_chars.space;
}
- n_attr = 1;
+ wlv.n_attr = 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2331,7 +2480,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = wp->w_p_lcs_chars.tab2;
}
wlv.c_final = wp->w_p_lcs_chars.tab3;
- n_attr = tab_len + 1;
+ wlv.n_attr = tab_len + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = wlv.char_attr; // save current attr
mb_c = c;
@@ -2358,15 +2507,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& wlv.line_attr == 0
&& wlv.line_attr_lowprio == 0) {
// In virtualedit, visual selections may extend beyond end of line
- if (area_highlighting && virtual_active()
- && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol) {
- wlv.n_extra = 0;
- } else {
+ if (!(area_highlighting && virtual_active()
+ && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol)) {
wlv.p_extra = at_end_str;
- wlv.n_extra = 1;
- wlv.c_extra = NUL;
- wlv.c_final = NUL;
}
+ wlv.n_extra = 0;
}
if (wp->w_p_list && wp->w_p_lcs_chars.eol > 0) {
c = wp->w_p_lcs_chars.eol;
@@ -2376,7 +2521,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
lcs_eol_one = -1;
ptr--; // put it back at the NUL
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
- n_attr = 1;
+ wlv.n_attr = 1;
mb_c = c;
mb_utf8 = check_mb_utf8(&c, u8cc);
} else if (c != NUL) {
@@ -2405,7 +2550,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.n_extra = byte2cells(c) - 1;
c = (uint8_t)(*wlv.p_extra++);
}
- n_attr = wlv.n_extra + 1;
+ wlv.n_attr = wlv.n_extra + 1;
wlv.extra_attr = win_hl_attr(wp, HLF_8);
saved_attr2 = wlv.char_attr; // save current attr
mb_utf8 = false; // don't draw as UTF-8
@@ -2465,7 +2610,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
} else if (n_skip == 0) {
is_concealing = true;
n_skip = 1;
@@ -2500,8 +2645,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
// Don't override visual selection highlighting.
- if (n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) {
+ if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, wlv.extra_attr);
+ if (wlv.reset_extra_attr) {
+ wlv.reset_extra_attr = false;
+ wlv.extra_attr = 0;
+ // search_attr_from_match can be restored now that the extra_attr has been applied
+ search_attr_from_match = saved_search_attr_from_match;
+ }
}
// Handle the case where we are in column 0 but not on the first
@@ -2521,7 +2672,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.c_extra = MB_FILLER_CHAR;
wlv.c_final = NUL;
wlv.n_extra = 1;
- n_attr = 2;
+ wlv.n_attr = 2;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
}
mb_c = c;
@@ -2737,7 +2888,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
- || (wlv.n_extra && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
+ || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
c = wp->w_p_lcs_chars.ext;
wlv.char_attr = win_hl_attr(wp, HLF_AT);
mb_c = c;
@@ -2808,6 +2959,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.col++;
// UTF-8: Put a 0 in the second screen char.
linebuf_char[wlv.off][0] = 0;
+ linebuf_attr[wlv.off] = linebuf_attr[wlv.off - 1];
if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) {
wlv.vcol++;
}
@@ -2857,7 +3009,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.boguscols += wlv.n_extra;
}
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
}
if (utf_char2cells(mb_c) > 1) {
@@ -2882,13 +3034,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
if (wlv.n_extra > 0) {
wlv.vcol += wlv.n_extra;
wlv.n_extra = 0;
- n_attr = 0;
+ wlv.n_attr = 0;
}
}
} else {
n_skip--;
}
+ // The skipped cells need to be accounted for in vcol.
+ if (wlv.draw_state > WL_STC && wlv.skipped_cells > 0) {
+ wlv.vcol += wlv.skipped_cells;
+ wlv.skipped_cells = 0;
+ }
+
// Only advance the "wlv.vcol" when after the 'number' or
// 'relativenumber' column.
if (wlv.draw_state > WL_STC
@@ -2906,7 +3064,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
// restore attributes after last 'listchars' or 'number' char
- if (n_attr > 0 && wlv.draw_state == WL_LINE && --n_attr == 0) {
+ if (wlv.n_attr > 0 && wlv.draw_state == WL_LINE && --wlv.n_attr == 0) {
wlv.char_attr = saved_attr2;
}
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 7f7c721379..4f79ba87af 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -2222,9 +2222,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
}
// Display one line
- row = win_line(wp, lnum, srow,
- foldinfo.fi_lines ? srow : wp->w_grid.rows,
- mod_top == 0, false, foldinfo, &line_providers, &provider_err);
+ row = win_line(wp, lnum, srow, foldinfo.fi_lines ? srow : wp->w_grid.rows,
+ mod_top, false, foldinfo, &line_providers, &provider_err);
if (foldinfo.fi_lines == 0) {
wp->w_lines[idx].wl_folded = false;
@@ -2261,7 +2260,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// text doesn't need to be drawn, but the number column does.
foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
cursorline_fi : fold_info(wp, lnum);
- (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
+ (void)win_line(wp, lnum, srow, wp->w_grid.rows, mod_top, true,
info, &line_providers, &provider_err);
}
@@ -2359,7 +2358,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// for ml_line_count+1 and only draw filler lines
foldinfo_T info = { 0 };
row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
- false, false, info, &line_providers, &provider_err);
+ mod_top, false, info, &line_providers, &provider_err);
}
} else if (dollar_vcol == -1) {
wp->w_botline = lnum;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 2078fc4251..d6d5ff8ac7 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -53,6 +53,7 @@
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
#include "nvim/search.h"
+#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
@@ -232,7 +233,7 @@ static void insert_enter(InsertState *s)
stop_insert_mode = false;
// need to position cursor again when on a TAB
- if (gchar_cursor() == TAB) {
+ if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) {
curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
}
@@ -876,12 +877,12 @@ static int insert_handle_key(InsertState *s)
state_handle_k_event();
goto check_pum;
- case K_COMMAND: // some command
+ case K_COMMAND: // <Cmd>command<CR>
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
goto check_pum;
case K_LUA:
- map_execute_lua();
+ map_execute_lua(false);
check_pum:
// nvim_select_popupmenu_item() can be called from the handling of
@@ -1526,10 +1527,11 @@ void edit_unputchar(void)
}
}
-// Called when p_dollar is set: display a '$' at the end of the changed text
-// Only works when cursor is in the line that changes.
-void display_dollar(colnr_T col)
+/// Called when "$" is in 'cpoptions': display a '$' at the end of the changed
+/// text. Only works when cursor is in the line that changes.
+void display_dollar(colnr_T col_arg)
{
+ colnr_T col = col_arg < 0 ? 0 : col_arg;
colnr_T save_col;
if (!redrawing()) {
@@ -2527,6 +2529,7 @@ int oneleft(void)
}
curwin->w_set_curswant = true;
+ adjust_skipcol();
return OK;
}
@@ -3469,7 +3472,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
State = MODE_NORMAL;
may_trigger_modechanged();
// need to position cursor again when on a TAB
- if (gchar_cursor() == TAB) {
+ if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) {
curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 13299b0253..52924bf9a5 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -3677,9 +3677,6 @@ static int eval_index_inner(typval_T *rettv, bool is_range, typval_T *var1, typv
} else if (n2 >= len) {
n2 = len;
}
- if (exclusive) {
- n2--;
- }
if (n1 >= len || n2 < 0 || n1 > n2) {
v = NULL;
} else {
@@ -4523,7 +4520,7 @@ bool garbage_collect(bool testing)
// Channels
{
Channel *data;
- map_foreach_value(&channels, data, {
+ pmap_foreach_value(&channels, data, {
set_ref_in_callback_reader(&data->on_data, copyID, NULL, NULL);
set_ref_in_callback_reader(&data->on_stderr, copyID, NULL, NULL);
set_ref_in_callback(&data->on_exit, copyID, NULL, NULL);
@@ -4533,7 +4530,7 @@ bool garbage_collect(bool testing)
// Timers
{
timer_T *timer;
- map_foreach_value(&timers, timer, {
+ pmap_foreach_value(&timers, timer, {
set_ref_in_callback(&timer->callback, copyID, NULL, NULL);
})
}
@@ -5989,7 +5986,7 @@ void add_timer_info_all(typval_T *rettv)
{
tv_list_alloc_ret(rettv, map_size(&timers));
timer_T *timer;
- map_foreach_value(&timers, timer, {
+ pmap_foreach_value(&timers, timer, {
if (!timer->stopped || timer->refcount > 1) {
add_timer_info(rettv, timer);
}
@@ -6087,7 +6084,7 @@ static void timer_close_cb(TimeWatcher *tw, void *data)
timer_T *timer = (timer_T *)data;
multiqueue_free(timer->tw.events);
callback_free(&timer->callback);
- pmap_del(uint64_t)(&timers, (uint64_t)timer->timer_id);
+ pmap_del(uint64_t)(&timers, (uint64_t)timer->timer_id, NULL);
timer_decref(timer);
}
@@ -6101,7 +6098,7 @@ static void timer_decref(timer_T *timer)
void timer_stop_all(void)
{
timer_T *timer;
- map_foreach_value(&timers, timer, {
+ pmap_foreach_value(&timers, timer, {
timer_stop(timer);
})
}
@@ -8657,7 +8654,7 @@ bool eval_has_provider(const char *feat)
return false;
}
- char name[32]; // Normalized: "python_compiled" => "python".
+ char name[32]; // Normalized: "python3_compiled" => "python3".
snprintf(name, sizeof(name), "%s", feat);
strchrsub(name, '_', '\0'); // Chop any "_xx" suffix.
@@ -8715,7 +8712,7 @@ void ex_checkhealth(exarg_T *eap)
{
Error err = ERROR_INIT;
MAXSIZE_TEMP_ARRAY(args, 1);
- ADD_C(args, STRING_OBJ(cstr_as_string(eap->arg)));
+ ADD_C(args, CSTR_AS_OBJ(eap->arg));
NLUA_EXEC_STATIC("return vim.health._check(...)", args, &err);
if (!ERROR_SET(&err)) {
return;
diff --git a/src/nvim/eval/decode.h b/src/nvim/eval/decode.h
index f1be5a1f69..7455130221 100644
--- a/src/nvim/eval/decode.h
+++ b/src/nvim/eval/decode.h
@@ -4,8 +4,8 @@
#include <msgpack.h>
#include <stddef.h>
-#include "nvim/eval/typval.h"
-#include "nvim/globals.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/types.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/decode.h.generated.h"
diff --git a/src/nvim/eval/executor.h b/src/nvim/eval/executor.h
index 42abf77f4a..e8bf147245 100644
--- a/src/nvim/eval/executor.h
+++ b/src/nvim/eval/executor.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EVAL_EXECUTOR_H
#define NVIM_EVAL_EXECUTOR_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
extern char *e_list_index_out_of_range_nr;
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index 1ae031a952..65a95196de 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -6,7 +6,6 @@
#include "nvim/api/private/dispatch.h"
#include "nvim/buffer_defs.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/types.h"
diff --git a/src/nvim/eval/gc.h b/src/nvim/eval/gc.h
index 3185750c3b..66e959ced5 100644
--- a/src/nvim/eval/gc.h
+++ b/src/nvim/eval/gc.h
@@ -1,7 +1,6 @@
#ifndef NVIM_EVAL_GC_H
#define NVIM_EVAL_GC_H
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
extern dict_T *gc_first_dict;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 5755178b18..cb8f8ce44d 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2166,6 +2166,16 @@ varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key,
return tv_get_number(&di->di_tv);
}
+varnumber_T tv_dict_get_bool(const dict_T *const d, const char *const key, const int def)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ dictitem_T *const di = tv_dict_find(d, key, -1);
+ if (di == NULL) {
+ return def;
+ }
+ return tv_get_bool(&di->di_tv);
+}
+
/// Converts a dict to an environment
char **tv_dict_to_env(dict_T *denv)
{
@@ -4049,6 +4059,18 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
return (ret_error == NULL ? -1 : 0);
}
+varnumber_T tv_get_bool(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return tv_get_number_chk(tv, NULL);
+}
+
+varnumber_T tv_get_bool_chk(const typval_T *const tv, bool *const ret_error)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
+{
+ return tv_get_number_chk(tv, ret_error);
+}
+
/// Get the line number from VimL object
///
/// @param[in] tv Object to get value from. Is expected to be a number or
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 84e4067f9d..767fd706b3 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -567,8 +567,4 @@ EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
# include "eval/typval.h.generated.h"
#endif
-#define tv_get_bool tv_get_number
-#define tv_get_bool_chk tv_get_number_chk
-#define tv_dict_get_bool tv_dict_get_number_def
-
#endif // NVIM_EVAL_TYPVAL_H
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
index 2f19144da3..171b0417d0 100644
--- a/src/nvim/eval/typval_encode.h
+++ b/src/nvim/eval/typval_encode.h
@@ -11,7 +11,7 @@
#include <string.h>
#include "klib/kvec.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
/// Type of the stack entry
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index fbb5e8d10c..a52b8d3f18 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -467,12 +467,10 @@ char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, b
/// @param name function name
void emsg_funcname(const char *errmsg, const char *name)
{
- char *p;
+ char *p = (char *)name;
- if ((uint8_t)(*name) == K_SPECIAL) {
+ if ((uint8_t)name[0] == K_SPECIAL && name[1] != NUL && name[2] != NUL) {
p = concat_str("<SNR>", name + 3);
- } else {
- p = (char *)name;
}
semsg(_(errmsg), p);
@@ -1863,8 +1861,7 @@ char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, part
// Check for hard coded <SNR>: already translated function ID (from a user
// command).
- if ((unsigned char)(*pp)[0] == K_SPECIAL && (unsigned char)(*pp)[1] == KS_EXTRA
- && (*pp)[2] == KE_SNR) {
+ if ((uint8_t)(*pp)[0] == K_SPECIAL && (uint8_t)(*pp)[1] == KS_EXTRA && (*pp)[2] == KE_SNR) {
*pp += 3;
len = get_id_len((const char **)pp) + 3;
return xmemdupz(start, (size_t)len);
@@ -2140,7 +2137,6 @@ void ex_function(exarg_T *eap)
char *theline;
char *line_to_free = NULL;
char c;
- int saved_did_emsg;
bool saved_wait_return = need_wait_return;
char *name = NULL;
char *p;
@@ -2234,7 +2230,7 @@ void ex_function(exarg_T *eap)
// An error in a function call during evaluation of an expression in magic
// braces should not cause the function not to be defined.
- saved_did_emsg = did_emsg;
+ const int saved_did_emsg = did_emsg;
did_emsg = false;
//
@@ -2896,9 +2892,9 @@ char *get_user_func_name(expand_T *xp, int idx)
cat_func_name(IObuff, IOSIZE, fp);
if (xp->xp_context != EXPAND_USER_FUNC) {
- STRCAT(IObuff, "(");
+ xstrlcat(IObuff, "(", IOSIZE);
if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) {
- STRCAT(IObuff, ")");
+ xstrlcat(IObuff, ")", IOSIZE);
}
}
return IObuff;
@@ -3509,7 +3505,7 @@ char *get_return_cmd(void *rettv)
s = "";
}
- STRCPY(IObuff, ":return ");
+ xstrlcpy(IObuff, ":return ", IOSIZE);
xstrlcpy(IObuff + 8, s, IOSIZE - 8);
if (strlen(s) + 8 >= IOSIZE) {
STRCPY(IObuff + IOSIZE - 4, "...");
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index 4a98afb00e..562c549b4b 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "nvim/eval.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/garray.h"
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index e0057faffb..39fed08c77 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -5,7 +5,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index dbfd1088d2..1d8c3c0cf4 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -54,7 +54,6 @@
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/input.h"
-#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/mark.h"
@@ -1926,6 +1925,9 @@ void do_wqall(exarg_T *eap)
int save_forceit = eap->forceit;
if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall) {
+ if (before_quit_all(eap) == FAIL) {
+ return;
+ }
exiting = true;
}
@@ -4801,29 +4803,3 @@ void ex_oldfiles(exarg_T *eap)
}
}
}
-
-void ex_trust(exarg_T *eap)
-{
- const char *const p = skiptowhite(eap->arg);
- char *arg1 = xmemdupz(eap->arg, (size_t)(p - eap->arg));
- const char *action = "allow";
- const char *path = skipwhite(p);
-
- if (strcmp(arg1, "++deny") == 0) {
- action = "deny";
- } else if (strcmp(arg1, "++remove") == 0) {
- action = "remove";
- } else if (*arg1 != '\0') {
- semsg(e_invarg2, arg1);
- goto theend;
- }
-
- if (path[0] == '\0') {
- path = NULL;
- }
-
- nlua_trust(action, path);
-
-theend:
- xfree(arg1);
-}
diff --git a/src/nvim/ex_cmds.h b/src/nvim/ex_cmds.h
index 39bff3e35d..148065e096 100644
--- a/src/nvim/ex_cmds.h
+++ b/src/nvim/ex_cmds.h
@@ -4,7 +4,6 @@
#include <stdbool.h>
#include "nvim/buffer_defs.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 2acedb5ec3..568d4d38ba 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -4,7 +4,7 @@
#include <stdbool.h>
#include <stdint.h>
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/normal.h"
#include "nvim/pos.h"
#include "nvim/regexp_defs.h"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index adb17f2cfd..9666d80de2 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1454,7 +1454,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
}
// Fail if command is invalid
if (eap->cmdidx == CMD_SIZE) {
- STRCPY(IObuff, _(e_not_an_editor_command));
+ xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE);
// If the modifier was parsed OK the error must be in the following command
char *cmdname = after_modifier ? after_modifier : cmdline;
append_command(cmdname);
@@ -2044,7 +2044,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
// Check for wrong commands.
if (ea.cmdidx == CMD_SIZE) {
if (!ea.skip) {
- STRCPY(IObuff, _(e_not_an_editor_command));
+ xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE);
// If the modifier was parsed OK the error must be in the following
// command
char *cmdname = after_modifier ? after_modifier : *cmdlinep;
@@ -2321,7 +2321,7 @@ doend:
if (errormsg != NULL && *errormsg != NUL && !did_emsg) {
if (flags & DOCMD_VERBOSE) {
if (errormsg != IObuff) {
- STRCPY(IObuff, errormsg);
+ xstrlcpy(IObuff, errormsg, IOSIZE);
errormsg = IObuff;
}
append_command(*ea.cmdlinep);
@@ -2888,7 +2888,7 @@ static void append_command(char *cmd)
d -= utf_head_off(IObuff, d);
STRCPY(d, "...");
}
- STRCAT(IObuff, ": ");
+ xstrlcat(IObuff, ": ", IOSIZE);
d = IObuff + strlen(IObuff);
while (*s != NUL && d - IObuff + 5 < IOSIZE) {
if ((uint8_t)s[0] == 0xc2 && (uint8_t)s[1] == 0xa0) {
@@ -4589,8 +4589,9 @@ static void ex_cquit(exarg_T *eap)
getout(eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE);
}
-/// ":qall": try to quit all windows
-static void ex_quit_all(exarg_T *eap)
+/// Do preparations for "qall" and "wqall".
+/// Returns FAIL when quitting should be aborted.
+int before_quit_all(exarg_T *eap)
{
if (cmdwin_type != 0) {
if (eap->forceit) {
@@ -4598,19 +4599,28 @@ static void ex_quit_all(exarg_T *eap)
} else {
cmdwin_result = K_XF2;
}
- return;
+ return FAIL;
}
// Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
- return;
+ return FAIL;
}
if (before_quit_autocmds(curwin, true, eap->forceit)) {
- return;
+ return FAIL;
}
+ return OK;
+}
+
+/// ":qall": try to quit all windows
+static void ex_quit_all(exarg_T *eap)
+{
+ if (before_quit_all(eap) == FAIL) {
+ return;
+ }
exiting = true;
if (eap->forceit || !check_changed_any(false, false)) {
getout(0);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index af2ec3356f..dd23f6ece9 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -127,6 +127,7 @@ typedef struct command_line_state {
int break_ctrl_c;
expand_T xpc;
long *b_im_ptr;
+ buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid
} CommandLineState;
typedef struct cmdpreview_win_info {
@@ -736,7 +737,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea
} else {
s->b_im_ptr = &curbuf->b_p_imsearch;
}
-
+ s->b_im_ptr_buf = curbuf;
if (*s->b_im_ptr == B_IMODE_LMAP) {
State |= MODE_LANGMAP;
}
@@ -1140,7 +1141,7 @@ static int command_line_execute(VimState *state, int key)
} else if (s->c == K_COMMAND) {
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
} else {
- map_execute_lua();
+ map_execute_lua(false);
}
// nvim_select_popupmenu_item() can be called from the handling of
@@ -1538,20 +1539,21 @@ static int command_line_erase_chars(CommandLineState *s)
/// language :lmap mappings and/or Input Method.
static void command_line_toggle_langmap(CommandLineState *s)
{
+ long *b_im_ptr = buf_valid(s->b_im_ptr_buf) ? s->b_im_ptr : NULL;
if (map_to_exists_mode("", MODE_LANGMAP, false)) {
// ":lmap" mappings exists, toggle use of mappings.
State ^= MODE_LANGMAP;
- if (s->b_im_ptr != NULL) {
+ if (b_im_ptr != NULL) {
if (State & MODE_LANGMAP) {
- *s->b_im_ptr = B_IMODE_LMAP;
+ *b_im_ptr = B_IMODE_LMAP;
} else {
- *s->b_im_ptr = B_IMODE_NONE;
+ *b_im_ptr = B_IMODE_NONE;
}
}
}
- if (s->b_im_ptr != NULL) {
- if (s->b_im_ptr == &curbuf->b_p_iminsert) {
+ if (b_im_ptr != NULL) {
+ if (b_im_ptr == &curbuf->b_p_iminsert) {
set_iminsert_global(curbuf);
} else {
set_imsearch_global(curbuf);
@@ -3385,7 +3387,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
} else {
Array item = arena_array(&arena, 2);
ADD_C(item, INTEGER_OBJ(0));
- ADD_C(item, STRING_OBJ(cstr_as_string(line->cmdbuff)));
+ ADD_C(item, CSTR_AS_OBJ(line->cmdbuff));
content = arena_array(&arena, 1);
ADD_C(content, ARRAY_OBJ(item));
}
@@ -3412,7 +3414,7 @@ void ui_ext_cmdline_block_append(size_t indent, const char *line)
Array item = ARRAY_DICT_INIT;
ADD(item, INTEGER_OBJ(0));
- ADD(item, STRING_OBJ(cstr_as_string(buf)));
+ ADD(item, CSTR_AS_OBJ(buf));
Array content = ARRAY_DICT_INIT;
ADD(content, ARRAY_OBJ(item));
ADD(cmdline_block, ARRAY_OBJ(content));
diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h
index 61ac4b69c5..b21fb0506d 100644
--- a/src/nvim/ex_getln.h
+++ b/src/nvim/ex_getln.h
@@ -4,7 +4,6 @@
#include <stdbool.h>
#include "klib/kvec.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/types.h"
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 727be1562c..f4a6a02682 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -50,11 +50,6 @@
# include "extmark.c.generated.h"
#endif
-static uint32_t *buf_ns_ref(buf_T *buf, uint32_t ns_id, bool put)
-{
- return map_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, put);
-}
-
/// Create or update an extmark
///
/// must not be used during iteration!
@@ -62,7 +57,7 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
colnr_T end_col, Decoration *decor, bool right_gravity, bool end_right_gravity,
ExtmarkOp op, Error *err)
{
- uint32_t *ns = buf_ns_ref(buf, ns_id, true);
+ uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL);
uint32_t id = idp ? *idp : 0;
bool decor_full = false;
@@ -153,6 +148,9 @@ revised:
}
if (decor) {
+ if (kv_size(decor->virt_text) && decor->virt_text_pos == kVTInline) {
+ buf->b_virt_text_inline++;
+ }
if (kv_size(decor->virt_lines)) {
buf->b_virt_line_blocks++;
}
@@ -237,7 +235,7 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
bool all_ns = (ns_id == 0);
uint32_t *ns = NULL;
if (!all_ns) {
- ns = buf_ns_ref(buf, ns_id, false);
+ ns = map_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL);
if (!ns) {
// nothing to do
return false;
@@ -258,15 +256,14 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
|| (mark.pos.row == u_row && mark.pos.col > u_col)) {
break;
}
- ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark),
- false);
+ ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark), NULL);
if (del_status) {
marktree_del_itr(buf->b_marktree, itr, false);
if (*del_status >= 0) { // we had a decor_id
DecorItem it = kv_A(decors, *del_status);
decor_remove(buf, it.row1, mark.pos.row, mark.decor_full);
}
- map_del(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark));
+ map_del(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark), NULL);
continue;
}
@@ -294,7 +291,7 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
}
uint64_t id;
ssize_t decor_id;
- map_foreach(&delete_set, id, decor_id, {
+ map_foreach(ssize_t, &delete_set, id, decor_id, {
mtkey_t mark = marktree_lookup(buf->b_marktree, id, itr);
assert(marktree_itr_valid(itr));
marktree_del_itr(buf->b_marktree, itr, false);
@@ -303,7 +300,7 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
decor_remove(buf, it.row1, mark.pos.row, mark.decor_full);
}
});
- map_clear(uint64_t, ssize_t)(&delete_set);
+ map_clear(uint64_t, &delete_set);
kv_size(decors) = 0;
return marks_cleared;
}
@@ -424,8 +421,8 @@ void extmark_free_all(buf_T *buf)
marktree_clear(buf->b_marktree);
- map_destroy(uint32_t, uint32_t)(buf->b_extmark_ns);
- map_init(uint32_t, uint32_t, buf->b_extmark_ns);
+ map_destroy(uint32_t, buf->b_extmark_ns);
+ *buf->b_extmark_ns = (Map(uint32_t, uint32_t)) MAP_INIT;
}
/// Save info for undo/redo of set marks
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index d659987686..e60007bf88 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1693,22 +1693,22 @@ failed:
#ifdef UNIX
if (S_ISFIFO(perm)) { // fifo
- STRCAT(IObuff, _("[fifo]"));
+ xstrlcat(IObuff, _("[fifo]"), IOSIZE);
c = true;
}
if (S_ISSOCK(perm)) { // or socket
- STRCAT(IObuff, _("[socket]"));
+ xstrlcat(IObuff, _("[socket]"), IOSIZE);
c = true;
}
# ifdef OPEN_CHR_FILES
if (S_ISCHR(perm)) { // or character special
- STRCAT(IObuff, _("[character special]"));
+ xstrlcat(IObuff, _("[character special]"), IOSIZE);
c = true;
}
# endif
#endif
if (curbuf->b_p_ro) {
- STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
+ xstrlcat(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"), IOSIZE);
c = true;
}
if (read_no_eol_lnum) {
@@ -1716,18 +1716,18 @@ failed:
c = true;
}
if (ff_error == EOL_DOS) {
- STRCAT(IObuff, _("[CR missing]"));
+ xstrlcat(IObuff, _("[CR missing]"), IOSIZE);
c = true;
}
if (split) {
- STRCAT(IObuff, _("[long lines split]"));
+ xstrlcat(IObuff, _("[long lines split]"), IOSIZE);
c = true;
}
if (notconverted) {
- STRCAT(IObuff, _("[NOT converted]"));
+ xstrlcat(IObuff, _("[NOT converted]"), IOSIZE);
c = true;
} else if (converted) {
- STRCAT(IObuff, _("[converted]"));
+ xstrlcat(IObuff, _("[converted]"), IOSIZE);
c = true;
}
if (conv_error != 0) {
@@ -1739,7 +1739,7 @@ failed:
_("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte);
c = true;
} else if (error) {
- STRCAT(IObuff, _("[READ ERRORS]"));
+ xstrlcat(IObuff, _("[READ ERRORS]"), IOSIZE);
c = true;
}
if (msg_add_fileformat(fileformat)) {
@@ -2128,17 +2128,17 @@ bool msg_add_fileformat(int eol_type)
{
#ifndef USE_CRNL
if (eol_type == EOL_DOS) {
- STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
+ xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"), IOSIZE);
return true;
}
#endif
if (eol_type == EOL_MAC) {
- STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
+ xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"), IOSIZE);
return true;
}
#ifdef USE_CRNL
if (eol_type == EOL_UNIX) {
- STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
+ xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"), IOSIZE);
return true;
}
#endif
@@ -2170,8 +2170,7 @@ void msg_add_lines(int insert_space, long lnum, off_T nchars)
/// Append message for missing line separator to IObuff.
void msg_add_eol(void)
{
- STRCAT(IObuff,
- shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
+ xstrlcat(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"), IOSIZE);
}
bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST
@@ -3482,8 +3481,7 @@ void vim_deltempdir(void)
char *vim_gettempdir(void)
{
static int notfound = 0;
- bool exists = false;
- if (vim_tempdir == NULL || !(exists = os_isdir(vim_tempdir))) {
+ if (vim_tempdir == NULL || !os_isdir(vim_tempdir)) {
if (vim_tempdir != NULL) {
notfound++;
if (notfound == 1) {
diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h
index a4566d754b..5eb2689233 100644
--- a/src/nvim/fileio.h
+++ b/src/nvim/fileio.h
@@ -2,7 +2,6 @@
#define NVIM_FILEIO_H
#include "nvim/buffer_defs.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/garray.h"
#include "nvim/os/os.h"
diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua
index 76b372eac2..b9fae7d0fe 100644
--- a/src/nvim/generators/gen_ex_cmds.lua
+++ b/src/nvim/generators/gen_ex_cmds.lua
@@ -55,6 +55,7 @@ defsfile:write(string.format([[
#include "nvim/help.h"
#include "nvim/indent.h"
#include "nvim/lua/executor.h"
+#include "nvim/lua/secure.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/match.h"
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index a0e8350287..5c1366c5b2 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -92,8 +92,8 @@ static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
static int typeahead_char = 0; // typeahead char that's not flushed
-// when block_redo is true redo buffer will not be changed
-// used by edit() to repeat insertions and 'V' command for redoing
+/// When block_redo is true the redo buffer will not be changed.
+/// Used by edit() to repeat insertions.
static int block_redo = false;
static int KeyNoremap = 0; // remapping flags
@@ -134,6 +134,10 @@ static size_t last_recorded_len = 0; // number of last recorded chars
#endif
static const char e_recursive_mapping[] = N_("E223: Recursive mapping");
+static const char e_cmd_mapping_must_end_with_cr[]
+ = N_("E1255: <Cmd> mapping must end with <CR>");
+static const char e_cmd_mapping_must_end_with_cr_before_second_cmd[]
+ = N_("E1136: <Cmd> mapping must end with <CR> before second <Cmd>");
// Free and clear a buffer.
void free_buff(buffheader_T *buf)
@@ -550,6 +554,25 @@ void AppendToRedobuffLit(const char *str, int len)
}
}
+/// Append "s" to the redo buffer, leaving 3-byte special key codes unmodified
+/// and escaping other K_SPECIAL bytes.
+void AppendToRedobuffSpec(const char *s)
+{
+ if (block_redo) {
+ return;
+ }
+
+ while (*s != NUL) {
+ if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
+ // Insert special key literally.
+ add_buff(&redobuff, s, 3L);
+ s += 3;
+ } else {
+ add_char_buff(&redobuff, mb_cptr2char_adv(&s));
+ }
+ }
+}
+
/// Append a character to the redo buffer.
/// Translates special keys, NUL, K_SPECIAL and multibyte characters.
void AppendCharToRedobuff(int c)
@@ -2884,7 +2907,8 @@ int fix_input_buffer(uint8_t *buf, int len)
return len;
}
-/// Get command argument for <Cmd> key
+/// Function passed to do_cmdline() to get the command after a <Cmd> key from
+/// typeahead.
char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
{
garray_T line_ga;
@@ -2894,6 +2918,7 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
ga_init(&line_ga, 1, 32);
+ // no mapping for these characters
no_mapping++;
got_int = false;
@@ -2903,16 +2928,17 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
if (vgetorpeek(false) == NUL) {
// incomplete <Cmd> is an error, because there is not much the user
// could do in this state.
- emsg(e_cmdmap_err);
+ emsg(_(e_cmd_mapping_must_end_with_cr));
aborted = true;
break;
}
// Get one character at a time.
c1 = vgetorpeek(true);
+
// Get two extra bytes for special keys
if (c1 == K_SPECIAL) {
- c1 = vgetorpeek(true); // no mapping for these chars
+ c1 = vgetorpeek(true);
c2 = vgetorpeek(true);
if (c1 == KS_MODIFIER) {
cmod = c2;
@@ -2928,8 +2954,8 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
} else if (c1 == ESC) {
aborted = true;
} else if (c1 == K_COMMAND) {
- // special case to give nicer error message
- emsg(e_cmdmap_repeated);
+ // give a nicer error message for this special case
+ emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd));
aborted = true;
} else if (c1 == K_SNR) {
ga_concat(&line_ga, "<SNR>");
@@ -2960,7 +2986,12 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
return line_ga.ga_data;
}
-bool map_execute_lua(void)
+/// Handle a Lua mapping: get its LuaRef from typeahead and execute it.
+///
+/// @param may_repeat save the LuaRef for redoing with "." later
+///
+/// @return false if getting the LuaRef was aborted, true otherwise
+bool map_execute_lua(bool may_repeat)
{
garray_T line_ga;
int c1 = -1;
@@ -2992,6 +3023,10 @@ bool map_execute_lua(void)
}
LuaRef ref = (LuaRef)atoi(line_ga.ga_data);
+ if (may_repeat) {
+ repeat_luaref = ref;
+ }
+
Error err = ERROR_INIT;
Array args = ARRAY_DICT_INIT;
nlua_call_ref(ref, NULL, args, false, &err);
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 698f4a98c7..bedb529d04 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -993,7 +993,8 @@ EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
-EXTERN const char e_menuothermode[] INIT(= N_("E328: Menu only exists in another mode"));
+EXTERN const char e_menu_only_exists_in_another_mode[]
+INIT(= N_("E328: Menu only exists in another mode"));
EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
@@ -1003,10 +1004,6 @@ EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit
EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
-EXTERN const char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>"));
-EXTERN const char e_cmdmap_repeated[]
-INIT(= N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
-
EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 037606c38f..76dd2a073a 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -316,8 +316,7 @@ int grid_puts_len(ScreenGrid *grid, const char *text, int textlen, int row, int
// When at the start of the text and overwriting the right half of a
// two-cell character in the same grid, truncate that into a '>'.
if (ptr == text && col > 0 && grid->chars[off][0] == 0) {
- grid->chars[off - 1][0] = '>';
- grid->chars[off - 1][1] = 0;
+ schar_from_ascii(grid->chars[off - 1], '>');
}
schar_copy(grid->chars[off], buf);
diff --git a/src/nvim/help.c b/src/nvim/help.c
index 633e9df244..d412f3a098 100644
--- a/src/nvim/help.c
+++ b/src/nvim/help.c
@@ -22,6 +22,7 @@
#include "nvim/globals.h"
#include "nvim/help.h"
#include "nvim/macros.h"
+#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index e2f3e2aafa..fad113adc5 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -50,7 +50,7 @@ static Map(int, int) blendthrough_attr_entries = MAP_INIT;
/// highlight entries private to a namespace
static Map(ColorKey, ColorItem) ns_hls;
typedef int NSHlAttr[HLF_COUNT + 1];
-static PMap(handle_T) ns_hl_attr;
+static PMap(int) ns_hl_attr;
void highlight_init(void)
{
@@ -207,7 +207,7 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault)
if (!valid_item && p->hl_def != LUA_NOREF && !recursive) {
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, INTEGER_OBJ((Integer)ns_id));
- ADD_C(args, STRING_OBJ(cstr_to_string(syn_id2name(hl_id))));
+ ADD_C(args, CSTR_TO_OBJ(syn_id2name(hl_id)));
ADD_C(args, BOOLEAN_OBJ(link));
// TODO(bfredl): preload the "global" attr dict?
@@ -277,7 +277,7 @@ bool hl_check_ns(void)
hl_attr_active = highlight_attr;
if (ns > 0) {
update_ns_hl(ns);
- NSHlAttr *hl_def = (NSHlAttr *)pmap_get(handle_T)(&ns_hl_attr, ns);
+ NSHlAttr *hl_def = (NSHlAttr *)pmap_get(int)(&ns_hl_attr, ns);
if (hl_def) {
hl_attr_active = *hl_def;
}
@@ -335,7 +335,7 @@ void update_window_hl(win_T *wp, bool invalid)
if (ns_id != wp->w_ns_hl_active || wp->w_ns_hl_attr == NULL) {
wp->w_ns_hl_active = ns_id;
- wp->w_ns_hl_attr = *(NSHlAttr *)pmap_get(handle_T)(&ns_hl_attr, ns_id);
+ wp->w_ns_hl_attr = *(NSHlAttr *)pmap_get(int)(&ns_hl_attr, ns_id);
if (!wp->w_ns_hl_attr) {
// No specific highlights, use the defaults.
wp->w_ns_hl_attr = highlight_attr;
@@ -398,6 +398,15 @@ void update_window_hl(win_T *wp, bool invalid)
} else {
wp->w_hl_attr_normalnc = hl_def[HLF_INACTIVE];
}
+
+ // if blend= attribute is not set, 'winblend' value overrides it.
+ if (wp->w_floating && wp->w_p_winbl > 0) {
+ HlEntry entry = kv_A(attr_entries, wp->w_hl_attr_normalnc);
+ if (entry.attr.hl_blend == -1) {
+ entry.attr.hl_blend = (int)wp->w_p_winbl;
+ wp->w_hl_attr_normalnc = get_attr_entry(entry);
+ }
+ }
}
void update_ns_hl(int ns_id)
@@ -410,7 +419,7 @@ void update_ns_hl(int ns_id)
return;
}
- NSHlAttr **alloc = (NSHlAttr **)pmap_ref(handle_T)(&ns_hl_attr, ns_id, true);
+ NSHlAttr **alloc = (NSHlAttr **)pmap_put_ref(int)(&ns_hl_attr, ns_id, NULL, NULL);
if (*alloc == NULL) {
*alloc = xmalloc(sizeof(**alloc));
}
@@ -482,28 +491,28 @@ void clear_hl_tables(bool reinit)
{
if (reinit) {
kv_size(attr_entries) = 1;
- map_clear(HlEntry, int)(&attr_entry_ids);
- map_clear(int, int)(&combine_attr_entries);
- map_clear(int, int)(&blend_attr_entries);
- map_clear(int, int)(&blendthrough_attr_entries);
+ map_clear(HlEntry, &attr_entry_ids);
+ map_clear(int, &combine_attr_entries);
+ map_clear(int, &blend_attr_entries);
+ map_clear(int, &blendthrough_attr_entries);
memset(highlight_attr_last, -1, sizeof(highlight_attr_last));
highlight_attr_set_all();
highlight_changed();
screen_invalidate_highlights();
} else {
kv_destroy(attr_entries);
- map_destroy(HlEntry, int)(&attr_entry_ids);
- map_destroy(int, int)(&combine_attr_entries);
- map_destroy(int, int)(&blend_attr_entries);
- map_destroy(int, int)(&blendthrough_attr_entries);
- map_destroy(ColorKey, ColorItem)(&ns_hls);
+ map_destroy(HlEntry, &attr_entry_ids);
+ map_destroy(int, &combine_attr_entries);
+ map_destroy(int, &blend_attr_entries);
+ map_destroy(int, &blendthrough_attr_entries);
+ map_destroy(ColorKey, &ns_hls);
}
}
void hl_invalidate_blends(void)
{
- map_clear(int, int)(&blend_attr_entries);
- map_clear(int, int)(&blendthrough_attr_entries);
+ map_clear(int, &blend_attr_entries);
+ map_clear(int, &blendthrough_attr_entries);
highlight_changed();
update_window_hl(curwin, true);
}
@@ -1132,21 +1141,21 @@ static void hl_inspect_impl(Array *arr, int attr)
HlEntry e = kv_A(attr_entries, attr);
switch (e.kind) {
case kHlSyntax:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("syntax")));
+ PUT(item, "kind", CSTR_TO_OBJ("syntax"));
PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string(syn_id2name(e.id1))));
+ CSTR_TO_OBJ(syn_id2name(e.id1)));
break;
case kHlUI:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("ui")));
+ PUT(item, "kind", CSTR_TO_OBJ("ui"));
const char *ui_name = (e.id1 == -1) ? "Normal" : hlf_names[e.id1];
- PUT(item, "ui_name", STRING_OBJ(cstr_to_string(ui_name)));
+ PUT(item, "ui_name", CSTR_TO_OBJ(ui_name));
PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string(syn_id2name(e.id2))));
+ CSTR_TO_OBJ(syn_id2name(e.id2)));
break;
case kHlTerminal:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("term")));
+ PUT(item, "kind", CSTR_TO_OBJ("term"));
break;
case kHlCombine:
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index a0f0a947b8..09e7d04e02 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -697,10 +697,18 @@ int load_colors(char *name)
char *buf = xmalloc(buflen);
apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf);
snprintf(buf, buflen, "colors/%s.vim", name);
- int retval = source_runtime(buf, DIP_START + DIP_OPT);
+ int retval = source_runtime(buf, 0);
if (retval == FAIL) {
snprintf(buf, buflen, "colors/%s.lua", name);
- retval = source_runtime(buf, DIP_START + DIP_OPT);
+ retval = source_runtime(buf, 0);
+ }
+ if (retval == FAIL) {
+ snprintf(buf, buflen, "colors/%s.vim", name);
+ retval = source_runtime(buf, DIP_NORTP + DIP_START + DIP_OPT);
+ }
+ if (retval == FAIL) {
+ snprintf(buf, buflen, "colors/%s.lua", name);
+ retval = source_runtime(buf, DIP_NORTP + DIP_START + DIP_OPT);
}
xfree(buf);
if (retval == OK) {
@@ -1420,7 +1428,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
void free_highlight(void)
{
ga_clear(&highlight_ga);
- map_destroy(cstr_t, int)(&highlight_unames);
+ map_destroy(cstr_t, &highlight_unames);
arena_mem_free(arena_finish(&highlight_arena));
}
@@ -1548,8 +1556,11 @@ static bool hlgroup2dict(Dictionary *hl, NS ns_id, int hl_id, Arena *arena)
HlAttrs attr =
syn_attr2entry(ns_id == 0 ? sgp->sg_attr : ns_get_hl(&ns_id, hl_id, false, sgp->sg_set));
*hl = arena_dict(arena, HLATTRS_DICT_SIZE + 1);
+ if (attr.rgb_ae_attr & HL_DEFAULT) {
+ PUT_C(*hl, "default", BOOLEAN_OBJ(true));
+ }
if (link > 0) {
- PUT_C(*hl, "link", STRING_OBJ(cstr_as_string(hl_table[link - 1].sg_name)));
+ PUT_C(*hl, "link", CSTR_AS_OBJ(hl_table[link - 1].sg_name));
}
Dictionary hl_cterm = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(hl, NULL, attr, true, true);
diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h
index ddc0acfbfa..241dd65cc7 100644
--- a/src/nvim/lua/converter.h
+++ b/src/nvim/lua/converter.h
@@ -6,7 +6,7 @@
#include <stdint.h>
#include "nvim/api/private/defs.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 9586b56f3c..8c1d8addcd 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -109,11 +109,16 @@ typedef enum luv_err_type {
kThreadCallback,
} luv_err_t;
+lua_State *get_global_lstate(void)
+{
+ return global_lstate;
+}
+
/// Convert lua error into a Vim error message
///
/// @param lstate Lua interpreter state.
/// @param[in] msg Message base, must contain one `%s`.
-static void nlua_error(lua_State *const lstate, const char *const msg)
+void nlua_error(lua_State *const lstate, const char *const msg)
FUNC_ATTR_NONNULL_ALL
{
size_t len;
@@ -150,7 +155,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
/// @param lstate Lua interpreter state
/// @param[in] nargs Number of arguments expected by the function being called.
/// @param[in] nresults Number of results the function returns.
-static int nlua_pcall(lua_State *lstate, int nargs, int nresults)
+int nlua_pcall(lua_State *lstate, int nargs, int nresults)
{
lua_getglobal(lstate, "debug");
lua_getfield(lstate, -1, "traceback");
@@ -336,7 +341,7 @@ static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg
lua_pushstring(L, argv[lua_arg0 - 1]);
lua_rawseti(L, -2, 0); // _G.arg[0] = "foo.lua"
- for (; lua_arg0 >= 0 && i + lua_arg0 < argc; i++) {
+ for (; i + lua_arg0 < argc; i++) {
lua_pushstring(L, argv[i + lua_arg0]);
lua_rawseti(L, -2, i + 1); // _G.arg[i+1] = "--foo"
}
@@ -836,7 +841,7 @@ void nlua_run_script(char **argv, int argc, int lua_arg0)
exit(lua_ok ? 0 : 1);
}
-lua_State *nlua_init_state(bool thread)
+static lua_State *nlua_init_state(bool thread)
{
// If it is called from the main thread, it will attempt to rebuild the cache.
const uv_thread_t self = uv_thread_self();
@@ -910,12 +915,13 @@ static void nlua_common_free_all_mem(lua_State *lstate)
if (nlua_track_refs) {
// in case there are leaked luarefs, leak the associated memory
// to get LeakSanitizer stacktraces on exit
- pmap_destroy(handle_T)(&ref_state->ref_markers);
+ map_destroy(int, &ref_state->ref_markers);
}
#endif
lua_close(lstate);
}
+
static void nlua_print_event(void **argv)
{
char *str = argv[0];
@@ -1285,7 +1291,7 @@ LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index)
#ifdef NLUA_TRACK_REFS
if (nlua_track_refs) {
// dummy allocation to make LeakSanitizer track our luarefs
- pmap_put(handle_T)(&ref_state->ref_markers, ref, xmalloc(3));
+ pmap_put(int)(&ref_state->ref_markers, ref, xmalloc(3));
}
#endif
}
@@ -1305,7 +1311,7 @@ void nlua_unref(lua_State *lstate, nlua_ref_state_t *ref_state, LuaRef ref)
#ifdef NLUA_TRACK_REFS
// NB: don't remove entry from map to track double-unref
if (nlua_track_refs) {
- xfree(pmap_get(handle_T)(&ref_state->ref_markers, ref));
+ xfree(pmap_get(int)(&ref_state->ref_markers, ref));
}
#endif
luaL_unref(lstate, LUA_REGISTRYINDEX, ref);
@@ -2275,80 +2281,3 @@ plain:
kv_printf(str, "<Lua %d>", ref);
return str.items;
}
-
-char *nlua_read_secure(const char *path)
-{
- lua_State *const lstate = global_lstate;
- const int top = lua_gettop(lstate);
-
- lua_getglobal(lstate, "vim");
- lua_getfield(lstate, -1, "secure");
- lua_getfield(lstate, -1, "read");
- lua_pushstring(lstate, path);
- if (nlua_pcall(lstate, 1, 1)) {
- nlua_error(lstate, _("Error executing vim.secure.read: %.*s"));
- lua_settop(lstate, top);
- return NULL;
- }
-
- size_t len = 0;
- const char *contents = lua_tolstring(lstate, -1, &len);
- char *buf = NULL;
- if (contents != NULL) {
- // Add one to include trailing null byte
- buf = xcalloc(len + 1, sizeof(char));
- memcpy(buf, contents, len + 1);
- }
-
- lua_settop(lstate, top);
- return buf;
-}
-
-bool nlua_trust(const char *action, const char *path)
-{
- lua_State *const lstate = global_lstate;
- const int top = lua_gettop(lstate);
-
- lua_getglobal(lstate, "vim");
- lua_getfield(lstate, -1, "secure");
- lua_getfield(lstate, -1, "trust");
-
- lua_newtable(lstate);
- lua_pushstring(lstate, "action");
- lua_pushstring(lstate, action);
- lua_settable(lstate, -3);
- if (path == NULL) {
- lua_pushstring(lstate, "bufnr");
- lua_pushnumber(lstate, 0);
- lua_settable(lstate, -3);
- } else {
- lua_pushstring(lstate, "path");
- lua_pushstring(lstate, path);
- lua_settable(lstate, -3);
- }
-
- if (nlua_pcall(lstate, 1, 2)) {
- nlua_error(lstate, _("Error executing vim.secure.trust: %.*s"));
- lua_settop(lstate, top);
- return false;
- }
-
- bool success = lua_toboolean(lstate, -2);
- const char *msg = lua_tostring(lstate, -1);
- if (msg != NULL) {
- if (success) {
- if (strcmp(action, "allow") == 0) {
- smsg("Allowed \"%s\" in trust database.", msg);
- } else if (strcmp(action, "deny") == 0) {
- smsg("Denied \"%s\" in trust database.", msg);
- } else if (strcmp(action, "remove") == 0) {
- smsg("Removed \"%s\" from trust database.", msg);
- }
- } else {
- semsg(e_trustfile, msg);
- }
- }
-
- lua_settop(lstate, top);
- return success;
-}
diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h
index c6747833e5..f340d9d0d8 100644
--- a/src/nvim/lua/executor.h
+++ b/src/nvim/lua/executor.h
@@ -8,7 +8,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/assert.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/func_attr.h"
#include "nvim/lua/converter.h"
@@ -24,7 +24,7 @@ typedef struct {
LuaRef empty_dict_ref;
int ref_count;
#if __has_feature(address_sanitizer)
- PMap(handle_T) ref_markers;
+ PMap(int) ref_markers;
#endif
} nlua_ref_state_t;
diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c
new file mode 100644
index 0000000000..30d5a95fc0
--- /dev/null
+++ b/src/nvim/lua/secure.c
@@ -0,0 +1,118 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#include "nvim/charset.h"
+#include "nvim/lua/executor.h"
+#include "nvim/lua/secure.h"
+#include "nvim/message.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/secure.c.generated.h"
+#endif
+
+char *nlua_read_secure(const char *path)
+{
+ lua_State *const lstate = get_global_lstate();
+ const int top = lua_gettop(lstate);
+
+ lua_getglobal(lstate, "vim");
+ lua_getfield(lstate, -1, "secure");
+ lua_getfield(lstate, -1, "read");
+ lua_pushstring(lstate, path);
+ if (nlua_pcall(lstate, 1, 1)) {
+ nlua_error(lstate, _("Error executing vim.secure.read: %.*s"));
+ lua_settop(lstate, top);
+ return NULL;
+ }
+
+ size_t len = 0;
+ const char *contents = lua_tolstring(lstate, -1, &len);
+ char *buf = NULL;
+ if (contents != NULL) {
+ // Add one to include trailing null byte
+ buf = xcalloc(len + 1, sizeof(char));
+ memcpy(buf, contents, len + 1);
+ }
+
+ lua_settop(lstate, top);
+ return buf;
+}
+
+static bool nlua_trust(const char *action, const char *path)
+{
+ lua_State *const lstate = get_global_lstate();
+ const int top = lua_gettop(lstate);
+
+ lua_getglobal(lstate, "vim");
+ lua_getfield(lstate, -1, "secure");
+ lua_getfield(lstate, -1, "trust");
+
+ lua_newtable(lstate);
+ lua_pushstring(lstate, "action");
+ lua_pushstring(lstate, action);
+ lua_settable(lstate, -3);
+ if (path == NULL) {
+ lua_pushstring(lstate, "bufnr");
+ lua_pushnumber(lstate, 0);
+ lua_settable(lstate, -3);
+ } else {
+ lua_pushstring(lstate, "path");
+ lua_pushstring(lstate, path);
+ lua_settable(lstate, -3);
+ }
+
+ if (nlua_pcall(lstate, 1, 2)) {
+ nlua_error(lstate, _("Error executing vim.secure.trust: %.*s"));
+ lua_settop(lstate, top);
+ return false;
+ }
+
+ bool success = lua_toboolean(lstate, -2);
+ const char *msg = lua_tostring(lstate, -1);
+ if (msg != NULL) {
+ if (success) {
+ if (strcmp(action, "allow") == 0) {
+ smsg("Allowed \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "deny") == 0) {
+ smsg("Denied \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "remove") == 0) {
+ smsg("Removed \"%s\" from trust database.", msg);
+ }
+ } else {
+ semsg(e_trustfile, msg);
+ }
+ }
+
+ lua_settop(lstate, top);
+ return success;
+}
+
+void ex_trust(exarg_T *eap)
+{
+ const char *const p = skiptowhite(eap->arg);
+ char *arg1 = xmemdupz(eap->arg, (size_t)(p - eap->arg));
+ const char *action = "allow";
+ const char *path = skipwhite(p);
+
+ if (strcmp(arg1, "++deny") == 0) {
+ action = "deny";
+ } else if (strcmp(arg1, "++remove") == 0) {
+ action = "remove";
+ } else if (*arg1 != '\0') {
+ semsg(e_invarg2, arg1);
+ goto theend;
+ }
+
+ if (path[0] == '\0') {
+ path = NULL;
+ }
+
+ nlua_trust(action, path);
+
+theend:
+ xfree(arg1);
+}
diff --git a/src/nvim/lua/secure.h b/src/nvim/lua/secure.h
new file mode 100644
index 0000000000..87c468538e
--- /dev/null
+++ b/src/nvim/lua/secure.h
@@ -0,0 +1,12 @@
+#ifndef NVIM_LUA_SECURE_H
+#define NVIM_LUA_SECURE_H
+
+#include <lua.h>
+
+#include "nvim/ex_cmds_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/secure.h.generated.h"
+#endif
+
+#endif // NVIM_LUA_SECURE_H
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index da64685a40..a9e7838980 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -20,6 +20,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/buffer_defs.h"
#include "nvim/globals.h"
+#include "nvim/lua/executor.h"
#include "nvim/lua/treesitter.h"
#include "nvim/macros.h"
#include "nvim/map.h"
@@ -43,6 +44,13 @@ typedef struct {
int max_match_id;
} TSLua_cursor;
+typedef struct {
+ LuaRef cb;
+ lua_State *lstate;
+ bool lex;
+ bool parse;
+} TSLuaLoggerOpts;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/treesitter.c.generated.h"
#endif
@@ -56,6 +64,8 @@ static struct luaL_Reg parser_meta[] = {
{ "included_ranges", parser_get_ranges },
{ "set_timeout", parser_set_timeout },
{ "timeout", parser_get_timeout },
+ { "_set_logger", parser_set_logger },
+ { "_logger", parser_get_logger },
{ NULL, NULL }
};
@@ -231,9 +241,9 @@ int tslua_remove_lang(lua_State *L)
const char *lang_name = luaL_checkstring(L, 1);
bool present = pmap_has(cstr_t)(&langs, lang_name);
if (present) {
- char *key = (char *)pmap_key(cstr_t)(&langs, lang_name);
- pmap_del(cstr_t)(&langs, lang_name);
- xfree(key);
+ cstr_t key;
+ pmap_del(cstr_t)(&langs, lang_name, &key);
+ xfree((void *)key);
}
lua_pushboolean(L, present);
return 1;
@@ -322,6 +332,12 @@ static int parser_gc(lua_State *L)
return 0;
}
+ TSLogger logger = ts_parser_logger(*p);
+ if (logger.log) {
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload;
+ xfree(opts);
+ }
+
ts_parser_delete(*p);
return 0;
}
@@ -669,9 +685,82 @@ static int parser_get_timeout(lua_State *L)
}
lua_pushinteger(L, (long)ts_parser_timeout_micros(*p));
+ return 1;
+}
+
+static void logger_cb(void *payload, TSLogType logtype, const char *s)
+{
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)payload;
+ if ((!opts->lex && logtype == TSLogTypeLex)
+ || (!opts->parse && logtype == TSLogTypeParse)) {
+ return;
+ }
+
+ lua_State *lstate = opts->lstate;
+
+ nlua_pushref(lstate, opts->cb);
+ lua_pushstring(lstate, logtype == TSLogTypeParse ? "parse" : "lex");
+ lua_pushstring(lstate, s);
+ if (lua_pcall(lstate, 2, 0, 0)) {
+ luaL_error(lstate, "Error executing treesitter logger callback");
+ }
+}
+
+static int parser_set_logger(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ if (!lua_isboolean(L, 2)) {
+ return luaL_argerror(L, 2, "boolean expected");
+ }
+
+ if (!lua_isboolean(L, 3)) {
+ return luaL_argerror(L, 3, "boolean expected");
+ }
+
+ if (!lua_isfunction(L, 4)) {
+ return luaL_argerror(L, 4, "function expected");
+ }
+
+ TSLuaLoggerOpts *opts = xmalloc(sizeof(TSLuaLoggerOpts));
+
+ *opts = (TSLuaLoggerOpts){
+ .lex = lua_toboolean(L, 2),
+ .parse = lua_toboolean(L, 3),
+ .cb = nlua_ref_global(L, 4),
+ .lstate = L
+ };
+
+ TSLogger logger = {
+ .payload = (void *)opts,
+ .log = logger_cb
+ };
+
+ ts_parser_set_logger(*p, logger);
return 0;
}
+static int parser_get_logger(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ TSLogger logger = ts_parser_logger(*p);
+ if (logger.log) {
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload;
+ nlua_pushref(L, opts->cb);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
// Tree methods
/// push tree interface on lua stack.
@@ -1349,6 +1438,11 @@ static int node_rawquery(lua_State *L)
} else {
cursor = ts_query_cursor_new();
}
+
+#ifdef NVIM_TS_HAS_SET_MAX_START_DEPTH
+ // reset the start depth
+ ts_query_cursor_set_max_start_depth(cursor, 0);
+#endif
ts_query_cursor_set_match_limit(cursor, 256);
ts_query_cursor_exec(cursor, query, node);
@@ -1360,6 +1454,29 @@ static int node_rawquery(lua_State *L)
ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 });
}
+ if (lua_gettop(L) >= 6 && !lua_isnil(L, 6)) {
+ if (!lua_istable(L, 6)) {
+ return luaL_error(L, "table expected");
+ }
+ lua_pushnil(L);
+ // stack: [dict, ..., nil]
+ while (lua_next(L, 6)) {
+ // stack: [dict, ..., key, value]
+ if (lua_type(L, -2) == LUA_TSTRING) {
+ char *k = (char *)lua_tostring(L, -2);
+ if (strequal("max_start_depth", k)) {
+ // TODO(lewis6991): remove ifdef when min TS version is 0.20.9
+#ifdef NVIM_TS_HAS_SET_MAX_START_DEPTH
+ uint32_t max_start_depth = (uint32_t)lua_tointeger(L, -1);
+ ts_query_cursor_set_max_start_depth(cursor, max_start_depth);
+#endif
+ }
+ }
+ lua_pop(L, 1); // pop the value; lua_next will pop the key.
+ // stack: [dict, ..., key]
+ }
+ }
+
TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata]
ud->cursor = cursor;
ud->predicated_match = -1;
diff --git a/src/nvim/main.c b/src/nvim/main.c
index ee643adab5..d4fbf8ce93 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -49,6 +49,7 @@
#include "nvim/keycodes.h"
#include "nvim/log.h"
#include "nvim/lua/executor.h"
+#include "nvim/lua/secure.h"
#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/mark.h"
@@ -443,8 +444,7 @@ int main(int argc, char **argv)
// If using the runtime (-u is not NONE), enable syntax & filetype plugins.
if (!vimrc_none || params.clean) {
- // Sources filetype.lua and filetype.vim unless the user explicitly disabled it with :filetype
- // off.
+ // Sources filetype.lua unless the user explicitly disabled it with :filetype off.
filetype_maybe_enable();
// Sources syntax/syntax.vim. We do this *after* the user startup scripts so that users can
// disable syntax highlighting with `:syntax off` if they wish.
@@ -2227,3 +2227,17 @@ static void check_swap_exists_action(void)
}
handle_swap_exists(NULL);
}
+
+#ifdef ENABLE_ASAN_UBSAN
+const char *__ubsan_default_options(void);
+const char *__ubsan_default_options(void)
+{
+ return "print_stacktrace=1";
+}
+
+const char *__asan_default_options(void);
+const char *__asan_default_options(void)
+{
+ return "handle_abort=1,handle_sigill=1";
+}
+#endif
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 191a459863..4c8506f468 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -16,7 +16,6 @@
#include "klib/khash.h"
#include "nvim/gettext.h"
#include "nvim/map.h"
-#include "nvim/map_defs.h"
#include "nvim/memory.h"
#define cstr_t_hash kh_str_hash_func
@@ -29,8 +28,6 @@
#define int_eq kh_int_hash_equal
#define handle_T_hash kh_int_hash_func
#define handle_T_eq kh_int_hash_equal
-#define KittyKey_hash kh_int_hash_func
-#define KittyKey_eq kh_int_hash_equal
#if defined(ARCH_64)
# define ptr_t_hash(key) uint64_t_hash((uint64_t)(key))
@@ -45,74 +42,69 @@
#define DEFAULT_INITIALIZER { 0 }
#define SSIZE_INITIALIZER { -1 }
+#define KEY_IMPL(T) \
+ __KHASH_IMPL(T, , T, T##_hash, T##_eq) \
+
#define MAP_IMPL(T, U, ...) \
INITIALIZER_DECLARE(T, U, __VA_ARGS__); \
- __KHASH_IMPL(T##_##U##_map, , T, U, 1, T##_hash, T##_eq) \
- void map_##T##_##U##_destroy(Map(T, U) *map) \
- { \
- kh_dealloc(T##_##U##_map, &map->table); \
- } \
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)) { \
+ if ((k = kh_get(T, &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); \
- } \
- T map_##T##_##U##_key(Map(T, U) *map, T key) \
- { \
- khiter_t k; \
- if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \
- abort(); /* Caller must check map_has(). */ \
- } \
- return kh_key(&map->table, k); \
+ return kh_val(U, &map->table, k); \
} \
U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \
{ \
+ STATIC_ASSERT(sizeof(U) <= KHASH_MAX_VAL_SIZE, "increase KHASH_MAX_VAL_SIZE"); \
int ret; \
U rv = INITIALIZER(T, U); \
- khiter_t k = kh_put(T##_##U##_map, &map->table, key, &ret); \
+ khiter_t k = kh_put(T, &map->table, key, &ret, sizeof(U)); \
if (!ret) { \
- rv = kh_val(&map->table, k); \
+ rv = kh_val(U, &map->table, k); \
} \
- kh_val(&map->table, k) = value; \
+ kh_val(U, &map->table, k) = value; \
return rv; \
} \
- U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \
+ U *map_##T##_##U##_ref(Map(T, U) *map, T key, T **key_alloc) \
+ { \
+ khiter_t k = kh_get(T, &map->table, key); \
+ if (k == kh_end(&map->table)) { \
+ return NULL; \
+ } \
+ if (key_alloc) { \
+ *key_alloc = &kh_key(&map->table, k); \
+ } \
+ return &kh_val(U, &map->table, k); \
+ } \
+ U *map_##T##_##U##_put_ref(Map(T, U) *map, T key, T **key_alloc, bool *new_item) \
{ \
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; \
- } \
+ khiter_t k = kh_put(T, &map->table, key, &ret, sizeof(U)); \
+ if (ret) { \
+ kh_val(U, &map->table, k) = INITIALIZER(T, U); \
} \
- return &kh_val(&map->table, k); \
+ if (new_item) { \
+ *new_item = (bool)ret; \
+ } \
+ if (key_alloc) { \
+ *key_alloc = &kh_key(&map->table, k); \
+ } \
+ return &kh_val(U, &map->table, k); \
} \
- U map_##T##_##U##_del(Map(T, U) *map, T key) \
+ U map_##T##_##U##_del(Map(T, U) *map, T key, T *key_alloc) \
{ \
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); \
+ if ((k = kh_get(T, &map->table, key)) != kh_end(&map->table)) { \
+ rv = kh_val(U, &map->table, k); \
+ if (key_alloc) { \
+ *key_alloc = kh_key(&map->table, k); \
+ } \
+ kh_del(T, &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)
@@ -162,7 +154,17 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
}
+KEY_IMPL(int)
+KEY_IMPL(cstr_t)
+KEY_IMPL(ptr_t)
+KEY_IMPL(uint64_t)
+KEY_IMPL(uint32_t)
+KEY_IMPL(String)
+KEY_IMPL(HlEntry)
+KEY_IMPL(ColorKey)
+
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
+MAP_IMPL(int, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER)
@@ -172,26 +174,19 @@ MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)
MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint32_t, uint32_t, DEFAULT_INITIALIZER)
-MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, String, DEFAULT_INITIALIZER)
-
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
-MAP_IMPL(KittyKey, cstr_t, DEFAULT_INITIALIZER)
-
/// Deletes a key:value pair from a string:pointer map, and frees the
/// storage of both key and value.
///
void pmap_del2(PMap(cstr_t) *map, const char *key)
{
- if (pmap_has(cstr_t)(map, key)) {
- void *k = (void *)pmap_key(cstr_t)(map, key);
- void *v = pmap_get(cstr_t)(map, key);
- pmap_del(cstr_t)(map, key);
- xfree(k);
- xfree(v);
- }
+ cstr_t key_alloc = NULL;
+ ptr_t val = pmap_del(cstr_t)(map, key, &key_alloc);
+ xfree((void *)key_alloc);
+ xfree(val);
}
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 92f0b32255..cc32a20740 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -7,39 +7,71 @@
#include "klib/khash.h"
#include "nvim/api/private/defs.h"
-#include "nvim/extmark_defs.h"
-#include "nvim/gettext.h"
+#include "nvim/assert.h"
#include "nvim/highlight_defs.h"
-#include "nvim/map_defs.h"
-#include "nvim/tui/input_defs.h"
#include "nvim/types.h"
-#include "nvim/ui_client.h"
#if defined(__NetBSD__)
# undef uint64_t
# define uint64_t uint64_t
#endif
+typedef const char *cstr_t;
+typedef void *ptr_t;
+
+#define Map(T, U) Map_##T##_##U
+#define PMap(T) Map(T, ptr_t)
+
+#define KEY_DECLS(T) \
+ KHASH_DECLARE(T) \
+ static inline bool set_put_##T(Set(T) *set, T key, T **key_alloc) { \
+ int kh_ret; \
+ khiter_t k = kh_put(T, set, key, &kh_ret, 0); \
+ if (key_alloc) { \
+ *key_alloc = &kh_key(set, k); \
+ } \
+ return kh_ret; \
+ } \
+ static inline void set_del_##T(Set(T) *set, T key) \
+ { \
+ khiter_t k; \
+ if ((k = kh_get(T, set, key)) != kh_end(set)) { \
+ kh_del(T, set, k); \
+ } \
+ } \
+ static inline bool set_has_##T(Set(T) *set, T key) { \
+ return (kh_get(T, set, key) != kh_end(set)); \
+ } \
+
#define MAP_DECLS(T, U) \
- KHASH_DECLARE(T##_##U##_map, T, U) \
typedef struct { \
- khash_t(T##_##U##_map) table; \
+ khash_t(T) table; \
} Map(T, U); \
- Map(T, U) *map_##T##_##U##_new(void); \
- void map_##T##_##U##_free(Map(T, U) *map); \
- void map_##T##_##U##_destroy(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); \
- T map_##T##_##U##_key(Map(T, U) *map, T key); \
+ static inline bool map_##T##_##U##_has(Map(T, U) *map, T key) \
+ { \
+ return kh_get(T, &map->table, key) != kh_end(&map->table); \
+ } \
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);
+ U *map_##T##_##U##_ref(Map(T, U) *map, T key, T **key_alloc); \
+ U *map_##T##_##U##_put_ref(Map(T, U) *map, T key, T **key_alloc, bool *new_item); \
+ U map_##T##_##U##_del(Map(T, U) *map, T key, T *key_alloc); \
-//
// NOTE: Keys AND values must be allocated! khash.h does not make a copy.
-//
+
+#define Set(type) khash_t(type)
+
+KEY_DECLS(int)
+KEY_DECLS(cstr_t)
+KEY_DECLS(ptr_t)
+KEY_DECLS(uint64_t)
+KEY_DECLS(uint32_t)
+KEY_DECLS(String)
+KEY_DECLS(HlEntry)
+KEY_DECLS(ColorKey)
+
MAP_DECLS(int, int)
+MAP_DECLS(int, ptr_t)
MAP_DECLS(int, cstr_t)
MAP_DECLS(cstr_t, ptr_t)
MAP_DECLS(cstr_t, int)
@@ -49,48 +81,50 @@ MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(uint64_t, ssize_t)
MAP_DECLS(uint64_t, uint64_t)
MAP_DECLS(uint32_t, uint32_t)
-
-MAP_DECLS(handle_T, ptr_t)
MAP_DECLS(HlEntry, int)
MAP_DECLS(String, handle_T)
MAP_DECLS(String, int)
MAP_DECLS(int, String)
-
MAP_DECLS(ColorKey, ColorItem)
-MAP_DECLS(KittyKey, cstr_t)
-
-#define MAP_INIT { { 0, 0, 0, 0, NULL, NULL, NULL } }
-#define map_init(k, v, map) do { *(map) = (Map(k, v)) MAP_INIT; } while (false)
+#define SET_INIT { 0, 0, 0, 0, NULL, NULL, NULL }
+#define MAP_INIT { SET_INIT }
-#define map_destroy(T, U) map_##T##_##U##_destroy
#define map_get(T, U) map_##T##_##U##_get
#define map_has(T, U) map_##T##_##U##_has
-#define map_key(T, U) map_##T##_##U##_key
#define map_put(T, U) map_##T##_##U##_put
#define map_ref(T, U) map_##T##_##U##_ref
+#define map_put_ref(T, U) map_##T##_##U##_put_ref
#define map_del(T, U) map_##T##_##U##_del
-#define map_clear(T, U) map_##T##_##U##_clear
+#define map_destroy(T, map) kh_dealloc(T, &(map)->table)
+#define map_clear(T, map) kh_clear(T, &(map)->table)
#define map_size(map) ((map)->table.size)
-#define pmap_destroy(T) map_destroy(T, ptr_t)
#define pmap_get(T) map_get(T, ptr_t)
#define pmap_has(T) map_has(T, ptr_t)
-#define pmap_key(T) map_key(T, ptr_t)
#define pmap_put(T) map_put(T, ptr_t)
#define pmap_ref(T) map_ref(T, ptr_t)
+#define pmap_put_ref(T) map_put_ref(T, ptr_t)
/// @see pmap_del2
#define pmap_del(T) map_del(T, ptr_t)
-#define pmap_clear(T) map_clear(T, ptr_t)
-#define pmap_init(k, map) map_init(k, ptr_t, map)
-#define map_foreach(map, key, value, block) \
- kh_foreach(&(map)->table, key, value, block)
+#define map_foreach(U, map, key, value, block) kh_foreach(U, &(map)->table, key, value, block)
-#define map_foreach_value(map, value, block) \
- kh_foreach_value(&(map)->table, value, block)
+#define map_foreach_value(U, map, value, block) kh_foreach_value(U, &(map)->table, value, block)
+#define map_foreach_key(map, key, block) kh_foreach_key(&(map)->table, key, block)
+#define set_foreach(set, key, block) kh_foreach_key(set, key, block)
+
+#define pmap_foreach_value(map, value, block) map_foreach_value(ptr_t, map, value, block)
+#define pmap_foreach(map, key, value, block) map_foreach(ptr_t, map, key, value, block)
void pmap_del2(PMap(cstr_t) *map, const char *key);
+#define set_has(T, set, key) set_has_##T(set, key)
+#define set_put(T, set, key) set_put_##T(set, key, NULL)
+#define set_put_ref(T, set, key, key_alloc) set_put_##T(set, key, key_alloc)
+#define set_del(T, set, key) set_del_##T(set, key)
+#define set_destroy(T, set) kh_dealloc(T, set)
+#define set_clear(T, set) kh_clear(T, set)
+
#endif // NVIM_MAP_H
diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h
deleted file mode 100644
index 61afedbe50..0000000000
--- a/src/nvim/map_defs.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef NVIM_MAP_DEFS_H
-#define NVIM_MAP_DEFS_H
-
-#include "klib/khash.h"
-
-typedef const char *cstr_t;
-typedef void *ptr_t;
-
-#define Map(T, U) Map_##T##_##U
-#define PMap(T) Map(T, ptr_t)
-
-#endif // NVIM_MAP_DEFS_H
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index c5449bd66e..e40e67cead 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -2096,13 +2096,13 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
: cstr_as_string(str2special_save(mp->m_str, false, true))));
}
if (mp->m_desc != NULL) {
- PUT(dict, "desc", STRING_OBJ(cstr_to_string(mp->m_desc)));
+ PUT(dict, "desc", CSTR_TO_OBJ(mp->m_desc));
}
- PUT(dict, "lhs", STRING_OBJ(cstr_as_string(lhs)));
- PUT(dict, "lhsraw", STRING_OBJ(cstr_to_string(mp->m_keys)));
+ PUT(dict, "lhs", CSTR_AS_OBJ(lhs));
+ PUT(dict, "lhsraw", CSTR_TO_OBJ(mp->m_keys));
if (lhsrawalt != NULL) {
// Also add the value for the simplified entry.
- PUT(dict, "lhsrawalt", STRING_OBJ(cstr_to_string(lhsrawalt)));
+ PUT(dict, "lhsrawalt", CSTR_TO_OBJ(lhsrawalt));
}
PUT(dict, "noremap", INTEGER_OBJ(noremap_value));
PUT(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0));
@@ -2115,7 +2115,7 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
if (mp->m_replace_keycodes) {
PUT(dict, "replace_keycodes", INTEGER_OBJ(1));
}
- PUT(dict, "mode", STRING_OBJ(cstr_as_string(mapmode)));
+ PUT(dict, "mode", CSTR_AS_OBJ(mapmode));
return dict;
}
diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h
index f9df0028db..cfe19eac6f 100644
--- a/src/nvim/mark_defs.h
+++ b/src/nvim/mark_defs.h
@@ -1,7 +1,7 @@
#ifndef NVIM_MARK_DEFS_H
#define NVIM_MARK_DEFS_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/os/time.h"
#include "nvim/pos.h"
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 757906d42f..840b6b646e 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -359,7 +359,7 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
}
b->n_keys--;
- pmap_del(uint64_t)(b->id2node, id);
+ pmap_del(uint64_t)(b->id2node, id, NULL);
// 5.
bool itr_dirty = false;
@@ -549,8 +549,8 @@ void marktree_clear(MarkTree *b)
b->root = NULL;
}
if (b->id2node->table.keys) {
- pmap_destroy(uint64_t)(b->id2node);
- pmap_init(uint64_t, b->id2node);
+ map_destroy(uint64_t, b->id2node);
+ *b->id2node = (PMap(uint64_t)) MAP_INIT;
}
b->n_keys = 0;
b->n_nodes = 0;
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 29d2abcd46..cd56115b58 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -9,7 +9,6 @@
#include "nvim/assert.h"
#include "nvim/garray.h"
#include "nvim/map.h"
-#include "nvim/map_defs.h"
#include "nvim/pos.h"
#include "nvim/types.h"
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 7d61b918d2..66c26275f1 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -2024,6 +2024,24 @@ int mb_charlen(const char *str)
return count;
}
+int mb_charlen2bytelen(const char *str, int charlen)
+{
+ const char *p = str;
+ int count = 0;
+
+ if (p == NULL) {
+ return 0;
+ }
+
+ for (int i = 0; *p != NUL && i < charlen; i++) {
+ int b = utfc_ptr2len(p);
+ p += b;
+ count += b;
+ }
+
+ return count;
+}
+
/// Like mb_charlen() but for a string with specified length.
int mb_charlen_len(const char *str, int len)
{
diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h
index 780f33e05b..724a16014d 100644
--- a/src/nvim/mbyte.h
+++ b/src/nvim/mbyte.h
@@ -5,7 +5,7 @@
#include <stdint.h>
#include <string.h>
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
#include "nvim/mbyte_defs.h"
#include "nvim/os/os_defs.h"
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index b9a26e1ac6..1f550ffb01 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -664,6 +664,7 @@ char *arena_memdupz(Arena *arena, const char *buf, size_t size)
# include "nvim/getchar.h"
# include "nvim/grid.h"
# include "nvim/mark.h"
+# include "nvim/msgpack_rpc/channel.h"
# include "nvim/ops.h"
# include "nvim/option.h"
# include "nvim/os/os.h"
@@ -823,6 +824,7 @@ void free_all_mem(void)
ui_free_all_mem();
nlua_free_all_mem();
+ rpc_free_all_mem();
// should be last, in case earlier free functions deallocates arenas
arena_free_reuse_blks();
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 16fea2ccf1..898e3ddd27 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -559,7 +559,7 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent)
}
} else if (*name != NUL) {
if (!silent) {
- emsg(_(e_menuothermode));
+ emsg(_(e_menu_only_exists_in_another_mode));
}
return FAIL;
}
@@ -760,7 +760,7 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
emsg(_(e_notsubmenu));
return NULL;
} else if ((menu->modes & modes) == 0x0) {
- emsg(_(e_menuothermode));
+ emsg(_(e_menu_only_exists_in_another_mode));
return NULL;
} else if (*p == NUL) { // found a full match
return menu;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 63bcf3e069..1cb4a3cbf4 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -181,7 +181,7 @@ void msg_grid_validate(void)
msg_grid.dirty_col = xcalloc((size_t)Rows, sizeof(*msg_grid.dirty_col));
// Tricky: allow resize while pager or ex mode is active
- int pos = MAX(max_rows - msg_scrolled, 0);
+ int pos = (State & MODE_ASKMORE) ? 0 : MAX(max_rows - msg_scrolled, 0);
msg_grid.throttled = false; // don't throttle in 'cmdheight' area
msg_grid_set_pos(pos, msg_scrolled);
ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols,
@@ -1069,7 +1069,7 @@ void ex_messages(void *const eap_p)
for (; p != NULL; p = p->next) {
if (kv_size(p->multiattr) || (p->msg && p->msg[0])) {
Array entry = ARRAY_DICT_INIT;
- ADD(entry, STRING_OBJ(cstr_to_string(p->kind)));
+ ADD(entry, CSTR_TO_OBJ(p->kind));
Array content = ARRAY_DICT_INIT;
if (kv_size(p->multiattr)) {
for (uint32_t i = 0; i < kv_size(p->multiattr); i++) {
@@ -1082,7 +1082,7 @@ void ex_messages(void *const eap_p)
} else if (p->msg && p->msg[0]) {
Array content_entry = ARRAY_DICT_INIT;
ADD(content_entry, INTEGER_OBJ(p->attr));
- ADD(content_entry, STRING_OBJ(cstr_to_string(p->msg)));
+ ADD(content_entry, CSTR_TO_OBJ(p->msg));
ADD(content, ARRAY_OBJ(content_entry));
}
ADD(entry, ARRAY_OBJ(content));
diff --git a/src/nvim/move.c b/src/nvim/move.c
index e09a95af70..9e8abbcd96 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -164,19 +164,25 @@ static void redraw_for_cursorcolumn(win_T *wp)
}
}
-/// Calculates how much overlap the smoothscroll marker "<<<" overlaps with
-/// buffer text for curwin.
+/// Calculates how much the 'listchars' "precedes" or 'smoothscroll' "<<<"
+/// marker overlaps with buffer text for window "wp".
/// Parameter "extra2" should be the padding on the 2nd line, not the first
/// line.
/// Returns the number of columns of overlap with buffer text, excluding the
/// extra padding on the ledge.
-static int smoothscroll_marker_overlap(win_T *wp, int extra2)
+int sms_marker_overlap(win_T *wp, int extra2)
{
- // We don't draw the <<< marker when in showbreak mode, thus no need to
+ // There is no marker overlap when in showbreak mode, thus no need to
// account for it. See grid_put_linebuf().
if (*get_showbreak_value(wp) != NUL) {
return 0;
}
+
+ // Overlap when 'list' and 'listchars' "precedes" are set is 1.
+ if (wp->w_p_list && wp->w_p_lcs_chars.prec) {
+ return 1;
+ }
+
return extra2 > 3 ? 0 : 3 - extra2;
}
@@ -212,8 +218,6 @@ static void reset_skipcol(win_T *wp)
// Update curwin->w_topline to move the cursor onto the screen.
void update_topline(win_T *wp)
{
- linenr_T old_topline;
- int old_topfill;
bool check_botline = false;
long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so;
long save_so = *so_ptr;
@@ -243,8 +247,8 @@ void update_topline(win_T *wp)
*so_ptr = mouse_dragging - 1;
}
- old_topline = wp->w_topline;
- old_topfill = wp->w_topfill;
+ linenr_T old_topline = wp->w_topline;
+ int old_topfill = wp->w_topfill;
// If the buffer is empty, always set topline to 1.
if (buf_is_empty(curbuf)) { // special case - file is empty
@@ -271,12 +275,11 @@ void update_topline(win_T *wp)
} else if (wp->w_skipcol > 0 && wp->w_cursor.lnum == wp->w_topline) {
colnr_T vcol;
- // Check that the cursor position is visible. Add columns for the
- // smoothscroll marker "<<<" displayed in the top-left if needed.
+ // Check that the cursor position is visible. Add columns for
+ // the marker displayed in the top-left if needed.
getvvcol(wp, &wp->w_cursor, &vcol, NULL, NULL);
- int smoothscroll_overlap = smoothscroll_marker_overlap(wp,
- win_col_off(wp) - win_col_off2(wp));
- if (wp->w_skipcol + smoothscroll_overlap > vcol) {
+ int overlap = sms_marker_overlap(wp, win_col_off(wp) - win_col_off2(wp));
+ if (wp->w_skipcol + overlap > vcol) {
check_topline = true;
}
}
@@ -408,7 +411,13 @@ void update_topline(win_T *wp)
|| wp->w_topfill != old_topfill) {
dollar_vcol = -1;
redraw_later(wp, UPD_VALID);
- reset_skipcol(wp);
+
+ // When 'smoothscroll' is not set, should reset w_skipcol.
+ if (!wp->w_p_sms) {
+ reset_skipcol(wp);
+ } else if (wp->w_skipcol != 0) {
+ redraw_later(wp, UPD_SOME_VALID);
+ }
// May need to set w_skipcol when cursor in w_topline.
if (wp->w_cursor.lnum == wp->w_topline) {
@@ -652,7 +661,7 @@ static void curs_rows(win_T *wp)
i--; // hold at inserted lines
}
}
- if (valid && (lnum != wp->w_topline || !win_may_fill(wp))) {
+ if (valid && (lnum != wp->w_topline || (wp->w_skipcol == 0 && !win_may_fill(wp)))) {
lnum = wp->w_lines[i].wl_lastlnum + 1;
// Cursor inside folded lines, don't count this row
if (lnum > wp->w_cursor.lnum) {
@@ -1315,14 +1324,6 @@ bool scrolldown(long line_count, int byfold)
return moved;
}
-/// Return TRUE if scrollup() will scroll by screen line rather than text line.
-static int scrolling_screenlines(bool byfold)
-{
- return (curwin->w_p_wrap && curwin->w_p_sms)
- || (byfold && hasAnyFolding(curwin))
- || (curwin->w_p_diff && !curwin->w_p_wrap);
-}
-
/// Scroll the current window up by "line_count" logical lines. "CTRL-E"
///
/// @param line_count number of lines to scroll
@@ -1333,7 +1334,7 @@ bool scrollup(long line_count, int byfold)
linenr_T botline = curwin->w_botline;
int do_sms = curwin->w_p_wrap && curwin->w_p_sms;
- if (scrolling_screenlines(byfold) || win_may_fill(curwin)) {
+ if (do_sms || (byfold && hasAnyFolding(curwin)) || win_may_fill(curwin)) {
int width1 = curwin->w_width_inner - curwin_col_off();
int width2 = width1 + curwin_col_off2();
unsigned size = 0;
@@ -1431,10 +1432,9 @@ bool scrollup(long line_count, int byfold)
long scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
int space_cols = (curwin->w_height_inner - 1) * width2;
- // If we have non-zero scrolloff, just ignore the <<< marker as we are
+ // If we have non-zero scrolloff, just ignore the marker as we are
// going past it anyway.
- int smoothscroll_overlap = scrolloff_cols != 0 ? 0 :
- smoothscroll_marker_overlap(curwin, extra2);
+ int overlap = scrolloff_cols != 0 ? 0 : sms_marker_overlap(curwin, extra2);
// Make sure the cursor is in a visible part of the line, taking
// 'scrolloff' into account, but using screen lines.
@@ -1443,13 +1443,13 @@ bool scrollup(long line_count, int byfold)
scrolloff_cols = space_cols / 2;
}
validate_virtcol();
- if (curwin->w_virtcol < curwin->w_skipcol + smoothscroll_overlap + scrolloff_cols) {
+ if (curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
colnr_T col = curwin->w_virtcol;
if (col < width1) {
col += width1;
}
- while (col < curwin->w_skipcol + smoothscroll_overlap + scrolloff_cols) {
+ while (col < curwin->w_skipcol + overlap + scrolloff_cols) {
col += width2;
}
curwin->w_curswant = col;
@@ -1494,19 +1494,20 @@ void adjust_skipcol(void)
}
validate_virtcol();
+ int overlap = sms_marker_overlap(curwin, curwin_col_off() - curwin_col_off2());
while (curwin->w_skipcol > 0
- && curwin->w_virtcol < curwin->w_skipcol + 3 + scrolloff_cols) {
+ && curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) {
// scroll a screen line down
if (curwin->w_skipcol >= width1 + width2) {
curwin->w_skipcol -= width2;
} else {
curwin->w_skipcol -= width1;
}
- redraw_later(curwin, UPD_NOT_VALID);
scrolled = true;
- validate_virtcol();
}
if (scrolled) {
+ validate_virtcol();
+ redraw_later(curwin, UPD_NOT_VALID);
return; // don't scroll in the other direction now
}
long col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols;
@@ -1870,6 +1871,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
int old_valid = curwin->w_valid;
int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
+ int do_sms = curwin->w_p_wrap && curwin->w_p_sms;
if (set_topbot) {
bool set_skipcol = false;
@@ -1886,7 +1888,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
break;
}
if (used + loff.height > curwin->w_height_inner) {
- if (curwin->w_p_sms && curwin->w_p_wrap) {
+ if (do_sms) {
// 'smoothscroll' and 'wrap' are set. The above line is
// too long to show in its entirety, so we show just a part
// of it.
@@ -1925,7 +1927,6 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
used = plines_win_nofill(curwin, cln, true);
int scrolled = 0;
- int min_scrolled = 1;
// If the cursor is on or below botline, we will at least scroll by the
// height of the cursor line, which is "used". Correct for empty lines,
// which are really part of botline.
@@ -1934,16 +1935,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
if (cln == curwin->w_botline) {
scrolled -= curwin->w_empty_rows;
}
- min_scrolled = scrolled;
- if (curwin->w_p_sms && curwin->w_p_wrap) {
- // 'smoothscroll' and 'wrap' are set
- if (cln > curwin->w_botline) {
- // add screen lines below w_botline
- for (linenr_T lnum = curwin->w_botline + 1; lnum <= cln; lnum++) {
- min_scrolled += plines_win_nofill(curwin, lnum, true);
- }
- }
-
+ if (do_sms) {
+ // 'smoothscroll' and 'wrap' are set.
// Calculate how many screen lines the current top line of window
// occupies. If it is occupying more than the entire window, we
// need to scroll the additional clipped lines to scroll past the
@@ -1962,7 +1955,6 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
top_plines -= skip_lines;
if (top_plines > curwin->w_height_inner) {
scrolled += (top_plines - curwin->w_height_inner);
- min_scrolled += (top_plines - curwin->w_height_inner);
}
}
}
@@ -2067,21 +2059,11 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
// Otherwise put it at 1/2 of the screen.
if (line_count >= curwin->w_height_inner && line_count > min_scroll) {
scroll_cursor_halfway(false, true);
- } else {
- // With 'smoothscroll' scroll at least the height of the cursor line,
- // unless it would move the cursor.
- if (curwin->w_p_wrap && curwin->w_p_sms && line_count < min_scrolled
- && (curwin->w_cursor.lnum < curwin->w_topline
- || (curwin->w_virtcol - curwin->w_skipcol >=
- curwin->w_width_inner - curwin_col_off()))) {
- line_count = min_scrolled;
- }
- if (line_count > 0) {
- if (scrolling_screenlines(true)) {
- scrollup(scrolled, true); // TODO(vim):
- } else {
- scrollup(line_count, true);
- }
+ } else if (line_count > 0) {
+ if (do_sms) {
+ scrollup(scrolled, true); // TODO(vim):
+ } else {
+ scrollup(line_count, true);
}
}
@@ -2112,38 +2094,38 @@ void scroll_cursor_halfway(bool atend, bool prefer_above)
boff.fill = 0;
linenr_T topline = loff.lnum;
colnr_T skipcol = 0;
- bool set_skipcol = false;
- int half_height = 0;
- bool smooth_scroll = false;
- if (curwin->w_p_sms && curwin->w_p_wrap) {
+ int want_height;
+ bool do_sms = curwin->w_p_wrap && curwin->w_p_sms;
+ if (do_sms) {
// 'smoothscroll' and 'wrap' are set
- smooth_scroll = true;
- half_height = (curwin->w_height_inner - used) / 2;
- used = 0;
+ if (atend) {
+ want_height = (curwin->w_height_inner - used) / 2;
+ used = 0;
+ } else {
+ want_height = curwin->w_height_inner;
+ }
}
int topfill = 0;
while (topline > 1) {
// If using smoothscroll, we can precisely scroll to the
// exact point where the cursor is halfway down the screen.
- if (smooth_scroll) {
+ if (do_sms) {
topline_back_winheight(curwin, &loff, false);
if (loff.height == MAXCOL) {
break;
- } else {
- used += loff.height;
}
- if (used > half_height) {
- if (used - loff.height < half_height) {
- int plines_offset = used - half_height;
- loff.height -= plines_offset;
- used = half_height;
-
+ used += loff.height;
+ if (!atend && boff.lnum < curbuf->b_ml.ml_line_count) {
+ botline_forw(curwin, &boff);
+ used += boff.height;
+ }
+ if (used > want_height) {
+ if (used - loff.height < want_height) {
topline = loff.lnum;
topfill = loff.fill;
- skipcol = skipcol_from_plines(curwin, plines_offset);
- set_skipcol = true;
+ skipcol = skipcol_from_plines(curwin, used - want_height);
}
break;
}
@@ -2208,12 +2190,12 @@ void scroll_cursor_halfway(bool atend, bool prefer_above)
}
if (!hasFolding(topline, &curwin->w_topline, NULL)
- && (curwin->w_topline != topline || set_skipcol || curwin->w_skipcol != 0)) {
+ && (curwin->w_topline != topline || skipcol != 0 || curwin->w_skipcol != 0)) {
curwin->w_topline = topline;
- if (set_skipcol) {
+ if (skipcol != 0) {
curwin->w_skipcol = skipcol;
redraw_later(curwin, UPD_NOT_VALID);
- } else {
+ } else if (do_sms) {
reset_skipcol(curwin);
}
}
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 96b4bf5c3a..1772b0497b 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -110,7 +110,7 @@ static void log_client_msg(uint64_t channel_id, bool is_request, const char *nam
# define log_server_msg(...)
#endif
-static PMap(cstr_t) event_strings = MAP_INIT;
+static Set(cstr_t) event_strings = SET_INIT;
static msgpack_sbuffer out_buffer;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -254,14 +254,12 @@ void rpc_subscribe(uint64_t id, char *event)
abort();
}
- char *event_string = pmap_get(cstr_t)(&event_strings, event);
-
- if (!event_string) {
- event_string = xstrdup(event);
- pmap_put(cstr_t)(&event_strings, event_string, event_string);
+ const char **key_alloc = NULL;
+ if (set_put_ref(cstr_t, &event_strings, event, &key_alloc)) {
+ *key_alloc = xstrdup(event);
}
- pmap_put(cstr_t)(channel->rpc.subscribed_events, event_string, event_string);
+ set_put(cstr_t, channel->rpc.subscribed_events, *key_alloc);
}
/// Unsubscribes to event broadcasts
@@ -553,9 +551,9 @@ static void broadcast_event(const char *name, Array args)
kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
Channel *channel;
- map_foreach_value(&channels, channel, {
+ pmap_foreach_value(&channels, channel, {
if (channel->is_rpc
- && pmap_has(cstr_t)(channel->rpc.subscribed_events, name)) {
+ && set_has(cstr_t, channel->rpc.subscribed_events, name)) {
kv_push(subscribed, channel);
}
});
@@ -583,24 +581,12 @@ end:
static void unsubscribe(Channel *channel, char *event)
{
- char *event_string = pmap_get(cstr_t)(&event_strings, event);
- if (!event_string) {
+ if (!set_has(cstr_t, &event_strings, event)) {
WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'",
channel->id, event);
return;
}
- pmap_del(cstr_t)(channel->rpc.subscribed_events, event_string);
-
- map_foreach_value(&channels, channel, {
- if (channel->is_rpc
- && pmap_has(cstr_t)(channel->rpc.subscribed_events, event_string)) {
- return;
- }
- });
-
- // Since the string is no longer used by other channels, release it's memory
- pmap_del(cstr_t)(&event_strings, event_string);
- xfree(event_string);
+ set_del(cstr_t, channel->rpc.subscribed_events, event);
}
/// Mark rpc state as closed, and release its reference to the channel.
@@ -630,13 +616,7 @@ void rpc_free(Channel *channel)
unpacker_teardown(channel->rpc.unpacker);
xfree(channel->rpc.unpacker);
- // Unsubscribe from all events
- char *event_string;
- map_foreach_value(channel->rpc.subscribed_events, event_string, {
- unsubscribe(channel, event_string);
- });
-
- pmap_destroy(cstr_t)(channel->rpc.subscribed_events);
+ set_destroy(cstr_t, channel->rpc.subscribed_events);
kv_destroy(channel->rpc.call_stack);
api_free_dictionary(channel->rpc.info);
}
@@ -648,7 +628,7 @@ static void chan_close_with_error(Channel *channel, char *msg, int loglevel)
ChannelCallFrame *frame = kv_A(channel->rpc.call_stack, i);
frame->returned = true;
frame->errored = true;
- frame->result = STRING_OBJ(cstr_to_string(msg));
+ frame->result = CSTR_TO_OBJ(msg);
}
channel_close(channel->id, kChannelPartRpc, NULL);
@@ -685,7 +665,7 @@ static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler
} else {
Array args = ARRAY_DICT_INIT;
ADD(args, INTEGER_OBJ(err->type));
- ADD(args, STRING_OBJ(cstr_to_string(err->msg)));
+ ADD(args, CSTR_TO_OBJ(err->msg));
msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
args, &pac);
api_free_array(args);
@@ -734,3 +714,12 @@ const char *rpc_client_name(Channel *chan)
return NULL;
}
+
+void rpc_free_all_mem(void)
+{
+ cstr_t key;
+ set_foreach(&event_strings, key, {
+ xfree((void *)key);
+ });
+ set_destroy(cstr_t, &event_strings);
+}
diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h
index 404e68329a..1b5f0bb298 100644
--- a/src/nvim/msgpack_rpc/channel_defs.h
+++ b/src/nvim/msgpack_rpc/channel_defs.h
@@ -31,7 +31,7 @@ typedef struct {
} RequestEvent;
typedef struct {
- PMap(cstr_t) subscribed_events[1];
+ Set(cstr_t) subscribed_events[1];
bool closed;
Unpacker *unpacker;
uint32_t next_request_id;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 890fa0f80a..60fff45323 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -107,6 +107,8 @@ static int VIsual_mode_orig = NUL; // saved Visual mode
#endif
static const char e_changelist_is_empty[] = N_("E664: Changelist is empty");
+static const char e_cmdline_window_already_open[]
+ = N_("E1292: Command-line window is already open");
static inline void normal_state_init(NormalState *s)
{
@@ -2029,7 +2031,7 @@ static void display_showcmd(void)
if (len > 0) {
// placeholder for future highlight support
ADD_C(chunk, INTEGER_OBJ(0));
- ADD_C(chunk, STRING_OBJ(cstr_as_string(showcmd_buf)));
+ ADD_C(chunk, CSTR_AS_OBJ(showcmd_buf));
ADD_C(content, ARRAY_OBJ(chunk));
}
ui_call_msg_showcmd(content);
@@ -3232,7 +3234,7 @@ static void nv_colon(cmdarg_T *cap)
}
if (is_lua) {
- cmd_result = map_execute_lua();
+ cmd_result = map_execute_lua(true);
} else {
// get a command line and execute it
cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
@@ -5272,6 +5274,7 @@ static void nv_g_home_m_cmd(cmdarg_T *cap)
curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = true;
+ adjust_skipcol();
}
/// "g_": to the last non-blank character in the line or <count> lines downward.
@@ -6371,6 +6374,10 @@ static void nv_record(cmdarg_T *cap)
}
if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') {
+ if (cmdwin_type != 0) {
+ emsg(_(e_cmdline_window_already_open));
+ return;
+ }
stuffcharReadbuff(cap->nchar);
stuffcharReadbuff(K_CMDWIN);
} else {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index bb66bb5731..de77cdd238 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -5777,6 +5777,11 @@ typedef struct {
int rv_arg; ///< extra argument
} redo_VIsual_T;
+static bool is_ex_cmdchar(cmdarg_T *cap)
+{
+ return cap->cmdchar == ':' || cap->cmdchar == K_COMMAND;
+}
+
/// Handle an operator after Visual mode or when the movement is finished.
/// "gui_yank" is true when yanking text for the clipboard.
void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
@@ -5831,7 +5836,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
if ((redo_yank || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
// Also redo Operator-pending Visual mode mappings.
- || ((cap->cmdchar == ':' || cap->cmdchar == K_COMMAND)
+ || ((is_ex_cmdchar(cap) || cap->cmdchar == K_LUA)
&& oap->op_type != OP_COLON))
&& cap->cmdchar != 'D'
&& oap->op_type != OP_FOLD
@@ -5851,17 +5856,24 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
AppendToRedobuffLit(cap->searchbuf, -1);
}
AppendToRedobuff(NL_STR);
- } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) {
+ } else if (is_ex_cmdchar(cap)) {
// do_cmdline() has stored the first typed line in
// "repeat_cmdline". When several lines are typed repeating
// won't be possible.
if (repeat_cmdline == NULL) {
ResetRedobuff();
} else {
- AppendToRedobuffLit(repeat_cmdline, -1);
+ if (cap->cmdchar == ':') {
+ AppendToRedobuffLit(repeat_cmdline, -1);
+ } else {
+ AppendToRedobuffSpec(repeat_cmdline);
+ }
AppendToRedobuff(NL_STR);
XFREE_CLEAR(repeat_cmdline);
}
+ } else if (cap->cmdchar == K_LUA) {
+ AppendNumberToRedobuff(repeat_luaref);
+ AppendToRedobuff(NL_STR);
}
}
@@ -6017,7 +6029,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
prep_redo(oap->regname, cap->count0,
get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
oap->motion_force, cap->cmdchar, cap->nchar);
- } else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND) {
+ } else if (!is_ex_cmdchar(cap) && cap->cmdchar != K_LUA) {
int opchar = get_op_char(oap->op_type);
int extra_opchar = get_extra_op_char(oap->op_type);
int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 75ea1853a0..81e006be27 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -4,8 +4,8 @@
#include <stdbool.h>
#include <stddef.h>
+#include "lauxlib.h"
#include "nvim/ascii.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/extmark.h"
@@ -126,4 +126,7 @@ static inline int op_reg_index(const int regname)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ops.h.generated.h"
#endif
+
+EXTERN LuaRef repeat_luaref INIT(= LUA_NOREF); ///< LuaRef for "."
+
#endif // NVIM_OPS_H
diff --git a/src/nvim/option.c b/src/nvim/option.c
index fc1fc87b62..722afa64d8 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1252,7 +1252,7 @@ static void do_set_option_string(int opt_idx, int opt_flags, char **argp, int ne
}
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- STRING_OBJ(cstr_as_string(saved_newval)));
+ CSTR_AS_OBJ(saved_newval));
}
}
xfree(saved_origval);
@@ -1626,7 +1626,7 @@ int do_set(char *arg, int opt_flags)
int i = (int)strlen(IObuff) + 2;
if (i + (arg - startarg) < IOSIZE) {
// append the argument with the error
- STRCAT(IObuff, ": ");
+ xstrlcat(IObuff, ": ", IOSIZE);
assert(arg >= startarg);
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
IObuff[i + (arg - startarg)] = NUL;
@@ -3803,7 +3803,7 @@ void ui_refresh_options(void)
value = INTEGER_OBJ(*(long *)varp);
} else if (flags & P_STRING) {
// cstr_as_string handles NULL string
- value = STRING_OBJ(cstr_as_string(*(char **)varp));
+ value = CSTR_AS_OBJ(*(char **)varp);
}
ui_call_option_set(name, value);
}
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index dc652054e8..ed9acde2b1 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -1,7 +1,7 @@
#ifndef NVIM_OPTION_DEFS_H
#define NVIM_OPTION_DEFS_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/macros.h"
#include "nvim/types.h"
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 1c75d5bd03..d3f676379d 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -2301,17 +2301,17 @@ static int get_encoded_char_adv(const char **p)
/// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters
///
-/// @param value points to either the global or the window-local value.
-/// @param opt_lcs is tue for "listchars" and FALSE for "fillchars".
+/// @param value points to either the global or the window-local value.
+/// @param is_listchars is true for "listchars" and false for "fillchars".
/// @param apply if false, do not store the flags, only check for errors.
/// @return error message, NULL if it's OK.
-static const char *set_chars_option(win_T *wp, const char *value, bool opt_lcs, bool apply)
+static const char *set_chars_option(win_T *wp, const char *value, const bool is_listchars,
+ const bool apply)
{
const char *last_multispace = NULL; // Last occurrence of "multispace:"
const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
int multispace_len = 0; // Length of lcs-multispace string
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
- const bool is_listchars = opt_lcs;
struct chars_tab {
int *cp; ///< char value
@@ -2358,13 +2358,13 @@ static const char *set_chars_option(win_T *wp, const char *value, bool opt_lcs,
if (is_listchars) {
tab = lcs_tab;
entries = ARRAY_SIZE(lcs_tab);
- if (opt_lcs && wp->w_p_lcs[0] == NUL) {
+ if (wp->w_p_lcs[0] == NUL) {
value = p_lcs; // local value is empty, use the global value
}
} else {
tab = fcs_tab;
entries = ARRAY_SIZE(fcs_tab);
- if (!opt_lcs && wp->w_p_fcs[0] == NUL) {
+ if (wp->w_p_fcs[0] == NUL) {
value = p_fcs; // local value is empty, use the global value
}
}
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
index 2a248a1e32..98ae251e2b 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/process.c
@@ -254,7 +254,7 @@ Dictionary os_proc_info(int pid)
if (pe.th32ProcessID == (DWORD)pid) {
PUT(pinfo, "pid", INTEGER_OBJ(pid));
PUT(pinfo, "ppid", INTEGER_OBJ((int)pe.th32ParentProcessID));
- PUT(pinfo, "name", STRING_OBJ(cstr_to_string(pe.szExeFile)));
+ PUT(pinfo, "name", CSTR_TO_OBJ(pe.szExeFile));
}
return pinfo;
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 2e850f8c22..a8330acd54 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include "nvim/ascii.h"
+#include "nvim/eval/typval.h"
#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
#include "nvim/memory.h"
#include "nvim/os/os.h"
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 5235828f7a..8b62b9e895 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -130,7 +130,7 @@ char *get_xdg_home(const XDGVarType idx)
xstrlcpy(IObuff, appname, appname_len + 1);
#if defined(MSWIN)
if (idx == kXDGDataHome || idx == kXDGStateHome) {
- STRCAT(IObuff, "-data");
+ xstrlcat(IObuff, "-data", IOSIZE);
}
#endif
dir = concat_fnames_realloc(dir, IObuff, true);
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 8d77e58177..0c3b254b9a 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -74,7 +74,7 @@ void os_delay(uint64_t ms, bool ignoreinput)
///
/// This blocks even "fast" events which is quite disruptive. This should only
/// be used in debug code. Prefer os_delay() and decide if the delay should be
-/// interupted by input or only a CTRL-C.
+/// interrupted by input or only a CTRL-C.
///
/// @see uv_sleep() (libuv v1.34.0)
///
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 3e69e547cb..25c745ae97 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -102,12 +102,16 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
char *s;
unsigned col;
int width;
+ chartabsize_T cts;
s = ml_get_buf(wp->w_buffer, lnum, false);
- if (*s == NUL) { // empty line
- return 1;
+ init_chartabsize_arg(&cts, wp, lnum, 0, s, s);
+ if (*s == NUL && !cts.cts_has_virt_text) {
+ return 1; // be quick for an empty line
}
- col = win_linetabsize(wp, lnum, s, MAXCOL);
+ win_linetabsize_cts(&cts, (colnr_T)MAXCOL);
+ clear_chartabsize_arg(&cts);
+ col = (unsigned)cts.cts_vcol;
// If list mode is on, then the '$' at the end of the line may take up one
// extra column.
@@ -262,6 +266,11 @@ int linetabsize_col(int startcol, char *s)
while (*cts.cts_ptr != NUL) {
cts.cts_vcol += lbr_chartabsize_adv(&cts);
}
+ if (cts.cts_has_virt_text && cts.cts_ptr == cts.cts_line) {
+ // check for virtual text in an empty line
+ (void)lbr_chartabsize_adv(&cts);
+ cts.cts_vcol += cts.cts_cur_text_width_left + cts.cts_cur_text_width_right;
+ }
clear_chartabsize_arg(&cts);
return cts.cts_vcol;
}
@@ -277,10 +286,7 @@ unsigned win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len)
{
chartabsize_T cts;
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
- for (; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < line + len);
- MB_PTR_ADV(cts.cts_ptr)) {
- cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
- }
+ win_linetabsize_cts(&cts, len);
clear_chartabsize_arg(&cts);
return (unsigned)cts.cts_vcol;
}
@@ -292,20 +298,43 @@ unsigned linetabsize(win_T *wp, linenr_T lnum)
return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum, false), (colnr_T)MAXCOL);
}
+void win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
+{
+ for (; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < cts->cts_line + len);
+ MB_PTR_ADV(cts->cts_ptr)) {
+ cts->cts_vcol += win_lbr_chartabsize(cts, NULL);
+ }
+ // check for a virtual text on an empty line
+ if (cts->cts_has_virt_text && *cts->cts_ptr == NUL
+ && cts->cts_ptr == cts->cts_line) {
+ (void)win_lbr_chartabsize(cts, NULL);
+ cts->cts_vcol += cts->cts_cur_text_width_left + cts->cts_cur_text_width_right;
+ }
+}
+
/// Prepare the structure passed to chartabsize functions.
///
/// "line" is the start of the line, "ptr" is the first relevant character.
-/// When "lnum" is zero do not use text properties that insert text.
-void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum FUNC_ATTR_UNUSED,
- colnr_T col, char *line, char *ptr)
+/// When "lnum" is zero do not use inline virtual text.
+void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T col, char *line,
+ char *ptr)
{
cts->cts_win = wp;
cts->cts_vcol = col;
cts->cts_line = line;
cts->cts_ptr = ptr;
- cts->cts_cur_text_width = 0;
- // TODO(bfredl): actually lookup inline virtual text here
+ cts->cts_cur_text_width_left = 0;
+ cts->cts_cur_text_width_right = 0;
cts->cts_has_virt_text = false;
+ cts->cts_row = lnum - 1;
+
+ if (cts->cts_row >= 0) {
+ marktree_itr_get(wp->w_buffer->b_marktree, cts->cts_row, 0, cts->cts_iter);
+ mtkey_t mark = marktree_itr_current(cts->cts_iter);
+ if (mark.pos.row == cts->cts_row) {
+ cts->cts_has_virt_text = true;
+ }
+ }
}
/// Free any allocated item in "cts".
@@ -369,7 +398,8 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
int mb_added = 0;
int numberextra;
- cts->cts_cur_text_width = 0;
+ cts->cts_cur_text_width_left = 0;
+ cts->cts_cur_text_width_right = 0;
// No 'linebreak', 'showbreak' and 'breakindent': return quickly.
if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL
@@ -383,7 +413,34 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// First get normal size, without 'linebreak' or virtual text
int size = win_chartabsize(wp, s, vcol);
if (cts->cts_has_virt_text) {
- // TODO(bfredl): inline virtual text
+ int tab_size = size;
+ int charlen = *s == NUL ? 1 : utf_ptr2len(s);
+ int col = (int)(s - line);
+ while (true) {
+ mtkey_t mark = marktree_itr_current(cts->cts_iter);
+ if (mark.pos.row != cts->cts_row || mark.pos.col > col) {
+ break;
+ } else if (mark.pos.col >= col && mark.pos.col < col + charlen) {
+ if (!mt_end(mark)) {
+ Decoration decor = get_decor(mark);
+ if (decor.virt_text_pos == kVTInline) {
+ if (mt_right(mark)) {
+ cts->cts_cur_text_width_right += decor.virt_text_width;
+ } else {
+ cts->cts_cur_text_width_left += decor.virt_text_width;
+ }
+ size += decor.virt_text_width;
+ if (*s == TAB) {
+ // tab size changes because of the inserted text
+ size -= tab_size;
+ tab_size = win_chartabsize(wp, s, vcol + size);
+ size += tab_size;
+ }
+ }
+ }
+ }
+ marktree_itr_next(wp->w_buffer->b_marktree, cts->cts_iter);
+ }
}
int c = (uint8_t)(*s);
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
index 808f6d284e..2ce7133705 100644
--- a/src/nvim/plines.h
+++ b/src/nvim/plines.h
@@ -11,10 +11,12 @@ typedef struct {
win_T *cts_win;
char *cts_line; // start of the line
char *cts_ptr; // current position in line
+ int cts_row;
bool cts_has_virt_text; // true if if a property inserts text
- int cts_cur_text_width; // width of current inserted text
- // TODO(bfredl): iterator in to the marktree for scanning virt text
+ int cts_cur_text_width_left; // width of virtual text left of cursor
+ int cts_cur_text_width_right; // width of virtual text right of cursor
+ MarkTreeIter cts_iter[1];
int cts_vcol; // virtual column at current position
} chartabsize_T;
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index d404aa9647..15d0372c6f 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -164,10 +164,10 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
Array arr = arena_array(&arena, (size_t)size);
for (int i = 0; i < size; i++) {
Array item = arena_array(&arena, 4);
- ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_text)));
- ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_kind)));
- ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_extra)));
- ADD_C(item, STRING_OBJ(cstr_as_string(array[i].pum_info)));
+ ADD_C(item, CSTR_AS_OBJ(array[i].pum_text));
+ ADD_C(item, CSTR_AS_OBJ(array[i].pum_kind));
+ ADD_C(item, CSTR_AS_OBJ(array[i].pum_extra));
+ ADD_C(item, CSTR_AS_OBJ(array[i].pum_info));
ADD_C(arr, ARRAY_OBJ(item));
}
ui_call_popupmenu_show(arr, selected, pum_win_row, cursor_col,
@@ -1083,7 +1083,7 @@ void pum_show_popupmenu(vimmenu_T *menu)
// When there are only Terminal mode menus, using "popup Edit" results in
// pum_size being zero.
if (pum_size <= 0) {
- emsg(e_menuothermode);
+ emsg(_(e_menu_only_exists_in_another_mode));
return;
}
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index b4a23d544e..4b27067fb8 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -512,7 +512,7 @@ Array runtime_inspect(void)
for (size_t i = 0; i < kv_size(path); i++) {
SearchPathItem *item = &kv_A(path, i);
Array entry = ARRAY_DICT_INIT;
- ADD(entry, STRING_OBJ(cstr_to_string(item->path)));
+ ADD(entry, CSTR_TO_OBJ(item->path));
ADD(entry, BOOLEAN_OBJ(item->after));
if (item->has_lua != kNone) {
ADD(entry, BOOLEAN_OBJ(item->has_lua == kTrue));
@@ -568,7 +568,7 @@ ArrayOf(String) runtime_get_named_common(bool lua, Array pat, bool all,
item->path, pat_item.data.string.data);
if (size < buf_len) {
if (os_file_is_readable(buf)) {
- ADD(rv, STRING_OBJ(cstr_to_string(buf)));
+ ADD(rv, CSTR_TO_OBJ(buf));
if (!all) {
goto done;
}
@@ -646,21 +646,20 @@ int do_in_path_and_pp(char *path, char *name, int flags, DoInRuntimepathCB callb
return done;
}
-static void push_path(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used, char *entry,
+static void push_path(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry,
bool after)
{
- handle_T h = map_get(String, handle_T)(rtp_used, cstr_as_string(entry));
- if (h == 0) {
- char *allocated = xstrdup(entry);
- map_put(String, handle_T)(rtp_used, cstr_as_string(allocated), 1);
- kv_push(*search_path, ((SearchPathItem){ allocated, after, kNone }));
+ String *key_alloc;
+ if (set_put_ref(String, rtp_used, cstr_as_string(entry), &key_alloc)) {
+ *key_alloc = cstr_to_string(entry);
+ kv_push(*search_path, ((SearchPathItem){ key_alloc->data, after, kNone }));
}
}
-static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used,
- char *entry, bool after)
+static void expand_rtp_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry,
+ bool after)
{
- if (map_get(String, handle_T)(rtp_used, cstr_as_string(entry))) {
+ if (set_has(String, rtp_used, cstr_as_string(entry))) {
return;
}
@@ -679,7 +678,7 @@ static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_
}
}
-static void expand_pack_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used,
+static void expand_pack_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used,
CharVec *after_path, char *pack_entry, size_t pack_entry_len)
{
static char buf[MAXPATHL];
@@ -712,10 +711,8 @@ static bool path_is_after(char *buf, size_t buflen)
RuntimeSearchPath runtime_search_path_build(void)
{
kvec_t(String) pack_entries = KV_INITIAL_VALUE;
- // TODO(bfredl): these should just be sets, when Set(String) is do merge to
- // master.
Map(String, handle_T) pack_used = MAP_INIT;
- Map(String, handle_T) rtp_used = MAP_INIT;
+ Set(String) rtp_used = SET_INIT;
RuntimeSearchPath search_path = KV_INITIAL_VALUE;
CharVec after_path = KV_INITIAL_VALUE;
@@ -744,7 +741,7 @@ RuntimeSearchPath runtime_search_path_build(void)
// fact: &rtp entries can contain wild chars
expand_rtp_entry(&search_path, &rtp_used, buf, false);
- handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string(buf), false);
+ handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string(buf), NULL);
if (h) {
(*h)++;
expand_pack_entry(&search_path, &rtp_used, &after_path, buf, buflen);
@@ -774,8 +771,8 @@ RuntimeSearchPath runtime_search_path_build(void)
// strings are not owned
kv_destroy(pack_entries);
kv_destroy(after_path);
- map_destroy(String, handle_T)(&pack_used);
- map_destroy(String, handle_T)(&rtp_used);
+ map_destroy(String, &pack_used);
+ set_destroy(String, &rtp_used);
return search_path;
}
@@ -1547,7 +1544,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
xstrlcpy(IObuff, appname, appname_len + 1);
#if defined(MSWIN)
if (type == kXDGDataHome || type == kXDGStateHome) {
- STRCAT(IObuff, "-data");
+ xstrlcat(IObuff, "-data", IOSIZE);
appname_len += 5;
}
#endif
@@ -2409,7 +2406,7 @@ void f_getscriptinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return;
}
if (sid <= 0) {
- semsg(e_invargNval, "sid", tv_get_string(&sid_di->di_tv));
+ semsg(_(e_invargNval), "sid", tv_get_string(&sid_di->di_tv));
return;
}
} else {
diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h
index 9a810298f8..188ff7b36c 100644
--- a/src/nvim/runtime.h
+++ b/src/nvim/runtime.h
@@ -5,7 +5,6 @@
#include "klib/kvec.h"
#include "nvim/autocmd.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_eval_defs.h"
diff --git a/src/nvim/search.c b/src/nvim/search.c
index d1a31a357f..bcaacede9e 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1519,7 +1519,7 @@ int searchc(cmdarg_T *cap, int t_cmd)
}
}
} else { // repeat previous search
- if (*lastc == NUL && lastc_bytelen == 1) {
+ if (*lastc == NUL && lastc_bytelen <= 1) {
return FAIL;
}
if (dir) { // repeat in opposite direction
@@ -1562,7 +1562,7 @@ int searchc(cmdarg_T *cap, int t_cmd)
}
col -= utf_head_off(p, p + col - 1) + 1;
}
- if (lastc_bytelen == 1) {
+ if (lastc_bytelen <= 1) {
if (p[col] == c && stop) {
break;
}
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 2f140ba840..eeff9f8744 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -5,7 +5,6 @@
#include <stdint.h>
#include "nvim/buffer_defs.h"
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/normal.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index c405b8ca5f..db911f4bfd 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -16,7 +16,6 @@
#include <uv.h>
#include "auto/config.h"
-#include "klib/khash.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
@@ -35,6 +34,7 @@
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/macros.h"
+#include "nvim/map.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
@@ -62,19 +62,6 @@
# include ENDIAN_INCLUDE_FILE
#endif
-// Note: when using bufset hash pointers are intentionally casted to uintptr_t
-// and not to khint32_t or khint64_t: this way compiler must give a warning
-// (-Wconversion) when types change.
-#ifdef ARCH_32
-KHASH_SET_INIT_INT(bufset)
-#elif defined(ARCH_64)
-KHASH_SET_INIT_INT64(bufset)
-#else
-# error Not a 64- or 32-bit architecture
-#endif
-KHASH_MAP_INIT_STR(fnamebufs, buf_T *)
-KHASH_SET_INIT_STR(strset)
-
#define SEARCH_KEY_MAGIC "sm"
#define SEARCH_KEY_SMARTCASE "sc"
#define SEARCH_KEY_HAS_LINE_OFFSET "sl"
@@ -305,8 +292,6 @@ typedef struct hm_llist_entry {
struct hm_llist_entry *prev; ///< Pointer to previous entry or NULL.
} HMLListEntry;
-KHASH_MAP_INIT_STR(hmll_entries, HMLListEntry *)
-
/// Sized linked list structure for history merger
typedef struct {
HMLListEntry *entries; ///< Pointer to the start of the allocated array of
@@ -318,9 +303,8 @@ typedef struct {
HMLListEntry *last_free_entry; ///< Last unused element in entries array.
size_t size; ///< Number of allocated entries.
size_t num_entries; ///< Number of entries already used.
- khash_t(hmll_entries) contained_entries; ///< Hash mapping all history entry
- ///< strings to corresponding entry
- ///< pointers.
+ PMap(cstr_t) contained_entries; ///< Map all history entry strings to
+ ///< corresponding entry pointers.
} HMLList;
typedef struct {
@@ -348,8 +332,6 @@ typedef struct {
Timestamp greatest_timestamp; ///< Greatest timestamp among marks.
} FileMarks;
-KHASH_MAP_INIT_STR(file_marks, FileMarks)
-
/// State structure used by shada_write
///
/// Before actually writing most of the data is read to this structure.
@@ -363,8 +345,8 @@ typedef struct {
PossiblyFreedShadaEntry search_pattern; ///< Last search pattern.
PossiblyFreedShadaEntry sub_search_pattern; ///< Last s/ search pattern.
PossiblyFreedShadaEntry replacement; ///< Last s// replacement string.
- khash_t(strset) dumped_variables; ///< Names of already dumped variables.
- khash_t(file_marks) file_marks; ///< All file marks.
+ Set(cstr_t) dumped_variables; ///< Names of already dumped variables.
+ PMap(cstr_t) file_marks; ///< All file marks.
} WriteMergerState;
struct sd_read_def;
@@ -504,7 +486,7 @@ static inline void hmll_init(HMLList *const hmll, const size_t size)
.free_entry = NULL,
.size = size,
.num_entries = 0,
- .contained_entries = KHASH_EMPTY_TABLE(hmll_entries),
+ .contained_entries = MAP_INIT,
};
hmll->last_free_entry = hmll->entries;
}
@@ -535,10 +517,10 @@ static inline void hmll_remove(HMLList *const hmll, HMLListEntry *const hmll_ent
assert(hmll->free_entry == NULL);
hmll->free_entry = hmll_entry;
}
- const khiter_t k = kh_get(hmll_entries, &hmll->contained_entries,
- hmll_entry->data.data.history_item.string);
- assert(k != kh_end(&hmll->contained_entries));
- kh_del(hmll_entries, &hmll->contained_entries, k);
+ ptr_t val = pmap_del(cstr_t)(&hmll->contained_entries,
+ hmll_entry->data.data.history_item.string, NULL);
+ assert(val);
+ (void)val;
if (hmll_entry->next == NULL) {
hmll->last = hmll_entry->prev;
} else {
@@ -586,11 +568,11 @@ static inline void hmll_insert(HMLList *const hmll, HMLListEntry *hmll_entry, co
}
target_entry->data = data;
target_entry->can_free_entry = can_free_entry;
- int kh_ret;
- const khiter_t k = kh_put(hmll_entries, &hmll->contained_entries,
- data.data.history_item.string, &kh_ret);
- if (kh_ret > 0) {
- kh_val(&hmll->contained_entries, k) = target_entry;
+ bool new_item = false;
+ ptr_t *val = pmap_put_ref(cstr_t)(&hmll->contained_entries, data.data.history_item.string,
+ NULL, &new_item);
+ if (new_item) {
+ *val = target_entry;
}
hmll->num_entries++;
target_entry->prev = hmll_entry;
@@ -614,7 +596,7 @@ static inline void hmll_insert(HMLList *const hmll, HMLListEntry *hmll_entry, co
static inline void hmll_dealloc(HMLList *const hmll)
FUNC_ATTR_NONNULL_ALL
{
- kh_dealloc(hmll_entries, &hmll->contained_entries);
+ map_destroy(cstr_t, &hmll->contained_entries);
xfree(hmll->entries);
}
@@ -771,30 +753,6 @@ static void close_file(void *cookie)
}
}
-/// Check whether buffer is in the given set
-///
-/// @param[in] set Set to check within.
-/// @param[in] buf Buffer to find.
-///
-/// @return true or false.
-static inline bool in_bufset(const khash_t(bufset) *const set, const buf_T *buf)
- FUNC_ATTR_PURE
-{
- return kh_get(bufset, set, (uintptr_t)buf) != kh_end(set);
-}
-
-/// Check whether string is in the given set
-///
-/// @param[in] set Set to check within.
-/// @param[in] buf Buffer to find.
-///
-/// @return true or false.
-static inline bool in_strset(const khash_t(strset) *const set, char *str)
- FUNC_ATTR_PURE
-{
- return kh_get(strset, set, str) != kh_end(set);
-}
-
/// Msgpack callback for writing to ShaDaWriteDef*
static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{
@@ -930,10 +888,11 @@ static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
}
}
HMLList *const hmll = &hms_p->hmll;
- const khiter_t k = kh_get(hmll_entries, &hms_p->hmll.contained_entries,
- entry.data.history_item.string);
- if (k != kh_end(&hmll->contained_entries)) {
- HMLListEntry *const existing_entry = kh_val(&hmll->contained_entries, k);
+ cstr_t *key_alloc = NULL;
+ ptr_t *val = pmap_ref(cstr_t)(&hms_p->hmll.contained_entries, entry.data.history_item.string,
+ &key_alloc);
+ if (val) {
+ HMLListEntry *const existing_entry = *val;
if (entry.timestamp > existing_entry->data.timestamp) {
hmll_remove(hmll, existing_entry);
} else if (!do_iter && entry.timestamp == existing_entry->data.timestamp) {
@@ -944,7 +903,7 @@ static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
existing_entry->data = entry;
existing_entry->can_free_entry = can_free_entry;
// Previous key was freed above, as part of freeing the ShaDa entry.
- kh_key(&hmll->contained_entries, k) = entry.data.history_item.string;
+ *key_alloc = entry.data.history_item.string;
return;
} else {
return;
@@ -1046,24 +1005,27 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
/// @param[in] fname File name to find.
///
/// @return Pointer to the buffer or NULL.
-static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs, const char *const fname)
+static buf_T *find_buffer(PMap(cstr_t) *const fname_bufs, const char *const fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- int kh_ret;
- khint_t k = kh_put(fnamebufs, fname_bufs, fname, &kh_ret);
- if (!kh_ret) {
- return kh_val(fname_bufs, k);
+ cstr_t *key_alloc = NULL;
+ bool new_item = false;
+ buf_T **ref = (buf_T **)pmap_put_ref(cstr_t)(fname_bufs, fname, &key_alloc, &new_item);
+ if (new_item) {
+ *key_alloc = xstrdup(fname);
+ } else {
+ return *ref; // item already existed (can be a NULL value)
}
- kh_key(fname_bufs, k) = xstrdup(fname);
+
FOR_ALL_BUFFERS(buf) {
if (buf->b_ffname != NULL) {
if (path_fnamecmp(fname, buf->b_ffname) == 0) {
- kh_val(fname_bufs, k) = buf;
+ *ref = buf;
return buf;
}
}
}
- kh_val(fname_bufs, k) = NULL;
+ *ref = NULL;
return NULL;
}
@@ -1163,9 +1125,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
}
ShadaEntry cur_entry;
- khash_t(bufset) cl_bufs = KHASH_EMPTY_TABLE(bufset);
- khash_t(fnamebufs) fname_bufs = KHASH_EMPTY_TABLE(fnamebufs);
- khash_t(strset) oldfiles_set = KHASH_EMPTY_TABLE(strset);
+ Set(ptr_t) cl_bufs = SET_INIT;
+ PMap(cstr_t) fname_bufs = MAP_INIT;
+ Set(cstr_t) oldfiles_set = SET_INIT;
if (get_old_files && (oldfiles_list == NULL || force)) {
oldfiles_list = tv_list_alloc(kListLenUnknown);
set_vim_var_list(VV_OLDFILES, oldfiles_list);
@@ -1359,8 +1321,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
break;
case kSDItemChange:
case kSDItemLocalMark: {
- if (get_old_files && !in_strset(&oldfiles_set,
- cur_entry.data.filemark.fname)) {
+ if (get_old_files && !set_has(cstr_t, &oldfiles_set, cur_entry.data.filemark.fname)) {
char *fname = cur_entry.data.filemark.fname;
if (want_marks) {
// Do not bother with allocating memory for the string if already
@@ -1368,8 +1329,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
// want_marks is set because this way it may be used for a mark.
fname = xstrdup(fname);
}
- int kh_ret;
- (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
+ set_put(cstr_t, &oldfiles_set, fname);
tv_list_append_allocated_string(oldfiles_list, fname);
if (!want_marks) {
// Avoid free because this string was already used.
@@ -1398,8 +1358,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
break;
}
} else {
- int kh_ret;
- (void)kh_put(bufset, &cl_bufs, (uintptr_t)buf, &kh_ret);
+ set_put(ptr_t, &cl_bufs, buf);
#define SDE_TO_FMARK(entry) fm
#define AFTERFREE(entry) (entry).data.filemark.fname = NULL
#define DUMMY_IDX_ADJ(i)
@@ -1440,18 +1399,18 @@ shada_read_main_cycle_end:
if (cl_bufs.n_occupied) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
(void)tp;
- if (in_bufset(&cl_bufs, wp->w_buffer)) {
+ if (set_has(ptr_t, &cl_bufs, wp->w_buffer)) {
wp->w_changelistidx = wp->w_buffer->b_changelistlen;
}
}
}
- kh_dealloc(bufset, &cl_bufs);
+ set_destroy(ptr_t, &cl_bufs);
const char *key;
- kh_foreach_key(&fname_bufs, key, {
- xfree((void *)key);
+ map_foreach_key(&fname_bufs, key, {
+ xfree((char *)key);
})
- kh_dealloc(fnamebufs, &fname_bufs);
- kh_dealloc(strset, &oldfiles_set);
+ map_destroy(cstr_t, &fname_bufs);
+ set_destroy(cstr_t, &oldfiles_set);
}
/// Default shada file location: cached path
@@ -2154,7 +2113,7 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re
break;
}
case kSDItemVariable:
- if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
+ if (!set_has(cstr_t, &wms->dumped_variables, entry.data.global_var.name)) {
ret = shada_pack_entry(packer, entry, 0);
}
shada_free_shada_entry(&entry);
@@ -2211,13 +2170,12 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re
break;
}
const char *const fname = entry.data.filemark.fname;
- khiter_t k;
- int kh_ret;
- k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
- FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
- if (kh_ret > 0) {
- CLEAR_POINTER(filemarks);
+ cstr_t *key = NULL;
+ ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, &key, NULL);
+ if (*val == NULL) {
+ *val = xcalloc(1, sizeof(FileMarks));
}
+ FileMarks *const filemarks = *val;
if (entry.timestamp > filemarks->greatest_timestamp) {
filemarks->greatest_timestamp = entry.timestamp;
}
@@ -2237,9 +2195,8 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re
break;
}
if (wms_entry->can_free_entry) {
- if (kh_key(&wms->file_marks, k)
- == wms_entry->data.data.filemark.fname) {
- kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
+ if (*key == wms_entry->data.data.filemark.fname) {
+ *key = entry.data.filemark.fname;
}
shada_free_shada_entry(&wms_entry->data);
}
@@ -2281,11 +2238,11 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re
/// @param[in] removable_bufs Cache of buffers ignored due to their location.
///
/// @return true or false.
-static inline bool ignore_buf(const buf_T *const buf, khash_t(bufset) *const removable_bufs)
+static inline bool ignore_buf(const buf_T *const buf, Set(ptr_t) *const removable_bufs)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
- || bt_terminal(buf) || in_bufset(removable_bufs, buf));
+ || bt_terminal(buf) || set_has(ptr_t, removable_bufs, (ptr_t)buf));
}
/// Get list of buffers to write to the shada file
@@ -2293,7 +2250,7 @@ static inline bool ignore_buf(const buf_T *const buf, khash_t(bufset) *const rem
/// @param[in] removable_bufs Buffers which are ignored
///
/// @return ShadaEntry List of buffers to save, kSDItemBufferList entry.
-static inline ShadaEntry shada_get_buflist(khash_t(bufset) *const removable_bufs)
+static inline ShadaEntry shada_get_buflist(Set(ptr_t) *const removable_bufs)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
int max_bufs = get_shada_parameter('%');
@@ -2461,12 +2418,11 @@ static inline void replace_numbered_mark(WriteMergerState *const wms, const size
/// Find buffers ignored due to their location.
///
/// @param[out] removable_bufs Cache of buffers ignored due to their location.
-static inline void find_removable_bufs(khash_t(bufset) *removable_bufs)
+static inline void find_removable_bufs(Set(ptr_t) *removable_bufs)
{
FOR_ALL_BUFFERS(buf) {
if (buf->b_ffname != NULL && shada_removable(buf->b_ffname)) {
- int kh_ret;
- (void)kh_put(bufset, removable_bufs, (uintptr_t)buf, &kh_ret);
+ set_put(ptr_t, removable_bufs, (ptr_t)buf);
}
}
}
@@ -2518,7 +2474,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
max_reg_lines = get_shada_parameter('"');
}
const bool dump_registers = (max_reg_lines != 0);
- khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
+ Set(ptr_t) removable_bufs = SET_INIT;
const size_t max_kbyte = (size_t)max_kbyte_i;
const size_t num_marked_files = (size_t)get_shada_parameter('\'');
const bool dump_global_marks = get_shada_parameter('f') != 0;
@@ -2573,15 +2529,15 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
.capacity = 5,
.items = ((KeyValuePair[]) {
{ STATIC_CSTR_AS_STRING("generator"),
- STRING_OBJ(STATIC_CSTR_AS_STRING("nvim")) },
+ STATIC_CSTR_AS_OBJ("nvim") },
{ STATIC_CSTR_AS_STRING("version"),
- STRING_OBJ(cstr_as_string(longVersion)) },
+ CSTR_AS_OBJ(longVersion) },
{ STATIC_CSTR_AS_STRING("max_kbyte"),
INTEGER_OBJ((Integer)max_kbyte) },
{ STATIC_CSTR_AS_STRING("pid"),
INTEGER_OBJ((Integer)os_get_pid()) },
{ STATIC_CSTR_AS_STRING("encoding"),
- STRING_OBJ(cstr_as_string(p_enc)) },
+ CSTR_AS_OBJ(p_enc) },
}),
}
}
@@ -2662,8 +2618,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
tv_clear(&vartv);
tv_clear(&tgttv);
if (spe_ret == kSDWriteSuccessful) {
- int kh_ret;
- (void)kh_put(strset, &wms->dumped_variables, name, &kh_ret);
+ set_put(cstr_t, &wms->dumped_variables, name);
}
} while (var_iter != NULL);
}
@@ -2723,7 +2678,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
} else {
const buf_T *const buf = buflist_findnr(fm.fmark.fnum);
if (buf == NULL || buf->b_ffname == NULL
- || in_bufset(&removable_bufs, buf)) {
+ || set_has(ptr_t, &removable_bufs, (ptr_t)buf)) {
continue;
}
fname = buf->b_ffname;
@@ -2759,18 +2714,16 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
// Initialize buffers
if (num_marked_files > 0) {
FOR_ALL_BUFFERS(buf) {
- if (buf->b_ffname == NULL || in_bufset(&removable_bufs, buf)) {
+ if (buf->b_ffname == NULL || set_has(ptr_t, &removable_bufs, buf)) {
continue;
}
const void *local_marks_iter = NULL;
const char *const fname = buf->b_ffname;
- khiter_t k;
- int kh_ret;
- k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
- FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
- if (kh_ret > 0) {
- CLEAR_POINTER(filemarks);
+ ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, NULL, NULL);
+ if (*val == NULL) {
+ *val = xcalloc(1, sizeof(FileMarks));
}
+ FileMarks *const filemarks = *val;
do {
fmark_T fm;
char name = NUL;
@@ -2887,16 +2840,14 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
PACK_WMS_ENTRY(wms->replacement);
#undef PACK_WMS_ENTRY
- const size_t file_markss_size = kh_size(&wms->file_marks);
+ const size_t file_markss_size = map_size(&wms->file_marks);
FileMarks **const all_file_markss =
xmalloc(file_markss_size * sizeof(*all_file_markss));
FileMarks **cur_file_marks = all_file_markss;
- for (khint_t i = kh_begin(&wms->file_marks); i != kh_end(&wms->file_marks);
- i++) {
- if (kh_exist(&wms->file_marks, i)) {
- *cur_file_marks++ = &kh_val(&wms->file_marks, i);
- }
- }
+ ptr_t val;
+ map_foreach_value(ptr_t, &wms->file_marks, val, {
+ *cur_file_marks++ = val;
+ })
qsort((void *)all_file_markss, file_markss_size, sizeof(*all_file_markss),
&compare_file_marks);
const size_t file_markss_to_dump = MIN(num_marked_files, file_markss_size);
@@ -2949,10 +2900,13 @@ shada_write_exit:
hms_dealloc(&wms->hms[i]);
}
}
- kh_dealloc(file_marks, &wms->file_marks);
- kh_dealloc(bufset, &removable_bufs);
+ map_foreach_value(ptr_t, &wms->file_marks, val, {
+ xfree(val);
+ })
+ map_destroy(cstr_t, &wms->file_marks);
+ set_destroy(ptr_t, &removable_bufs);
msgpack_packer_free(packer);
- kh_dealloc(strset, &wms->dumped_variables);
+ set_destroy(cstr_t, &wms->dumped_variables);
xfree(wms);
return ret;
}
@@ -4035,7 +3989,7 @@ static bool shada_removable(const char *name)
///
/// @return number of jumplist entries
static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
- khash_t(bufset) *const removable_bufs)
+ Set(ptr_t) *const removable_bufs)
{
// Initialize jump list
size_t jumps_size = 0;
@@ -4056,7 +4010,7 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
? NULL
: buflist_findnr(fm.fmark.fnum));
if (buf != NULL
- ? in_bufset(removable_bufs, buf)
+ ? set_has(ptr_t, removable_bufs, (ptr_t)buf)
: fm.fmark.fnum != 0) {
continue;
}
@@ -4111,7 +4065,7 @@ void shada_encode_regs(msgpack_sbuffer *const sbuf)
void shada_encode_jumps(msgpack_sbuffer *const sbuf)
FUNC_ATTR_NONNULL_ALL
{
- khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
+ Set(ptr_t) removable_bufs = SET_INIT;
find_removable_bufs(&removable_bufs);
PossiblyFreedShadaEntry jumps[JUMPLISTSIZE];
size_t jumps_size = shada_init_jumps(jumps, &removable_bufs);
@@ -4130,7 +4084,7 @@ void shada_encode_jumps(msgpack_sbuffer *const sbuf)
void shada_encode_buflist(msgpack_sbuffer *const sbuf)
FUNC_ATTR_NONNULL_ALL
{
- khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
+ Set(ptr_t) removable_bufs = SET_INIT;
find_removable_bufs(&removable_bufs);
ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
msgpack_packer packer;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 84875261f1..778266e5ac 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1189,11 +1189,19 @@ bool spell_valid_case(int wordflags, int treeflags)
|| (wordflags & WF_ONECAP) != 0));
}
-// Returns true if spell checking is not enabled.
+/// Return true if spell checking is enabled for "wp".
+bool spell_check_window(win_T *wp)
+{
+ return wp->w_p_spell
+ && *wp->w_s->b_p_spl != NUL
+ && wp->w_s->b_langp.ga_len > 0
+ && *(char **)(wp->w_s->b_langp.ga_data) != NULL;
+}
+
+/// Return true and give an error if spell checking is not enabled.
bool no_spell_checking(win_T *wp)
{
- if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL
- || GA_EMPTY(&wp->w_s->b_langp)) {
+ if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL || GA_EMPTY(&wp->w_s->b_langp)) {
emsg(_(e_no_spell));
return true;
}
@@ -1304,7 +1312,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
} else if (curline && wp == curwin) {
// For spellbadword(): check if first word needs a capital.
col = (colnr_T)getwhitecols(line);
- if (check_need_cap(lnum, col)) {
+ if (check_need_cap(curwin, lnum, col)) {
capcol = col;
}
@@ -2528,25 +2536,24 @@ int spell_casefold(const win_T *wp, char *str, int len, char *buf, int buflen)
}
// Check if the word at line "lnum" column "col" is required to start with a
-// capital. This uses 'spellcapcheck' of the current buffer.
-bool check_need_cap(linenr_T lnum, colnr_T col)
+// capital. This uses 'spellcapcheck' of the buffer in window "wp".
+bool check_need_cap(win_T *wp, linenr_T lnum, colnr_T col)
{
- bool need_cap = false;
-
- if (curwin->w_s->b_cap_prog == NULL) {
+ if (wp->w_s->b_cap_prog == NULL) {
return false;
}
- char *line = get_cursor_line_ptr();
+ bool need_cap = false;
+ char *line = col ? ml_get_buf(wp->w_buffer, lnum, false) : NULL;
char *line_copy = NULL;
colnr_T endcol = 0;
- if (getwhitecols(line) >= (int)col) {
+ if (col == 0 || getwhitecols(line) >= col) {
// At start of line, check if previous line is empty or sentence
// ends there.
if (lnum == 1) {
need_cap = true;
} else {
- line = ml_get(lnum - 1);
+ line = ml_get_buf(wp->w_buffer, lnum - 1, false);
if (*skipwhite(line) == NUL) {
need_cap = true;
} else {
@@ -2563,13 +2570,13 @@ bool check_need_cap(linenr_T lnum, colnr_T col)
if (endcol > 0) {
// Check if sentence ends before the bad word.
regmatch_T regmatch = {
- .regprog = curwin->w_s->b_cap_prog,
+ .regprog = wp->w_s->b_cap_prog,
.rm_ic = false
};
char *p = line + endcol;
while (true) {
MB_PTR_BACK(line, p);
- if (p == line || spell_iswordp_nmw(p, curwin)) {
+ if (p == line || spell_iswordp_nmw(p, wp)) {
break;
}
if (vim_regexec(&regmatch, p, 0)
@@ -2578,7 +2585,7 @@ bool check_need_cap(linenr_T lnum, colnr_T col)
break;
}
}
- curwin->w_s->b_cap_prog = regmatch.regprog;
+ wp->w_s->b_cap_prog = regmatch.regprog;
}
xfree(line_copy);
@@ -3593,7 +3600,7 @@ static bool spell_expand_need_cap;
void spell_expand_check_cap(colnr_T col)
{
- spell_expand_need_cap = check_need_cap(curwin->w_cursor.lnum, col);
+ spell_expand_need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, col);
}
// Get list of spelling suggestions.
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 5e4a429cc7..e81cebe18a 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -3131,7 +3131,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile)
// Remove CR, LF and white space from the end. White space halfway through
// the word is kept to allow multi-word terms like "et al.".
l = (int)strlen(line);
- while (l > 0 && line[l - 1] <= ' ') {
+ while (l > 0 && (uint8_t)line[l - 1] <= ' ') {
l--;
}
if (l == 0) {
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index 84be88be7b..1c34c2487f 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -509,7 +509,7 @@ void spell_suggest(int count)
// Get the word and its length.
// Figure out if the word should be capitalised.
- int need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col);
+ int need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, curwin->w_cursor.col);
// Make a copy of current line since autocommands may free the line.
line = xstrdup(get_cursor_line_ptr());
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index a6fd1d677b..015c578396 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -336,7 +336,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
grid_adjust(&grid, &row, &col);
if (row < 0) {
- return;
+ goto theend;
}
fillchar = wp->w_p_fcs_chars.wbr;
@@ -596,7 +596,7 @@ void win_redr_ruler(win_T *wp)
MAXSIZE_TEMP_ARRAY(content, 1);
MAXSIZE_TEMP_ARRAY(chunk, 2);
ADD_C(chunk, INTEGER_OBJ(attr));
- ADD_C(chunk, STRING_OBJ(cstr_as_string(buffer)));
+ ADD_C(chunk, CSTR_AS_OBJ(buffer));
ADD_C(content, ARRAY_OBJ(chunk));
ui_call_msg_ruler(content);
did_show_ext_ruler = true;
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 5231ec0841..4e521b14f7 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -1502,7 +1502,8 @@ char *strrep(const char *src, const char *what, const char *rep)
return ret;
}
-static void byteidx(typval_T *argvars, typval_T *rettv, int comp)
+/// Implementation of "byteidx()" and "byteidxcomp()" functions
+static void byteidx_common(typval_T *argvars, typval_T *rettv, int comp)
{
rettv->vval.v_number = -1;
@@ -1514,7 +1515,11 @@ static void byteidx(typval_T *argvars, typval_T *rettv, int comp)
varnumber_T utf16idx = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
- utf16idx = tv_get_bool(&argvars[2]);
+ bool error = false;
+ utf16idx = tv_get_bool_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
if (utf16idx < 0 || utf16idx > 1) {
semsg(_(e_using_number_as_bool_nr), utf16idx);
return;
@@ -1550,13 +1555,13 @@ static void byteidx(typval_T *argvars, typval_T *rettv, int comp)
/// "byteidx()" function
void f_byteidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- byteidx(argvars, rettv, false);
+ byteidx_common(argvars, rettv, false);
}
/// "byteidxcomp()" function
void f_byteidxcomp(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- byteidx(argvars, rettv, true);
+ byteidx_common(argvars, rettv, true);
}
/// "charidx()" function
@@ -1764,16 +1769,21 @@ void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "strchars()" function
void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- int skipcc = false;
+ varnumber_T skipcc = false;
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = (int)tv_get_bool(&argvars[1]);
- }
- if (skipcc < 0 || skipcc > 1) {
- semsg(_(e_using_number_as_bool_nr), skipcc);
- } else {
- strchar_common(argvars, rettv, skipcc);
+ bool error = false;
+ skipcc = tv_get_bool_chk(&argvars[1], &error);
+ if (error) {
+ return;
+ }
+ if (skipcc < 0 || skipcc > 1) {
+ semsg(_(e_using_number_as_bool_nr), skipcc);
+ return;
+ }
}
+
+ strchar_common(argvars, rettv, skipcc);
}
/// "strutf16len()" function
@@ -1840,7 +1850,10 @@ void f_strcharpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (!error) {
if (argvars[2].v_type != VAR_UNKNOWN
&& argvars[3].v_type != VAR_UNKNOWN) {
- skipcc = tv_get_bool(&argvars[3]);
+ skipcc = tv_get_bool_chk(&argvars[3], &error);
+ if (error) {
+ return;
+ }
if (skipcc < 0 || skipcc > 1) {
semsg(_(e_using_number_as_bool_nr), skipcc);
return;
diff --git a/src/nvim/strings.h b/src/nvim/strings.h
index 6ad9daf5bf..f4ccf9b30c 100644
--- a/src/nvim/strings.h
+++ b/src/nvim/strings.h
@@ -6,7 +6,7 @@
#include <string.h>
#include "klib/kvec.h"
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/types.h"
/// Append string to string and return pointer to the next byte
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index ff16a10d8e..18331cc95d 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -732,7 +732,7 @@ void do_tag(char *tag, int type, int count, int forceit, int verbose)
num_matches,
max_num_matches != MAXCOL ? _(" or more") : "");
if (ic) {
- STRCAT(IObuff, _(" Using tag with different case!"));
+ xstrlcat(IObuff, _(" Using tag with different case!"), IOSIZE);
}
if ((num_matches > prev_num_matches || new_tag)
&& num_matches > 1) {
@@ -2901,21 +2901,10 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, int keep_help)
buf_T *const existing_buf = buflist_findname_exp(fname);
if (existing_buf != NULL) {
- const win_T *wp = NULL;
-
- if (swb_flags & SWB_USEOPEN) {
- wp = buf_jump_open_win(existing_buf);
- }
-
- // If 'switchbuf' contains "usetab": jump to first window in any tab
- // page containing "existing_buf" if one exists
- if (wp == NULL && (swb_flags & SWB_USETAB)) {
- wp = buf_jump_open_tab(existing_buf);
- }
-
- // We've switched to the buffer, the usual loading of the file must
- // be skipped.
- if (wp != NULL) {
+ // If 'switchbuf' is set jump to the window containing "buf".
+ if (swbuf_goto_win_with_buf(existing_buf) != NULL) {
+ // We've switched to the buffer, the usual loading of the file
+ // must be skipped.
getfile_result = GETFILE_SAME_FILE;
}
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 0686305d02..792071963d 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -169,7 +169,7 @@ static VTermScreenCallbacks vterm_screen_callbacks = {
.sb_popline = term_sb_pop,
};
-static PMap(ptr_t) invalidated_terminals = MAP_INIT;
+static Set(ptr_t) invalidated_terminals = SET_INIT;
void terminal_init(void)
{
@@ -183,10 +183,10 @@ void terminal_teardown(void)
time_watcher_stop(&refresh_timer);
multiqueue_free(refresh_timer.events);
time_watcher_close(&refresh_timer, NULL);
- pmap_destroy(ptr_t)(&invalidated_terminals);
+ set_destroy(ptr_t, &invalidated_terminals);
// terminal_destroy might be called after terminal_teardown is invoked
// make sure it is in an empty, valid state
- pmap_init(ptr_t, &invalidated_terminals);
+ invalidated_terminals = (Set(ptr_t)) SET_INIT;
}
static void term_output_callback(const char *s, size_t len, void *user_data)
@@ -220,6 +220,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
// Set up screen
rv->vts = vterm_obtain_screen(rv->vt);
vterm_screen_enable_altscreen(rv->vts, true);
+ vterm_screen_enable_reflow(rv->vts, true);
// delete empty lines at the end of the buffer
vterm_screen_set_callbacks(rv->vts, &vterm_screen_callbacks, rv);
vterm_screen_set_damage_merge(rv->vts, VTERM_DAMAGE_SCROLL);
@@ -596,7 +597,7 @@ static int terminal_execute(VimState *state, int key)
break;
case K_LUA:
- map_execute_lua();
+ map_execute_lua(false);
break;
case Ctrl_N:
@@ -652,12 +653,12 @@ void terminal_destroy(Terminal **termpp)
}
if (!term->refcount) {
- if (pmap_has(ptr_t)(&invalidated_terminals, term)) {
+ if (set_has(ptr_t, &invalidated_terminals, term)) {
// flush any pending changes to the buffer
block_autocmds();
refresh_terminal(term);
unblock_autocmds();
- pmap_del(ptr_t)(&invalidated_terminals, term);
+ set_del(ptr_t, &invalidated_terminals, term);
}
for (size_t i = 0; i < term->sb_current; i++) {
xfree(term->sb_buffer[i]);
@@ -1027,7 +1028,7 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data)
}
memcpy(sbrow->cells, cells, sizeof(cells[0]) * c);
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
return 1;
}
@@ -1068,7 +1069,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
}
xfree(sbrow);
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
return 1;
}
@@ -1524,7 +1525,7 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
term->invalid_end = MAX(term->invalid_end, end_row);
}
- pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
+ set_put(ptr_t, &invalidated_terminals, term);
if (!refresh_pending) {
time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0);
refresh_pending = true;
@@ -1567,10 +1568,10 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
void *stub; (void)(stub);
// don't process autocommands while updating terminal buffers
block_autocmds();
- map_foreach(&invalidated_terminals, term, stub, {
+ set_foreach(&invalidated_terminals, term, {
refresh_terminal(term);
});
- pmap_clear(ptr_t)(&invalidated_terminals);
+ set_clear(ptr_t, &invalidated_terminals);
unblock_autocmds();
}
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index 5483a58525..25ec8e898a 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -418,11 +418,11 @@ static int assert_equalfile(typval_T *argvars)
const int c2 = fgetc(fd2);
if (c1 == EOF) {
if (c2 != EOF) {
- STRCPY(IObuff, "first file is shorter");
+ xstrlcpy(IObuff, "first file is shorter", IOSIZE);
}
break;
} else if (c2 == EOF) {
- STRCPY(IObuff, "second file is shorter");
+ xstrlcpy(IObuff, "second file is shorter", IOSIZE);
break;
} else {
line1[lineidx] = (char)c1;
diff --git a/src/nvim/testing.h b/src/nvim/testing.h
index 69596d725c..69ceeb16b5 100644
--- a/src/nvim/testing.h
+++ b/src/nvim/testing.h
@@ -1,7 +1,7 @@
#ifndef NVIM_TESTING_H
#define NVIM_TESTING_H
-#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "testing.h.generated.h"
diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c
index 428b14a68d..5036c10827 100644
--- a/src/nvim/textobject.c
+++ b/src/nvim/textobject.c
@@ -22,6 +22,7 @@
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option_defs.h"
#include "nvim/pos.h"
@@ -414,6 +415,7 @@ int bck_word(long count, bool bigword, bool stop)
finished:
stop = false;
}
+ adjust_skipcol();
return OK;
}
@@ -518,6 +520,7 @@ int bckend_word(long count, bool bigword, bool eol)
}
}
}
+ adjust_skipcol();
return OK;
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 73ed7b6096..30a1af68ad 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -33,7 +33,7 @@
#define KEY_BUFFER_SIZE 0xfff
static const struct kitty_key_map_entry {
- KittyKey key;
+ int key;
const char *name;
} kitty_key_map_entry[] = {
{ KITTY_KEY_ESCAPE, "Esc" },
@@ -115,7 +115,7 @@ static const struct kitty_key_map_entry {
{ KITTY_KEY_KP_BEGIN, "kOrigin" },
};
-static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT;
+static Map(int, cstr_t) kitty_key_map = MAP_INIT;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/input.c.generated.h"
@@ -135,8 +135,8 @@ void tinput_init(TermInput *input, Loop *loop)
input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) {
- map_put(KittyKey, cstr_t)(&kitty_key_map, kitty_key_map_entry[i].key,
- kitty_key_map_entry[i].name);
+ map_put(int, cstr_t)(&kitty_key_map, kitty_key_map_entry[i].key,
+ kitty_key_map_entry[i].name);
}
input->in_fd = STDIN_FILENO;
@@ -162,7 +162,7 @@ void tinput_init(TermInput *input, Loop *loop)
void tinput_destroy(TermInput *input)
{
- map_destroy(KittyKey, cstr_t)(&kitty_key_map);
+ map_destroy(int, &kitty_key_map);
rbuffer_free(input->key_buffer);
time_watcher_close(&input->timer_handle, NULL);
stream_close(&input->read_stream, NULL, NULL);
@@ -231,7 +231,7 @@ static void tinput_enqueue(TermInput *input, char *buf, size_t size)
static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key)
{
- const char *name = map_get(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint);
+ const char *name = map_get(int, cstr_t)(&kitty_key_map, (int)key->code.codepoint);
if (name) {
char buf[64];
size_t len = 0;
@@ -257,7 +257,7 @@ static void forward_simple_utf8(TermInput *input, TermKeyKey *key)
char *ptr = key->utf8;
if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF
- && map_has(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint)) {
+ && map_has(int, cstr_t)(&kitty_key_map, (int)key->code.codepoint)) {
handle_kitty_key_protocol(input, key);
return;
}
@@ -286,8 +286,7 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
} else {
assert(key->modifiers);
if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF
- && map_has(KittyKey, cstr_t)(&kitty_key_map,
- (KittyKey)key->code.codepoint)) {
+ && map_has(int, cstr_t)(&kitty_key_map, (int)key->code.codepoint)) {
handle_kitty_key_protocol(input, key);
return;
}
@@ -548,8 +547,8 @@ static void set_bg(char *bgvalue)
{
if (ui_client_attached) {
MAXSIZE_TEMP_ARRAY(args, 2);
- ADD_C(args, STRING_OBJ(cstr_as_string("term_background")));
- ADD_C(args, STRING_OBJ(cstr_as_string(bgvalue)));
+ ADD_C(args, CSTR_AS_OBJ("term_background"));
+ ADD_C(args, CSTR_AS_OBJ(bgvalue));
rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args);
}
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 2de1467511..c9d9b08b79 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -106,6 +106,7 @@ struct TUIData {
bool bce;
bool mouse_enabled;
bool mouse_move_enabled;
+ bool title_enabled;
bool busy, is_invisible, want_invisible;
bool cork, overflow;
bool set_cursor_color_as_str;
@@ -325,8 +326,6 @@ static void terminfo_start(TUIData *tui)
// Enter alternate screen, save title, and clear.
// NOTE: Do this *before* changing terminal settings. #6433
unibi_out(tui, unibi_enter_ca_mode);
- // Save title/icon to the "stack". #4063
- unibi_out_ext(tui, tui->unibi_ext.save_title);
unibi_out(tui, unibi_keypad_xmit);
unibi_out(tui, unibi_clear_screen);
// Ask the terminal to send us the background color.
@@ -383,8 +382,7 @@ static void terminfo_stop(TUIData *tui)
// Disable extended keys before exiting alternate screen.
unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys);
unibi_out(tui, unibi_exit_ca_mode);
- // Restore title/icon from the "stack". #4063
- unibi_out_ext(tui, tui->unibi_ext.restore_title);
+ tui_set_title(tui, (String)STRING_INIT);
if (tui->cursor_color_changed) {
unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color);
}
@@ -1304,16 +1302,16 @@ static void show_verbose_terminfo(TUIData *tui)
Array chunks = ARRAY_DICT_INIT;
Array title = ARRAY_DICT_INIT;
- ADD(title, STRING_OBJ(cstr_to_string("\n\n--- Terminal info --- {{{\n")));
- ADD(title, STRING_OBJ(cstr_to_string("Title")));
+ ADD(title, CSTR_TO_OBJ("\n\n--- Terminal info --- {{{\n"));
+ ADD(title, CSTR_TO_OBJ("Title"));
ADD(chunks, ARRAY_OBJ(title));
Array info = ARRAY_DICT_INIT;
String str = terminfo_info_msg(ut, tui->term);
ADD(info, STRING_OBJ(str));
ADD(chunks, ARRAY_OBJ(info));
Array end_fold = ARRAY_DICT_INIT;
- ADD(end_fold, STRING_OBJ(cstr_to_string("}}}\n")));
- ADD(end_fold, STRING_OBJ(cstr_to_string("Title")));
+ ADD(end_fold, CSTR_TO_OBJ("}}}\n"));
+ ADD(end_fold, CSTR_TO_OBJ("Title"));
ADD(chunks, ARRAY_OBJ(end_fold));
Array args = ARRAY_DICT_INIT;
@@ -1361,13 +1359,24 @@ void tui_suspend(TUIData *tui)
void tui_set_title(TUIData *tui, String title)
{
- if (!(title.data && unibi_get_str(tui->ut, unibi_to_status_line)
+ if (!(unibi_get_str(tui->ut, unibi_to_status_line)
&& unibi_get_str(tui->ut, unibi_from_status_line))) {
return;
}
- unibi_out(tui, unibi_to_status_line);
- out(tui, title.data, title.size);
- unibi_out(tui, unibi_from_status_line);
+ if (title.size > 0) {
+ if (!tui->title_enabled) {
+ // Save title/icon to the "stack". #4063
+ unibi_out_ext(tui, tui->unibi_ext.save_title);
+ tui->title_enabled = true;
+ }
+ unibi_out(tui, unibi_to_status_line);
+ out(tui, title.data, title.size);
+ unibi_out(tui, unibi_from_status_line);
+ } else if (tui->title_enabled) {
+ // Restore title/icon from the "stack". #4063
+ unibi_out_ext(tui, tui->unibi_ext.restore_title);
+ tui->title_enabled = false;
+ }
}
void tui_set_icon(TUIData *tui, String icon)
@@ -1416,7 +1425,7 @@ void tui_option_set(TUIData *tui, String name, Object value)
if (ui_client_channel_id) {
MAXSIZE_TEMP_ARRAY(args, 2);
- ADD_C(args, STRING_OBJ(cstr_as_string("rgb")));
+ ADD_C(args, CSTR_AS_OBJ("rgb"));
ADD_C(args, BOOLEAN_OBJ(value.data.boolean));
rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args);
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 6d09b9f3a3..8c31032492 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -127,10 +127,10 @@ void ui_free_all_mem(void)
kv_destroy(call_buf);
UIEventCallback *event_cb;
- map_foreach_value(&ui_event_cbs, event_cb, {
+ pmap_foreach_value(&ui_event_cbs, event_cb, {
free_ui_event_callback(event_cb);
})
- pmap_destroy(uint32_t)(&ui_event_cbs);
+ map_destroy(uint32_t, &ui_event_cbs);
}
#endif
@@ -613,8 +613,8 @@ Array ui_array(void)
PUT(info, "override", BOOLEAN_OBJ(ui->override));
// TUI fields. (`stdin_fd` is intentionally omitted.)
- PUT(info, "term_name", STRING_OBJ(cstr_to_string(ui->term_name)));
- PUT(info, "term_background", STRING_OBJ(cstr_to_string(ui->term_background)));
+ PUT(info, "term_name", CSTR_TO_OBJ(ui->term_name));
+ PUT(info, "term_background", CSTR_TO_OBJ(ui->term_background));
PUT(info, "term_colors", INTEGER_OBJ(ui->term_colors));
PUT(info, "stdin_tty", BOOLEAN_OBJ(ui->stdin_tty));
PUT(info, "stdout_tty", BOOLEAN_OBJ(ui->stdout_tty));
@@ -660,7 +660,7 @@ void ui_call_event(char *name, Array args)
{
UIEventCallback *event_cb;
bool handled = false;
- map_foreach_value(&ui_event_cbs, event_cb, {
+ pmap_foreach_value(&ui_event_cbs, event_cb, {
Error err = ERROR_INIT;
Object res = nlua_call_ref(event_cb->cb, name, args, false, &err);
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
@@ -686,7 +686,7 @@ void ui_cb_update_ext(void)
for (size_t i = 0; i < kUIGlobalCount; i++) {
UIEventCallback *event_cb;
- map_foreach_value(&ui_event_cbs, event_cb, {
+ pmap_foreach_value(&ui_event_cbs, event_cb, {
if (event_cb->ext_widgets[i]) {
ui_cb_ext[i] = true;
break;
@@ -710,9 +710,9 @@ void ui_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets)
event_cb->ext_widgets[kUICmdline] = true;
}
- UIEventCallback **item = (UIEventCallback **)pmap_ref(uint32_t)(&ui_event_cbs, ns_id, true);
+ ptr_t *item = pmap_put_ref(uint32_t)(&ui_event_cbs, ns_id, NULL, NULL);
if (*item) {
- free_ui_event_callback(*item);
+ free_ui_event_callback((UIEventCallback *)(*item));
}
*item = event_cb;
@@ -723,8 +723,8 @@ void ui_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets)
void ui_remove_cb(uint32_t ns_id)
{
if (pmap_has(uint32_t)(&ui_event_cbs, ns_id)) {
- free_ui_event_callback(pmap_get(uint32_t)(&ui_event_cbs, ns_id));
- pmap_del(uint32_t)(&ui_event_cbs, ns_id);
+ UIEventCallback *item = pmap_del(uint32_t)(&ui_event_cbs, ns_id, NULL);
+ free_ui_event_callback(item);
}
ui_cb_update_ext();
ui_refresh();
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index b93b31f7dc..1918b0b800 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -83,11 +83,11 @@ void ui_client_attach(int width, int height, char *term)
PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true));
if (term) {
- PUT_C(opts, "term_name", STRING_OBJ(cstr_as_string(term)));
+ PUT_C(opts, "term_name", CSTR_AS_OBJ(term));
}
if (ui_client_bg_response != kNone) {
bool is_dark = (ui_client_bg_response == kTrue);
- PUT_C(opts, "term_background", STRING_OBJ(cstr_as_string(is_dark ? "dark" : "light")));
+ PUT_C(opts, "term_background", CSTR_AS_OBJ(is_dark ? "dark" : "light"));
}
PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors));
if (!ui_client_is_remote) {
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 35f46e512d..1eb73d85d7 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -120,6 +120,7 @@
#include "nvim/path.h"
#include "nvim/pos.h"
#include "nvim/sha256.h"
+#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/types.h"
@@ -2372,6 +2373,12 @@ static void u_undoredo(int undo, bool do_buf_event)
}
changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event);
+ // When text has been changed, possibly the start of the next line
+ // may have SpellCap that should be removed or it needs to be
+ // displayed. Schedule the next line for redrawing just in case.
+ if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) {
+ redrawWinline(curwin, bot);
+ }
// Set the '[ mark.
if (top + 1 < curbuf->b_op_start.lnum) {
@@ -2667,7 +2674,7 @@ void ex_undolist(exarg_T *eap)
undo_fmt_time(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), uhp->uh_time);
if (uhp->uh_save_nr > 0) {
while (strlen(IObuff) < 33) {
- STRCAT(IObuff, " ");
+ xstrlcat(IObuff, " ", IOSIZE);
}
vim_snprintf_add(IObuff, IOSIZE, " %3ld", uhp->uh_save_nr);
}
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index 11f2620aaa..c56b241988 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -1754,8 +1754,8 @@ Dictionary commands_array(buf_T *buf)
Dictionary d = ARRAY_DICT_INIT;
ucmd_T *cmd = USER_CMD_GA(gap, i);
- PUT(d, "name", STRING_OBJ(cstr_to_string(cmd->uc_name)));
- PUT(d, "definition", STRING_OBJ(cstr_to_string(cmd->uc_rep)));
+ PUT(d, "name", CSTR_TO_OBJ(cmd->uc_name));
+ PUT(d, "definition", CSTR_TO_OBJ(cmd->uc_rep));
PUT(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid));
PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG)));
PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR)));
@@ -1775,21 +1775,21 @@ Dictionary commands_array(buf_T *buf)
case (EX_EXTRA | EX_NOSPC | EX_NEEDARG):
arg[0] = '1'; break;
}
- PUT(d, "nargs", STRING_OBJ(cstr_to_string(arg)));
+ PUT(d, "nargs", CSTR_TO_OBJ(arg));
char *cmd_compl = get_command_complete(cmd->uc_compl);
PUT(d, "complete", (cmd_compl == NULL
- ? NIL : STRING_OBJ(cstr_to_string(cmd_compl))));
+ ? NIL : CSTR_TO_OBJ(cmd_compl)));
PUT(d, "complete_arg", cmd->uc_compl_arg == NULL
- ? NIL : STRING_OBJ(cstr_to_string(cmd->uc_compl_arg)));
+ ? NIL : CSTR_TO_OBJ(cmd->uc_compl_arg));
Object obj = NIL;
if (cmd->uc_argt & EX_COUNT) {
if (cmd->uc_def >= 0) {
snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def);
- obj = STRING_OBJ(cstr_to_string(str)); // -count=N
+ obj = CSTR_TO_OBJ(str); // -count=N
} else {
- obj = STRING_OBJ(cstr_to_string("0")); // -count
+ obj = CSTR_TO_OBJ("0"); // -count
}
}
PUT(d, "count", obj);
@@ -1797,12 +1797,12 @@ Dictionary commands_array(buf_T *buf)
obj = NIL;
if (cmd->uc_argt & EX_RANGE) {
if (cmd->uc_argt & EX_DFLALL) {
- obj = STRING_OBJ(cstr_to_string("%")); // -range=%
+ obj = CSTR_TO_OBJ("%"); // -range=%
} else if (cmd->uc_def >= 0) {
snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def);
- obj = STRING_OBJ(cstr_to_string(str)); // -range=N
+ obj = CSTR_TO_OBJ(str); // -range=N
} else {
- obj = STRING_OBJ(cstr_to_string(".")); // -range
+ obj = CSTR_TO_OBJ("."); // -range
}
}
PUT(d, "range", obj);
@@ -1811,7 +1811,7 @@ Dictionary commands_array(buf_T *buf)
for (int j = 0; addr_type_complete[j].expand != ADDR_NONE; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
- obj = STRING_OBJ(cstr_to_string(addr_type_complete[j].name));
+ obj = CSTR_TO_OBJ(addr_type_complete[j].name);
break;
}
}
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index d1c6426cba..830d8c5f34 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -2866,7 +2866,7 @@ viml_pexpr_parse_no_paren_closing_error: {}
case kENodeOperator:
if (prev_token.type == kExprLexSpacing) {
// For some reason "function (args)" is a function call, but
- // "(funcref) (args)" is not. AFAIR this somehow involves
+ // "(funcref) (args)" is not. As far as I remember this somehow involves
// compatibility and Bram was commenting that this is
// intentionally inconsistent and he is not very happy with the
// situation himself.
diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h
index 6fe6a784a0..245f4c500c 100644
--- a/src/nvim/viml/parser/expressions.h
+++ b/src/nvim/viml/parser/expressions.h
@@ -5,7 +5,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/types.h"
#include "nvim/viml/parser/parser.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index fd6755a382..90c8ba92f9 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -139,6 +139,32 @@ win_T *prevwin_curwin(void)
return is_in_cmdwin() && prevwin != NULL ? prevwin : curwin;
}
+/// If the 'switchbuf' option contains "useopen" or "usetab", then try to jump
+/// to a window containing "buf".
+/// Returns the pointer to the window that was jumped to or NULL.
+win_T *swbuf_goto_win_with_buf(buf_T *buf)
+{
+ win_T *wp = NULL;
+
+ if (buf == NULL) {
+ return wp;
+ }
+
+ // If 'switchbuf' contains "useopen": jump to first window in the current
+ // tab page containing "buf" if one exists.
+ if (swb_flags & SWB_USEOPEN) {
+ wp = buf_jump_open_win(buf);
+ }
+
+ // If 'switchbuf' contains "usetab": jump to first window in any tab page
+ // containing "buf" if one exists.
+ if (wp == NULL && (swb_flags & SWB_USETAB)) {
+ wp = buf_jump_open_tab(buf);
+ }
+
+ return wp;
+}
+
/// all CTRL-W window commands are handled here, called from normal_cmd().
///
/// @param xchar extra char from ":wincmd gx" or NUL
@@ -514,18 +540,31 @@ wingotofile:
tabpage_T *oldtab = curtab;
win_T *oldwin = curwin;
setpcmark();
- if (win_split(0, 0) == OK) {
+
+ // If 'switchbuf' is set to 'useopen' or 'usetab' and the
+ // file is already opened in a window, then jump to it.
+ win_T *wp = NULL;
+ if ((swb_flags & (SWB_USEOPEN | SWB_USETAB))
+ && cmdmod.cmod_tab == 0) {
+ wp = swbuf_goto_win_with_buf(buflist_findname_exp(ptr));
+ }
+
+ if (wp == NULL && win_split(0, 0) == OK) {
RESET_BINDING(curwin);
if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
// Failed to open the file, close the window opened for it.
win_close(curwin, false, false);
goto_tabpage_win(oldtab, oldwin);
- } else if (nchar == 'F' && lnum >= 0) {
- curwin->w_cursor.lnum = lnum;
- check_cursor_lnum();
- beginline(BL_SOL | BL_FIX);
+ } else {
+ wp = curwin;
}
}
+
+ if (wp != NULL && nchar == 'F' && lnum >= 0) {
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_SOL | BL_FIX);
+ }
xfree(ptr);
}
break;
@@ -2278,6 +2317,9 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
}
if (hnc) { // add next_curwin size
next_curwin_size -= (int)p_wiw - (m - n);
+ if (next_curwin_size < 0) {
+ next_curwin_size = 0;
+ }
new_size += next_curwin_size;
room -= new_size - next_curwin_size;
} else {
@@ -4035,7 +4077,7 @@ static tabpage_T *alloc_tabpage(void)
static int last_tp_handle = 0;
tabpage_T *tp = xcalloc(1, sizeof(tabpage_T));
tp->handle = ++last_tp_handle;
- pmap_put(handle_T)(&tabpage_handles, tp->handle, tp);
+ pmap_put(int)(&tabpage_handles, tp->handle, tp);
// Init t: variables.
tp->tp_vars = tv_dict_alloc();
@@ -4048,7 +4090,7 @@ static tabpage_T *alloc_tabpage(void)
void free_tabpage(tabpage_T *tp)
{
- pmap_del(handle_T)(&tabpage_handles, tp->handle);
+ pmap_del(int)(&tabpage_handles, tp->handle, NULL);
diff_clear(tp);
for (int idx = 0; idx < SNAP_COUNT; idx++) {
clear_snapshot(tp, idx);
@@ -5020,7 +5062,7 @@ static win_T *win_alloc(win_T *after, bool hidden)
win_T *new_wp = xcalloc(1, sizeof(win_T));
new_wp->handle = ++last_win_id;
- pmap_put(handle_T)(&window_handles, new_wp->handle, new_wp);
+ pmap_put(int)(&window_handles, new_wp->handle, new_wp);
grid_assign_handle(&new_wp->w_grid_alloc);
@@ -5082,7 +5124,7 @@ void free_wininfo(wininfo_T *wip, buf_T *bp)
/// @param tp tab page "win" is in, NULL for current
static void win_free(win_T *wp, tabpage_T *tp)
{
- pmap_del(handle_T)(&window_handles, wp->handle);
+ pmap_del(int)(&window_handles, wp->handle, NULL);
clearFolding(wp);
// reduce the reference count to the argument list.
@@ -6660,7 +6702,8 @@ static int win_border_width(win_T *wp)
/// Set the width of a window.
void win_new_width(win_T *wp, int width)
{
- wp->w_width = width;
+ // Should we give an error if width < 0?
+ wp->w_width = width < 0 ? 0 : width;
wp->w_pos_changed = true;
win_set_inner_size(wp, true);
}
diff --git a/src/nvim/window.h b/src/nvim/window.h
index 4ab2bea60a..9201800d53 100644
--- a/src/nvim/window.h
+++ b/src/nvim/window.h
@@ -4,13 +4,9 @@
#include <stdbool.h>
#include <stddef.h>
-#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/macros.h"
-#include "nvim/mark.h"
-#include "nvim/os/os.h"
-#include "nvim/os/os_defs.h"
-#include "nvim/vim.h"
+#include "nvim/option_defs.h"
// Values for file_name_in_line()
#define FNAME_MESS 1 // give error message
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
index 5934c088df..32cf173741 100644
--- a/src/uncrustify.cfg
+++ b/src/uncrustify.cfg
@@ -1,4 +1,4 @@
-# Uncrustify-0.76.0_f
+# Uncrustify-0.77.1_f
#
# General options
@@ -195,6 +195,11 @@ sp_before_ptr_star = force # ignore/add/remove/force/not_defined
# variable name. If set to ignore, sp_before_ptr_star is used instead.
sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between a qualifier and a pointer star '*' that isn't
+# followed by a variable name, as in '(char const *)'. If set to ignore,
+# sp_before_ptr_star is used instead.
+sp_qualifier_unnamed_ptr_star = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space between pointer stars '*', as in 'int ***a;'.
sp_between_ptr_star = ignore # ignore/add/remove/force/not_defined
@@ -232,13 +237,24 @@ sp_ptr_star_func_type = ignore # ignore/add/remove/force/not_defined
sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined
# Add or remove space before a pointer star '*', if followed by a function
-# prototype or function definition.
+# prototype or function definition. If set to ignore, sp_before_ptr_star is
+# used instead.
sp_before_ptr_star_func = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between a qualifier and a pointer star '*' followed by
+# the name of the function in a function prototype or definition, as in
+# 'char const *foo()`. If set to ignore, sp_before_ptr_star is used instead.
+sp_qualifier_ptr_star_func = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space before a pointer star '*' in the trailing return of a
# function prototype or function definition.
sp_before_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between a qualifier and a pointer star '*' in the
+# trailing return of a function prototype or function definition, as in
+# 'auto foo() -> char const *'.
+sp_qualifier_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space before a reference sign '&'.
sp_before_byref = ignore # ignore/add/remove/force/not_defined
@@ -628,6 +644,16 @@ sp_inside_fparens = remove # ignore/add/remove/force/not_defined
# Add or remove space inside function '(' and ')'.
sp_inside_fparen = remove # ignore/add/remove/force/not_defined
+# Add or remove space inside user functor '(' and ')'.
+sp_func_call_user_inside_rparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside empty functor '()'.
+# Overrides sp_after_angle unless use_sp_after_angle_always is set to true.
+sp_inside_rparens = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside functor '(' and ')'.
+sp_inside_rparen = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space inside the first parentheses in a function type, as in
# 'void (*x)(...)'.
sp_inside_tparen = remove # ignore/add/remove/force/not_defined
@@ -967,6 +993,14 @@ sp_extern_paren = ignore # ignore/add/remove/force/not_defined
# Add or remove space after the opening of a C++ comment, as in '// <here> A'.
sp_cmt_cpp_start = ignore # ignore/add/remove/force/not_defined
+# remove space after the '//' and the pvs command '-V1234',
+# only works with sp_cmt_cpp_start set to add or force.
+sp_cmt_cpp_pvs = false # true/false
+
+# remove space after the '//' and the command 'lint',
+# only works with sp_cmt_cpp_start set to add or force.
+sp_cmt_cpp_lint = false # true/false
+
# Add or remove space in a C++ region marker comment, as in '// <here> BEGIN'.
# A region marker is defined as a comment which is not preceded by other text
# (i.e. the comment is the first non-whitespace on the line), and which starts
@@ -2833,9 +2867,16 @@ align_single_line_brace_gap = 0 # unsigned number
# 0: Don't align (default).
align_oc_msg_spec_span = 0 # unsigned number
-# Whether to align macros wrapped with a backslash and a newline. This will
-# not work right if the macro contains a multi-line comment.
-align_nl_cont = false # true/false
+# Whether and how to align backslashes that split a macro onto multiple lines.
+# This will not work right if the macro contains a multi-line comment.
+#
+# 0: Do nothing (default)
+# 1: Align the backslashes in the column at the end of the longest line
+# 2: Align with the backslash that is farthest to the left, or, if that
+# backslash is farther left than the end of the longest line, at the end of
+# the longest line
+# 3: Align with the backslash that is farthest to the right
+align_nl_cont = 0 # unsigned number
# Whether to align macro functions and variables together.
align_pp_define_together = false # true/false
@@ -3146,6 +3187,12 @@ mod_remove_extra_semicolon = true # true/false
# Whether to remove duplicate include.
mod_remove_duplicate_include = true # true/false
+# the following options (mod_XX_closebrace_comment) use different comment,
+# depending of the setting of the next option.
+# false: Use the c comment (default)
+# true : Use the cpp comment
+mod_add_force_c_closebrace_comment = false # true/false
+
# If a function body exceeds the specified number of newlines and doesn't have
# a comment after the close brace, a comment will be added.
mod_add_long_function_closebrace_comment = 0 # unsigned number