aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py17
-rw-r--r--src/nvim/api/buffer.c38
-rw-r--r--src/nvim/api/private/helpers.c4
-rw-r--r--src/nvim/api/tabpage.c14
-rw-r--r--src/nvim/api/ui.c12
-rw-r--r--src/nvim/api/ui_events.in.h56
-rw-r--r--src/nvim/api/vim.c86
-rw-r--r--src/nvim/api/window.c32
-rw-r--r--src/nvim/buffer.c211
-rw-r--r--src/nvim/buffer.h8
-rw-r--r--src/nvim/buffer_defs.h24
-rw-r--r--src/nvim/bufhl_defs.h23
-rw-r--r--src/nvim/charset.c55
-rw-r--r--src/nvim/cursor_shape.c2
-rw-r--r--src/nvim/diff.c2
-rw-r--r--src/nvim/eval.c281
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/decode.c8
-rw-r--r--src/nvim/eval/executor.c6
-rw-r--r--src/nvim/eval/typval.c29
-rw-r--r--src/nvim/eval/typval.h13
-rw-r--r--src/nvim/event/loop.c21
-rw-r--r--src/nvim/event/socket.c12
-rw-r--r--src/nvim/ex_cmds.c42
-rw-r--r--src/nvim/ex_docmd.c21
-rw-r--r--src/nvim/ex_getln.c296
-rw-r--r--src/nvim/fileio.c39
-rw-r--r--src/nvim/fold.c2
-rw-r--r--src/nvim/func_attr.h18
-rw-r--r--src/nvim/garray.h2
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/globals.h151
-rw-r--r--src/nvim/highlight_defs.h126
-rw-r--r--src/nvim/indent.c4
-rw-r--r--src/nvim/indent_c.c39
-rw-r--r--src/nvim/keymap.c2
-rw-r--r--src/nvim/lib/kbtree.h451
-rw-r--r--src/nvim/log.c106
-rw-r--r--src/nvim/log.h74
-rw-r--r--src/nvim/lua/executor.c73
-rw-r--r--src/nvim/lua/vim.lua64
-rw-r--r--src/nvim/main.c30
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/mark.c19
-rw-r--r--src/nvim/mark.h3
-rw-r--r--src/nvim/mbyte.c85
-rw-r--r--src/nvim/memfile.c20
-rw-r--r--src/nvim/memline.c9
-rw-r--r--src/nvim/message.c161
-rw-r--r--src/nvim/misc1.c6
-rw-r--r--src/nvim/msgpack_rpc/channel.c12
-rw-r--r--src/nvim/msgpack_rpc/server.c4
-rw-r--r--src/nvim/normal.c11
-rw-r--r--src/nvim/ops.c70
-rw-r--r--src/nvim/option.c52
-rw-r--r--src/nvim/options.lua4
-rw-r--r--src/nvim/os/fileio.c76
-rw-r--r--src/nvim/os/fs.c4
-rw-r--r--src/nvim/os/os_defs.h7
-rw-r--r--src/nvim/os/shell.c10
-rw-r--r--src/nvim/os/win_defs.h10
-rw-r--r--src/nvim/os_unix.c6
-rw-r--r--src/nvim/popupmnu.c8
-rw-r--r--src/nvim/quickfix.c12
-rw-r--r--src/nvim/regexp.c7
-rw-r--r--src/nvim/screen.c419
-rw-r--r--src/nvim/search.c7
-rw-r--r--src/nvim/shada.c12
-rw-r--r--src/nvim/spell.c12
-rw-r--r--src/nvim/strings.c9
-rw-r--r--src/nvim/syntax.c17
-rw-r--r--src/nvim/syntax_defs.h3
-rw-r--r--src/nvim/tag.c86
-rw-r--r--src/nvim/terminal.c10
-rw-r--r--src/nvim/testdir/Makefile4
-rw-r--r--src/nvim/testdir/runtest.vim116
-rw-r--r--src/nvim/testdir/shared.vim2
-rw-r--r--src/nvim/testdir/test49.vim2
-rw-r--r--src/nvim/testdir/test_alot.vim2
-rw-r--r--src/nvim/testdir/test_cscope.vim2
-rw-r--r--src/nvim/testdir/test_cursor_func.vim8
-rw-r--r--src/nvim/testdir/test_expr.vim31
-rw-r--r--src/nvim/testdir/test_float_func.vim332
-rw-r--r--src/nvim/testdir/test_functions.vim19
-rw-r--r--src/nvim/testdir/test_largefile.vim34
-rw-r--r--src/nvim/testdir/test_menu.vim2
-rw-r--r--src/nvim/testdir/test_popup.vim2
-rw-r--r--src/nvim/testdir/test_search.vim285
-rw-r--r--src/nvim/testdir/test_startup.vim2
-rw-r--r--src/nvim/testdir/test_stat.vim64
-rw-r--r--src/nvim/testdir/test_vimscript.vim (renamed from src/nvim/testdir/test_viml.vim)151
-rw-r--r--src/nvim/undo.c8
-rw-r--r--src/nvim/version.c30
-rw-r--r--src/nvim/window.c4
95 files changed, 3434 insertions, 1346 deletions
diff --git a/src/clint.py b/src/clint.py
index 3babb7772b..69a061d2ab 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -2529,6 +2529,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
r'(?<!\bklist_t)'
r'(?<!\bkliter_t)'
r'(?<!\bkhash_t)'
+ r'(?<!\bkbtree_t)'
+ r'(?<!\bkbitr_t)'
r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)'
r' +'
r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line)
@@ -2600,16 +2602,23 @@ def CheckBraces(filename, clean_lines, linenum, error):
else:
func_start_linenum = end_linenum + 1
while not clean_lines.lines[func_start_linenum] == '{':
- if not Match(r'^(?:\s*\b(?:FUNC_ATTR|REAL_FATTR)_\w+\b(?:\(\d+(, \d+)*\))?)+$',
- clean_lines.lines[func_start_linenum]):
+ attrline = Match(r'^((?!# *define).*?)(?:FUNC_ATTR|FUNC_API|REAL_FATTR)_\w+(?:\(\d+(, \d+)*\))?',
+ clean_lines.lines[func_start_linenum])
+ if attrline:
+ if len(attrline.group(1)) != 2:
+ error(filename, func_start_linenum,
+ 'whitespace/indent', 5,
+ 'Function attribute line should have 2-space '
+ 'indent')
+
+ func_start_linenum += 1
+ else:
if clean_lines.lines[func_start_linenum].endswith('{'):
error(filename, func_start_linenum,
'readability/braces', 5,
'Brace starting function body must be placed '
'after the function signature')
break
- else:
- func_start_linenum += 1
# An else clause should be on the same line as the preceding closing brace.
# If there is no preceding closing brace, there should be one.
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index fc11708bd6..82de8fd4a2 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -35,7 +35,7 @@
/// @param[out] err Error details, if any
/// @return Line count
Integer nvim_buf_line_count(Buffer buffer, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -157,7 +157,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
Integer end,
Boolean strict_indexing,
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -270,7 +270,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
Boolean strict_indexing,
ArrayOf(String) replacement, // NOLINT
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -330,7 +330,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
}
try_start();
- bufref_T save_curbuf = { NULL, 0 };
+ bufref_T save_curbuf = { NULL, 0, 0 };
switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
if (u_save((linenr_T)(start - 1), (linenr_T)end) == FAIL) {
@@ -399,7 +399,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
// Only adjust marks if we managed to switch to a window that holds
// the buffer, otherwise line numbers will be invalid.
if (save_curbuf.br_buf == NULL) {
- mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra);
+ mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra, false);
}
changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra);
@@ -425,7 +425,7 @@ end:
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -442,7 +442,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
///
/// @return `b:changedtick` value.
Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
- FUNC_API_SINCE(2)
+ FUNC_API_SINCE(2)
{
const buf_T *const buf = find_buffer_by_handle(buffer, err);
@@ -480,7 +480,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
/// @param value Variable value
/// @param[out] err Error details, if any
void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -497,7 +497,7 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
void nvim_buf_del_var(Buffer buffer, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -558,7 +558,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
/// @param[out] err Error details, if any
/// @return Option value
Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -577,7 +577,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
/// @param value Option value
/// @param[out] err Error details, if any
void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -597,8 +597,8 @@ void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
/// @param[out] err Error details, if any
/// @return Buffer number
Integer nvim_buf_get_number(Buffer buffer, Error *err)
- FUNC_API_SINCE(1)
- FUNC_API_DEPRECATED_SINCE(2)
+ FUNC_API_SINCE(1)
+ FUNC_API_DEPRECATED_SINCE(2)
{
Integer rv = 0;
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -616,7 +616,7 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err)
/// @param[out] err Error details, if any
/// @return Buffer name
String nvim_buf_get_name(Buffer buffer, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
String rv = STRING_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -634,7 +634,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err)
/// @param name Buffer name
/// @param[out] err Error details, if any
void nvim_buf_set_name(Buffer buffer, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -664,7 +664,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
/// @param buffer Buffer handle
/// @return true if the buffer is valid, false otherwise
Boolean nvim_buf_is_valid(Buffer buffer)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Error stub = ERROR_INIT;
Boolean ret = find_buffer_by_handle(buffer, &stub) != NULL;
@@ -698,7 +698,7 @@ void buffer_insert(Buffer buffer,
/// @param[out] err Error details, if any
/// @return (row, col) tuple
ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -774,7 +774,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
Integer col_start,
Integer col_end,
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
@@ -815,7 +815,7 @@ void nvim_buf_clear_highlight(Buffer buffer,
Integer line_start,
Integer line_end,
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index ef789b3ed4..1ed2bc013e 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -95,7 +95,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di == NULL) {
- api_set_error(err, kErrorTypeValidation, "Key not found");
+ api_set_error(err, kErrorTypeValidation, "Key '%s' not found", key.data);
return (Object)OBJECT_INIT;
}
@@ -961,7 +961,7 @@ static void set_option_value_for(char *key,
{
win_T *save_curwin = NULL;
tabpage_T *save_curtab = NULL;
- bufref_T save_curbuf = { NULL, 0 };
+ bufref_T save_curbuf = { NULL, 0, 0 };
try_start();
switch (opt_type)
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 6f2f9e1d2a..b6830d9fcf 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -18,7 +18,7 @@
/// @param[out] err Error details, if any
/// @return List of windows in `tabpage`
ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -48,7 +48,7 @@ ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -69,7 +69,7 @@ void nvim_tabpage_set_var(Tabpage tabpage,
String name,
Object value,
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -86,7 +86,7 @@ void nvim_tabpage_set_var(Tabpage tabpage,
/// @param name Variable name
/// @param[out] err Error details, if any
void nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -145,7 +145,7 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
/// @param[out] err Error details, if any
/// @return Window handle
Window nvim_tabpage_get_win(Tabpage tabpage, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Window rv = 0;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -173,7 +173,7 @@ Window nvim_tabpage_get_win(Tabpage tabpage, Error *err)
/// @param[out] err Error details, if any
/// @return Tabpage number
Integer nvim_tabpage_get_number(Tabpage tabpage, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Integer rv = 0;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -190,7 +190,7 @@ Integer nvim_tabpage_get_number(Tabpage tabpage, Error *err)
/// @param tabpage Tabpage handle
/// @return true if the tabpage is valid, false otherwise
Boolean nvim_tabpage_is_valid(Tabpage tabpage)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Error stub = ERROR_INIT;
Boolean ret = find_tab_by_handle(tabpage, &stub) != NULL;
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 1b29f2fc78..573be23d8e 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -30,13 +30,13 @@ typedef struct {
static PMap(uint64_t) *connected_uis = NULL;
void remote_ui_init(void)
- FUNC_API_NOEXPORT
+ FUNC_API_NOEXPORT
{
connected_uis = pmap_new(uint64_t)();
}
void remote_ui_disconnect(uint64_t channel_id)
- FUNC_API_NOEXPORT
+ FUNC_API_NOEXPORT
{
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
if (!ui) {
@@ -53,7 +53,7 @@ void remote_ui_disconnect(uint64_t channel_id)
void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
Dictionary options, Error *err)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI already attached for channel");
@@ -125,7 +125,7 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height,
}
void nvim_ui_detach(uint64_t channel_id, Error *err)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI is not attached for channel");
@@ -137,7 +137,7 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
void nvim_ui_try_resize(uint64_t channel_id, Integer width,
Integer height, Error *err)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI is not attached for channel");
@@ -158,7 +158,7 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
void nvim_ui_set_option(uint64_t channel_id, String name,
Object value, Error *error)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(error, kErrorTypeException, "UI is not attached for channel");
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 45d04335e4..1b5d17584f 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -11,61 +11,61 @@
#include "nvim/ui.h"
void resize(Integer rows, Integer columns)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void clear(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void eol_clear(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void cursor_goto(Integer row, Integer col)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void mode_info_set(Boolean enabled, Array cursor_styles)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void update_menu(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void busy_start(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void busy_stop(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void mouse_on(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void mouse_off(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void mode_change(String mode, Integer mode_idx)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void set_scroll_region(Integer top, Integer bot, Integer left, Integer right)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void scroll(Integer count)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void highlight_set(HlAttrs attrs)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
void put(String str)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void bell(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void visual_bell(void)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void flush(void)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
void update_fg(Integer fg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void update_bg(Integer bg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void update_sp(Integer sp)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void suspend(void)
- FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void set_title(String title)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void set_icon(String icon)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3);
void popupmenu_show(Array items, Integer selected, Integer row, Integer col)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void popupmenu_hide(void)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void popupmenu_select(Integer selected)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void tabline_update(Tabpage current, Array tabs)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
#endif // NVIM_API_UI_EVENTS_IN_H
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 0cffb2c87d..80efe86ea3 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -13,6 +13,7 @@
#include "nvim/ascii.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/buffer.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/lua/executor.h"
@@ -45,7 +46,7 @@
/// @param command Ex-command string
/// @param[out] err Error details (including actual VimL error), if any
void nvim_command(String command, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
// Run the command
try_start();
@@ -63,7 +64,7 @@ void nvim_command(String command, Error *err)
/// @see feedkeys()
/// @see vim_strsave_escape_csi
void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
bool remap = true;
bool insert = false;
@@ -130,7 +131,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
/// @return Number of bytes actually written (can be fewer than
/// requested if the buffer becomes full).
Integer nvim_input(String keys)
- FUNC_API_SINCE(1) FUNC_API_ASYNC
+ FUNC_API_SINCE(1) FUNC_API_ASYNC
{
return (Integer)input_enqueue(keys);
}
@@ -142,7 +143,7 @@ Integer nvim_input(String keys)
/// @see cpoptions
String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
Boolean special)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
if (str.size == 0) {
// Empty string
@@ -162,7 +163,7 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
}
String nvim_command_output(String str, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
do_cmdline_cmd("redir => v:command_output");
nvim_command(str, err);
@@ -183,7 +184,7 @@ String nvim_command_output(String str, Error *err)
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
Object nvim_eval(String expr, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Object rv = OBJECT_INIT;
// Evaluate the expression
@@ -214,7 +215,7 @@ Object nvim_eval(String expr, Error *err)
/// @param[out] err Error details, if any
/// @return Result of the function call
Object nvim_call_function(String fname, Array args, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Object rv = OBJECT_INIT;
if (args.size > MAX_FUNC_ARGS) {
@@ -282,7 +283,7 @@ Object nvim_execute_lua(String code, Array args, Error *err)
/// @param[out] err Error details, if any
/// @return Number of cells
Integer nvim_strwidth(String str, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
if (str.size > INT_MAX) {
api_set_error(err, kErrorTypeValidation, "String length is too high");
@@ -296,10 +297,10 @@ Integer nvim_strwidth(String str, Error *err)
///
/// @return List of paths
ArrayOf(String) nvim_list_runtime_paths(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
- uint8_t *rtp = p_rtp;
+ char_u *rtp = p_rtp;
if (*rtp == NUL) {
// No paths
@@ -313,13 +314,14 @@ ArrayOf(String) nvim_list_runtime_paths(void)
}
rtp++;
}
+ rv.size++;
// Allocate memory for the copies
- rv.items = xmalloc(sizeof(Object) * rv.size);
+ rv.items = xmalloc(sizeof(*rv.items) * rv.size);
// Reset the position
rtp = p_rtp;
// Start copying
- for (size_t i = 0; i < rv.size && *rtp != NUL; i++) {
+ for (size_t i = 0; i < rv.size; i++) {
rv.items[i].type = kObjectTypeString;
rv.items[i].data.string.data = xmalloc(MAXPATHL);
// Copy the path from 'runtimepath' to rv.items[i]
@@ -338,7 +340,7 @@ ArrayOf(String) nvim_list_runtime_paths(void)
/// @param dir Directory path
/// @param[out] err Error details, if any
void nvim_set_current_dir(String dir, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
if (dir.size >= MAXPATHL) {
api_set_error(err, kErrorTypeValidation, "Directory string is too long");
@@ -367,7 +369,7 @@ void nvim_set_current_dir(String dir, Error *err)
/// @param[out] err Error details, if any
/// @return Current line string
String nvim_get_current_line(Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return buffer_get_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
}
@@ -377,7 +379,7 @@ String nvim_get_current_line(Error *err)
/// @param line Line contents
/// @param[out] err Error details, if any
void nvim_set_current_line(String line, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err);
}
@@ -386,7 +388,7 @@ void nvim_set_current_line(String line, Error *err)
///
/// @param[out] err Error details, if any
void nvim_del_current_line(Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
}
@@ -397,7 +399,7 @@ void nvim_del_current_line(Error *err)
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_get_var(String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return dict_get_value(&globvardict, name, err);
}
@@ -408,7 +410,7 @@ Object nvim_get_var(String name, Error *err)
/// @param value Variable value
/// @param[out] err Error details, if any
void nvim_set_var(String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
dict_set_var(&globvardict, name, value, false, false, err);
}
@@ -418,7 +420,7 @@ void nvim_set_var(String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
void nvim_del_var(String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
dict_set_var(&globvardict, name, NIL, true, false, err);
}
@@ -457,7 +459,7 @@ Object vim_del_var(String name, Error *err)
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_get_vvar(String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return dict_get_value(&vimvardict, name, err);
}
@@ -468,7 +470,7 @@ Object nvim_get_vvar(String name, Error *err)
/// @param[out] err Error details, if any
/// @return Option value (global)
Object nvim_get_option(String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return get_option_from(NULL, SREQ_GLOBAL, name, err);
}
@@ -479,7 +481,7 @@ Object nvim_get_option(String name, Error *err)
/// @param value New option value
/// @param[out] err Error details, if any
void nvim_set_option(String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
@@ -488,7 +490,7 @@ void nvim_set_option(String name, Object value, Error *err)
///
/// @param str Message
void nvim_out_write(String str)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
write_msg(str, false);
}
@@ -497,7 +499,7 @@ void nvim_out_write(String str)
///
/// @param str Message
void nvim_err_write(String str)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
write_msg(str, true);
}
@@ -508,7 +510,7 @@ void nvim_err_write(String str)
/// @param str Message
/// @see nvim_err_write()
void nvim_err_writeln(String str)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
nvim_err_write(str);
nvim_err_write((String) { .data = "\n", .size = 1 });
@@ -518,7 +520,7 @@ void nvim_err_writeln(String str)
///
/// @return List of buffer handles
ArrayOf(Buffer) nvim_list_bufs(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@@ -540,7 +542,7 @@ ArrayOf(Buffer) nvim_list_bufs(void)
///
/// @return Buffer handle
Buffer nvim_get_current_buf(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return curbuf->handle;
}
@@ -550,7 +552,7 @@ Buffer nvim_get_current_buf(void)
/// @param id Buffer handle
/// @param[out] err Error details, if any
void nvim_set_current_buf(Buffer buffer, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -572,7 +574,7 @@ void nvim_set_current_buf(Buffer buffer, Error *err)
///
/// @return List of window handles
ArrayOf(Window) nvim_list_wins(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@@ -594,7 +596,7 @@ ArrayOf(Window) nvim_list_wins(void)
///
/// @return Window handle
Window nvim_get_current_win(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return curwin->handle;
}
@@ -603,7 +605,7 @@ Window nvim_get_current_win(void)
///
/// @param handle Window handle
void nvim_set_current_win(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -625,7 +627,7 @@ void nvim_set_current_win(Window window, Error *err)
///
/// @return List of tabpage handles
ArrayOf(Tabpage) nvim_list_tabpages(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@@ -647,7 +649,7 @@ ArrayOf(Tabpage) nvim_list_tabpages(void)
///
/// @return Tabpage handle
Tabpage nvim_get_current_tabpage(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
return curtab->handle;
}
@@ -657,7 +659,7 @@ Tabpage nvim_get_current_tabpage(void)
/// @param handle Tabpage handle
/// @param[out] err Error details, if any
void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
tabpage_T *tp = find_tab_by_handle(tabpage, err);
@@ -680,7 +682,7 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
/// @param channel_id Channel id (passed automatically by the dispatcher)
/// @param event Event type string
void nvim_subscribe(uint64_t channel_id, String event)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
size_t length = (event.size < METHOD_MAXLEN ? event.size : METHOD_MAXLEN);
char e[METHOD_MAXLEN + 1];
@@ -694,7 +696,7 @@ void nvim_subscribe(uint64_t channel_id, String event)
/// @param channel_id Channel id (passed automatically by the dispatcher)
/// @param event Event type string
void nvim_unsubscribe(uint64_t channel_id, String event)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
size_t length = (event.size < METHOD_MAXLEN ?
event.size :
@@ -706,13 +708,13 @@ void nvim_unsubscribe(uint64_t channel_id, String event)
}
Integer nvim_get_color_by_name(String name)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
- return name_to_color((uint8_t *)name.data);
+ return name_to_color((char_u *)name.data);
}
Dictionary nvim_get_color_map(void)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Dictionary colors = ARRAY_DICT_INIT;
@@ -754,7 +756,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
}
Array nvim_get_api_info(uint64_t channel_id)
- FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY
{
Array rv = ARRAY_DICT_INIT;
@@ -787,7 +789,7 @@ Array nvim_get_api_info(uint64_t channel_id)
/// which resulted in an error, the error type and the error message. If an
/// error ocurred, the values from all preceding calls will still be returned.
Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
- FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
Array rv = ARRAY_DICT_INIT;
Array results = ARRAY_DICT_INIT;
@@ -870,7 +872,7 @@ static void write_msg(String message, bool to_err)
#define PUSH_CHAR(i, pos, line_buf, msg) \
if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \
line_buf[pos] = NUL; \
- msg((uint8_t *)line_buf); \
+ msg((char_u *)line_buf); \
pos = 0; \
continue; \
} \
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 22902800ea..9bc91ef8fb 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -22,7 +22,7 @@
/// @param[out] err Error details, if any
/// @return Buffer handle
Buffer nvim_win_get_buf(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -39,7 +39,7 @@ Buffer nvim_win_get_buf(Window window, Error *err)
/// @param[out] err Error details, if any
/// @return (row, col) tuple
ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
@@ -58,7 +58,7 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
/// @param pos (row, col) tuple representing the new position
/// @param[out] err Error details, if any
void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -105,7 +105,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
/// @param[out] err Error details, if any
/// @return Height as a count of rows
Integer nvim_win_get_height(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -123,7 +123,7 @@ Integer nvim_win_get_height(Window window, Error *err)
/// @param height Height as a count of rows
/// @param[out] err Error details, if any
void nvim_win_set_height(Window window, Integer height, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -150,7 +150,7 @@ void nvim_win_set_height(Window window, Integer height, Error *err)
/// @param[out] err Error details, if any
/// @return Width as a count of columns
Integer nvim_win_get_width(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -168,7 +168,7 @@ Integer nvim_win_get_width(Window window, Error *err)
/// @param width Width as a count of columns
/// @param[out] err Error details, if any
void nvim_win_set_width(Window window, Integer width, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -196,7 +196,7 @@ void nvim_win_set_width(Window window, Integer width, Error *err)
/// @param[out] err Error details, if any
/// @return Variable value
Object nvim_win_get_var(Window window, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -214,7 +214,7 @@ Object nvim_win_get_var(Window window, String name, Error *err)
/// @param value Variable value
/// @param[out] err Error details, if any
void nvim_win_set_var(Window window, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -231,7 +231,7 @@ void nvim_win_set_var(Window window, String name, Object value, Error *err)
/// @param name Variable name
/// @param[out] err Error details, if any
void nvim_win_del_var(Window window, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -291,7 +291,7 @@ Object window_del_var(Window window, String name, Error *err)
/// @param[out] err Error details, if any
/// @return Option value
Object nvim_win_get_option(Window window, String name, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -310,7 +310,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
/// @param value Option value
/// @param[out] err Error details, if any
void nvim_win_set_option(Window window, String name, Object value, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -327,7 +327,7 @@ void nvim_win_set_option(Window window, String name, Object value, Error *err)
/// @param[out] err Error details, if any
/// @return (row, col) tuple with the window position
ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
@@ -346,7 +346,7 @@ ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err)
/// @param[out] err Error details, if any
/// @return Tabpage that contains the window
Tabpage nvim_win_get_tabpage(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Tabpage rv = 0;
win_T *win = find_window_by_handle(window, err);
@@ -364,7 +364,7 @@ Tabpage nvim_win_get_tabpage(Window window, Error *err)
/// @param[out] err Error details, if any
/// @return Window number
Integer nvim_win_get_number(Window window, Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
int rv = 0;
win_T *win = find_window_by_handle(window, err);
@@ -384,7 +384,7 @@ Integer nvim_win_get_number(Window window, Error *err)
/// @param window Window handle
/// @return true if the window is valid, false otherwise
Boolean nvim_win_is_valid(Window window)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(1)
{
Error stub = ERROR_INIT;
Boolean ret = find_window_by_handle(window, &stub) != NULL;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 6abd505ead..b5ca6543c5 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -74,6 +74,12 @@
#include "nvim/os/time.h"
#include "nvim/os/input.h"
+typedef enum {
+ kBLSUnchanged = 0,
+ kBLSChanged = 1,
+ kBLSDeleted = 2,
+} BufhlLineStatus;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.c.generated.h"
#endif
@@ -281,19 +287,22 @@ open_buffer (
void set_bufref(bufref_T *bufref, buf_T *buf)
{
bufref->br_buf = buf;
+ bufref->br_fnum = buf->b_fnum;
bufref->br_buf_free_count = buf_free_count;
}
-/// Check if "bufref" points to a valid buffer.
-///
+/// Return true if "bufref->br_buf" points to the same buffer as when
+/// set_bufref() was called and it is a valid buffer.
/// Only goes through the buffer list if buf_free_count changed.
+/// Also checks if b_fnum is still the same, a :bwipe followed by :new might get
+/// the same allocated memory, but it's a different buffer.
///
/// @param bufref Buffer reference to check for.
bool bufref_valid(bufref_T *bufref)
{
return bufref->br_buf_free_count == buf_free_count
? true
- : buf_valid(bufref->br_buf);
+ : buf_valid(bufref->br_buf) && bufref->br_fnum == bufref->br_buf->b_fnum;
}
/// Check that "buf" points to a valid buffer in the buffer list.
@@ -1753,16 +1762,15 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_bkc);
}
-/*
- * get alternate file n
- * set linenr to lnum or altfpos.lnum if lnum == 0
- * also set cursor column to altfpos.col if 'startofline' is not set.
- * if (options & GETF_SETMARK) call setpcmark()
- * if (options & GETF_ALT) we are jumping to an alternate file.
- * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
- *
- * return FAIL for failure, OK for success
- */
+
+/// Get alternate file "n".
+/// Set linenr to "lnum" or altfpos.lnum if "lnum" == 0.
+/// Also set cursor column to altfpos.col if 'startofline' is not set.
+/// if (options & GETF_SETMARK) call setpcmark()
+/// if (options & GETF_ALT) we are jumping to an alternate file.
+/// if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
+///
+/// Return FAIL for failure, OK for success.
int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
{
buf_T *buf;
@@ -5136,6 +5144,30 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_a
// bufhl: plugin highlights associated with a buffer
+/// Get reference to line in kbtree_t
+///
+/// @param b the three
+/// @param line the linenumber to lookup
+/// @param put if true, put a new line when not found
+/// if false, return NULL when not found
+BufhlLine *bufhl_tree_ref(BufhlInfo *b, linenr_T line, bool put)
+{
+ BufhlLine t = BUFHLLINE_INIT(line);
+
+ // kp_put() only works if key is absent, try get first
+ BufhlLine **pp = kb_get(bufhl, b, &t);
+ if (pp) {
+ return *pp;
+ } else if (!put) {
+ return NULL;
+ }
+
+ BufhlLine *p = xmalloc(sizeof(*p));
+ *p = (BufhlLine)BUFHLLINE_INIT(line);
+ kb_put(bufhl, b, p);
+ return p;
+}
+
/// Adds a highlight to buffer.
///
/// Unlike matchaddpos() highlights follow changes to line numbering (as lines
@@ -5173,13 +5205,10 @@ int bufhl_add_hl(buf_T *buf,
// no highlight group or invalid line, just return src_id
return src_id;
}
- if (!buf->b_bufhl_info) {
- buf->b_bufhl_info = map_new(linenr_T, bufhl_vec_T)();
- }
- bufhl_vec_T* lineinfo = map_ref(linenr_T, bufhl_vec_T)(buf->b_bufhl_info,
- lnum, true);
- bufhl_hl_item_T *hlentry = kv_pushp(*lineinfo);
+ BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, true);
+
+ BufhlItem *hlentry = kv_pushp(lineinfo->items);
hlentry->src_id = src_id;
hlentry->hl_id = hl_id;
hlentry->start = col_start;
@@ -5201,20 +5230,24 @@ int bufhl_add_hl(buf_T *buf,
void bufhl_clear_line_range(buf_T *buf,
int src_id,
linenr_T line_start,
- linenr_T line_end) {
- if (!buf->b_bufhl_info) {
- return;
- }
- linenr_T line;
+ linenr_T line_end)
+{
linenr_T first_changed = MAXLNUM, last_changed = -1;
- // In the case line_start - line_end << bufhl_info->size
- // it might be better to reverse this, i e loop over the lines
- // to clear on.
- bufhl_vec_T unused;
- map_foreach(buf->b_bufhl_info, line, unused, {
- (void)unused;
+
+ kbitr_t(bufhl) itr;
+ BufhlLine *l, t = BUFHLLINE_INIT(line_start);
+ if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
+ kb_itr_next(bufhl, &buf->b_bufhl_info, &itr);
+ }
+ for (; kb_itr_valid(&itr); kb_itr_next(bufhl, &buf->b_bufhl_info, &itr)) {
+ l = kb_itr_key(&itr);
+ linenr_T line = l->line;
+ if (line > line_end) {
+ break;
+ }
if (line_start <= line && line <= line_end) {
- if (bufhl_clear_line(buf->b_bufhl_info, src_id, line)) {
+ BufhlLineStatus status = bufhl_clear_line(l, src_id, line);
+ if (status != kBLSUnchanged) {
if (line > last_changed) {
last_changed = line;
}
@@ -5222,8 +5255,12 @@ void bufhl_clear_line_range(buf_T *buf,
first_changed = line;
}
}
+ if (status == kBLSDeleted) {
+ kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
+ xfree(l);
+ }
}
- })
+ }
if (last_changed != -1) {
changed_lines_buf(buf, first_changed, last_changed+1, 0);
@@ -5236,42 +5273,40 @@ void bufhl_clear_line_range(buf_T *buf,
/// @param bufhl_info The highlight info for the buffer
/// @param src_id Highlight source group to clear, or -1 to clear all groups.
/// @param lnum Linenr where the highlight should be cleared
-static bool bufhl_clear_line(bufhl_info_T *bufhl_info, int src_id,
- linenr_T lnum)
+static BufhlLineStatus bufhl_clear_line(BufhlLine *lineinfo, int src_id,
+ linenr_T lnum)
{
- bufhl_vec_T *lineinfo = map_ref(linenr_T, bufhl_vec_T)(bufhl_info,
- lnum, false);
- size_t oldsize = kv_size(*lineinfo);
+ size_t oldsize = kv_size(lineinfo->items);
if (src_id < 0) {
- kv_size(*lineinfo) = 0;
+ kv_size(lineinfo->items) = 0;
} else {
- size_t newind = 0;
- for (size_t i = 0; i < kv_size(*lineinfo); i++) {
- if (kv_A(*lineinfo, i).src_id != src_id) {
- if (i != newind) {
- kv_A(*lineinfo, newind) = kv_A(*lineinfo, i);
+ size_t newidx = 0;
+ for (size_t i = 0; i < kv_size(lineinfo->items); i++) {
+ if (kv_A(lineinfo->items, i).src_id != src_id) {
+ if (i != newidx) {
+ kv_A(lineinfo->items, newidx) = kv_A(lineinfo->items, i);
}
- newind++;
+ newidx++;
}
}
- kv_size(*lineinfo) = newind;
+ kv_size(lineinfo->items) = newidx;
}
- if (kv_size(*lineinfo) == 0) {
- kv_destroy(*lineinfo);
- map_del(linenr_T, bufhl_vec_T)(bufhl_info, lnum);
+ if (kv_size(lineinfo->items) == 0) {
+ kv_destroy(lineinfo->items);
+ return kBLSDeleted;
}
- return kv_size(*lineinfo) != oldsize;
+ return kv_size(lineinfo->items) != oldsize ? kBLSChanged : kBLSUnchanged;
}
/// Remove all highlights and free the highlight data
-void bufhl_clear_all(buf_T* buf) {
- if (!buf->b_bufhl_info) {
- return;
- }
+void bufhl_clear_all(buf_T *buf)
+{
bufhl_clear_line_range(buf, -1, 1, MAXLNUM);
- map_free(linenr_T, bufhl_vec_T)(buf->b_bufhl_info);
- buf->b_bufhl_info = NULL;
+ kb_destroy(bufhl, (&buf->b_bufhl_info));
+ kb_init(&buf->b_bufhl_info);
+ kv_destroy(buf->b_bufhl_move_space);
+ kv_init(buf->b_bufhl_move_space);
}
/// Adjust a placed highlight for inserted/deleted lines.
@@ -5279,29 +5314,49 @@ void bufhl_mark_adjust(buf_T* buf,
linenr_T line1,
linenr_T line2,
long amount,
- long amount_after) {
- if (!buf->b_bufhl_info) {
+ long amount_after,
+ bool end_temp)
+{
+ kbitr_t(bufhl) itr;
+ BufhlLine *l, t = BUFHLLINE_INIT(line1);
+ if (end_temp && amount < 0) {
+ // Move all items from b_bufhl_move_space to the btree.
+ for (size_t i = 0; i < kv_size(buf->b_bufhl_move_space); i++) {
+ l = kv_A(buf->b_bufhl_move_space, i);
+ l->line += amount;
+ kb_put(bufhl, &buf->b_bufhl_info, l);
+ }
+ kv_size(buf->b_bufhl_move_space) = 0;
return;
}
- bufhl_info_T *newmap = map_new(linenr_T, bufhl_vec_T)();
- linenr_T line;
- bufhl_vec_T lineinfo;
- map_foreach(buf->b_bufhl_info, line, lineinfo, {
- if (line >= line1 && line <= line2) {
+ if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
+ kb_itr_next(bufhl, &buf->b_bufhl_info, &itr);
+ }
+ for (; kb_itr_valid(&itr); kb_itr_next(bufhl, &buf->b_bufhl_info, &itr)) {
+ l = kb_itr_key(&itr);
+ if (l->line >= line1 && l->line <= line2) {
+ if (end_temp && amount > 0) {
+ kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
+ kv_push(buf->b_bufhl_move_space, l);
+ }
if (amount == MAXLNUM) {
- bufhl_clear_line(buf->b_bufhl_info, -1, line);
- continue;
+ if (bufhl_clear_line(l, -1, l->line) == kBLSDeleted) {
+ kb_del_itr(bufhl, &buf->b_bufhl_info, &itr);
+ xfree(l);
+ } else {
+ assert(false);
+ }
} else {
- line += amount;
+ l->line += amount;
+ }
+ } else if (l->line > line2) {
+ if (amount_after == 0) {
+ break;
}
- } else if (line > line2) {
- line += amount_after;
+ l->line += amount_after;
}
- map_put(linenr_T, bufhl_vec_T)(newmap, line, lineinfo);
- });
- map_free(linenr_T, bufhl_vec_T)(buf->b_bufhl_info);
- buf->b_bufhl_info = newmap;
+ }
}
@@ -5311,13 +5366,14 @@ void bufhl_mark_adjust(buf_T* buf,
/// @param lnum The line number
/// @param[out] info The highligts for the line
/// @return true if there was highlights to display
-bool bufhl_start_line(buf_T *buf, linenr_T lnum, bufhl_lineinfo_T *info) {
- if (!buf->b_bufhl_info) {
+bool bufhl_start_line(buf_T *buf, linenr_T lnum, BufhlLineInfo *info)
+{
+ BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, false);
+ if (!lineinfo) {
return false;
}
-
info->valid_to = -1;
- info->entries = map_get(linenr_T, bufhl_vec_T)(buf->b_bufhl_info, lnum);
+ info->entries = lineinfo->items;
return kv_size(info->entries) > 0;
}
@@ -5331,14 +5387,15 @@ bool bufhl_start_line(buf_T *buf, linenr_T lnum, bufhl_lineinfo_T *info) {
/// @param info The info returned by bufhl_start_line
/// @param col The column to get the attr for
/// @return The highilight attr to display at the column
-int bufhl_get_attr(bufhl_lineinfo_T *info, colnr_T col) {
+int bufhl_get_attr(BufhlLineInfo *info, colnr_T col)
+{
if (col <= info->valid_to) {
return info->current;
}
int attr = 0;
info->valid_to = MAXCOL;
for (size_t i = 0; i < kv_size(info->entries); i++) {
- bufhl_hl_item_T entry = kv_A(info->entries, i);
+ BufhlItem entry = kv_A(info->entries, i);
if (entry.start <= col && col <= entry.stop) {
int entry_attr = syn_id2attr(entry.hl_id);
attr = hl_combine_attr(attr, entry_attr);
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h
index 39b9faf8b1..faeeed121c 100644
--- a/src/nvim/buffer.h
+++ b/src/nvim/buffer.h
@@ -83,14 +83,16 @@ static inline void restore_win_for_buf(win_T *save_curwin,
}
}
-static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
+static inline void buf_set_changedtick(buf_T *const buf,
+ const varnumber_T changedtick)
REAL_FATTR_NONNULL_ALL REAL_FATTR_ALWAYS_INLINE;
/// Set b_changedtick and corresponding variable
///
/// @param[out] buf Buffer to set changedtick in.
/// @param[in] changedtick New value.
-static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
+static inline void buf_set_changedtick(buf_T *const buf,
+ const varnumber_T changedtick)
{
#ifndef NDEBUG
dictitem_T *const changedtick_di = tv_dict_find(
@@ -113,7 +115,7 @@ static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
do { \
win_T *save_curwin = NULL; \
tabpage_T *save_curtab = NULL; \
- bufref_T save_curbuf = { NULL, 0 }; \
+ bufref_T save_curbuf = { NULL, 0, 0 }; \
switch_to_win_for_buf(b, &save_curwin, &save_curtab, &save_curbuf); \
code; \
restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); \
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index d96b9355f1..559dffb945 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -12,11 +12,14 @@ typedef struct file_buffer buf_T; // Forward declaration
// bufref_valid() only needs to check "buf" when the count differs.
typedef struct {
buf_T *br_buf;
+ int br_fnum;
int br_buf_free_count;
} bufref_T;
// for garray_T
#include "nvim/garray.h"
+// for HLF_COUNT
+#include "nvim/highlight_defs.h"
// for pos_T, lpos_T and linenr_T
#include "nvim/pos.h"
// for the number window-local and buffer-local options
@@ -103,8 +106,6 @@ typedef struct frame_S frame_T;
// for bufhl_*_T
#include "nvim/bufhl_defs.h"
-typedef Map(linenr_T, bufhl_vec_T) bufhl_info_T;
-
#include "nvim/os/fs_defs.h" // for FileID
#include "nvim/terminal.h" // for Terminal
@@ -759,7 +760,9 @@ struct file_buffer {
int b_mapped_ctrl_c; // modes where CTRL-C is mapped
- bufhl_info_T *b_bufhl_info; // buffer stored highlights
+ BufhlInfo b_bufhl_info; // buffer stored highlights
+
+ kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
};
/*
@@ -935,9 +938,13 @@ struct window_S {
synblock_T *w_s; /* for :ownsyntax */
- int w_hl_id; ///< 'winhighlight' id
- int w_hl_id_inactive; ///< 'winhighlight' id for inactive window
- int w_hl_attr; ///< 'winhighlight' final attrs
+ int w_hl_id_normal; ///< 'winhighlight' normal id
+ int w_hl_attr_normal; ///< 'winhighlight' normal final attrs
+
+ int w_hl_ids[HLF_COUNT]; ///< 'winhighlight' id
+ int w_hl_attrs[HLF_COUNT]; ///< 'winhighlight' final attrs
+
+ int w_hl_needs_update; ///< attrs need to be recalculated
win_T *w_prev; /* link to previous window */
win_T *w_next; /* link to next window */
@@ -1168,4 +1175,9 @@ struct window_S {
qf_info_T *w_llist_ref;
};
+static inline int win_hl_attr(win_T *wp, int hlf)
+{
+ return wp->w_hl_attrs[hlf];
+}
+
#endif // NVIM_BUFFER_DEFS_H
diff --git a/src/nvim/bufhl_defs.h b/src/nvim/bufhl_defs.h
index e47bb2a238..14b1afa7d9 100644
--- a/src/nvim/bufhl_defs.h
+++ b/src/nvim/bufhl_defs.h
@@ -3,23 +3,32 @@
#include "nvim/pos.h"
#include "nvim/lib/kvec.h"
+#include "nvim/lib/kbtree.h"
+
// bufhl: buffer specific highlighting
-struct bufhl_hl_item
-{
+typedef struct {
int src_id;
int hl_id; // highlight group
colnr_T start; // first column to highlight
colnr_T stop; // last column to highlight
-};
-typedef struct bufhl_hl_item bufhl_hl_item_T;
+} BufhlItem;
-typedef kvec_t(struct bufhl_hl_item) bufhl_vec_T;
+typedef kvec_t(BufhlItem) BufhlItemVec;
+
+typedef struct {
+ linenr_T line;
+ BufhlItemVec items;
+} BufhlLine;
+#define BUFHLLINE_INIT(l) { l, KV_INITIAL_VALUE }
typedef struct {
- bufhl_vec_T entries;
+ BufhlItemVec entries;
int current;
colnr_T valid_to;
-} bufhl_lineinfo_T;
+} BufhlLineInfo;
+#define BUFHL_CMP(a, b) ((int)(((a)->line - (b)->line)))
+KBTREE_INIT(bufhl, BufhlLine *, BUFHL_CMP, 10) // -V512
+typedef kbtree_t(bufhl) BufhlInfo;
#endif // NVIM_BUFHL_DEFS_H
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 5a0590d075..403ef65c4f 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -981,10 +981,8 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he
mb_ptr_adv(s);
c = *s;
- if (!((c != NUL)
- && (vim_isbreak(c)
- || (!vim_isbreak(c)
- && ((col2 == col) || !vim_isbreak(*ps)))))) {
+ if (!(c != NUL
+ && (vim_isbreak(c) || col2 == col || !vim_isbreak(*ps)))) {
break;
}
@@ -1621,13 +1619,13 @@ bool vim_isblankline(char_u *lbuf)
/// @param unptr Returns the unsigned result.
/// @param maxlen Max length of string to check.
void vim_str2nr(const char_u *const start, int *const prep, int *const len,
- const int what, long *const nptr, unsigned long *const unptr,
- const int maxlen)
+ const int what, varnumber_T *const nptr,
+ uvarnumber_T *const unptr, const int maxlen)
{
const char_u *ptr = start;
int pre = 0; // default is decimal
bool negative = false;
- unsigned long un = 0;
+ uvarnumber_T un = 0;
if (ptr[0] == '-') {
negative = true;
@@ -1683,7 +1681,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
n += 2; // skip over "0b"
}
while ('0' <= *ptr && *ptr <= '1') {
- un = 2 * un + (unsigned long)(*ptr - '0');
+ // avoid ubsan error for overflow
+ if (un < UVARNUMBER_MAX / 2) {
+ un = 2 * un + (uvarnumber_T)(*ptr - '0');
+ } else {
+ un = UVARNUMBER_MAX;
+ }
ptr++;
if (n++ == maxlen) {
break;
@@ -1692,7 +1695,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) {
// octal
while ('0' <= *ptr && *ptr <= '7') {
- un = 8 * un + (unsigned long)(*ptr - '0');
+ // avoid ubsan error for overflow
+ if (un < UVARNUMBER_MAX / 8) {
+ un = 8 * un + (uvarnumber_T)(*ptr - '0');
+ } else {
+ un = UVARNUMBER_MAX;
+ }
ptr++;
if (n++ == maxlen) {
break;
@@ -1705,7 +1713,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
n += 2; // skip over "0x"
}
while (ascii_isxdigit(*ptr)) {
- un = 16 * un + (unsigned long)hex2nr(*ptr);
+ // avoid ubsan error for overflow
+ if (un < UVARNUMBER_MAX / 16) {
+ un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
+ } else {
+ un = UVARNUMBER_MAX;
+ }
ptr++;
if (n++ == maxlen) {
break;
@@ -1714,7 +1727,12 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} else {
// decimal
while (ascii_isdigit(*ptr)) {
- un = 10 * un + (unsigned long)(*ptr - '0');
+ // avoid ubsan error for overflow
+ if (un < UVARNUMBER_MAX / 10) {
+ un = 10 * un + (uvarnumber_T)(*ptr - '0');
+ } else {
+ un = UVARNUMBER_MAX;
+ }
ptr++;
if (n++ == maxlen) {
break;
@@ -1731,11 +1749,18 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
}
if (nptr != NULL) {
- if (negative) {
- // account for leading '-' for decimal numbers
- *nptr = -(long)un;
+ if (negative) { // account for leading '-' for decimal numbers
+ // avoid ubsan error for overflow
+ if (un > VARNUMBER_MAX) {
+ *nptr = VARNUMBER_MIN;
+ } else {
+ *nptr = -(varnumber_T)un;
+ }
} else {
- *nptr = (long)un;
+ if (un > VARNUMBER_MAX) {
+ un = VARNUMBER_MAX;
+ }
+ *nptr = (varnumber_T)un;
}
}
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index e302d5aa4c..97fc3a3ca3 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -260,7 +260,7 @@ int cursor_mode_str2int(const char *mode)
return current_mode;
}
}
- ELOG("Unknown mode %s", mode);
+ WLOG("Unknown mode %s", mode);
return -1;
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 0bd3f59cf2..7da6665cb7 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -2311,7 +2311,7 @@ void ex_diffgetput(exarg_T *eap)
// Adjust marks. This will change the following entries!
if (added != 0) {
- mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added);
+ mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added, false);
if (curwin->w_cursor.lnum >= lnum) {
// Adjust the cursor position if it's in/after the changed
// lines.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 7187386ec7..662270e788 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6,6 +6,7 @@
*/
#include <assert.h>
+#include <float.h>
#include <inttypes.h>
#include <stdarg.h>
#include <string.h>
@@ -446,7 +447,7 @@ typedef struct {
bool rpc;
int refcount;
Callback on_stdout, on_stderr, on_exit;
- int *status_ptr;
+ varnumber_T *status_ptr;
uint64_t id;
MultiQueue *events;
} TerminalJobData;
@@ -1081,10 +1082,10 @@ char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox)
* Evaluates "expr" silently.
* Returns -1 for an error.
*/
-int eval_to_number(char_u *expr)
+varnumber_T eval_to_number(char_u *expr)
{
typval_T rettv;
- int retval;
+ varnumber_T retval;
char_u *p = skipwhite(expr);
++emsg_off;
@@ -1189,7 +1190,7 @@ int get_spellword(list_T *list, const char **pp)
}
-// Call some vimL function and return the result in "*rettv".
+// Call some vim script function and return the result in "*rettv".
// Uses argv[argc] for the function arguments. Only Number and String
// arguments are currently supported.
//
@@ -1203,7 +1204,7 @@ int call_vim_function(
typval_T *rettv
)
{
- long n;
+ varnumber_T n;
int len;
int doesrange;
void *save_funccalp = NULL;
@@ -1256,21 +1257,19 @@ int call_vim_function(
return ret;
}
-/*
- * Call vimL function "func" and return the result as a number.
- * Returns -1 when calling the function fails.
- * Uses argv[argc] for the function arguments.
- */
-long
-call_func_retnr (
- char_u *func,
- int argc,
- const char_u *const *const argv,
- int safe // use the sandbox
-)
+/// Call Vim script function and return the result as a number
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with string arguments.
+/// @param[in] safe Use with sandbox.
+///
+/// @return -1 when calling function fails, result of function otherwise.
+varnumber_T call_func_retnr(char_u *func, int argc,
+ const char_u *const *const argv, int safe)
{
typval_T rettv;
- long retval;
+ varnumber_T retval;
/* All arguments are passed as strings, no conversion to number. */
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
@@ -1281,14 +1280,14 @@ call_func_retnr (
return retval;
}
-/// Call VimL function and return the result as a string
+/// Call Vim script function and return the result as a string
///
/// @param[in] func Function name.
/// @param[in] argc Number of arguments.
/// @param[in] argv Array with string arguments.
/// @param[in] safe Use the sandbox.
///
-/// @return [allocated] NULL when calling function failes, allocated string
+/// @return [allocated] NULL when calling function fails, allocated string
/// otherwise.
char *call_func_retstr(const char *const func, const int argc,
const char_u *const *const argv,
@@ -1307,18 +1306,17 @@ char *call_func_retstr(const char *const func, const int argc,
return retval;
}
-/*
- * Call vimL function "func" and return the result as a List.
- * Uses argv[argc] for the function arguments.
- * Returns NULL when there is something wrong.
- */
-void *
-call_func_retlist (
- char_u *func,
- int argc,
- const char_u *const *const argv,
- int safe // use the sandbox
-)
+/// Call Vim script function and return the result as a List
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with string arguments.
+/// @param[in] safe Use the sandbox.
+///
+/// @return [allocated] NULL when calling function fails or return tv is not a
+/// List, allocated List otherwise.
+void *call_func_retlist(char_u *func, int argc, const char_u *const *const argv,
+ int safe)
{
typval_T rettv;
@@ -1399,7 +1397,7 @@ void prof_child_exit(proftime_T *tm /* where waittime was stored */
int eval_foldexpr(char_u *arg, int *cp)
{
typval_T tv;
- int retval;
+ varnumber_T retval;
char_u *s;
int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
OPT_LOCAL);
@@ -1432,7 +1430,7 @@ int eval_foldexpr(char_u *arg, int *cp)
--sandbox;
--textlock;
- return retval;
+ return (int)retval;
}
/*
@@ -2286,7 +2284,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
if (empty1) {
lp->ll_n1 = 0;
} else {
- lp->ll_n1 = tv_get_number(&var1); // Is number or string.
+ lp->ll_n1 = (long)tv_get_number(&var1); // Is number or string.
tv_clear(&var1);
}
lp->ll_dict = NULL;
@@ -2315,7 +2313,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
* Otherwise "lp->ll_n2" is set to the second index.
*/
if (lp->ll_range && !lp->ll_empty2) {
- lp->ll_n2 = tv_get_number(&var2); // Is number or string.
+ lp->ll_n2 = (long)tv_get_number(&var2); // Is number or string.
tv_clear(&var2);
if (lp->ll_n2 < 0) {
ni = tv_list_find(lp->ll_list, lp->ll_n2);
@@ -3525,7 +3523,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
exptype_T type = TYPE_UNKNOWN;
int type_is = FALSE; /* TRUE for "is" and "isnot" */
int len = 2;
- long n1, n2;
+ varnumber_T n1, n2;
int ic;
/*
@@ -3787,7 +3785,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
typval_T var2;
typval_T var3;
int op;
- long n1, n2;
+ varnumber_T n1, n2;
float_T f1 = 0, f2 = 0;
char_u *p;
@@ -3917,29 +3915,26 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
// TODO(ZyX-I): move to eval/expressions
-/*
- * Handle fifth level expression:
- * * number multiplication
- * / number division
- * % number modulo
- *
- * "arg" must point to the first non-white of the expression.
- * "arg" is advanced to the next non-white after the recognized expression.
- *
- * Return OK or FAIL.
- */
-static int
-eval6 (
- char_u **arg,
- typval_T *rettv,
- int evaluate,
- int want_string /* after "." operator */
-)
+/// Handle fifth level expression:
+/// - * number multiplication
+/// - / number division
+/// - % number modulo
+///
+/// @param[in,out] arg Points to the first non-whitespace character of the
+/// expression. Is advanced to the next non-whitespace
+/// character after the recognized expression.
+/// @param[out] rettv Location where result is saved.
+/// @param[in] evaluate If not true, rettv is not populated.
+/// @param[in] want_string True if "." is string_concatenation, otherwise
+/// float
+/// @return OK or FAIL.
+static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
+ FUNC_ATTR_NO_SANITIZE_UNDEFINED
{
typval_T var2;
int op;
- long n1, n2;
- int use_float = FALSE;
+ varnumber_T n1, n2;
+ bool use_float = false;
float_T f1 = 0, f2;
bool error = false;
@@ -3960,7 +3955,7 @@ eval6 (
if (evaluate) {
if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float;
- use_float = TRUE;
+ use_float = true;
n1 = 0;
} else {
n1 = tv_get_number_chk(rettv, &error);
@@ -3984,7 +3979,7 @@ eval6 (
if (var2.v_type == VAR_FLOAT) {
if (!use_float) {
f1 = n1;
- use_float = TRUE;
+ use_float = true;
}
f2 = var2.vval.v_float;
n2 = 0;
@@ -4027,18 +4022,20 @@ eval6 (
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f1;
} else {
- if (op == '*')
+ if (op == '*') {
n1 = n1 * n2;
- else if (op == '/') {
- if (n2 == 0) { /* give an error message? */
- if (n1 == 0)
- n1 = -0x7fffffffL - 1L; /* similar to NaN */
- else if (n1 < 0)
- n1 = -0x7fffffffL;
- else
- n1 = 0x7fffffffL;
- } else
+ } else if (op == '/') {
+ if (n2 == 0) { // give an error message?
+ if (n1 == 0) {
+ n1 = VARNUMBER_MIN; // similar to NaN
+ } else if (n1 < 0) {
+ n1 = -VARNUMBER_MAX;
+ } else {
+ n1 = VARNUMBER_MAX;
+ }
+ } else {
n1 = n1 / n2;
+ }
} else {
if (n2 == 0) /* give an error message? */
n1 = 0;
@@ -4087,7 +4084,7 @@ static int eval7(
int want_string // after "." operator
)
{
- long n;
+ varnumber_T n;
int len;
char_u *s;
char_u *start_leader, *end_leader;
@@ -4285,7 +4282,7 @@ static int eval7(
// Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
bool error = false;
- int val = 0;
+ varnumber_T val = 0;
float_T f = 0.0;
if (rettv->v_type == VAR_FLOAT) {
@@ -5898,6 +5895,19 @@ size_t string2float(const char *const text, float_T *const ret_value)
{
char *s = NULL;
+ // MS-Windows does not deal with "inf" and "nan" properly
+ if (STRNICMP(text, "inf", 3) == 0) {
+ *ret_value = INFINITY;
+ return 3;
+ }
+ if (STRNICMP(text, "-inf", 3) == 0) {
+ *ret_value = -INFINITY;
+ return 4;
+ }
+ if (STRNICMP(text, "nan", 3) == 0) {
+ *ret_value = NAN;
+ return 3;
+ }
*ret_value = strtod(text, &s);
return (size_t) (s - text);
}
@@ -6678,7 +6688,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int idx;
if (argvars[0].v_type != VAR_UNKNOWN) {
- idx = tv_get_number_chk(&argvars[0], NULL);
+ idx = (int)tv_get_number_chk(&argvars[0], NULL);
if (idx >= 0 && idx < ARGCOUNT) {
rettv->vval.v_string = (char_u *)xstrdup(
(const char *)alist_name(&ARGLIST[idx]));
@@ -6794,6 +6804,17 @@ static void f_assert_notequal(typval_T *argvars, typval_T *rettv, FunPtr fptr)
assert_equal_common(argvars, ASSERT_NOTEQUAL);
}
+/// "assert_report(msg)
+static void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ garray_T ga;
+
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (const char_u *)tv_get_string(&argvars[0]));
+ assert_error(&ga);
+ ga_clear(&ga);
+}
+
/// "assert_exception(string[, msg])" function
static void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -7403,7 +7424,7 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- const int startcol = tv_get_number_chk(&argvars[0], NULL);
+ const colnr_T startcol = tv_get_number_chk(&argvars[0], NULL);
if (startcol <= 0) {
return;
}
@@ -7614,9 +7635,9 @@ static void f_cursor(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else {
line = tv_get_lnum(argvars);
- col = tv_get_number_chk(&argvars[1], NULL);
+ col = (long)tv_get_number_chk(&argvars[1], NULL);
if (argvars[2].v_type != VAR_UNKNOWN) {
- coladd = tv_get_number_chk(&argvars[2], NULL);
+ coladd = (long)tv_get_number_chk(&argvars[2], NULL);
}
}
if (line < 0 || col < 0
@@ -8170,7 +8191,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else if (!tv_check_lock(l1->lv_lock, arg_errmsg, TV_TRANSLATE)) {
listitem_T *item;
if (argvars[2].v_type != VAR_UNKNOWN) {
- before = tv_get_number_chk(&argvars[2], &error);
+ before = (long)tv_get_number_chk(&argvars[2], &error);
if (error) {
return; // Type error; errmsg already given.
}
@@ -8539,9 +8560,9 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
float_T f;
if (tv_get_float_chk(argvars, &f)) {
- if (f < VARNUMBER_MIN) {
- rettv->vval.v_number = VARNUMBER_MIN;
- } else if (f > VARNUMBER_MAX) {
+ if (f <= -VARNUMBER_MAX + DBL_EPSILON) {
+ rettv->vval.v_number = -VARNUMBER_MAX;
+ } else if (f >= VARNUMBER_MAX - DBL_EPSILON) {
rettv->vval.v_number = VARNUMBER_MAX;
} else {
rettv->vval.v_number = (varnumber_T)f;
@@ -10516,6 +10537,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"mouse",
"multi_byte",
"multi_lang",
+ "num64",
"packages",
"path_extra",
"persistent_undo",
@@ -12095,9 +12117,11 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(keys_buf);
if (!get_dict) {
- /* Return a string. */
- if (rhs != NULL)
- rettv->vval.v_string = str2special_save(rhs, FALSE);
+ // Return a string.
+ if (rhs != NULL) {
+ rettv->vval.v_string = (char_u *)str2special_save(
+ (const char *)rhs, false, false);
+ }
} else {
tv_dict_alloc_ret(rettv);
@@ -12130,9 +12154,10 @@ void mapblock_fill_dict(dict_T *const dict,
const mapblock_T *const mp,
long buffer_value,
bool compatible)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL
{
- char_u *lhs = str2special_save(mp->m_keys, true);
+ char *const lhs = str2special_save((const char *)mp->m_keys,
+ compatible, !compatible);
char *const mapmode = map_mode_to_chars(mp->m_mode);
varnumber_T noremap_value;
@@ -12146,18 +12171,21 @@ void mapblock_fill_dict(dict_T *const dict,
noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
}
- tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs);
- tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
+ if (compatible) {
+ tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
+ } else {
+ tv_dict_add_allocated_str(dict, S_LEN("rhs"),
+ str2special_save((const char *)mp->m_str, false,
+ true));
+ }
+ tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID);
tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value);
tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
- tv_dict_add_str(dict, S_LEN("mode"), mapmode);
-
- xfree(lhs);
- xfree(mapmode);
+ tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
}
/*
@@ -12945,7 +12973,7 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
varnumber_T start;
varnumber_T end;
varnumber_T stride = 1;
- long i;
+ varnumber_T i;
bool error = false;
start = tv_get_number_chk(&argvars[0], &error);
@@ -13163,7 +13191,7 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL
// in f_reltime() we split up the 64-bit proftime_T into two 32-bit
// values, now we combine them again.
union {
- struct { varnumber_T low, high; } split;
+ struct { int32_t low, high; } split;
proftime_T prof;
} u = { .split.high = n1, .split.low = n2 };
@@ -13204,7 +13232,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// (varnumber_T is defined as int). For all our supported platforms, int's
// are at least 32-bits wide. So we'll use two 32-bit values to store it.
union {
- struct { varnumber_T low, high; } split;
+ struct { int32_t low, high; } split;
proftime_T prof;
} u = { .prof = res };
@@ -14340,7 +14368,7 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (result != 0) {
EMSG2("Failed to start server: %s",
- result > 0 ? "Unknonwn system error" : uv_strerror(result));
+ result > 0 ? "Unknown system error" : uv_strerror(result));
return;
}
@@ -15152,8 +15180,8 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
int res;
if (sortinfo->item_compare_numbers) {
- const long v1 = tv_get_number(tv1);
- const long v2 = tv_get_number(tv2);
+ const varnumber_T v1 = tv_get_number(tv1);
+ const varnumber_T v2 = tv_get_number(tv2);
res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
goto item_compare_end;
@@ -15685,11 +15713,15 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
+ bool isneg = (*p == '-');
- if (*p == '+') {
+ if (*p == '+' || *p == '-') {
p = skipwhite(p + 1);
}
(void)string2float((char *)p, &rettv->vval.v_float);
+ if (isneg) {
+ rettv->vval.v_float *= -1;
+ }
rettv->v_type = VAR_FLOAT;
}
@@ -15697,7 +15729,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int base = 10;
- long n;
+ varnumber_T n;
int what;
if (argvars[1].v_type != VAR_UNKNOWN) {
@@ -15709,7 +15741,8 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
- if (*p == '+') {
+ bool isneg = (*p == '-');
+ if (*p == '+' || *p == '-') {
p = skipwhite(p + 1);
}
switch (base) {
@@ -15730,7 +15763,11 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
- rettv->vval.v_number = n;
+ if (isneg) {
+ rettv->vval.v_number = -n;
+ } else {
+ rettv->vval.v_number = n;
+ }
}
/*
@@ -18108,7 +18145,7 @@ static int eval_isnamec1(int c)
/*
* Get number v: variable value.
*/
-long get_vim_var_nr(int idx) FUNC_ATTR_PURE
+varnumber_T get_vim_var_nr(int idx) FUNC_ATTR_PURE
{
return vimvars[idx].vv_nr;
}
@@ -19734,10 +19771,12 @@ void ex_function(exarg_T *eap)
/* When there is a line break use what follows for the function body.
* Makes 'exe "func Test()\n...\nendfunc"' work. */
- if (*p == '\n')
+ const char *const end = (const char *)p + STRLEN(p);
+ if (*p == '\n') {
line_arg = p + 1;
- else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg)
- EMSG(_(e_trailing));
+ } else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg) {
+ emsgf(_(e_trailing));
+ }
/*
* Read the body of the function, until ":endfunction" is found.
@@ -19811,8 +19850,30 @@ void ex_function(exarg_T *eap)
/* Check for "endfunction". */
if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) {
- if (line_arg == NULL)
+ if (*p == '!') {
+ p++;
+ }
+ const char *const comment_start = strchr((const char *)p, '"');
+ const char *const endfunc_end = (comment_start
+ ? strchr(comment_start, '\n')
+ : strpbrk((const char *)p, "\n|"));
+ p = (endfunc_end
+ ? (char_u *)endfunc_end
+ : p + STRLEN(p));
+ if (*p == '|') {
+ emsgf(_(e_trailing2), p);
+ if (line_arg == NULL) {
+ xfree(theline);
+ }
+ goto erret;
+ }
+ if (line_arg == NULL) {
xfree(theline);
+ } else {
+ if ((const char *)p < end) {
+ eap->nextcmd = p + 1;
+ }
+ }
break;
}
@@ -19839,9 +19900,15 @@ void ex_function(exarg_T *eap)
}
}
- /* Check for ":append" or ":insert". */
+ // Check for ":append", ":change", ":insert".
p = skip_range(p, NULL);
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
+ || (p[0] == 'c'
+ && (!ASCII_ISALPHA(p[1])
+ || (p[1] == 'h' && (!ASCII_ISALPHA(p[2])
+ || (p[2] == 'a'
+ && (STRNCMP(&p[3], "nge", 3) != 0
+ || !ASCII_ISALPHA(p[6])))))))
|| (p[0] == 'i'
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
&& (!ASCII_ISALPHA(p[2])
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 334e10eb6c..30766a0734 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -33,6 +33,7 @@ return {
assert_match={args={2, 3}},
assert_notequal={args={2, 3}},
assert_notmatch={args={2, 3}},
+ assert_report={args=1},
assert_true={args={1, 2}},
atan={args=1, func="float_op_wrapper", data="&atan"},
atan2={args=2},
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 935c98fb84..9c9c2c2dc8 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -435,8 +435,8 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
case 'u': {
const char ubuf[] = { t[1], t[2], t[3], t[4] };
t += 4;
- unsigned long ch;
- vim_str2nr((char_u *) ubuf, NULL, NULL,
+ uvarnumber_T ch;
+ vim_str2nr((char_u *)ubuf, NULL, NULL,
STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4);
if (ch == 0) {
hasnul = true;
@@ -609,7 +609,7 @@ parse_json_number_check:
tv.v_type = VAR_FLOAT;
} else {
// Convert integer
- long nr;
+ varnumber_T nr;
int num_len;
vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s));
if ((int) exp_num_len != num_len) {
@@ -617,7 +617,7 @@ parse_json_number_check:
"to integer vim_str2nr consumed %i bytes in place of %zu"),
(int) exp_num_len, s, num_len, exp_num_len);
}
- tv.vval.v_number = (varnumber_T) nr;
+ tv.vval.v_number = nr;
}
if (json_decoder_pop(OBJ(tv, false, *didcomma, *didcolon),
stack, container_stack,
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index 91bb61323f..99298cbbcf 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -25,7 +25,7 @@ char *e_listidx = N_("E684: list index out of range: %" PRId64);
/// @return OK or FAIL.
int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
const char *const op)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NO_SANITIZE_UNDEFINED
{
// Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
@@ -55,7 +55,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
// nr += nr or nr -= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
- float_T f = n;
+ float_T f = (float_T)n;
if (*op == '+') {
f += tv2->vval.v_float;
@@ -99,7 +99,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
}
const float_T f = (tv2->v_type == VAR_FLOAT
? tv2->vval.v_float
- : tv_get_number(tv2));
+ : (float_T)tv_get_number(tv2));
if (*op == '+') {
tv1->vval.v_float += f;
} else {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index f017f57b12..c339a5cdd2 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1387,11 +1387,32 @@ int tv_dict_add_str(dict_T *const d,
const char *const val)
FUNC_ATTR_NONNULL_ALL
{
+ return tv_dict_add_allocated_str(d, key, key_len, xstrdup(val));
+}
+
+/// Add a string entry to dictionary
+///
+/// Unlike tv_dict_add_str() saves val to the new dictionary item in place of
+/// creating a new copy.
+///
+/// @warning String will be freed even in case addition fails.
+///
+/// @param[out] d Dictionary to add entry to.
+/// @param[in] key Key to add.
+/// @param[in] key_len Key length.
+/// @param[in] val String to add.
+///
+/// @return OK in case of success, FAIL when key already exists.
+int tv_dict_add_allocated_str(dict_T *const d,
+ const char *const key, const size_t key_len,
+ char *const val)
+ FUNC_ATTR_NONNULL_ALL
+{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_STRING;
- item->di_tv.vval.v_string = (char_u *)xstrdup(val);
+ item->di_tv.vval.v_string = (char_u *)val;
if (tv_dict_add(d, item) == FAIL) {
tv_dict_item_free(item);
return FAIL;
@@ -2405,9 +2426,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
case VAR_STRING: {
varnumber_T n = 0;
if (tv->vval.v_string != NULL) {
- long nr;
- vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &nr, NULL, 0);
- n = (varnumber_T)nr;
+ vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0);
}
return n;
}
@@ -2444,7 +2463,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
linenr_T tv_get_lnum(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- linenr_T lnum = tv_get_number_chk(tv, NULL);
+ linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL);
if (lnum == 0) { // No valid number, try using same function as line() does.
int fnum;
pos_T *const fp = var2fpos(tv, true, &fnum);
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 0f659727ee..3f8ed3b3f9 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EVAL_TYPVAL_H
#define NVIM_EVAL_TYPVAL_H
-#include <limits.h>
+#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@@ -20,20 +20,21 @@
#include "nvim/macros.h"
/// Type used for VimL VAR_NUMBER values
-typedef int varnumber_T;
+typedef int64_t varnumber_T;
+typedef uint64_t uvarnumber_T;
/// Type used for VimL VAR_FLOAT values
typedef double float_T;
/// Maximal possible value of varnumber_T variable
-#define VARNUMBER_MAX INT_MAX
+#define VARNUMBER_MAX INT64_MAX
+#define UVARNUMBER_MAX UINT64_MAX
/// Mimimal possible value of varnumber_T variable
-#define VARNUMBER_MIN INT_MIN
-#define PRIdVARNUMBER "d"
+#define VARNUMBER_MIN INT64_MIN
/// %d printf format specifier for varnumber_T
-#define PRIdVARNUMBER "d"
+#define PRIdVARNUMBER PRId64
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index c709ce9a1c..25701a1621 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -8,6 +8,7 @@
#include "nvim/event/loop.h"
#include "nvim/event/process.h"
+#include "nvim/log.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/loop.c.generated.h"
@@ -78,20 +79,34 @@ void loop_on_put(MultiQueue *queue, void *data)
uv_stop(&loop->uv);
}
-void loop_close(Loop *loop, bool wait)
+/// @returns false if the loop could not be closed gracefully
+bool loop_close(Loop *loop, bool wait)
{
+ bool rv = true;
uv_mutex_destroy(&loop->mutex);
uv_close((uv_handle_t *)&loop->children_watcher, NULL);
uv_close((uv_handle_t *)&loop->children_kill_timer, NULL);
uv_close((uv_handle_t *)&loop->poll_timer, NULL);
uv_close((uv_handle_t *)&loop->async, NULL);
- do {
+ uint64_t start = wait ? os_hrtime() : 0;
+ while (true) {
uv_run(&loop->uv, wait ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
- } while (uv_loop_close(&loop->uv) && wait);
+ if (!uv_loop_close(&loop->uv) || !wait) {
+ break;
+ }
+ if (os_hrtime() - start >= 2 * 1000000000) {
+ // Some libuv resource was not correctly deref'd. Log and bail.
+ rv = false;
+ ELOG("uv_loop_close() hang?");
+ log_uv_handles(&loop->uv);
+ break;
+ }
+ }
multiqueue_free(loop->fast_events);
multiqueue_free(loop->thread_events);
multiqueue_free(loop->events);
kl_destroy(WatcherPtr, loop->children);
+ return rv;
}
void loop_purge(Loop *loop)
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 30a71a5586..6f45b09fce 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -66,6 +66,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher,
watcher->uv.tcp.addrinfo = request.addrinfo;
uv_tcp_init(&loop->uv, &watcher->uv.tcp.handle);
+ uv_tcp_nodelay(&watcher->uv.tcp.handle, true);
watcher->stream = STRUCT_CAST(uv_stream_t, &watcher->uv.tcp.handle);
} else {
uv_pipe_init(&loop->uv, &watcher->uv.pipe.handle, 0);
@@ -104,9 +105,10 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
// contain 0 in this case, unless uv_tcp_getsockname() is used first.
uv_tcp_getsockname(&watcher->uv.tcp.handle, (struct sockaddr *)&sas,
&(int){ sizeof(sas) });
- uint16_t port = (uint16_t)((sas.ss_family == AF_INET)
- ? ((struct sockaddr_in *)&sas)->sin_port
- : ((struct sockaddr_in6 *)&sas)->sin6_port);
+ uint16_t port = (uint16_t)(
+ (sas.ss_family == AF_INET)
+ ? (STRUCT_CAST(struct sockaddr_in, &sas))->sin_port
+ : (STRUCT_CAST(struct sockaddr_in6, &sas))->sin6_port);
// v:servername uses the string from watcher->addr
size_t len = strlen(watcher->addr);
snprintf(watcher->addr+len, sizeof(watcher->addr)-len, ":%" PRIu16,
@@ -146,6 +148,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
if (watcher->stream->type == UV_TCP) {
client = STRUCT_CAST(uv_stream_t, &stream->uv.tcp);
uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client);
+ uv_tcp_nodelay((uv_tcp_t *)client, true);
} else {
client = STRUCT_CAST(uv_stream_t, &stream->uv.pipe);
uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0);
@@ -237,6 +240,7 @@ bool socket_connect(Loop *loop, Stream *stream,
tcp_retry:
uv_tcp_init(&loop->uv, tcp);
+ uv_tcp_nodelay(tcp, true);
uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb);
uv_stream = (uv_stream_t *)tcp;
@@ -244,7 +248,7 @@ tcp_retry:
uv_pipe_t *pipe = &stream->uv.pipe;
uv_pipe_init(&loop->uv, pipe, 0);
uv_pipe_connect(&req, pipe, address, connect_cb);
- uv_stream = (uv_stream_t *)pipe;
+ uv_stream = STRUCT_CAST(uv_stream_t, pipe);
}
status = 1;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a528a65abb..8dcb3ac449 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -318,14 +318,12 @@ static int sort_abort; ///< flag to indicate if sorting has been interrupted
/// Struct to store info to be sorted.
typedef struct {
linenr_T lnum; ///< line number
- long start_col_nr; ///< starting column number or number
- long end_col_nr; ///< ending column number
union {
struct {
- long start_col_nr; ///< starting column number
- long end_col_nr; ///< ending column number
+ varnumber_T start_col_nr; ///< starting column number
+ varnumber_T end_col_nr; ///< ending column number
} line;
- long value; ///< value if sorting by integer
+ varnumber_T value; ///< value if sorting by integer
float_T value_flt; ///< value if sorting by float
} st_u;
} sorti_T;
@@ -599,9 +597,10 @@ void ex_sort(exarg_T *eap)
// Adjust marks for deleted (or added) lines and prepare for displaying.
deleted = (long)(count - (lnum - eap->line2));
if (deleted > 0) {
- mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
+ mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted,
+ false);
} else if (deleted < 0) {
- mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
+ mark_adjust(eap->line2, MAXLNUM, -deleted, 0L, false);
}
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
@@ -796,9 +795,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
* their final destination at the new text position -- webb
*/
last_line = curbuf->b_ml.ml_line_count;
- mark_adjust_nofold(line1, line2, last_line - line2, 0L);
+ mark_adjust_nofold(line1, line2, last_line - line2, 0L, true);
if (dest >= line2) {
- mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L);
+ mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, false);
FOR_ALL_TAB_WINDOWS(tab, win) {
if (win->w_buffer == curbuf) {
foldMoveRange(&win->w_folds, line1, line2, dest);
@@ -807,7 +806,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
curbuf->b_op_start.lnum = dest - num_lines + 1;
curbuf->b_op_end.lnum = dest;
} else {
- mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L);
+ mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, false);
FOR_ALL_TAB_WINDOWS(tab, win) {
if (win->w_buffer == curbuf) {
foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
@@ -818,7 +817,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
}
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
mark_adjust_nofold(last_line - num_lines + 1, last_line,
- -(last_line - dest - extra), 0L);
+ -(last_line - dest - extra), 0L, true);
/*
* Now we delete the original text -- webb
@@ -1214,15 +1213,14 @@ static void do_filter(
if (do_in) {
if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL) {
- if (read_linecount >= linecount)
- /* move all marks from old lines to new lines */
- mark_adjust(line1, line2, linecount, 0L);
- else {
- /* move marks from old lines to new lines, delete marks
- * that are in deleted lines */
- mark_adjust(line1, line1 + read_linecount - 1,
- linecount, 0L);
- mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L);
+ if (read_linecount >= linecount) {
+ // move all marks from old lines to new lines
+ mark_adjust(line1, line2, linecount, 0L, false);
+ } else {
+ // move marks from old lines to new lines, delete marks
+ // that are in deleted lines
+ mark_adjust(line1, line1 + read_linecount - 1, linecount, 0L, false);
+ mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L, false);
}
}
@@ -3760,7 +3758,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
*p1 = NUL; // truncate up to the CR
ml_append(lnum - 1, new_start,
(colnr_T)(p1 - new_start + 1), false);
- mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
+ mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
if (subflags.do_ask) {
appended_lines(lnum - 1, 1L);
} else {
@@ -3849,7 +3847,7 @@ skip:
for (i = 0; i < nmatch_tl; ++i)
ml_delete(lnum, (int)FALSE);
mark_adjust(lnum, lnum + nmatch_tl - 1,
- (long)MAXLNUM, -nmatch_tl);
+ (long)MAXLNUM, -nmatch_tl, false);
if (subflags.do_ask) {
deleted_lines(lnum, nmatch_tl);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index a0406cf418..af8845de87 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8847,15 +8847,16 @@ makeopens (
*/
tab_firstwin = firstwin; /* first window in tab page "tabnr" */
tab_topframe = topframe;
- for (tabnr = 1;; ++tabnr) {
+ for (tabnr = 1;; tabnr++) {
+ tabpage_T *tp = find_tabpage(tabnr);
+ if (tp == NULL) {
+ break; // done all tab pages
+ }
+
int need_tabnew = false;
int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES)) {
- tabpage_T *tp = find_tabpage(tabnr);
-
- if (tp == NULL)
- break; /* done all tab pages */
if (tp == curtab) {
tab_firstwin = firstwin;
tab_topframe = topframe;
@@ -8968,6 +8969,16 @@ makeopens (
if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
return FAIL;
+ // Take care of tab-local working directories if applicable
+ if (tp->tp_localdir) {
+ if (fputs("if has('nvim') | tcd ", fd) < 0
+ || ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
+ || fputs(" | endif", fd) < 0
+ || put_eol(fd) == FAIL) {
+ return FAIL;
+ }
+ }
+
/* Don't continue in another tab page when doing only the current one
* or when at the last tab page. */
if (!(ssop_flags & SSOP_TABPAGES))
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 0c14bf4255..0ba6c79a71 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -100,12 +100,20 @@ typedef struct command_line_state {
char_u *lookfor; // string to match
int hiscnt; // current history line in use
int histype; // history type to be used
- pos_T old_cursor;
+ pos_T search_start; // where 'incsearch' starts searching
+ pos_T save_cursor;
colnr_T old_curswant;
+ colnr_T init_curswant;
colnr_T old_leftcol;
+ colnr_T init_leftcol;
linenr_T old_topline;
+ linenr_T init_topline;
int old_topfill;
+ int init_topfill;
linenr_T old_botline;
+ linenr_T init_botline;
+ pos_T match_start;
+ pos_T match_end;
int did_incsearch;
int incsearch_postponed;
int did_wild_list; // did wild_list() recently
@@ -167,6 +175,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
s->save_State = State;
s->save_p_icm = vim_strsave(p_icm);
s->ignore_drag_release = true;
+ s->match_start = curwin->w_cursor;
+ s->init_curswant = curwin->w_curswant;
+ s->init_leftcol = curwin->w_leftcol;
+ s->init_topline = curwin->w_topline;
+ s->init_topfill = curwin->w_topfill;
+ s->init_botline = curwin->w_botline;
if (s->firstc == -1) {
s->firstc = NUL;
@@ -179,7 +193,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
ccline.overstrike = false; // always start in insert mode
- s->old_cursor = curwin->w_cursor; // needs to be restored later
+ clearpos(&s->match_end);
+ s->save_cursor = curwin->w_cursor; // may be restored later
+ s->search_start = curwin->w_cursor;
s->old_curswant = curwin->w_curswant;
s->old_leftcol = curwin->w_leftcol;
s->old_topline = curwin->w_topline;
@@ -282,7 +298,16 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
ccline.xpc = NULL;
if (s->did_incsearch) {
- curwin->w_cursor = s->old_cursor;
+ if (s->gotesc) {
+ curwin->w_cursor = s->save_cursor;
+ } else {
+ if (!equalpos(s->save_cursor, s->search_start)) {
+ // put the '" mark at the original position
+ curwin->w_cursor = s->save_cursor;
+ setpcmark();
+ }
+ curwin->w_cursor = s->search_start; // -V519
+ }
curwin->w_curswant = s->old_curswant;
curwin->w_leftcol = s->old_leftcol;
curwin->w_topline = s->old_topline;
@@ -857,6 +882,118 @@ static int command_line_execute(VimState *state, int key)
return command_line_handle_key(s);
}
+static void command_line_next_incsearch(CommandLineState *s, bool next_match)
+{
+ ui_busy_start();
+ ui_flush();
+
+ pos_T t;
+ int search_flags = SEARCH_KEEP + SEARCH_NOOF + SEARCH_PEEK;
+ if (next_match) {
+ t = s->match_end;
+ search_flags += SEARCH_COL;
+ } else {
+ t = s->match_start;
+ }
+ emsg_off++;
+ s->i = searchit(curwin, curbuf, &t,
+ next_match ? FORWARD : BACKWARD,
+ ccline.cmdbuff, s->count, search_flags,
+ RE_SEARCH, 0, NULL);
+ emsg_off--;
+ ui_busy_stop();
+ if (s->i) {
+ s->search_start = s->match_start;
+ s->match_end = t;
+ s->match_start = t;
+ if (!next_match && s->firstc == '/') {
+ // move just before the current match, so that
+ // when nv_search finishes the cursor will be
+ // put back on the match
+ s->search_start = t;
+ (void)decl(&s->search_start);
+ }
+ if (lt(t, s->search_start) && next_match) {
+ // wrap around
+ s->search_start = t;
+ if (s->firstc == '?') {
+ (void)incl(&s->search_start);
+ } else {
+ (void)decl(&s->search_start);
+ }
+ }
+
+ set_search_match(&s->match_end);
+ curwin->w_cursor = s->match_start;
+ changed_cline_bef_curs();
+ update_topline();
+ validate_cursor();
+ highlight_match = true;
+ s->old_curswant = curwin->w_curswant;
+ s->old_leftcol = curwin->w_leftcol;
+ s->old_topline = curwin->w_topline;
+ s->old_topfill = curwin->w_topfill;
+ s->old_botline = curwin->w_botline;
+ update_screen(NOT_VALID);
+ redrawcmdline();
+ } else {
+ vim_beep(BO_ERROR);
+ }
+ return;
+}
+
+static void command_line_next_histidx(CommandLineState *s, bool next_match)
+{
+ s->j = (int)STRLEN(s->lookfor);
+ for (;; ) {
+ // one step backwards
+ if (!next_match) {
+ if (s->hiscnt == hislen) {
+ // first time
+ s->hiscnt = hisidx[s->histype];
+ } else if (s->hiscnt == 0 && hisidx[s->histype] != hislen - 1) {
+ s->hiscnt = hislen - 1;
+ } else if (s->hiscnt != hisidx[s->histype] + 1) {
+ s->hiscnt--;
+ } else {
+ // at top of list
+ s->hiscnt = s->i;
+ break;
+ }
+ } else { // one step forwards
+ // on last entry, clear the line
+ if (s->hiscnt == hisidx[s->histype]) {
+ s->hiscnt = hislen;
+ break;
+ }
+
+ // not on a history line, nothing to do
+ if (s->hiscnt == hislen) {
+ break;
+ }
+
+ if (s->hiscnt == hislen - 1) {
+ // wrap around
+ s->hiscnt = 0;
+ } else {
+ s->hiscnt++;
+ }
+ }
+
+ if (s->hiscnt < 0 || history[s->histype][s->hiscnt].hisstr == NULL) {
+ s->hiscnt = s->i;
+ break;
+ }
+
+ if ((s->c != K_UP && s->c != K_DOWN)
+ || s->hiscnt == s->i
+ || STRNCMP(history[s->histype][s->hiscnt].hisstr,
+ s->lookfor, (size_t)s->j) == 0) {
+ break;
+ }
+ }
+}
+
static int command_line_handle_key(CommandLineState *s)
{
// Big switch for a typed command line character.
@@ -929,6 +1066,16 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
+ if (ccline.cmdlen == 0) {
+ s->search_start = s->save_cursor;
+ // save view settings, so that the screen won't be restored at the
+ // wrong position
+ s->old_curswant = s->init_curswant;
+ s->old_leftcol = s->init_leftcol;
+ s->old_topline = s->init_topline;
+ s->old_topfill = s->init_topfill;
+ s->old_botline = s->init_botline;
+ }
redrawcmd();
} else if (ccline.cmdlen == 0 && s->c != Ctrl_W
&& ccline.cmdprompt == NULL && s->indent == 0) {
@@ -947,6 +1094,7 @@ static int command_line_handle_key(CommandLineState *s)
}
msg_putchar(' '); // delete ':'
}
+ s->search_start = s->save_cursor;
redraw_cmdline = true;
return 0; // back to cmd mode
}
@@ -1001,6 +1149,9 @@ static int command_line_handle_key(CommandLineState *s)
// Truncate at the end, required for multi-byte chars.
ccline.cmdbuff[ccline.cmdlen] = NUL;
+ if (ccline.cmdlen == 0) {
+ s->search_start = s->save_cursor;
+ }
redrawcmd();
return command_line_changed(s);
@@ -1230,24 +1381,27 @@ static int command_line_handle_key(CommandLineState *s)
case Ctrl_L:
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
// Add a character from under the cursor for 'incsearch'
- if (s->did_incsearch && !equalpos(curwin->w_cursor, s->old_cursor)) {
- s->c = gchar_cursor();
- // If 'ignorecase' and 'smartcase' are set and the
- // command line has no uppercase characters, convert
- // the character to lowercase
- if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff)) {
- s->c = mb_tolower(s->c);
- }
-
- if (s->c != NUL) {
- if (s->c == s->firstc
- || vim_strchr((char_u *)(p_magic ? "\\^$.*[" : "\\^$"), s->c)
- != NULL) {
- // put a backslash before special characters
- stuffcharReadbuff(s->c);
- s->c = '\\';
+ if (s->did_incsearch) {
+ curwin->w_cursor = s->match_end;
+ if (!equalpos(curwin->w_cursor, s->search_start)) {
+ s->c = gchar_cursor();
+ // If 'ignorecase' and 'smartcase' are set and the
+ // command line has no uppercase characters, convert
+ // the character to lowercase
+ if (p_ic && p_scs
+ && !pat_has_uppercase(ccline.cmdbuff)) {
+ s->c = mb_tolower(s->c);
+ }
+ if (s->c != NUL) {
+ if (s->c == s->firstc
+ || vim_strchr((char_u *)(p_magic ? "\\^$.*[" : "\\^$"), s->c)
+ != NULL) {
+ // put a backslash before special characters
+ stuffcharReadbuff(s->c);
+ s->c = '\\';
+ }
+ break;
}
- break;
}
}
return command_line_not_changed(s);
@@ -1266,7 +1420,7 @@ static int command_line_handle_key(CommandLineState *s)
0, s->firstc != '@') == FAIL) {
break;
}
- return command_line_changed(s);
+ return command_line_not_changed(s);
}
// fallthrough
@@ -1291,55 +1445,9 @@ static int command_line_handle_key(CommandLineState *s)
s->lookfor[ccline.cmdpos] = NUL;
}
- s->j = (int)STRLEN(s->lookfor);
- for (;; ) {
- // one step backwards
- if (s->c == K_UP|| s->c == K_S_UP || s->c == Ctrl_P
- || s->c == K_PAGEUP || s->c == K_KPAGEUP) {
- if (s->hiscnt == hislen) {
- // first time
- s->hiscnt = hisidx[s->histype];
- } else if (s->hiscnt == 0 && hisidx[s->histype] != hislen - 1) {
- s->hiscnt = hislen - 1;
- } else if (s->hiscnt != hisidx[s->histype] + 1) {
- --s->hiscnt;
- } else {
- // at top of list
- s->hiscnt = s->i;
- break;
- }
- } else { // one step forwards
- // on last entry, clear the line
- if (s->hiscnt == hisidx[s->histype]) {
- s->hiscnt = hislen;
- break;
- }
-
- // not on a history line, nothing to do
- if (s->hiscnt == hislen) {
- break;
- }
-
- if (s->hiscnt == hislen - 1) {
- // wrap around
- s->hiscnt = 0;
- } else {
- ++s->hiscnt;
- }
- }
-
- if (s->hiscnt < 0 || history[s->histype][s->hiscnt].hisstr == NULL) {
- s->hiscnt = s->i;
- break;
- }
-
- if ((s->c != K_UP && s->c != K_DOWN)
- || s->hiscnt == s->i
- || STRNCMP(history[s->histype][s->hiscnt].hisstr,
- s->lookfor, (size_t)s->j) == 0) {
- break;
- }
- }
+ bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N
+ || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
+ command_line_next_histidx(s, next_match);
if (s->hiscnt != s->i) {
// jumped to other entry
@@ -1407,6 +1515,17 @@ static int command_line_handle_key(CommandLineState *s)
beep_flush();
return command_line_not_changed(s);
+ case Ctrl_G: // next match
+ case Ctrl_T: // previous match
+ if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
+ if (char_avail()) {
+ return 1;
+ }
+ command_line_next_incsearch(s, s->c == Ctrl_G);
+ return command_line_not_changed(s);
+ }
+ break;
+
case Ctrl_V:
case Ctrl_Q:
s->ignore_drag_release = true;
@@ -1521,7 +1640,7 @@ static int command_line_changed(CommandLineState *s)
return 1;
}
s->incsearch_postponed = false;
- curwin->w_cursor = s->old_cursor; // start at old position
+ curwin->w_cursor = s->search_start; // start at old position
// If there is no command line, don't do anything
if (ccline.cmdlen == 0) {
@@ -1566,16 +1685,11 @@ static int command_line_changed(CommandLineState *s)
if (s->i != 0) {
pos_T save_pos = curwin->w_cursor;
- // First move cursor to end of match, then to the start. This
- // moves the whole match onto the screen when 'nowrap' is set.
- curwin->w_cursor.lnum += search_match_lines;
- curwin->w_cursor.col = search_match_endcol;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
- curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
- }
+ s->match_start = curwin->w_cursor;
+ set_search_match(&curwin->w_cursor);
validate_cursor();
end_pos = curwin->w_cursor;
+ s->match_end = end_pos;
curwin->w_cursor = save_pos;
} else {
end_pos = curwin->w_cursor; // shutup gcc 4
@@ -1617,7 +1731,7 @@ static int command_line_changed(CommandLineState *s)
emsg_silent--; // Unblock error reporting
// Restore the window "view".
- curwin->w_cursor = s->old_cursor;
+ curwin->w_cursor = s->save_cursor;
curwin->w_curswant = s->old_curswant;
curwin->w_leftcol = s->old_leftcol;
curwin->w_topline = s->old_topline;
@@ -4073,7 +4187,7 @@ void ExpandGeneric(
/// @param flagsarg is a combination of EW_* flags.
static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
int flagsarg)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL
{
char_u *pat;
int i;
@@ -4174,10 +4288,8 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
}
}
-/*
- * Call "user_expand_func()" to invoke a user defined VimL function and return
- * the result (either a string or a List).
- */
+/// Call "user_expand_func()" to invoke a user defined Vim script function and
+/// return the result (either a string or a List).
static void * call_user_expand_func(user_expand_func_T user_expand_func,
expand_T *xp, int *num_file, char_u ***file)
{
@@ -5004,7 +5116,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
{
int len;
int first = false;
- long num;
+ varnumber_T num;
*str = skipwhite(*str);
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
@@ -5521,3 +5633,15 @@ histentry_T *hist_get_array(const uint8_t history_type, int **const new_hisidx,
*new_hisnum = &(hisnum[history_type]);
return history[history_type];
}
+
+static void set_search_match(pos_T *t)
+{
+ // First move cursor to end of match, then to the start. This
+ // moves the whole match onto the screen when 'nowrap' is set.
+ t->lnum += search_match_lines;
+ t->col = search_match_endcol;
+ if (t->lnum > curbuf->b_ml.ml_line_count) {
+ t->lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ }
+}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 4063277403..be4188c4df 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -281,8 +281,8 @@ readfile (
colnr_T len;
long size = 0;
char_u *p = NULL;
- off_t filesize = 0;
- int skip_read = FALSE;
+ off_T filesize = 0;
+ int skip_read = false;
context_sha256_T sha_ctx;
int read_undo_file = FALSE;
int split = 0; /* number of split lines */
@@ -777,9 +777,9 @@ retry:
if (read_buffer) {
read_buf_lnum = 1;
read_buf_col = 0;
- } else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0) {
- /* Can't rewind the file, give up. */
- error = TRUE;
+ } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) {
+ // Can't rewind the file, give up.
+ error = true;
goto failed;
}
/* Delete the previously read lines. */
@@ -1614,19 +1614,16 @@ rewind_retry:
if (fileformat == EOL_DOS) {
if (ptr[-1] == CAR) { /* remove CR */
ptr[-1] = NUL;
- --len;
- }
- /*
- * Reading in Dos format, but no CR-LF found!
- * When 'fileformats' includes "unix", delete all
- * the lines read so far and start all over again.
- * Otherwise give an error message later.
- */
- else if (ff_error != EOL_DOS) {
- if ( try_unix
- && !read_stdin
- && (read_buffer
- || lseek(fd, (off_t)0L, SEEK_SET) == 0)) {
+ len--;
+ } else if (ff_error != EOL_DOS) {
+ // Reading in Dos format, but no CR-LF found!
+ // When 'fileformats' includes "unix", delete all
+ // the lines read so far and start all over again.
+ // Otherwise give an error message later.
+ if (try_unix
+ && !read_stdin
+ && (read_buffer
+ || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) {
fileformat = EOL_UNIX;
if (set_options)
set_fileformat(EOL_UNIX, OPT_LOCAL);
@@ -3833,7 +3830,7 @@ static bool msg_add_fileformat(int eol_type)
/*
* Append line and character count to IObuff.
*/
-void msg_add_lines(int insert_space, long lnum, off_t nchars)
+void msg_add_lines(int insert_space, long lnum, off_T nchars)
{
char_u *p;
@@ -6870,8 +6867,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
patcmd.next = active_apc_list;
active_apc_list = &patcmd;
- /* set v:cmdarg (only when there is a matching pattern) */
- save_cmdbang = get_vim_var_nr(VV_CMDBANG);
+ // set v:cmdarg (only when there is a matching pattern)
+ save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
if (eap != NULL) {
save_cmdarg = set_cmdarg(eap, NULL);
set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 9c44e89eed..db88791967 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -2894,7 +2894,7 @@ static void foldlevelExpr(fline_T *flp)
/* KeyTyped may be reset to 0 when calling a function which invokes
* do_cmdline(). To make 'foldopen' work correctly restore KeyTyped. */
save_keytyped = KeyTyped;
- n = eval_foldexpr(flp->wp->w_p_fde, &c);
+ n = (int)eval_foldexpr(flp->wp->w_p_fde, &c);
KeyTyped = save_keytyped;
switch (c) {
diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h
index f1a1d9a563..bd26205d6d 100644
--- a/src/nvim/func_attr.h
+++ b/src/nvim/func_attr.h
@@ -95,6 +95,10 @@
# undef FUNC_ATTR_NORETURN
#endif
+#ifdef FUNC_ATTR_NO_SANITIZE_UNDEFINED
+# undef FUNC_ATTR_NO_SANITIZE_UNDEFINED
+#endif
+
#ifndef DID_REAL_ATTR
# define DID_REAL_ATTR
# ifdef __GNUC__
@@ -122,6 +126,14 @@
# define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
# define REAL_FATTR_ALLOC_SIZE_PROD(x, y) __attribute__((alloc_size(x, y)))
# endif
+
+# if NVIM_HAS_ATTRIBUTE(no_sanitize_undefined)
+# define REAL_FATTR_NO_SANITIZE_UNDEFINED \
+ __attribute__((no_sanitize_undefined))
+# elif NVIM_HAS_ATTRIBUTE(no_sanitize)
+# define REAL_FATTR_NO_SANITIZE_UNDEFINED \
+ __attribute__((no_sanitize("undefined")))
+# endif
# endif
// Define attributes that are not defined for this compiler.
@@ -177,6 +189,10 @@
# ifndef REAL_FATTR_NORETURN
# define REAL_FATTR_NORETURN
# endif
+
+# ifndef REAL_FATTR_NO_SANITIZE_UNDEFINED
+# define REAL_FATTR_NO_SANITIZE_UNDEFINED
+# endif
#endif
#ifdef DEFINE_FUNC_ATTRIBUTES
@@ -198,6 +214,7 @@
# define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__)
# define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET
# define FUNC_ATTR_NORETURN REAL_FATTR_NORETURN
+# define FUNC_ATTR_NO_SANITIZE_UNDEFINED REAL_FATTR_NO_SANITIZE_UNDEFINED
#elif !defined(DO_NOT_DEFINE_EMPTY_ATTRIBUTES)
# define FUNC_ATTR_MALLOC
# define FUNC_ATTR_ALLOC_SIZE(x)
@@ -212,4 +229,5 @@
# define FUNC_ATTR_NONNULL_ARG(...)
# define FUNC_ATTR_NONNULL_RET
# define FUNC_ATTR_NORETURN
+# define FUNC_ATTR_NO_SANITIZE_UNDEFINED
#endif
diff --git a/src/nvim/garray.h b/src/nvim/garray.h
index 5d7806bbfa..94e1b61671 100644
--- a/src/nvim/garray.h
+++ b/src/nvim/garray.h
@@ -37,7 +37,7 @@ typedef struct growarray {
static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size)
{
if ((int)item_size != gap->ga_itemsize) {
- ELOG("wrong item size in garray(%d), should be %d", item_size);
+ WLOG("wrong item size (%d), should be %d", item_size, gap->ga_itemsize);
}
ga_grow(gap, 1);
return ((char *)gap->ga_data) + (item_size * (size_t)gap->ga_len++);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 4e42042959..fc1b8ccfcb 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1806,7 +1806,7 @@ static int vgetorpeek(int advance)
* <M-a> and then changing 'encoding'. Beware
* that 0x80 is escaped. */
char_u *p1 = mp->m_keys;
- char_u *p2 = mb_unescape(&p1);
+ char_u *p2 = (char_u *)mb_unescape((const char **)&p1);
if (has_mbyte && p2 != NULL && MB_BYTE2LEN(c1) > MB_PTR2LEN(p2))
mlen = 0;
@@ -3999,12 +3999,10 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
return OK;
}
- for (; *str != NUL; ++str) {
- char_u *p;
-
- /* Check for a multi-byte character, which may contain escaped
- * K_SPECIAL and CSI bytes */
- p = mb_unescape(&str);
+ for (; *str != NUL; str++) {
+ // Check for a multi-byte character, which may contain escaped
+ // K_SPECIAL and CSI bytes.
+ const char *p = mb_unescape((const char **)&str);
if (p != NULL) {
while (*p != NUL)
if (fputc(*p++, fd) < 0)
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index a3657f2122..6d1bd1de12 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -97,6 +97,34 @@ typedef enum {
EXTERN long Rows INIT(= DFLT_ROWS); // nr of rows in the screen
EXTERN long Columns INIT(= DFLT_COLS); // nr of columns in the screen
+// We use 64-bit file functions here, if available. E.g. ftello() returns
+// off_t instead of long, which helps if long is 32 bit and off_t is 64 bit.
+// We assume that when fseeko() is available then ftello() is too.
+// Note that Windows has different function names.
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
+typedef __int64 off_T;
+# ifdef __MINGW32__
+# define vim_lseek lseek64
+# define vim_fseek fseeko64
+# define vim_ftell ftello64
+# else
+# define vim_lseek _lseeki64
+# define vim_fseek _fseeki64
+# define vim_ftell _ftelli64
+# endif
+#else
+typedef off_t off_T;
+# ifdef HAVE_FSEEKO
+# define vim_lseek lseek
+# define vim_ftell ftello
+# define vim_fseek fseeko
+# else
+# define vim_lseek lseek
+# define vim_ftell ftell
+# define vim_fseek(a, b, c) fseek(a, (long)b, c)
+# endif
+#endif
+
/*
* The characters and attributes cached for the screen.
*/
@@ -411,124 +439,6 @@ EXTERN int did_check_timestamps INIT(= FALSE); /* did check timestamps
recently */
EXTERN int no_check_timestamps INIT(= 0); /* Don't check timestamps */
-/*
- * Values for index in highlight_attr[].
- * When making changes, also update hlf_names below!
- */
-typedef enum {
- HLF_8 = 0 /* Meta & special keys listed with ":map", text that is
- displayed different from what it is */
- , HLF_EOB // after the last line in the buffer
- , HLF_TERM // terminal cursor focused
- , HLF_TERMNC // terminal cursor unfocused
- , HLF_AT // @ characters at end of screen, characters that
- // don't really exist in the text
- , HLF_D // directories in CTRL-D listing
- , HLF_E // error messages
- , HLF_I // incremental search
- , HLF_L // last search string
- , HLF_M // "--More--" message
- , HLF_CM // Mode (e.g., "-- INSERT --")
- , HLF_N // line number for ":number" and ":#" commands
- , HLF_CLN // current line number
- , HLF_R // return to continue message and yes/no questions
- , HLF_S // status lines
- , HLF_SNC // status lines of not-current windows
- , HLF_C // column to separate vertically split windows
- , HLF_T // Titles for output from ":set all", ":autocmd" etc.
- , HLF_V // Visual mode
- , HLF_VNC // Visual mode, autoselecting and not clipboard owner
- , HLF_W // warning messages
- , HLF_WM // Wildmenu highlight
- , HLF_FL // Folded line
- , HLF_FC // Fold column
- , HLF_ADD // Added diff line
- , HLF_CHD // Changed diff line
- , HLF_DED // Deleted diff line
- , HLF_TXD // Text Changed in diff line
- , HLF_SC // Sign column
- , HLF_CONCEAL // Concealed text
- , HLF_SPB // SpellBad
- , HLF_SPC // SpellCap
- , HLF_SPR // SpellRare
- , HLF_SPL // SpellLocal
- , HLF_PNI // popup menu normal item
- , HLF_PSI // popup menu selected item
- , HLF_PSB // popup menu scrollbar
- , HLF_PST // popup menu scrollbar thumb
- , HLF_TP // tabpage line
- , HLF_TPS // tabpage line selected
- , HLF_TPF // tabpage line filler
- , HLF_CUC // 'cursurcolumn'
- , HLF_CUL // 'cursurline'
- , HLF_MC // 'colorcolumn'
- , HLF_QFL // selected quickfix line
- , HLF_0 // Whitespace
- , HLF_INACTIVE // NormalNC: Normal text in non-current windows
- , HLF_COUNT // MUST be the last one
-} hlf_T;
-
-EXTERN const char *hlf_names[] INIT(= {
- [HLF_8] = "SpecialKey",
- [HLF_EOB] = "EndOfBuffer",
- [HLF_TERM] = "TermCursor",
- [HLF_TERMNC] = "TermCursorNC",
- [HLF_AT] = "NonText",
- [HLF_D] = "Directory",
- [HLF_E] = "ErrorMsg",
- [HLF_I] = "IncSearch",
- [HLF_L] = "Search",
- [HLF_M] = "MoreMsg",
- [HLF_CM] = "ModeMsg",
- [HLF_N] = "LineNr",
- [HLF_CLN] = "CursorLineNr",
- [HLF_R] = "Question",
- [HLF_S] = "StatusLine",
- [HLF_SNC] = "StatusLineNC",
- [HLF_C] = "VertSplit",
- [HLF_T] = "Title",
- [HLF_V] = "Visual",
- [HLF_VNC] = "VisualNOS",
- [HLF_W] = "WarningMsg",
- [HLF_WM] = "WildMenu",
- [HLF_FL] = "Folded",
- [HLF_FC] = "FoldColumn",
- [HLF_ADD] = "DiffAdd",
- [HLF_CHD] = "DiffChange",
- [HLF_DED] = "DiffDelete",
- [HLF_TXD] = "DiffText",
- [HLF_SC] = "SignColumn",
- [HLF_CONCEAL] = "Conceal",
- [HLF_SPB] = "SpellBad",
- [HLF_SPC] = "SpellCap",
- [HLF_SPR] = "SpellRare",
- [HLF_SPL] = "SpellLocal",
- [HLF_PNI] = "Pmenu",
- [HLF_PSI] = "PmenuSel",
- [HLF_PSB] = "PmenuSbar",
- [HLF_PST] = "PmenuThumb",
- [HLF_TP] = "TabLine",
- [HLF_TPS] = "TabLineSel",
- [HLF_TPF] = "TabLineFill",
- [HLF_CUC] = "CursorColumn",
- [HLF_CUL] = "CursorLine",
- [HLF_MC] = "ColorColumn",
- [HLF_QFL] = "QuickFixLine",
- [HLF_0] = "Whitespace",
- [HLF_INACTIVE] = "NormalNC",
-});
-
-
-EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */
-EXTERN int highlight_user[9]; /* User[1-9] attributes */
-EXTERN int highlight_stlnc[9]; /* On top of user */
-EXTERN int cterm_normal_fg_color INIT(= 0);
-EXTERN int cterm_normal_fg_bold INIT(= 0);
-EXTERN int cterm_normal_bg_color INIT(= 0);
-EXTERN RgbValue normal_fg INIT(= -1);
-EXTERN RgbValue normal_bg INIT(= -1);
-EXTERN RgbValue normal_sp INIT(= -1);
-
EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */
EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */
@@ -540,7 +450,7 @@ EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when
// When deleting the current buffer, another one must be loaded.
// If we know which one is preferred, au_new_curbuf is set to it.
-EXTERN bufref_T au_new_curbuf INIT(= { NULL, 0 });
+EXTERN bufref_T au_new_curbuf INIT(= { NULL, 0, 0 });
// When deleting a buffer/window and autocmd_busy is TRUE, do not free the
// buffer/window. but link it in the list starting with
@@ -987,7 +897,7 @@ EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd
// for CursorMoved event
EXTERN pos_T last_cursormoved INIT(= INIT_POS_T(0, 0, 0));
-EXTERN int last_changedtick INIT(= 0); // for TextChanged event
+EXTERN varnumber_T last_changedtick INIT(= 0); // for TextChanged event
EXTERN buf_T *last_changedtick_buf INIT(= NULL);
EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */
@@ -1221,6 +1131,7 @@ EXTERN char_u e_longname[] INIT(= N_("E75: Name too long"));
EXTERN char_u e_toomsbra[] INIT(= N_("E76: Too many ["));
EXTERN char_u e_toomany[] INIT(= N_("E77: Too many file names"));
EXTERN char_u e_trailing[] INIT(= N_("E488: Trailing characters"));
+EXTERN char_u e_trailing2[] INIT(= N_("E488: Trailing characters: %s"));
EXTERN char_u e_umark[] INIT(= N_("E78: Unknown mark"));
EXTERN char_u e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
EXTERN char_u e_winheight[] INIT(= N_(
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
new file mode 100644
index 0000000000..927fc94bbe
--- /dev/null
+++ b/src/nvim/highlight_defs.h
@@ -0,0 +1,126 @@
+#ifndef NVIM_HIGHLIGHT_DEFS_H
+#define NVIM_HIGHLIGHT_DEFS_H
+
+#include <inttypes.h>
+
+#include "nvim/macros.h"
+
+typedef int32_t RgbValue;
+
+/// Values for index in highlight_attr[].
+/// When making changes, also update hlf_names below!
+typedef enum {
+ HLF_8 = 0 // Meta & special keys listed with ":map", text that is
+ // displayed different from what it is
+ , HLF_EOB // after the last line in the buffer
+ , HLF_TERM // terminal cursor focused
+ , HLF_TERMNC // terminal cursor unfocused
+ , HLF_AT // @ characters at end of screen, characters that
+ // don't really exist in the text
+ , HLF_D // directories in CTRL-D listing
+ , HLF_E // error messages
+ , HLF_I // incremental search
+ , HLF_L // last search string
+ , HLF_M // "--More--" message
+ , HLF_CM // Mode (e.g., "-- INSERT --")
+ , HLF_N // line number for ":number" and ":#" commands
+ , HLF_CLN // current line number
+ , HLF_R // return to continue message and yes/no questions
+ , HLF_S // status lines
+ , HLF_SNC // status lines of not-current windows
+ , HLF_C // column to separate vertically split windows
+ , HLF_T // Titles for output from ":set all", ":autocmd" etc.
+ , HLF_V // Visual mode
+ , HLF_VNC // Visual mode, autoselecting and not clipboard owner
+ , HLF_W // warning messages
+ , HLF_WM // Wildmenu highlight
+ , HLF_FL // Folded line
+ , HLF_FC // Fold column
+ , HLF_ADD // Added diff line
+ , HLF_CHD // Changed diff line
+ , HLF_DED // Deleted diff line
+ , HLF_TXD // Text Changed in diff line
+ , HLF_SC // Sign column
+ , HLF_CONCEAL // Concealed text
+ , HLF_SPB // SpellBad
+ , HLF_SPC // SpellCap
+ , HLF_SPR // SpellRare
+ , HLF_SPL // SpellLocal
+ , HLF_PNI // popup menu normal item
+ , HLF_PSI // popup menu selected item
+ , HLF_PSB // popup menu scrollbar
+ , HLF_PST // popup menu scrollbar thumb
+ , HLF_TP // tabpage line
+ , HLF_TPS // tabpage line selected
+ , HLF_TPF // tabpage line filler
+ , HLF_CUC // 'cursurcolumn'
+ , HLF_CUL // 'cursurline'
+ , HLF_MC // 'colorcolumn'
+ , HLF_QFL // selected quickfix line
+ , HLF_0 // Whitespace
+ , HLF_INACTIVE // NormalNC: Normal text in non-current windows
+ , HLF_COUNT // MUST be the last one
+} hlf_T;
+
+EXTERN const char *hlf_names[] INIT(= {
+ [HLF_8] = "SpecialKey",
+ [HLF_EOB] = "EndOfBuffer",
+ [HLF_TERM] = "TermCursor",
+ [HLF_TERMNC] = "TermCursorNC",
+ [HLF_AT] = "NonText",
+ [HLF_D] = "Directory",
+ [HLF_E] = "ErrorMsg",
+ [HLF_I] = "IncSearch",
+ [HLF_L] = "Search",
+ [HLF_M] = "MoreMsg",
+ [HLF_CM] = "ModeMsg",
+ [HLF_N] = "LineNr",
+ [HLF_CLN] = "CursorLineNr",
+ [HLF_R] = "Question",
+ [HLF_S] = "StatusLine",
+ [HLF_SNC] = "StatusLineNC",
+ [HLF_C] = "VertSplit",
+ [HLF_T] = "Title",
+ [HLF_V] = "Visual",
+ [HLF_VNC] = "VisualNC",
+ [HLF_W] = "WarningMsg",
+ [HLF_WM] = "WildMenu",
+ [HLF_FL] = "Folded",
+ [HLF_FC] = "FoldColumn",
+ [HLF_ADD] = "DiffAdd",
+ [HLF_CHD] = "DiffChange",
+ [HLF_DED] = "DiffDelete",
+ [HLF_TXD] = "DiffText",
+ [HLF_SC] = "SignColumn",
+ [HLF_CONCEAL] = "Conceal",
+ [HLF_SPB] = "SpellBad",
+ [HLF_SPC] = "SpellCap",
+ [HLF_SPR] = "SpellRare",
+ [HLF_SPL] = "SpellLocal",
+ [HLF_PNI] = "Pmenu",
+ [HLF_PSI] = "PmenuSel",
+ [HLF_PSB] = "PmenuSbar",
+ [HLF_PST] = "PmenuThumb",
+ [HLF_TP] = "TabLine",
+ [HLF_TPS] = "TabLineSel",
+ [HLF_TPF] = "TabLineFill",
+ [HLF_CUC] = "CursorColumn",
+ [HLF_CUL] = "CursorLine",
+ [HLF_MC] = "ColorColumn",
+ [HLF_QFL] = "QuickFixLine",
+ [HLF_0] = "Whitespace",
+ [HLF_INACTIVE] = "NormalNC"
+});
+
+
+EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
+EXTERN int highlight_user[9]; // User[1-9] attributes
+EXTERN int highlight_stlnc[9]; // On top of user
+EXTERN int cterm_normal_fg_color INIT(= 0);
+EXTERN int cterm_normal_fg_bold INIT(= 0);
+EXTERN int cterm_normal_bg_color INIT(= 0);
+EXTERN RgbValue normal_fg INIT(= -1);
+EXTERN RgbValue normal_bg INIT(= -1);
+EXTERN RgbValue normal_sp INIT(= -1);
+
+#endif // NVIM_HIGHLIGHT_DEFS_H
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 5471b41b2c..efca739c2d 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -471,7 +471,7 @@ int get_breakindent_win(win_T *wp, char_u *line) {
|| prev_tick != wp->w_buffer->b_changedtick) {
prev_line = line;
prev_ts = wp->w_buffer->b_p_ts;
- prev_tick = wp->w_buffer->b_changedtick;
+ prev_tick = (int)wp->w_buffer->b_changedtick;
prev_indent = get_indent_str(line,
(int)wp->w_buffer->b_p_ts, wp->w_p_list);
}
@@ -538,7 +538,7 @@ int get_expr_indent(void)
sandbox++;
}
textlock++;
- indent = eval_to_number(curbuf->b_p_inde);
+ indent = (int)eval_to_number(curbuf->b_p_inde);
if (use_sandbox) {
sandbox--;
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 4806f46705..fd194a4080 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -822,21 +822,22 @@ cin_isterminated (
return found_start;
}
-/*
- * Recognize the basic picture of a function declaration -- it needs to
- * have an open paren somewhere and a close paren at the end of the line and
- * no semicolons anywhere.
- * When a line ends in a comma we continue looking in the next line.
- * "sp" points to a string with the line. When looking at other lines it must
- * be restored to the line. When it's NULL fetch lines here.
- * "lnum" is where we start looking.
- * "min_lnum" is the line before which we will not be looking.
- */
+/// Recognizes the basic picture of a function declaration -- it needs to
+/// have an open paren somewhere and a close paren at the end of the line and
+/// no semicolons anywhere.
+/// When a line ends in a comma we continue looking in the next line.
+///
+/// @param[in] sp Points to a string with the line. When looking at other
+/// lines it must be restored to the line. When it's NULL fetch
+/// lines here.
+/// @param[in] first_lnum Where to start looking.
+/// @param[in] min_lnum The line before which we will not be looking.
static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum)
{
char_u *s;
linenr_T lnum = first_lnum;
- int retval = FALSE;
+ linenr_T save_lnum = curwin->w_cursor.lnum;
+ int retval = false;
pos_T *trypos;
int just_started = TRUE;
@@ -845,18 +846,22 @@ static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum)
else
s = *sp;
+ curwin->w_cursor.lnum = lnum;
if (find_last_paren(s, '(', ')')
&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) {
lnum = trypos->lnum;
- if (lnum < min_lnum)
- return FALSE;
-
+ if (lnum < min_lnum) {
+ curwin->w_cursor.lnum = save_lnum;
+ return false;
+ }
s = ml_get(lnum);
}
- /* Ignore line starting with #. */
- if (cin_ispreproc(s))
- return FALSE;
+ curwin->w_cursor.lnum = save_lnum;
+ // Ignore line starting with #.
+ if (cin_ispreproc(s)) {
+ return false;
+ }
while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"') {
// ignore comments
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 9c5fe78c7c..ee67b4c19d 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -557,7 +557,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
int modifiers;
int bit;
int key;
- unsigned long n;
+ uvarnumber_T n;
int l;
if (src_len == 0) {
diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h
new file mode 100644
index 0000000000..a3943054e6
--- /dev/null
+++ b/src/nvim/lib/kbtree.h
@@ -0,0 +1,451 @@
+/*-
+ * Copyright 1997-1999, 2001, John-Mark Gurney.
+ * 2008-2009, Attractive Chaos <attractor@live.co.uk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef NVIM_LIB_KBTREE_H
+#define NVIM_LIB_KBTREE_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "nvim/memory.h"
+
+#define KB_MAX_DEPTH 64
+
+#define __KB_KEY(type, x) (x->key)
+#define __KB_PTR(btr, x) (x->ptr)
+
+#define __KB_TREE_T(name,key_t,T) \
+ typedef struct kbnode_##name##_s kbnode_##name##_t; \
+ struct kbnode_##name##_s { \
+ int32_t n; \
+ bool is_internal; \
+ key_t key[2*T-1]; \
+ kbnode_##name##_t *ptr[]; \
+ } ; \
+ \
+ typedef struct { \
+ kbnode_##name##_t *root; \
+ int n_keys, n_nodes; \
+ } kbtree_##name##_t; \
+ \
+ typedef struct { \
+ kbnode_##name##_t *x; \
+ int i; \
+ } kbpos_##name##_t; \
+ typedef struct { \
+ kbpos_##name##_t stack[KB_MAX_DEPTH], *p; \
+ } kbitr_##name##_t; \
+
+
+#define __kb_destroy(kbnode_t,b) do { \
+ int i; \
+ unsigned int max = 8; \
+ kbnode_t *x, **top, **stack = 0; \
+ if (b->root) { \
+ top = stack = (kbnode_t**)xcalloc(max, sizeof(kbnode_t*)); \
+ *top++ = (b)->root; \
+ while (top != stack) { \
+ x = *--top; \
+ if (x->is_internal == 0) { xfree(x); continue; } \
+ for (i = 0; i <= x->n; ++i) \
+ if (__KB_PTR(b, x)[i]) { \
+ if (top - stack == (int)max) { \
+ max <<= 1; \
+ stack = (kbnode_t**)xrealloc(stack, max * sizeof(kbnode_t*)); \
+ top = stack + (max>>1); \
+ } \
+ *top++ = __KB_PTR(b, x)[i]; \
+ } \
+ xfree(x); \
+ } \
+ } \
+ xfree(stack); \
+ } while (0)
+
+#define __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \
+ static inline int __kb_getp_aux_##name(const kbnode_t * __restrict x, key_t * __restrict k, int *r) \
+ { \
+ int tr, *rr, begin = 0, end = x->n; \
+ if (x->n == 0) return -1; \
+ rr = r? r : &tr; \
+ while (begin < end) { \
+ int mid = (begin + end) >> 1; \
+ if (__cmp(__KB_KEY(key_t, x)[mid], *k) < 0) begin = mid + 1; \
+ else end = mid; \
+ } \
+ if (begin == x->n) { *rr = 1; return x->n - 1; } \
+ if ((*rr = __cmp(*k, __KB_KEY(key_t, x)[begin])) < 0) --begin; \
+ return begin; \
+ }
+
+#define __KB_GET(name, key_t, kbnode_t) \
+ static key_t *kb_getp_##name(kbtree_##name##_t *b, key_t * __restrict k) \
+ { \
+ if (!b->root) { \
+ return 0; \
+ } \
+ int i, r = 0; \
+ kbnode_t *x = b->root; \
+ while (x) { \
+ i = __kb_getp_aux_##name(x, k, &r); \
+ if (i >= 0 && r == 0) return &__KB_KEY(key_t, x)[i]; \
+ if (x->is_internal == 0) return 0; \
+ x = __KB_PTR(b, x)[i + 1]; \
+ } \
+ return 0; \
+ } \
+ static inline key_t *kb_get_##name(kbtree_##name##_t *b, key_t k) \
+ { \
+ return kb_getp_##name(b, &k); \
+ }
+
+#define __KB_INTERVAL(name, key_t, kbnode_t) \
+ static inline void kb_intervalp_##name(kbtree_##name##_t *b, key_t * __restrict k, key_t **lower, key_t **upper) \
+ { \
+ if (!b->root) { \
+ return; \
+ } \
+ int i, r = 0; \
+ kbnode_t *x = b->root; \
+ *lower = *upper = 0; \
+ while (x) { \
+ i = __kb_getp_aux_##name(x, k, &r); \
+ if (i >= 0 && r == 0) { \
+ *lower = *upper = &__KB_KEY(key_t, x)[i]; \
+ return; \
+ } \
+ if (i >= 0) *lower = &__KB_KEY(key_t, x)[i]; \
+ if (i < x->n - 1) *upper = &__KB_KEY(key_t, x)[i + 1]; \
+ if (x->is_internal == 0) return; \
+ x = __KB_PTR(b, x)[i + 1]; \
+ } \
+ } \
+ static inline void kb_interval_##name(kbtree_##name##_t *b, key_t k, key_t **lower, key_t **upper) \
+ { \
+ kb_intervalp_##name(b, &k, lower, upper); \
+ }
+
+#define __KB_PUT(name, key_t, kbnode_t, __cmp, T, ILEN) \
+ /* x must be an internal node */ \
+ static inline void __kb_split_##name(kbtree_##name##_t *b, kbnode_t *x, int i, kbnode_t *y) \
+ { \
+ kbnode_t *z; \
+ z = (kbnode_t*)xcalloc(1, y->is_internal? ILEN : sizeof(kbnode_##name##_t)); \
+ ++b->n_nodes; \
+ z->is_internal = y->is_internal; \
+ z->n = T - 1; \
+ memcpy(__KB_KEY(key_t, z), &__KB_KEY(key_t, y)[T], sizeof(key_t) * (T - 1)); \
+ if (y->is_internal) memcpy(__KB_PTR(b, z), &__KB_PTR(b, y)[T], sizeof(void*) * T); \
+ y->n = T - 1; \
+ memmove(&__KB_PTR(b, x)[i + 2], &__KB_PTR(b, x)[i + 1], sizeof(void*) * (unsigned int)(x->n - i)); \
+ __KB_PTR(b, x)[i + 1] = z; \
+ memmove(&__KB_KEY(key_t, x)[i + 1], &__KB_KEY(key_t, x)[i], sizeof(key_t) * (unsigned int)(x->n - i)); \
+ __KB_KEY(key_t, x)[i] = __KB_KEY(key_t, y)[T - 1]; \
+ ++x->n; \
+ } \
+ static inline key_t *__kb_putp_aux_##name(kbtree_##name##_t *b, kbnode_t *x, key_t * __restrict k) \
+ { \
+ int i = x->n - 1; \
+ key_t *ret; \
+ if (x->is_internal == 0) { \
+ i = __kb_getp_aux_##name(x, k, 0); \
+ if (i != x->n - 1) \
+ memmove(&__KB_KEY(key_t, x)[i + 2], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
+ ret = &__KB_KEY(key_t, x)[i + 1]; \
+ *ret = *k; \
+ ++x->n; \
+ } else { \
+ i = __kb_getp_aux_##name(x, k, 0) + 1; \
+ if (__KB_PTR(b, x)[i]->n == 2 * T - 1) { \
+ __kb_split_##name(b, x, i, __KB_PTR(b, x)[i]); \
+ if (__cmp(*k, __KB_KEY(key_t, x)[i]) > 0) ++i; \
+ } \
+ ret = __kb_putp_aux_##name(b, __KB_PTR(b, x)[i], k); \
+ } \
+ return ret; \
+ } \
+ static inline key_t *kb_putp_##name(kbtree_##name##_t *b, key_t * __restrict k) \
+ { \
+ if (!b->root) { \
+ b->root = (kbnode_t*)xcalloc(1, ILEN); \
+ ++b->n_nodes; \
+ } \
+ kbnode_t *r, *s; \
+ ++b->n_keys; \
+ r = b->root; \
+ if (r->n == 2 * T - 1) { \
+ ++b->n_nodes; \
+ s = (kbnode_t*)xcalloc(1, ILEN); \
+ b->root = s; s->is_internal = 1; s->n = 0; \
+ __KB_PTR(b, s)[0] = r; \
+ __kb_split_##name(b, s, 0, r); \
+ r = s; \
+ } \
+ return __kb_putp_aux_##name(b, r, k); \
+ } \
+ static inline void kb_put_##name(kbtree_##name##_t *b, key_t k) \
+ { \
+ kb_putp_##name(b, &k); \
+ }
+
+
+#define __KB_DEL(name, key_t, kbnode_t, T) \
+ static inline key_t __kb_delp_aux_##name(kbtree_##name##_t *b, kbnode_t *x, key_t * __restrict k, int s) \
+ { \
+ int yn, zn, i, r = 0; \
+ kbnode_t *xp, *y, *z; \
+ key_t kp; \
+ if (x == 0) return *k; \
+ if (s) { /* s can only be 0, 1 or 2 */ \
+ r = x->is_internal == 0? 0 : s == 1? 1 : -1; \
+ i = s == 1? x->n - 1 : -1; \
+ } else i = __kb_getp_aux_##name(x, k, &r); \
+ if (x->is_internal == 0) { \
+ if (s == 2) ++i; \
+ kp = __KB_KEY(key_t, x)[i]; \
+ memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
+ --x->n; \
+ return kp; \
+ } \
+ if (r == 0) { \
+ if ((yn = __KB_PTR(b, x)[i]->n) >= T) { \
+ xp = __KB_PTR(b, x)[i]; \
+ kp = __KB_KEY(key_t, x)[i]; \
+ __KB_KEY(key_t, x)[i] = __kb_delp_aux_##name(b, xp, 0, 1); \
+ return kp; \
+ } else if ((zn = __KB_PTR(b, x)[i + 1]->n) >= T) { \
+ xp = __KB_PTR(b, x)[i + 1]; \
+ kp = __KB_KEY(key_t, x)[i]; \
+ __KB_KEY(key_t, x)[i] = __kb_delp_aux_##name(b, xp, 0, 2); \
+ return kp; \
+ } else if (yn == T - 1 && zn == T - 1) { \
+ y = __KB_PTR(b, x)[i]; z = __KB_PTR(b, x)[i + 1]; \
+ __KB_KEY(key_t, y)[y->n++] = *k; \
+ memmove(&__KB_KEY(key_t, y)[y->n], __KB_KEY(key_t, z), (unsigned int)z->n * sizeof(key_t)); \
+ if (y->is_internal) memmove(&__KB_PTR(b, y)[y->n], __KB_PTR(b, z), (unsigned int)(z->n + 1) * sizeof(void*)); \
+ y->n += z->n; \
+ memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
+ memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \
+ --x->n; \
+ xfree(z); \
+ return __kb_delp_aux_##name(b, y, k, s); \
+ } \
+ } \
+ ++i; \
+ if ((xp = __KB_PTR(b, x)[i])->n == T - 1) { \
+ if (i > 0 && (y = __KB_PTR(b, x)[i - 1])->n >= T) { \
+ memmove(&__KB_KEY(key_t, xp)[1], __KB_KEY(key_t, xp), (unsigned int)xp->n * sizeof(key_t)); \
+ if (xp->is_internal) memmove(&__KB_PTR(b, xp)[1], __KB_PTR(b, xp), (unsigned int)(xp->n + 1) * sizeof(void*)); \
+ __KB_KEY(key_t, xp)[0] = __KB_KEY(key_t, x)[i - 1]; \
+ __KB_KEY(key_t, x)[i - 1] = __KB_KEY(key_t, y)[y->n - 1]; \
+ if (xp->is_internal) __KB_PTR(b, xp)[0] = __KB_PTR(b, y)[y->n]; \
+ --y->n; ++xp->n; \
+ } else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n >= T) { \
+ __KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \
+ __KB_KEY(key_t, x)[i] = __KB_KEY(key_t, y)[0]; \
+ if (xp->is_internal) __KB_PTR(b, xp)[xp->n] = __KB_PTR(b, y)[0]; \
+ --y->n; \
+ memmove(__KB_KEY(key_t, y), &__KB_KEY(key_t, y)[1], (unsigned int)y->n * sizeof(key_t)); \
+ if (y->is_internal) memmove(__KB_PTR(b, y), &__KB_PTR(b, y)[1], (unsigned int)(y->n + 1) * sizeof(void*)); \
+ } else if (i > 0 && (y = __KB_PTR(b, x)[i - 1])->n == T - 1) { \
+ __KB_KEY(key_t, y)[y->n++] = __KB_KEY(key_t, x)[i - 1]; \
+ memmove(&__KB_KEY(key_t, y)[y->n], __KB_KEY(key_t, xp), (unsigned int)xp->n * sizeof(key_t)); \
+ if (y->is_internal) memmove(&__KB_PTR(b, y)[y->n], __KB_PTR(b, xp), (unsigned int)(xp->n + 1) * sizeof(void*)); \
+ y->n += xp->n; \
+ memmove(&__KB_KEY(key_t, x)[i - 1], &__KB_KEY(key_t, x)[i], (unsigned int)(x->n - i) * sizeof(key_t)); \
+ memmove(&__KB_PTR(b, x)[i], &__KB_PTR(b, x)[i + 1], (unsigned int)(x->n - i) * sizeof(void*)); \
+ --x->n; \
+ xfree(xp); \
+ xp = y; \
+ } else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n == T - 1) { \
+ __KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \
+ memmove(&__KB_KEY(key_t, xp)[xp->n], __KB_KEY(key_t, y), (unsigned int)y->n * sizeof(key_t)); \
+ if (xp->is_internal) memmove(&__KB_PTR(b, xp)[xp->n], __KB_PTR(b, y), (unsigned int)(y->n + 1) * sizeof(void*)); \
+ xp->n += y->n; \
+ memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \
+ memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \
+ --x->n; \
+ xfree(y); \
+ } \
+ } \
+ return __kb_delp_aux_##name(b, xp, k, s); \
+ } \
+ static inline key_t kb_delp_##name(kbtree_##name##_t *b, key_t * __restrict k) \
+ { \
+ kbnode_t *x; \
+ key_t ret; \
+ ret = __kb_delp_aux_##name(b, b->root, k, 0); \
+ --b->n_keys; \
+ if (b->root->n == 0 && b->root->is_internal) { \
+ --b->n_nodes; \
+ x = b->root; \
+ b->root = __KB_PTR(b, x)[0]; \
+ xfree(x); \
+ } \
+ return ret; \
+ } \
+ static inline key_t kb_del_##name(kbtree_##name##_t *b, key_t k) \
+ { \
+ return kb_delp_##name(b, &k); \
+ }
+
+#define __KB_ITR(name, key_t, kbnode_t) \
+ static inline void kb_itr_first_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \
+ { \
+ itr->p = 0; \
+ if (b->n_keys == 0) return; \
+ itr->p = itr->stack; \
+ itr->p->x = b->root; itr->p->i = 0; \
+ while (itr->p->x->is_internal && __KB_PTR(b, itr->p->x)[0] != 0) { \
+ kbnode_t *x = itr->p->x; \
+ ++itr->p; \
+ itr->p->x = __KB_PTR(b, x)[0]; itr->p->i = 0; \
+ } \
+ } \
+ static inline int kb_itr_next_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \
+ { \
+ if (itr->p < itr->stack) return 0; \
+ for (;;) { \
+ ++itr->p->i; \
+ while (itr->p->x && itr->p->i <= itr->p->x->n) { \
+ itr->p[1].i = 0; \
+ itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[itr->p->i] : 0; \
+ ++itr->p; \
+ } \
+ --itr->p; \
+ if (itr->p < itr->stack) return 0; \
+ if (itr->p->x && itr->p->i < itr->p->x->n) return 1; \
+ } \
+ } \
+ static inline int kb_itr_prev_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \
+ { \
+ if (itr->p < itr->stack) return 0; \
+ for (;;) { \
+ while (itr->p->x && itr->p->i >= 0) { \
+ itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[itr->p->i] : 0; \
+ itr->p[1].i = itr->p[1].x ? itr->p[1].x->n : -1; \
+ ++itr->p; \
+ } \
+ --itr->p; \
+ if (itr->p < itr->stack) return 0; \
+ --itr->p->i; \
+ if (itr->p->x && itr->p->i >= 0) return 1; \
+ } \
+ } \
+ static inline int kb_itr_getp_##name(kbtree_##name##_t *b, key_t * __restrict k, kbitr_##name##_t *itr) \
+ { \
+ if (b->n_keys == 0) { \
+ itr->p = NULL; \
+ return 0; \
+ } \
+ int i, r = 0; \
+ itr->p = itr->stack; \
+ itr->p->x = b->root; \
+ while (itr->p->x) { \
+ i = __kb_getp_aux_##name(itr->p->x, k, &r); \
+ itr->p->i = i; \
+ if (i >= 0 && r == 0) return 1; \
+ ++itr->p->i; \
+ itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[i + 1] : 0; \
+ ++itr->p; \
+ } \
+ return 0; \
+ } \
+ static inline int kb_itr_get_##name(kbtree_##name##_t *b, key_t k, kbitr_##name##_t *itr) \
+ { \
+ return kb_itr_getp_##name(b,&k,itr); \
+ } \
+ static inline void kb_del_itr_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \
+ { \
+ key_t k = kb_itr_key(itr); \
+ kb_delp_##name(b, &k); \
+ kb_itr_getp_##name(b, &k, itr); \
+ }
+
+#define KBTREE_INIT(name, key_t, __cmp, T) \
+ KBTREE_INIT_IMPL(name, key_t, kbnode_##name##_t, __cmp, T, (sizeof(kbnode_##name##_t)+(2*T)*sizeof(void *)))
+
+#if (!defined(__clang__) && !defined(__INTEL_COMPILER)) && (__GNUC__ > 4 )
+
+// The index trickery shouldn't be UB anymore,
+// still it is to much for gcc:s -Werror=array-bounds
+# define __KB_PRAGMA_START \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+
+# define __KB_PRAGMA_END \
+ _Pragma("GCC diagnostic pop") \
+
+#else
+
+# define __KB_PRAGMA_START
+# define __KB_PRAGMA_END
+
+#endif
+
+#define KBTREE_INIT_IMPL(name, key_t, kbnode_t, __cmp, T, ILEN) \
+ __KB_PRAGMA_START \
+ __KB_TREE_T(name, key_t, T) \
+ __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \
+ __KB_GET(name, key_t, kbnode_t) \
+ __KB_INTERVAL(name, key_t, kbnode_t) \
+ __KB_PUT(name, key_t, kbnode_t, __cmp, T, ILEN) \
+ __KB_DEL(name, key_t, kbnode_t, T) \
+ __KB_ITR(name, key_t, kbnode_t) \
+ __KB_PRAGMA_END
+
+#define KB_DEFAULT_SIZE 512
+
+#define kbtree_t(name) kbtree_##name##_t
+#define kbitr_t(name) kbitr_##name##_t
+#define kb_init(b) ((b)->n_keys = (b)->n_nodes = 0, (b)->root = 0)
+#define kb_destroy(name, b) __kb_destroy(kbnode_##name##_t, b)
+#define kb_get(name, b, k) kb_get_##name(b, k)
+#define kb_put(name, b, k) kb_put_##name(b, k)
+#define kb_del(name, b, k) kb_del_##name(b, k)
+#define kb_interval(name, b, k, l, u) kb_interval_##name(b, k, l, u)
+#define kb_getp(name, b, k) kb_getp_##name(b, k)
+#define kb_putp(name, b, k) kb_putp_##name(b, k)
+#define kb_delp(name, b, k) kb_delp_##name(b, k)
+#define kb_intervalp(name, b, k, l, u) kb_intervalp_##name(b, k, l, u)
+
+#define kb_itr_first(name, b, i) kb_itr_first_##name(b, i)
+#define kb_itr_get(name, b, k, i) kb_itr_get_##name(b, k, i)
+#define kb_itr_getp(name, b, k, i) kb_itr_getp_##name(b, k, i)
+#define kb_itr_next(name, b, i) kb_itr_next_##name(b, i)
+#define kb_itr_prev(name, b, i) kb_itr_prev_##name(b, i)
+#define kb_del_itr(name, b, i) kb_del_itr_##name(b, i)
+#define kb_itr_key(itr) __KB_KEY(dummy, (itr)->p->x)[(itr)->p->i]
+#define kb_itr_valid(itr) ((itr)->p >= (itr)->stack)
+
+#define kb_size(b) ((b)->n_keys)
+
+#define kb_generic_cmp(a, b) (((b) < (a)) - ((a) < (b)))
+#define kb_str_cmp(a, b) strcmp(a, b)
+
+#endif // NVIM_LIB_KBTREE_H
diff --git a/src/nvim/log.c b/src/nvim/log.c
index d059e28d5d..f1dbe61dda 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -7,20 +7,17 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+#include <uv.h>
#include "nvim/log.h"
#include "nvim/types.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-/// First location of the log file used by log_path_init()
-#define USR_LOG_FILE "$NVIM_LOG_FILE"
+#define LOG_FILE_ENV "NVIM_LOG_FILE"
-/// Fall back location of the log file used by log_path_init()
-#define USR_LOG_FILE_2 "$HOME" _PATHSEPSTR ".nvimlog"
-
-/// Cached location of the log file set by log_path_init()
-static char expanded_log_file_path[MAXPATHL + 1] = { 0 };
+/// Cached location of the expanded log file path decided by log_path_init().
+static char log_file_path[MAXPATHL + 1] = { 0 };
static uv_mutex_t mutex;
@@ -28,31 +25,53 @@ static uv_mutex_t mutex;
# include "log.c.generated.h"
#endif
-/// Initialize path to log file
+static bool log_try_create(char *fname)
+{
+ if (fname == NULL || fname[0] == '\0') {
+ return false;
+ }
+ FILE *log_file = fopen(fname, "a");
+ if (log_file == NULL) {
+ return false;
+ }
+ fclose(log_file);
+ return true;
+}
+
+/// Initializes path to log file. Sets $NVIM_LOG_FILE if empty.
///
-/// Tries to use #USR_LOG_FILE, then falls back #USR_LOG_FILE_2. Path to log
+/// Tries $NVIM_LOG_FILE, or falls back to $XDG_DATA_HOME/nvim/log. Path to log
/// file is cached, so only the first call has effect, unless first call was not
-/// successful. To make initialization not succeed either a bug in expand_env()
-/// is needed or both `$NVIM_LOG_FILE` and `$HOME` environment variables
-/// undefined.
+/// successful. Failed initialization indicates either a bug in expand_env()
+/// or both $NVIM_LOG_FILE and $HOME environment variables are undefined.
///
/// @return true if path was initialized, false otherwise.
static bool log_path_init(void)
{
- if (expanded_log_file_path[0]) {
+ if (log_file_path[0]) {
return true;
}
- expand_env((char_u *)USR_LOG_FILE, (char_u *)expanded_log_file_path,
- sizeof(expanded_log_file_path) - 1);
- // if the log file path expansion failed then fall back to stderr
- if (strcmp(USR_LOG_FILE, expanded_log_file_path) == 0) {
- memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path));
- expand_env((char_u *)USR_LOG_FILE_2, (char_u *)expanded_log_file_path,
- sizeof(expanded_log_file_path) - 1);
- if (strcmp(USR_LOG_FILE_2, expanded_log_file_path) == 0) {
- memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path));
+ size_t size = sizeof(log_file_path);
+ expand_env((char_u *)"$" LOG_FILE_ENV, (char_u *)log_file_path,
+ (int)size - 1);
+ if (strequal("$" LOG_FILE_ENV, log_file_path)
+ || log_file_path[0] == '\0'
+ || os_isdir((char_u *)log_file_path)
+ || !log_try_create(log_file_path)) {
+ // Invalid $NVIM_LOG_FILE or failed to expand; fall back to default.
+ char *defaultpath = stdpaths_user_data_subpath("log", 0, true);
+ size_t len = xstrlcpy(log_file_path, defaultpath, size);
+ xfree(defaultpath);
+ // Fall back to .nvimlog
+ if (len >= size || !log_try_create(log_file_path)) {
+ len = xstrlcpy(log_file_path, ".nvimlog", size);
+ }
+ // Fall back to stderr
+ if (len >= size || !log_try_create(log_file_path)) {
+ log_file_path[0] = '\0';
return false;
}
+ os_setenv(LOG_FILE_ENV, log_file_path, true);
}
return true;
}
@@ -75,6 +94,10 @@ void log_unlock(void)
bool do_log(int log_level, const char *func_name, int line_num, bool eol,
const char* fmt, ...) FUNC_ATTR_UNUSED
{
+ if (log_level < MIN_LOG_LEVEL) {
+ return false;
+ }
+
log_lock();
bool ret = false;
FILE *log_file = open_log_file();
@@ -97,26 +120,42 @@ end:
return ret;
}
+void log_uv_handles(void *loop)
+{
+ uv_loop_t *l = loop;
+ log_lock();
+ FILE *log_file = open_log_file();
+
+ if (log_file == NULL) {
+ goto end;
+ }
+
+ uv_print_all_handles(l, log_file);
+
+ if (log_file != stderr && log_file != stdout) {
+ fclose(log_file);
+ }
+end:
+ log_unlock();
+}
+
/// Open the log file for appending.
///
-/// @return The FILE* specified by the USR_LOG_FILE path or stderr in case of
-/// error
+/// @return FILE* decided by log_path_init() or stderr in case of error
FILE *open_log_file(void)
{
static bool opening_log_file = false;
-
// check if it's a recursive call
if (opening_log_file) {
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
- "Trying to LOG() recursively! Please fix it.");
+ "Cannot LOG() recursively.");
return stderr;
}
- // expand USR_LOG_FILE if needed and open the file
FILE *log_file = NULL;
opening_log_file = true;
if (log_path_init()) {
- log_file = fopen(expanded_log_file_path, "a");
+ log_file = fopen(log_file_path, "a");
}
opening_log_file = false;
@@ -124,10 +163,13 @@ FILE *open_log_file(void)
return log_file;
}
+ // May happen if:
+ // - LOG() is called before early_init()
+ // - Directory does not exist
+ // - File is not writable
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
- "Couldn't open USR_LOG_FILE, logging to stderr! This may be "
- "caused by attempting to LOG() before initialization "
- "functions are called (e.g. init_homedir()).");
+ "Logging to stderr, failed to open $" LOG_FILE_ENV ": %s",
+ log_file_path);
return stderr;
}
@@ -152,7 +194,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
[DEBUG_LOG_LEVEL] = "DEBUG",
[INFO_LOG_LEVEL] = "INFO ",
[WARNING_LOG_LEVEL] = "WARN ",
- [ERROR_LOG_LEVEL] = "ERROR"
+ [ERROR_LOG_LEVEL] = "ERROR",
};
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
diff --git a/src/nvim/log.h b/src/nvim/log.h
index 32b7276f14..221f0bbaf6 100644
--- a/src/nvim/log.h
+++ b/src/nvim/log.h
@@ -18,55 +18,47 @@
#define ELOG(...)
#define ELOGN(...)
-// Logging is disabled if NDEBUG or DISABLE_LOG is defined.
-#if !defined(DISABLE_LOG) && defined(NDEBUG)
-# define DISABLE_LOG
-#endif
-
-// MIN_LOG_LEVEL can be defined during compilation to adjust the desired level
-// of logging. INFO_LOG_LEVEL is used by default.
#ifndef MIN_LOG_LEVEL
# define MIN_LOG_LEVEL INFO_LOG_LEVEL
#endif
-#ifndef DISABLE_LOG
-
-# if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
-# undef DLOG
-# undef DLOGN
-# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, true, \
- __VA_ARGS__)
-# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, false, \
- __VA_ARGS__)
-# endif
+#define LOG(level, ...) do_log((level), __func__, __LINE__, true, \
+ __VA_ARGS__)
-# if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
-# undef ILOG
-# undef ILOGN
-# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, true, \
- __VA_ARGS__)
-# define ILOGN(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, false, \
- __VA_ARGS__)
-# endif
+#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
+# undef DLOG
+# undef DLOGN
+# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, true, \
+ __VA_ARGS__)
+# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, false, \
+ __VA_ARGS__)
+#endif
-# if MIN_LOG_LEVEL <= WARNING_LOG_LEVEL
-# undef WLOG
-# undef WLOGN
-# define WLOG(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, true, \
- __VA_ARGS__)
-# define WLOGN(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, false, \
- __VA_ARGS__)
-# endif
+#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
+# undef ILOG
+# undef ILOGN
+# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, true, \
+ __VA_ARGS__)
+# define ILOGN(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, false, \
+ __VA_ARGS__)
+#endif
-# if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
-# undef ELOG
-# undef ELOGN
-# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, true, \
- __VA_ARGS__)
-# define ELOGN(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, false, \
- __VA_ARGS__)
-# endif
+#if MIN_LOG_LEVEL <= WARNING_LOG_LEVEL
+# undef WLOG
+# undef WLOGN
+# define WLOG(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, true, \
+ __VA_ARGS__)
+# define WLOGN(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, false, \
+ __VA_ARGS__)
+#endif
+#if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
+# undef ELOG
+# undef ELOGN
+# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, true, \
+ __VA_ARGS__)
+# define ELOGN(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, false, \
+ __VA_ARGS__)
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 6f9e381d8d..9ec5bfb8ad 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -14,6 +14,7 @@
#include "nvim/api/vim.h"
#include "nvim/vim.h"
#include "nvim/ex_getln.h"
+#include "nvim/ex_cmds2.h"
#include "nvim/message.h"
#include "nvim/memline.h"
#include "nvim/buffer_defs.h"
@@ -284,7 +285,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
///
/// Crashes NeoVim if initialization fails. Should be called once per lua
/// interpreter instance.
-static lua_State *init_lua(void)
+///
+/// @return New lua interpreter instance.
+static lua_State *nlua_init(void)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
{
lua_State *lstate = luaL_newstate();
@@ -297,7 +300,43 @@ static lua_State *init_lua(void)
return lstate;
}
-static lua_State *global_lstate = NULL;
+/// Enter lua interpreter
+///
+/// Calls nlua_init() if needed. Is responsible for pre-lua call initalization
+/// like updating `package.[c]path` with directories derived from &runtimepath.
+///
+/// @return Interprter instance to use. Will either be initialized now or taken
+/// from previous initalization.
+static lua_State *nlua_enter(void)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static lua_State *global_lstate = NULL;
+ if (global_lstate == NULL) {
+ global_lstate = nlua_init();
+ }
+ lua_State *const lstate = global_lstate;
+ // Last used p_rtp value. Must not be dereferenced because value pointed to
+ // may already be freed. Used to check whether &runtimepath option value
+ // changed.
+ static const void *last_p_rtp = NULL;
+ if (last_p_rtp != (const void *)p_rtp) {
+ // stack: (empty)
+ lua_getglobal(lstate, "vim");
+ // stack: vim
+ lua_getfield(lstate, -1, "_update_package_paths");
+ // stack: vim, vim._update_package_paths
+ if (lua_pcall(lstate, 0, 0, 0)) {
+ // stack: vim, error
+ nlua_error(lstate, _("E5117: Error while updating package paths: %.*s"));
+ // stack: vim
+ }
+ // stack: vim
+ lua_pop(lstate, 1);
+ // stack: (empty)
+ last_p_rtp = (const void *)p_rtp;
+ }
+ return lstate;
+}
/// Execute lua string
///
@@ -308,11 +347,7 @@ static lua_State *global_lstate = NULL;
void executor_exec_lua(const String str, typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
- if (global_lstate == NULL) {
- global_lstate = init_lua();
- }
-
- NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_lua_string, 0,
+ NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_lua_string, 0,
(void *)&str, ret_tv);
}
@@ -382,7 +417,7 @@ static int nlua_eval_lua_string(lua_State *const lstate)
/// and locations where result and error are saved, respectively. Always
/// returns nothing (from the lua point of view).
static int nlua_exec_lua_string_api(lua_State *const lstate)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL
{
const String *str = (const String *)lua_touserdata(lstate, 1);
const Array *args = (const Array *)lua_touserdata(lstate, 2);
@@ -551,11 +586,7 @@ void executor_eval_lua(const String str, typval_T *const arg,
typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
- if (global_lstate == NULL) {
- global_lstate = init_lua();
- }
-
- NLUA_CALL_C_FUNCTION_3(global_lstate, nlua_eval_lua_string, 0,
+ NLUA_CALL_C_FUNCTION_3(nlua_enter(), nlua_eval_lua_string, 0,
(void *)&str, arg, ret_tv);
}
@@ -570,12 +601,8 @@ void executor_eval_lua(const String str, typval_T *const arg,
/// @return Return value of the execution.
Object executor_exec_lua_api(const String str, const Array args, Error *err)
{
- if (global_lstate == NULL) {
- global_lstate = init_lua();
- }
-
Object retval = NIL;
- NLUA_CALL_C_FUNCTION_4(global_lstate, nlua_exec_lua_string_api, 0,
+ NLUA_CALL_C_FUNCTION_4(nlua_enter(), nlua_exec_lua_string_api, 0,
(void *)&str, (void *)&args, &retval, err);
return retval;
}
@@ -609,9 +636,6 @@ void ex_lua(exarg_T *const eap)
void ex_luado(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
- if (global_lstate == NULL) {
- global_lstate = init_lua();
- }
if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) {
EMSG(_("cannot save undo information"));
return;
@@ -621,7 +645,7 @@ void ex_luado(exarg_T *const eap)
.data = (char *)eap->arg,
};
const linenr_T range[] = { eap->line1, eap->line2 };
- NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_luado_string, 0,
+ NLUA_CALL_C_FUNCTION_2(nlua_enter(), nlua_exec_luado_string, 0,
(void *)&cmd, (void *)range);
}
@@ -633,9 +657,6 @@ void ex_luado(exarg_T *const eap)
void ex_luafile(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
- if (global_lstate == NULL) {
- global_lstate = init_lua();
- }
- NLUA_CALL_C_FUNCTION_1(global_lstate, nlua_exec_lua_file, 0,
+ NLUA_CALL_C_FUNCTION_1(nlua_enter(), nlua_exec_lua_file, 0,
(void *)eap->arg);
}
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 8d1c5bdf4f..c7952520b0 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -1,2 +1,64 @@
-- TODO(ZyX-I): Create compatibility layer.
-return {}
+--{{{1 package.path updater function
+-- Last inserted paths. Used to clear out items from package.[c]path when they
+-- are no longer in &runtimepath.
+local last_nvim_paths = {}
+local function _update_package_paths()
+ local cur_nvim_paths = {}
+ local rtps = vim.api.nvim_list_runtime_paths()
+ local sep = package.config:sub(1, 1)
+ for _, key in ipairs({'path', 'cpath'}) do
+ local orig_str = package[key] .. ';'
+ local pathtrails_ordered = {}
+ local orig = {}
+ -- Note: ignores trailing item without trailing `;`. Not using something
+ -- simpler in order to preserve empty items (stand for default path).
+ for s in orig_str:gmatch('[^;]*;') do
+ s = s:sub(1, -2) -- Strip trailing semicolon
+ orig[#orig + 1] = s
+ end
+ if key == 'path' then
+ -- /?.lua and /?/init.lua
+ pathtrails_ordered = {sep .. '?.lua', sep .. '?' .. sep .. 'init.lua'}
+ else
+ local pathtrails = {}
+ for _, s in ipairs(orig) do
+ -- Find out path patterns. pathtrail should contain something like
+ -- /?.so, \?.dll. This allows not to bother determining what correct
+ -- suffixes are.
+ local pathtrail = s:match('[/\\][^/\\]*%?.*$')
+ if pathtrail and not pathtrails[pathtrail] then
+ pathtrails[pathtrail] = true
+ pathtrails_ordered[#pathtrails_ordered + 1] = pathtrail
+ end
+ end
+ end
+ local new = {}
+ for _, rtp in ipairs(rtps) do
+ if not rtp:match(';') then
+ for _, pathtrail in pairs(pathtrails_ordered) do
+ local new_path = rtp .. sep .. 'lua' .. pathtrail
+ -- Always keep paths from &runtimepath at the start:
+ -- append them here disregarding orig possibly containing one of them.
+ new[#new + 1] = new_path
+ cur_nvim_paths[new_path] = true
+ end
+ end
+ end
+ for _, orig_path in ipairs(orig) do
+ -- Handle removing obsolete paths originating from &runtimepath: such
+ -- paths either belong to cur_nvim_paths and were already added above or
+ -- to last_nvim_paths and should not be added at all if corresponding
+ -- entry was removed from &runtimepath list.
+ if not (cur_nvim_paths[orig_path] or last_nvim_paths[orig_path]) then
+ new[#new + 1] = orig_path
+ end
+ end
+ package[key] = table.concat(new, ';')
+ end
+ last_nvim_paths = cur_nvim_paths
+end
+--{{{1 Module definition
+return {
+ _update_package_paths = _update_package_paths,
+}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 46607da6ea..7dcf00c26b 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -57,6 +57,7 @@
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
+#include "nvim/os/fileio.h"
#include "nvim/event/loop.h"
#include "nvim/os/signal.h"
#include "nvim/event/process.h"
@@ -153,10 +154,11 @@ void event_init(void)
terminal_init();
}
-void event_teardown(void)
+/// @returns false if main_loop could not be closed gracefully
+bool event_teardown(void)
{
if (!main_loop.events) {
- return;
+ return true;
}
multiqueue_process_events(main_loop.events);
@@ -168,7 +170,7 @@ void event_teardown(void)
signal_teardown();
terminal_teardown();
- loop_close(&main_loop, true);
+ return loop_close(&main_loop, true);
}
/// Performs early initialization.
@@ -765,16 +767,26 @@ static void command_line_scan(mparm_T *parmp)
version();
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
- msgpack_sbuffer* b = msgpack_sbuffer_new();
- msgpack_packer* p = msgpack_packer_new(b, msgpack_sbuffer_write);
- Object md = DICTIONARY_OBJ(api_metadata());
- msgpack_rpc_from_object(md, p);
+ FileDescriptor fp;
+ const int fof_ret = file_open_fd(&fp, OS_STDOUT_FILENO, true);
+ msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
+
+ if (fof_ret != 0) {
+ emsgf(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret));
+ }
- for (size_t i = 0; i < b->size; i++) {
- putchar(b->data[i]);
+ if (p == NULL) {
+ emsgf(_(e_outofmem));
}
+ Object md = DICTIONARY_OBJ(api_metadata());
+ msgpack_rpc_from_object(md, p);
+
msgpack_packer_free(p);
+ const int ff_ret = file_flush(&fp);
+ if (ff_ret < 0) {
+ msgpack_file_write_error(ff_ret);
+ }
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
parmp->headless = true;
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 366b286d14..537b6751e2 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -149,4 +149,3 @@ MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .async = false }
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
-MAP_IMPL(linenr_T, bufhl_vec_T, KVEC_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index a4fccf47f9..047aa163ce 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -30,7 +30,6 @@ MAP_DECLS(ptr_t, ptr_t)
MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(handle_T, ptr_t)
MAP_DECLS(String, MsgpackRpcRequestHandler)
-MAP_DECLS(linenr_T, bufhl_vec_T)
#define map_new(T, U) map_##T##_##U##_new
#define map_free(T, U) map_##T##_##U##_free
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 675fe4d57f..7889fabd45 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -888,9 +888,13 @@ void ex_changes(exarg_T *eap)
* Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
* or: mark_adjust(56, 55, MAXLNUM, 2);
*/
-void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
+void mark_adjust(linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after,
+ bool end_temp)
{
- mark_adjust_internal(line1, line2, amount, amount_after, true);
+ mark_adjust_internal(line1, line2, amount, amount_after, true, end_temp);
}
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
@@ -899,13 +903,14 @@ void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after,
// for an example of why this may be necessary, see do_move().
void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount,
- long amount_after)
+ long amount_after, bool end_temp)
{
- mark_adjust_internal(line1, line2, amount, amount_after, false);
+ mark_adjust_internal(line1, line2, amount, amount_after, false, end_temp);
}
-static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
- long amount_after, bool adjust_folds)
+static void mark_adjust_internal(linenr_T line1, linenr_T line2,
+ long amount, long amount_after,
+ bool adjust_folds, bool end_temp)
{
int i;
int fnum = curbuf->b_fnum;
@@ -954,7 +959,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
}
sign_mark_adjust(line1, line2, amount, amount_after);
- bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after);
+ bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after, end_temp);
}
/* previous context mark */
diff --git a/src/nvim/mark.h b/src/nvim/mark.h
index a356c1f398..ed4e47907b 100644
--- a/src/nvim/mark.h
+++ b/src/nvim/mark.h
@@ -81,7 +81,8 @@ static inline bool equalpos(pos_T, pos_T)
REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE;
static inline bool ltoreq(pos_T, pos_T)
REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE;
-static inline void clearpos(pos_T *) REAL_FATTR_ALWAYS_INLINE;
+static inline void clearpos(pos_T *)
+ REAL_FATTR_ALWAYS_INLINE;
/// Return true if position a is before (less than) position b.
static inline bool lt(pos_T a, pos_T b)
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index d5907da2ed..5b00a4b9a8 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1739,52 +1739,55 @@ int mb_charlen_len(char_u *str, int len)
return count;
}
-/*
- * Try to un-escape a multi-byte character.
- * Used for the "to" and "from" part of a mapping.
- * Return the un-escaped string if it is a multi-byte character, and advance
- * "pp" to just after the bytes that formed it.
- * Return NULL if no multi-byte char was found.
- */
-char_u * mb_unescape(char_u **pp)
-{
- static char_u buf[6];
- int n;
- int m = 0;
- char_u *str = *pp;
-
- /* Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
- * KS_EXTRA KE_CSI to CSI.
- * Maximum length of a utf-8 character is 4 bytes. */
- for (n = 0; str[n] != NUL && m < 4; ++n) {
- if (str[n] == K_SPECIAL
- && str[n + 1] == KS_SPECIAL
- && str[n + 2] == KE_FILLER) {
- buf[m++] = K_SPECIAL;
- n += 2;
- } else if ((str[n] == K_SPECIAL
- )
- && str[n + 1] == KS_EXTRA
- && str[n + 2] == (int)KE_CSI) {
- buf[m++] = CSI;
- n += 2;
- } else if (str[n] == K_SPECIAL
- )
- break; /* a special key can't be a multibyte char */
- else
- buf[m++] = str[n];
- buf[m] = NUL;
+/// Try to unescape a multibyte character
+///
+/// Used for the rhs and lhs of the mappings.
+///
+/// @param[in,out] pp String to unescape. Is advanced to just after the bytes
+/// that form a multibyte character.
+///
+/// @return Unescaped string if it is a multibyte character, NULL if no
+/// multibyte character was found. Returns a static buffer, always one
+/// and the same.
+const char *mb_unescape(const char **const pp)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ static char buf[6];
+ size_t buf_idx = 0;
+ uint8_t *str = (uint8_t *)(*pp);
+
+ // Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
+ // KS_EXTRA KE_CSI to CSI.
+ // Maximum length of a utf-8 character is 4 bytes.
+ for (size_t str_idx = 0; str[str_idx] != NUL && buf_idx < 4; str_idx++) {
+ if (str[str_idx] == K_SPECIAL
+ && str[str_idx + 1] == KS_SPECIAL
+ && str[str_idx + 2] == KE_FILLER) {
+ buf[buf_idx++] = (char)K_SPECIAL;
+ str_idx += 2;
+ } else if ((str[str_idx] == K_SPECIAL)
+ && str[str_idx + 1] == KS_EXTRA
+ && str[str_idx + 2] == KE_CSI) {
+ buf[buf_idx++] = (char)CSI;
+ str_idx += 2;
+ } else if (str[str_idx] == K_SPECIAL) {
+ break; // A special key can't be a multibyte char.
+ } else {
+ buf[buf_idx++] = (char)str[str_idx];
+ }
+ buf[buf_idx] = NUL;
- /* Return a multi-byte character if it's found. An illegal sequence
- * will result in a 1 here. */
- if ((*mb_ptr2len)(buf) > 1) {
- *pp = str + n + 1;
+ // Return a multi-byte character if it's found. An illegal sequence
+ // will result in a 1 here.
+ if (utf_ptr2len((const char_u *)buf) > 1) {
+ *pp = (const char *)str + buf_idx + 1;
return buf;
}
- /* Bail out quickly for ASCII. */
- if (buf[0] < 128)
+ // Bail out quickly for ASCII.
+ if ((uint8_t)buf[0] < 128) {
break;
+ }
}
return NULL;
}
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 1abc69727c..9429703620 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -115,18 +115,18 @@ memfile_T *mf_open(char_u *fname, int flags)
}
}
- off_t size;
+ off_T size;
// When recovering, the actual block size will be retrieved from block 0
// in ml_recover(). The size used here may be wrong, therefore mf_blocknr_max
// must be rounded up.
if (mfp->mf_fd < 0
|| (flags & (O_TRUNC|O_EXCL))
- || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) {
+ || (size = vim_lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0) {
// no file or empty file
mfp->mf_blocknr_max = 0;
} else {
- assert(sizeof(off_t) <= sizeof(blocknr_T)
+ assert(sizeof(off_T) <= sizeof(blocknr_T)
&& mfp->mf_page_size > 0
&& mfp->mf_page_size - 1 <= INT64_MAX - size);
mfp->mf_blocknr_max = (((blocknr_T)size + mfp->mf_page_size - 1)
@@ -689,9 +689,9 @@ static int mf_read(memfile_T *mfp, bhdr_T *hp)
return FAIL;
unsigned page_size = mfp->mf_page_size;
- // TODO(elmart): Check (page_size * hp->bh_bnum) within off_t bounds.
- off_t offset = (off_t)(page_size * hp->bh_bnum);
- if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset) {
+ // TODO(elmart): Check (page_size * hp->bh_bnum) within off_T bounds.
+ off_T offset = (off_T)(page_size * hp->bh_bnum);
+ if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) {
PERROR(_("E294: Seek error in swap file read"));
return FAIL;
}
@@ -716,7 +716,7 @@ static int mf_read(memfile_T *mfp, bhdr_T *hp)
/// - Write error in swap file.
static int mf_write(memfile_T *mfp, bhdr_T *hp)
{
- off_t offset; // offset in the file
+ off_T offset; // offset in the file
blocknr_T nr; // block nr which is being written
bhdr_T *hp2;
unsigned page_size; // number of bytes in a page
@@ -745,9 +745,9 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
hp2 = hp;
}
- // TODO(elmart): Check (page_size * nr) within off_t bounds.
- offset = (off_t)(page_size * nr);
- if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset) {
+ // TODO(elmart): Check (page_size * nr) within off_T bounds.
+ offset = (off_T)(page_size * nr);
+ if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) {
PERROR(_("E296: Seek error in swap file write"));
return FAIL;
}
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 40a6761225..55e7e01825 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -763,7 +763,7 @@ void ml_recover(void)
int idx;
int top;
int txt_start;
- off_t size;
+ off_T size;
int called_from_main;
int serious_error = TRUE;
long mtime;
@@ -914,10 +914,11 @@ void ml_recover(void)
msg_end();
goto theend;
}
- if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
- mfp->mf_blocknr_max = 0; /* no file or empty file */
- else
+ if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) {
+ mfp->mf_blocknr_max = 0; // no file or empty file
+ } else {
mfp->mf_blocknr_max = size / mfp->mf_page_size;
+ }
mfp->mf_infile_count = mfp->mf_blocknr_max;
/* need to reallocate the memory used to store the data */
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 057ce75f79..36f9ca84ed 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1196,7 +1196,7 @@ int msg_outtrans_len_attr(char_u *msgstr, int len, int attr)
len -= mb_l - 1;
str += mb_l;
} else {
- s = transchar_byte(*str);
+ s = transchar_byte((uint8_t)(*str));
if (s[1] != NUL) {
// Unprintable char: print the printable chars so far and the
// translation of the unprintable char.
@@ -1269,7 +1269,7 @@ msg_outtrans_special (
string = "<Space>";
str++;
} else {
- string = (const char *)str2special((char_u **)&str, from);
+ string = str2special((const char **)&str, from, false);
}
const int len = vim_strsize((char_u *)string);
// Highlight special keys
@@ -1281,108 +1281,125 @@ msg_outtrans_special (
return retval;
}
-/*
- * Return the lhs or rhs of a mapping, with the key codes turned into printable
- * strings, in an allocated string.
- */
-char_u *
-str2special_save (
- char_u *str,
- int is_lhs /* TRUE for lhs, FALSE for rhs */
-)
+/// Convert string, replacing key codes with printables
+///
+/// Used for lhs or rhs of mappings.
+///
+/// @param[in] str String to convert.
+/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used fo
+/// lhs, but not rhs.
+/// @param[in] replace_lt Convert `<` into `<lt>`.
+///
+/// @return [allocated] Converted string.
+char *str2special_save(const char *const str, const bool replace_spaces,
+ const bool replace_lt)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
+ FUNC_ATTR_NONNULL_RET
{
garray_T ga;
- char_u *p = str;
-
ga_init(&ga, 1, 40);
- while (*p != NUL)
- ga_concat(&ga, str2special(&p, is_lhs));
+
+ const char *p = str;
+ while (*p != NUL) {
+ ga_concat(&ga, (const char_u *)str2special(&p, replace_spaces, replace_lt));
+ }
ga_append(&ga, NUL);
- return (char_u *)ga.ga_data;
+ return (char *)ga.ga_data;
}
-/*
- * Return the printable string for the key codes at "*sp".
- * Used for translating the lhs or rhs of a mapping to printable chars.
- * Advances "sp" to the next code.
- */
-char_u *
-str2special (
- char_u **sp,
- int from /* TRUE for lhs of mapping */
-)
-{
- int c;
- static char_u buf[7];
- char_u *str = *sp;
- int modifiers = 0;
- int special = FALSE;
-
- if (has_mbyte) {
- char_u *p;
-
- /* Try to un-escape a multi-byte character. Return the un-escaped
- * string if it is a multi-byte character. */
- p = mb_unescape(sp);
- if (p != NULL)
- return p;
+/// Convert character, replacing key one key code with printable representation
+///
+/// @param[in,out] sp String to convert. Is advanced to the next key code.
+/// @param[in] replace_spaces Convert spaces into <Space>, normally used for
+/// lhs, but not rhs.
+/// @param[in] replace_lt Convert `<` into `<lt>`.
+///
+/// @return Converted key code, in a static buffer. Buffer is always one and the
+/// same, so save converted string somewhere before running str2special
+/// for the second time.
+const char *str2special(const char **const sp, const bool replace_spaces,
+ const bool replace_lt)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
+{
+ static char buf[7];
+
+ // Try to un-escape a multi-byte character. Return the un-escaped
+ // string if it is a multi-byte character.
+ const char *const p = mb_unescape(sp);
+ if (p != NULL) {
+ return p;
}
- c = *str;
+ const char *str = *sp;
+ int c = (uint8_t)(*str);
+ int modifiers = 0;
+ bool special = false;
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
- if (str[1] == KS_MODIFIER) {
- modifiers = str[2];
+ if ((uint8_t)str[1] == KS_MODIFIER) {
+ modifiers = (uint8_t)str[2];
str += 3;
- c = *str;
+ c = (uint8_t)(*str);
}
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
- c = TO_SPECIAL(str[1], str[2]);
+ c = TO_SPECIAL((uint8_t)str[1], (uint8_t)str[2]);
str += 2;
- if (c == KS_ZERO) /* display <Nul> as ^@ or <Nul> */
+ if (c == KS_ZERO) { // display <Nul> as ^@ or <Nul>
c = NUL;
+ }
+ }
+ if (IS_SPECIAL(c) || modifiers) { // Special key.
+ special = true;
}
- if (IS_SPECIAL(c) || modifiers) /* special key */
- special = TRUE;
}
- if (has_mbyte && !IS_SPECIAL(c)) {
- int len = (*mb_ptr2len)(str);
+ if (!IS_SPECIAL(c)) {
+ const int len = utf_ptr2len((const char_u *)str);
- /* For multi-byte characters check for an illegal byte. */
- if (has_mbyte && MB_BYTE2LEN(*str) > len) {
- transchar_nonprint(buf, c);
+ // Check for an illegal byte.
+ if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
+ transchar_nonprint((char_u *)buf, c);
*sp = str + 1;
return buf;
}
- /* Since 'special' is TRUE the multi-byte character 'c' will be
- * processed by get_special_key_name() */
- c = (*mb_ptr2char)(str);
+ // Since 'special' is TRUE the multi-byte character 'c' will be
+ // processed by get_special_key_name().
+ c = utf_ptr2char((const char_u *)str);
*sp = str + len;
- } else
+ } else {
*sp = str + 1;
+ }
- /* Make unprintable characters in <> form, also <M-Space> and <Tab>.
- * Use <Space> only for lhs of a mapping. */
- if (special || char2cells(c) > 1 || (from && c == ' '))
- return get_special_key_name(c, modifiers);
+ // Make unprintable characters in <> form, also <M-Space> and <Tab>.
+ if (special
+ || char2cells(c) > 1
+ || (replace_spaces && c == ' ')
+ || (replace_lt && c == '<')) {
+ return (const char *)get_special_key_name(c, modifiers);
+ }
buf[0] = c;
buf[1] = NUL;
return buf;
}
-/*
- * Translate a key sequence into special key names.
- */
-void str2specialbuf(char_u *sp, char_u *buf, int len)
+/// Convert string, replacing key codes with printables
+///
+/// @param[in] str String to convert.
+/// @param[out] buf Buffer to save results to.
+/// @param[in] len Buffer length.
+void str2specialbuf(const char *sp, char *buf, size_t len)
+ FUNC_ATTR_NONNULL_ALL
{
- char_u *s;
-
- *buf = NUL;
while (*sp) {
- s = str2special(&sp, FALSE);
- if ((int)(STRLEN(s) + STRLEN(buf)) < len)
- STRCAT(buf, s);
+ const char *s = str2special(&sp, false, false);
+ const size_t s_len = strlen(s);
+ if (s_len <= len) {
+ break;
+ }
+ memcpy(buf, s, s_len);
+ buf += s_len;
+ len -= s_len;
}
+ *buf = NUL;
}
/*
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 9630656f3f..835b9c7b20 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -751,7 +751,7 @@ open_line (
// Skip mark_adjust when adding a line after the last one, there can't
// be marks there.
if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count) {
- mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
+ mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
}
did_append = true;
} else {
@@ -1866,7 +1866,7 @@ void appended_lines_mark(linenr_T lnum, long count)
// Skip mark_adjust when adding a line after the last one, there can't
// be marks there.
if (lnum + count < curbuf->b_ml.ml_line_count) {
- mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L);
+ mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L, false);
}
changed_lines(lnum + 1, 0, lnum + 1, count);
}
@@ -1888,7 +1888,7 @@ void deleted_lines(linenr_T lnum, long count)
*/
void deleted_lines_mark(linenr_T lnum, long count)
{
- mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count);
+ mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count, false);
changed_lines(lnum, 0, lnum + count, -count);
}
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 413b800af5..68ac35bc4e 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -370,7 +370,7 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
char buf[256];
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
channel->id);
- call_set_error(channel, buf);
+ call_set_error(channel, buf, WARNING_LOG_LEVEL);
goto end;
}
@@ -409,7 +409,7 @@ static void parse_msgpack(Channel *channel)
"ch %" PRIu64 " returned a response with an unknown request "
"id. Ensure the client is properly synchronized",
channel->id);
- call_set_error(channel, buf);
+ call_set_error(channel, buf, ERROR_LOG_LEVEL);
}
msgpack_unpacked_destroy(&unpacked);
// Bail out from this event loop iteration
@@ -459,7 +459,7 @@ static void handle_request(Channel *channel, msgpack_object *request)
snprintf(buf, sizeof(buf),
"ch %" PRIu64 " sent an invalid message, closed.",
channel->id);
- call_set_error(channel, buf);
+ call_set_error(channel, buf, ERROR_LOG_LEVEL);
}
api_clear_error(&error);
return;
@@ -564,7 +564,7 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
"Before returning from a RPC call, ch %" PRIu64 " was "
"closed due to a failed write",
channel->id);
- call_set_error(channel, buf);
+ call_set_error(channel, buf, ERROR_LOG_LEVEL);
}
return success;
@@ -795,9 +795,9 @@ static void complete_call(msgpack_object *obj, Channel *channel)
}
}
-static void call_set_error(Channel *channel, char *msg)
+static void call_set_error(Channel *channel, char *msg, int loglevel)
{
- ELOG("RPC: %s", msg);
+ LOG(loglevel, "RPC: %s", msg);
for (size_t i = 0; i < kv_size(channel->call_stack); i++) {
ChannelCallFrame *frame = kv_A(channel->call_stack, i);
frame->returned = true;
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index c9edd05dc2..1e0cc27886 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -125,7 +125,7 @@ bool server_owns_pipe_address(const char *path)
int server_start(const char *endpoint)
{
if (endpoint == NULL || endpoint[0] == '\0') {
- ELOG("Empty or NULL endpoint");
+ WLOG("Empty or NULL endpoint");
return 1;
}
@@ -151,7 +151,7 @@ int server_start(const char *endpoint)
result = socket_watcher_start(watcher, MAX_CONNECTIONS, connection_cb);
if (result < 0) {
- ELOG("Failed to start server: %s", uv_strerror(result));
+ WLOG("Failed to start server: %s", uv_strerror(result));
socket_watcher_close(watcher, free_server);
return result;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 050020d79d..d891c74fd2 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1451,9 +1451,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
/* Never redo "zf" (define fold). */
if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
- /* Also redo Operator-pending Visual mode mappings */
- || (VIsual_active && cap->cmdchar == ':'
- && oap->op_type != OP_COLON))
+ // Also redo Operator-pending Visual mode mappings.
+ || (cap->cmdchar == ':' && oap->op_type != OP_COLON))
&& cap->cmdchar != 'D'
&& oap->op_type != OP_FOLD
&& oap->op_type != OP_FOLDOPEN
@@ -5231,6 +5230,7 @@ static void nv_dollar(cmdarg_T *cap)
static void nv_search(cmdarg_T *cap)
{
oparg_T *oap = cap->oap;
+ pos_T save_cursor = curwin->w_cursor;
if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13) {
/* Translate "g??" to "g?g?" */
@@ -5240,6 +5240,8 @@ static void nv_search(cmdarg_T *cap)
return;
}
+ // When using 'incsearch' the cursor may be moved to set a different search
+ // start position.
cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
if (cap->searchbuf == NULL) {
@@ -5248,7 +5250,8 @@ static void nv_search(cmdarg_T *cap)
}
(void)normal_search(cap, cap->cmdchar, cap->searchbuf,
- (cap->arg ? 0 : SEARCH_MARK));
+ (cap->arg || !equalpos(save_cursor, curwin->w_cursor))
+ ? 0 : SEARCH_MARK);
}
/*
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index e374686286..5c6f4d0d07 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -938,13 +938,11 @@ static int stuff_yank(int regname, char_u *p)
static int execreg_lastc = NUL;
-/*
- * execute a yank register: copy it into the stuff buffer
- *
- * return FAIL for failure, OK otherwise
- */
-int
-do_execreg (
+/// Execute a yank register: copy it into the stuff buffer
+///
+/// Return FAIL for failure, OK otherwise
+int
+do_execreg(
int regname,
int colon, /* insert ':' before each line */
int addcr, /* always add '\n' to end of line */
@@ -1410,6 +1408,9 @@ int op_delete(oparg_T *oap)
}
if (oap->regname == 0) {
+ if (reg == NULL) {
+ abort();
+ }
set_clipboard(0, reg);
do_autocmd_textyankpost(oap, reg);
}
@@ -3181,7 +3182,7 @@ error:
if (curbuf->b_op_start.lnum + (y_type == kMTCharWise) - 1 + nr_lines
< curbuf->b_ml.ml_line_count) {
mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise),
- (linenr_T)MAXLNUM, nr_lines, 0L);
+ (linenr_T)MAXLNUM, nr_lines, 0L, false);
}
// note changed text for displaying and folding
@@ -4439,8 +4440,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
char_u buf2[NUMBUFLEN];
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
static bool hexupper = false; // 0xABC
- unsigned long n;
- unsigned long oldn;
+ uvarnumber_T n;
+ uvarnumber_T oldn;
char_u *ptr;
int c;
int todel;
@@ -4635,20 +4636,20 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
oldn = n;
- n = subtract ? n - (unsigned long) Prenum1
- : n + (unsigned long) Prenum1;
+ n = subtract ? n - (uvarnumber_T)Prenum1
+ : n + (uvarnumber_T)Prenum1;
// handle wraparound for decimal numbers
if (!pre) {
if (subtract) {
if (n > oldn) {
- n = 1 + (n ^ (unsigned long)-1);
+ n = 1 + (n ^ (uvarnumber_T)-1);
negative ^= true;
}
} else {
// add
if (n < oldn) {
- n = (n ^ (unsigned long)-1);
+ n = (n ^ (uvarnumber_T)-1);
negative ^= true;
}
}
@@ -5238,11 +5239,13 @@ void clear_oparg(oparg_T *oap)
* case, eol_size will be added to the character count to account for
* the size of the EOL character.
*/
-static long line_count_info(char_u *line, long *wc, long *cc, long limit, int eol_size)
+static varnumber_T line_count_info(char_u *line, varnumber_T *wc,
+ varnumber_T *cc, varnumber_T limit,
+ int eol_size)
{
- long i;
- long words = 0;
- long chars = 0;
+ varnumber_T i;
+ varnumber_T words = 0;
+ varnumber_T chars = 0;
int is_word = 0;
for (i = 0; i < limit && line[i] != NUL; ) {
@@ -5280,15 +5283,15 @@ void cursor_pos_info(dict_T *dict)
char_u buf1[50];
char_u buf2[40];
linenr_T lnum;
- long byte_count = 0;
- long bom_count = 0;
- long byte_count_cursor = 0;
- long char_count = 0;
- long char_count_cursor = 0;
- long word_count = 0;
- long word_count_cursor = 0;
+ varnumber_T byte_count = 0;
+ varnumber_T bom_count = 0;
+ varnumber_T byte_count_cursor = 0;
+ varnumber_T char_count = 0;
+ varnumber_T char_count_cursor = 0;
+ varnumber_T word_count = 0;
+ varnumber_T word_count_cursor = 0;
int eol_size;
- long last_check = 100000L;
+ varnumber_T last_check = 100000L;
long line_count_selected = 0;
pos_T min_pos, max_pos;
oparg_T oparg;
@@ -5395,15 +5398,16 @@ void cursor_pos_info(dict_T *dict)
if (lnum == curwin->w_cursor.lnum) {
word_count_cursor += word_count;
char_count_cursor += char_count;
- byte_count_cursor = byte_count +
- line_count_info(ml_get(lnum),
- &word_count_cursor, &char_count_cursor,
- (long)(curwin->w_cursor.col + 1), eol_size);
+ byte_count_cursor = byte_count
+ + line_count_info(ml_get(lnum), &word_count_cursor,
+ &char_count_cursor,
+ (varnumber_T)(curwin->w_cursor.col + 1),
+ eol_size);
}
}
- /* Add to the running totals */
- byte_count += line_count_info(ml_get(lnum), &word_count,
- &char_count, (long)MAXCOL, eol_size);
+ // Add to the running totals
+ byte_count += line_count_info(ml_get(lnum), &word_count, &char_count,
+ (varnumber_T)MAXCOL, eol_size);
}
// Correction for when last line doesn't have an EOL.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index cc7f8333ff..ed058c420d 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1147,7 +1147,7 @@ do_set (
int afterchar; /* character just after option name */
int len;
int i;
- long value;
+ varnumber_T value;
int key;
uint32_t flags; /* flags for current option */
char_u *varp = NULL; /* pointer to variable for current option */
@@ -1480,7 +1480,7 @@ do_set (
if (removing) {
value = *(long *)varp - value;
}
- errmsg = (char_u *)set_num_option(opt_idx, varp, value,
+ errmsg = (char_u *)set_num_option(opt_idx, varp, (long)value,
errbuf, sizeof(errbuf),
opt_flags);
} else if (opt_idx >= 0) { // String.
@@ -3582,7 +3582,9 @@ static char_u *compile_cap_prog(synblock_T *synblock)
/// Handle setting `winhighlight' in window "wp"
static bool parse_winhl_opt(win_T *wp)
{
- int w_hl_id = 0, w_hl_id_inactive = 0;
+ int w_hl_id_normal = 0;
+ int w_hl_ids[HLF_COUNT] = { 0 };
+ int hlf;
const char *p = (const char *)wp->w_p_winhl;
while (*p) {
@@ -3596,18 +3598,25 @@ static bool parse_winhl_opt(win_T *wp)
int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi));
if (strncmp("Normal", p, nlen) == 0) {
- w_hl_id = hl_id;
- } else if (strncmp("NormalNC", p, nlen) == 0) {
- w_hl_id_inactive = hl_id;
+ w_hl_id_normal = hl_id;
} else {
- return false;
+ for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
+ if (strncmp(hlf_names[hlf], p, nlen) == 0) {
+ w_hl_ids[hlf] = hl_id;
+ break;
+ }
+ }
+ if (hlf == HLF_COUNT) {
+ return false;
+ }
}
p = *commap ? commap+1 : "";
}
- wp->w_hl_id = w_hl_id;
- wp->w_hl_id_inactive = w_hl_id_inactive;
+ wp->w_hl_id_normal = w_hl_id_normal;
+ memcpy(wp->w_hl_ids, w_hl_ids, sizeof(w_hl_ids));
+ wp->w_hl_needs_update = true;
return true;
}
@@ -4633,7 +4642,7 @@ get_option_value (
if ((int *)varp == &curbuf->b_changed) {
*numval = curbufIsChanged();
} else {
- *numval = *(int *)varp;
+ *numval = (long) *(int *)varp; // NOLINT(whitespace/cast)
}
}
return 1;
@@ -5169,9 +5178,13 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int e
* CTRL-V or backslash */
if (valuep == &p_pt) {
s = *valuep;
- while (*s != NUL)
- if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
+ while (*s != NUL) {
+ if (put_escstr(fd, (char_u *)str2special((const char **)&s, false,
+ false), 2)
+ == FAIL) {
return FAIL;
+ }
+ }
} else if (expand) {
buf = xmalloc(MAXPATHL);
home_replace(NULL, *valuep, buf, MAXPATHL, FALSE);
@@ -6167,15 +6180,16 @@ option_value2string (
}
} else { // P_STRING
varp = *(char_u **)(varp);
- if (varp == NULL) /* just in case */
+ if (varp == NULL) { // Just in case.
NameBuff[0] = NUL;
- else if (opp->flags & P_EXPAND)
- home_replace(NULL, varp, NameBuff, MAXPATHL, FALSE);
- /* Translate 'pastetoggle' into special key names */
- else if ((char_u **)opp->var == &p_pt)
- str2specialbuf(p_pt, NameBuff, MAXPATHL);
- else
+ } else if (opp->flags & P_EXPAND) {
+ home_replace(NULL, varp, NameBuff, MAXPATHL, false);
+ // Translate 'pastetoggle' into special key names.
+ } else if ((char_u **)opp->var == &p_pt) {
+ str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL);
+ } else {
STRLCPY(NameBuff, varp, MAXPATHL);
+ }
}
}
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index c2778a6329..103227f6b5 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2513,14 +2513,14 @@ return {
vi_def=true,
vim=true,
varname='p_ttimeout',
- defaults={if_true={vi=false}}
+ defaults={if_true={vi=true}}
},
{
full_name='ttimeoutlen', abbreviation='ttm',
type='number', scope={'global'},
vi_def=true,
varname='p_ttm',
- defaults={if_true={vi=-1}}
+ defaults={if_true={vi=50}}
},
{
full_name='ttyfast', abbreviation='tf',
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index 4309ac723c..5d68473982 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -26,6 +26,7 @@
#include "nvim/globals.h"
#include "nvim/rbuffer.h"
#include "nvim/macros.h"
+#include "nvim/message.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fileio.c.generated.h"
@@ -48,7 +49,6 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int os_open_flags = 0;
- int fd;
TriState wr = kNone;
// -V:FLAG:501
#define FLAG(flags, flag, fcntl_flags, wrval, cond) \
@@ -73,14 +73,35 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true);
#endif
#undef FLAG
+ // wr is used for kFileReadOnly flag, but on
+ // QB:neovim-qb-slave-ubuntu-12-04-64bit it still errors out with
+ // `error: variable ‘wr’ set but not used [-Werror=unused-but-set-variable]`
+ (void)wr;
- fd = os_open(fname, os_open_flags, mode);
+ const int fd = os_open(fname, os_open_flags, mode);
if (fd < 0) {
return fd;
}
+ return file_open_fd(ret_fp, fd, (wr == kTrue));
+}
- ret_fp->wr = (wr == kTrue);
+/// Wrap file descriptor with FileDescriptor structure
+///
+/// @warning File descriptor wrapped like this must not be accessed by other
+/// means.
+///
+/// @param[out] ret_fp Address where information needed for reading from or
+/// writing to a file is saved
+/// @param[in] fd File descriptor to wrap.
+/// @param[in] wr True if fd is opened for writing only, false if it is read
+/// only.
+///
+/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
+int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ ret_fp->wr = wr;
ret_fp->fd = fd;
ret_fp->eof = false;
ret_fp->rv = rbuffer_new(kRWBufferSize);
@@ -114,6 +135,26 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
return fp;
}
+/// Like file_open_fd(), but allocate and return ret_fp
+///
+/// @param[out] error Error code, @see os_strerror(). Is set to zero on
+/// success.
+/// @param[in] fd File descriptor to wrap.
+/// @param[in] wr True if fd is opened for writing only, false if it is read
+/// only.
+///
+/// @return [allocated] Opened file or NULL in case of error.
+FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ FileDescriptor *const fp = xmalloc(sizeof(*fp));
+ if ((*error = file_open_fd(fp, fd, wr)) != 0) {
+ xfree(fp);
+ return NULL;
+ }
+ return fp;
+}
+
/// Close file and free its buffer
///
/// @param[in,out] fp File to close.
@@ -345,3 +386,32 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
return (ptrdiff_t)read_bytes;
}
+
+/// Msgpack callback for writing to a file
+///
+/// @param data File to write to.
+/// @param[in] buf Data to write.
+/// @param[in] len Length of the data to write.
+///
+/// @return 0 in case of success, -1 in case of error.
+int msgpack_file_write(void *data, const char *buf, size_t len)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ assert(len < PTRDIFF_MAX);
+ const ptrdiff_t written_bytes = file_write((FileDescriptor *)data, buf, len);
+ if (written_bytes < 0) {
+ return msgpack_file_write_error((int)written_bytes);
+ }
+ return 0;
+}
+
+/// Print error which occurs when failing to write msgpack data
+///
+/// @param[in] error Error code of the error to print.
+///
+/// @return -1 (error return for msgpack_packer callbacks).
+int msgpack_file_write_error(const int error)
+{
+ emsgf(_("E5420: Failed to write to file: %s"), os_strerror(error));
+ return -1;
+}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index b9a9480cb8..14dacd97c4 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -171,6 +171,10 @@ int os_nodetype(const char *name)
| O_NONBLOCK
#endif
, 0);
+ if (fd == -1) {
+ return NODE_OTHER; // open() failed.
+ }
+
switch (uv_guess_handle(fd)) {
case UV_TTY: // FILE_TYPE_CHAR
nodetype = NODE_WRITABLE;
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index f81785675e..923a362b41 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -13,6 +13,13 @@
# include "nvim/os/unix_defs.h"
#endif
+/// File descriptor number used for standard IO streams
+enum {
+ OS_STDIN_FILENO = STDIN_FILENO,
+ OS_STDOUT_FILENO = STDOUT_FILENO,
+ OS_STDERR_FILENO = STDERR_FILENO,
+};
+
#define BASENAMELEN (NAME_MAX - 5)
// Use the system path length if it makes sense.
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 1a40309655..9d80a43718 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -496,8 +496,12 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
size_t cnt;
char *ptr = rbuffer_read_ptr(buf, &cnt);
- if (ptr != NULL && cnt > 0
- && out_data_decide_throttle(cnt)) { // Skip output above a threshold.
+ if (ptr == NULL || cnt == 0) {
+ // Nothing to read;
+ return;
+ }
+
+ if (out_data_decide_throttle(cnt)) { // Skip output above a threshold.
// Save the skipped output. If it is the final chunk, we display it later.
out_data_ring(ptr, cnt);
} else {
@@ -685,7 +689,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
uv_err_name(status));
}
if (stream->closed) { // Process may have exited before this write.
- ELOG("stream was already closed");
+ WLOG("stream was already closed");
return;
}
stream_close(stream, NULL, NULL);
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index 7c980c3768..7ed70f6092 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -91,4 +91,14 @@ typedef SSIZE_T ssize_t;
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+
#endif // NVIM_OS_WIN_DEFS_H
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 7cf0d7817c..692bcc97f4 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -141,7 +141,9 @@ void mch_exit(int r) FUNC_ATTR_NORETURN
ui_flush();
ml_close_all(true); // remove all memfiles
- event_teardown();
+ if (!event_teardown() && r == 0) {
+ r = 1; // Exit with error if main_loop did not teardown gracefully.
+ }
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
#ifdef EXITFREE
@@ -173,7 +175,7 @@ void mch_exit(int r) FUNC_ATTR_NORETURN
/// @returns OK for success or FAIL for error.
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
char_u ***file, int flags) FUNC_ATTR_NONNULL_ARG(3)
- FUNC_ATTR_NONNULL_ARG(4)
+ FUNC_ATTR_NONNULL_ARG(4)
{
int i;
size_t len;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 9f3abfcb89..2462975c9b 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -307,10 +307,10 @@ void pum_redraw(void)
{
int row = pum_row;
int col;
- int attr_norm = highlight_attr[HLF_PNI];
- int attr_select = highlight_attr[HLF_PSI];
- int attr_scroll = highlight_attr[HLF_PSB];
- int attr_thumb = highlight_attr[HLF_PST];
+ int attr_norm = win_hl_attr(curwin, HLF_PNI);
+ int attr_select = win_hl_attr(curwin, HLF_PSI);
+ int attr_scroll = win_hl_attr(curwin, HLF_PSB);
+ int attr_thumb = win_hl_attr(curwin, HLF_PST);
int attr;
int i;
int idx;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index ff51bf289e..bd5dfa92cc 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -191,7 +191,7 @@ typedef struct {
// Looking up a buffer can be slow if there are many. Remember the last one
// to make this a lot faster if there are multiple matches in the same file.
static char_u *qf_last_bufname = NULL;
-static bufref_T qf_last_bufref = { NULL, 0 };
+static bufref_T qf_last_bufref = { NULL, 0, 0 };
/*
* Read the errorfile "efile" into memory, line by line, building the error
@@ -2330,9 +2330,7 @@ void qf_history(exarg_T *eap)
}
}
-/*
- * Free error list "idx".
- */
+/// Free all the entries in the error list "idx".
static void qf_free(qf_info_T *qi, int idx)
{
qfline_T *qfp;
@@ -4027,7 +4025,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
- qf_idx = di->di_tv.vval.v_number - 1;
+ qf_idx = (int)di->di_tv.vval.v_number - 1;
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
}
@@ -4101,7 +4099,7 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
char *const filename = tv_dict_get_string(d, "filename", true);
int bufnum = (int)tv_dict_get_number(d, "bufnr");
- long lnum = tv_dict_get_number(d, "lnum");
+ long lnum = (long)tv_dict_get_number(d, "lnum");
int col = (int)tv_dict_get_number(d, "col");
char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
int nr = (int)tv_dict_get_number(d, "nr");
@@ -4183,7 +4181,7 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
- qf_idx = di->di_tv.vval.v_number - 1;
+ qf_idx = (int)di->di_tv.vval.v_number - 1;
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 5448cc7131..41070aebf4 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -6928,9 +6928,10 @@ char_u *reg_submatch(int no)
STRNCPY(retval + len, reg_getline_submatch(lnum),
submatch_mmatch->endpos[no].col);
len += submatch_mmatch->endpos[no].col;
- if (round == 2)
- retval[len] = NUL;
- ++len;
+ if (round == 2) {
+ retval[len] = NUL; // -V595
+ }
+ len++;
}
if (retval == NULL) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 537b13f33d..a8353153fd 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -155,7 +155,6 @@ static schar_T *current_ScreenLine;
StlClickDefinition *tab_page_click_defs = NULL;
long tab_page_click_defs_size = 0;
-# define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
@@ -380,15 +379,24 @@ void update_screen(int type)
))
curwin->w_redr_type = type;
- /* Redraw the tab pages line if needed. */
- if (redraw_tabline || type >= NOT_VALID)
+ // Redraw the tab pages line if needed.
+ if (redraw_tabline || type >= NOT_VALID) {
+ update_window_hl(curwin, type >= NOT_VALID);
+ FOR_ALL_TABS(tp) {
+ if (tp != curtab) {
+ update_window_hl(tp->tp_curwin, type >= NOT_VALID);
+ }
+ }
draw_tabline();
+ }
/*
* Correct stored syntax highlighting info for changes in each displayed
* buffer. Each buffer must only be done once.
*/
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ update_window_hl(wp, type >= NOT_VALID);
+
if (wp->w_buffer->b_mod_set) {
win_T *wwp;
@@ -1488,11 +1496,11 @@ static void win_update(win_T *wp)
// Last line isn't finished: Display "@@@" in the last screen line.
screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
- hl_attr(HLF_AT));
+ win_hl_attr(wp, HLF_AT));
screen_fill(scr_row, scr_row + 1,
(int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
- '@', ' ', hl_attr(HLF_AT));
+ '@', ' ', win_hl_attr(wp, HLF_AT));
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline"
@@ -1500,7 +1508,7 @@ static void win_update(win_T *wp)
screen_fill(wp->w_winrow + wp->w_height - 1,
wp->w_winrow + wp->w_height,
W_ENDCOL(wp) - 3, W_ENDCOL(wp),
- '@', '@', hl_attr(HLF_AT));
+ '@', '@', win_hl_attr(wp, HLF_AT));
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else {
@@ -1584,10 +1592,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
# define FDC_OFF n
int fdc = compute_foldcolumn(wp, 0);
- int attr = hl_attr(hl);
- if (wp->w_hl_attr != 0) {
- attr = hl_combine_attr(wp->w_hl_attr, attr);
- }
+ int attr = win_hl_attr(wp, hl);
if (wp->w_p_rl) {
// No check for cmdline window: should never be right-left.
@@ -1599,7 +1604,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
n = wp->w_width;
screen_fill(wp->w_winrow + row, wp->w_winrow + endrow,
W_ENDCOL(wp) - n, W_ENDCOL(wp),
- ' ', ' ', hl_attr(HLF_FC));
+ ' ', ' ', win_hl_attr(wp, HLF_FC));
}
if (signcolumn_on(wp)) {
@@ -1611,7 +1616,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
}
screen_fill(wp->w_winrow + row, wp->w_winrow + endrow,
W_ENDCOL(wp) - nn, W_ENDCOL(wp) - n,
- ' ', ' ', hl_attr(HLF_SC));
+ ' ', ' ', win_hl_attr(wp, HLF_SC));
n = nn;
}
@@ -1629,7 +1634,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
n = wp->w_width;
screen_fill(wp->w_winrow + row, wp->w_winrow + endrow,
wp->w_wincol, wp->w_wincol + n,
- cmdwin_type, ' ', hl_attr(HLF_AT));
+ cmdwin_type, ' ', win_hl_attr(wp, HLF_AT));
}
if (fdc > 0) {
int nn = n + fdc;
@@ -1639,7 +1644,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
nn = wp->w_width;
screen_fill(wp->w_winrow + row, wp->w_winrow + endrow,
wp->w_wincol + n, wp->w_wincol + nn,
- ' ', ' ', hl_attr(HLF_FC));
+ ' ', ' ', win_hl_attr(wp, HLF_FC));
n = nn;
}
@@ -1652,7 +1657,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
}
screen_fill(wp->w_winrow + row, wp->w_winrow + endrow,
wp->w_wincol + n, wp->w_wincol + nn,
- ' ', ' ', hl_attr(HLF_SC));
+ ' ', ' ', win_hl_attr(wp, HLF_SC));
n = nn;
}
@@ -1720,10 +1725,9 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
*/
if (cmdwin_type != 0 && wp == curwin) {
ScreenLines[off] = cmdwin_type;
- ScreenAttrs[off] = hl_attr(HLF_AT);
- if (enc_utf8)
- ScreenLinesUC[off] = 0;
- ++col;
+ ScreenAttrs[off] = win_hl_attr(wp, HLF_AT);
+ ScreenLinesUC[off] = 0;
+ col++;
}
// 2. Add the 'foldcolumn'
@@ -1735,12 +1739,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
int i;
copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
- hl_attr(HLF_FC));
- /* reverse the fold column */
- for (i = 0; i < fdc; ++i)
+ win_hl_attr(wp, HLF_FC));
+ // reverse the fold column
+ for (i = 0; i < fdc; i++) {
ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
- } else
- copy_text_attr(off + col, buf, fdc, hl_attr(HLF_FC));
+ }
+ } else {
+ copy_text_attr(off + col, buf, fdc, win_hl_attr(wp, HLF_FC));
+ }
col += fdc;
}
@@ -1753,7 +1759,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
/* Set all attributes of the 'number' or 'relativenumber' column and the
* text */
- RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col);
+ RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_width - col);
// If signs are being displayed, add two spaces.
if (signcolumn_on(wp)) {
@@ -1762,7 +1768,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
if (len > 2) {
len = 2;
}
- copy_text_attr(off + col, (char_u *)" ", len, hl_attr(HLF_FL));
+ copy_text_attr(off + col, (char_u *)" ", len,
+ win_hl_attr(wp, HLF_FL));
col += len;
}
}
@@ -1794,13 +1801,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
}
- sprintf((char *)buf, fmt, w, num);
- if (wp->w_p_rl)
- /* the line number isn't reversed */
+ snprintf((char *)buf, FOLD_TEXT_LEN, fmt, w, num);
+ if (wp->w_p_rl) {
+ // the line number isn't reversed
copy_text_attr(off + wp->w_width - len - col, buf, len,
- hl_attr(HLF_FL));
- else
- copy_text_attr(off + col, buf, len, hl_attr(HLF_FL));
+ win_hl_attr(wp, HLF_FL));
+ } else {
+ copy_text_attr(off + col, buf, len, win_hl_attr(wp, HLF_FL));
+ }
col += len;
}
}
@@ -1958,12 +1966,12 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
len = wp->w_old_cursor_lcol;
else
len = wp->w_width - txtcol;
- RL_MEMSET(wp->w_old_cursor_fcol + txtcol, hl_attr(HLF_V),
- len - (int)wp->w_old_cursor_fcol);
+ RL_MEMSET(wp->w_old_cursor_fcol + txtcol, win_hl_attr(wp, HLF_V),
+ len - (int)wp->w_old_cursor_fcol);
}
} else {
- /* Set all attributes of the text */
- RL_MEMSET(txtcol, hl_attr(HLF_V), wp->w_width - txtcol);
+ // Set all attributes of the text
+ RL_MEMSET(txtcol, win_hl_attr(wp, HLF_V), wp->w_width - txtcol);
}
}
}
@@ -1983,7 +1991,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
if (txtcol >= 0 && txtcol < wp->w_width) {
ScreenAttrs[off + txtcol] =
- hl_combine_attr(ScreenAttrs[off + txtcol], hl_attr(HLF_MC));
+ hl_combine_attr(ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_MC));
}
txtcol = old_txtcol;
j = wp->w_p_cc_cols[++i];
@@ -1999,11 +2007,11 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
txtcol -= wp->w_leftcol;
if (txtcol >= 0 && txtcol < wp->w_width)
ScreenAttrs[off + txtcol] = hl_combine_attr(
- ScreenAttrs[off + txtcol], hl_attr(HLF_CUC));
+ ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_CUC));
}
- SCREEN_LINE(row + wp->w_winrow, wp->w_wincol, wp->w_width,
- wp->w_width, FALSE);
+ screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width,
+ wp->w_width, false, wp);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -2202,7 +2210,7 @@ win_line (
bool search_attr_from_match = false; // if search_attr is from :match
bool has_bufhl = false; // this buffer has highlight matches
int bufhl_attr = 0; // attributes desired by bufhl
- bufhl_lineinfo_T bufhl_info; // bufhl data for this line
+ BufhlLineInfo bufhl_info; // bufhl data for this line
/* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */
@@ -2218,7 +2226,7 @@ win_line (
int syntax_flags = 0;
int syntax_seqnr = 0;
int prev_syntax_id = 0;
- int conceal_attr = hl_attr(HLF_CONCEAL);
+ int conceal_attr = win_hl_attr(wp, HLF_CONCEAL);
int is_concealing = false;
int boguscols = 0; ///< nonexistent columns added to
///< force wrapping
@@ -2366,8 +2374,8 @@ win_line (
/* if inverting in this line set area_highlighting */
if (fromcol >= 0) {
- area_highlighting = TRUE;
- attr = hl_attr(HLF_V);
+ area_highlighting = true;
+ attr = win_hl_attr(wp, HLF_V);
}
}
/*
@@ -2391,8 +2399,8 @@ win_line (
/* do at least one character; happens when past end of line */
if (fromcol == tocol)
tocol = fromcol + 1;
- area_highlighting = TRUE;
- attr = hl_attr(HLF_I);
+ area_highlighting = true;
+ attr = win_hl_attr(wp, HLF_I);
}
filler_lines = diff_check(wp, lnum);
@@ -2420,11 +2428,11 @@ win_line (
// Highlight the current line in the quickfix window.
if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) {
- line_attr = hl_attr(HLF_QFL);
+ line_attr = win_hl_attr(wp, HLF_QFL);
}
- if (wp->w_hl_attr != 0) {
- line_attr = hl_combine_attr(wp->w_hl_attr, line_attr);
+ if (wp->w_hl_attr_normal != 0) {
+ line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
}
if (line_attr != 0) {
@@ -2652,9 +2660,9 @@ win_line (
&& !(wp == curwin && VIsual_active)) {
if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer)
&& qf_current_entry(wp) == lnum) {
- line_attr = hl_combine_attr(hl_attr(HLF_CUL), line_attr);
+ line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr);
} else {
- line_attr = hl_attr(HLF_CUL);
+ line_attr = win_hl_attr(wp, HLF_CUL);
}
area_highlighting = true;
}
@@ -2687,7 +2695,7 @@ win_line (
/* Draw the cmdline character. */
n_extra = 1;
c_extra = cmdwin_type;
- char_attr = hl_attr(HLF_AT);
+ char_attr = win_hl_attr(wp, HLF_AT);
}
}
@@ -2702,7 +2710,7 @@ win_line (
p_extra = extra;
p_extra[n_extra] = NUL;
c_extra = NUL;
- char_attr = hl_attr(HLF_FC);
+ char_attr = win_hl_attr(wp, HLF_FC);
}
}
@@ -2715,7 +2723,7 @@ win_line (
int text_sign;
/* Draw two cells with the sign value or blank. */
c_extra = ' ';
- char_attr = hl_attr(HLF_SC);
+ char_attr = win_hl_attr(wp, HLF_SC);
n_extra = 2;
if (row == startrow + filler_lines && filler_todo <= 0) {
@@ -2772,14 +2780,15 @@ win_line (
} else
c_extra = ' ';
n_extra = number_width(wp) + 1;
- char_attr = hl_attr(HLF_N);
- /* When 'cursorline' is set highlight the line number of
- * the current line differently.
- * TODO: Can we use CursorLine instead of CursorLineNr
- * when CursorLineNr isn't set? */
+ char_attr = win_hl_attr(wp, HLF_N);
+ // When 'cursorline' is set highlight the line number of
+ // the current line differently.
+ // TODO(vim): Can we use CursorLine instead of CursorLineNr
+ // when CursorLineNr isn't set?
if ((wp->w_p_cul || wp->w_p_rnu)
- && lnum == wp->w_cursor.lnum)
- char_attr = hl_attr(HLF_CLN);
+ && lnum == wp->w_cursor.lnum) {
+ char_attr = win_hl_attr(wp, HLF_CLN);
+ }
}
}
@@ -2796,12 +2805,12 @@ win_line (
if (draw_state == WL_BRI - 1 && n_extra == 0) {
draw_state = WL_BRI;
if (wp->w_p_bri && row != startrow && filler_lines == 0) {
- char_attr = 0; // was: hl_attr(HLF_AT);
+ char_attr = wp->w_hl_attr_normal; // was: hl_attr(HLF_AT);
if (diff_hlf != (hlf_T)0) {
- char_attr = hl_attr(diff_hlf);
+ char_attr = win_hl_attr(wp, diff_hlf);
if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL));
+ char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL));
}
}
p_extra = NULL;
@@ -2826,15 +2835,15 @@ win_line (
n_extra = col + 1;
else
n_extra = wp->w_width - col;
- char_attr = hl_attr(HLF_DED);
+ char_attr = win_hl_attr(wp, HLF_DED);
}
if (*p_sbr != NUL && need_showbreak) {
/* Draw 'showbreak' at the start of each broken line. */
p_extra = p_sbr;
c_extra = NUL;
n_extra = (int)STRLEN(p_sbr);
- char_attr = hl_attr(HLF_AT);
- need_showbreak = FALSE;
+ char_attr = win_hl_attr(wp, HLF_AT);
+ need_showbreak = false;
vcol_sbr = vcol + MB_CHARLEN(p_sbr);
/* Correct end of highlighted area for 'showbreak',
* required when 'linebreak' is also set. */
@@ -2842,7 +2851,7 @@ win_line (
tocol += n_extra;
/* combine 'showbreak' with 'cursorline' */
if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL));
+ char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL));
}
}
}
@@ -2855,12 +2864,9 @@ win_line (
c_extra = saved_c_extra;
p_extra = saved_p_extra;
char_attr = saved_char_attr;
- } else
- char_attr = 0;
- }
-
- if (wp->w_hl_attr != 0) {
- char_attr = hl_combine_attr(wp->w_hl_attr, char_attr);
+ } else {
+ char_attr = wp->w_hl_attr_normal;
+ }
}
}
@@ -2869,13 +2875,14 @@ win_line (
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
&& filler_todo <= 0
) {
- SCREEN_LINE(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl);
- /* Pretend we have finished updating the window. Except when
- * 'cursorcolumn' is set. */
- if (wp->w_p_cuc)
+ screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp);
+ // Pretend we have finished updating the window. Except when
+ // 'cursorcolumn' is set.
+ if (wp->w_p_cuc) {
row = wp->w_cline_row + wp->w_cline_height;
- else
+ } else {
row = wp->w_height;
+ }
break;
}
@@ -3003,14 +3010,16 @@ win_line (
if (diff_hlf != (hlf_T)0) {
if (diff_hlf == HLF_CHD && ptr - line >= change_start
- && n_extra == 0)
- diff_hlf = HLF_TXD; /* changed text */
+ && n_extra == 0) {
+ diff_hlf = HLF_TXD; // changed text
+ }
if (diff_hlf == HLF_TXD && ptr - line > change_end
- && n_extra == 0)
- diff_hlf = HLF_CHD; /* changed line */
- line_attr = hl_attr(diff_hlf);
+ && n_extra == 0) {
+ diff_hlf = HLF_CHD; // changed line
+ }
+ line_attr = win_hl_attr(wp, diff_hlf);
if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- line_attr = hl_combine_attr(line_attr, hl_attr(HLF_CUL));
+ line_attr = hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL));
}
}
@@ -3026,14 +3035,15 @@ win_line (
// (area_attr may be 0 when "noinvcur" is set).
else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
|| vcol < fromcol || vcol_prev < fromcol_prev
- || vcol >= tocol))
+ || vcol >= tocol)) {
char_attr = line_attr;
- else {
- attr_pri = FALSE;
- if (has_syntax)
+ } else {
+ attr_pri = false;
+ if (has_syntax) {
char_attr = syntax_attr;
- else
- char_attr = 0;
+ } else {
+ char_attr = wp->w_hl_attr_normal;
+ }
}
}
@@ -3094,11 +3104,8 @@ win_line (
c = '>';
mb_c = c;
mb_l = 1;
- mb_utf8 = FALSE;
- multi_attr = hl_attr(HLF_AT);
- if (wp->w_hl_attr != 0) {
- multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr);
- }
+ mb_utf8 = false;
+ multi_attr = win_hl_attr(wp, HLF_AT);
// put the pointer back to output the double-width
// character at the start of the next line.
@@ -3166,8 +3173,8 @@ win_line (
c_extra = NUL;
if (area_attr == 0 && search_attr == 0) {
n_attr = n_extra + 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
+ extra_attr = win_hl_attr(wp, HLF_8);
+ saved_attr2 = char_attr; // save current attr
}
} else if (mb_l == 0) /* at the NUL at end-of-line */
mb_l = 1;
@@ -3219,8 +3226,8 @@ win_line (
c = *p_extra++;
if (area_attr == 0 && search_attr == 0) {
n_attr = n_extra + 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
+ extra_attr = win_hl_attr(wp, HLF_8);
+ saved_attr2 = char_attr; // save current attr
}
mb_c = c;
}
@@ -3237,10 +3244,7 @@ win_line (
mb_c = c;
mb_utf8 = FALSE;
mb_l = 1;
- multi_attr = hl_attr(HLF_AT);
- if (wp->w_hl_attr != 0) {
- multi_attr = hl_combine_attr(wp->w_hl_attr, multi_attr);
- }
+ multi_attr = win_hl_attr(wp, HLF_AT);
// Put pointer back so that the character will be
// displayed at the start of the next line.
ptr--;
@@ -3257,8 +3261,8 @@ win_line (
c = ' ';
if (area_attr == 0 && search_attr == 0) {
n_attr = n_extra + 1;
- extra_attr = hl_attr(HLF_AT);
- saved_attr2 = char_attr; /* save current attr */
+ extra_attr = win_hl_attr(wp, HLF_AT);
+ saved_attr2 = char_attr; // save current attr
}
mb_c = c;
mb_utf8 = FALSE;
@@ -3306,7 +3310,7 @@ win_line (
else
syntax_flags = get_syntax_info(&syntax_seqnr);
} else if (!attr_pri) {
- char_attr = 0;
+ char_attr = wp->w_hl_attr_normal;
}
/* Check spelling (unless at the end of the line).
@@ -3432,7 +3436,7 @@ win_line (
|| (c == ' ' && lcs_space && ptr - line <= trailcol))) {
c = (c == ' ') ? lcs_space : lcs_nbsp;
n_attr = 1;
- extra_attr = hl_attr(HLF_0);
+ extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3447,7 +3451,7 @@ win_line (
if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') {
c = lcs_trail;
n_attr = 1;
- extra_attr = hl_attr(HLF_0);
+ extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3548,7 +3552,7 @@ win_line (
c_extra = lcs_tab2;
}
n_attr = tab_len + 1;
- extra_attr = hl_attr(HLF_0);
+ extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3595,7 +3599,7 @@ win_line (
}
lcs_eol_one = -1;
ptr--; // put it back at the NUL
- extra_attr = hl_attr(HLF_AT);
+ extra_attr = win_hl_attr(wp, HLF_AT);
n_attr = 1;
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3626,7 +3630,7 @@ win_line (
c = *p_extra++;
}
n_attr = n_extra + 1;
- extra_attr = hl_attr(HLF_8);
+ extra_attr = win_hl_attr(wp, HLF_8);
saved_attr2 = char_attr; // save current attr
mb_utf8 = false; // don't draw as UTF-8
} else if (VIsual_active
@@ -3658,9 +3662,10 @@ win_line (
if (diff_hlf == HLF_TXD) {
diff_hlf = HLF_CHD;
if (attr == 0 || char_attr != attr) {
- char_attr = hl_attr(diff_hlf);
+ char_attr = win_hl_attr(wp, diff_hlf);
if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUL));
+ char_attr = hl_combine_attr(char_attr,
+ win_hl_attr(wp, HLF_CUL));
}
}
}
@@ -3762,7 +3767,7 @@ win_line (
c_extra = MB_FILLER_CHAR;
n_extra = 1;
n_attr = 2;
- extra_attr = hl_attr(HLF_AT);
+ extra_attr = win_hl_attr(wp, HLF_AT);
}
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3773,10 +3778,7 @@ win_line (
mb_utf8 = false; // don't draw as UTF-8
}
saved_attr3 = char_attr; // save current attr
- char_attr = hl_attr(HLF_AT); // overwriting char_attr
- if (wp->w_hl_attr != 0) {
- char_attr = hl_combine_attr(wp->w_hl_attr, char_attr);
- }
+ char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr
n_attr3 = 1;
}
@@ -3861,8 +3863,8 @@ win_line (
}
}
- if (wp->w_hl_attr != 0) {
- char_attr = hl_combine_attr(wp->w_hl_attr, char_attr);
+ if (wp->w_hl_attr_normal != 0) {
+ char_attr = hl_combine_attr(wp->w_hl_attr_normal, char_attr);
}
ScreenAttrs[off] = char_attr;
if (wp->w_p_rl) {
@@ -3925,13 +3927,8 @@ win_line (
if (rightmost_vcol < color_cols[i])
rightmost_vcol = color_cols[i];
- int cuc_attr = hl_attr(HLF_CUC);
- int mc_attr = hl_attr(HLF_MC);
- if (wp->w_hl_attr != 0) {
- cuc_attr = hl_combine_attr(wp->w_hl_attr, cuc_attr);
- mc_attr = hl_combine_attr(wp->w_hl_attr, mc_attr);
- }
-
+ int cuc_attr = win_hl_attr(wp, HLF_CUC);
+ int mc_attr = win_hl_attr(wp, HLF_MC);
while (col < wp->w_width) {
ScreenLines[off] = ' ';
@@ -3947,7 +3944,7 @@ win_line (
} else if (draw_color_col && VCOL_HLC == *color_cols) {
ScreenAttrs[off++] = mc_attr;
} else {
- ScreenAttrs[off++] = wp->w_hl_attr;
+ ScreenAttrs[off++] = wp->w_hl_attr_normal;
}
if (VCOL_HLC >= rightmost_vcol)
@@ -3970,7 +3967,7 @@ win_line (
col++;
}
}
- SCREEN_LINE(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl);
+ screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp);
row++;
/*
@@ -3998,10 +3995,7 @@ win_line (
|| (wp->w_p_list && lcs_eol_one > 0)
|| (n_extra && (c_extra != NUL || *p_extra != NUL)))) {
c = lcs_ext;
- char_attr = hl_attr(HLF_AT);
- if (wp->w_hl_attr != 0) {
- char_attr = hl_combine_attr(wp->w_hl_attr, char_attr);
- }
+ char_attr = win_hl_attr(wp, HLF_AT);
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
mb_utf8 = TRUE;
@@ -4024,10 +4018,10 @@ win_line (
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
&& lnum != wp->w_cursor.lnum) {
vcol_save_attr = char_attr;
- char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUC));
+ char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUC));
} else if (draw_color_col && VCOL_HLC == *color_cols) {
vcol_save_attr = char_attr;
- char_attr = hl_combine_attr(char_attr, hl_attr(HLF_MC));
+ char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_MC));
}
}
@@ -4195,8 +4189,8 @@ win_line (
|| (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
|| (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
) {
- SCREEN_LINE(screen_row, wp->w_wincol, col - boguscols,
- wp->w_width, wp->w_p_rl);
+ screen_line(screen_row, wp->w_wincol, col - boguscols,
+ wp->w_width, wp->w_p_rl, wp);
boguscols = 0;
++row;
++screen_row;
@@ -4363,7 +4357,8 @@ static int char_needs_redraw(int off_from, int off_to, int cols)
* When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
*/
-static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag)
+static void screen_line(int row, int coloff, int endcol,
+ int clear_width, int rlflag, win_T *wp)
{
unsigned off_from;
unsigned off_to;
@@ -4525,11 +4520,11 @@ static void screen_line(int row, int coloff, int endcol, int clear_width, int rl
}
if (clear_width > 0) {
- /* For a window that's left of another, draw the separator char. */
- if (col + coloff < Columns) {
+ // For a window that's left of another, draw the separator char.
+ if (col + coloff < Columns && wp->w_vsep_width > 0) {
int c;
- c = fillchar_vsep(&hl);
+ c = fillchar_vsep(wp, &hl);
if (ScreenLines[off_to] != (schar_T)c
|| (enc_utf8 && (int)ScreenLinesUC[off_to]
!= (c >= 0x80 ? c : 0))
@@ -4634,8 +4629,8 @@ static void draw_vsep_win(win_T *wp, int row)
int c;
if (wp->w_vsep_width) {
- /* draw the vertical separator right of this window */
- c = fillchar_vsep(&hl);
+ // draw the vertical separator right of this window
+ c = fillchar_vsep(wp, &hl);
screen_fill(wp->w_winrow + row, wp->w_winrow + wp->w_height,
W_ENDCOL(wp), W_ENDCOL(wp) + 1,
c, ' ', hl);
@@ -4765,7 +4760,7 @@ win_redr_status_matches (
--first_match;
}
- fillchar = fillchar_status(&attr, TRUE);
+ fillchar = fillchar_status(&attr, curwin);
if (first_match == 0) {
*buf = NUL;
@@ -4897,7 +4892,7 @@ void win_redr_status(win_T *wp)
/* redraw custom status line */
redraw_custom_statusline(wp);
} else {
- fillchar = fillchar_status(&attr, wp == curwin);
+ fillchar = fillchar_status(&attr, wp);
get_trans_bufname(wp->w_buffer);
p = NameBuff;
@@ -4969,10 +4964,11 @@ void win_redr_status(win_T *wp)
* May need to draw the character below the vertical separator.
*/
if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing()) {
- if (stl_connected(wp))
- fillchar = fillchar_status(&attr, wp == curwin);
- else
- fillchar = fillchar_vsep(&attr);
+ if (stl_connected(wp)) {
+ fillchar = fillchar_status(&attr, wp);
+ } else {
+ fillchar = fillchar_vsep(wp, &attr);
+ }
screen_putchar(fillchar, wp->w_winrow + wp->w_height,
W_ENDCOL(wp), attr);
}
@@ -5122,7 +5118,7 @@ win_redr_custom (
use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
} else {
row = wp->w_winrow + wp->w_height;
- fillchar = fillchar_status(&attr, wp == curwin);
+ fillchar = fillchar_status(&attr, wp);
maxwidth = wp->w_width;
if (draw_ruler) {
@@ -5507,8 +5503,7 @@ static void start_search_hl(void)
{
if (p_hls && !no_hlsearch) {
last_pat_prog(&search_hl.rm);
- search_hl.attr = hl_attr(HLF_L);
- /* Set the time limit to 'redrawtime'. */
+ // Set the time limit to 'redrawtime'.
search_hl.tm = profile_setlimit(p_rdt);
}
}
@@ -5524,6 +5519,42 @@ static void end_search_hl(void)
}
}
+static void update_window_hl(win_T *wp, bool invalid)
+{
+ if (!wp->w_hl_needs_update && !invalid) {
+ return;
+ }
+ wp->w_hl_needs_update = false;
+
+ // determine window specific background set in 'winhighlight'
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) {
+ wp->w_hl_attr_normal = syn_id2attr(wp->w_hl_ids[HLF_INACTIVE]);
+ } else if (wp->w_hl_id_normal > 0) {
+ wp->w_hl_attr_normal = syn_id2attr(wp->w_hl_id_normal);
+ } else {
+ wp->w_hl_attr_normal = 0;
+ }
+ if (wp != curwin) {
+ wp->w_hl_attr_normal = hl_combine_attr(hl_attr(HLF_INACTIVE),
+ wp->w_hl_attr_normal);
+ }
+
+ for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
+ int attr;
+ if (wp->w_hl_ids[hlf] > 0) {
+ attr = syn_id2attr(wp->w_hl_ids[hlf]);
+ } else {
+ attr = hl_attr(hlf);
+ }
+ if (wp->w_hl_attr_normal != 0) {
+ attr = hl_combine_attr(wp->w_hl_attr_normal, attr);
+ }
+ wp->w_hl_attrs[hlf] = attr;
+ }
+}
+
+
+
/*
* Init for calling prepare_search_hl().
*/
@@ -5550,19 +5581,9 @@ static void init_search_hl(win_T *wp)
search_hl.buf = wp->w_buffer;
search_hl.lnum = 0;
search_hl.first_lnum = 0;
- // time limit is set at the toplevel, for all windows
+ search_hl.attr = win_hl_attr(wp, HLF_L);
- // determine window specific background set in 'winhighlight'
- if (wp != curwin && wp->w_hl_id_inactive > 0) {
- wp->w_hl_attr = syn_id2attr(wp->w_hl_id_inactive);
- } else if (wp->w_hl_id > 0) {
- wp->w_hl_attr = syn_id2attr(wp->w_hl_id);
- } else {
- wp->w_hl_attr = 0;
- }
- if (wp != curwin) {
- wp->w_hl_attr = hl_combine_attr(hl_attr(HLF_INACTIVE), wp->w_hl_attr);
- }
+ // time limit is set at the toplevel, for all windows
}
/*
@@ -6774,7 +6795,7 @@ int showmode(void)
if (edit_submode_extra != NULL) {
MSG_PUTS_ATTR(" ", attr); // Add a space in between.
if ((int)edit_submode_highl < (int)HLF_COUNT) {
- sub_attr = hl_attr(edit_submode_highl);
+ sub_attr = win_hl_attr(curwin, edit_submode_highl);
} else {
sub_attr = attr;
}
@@ -6927,7 +6948,6 @@ static void draw_tabline(void)
int modified;
int c;
int len;
- int attr_sel = hl_attr(HLF_TPS);
int attr_nosel = hl_attr(HLF_TP);
int attr_fill = hl_attr(HLF_TPF);
char_u *p;
@@ -6989,16 +7009,6 @@ static void draw_tabline(void)
scol = col;
- if (tp->tp_topframe == topframe)
- attr = attr_sel;
- if (use_sep_chars && col > 0)
- screen_putchar('|', 0, col++, attr);
-
- if (tp->tp_topframe != topframe)
- attr = attr_nosel;
-
- screen_putchar(' ', 0, col++, attr);
-
if (tp == curtab) {
cwp = curwin;
wp = firstwin;
@@ -7007,10 +7017,29 @@ static void draw_tabline(void)
wp = tp->tp_firstwin;
}
- modified = FALSE;
- for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
- if (bufIsChanged(wp->w_buffer))
- modified = TRUE;
+
+ if (tp->tp_topframe == topframe) {
+ attr = win_hl_attr(cwp, HLF_TPS);
+ }
+ if (use_sep_chars && col > 0) {
+ screen_putchar('|', 0, col++, attr);
+ }
+
+ if (tp->tp_topframe != topframe) {
+ attr = win_hl_attr(cwp, HLF_TP);
+ }
+
+ screen_putchar(' ', 0, col++, attr);
+
+ modified = false;
+
+ for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount) {
+ if (bufIsChanged(wp->w_buffer)) {
+ modified = true;
+ }
+ }
+
+
if (modified || wincount > 1) {
if (wincount > 1) {
vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
@@ -7018,7 +7047,7 @@ static void draw_tabline(void)
if (col + len >= Columns - 3)
break;
screen_puts_len(NameBuff, len, 0, col,
- hl_combine_attr(attr, hl_attr(HLF_T)));
+ hl_combine_attr(attr, win_hl_attr(cwp, HLF_T)));
col += len;
}
if (modified)
@@ -7116,25 +7145,28 @@ void get_trans_bufname(buf_T *buf)
/*
* Get the character to use in a status line. Get its attributes in "*attr".
*/
-static int fillchar_status(int *attr, int is_curwin)
+static int fillchar_status(int *attr, win_T *wp)
{
int fill;
+ bool is_curwin = (wp == curwin);
if (is_curwin) {
- *attr = hl_attr(HLF_S);
+ *attr = win_hl_attr(wp, HLF_S);
fill = fill_stl;
} else {
- *attr = hl_attr(HLF_SNC);
+ *attr = win_hl_attr(wp, HLF_SNC);
fill = fill_stlnc;
}
/* Use fill when there is highlighting, and highlighting of current
* window differs, or the fillchars differ, or this is not the
* current window */
- if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC)
+ if (*attr != 0 && ((win_hl_attr(wp, HLF_S) != win_hl_attr(wp, HLF_SNC)
|| !is_curwin || firstwin == lastwin)
- || (fill_stl != fill_stlnc)))
+ || (fill_stl != fill_stlnc))) {
return fill;
- if (is_curwin)
+ }
+ if (is_curwin) {
return '^';
+ }
return '=';
}
@@ -7142,13 +7174,14 @@ static int fillchar_status(int *attr, int is_curwin)
* Get the character to use in a separator between vertically split windows.
* Get its attributes in "*attr".
*/
-static int fillchar_vsep(int *attr)
+static int fillchar_vsep(win_T *wp, int *attr)
{
- *attr = hl_attr(HLF_C);
- if (*attr == 0 && fill_vert == ' ')
+ *attr = win_hl_attr(wp, HLF_C);
+ if (*attr == 0 && fill_vert == ' ') {
return '|';
- else
+ } else {
return fill_vert;
+ }
}
/*
@@ -7263,7 +7296,7 @@ static void win_redr_ruler(win_T *wp, int always)
if (wp->w_status_height) {
row = wp->w_winrow + wp->w_height;
- fillchar = fillchar_status(&attr, wp == curwin);
+ fillchar = fillchar_status(&attr, wp);
off = wp->w_wincol;
width = wp->w_width;
} else {
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 61ef2e9ba3..1bf2317d2a 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1005,14 +1005,13 @@ int do_search(
dircp = NULL;
/* use previous pattern */
if (pat == NULL || *pat == NUL || *pat == dirc) {
- if (spats[RE_SEARCH].pat == NULL) { /* no previous pattern */
- pat = spats[RE_SUBST].pat;
- if (pat == NULL) {
+ if (spats[RE_SEARCH].pat == NULL) { // no previous pattern
+ searchstr = spats[RE_SUBST].pat;
+ if (searchstr == NULL) {
EMSG(_(e_noprevre));
retval = 0;
goto end_do_search;
}
- searchstr = pat;
} else {
/* make search_regcomp() use spats[RE_SEARCH].pat */
searchstr = (char_u *)"";
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 4788b1e7d0..736d6bf162 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -3413,8 +3413,16 @@ shada_read_next_item_start:
return mru_ret;
}
- const size_t length = (size_t) length_u64;
- entry->timestamp = (Timestamp) timestamp_u64;
+ if (length_u64 > PTRDIFF_MAX) {
+ emsgf(_(RCERR "Error while reading ShaDa file: "
+ "there is an item at position %" PRIu64 " "
+ "that is stated to be too long"),
+ initial_fpos);
+ return kSDReadStatusNotShaDa;
+ }
+
+ const size_t length = (size_t)length_u64;
+ entry->timestamp = (Timestamp)timestamp_u64;
if (type_u64 == 0) {
// kSDItemUnknown cannot possibly pass that far because it is -1 and that
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 25ae562e65..715228cb4b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1433,12 +1433,10 @@ spell_move_to (
// the cursor.
if (dir == BACKWARD
|| lnum != wp->w_cursor.lnum
- || (lnum == wp->w_cursor.lnum
- && (wrapped
- || ((colnr_T)(curline
- ? p - buf + (ptrdiff_t)len
- : p - buf)
- > wp->w_cursor.col)))) {
+ || wrapped
+ || ((colnr_T)(curline
+ ? p - buf + (ptrdiff_t)len
+ : p - buf) > wp->w_cursor.col)) {
if (has_syntax) {
col = (int)(p - buf);
(void)syn_get_id(wp, lnum, (colnr_T)col,
@@ -3635,7 +3633,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// word).
depth = 0;
sp = &stack[0];
- memset(sp, 0, sizeof(trystate_T));
+ memset(sp, 0, sizeof(trystate_T)); // -V512
sp->ts_curi = 1;
if (soundfold) {
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index c5fd8741b8..687f734742 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -653,7 +653,7 @@ static float_T tv_float(typval_T *const tvs, int *const idxp)
if (tvs[idx].v_type == VAR_FLOAT) {
f = tvs[idx].vval.v_float;
} else if (tvs[idx].v_type == VAR_NUMBER) {
- f = tvs[idx].vval.v_number;
+ f = (float_T)tvs[idx].vval.v_number;
} else {
EMSG(_("E807: Expected Float argument for printf()"));
}
@@ -910,6 +910,13 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
default: break;
}
+ switch (fmt_spec) {
+ case 'd': case 'u': case 'o': case 'x': case 'X':
+ if (tvs && length_modifier == '\0') {
+ length_modifier = '2';
+ }
+ }
+
// get parameter value, do initial processing
switch (fmt_spec) {
// '%' and 'c' behave similar to 's' regarding flags and field widths
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index a4bb260183..f0171fa525 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -1666,8 +1666,9 @@ syn_current_attr (
* If we found a match after the last column, use it.
*/
if (next_match_idx >= 0 && next_match_col >= (int)current_col
- && next_match_col != MAXCOL)
- (void)push_next_match(NULL);
+ && next_match_col != MAXCOL) {
+ (void)push_next_match();
+ }
current_finished = TRUE;
current_state_stored = FALSE;
@@ -1985,9 +1986,10 @@ syn_current_attr (
* endless loop). */
GA_APPEND(int, &zero_width_next_ga, next_match_idx);
next_match_idx = -1;
- } else
- cur_si = push_next_match(cur_si);
- found_match = TRUE;
+ } else {
+ cur_si = push_next_match();
+ }
+ found_match = true;
}
}
}
@@ -2167,9 +2169,10 @@ static int did_match_already(int idx, garray_T *gap)
/*
* Push the next match onto the stack.
*/
-static stateitem_T *push_next_match(stateitem_T *cur_si)
+static stateitem_T *push_next_match(void)
{
- synpat_T *spp;
+ stateitem_T *cur_si;
+ synpat_T *spp;
int save_flags;
spp = &(SYN_ITEMS(syn_block)[next_match_idx]);
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 8d207e6286..9f309451b0 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -1,10 +1,9 @@
#ifndef NVIM_SYNTAX_DEFS_H
#define NVIM_SYNTAX_DEFS_H
+#include "nvim/highlight_defs.h"
#include "nvim/regexp_defs.h"
-typedef int32_t RgbValue;
-
# define SST_MIN_ENTRIES 150 /* minimal size for state stack array */
# define SST_MAX_ENTRIES 1000 /* maximal size for state stack array */
# define SST_FIX_STATES 7 /* size of sst_stack[]. */
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 88b45add54..be9d621c7d 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -106,15 +106,6 @@ static char_u *topmsg = (char_u *)N_("E556: at top of tag stack");
static char_u *tagmatchname = NULL; /* name of last used tag */
/*
- * We use ftello() here, if available. It returns off_t instead of long,
- * which helps if long is 32 bit and off_t is 64 bit.
- * We assume that when fseeko() is available then ftello() is too.
- */
-#ifdef HAVE_FSEEKO
-# define ftell ftello
-#endif
-
-/*
* Tag for preview window is remembered separately, to avoid messing up the
* normal tagstack.
*/
@@ -1088,22 +1079,21 @@ find_tags (
char_u *p;
char_u *s;
int i;
- int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */
- struct tag_search_info /* Binary search file offsets */
- {
- off_t low_offset; /* offset for first char of first line that
- could match */
- off_t high_offset; /* offset of char after last line that could
- match */
- off_t curr_offset; /* Current file offset in search range */
- off_t curr_offset_used; /* curr_offset used when skipping back */
- off_t match_offset; /* Where the binary search found a tag */
- int low_char; /* first char at low_offset */
- int high_char; /* first char at high_offset */
+ int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
+ struct tag_search_info { // Binary search file offsets
+ off_T low_offset; // offset for first char of first line that
+ // could match
+ off_T high_offset; // offset of char after last line that could
+ // match
+ off_T curr_offset; // Current file offset in search range
+ off_T curr_offset_used; // curr_offset used when skipping back
+ off_T match_offset; // Where the binary search found a tag
+ int low_char; // first char at low_offset
+ int high_char; // first char at high_offset
} search_info;
- off_t filesize;
+ off_T filesize;
int tagcmp;
- off_t offset;
+ off_T offset;
int round;
enum {
TS_START, /* at start of file */
@@ -1378,36 +1368,28 @@ find_tags (
if (state == TS_BINARY || state == TS_SKIP_BACK) {
/* Adjust the search file offset to the correct position */
search_info.curr_offset_used = search_info.curr_offset;
-#ifdef HAVE_FSEEKO
- fseeko(fp, search_info.curr_offset, SEEK_SET);
-#else
- fseek(fp, (long)search_info.curr_offset, SEEK_SET);
-#endif
+ vim_fseek(fp, search_info.curr_offset, SEEK_SET);
eof = vim_fgets(lbuf, LSIZE, fp);
if (!eof && search_info.curr_offset != 0) {
/* The explicit cast is to work around a bug in gcc 3.4.2
* (repeated below). */
- search_info.curr_offset = ftell(fp);
+ search_info.curr_offset = vim_ftell(fp);
if (search_info.curr_offset == search_info.high_offset) {
- /* oops, gone a bit too far; try from low offset */
-#ifdef HAVE_FSEEKO
- fseeko(fp, search_info.low_offset, SEEK_SET);
-#else
- fseek(fp, (long)search_info.low_offset, SEEK_SET);
-#endif
+ // oops, gone a bit too far; try from low offset
+ vim_fseek(fp, search_info.low_offset, SEEK_SET);
search_info.curr_offset = search_info.low_offset;
}
eof = vim_fgets(lbuf, LSIZE, fp);
}
/* skip empty and blank lines */
while (!eof && vim_isblankline(lbuf)) {
- search_info.curr_offset = ftell(fp);
+ search_info.curr_offset = vim_ftell(fp);
eof = vim_fgets(lbuf, LSIZE, fp);
}
if (eof) {
/* Hit end of file. Skip backwards. */
state = TS_SKIP_BACK;
- search_info.match_offset = ftell(fp);
+ search_info.match_offset = vim_ftell(fp);
search_info.curr_offset = search_info.curr_offset_used;
continue;
}
@@ -1523,10 +1505,10 @@ line_read_in:
*/
if (state == TS_BINARY) {
// Get the tag file size.
- if ((filesize = lseek(fileno(fp), (off_t)0L, SEEK_END)) <= 0) {
+ if ((filesize = vim_lseek(fileno(fp), (off_T)0L, SEEK_END)) <= 0) {
state = TS_LINEAR;
} else {
- lseek(fileno(fp), (off_t)0L, SEEK_SET);
+ vim_lseek(fileno(fp), (off_T)0L, SEEK_SET);
/* Calculate the first read offset in the file. Start
* the search in the middle of the file. */
@@ -1564,11 +1546,7 @@ parse_line:
/* Avoid getting stuck. */
linear = TRUE;
state = TS_LINEAR;
-# ifdef HAVE_FSEEKO
- fseeko(fp, search_info.low_offset, SEEK_SET);
-# else
- fseek(fp, (long)search_info.low_offset, SEEK_SET);
-# endif
+ vim_fseek(fp, search_info.low_offset, SEEK_SET);
}
continue;
}
@@ -1647,7 +1625,7 @@ parse_line:
continue;
}
if (tagcmp < 0) {
- search_info.curr_offset = ftell(fp);
+ search_info.curr_offset = vim_ftell(fp);
if (search_info.curr_offset < search_info.high_offset) {
search_info.low_offset = search_info.curr_offset;
if (sortic)
@@ -1683,10 +1661,11 @@ parse_line:
} else if (state == TS_STEP_FORWARD) {
assert(cmplen >= 0);
if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) {
- if ((off_t)ftell(fp) > search_info.match_offset)
- break; /* past last match */
- else
- continue; /* before first match */
+ if ((off_T)vim_ftell(fp) > search_info.match_offset) {
+ break; // past last match
+ } else {
+ continue; // before first match
+ }
}
} else
/* skip this match if it can't match */
@@ -1907,10 +1886,11 @@ parse_line:
if (line_error) {
EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname);
- if (!use_cscope)
- EMSGN(_("Before byte %" PRId64), ftell(fp));
- stop_searching = TRUE;
- line_error = FALSE;
+ if (!use_cscope) {
+ EMSGN(_("Before byte %" PRId64), vim_ftell(fp));
+ }
+ stop_searching = true;
+ line_error = false;
}
if (!use_cscope)
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 5b250ebf54..099f49f09b 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -229,7 +229,7 @@ Terminal *terminal_open(TerminalOptions opts)
rv->invalid_start = 0;
rv->invalid_end = opts.height;
refresh_screen(rv, curbuf);
- set_option_value("buftype", 0, "terminal", OPT_LOCAL);
+ set_option_value("buftype", 0, "terminal", OPT_LOCAL); // -V666
// Default settings for terminal buffers
curbuf->b_p_ma = false; // 'nomodifiable'
@@ -601,8 +601,10 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
if (term->cursor.visible && term->cursor.row == row
&& term->cursor.col == col) {
- attr_id = hl_combine_attr(attr_id, is_focused(term) && wp == curwin ?
- hl_attr(HLF_TERM) : hl_attr(HLF_TERMNC));
+ attr_id = hl_combine_attr(attr_id,
+ is_focused(term) && wp == curwin
+ ? win_hl_attr(wp, HLF_TERM)
+ : win_hl_attr(wp, HLF_TERMNC));
}
term_attrs[col] = attr_id;
@@ -637,7 +639,7 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible,
}
static void buf_set_term_title(buf_T *buf, char *title)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ALL
{
Error err = ERROR_INIT;
dict_set_var(buf->b_vars,
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 70a9f2b8c4..7e55fffa06 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -58,8 +58,10 @@ NEW_TESTS ?= \
test_nested_function.res \
test_normal.res \
test_quickfix.res \
+ test_search.res \
test_signs.res \
test_smartindent.res \
+ test_stat.res \
test_substitute.res \
test_syntax.res \
test_tabpage.res \
@@ -67,7 +69,7 @@ NEW_TESTS ?= \
test_timers.res \
test_undo.res \
test_usercommands.res \
- test_viml.res \
+ test_vimscript.res \
test_visual.res \
test_window_id.res \
test_writefile.res \
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 732b0aaf74..117ba52eb6 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -74,9 +74,9 @@ set backspace=
set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
set listchars=eol:$
" Prevent Nvim log from writing to stderr.
-let $NVIM_LOG_FILE='Xnvim.log'
+let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
-function RunTheTest(test)
+func RunTheTest(test)
echo 'Executing ' . a:test
if exists("*SetUp")
call SetUp()
@@ -113,6 +113,60 @@ function RunTheTest(test)
set nomodified
endfunc
+func AfterTheTest()
+ if len(v:errors) > 0
+ let s:fail += 1
+ call add(s:errors, 'Found errors in ' . s:test . ':')
+ call extend(s:errors, v:errors)
+ let v:errors = []
+ endif
+endfunc
+
+" This function can be called by a test if it wants to abort testing.
+func FinishTesting()
+ call AfterTheTest()
+
+ " Don't write viminfo on exit.
+ set viminfo=
+
+ if s:fail == 0
+ " Success, create the .res file so that make knows it's done.
+ exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
+ write
+ endif
+
+ if len(s:errors) > 0
+ " Append errors to test.log
+ split test.log
+ call append(line('$'), '')
+ call append(line('$'), 'From ' . g:testname . ':')
+ call append(line('$'), s:errors)
+ write
+ endif
+
+ let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
+ echo message
+ call add(s:messages, message)
+ if s:fail > 0
+ let message = s:fail . ' FAILED:'
+ echo message
+ call add(s:messages, message)
+ call extend(s:messages, s:errors)
+ endif
+
+ " Add SKIPPED messages
+ call extend(s:messages, s:skipped)
+
+ " Append messages to the file "messages"
+ split messages
+ call append(line('$'), '')
+ call append(line('$'), 'From ' . g:testname . ':')
+ call append(line('$'), s:messages)
+ write
+
+ qall!
+endfunc
+
" Source the test script. First grab the file name, in case the script
" navigates away. g:testname can be used by the tests.
let g:testname = expand('%')
@@ -121,7 +175,7 @@ let s:fail = 0
let s:errors = []
let s:messages = []
let s:skipped = []
-if expand('%') =~ 'test_viml.vim'
+if expand('%') =~ 'test_vimscript.vim'
" this test has intentional s:errors, don't use try/catch.
source %
else
@@ -136,8 +190,8 @@ endif
" Names of flaky tests.
let s:flaky = [
\ 'Test_with_partial_callback()',
- \ 'Test_oneshot()'
- \ 'Test_lambda_with_timer()'
+ \ 'Test_oneshot()',
+ \ 'Test_lambda_with_timer()',
\ ]
" Locate Test_ functions and execute them.
@@ -157,56 +211,14 @@ for s:test in sort(s:tests)
call RunTheTest(s:test)
if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
- call add(s:messages, 'Flaky test failed, running it again')
- let v:errors = []
- call RunTheTest(s:test)
- endif
-
- if len(v:errors) > 0
- let s:fail += 1
- call add(s:errors, 'Found errors in ' . s:test . ':')
- call extend(s:errors, v:errors)
+ call add(s:messages, 'Flaky test failed, running it again')
let v:errors = []
+ call RunTheTest(s:test)
endif
+ call AfterTheTest()
endfor
-" Don't write viminfo on exit.
-set viminfo=
-
-if s:fail == 0
- " Success, create the .res file so that make knows it's done.
- exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
- write
-endif
-
-if len(s:errors) > 0
- " Append errors to test.log
- split test.log
- call append(line('$'), '')
- call append(line('$'), 'From ' . g:testname . ':')
- call append(line('$'), s:errors)
- write
-endif
-
-let message = 'Executed ' . s:done . (s:done > 1 ? ' tests': ' test')
-echo message
-call add(s:messages, message)
-if s:fail > 0
- let message = s:fail . ' FAILED'
- echo message
- call add(s:messages, message)
- call extend(s:messages, s:errors)
-endif
-
-" Add SKIPPED messages
-call extend(s:messages, s:skipped)
-
-" Append messages to the file "messages"
-split messages
-call append(line('$'), '')
-call append(line('$'), 'From ' . g:testname . ':')
-call append(line('$'), s:messages)
-write
+call FinishTesting()
-qall!
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index 784e4a0a02..72cfea96c6 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -187,7 +187,7 @@ func RunVim(before, after, arguments)
endfunc
func RunVimPiped(before, after, arguments, pipecmd)
- let $NVIM_LOG_FILE='Xnvim.log'
+ let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
let cmd = GetVimCommand()
if cmd == ''
return 0
diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim
index adbabd61b9..467abcd9b9 100644
--- a/src/nvim/testdir/test49.vim
+++ b/src/nvim/testdir/test49.vim
@@ -608,7 +608,7 @@ com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
-" Tests 1 to 15 were moved to test_viml.vim
+" Tests 1 to 15 were moved to test_vimscript.vim
let Xtest = 16
"-------------------------------------------------------------------------------
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 5da9a8b0f4..1103778107 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -10,6 +10,8 @@ source test_expr_utf8.vim
source test_feedkeys.vim
source test_filter_cmd.vim
source test_filter_map.vim
+source test_float_func.vim
+source test_functions.vim
source test_goto.vim
source test_jumps.vim
source test_lambda.vim
diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim
index c8d2ebd7da..01a9a3f9ad 100644
--- a/src/nvim/testdir/test_cscope.vim
+++ b/src/nvim/testdir/test_cscope.vim
@@ -28,7 +28,7 @@ func Test_cscopeWithCscopeConnections()
cscope add Xcscope.out
set cscopeverbose
catch
- call assert_true(0)
+ call assert_report('exception thrown')
endtry
call assert_fails('cscope add', 'E560')
call assert_fails('cscope add Xcscope.out', 'E568')
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index d819b7b092..e1b9651c84 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -1,13 +1,7 @@
" Tests for cursor().
func Test_wrong_arguments()
- try
- call cursor(1. 3)
- " not reached
- call assert_false(1)
- catch
- call assert_exception('E474:')
- endtry
+ call assert_fails('call cursor(1. 3)', 'E474:')
endfunc
func Test_move_cursor()
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 03a9155512..82c5d21bd0 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -78,7 +78,7 @@ endfunc
func Test_loop_over_null_list()
let null_list = submatch(1, 1)
for i in null_list
- call assert_true(0, 'should not get here')
+ call assert_report('should not get here')
endfor
endfunc
@@ -98,6 +98,35 @@ func Test_special_char()
call assert_fails('echo "\<C-">')
endfunc
+func Test_option_value()
+ " boolean
+ set bri
+ call assert_equal(1, &bri)
+ set nobri
+ call assert_equal(0, &bri)
+
+ " number
+ set ts=1
+ call assert_equal(1, &ts)
+ set ts=8
+ call assert_equal(8, &ts)
+
+ " string
+ exe "set cedit=\<Esc>"
+ call assert_equal("\<Esc>", &cedit)
+ set cpo=
+ call assert_equal("", &cpo)
+ set cpo=abcdefi
+ call assert_equal("abcdefi", &cpo)
+ set cpo&vim
+endfunc
+
+function Test_printf_64bit()
+ if has('num64')
+ call assert_equal("123456789012345", printf('%d', 123456789012345))
+ endif
+endfunc
+
func Test_setmatches()
hi def link 1 Comment
hi def link 2 PreProc
diff --git a/src/nvim/testdir/test_float_func.vim b/src/nvim/testdir/test_float_func.vim
new file mode 100644
index 0000000000..5ea5192994
--- /dev/null
+++ b/src/nvim/testdir/test_float_func.vim
@@ -0,0 +1,332 @@
+" test float functions
+
+if !has('float')
+ finish
+end
+
+func Test_abs()
+ call assert_equal('1.23', string(abs(1.23)))
+ call assert_equal('1.23', string(abs(-1.23)))
+ call assert_equal('0.0', string(abs(0.0)))
+ call assert_equal('0.0', string(abs(1.0/(1.0/0.0))))
+ call assert_equal('0.0', string(abs(-1.0/(1.0/0.0))))
+ call assert_equal("str2float('inf')", string(abs(1.0/0.0)))
+ call assert_equal("str2float('inf')", string(abs(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(abs(0.0/0.0)))
+ call assert_equal('12', string(abs('-12abc')))
+ call assert_fails("call abs([])", 'E745:')
+ call assert_fails("call abs({})", 'E728:')
+ call assert_fails("call abs(function('string'))", 'E703:')
+endfunc
+
+func Test_sqrt()
+ call assert_equal('0.0', string(sqrt(0.0)))
+ call assert_equal('1.414214', string(sqrt(2.0)))
+ call assert_equal("str2float('inf')", string(sqrt(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(sqrt(-1.0)))
+ call assert_equal("str2float('nan')", string(sqrt(0.0/0.0)))
+ call assert_fails('call sqrt("")', 'E808:')
+endfunc
+
+func Test_log()
+ call assert_equal('0.0', string(log(1.0)))
+ call assert_equal('-0.693147', string(log(0.5)))
+ call assert_equal("-str2float('inf')", string(log(0.0)))
+ call assert_equal("str2float('nan')", string(log(-1.0)))
+ call assert_equal("str2float('inf')", string(log(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(log(0.0/0.0)))
+ call assert_fails('call log("")', 'E808:')
+endfunc
+
+func Test_log10()
+ call assert_equal('0.0', string(log10(1.0)))
+ call assert_equal('2.0', string(log10(100.0)))
+ call assert_equal('2.079181', string(log10(120.0)))
+ call assert_equal("-str2float('inf')", string(log10(0.0)))
+ call assert_equal("str2float('nan')", string(log10(-1.0)))
+ call assert_equal("str2float('inf')", string(log10(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(log10(0.0/0.0)))
+ call assert_fails('call log10("")', 'E808:')
+endfunc
+
+func Test_exp()
+ call assert_equal('1.0', string(exp(0.0)))
+ call assert_equal('7.389056', string(exp(2.0)))
+ call assert_equal('0.367879', string(exp(-1.0)))
+ call assert_equal("str2float('inf')", string(exp(1.0/0.0)))
+ call assert_equal('0.0', string(exp(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(exp(0.0/0.0)))
+ call assert_fails('call exp("")', 'E808:')
+endfunc
+
+func Test_sin()
+ call assert_equal('0.0', string(sin(0.0)))
+ call assert_equal('0.841471', string(sin(1.0)))
+ call assert_equal('-0.479426', string(sin(-0.5)))
+ call assert_equal("str2float('nan')", string(sin(0.0/0.0)))
+ call assert_equal("str2float('nan')", string(sin(1.0/0.0)))
+ call assert_equal('0.0', string(sin(1.0/(1.0/0.0))))
+ call assert_equal('-0.0', string(sin(-1.0/(1.0/0.0))))
+ call assert_fails('call sin("")', 'E808:')
+endfunc
+
+func Test_asin()
+ call assert_equal('0.0', string(asin(0.0)))
+ call assert_equal('1.570796', string(asin(1.0)))
+ call assert_equal('-0.523599', string(asin(-0.5)))
+ call assert_equal("str2float('nan')", string(asin(1.1)))
+ call assert_equal("str2float('nan')", string(asin(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(asin(0.0/0.0)))
+ call assert_fails('call asin("")', 'E808:')
+endfunc
+
+func Test_sinh()
+ call assert_equal('0.0', string(sinh(0.0)))
+ call assert_equal('0.521095', string(sinh(0.5)))
+ call assert_equal('-1.026517', string(sinh(-0.9)))
+ call assert_equal("str2float('inf')", string(sinh(1.0/0.0)))
+ call assert_equal("-str2float('inf')", string(sinh(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(sinh(0.0/0.0)))
+ call assert_fails('call sinh("")', 'E808:')
+endfunc
+
+func Test_cos()
+ call assert_equal('1.0', string(cos(0.0)))
+ call assert_equal('0.540302', string(cos(1.0)))
+ call assert_equal('0.877583', string(cos(-0.5)))
+ call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
+ call assert_equal("str2float('nan')", string(cos(1.0/0.0)))
+ call assert_fails('call cos("")', 'E808:')
+endfunc
+
+func Test_acos()
+ call assert_equal('1.570796', string(acos(0.0)))
+ call assert_equal('0.0', string(acos(1.0)))
+ call assert_equal('3.141593', string(acos(-1.0)))
+ call assert_equal('2.094395', string(acos(-0.5)))
+ call assert_equal("str2float('nan')", string(acos(1.1)))
+ call assert_equal("str2float('nan')", string(acos(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(acos(0.0/0.0)))
+ call assert_fails('call acos("")', 'E808:')
+endfunc
+
+func Test_cosh()
+ call assert_equal('1.0', string(cosh(0.0)))
+ call assert_equal('1.127626', string(cosh(0.5)))
+ call assert_equal("str2float('inf')", string(cosh(1.0/0.0)))
+ call assert_equal("str2float('inf')", string(cosh(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(cosh(0.0/0.0)))
+ call assert_fails('call cosh("")', 'E808:')
+endfunc
+
+func Test_tan()
+ call assert_equal('0.0', string(tan(0.0)))
+ call assert_equal('0.546302', string(tan(0.5)))
+ call assert_equal('-0.546302', string(tan(-0.5)))
+ call assert_equal("str2float('nan')", string(tan(1.0/0.0)))
+ call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
+ call assert_equal('0.0', string(tan(1.0/(1.0/0.0))))
+ call assert_equal('-0.0', string(tan(-1.0/(1.0/0.0))))
+ call assert_fails('call tan("")', 'E808:')
+endfunc
+
+func Test_atan()
+ call assert_equal('0.0', string(atan(0.0)))
+ call assert_equal('0.463648', string(atan(0.5)))
+ call assert_equal('-0.785398', string(atan(-1.0)))
+ call assert_equal('1.570796', string(atan(1.0/0.0)))
+ call assert_equal('-1.570796', string(atan(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(atan(0.0/0.0)))
+ call assert_fails('call atan("")', 'E808:')
+endfunc
+
+func Test_atan2()
+ call assert_equal('-2.356194', string(atan2(-1, -1)))
+ call assert_equal('2.356194', string(atan2(1, -1)))
+ call assert_equal('0.0', string(atan2(1.0, 1.0/0.0)))
+ call assert_equal('1.570796', string(atan2(1.0/0.0, 1.0)))
+ call assert_equal("str2float('nan')", string(atan2(0.0/0.0, 1.0)))
+ call assert_fails('call atan2("", -1)', 'E808:')
+ call assert_fails('call atan2(-1, "")', 'E808:')
+endfunc
+
+func Test_tanh()
+ call assert_equal('0.0', string(tanh(0.0)))
+ call assert_equal('0.462117', string(tanh(0.5)))
+ call assert_equal('-0.761594', string(tanh(-1.0)))
+ call assert_equal('1.0', string(tanh(1.0/0.0)))
+ call assert_equal('-1.0', string(tanh(-1.0/0.0)))
+ call assert_equal("str2float('nan')", string(tanh(0.0/0.0)))
+ call assert_fails('call tanh("")', 'E808:')
+endfunc
+
+func Test_fmod()
+ call assert_equal('0.13', string(fmod(12.33, 1.22)))
+ call assert_equal('-0.13', string(fmod(-12.33, 1.22)))
+ call assert_equal("str2float('nan')", string(fmod(1.0/0.0, 1.0)))
+ " On Windows we get "nan" instead of 1.0, accept both.
+ let res = string(fmod(1.0, 1.0/0.0))
+ if res != "str2float('nan')"
+ call assert_equal('1.0', res)
+ endif
+ call assert_equal("str2float('nan')", string(fmod(1.0, 0.0)))
+ call assert_fails("call fmod('', 1.22)", 'E808:')
+ call assert_fails("call fmod(12.33, '')", 'E808:')
+endfunc
+
+func Test_pow()
+ call assert_equal('1.0', string(pow(0.0, 0.0)))
+ call assert_equal('8.0', string(pow(2.0, 3.0)))
+ call assert_equal("str2float('nan')", string(pow(2.0, 0.0/0.0)))
+ call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
+ call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
+ call assert_equal("str2float('inf')", string(pow(2.0, 1.0/0.0)))
+ call assert_equal("str2float('inf')", string(pow(1.0/0.0, 3.0)))
+ call assert_fails("call pow('', 2.0)", 'E808:')
+ call assert_fails("call pow(2.0, '')", 'E808:')
+endfunc
+
+func Test_str2float()
+ call assert_equal('1.0', string(str2float('1')))
+ call assert_equal('1.0', string(str2float(' 1 ')))
+ call assert_equal('1.0', string(str2float(' 1.0 ')))
+ call assert_equal('1.23', string(str2float('1.23')))
+ call assert_equal('1.23', string(str2float('1.23abc')))
+ call assert_equal('1.0e40', string(str2float('1e40')))
+ call assert_equal('-1.23', string(str2float('-1.23')))
+ call assert_equal('1.23', string(str2float(' + 1.23 ')))
+
+ call assert_equal('1.0', string(str2float('+1')))
+ call assert_equal('1.0', string(str2float('+1')))
+ call assert_equal('1.0', string(str2float(' +1 ')))
+ call assert_equal('1.0', string(str2float(' + 1 ')))
+
+ call assert_equal('-1.0', string(str2float('-1')))
+ call assert_equal('-1.0', string(str2float('-1')))
+ call assert_equal('-1.0', string(str2float(' -1 ')))
+ call assert_equal('-1.0', string(str2float(' - 1 ')))
+
+ call assert_equal('0.0', string(str2float('+0.0')))
+ call assert_equal('-0.0', string(str2float('-0.0')))
+ call assert_equal("str2float('inf')", string(str2float('1e1000')))
+ call assert_equal("str2float('inf')", string(str2float('inf')))
+ call assert_equal("-str2float('inf')", string(str2float('-inf')))
+ call assert_equal("str2float('inf')", string(str2float('+inf')))
+ call assert_equal("str2float('inf')", string(str2float('Inf')))
+ call assert_equal("str2float('inf')", string(str2float(' +inf ')))
+ call assert_equal("str2float('nan')", string(str2float('nan')))
+ call assert_equal("str2float('nan')", string(str2float('NaN')))
+ call assert_equal("str2float('nan')", string(str2float(' nan ')))
+
+ call assert_fails("call str2float(1.2)", 'E806:')
+ call assert_fails("call str2float([])", 'E730:')
+ call assert_fails("call str2float({})", 'E731:')
+ call assert_fails("call str2float(function('string'))", 'E729:')
+endfunc
+
+func Test_float2nr()
+ call assert_equal(1, float2nr(1.234))
+ call assert_equal(123, float2nr(1.234e2))
+ call assert_equal(12, float2nr(123.4e-1))
+ let max_number = 1/0
+ let min_number = -max_number
+ call assert_equal(max_number/2+1, float2nr(pow(2, 62)))
+ call assert_equal(max_number, float2nr(pow(2, 63)))
+ call assert_equal(max_number, float2nr(pow(2, 64)))
+ call assert_equal(min_number/2-1, float2nr(-pow(2, 62)))
+ call assert_equal(min_number, float2nr(-pow(2, 63)))
+ call assert_equal(min_number, float2nr(-pow(2, 64)))
+endfunc
+
+func Test_floor()
+ call assert_equal('2.0', string(floor(2.0)))
+ call assert_equal('2.0', string(floor(2.11)))
+ call assert_equal('2.0', string(floor(2.99)))
+ call assert_equal('-3.0', string(floor(-2.11)))
+ call assert_equal('-3.0', string(floor(-2.99)))
+ call assert_equal("str2float('nan')", string(floor(0.0/0.0)))
+ call assert_equal("str2float('inf')", string(floor(1.0/0.0)))
+ call assert_equal("-str2float('inf')", string(floor(-1.0/0.0)))
+ call assert_fails("call floor('')", 'E808:')
+endfunc
+
+func Test_ceil()
+ call assert_equal('2.0', string(ceil(2.0)))
+ call assert_equal('3.0', string(ceil(2.11)))
+ call assert_equal('3.0', string(ceil(2.99)))
+ call assert_equal('-2.0', string(ceil(-2.11)))
+ call assert_equal('-2.0', string(ceil(-2.99)))
+ call assert_equal("str2float('nan')", string(ceil(0.0/0.0)))
+ call assert_equal("str2float('inf')", string(ceil(1.0/0.0)))
+ call assert_equal("-str2float('inf')", string(ceil(-1.0/0.0)))
+ call assert_fails("call ceil('')", 'E808:')
+endfunc
+
+func Test_round()
+ call assert_equal('2.0', string(round(2.1)))
+ call assert_equal('3.0', string(round(2.5)))
+ call assert_equal('3.0', string(round(2.9)))
+ call assert_equal('-2.0', string(round(-2.1)))
+ call assert_equal('-3.0', string(round(-2.5)))
+ call assert_equal('-3.0', string(round(-2.9)))
+ call assert_equal("str2float('nan')", string(round(0.0/0.0)))
+ call assert_equal("str2float('inf')", string(round(1.0/0.0)))
+ call assert_equal("-str2float('inf')", string(round(-1.0/0.0)))
+ call assert_fails("call round('')", 'E808:')
+endfunc
+
+func Test_trunc()
+ call assert_equal('2.0', string(trunc(2.1)))
+ call assert_equal('2.0', string(trunc(2.5)))
+ call assert_equal('2.0', string(trunc(2.9)))
+ call assert_equal('-2.0', string(trunc(-2.1)))
+ call assert_equal('-2.0', string(trunc(-2.5)))
+ call assert_equal('-2.0', string(trunc(-2.9)))
+ call assert_equal("str2float('nan')", string(trunc(0.0/0.0)))
+ call assert_equal("str2float('inf')", string(trunc(1.0/0.0)))
+ call assert_equal("-str2float('inf')", string(trunc(-1.0/0.0)))
+ call assert_fails("call trunc('')", 'E808:')
+endfunc
+
+func Test_isnan()
+ throw 'skipped: Nvim does not support isnan()'
+ call assert_equal(0, isnan(1.0))
+ call assert_equal(1, isnan(0.0/0.0))
+ call assert_equal(0, isnan(1.0/0.0))
+ call assert_equal(0, isnan('a'))
+ call assert_equal(0, isnan([]))
+ call assert_equal(0, isnan({}))
+endfunc
+
+" This was converted from test65
+func Test_float_misc()
+ call assert_equal('123.456000', printf('%f', 123.456))
+ call assert_equal('1.234560e+02', printf('%e', 123.456))
+ call assert_equal('123.456', printf('%g', 123.456))
+ " +=
+ let v = 1.234
+ let v += 6.543
+ call assert_equal('7.777', printf('%g', v))
+ let v = 1.234
+ let v += 5
+ call assert_equal('6.234', printf('%g', v))
+ let v = 5
+ let v += 3.333
+ call assert_equal('8.333', string(v))
+ " ==
+ let v = 1.234
+ call assert_true(v == 1.234)
+ call assert_false(v == 1.2341)
+ " add-subtract
+ call assert_equal('5.234', printf('%g', 4 + 1.234))
+ call assert_equal('-6.766', printf('%g', 1.234 - 8))
+ " mult-div
+ call assert_equal('4.936', printf('%g', 4 * 1.234))
+ call assert_equal('0.003241', printf('%g', 4.0 / 1234))
+ " dict
+ call assert_equal("{'x': 1.234, 'y': -2.0e20}", string({'x': 1.234, 'y': -2.0e20}))
+ " list
+ call assert_equal('[-123.4, 2.0e-20]', string([-123.4, 2.0e-20]))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 3c258299c1..237a2dc820 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1,3 +1,22 @@
+" Tests for various functions.
+
+func Test_str2nr()
+ call assert_equal(0, str2nr(''))
+ call assert_equal(1, str2nr('1'))
+ call assert_equal(1, str2nr(' 1 '))
+
+ call assert_equal(1, str2nr('+1'))
+ call assert_equal(1, str2nr('+ 1'))
+ call assert_equal(1, str2nr(' + 1 '))
+
+ call assert_equal(-1, str2nr('-1'))
+ call assert_equal(-1, str2nr('- 1'))
+ call assert_equal(-1, str2nr(' - 1 '))
+
+ call assert_equal(123456789, str2nr('123456789'))
+ call assert_equal(-123456789, str2nr('-123456789'))
+endfunc
+
func Test_setbufvar_options()
" This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the
" window layout.
diff --git a/src/nvim/testdir/test_largefile.vim b/src/nvim/testdir/test_largefile.vim
new file mode 100644
index 0000000000..1b3e02a0c8
--- /dev/null
+++ b/src/nvim/testdir/test_largefile.vim
@@ -0,0 +1,34 @@
+" Tests for large files
+" This is only executed manually: "make test_largefile".
+" This is not run as part of "make test".
+
+func Test_largefile()
+ let fname = 'Xlarge.txt'
+
+ call delete(fname)
+ exe "e" fname
+ " Make sure that a line break is 1 byte (LF).
+ set ff=unix
+ set undolevels=-1
+ " Input 99 'A's. The line becomes 100 bytes including a line break.
+ exe "normal 99iA\<Esc>"
+ yank
+ " Put 39,999,999 times. The file becomes 4,000,000,000 bytes.
+ normal 39999999p
+ " Moving around in the file randomly.
+ normal G
+ normal 10%
+ normal 90%
+ normal 50%
+ normal gg
+ w
+ " Check if the file size is 4,000,000,000 bytes.
+ let fsize=getfsize(fname)
+ if has('num64')
+ call assert_true(fsize == 4000000000)
+ else
+ " getfsize() returns -2 if a Number is 32 bits.
+ call assert_true(fsize == -2)
+ endif
+ call delete(fname)
+endfunc
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
index be559467c8..af18760065 100644
--- a/src/nvim/testdir/test_menu.vim
+++ b/src/nvim/testdir/test_menu.vim
@@ -4,6 +4,6 @@ func Test_load_menu()
try
source $VIMRUNTIME/menu.vim
catch
- call assert_false(1, 'error while loading menus: ' . v:exception)
+ call assert_report('error while loading menus: ' . v:exception)
endtry
endfunc
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index fd0f3c0d2d..519d855cd8 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -533,7 +533,7 @@ func Test_completion_comment_formatting()
%d
try
call feedkeys("o/*\<cr>\<cr>\<c-x>\<c-u>/\<esc>", 'tx')
- call assert_false(1, 'completefunc not set, should have failed')
+ call assert_report('completefunc not set, should have failed')
catch
call assert_exception('E764:')
endtry
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
new file mode 100644
index 0000000000..2106fc2dec
--- /dev/null
+++ b/src/nvim/testdir/test_search.vim
@@ -0,0 +1,285 @@
+" Test for the search command
+
+func Test_search_cmdline()
+ " See test/functional/legacy/search_spec.lua
+ throw 'skipped: Nvim does not support test_disable_char_avail()'
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_disable_char_avail(1)
+ new
+ call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
+ " Test 1
+ " CTRL-N / CTRL-P skips through the previous search history
+ set noincsearch
+ :1
+ call feedkeys("/foobar\<cr>", 'tx')
+ call feedkeys("/the\<cr>",'tx')
+ call assert_equal('the', @/)
+ call feedkeys("/thes\<C-P>\<C-P>\<cr>",'tx')
+ call assert_equal('foobar', @/)
+
+ " Test 2
+ " Ctrl-G goes from one match to the next
+ " until the end of the buffer
+ set incsearch nowrapscan
+ :1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ :1
+ " second match
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+ call assert_equal([0, 0, 0, 0], getpos('"'))
+ :1
+ " third match
+ call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ :1
+ " fourth match
+ call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
+ call assert_equal(' 5 there', getline('.'))
+ :1
+ " fifth match
+ call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
+ call assert_equal(' 6 their', getline('.'))
+ :1
+ " sixth match
+ call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
+ call assert_equal(' 7 the', getline('.'))
+ :1
+ " seventh match
+ call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ :1
+ " eigth match
+ call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ :1
+ " no further match
+ call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ call assert_equal([0, 0, 0, 0], getpos('"'))
+
+ " Test 3
+ " Ctrl-G goes from one match to the next
+ " and continues back at the top
+ set incsearch wrapscan
+ :1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ :1
+ " second match
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+ :1
+ " third match
+ call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ :1
+ " fourth match
+ call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
+ call assert_equal(' 5 there', getline('.'))
+ :1
+ " fifth match
+ call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
+ call assert_equal(' 6 their', getline('.'))
+ :1
+ " sixth match
+ call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
+ call assert_equal(' 7 the', getline('.'))
+ :1
+ " seventh match
+ call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ :1
+ " eigth match
+ call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ :1
+ " back at first match
+ call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 4
+ " CTRL-T goes to the previous match
+ set incsearch nowrapscan
+ $
+ " first match
+ call feedkeys("?the\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " first match
+ call feedkeys("?the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " second match
+ call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 5
+ " CTRL-T goes to the previous match
+ set incsearch wrapscan
+ $
+ " first match
+ call feedkeys("?the\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " first match at the top
+ call feedkeys("?the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " second match
+ call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " back at the bottom of the buffer
+ call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+
+ " Test 6
+ " CTRL-L adds to the search pattern
+ set incsearch wrapscan
+ 1
+ " first match
+ call feedkeys("/the\<c-l>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " go to next match of 'thes'
+ call feedkeys("/the\<c-l>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ 1
+ " wrap around
+ call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " wrap around
+ set nowrapscan
+ call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+
+ " Test 7
+ " <bs> remove from match, but stay at current match
+ set incsearch wrapscan
+ 1
+ " first match
+ call feedkeys("/thei\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ 1
+ " delete one char, add another
+ call feedkeys("/thei\<bs>s\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " delete one char, add another, go to previous match, add one char
+ call feedkeys("/thei\<bs>s\<bs>\<C-T>\<c-l>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ 1
+ " delete all chars, start from the beginning again
+ call feedkeys("/them". repeat("\<bs>",4).'the\>'."\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+
+ " clean up
+ call test_disable_char_avail(0)
+ bw!
+endfunc
+
+func Test_search_cmdline2()
+ " See test/functional/legacy/search_spec.lua
+ throw 'skipped: Nvim does not support test_disable_char_avail()'
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_disable_char_avail(1)
+ new
+ call setline(1, [' 1', ' 2 these', ' 3 the theother'])
+ " Test 1
+ " Ctrl-T goes correctly back and forth
+ set incsearch
+ 1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " go to next match (on next line)
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to next match (still on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to next match (still on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 2)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 2: keep the view,
+ " after deleting a character from the search cmd
+ call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
+ resize 5
+ 1
+ call feedkeys("/foo\<bs>\<cr>", 'tx')
+ redraw
+ call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
+
+ " remove all history entries
+ for i in range(10)
+ call histdel('/')
+ endfor
+
+ " Test 3: reset the view,
+ " after deleting all characters from the search cmd
+ norm! 1gg0
+ " unfortunately, neither "/foo\<c-w>\<cr>", nor "/foo\<bs>\<bs>\<bs>\<cr>",
+ " nor "/foo\<c-u>\<cr>" works to delete the commandline.
+ " In that case Vim should return "E35 no previous regular expression",
+ " but it looks like Vim still sees /foo and therefore the test fails.
+ " Therefore, disableing this test
+ "call assert_fails(feedkeys("/foo\<c-w>\<cr>", 'tx'), 'E35')
+ "call assert_equal({'lnum': 1, 'leftcol': 0, 'col': 0, 'topfill': 0, 'topline': 1, 'coladd': 0, 'skipcol': 0, 'curswant': 0}, winsaveview())
+
+ " clean up
+ set noincsearch
+ call test_disable_char_avail(0)
+ bw!
+endfunc
+
+func Test_use_sub_pat()
+ split
+ let @/ = ''
+ func X()
+ s/^/a/
+ /
+ endfunc
+ call X()
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index f78d92f3ff..5996b2cd4a 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -83,7 +83,7 @@ func Test_help_arg()
call add(found, "--version")
endif
endfor
- call assert_equal(['--version'], found)
+ call assert_equal(['Readonly mode', '--version'], found)
endif
call delete('Xtestout')
endfunc
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
new file mode 100644
index 0000000000..89ca9ef379
--- /dev/null
+++ b/src/nvim/testdir/test_stat.vim
@@ -0,0 +1,64 @@
+" Tests for stat functions and checktime
+
+func Test_existent_file()
+ let fname='Xtest.tmp'
+
+ let ts=localtime()
+ sleep 1
+ let fl=['Hello World!']
+ call writefile(fl, fname)
+ let tf=getftime(fname)
+ sleep 1
+ let te=localtime()
+
+ call assert_true(ts <= tf && tf <= te)
+ call assert_equal(strlen(fl[0] . "\n"), getfsize(fname))
+ call assert_equal('file', getftype(fname))
+ call assert_equal('rw-', getfperm(fname)[0:2])
+endfunc
+
+func Test_existent_directory()
+ let dname='.'
+
+ call assert_equal(0, getfsize(dname))
+ call assert_equal('dir', getftype(dname))
+ call assert_equal('rwx', getfperm(dname)[0:2])
+endfunc
+
+func Test_checktime()
+ let fname='Xtest.tmp'
+
+ let fl=['Hello World!']
+ call writefile(fl, fname)
+ set autoread
+ exec 'e' fname
+ sleep 2
+ let fl=readfile(fname)
+ let fl[0] .= ' - checktime'
+ call writefile(fl, fname)
+ checktime
+ call assert_equal(fl[0], getline(1))
+endfunc
+
+func Test_nonexistent_file()
+ let fname='Xtest.tmp'
+
+ call delete(fname)
+ call assert_equal(-1, getftime(fname))
+ call assert_equal(-1, getfsize(fname))
+ call assert_equal('', getftype(fname))
+ call assert_equal('', getfperm(fname))
+endfunc
+
+func Test_win32_symlink_dir()
+ " On Windows, non-admin users cannot create symlinks.
+ " So we use an existing symlink for this test.
+ if has('win32')
+ " Check if 'C:\Users\All Users' is a symlink to a directory.
+ let res=system('dir C:\Users /a')
+ if match(res, '\C<SYMLINKD> *All Users') >= 0
+ " Get the filetype of the symlink.
+ call assert_equal('dir', getftype('C:\Users\All Users'))
+ endif
+ endif
+endfunc
diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_vimscript.vim
index a2997b6d4d..4e0f1bbd2f 100644
--- a/src/nvim/testdir/test_viml.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1062,6 +1062,157 @@ func Test_echo_and_string()
call assert_equal(["{'a': [], 'b': []}",
\ "{'a': [], 'b': []}"], l)
+"-------------------------------------------------------------------------------
+" Test 94: 64-bit Numbers {{{1
+"-------------------------------------------------------------------------------
+
+func Test_num64()
+ if !has('num64')
+ return
+ endif
+
+ call assert_notequal( 4294967296, 0)
+ call assert_notequal(-4294967296, 0)
+ call assert_equal( 4294967296, 0xFFFFffff + 1)
+ call assert_equal(-4294967296, -0xFFFFffff - 1)
+
+ call assert_equal( 9223372036854775807, 1 / 0)
+ call assert_equal(-9223372036854775807, -1 / 0)
+ call assert_equal(-9223372036854775807 - 1, 0 / 0)
+
+ call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
+ call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))
+
+ let rng = range(0xFFFFffff, 0x100000001)
+ call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng)
+ call assert_equal(0x100000001, max(rng))
+ call assert_equal(0xFFFFffff, min(rng))
+ call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N'))
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 95: lines of :append, :change, :insert {{{1
+"-------------------------------------------------------------------------------
+
+function! DefineFunction(name, body)
+ let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
+ exec func
+endfunction
+
+func Test_script_lines()
+ " :append
+ try
+ call DefineFunction('T_Append', [
+ \ 'append',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Append', [
+ \ 'append',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+
+ " :change
+ try
+ call DefineFunction('T_Change', [
+ \ 'change',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Change', [
+ \ 'change',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+
+ " :insert
+ try
+ call DefineFunction('T_Insert', [
+ \ 'insert',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Insert', [
+ \ 'insert',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 96: line continuation {{{1
+"
+" Undefined behavior was detected by ubsan with line continuation
+" after an empty line.
+"-------------------------------------------------------------------------------
+func Test_script_emty_line_continuation()
+
+ \
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 97: bitwise functions {{{1
+"-------------------------------------------------------------------------------
+func Test_bitwise_functions()
+ " and
+ call assert_equal(127, and(127, 127))
+ call assert_equal(16, and(127, 16))
+ call assert_equal(0, and(127, 128))
+ call assert_fails("call and(1.0, 1)", 'E805:')
+ call assert_fails("call and([], 1)", 'E745:')
+ call assert_fails("call and({}, 1)", 'E728:')
+ call assert_fails("call and(1, 1.0)", 'E805:')
+ call assert_fails("call and(1, [])", 'E745:')
+ call assert_fails("call and(1, {})", 'E728:')
+ " or
+ call assert_equal(23, or(16, 7))
+ call assert_equal(15, or(8, 7))
+ call assert_equal(123, or(0, 123))
+ call assert_fails("call or(1.0, 1)", 'E805:')
+ call assert_fails("call or([], 1)", 'E745:')
+ call assert_fails("call or({}, 1)", 'E728:')
+ call assert_fails("call or(1, 1.0)", 'E805:')
+ call assert_fails("call or(1, [])", 'E745:')
+ call assert_fails("call or(1, {})", 'E728:')
+ " xor
+ call assert_equal(0, xor(127, 127))
+ call assert_equal(111, xor(127, 16))
+ call assert_equal(255, xor(127, 128))
+ call assert_fails("call xor(1.0, 1)", 'E805:')
+ call assert_fails("call xor([], 1)", 'E745:')
+ call assert_fails("call xor({}, 1)", 'E728:')
+ call assert_fails("call xor(1, 1.0)", 'E805:')
+ call assert_fails("call xor(1, [])", 'E745:')
+ call assert_fails("call xor(1, {})", 'E728:')
+ " invert
+ call assert_equal(65408, and(invert(127), 65535))
+ call assert_equal(65519, and(invert(16), 65535))
+ call assert_equal(65407, and(invert(128), 65535))
+ call assert_fails("call invert(1.0)", 'E805:')
+ call assert_fails("call invert([])", 'E745:')
+ call assert_fails("call invert({})", 'E728:')
endfunc
"-------------------------------------------------------------------------------
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 290d5d7553..81af3bfda9 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2232,11 +2232,13 @@ static void u_undoredo(int undo)
/* adjust marks */
if (oldsize != newsize) {
mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
- (long)newsize - (long)oldsize);
- if (curbuf->b_op_start.lnum > top + oldsize)
+ (long)newsize - (long)oldsize, false);
+ if (curbuf->b_op_start.lnum > top + oldsize) {
curbuf->b_op_start.lnum += newsize - oldsize;
- if (curbuf->b_op_end.lnum > top + oldsize)
+ }
+ if (curbuf->b_op_end.lnum > top + oldsize) {
curbuf->b_op_end.lnum += newsize - oldsize;
+ }
}
changed_lines(top + 1, 0, bot, newsize - oldsize);
diff --git a/src/nvim/version.c b/src/nvim/version.c
index b579cdef12..094ca29b01 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -84,11 +84,11 @@ static const int included_patches[] = {
// 2363 NA
2362,
// 2361 NA
- // 2360,
+ 2360,
2359,
// 2358 NA
2357,
- // 2356,
+ 2356,
2355,
// 2354,
2353,
@@ -124,9 +124,9 @@ static const int included_patches[] = {
2323,
2322,
2321,
- // 2320,
+ 2320,
// 2319 NA
- // 2318,
+ 2318,
2317,
// 2316 NA
2315,
@@ -176,7 +176,7 @@ static const int included_patches[] = {
// 2271 NA
// 2270 NA
2269,
- // 2268,
+ 2268,
// 2267 NA
2266,
2265,
@@ -185,7 +185,7 @@ static const int included_patches[] = {
// 2262 NA
// 2261 NA
// 2260 NA
- // 2259,
+ 2259,
// 2258 NA
// 2257 NA
2256,
@@ -220,7 +220,7 @@ static const int included_patches[] = {
2227,
2226,
2225,
- // 2224,
+ 2224,
2223,
2222,
2221,
@@ -254,7 +254,7 @@ static const int included_patches[] = {
// 2193 NA
// 2192 NA
// 2191 NA
- // 2190,
+ 2190,
// 2189,
2188,
2187,
@@ -415,7 +415,7 @@ static const int included_patches[] = {
// 2032 NA
2031,
// 2030 NA
- // 2029,
+ 2029,
2028,
// 2027 NA
// 2026 NA
@@ -458,18 +458,18 @@ static const int included_patches[] = {
1989,
// 1988 NA
// 1987 NA
- // 1986,
+ 1986,
// 1985 NA
1984,
// 1983 NA
// 1982 NA
1981,
1980,
- // 1979,
- // 1978,
- // 1977,
- // 1976,
- // 1975,
+ 1979,
+ 1978,
+ 1977,
+ 1976,
+ 1975,
// 1974 NA
1973,
// 1972 NA
diff --git a/src/nvim/window.c b/src/nvim/window.c
index b71b48a6b7..43af2e5e4f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3723,8 +3723,8 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
redraw_later(VALID); /* causes status line redraw */
if (hl_attr(HLF_INACTIVE)
- || (prevwin && prevwin->w_hl_id_inactive)
- || curwin->w_hl_id_inactive) {
+ || (prevwin && prevwin->w_hl_ids[HLF_INACTIVE])
+ || curwin->w_hl_ids[HLF_INACTIVE]) {
redraw_all_later(NOT_VALID);
}