aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt9
-rw-r--r--src/nvim/api/buffer.c63
-rw-r--r--src/nvim/api/private/defs.h2
-rw-r--r--src/nvim/api/private/helpers.c60
-rw-r--r--src/nvim/api/private/helpers.h1
-rw-r--r--src/nvim/api/ui.c15
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c377
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/ascii.h2
-rw-r--r--src/nvim/auevents.lua2
-rw-r--r--src/nvim/buffer.c154
-rw-r--r--src/nvim/buffer_defs.h4
-rw-r--r--src/nvim/channel.c79
-rw-r--r--src/nvim/charset.c261
-rw-r--r--src/nvim/cursor_shape.c9
-rw-r--r--src/nvim/diff.c20
-rw-r--r--src/nvim/digraph.c6
-rw-r--r--src/nvim/edit.c33
-rw-r--r--src/nvim/eval.c225
-rw-r--r--src/nvim/eval.h1
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/decode.c2
-rw-r--r--src/nvim/eval/typval.c2
-rw-r--r--src/nvim/eval/typval.h18
-rw-r--r--src/nvim/eval/typval_encode.c.h8
-rw-r--r--src/nvim/event/libuv_process.c16
-rw-r--r--src/nvim/event/loop.c1
-rw-r--r--src/nvim/event/loop.h3
-rw-r--r--src/nvim/event/process.c64
-rw-r--r--src/nvim/event/process.h3
-rw-r--r--src/nvim/event/time.c9
-rw-r--r--src/nvim/ex_cmds.c142
-rw-r--r--src/nvim/ex_cmds2.c42
-rw-r--r--src/nvim/ex_docmd.c427
-rw-r--r--src/nvim/ex_eval.c354
-rw-r--r--src/nvim/ex_getln.c99
-rw-r--r--src/nvim/file_search.c32
-rw-r--r--src/nvim/fileio.c179
-rw-r--r--src/nvim/fold.c2
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua2
-rw-r--r--src/nvim/getchar.c194
-rw-r--r--src/nvim/getchar.h24
-rw-r--r--src/nvim/globals.h64
-rw-r--r--src/nvim/highlight_defs.h4
-rw-r--r--src/nvim/if_cscope.c4
-rw-r--r--src/nvim/keymap.c1
-rw-r--r--src/nvim/keymap.h4
-rw-r--r--src/nvim/lib/kvec.h2
-rw-r--r--src/nvim/lua/converter.c2
-rw-r--r--src/nvim/lua/vim.lua68
-rw-r--r--src/nvim/macros.h23
-rw-r--r--src/nvim/main.c157
-rw-r--r--src/nvim/map.h5
-rw-r--r--src/nvim/mbyte.c64
-rw-r--r--src/nvim/mbyte.h7
-rw-r--r--src/nvim/memfile.c152
-rw-r--r--src/nvim/memfile_defs.h3
-rw-r--r--src/nvim/memline.c81
-rw-r--r--src/nvim/memory.c22
-rw-r--r--src/nvim/message.c40
-rw-r--r--src/nvim/misc1.c2
-rw-r--r--src/nvim/move.c2
-rw-r--r--src/nvim/msgpack_rpc/server.c43
-rw-r--r--src/nvim/normal.c32
-rw-r--r--src/nvim/ops.c49
-rw-r--r--src/nvim/option.c569
-rw-r--r--src/nvim/option_defs.h13
-rw-r--r--src/nvim/options.lua26
-rw-r--r--src/nvim/os/env.c162
-rw-r--r--src/nvim/os/fileio.c55
-rw-r--r--src/nvim/os/fileio.h3
-rw-r--r--src/nvim/os/fs.c59
-rw-r--r--src/nvim/os/os_defs.h9
-rw-r--r--src/nvim/os/process.c267
-rw-r--r--src/nvim/os/process.h11
-rw-r--r--src/nvim/os/pty_process_unix.c6
-rw-r--r--src/nvim/os/shell.c41
-rw-r--r--src/nvim/os/signal.c2
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/os/win_defs.h7
-rw-r--r--src/nvim/path.c55
-rw-r--r--src/nvim/po/CMakeLists.txt36
-rw-r--r--src/nvim/popupmnu.c2
-rw-r--r--src/nvim/pos.h6
-rw-r--r--src/nvim/quickfix.c41
-rw-r--r--src/nvim/regexp_nfa.c18
-rw-r--r--src/nvim/screen.c403
-rw-r--r--src/nvim/search.c69
-rw-r--r--src/nvim/shada.c261
-rw-r--r--src/nvim/spell.c22
-rw-r--r--src/nvim/spellfile.c80
-rw-r--r--src/nvim/strings.c18
-rw-r--r--src/nvim/strings.h18
-rw-r--r--src/nvim/syntax.c1450
-rw-r--r--src/nvim/terminal.c29
-rw-r--r--src/nvim/testdir/Makefile74
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh82
-rw-r--r--src/nvim/testdir/runnvim.vim55
-rw-r--r--src/nvim/testdir/runtest.vim3
-rw-r--r--src/nvim/testdir/setup.vim8
-rw-r--r--src/nvim/testdir/test_cmdline.vim6
-rw-r--r--src/nvim/testdir/test_find_complete.vim3
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim2
-rw-r--r--src/nvim/testdir/test_makeencoding.vim9
-rw-r--r--src/nvim/testdir/test_options.vim12
-rw-r--r--src/nvim/testdir/test_quickfix.vim16
-rw-r--r--src/nvim/testdir/test_recover.vim5
-rw-r--r--src/nvim/testdir/test_spell.vim2
-rw-r--r--src/nvim/testdir/test_stat.vim2
-rw-r--r--src/nvim/testdir/test_system.vim54
-rw-r--r--src/nvim/testdir/test_timers.vim2
-rw-r--r--src/nvim/testdir/test_unlet.vim4
-rw-r--r--src/nvim/tui/input.c15
-rw-r--r--src/nvim/tui/tui.c23
-rw-r--r--src/nvim/ugrid.h2
-rw-r--r--src/nvim/ui.c6
-rw-r--r--src/nvim/ui_bridge.c2
-rw-r--r--src/nvim/undo.c4
-rw-r--r--src/nvim/viml/parser/expressions.c13
-rw-r--r--src/nvim/window.c5
121 files changed, 4615 insertions, 3319 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 0e174c3c61..2d803792c8 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -175,7 +175,7 @@ endif()
get_directory_property(gen_cdefs COMPILE_DEFINITIONS)
foreach(gen_cdef ${gen_cdefs} DO_NOT_DEFINE_EMPTY_ATTRIBUTES)
- if(NOT "${gen_cdef}" MATCHES "INCLUDE_GENERATED_DECLARATIONS")
+ if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS")
list(APPEND gen_cflags "-D${gen_cdef}")
endif()
endforeach()
@@ -359,6 +359,10 @@ endforeach()
# Our dependencies come first.
+if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ list(APPEND NVIM_LINK_LIBRARIES pthread c++abi)
+endif()
+
if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif()
@@ -437,6 +441,7 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/tidy.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/win32yank.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/winpty-agent.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
+ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/xxd.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/D3Dcompiler_47.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/libEGL.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
@@ -455,6 +460,8 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/platforms/qwindows.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms/
)
add_dependencies(nvim_runtime_deps external_blobs)
+else()
+ add_custom_target(nvim_runtime_deps) # Stub target to avoid CMP0046.
endif()
add_library(
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index af723639c5..fa4ad27e60 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -24,6 +24,7 @@
#include "nvim/syntax.h"
#include "nvim/window.h"
#include "nvim/undo.h"
+#include "nvim/ex_docmd.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/buffer.c.generated.h"
@@ -186,12 +187,12 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
for (size_t i = 0; i < rv.size; i++) {
int64_t lnum = start + (int64_t)i;
- if (lnum > LONG_MAX) {
+ if (lnum >= MAXLNUM) {
api_set_error(err, kErrorTypeValidation, "Line index is too high");
goto end;
}
- const char *bufstr = (char *) ml_get_buf(buf, (linenr_T) lnum, false);
+ const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false);
Object str = STRING_OBJ(cstr_to_string(bufstr));
// Vim represents NULs as NLs, but this may confuse clients.
@@ -360,7 +361,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start + (int64_t)i;
- if (lnum > LONG_MAX) {
+ if (lnum >= MAXLNUM) {
api_set_error(err, kErrorTypeValidation, "Index value is too high");
goto end;
}
@@ -378,7 +379,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
for (size_t i = to_replace; i < new_len; i++) {
int64_t lnum = start + (int64_t)i - 1;
- if (lnum > LONG_MAX) {
+ if (lnum >= MAXLNUM) {
api_set_error(err, kErrorTypeValidation, "Index value is too high");
goto end;
}
@@ -458,16 +459,15 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
return buf->b_changedtick;
}
-/// Gets a list of dictionaries describing buffer-local mappings.
-/// The "buffer" key in the returned dictionary reflects the buffer
-/// handle where the mapping is present.
+/// Gets a list of buffer-local |mapping| definitions.
///
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @param buffer Buffer handle
/// @param[out] err Error details, if any
-/// @returns Array of maparg()-like dictionaries describing mappings
+/// @returns Array of maparg()-like dictionaries describing mappings.
+/// The "buffer" key holds the associated buffer handle.
ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
- FUNC_API_SINCE(3)
+ FUNC_API_SINCE(3)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -478,6 +478,46 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
return keymap_array(mode, buf);
}
+/// Gets a map of buffer-local |user-commands|.
+///
+/// @param buffer Buffer handle.
+/// @param opts Optional parameters. Currently not used.
+/// @param[out] err Error details, if any.
+///
+/// @returns Map of maps describing commands.
+Dictionary nvim_buf_get_commands(Buffer buffer, Dictionary opts, Error *err)
+ FUNC_API_SINCE(4)
+{
+ bool global = (buffer == -1);
+ bool builtin = false;
+
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object v = opts.items[i].value;
+ if (!strequal("builtin", k.data)) {
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ return (Dictionary)ARRAY_DICT_INIT;
+ }
+ if (strequal("builtin", k.data)) {
+ builtin = v.data.boolean;
+ }
+ }
+
+ if (global) {
+ if (builtin) {
+ api_set_error(err, kErrorTypeValidation, "builtin=true not implemented");
+ return (Dictionary)ARRAY_DICT_INIT;
+ }
+ return commands_array(NULL);
+ }
+
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (builtin || !buf) {
+ return (Dictionary)ARRAY_DICT_INIT;
+ }
+ return commands_array(buf);
+}
+
/// Sets a buffer-scoped (b:) variable
///
/// @param buffer Buffer handle
@@ -581,7 +621,8 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
-void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
+void nvim_buf_set_option(uint64_t channel_id, Buffer buffer,
+ String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -590,7 +631,7 @@ void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
return;
}
- set_option_to(buf, SREQ_BUF, name, value, err);
+ set_option_to(channel_id, buf, SREQ_BUF, name, value, err);
}
/// Gets the buffer number
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index 2144c80d6a..390b7e8363 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -47,7 +47,7 @@ typedef enum {
/// Internal call from lua code
#define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1)
-static inline bool is_internal_call(uint64_t channel_id)
+static inline bool is_internal_call(const uint64_t channel_id)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
/// Check whether call is internal
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 65c306d4b1..17ee3ed711 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -47,13 +47,15 @@ typedef struct {
/// @param[out] tstate Location where try state should be saved.
void try_enter(TryState *const tstate)
{
+ // TODO(ZyX-I): Check whether try_enter()/try_leave() may use
+ // enter_cleanup()/leave_cleanup(). Or
+ // save_dbg_stuff()/restore_dbg_stuff().
*tstate = (TryState) {
.current_exception = current_exception,
.msg_list = (const struct msglist *const *)msg_list,
.private_msg_list = NULL,
.trylevel = trylevel,
.got_int = got_int,
- .did_throw = did_throw,
.need_rethrow = need_rethrow,
.did_emsg = did_emsg,
};
@@ -61,7 +63,6 @@ void try_enter(TryState *const tstate)
current_exception = NULL;
trylevel = 1;
got_int = false;
- did_throw = false;
need_rethrow = false;
did_emsg = false;
}
@@ -82,7 +83,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
assert(trylevel == 0);
assert(!need_rethrow);
assert(!got_int);
- assert(!did_throw);
assert(!did_emsg);
assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL);
@@ -91,7 +91,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
current_exception = tstate->current_exception;
trylevel = tstate->trylevel;
got_int = tstate->got_int;
- did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg;
return ret;
@@ -121,13 +120,11 @@ bool try_end(Error *err)
// try_enter/try_leave.
trylevel--;
- // Without this it stops processing all subsequent VimL commands and
- // generates strange error messages if I e.g. try calling Test() in a
- // cycle
+ // Set by emsg(), affects aborting(). See also enter_cleanup().
did_emsg = false;
if (got_int) {
- if (did_throw) {
+ if (current_exception) {
// If we got an interrupt, discard the current exception
discard_current_exception();
}
@@ -146,7 +143,7 @@ bool try_end(Error *err)
if (should_free) {
xfree(msg);
}
- } else if (did_throw) {
+ } else if (current_exception) {
api_set_error(err, kErrorTypeException, "%s", current_exception->value);
discard_current_exception();
}
@@ -327,7 +324,8 @@ Object get_option_from(void *from, int type, String name, Error *err)
/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
-void set_option_to(void *to, int type, String name, Object value, Error *err)
+void set_option_to(uint64_t channel_id, void *to, int type,
+ String name, Object value, Error *err)
{
if (name.size == 0) {
api_set_error(err, kErrorTypeValidation, "Empty option name");
@@ -364,7 +362,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
}
}
- int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
+ int numval = 0;
+ char *stringval = NULL;
if (flags & SOPT_BOOL) {
if (value.type != kObjectTypeBoolean) {
@@ -375,8 +374,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
- bool val = value.data.boolean;
- set_option_value_for(name.data, val, NULL, opt_flags, type, to, err);
+ numval = value.data.boolean;
} else if (flags & SOPT_NUM) {
if (value.type != kObjectTypeInteger) {
api_set_error(err,
@@ -394,8 +392,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
- int val = (int) value.data.integer;
- set_option_value_for(name.data, val, NULL, opt_flags, type, to, err);
+ numval = (int)value.data.integer;
} else {
if (value.type != kObjectTypeString) {
api_set_error(err,
@@ -405,9 +402,18 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
- set_option_value_for(name.data, 0, value.data.string.data,
- opt_flags, type, to, err);
+ stringval = (char *)value.data.string.data;
}
+
+ const scid_T save_current_SID = current_SID;
+ current_SID = channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
+ current_channel_id = channel_id;
+
+ const int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
+ set_option_value_for(name.data, numval, stringval,
+ opt_flags, type, to, err);
+
+ current_SID = save_current_SID;
}
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
@@ -567,7 +573,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
typval_encode_dict_end(edata)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- TYPVAL_ENCODE_CONV_NIL()
+ TYPVAL_ENCODE_CONV_NIL(val)
#define TYPVAL_ENCODE_SCOPE static
#define TYPVAL_ENCODE_NAME object
@@ -679,7 +685,7 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err)
String cchar_to_string(char c)
{
char buf[] = { c, NUL };
- return (String) {
+ return (String){
.data = xmemdupz(buf, 1),
.size = (c != NUL) ? 1 : 0
};
@@ -695,13 +701,13 @@ String cchar_to_string(char c)
String cstr_to_string(const char *str)
{
if (str == NULL) {
- return (String) STRING_INIT;
+ return (String)STRING_INIT;
}
size_t len = strlen(str);
- return (String) {
- .data = xmemdupz(str, len),
- .size = len
+ return (String){
+ .data = xmemdupz(str, len),
+ .size = len,
};
}
@@ -716,7 +722,7 @@ String cstr_to_string(const char *str)
String cbuf_to_string(const char *buf, size_t size)
FUNC_ATTR_NONNULL_ALL
{
- return (String) {
+ return (String){
.data = xmemdupz(buf, size),
.size = size
};
@@ -731,9 +737,9 @@ String cbuf_to_string(const char *buf, size_t size)
String cstr_as_string(char *str) FUNC_ATTR_PURE
{
if (str == NULL) {
- return (String) STRING_INIT;
+ return (String)STRING_INIT;
}
- return (String) { .data = str, .size = strlen(str) };
+ return (String){ .data = str, .size = strlen(str) };
}
/// Converts from type Object to a VimL value.
@@ -1143,7 +1149,7 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
///
/// @param mode The abbreviation for the mode
/// @param buf The buffer to get the mapping array. NULL for global
-/// @returns An array of maparg() like dictionaries describing mappings
+/// @returns Array of maparg()-like dictionaries describing mappings
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
{
Array mappings = ARRAY_DICT_INIT;
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 87f334ac30..0634764f13 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -93,7 +93,6 @@ typedef struct {
const struct msglist *const *msg_list;
int trylevel;
int got_int;
- int did_throw;
int need_rethrow;
int did_emsg;
} TryState;
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 4870c3fb8a..4cd2657561 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -56,7 +56,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
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");
+ api_set_error(err, kErrorTypeException,
+ "UI already attached to channel: %" PRId64, channel_id);
return;
}
@@ -130,7 +131,8 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
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");
+ api_set_error(err, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
remote_ui_disconnect(channel_id);
@@ -142,7 +144,8 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
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");
+ api_set_error(err, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
@@ -163,7 +166,8 @@ void nvim_ui_set_option(uint64_t channel_id, String name,
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");
+ api_set_error(error, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
@@ -209,7 +213,8 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
return;
}
- api_set_error(error, kErrorTypeValidation, "No such ui option");
+ api_set_error(error, kErrorTypeValidation, "No such UI option: %s",
+ name.data);
#undef UI_EXT_OPTION
}
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index c599b0ce72..96d494460b 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -10,7 +10,7 @@
#include "nvim/func_attr.h"
#include "nvim/ui.h"
-void resize(Integer rows, Integer columns)
+void resize(Integer width, Integer height)
FUNC_API_SINCE(3);
void clear(void)
FUNC_API_SINCE(3);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index dad67c5e4b..7a951d4e67 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -33,6 +33,7 @@
#include "nvim/syntax.h"
#include "nvim/getchar.h"
#include "nvim/os/input.h"
+#include "nvim/os/process.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/ui.h"
@@ -45,8 +46,7 @@
/// Executes an ex-command.
///
-/// On parse error: forwards the Vim error; does not update v:errmsg.
-/// On runtime error: forwards the Vim error; does not update v:errmsg.
+/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// @param command Ex-command string
/// @param[out] err Error details (Vim error), if any
@@ -102,7 +102,8 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
}
/// Passes input keys to Nvim.
-/// On VimL error: Does not fail, but updates v:errmsg.
+///
+/// On execution error: does not fail, but updates v:errmsg.
///
/// @param keys to be typed
/// @param mode mapping options
@@ -168,7 +169,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
}
/// Passes keys to Nvim as raw user-input.
-/// On VimL error: Does not fail, but updates v:errmsg.
+///
+/// On execution error: does not fail, but updates v:errmsg.
///
/// Unlike `nvim_feedkeys`, this uses a lower-level input buffer and the call
/// is not deferred. This is the most reliable way to send real user input.
@@ -212,8 +214,7 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
/// Executes an ex-command and returns its (non-error) output.
/// Shell |:!| output is not captured.
///
-/// On parse error: forwards the Vim error; does not update v:errmsg.
-/// On runtime error: forwards the Vim error; does not update v:errmsg.
+/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// @param command Ex-command string
/// @param[out] err Error details (Vim error), if any
@@ -238,15 +239,17 @@ String nvim_command_output(String command, Error *err)
}
if (capture_local.ga_len > 1) {
- // redir always(?) prepends a newline; remove it.
- char *s = capture_local.ga_data;
- assert(s[0] == '\n');
- memmove(s, s + 1, (size_t)capture_local.ga_len);
- s[capture_local.ga_len - 1] = '\0';
- return (String) { // Caller will free the memory.
- .data = s,
- .size = (size_t)(capture_local.ga_len - 1),
+ String s = (String){
+ .data = capture_local.ga_data,
+ .size = (size_t)capture_local.ga_len,
};
+ // redir usually (except :echon) prepends a newline.
+ if (s.data[0] == '\n') {
+ memmove(s.data, s.data + 1, s.size);
+ s.data[s.size - 1] = '\0';
+ s.size = s.size - 1;
+ }
+ return s; // Caller will free the memory.
}
theend:
@@ -256,7 +259,8 @@ theend:
/// Evaluates a VimL expression (:help expression).
/// Dictionaries and Lists are recursively expanded.
-/// On VimL error: Returns a generic error; v:errmsg is not updated.
+///
+/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// @param expr VimL expression string
/// @param[out] err Error details, if any
@@ -264,41 +268,79 @@ theend:
Object nvim_eval(String expr, Error *err)
FUNC_API_SINCE(1)
{
+ static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
- // Evaluate the expression
+
+ // `msg_list` controls the collection of abort-causing non-exception errors,
+ // which would otherwise be ignored. This pattern is from do_cmdline().
+ struct msglist **saved_msg_list = msg_list;
+ struct msglist *private_msg_list;
+ msg_list = &private_msg_list;
+ private_msg_list = NULL;
+
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ current_exception = NULL;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
+ recursive++;
try_start();
typval_T rettv;
- if (eval0((char_u *)expr.data, &rettv, NULL, true) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to evaluate expression");
- }
+ int ok = eval0((char_u *)expr.data, &rettv, NULL, true);
if (!try_end(err)) {
- // No errors, convert the result
- rv = vim_to_object(&rettv);
+ if (ok == FAIL) {
+ // Should never happen, try_end() should get the error. #8371
+ api_set_error(err, kErrorTypeException, "Failed to evaluate expression");
+ } else {
+ rv = vim_to_object(&rettv);
+ }
}
- // Free the Vim object
tv_clear(&rettv);
+ msg_list = saved_msg_list; // Restore the exception context.
+ recursive--;
return rv;
}
-/// Calls a VimL function with the given arguments
+/// Execute lua code. Parameters (if any) are available as `...` inside the
+/// chunk. The chunk can return a value.
///
-/// On VimL error: Returns a generic error; v:errmsg is not updated.
+/// Only statements are executed. To evaluate an expression, prefix it
+/// with `return`: return my_function(...)
///
-/// @param fname Function to call
-/// @param args Function arguments packed in an Array
+/// @param code lua code to execute
+/// @param args Arguments to the code
+/// @param[out] err Details of an error encountered while parsing
+/// or executing the lua code.
+///
+/// @return Return value of lua code if present or NIL.
+Object nvim_execute_lua(String code, Array args, Error *err)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY
+{
+ return executor_exec_lua_api(code, args, err);
+}
+
+/// Calls a VimL function.
+///
+/// @param fn Function name
+/// @param args Function arguments
+/// @param self `self` dict, or NULL for non-dict functions
/// @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)
+static Object _call_function(String fn, Array args, dict_T *self, Error *err)
{
+ static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
+
if (args.size > MAX_FUNC_ARGS) {
api_set_error(err, kErrorTypeValidation,
- "Function called with too many arguments.");
+ "Function called with too many arguments");
return rv;
}
@@ -311,21 +353,36 @@ Object nvim_call_function(String fname, Array args, Error *err)
}
}
+ // `msg_list` controls the collection of abort-causing non-exception errors,
+ // which would otherwise be ignored. This pattern is from do_cmdline().
+ struct msglist **saved_msg_list = msg_list;
+ struct msglist *private_msg_list;
+ msg_list = &private_msg_list;
+ private_msg_list = NULL;
+
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ current_exception = NULL;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
+ recursive++;
try_start();
- // Call the function
typval_T rettv;
int dummy;
- int r = call_func((char_u *)fname.data, (int)fname.size,
- &rettv, (int)args.size, vim_args, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
- true, NULL, NULL);
- if (r == FAIL) {
- api_set_error(err, kErrorTypeException, "Error calling function.");
- }
+ // call_func() retval is deceptive, ignore it. Instead we set `msg_list`
+ // (see above) to capture abort-causing non-exception errors.
+ (void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
+ vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &dummy, true, NULL, self);
if (!try_end(err)) {
rv = vim_to_object(&rettv);
}
tv_clear(&rettv);
+ msg_list = saved_msg_list; // Restore the exception context.
+ recursive--;
free_vim_args:
while (i > 0) {
@@ -335,22 +392,102 @@ free_vim_args:
return rv;
}
-/// Execute lua code. Parameters (if any) are available as `...` inside the
-/// chunk. The chunk can return a value.
+/// Calls a VimL function with the given arguments.
///
-/// Only statements are executed. To evaluate an expression, prefix it
-/// with `return`: return my_function(...)
+/// On execution error: fails with VimL error, does not update v:errmsg.
///
-/// @param code lua code to execute
-/// @param args Arguments to the code
-/// @param[out] err Details of an error encountered while parsing
-/// or executing the lua code.
+/// @param fn Function to call
+/// @param args Function arguments packed in an Array
+/// @param[out] err Error details, if any
+/// @return Result of the function call
+Object nvim_call_function(String fn, Array args, Error *err)
+ FUNC_API_SINCE(1)
+{
+ return _call_function(fn, args, NULL, err);
+}
+
+/// Calls a VimL |Dictionary-function| with the given arguments.
///
-/// @return Return value of lua code if present or NIL.
-Object nvim_execute_lua(String code, Array args, Error *err)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY
+/// On execution error: fails with VimL error, does not update v:errmsg.
+///
+/// @param dict Dictionary, or String evaluating to a VimL |self| dict
+/// @param fn Name of the function defined on the VimL dict
+/// @param args Function arguments packed in an Array
+/// @param[out] err Error details, if any
+/// @return Result of the function call
+Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
+ FUNC_API_SINCE(4)
{
- return executor_exec_lua_api(code, args, err);
+ Object rv = OBJECT_INIT;
+
+ typval_T rettv;
+ bool mustfree = false;
+ switch (dict.type) {
+ case kObjectTypeString: {
+ try_start();
+ if (eval0((char_u *)dict.data.string.data, &rettv, NULL, true) == FAIL) {
+ api_set_error(err, kErrorTypeException,
+ "Failed to evaluate dict expression");
+ }
+ if (try_end(err)) {
+ return rv;
+ }
+ // Evaluation of the string arg created a new dict or increased the
+ // refcount of a dict. Not necessary for a RPC dict.
+ mustfree = true;
+ break;
+ }
+ case kObjectTypeDictionary: {
+ if (!object_to_vim(dict, &rettv, err)) {
+ goto end;
+ }
+ break;
+ }
+ default: {
+ api_set_error(err, kErrorTypeValidation,
+ "dict argument type must be String or Dictionary");
+ return rv;
+ }
+ }
+ dict_T *self_dict = rettv.vval.v_dict;
+ if (rettv.v_type != VAR_DICT || !self_dict) {
+ api_set_error(err, kErrorTypeValidation, "dict not found");
+ goto end;
+ }
+
+ if (fn.data && fn.size > 0 && dict.type != kObjectTypeDictionary) {
+ dictitem_T *const di = tv_dict_find(self_dict, fn.data, (ptrdiff_t)fn.size);
+ if (di == NULL) {
+ api_set_error(err, kErrorTypeValidation, "Not found: %s", fn.data);
+ goto end;
+ }
+ if (di->di_tv.v_type == VAR_PARTIAL) {
+ api_set_error(err, kErrorTypeValidation,
+ "partial function not supported");
+ goto end;
+ }
+ if (di->di_tv.v_type != VAR_FUNC) {
+ api_set_error(err, kErrorTypeValidation, "Not a function: %s", fn.data);
+ goto end;
+ }
+ fn = (String) {
+ .data = (char *)di->di_tv.vval.v_string,
+ .size = strlen((char *)di->di_tv.vval.v_string),
+ };
+ }
+
+ if (!fn.data || fn.size < 1) {
+ api_set_error(err, kErrorTypeValidation, "Invalid (empty) function name");
+ goto end;
+ }
+
+ rv = _call_function(fn, args, self_dict, err);
+end:
+ if (mustfree) {
+ tv_clear(&rettv);
+ }
+
+ return rv;
}
/// Calculates the number of display cells occupied by `text`.
@@ -546,10 +683,10 @@ Object nvim_get_option(String name, Error *err)
/// @param name Option name
/// @param value New option value
/// @param[out] err Error details, if any
-void nvim_set_option(String name, Object value, Error *err)
+void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
- set_option_to(NULL, SREQ_GLOBAL, name, value, err);
+ set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
}
/// Writes a message to the Vim output buffer. Does not append "\n", the
@@ -811,17 +948,32 @@ Dictionary nvim_get_mode(void)
return rv;
}
-/// Gets a list of dictionaries describing global (non-buffer) mappings.
-/// The "buffer" key in the returned dictionary is always zero.
+/// Gets a list of global (non-buffer-local) |mapping| definitions.
///
/// @param mode Mode short-name ("n", "i", "v", ...)
-/// @returns Array of maparg()-like dictionaries describing mappings
+/// @returns Array of maparg()-like dictionaries describing mappings.
+/// The "buffer" key is always zero.
ArrayOf(Dictionary) nvim_get_keymap(String mode)
- FUNC_API_SINCE(3)
+ FUNC_API_SINCE(3)
{
return keymap_array(mode, NULL);
}
+/// Gets a map of global (non-buffer-local) Ex commands.
+///
+/// Currently only |user-commands| are supported, not builtin Ex commands.
+///
+/// @param opts Optional parameters. Currently only supports
+/// {"builtin":false}
+/// @param[out] err Error details, if any.
+///
+/// @returns Map of maps describing commands.
+Dictionary nvim_get_commands(Dictionary opts, Error *err)
+ FUNC_API_SINCE(4)
+{
+ return nvim_buf_get_commands(-1, opts, err);
+}
+
/// Returns a 2-tuple (Array), where item 0 is the current channel id and item
/// 1 is the |api-metadata| map (Dictionary).
///
@@ -838,27 +990,26 @@ Array nvim_get_api_info(uint64_t channel_id)
return rv;
}
-/// Call many api methods atomically
+/// Calls many API methods atomically.
///
-/// This has two main usages: Firstly, to perform several requests from an
-/// async context atomically, i.e. without processing requests from other rpc
-/// clients or redrawing or allowing user interaction in between. Note that api
-/// methods that could fire autocommands or do event processing still might do
-/// so. For instance invoking the :sleep command might call timer callbacks.
-/// Secondly, it can be used to reduce rpc overhead (roundtrips) when doing
-/// many requests in sequence.
+/// This has two main usages:
+/// 1. To perform several requests from an async context atomically, i.e.
+/// without interleaving redraws, RPC requests from other clients, or user
+/// interactions (however API methods may trigger autocommands or event
+/// processing which have such side-effects, e.g. |:sleep| may wake timers).
+/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests.
///
/// @param calls an array of calls, where each call is described by an array
/// with two elements: the request name, and an array of arguments.
/// @param[out] err Details of a validation error of the nvim_multi_request call
-/// itself, i e malformatted `calls` parameter. Errors from called methods will
+/// itself, i.e. malformed `calls` parameter. Errors from called methods will
/// be indicated in the return value, see below.
///
/// @return an array with two elements. The first is an array of return
/// values. The second is NIL if all calls succeeded. If a call resulted in
/// an error, it is a three-element array with the zero-based index of the call
/// 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.
+/// error occurred, 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
{
@@ -1197,7 +1348,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
.node_p = &node->next,
.ret_node_p = cur_item.ret_node_p + 1,
}));
- } else if (node != NULL) {
+ } else {
kv_drop(ast_conv_stack, 1);
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("type"),
@@ -1470,6 +1621,17 @@ Float nvim__id_float(Float flt)
return flt;
}
+/// Gets internal stats.
+///
+/// @return Map of various internal stats.
+Dictionary nvim__stats(void)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+ PUT(rv, "fsync", INTEGER_OBJ(g_stats.fsync));
+ PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
+ return rv;
+}
+
/// Gets a list of dictionaries representing attached UIs.
///
/// @return Array of UI dictionaries
@@ -1478,3 +1640,86 @@ Array nvim_list_uis(void)
{
return ui_array();
}
+
+/// Gets the immediate children of process `pid`.
+///
+/// @return Array of child process ids, empty if process not found.
+Array nvim_get_proc_children(Integer pid, Error *err)
+ FUNC_API_SINCE(4)
+{
+ Array rvobj = ARRAY_DICT_INIT;
+ int *proc_list = NULL;
+
+ if (pid <= 0 || pid > INT_MAX) {
+ api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid);
+ goto end;
+ }
+
+ size_t proc_count;
+ int rv = os_proc_children((int)pid, &proc_list, &proc_count);
+ if (rv != 0) {
+ // syscall failed (possibly because of kernel options), try shelling out.
+ DLOG("fallback to vim._os_proc_children()");
+ Array a = ARRAY_DICT_INIT;
+ ADD(a, INTEGER_OBJ(pid));
+ String s = cstr_to_string("return vim._os_proc_children(select(1, ...))");
+ Object o = nvim_execute_lua(s, a, err);
+ api_free_string(s);
+ api_free_array(a);
+ if (o.type == kObjectTypeArray) {
+ rvobj = o.data.array;
+ } else if (!ERROR_SET(err)) {
+ api_set_error(err, kErrorTypeException,
+ "Failed to get process children. pid=%" PRId64 " error=%d",
+ pid, rv);
+ }
+ goto end;
+ }
+
+ for (size_t i = 0; i < proc_count; i++) {
+ ADD(rvobj, INTEGER_OBJ(proc_list[i]));
+ }
+
+end:
+ xfree(proc_list);
+ return rvobj;
+}
+
+/// Gets info describing process `pid`.
+///
+/// @return Map of process properties, or NIL if process not found.
+Object nvim_get_proc(Integer pid, Error *err)
+ FUNC_API_SINCE(4)
+{
+ Object rvobj = OBJECT_INIT;
+ rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT;
+ rvobj.type = kObjectTypeDictionary;
+
+ if (pid <= 0 || pid > INT_MAX) {
+ api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid);
+ return NIL;
+ }
+#ifdef WIN32
+ rvobj.data.dictionary = os_proc_info((int)pid);
+ if (rvobj.data.dictionary.size == 0) { // Process not found.
+ return NIL;
+ }
+#else
+ // Cross-platform process info APIs are miserable, so use `ps` instead.
+ Array a = ARRAY_DICT_INIT;
+ ADD(a, INTEGER_OBJ(pid));
+ String s = cstr_to_string("return vim._os_proc_info(select(1, ...))");
+ Object o = nvim_execute_lua(s, a, err);
+ api_free_string(s);
+ api_free_array(a);
+ if (o.type == kObjectTypeArray && o.data.array.size == 0) {
+ return NIL; // Process not found.
+ } else if (o.type == kObjectTypeDictionary) {
+ rvobj.data.dictionary = o.data.dictionary;
+ } else if (!ERROR_SET(err)) {
+ api_set_error(err, kErrorTypeException,
+ "Failed to get process info. pid=%" PRId64, pid);
+ }
+#endif
+ return rvobj;
+}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9bc91ef8fb..abfa0dc20b 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -309,7 +309,8 @@ Object nvim_win_get_option(Window window, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
-void nvim_win_set_option(Window window, String name, Object value, Error *err)
+void nvim_win_set_option(uint64_t channel_id, Window window,
+ String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -318,7 +319,7 @@ void nvim_win_set_option(Window window, String name, Object value, Error *err)
return;
}
- set_option_to(win, SREQ_WIN, name, value, err);
+ set_option_to(channel_id, win, SREQ_WIN, name, value, err);
}
/// Gets the window position in display cells. First position is zero.
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 9ccb70764d..ff6840d690 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -146,7 +146,7 @@ static inline bool ascii_isxdigit(int c)
/// Checks if `c` is an “identifier” character
///
/// That is, whether it is alphanumeric character or underscore.
-static inline bool ascii_isident(const int c)
+static inline bool ascii_isident(int c)
{
return ASCII_ISALNUM(c) || c == '_';
}
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 7dfaf54ff0..1153314e76 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -92,6 +92,8 @@ return {
'VimLeave', -- before exiting Vim
'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
+ 'VimResume', -- after Nvim is resumed
+ 'VimSuspend', -- before Nvim is suspended
'WinNew', -- when entering a new window
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 3958fb05e9..ba63822837 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -22,6 +22,7 @@
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
+#include <assert.h>
#include "nvim/api/private/handle.h"
#include "nvim/api/private/helpers.h"
@@ -2683,7 +2684,7 @@ void buflist_altfpos(win_T *win)
}
/// Check that "ffname" is not the same file as current file.
-/// Fname must have a full path (expanded by path_get_absolute_path()).
+/// Fname must have a full path (expanded by path_to_absolute()).
///
/// @param ffname full path name to check
bool otherfile(char_u *ffname)
@@ -2693,7 +2694,7 @@ bool otherfile(char_u *ffname)
}
/// Check that "ffname" is not the same file as the file loaded in "buf".
-/// Fname must have a full path (expanded by path_get_absolute_path()).
+/// Fname must have a full path (expanded by path_to_absolute()).
///
/// @param buf buffer to check
/// @param ffname full path name to check
@@ -2885,15 +2886,13 @@ static char_u *lasticon = NULL;
void maketitle(void)
{
- char_u *p;
char_u *t_str = NULL;
char_u *i_name;
char_u *i_str = NULL;
int maxlen = 0;
int len;
int mustset;
- char_u buf[IOSIZE];
- int off;
+ char buf[IOSIZE];
if (!redrawing()) {
/* Postpone updating the title when 'lazyredraw' is set. */
@@ -2913,97 +2912,117 @@ void maketitle(void)
}
}
- t_str = buf;
if (*p_titlestring != NUL) {
if (stl_syntax & STL_IN_TITLE) {
int use_sandbox = FALSE;
int save_called_emsg = called_emsg;
use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
- called_emsg = FALSE;
- build_stl_str_hl(curwin, t_str, sizeof(buf),
- p_titlestring, use_sandbox,
- 0, maxlen, NULL, NULL);
- if (called_emsg)
- set_string_option_direct((char_u *)"titlestring", -1,
- (char_u *)"", OPT_FREE, SID_ERROR);
+ called_emsg = false;
+ build_stl_str_hl(curwin, (char_u *)buf, sizeof(buf),
+ p_titlestring, use_sandbox,
+ 0, maxlen, NULL, NULL);
+ t_str = (char_u *)buf;
+ if (called_emsg) {
+ set_string_option_direct((char_u *)"titlestring", -1, (char_u *)"",
+ OPT_FREE, SID_ERROR);
+ }
called_emsg |= save_called_emsg;
- } else
+ } else {
t_str = p_titlestring;
+ }
} else {
- /* format: "fname + (path) (1 of 2) - VIM" */
-
-#define SPACE_FOR_FNAME (IOSIZE - 100)
-#define SPACE_FOR_DIR (IOSIZE - 20)
-#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */
- if (curbuf->b_fname == NULL)
- STRLCPY(buf, _("[No Name]"), SPACE_FOR_FNAME + 1);
- else {
- p = transstr(path_tail(curbuf->b_fname));
- STRLCPY(buf, p, SPACE_FOR_FNAME + 1);
- xfree(p);
+ // Format: "fname + (path) (1 of 2) - VIM".
+
+#define SPACE_FOR_FNAME (sizeof(buf) - 100)
+#define SPACE_FOR_DIR (sizeof(buf) - 20)
+#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM".
+ char *buf_p = buf;
+ if (curbuf->b_fname == NULL) {
+ const size_t size = xstrlcpy(buf_p, _("[No Name]"),
+ SPACE_FOR_FNAME + 1);
+ buf_p += MIN(size, SPACE_FOR_FNAME);
+ } else {
+ buf_p += transstr_buf((const char *)path_tail(curbuf->b_fname),
+ buf_p, SPACE_FOR_FNAME + 1);
}
switch (bufIsChanged(curbuf)
- + (curbuf->b_p_ro * 2)
- + (!MODIFIABLE(curbuf) * 4)) {
- case 1: STRCAT(buf, " +"); break;
- case 2: STRCAT(buf, " ="); break;
- case 3: STRCAT(buf, " =+"); break;
- case 4:
- case 6: STRCAT(buf, " -"); break;
- case 5:
- case 7: STRCAT(buf, " -+"); break;
+ | (curbuf->b_p_ro << 1)
+ | (!MODIFIABLE(curbuf) << 2)) {
+ case 0: break;
+ case 1: buf_p = strappend(buf_p, " +"); break;
+ case 2: buf_p = strappend(buf_p, " ="); break;
+ case 3: buf_p = strappend(buf_p, " =+"); break;
+ case 4:
+ case 6: buf_p = strappend(buf_p, " -"); break;
+ case 5:
+ case 7: buf_p = strappend(buf_p, " -+"); break;
+ default: assert(false);
}
if (curbuf->b_fname != NULL) {
- /* Get path of file, replace home dir with ~ */
- off = (int)STRLEN(buf);
- buf[off++] = ' ';
- buf[off++] = '(';
- home_replace(curbuf, curbuf->b_ffname,
- buf + off, (size_t)(SPACE_FOR_DIR - off), true);
+ // Get path of file, replace home dir with ~.
+ *buf_p++ = ' ';
+ *buf_p++ = '(';
+ home_replace(curbuf, curbuf->b_ffname, (char_u *)buf_p,
+ (SPACE_FOR_DIR - (size_t)(buf_p - buf)), true);
#ifdef BACKSLASH_IN_FILENAME
- /* avoid "c:/name" to be reduced to "c" */
- if (isalpha(buf[off]) && buf[off + 1] == ':')
- off += 2;
+ // Avoid "c:/name" to be reduced to "c".
+ if (isalpha((uint8_t)buf_p) && *(buf_p + 1) == ':') {
+ buf_p += 2;
+ }
#endif
- /* remove the file name */
- p = path_tail_with_sep(buf + off);
- if (p == buf + off)
- /* must be a help buffer */
- STRLCPY(buf + off, _("help"), SPACE_FOR_DIR - off);
- else
+ // Remove the file name.
+ char *p = (char *)path_tail_with_sep((char_u *)buf_p);
+ if (p == buf_p) {
+ // Must be a help buffer.
+ xstrlcpy(buf_p, _("help"), SPACE_FOR_DIR - (size_t)(buf_p - buf));
+ } else {
*p = NUL;
+ }
- /* Translate unprintable chars and concatenate. Keep some
- * room for the server name. When there is no room (very long
- * file name) use (...). */
- if (off < SPACE_FOR_DIR) {
- p = transstr(buf + off);
- STRLCPY(buf + off, p, SPACE_FOR_DIR - off + 1);
- xfree(p);
+ // Translate unprintable chars and concatenate. Keep some
+ // room for the server name. When there is no room (very long
+ // file name) use (...).
+ if ((size_t)(buf_p - buf) < SPACE_FOR_DIR) {
+ char *const tbuf = transstr(buf_p);
+ const size_t free_space = SPACE_FOR_DIR - (size_t)(buf_p - buf) + 1;
+ const size_t dir_len = xstrlcpy(buf_p, tbuf, free_space);
+ buf_p += MIN(dir_len, free_space - 1);
+ xfree(tbuf);
} else {
- STRLCPY(buf + off, "...", SPACE_FOR_ARGNR - off + 1);
+ const size_t free_space = SPACE_FOR_ARGNR - (size_t)(buf_p - buf) + 1;
+ const size_t dots_len = xstrlcpy(buf_p, "...", free_space);
+ buf_p += MIN(dots_len, free_space - 1);
}
- STRCAT(buf, ")");
+ *buf_p++ = ')';
+ *buf_p = NUL;
+ } else {
+ *buf_p = NUL;
}
- append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
+ append_arg_number(curwin, (char_u *)buf_p,
+ (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf)), false);
- STRCAT(buf, " - NVIM");
+ xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf)));
if (maxlen > 0) {
- /* make it shorter by removing a bit in the middle */
- if (vim_strsize(buf) > maxlen)
- trunc_string(buf, buf, maxlen, IOSIZE);
+ // Make it shorter by removing a bit in the middle.
+ if (vim_strsize((char_u *)buf) > maxlen) {
+ trunc_string((char_u *)buf, (char_u *)buf, maxlen, sizeof(buf));
+ }
}
+ t_str = (char_u *)buf;
+#undef SPACE_FOR_FNAME
+#undef SPACE_FOR_DIR
+#undef SPACE_FOR_ARGNR
}
}
mustset = ti_change(t_str, &lasttitle);
if (p_icon) {
- i_str = buf;
+ i_str = (char_u *)buf;
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
int use_sandbox = FALSE;
@@ -3091,7 +3110,6 @@ void free_titles(void)
/// be used when printing numbers in the status line.
typedef enum {
kNumBaseDecimal = 10,
- kNumBaseOctal = 8,
kNumBaseHexadecimal = 16
} NumberBase;
@@ -3889,9 +3907,7 @@ int build_stl_str_hl(
// Note: The `*` means we take the width as one of the arguments
*t++ = '*';
- *t++ = (char_u) (base == kNumBaseHexadecimal ? 'X'
- : (base == kNumBaseOctal ? 'o'
- : 'd'));
+ *t++ = (char_u)(base == kNumBaseHexadecimal ? 'X' : 'd');
*t = 0;
// }
@@ -5346,7 +5362,7 @@ void bufhl_clear_line_range(buf_T *buf,
if (line > line_end) {
break;
}
- if (line_start <= line && line <= line_end) {
+ if (line_start <= line) {
BufhlLineStatus status = bufhl_clear_line(l, src_id, line);
if (status != kBLSUnchanged) {
if (line > last_changed) {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 8de4286216..53edae58a5 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -237,7 +237,7 @@ typedef struct {
char_u *wo_winhl;
# define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight'
- int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */
+ LastSet wo_scriptID[WV_COUNT]; // SIDs for window-local options
# define w_p_scriptID w_onebuf_opt.wo_scriptID
} winopt_T;
@@ -590,7 +590,7 @@ struct file_buffer {
*/
bool b_p_initialized; /* set when options initialized */
- int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */
+ LastSet b_p_scriptID[BV_COUNT]; // SIDs for buffer-local options
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 265d4d8b89..4e6ca8d278 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -180,10 +180,12 @@ static Channel *channel_alloc(ChannelStreamType type)
}
/// Not implemented, only logging for now
-void channel_create_event(Channel *chan, char *ext_source)
+void channel_create_event(Channel *chan, const char *ext_source)
{
#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
- char *stream_desc, *mode_desc, *source;
+ const char *stream_desc;
+ const char *mode_desc;
+ const char *source;
switch (chan->streamtype) {
case kChannelStreamProc:
@@ -223,8 +225,8 @@ void channel_create_event(Channel *chan, char *ext_source)
// external events should be included.
source = ext_source;
} else {
- eval_format_source_name_line((char *)IObuff, sizeof(IObuff));
- source = (char *)IObuff;
+ eval_fmt_source_name_line((char *)IObuff, sizeof(IObuff));
+ source = (const char *)IObuff;
}
ILOG("new channel %" PRIu64 " (%s%s): %s", chan->id, stream_desc,
@@ -235,15 +237,16 @@ void channel_create_event(Channel *chan, char *ext_source)
#endif
}
-void channel_incref(Channel *channel)
+void channel_incref(Channel *chan)
{
- channel->refcount++;
+ chan->refcount++;
}
-void channel_decref(Channel *channel)
+void channel_decref(Channel *chan)
{
- if (!(--channel->refcount)) {
- multiqueue_put(main_loop.fast_events, free_channel_event, 1, channel);
+ if (!(--chan->refcount)) {
+ // delay free, so that libuv is done with the handles
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
}
@@ -265,18 +268,18 @@ void callback_reader_start(CallbackReader *reader)
static void free_channel_event(void **argv)
{
- Channel *channel = argv[0];
- if (channel->is_rpc) {
- rpc_free(channel);
+ Channel *chan = argv[0];
+ if (chan->is_rpc) {
+ rpc_free(chan);
}
- callback_reader_free(&channel->on_stdout);
- callback_reader_free(&channel->on_stderr);
- callback_free(&channel->on_exit);
+ callback_reader_free(&chan->on_stdout);
+ callback_reader_free(&chan->on_stderr);
+ callback_free(&chan->on_exit);
- pmap_del(uint64_t)(channels, channel->id);
- multiqueue_free(channel->events);
- xfree(channel);
+ pmap_del(uint64_t)(channels, chan->id);
+ multiqueue_free(chan->events);
+ xfree(chan);
}
static void channel_destroy_early(Channel *chan)
@@ -284,12 +287,15 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
+ pmap_del(uint64_t)(channels, chan->id);
+ chan->id = 0;
if ((--chan->refcount != 0)) {
abort();
}
- free_channel_event((void **)&chan);
+ // uv will keep a reference to handles until next loop tick, so delay free
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
@@ -392,17 +398,22 @@ uint64_t channel_connect(bool tcp, const char *address,
bool rpc, CallbackReader on_output,
int timeout, const char **error)
{
+ Channel *channel;
+
if (!tcp && rpc) {
char *path = fix_fname(address);
- if (server_owns_pipe_address(path)) {
- // avoid deadlock
- xfree(path);
- return channel_create_internal_rpc();
- }
+ bool loopback = server_owns_pipe_address(path);
xfree(path);
+ if (loopback) {
+ // Create a loopback channel. This avoids deadlock if nvim connects to
+ // its own named pipe.
+ channel = channel_alloc(kChannelStreamInternal);
+ rpc_start(channel);
+ goto end;
+ }
}
- Channel *channel = channel_alloc(kChannelStreamSocket);
+ channel = channel_alloc(kChannelStreamSocket);
if (!socket_connect(&main_loop, &channel->stream.socket,
tcp, address, timeout, error)) {
channel_destroy_early(channel);
@@ -422,7 +433,8 @@ uint64_t channel_connect(bool tcp, const char *address,
rstream_start(&channel->stream.socket, on_socket_output, channel);
}
- channel_create_event(channel, NULL);
+end:
+ channel_create_event(channel, address);
return channel->id;
}
@@ -441,15 +453,6 @@ void channel_from_connection(SocketWatcher *watcher)
channel_create_event(channel, watcher->addr);
}
-/// Creates a loopback channel. This is used to avoid deadlock
-/// when an instance connects to its own named pipe.
-static uint64_t channel_create_internal_rpc(void)
-{
- Channel *channel = channel_alloc(kChannelStreamInternal);
- rpc_start(channel);
- return channel->id;
-}
-
/// Creates an API channel from stdin/stdout. This is used when embedding
/// Neovim
uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
@@ -655,9 +658,9 @@ static void channel_process_exit_cb(Process *proc, int status, void *data)
terminal_close(chan->term, msg);
}
- // if status is -1 the process did not really exit,
- // we just closed the handle onto a detached process
- if (status >= 0) {
+ // If process did not exit, we only closed the handle of a detached process.
+ bool exited = (status >= 0);
+ if (exited) {
process_channel_event(chan, &chan->on_exit, "exit", NULL, 0, status);
}
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 980b4ed426..7d5f80c531 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -313,69 +313,112 @@ void trans_characters(char_u *buf, int bufsize)
}
}
-/// Translate a string into allocated memory, replacing special chars with
-/// printable chars.
+/// Find length of a string capable of holding s with all specials replaced
///
-/// @param s
+/// Assumes replacing special characters with printable ones just like
+/// strtrans() does.
+///
+/// @param[in] s String to check.
///
-/// @return translated string
-char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET
+/// @return number of bytes needed to hold a translation of `s`, NUL byte not
+/// included.
+size_t transstr_len(const char *const s)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
- char_u *res;
- char_u *p;
- int c;
- size_t l;
- char_u hexbuf[11];
-
- // Compute the length of the result, taking account of unprintable
- // multi-byte characters.
+ const char *p = s;
size_t len = 0;
- p = s;
- while (*p != NUL) {
- if ((l = (size_t)(*mb_ptr2len)(p)) > 1) {
- c = (*mb_ptr2char)(p);
- p += l;
+ while (*p) {
+ const size_t l = (size_t)utfc_ptr2len((const char_u *)p);
+ if (l > 1) {
+ int pcc[MAX_MCO + 2];
+ pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]);
- if (vim_isprintc(c)) {
+ if (vim_isprintc(pcc[0])) {
len += l;
} else {
- transchar_hex(hexbuf, c);
- len += STRLEN(hexbuf);
+ for (size_t i = 0; i < ARRAY_SIZE(pcc); i++) {
+ char hexbuf[11];
+ len += transchar_hex(hexbuf, pcc[i]);
+ }
}
+ p += l;
} else {
- l = (size_t)byte2cells(*p++);
-
- if (l > 0) {
- len += l;
- } else {
- // illegal byte sequence
- len += 4;
- }
+ const int b2c_l = byte2cells((uint8_t)(*p++));
+ // Illegal byte sequence may occupy up to 4 characters.
+ len += (size_t)(b2c_l > 0 ? b2c_l : 4);
}
}
- res = xmallocz(len);
-
- *res = NUL;
- p = s;
+ return len;
+}
- while (*p != NUL) {
- if ((l = (size_t)(*mb_ptr2len)(p)) > 1) {
- c = (*mb_ptr2char)(p);
+/// Replace special characters with printable ones
+///
+/// @param[in] s String to replace characters from.
+/// @param[out] buf Buffer to which result should be saved.
+/// @param[in] len Buffer length. Resulting string may not occupy more then
+/// len - 1 bytes (one for trailing NUL byte).
+///
+/// @return length of the resulting string, without the NUL byte.
+size_t transstr_buf(const char *const s, char *const buf, const size_t len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *p = s;
+ char *buf_p = buf;
+ char *const buf_e = buf_p + len - 1;
+
+ while (*p != NUL && buf_p < buf_e) {
+ const size_t l = (size_t)utfc_ptr2len((const char_u *)p);
+ if (l > 1) {
+ if (buf_p + l >= buf_e) {
+ break;
+ }
+ int pcc[MAX_MCO + 2];
+ pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]);
- if (vim_isprintc(c)) {
- // append printable multi-byte char
- STRNCAT(res, p, l);
+ if (vim_isprintc(pcc[0])) {
+ memmove(buf_p, p, l);
+ buf_p += l;
} else {
- transchar_hex(res + STRLEN(res), c);
+ for (size_t i = 0; i < ARRAY_SIZE(pcc); i++) {
+ char hexbuf[11];
+ const size_t hexlen = transchar_hex(hexbuf, pcc[i]);
+ if (buf_p + hexlen >= buf_e) {
+ break;
+ }
+ memmove(buf_p, hexbuf, hexlen);
+ buf_p += hexlen;
+ }
}
p += l;
} else {
- STRCAT(res, transchar_byte(*p++));
+ const char *const tb = (const char *)transchar_byte((uint8_t)(*p++));
+ const size_t tb_len = strlen(tb);
+ memmove(buf_p, tb, tb_len);
+ buf_p += tb_len;
}
}
+ *buf_p = NUL;
+ assert(buf_p <= buf_e);
+ return (size_t)(buf_p - buf);
+}
- return res;
+/// Copy string and replace special characters with printable characters
+///
+/// Works like `strtrans()` does, used for that and in some other places.
+///
+/// @param[in] s String to replace characters from.
+///
+/// @return [allocated] translated string
+char *transstr(const char *const s)
+ FUNC_ATTR_NONNULL_RET
+{
+ // Compute the length of the result, taking account of unprintable
+ // multi-byte characters.
+ const size_t len = transstr_len((const char *)s) + 1;
+ char *const buf = xmalloc(len);
+ transstr_buf(s, buf, len);
+ return buf;
}
/// Convert the string "str[orglen]" to do ignore-case comparing.
@@ -474,14 +517,16 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
-static char_u transchar_buf[7];
+static char_u transchar_buf[11];
-/// Translates a character
+/// Translate a character into a printable one, leaving printable ASCII intact
///
-/// @param c
+/// All unicode characters are considered non-printable in this function.
///
-/// @return translated character.
-char_u* transchar(int c)
+/// @param[in] c Character to translate.
+///
+/// @return translated character into a static buffer.
+char_u *transchar(int c)
{
int i = 0;
if (IS_SPECIAL(c)) {
@@ -494,23 +539,27 @@ char_u* transchar(int c)
if ((!chartab_initialized && (((c >= ' ') && (c <= '~'))
|| (p_altkeymap && F_ischar(c))))
- || ((c < 256) && vim_isprintc_strict(c))) {
+ || ((c <= 0xFF) && vim_isprintc_strict(c))) {
// printable character
transchar_buf[i] = (char_u)c;
transchar_buf[i + 1] = NUL;
- } else {
+ } else if (c <= 0xFF) {
transchar_nonprint(transchar_buf + i, c);
+ } else {
+ transchar_hex((char *)transchar_buf + i, c);
}
return transchar_buf;
}
-/// Like transchar(), but called with a byte instead of a character. Checks
-/// for an illegal UTF-8 byte.
+/// Like transchar(), but called with a byte instead of a character
///
-/// @param c
+/// Checks for an illegal UTF-8 byte.
+///
+/// @param[in] c Byte to translate.
///
/// @return pointer to translated character in transchar_buf.
-char_u* transchar_byte(int c)
+char_u *transchar_byte(const int c)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c >= 0x80) {
transchar_nonprint(transchar_buf, c);
@@ -519,12 +568,14 @@ char_u* transchar_byte(int c)
return transchar(c);
}
-/// Convert non-printable character to two or more printable characters in
-/// "buf[]". "buf" needs to be able to hold five bytes.
-/// Does NOT work for multi-byte characters, c must be <= 255.
+/// Convert non-printable characters to 2..4 printable ones
///
-/// @param buf
-/// @param c
+/// @warning Does not work for multi-byte characters, c must be <= 255.
+///
+/// @param[out] buf Buffer to store result in, must be able to hold at least
+/// 5 bytes (conversion result + NUL).
+/// @param[in] c Character to convert. NUL is assumed to be NL according to
+/// `:h NL-used-for-NUL`.
void transchar_nonprint(char_u *buf, int c)
{
if (c == NL) {
@@ -534,54 +585,63 @@ void transchar_nonprint(char_u *buf, int c)
// we use CR in place of NL in this case
c = NL;
}
+ assert(c <= 0xff);
- if (dy_flags & DY_UHEX) {
+ if (dy_flags & DY_UHEX || c > 0x7f) {
// 'display' has "uhex"
- transchar_hex(buf, c);
- } else if (c <= 0x7f) {
+ transchar_hex((char *)buf, c);
+ } else {
// 0x00 - 0x1f and 0x7f
buf[0] = '^';
// DEL displayed as ^?
buf[1] = (char_u)(c ^ 0x40);
buf[2] = NUL;
- } else {
- transchar_hex(buf, c);
}
}
-/// Convert a non-printable character to hex.
+/// Convert a non-printable character to hex C string like "<FFFF>"
///
-/// @param buf
-/// @param c
-void transchar_hex(char_u *buf, int c)
+/// @param[out] buf Buffer to store result in.
+/// @param[in] c Character to convert.
+///
+/// @return Number of bytes stored in buffer, excluding trailing NUL byte.
+size_t transchar_hex(char *const buf, const int c)
+ FUNC_ATTR_NONNULL_ALL
{
- int i = 0;
+ size_t i = 0;
- buf[0] = '<';
+ buf[i++] = '<';
if (c > 255) {
- buf[++i] = (char_u)nr2hex((unsigned)c >> 12);
- buf[++i] = (char_u)nr2hex((unsigned)c >> 8);
- }
- buf[++i] = (char_u)(nr2hex((unsigned)c >> 4));
- buf[++i] = (char_u)(nr2hex((unsigned)c));
- buf[++i] = '>';
- buf[++i] = NUL;
+ if (c > 255 * 256) {
+ buf[i++] = (char)nr2hex((unsigned)c >> 20);
+ buf[i++] = (char)nr2hex((unsigned)c >> 16);
+ }
+ buf[i++] = (char)nr2hex((unsigned)c >> 12);
+ buf[i++] = (char)nr2hex((unsigned)c >> 8);
+ }
+ buf[i++] = (char)(nr2hex((unsigned)c >> 4));
+ buf[i++] = (char)(nr2hex((unsigned)c));
+ buf[i++] = '>';
+ buf[i] = NUL;
+ return i;
}
-/// Convert the lower 4 bits of byte "c" to its hex character.
+/// Convert the lower 4 bits of byte "c" to its hex character
+///
/// Lower case letters are used to avoid the confusion of <F1> being 0xf1 or
/// function key 1.
///
-/// @param c
+/// @param[in] n Number to convert.
///
/// @return the hex character.
-static unsigned nr2hex(unsigned c)
+static inline unsigned nr2hex(unsigned n)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
- if ((c & 0xf) <= 9) {
- return (c & 0xf) + '0';
+ if ((n & 0xf) <= 9) {
+ return (n & 0xf) + '0';
}
- return (c & 0xf) - 10 + 'a';
+ return (n & 0xf) - 10 + 'a';
}
/// Return number of display cells occupied by byte "b".
@@ -863,7 +923,7 @@ bool vim_isprintc(int c)
if (c >= 0x100) {
return utf_printable(c);
}
- return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR));
+ return c > 0 && (g_chartab[c] & CT_PRINT_CHAR);
}
/// Strict version of vim_isprintc(c), don't return true if "c" is the head
@@ -1671,7 +1731,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
&& !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1];
- // Detect hexadecimal: 0x or 0X follwed by hex digit
+ // Detect hexadecimal: 0x or 0X followed by hex digit.
if ((what & STR2NR_HEX)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x')
@@ -1679,7 +1739,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr += 2;
goto vim_str2nr_hex;
}
- // Detect binary: 0b or 0B follwed by 0 or 1
+ // Detect binary: 0b or 0B followed by 0 or 1.
if ((what & STR2NR_BIN)
&& !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b')
@@ -1687,7 +1747,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr += 2;
goto vim_str2nr_bin;
}
- // Detect octal number: zero followed by octal digits without '8' or '9'
+ // Detect octal number: zero followed by octal digits without '8' or '9'.
pre = 0;
if (!(what & STR2NR_OCT)
|| !('0' <= ptr[1] && ptr[1] <= '7')) {
@@ -1718,32 +1778,21 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr++; \
} \
} while (0)
- switch (pre) {
- case 'b':
- case 'B': {
vim_str2nr_bin:
- PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
- break;
- }
- case '0': {
+ PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
+ goto vim_str2nr_proceed;
vim_str2nr_oct:
- PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
- break;
- }
- case 0: {
+ PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
+ goto vim_str2nr_proceed;
vim_str2nr_dec:
- PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
- break;
- }
- case 'x':
- case 'X': {
+ PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
+ goto vim_str2nr_proceed;
vim_str2nr_hex:
- PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
- break;
- }
- }
+ PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
+ goto vim_str2nr_proceed;
#undef PARSE_NUMBER
+vim_str2nr_proceed:
if (prep != NULL) {
*prep = pre;
}
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index 97fc3a3ca3..b45e7002f7 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -102,11 +102,14 @@ char_u *parse_shape_opt(int what)
}
while (*modep != NUL) {
colonp = vim_strchr(modep, ':');
- if (colonp == NULL)
+ commap = vim_strchr(modep, ',');
+
+ if (colonp == NULL || (commap != NULL && commap < colonp)) {
return (char_u *)N_("E545: Missing colon");
- if (colonp == modep)
+ }
+ if (colonp == modep) {
return (char_u *)N_("E546: Illegal mode");
- commap = vim_strchr(modep, ',');
+ }
// Repeat for all modes before the colon.
// For the 'a' mode, we loop to handle all the modes.
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 0ee1c3815d..f9e40ed06f 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -859,9 +859,9 @@ void ex_diffpatch(exarg_T *eap)
char_u *esc_name = NULL;
#ifdef UNIX
- char_u dirbuf[MAXPATHL];
- char_u *fullname = NULL;
+ char *fullname = NULL;
#endif
+
// We need two temp file names.
// Name of original temp file.
char_u *tmp_orig = vim_tempname();
@@ -881,21 +881,17 @@ void ex_diffpatch(exarg_T *eap)
#ifdef UNIX
// Get the absolute path of the patchfile, changing directory below.
- fullname = (char_u *)FullName_save((char *)eap->arg, false);
-#endif
-
+ fullname = FullName_save((char *)eap->arg, false);
esc_name = vim_strsave_shellescape(
-#ifdef UNIX
- fullname != NULL ? fullname :
+ (fullname != NULL ? (char_u *)fullname : eap->arg), true, true);
+#else
+ esc_name = vim_strsave_shellescape(eap->arg, true, true);
#endif
- eap->arg, true, true);
- if (esc_name == NULL) {
- goto theend;
- }
size_t buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16;
buf = xmalloc(buflen);
#ifdef UNIX
+ char_u dirbuf[MAXPATHL];
// Temporarily chdir to /tmp, to avoid patching files in the current
// directory when the patch file contains more than one patch. When we
// have our own temp dir use that instead, it will be cleaned up when we
@@ -918,7 +914,7 @@ void ex_diffpatch(exarg_T *eap)
// Use 'patchexpr' to generate the new file.
#ifdef UNIX
eval_patch((char *)tmp_orig,
- (char *)(fullname != NULL ? fullname : eap->arg),
+ (fullname != NULL ? fullname : (char *)eap->arg),
(char *)tmp_new);
#else
eval_patch((char *)tmp_orig, (char *)eap->arg, (char *)tmp_new);
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index e3d5ca07d1..6dbb0d05e0 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1700,6 +1700,9 @@ static void printdigraph(digr_T *dp)
*p++ = dp->char1;
*p++ = dp->char2;
*p++ = ' ';
+ *p = NUL;
+ msg_outtrans(buf);
+ p = buf;
// add a space to draw a composing char on
if (utf_iscomposing(dp->result)) {
@@ -1707,6 +1710,9 @@ static void printdigraph(digr_T *dp)
}
p += (*mb_char2bytes)(dp->result, p);
+ *p = NUL;
+ msg_outtrans_attr(buf, hl_attr(HLF_8));
+ p = buf;
if (char2cells(dp->result) == 1) {
*p++ = ' ';
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index cf4328fe0a..a1987cf2d5 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -847,7 +847,7 @@ static int insert_handle_key(InsertState *s)
case ' ':
- if (mod_mask != 4) {
+ if (mod_mask != MOD_MASK_CTRL) {
goto normalchar;
}
// FALLTHROUGH
@@ -974,6 +974,10 @@ static int insert_handle_key(InsertState *s)
multiqueue_process_events(main_loop.events);
break;
+ case K_COMMAND: // some command
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
+
case K_HOME: // <Home>
case K_KHOME:
case K_S_HOME:
@@ -1176,6 +1180,14 @@ static int insert_handle_key(InsertState *s)
normalchar:
// Insert a normal character.
+
+ if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) {
+ // Unmapped ALT/META chord behaves like ESC+c. #8213
+ stuffcharReadbuff(ESC);
+ stuffcharReadbuff(s->c);
+ break;
+ }
+
if (!p_paste) {
// Trigger InsertCharPre.
char_u *str = do_insert_char_pre(s->c);
@@ -1428,7 +1440,7 @@ static void ins_ctrl_v(void)
* line and will not removed by the redraw */
edit_unputchar();
clear_showcmd();
- insert_special(c, FALSE, TRUE);
+ insert_special(c, true, true);
revins_chars++;
revins_legal++;
}
@@ -3611,6 +3623,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
memset(cptext, 0, sizeof(cptext));
}
if (word == NULL || (!aempty && *word == NUL)) {
+ for (size_t i = 0; i < CPT_COUNT; i++) {
+ xfree(cptext[i]);
+ }
return FAIL;
}
return ins_compl_add((char_u *)word, -1, icase, NULL,
@@ -5050,13 +5065,11 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
char_u *p;
int len;
- /*
- * Special function key, translate into "<Key>". Up to the last '>' is
- * inserted with ins_str(), so as not to replace characters in replace
- * mode.
- * Only use mod_mask for special keys, to avoid things like <S-Space>,
- * unless 'allow_modmask' is TRUE.
- */
+ // Special function key, translate into "<Key>". Up to the last '>' is
+ // inserted with ins_str(), so as not to replace characters in replace
+ // mode.
+ // Only use mod_mask for special keys, to avoid things like <S-Space>,
+ // unless 'allow_modmask' is TRUE.
if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key.
allow_modmask = true;
}
@@ -5252,7 +5265,7 @@ insertchar (
// - need to check for abbreviation: A non-word char after a word-char
while ((c = vpeekc()) != NUL
&& !ISSPECIAL(c)
- && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
+ && MB_BYTE2LEN(c) == 1
&& i < INPUT_BUFLEN
&& !(p_fkmap && KeyTyped) // Farsi mode mapping moves cursor
&& (textwidth == 0
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 4140eebdf6..a3540b3153 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2682,19 +2682,21 @@ void ex_call(exarg_T *eap)
return;
}
- tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
+ tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial);
if (fudi.fd_newkey != NULL) {
- /* Still need to give an error message for missing key. */
+ // Still need to give an error message for missing key.
EMSG2(_(e_dictkey), fudi.fd_newkey);
xfree(fudi.fd_newkey);
}
- if (tofree == NULL)
+ if (tofree == NULL) {
return;
+ }
- /* Increase refcount on dictionary, it could get deleted when evaluating
- * the arguments. */
- if (fudi.fd_dict != NULL)
- ++fudi.fd_dict->dv_refcount;
+ // Increase refcount on dictionary, it could get deleted when evaluating
+ // the arguments.
+ if (fudi.fd_dict != NULL) {
+ fudi.fd_dict->dv_refcount++;
+ }
// If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
// contents. For VAR_PARTIAL get its partial, unless we already have one
@@ -2703,8 +2705,8 @@ void ex_call(exarg_T *eap)
name = deref_func_name((const char *)tofree, &len,
partial != NULL ? NULL : &partial, false);
- /* Skip white space to allow ":call func ()". Not good, but required for
- * backward compatibility. */
+ // Skip white space to allow ":call func ()". Not good, but required for
+ // backward compatibility.
startarg = skipwhite(arg);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
@@ -2713,20 +2715,9 @@ void ex_call(exarg_T *eap)
goto end;
}
- /*
- * When skipping, evaluate the function once, to find the end of the
- * arguments.
- * When the function takes a range, this is discovered after the first
- * call, and the loop is broken.
- */
- if (eap->skip) {
- emsg_skip++;
- lnum = eap->line2; // Do it once, also with an invalid range.
- } else {
- lnum = eap->line1;
- }
+ lnum = eap->line1;
for (; lnum <= eap->line2; lnum++) {
- if (!eap->skip && eap->addr_count > 0) { // -V560
+ if (eap->addr_count > 0) { // -V560
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
@@ -2734,40 +2725,40 @@ void ex_call(exarg_T *eap)
arg = startarg;
if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
eap->line1, eap->line2, &doesrange,
- !eap->skip, partial, fudi.fd_dict) == FAIL) {
+ true, partial, fudi.fd_dict) == FAIL) {
failed = true;
break;
}
// Handle a function returning a Funcref, Dictionary or List.
- if (handle_subscript((const char **)&arg, &rettv, !eap->skip, true)
+ if (handle_subscript((const char **)&arg, &rettv, true, true)
== FAIL) {
failed = true;
break;
}
tv_clear(&rettv);
- if (doesrange || eap->skip) { // -V560
+ if (doesrange) {
break;
}
- /* Stop when immediately aborting on error, or when an interrupt
- * occurred or an exception was thrown but not caught.
- * get_func_tv() returned OK, so that the check for trailing
- * characters below is executed. */
- if (aborting())
+ // Stop when immediately aborting on error, or when an interrupt
+ // occurred or an exception was thrown but not caught.
+ // get_func_tv() returned OK, so that the check for trailing
+ // characters below is executed.
+ if (aborting()) {
break;
+ }
}
- if (eap->skip)
- --emsg_skip;
if (!failed) {
- /* Check for trailing illegal characters and a following command. */
+ // Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
emsg_severe = TRUE;
EMSG(_(e_trailing));
- } else
+ } else {
eap->nextcmd = check_nextcmd(arg);
+ }
}
end:
@@ -5807,8 +5798,8 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
lambda_no++;
snprintf((char *)name, sizeof(name), "<lambda>%d", lambda_no);
- fp = (ufunc_T *)xcalloc(1, sizeof(ufunc_T) + STRLEN(name));
- pt = (partial_T *)xcalloc(1, sizeof(partial_T));
+ fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ pt = xcalloc(1, sizeof(partial_T));
ga_init(&newlines, (int)sizeof(char_u *), 1);
ga_grow(&newlines, 1);
@@ -6250,20 +6241,21 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
/// invoked function uses them. It is called like this:
/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
///
-/// Return FAIL when the function can't be called, OK otherwise.
-/// Also returns OK when an error was encountered while executing the function.
+/// @return FAIL if function cannot be called, else OK (even if an error
+/// occurred while executing the function! Set `msg_list` to capture
+/// the error, see do_cmdline()).
int
call_func(
const char_u *funcname, // name of the function
int len, // length of "name"
- typval_T *rettv, // return value goes here
+ typval_T *rettv, // [out] value goes here
int argcount_in, // number of "argvars"
typval_T *argvars_in, // vars for arguments, must have "argcount"
// PLUS ONE elements!
ArgvFunc argv_func, // function to fill in argvars
linenr_T firstline, // first line of range
linenr_T lastline, // last line of range
- int *doesrange, // return: function handled range
+ int *doesrange, // [out] function handled range
bool evaluate,
partial_T *partial, // optional, can be NULL
dict_T *selfdict_in // Dictionary for "self"
@@ -6437,21 +6429,25 @@ call_func(
return ret;
}
-/*
- * Give an error message with a function name. Handle <SNR> things.
- * "ermsg" is to be passed without translation, use N_() instead of _().
- */
+/// Give an error message with a function name. Handle <SNR> things.
+///
+/// @param ermsg must be passed without translation (use N_() instead of _()).
+/// @param name function name
static void emsg_funcname(char *ermsg, char_u *name)
{
- char_u *p;
+ char_u *p;
- if (*name == K_SPECIAL)
+ if (*name == K_SPECIAL) {
p = concat_str((char_u *)"<SNR>", name + 3);
- else
+ } else {
p = name;
+ }
+
EMSG2(_(ermsg), p);
- if (p != name)
+
+ if (p != name) {
xfree(p);
+ }
}
/*
@@ -13496,7 +13492,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
q[-1] = NUL;
q = (char *)path_tail((char_u *)p);
}
- if (q > p && !path_is_absolute_path((const char_u *)buf)) {
+ if (q > p && !path_is_absolute((const char_u *)buf)) {
// Symlink is relative to directory of argument. Replace the
// symlink with the resolved name in the same directory.
const size_t p_len = strlen(p);
@@ -13814,7 +13810,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
scid_T save_current_SID;
uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match;
linenr_T save_sourcing_lnum;
- int save_autocmd_fname_full, save_autocmd_bufnr;
+ int save_autocmd_bufnr;
void *save_funccalp;
if (l_provider_call_nesting) {
@@ -13825,16 +13821,14 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
save_sourcing_lnum = sourcing_lnum;
save_autocmd_fname = autocmd_fname;
save_autocmd_match = autocmd_match;
- save_autocmd_fname_full = autocmd_fname_full;
save_autocmd_bufnr = autocmd_bufnr;
save_funccalp = save_funccal();
- //
+
current_SID = provider_caller_scope.SID;
sourcing_name = provider_caller_scope.sourcing_name;
sourcing_lnum = provider_caller_scope.sourcing_lnum;
autocmd_fname = provider_caller_scope.autocmd_fname;
autocmd_match = provider_caller_scope.autocmd_match;
- autocmd_fname_full = provider_caller_scope.autocmd_fname_full;
autocmd_bufnr = provider_caller_scope.autocmd_bufnr;
restore_funccal(provider_caller_scope.funccalp);
}
@@ -13850,7 +13844,6 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
sourcing_lnum = save_sourcing_lnum;
autocmd_fname = save_autocmd_fname;
autocmd_match = save_autocmd_match;
- autocmd_fname_full = save_autocmd_fname_full;
autocmd_bufnr = save_autocmd_bufnr;
restore_funccal(save_funccalp);
}
@@ -14406,8 +14399,11 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
if (argvars[0].vval.v_string) {
- server_stop((char *) argvars[0].vval.v_string);
+ bool rv = server_stop((char *)argvars[0].vval.v_string);
+ rettv->vval.v_number = (rv ? 1 : 0);
}
}
@@ -15456,7 +15452,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
; li != NULL;) {
listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li);
if (item_compare_func_ptr(&prev_li, &li) == 0) {
- if (info.item_compare_func_err) {
+ if (info.item_compare_func_err) { // -V547
EMSG(_("E882: Uniq compare function failed"));
break;
}
@@ -15630,7 +15626,6 @@ f_spellsuggest_return:
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- regmatch_T regmatch;
char_u *save_cpo;
int match;
colnr_T col = 0;
@@ -15663,9 +15658,13 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING);
+ regmatch_T regmatch = {
+ .regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING),
+ .startp = { NULL },
+ .endp = { NULL },
+ .rm_ic = false,
+ };
if (regmatch.regprog != NULL) {
- regmatch.rm_ic = FALSE;
while (*str != NUL || keepempty) {
if (*str == NUL) {
match = false; // Empty item at the end.
@@ -15684,8 +15683,9 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
&& end < (const char *)regmatch.endp[0])) {
tv_list_append_string(rettv->vval.v_list, str, end - str);
}
- if (!match)
+ if (!match) {
break;
+ }
// Advance to just after the match.
if (regmatch.endp[0] > (char_u *)str) {
col = 0;
@@ -15702,6 +15702,56 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p_cpo = save_cpo;
}
+/// "stdpath()" helper for list results
+static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const void *iter = NULL;
+ list_T *const list = tv_list_alloc(kListLenShouldKnow);
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = list;
+ tv_list_ref(list);
+ char *const dirs = stdpaths_get_xdg_var(xdg);
+ do {
+ size_t dir_len;
+ const char *dir;
+ iter = vim_env_iter(':', dirs, iter, &dir, &dir_len);
+ if (dir != NULL && dir_len > 0) {
+ char *dir_with_nvim = xmemdupz(dir, dir_len);
+ dir_with_nvim = concat_fnames_realloc(dir_with_nvim, "nvim", true);
+ tv_list_append_string(list, dir_with_nvim, strlen(dir_with_nvim));
+ xfree(dir_with_nvim);
+ }
+ } while (iter != NULL);
+ xfree(dirs);
+}
+
+/// "stdpath(type)" function
+static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ const char *const p = tv_get_string_chk(&argvars[0]);
+ if (p == NULL) {
+ return; // Type error; errmsg already given.
+ }
+
+ if (strcmp(p, "config") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGConfigHome);
+ } else if (strcmp(p, "data") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGDataHome);
+ } else if (strcmp(p, "cache") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGCacheHome);
+ } else if (strcmp(p, "config_dirs") == 0) {
+ get_xdg_var_list(kXDGConfigDirs, rettv);
+ } else if (strcmp(p, "data_dirs") == 0) {
+ get_xdg_var_list(kXDGDataDirs, rettv);
+ } else {
+ EMSG2(_("E6100: \"%s\" is not a valid stdpath"), p);
+ }
+}
+
/*
* "str2float()" function
*/
@@ -16093,7 +16143,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = transstr((char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]));
}
/*
@@ -16864,6 +16914,12 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr)
int paused = (bool)tv_get_number(&argvars[1]);
timer_T *timer = pmap_get(uint64_t)(timers, tv_get_number(&argvars[0]));
if (timer != NULL) {
+ if (!timer->paused && paused) {
+ time_watcher_stop(&timer->tw);
+ } else if (timer->paused && !paused) {
+ time_watcher_start(&timer->tw, timer_due_cb, timer->timeout,
+ timer->timeout);
+ }
timer->paused = paused;
}
}
@@ -16983,7 +17039,8 @@ static void timer_stop(timer_T *timer)
time_watcher_close(&timer->tw, timer_close_cb);
}
-// invoked on next event loop tick, so queue is empty
+// This will be run on the main loop after the last timer_due_cb, so at this
+// point it is safe to free the callback.
static void timer_close_cb(TimeWatcher *tw, void *data)
{
timer_T *timer = (timer_T *)data;
@@ -18725,7 +18782,7 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len,
if (name_len == 0) {
return NULL;
}
- if (name_len == 1 || (name_len >= 2 && name[1] != ':')) {
+ if (name_len == 1 || name[1] != ':') {
// name has implicit scope
if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
// The name must not start with a colon or #.
@@ -20056,7 +20113,7 @@ void ex_function(exarg_T *eap)
}
}
- fp = xcalloc(1, sizeof(ufunc_T) + STRLEN(name));
+ fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
if (fudi.fd_dict != NULL) {
if (fudi.fd_di == NULL) {
@@ -20811,8 +20868,9 @@ char_u *get_user_func_name(expand_T *xp, int idx)
return (char_u *)""; // don't show dict and lambda functions
}
- if (STRLEN(fp->uf_name) + 4 >= IOSIZE)
- return fp->uf_name; /* prevents overflow */
+ if (STRLEN(fp->uf_name) + 4 >= IOSIZE) {
+ return fp->uf_name; // Prevent overflow.
+ }
cat_func_name(IObuff, fp);
if (xp->xp_context != EXPAND_USER_FUNC) {
@@ -22009,12 +22067,27 @@ int store_session_globals(FILE *fd)
*/
void last_set_msg(scid_T scriptID)
{
- if (scriptID != 0) {
- char_u *p = home_replace_save(NULL, get_scriptname(scriptID));
+ const LastSet last_set = (LastSet){
+ .script_id = scriptID,
+ .channel_id = 0,
+ };
+ option_last_set_msg(last_set);
+}
+
+/// Displays where an option was last set.
+///
+/// Should only be invoked when 'verbose' is non-zero.
+void option_last_set_msg(LastSet last_set)
+{
+ if (last_set.script_id != 0) {
+ bool should_free;
+ char_u *p = get_scriptname(last_set, &should_free);
verbose_enter();
MSG_PUTS(_("\n\tLast set from "));
MSG_PUTS(p);
- xfree(p);
+ if (should_free) {
+ xfree(p);
+ }
verbose_leave();
}
}
@@ -22448,7 +22521,6 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
.sourcing_lnum = sourcing_lnum,
.autocmd_fname = autocmd_fname,
.autocmd_match = autocmd_match,
- .autocmd_fname_full = autocmd_fname_full,
.autocmd_bufnr = autocmd_bufnr,
.funccalp = save_funccal()
};
@@ -22481,7 +22553,8 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
restore_funccal(provider_caller_scope.funccalp);
provider_caller_scope = saved_provider_caller_scope;
provider_call_nesting--;
-
+ assert(provider_call_nesting >= 0);
+
return rettv;
}
@@ -22521,11 +22594,13 @@ bool eval_has_provider(const char *name)
}
/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
-void eval_format_source_name_line(char *buf, size_t bufsize)
+void eval_fmt_source_name_line(char *buf, size_t bufsize)
{
- snprintf(buf, bufsize, "%s:%" PRIdLINENR,
- (sourcing_name ? sourcing_name : (char_u *)"?"),
- (sourcing_name ? sourcing_lnum : 0));
+ if (sourcing_name) {
+ snprintf(buf, bufsize, "%s:%" PRIdLINENR, sourcing_name, sourcing_lnum);
+ } else {
+ snprintf(buf, bufsize, "?");
+ }
}
/// ":checkhealth [plugins]"
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index b798eae187..149dae688e 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -10,6 +10,7 @@
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/channel.h"
+#include "nvim/os/stdpaths_defs.h"
#define COPYID_INC 2
#define COPYID_MASK (~0x1)
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index daa3b637a3..801d2cc468 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -280,6 +280,7 @@ return {
spellsuggest={args={1, 3}},
split={args={1, 3}},
sqrt={args=1, func="float_op_wrapper", data="&sqrt"},
+ stdpath={args=1},
str2float={args=1},
str2nr={args={1, 2}},
strcharpart={args={2, 3}},
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 17799b500c..4d75c7bda1 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -985,7 +985,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
break;
}
case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
- if (mobj.via.i64 >= VARNUMBER_MIN) {
+ if (mobj.via.i64 >= VARNUMBER_MIN) { // -V547
*rettv = (typval_T) {
.v_type = VAR_NUMBER,
.v_lock = VAR_UNLOCKED,
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index c8b550f902..7930653be0 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2825,7 +2825,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
{
switch (tv->v_type) {
case VAR_NUMBER: {
- snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number);
+ snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); // -V576
return buf;
}
case VAR_STRING: {
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 40a1738d9e..33e2aa6b61 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -197,20 +197,11 @@ typedef struct {
}, \
}
-// Structure to hold an item of a Dictionary.
-// Also used for a variable.
-// The key is copied into "di_key" to avoid an extra alloc/free for it.
-struct dictitem_S {
- typval_T di_tv; ///< type and value of the variable
- char_u di_flags; ///< flags (only used for variable)
- char_u di_key[1]; ///< key (actually longer!)
-};
-
-#define TV_DICTITEM_STRUCT(KEY_LEN) \
+#define TV_DICTITEM_STRUCT(...) \
struct { \
typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
uint8_t di_flags; /* Flags. */ \
- char_u di_key[KEY_LEN]; /* Key value. */ \
+ char_u di_key[__VA_ARGS__]; /* Key value. */ \
}
/// Structure to hold a scope dictionary
@@ -286,9 +277,8 @@ struct ufunc {
///< used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
- char_u uf_name[1]; ///< name of function (actually longer); can
- ///< start with <SNR>123_ (<SNR> is K_SPECIAL
- ///< KS_EXTRA KE_SNR)
+ char_u uf_name[]; ///< Name of function; can start with <SNR>123_
+ ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
};
/// Maximum number of function arguments
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index f2d0d7265f..4556ce8193 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -340,8 +340,9 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_PARTIAL: {
partial_T *const pt = tv->vval.v_partial;
(void)pt;
- TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt)));
- _mp_push(*mpstack, ((MPConvStackVal) {
+ TYPVAL_ENCODE_CONV_FUNC_START( // -V547
+ tv, (pt == NULL ? NULL : partial_name(pt)));
+ _mp_push(*mpstack, ((MPConvStackVal) { // -V779
.type = kMPConvPartial,
.tv = tv,
.saved_copyID = copyID - 1,
@@ -541,7 +542,8 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
}
list_T *const val_list = val_di->di_tv.vval.v_list;
if (val_list == NULL || tv_list_len(val_list) == 0) {
- TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR);
+ TYPVAL_ENCODE_CONV_EMPTY_DICT( // -V501
+ tv, TYPVAL_ENCODE_NODICT_VAR);
break;
}
TV_LIST_ITER_CONST(val_list, li, {
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index c101cb1bb9..ffe2db9b76 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -26,15 +26,18 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvopts.file = proc->argv[0];
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
- if (proc->detach) {
- uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
- }
#ifdef WIN32
// libuv collapses the argv to a CommandLineToArgvW()-style string. cmd.exe
// expects a different syntax (must be prepared by the caller before now).
if (os_shell_is_cmdexe(proc->argv[0])) {
uvproc->uvopts.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
}
+ if (proc->detach) {
+ uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
+ }
+#else
+ // Always setsid() on unix-likes. #8107
+ uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
#endif
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = proc->cwd;
@@ -48,12 +51,19 @@ int libuv_process_spawn(LibuvProcess *uvproc)
if (!proc->in.closed) {
uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+#ifdef WIN32
+ uvproc->uvstdio[0].flags |= UV_OVERLAPPED_PIPE;
+#endif
uvproc->uvstdio[0].data.stream = STRUCT_CAST(uv_stream_t,
&proc->in.uv.pipe);
}
if (!proc->out.closed) {
uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+#ifdef WIN32
+ // pipe must be readable for IOCP to work.
+ uvproc->uvstdio[1].flags |= UV_READABLE_PIPE | UV_OVERLAPPED_PIPE;
+#endif
uvproc->uvstdio[1].data.stream = STRUCT_CAST(uv_stream_t,
&proc->out.uv.pipe);
}
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index d92464f17b..7998e0b8d0 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -21,7 +21,6 @@ void loop_init(Loop *loop, void *data)
loop->recursive = 0;
loop->uv.data = loop;
loop->children = kl_init(WatcherPtr);
- loop->children_stop_requests = 0;
loop->events = multiqueue_new_parent(loop_on_put, loop);
loop->fast_events = multiqueue_new_child(loop->events);
loop->thread_events = multiqueue_new_parent(NULL, NULL);
diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h
index d1a40d5cc9..f5dd23ac8b 100644
--- a/src/nvim/event/loop.h
+++ b/src/nvim/event/loop.h
@@ -37,7 +37,6 @@ typedef struct loop {
// generic timer, used by loop_poll_events()
uv_timer_t poll_timer;
- size_t children_stop_requests;
uv_async_t async;
uv_mutex_t mutex;
int recursive;
@@ -53,6 +52,8 @@ typedef struct loop {
} \
} while (0)
+// -V:LOOP_PROCESS_EVENTS_UNTIL:547
+
// Poll for events until a condition or timeout
#define LOOP_PROCESS_EVENTS_UNTIL(loop, multiqueue, timeout, condition) \
do { \
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index a06f5f4ff3..7a8a39dbcf 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -12,6 +12,7 @@
#include "nvim/event/wstream.h"
#include "nvim/event/process.h"
#include "nvim/event/libuv_process.h"
+#include "nvim/os/process.h"
#include "nvim/os/pty_process.h"
#include "nvim/globals.h"
#include "nvim/macros.h"
@@ -22,7 +23,7 @@
#endif
// Time for a process to exit cleanly before we send KILL.
-// For pty processes SIGTERM is sent first (in case SIGHUP was not enough).
+// For PTY processes SIGTERM is sent first (in case SIGHUP was not enough).
#define KILL_TIMEOUT_MS 2000
static bool process_is_tearing_down = false;
@@ -110,6 +111,7 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
proc->internal_close_cb = decref;
proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc);
+ DLOG("new: pid=%d argv=[%s]", proc->pid, *proc->argv);
return 0;
}
@@ -187,8 +189,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
}
if (proc->refcount == 1) {
- // Job exited, collect status and manually invoke close_cb to free the job
- // resources
+ // Job exited, free its resources.
decref(proc);
if (events) {
// the decref call created an exit event, process it now
@@ -204,19 +205,19 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
/// Ask a process to terminate and eventually kill if it doesn't respond
void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
{
- if (proc->stopped_time) {
+ bool exited = (proc->status >= 0);
+ if (exited || proc->stopped_time) {
return;
}
-
proc->stopped_time = os_hrtime();
+
switch (proc->type) {
case kProcessTypeUv:
// Close the process's stdin. If the process doesn't close its own
// stdout/stderr, they will be closed when it exits(possibly due to being
// terminated after a timeout)
stream_may_close(&proc->in);
- ILOG("Sending SIGTERM to pid %d", proc->pid);
- uv_kill(proc->pid, SIGTERM);
+ os_proc_tree_kill(proc->pid, SIGTERM);
break;
case kProcessTypePty:
// close all streams for pty processes to send SIGHUP to the process
@@ -227,37 +228,32 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
abort();
}
- Loop *loop = proc->loop;
- if (!loop->children_stop_requests++) {
- // When there's at least one stop request pending, start a timer that
- // will periodically check if a signal should be send to the job.
- ILOG("Starting job kill timer");
- uv_timer_start(&loop->children_kill_timer, children_kill_cb,
- KILL_TIMEOUT_MS, KILL_TIMEOUT_MS);
- }
+ // (Re)start timer to verify that stopped process(es) died.
+ uv_timer_start(&proc->loop->children_kill_timer, children_kill_cb,
+ KILL_TIMEOUT_MS, 0);
}
-/// Iterates the process list sending SIGTERM to stopped processes and SIGKILL
-/// to those that didn't die from SIGTERM after a while(exit_timeout is 0).
+/// Sends SIGKILL (or SIGTERM..SIGKILL for PTY jobs) to processes that did
+/// not terminate after process_stop().
static void children_kill_cb(uv_timer_t *handle)
{
Loop *loop = handle->loop->data;
- uint64_t now = os_hrtime();
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
- if (!proc->stopped_time) {
+ bool exited = (proc->status >= 0);
+ if (exited || !proc->stopped_time) {
continue;
}
- uint64_t elapsed = (now - proc->stopped_time) / 1000000 + 1;
-
- if (elapsed >= KILL_TIMEOUT_MS) {
- int sig = proc->type == kProcessTypePty && elapsed < KILL_TIMEOUT_MS * 2
- ? SIGTERM
- : SIGKILL;
- ILOG("Sending %s to pid %d", sig == SIGTERM ? "SIGTERM" : "SIGKILL",
- proc->pid);
- uv_kill(proc->pid, sig);
+ uint64_t term_sent = UINT64_MAX == proc->stopped_time;
+ if (kProcessTypePty != proc->type || term_sent) {
+ os_proc_tree_kill(proc->pid, SIGKILL);
+ } else {
+ os_proc_tree_kill(proc->pid, SIGTERM);
+ proc->stopped_time = UINT64_MAX; // Flag: SIGTERM was sent.
+ // Restart timer.
+ uv_timer_start(&proc->loop->children_kill_timer, children_kill_cb,
+ KILL_TIMEOUT_MS, 0);
}
}
}
@@ -269,7 +265,7 @@ static void process_close_event(void **argv)
if (proc->type == kProcessTypePty) {
xfree(((PtyProcess *)proc)->term_name);
}
- if (proc->cb) {
+ if (proc->cb) { // "on_exit" for jobstart(). See channel_job_start().
proc->cb(proc, proc->status, proc->data);
}
}
@@ -360,7 +356,7 @@ static void flush_stream(Process *proc, Stream *stream)
}
// Stream can be closed if it is empty.
- if (num_bytes == stream->num_bytes) {
+ if (num_bytes == stream->num_bytes) { // -V547
if (stream->read_cb && !stream->did_eof) {
// Stream callback could miss EOF handling if a child keeps the stream
// open. But only send EOF if we haven't already.
@@ -385,12 +381,8 @@ static void process_close_handles(void **argv)
static void on_process_exit(Process *proc)
{
Loop *loop = proc->loop;
- if (proc->stopped_time && loop->children_stop_requests
- && !--loop->children_stop_requests) {
- // Stop the timer if no more stop requests are pending
- DLOG("Stopping process kill timer");
- uv_timer_stop(&loop->children_kill_timer);
- }
+ ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status,
+ proc->stopped_time);
// Process has terminated, but there could still be data to be read from the
// OS. We are still in the libuv loop, so we cannot call code that polls for
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 033ce3604b..ba2c2a6a11 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -19,8 +19,7 @@ struct process {
Loop *loop;
void *data;
int pid, status, refcount;
- // set to the hrtime of when process_stop was called for the process.
- uint64_t stopped_time;
+ uint64_t stopped_time; // process_stop() timestamp
const char *cwd;
char **argv;
Stream in, out, err;
diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c
index 80289c27d1..b7e30e392b 100644
--- a/src/nvim/event/time.c
+++ b/src/nvim/event/time.c
@@ -61,10 +61,17 @@ static void time_watcher_cb(uv_timer_t *handle)
CREATE_EVENT(watcher->events, time_event, 1, watcher);
}
+static void close_event(void **argv)
+{
+ TimeWatcher *watcher = argv[0];
+ watcher->close_cb(watcher, watcher->data);
+}
+
static void close_cb(uv_handle_t *handle)
+ FUNC_ATTR_NONNULL_ALL
{
TimeWatcher *watcher = handle->data;
if (watcher->close_cb) {
- watcher->close_cb(watcher, watcher->data);
+ CREATE_EVENT(watcher->events, close_event, 1, watcher);
}
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index c396b5891a..f575d58f05 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -109,82 +109,86 @@ typedef struct {
# include "ex_cmds.c.generated.h"
#endif
-/*
- * ":ascii" and "ga".
- */
-void do_ascii(exarg_T *eap)
+/// ":ascii" and "ga" implementation
+void do_ascii(const exarg_T *const eap)
{
- int c;
- int cval;
- char buf1[20];
- char buf2[20];
- char_u buf3[7];
int cc[MAX_MCO];
- int ci = 0;
- int len;
- const bool l_enc_utf8 = enc_utf8;
-
- if (l_enc_utf8)
- c = utfc_ptr2char(get_cursor_pos_ptr(), cc);
- else
- c = gchar_cursor();
+ int c = utfc_ptr2char(get_cursor_pos_ptr(), cc);
if (c == NUL) {
MSG("NUL");
return;
}
- IObuff[0] = NUL;
- if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80) {
- if (c == NL) /* NUL is stored as NL */
+ size_t iobuff_len = 0;
+
+ int ci = 0;
+ if (c < 0x80) {
+ if (c == NL) { // NUL is stored as NL.
c = NUL;
- if (c == CAR && get_fileformat(curbuf) == EOL_MAC)
- cval = NL; /* NL is stored as CR */
- else
- cval = c;
- if (vim_isprintc_strict(c) && (c < ' '
- || c > '~'
- )) {
+ }
+ const int cval = (c == CAR && get_fileformat(curbuf) == EOL_MAC
+ ? NL // NL is stored as CR.
+ : c);
+ char buf1[20];
+ if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) {
+ char_u buf3[7];
transchar_nonprint(buf3, c);
vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
- } else
+ } else {
buf1[0] = NUL;
- if (c >= 0x80)
- vim_snprintf(buf2, sizeof(buf2), " <M-%s>",
- (char *)transchar(c & 0x7f));
- else
- buf2[0] = NUL;
- vim_snprintf((char *)IObuff, IOSIZE,
- _("<%s>%s%s %d, Hex %02x, Octal %03o"),
- transchar(c), buf1, buf2, cval, cval, cval);
- if (l_enc_utf8)
- c = cc[ci++];
- else
- c = 0;
- }
-
- /* Repeat for combining characters. */
- while (has_mbyte && (c >= 0x100 || (l_enc_utf8 && c >= 0x80))) {
- len = (int)STRLEN(IObuff);
- /* This assumes every multi-byte char is printable... */
- if (len > 0)
- IObuff[len++] = ' ';
- IObuff[len++] = '<';
- if (l_enc_utf8 && utf_iscomposing(c)
-# ifdef USE_GUI
- && !gui.in_use
-# endif
- )
- IObuff[len++] = ' '; /* draw composing char on top of a space */
- len += (*mb_char2bytes)(c, IObuff + len);
- vim_snprintf((char *)IObuff + len, IOSIZE - len,
- c < 0x10000 ? _("> %d, Hex %04x, Octal %o")
- : _("> %d, Hex %08x, Octal %o"), c, c, c);
- if (ci == MAX_MCO)
+ }
+ char buf2[20];
+ buf2[0] = NUL;
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len,
+ _("<%s>%s%s %d, Hex %02x, Octal %03o"),
+ transchar(c), buf1, buf2, cval, cval, cval));
+ c = cc[ci++];
+ }
+
+#define SPACE_FOR_DESC (1 + 1 + 1 + MB_MAXBYTES + 16 + 4 + 3 + 3 + 1)
+ // Space for description:
+ // - 1 byte for separator (starting from second entry)
+ // - 1 byte for "<"
+ // - 1 byte for space to draw composing character on (optional, but really
+ // mostly required)
+ // - up to MB_MAXBYTES bytes for character itself
+ // - 16 bytes for raw text ("> , Hex , Octal ").
+ // - at least 4 bytes for hexadecimal representation
+ // - at least 3 bytes for decimal representation
+ // - at least 3 bytes for octal representation
+ // - 1 byte for NUL
+ //
+ // Taking into account MAX_MCO and characters which need 8 bytes for
+ // hexadecimal representation, but not taking translation into account:
+ // resulting string will occupy less then 400 bytes (conservative estimate).
+ //
+ // Less then 1000 bytes if translation multiplies number of bytes needed for
+ // raw text by 6, so it should always fit into 1025 bytes reserved for IObuff.
+
+ // Repeat for combining characters, also handle multiby here.
+ while (c >= 0x80 && iobuff_len < sizeof(IObuff) - SPACE_FOR_DESC) {
+ // This assumes every multi-byte char is printable...
+ if (iobuff_len > 0) {
+ IObuff[iobuff_len++] = ' ';
+ }
+ IObuff[iobuff_len++] = '<';
+ if (utf_iscomposing(c)) {
+ IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space.
+ }
+ iobuff_len += utf_char2bytes(c, IObuff + iobuff_len);
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len, sizeof(IObuff) - iobuff_len,
+ (c < 0x10000
+ ? _("> %d, Hex %04x, Octal %o")
+ : _("> %d, Hex %08x, Octal %o")), c, c, c));
+ if (ci == MAX_MCO) {
break;
- if (l_enc_utf8)
- c = cc[ci++];
- else
- c = 0;
+ }
+ c = cc[ci++];
+ }
+ if (ci != MAX_MCO && c != 0) {
+ xstrlcpy((char *)IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len);
}
msg(IObuff);
@@ -2018,13 +2022,13 @@ int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm, linenr_T lnum,
}
if (other && !forceit && curbuf->b_nwindows == 1 && !buf_hide(curbuf)
&& curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) {
- if (p_confirm && p_write)
- dialog_changed(curbuf, FALSE);
+ if (p_confirm && p_write) {
+ dialog_changed(curbuf, false);
+ }
if (curbufIsChanged()) {
- if (other)
- --no_wait_return;
+ no_wait_return--;
EMSG(_(e_nowrtmsg));
- retval = 2; /* file has been changed */
+ retval = 2; // File has been changed.
goto theend;
}
}
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 821c050c50..96d2102156 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -3055,24 +3055,32 @@ void scriptnames_slash_adjust(void)
# endif
/// Get a pointer to a script name. Used for ":verbose set".
-char_u *get_scriptname(scid_T id)
-{
- if (id == SID_MODELINE) {
- return (char_u *)_("modeline");
- }
- if (id == SID_CMDARG) {
- return (char_u *)_("--cmd argument");
- }
- if (id == SID_CARG) {
- return (char_u *)_("-c argument");
- }
- if (id == SID_ENV) {
- return (char_u *)_("environment variable");
- }
- if (id == SID_ERROR) {
- return (char_u *)_("error handler");
+char_u *get_scriptname(LastSet last_set, bool *should_free)
+{
+ *should_free = false;
+
+ switch (last_set.script_id) {
+ case SID_MODELINE:
+ return (char_u *)_("modeline");
+ case SID_CMDARG:
+ return (char_u *)_("--cmd argument");
+ case SID_CARG:
+ return (char_u *)_("-c argument");
+ case SID_ENV:
+ return (char_u *)_("environment variable");
+ case SID_ERROR:
+ return (char_u *)_("error handler");
+ case SID_LUA:
+ return (char_u *)_("Lua");
+ case SID_API_CLIENT:
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("API client (channel id %" PRIu64 ")"),
+ last_set.channel_id);
+ return IObuff;
+ default:
+ *should_free = true;
+ return home_replace_save(NULL, SCRIPT_ITEM(last_set.script_id).sn_name);
}
- return SCRIPT_ITEM(id).sn_name;
}
# if defined(EXITFREE)
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e1d28b4a9c..52b810085c 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -73,6 +73,7 @@
#include "nvim/shada.h"
#include "nvim/lua/executor.h"
#include "nvim/globals.h"
+#include "nvim/api/private/helpers.h"
static int quitmore = 0;
static int ex_pressedreturn = FALSE;
@@ -133,7 +134,6 @@ struct dbg_stuff {
char_u *vv_throwpoint;
int did_emsg;
int got_int;
- int did_throw;
int need_rethrow;
int check_cstack;
except_T *current_exception;
@@ -165,12 +165,11 @@ static void save_dbg_stuff(struct dbg_stuff *dsp)
dsp->vv_exception = v_exception(NULL);
dsp->vv_throwpoint = v_throwpoint(NULL);
- /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */
- dsp->did_emsg = did_emsg; did_emsg = FALSE;
- dsp->got_int = got_int; got_int = FALSE;
- dsp->did_throw = did_throw; did_throw = FALSE;
- dsp->need_rethrow = need_rethrow; need_rethrow = FALSE;
- dsp->check_cstack = check_cstack; check_cstack = FALSE;
+ // Necessary for debugging an inactive ":catch", ":finally", ":endtry".
+ dsp->did_emsg = did_emsg; did_emsg = false;
+ dsp->got_int = got_int; got_int = false;
+ dsp->need_rethrow = need_rethrow; need_rethrow = false;
+ dsp->check_cstack = check_cstack; check_cstack = false;
dsp->current_exception = current_exception; current_exception = NULL;
}
@@ -184,7 +183,6 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp)
(void)v_throwpoint(dsp->vv_throwpoint);
did_emsg = dsp->did_emsg;
got_int = dsp->got_int;
- did_throw = dsp->did_throw;
need_rethrow = dsp->need_rethrow;
check_cstack = dsp->check_cstack;
current_exception = dsp->current_exception;
@@ -400,16 +398,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
initial_trylevel = trylevel;
- /*
- * "did_throw" will be set to TRUE when an exception is being thrown.
- */
- did_throw = FALSE;
- /*
- * "did_emsg" will be set to TRUE when emsg() is used, in which case we
- * cancel the whole command line, and any if/endif or loop.
- * If force_abort is set, we cancel everything.
- */
- did_emsg = FALSE;
+ current_exception = NULL;
+ // "did_emsg" will be set to TRUE when emsg() is used, in which case we
+ // cancel the whole command line, and any if/endif or loop.
+ // If force_abort is set, we cancel everything.
+ did_emsg = false;
/*
* KeyTyped is only set when calling vgetc(). Reset it here when not
@@ -611,6 +604,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
cmd_getline, cmd_cookie);
recursive--;
+ // Ignore trailing '|'-separated commands in preview-mode ('inccommand').
+ if (State & CMDPREVIEW) {
+ next_cmdline = NULL;
+ }
+
if (cmd_cookie == (void *)&cmd_loop_cookie)
/* Use "current_line" from "cmd_loop_cookie", it may have been
* incremented when defining a function. */
@@ -659,7 +657,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* not to use a cs_line[] from an entry that isn't a ":while"
* or ":for": It would make "current_line" invalid and can
* cause a crash. */
- if (!did_emsg && !got_int && !did_throw
+ if (!did_emsg && !got_int && !current_exception
&& cstack.cs_idx >= 0
&& (cstack.cs_flags[cstack.cs_idx]
& (CSF_WHILE | CSF_FOR))
@@ -707,7 +705,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
}
/*
- * A ":finally" makes did_emsg, got_int, and did_throw pending for
+ * A ":finally" makes did_emsg, got_int and current_exception pending for
* being restored at the ":endtry". Reset them here and set the
* ACTIVE and FINALLY flags, so that the finally clause gets executed.
* This includes the case where a missing ":endif", ":endwhile" or
@@ -715,10 +713,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
*/
if (cstack.cs_lflags & CSL_HAD_FINA) {
cstack.cs_lflags &= ~CSL_HAD_FINA;
- report_make_pending(cstack.cs_pending[cstack.cs_idx]
- & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW),
- did_throw ? (void *)current_exception : NULL);
- did_emsg = got_int = did_throw = FALSE;
+ report_make_pending((cstack.cs_pending[cstack.cs_idx]
+ & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW)),
+ current_exception);
+ did_emsg = got_int = false;
+ current_exception = NULL;
cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY;
}
@@ -726,15 +725,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* within this loop. */
trylevel = initial_trylevel + cstack.cs_trylevel;
- /*
- * If the outermost try conditional (across function calls and sourced
- * files) is aborted because of an error, an interrupt, or an uncaught
- * exception, cancel everything. If it is left normally, reset
- * force_abort to get the non-EH compatible abortion behavior for
- * the rest of the script.
- */
- if (trylevel == 0 && !did_emsg && !got_int && !did_throw)
- force_abort = FALSE;
+ // If the outermost try conditional (across function calls and sourced
+ // files) is aborted because of an error, an interrupt, or an uncaught
+ // exception, cancel everything. If it is left normally, reset
+ // force_abort to get the non-EH compatible abortion behavior for
+ // the rest of the script.
+ if (trylevel == 0 && !did_emsg && !got_int && !current_exception) {
+ force_abort = false;
+ }
/* Convert an interrupt to an exception if appropriate. */
(void)do_intthrow(&cstack);
@@ -749,11 +747,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* - there is a command after '|', inside a :if, :while, :for or :try, or
* looping for ":source" command or function call.
*/
- while (!((got_int
- || (did_emsg && force_abort) || did_throw
- )
- && cstack.cs_trylevel == 0
- )
+ while (!((got_int || (did_emsg && force_abort) || current_exception)
+ && cstack.cs_trylevel == 0)
&& !(did_emsg
/* Keep going when inside try/catch, so that the error can be
* deal with, except when it is a syntax error, it may cause
@@ -775,7 +770,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* If a sourced file or executed function ran to its end, report the
* unclosed conditional.
*/
- if (!got_int && !did_throw
+ if (!got_int && !current_exception
&& ((getline_equal(fgetline, cookie, getsourceline)
&& !source_finished(fgetline, cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
@@ -815,17 +810,16 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
? (char_u *)"endfunction" : (char_u *)NULL);
if (trylevel == 0) {
- /*
- * When an exception is being thrown out of the outermost try
- * conditional, discard the uncaught exception, disable the conversion
- * of interrupts or errors to exceptions, and ensure that no more
- * commands are executed.
- */
- if (did_throw) {
- void *p = NULL;
- char_u *saved_sourcing_name;
+ // When an exception is being thrown out of the outermost try
+ // conditional, discard the uncaught exception, disable the conversion
+ // of interrupts or errors to exceptions, and ensure that no more
+ // commands are executed.
+ if (current_exception) {
+ void *p = NULL;
+ char_u *saved_sourcing_name;
int saved_sourcing_lnum;
- struct msglist *messages = NULL, *next;
+ struct msglist *messages = NULL;
+ struct msglist *next;
/*
* If the uncaught exception is a user exception, report it as an
@@ -885,22 +879,22 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
suppress_errthrow = TRUE;
}
- /*
- * The current cstack will be freed when do_cmdline() returns. An uncaught
- * exception will have to be rethrown in the previous cstack. If a function
- * has just returned or a script file was just finished and the previous
- * cstack belongs to the same function or, respectively, script file, it
- * will have to be checked for finally clauses to be executed due to the
- * ":return" or ":finish". This is done in do_one_cmd().
- */
- if (did_throw)
- need_rethrow = TRUE;
+ // The current cstack will be freed when do_cmdline() returns. An uncaught
+ // exception will have to be rethrown in the previous cstack. If a function
+ // has just returned or a script file was just finished and the previous
+ // cstack belongs to the same function or, respectively, script file, it
+ // will have to be checked for finally clauses to be executed due to the
+ // ":return" or ":finish". This is done in do_one_cmd().
+ if (current_exception) {
+ need_rethrow = true;
+ }
if ((getline_equal(fgetline, cookie, getsourceline)
&& ex_nesting_level > source_level(real_cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
&& ex_nesting_level > func_level(real_cookie) + 1)) {
- if (!did_throw)
- check_cstack = TRUE;
+ if (!current_exception) {
+ check_cstack = true;
+ }
} else {
/* When leaving a function, reduce nesting level. */
if (getline_equal(fgetline, cookie, get_func_line))
@@ -1480,10 +1474,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
char_u *after_modifier = ea.cmd;
- ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0
- && !(cstack->cs_flags[cstack->
- cs_idx]
- & CSF_ACTIVE));
+ ea.skip = (did_emsg
+ || got_int
+ || current_exception
+ || (cstack->cs_idx >= 0
+ && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
/* Count this line for profiling if ea.skip is FALSE. */
if (do_profiling == PROF_YES && !ea.skip) {
@@ -1782,13 +1777,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
));
- /* forced commands */
+ // Forced commands.
if (*p == '!' && ea.cmdidx != CMD_substitute
&& ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic) {
- ++p;
- ea.forceit = TRUE;
- } else
- ea.forceit = FALSE;
+ p++;
+ ea.forceit = true;
+ } else {
+ ea.forceit = false;
+ }
/*
* 6. Parse arguments.
@@ -4867,51 +4863,56 @@ static struct {
* List of names for completion for ":command" with the EXPAND_ flag.
* Must be alphabetical for completion.
*/
-static struct {
- int expand;
- char *name;
-} command_complete[] =
-{
- { EXPAND_AUGROUP, "augroup" },
- { EXPAND_BEHAVE, "behave" },
- { EXPAND_BUFFERS, "buffer" },
- { EXPAND_CHECKHEALTH, "checkhealth" },
- { EXPAND_COLORS, "color" },
- { EXPAND_COMMANDS, "command" },
- { EXPAND_COMPILER, "compiler" },
- { EXPAND_CSCOPE, "cscope" },
- { EXPAND_USER_DEFINED, "custom" },
- { EXPAND_USER_LIST, "customlist" },
- { EXPAND_DIRECTORIES, "dir" },
- { EXPAND_ENV_VARS, "environment" },
- { EXPAND_EVENTS, "event" },
- { EXPAND_EXPRESSION, "expression" },
- { EXPAND_FILES, "file" },
- { EXPAND_FILES_IN_PATH, "file_in_path" },
- { EXPAND_FILETYPE, "filetype" },
- { EXPAND_FUNCTIONS, "function" },
- { EXPAND_HELP, "help" },
- { EXPAND_HIGHLIGHT, "highlight" },
- { EXPAND_HISTORY, "history" },
+static const char *command_complete[] =
+{
+ [EXPAND_AUGROUP] = "augroup",
+ [EXPAND_BEHAVE] = "behave",
+ [EXPAND_BUFFERS] = "buffer",
+ [EXPAND_CHECKHEALTH] = "checkhealth",
+ [EXPAND_COLORS] = "color",
+ [EXPAND_COMMANDS] = "command",
+ [EXPAND_COMPILER] = "compiler",
+ [EXPAND_CSCOPE] = "cscope",
+ [EXPAND_USER_DEFINED] = "custom",
+ [EXPAND_USER_LIST] = "customlist",
+ [EXPAND_DIRECTORIES] = "dir",
+ [EXPAND_ENV_VARS] = "environment",
+ [EXPAND_EVENTS] = "event",
+ [EXPAND_EXPRESSION] = "expression",
+ [EXPAND_FILES] = "file",
+ [EXPAND_FILES_IN_PATH] = "file_in_path",
+ [EXPAND_FILETYPE] = "filetype",
+ [EXPAND_FUNCTIONS] = "function",
+ [EXPAND_HELP] = "help",
+ [EXPAND_HIGHLIGHT] = "highlight",
+ [EXPAND_HISTORY] = "history",
#ifdef HAVE_WORKING_LIBINTL
- { EXPAND_LOCALES, "locale" },
+ [EXPAND_LOCALES] = "locale",
#endif
- { EXPAND_MAPPINGS, "mapping" },
- { EXPAND_MENUS, "menu" },
- { EXPAND_MESSAGES, "messages" },
- { EXPAND_OWNSYNTAX, "syntax" },
- { EXPAND_SYNTIME, "syntime" },
- { EXPAND_SETTINGS, "option" },
- { EXPAND_PACKADD, "packadd" },
- { EXPAND_SHELLCMD, "shellcmd" },
- { EXPAND_SIGN, "sign" },
- { EXPAND_TAGS, "tag" },
- { EXPAND_TAGS_LISTFILES, "tag_listfiles" },
- { EXPAND_USER, "user" },
- { EXPAND_USER_VARS, "var" },
- { 0, NULL }
+ [EXPAND_MAPPINGS] = "mapping",
+ [EXPAND_MENUS] = "menu",
+ [EXPAND_MESSAGES] = "messages",
+ [EXPAND_OWNSYNTAX] = "syntax",
+ [EXPAND_SYNTIME] = "syntime",
+ [EXPAND_SETTINGS] = "option",
+ [EXPAND_PACKADD] = "packadd",
+ [EXPAND_SHELLCMD] = "shellcmd",
+ [EXPAND_SIGN] = "sign",
+ [EXPAND_TAGS] = "tag",
+ [EXPAND_TAGS_LISTFILES] = "tag_listfiles",
+ [EXPAND_USER] = "user",
+ [EXPAND_USER_VARS] = "var",
};
+static char *get_command_complete(int arg)
+{
+ if (arg >= (int)(ARRAY_SIZE(command_complete))) {
+ return NULL;
+ } else {
+ return (char *)command_complete[arg];
+ }
+}
+
static void uc_list(char_u *name, size_t name_len)
{
int i, j;
@@ -5005,13 +5006,12 @@ static void uc_list(char_u *name, size_t name_len)
IObuff[len++] = ' ';
} while (len < 21);
- /* Completion */
- for (j = 0; command_complete[j].expand != 0; ++j)
- if (command_complete[j].expand == cmd->uc_compl) {
- STRCPY(IObuff + len, command_complete[j].name);
- len += (int)STRLEN(IObuff + len);
- break;
- }
+ // Completion
+ char *cmd_compl = get_command_complete(cmd->uc_compl);
+ if (cmd_compl != NULL) {
+ STRCPY(IObuff + len, get_command_complete(cmd->uc_compl));
+ len += (int)STRLEN(IObuff + len);
+ }
do {
IObuff[len++] = ' ';
@@ -5191,11 +5191,13 @@ static void ex_command(exarg_T *eap)
p = skipwhite(end);
}
- /* Get the name (if any) and skip to the following argument */
+ // Get the name (if any) and skip to the following argument.
name = p;
- if (ASCII_ISALPHA(*p))
- while (ASCII_ISALNUM(*p))
- ++p;
+ if (ASCII_ISALPHA(*p)) {
+ while (ASCII_ISALNUM(*p)) {
+ p++;
+ }
+ }
if (!ends_excmd(*p) && !ascii_iswhite(*p)) {
EMSG(_("E182: Invalid command name"));
return;
@@ -5213,8 +5215,7 @@ static void ex_command(exarg_T *eap)
EMSG(_("E183: User defined commands must start with an uppercase letter"));
return;
} else if ((name_len == 1 && *name == 'X')
- || (name_len <= 4
- && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) {
+ || (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0)) {
EMSG(_("E841: Reserved name, cannot be used for user defined command"));
return;
} else
@@ -5678,22 +5679,21 @@ static void do_ucmd(exarg_T *eap)
if (start != NULL)
end = vim_strchr(start + 1, '>');
if (buf != NULL) {
- for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp)
- ;
+ for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ksp++) {
+ }
if (*ksp == K_SPECIAL
&& (start == NULL || ksp < start || end == NULL)
- && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)
- )) {
- /* K_SPECIAL has been put in the buffer as K_SPECIAL
- * KS_SPECIAL KE_FILLER, like for mappings, but
- * do_cmdline() doesn't handle that, so convert it back.
- * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */
+ && (ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)) {
+ // K_SPECIAL has been put in the buffer as K_SPECIAL
+ // KS_SPECIAL KE_FILLER, like for mappings, but
+ // do_cmdline() doesn't handle that, so convert it back.
+ // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI.
len = ksp - p;
if (len > 0) {
memmove(q, p, len);
q += len;
}
- *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI;
+ *q++ = K_SPECIAL;
p = ksp + 3;
continue;
}
@@ -5802,7 +5802,15 @@ char_u *get_user_cmd_nargs(expand_T *xp, int idx)
*/
char_u *get_user_cmd_complete(expand_T *xp, int idx)
{
- return (char_u *)command_complete[idx].name;
+ if (idx >= (int)ARRAY_SIZE(command_complete)) {
+ return NULL;
+ }
+ char *cmd_compl = get_command_complete(idx);
+ if (cmd_compl == NULL) {
+ return (char_u *)"";
+ } else {
+ return (char_u *)cmd_compl;
+ }
}
/*
@@ -5862,20 +5870,23 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp,
}
}
- for (i = 0; command_complete[i].expand != 0; ++i) {
- if ((int)STRLEN(command_complete[i].name) == valend
- && STRNCMP(value, command_complete[i].name, valend) == 0) {
- *complp = command_complete[i].expand;
- if (command_complete[i].expand == EXPAND_BUFFERS)
+ for (i = 0; i < (int)ARRAY_SIZE(command_complete); i++) {
+ if (get_command_complete(i) == NULL) {
+ continue;
+ }
+ if ((int)STRLEN(command_complete[i]) == valend
+ && STRNCMP(value, command_complete[i], valend) == 0) {
+ *complp = i;
+ if (i == EXPAND_BUFFERS) {
*argt |= BUFNAME;
- else if (command_complete[i].expand == EXPAND_DIRECTORIES
- || command_complete[i].expand == EXPAND_FILES)
+ } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES) {
*argt |= XFILE;
+ }
break;
}
}
- if (command_complete[i].expand == 0) {
+ if (i == (int)ARRAY_SIZE(command_complete)) {
EMSG2(_("E180: Invalid complete value: %s"), value);
return FAIL;
}
@@ -5899,9 +5910,13 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp,
int cmdcomplete_str_to_type(char_u *complete_str)
{
- for (int i = 0; command_complete[i].expand != 0; i++) {
- if (STRCMP(complete_str, command_complete[i].name) == 0) {
- return command_complete[i].expand;
+ for (int i = 0; i < (int)(ARRAY_SIZE(command_complete)); i++) {
+ char *cmd_compl = get_command_complete(i);
+ if (cmd_compl == NULL) {
+ continue;
+ }
+ if (STRCMP(complete_str, command_complete[i]) == 0) {
+ return i;
}
}
@@ -6310,15 +6325,18 @@ static void ex_stop(exarg_T *eap)
if (!eap->forceit) {
autowrite_all();
}
+ apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL);
ui_cursor_goto((int)Rows - 1, 0);
ui_linefeed();
ui_flush();
ui_call_suspend(); // call machine specific function
+
ui_flush();
maketitle();
resettitle(); // force updating the title
redraw_later_clear();
ui_refresh(); // may have resized window
+ apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL);
}
}
@@ -6554,18 +6572,14 @@ void alist_slash_adjust(void)
#endif
-/*
- * ":preserve".
- */
+/// ":preserve".
static void ex_preserve(exarg_T *eap)
{
curbuf->b_flags |= BF_PRESERVED;
- ml_preserve(curbuf, TRUE);
+ ml_preserve(curbuf, true, true);
}
-/*
- * ":recover".
- */
+/// ":recover".
static void ex_recover(exarg_T *eap)
{
/* Set recoverymode right away to avoid the ATTENTION prompt. */
@@ -6985,12 +6999,10 @@ do_exedit (
ex_no_reprint = TRUE;
}
-/*
- * ":gui" and ":gvim" when there is no GUI.
- */
+/// ":gui" and ":gvim" when there is no GUI.
static void ex_nogui(exarg_T *eap)
{
- eap->errmsg = e_nogvim;
+ eap->errmsg = (char_u *)N_("E25: Nvim does not have a built-in GUI");
}
@@ -8156,6 +8168,10 @@ static void ex_startinsert(exarg_T *eap)
restart_edit = 'i';
curwin->w_curswant = 0; /* avoid MAXCOL */
}
+
+ if (VIsual_active) {
+ showmode();
+ }
}
/*
@@ -8546,22 +8562,22 @@ eval_vars (
resultbuf = result; /* remember allocated string */
break;
- case SPEC_AFILE: /* file name for autocommand */
- result = autocmd_fname;
- if (result != NULL && !autocmd_fname_full) {
- /* Still need to turn the fname into a full path. It is
- * postponed to avoid a delay when <afile> is not used. */
- autocmd_fname_full = TRUE;
- result = (char_u *)FullName_save((char *)autocmd_fname, FALSE);
- xfree(autocmd_fname);
- autocmd_fname = result;
+ case SPEC_AFILE: // file name for autocommand
+ if (autocmd_fname != NULL && !path_is_absolute(autocmd_fname)) {
+ // Still need to turn the fname into a full path. It was
+ // postponed to avoid a delay when <afile> is not used.
+ result = (char_u *)FullName_save((char *)autocmd_fname, false);
+ // Copy into `autocmd_fname`, don't reassign it. #8165
+ xstrlcpy((char *)autocmd_fname, (char *)result, MAXPATHL);
+ xfree(result);
}
+ result = autocmd_fname;
if (result == NULL) {
*errormsg = (char_u *)_(
"E495: no autocommand file name to substitute for \"<afile>\"");
return NULL;
}
- result = path_shorten_fname_if_possible(result);
+ result = path_try_shorten_fname(result);
break;
case SPEC_ABUF: /* buffer number for autocommand */
@@ -9952,3 +9968,82 @@ bool cmd_can_preview(char_u *cmd)
return false;
}
+
+/// Gets a map of maps describing user-commands defined for buffer `buf` or
+/// defined globally if `buf` is NULL.
+///
+/// @param buf Buffer to inspect, or NULL to get global commands.
+///
+/// @return Map of maps describing commands
+Dictionary commands_array(buf_T *buf)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+ Object obj = NIL;
+ char str[10];
+ garray_T *gap = (buf == NULL) ? &ucmds : &buf->b_ucmds;
+
+ for (int i = 0; i < gap->ga_len; i++) {
+ char arg[2] = { 0, 0 };
+ Dictionary d = ARRAY_DICT_INIT;
+ ucmd_T *cmd = USER_CMD_GA(gap, i);
+
+ PUT(d, "name", STRING_OBJ(cstr_to_string((char *)cmd->uc_name)));
+ PUT(d, "definition", STRING_OBJ(cstr_to_string((char *)cmd->uc_rep)));
+ PUT(d, "script_id", INTEGER_OBJ(cmd->uc_scriptID));
+ PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & BANG)));
+ PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & TRLBAR)));
+ PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & REGSTR)));
+
+ switch (cmd->uc_argt & (EXTRA|NOSPC|NEEDARG)) {
+ case 0: arg[0] = '0'; break;
+ case(EXTRA): arg[0] = '*'; break;
+ case(EXTRA|NOSPC): arg[0] = '?'; break;
+ case(EXTRA|NEEDARG): arg[0] = '+'; break;
+ case(EXTRA|NOSPC|NEEDARG): arg[0] = '1'; break;
+ }
+ PUT(d, "nargs", STRING_OBJ(cstr_to_string(arg)));
+
+ char *cmd_compl = get_command_complete(cmd->uc_compl);
+ PUT(d, "complete", (cmd_compl == NULL
+ ? NIL : STRING_OBJ(cstr_to_string(cmd_compl))));
+ PUT(d, "complete_arg", cmd->uc_compl_arg == NULL
+ ? NIL : STRING_OBJ(cstr_to_string((char *)cmd->uc_compl_arg)));
+
+ obj = NIL;
+ if (cmd->uc_argt & COUNT) {
+ if (cmd->uc_def >= 0) {
+ snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def);
+ obj = STRING_OBJ(cstr_to_string(str)); // -count=N
+ } else {
+ obj = STRING_OBJ(cstr_to_string("0")); // -count
+ }
+ }
+ PUT(d, "count", obj);
+
+ obj = NIL;
+ if (cmd->uc_argt & RANGE) {
+ if (cmd->uc_argt & DFLALL) {
+ obj = STRING_OBJ(cstr_to_string("%")); // -range=%
+ } else if (cmd->uc_def >= 0) {
+ snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def);
+ obj = STRING_OBJ(cstr_to_string(str)); // -range=N
+ } else {
+ obj = STRING_OBJ(cstr_to_string(".")); // -range
+ }
+ }
+ PUT(d, "range", obj);
+
+ obj = NIL;
+ for (int j = 0; addr_type_complete[j].expand != -1; j++) {
+ if (addr_type_complete[j].expand != ADDR_LINES
+ && addr_type_complete[j].expand == cmd->uc_addr_type) {
+ obj = STRING_OBJ(cstr_to_string(addr_type_complete[j].name));
+ break;
+ }
+ }
+ PUT(d, "addr", obj);
+
+ PUT(rv, (char *)cmd->uc_name, DICTIONARY_OBJ(d));
+ }
+ return rv;
+}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 4010a088c8..7f7851f078 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -28,39 +28,37 @@
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h"
#endif
-/*
- * Exception handling terms:
- *
- * :try ":try" command \
- * ... try block |
- * :catch RE ":catch" command |
- * ... catch clause |- try conditional
- * :finally ":finally" command |
- * ... finally clause |
- * :endtry ":endtry" command /
- *
- * The try conditional may have any number of catch clauses and at most one
- * finally clause. A ":throw" command can be inside the try block, a catch
- * clause, the finally clause, or in a function called or script sourced from
- * there or even outside the try conditional. Try conditionals may be nested.
- */
-/*
- * Configuration whether an exception is thrown on error or interrupt. When
- * the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
- * interrupt (got_int) under an active try conditional terminates the script
- * after the non-active finally clauses of all active try conditionals have been
- * executed. Otherwise, errors and/or interrupts are converted into catchable
- * exceptions (did_throw additionally set), which terminate the script only if
- * not caught. For user exceptions, only did_throw is set. (Note: got_int can
- * be set asynchronously afterwards by a SIGINT, so did_throw && got_int is not
- * a reliant test that the exception currently being thrown is an interrupt
- * exception. Similarly, did_emsg can be set afterwards on an error in an
- * (unskipped) conditional command inside an inactive conditional, so did_throw
- * && did_emsg is not a reliant test that the exception currently being thrown
- * is an error exception.) - The macros can be defined as expressions checking
- * for a variable that is allowed to be changed during execution of a script.
- */
+// Exception handling terms:
+//
+// :try ":try" command ─┐
+// ... try block │
+// :catch RE ":catch" command │
+// ... catch clause ├─ try conditional
+// :finally ":finally" command │
+// ... finally clause │
+// :endtry ":endtry" command ─┘
+//
+// The try conditional may have any number of catch clauses and at most one
+// finally clause. A ":throw" command can be inside the try block, a catch
+// clause, the finally clause, or in a function called or script sourced from
+// there or even outside the try conditional. Try conditionals may be nested.
+
+// Configuration whether an exception is thrown on error or interrupt. When
+// the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
+// interrupt (got_int) under an active try conditional terminates the script
+// after the non-active finally clauses of all active try conditionals have been
+// executed. Otherwise, errors and/or interrupts are converted into catchable
+// exceptions, which terminate the script only if not caught. For user
+// exceptions, only current_exception is set. (Note: got_int can be set
+// asynchronously afterwards by a SIGINT, so current_exception && got_int is not
+// a reliant test that the exception currently being thrown is an interrupt
+// exception. Similarly, did_emsg can be set afterwards on an error in an
+// (unskipped) conditional command inside an inactive conditional, so
+// current_exception && did_emsg is not a reliant test that the exception
+// currently being thrown is an error exception.) - The macros can be defined
+// as expressions checking for a variable that is allowed to be changed during
+// execution of a script.
// Values used for the Vim release.
#define THROW_ON_ERROR true
@@ -68,6 +66,15 @@
#define THROW_ON_INTERRUPT true
#define THROW_ON_INTERRUPT_TRUE
+// Don't do something after an error, interrupt, or throw, or when
+// there is a surrounding conditional and it was not active.
+#define CHECK_SKIP \
+ (did_emsg \
+ || got_int \
+ || current_exception \
+ || (cstack->cs_idx > 0 \
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))
+
#define discard_pending_return(p) tv_free((typval_T *)(p))
/*
@@ -94,7 +101,7 @@ static int cause_abort = FALSE;
*/
int aborting(void)
{
- return (did_emsg && force_abort) || got_int || did_throw;
+ return (did_emsg && force_abort) || got_int || current_exception;
}
/*
@@ -178,8 +185,9 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* currently throwing an exception, do nothing. The message text will
* then be stored to v:errmsg by emsg() without displaying it.
*/
- if (((trylevel == 0 && !cause_abort) || emsg_silent) && !did_throw)
- return FALSE;
+ if (((trylevel == 0 && !cause_abort) || emsg_silent) && !current_exception) {
+ return false;
+ }
/*
* Ignore an interrupt message when inside a try conditional or when an
@@ -208,12 +216,13 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* exception currently being thrown to prevent it from being caught. Just
* execute finally clauses and terminate.
*/
- if (did_throw) {
- /* When discarding an interrupt exception, reset got_int to prevent the
- * same interrupt being converted to an exception again and discarding
- * the error exception we are about to throw here. */
- if (current_exception->type == ET_INTERRUPT)
- got_int = FALSE;
+ if (current_exception) {
+ // When discarding an interrupt exception, reset got_int to prevent the
+ // same interrupt being converted to an exception again and discarding
+ // the error exception we are about to throw here.
+ if (current_exception->type == ET_INTERRUPT) {
+ got_int = false;
+ }
discard_current_exception();
}
@@ -333,45 +342,44 @@ void do_errthrow(struct condstack *cstack, char_u *cmdname)
*/
int do_intthrow(struct condstack *cstack)
{
- /*
- * If no interrupt occurred or no try conditional is active and no exception
- * is being thrown, do nothing (for compatibility of non-EH scripts).
- */
- if (!got_int || (trylevel == 0 && !did_throw))
- return FALSE;
+ // If no interrupt occurred or no try conditional is active and no exception
+ // is being thrown, do nothing (for compatibility of non-EH scripts).
+ if (!got_int || (trylevel == 0 && !current_exception)) {
+ return false;
+ }
-#ifdef THROW_TEST /* avoid warning for condition always true */
+#ifdef THROW_TEST // avoid warning for condition always true
if (!THROW_ON_INTERRUPT) {
- /*
- * The interrupt aborts everything except for executing finally clauses.
- * Discard any user or error or interrupt exception currently being
- * thrown.
- */
- if (did_throw)
+ // The interrupt aborts everything except for executing finally clauses.
+ // Discard any user or error or interrupt exception currently being
+ // thrown.
+ if (current_exception) {
discard_current_exception();
- } else
+ }
+ } else {
#endif
- {
- /*
- * Throw an interrupt exception, so that everything will be aborted
- * (except for executing finally clauses), until the interrupt exception
- * is caught; if still uncaught at the top level, the script processing
- * will be terminated then. - If an interrupt exception is already
- * being thrown, do nothing.
- *
- */
- if (did_throw) {
- if (current_exception->type == ET_INTERRUPT)
- return FALSE;
+ // Throw an interrupt exception, so that everything will be aborted
+ // (except for executing finally clauses), until the interrupt exception
+ // is caught; if still uncaught at the top level, the script processing
+ // will be terminated then. - If an interrupt exception is already
+ // being thrown, do nothing.
+
+ if (current_exception) {
+ if (current_exception->type == ET_INTERRUPT) {
+ return false;
+ }
- /* An interrupt exception replaces any user or error exception. */
+ // An interrupt exception replaces any user or error exception.
discard_current_exception();
}
- if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL)
+ if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL) {
do_throw(cstack);
+ }
+#ifdef THROW_TEST
}
+#endif
- return TRUE;
+ return true;
}
// Get an exception message that is to be stored in current_exception->value.
@@ -565,8 +573,7 @@ void discard_current_exception(void)
// Note: all globals manipulated here should be saved/restored in
// try_enter/try_leave.
current_exception = NULL;
- did_throw = FALSE;
- need_rethrow = FALSE;
+ need_rethrow = false;
}
/*
@@ -795,15 +802,7 @@ void ex_if(exarg_T *eap)
++cstack->cs_idx;
cstack->cs_flags[cstack->cs_idx] = 0;
- /*
- * Don't do something after an error, interrupt, or throw, or when there
- * is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
@@ -854,15 +853,7 @@ void ex_else(exarg_T *eap)
int result;
struct condstack *cstack = eap->cstack;
- /*
- * Don't do something after an error, interrupt, or throw, or when there is
- * a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (cstack->cs_idx < 0
|| (cstack->cs_flags[cstack->cs_idx]
@@ -952,15 +943,7 @@ void ex_while(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] =
eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR;
- /*
- * Don't do something after an error, interrupt, or throw, or when
- * there is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (eap->cmdidx == CMD_while) {
/*
* ":while bool-expr"
@@ -1233,8 +1216,6 @@ void do_throw(struct condstack *cstack)
cstack->cs_flags[idx] &= ~CSF_ACTIVE;
cstack->cs_exception[idx] = current_exception;
}
-
- did_throw = TRUE;
}
/*
@@ -1253,15 +1234,7 @@ void ex_try(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
- /*
- * Don't do something after an error, interrupt, or throw, or when there
- * is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (!skip) {
/* Set ACTIVE and TRUE. TRUE means that the corresponding ":catch"
@@ -1353,8 +1326,9 @@ void ex_catch(exarg_T *eap)
* corresponding try block never got active (because of an inactive
* surrounding conditional or after an error or interrupt or throw).
*/
- if (!did_throw || !(cstack->cs_flags[idx] & CSF_TRUE))
- skip = TRUE;
+ if (!current_exception || !(cstack->cs_flags[idx] & CSF_TRUE)) {
+ skip = true;
+ }
/*
* Check for a match only if an exception is thrown but not caught by
@@ -1413,10 +1387,10 @@ void ex_catch(exarg_T *eap)
}
if (caught) {
- /* Make this ":catch" clause active and reset did_emsg, got_int,
- * and did_throw. Put the exception on the caught stack. */
+ /* Make this ":catch" clause active and reset did_emsg and got_int.
+ * Put the exception on the caught stack. */
cstack->cs_flags[idx] |= CSF_ACTIVE | CSF_CAUGHT;
- did_emsg = got_int = did_throw = FALSE;
+ did_emsg = got_int = false;
catch_exception((except_T *)cstack->cs_exception[idx]);
/* It's mandatory that the current exception is stored in the cstack
* so that it can be discarded at the next ":catch", ":finally", or
@@ -1426,6 +1400,10 @@ void ex_catch(exarg_T *eap)
if (cstack->cs_exception[cstack->cs_idx] != current_exception) {
internal_error("ex_catch()");
}
+ // Discarding current_exceptions happens based on what is stored in
+ // cstack->cs_exception, *all* calls to discard_current_exception() are
+ // (and must be) guarded by current_exception check.
+ current_exception = NULL;
} else {
/*
* If there is a preceding catch clause and it caught the exception,
@@ -1484,7 +1462,7 @@ void ex_finally(exarg_T *eap)
* interrupt or throw) or for a ":finally" without ":try" or a multiple
* ":finally". After every other error (did_emsg or the conditional
* errors detected above) or after an interrupt (got_int) or an
- * exception (did_throw), the finally clause must be executed.
+ * exception (current_exception), the finally clause must be executed.
*/
skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
@@ -1511,30 +1489,31 @@ void ex_finally(exarg_T *eap)
cleanup_conditionals(cstack, CSF_TRY, FALSE);
/*
- * Make did_emsg, got_int, did_throw pending. If set, they overrule
- * a pending ":continue", ":break", ":return", or ":finish". Then
- * we have particularly to discard a pending return value (as done
+ * Make did_emsg, got_int, current_exception pending. If set, they
+ * overrule a pending ":continue", ":break", ":return", or ":finish".
+ * Then we have particularly to discard a pending return value (as done
* by the call to cleanup_conditionals() above when did_emsg or
* got_int is set). The pending values are restored by the
* ":endtry", except if there is a new error, interrupt, exception,
* ":continue", ":break", ":return", or ":finish" in the following
* finally clause. A missing ":endwhile", ":endfor" or ":endif"
- * detected here is treated as if did_emsg and did_throw had
+ * detected here is treated as if did_emsg and current_exception had
* already been set, respectively in case that the error is not
- * converted to an exception, did_throw had already been unset.
+ * converted to an exception, current_exception had already been unset.
* We must not set did_emsg here since that would suppress the
* error message.
*/
- if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) {
+ if (pending == CSTP_ERROR || did_emsg || got_int || current_exception) {
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
report_discard_pending(CSTP_RETURN,
cstack->cs_rettv[cstack->cs_idx]);
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
}
- if (pending == CSTP_ERROR && !did_emsg)
- pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0;
- else
- pending |= did_throw ? CSTP_THROW : 0;
+ if (pending == CSTP_ERROR && !did_emsg) {
+ pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
+ } else {
+ pending |= (current_exception ? CSTP_THROW : 0);
+ }
pending |= did_emsg ? CSTP_ERROR : 0;
pending |= got_int ? CSTP_INTERRUPT : 0;
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
@@ -1547,14 +1526,15 @@ void ex_finally(exarg_T *eap)
* exception. When emsg() is called for a missing ":endif" or
* a missing ":endwhile"/":endfor" detected here, the
* exception will be discarded. */
- if (did_throw && cstack->cs_exception[cstack->cs_idx]
- != current_exception)
+ if (current_exception
+ && cstack->cs_exception[cstack->cs_idx] != current_exception) {
internal_error("ex_finally()");
+ }
}
/*
* Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
- * got_int, and did_throw and make the finally clause active.
+ * got_int, and current_exception and make the finally clause active.
* This will happen after emsg() has been called for a missing
* ":endif" or a missing ":endwhile"/":endfor" detected here, so
* that the following finally clause will be executed even then.
@@ -1589,7 +1569,7 @@ void ex_endtry(exarg_T *eap)
// made inactive by a ":continue", ":break", ":return", or ":finish" in
// the finally clause. The latter case need not be tested since then
// anything pending has already been discarded.
- skip = (did_emsg || got_int || did_throw
+ skip = (did_emsg || got_int || current_exception
|| !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE));
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
@@ -1606,12 +1586,13 @@ void ex_endtry(exarg_T *eap)
/*
* If an exception is being thrown, discard it to prevent it from
* being rethrown at the end of this function. It would be
- * discarded by the error message, anyway. Resets did_throw.
+ * discarded by the error message, anyway. Resets current_exception.
* This does not affect the script termination due to the error
* since "trylevel" is decremented after emsg() has been called.
*/
- if (did_throw)
+ if (current_exception) {
discard_current_exception();
+ }
} else {
idx = cstack->cs_idx;
@@ -1621,9 +1602,11 @@ void ex_endtry(exarg_T *eap)
* a finally clause, we need to rethrow it after closing the try
* conditional.
*/
- if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE)
- && !(cstack->cs_flags[idx] & CSF_FINALLY))
- rethrow = TRUE;
+ if (current_exception
+ && (cstack->cs_flags[idx] & CSF_TRUE)
+ && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
+ rethrow = true;
+ }
}
/* If there was no finally clause, show the user when debugging or
@@ -1644,11 +1627,12 @@ void ex_endtry(exarg_T *eap)
if (got_int) {
skip = TRUE;
(void)do_intthrow(cstack);
- /* The do_intthrow() call may have reset did_throw or
- * cstack->cs_pending[idx].*/
- rethrow = FALSE;
- if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY))
- rethrow = TRUE;
+ // The do_intthrow() call may have reset current_exception or
+ // cstack->cs_pending[idx].
+ rethrow = false;
+ if (current_exception && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
+ rethrow = true;
+ }
}
}
@@ -1710,26 +1694,30 @@ void ex_endtry(exarg_T *eap)
do_finish(eap, FALSE);
break;
- /* When the finally clause was entered due to an error,
- * interrupt or throw (as opposed to a ":continue", ":break",
- * ":return", or ":finish"), restore the pending values of
- * did_emsg, got_int, and did_throw. This is skipped, if there
- * was a new error, interrupt, throw, ":continue", ":break",
- * ":return", or ":finish". in the finally clause. */
+ // When the finally clause was entered due to an error,
+ // interrupt or throw (as opposed to a ":continue", ":break",
+ // ":return", or ":finish"), restore the pending values of
+ // did_emsg, got_int, and current_exception. This is skipped, if there
+ // was a new error, interrupt, throw, ":continue", ":break",
+ // ":return", or ":finish". in the finally clause.
default:
- if (pending & CSTP_ERROR)
- did_emsg = TRUE;
- if (pending & CSTP_INTERRUPT)
- got_int = TRUE;
- if (pending & CSTP_THROW)
- rethrow = TRUE;
+ if (pending & CSTP_ERROR) {
+ did_emsg = true;
+ }
+ if (pending & CSTP_INTERRUPT) {
+ got_int = true;
+ }
+ if (pending & CSTP_THROW) {
+ rethrow = true;
+ }
break;
}
}
- if (rethrow)
- /* Rethrow the current exception (within this cstack). */
+ if (rethrow) {
+ // Rethrow the current exception (within this cstack).
do_throw(cstack);
+ }
}
}
@@ -1759,33 +1747,34 @@ void enter_cleanup(cleanup_T *csp)
int pending = CSTP_NONE;
/*
- * Postpone did_emsg, got_int, did_throw. The pending values will be
+ * Postpone did_emsg, got_int, current_exception. The pending values will be
* restored by leave_cleanup() except if there was an aborting error,
* interrupt, or uncaught exception after this function ends.
*/
- if (did_emsg || got_int || did_throw || need_rethrow) {
- csp->pending = (did_emsg ? CSTP_ERROR : 0)
- | (got_int ? CSTP_INTERRUPT : 0)
- | (did_throw ? CSTP_THROW : 0)
- | (need_rethrow ? CSTP_THROW : 0);
-
- /* If we are currently throwing an exception (did_throw), save it as
- * well. On an error not yet converted to an exception, update
- * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
- * This is needed for the do_cmdline() call that is going to be made
- * for autocommand execution. We need not save *msg_list because
- * there is an extra instance for every call of do_cmdline(), anyway.
+ if (did_emsg || got_int || current_exception || need_rethrow) {
+ csp->pending = (did_emsg ? CSTP_ERROR : 0)
+ | (got_int ? CSTP_INTERRUPT : 0)
+ | (current_exception ? CSTP_THROW : 0)
+ | (need_rethrow ? CSTP_THROW : 0);
+
+ /* If we are currently throwing an exception, save it as well. On an error
+ * not yet converted to an exception, update "force_abort" and reset
+ * "cause_abort" (as do_errthrow() would do). This is needed for the
+ * do_cmdline() call that is going to be made for autocommand execution. We
+ * need not save *msg_list because there is an extra instance for every call
+ * of do_cmdline(), anyway.
*/
- if (did_throw || need_rethrow)
+ if (current_exception || need_rethrow) {
csp->exception = current_exception;
- else {
+ } else {
csp->exception = NULL;
if (did_emsg) {
force_abort |= cause_abort;
cause_abort = FALSE;
}
}
- did_emsg = got_int = did_throw = need_rethrow = FALSE;
+ did_emsg = got_int = need_rethrow = false;
+ current_exception = NULL;
/* Report if required by the 'verbose' option or when debugging. */
report_make_pending(pending, csp->exception);
@@ -1857,19 +1846,20 @@ void leave_cleanup(cleanup_T *csp)
force_abort = FALSE;
}
- /*
- * Restore the pending values of did_emsg, got_int, and did_throw.
- */
- if (pending & CSTP_ERROR)
- did_emsg = TRUE;
- if (pending & CSTP_INTERRUPT)
- got_int = TRUE;
- if (pending & CSTP_THROW)
- need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
+ // Restore the pending values of did_emsg, got_int, and current_exception.
+ if (pending & CSTP_ERROR) {
+ did_emsg = true;
+ }
+ if (pending & CSTP_INTERRUPT) {
+ got_int = true;
+ }
+ if (pending & CSTP_THROW) {
+ need_rethrow = true; // current_exception will be set by do_one_cmd()
+ }
- /* Report if required by the 'verbose' option or when debugging. */
- report_resume_pending(pending,
- (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ // Report if required by the 'verbose' option or when debugging.
+ report_resume_pending(
+ pending, ((pending & CSTP_THROW) ? (void *)current_exception : NULL));
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index dd7504c05e..96388a2a9d 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -347,6 +347,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
redrawcmd();
}
+ // redraw the statusline for statuslines that display the current mode
+ // using the mode() function.
+ if (KeyTyped) {
+ curwin->w_redr_status = true;
+ redraw_statuslines();
+ }
+
did_emsg = false;
got_int = false;
s->state.check = command_line_check;
@@ -512,8 +519,12 @@ static int command_line_execute(VimState *state, int key)
CommandLineState *s = (CommandLineState *)state;
s->c = key;
- if (s->c == K_EVENT) {
- multiqueue_process_events(main_loop.events);
+ if (s->c == K_EVENT || s->c == K_COMMAND) {
+ if (s->c == K_EVENT) {
+ multiqueue_process_events(main_loop.events);
+ } else {
+ do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
+ }
redrawcmdline();
return 1;
}
@@ -3586,40 +3597,33 @@ nextwild (
xp->xp_pattern_len = ccline.cmdpos - i;
if (type == WILD_NEXT || type == WILD_PREV) {
- /*
- * Get next/previous match for a previous expanded pattern.
- */
+ // Get next/previous match for a previous expanded pattern.
p2 = ExpandOne(xp, NULL, NULL, 0, type);
} else {
- /*
- * Translate string into pattern and expand it.
- */
- if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len,
- xp->xp_context)) == NULL)
- p2 = NULL;
- else {
- int use_options = options |
- WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT;
- if (escape)
- use_options |= WILD_ESCAPE;
-
- if (p_wic)
- use_options += WILD_ICASE;
- p2 = ExpandOne(xp, p1,
- vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len),
- use_options, type);
- xfree(p1);
- /* longest match: make sure it is not shorter, happens with :help */
- if (p2 != NULL && type == WILD_LONGEST) {
- for (j = 0; j < xp->xp_pattern_len; ++j)
- if (ccline.cmdbuff[i + j] == '*'
- || ccline.cmdbuff[i + j] == '?')
- break;
- if ((int)STRLEN(p2) < j) {
- xfree(p2);
- p2 = NULL;
+ // Translate string into pattern and expand it.
+ p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context);
+ const int use_options = (
+ options
+ | WILD_HOME_REPLACE
+ | WILD_ADD_SLASH
+ | WILD_SILENT
+ | (escape ? WILD_ESCAPE : 0)
+ | (p_wic ? WILD_ICASE : 0));
+ p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len),
+ use_options, type);
+ xfree(p1);
+ // Longest match: make sure it is not shorter, happens with :help.
+ if (p2 != NULL && type == WILD_LONGEST) {
+ for (j = 0; j < xp->xp_pattern_len; j++) {
+ if (ccline.cmdbuff[i + j] == '*'
+ || ccline.cmdbuff[i + j] == '?') {
+ break;
}
}
+ if ((int)STRLEN(p2) < j) {
+ xfree(p2);
+ p2 = NULL;
+ }
}
}
@@ -4852,23 +4856,27 @@ void ExpandGeneric(
// copy the matching names into allocated memory
count = 0;
- for (i = 0;; ++i) {
+ for (i = 0;; i++) {
str = (*func)(xp, i);
- if (str == NULL) // end of list
+ if (str == NULL) { // End of list.
break;
- if (*str == NUL) // skip empty strings
+ }
+ if (*str == NUL) { // Skip empty strings.
continue;
+ }
if (vim_regexec(regmatch, str, (colnr_T)0)) {
- if (escaped)
+ if (escaped) {
str = vim_strsave_escaped(str, (char_u *)" \t\\.");
- else
+ } else {
str = vim_strsave(str);
+ }
(*file)[count++] = str;
- if (func == get_menu_names && str != NULL) {
- /* test for separator added by get_menu_names() */
+ if (func == get_menu_names) {
+ // Test for separator added by get_menu_names().
str += STRLEN(str) - 1;
- if (*str == '\001')
+ if (*str == '\001') {
*str = '.';
+ }
}
}
}
@@ -4923,13 +4931,14 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
flags |= EW_FILE | EW_EXEC | EW_SHELLCMD;
bool mustfree = false; // Track memory allocation for *path.
- /* For an absolute name we don't use $PATH. */
- if (path_is_absolute_path(pat))
+ // For an absolute name we don't use $PATH.
+ if (path_is_absolute(pat)) {
path = (char_u *)" ";
- else if ((pat[0] == '.' && (vim_ispathsep(pat[1])
- || (pat[1] == '.' && vim_ispathsep(pat[2])))))
+ } else if (pat[0] == '.' && (vim_ispathsep(pat[1])
+ || (pat[1] == '.'
+ && vim_ispathsep(pat[2])))) {
path = (char_u *)".";
- else {
+ } else {
path = (char_u *)vim_getenv("PATH");
if (path == NULL) {
path = (char_u *)"";
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index c6f2166dab..5b17b58781 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1541,26 +1541,30 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope)
char buf[8];
switch (scope) {
- case kCdScopeGlobal:
- snprintf(buf, sizeof(buf), "global");
- break;
- case kCdScopeTab:
- snprintf(buf, sizeof(buf), "tab");
- break;
- case kCdScopeWindow:
- snprintf(buf, sizeof(buf), "window");
- break;
- case kCdScopeInvalid:
- // Should never happen.
- assert(false);
+ case kCdScopeGlobal: {
+ snprintf(buf, sizeof(buf), "global");
+ break;
+ }
+ case kCdScopeTab: {
+ snprintf(buf, sizeof(buf), "tab");
+ break;
+ }
+ case kCdScopeWindow: {
+ snprintf(buf, sizeof(buf), "window");
+ break;
+ }
+ case kCdScopeInvalid: {
+ // Should never happen.
+ assert(false);
+ }
}
- tv_dict_add_str(dict, S_LEN("scope"), buf);
+ tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614
tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
tv_dict_set_keys_readonly(dict);
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
- NULL);
+ curbuf);
tv_dict_clear(dict);
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 91b0a695f1..efeee1ba2b 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1,9 +1,7 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * fileio.c: read from and write to a file
- */
+// fileio.c: read from and write to a file
#include <assert.h>
#include <errno.h>
@@ -65,57 +63,62 @@
#define BUFSIZE 8192 /* size of normal write buffer */
#define SMBUFSIZE 256 /* size of emergency write buffer */
-/*
- * The autocommands are stored in a list for each event.
- * Autocommands for the same pattern, that are consecutive, are joined
- * together, to avoid having to match the pattern too often.
- * The result is an array of Autopat lists, which point to AutoCmd lists:
- *
- * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
- * Autopat.cmds Autopat.cmds
- * | |
- * V V
- * AutoCmd.next AutoCmd.next
- * | |
- * V V
- * AutoCmd.next NULL
- * |
- * V
- * NULL
- *
- * first_autopat[1] --> Autopat.next --> NULL
- * Autopat.cmds
- * |
- * V
- * AutoCmd.next
- * |
- * V
- * NULL
- * etc.
- *
- * The order of AutoCmds is important, this is the order in which they were
- * defined and will have to be executed.
- */
+//
+// The autocommands are stored in a list for each event.
+// Autocommands for the same pattern, that are consecutive, are joined
+// together, to avoid having to match the pattern too often.
+// The result is an array of Autopat lists, which point to AutoCmd lists:
+//
+// last_autopat[0] -----------------------------+
+// V
+// first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
+// Autopat.cmds Autopat.cmds
+// | |
+// V V
+// AutoCmd.next AutoCmd.next
+// | |
+// V V
+// AutoCmd.next NULL
+// |
+// V
+// NULL
+//
+// last_autopat[1] --------+
+// V
+// first_autopat[1] --> Autopat.next --> NULL
+// Autopat.cmds
+// |
+// V
+// AutoCmd.next
+// |
+// V
+// NULL
+// etc.
+//
+// The order of AutoCmds is important, this is the order in which they were
+// defined and will have to be executed.
+//
typedef struct AutoCmd {
- char_u *cmd; /* The command to be executed (NULL
- when command has been removed) */
- char nested; /* If autocommands nest here */
- char last; /* last command in list */
- scid_T scriptID; /* script ID where defined */
- struct AutoCmd *next; /* Next AutoCmd in list */
+ char_u *cmd; // The command to be executed (NULL
+ // when command has been removed)
+ char nested; // If autocommands nest here
+ char last; // last command in list
+ scid_T scriptID; // script ID where defined
+ struct AutoCmd *next; // Next AutoCmd in list
} AutoCmd;
typedef struct AutoPat {
- char_u *pat; /* pattern as typed (NULL when pattern
- has been removed) */
- regprog_T *reg_prog; /* compiled regprog for pattern */
- AutoCmd *cmds; /* list of commands to do */
- struct AutoPat *next; /* next AutoPat in AutoPat list */
- int group; /* group ID */
- int patlen; /* strlen() of pat */
- int buflocal_nr; /* !=0 for buffer-local AutoPat */
- char allow_dirs; /* Pattern may match whole path */
- char last; /* last pattern for apply_autocmds() */
+ struct AutoPat *next; // next AutoPat in AutoPat list; MUST
+ // be the first entry
+ char_u *pat; // pattern as typed (NULL when pattern
+ // has been removed)
+ regprog_T *reg_prog; // compiled regprog for pattern
+ AutoCmd *cmds; // list of commands to do
+ int group; // group ID
+ int patlen; // strlen() of pat
+ int buflocal_nr; // !=0 for buffer-local AutoPat
+ char allow_dirs; // Pattern may match whole path
+ char last; // last pattern for apply_autocmds()
} AutoPat;
/*
@@ -226,6 +229,15 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
msg_scrolled_ign = FALSE;
}
+static AutoPat *last_autopat[NUM_EVENTS] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
/*
* Read lines from file "fname" into the buffer after line "from".
*
@@ -286,8 +298,7 @@ readfile (
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 */
+ int read_undo_file = false;
linenr_T linecnt;
int error = FALSE; /* errors encountered */
int ff_error = EOL_UNKNOWN; /* file format with errors */
@@ -1017,8 +1028,8 @@ retry:
size = size / ICONV_MULT; /* worst case */
if (conv_restlen > 0) {
- /* Insert unconverted bytes from previous line. */
- memmove(ptr, conv_rest, conv_restlen);
+ // Insert unconverted bytes from previous line.
+ memmove(ptr, conv_rest, conv_restlen); // -V614
ptr += conv_restlen;
size -= conv_restlen;
}
@@ -1725,9 +1736,17 @@ failed:
xfree(buffer);
if (read_stdin) {
- /* Use stderr for stdin, makes shell commands work. */
close(0);
+#ifndef WIN32
+ // On Unix, use stderr for stdin, makes shell commands work.
ignored = dup(2);
+#else
+ // On Windows, use the console input handle for stdin.
+ HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING, 0, (HANDLE)NULL);
+ ignored = _open_osfhandle(conin, _O_RDONLY);
+#endif
}
if (tmpname != NULL) {
@@ -1822,10 +1841,6 @@ failed:
STRCAT(IObuff, _("[CR missing]"));
c = TRUE;
}
- if (split) {
- STRCAT(IObuff, _("[long lines split]"));
- c = TRUE;
- }
if (notconverted) {
STRCAT(IObuff, _("[NOT converted]"));
c = TRUE;
@@ -3048,7 +3063,7 @@ nobackup:
*/
if (reset_changed && !newfile && overwriting
&& !(exiting && backup != NULL)) {
- ml_preserve(buf, FALSE);
+ ml_preserve(buf, false, !!p_fs);
if (got_int) {
SET_ERRMSG(_(e_interr));
goto restore_backup;
@@ -3332,9 +3347,9 @@ restore_backup:
*s++ = NL;
}
}
- if (++len == bufsize && end) {
+ if (++len == bufsize) {
if (buf_write_bytes(&write_info) == FAIL) {
- end = 0; /* write error: break loop */
+ end = 0; // Write error: break loop.
break;
}
nchars += bufsize;
@@ -3343,7 +3358,7 @@ restore_backup:
os_breakcheck();
if (got_int) {
- end = 0; /* Interrupted, break loop */
+ end = 0; // Interrupted, break loop.
break;
}
}
@@ -4318,7 +4333,7 @@ void shorten_fnames(int force)
&& !path_with_url((char *)buf->b_fname)
&& (force
|| buf->b_sfname == NULL
- || path_is_absolute_path(buf->b_sfname))) {
+ || path_is_absolute(buf->b_sfname))) {
xfree(buf->b_sfname);
buf->b_sfname = NULL;
p = path_shorten_fname(buf->b_ffname, dirname);
@@ -4440,7 +4455,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
/// @param size size of the buffer
/// @param fp file to read from
///
-/// @return true for end-of-file.
+/// @return true for EOF or error
bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
{
char *retval;
@@ -4451,7 +4466,7 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
do {
errno = 0;
retval = fgets((char *)buf, size, fp);
- } while (retval == NULL && errno == EINTR);
+ } while (retval == NULL && errno == EINTR && ferror(fp));
if (buf[size - 2] != NUL && buf[size - 2] != '\n') {
char tbuf[200];
@@ -4463,12 +4478,12 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
tbuf[sizeof(tbuf) - 2] = NUL;
errno = 0;
retval = fgets((char *)tbuf, sizeof(tbuf), fp);
- if (retval == NULL && errno != EINTR) {
+ if (retval == NULL && (feof(fp) || errno != EINTR)) {
break;
}
} while (tbuf[sizeof(tbuf) - 2] != NUL && tbuf[sizeof(tbuf) - 2] != '\n');
}
- return retval ? false : feof(fp);
+ return retval == NULL;
}
/// Read 2 bytes from "fd" and turn them into an int, MSB first.
@@ -5528,6 +5543,15 @@ static void au_cleanup(void)
/* remove the pattern if it has been marked for deletion */
if (ap->pat == NULL) {
+ if (ap->next == NULL) {
+ if (prev_ap == &(first_autopat[(int)event])) {
+ last_autopat[(int)event] = NULL;
+ } else {
+ // this depends on the "next" field being the first in
+ // the struct
+ last_autopat[(int)event] = (AutoPat *)prev_ap;
+ }
+ }
*prev_ap = ap->next;
vim_regfree(ap->reg_prog);
xfree(ap);
@@ -6120,10 +6144,13 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
}
- /*
- * Find AutoPat entries with this pattern.
- */
- prev_ap = &first_autopat[(int)event];
+ // Find AutoPat entries with this pattern. When adding a command it
+ // always goes at or after the last one, so start at the end.
+ if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) {
+ prev_ap = &last_autopat[(int)event];
+ } else {
+ prev_ap = &first_autopat[(int)event];
+ }
while ((ap = *prev_ap) != NULL) {
if (ap->pat != NULL) {
/* Accept a pattern when:
@@ -6209,6 +6236,7 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
}
ap->cmds = NULL;
*prev_ap = ap;
+ last_autopat[(int)event] = ap;
ap->next = NULL;
if (group == AUGROUP_ALL)
ap->group = current_augroup;
@@ -6655,7 +6683,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
char_u *save_autocmd_fname;
- int save_autocmd_fname_full;
int save_autocmd_bufnr;
char_u *save_autocmd_match;
int save_autocmd_busy;
@@ -6728,7 +6755,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
* Save the autocmd_* variables and info about the current buffer.
*/
save_autocmd_fname = autocmd_fname;
- save_autocmd_fname_full = autocmd_fname_full;
save_autocmd_bufnr = autocmd_bufnr;
save_autocmd_match = autocmd_match;
save_autocmd_busy = autocmd_busy;
@@ -6755,9 +6781,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
autocmd_fname = fname_io;
}
if (autocmd_fname != NULL) {
- autocmd_fname = vim_strsave(autocmd_fname);
+ // Allocate MAXPATHL for when eval_vars() resolves the fullpath.
+ autocmd_fname = vim_strnsave(autocmd_fname, MAXPATHL);
}
- autocmd_fname_full = false; // call FullName_save() later
/*
* Set the buffer number to be used for <abuf>.
@@ -6924,7 +6950,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
sourcing_lnum = save_sourcing_lnum;
xfree(autocmd_fname);
autocmd_fname = save_autocmd_fname;
- autocmd_fname_full = save_autocmd_fname_full;
autocmd_bufnr = save_autocmd_bufnr;
autocmd_match = save_autocmd_match;
current_SID = save_current_SID;
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index db88791967..ad9cd4d562 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1775,7 +1775,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
break;
}
if (*p != NUL) {
- p = transstr(text);
+ p = (char_u *)transstr((const char *)text);
xfree(text);
text = p;
}
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index b01321e713..2ee1e5d4c5 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -324,6 +324,8 @@ end
output = io.open(lua_c_bindings_outputf, 'wb')
output:write([[
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index d1a28ae3b0..07a65c2611 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -48,8 +48,14 @@
#include "nvim/event/loop.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
+#include "nvim/os/fileio.h"
#include "nvim/api/private/handle.h"
+
+/// Index in scriptin
+static int curscript = 0;
+FileDescriptor *scriptin[NSCRIPT] = { NULL };
+
/*
* These buffers are used for storing:
* - stuffed characters: A command that is translated into another command.
@@ -1243,10 +1249,13 @@ openscript (
++curscript;
/* use NameBuff for expanded name */
expand_env(name, NameBuff, MAXPATHL);
- if ((scriptin[curscript] = mch_fopen((char *)NameBuff, READBIN)) == NULL) {
- EMSG2(_(e_notopen), name);
- if (curscript)
- --curscript;
+ int error;
+ if ((scriptin[curscript] = file_open_new(&error, (char *)NameBuff,
+ kFileReadOnly, 0)) == NULL) {
+ emsgf(_(e_notopen_2), name, os_strerror(error));
+ if (curscript) {
+ curscript--;
+ }
return;
}
save_typebuf();
@@ -1296,7 +1305,7 @@ static void closescript(void)
free_typebuf();
typebuf = saved_typebuf[curscript];
- fclose(scriptin[curscript]);
+ file_free(scriptin[curscript], false);
scriptin[curscript] = NULL;
if (curscript > 0)
--curscript;
@@ -1319,10 +1328,8 @@ int using_script(void)
return scriptin[curscript] != NULL;
}
-/*
- * This function is called just before doing a blocking wait. Thus after
- * waiting 'updatetime' for a character to arrive.
- */
+/// This function is called just before doing a blocking wait. Thus after
+/// waiting 'updatetime' for a character to arrive.
void before_blocking(void)
{
updatescript(0);
@@ -1331,21 +1338,22 @@ void before_blocking(void)
}
}
-/*
- * updatescipt() is called when a character can be written into the script file
- * or when we have waited some time for a character (c == 0)
- *
- * All the changed memfiles are synced if c == 0 or when the number of typed
- * characters reaches 'updatecount' and 'updatecount' is non-zero.
- */
-void updatescript(int c)
+/// updatescript() is called when a character can be written to the script file
+/// or when we have waited some time for a character (c == 0).
+///
+/// All the changed memfiles are synced if c == 0 or when the number of typed
+/// characters reaches 'updatecount' and 'updatecount' is non-zero.
+static void updatescript(int c)
{
static int count = 0;
- if (c && scriptout)
+ if (c && scriptout) {
putc(c, scriptout);
- if (c == 0 || (p_uc > 0 && ++count >= p_uc)) {
- ml_sync_all(c == 0, TRUE);
+ }
+ bool idle = (c == 0);
+ if (idle || (p_uc > 0 && ++count >= p_uc)) {
+ ml_sync_all(idle, true,
+ (!!p_fs || idle)); // Always fsync at idle (CursorHold).
count = 0;
}
}
@@ -1577,7 +1585,7 @@ vungetc ( /* unget one character (can only be done once!) */
old_mouse_col = mouse_col;
}
-/// get a character:
+/// Gets a character:
/// 1. from the stuffbuffer
/// This is used for abbreviated commands like "D" -> "d$".
/// Also used to redo a command for ".".
@@ -1595,7 +1603,7 @@ vungetc ( /* unget one character (can only be done once!) */
/// if "advance" is FALSE (vpeekc()):
/// just look whether there is a character available.
///
-/// When "no_mapping" is zero, checks for mappings in the current mode.
+/// When `no_mapping` (global) is zero, checks for mappings in the current mode.
/// Only returns one byte (of a multi-byte character).
/// K_SPECIAL and CSI may be escaped, need to get two more bytes then.
static int vgetorpeek(int advance)
@@ -2346,9 +2354,8 @@ inchar (
int tb_change_cnt
)
{
- int len = 0; /* init for GCC */
- int retesc = FALSE; /* return ESC with gotint */
- int script_char;
+ int len = 0; // Init for GCC.
+ int retesc = false; // Return ESC with gotint.
if (wait_time == -1L || wait_time > 100L) {
// flush output before waiting
@@ -2366,45 +2373,38 @@ inchar (
}
undo_off = FALSE; /* restart undo now */
- /*
- * Get a character from a script file if there is one.
- * If interrupted: Stop reading script files, close them all.
- */
- script_char = -1;
- while (scriptin[curscript] != NULL && script_char < 0
- && !ignore_script
- ) {
-
-
- if (got_int || (script_char = getc(scriptin[curscript])) < 0) {
- /* Reached EOF.
- * Careful: closescript() frees typebuf.tb_buf[] and buf[] may
- * point inside typebuf.tb_buf[]. Don't use buf[] after this! */
+ // Get a character from a script file if there is one.
+ // If interrupted: Stop reading script files, close them all.
+ ptrdiff_t read_size = -1;
+ while (scriptin[curscript] != NULL && read_size <= 0 && !ignore_script) {
+ char script_char;
+ if (got_int
+ || (read_size = file_read(scriptin[curscript], &script_char, 1)) != 1) {
+ // Reached EOF or some error occurred.
+ // Careful: closescript() frees typebuf.tb_buf[] and buf[] may
+ // point inside typebuf.tb_buf[]. Don't use buf[] after this!
closescript();
- /*
- * When reading script file is interrupted, return an ESC to get
- * back to normal mode.
- * Otherwise return -1, because typebuf.tb_buf[] has changed.
- */
- if (got_int)
- retesc = TRUE;
- else
+ // When reading script file is interrupted, return an ESC to get
+ // back to normal mode.
+ // Otherwise return -1, because typebuf.tb_buf[] has changed.
+ if (got_int) {
+ retesc = true;
+ } else {
return -1;
+ }
} else {
buf[0] = (char_u)script_char;
len = 1;
}
}
- if (script_char < 0) { /* did not get a character from script */
- /*
- * If we got an interrupt, skip all previously typed characters and
- * return TRUE if quit reading script file.
- * Stop reading typeahead when a single CTRL-C was read,
- * fill_input_buf() returns this when not able to read from stdin.
- * Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
- * and buf may be pointing inside typebuf.tb_buf[].
- */
+ if (read_size <= 0) { // Did not get a character from script.
+ // If we got an interrupt, skip all previously typed characters and
+ // return TRUE if quit reading script file.
+ // Stop reading typeahead when a single CTRL-C was read,
+ // fill_input_buf() returns this when not able to read from stdin.
+ // Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
+ // and buf may be pointing inside typebuf.tb_buf[].
if (got_int) {
#define DUM_LEN MAXMAPLEN * 3 + 3
char_u dum[DUM_LEN + 1];
@@ -2417,21 +2417,18 @@ inchar (
return retesc;
}
- /*
- * Always flush the output characters when getting input characters
- * from the user.
- */
+ // Always flush the output characters when getting input characters
+ // from the user.
ui_flush();
- /*
- * Fill up to a third of the buffer, because each character may be
- * tripled below.
- */
+ // Fill up to a third of the buffer, because each character may be
+ // tripled below.
len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);
}
- if (typebuf_changed(tb_change_cnt))
+ if (typebuf_changed(tb_change_cnt)) {
return 0;
+ }
return fix_input_buffer(buf, len);
}
@@ -4257,3 +4254,70 @@ mapblock_T *get_maphash(int index, buf_T *buf)
return (buf == NULL) ? maphash[index] : buf->b_maphash[index];
}
+
+/// Get command argument for <Cmd> key
+char_u * getcmdkeycmd(int promptc, void *cookie, int indent)
+{
+ garray_T line_ga;
+ int c1 = -1, c2;
+ int cmod = 0;
+ bool aborted = false;
+
+ ga_init(&line_ga, 1, 32);
+
+ no_mapping++;
+
+ got_int = false;
+ while (c1 != NUL && !aborted) {
+ ga_grow(&line_ga, 32);
+
+ if (vgetorpeek(false) == NUL) {
+ // incomplete <Cmd> is an error, because there is not much the user
+ // could do in this state.
+ EMSG(e_cmdmap_err);
+ aborted = true;
+ break;
+ }
+
+ // Get one character at a time.
+ c1 = vgetorpeek(true);
+ // Get two extra bytes for special keys
+ if (c1 == K_SPECIAL) {
+ c1 = vgetorpeek(true); // no mapping for these chars
+ c2 = vgetorpeek(true);
+ if (c1 == KS_MODIFIER) {
+ cmod = c2;
+ continue;
+ }
+ c1 = TO_SPECIAL(c1, c2);
+ }
+
+
+ if (got_int) {
+ aborted = true;
+ } else if (c1 == '\r' || c1 == '\n') {
+ c1 = NUL; // end the line
+ } else if (c1 == ESC) {
+ aborted = true;
+ } else if (c1 == K_COMMAND) {
+ // special case to give nicer error message
+ EMSG(e_cmdmap_repeated);
+ aborted = true;
+ } else if (IS_SPECIAL(c1)) {
+ EMSG2(e_cmdmap_key, get_special_key_name(c1, cmod));
+ aborted = true;
+ } else {
+ ga_append(&line_ga, (char)c1);
+ }
+
+ cmod = 0;
+ }
+
+ no_mapping--;
+
+ if (aborted) {
+ ga_clear(&line_ga);
+ }
+
+ return (char_u *)line_ga.ga_data;
+}
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index e634273e0d..38a2e75663 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -1,24 +1,30 @@
#ifndef NVIM_GETCHAR_H
#define NVIM_GETCHAR_H
+#include "nvim/os/fileio.h"
#include "nvim/types.h"
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h"
-/// Values for "noremap" argument of ins_typebuf(). Also used for
-/// map->m_noremap and menu->noremap[].
-/// @addtogroup REMAP_VALUES
-/// @{
-#define REMAP_YES 0 ///< allow remapping
-#define REMAP_NONE -1 ///< no remapping
-#define REMAP_SCRIPT -2 ///< remap script-local mappings only
-#define REMAP_SKIP -3 ///< no remapping for first char
-/// @}
+/// Values for "noremap" argument of ins_typebuf()
+///
+/// Also used for map->m_noremap and menu->noremap[].
+enum {
+ REMAP_YES = 0, ///< Allow remapping.
+ REMAP_NONE = -1, ///< No remapping.
+ REMAP_SCRIPT = -2, ///< Remap script-local mappings only.
+ REMAP_SKIP = -3, ///< No remapping for first char.
+} RemapValues;
#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */
#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
+/// Maximum number of streams to read script from
+enum { NSCRIPT = 15 };
+
+/// Streams to read script from
+extern FileDescriptor *scriptin[NSCRIPT];
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "getchar.h.generated.h"
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 1856384ffa..ddc58c2425 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -16,8 +16,6 @@
#define IOSIZE (1024+1) // file I/O and sprintf buffer size
-#define MAX_MCO 6 // maximum value for 'maxcombine'
-
# define MSG_BUF_LEN 480 // length of buffer for small messages
# define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8
// takes 6 bytes for one cell)
@@ -80,6 +78,11 @@ typedef enum {
kTrue = 1,
} TriState;
+EXTERN struct nvim_stats_s {
+ int64_t fsync;
+ int64_t redraw;
+} g_stats INIT(= { 0, 0 });
+
/* Values for "starting" */
#define NO_SCREEN 2 /* no screen updating yet */
#define NO_BUFFERS 1 /* not all buffers loaded yet */
@@ -160,10 +163,6 @@ EXTERN u8char_T *ScreenLinesC[MAX_MCO]; /* composing characters */
EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when
allocating ScreenLinesC[] */
-/* Only used for euc-jp: Second byte of a character that starts with 0x8e.
- * These are single-width. */
-EXTERN schar_T *ScreenLines2 INIT(= NULL);
-
EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */
EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */
@@ -317,17 +316,11 @@ EXTERN int do_profiling INIT(= PROF_NONE); /* PROF_ values */
/*
* The exception currently being thrown. Used to pass an exception to
* a different cstack. Also used for discarding an exception before it is
- * caught or made pending. Only valid when did_throw is TRUE.
+ * caught or made pending.
*/
EXTERN except_T *current_exception;
/*
- * did_throw: An exception is being thrown. Reset when the exception is caught
- * or as long as it is pending in a finally clause.
- */
-EXTERN int did_throw INIT(= FALSE);
-
-/*
* need_rethrow: set to TRUE when a throw that cannot be handled in do_cmdline()
* must be propagated to the cstack of the previously called do_cmdline().
*/
@@ -397,16 +390,20 @@ EXTERN int may_garbage_collect INIT(= FALSE);
EXTERN int want_garbage_collect INIT(= FALSE);
EXTERN int garbage_collect_at_exit INIT(= FALSE);
-/* Special values for current_SID. */
-#define SID_MODELINE -1 /* when using a modeline */
-#define SID_CMDARG -2 /* for "--cmd" argument */
-#define SID_CARG -3 /* for "-c" argument */
-#define SID_ENV -4 /* for sourcing environment variable */
-#define SID_ERROR -5 /* option was reset because of an error */
-#define SID_NONE -6 /* don't set scriptID */
-
-/* ID of script being sourced or was sourced to define the current function. */
+// Special values for current_SID.
+#define SID_MODELINE -1 // when using a modeline
+#define SID_CMDARG -2 // for "--cmd" argument
+#define SID_CARG -3 // for "-c" argument
+#define SID_ENV -4 // for sourcing environment variable
+#define SID_ERROR -5 // option was reset because of an error
+#define SID_NONE -6 // don't set scriptID
+#define SID_LUA -7 // for Lua scripts/chunks
+#define SID_API_CLIENT -8 // for API clients
+
+// ID of script being sourced or was sourced to define the current function.
EXTERN scid_T current_SID INIT(= 0);
+// ID of the current channel making a client API call
+EXTERN uint64_t current_channel_id INIT(= 0);
EXTERN bool did_source_packages INIT(= false);
@@ -416,7 +413,7 @@ EXTERN struct caller_scope {
scid_T SID;
uint8_t *sourcing_name, *autocmd_fname, *autocmd_match;
linenr_T sourcing_lnum;
- int autocmd_fname_full, autocmd_bufnr;
+ int autocmd_bufnr;
void *funccalp;
} provider_caller_scope;
EXTERN int provider_call_nesting INIT(= 0);
@@ -547,10 +544,6 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer
#define FOR_ALL_BUFFERS_BACKWARDS(buf) \
for (buf_T *buf = lastbuf; buf != NULL; buf = buf->b_prev)
-/* Flag that is set when switching off 'swapfile'. It means that all blocks
- * are to be loaded into memory. Shouldn't be global... */
-EXTERN int mf_dont_release INIT(= FALSE); /* don't release blocks */
-
/*
* List of files being edited (global argument list). curwin->w_alist points
* to this when the window is using the global argument list.
@@ -722,7 +715,7 @@ EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
// mbyte flags that used to depend on 'encoding'. These are now deprecated, as
// 'encoding' is always "utf-8". Code that use them can be refactored to
// remove dead code.
-#define enc_dbcs false
+#define enc_dbcs 0
#define enc_utf8 true
#define has_mbyte true
@@ -840,10 +833,7 @@ EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
EXTERN int need_highlight_changed INIT(= true);
EXTERN char *used_shada_file INIT(= NULL); // name of the ShaDa file to use
-#define NSCRIPT 15
-EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
-EXTERN int curscript INIT(= 0); /* index in scriptin[] */
-EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
+EXTERN FILE *scriptout INIT(= NULL); ///< Stream to write script to.
// volatile because it is used in a signal handler.
EXTERN volatile int got_int INIT(= false); // set to true when interrupt
@@ -872,7 +862,6 @@ EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":)
EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "."
EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline
EXTERN char_u *autocmd_fname INIT(= NULL); // fname for <afile> on cmdline
-EXTERN int autocmd_fname_full; // autocmd_fname is full path
EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline
EXTERN char_u *autocmd_match INIT(= NULL); // name for <amatch> on cmdline
EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd
@@ -954,6 +943,7 @@ EXTERN int fill_stlnc INIT(= ' ');
EXTERN int fill_vert INIT(= 9474); // │
EXTERN int fill_fold INIT(= 183); // ·
EXTERN int fill_diff INIT(= '-');
+EXTERN int fill_msgsep INIT(= ' ');
/* Whether 'keymodel' contains "stopsel" and "startsel". */
EXTERN int km_stopsel INIT(= FALSE);
@@ -1076,7 +1066,6 @@ EXTERN char_u e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
EXTERN char_u e_noalt[] INIT(= N_("E23: No alternate file"));
EXTERN char_u e_noabbr[] INIT(= N_("E24: No such abbreviation"));
EXTERN char_u e_nobang[] INIT(= N_("E477: No ! allowed"));
-EXTERN char_u e_nogvim[] INIT(= N_("E25: Nvim does not have a built-in GUI"));
EXTERN char_u e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
EXTERN char_u e_noinstext[] INIT(= N_("E29: No inserted text yet"));
EXTERN char_u e_nolastcmd[] INIT(= N_("E30: No previous command line"));
@@ -1092,6 +1081,7 @@ EXTERN char_u e_norange[] INIT(= N_("E481: No range allowed"));
EXTERN char_u e_noroom[] INIT(= N_("E36: Not enough room"));
EXTERN char_u e_notmp[] INIT(= N_("E483: Can't get temp file name"));
EXTERN char_u e_notopen[] INIT(= N_("E484: Can't open file %s"));
+EXTERN char_u e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
EXTERN char_u e_notread[] INIT(= N_("E485: Can't read file %s"));
EXTERN char_u e_nowrtmsg[] INIT(= N_(
"E37: No write since last change (add ! to override)"));
@@ -1155,6 +1145,12 @@ EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long"));
EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String"));
EXTERN char_u e_autocmd_err[] INIT(=N_(
"E5500: autocmd has thrown an exception: %s"));
+EXTERN char_u e_cmdmap_err[] INIT(=N_(
+ "E5520: <Cmd> mapping must end with <CR>"));
+EXTERN char_u e_cmdmap_repeated[] INIT(=N_(
+ "E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
+EXTERN char_u e_cmdmap_key[] INIT(=N_(
+ "E5522: <Cmd> mapping must not include %s key"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 08157935f5..3518c8bdcc 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -87,6 +87,7 @@ typedef enum {
, HLF_QFL // selected quickfix line
, HLF_0 // Whitespace
, HLF_INACTIVE // NormalNC: Normal text in non-current windows
+ , HLF_MSGSEP // message separator line
, HLF_COUNT // MUST be the last one
} hlf_T;
@@ -137,7 +138,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_MC] = "ColorColumn",
[HLF_QFL] = "QuickFixLine",
[HLF_0] = "Whitespace",
- [HLF_INACTIVE] = "NormalNC"
+ [HLF_INACTIVE] = "NormalNC",
+ [HLF_MSGSEP] = "MsgSeparator",
});
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index b78b56562c..5d7bd26a2b 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1001,8 +1001,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
return FALSE;
}
- if (qfpos != NULL && *qfpos != '0' && totmatches > 0) {
- /* fill error list */
+ if (qfpos != NULL && *qfpos != '0') {
+ // Fill error list.
FILE *f;
char_u *tmp = vim_tempname();
qf_info_T *qi = NULL;
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 5e56e5f41b..628bfef221 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -285,6 +285,7 @@ static const struct key_name_entry {
{ K_SNR, "SNR" },
{ K_PLUG, "Plug" },
{ K_PASTE, "Paste" },
+ { K_COMMAND, "Cmd" },
{ 0, NULL }
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 04fc93e29e..c64691e8ea 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -243,6 +243,7 @@ enum key_extra {
, KE_EVENT // event
, KE_PASTE // special key to toggle the 'paste' option.
// sent only by UIs
+ , KE_COMMAND // special key to execute command in any mode
};
/*
@@ -431,6 +432,7 @@ enum key_extra {
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
+#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
/* Bits for modifier mask */
/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
@@ -441,7 +443,7 @@ enum key_extra {
#define MOD_MASK_2CLICK 0x20 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_3CLICK 0x40 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_4CLICK 0x60 // use MOD_MASK_MULTI_CLICK
-#define MOD_MASK_CMD 0x80 // "super" key (OSX/Mac: command-key)
+#define MOD_MASK_CMD 0x80 // "super" key (macOS: command-key)
#define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \
MOD_MASK_4CLICK)
diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h
index ad56c9237b..6d54c7f78d 100644
--- a/src/nvim/lib/kvec.h
+++ b/src/nvim/lib/kvec.h
@@ -142,6 +142,8 @@ static inline void *_memcpy_free(void *const restrict dest,
return dest;
}
+// -V:kvi_push:512
+
/// Resize vector with preallocated array
///
/// @note May not resize to an array smaller then init_array: if requested,
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 9e3063b164..5da6d2c0a0 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -423,7 +423,7 @@ nlua_pop_typval_table_processing_end:
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \
- TYPVAL_ENCODE_CONV_NIL()
+ TYPVAL_ENCODE_CONV_NIL(tv)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
do { \
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index c7952520b0..e1bbb03d3f 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -1,3 +1,62 @@
+-- Internal-only until comments in #8107 are addressed.
+-- Returns:
+-- {errcode}, {output}
+local function _system(cmd)
+ local out = vim.api.nvim_call_function('system', { cmd })
+ local err = vim.api.nvim_get_vvar('shell_error')
+ return err, out
+end
+
+-- Gets process info from the `ps` command.
+-- Used by nvim_get_proc() as a fallback.
+local function _os_proc_info(pid)
+ if pid == nil or pid <= 0 or type(pid) ~= 'number' then
+ error('invalid pid')
+ end
+ local cmd = { 'ps', '-p', pid, '-o', 'ucomm=', }
+ local err, name = _system(cmd)
+ if 1 == err and string.gsub(name, '%s*', '') == '' then
+ return {} -- Process not found.
+ elseif 0 ~= err then
+ local args_str = vim.api.nvim_call_function('string', { cmd })
+ error('command failed: '..args_str)
+ end
+ local _, ppid = _system({ 'ps', '-p', pid, '-o', 'ppid=', })
+ -- Remove trailing whitespace.
+ name = string.gsub(name, '%s+$', '')
+ ppid = string.gsub(ppid, '%s+$', '')
+ ppid = tonumber(ppid) == nil and -1 or tonumber(ppid)
+ return {
+ name = name,
+ pid = pid,
+ ppid = ppid,
+ }
+end
+
+-- Gets process children from the `pgrep` command.
+-- Used by nvim_get_proc_children() as a fallback.
+local function _os_proc_children(ppid)
+ if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then
+ error('invalid ppid')
+ end
+ local cmd = { 'pgrep', '-P', ppid, }
+ local err, rv = _system(cmd)
+ if 1 == err and string.gsub(rv, '%s*', '') == '' then
+ return {} -- Process not found.
+ elseif 0 ~= err then
+ local args_str = vim.api.nvim_call_function('string', { cmd })
+ error('command failed: '..args_str)
+ end
+ local children = {}
+ for s in string.gmatch(rv, '%S+') do
+ local i = tonumber(s)
+ if i ~= nil then
+ table.insert(children, i)
+ end
+ end
+ return children
+end
+
-- TODO(ZyX-I): Create compatibility layer.
--{{{1 package.path updater function
-- Last inserted paths. Used to clear out items from package.[c]path when they
@@ -58,7 +117,12 @@ local function _update_package_paths()
end
last_nvim_paths = cur_nvim_paths
end
---{{{1 Module definition
-return {
+
+local module = {
_update_package_paths = _update_package_paths,
+ _os_proc_children = _os_proc_children,
+ _os_proc_info = _os_proc_info,
+ _system = _system,
}
+
+return module
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 61834c6499..348df2d9b6 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -136,19 +136,24 @@
# define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
-/// Calculate the length of a C array.
+/// Calculate the length of a C array
///
/// This should be called with a real array. Calling this with a pointer is an
-/// error. A mechanism to detect many (though not all) of those errors at compile
-/// time is implemented. It works by the second division producing a division by
-/// zero in those cases (-Wdiv-by-zero in GCC).
-#define ARRAY_SIZE(arr) ((sizeof(arr)/sizeof((arr)[0])) / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+/// error. A mechanism to detect many (though not all) of those errors at
+/// compile time is implemented. It works by the second division producing
+/// a division by zero in those cases (-Wdiv-by-zero in GCC).
+#define ARRAY_SIZE(arr) \
+ ((sizeof(arr)/sizeof((arr)[0])) \
+ / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+
+/// Get last array entry
+///
+/// This should be called with a real array. Calling this with a pointer is an
+/// error.
+#define ARRAY_LAST_ENTRY(arr) (arr)[ARRAY_SIZE(arr) - 1]
// Duplicated in os/win_defs.h to avoid include-order sensitivity.
-#if defined(WIN32) && defined(RGB)
-# undef RGB
-#endif
-#define RGB(r, g, b) ((r << 16) | (g << 8) | b)
+#define RGB_(r, g, b) ((r << 16) | (g << 8) | b)
#define STR_(x) #x
#define STR(x) STR_(x)
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 4288d7f9d7..a4ed868af1 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -72,30 +72,30 @@
# include "nvim/os/pty_process_unix.h"
#endif
-/* Maximum number of commands from + or -c arguments. */
+// Maximum number of commands from + or -c arguments.
#define MAX_ARG_CMDS 10
-/* values for "window_layout" */
-#define WIN_HOR 1 /* "-o" horizontally split windows */
-#define WIN_VER 2 /* "-O" vertically split windows */
-#define WIN_TABS 3 /* "-p" windows on tab pages */
+// values for "window_layout"
+#define WIN_HOR 1 // "-o" horizontally split windows
+#define WIN_VER 2 // "-O" vertically split windows
+#define WIN_TABS 3 // "-p" windows on tab pages
-/* Struct for various parameters passed between main() and other functions. */
+// Struct for various parameters passed between main() and other functions.
typedef struct {
int argc;
char **argv;
char *use_vimrc; // vimrc from -u argument
- int n_commands; /* no. of commands from + or -c */
+ int n_commands; // no. of commands from + or -c
char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
- char_u cmds_tofree[MAX_ARG_CMDS]; /* commands that need free() */
- int n_pre_commands; /* no. of commands from --cmd */
+ char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
+ int n_pre_commands; // no. of commands from --cmd
char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
- int edit_type; /* type of editing to do */
- char_u *tagname; /* tag from -t argument */
- char_u *use_ef; /* 'errorfile' from -q argument */
+ int edit_type; // type of editing to do
+ char_u *tagname; // tag from -t argument
+ char_u *use_ef; // 'errorfile' from -q argument
int want_full_screen;
bool input_isatty; // stdin is a terminal
@@ -103,13 +103,15 @@ typedef struct {
bool err_isatty; // stderr is a terminal
int no_swap_file; // "-n" argument used
int use_debug_break_level;
- int window_count; /* number of windows to use */
- int window_layout; /* 0, WIN_HOR, WIN_VER or WIN_TABS */
+ int window_count; // number of windows to use
+ int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
#if !defined(UNIX)
- int literal; /* don't expand file names */
+ int literal; // don't expand file names
#endif
- int diff_mode; /* start with 'diff' set */
+ int diff_mode; // start with 'diff' set
+
+ char *listen_addr; // --listen {address}
} mparm_T;
/* Values for edit_type. */
@@ -150,7 +152,6 @@ void event_init(void)
signal_init();
// finish mspgack-rpc initialization
channel_init();
- server_init();
terminal_init();
}
@@ -241,9 +242,8 @@ int main(int argc, char **argv)
char_u *cwd = NULL; // current workding dir on startup
time_init();
- /* Many variables are in "params" so that we can pass them to invoked
- * functions without a lot of arguments. "argc" and "argv" are also
- * copied, so that they can be changed. */
+ // Many variables are in `params` so that we can pass them around easily.
+ // `argc` and `argv` are also copied, so that they can be changed.
init_params(&params, argc, argv);
init_startuptime(&params);
@@ -254,11 +254,10 @@ int main(int argc, char **argv)
check_and_set_isatty(&params);
event_init();
- /*
- * Process the command line arguments. File names are put in the global
- * argument list "global_alist".
- */
+ // Process the command line arguments. File names are put in the global
+ // argument list "global_alist".
command_line_scan(&params);
+ server_init(params.listen_addr);
if (GARGCOUNT > 0) {
fname = get_fname(&params, cwd);
@@ -726,9 +725,7 @@ static void init_locale(void)
#endif
-/*
- * Scan the command line arguments.
- */
+/// Scan the command line arguments.
static void command_line_scan(mparm_T *parmp)
{
int argc = parmp->argc;
@@ -790,7 +787,8 @@ static void command_line_scan(mparm_T *parmp)
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
FileDescriptor fp;
- const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, true);
+ const int fof_ret = file_open_fd(&fp, STDOUT_FILENO,
+ kFileWriteOnly);
msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
if (fof_ret != 0) {
@@ -819,6 +817,9 @@ static void command_line_scan(mparm_T *parmp)
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
abort();
}
+ } else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
+ want_argument = true;
+ argv_idx += 6;
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
#if !defined(UNIX)
parmp->literal = TRUE;
@@ -864,10 +865,6 @@ static void command_line_scan(mparm_T *parmp)
case 'f': /* "-f" GUI: run in foreground. */
break;
- case 'g': /* "-g" start GUI */
- main_start_gui();
- break;
-
case 'F': { // "-F" start in Farsi mode: rl + fkmap set.
p_fkmap = true;
set_option_value("rl", 1L, NULL, 0);
@@ -898,26 +895,17 @@ static void command_line_scan(mparm_T *parmp)
p_write = FALSE;
break;
- case 'N': /* "-N" Nocompatible */
- /* No-op */
+ case 'N': // "-N" Nocompatible
+ case 'X': // "-X" Do not connect to X server
+ // No-op
break;
case 'n': /* "-n" no swap file */
parmp->no_swap_file = TRUE;
break;
- case 'p': /* "-p[N]" open N tab pages */
-#ifdef TARGET_API_MAC_OSX
- /* For some reason on MacOS X, an argument like:
- -psn_0_10223617 is passed in when invoke from Finder
- or with the 'open' command */
- if (argv[0][argv_idx] == 's') {
- argv_idx = -1; /* bypass full -psn */
- main_start_gui();
- break;
- }
-#endif
- /* default is 0: open window for each file */
+ case 'p': // "-p[N]" open N tab pages
+ // default is 0: open window for each file
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
parmp->window_layout = WIN_TABS;
break;
@@ -1030,15 +1018,12 @@ static void command_line_scan(mparm_T *parmp)
mainerr(err_opt_unknown, argv[0]);
}
- /*
- * Handle option arguments with argument.
- */
+ // Handle option arguments with argument.
if (want_argument) {
- /*
- * Check for garbage immediately after the option letter.
- */
- if (argv[0][argv_idx] != NUL)
+ // Check for garbage immediately after the option letter.
+ if (argv[0][argv_idx] != NUL) {
mainerr(err_opt_garbage, argv[0]);
+ }
--argc;
if (argc < 1 && c != 'S') /* -S has an optional argument */
@@ -1077,13 +1062,17 @@ static void command_line_scan(mparm_T *parmp)
break;
case '-':
- if (argv[-1][2] == 'c') {
- /* "--cmd {command}" execute command */
- if (parmp->n_pre_commands >= MAX_ARG_CMDS)
+ if (strequal(argv[-1], "--cmd")) {
+ // "--cmd {command}" execute command
+ if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
+ }
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
+ } else if (strequal(argv[-1], "--listen")) {
+ // "--listen {address}"
+ parmp->listen_addr = argv[0];
}
- /* "--startuptime <file>" already handled */
+ // "--startuptime <file>" already handled
break;
case 'q': /* "-q {errorfile}" QuickFix mode */
@@ -1097,17 +1086,36 @@ static void command_line_scan(mparm_T *parmp)
case 's': /* "-s {scriptin}" read from script file */
if (scriptin[0] != NULL) {
scripterror:
- mch_errmsg(_("Attempt to open script file again: \""));
- mch_errmsg(argv[-1]);
- mch_errmsg(" ");
- mch_errmsg(argv[0]);
- mch_errmsg("\"\n");
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Attempt to open script file again: \"%s %s\"\n"),
+ argv[-1], argv[0]);
+ mch_errmsg((const char *)IObuff);
mch_exit(2);
}
- if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL) {
- mch_errmsg(_("Cannot open for reading: \""));
- mch_errmsg(argv[0]);
- mch_errmsg("\"\n");
+ int error;
+ if (STRCMP(argv[0], "-") == 0) {
+ const int stdin_dup_fd = os_dup(STDIN_FILENO);
+#ifdef WIN32
+ // On Windows, replace the original stdin with the
+ // console input handle.
+ close(STDIN_FILENO);
+ const HANDLE conin_handle =
+ CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING, 0, (HANDLE)NULL);
+ const int conin_fd = _open_osfhandle(conin_handle, _O_RDONLY);
+ assert(conin_fd == STDIN_FILENO);
+#endif
+ FileDescriptor *const stdin_dup = file_open_fd_new(
+ &error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
+ assert(stdin_dup != NULL);
+ scriptin[0] = stdin_dup;
+ } else if ((scriptin[0] = file_open_new(
+ &error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Cannot open for reading: \"%s\": %s\n"),
+ argv[0], os_strerror(error));
+ mch_errmsg((const char *)IObuff);
mch_exit(2);
}
save_typebuf();
@@ -1224,11 +1232,10 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
paramp->want_full_screen = true;
paramp->use_debug_break_level = -1;
paramp->window_count = -1;
+ paramp->listen_addr = NULL;
}
-/*
- * Initialize global startuptime file if "--startuptime" passed as an argument.
- */
+/// Initialize global startuptime file if "--startuptime" passed as an argument.
static void init_startuptime(mparm_T *paramp)
{
for (int i = 1; i < paramp->argc; i++) {
@@ -1834,17 +1841,6 @@ static void source_startup_scripts(const mparm_T *const parmp)
TIME_MSG("sourcing vimrc file(s)");
}
-/*
- * Setup to start using the GUI. Exit with an error when not available.
- */
-static void main_start_gui(void)
-{
- mch_errmsg(_(e_nogvim));
- mch_errmsg("\n");
- mch_exit(2);
-}
-
-
/// Get an environment variable, and execute it as Ex commands.
///
/// @param env environment variable to execute
@@ -1968,6 +1964,7 @@ static void usage(void)
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
mch_msg(_(" --headless Don't start a user interface\n"));
+ mch_msg(_(" --listen <address> Start RPC server at this address\n"));
#if !defined(UNIX)
mch_msg(_(" --literal Don't expand wildcards\n"));
#endif
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 047aa163ce..ac1239a548 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -8,6 +8,11 @@
#include "nvim/api/private/dispatch.h"
#include "nvim/bufhl_defs.h"
+#if defined(__NetBSD__)
+# undef uint64_t
+# define uint64_t uint64_t
+#endif
+
#define MAP_DECLS(T, U) \
KHASH_DECLARE(T##_##U##_map, T, U) \
\
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 008bce6df6..a52ab9f5d3 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -704,12 +704,14 @@ bool utf_composinglike(const char_u *p1, const char_u *p2)
return arabic_combine(utf_ptr2char(p1), c2);
}
-/*
- * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO
- * composing characters.
- *
- * @param [out] pcc: composing chars, last one is 0
- */
+/// Convert a UTF-8 string to a wide character
+///
+/// Also gets up to #MAX_MCO composing characters.
+///
+/// @param[out] pcc Location where to store composing characters. Must have
+/// space at least for #MAX_MCO + 1 elements.
+///
+/// @return leading character.
int utfc_ptr2char(const char_u *p, int *pcc)
{
int len;
@@ -1977,37 +1979,39 @@ char_u * enc_locale(void)
return NULL;
}
- /* The most generic locale format is:
- * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
- * If there is a '.' remove the part before it.
- * if there is something after the codeset, remove it.
- * Make the name lowercase and replace '_' with '-'.
- * Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn",
- * "ko_KR.EUC" == "euc-kr"
- */
+ // The most generic locale format is:
+ // language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
+ // If there is a '.' remove the part before it.
+ // if there is something after the codeset, remove it.
+ // Make the name lowercase and replace '_' with '-'.
+ // Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn",
+ // "ko_KR.EUC" == "euc-kr"
const char *p = (char *)vim_strchr((char_u *)s, '.');
if (p != NULL) {
if (p > s + 2 && !STRNICMP(p + 1, "EUC", 3)
&& !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') {
- /* copy "XY.EUC" to "euc-XY" to buf[10] */
- strcpy(buf + 10, "euc-");
- buf[14] = p[-2];
- buf[15] = p[-1];
- buf[16] = 0;
- s = buf + 10;
- } else
- s = p + 1;
- }
- for (i = 0; i < (int)sizeof(buf) - 1 && s[i] != NUL; i++) {
- if (s[i] == '_' || s[i] == '-') {
- buf[i] = '-';
- } else if (isalnum((int)s[i])) {
- buf[i] = TOLOWER_ASC(s[i]);
+ // Copy "XY.EUC" to "euc-XY" to buf[10].
+ memmove(buf, "euc-", 4);
+ buf[4] = (ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0);
+ buf[5] = (ASCII_ISALNUM(p[-1]) ? TOLOWER_ASC(p[-1]) : 0);
+ buf[6] = NUL;
} else {
- break;
+ s = p + 1;
+ goto enc_locale_copy_enc;
+ }
+ } else {
+enc_locale_copy_enc:
+ for (i = 0; i < (int)sizeof(buf) - 1 && s[i] != NUL; i++) {
+ if (s[i] == '_' || s[i] == '-') {
+ buf[i] = '-';
+ } else if (ASCII_ISALNUM((uint8_t)s[i])) {
+ buf[i] = TOLOWER_ASC(s[i]);
+ } else {
+ break;
+ }
}
+ buf[i] = NUL;
}
- buf[i] = NUL;
return enc_canonize((char_u *)buf);
}
diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h
index a5ce1b0a15..dd8e44b3f9 100644
--- a/src/nvim/mbyte.h
+++ b/src/nvim/mbyte.h
@@ -19,6 +19,13 @@
#define MB_BYTE2LEN(b) utf8len_tab[b]
#define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : utf8len_tab[b])
+/// Maximum value for 'maxcombine'
+///
+/// At most that number of composing characters may be attached to the leading
+/// character by various `utfc_*` functions. Note that some functions do not
+/// have this limit.
+enum { MAX_MCO = 6 };
+
// max length of an unicode char
#define MB_MAXCHAR 6
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 4eeba12b87..f6e03e2532 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -61,8 +61,6 @@
#define MEMFILE_PAGE_SIZE 4096 /// default page size
-static size_t total_mem_used = 0; /// total memory used for memfiles
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "memfile.c.generated.h"
#endif
@@ -99,7 +97,6 @@ memfile_T *mf_open(char_u *fname, int flags)
mfp->mf_used_first = NULL; // used list is empty
mfp->mf_used_last = NULL;
mfp->mf_dirty = false;
- mfp->mf_used_count = 0;
mf_hash_init(&mfp->mf_hash);
mf_hash_init(&mfp->mf_trans);
mfp->mf_page_size = MEMFILE_PAGE_SIZE;
@@ -136,25 +133,6 @@ memfile_T *mf_open(char_u *fname, int flags)
mfp->mf_neg_count = 0;
mfp->mf_infile_count = mfp->mf_blocknr_max;
- // Compute maximum number of pages ('maxmem' is in Kbytes):
- // 'mammem' * 1Kbyte / page-size-in-bytes.
- // Avoid overflow by first reducing page size as much as possible.
- {
- int shift = 10;
- unsigned page_size = mfp->mf_page_size;
-
- while (shift > 0 && (page_size & 1) == 0) {
- page_size /= 2;
- --shift;
- }
-
- assert(p_mm <= LONG_MAX >> shift); // check we don't overflow
- assert((uintmax_t)(p_mm << shift) <= UINT_MAX); // check we can cast safely
- mfp->mf_used_count_max = (unsigned)(p_mm << shift) / page_size;
- if (mfp->mf_used_count_max < 10)
- mfp->mf_used_count_max = 10;
- }
-
return mfp;
}
@@ -198,7 +176,6 @@ void mf_close(memfile_T *mfp, bool del_file)
// free entries in used list
for (bhdr_T *hp = mfp->mf_used_first, *nextp; hp != NULL; hp = nextp) {
- total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
nextp = hp->bh_next;
mf_free_bhdr(hp);
}
@@ -223,12 +200,9 @@ void mf_close_file(buf_T *buf, bool getlines)
if (getlines) {
// get all blocks in memory by accessing all lines (clumsy!)
- mf_dont_release = true;
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) {
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
(void)ml_get_buf(buf, lnum, false);
}
- mf_dont_release = false;
- // TODO(elmart): should check if all blocks are really in core
}
if (close(mfp->mf_fd) < 0) { // close the file
@@ -246,13 +220,6 @@ void mf_close_file(buf_T *buf, bool getlines)
/// and the size it indicates differs from what was guessed.
void mf_new_page_size(memfile_T *mfp, unsigned new_size)
{
- // Correct the memory used for block 0 to the new size, because it will be
- // freed with that size later on.
- if (new_size >= mfp->mf_page_size) {
- total_mem_used += new_size - mfp->mf_page_size;
- } else {
- total_mem_used -= mfp->mf_page_size - new_size;
- }
mfp->mf_page_size = new_size;
}
@@ -262,10 +229,7 @@ void mf_new_page_size(memfile_T *mfp, unsigned new_size)
/// @param page_count Desired number of pages.
bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count)
{
- // If we reached the maximum size for the used memory blocks, release one.
- // If a bhdr_T is returned, use it and adjust the page_count if necessary.
- // If no bhdr_T is returned, a new one will be created.
- bhdr_T *hp = mf_release(mfp, page_count); // the block to be returned
+ bhdr_T *hp = NULL;
// Decide on the number to use:
// If there is a free block, use its number.
@@ -273,34 +237,22 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count)
// a positive number.
bhdr_T *freep = mfp->mf_free_first; // first free block
if (!negative && freep != NULL && freep->bh_page_count >= page_count) {
- // If the block in the free list has more pages, take only the number
- // of pages needed and allocate a new bhdr_T with data.
- //
- // If the number of pages matches and mf_release() did not return a
- // bhdr_T, use the bhdr_T from the free list and allocate the data.
- //
- // If the number of pages matches and mf_release() returned a bhdr_T,
- // just use the number and free the bhdr_T from the free list
if (freep->bh_page_count > page_count) {
- if (hp == NULL) {
- hp = mf_alloc_bhdr(mfp, page_count);
- }
+ // If the block in the free list has more pages, take only the number
+ // of pages needed and allocate a new bhdr_T with data.
+ hp = mf_alloc_bhdr(mfp, page_count);
hp->bh_bnum = freep->bh_bnum;
freep->bh_bnum += page_count;
freep->bh_page_count -= page_count;
- } else if (hp == NULL) { // need to allocate memory for this block
+ } else { // need to allocate memory for this block
+ // If the number of pages matches use the bhdr_T from the free list and
+ // allocate the data.
void *p = xmalloc(mfp->mf_page_size * page_count);
hp = mf_rem_free(mfp);
hp->bh_data = p;
- } else { // use the number, remove entry from free list
- freep = mf_rem_free(mfp);
- hp->bh_bnum = freep->bh_bnum;
- xfree(freep);
}
} else { // get a new number
- if (hp == NULL) {
- hp = mf_alloc_bhdr(mfp, page_count);
- }
+ hp = mf_alloc_bhdr(mfp, page_count);
if (negative) {
hp->bh_bnum = mfp->mf_blocknr_min--;
mfp->mf_neg_count++;
@@ -341,13 +293,7 @@ bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, unsigned page_count)
// could check here if the block is in the free list
- // Check if we need to flush an existing block.
- // If so, use that block.
- // If not, allocate a new block.
- hp = mf_release(mfp, page_count);
- if (hp == NULL) {
- hp = mf_alloc_bhdr(mfp, page_count);
- }
+ hp = mf_alloc_bhdr(mfp, page_count);
hp->bh_bnum = nr;
hp->bh_flags = 0;
@@ -514,8 +460,6 @@ static void mf_ins_used(memfile_T *mfp, bhdr_T *hp)
} else {
hp->bh_next->bh_prev = hp;
}
- mfp->mf_used_count += hp->bh_page_count;
- total_mem_used += hp->bh_page_count * mfp->mf_page_size;
}
/// Remove block from memfile's used list.
@@ -530,82 +474,6 @@ static void mf_rem_used(memfile_T *mfp, bhdr_T *hp)
mfp->mf_used_first = hp->bh_next;
else
hp->bh_prev->bh_next = hp->bh_next;
-
- mfp->mf_used_count -= hp->bh_page_count;
- total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
-}
-
-/// Try to release the least recently used block from the used list if the
-/// number of used memory blocks gets too big.
-///
-/// @return The block header, when release needed and possible.
-/// Resulting block header includes memory block, so it can be
-/// reused. Page count is checked to be right.
-/// NULL, when release not needed, or not possible.
-/// Not needed when number of blocks less than allowed maximum and
-/// total memory used below 'maxmemtot'.
-/// Not possible when:
-/// - Called while closing file.
-/// - Tried to create swap file but couldn't.
-/// - All blocks are locked.
-/// - Unlocked dirty block found, but flush failed.
-static bhdr_T *mf_release(memfile_T *mfp, unsigned page_count)
-{
- // don't release while in mf_close_file()
- if (mf_dont_release)
- return NULL;
-
- /// Need to release a block if the number of blocks for this memfile is
- /// higher than the maximum one or total memory used is over 'maxmemtot'.
- bool need_release = (mfp->mf_used_count >= mfp->mf_used_count_max
- || (total_mem_used >> 10) >= (size_t)p_mmt);
-
- /// Try to create swap file if the amount of memory used is getting too high.
- if (mfp->mf_fd < 0 && need_release && p_uc) {
- // find for which buffer this memfile is
- buf_T *buf = NULL;
- FOR_ALL_BUFFERS(bp) {
- if (bp->b_ml.ml_mfp == mfp) {
- buf = bp;
- break;
- }
- }
- if (buf != NULL && buf->b_may_swap) {
- ml_open_file(buf);
- }
- }
-
- /// Don't release a block if:
- /// there is no file for this memfile
- /// or
- /// the number of blocks for this memfile is lower than the maximum
- /// and
- /// total memory used is not up to 'maxmemtot'
- if (mfp->mf_fd < 0 || !need_release)
- return NULL;
-
- bhdr_T *hp;
- for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
- if (!(hp->bh_flags & BH_LOCKED))
- break;
- if (hp == NULL) // not a single one that can be released
- return NULL;
-
- // If the block is dirty, write it.
- // If the write fails we don't free it.
- if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
- return NULL;
-
- mf_rem_used(mfp, hp);
- mf_rem_hash(mfp, hp);
-
- /// Make sure page_count of bh_data is right.
- if (hp->bh_page_count != page_count) {
- xfree(hp->bh_data);
- hp->bh_data = xmalloc(mfp->mf_page_size * page_count);
- hp->bh_page_count = page_count;
- }
- return hp;
}
/// Release as many blocks as possible.
diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h
index b3c2f3564c..2402d2147d 100644
--- a/src/nvim/memfile_defs.h
+++ b/src/nvim/memfile_defs.h
@@ -56,7 +56,6 @@ typedef struct mf_hashtab {
///
/// The used list is a doubly linked list, most recently used block first.
/// The blocks in the used list have a block of memory allocated.
-/// mf_used_count is the number of pages in the used list.
/// The hash lists are used to quickly find a block in the used list.
/// The free list is a single linked list, not sorted.
/// The blocks in the free list have no block of memory allocated and
@@ -95,8 +94,6 @@ typedef struct memfile {
bhdr_T *mf_free_first; /// first block header in free list
bhdr_T *mf_used_first; /// mru block header in used list
bhdr_T *mf_used_last; /// lru block header in used list
- unsigned mf_used_count; /// number of pages in used list
- unsigned mf_used_count_max; /// maximum number of pages in memory
mf_hashtab_T mf_hash; /// hash lists
mf_hashtab_T mf_trans; /// trans lists
blocknr_T mf_blocknr_max; /// highest positive block number + 1
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index c594782a1c..06de9fda67 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -843,8 +843,7 @@ void ml_recover(void)
mfp = mf_open(fname_used, O_RDONLY);
fname_used = p;
if (mfp == NULL || mfp->mf_fd < 0) {
- if (fname_used != NULL)
- EMSG2(_("E306: Cannot open %s"), fname_used);
+ EMSG2(_("E306: Cannot open %s"), fname_used);
goto theend;
}
buf->b_ml.ml_mfp = mfp;
@@ -1297,18 +1296,14 @@ recover_names (
msg_putchar('\n');
}
- /*
- * Do the loop for every directory in 'directory'.
- * First allocate some memory to put the directory name in.
- */
+ // Do the loop for every directory in 'directory'.
+ // First allocate some memory to put the directory name in.
dir_name = xmalloc(STRLEN(p_dir) + 1);
dirp = p_dir;
- while (dir_name != NULL && *dirp) {
- /*
- * Isolate a directory name from *dirp and put it in dir_name (we know
- * it is large enough, so use 31000 for length).
- * Advance dirp to next directory name.
- */
+ while (*dirp) {
+ // Isolate a directory name from *dirp and put it in dir_name (we know
+ // it is large enough, so use 31000 for length).
+ // Advance dirp to next directory name.
(void)copy_option_part(&dirp, dir_name, 31000, ",");
if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */
@@ -1330,7 +1325,7 @@ recover_names (
names[2] = (char_u *)concat_fnames((char *)dir_name, ".sw?", TRUE);
num_names = 3;
} else {
- int len = STRLEN(dir_name);
+ int len = (int)STRLEN(dir_name);
p = dir_name + len;
if (after_pathsep((char *)dir_name, (char *)p)
&& len > 1
@@ -1593,7 +1588,7 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
* If 'check_char' is TRUE, stop syncing when character becomes available, but
* always sync at least one block.
*/
-void ml_sync_all(int check_file, int check_char)
+void ml_sync_all(int check_file, int check_char, bool do_fsync)
{
FOR_ALL_BUFFERS(buf) {
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
@@ -1612,16 +1607,17 @@ void ml_sync_all(int check_file, int check_char)
if (!os_fileinfo((char *)buf->b_ffname, &file_info)
|| file_info.stat.st_mtim.tv_sec != buf->b_mtime_read
|| os_fileinfo_size(&file_info) != buf->b_orig_size) {
- ml_preserve(buf, FALSE);
- did_check_timestamps = FALSE;
- need_check_timestamps = TRUE; /* give message later */
+ ml_preserve(buf, false, do_fsync);
+ did_check_timestamps = false;
+ need_check_timestamps = true; // give message later
}
}
if (buf->b_ml.ml_mfp->mf_dirty) {
(void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
- | (bufIsChanged(buf) ? MFS_FLUSH : 0));
- if (check_char && os_char_avail()) /* character available now */
+ | (do_fsync && bufIsChanged(buf) ? MFS_FLUSH : 0));
+ if (check_char && os_char_avail()) { // character available now
break;
+ }
}
}
}
@@ -1636,7 +1632,7 @@ void ml_sync_all(int check_file, int check_char)
*
* when message is TRUE the success of preserving is reported
*/
-void ml_preserve(buf_T *buf, int message)
+void ml_preserve(buf_T *buf, int message, bool do_fsync)
{
bhdr_T *hp;
linenr_T lnum;
@@ -1654,9 +1650,9 @@ void ml_preserve(buf_T *buf, int message)
* before. */
got_int = FALSE;
- ml_flush_line(buf); /* flush buffered line */
- (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
- status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
+ ml_flush_line(buf); // flush buffered line
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block
+ status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0));
/* stack is invalid after mf_sync(.., MFS_ALL) */
buf->b_ml.ml_stack_top = 0;
@@ -1684,11 +1680,12 @@ void ml_preserve(buf_T *buf, int message)
CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
lnum = buf->b_ml.ml_locked_high + 1;
}
- (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
- /* sync the updated pointer blocks */
- if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block
+ // sync the updated pointer blocks
+ if (mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0)) == FAIL) {
status = FAIL;
- buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
+ }
+ buf->b_ml.ml_stack_top = 0; // stack is invalid now
}
theend:
got_int |= got_int_save;
@@ -1769,7 +1766,7 @@ errorret:
* Don't use the last used line when 'swapfile' is reset, need to load all
* blocks.
*/
- if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release) {
+ if (buf->b_ml.ml_line_lnum != lnum) {
ml_flush_line(buf);
/*
@@ -2770,9 +2767,8 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
if (buf->b_ml.ml_locked) {
if (ML_SIMPLE(action)
&& buf->b_ml.ml_locked_low <= lnum
- && buf->b_ml.ml_locked_high >= lnum
- && !mf_dont_release) {
- /* remember to update pointer blocks and stack later */
+ && buf->b_ml.ml_locked_high >= lnum) {
+ // remember to update pointer blocks and stack later
if (action == ML_INSERT) {
++(buf->b_ml.ml_locked_lineadd);
++(buf->b_ml.ml_locked_high);
@@ -3020,20 +3016,17 @@ int resolve_symlink(const char_u *fname, char_u *buf)
}
buf[ret] = NUL;
- /*
- * Check whether the symlink is relative or absolute.
- * If it's relative, build a new path based on the directory
- * portion of the filename (if any) and the path the symlink
- * points to.
- */
- if (path_is_absolute_path(buf))
+ // Check whether the symlink is relative or absolute.
+ // If it's relative, build a new path based on the directory
+ // portion of the filename (if any) and the path the symlink
+ // points to.
+ if (path_is_absolute(buf)) {
STRCPY(tmp, buf);
- else {
- char_u *tail;
-
- tail = path_tail(tmp);
- if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
+ } else {
+ char_u *tail = path_tail(tmp);
+ if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL) {
return FAIL;
+ }
STRCPY(tail, buf);
}
}
@@ -3058,7 +3051,7 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
#endif
- int len = STRLEN(dir_name);
+ int len = (int)STRLEN(dir_name);
s = dir_name + len;
if (after_pathsep((char *)dir_name, (char *)s)
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index a66ab6a3cc..bfc2f208dd 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -369,10 +369,12 @@ char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
/// string that fits in the buffer (unless, of course, the buffer size is
/// zero). It does not pad out the result like strncpy() does.
///
-/// @param dst Buffer to store the result
-/// @param src String to be copied
-/// @param dsize Size of `dst`
-/// @return strlen(src). If retval >= dstsize, truncation occurs.
+/// @param[out] dst Buffer to store the result.
+/// @param[in] src String to be copied.
+/// @param[in] dsize Size of `dst`.
+///
+/// @return Length of `src`. May be greater than `dsize - 1`, which would mean
+/// that string was truncated.
size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
FUNC_ATTR_NONNULL_ALL
{
@@ -394,11 +396,13 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
/// @see vim_strcat from Vim.
/// @see strlcat from OpenBSD.
///
-/// @param dst Buffer to be appended-to. Must have a NUL byte.
-/// @param src String to put at the end of `dst`
-/// @param dsize Size of `dst` including NUL byte. Must be greater than 0.
-/// @return strlen(src) + strlen(initial dst)
-/// If retval >= dsize, truncation occurs.
+/// @param[in,out] dst Buffer to be appended-to. Must have a NUL byte.
+/// @param[in] src String to put at the end of `dst`.
+/// @param[in] dsize Size of `dst` including NUL byte. Must be greater than 0.
+///
+/// @return Length of the resulting string as if destination size was #SIZE_MAX.
+/// May be greater than `dsize - 1`, which would mean that string was
+/// truncated.
size_t xstrlcat(char *const dst, const char *const src, const size_t dsize)
FUNC_ATTR_NONNULL_ALL
{
diff --git a/src/nvim/message.c b/src/nvim/message.c
index e522670a65..7ca82c2878 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -487,9 +487,6 @@ int emsg(const char_u *s_)
}
called_emsg = true;
- if (emsg_silent == 0) {
- ex_exitval = 1;
- }
// If "emsg_severe" is TRUE: When an error exception is to be thrown,
// prefer this message over previous messages for the same command.
@@ -540,6 +537,8 @@ int emsg(const char_u *s_)
return true;
}
+ ex_exitval = 1;
+
// Reset msg_silent, an error causes messages to be switched back on.
msg_silent = 0;
cmd_silent = FALSE;
@@ -1383,9 +1382,6 @@ const char *str2special(const char **const sp, const bool replace_spaces,
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
c = TO_SPECIAL((uint8_t)str[1], (uint8_t)str[2]);
str += 2;
- if (c == KS_ZERO) { // display <Nul> as ^@ or <Nul>
- c = NUL;
- }
}
if (IS_SPECIAL(c) || modifiers) { // Special key.
special = true;
@@ -1416,7 +1412,7 @@ const char *str2special(const char **const sp, const bool replace_spaces,
|| (replace_lt && c == '<')) {
return (const char *)get_special_key_name(c, modifiers);
}
- buf[0] = c;
+ buf[0] = (char)c;
buf[1] = NUL;
return buf;
}
@@ -1876,13 +1872,29 @@ bool message_filtered(char_u *msg)
return cmdmod.filter_force ? match : !match;
}
+/// including horizontal separator
+int msg_scrollsize(void)
+{
+ return msg_scrolled + p_ch + 1;
+}
+
/*
* Scroll the screen up one line for displaying the next message line.
*/
static void msg_scroll_up(void)
{
- /* scrolling up always works */
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ if (dy_flags & DY_MSGSEP) {
+ if (msg_scrolled == 0) {
+ screen_fill(Rows-p_ch-1, Rows-p_ch, 0, (int)Columns,
+ fill_msgsep, fill_msgsep, hl_attr(HLF_MSGSEP));
+ }
+ int nscroll = MIN(msg_scrollsize()+1, Rows);
+ ui_call_set_scroll_region(Rows-nscroll, Rows-1, 0, Columns-1);
+ screen_del_lines(Rows-nscroll, 0, 1, nscroll, NULL);
+ ui_reset_scroll_region();
+ } else {
+ screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ }
}
/*
@@ -2336,10 +2348,9 @@ static int do_more_prompt(int typed_char)
* yet. When stderr can't be used, collect error messages until the GUI has
* started and they can be displayed in a message box.
*/
-void mch_errmsg(char *str)
+void mch_errmsg(const char *const str)
+ FUNC_ATTR_NONNULL_ALL
{
- int len;
-
#ifdef UNIX
/* On Unix use stderr if it's a tty.
* When not going to start the GUI also use stderr.
@@ -2353,14 +2364,13 @@ void mch_errmsg(char *str)
/* avoid a delay for a message that isn't there */
emsg_on_display = FALSE;
- len = (int)STRLEN(str) + 1;
+ const size_t len = strlen(str) + 1;
if (error_ga.ga_data == NULL) {
ga_set_growsize(&error_ga, 80);
error_ga.ga_itemsize = 1;
}
ga_grow(&error_ga, len);
- memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
- (char_u *)str, len);
+ memmove(error_ga.ga_data + error_ga.ga_len, str, len);
#ifdef UNIX
/* remove CR characters, they are displayed */
{
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index b0232b6516..28455f0ba9 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -2643,7 +2643,7 @@ void preserve_exit(void)
if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
mch_errmsg((uint8_t *)"Vim: preserving files...\n");
ui_flush();
- ml_sync_all(false, false); // preserve all swap files
+ ml_sync_all(false, false, true); // preserve all swap files
break;
}
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 6548d351a6..cb13a9e207 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -672,7 +672,7 @@ int win_col_off(win_T *wp)
return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
+ (cmdwin_type == 0 || wp != curwin ? 0 : 1)
+ (int)wp->w_p_fdc
- + (signcolumn_on(wp) ? 2 : 0);
+ + (signcolumn_on(wp) ? win_signcol_width(wp) : 0);
}
int curwin_col_off(void)
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 9bf122f4db..e5d80aea1d 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -32,26 +32,27 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
#endif
/// Initializes the module
-bool server_init(void)
+bool server_init(const char *listen_addr)
{
ga_init(&watchers, sizeof(SocketWatcher *), 1);
- bool must_free = false;
- const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- if (listen_address == NULL) {
- must_free = true;
- listen_address = server_address_new();
- }
+ // $NVIM_LISTEN_ADDRESS
+ const char *env_addr = os_getenv(LISTEN_ADDRESS_ENV_VAR);
+ int rv = listen_addr == NULL ? 1 : server_start(listen_addr);
- if (!listen_address) {
- return false;
+ if (0 != rv) {
+ rv = env_addr == NULL ? 1 : server_start(env_addr);
+ if (0 != rv) {
+ listen_addr = server_address_new();
+ if (listen_addr == NULL) {
+ return false;
+ }
+ rv = server_start(listen_addr);
+ xfree((char *)listen_addr);
+ }
}
- bool ok = (server_start(listen_address) == 0);
- if (must_free) {
- xfree((char *) listen_address);
- }
- return ok;
+ return rv == 0;
}
/// Teardown a single server
@@ -120,8 +121,8 @@ bool server_owns_pipe_address(const char *path)
/// @param endpoint Address of the server. Either a 'ip:[port]' string or an
/// arbitrary identifier (trimmed to 256 bytes) for the Unix
/// socket or named pipe.
-/// @returns 0 on success, 1 on a regular error, and negative errno
-/// on failure to bind or listen.
+/// @returns 0: success, 1: validation error, 2: already listening,
+/// -errno: failed to bind or listen.
int server_start(const char *endpoint)
{
if (endpoint == NULL || endpoint[0] == '\0') {
@@ -145,7 +146,7 @@ int server_start(const char *endpoint)
uv_freeaddrinfo(watcher->uv.tcp.addrinfo);
}
socket_watcher_close(watcher, free_server);
- return 1;
+ return 2;
}
}
@@ -177,7 +178,7 @@ int server_start(const char *endpoint)
/// Stops listening on the address specified by `endpoint`.
///
/// @param endpoint Address of the server.
-void server_stop(char *endpoint)
+bool server_stop(char *endpoint)
{
SocketWatcher *watcher;
bool watcher_found = false;
@@ -196,8 +197,8 @@ void server_stop(char *endpoint)
}
if (!watcher_found) {
- ELOG("Not listening on %s", addr);
- return;
+ WLOG("Not listening on %s", addr);
+ return false;
}
// Unset $NVIM_LISTEN_ADDRESS if it is the stopped address.
@@ -219,6 +220,8 @@ void server_stop(char *endpoint)
if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
set_vservername(&watchers);
}
+
+ return true;
}
/// Returns an allocated array of server addresses.
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index fbbc8248e8..e4310de5d8 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -345,6 +345,7 @@ static const struct nv_cmd {
{ K_F8, farsi_f8, 0, 0 },
{ K_F9, farsi_f9, 0, 0 },
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
+ { K_COMMAND, nv_colon, 0, 0 },
};
/* Number of commands in nv_cmds[]. */
@@ -1473,13 +1474,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
AppendToRedobuffLit(cap->searchbuf, -1);
}
AppendToRedobuff(NL_STR);
- } else if (cap->cmdchar == ':') {
- /* do_cmdline() has stored the first typed line in
- * "repeat_cmdline". When several lines are typed repeating
- * won't be possible. */
- if (repeat_cmdline == NULL)
+ } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) {
+ // do_cmdline() has stored the first typed line in
+ // "repeat_cmdline". When several lines are typed repeating
+ // won't be possible.
+ if (repeat_cmdline == NULL) {
ResetRedobuff();
- else {
+ } else {
AppendToRedobuffLit(repeat_cmdline, -1);
AppendToRedobuff(NL_STR);
xfree(repeat_cmdline);
@@ -4524,23 +4525,22 @@ static void nv_exmode(cmdarg_T *cap)
}
}
-/*
- * Handle a ":" command.
- */
+/// Handle a ":" command and <Cmd>.
static void nv_colon(cmdarg_T *cap)
{
int old_p_im;
bool cmd_result;
+ bool is_cmdkey = cap->cmdchar == K_COMMAND;
- if (VIsual_active)
+ if (VIsual_active && !is_cmdkey) {
nv_operator(cap);
- else {
+ } else {
if (cap->oap->op_type != OP_NOP) {
// Using ":" as a movement is characterwise exclusive.
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
- } else if (cap->count0) {
- /* translate "count:" into ":.,.+(count - 1)" */
+ } else if (cap->count0 && !is_cmdkey) {
+ // translate "count:" into ":.,.+(count - 1)"
stuffcharReadbuff('.');
if (cap->count0 > 1) {
stuffReadbuff(",.+");
@@ -4554,9 +4554,9 @@ static void nv_colon(cmdarg_T *cap)
old_p_im = p_im;
- /* get a command line and execute it */
- cmd_result = do_cmdline(NULL, getexline, NULL,
- cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
+ // get a command line and execute it
+ cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
+ cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
/* If 'insertmode' changed, enter or exit Insert mode */
if (p_im != old_p_im) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b421d81b7e..b39b139f9b 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3568,7 +3568,7 @@ int do_join(size_t count,
int *comments = NULL;
int remove_comments = (use_formatoptions == TRUE)
&& has_format_option(FO_REMOVE_COMS);
- bool prev_was_comment;
+ bool prev_was_comment = false;
if (save_undo && u_save(curwin->w_cursor.lnum - 1,
curwin->w_cursor.lnum + (linenr_T)count) == FAIL) {
@@ -3592,17 +3592,16 @@ int do_join(size_t count,
curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr);
}
if (remove_comments) {
- /* We don't want to remove the comment leader if the
- * previous line is not a comment. */
+ // We don't want to remove the comment leader if the
+ // previous line is not a comment.
if (t > 0 && prev_was_comment) {
-
- char_u *new_curr = skip_comment(curr, TRUE, insert_space,
- &prev_was_comment);
+ char_u *new_curr = skip_comment(curr, true, insert_space,
+ &prev_was_comment);
comments[t] = (int)(new_curr - curr);
curr = new_curr;
- } else
- curr = skip_comment(curr, FALSE, insert_space,
- &prev_was_comment);
+ } else {
+ curr = skip_comment(curr, false, insert_space, &prev_was_comment);
+ }
}
if (insert_space && t > 0) {
@@ -3891,9 +3890,6 @@ fex_format (
// Make a copy, the option could be changed while calling it.
fex = vim_strsave(curbuf->b_p_fex);
- if (fex == NULL) {
- return 0;
- }
// Evaluate the function.
if (use_sandbox) {
sandbox++;
@@ -4610,9 +4606,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
}
}
curwin->w_cursor.col = col;
- if (!did_change) {
- startpos = curwin->w_cursor;
- }
+ startpos = curwin->w_cursor;
did_change = true;
(void)del_char(false);
ins_char(firstdigit);
@@ -4687,9 +4681,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// Delete the old number.
curwin->w_cursor.col = col;
- if (!did_change) {
- startpos = curwin->w_cursor;
- }
+ startpos = curwin->w_cursor;
did_change = true;
todel = length;
c = gchar_cursor();
@@ -4716,9 +4708,6 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// When there are many leading zeros it could be very long.
// Allocate a bit too much.
buf1 = xmalloc((size_t)length + NUMBUFLEN);
- if (buf1 == NULL) {
- goto theend;
- }
ptr = buf1;
if (negative && (!visual || was_positive)) {
*ptr++ = '-';
@@ -4754,7 +4743,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n);
- } else if (pre && hexupper) {
+ } else if (hexupper) {
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n);
} else {
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n);
@@ -4775,18 +4764,16 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
ins_str(buf1); // insert the new number
xfree(buf1);
endpos = curwin->w_cursor;
- if (did_change && curwin->w_cursor.col) {
+ if (curwin->w_cursor.col) {
curwin->w_cursor.col--;
}
}
- if (did_change) {
- // set the '[ and '] marks
- curbuf->b_op_start = startpos;
- curbuf->b_op_end = endpos;
- if (curbuf->b_op_end.col > 0) {
- curbuf->b_op_end.col--;
- }
+ // set the '[ and '] marks
+ curbuf->b_op_start = startpos;
+ curbuf->b_op_end = endpos;
+ if (curbuf->b_op_end.col > 0) {
+ curbuf->b_op_end.col--;
}
theend:
@@ -5764,7 +5751,7 @@ static void set_clipboard(int name, yankreg_T *reg)
list_T *args = tv_list_alloc(3);
tv_list_append_list(args, lines);
- tv_list_append_string(args, &regtype, 1);
+ tv_list_append_string(args, &regtype, 1); // -V614
tv_list_append_string(args, ((char[]) { (char)name }), 1);
(void)eval_call_provider("clipboard", "set", args);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d6903c8db7..1da259e6b8 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -13,7 +13,8 @@
// add some code to didset_window_options().
// - For a buffer option, add some code to buf_copy_options().
// - For a buffer string option, add code to check_buf_options().
-// - If it's a numeric option, add any necessary bounds checks to do_set().
+// - If it's a numeric option, add any necessary bounds checks to
+// set_num_option().
// - If it's a list of flags, add some code in do_set(), search for WW_ALL.
// - When adding an option with expansion (P_EXPAND), but with a different
// default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
@@ -186,16 +187,16 @@ static long p_tw_nopaste;
static long p_wm_nopaste;
typedef struct vimoption {
- char *fullname; /* full option name */
- char *shortname; /* permissible abbreviation */
- uint32_t flags; /* see below */
- char_u *var; /* global option: pointer to variable;
- * window-local option: VAR_WIN;
- * buffer-local option: global value */
- idopt_T indir; /* global option: PV_NONE;
- * local option: indirect option index */
- char_u *def_val[2]; /* default values for variable (vi and vim) */
- scid_T scriptID; /* script in which the option was last set */
+ char *fullname; // full option name
+ char *shortname; // permissible abbreviation
+ uint32_t flags; // see below
+ char_u *var; // global option: pointer to variable;
+ // window-local option: VAR_WIN;
+ // buffer-local option: global value
+ idopt_T indir; // global option: PV_NONE;
+ // local option: indirect option index
+ char_u *def_val[2]; // default values for variable (vi and vim)
+ LastSet last_set; // script in which the option was last set
# define SCRIPTID_INIT , 0
} vimoption_T;
@@ -618,27 +619,6 @@ void set_init_1(void)
}
}
- /*
- * 'maxmemtot' and 'maxmem' may have to be adjusted for available memory
- */
- opt_idx = findoption("maxmemtot");
- if (opt_idx >= 0) {
- {
- /* Use half of amount of memory available to Vim. */
- /* If too much to fit in uintptr_t, get uintptr_t max */
- uint64_t available_kib = os_get_total_mem_kib();
- uintptr_t n = available_kib / 2 > UINTPTR_MAX
- ? UINTPTR_MAX
- : (uintptr_t)(available_kib /2);
- options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
- opt_idx = findoption("maxmem");
- if (opt_idx >= 0) {
- options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
- }
- }
- }
-
-
{
char_u *cdpath;
char_u *buf;
@@ -1365,15 +1345,16 @@ do_set (
if (opt_idx >= 0) {
showoneopt(&options[opt_idx], opt_flags);
if (p_verbose > 0) {
- /* Mention where the option was last set. */
- if (varp == options[opt_idx].var)
- last_set_msg(options[opt_idx].scriptID);
- else if ((int)options[opt_idx].indir & PV_WIN)
- last_set_msg(curwin->w_p_scriptID[
- (int)options[opt_idx].indir & PV_MASK]);
- else if ((int)options[opt_idx].indir & PV_BUF)
- last_set_msg(curbuf->b_p_scriptID[
- (int)options[opt_idx].indir & PV_MASK]);
+ // Mention where the option was last set.
+ if (varp == options[opt_idx].var) {
+ option_last_set_msg(options[opt_idx].last_set);
+ } else if ((int)options[opt_idx].indir & PV_WIN) {
+ option_last_set_msg(curwin->w_p_scriptID[
+ (int)options[opt_idx].indir & PV_MASK]);
+ } else if ((int)options[opt_idx].indir & PV_BUF) {
+ option_last_set_msg(curbuf->b_p_scriptID[
+ (int)options[opt_idx].indir & PV_MASK]);
+ }
}
} else {
errmsg = (char_u *)N_("E846: Key code not set");
@@ -1467,8 +1448,7 @@ do_set (
goto skip;
}
} else if (*arg == '-' || ascii_isdigit(*arg)) {
- // Allow negative (for 'undolevels'), octal and
- // hex numbers.
+ // Allow negative, octal and hex numbers.
vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg;
@@ -3411,6 +3391,7 @@ static char_u *set_chars_option(char_u **varp)
{ &fill_vert, "vert" , 9474 }, // │
{ &fill_fold, "fold" , 183 }, // ·
{ &fill_diff, "diff" , '-' },
+ { &fill_msgsep, "msgsep", ' ' },
};
static struct charstab lcstab[] = {
{ &lcs_eol, "eol", NUL },
@@ -3662,16 +3643,19 @@ static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int indir = (int)options[opt_idx].indir;
+ const LastSet last_set = { id, current_channel_id };
- /* Remember where the option was set. For local options need to do that
- * in the buffer or window structure. */
- if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0)
- options[opt_idx].scriptID = id;
+ // Remember where the option was set. For local options need to do that
+ // in the buffer or window structure.
+ if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) {
+ options[opt_idx].last_set = last_set;
+ }
if (both || (opt_flags & OPT_LOCAL)) {
- if (indir & PV_BUF)
- curbuf->b_p_scriptID[indir & PV_MASK] = id;
- else if (indir & PV_WIN)
- curwin->w_p_scriptID[indir & PV_MASK] = id;
+ if (indir & PV_BUF) {
+ curbuf->b_p_scriptID[indir & PV_MASK] = last_set;
+ } else if (indir & PV_WIN) {
+ curwin->w_p_scriptID[indir & PV_MASK] = last_set;
+ }
}
}
@@ -4089,238 +4073,251 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
return (char *)e_secure;
}
- *pp = value;
- /* Remember where the option was set. */
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
-
- if (curbuf->b_p_sw < 0) {
- errmsg = e_positive;
- curbuf->b_p_sw = curbuf->b_p_ts;
+ // Many number options assume their value is in the signed int range.
+ if (value < INT_MIN || value > INT_MAX) {
+ return (char *)e_invarg;
}
- /*
- * Number options that need some action when changed
- */
- if (pp == &p_wh || pp == &p_hh) {
- if (p_wh < 1) {
+ // Options that need some validation.
+ if (pp == &p_wh) {
+ if (value < 1) {
errmsg = e_positive;
- p_wh = 1;
- }
- if (p_wmh > p_wh) {
+ } else if (p_wmh > value) {
errmsg = e_winheight;
- p_wh = p_wmh;
}
- if (p_hh < 0) {
+ } else if (pp == &p_hh) {
+ if (value < 0) {
errmsg = e_positive;
- p_hh = 0;
- }
-
- /* Change window height NOW */
- if (!ONE_WINDOW) {
- if (pp == &p_wh && curwin->w_height < p_wh)
- win_setheight((int)p_wh);
- if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
- win_setheight((int)p_hh);
}
- }
- /* 'winminheight' */
- else if (pp == &p_wmh) {
- if (p_wmh < 0) {
+ } else if (pp == &p_wmh) {
+ if (value < 0) {
errmsg = e_positive;
- p_wmh = 0;
- }
- if (p_wmh > p_wh) {
+ } else if (value > p_wh) {
errmsg = e_winheight;
- p_wmh = p_wh;
}
- win_setminheight();
} else if (pp == &p_wiw) {
- if (p_wiw < 1) {
+ if (value < 1) {
errmsg = e_positive;
- p_wiw = 1;
+ } else if (p_wmw > value) {
+ errmsg = e_winwidth;
}
- if (p_wmw > p_wiw) {
+ } else if (pp == &p_wmw) {
+ if (value < 0) {
+ errmsg = e_positive;
+ } else if (value > p_wiw) {
errmsg = e_winwidth;
- p_wiw = p_wmw;
}
-
- /* Change window width NOW */
- if (!ONE_WINDOW && curwin->w_width < p_wiw)
- win_setwidth((int)p_wiw);
- }
- /* 'winminwidth' */
- else if (pp == &p_wmw) {
- if (p_wmw < 0) {
+ } else if (pp == &p_mco) {
+ if (value > MAX_MCO) {
+ errmsg = e_invarg;
+ } else if (value < 0) {
errmsg = e_positive;
- p_wmw = 0;
}
- if (p_wmw > p_wiw) {
- errmsg = e_winwidth;
- p_wmw = p_wiw;
+ } else if (pp == &p_titlelen) {
+ if (value < 0) {
+ errmsg = e_positive;
}
- win_setminheight();
- } else if (pp == &p_ls) {
- /* (re)set last window status line */
- last_status(false);
- }
- /* (re)set tab page line */
- else if (pp == &p_stal) {
- shell_new_rows(); /* recompute window positions and heights */
- }
- /* 'foldlevel' */
- else if (pp == &curwin->w_p_fdl) {
- if (curwin->w_p_fdl < 0)
- curwin->w_p_fdl = 0;
- newFoldLevel();
- }
- /* 'foldminlines' */
- else if (pp == &curwin->w_p_fml) {
- foldUpdateAll(curwin);
- }
- /* 'foldnestmax' */
- else if (pp == &curwin->w_p_fdn) {
- if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
- foldUpdateAll(curwin);
- }
- /* 'foldcolumn' */
- else if (pp == &curwin->w_p_fdc) {
- if (curwin->w_p_fdc < 0) {
+ } else if (pp == &p_uc) {
+ if (value < 0) {
errmsg = e_positive;
- curwin->w_p_fdc = 0;
- } else if (curwin->w_p_fdc > 12) {
- errmsg = e_invarg;
- curwin->w_p_fdc = 12;
}
- // 'shiftwidth' or 'tabstop'
- } else if (pp == &curbuf->b_p_sw || pp == (long *)&curbuf->b_p_ts) {
- if (foldmethodIsIndent(curwin)) {
- foldUpdateAll(curwin);
+ } else if (pp == &p_ch) {
+ if (value < 1) {
+ errmsg = e_positive;
}
- // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
- // parse 'cinoptions'.
- if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
- parse_cino(curbuf);
+ } else if (pp == &p_tm) {
+ if (value < 0) {
+ errmsg = e_positive;
}
- }
- /* 'maxcombine' */
- else if (pp == &p_mco) {
- if (p_mco > MAX_MCO)
- p_mco = MAX_MCO;
- else if (p_mco < 0)
- p_mco = 0;
- screenclear(); /* will re-allocate the screen */
- } else if (pp == &curbuf->b_p_iminsert) {
- if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST) {
+ } else if (pp == &p_hi) {
+ if (value < 0) {
+ errmsg = e_positive;
+ } else if (value > 10000) {
errmsg = e_invarg;
- curbuf->b_p_iminsert = B_IMODE_NONE;
}
- p_iminsert = curbuf->b_p_iminsert;
- showmode();
- /* Show/unshow value of 'keymap' in status lines. */
- status_redraw_curbuf();
- } else if (pp == &p_window) {
- if (p_window < 1)
- p_window = 1;
- else if (p_window >= Rows)
- p_window = Rows - 1;
- } else if (pp == &curbuf->b_p_imsearch) {
- if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST) {
+ } else if (pp == &p_re) {
+ if (value < 0 || value > 2) {
errmsg = e_invarg;
- curbuf->b_p_imsearch = B_IMODE_NONE;
}
- p_imsearch = curbuf->b_p_imsearch;
- } else if (pp == &p_channel || pp == &curbuf->b_p_channel) {
- errmsg = e_invarg;
- *pp = old_value;
- }
- /* if 'titlelen' has changed, redraw the title */
- else if (pp == &p_titlelen) {
- if (p_titlelen < 0) {
+ } else if (pp == &p_report) {
+ if (value < 0) {
errmsg = e_positive;
- p_titlelen = 85;
}
- if (starting != NO_SCREEN && old_value != p_titlelen)
- need_maketitle = TRUE;
- }
- /* if p_ch changed value, change the command line height */
- else if (pp == &p_ch) {
- if (p_ch < 1) {
+ } else if (pp == &p_so) {
+ if (value < 0 && full_screen) {
+ errmsg = e_scroll;
+ }
+ } else if (pp == &p_siso) {
+ if (value < 0 && full_screen) {
errmsg = e_positive;
- p_ch = 1;
}
- if (p_ch > Rows - min_rows() + 1)
- p_ch = Rows - min_rows() + 1;
-
- /* Only compute the new window layout when startup has been
- * completed. Otherwise the frame sizes may be wrong. */
- if (p_ch != old_value && full_screen
- )
- command_height();
- }
- /* when 'updatecount' changes from zero to non-zero, open swap files */
- else if (pp == &p_uc) {
- if (p_uc < 0) {
+ } else if (pp == &p_cwh) {
+ if (value < 1) {
errmsg = e_positive;
- p_uc = 100;
}
- if (p_uc && !old_value)
- ml_open_files();
- } else if (pp == &curwin->w_p_cole) {
- if (curwin->w_p_cole < 0) {
+ } else if (pp == &p_ut) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &p_ss) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curwin->w_p_fdl || pp == &curwin->w_allbuf_opt.wo_fdl) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) {
+ if (value < 0) {
+ errmsg = e_positive;
+ } else if (value > 12) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) {
+ if (value < 0) {
errmsg = e_positive;
- curwin->w_p_cole = 0;
- } else if (curwin->w_p_cole > 3) {
+ } else if (value > 3) {
errmsg = e_invarg;
- curwin->w_p_cole = 3;
- }
- }
- /* sync undo before 'undolevels' changes */
- else if (pp == &p_ul) {
- /* use the old value, otherwise u_sync() may not work properly */
- p_ul = old_value;
- u_sync(TRUE);
- p_ul = value;
- } else if (pp == &curbuf->b_p_ul) {
- /* use the old value, otherwise u_sync() may not work properly */
- curbuf->b_p_ul = old_value;
- u_sync(TRUE);
- curbuf->b_p_ul = value;
- }
- /* 'numberwidth' must be positive */
- else if (pp == &curwin->w_p_nuw) {
- if (curwin->w_p_nuw < 1) {
+ }
+ } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) {
+ if (value < 1) {
errmsg = e_positive;
- curwin->w_p_nuw = 1;
+ } else if (value > 10) {
+ errmsg = e_invarg;
}
- if (curwin->w_p_nuw > 10) {
+ } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) {
+ if (value < 0 || value > B_IMODE_LAST) {
errmsg = e_invarg;
- curwin->w_p_nuw = 10;
}
- curwin->w_nrwidth_line_count = 0;
- } else if (pp == &curbuf->b_p_tw) {
- if (curbuf->b_p_tw < 0) {
+ } else if (pp == &curbuf->b_p_imsearch || pp == &p_imsearch) {
+ if (value < -1 || value > B_IMODE_LAST) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curbuf->b_p_channel || pp == &p_channel) {
+ errmsg = e_invarg;
+ } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
+ if (value < -1 || value > SB_MAX
+ || (value != -1 && opt_flags == OPT_LOCAL && !curbuf->terminal)) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curbuf->b_p_sw || pp == &p_sw) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curbuf->b_p_ts || pp == &p_ts) {
+ if (value < 1) {
errmsg = e_positive;
- curbuf->b_p_tw = 0;
}
+ } else if (pp == &curbuf->b_p_tw || pp == &p_tw) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ }
+
+ // Don't change the value and return early if validation failed.
+ if (errmsg != NULL) {
+ return (char *)errmsg;
+ }
+
+ *pp = value;
+ // Remember where the option was set.
+ set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
+
+ // For these options we want to fix some invalid values.
+ if (pp == &p_window) {
+ if (p_window < 1) {
+ p_window = Rows - 1;
+ } else if (p_window >= Rows) {
+ p_window = Rows - 1;
+ }
+ } else if (pp == &p_ch) {
+ if (p_ch > Rows - min_rows() + 1) {
+ p_ch = Rows - min_rows() + 1;
+ }
+ }
+ // Number options that need some action when changed
+ if (pp == &p_wh) {
+ if (!ONE_WINDOW && curwin->w_height < p_wh) {
+ win_setheight((int)p_wh);
+ }
+ } else if (pp == &p_hh) {
+ if (!ONE_WINDOW && curbuf->b_help && curwin->w_height < p_hh) {
+ win_setheight((int)p_hh);
+ }
+ } else if (pp == &p_wmh) {
+ win_setminheight();
+ } else if (pp == &p_wiw) {
+ if (!ONE_WINDOW && curwin->w_width < p_wiw) {
+ win_setwidth((int)p_wiw);
+ }
+ } else if (pp == &p_ls) {
+ last_status(false); // (re)set last window status line.
+ } else if (pp == &p_stal) {
+ // (re)set tab page line
+ shell_new_rows(); // recompute window positions and heights
+ } else if (pp == &curwin->w_p_fdl) {
+ newFoldLevel();
+ } else if (pp == &curwin->w_p_fml) {
+ foldUpdateAll(curwin);
+ } else if (pp == &curwin->w_p_fdn) {
+ if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) {
+ // 'shiftwidth' or 'tabstop'
+ if (foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
+ // parse 'cinoptions'.
+ if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
+ parse_cino(curbuf);
+ }
+ } else if (pp == &p_mco) {
+ screenclear(); // will re-allocate the screen
+ } else if (pp == &curbuf->b_p_iminsert) {
+ showmode();
+ // Show/unshow value of 'keymap' in status lines.
+ status_redraw_curbuf();
+ } else if (pp == &p_titlelen) {
+ // if 'titlelen' has changed, redraw the title
+ if (starting != NO_SCREEN && old_value != p_titlelen) {
+ need_maketitle = true;
+ }
+ } else if (pp == &p_ch) {
+ // if p_ch changed value, change the command line height
+ // Only compute the new window layout when startup has been
+ // completed. Otherwise the frame sizes may be wrong.
+ if (p_ch != old_value && full_screen) {
+ command_height();
+ }
+ } else if (pp == &p_uc) {
+ // when 'updatecount' changes from zero to non-zero, open swap files
+ if (p_uc && !old_value) {
+ ml_open_files();
+ }
+ } else if (pp == &p_ul || pp == &curbuf->b_p_ul) {
+ // sync undo before 'undolevels' changes
+ // use the old value, otherwise u_sync() may not work properly
+ *pp = old_value;
+ u_sync(true);
+ *pp = value;
+ } else if (pp == &curbuf->b_p_tw) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
check_colorcolumn(wp);
}
} else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
- // 'scrollback'
- if (*pp < -1 || *pp > SB_MAX
- || (*pp != -1 && opt_flags == OPT_LOCAL && !curbuf->terminal)) {
- errmsg = e_invarg;
- *pp = old_value;
- } else if (curbuf->terminal) {
+ if (curbuf->terminal) {
// Force the scrollback to take effect.
terminal_resize(curbuf->terminal, UINT16_MAX, UINT16_MAX);
}
+ } else if (pp == &curwin->w_p_nuw) {
+ curwin->w_nrwidth_line_count = 0;
}
- /*
- * Check the bounds for numeric options here
- */
+
+ // Check the (new) bounds for Rows and Columns here.
if (Rows < min_rows() && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
@@ -4340,19 +4337,17 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
limit_screen_size();
- /*
- * If the screen (shell) height has been changed, assume it is the
- * physical screenheight.
- */
+ // If the screen (shell) height has been changed, assume it is the
+ // physical screenheight.
if (old_Rows != Rows || old_Columns != Columns) {
- /* Changing the screen size is not allowed while updating the screen. */
+ // Changing the screen size is not allowed while updating the screen.
if (updating_screen) {
*pp = old_value;
} else if (full_screen) {
screen_resize((int)Columns, (int)Rows);
} else {
- /* Postpone the resizing; check the size and cmdline position for
- * messages. */
+ // Postpone the resizing; check the size and cmdline position for
+ // messages.
check_shellsize();
if (cmdline_row > Rows - p_ch && Rows > p_ch) {
assert(p_ch >= 0 && Rows - p_ch <= INT_MAX);
@@ -4364,14 +4359,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
}
}
- if (curbuf->b_p_ts <= 0) {
- errmsg = e_positive;
- curbuf->b_p_ts = 8;
- }
- if (p_tm < 0) {
- errmsg = e_positive;
- p_tm = 0;
- }
if ((curwin->w_p_scr <= 0
|| (curwin->w_p_scr > curwin->w_height
&& curwin->w_height > 0))
@@ -4388,21 +4375,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
else /* curwin->w_p_scr > curwin->w_height */
curwin->w_p_scr = curwin->w_height;
}
- if (p_hi < 0) {
- errmsg = e_positive;
- p_hi = 0;
- } else if (p_hi > 10000) {
- errmsg = e_invarg;
- p_hi = 10000;
- }
- if (p_re < 0 || p_re > 2) {
- errmsg = e_invarg;
- p_re = 0;
- }
- if (p_report < 0) {
- errmsg = e_positive;
- p_report = 1;
- }
if ((p_sj < -100 || p_sj >= Rows) && full_screen) {
if (Rows != old_Rows) /* Rows changed, just adjust p_sj */
p_sj = Rows / 2;
@@ -4411,30 +4383,11 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
p_sj = 1;
}
}
- if (p_so < 0 && full_screen) {
- errmsg = e_scroll;
- p_so = 0;
- }
- if (p_siso < 0 && full_screen) {
- errmsg = e_positive;
- p_siso = 0;
- }
- if (p_cwh < 1) {
- errmsg = e_positive;
- p_cwh = 1;
- }
- if (p_ut < 0) {
- errmsg = e_positive;
- p_ut = 2000;
- }
- if (p_ss < 0) {
- errmsg = e_positive;
- p_ss = 0;
- }
- /* May set global value for local option. */
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+ // May set global value for local option.
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
+ }
if (pp == &curbuf->b_p_scbk && !curbuf->terminal) {
// Normal buffer: reset local 'scrollback' after updating the global value.
@@ -5823,25 +5776,28 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_ro = FALSE; /* don't copy readonly */
buf->b_p_fenc = vim_strsave(p_fenc);
switch (*p_ffs) {
- case 'm':
- buf->b_p_ff = vim_strsave((char_u *)FF_MAC);
- break;
- case 'd':
- buf->b_p_ff = vim_strsave((char_u *)FF_DOS);
- break;
- case 'u':
- buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
- break;
- default:
- buf->b_p_ff = vim_strsave(p_ff);
- }
- if (buf->b_p_ff != NULL) {
- buf->b_start_ffc = *buf->b_p_ff;
+ case 'm': {
+ buf->b_p_ff = vim_strsave((char_u *)FF_MAC);
+ break;
+ }
+ case 'd': {
+ buf->b_p_ff = vim_strsave((char_u *)FF_DOS);
+ break;
+ }
+ case 'u': {
+ buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
+ break;
+ }
+ default: {
+ buf->b_p_ff = vim_strsave(p_ff);
+ break;
+ }
}
buf->b_p_bh = empty_option;
buf->b_p_bt = empty_option;
- } else
- free_buf_options(buf, FALSE);
+ } else {
+ free_buf_options(buf, false);
+ }
buf->b_p_ai = p_ai;
buf->b_p_ai_nopaste = p_ai_nopaste;
@@ -6102,7 +6058,7 @@ set_context_in_set_cmd (
xp->xp_context = EXPAND_UNSUCCESSFUL;
return;
}
- if (xp->xp_context != EXPAND_BOOL_SETTINGS && p[1] == NUL) {
+ if (p[1] == NUL) {
xp->xp_context = EXPAND_OLD_SETTING;
if (is_term_option)
expand_option_idx = -1;
@@ -6246,14 +6202,15 @@ void ExpandOldSetting(int *num_file, char_u ***file)
}
if (expand_option_idx >= 0) {
- /* put string of option value in NameBuff */
+ // Put string of option value in NameBuff.
option_value2string(&options[expand_option_idx], expand_option_flags);
var = NameBuff;
- } else if (var == NULL)
+ } else {
var = (char_u *)"";
+ }
- /* A backslash is required before some characters. This is the reverse of
- * what happens in do_set(). */
+ // A backslash is required before some characters. This is the reverse of
+ // what happens in do_set().
char_u *buf = vim_strsave_escaped(var, escape_chars);
#ifdef BACKSLASH_IN_FILENAME
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index e2e98f251e..f7dfa65053 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -3,6 +3,7 @@
#include "nvim/types.h"
#include "nvim/macros.h" // For EXTERN
+#include "eval/typval.h" // For scid_T
// option_defs.h: definition of global variables for settable options
@@ -394,11 +395,13 @@ EXTERN char_u *p_dir; /* 'directory' */
EXTERN char_u *p_dy; /* 'display' */
EXTERN unsigned dy_flags;
#ifdef IN_OPTION_C
-static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", NULL };
+static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", "msgsep",
+ NULL };
#endif
#define DY_LASTLINE 0x001
#define DY_TRUNCATE 0x002
#define DY_UHEX 0x004
+#define DY_MSGSEP 0x008
EXTERN int p_ed; // 'edcompatible'
EXTERN int p_emoji; // 'emoji'
EXTERN char_u *p_ead; // 'eadirection'
@@ -496,9 +499,7 @@ EXTERN long p_mat; // 'matchtime'
EXTERN long p_mco; // 'maxcombine'
EXTERN long p_mfd; // 'maxfuncdepth'
EXTERN long p_mmd; // 'maxmapdepth'
-EXTERN long p_mm; // 'maxmem'
EXTERN long p_mmp; // 'maxmempattern'
-EXTERN long p_mmt; // 'maxmemtot'
EXTERN long p_mis; // 'menuitems'
EXTERN char_u *p_msm; // 'mkspellmem'
EXTERN long p_mls; // 'modelines'
@@ -819,4 +820,10 @@ enum {
#define SB_MAX 100000 // Maximum 'scrollback' value.
+/// Stores an identifier of a script or channel that last set an option.
+typedef struct {
+ scid_T script_id; /// Script ID or one of SID_* special values.
+ uint64_t channel_id; /// Only used when script_id is SID_API_CLIENT.
+} LastSet;
+
#endif // NVIM_OPTION_DEFS_H
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 34ff810410..f1f559fff0 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -642,7 +642,7 @@ return {
vim=true,
redraw={'all_windows'},
varname='p_dy',
- defaults={if_true={vi="", vim="lastline"}}
+ defaults={if_true={vi="", vim="lastline,msgsep"}}
},
{
full_name='eadirection', abbreviation='ead',
@@ -976,7 +976,7 @@ return {
secure=true,
vi_def=true,
varname='p_fs',
- defaults={if_true={vi=true}}
+ defaults={if_true={vi=false}}
},
{
full_name='gdefault', abbreviation='gd',
@@ -1512,13 +1512,6 @@ return {
defaults={if_true={vi=1000}}
},
{
- full_name='maxmem', abbreviation='mm',
- type='number', scope={'global'},
- vi_def=true,
- varname='p_mm',
- defaults={if_true={vi=macros('DFLT_MAXMEM')}}
- },
- {
full_name='maxmempattern', abbreviation='mmp',
type='number', scope={'global'},
vi_def=true,
@@ -1526,13 +1519,6 @@ return {
defaults={if_true={vi=1000}}
},
{
- full_name='maxmemtot', abbreviation='mmt',
- type='number', scope={'global'},
- vi_def=true,
- varname='p_mmt',
- defaults={if_true={vi=macros('DFLT_MAXMEMTOT')}}
- },
- {
full_name='menuitems', abbreviation='mis',
type='number', scope={'global'},
vi_def=true,
@@ -2048,7 +2034,7 @@ return {
varname='p_shcf',
defaults={
condition='WIN32',
- if_true={vi="/c"},
+ if_true={vi="/s /c"},
if_false={vi="-c"}
}
},
@@ -2104,7 +2090,11 @@ return {
secure=true,
vi_def=true,
varname='p_sxq',
- defaults={if_true={vi=""}}
+ defaults={
+ condition='WIN32',
+ if_true={vi="\""},
+ if_false={vi=""},
+ }
},
{
full_name='shellxescape', abbreviation='sxe',
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 999fcd434a..7fb4a93b54 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -14,6 +14,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/path.h"
+#include "nvim/macros.h"
#include "nvim/strings.h"
#include "nvim/eval.h"
#include "nvim/ex_getln.h"
@@ -176,7 +177,7 @@ void os_get_hostname(char *hostname, size_t size)
/// - do os_dirname() to get the real name of that directory.
/// This also works with mounts and links.
/// Don't do this for Windows, it will change the "current dir" for a drive.
-static char_u *homedir = NULL;
+static char *homedir = NULL;
void init_homedir(void)
{
@@ -220,7 +221,7 @@ void init_homedir(void)
}
}
#endif
- homedir = vim_strsave((char_u *)var);
+ homedir = xstrdup(var);
}
}
@@ -357,7 +358,7 @@ void expand_env_esc(char_u *restrict srcp,
} else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
- var = homedir;
+ var = (char_u *)homedir;
tail = src + 1;
} else { // user directory
#if defined(UNIX)
@@ -719,108 +720,123 @@ char *vim_getenv(const char *name)
/// Replace home directory by "~" in each space or comma separated file name in
/// 'src'.
+///
+/// Replace home directory with tilde in each file name
+///
/// If anything fails (except when out of space) dst equals src.
-/// @param buf When not NULL, check for help files
-/// @param src Input file name
-/// @param dst Where to put the result
-/// @param dstlen Maximum length of the result
-/// @param one If true, only replace one file name, including spaces and commas
-/// in the file name
-void home_replace(const buf_T *const buf, const char_u *src,
- char_u *dst, size_t dstlen, bool one)
+///
+/// @param[in] buf When not NULL, uses this buffer to check whether it is
+/// a help file. If it is then path to file is removed
+/// completely, `one` is ignored and assumed to be true.
+/// @param[in] src Input file names. Assumed to be a space/comma separated
+/// list unless `one` is true.
+/// @param[out] dst Where to put the result.
+/// @param[in] dstlen Destination length.
+/// @param[in] one If true, assumes source is a single file name and not
+/// a list of them.
+///
+/// @return length of the string put into dst, does not include NUL byte.
+size_t home_replace(const buf_T *const buf, const char_u *src,
+ char_u *const dst, size_t dstlen, const bool one)
+ FUNC_ATTR_NONNULL_ARG(3)
{
- size_t dirlen = 0, envlen = 0;
- size_t len;
+ size_t dirlen = 0;
+ size_t envlen = 0;
if (src == NULL) {
*dst = NUL;
- return;
+ return 0;
}
- /*
- * If the file is a help file, remove the path completely.
- */
if (buf != NULL && buf->b_help) {
- xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
- return;
+ const size_t dlen = xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
+ return MIN(dlen, dstlen - 1);
}
- /*
- * We check both the value of the $HOME environment variable and the
- * "real" home directory.
- */
- if (homedir != NULL)
- dirlen = STRLEN(homedir);
+ // We check both the value of the $HOME environment variable and the
+ // "real" home directory.
+ if (homedir != NULL) {
+ dirlen = strlen(homedir);
+ }
- char_u *homedir_env = (char_u *)os_getenv("HOME");
+ const char *const homedir_env = os_getenv("HOME");
+ char *homedir_env_mod = (char *)homedir_env;
bool must_free = false;
- if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) {
+ if (homedir_env_mod != NULL && strchr(homedir_env_mod, '~') != NULL) {
must_free = true;
size_t usedlen = 0;
- size_t flen = STRLEN(homedir_env);
+ size_t flen = strlen(homedir_env_mod);
char_u *fbuf = NULL;
- (void)modify_fname((char_u *)":p", &usedlen, &homedir_env, &fbuf, &flen);
- flen = STRLEN(homedir_env);
- if (flen > 0 && vim_ispathsep(homedir_env[flen - 1]))
- /* Remove the trailing / that is added to a directory. */
- homedir_env[flen - 1] = NUL;
+ (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod,
+ &fbuf, &flen);
+ flen = strlen(homedir_env_mod);
+ assert(homedir_env_mod != homedir_env);
+ if (vim_ispathsep(homedir_env_mod[flen - 1])) {
+ // Remove the trailing / that is added to a directory.
+ homedir_env_mod[flen - 1] = NUL;
+ }
}
- if (homedir_env != NULL)
- envlen = STRLEN(homedir_env);
+ if (homedir_env_mod != NULL) {
+ envlen = strlen(homedir_env_mod);
+ }
- if (!one)
+ if (!one) {
src = skipwhite(src);
+ }
+ char *dst_p = (char *)dst;
while (*src && dstlen > 0) {
- /*
- * Here we are at the beginning of a file name.
- * First, check to see if the beginning of the file name matches
- * $HOME or the "real" home directory. Check that there is a '/'
- * after the match (so that if e.g. the file is "/home/pieter/bla",
- * and the home directory is "/home/piet", the file does not end up
- * as "~er/bla" (which would seem to indicate the file "bla" in user
- * er's home directory)).
- */
- char_u *p = homedir;
- len = dirlen;
- for (;; ) {
- if ( len
- && fnamencmp(src, p, len) == 0
- && (vim_ispathsep(src[len])
- || (!one && (src[len] == ',' || src[len] == ' '))
- || src[len] == NUL)) {
+ // Here we are at the beginning of a file name.
+ // First, check to see if the beginning of the file name matches
+ // $HOME or the "real" home directory. Check that there is a '/'
+ // after the match (so that if e.g. the file is "/home/pieter/bla",
+ // and the home directory is "/home/piet", the file does not end up
+ // as "~er/bla" (which would seem to indicate the file "bla" in user
+ // er's home directory)).
+ char *p = homedir;
+ size_t len = dirlen;
+ for (;;) {
+ if (len
+ && fnamencmp(src, (char_u *)p, len) == 0
+ && (vim_ispathsep(src[len])
+ || (!one && (src[len] == ',' || src[len] == ' '))
+ || src[len] == NUL)) {
src += len;
- if (--dstlen > 0)
- *dst++ = '~';
-
- /*
- * If it's just the home directory, add "/".
- */
- if (!vim_ispathsep(src[0]) && --dstlen > 0)
- *dst++ = '/';
+ if (--dstlen > 0) {
+ *dst_p++ = '~';
+ }
+
+ // If it's just the home directory, add "/".
+ if (!vim_ispathsep(src[0]) && --dstlen > 0) {
+ *dst_p++ = '/';
+ }
break;
}
- if (p == homedir_env)
+ if (p == homedir_env_mod) {
break;
- p = homedir_env;
+ }
+ p = homedir_env_mod;
len = envlen;
}
- /* if (!one) skip to separator: space or comma */
- while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0)
- *dst++ = *src++;
- /* skip separator */
- while ((*src == ' ' || *src == ',') && --dstlen > 0)
- *dst++ = *src++;
+ // if (!one) skip to separator: space or comma.
+ while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) {
+ *dst_p++ = (char)(*src++);
+ }
+ // Skip separator.
+ while ((*src == ' ' || *src == ',') && --dstlen > 0) {
+ *dst_p++ = (char)(*src++);
+ }
}
- /* if (dstlen == 0) out of space, what to do??? */
+ // If (dstlen == 0) out of space, what to do???
- *dst = NUL;
+ *dst_p = NUL;
if (must_free) {
- xfree(homedir_env);
+ xfree(homedir_env_mod);
}
+ return (size_t)(dst_p - (char *)dst);
}
/// Like home_replace, store the replaced string in allocated memory.
@@ -886,7 +902,7 @@ bool os_setenv_append_path(const char *fname)
// No prescribed maximum on unix.
# define MAX_ENVPATHLEN INT_MAX
#endif
- if (!path_is_absolute_path((char_u *)fname)) {
+ if (!path_is_absolute((char_u *)fname)) {
internal_error("os_setenv_append_path()");
return false;
}
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index d294f9139b..ccf35fd57c 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -4,7 +4,7 @@
/// @file fileio.c
///
/// Buffered reading/writing to a file. Unlike fileio.c this is not dealing with
-/// Neovim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite
+/// Nvim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite
/// replacement.
#include <assert.h>
@@ -43,7 +43,7 @@
/// @param[in] mode Permissions for the newly created file (ignored if flags
/// does not have kFileCreate\*).
///
-/// @return Error code (@see os_strerror()) or 0.
+/// @return Error code, or 0 on success. @see os_strerror()
int file_open(FileDescriptor *const ret_fp, const char *const fname,
const int flags, const int mode)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
@@ -83,7 +83,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
if (fd < 0) {
return fd;
}
- return file_open_fd(ret_fp, fd, (wr == kTrue));
+ return file_open_fd(ret_fp, fd, flags);
}
/// Wrap file descriptor with FileDescriptor structure
@@ -94,14 +94,23 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
/// @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.
+/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and
+/// writing to the file at once is not supported, so either
+/// FILE_WRITE_ONLY or FILE_READ_ONLY is required.
///
/// @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)
+int file_open_fd(FileDescriptor *const ret_fp, const int fd,
+ const int flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- ret_fp->wr = wr;
+ ret_fp->wr = !!(flags & (kFileCreate
+ |kFileCreateOnly
+ |kFileTruncate
+ |kFileAppend
+ |kFileWriteOnly));
+ ret_fp->non_blocking = !!(flags & kFileNonBlocking);
+ // Non-blocking writes not supported currently.
+ assert(!ret_fp->wr || !ret_fp->non_blocking);
ret_fp->fd = fd;
ret_fp->eof = false;
ret_fp->rv = rbuffer_new(kRWBufferSize);
@@ -115,8 +124,7 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
/// Like file_open(), but allocate and return ret_fp
///
-/// @param[out] error Error code, @see os_strerror(). Is set to zero on
-/// success.
+/// @param[out] error Error code, or 0 on success. @see os_strerror()
/// @param[in] fname File name to open.
/// @param[in] flags Flags, @see FileOpenFlags.
/// @param[in] mode Permissions for the newly created file (ignored if flags
@@ -137,18 +145,19 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
/// 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[out] error Error code, or 0 on success. @see os_strerror()
/// @param[in] fd File descriptor to wrap.
-/// @param[in] wr True if fd is opened for writing only, false if it is read
-/// only.
+/// @param[in] flags Flags, @see FileOpenFlags.
+/// @param[in] mode Permissions for the newly created file (ignored if flags
+/// does not have FILE_CREATE\*).
///
/// @return [allocated] Opened file or NULL in case of error.
-FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr)
+FileDescriptor *file_open_fd_new(int *const error, const int fd,
+ const int flags)
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) {
+ if ((*error = file_open_fd(fp, fd, flags)) != 0) {
xfree(fp);
return NULL;
}
@@ -246,7 +255,8 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)
return;
}
const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
- const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes);
+ const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes,
+ fp->non_blocking);
if (wres != (ptrdiff_t)read_bytes) {
if (wres >= 0) {
fp->_error = UV_EIO;
@@ -272,6 +282,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
char *buf = ret_buf;
size_t read_remaining = size;
RBuffer *const rv = fp->rv;
+ bool called_read = false;
while (read_remaining) {
const size_t rv_size = rbuffer_size(rv);
if (rv_size > 0) {
@@ -279,7 +290,9 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
buf += rsize;
read_remaining -= rsize;
}
- if (fp->eof) {
+ if (fp->eof
+ // Allow only at most one os_read[v] call.
+ || (called_read && fp->non_blocking)) {
break;
}
if (read_remaining) {
@@ -296,7 +309,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
};
assert(write_count == kRWBufferSize);
const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
- ARRAY_SIZE(iov));
+ ARRAY_SIZE(iov), fp->non_blocking);
if (r_ret > 0) {
if (r_ret > (ptrdiff_t)read_remaining) {
rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining));
@@ -312,7 +325,8 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
if (read_remaining >= kRWBufferSize) {
// …otherwise leave RBuffer empty and populate only target buffer,
// because filtering information through rbuffer will be more syscalls.
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining);
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
+ fp->non_blocking);
if (r_ret >= 0) {
read_remaining -= (size_t)r_ret;
return (ptrdiff_t)(size - read_remaining);
@@ -323,7 +337,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
size_t write_count;
const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
rbuffer_write_ptr(rv, &write_count),
- kRWBufferSize);
+ kRWBufferSize, fp->non_blocking);
assert(write_count == kRWBufferSize);
if (r_ret > 0) {
rbuffer_produced(rv, (size_t)r_ret);
@@ -332,6 +346,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
}
}
#endif
+ called_read = true;
}
}
return (ptrdiff_t)(size - read_remaining);
diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h
index 0b55cc695f..7c53cd4f07 100644
--- a/src/nvim/os/fileio.h
+++ b/src/nvim/os/fileio.h
@@ -14,6 +14,7 @@ typedef struct {
RBuffer *rv; ///< Read or write buffer.
bool wr; ///< True if file is in write mode.
bool eof; ///< True if end of file was encountered.
+ bool non_blocking; ///< True if EAGAIN should not restart syscalls.
} FileDescriptor;
/// file_open() flags
@@ -32,6 +33,8 @@ typedef enum {
///< kFileCreateOnly.
kFileAppend = 64, ///< Append to the file. Implies kFileWriteOnly. Cannot
///< be used with kFileCreateOnly.
+ kFileNonBlocking = 128, ///< Do not restart read() or write() syscall if
+ ///< EAGAIN was encountered.
} FileOpenFlags;
static inline bool file_eof(const FileDescriptor *const fp)
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index c0a97aeb34..5412c5daae 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -222,7 +222,7 @@ int os_exepath(char *buffer, size_t *size)
bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
FUNC_ATTR_NONNULL_ARG(1)
{
- bool no_path = !use_path || path_is_absolute_path(name);
+ bool no_path = !use_path || path_is_absolute(name);
#ifndef WIN32
// If the filename is "qualified" (relative or absolute) do not check $PATH.
no_path |= (name[0] == '.'
@@ -244,7 +244,7 @@ bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
#endif
if (ok) {
if (abspath != NULL) {
- *abspath = save_absolute_path(name);
+ *abspath = save_abs_path(name);
}
return true;
}
@@ -357,7 +357,7 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
#endif
if (ok) {
if (abspath != NULL) { // Caller asked for a copy of the path.
- *abspath = save_absolute_path((char_u *)buf);
+ *abspath = save_abs_path((char_u *)buf);
}
rv = true;
@@ -436,6 +436,29 @@ int os_close(const int fd)
return r;
}
+/// Duplicate file descriptor
+///
+/// @param[in] fd File descriptor to duplicate.
+///
+/// @return New file descriptor or libuv error code (< 0).
+int os_dup(const int fd)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ int ret;
+os_dup_dup:
+ ret = dup(fd);
+ if (ret < 0) {
+ const int error = os_translate_sys_error(errno);
+ errno = 0;
+ if (error == UV_EINTR) {
+ goto os_dup_dup;
+ } else {
+ return error;
+ }
+ }
+ return ret;
+}
+
/// Read from a file
///
/// Handles EINTR and ENOMEM, but not other errors.
@@ -445,10 +468,11 @@ int os_close(const int fd)
/// to false. Initial value is ignored.
/// @param[out] ret_buf Buffer to write to. May be NULL if size is zero.
/// @param[in] size Amount of bytes to read.
+/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
///
/// @return Number of bytes read or libuv error code (< 0).
-ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
- const size_t size)
+ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf,
+ const size_t size, const bool non_blocking)
FUNC_ATTR_WARN_UNUSED_RESULT
{
*ret_eof = false;
@@ -468,7 +492,9 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
if (cur_read_bytes < 0) {
const int error = os_translate_sys_error(errno);
errno = 0;
- if (error == UV_EINTR || error == UV_EAGAIN) {
+ if (non_blocking && error == UV_EAGAIN) {
+ break;
+ } else if (error == UV_EINTR || error == UV_EAGAIN) {
continue;
} else if (error == UV_ENOMEM && !did_try_to_free) {
try_to_free_memory();
@@ -498,7 +524,11 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
/// may change, it is incorrect to use data it points to after
/// os_readv().
/// @param[in] iov_size Number of buffers in iov.
-ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
+/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
+///
+/// @return Number of bytes read or libuv error code (< 0).
+ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov,
+ size_t iov_size, const bool non_blocking)
FUNC_ATTR_NONNULL_ALL
{
*ret_eof = false;
@@ -512,7 +542,7 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
}
while (read_bytes < toread && iov_size && !*ret_eof) {
ptrdiff_t cur_read_bytes = readv(fd, iov, (int)iov_size);
- if (toread && cur_read_bytes == 0) {
+ if (cur_read_bytes == 0) {
*ret_eof = true;
}
if (cur_read_bytes > 0) {
@@ -531,7 +561,9 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
} else if (cur_read_bytes < 0) {
const int error = os_translate_sys_error(errno);
errno = 0;
- if (error == UV_EINTR || error == UV_EAGAIN) {
+ if (non_blocking && error == UV_EAGAIN) {
+ break;
+ } else if (error == UV_EINTR || error == UV_EAGAIN) {
continue;
} else if (error == UV_ENOMEM && !did_try_to_free) {
try_to_free_memory();
@@ -551,9 +583,11 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)
/// @param[in] fd File descriptor to write to.
/// @param[in] buf Data to write. May be NULL if size is zero.
/// @param[in] size Amount of bytes to write.
+/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
///
/// @return Number of bytes written or libuv error code (< 0).
-ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)
+ptrdiff_t os_write(const int fd, const char *const buf, const size_t size,
+ const bool non_blocking)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (buf == NULL) {
@@ -571,7 +605,9 @@ ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)
if (cur_written_bytes < 0) {
const int error = os_translate_sys_error(errno);
errno = 0;
- if (error == UV_EINTR || error == UV_EAGAIN) {
+ if (non_blocking && error == UV_EAGAIN) {
+ break;
+ } else if (error == UV_EINTR || error == UV_EAGAIN) {
continue;
} else {
return error;
@@ -593,6 +629,7 @@ int os_fsync(int fd)
{
int r;
RUN_UV_FS_FUNC(r, uv_fs_fsync, fd, NULL);
+ g_stats.fsync++;
return r;
}
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index f81785675e..c29af5c160 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -25,15 +25,6 @@
// Command-processing buffer. Use large buffers for all platforms.
#define CMDBUFFSIZE 1024
-// Use up to 5 Mbyte for a buffer.
-#ifndef DFLT_MAXMEM
-# define DFLT_MAXMEM (5 * 1024)
-#endif
-// use up to 10 Mbyte for Vim.
-#ifndef DFLT_MAXMEMTOT
-# define DFLT_MAXMEMTOT (10 * 1024)
-#endif
-
// Note: Some systems need both string.h and strings.h (Savage). However,
// some systems can't handle both, only use string.h in that case.
#include <string.h>
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
new file mode 100644
index 0000000000..a67e7487eb
--- /dev/null
+++ b/src/nvim/os/process.c
@@ -0,0 +1,267 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+/// OS process functions
+///
+/// psutil is a good reference for cross-platform syscall voodoo:
+/// https://github.com/giampaolo/psutil/tree/master/psutil/arch
+
+#include <uv.h> // for HANDLE (win32)
+
+#ifdef WIN32
+# include <tlhelp32.h> // for CreateToolhelp32Snapshot
+#endif
+
+#if defined(__FreeBSD__) // XXX: OpenBSD ?
+# include <string.h>
+# include <sys/types.h>
+# include <sys/user.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/param.h>
+#endif
+
+#if defined(__APPLE__) || defined(BSD)
+# include <sys/sysctl.h>
+# include <pwd.h>
+#endif
+
+#include "nvim/globals.h"
+#include "nvim/log.h"
+#include "nvim/os/process.h"
+#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
+#include "nvim/api/private/helpers.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/process.c.generated.h"
+#endif
+
+#ifdef WIN32
+static bool os_proc_tree_kill_rec(HANDLE process, int sig)
+{
+ if (process == NULL) {
+ return false;
+ }
+ PROCESSENTRY32 pe;
+ DWORD pid = GetProcessId(process);
+
+ if (pid != 0) {
+ HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h != INVALID_HANDLE_VALUE) {
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(h, &pe)) {
+ goto theend;
+ }
+ do {
+ if (pe.th32ParentProcessID == pid) {
+ HANDLE ph = OpenProcess(PROCESS_ALL_ACCESS, false, pe.th32ProcessID);
+ if (ph != NULL) {
+ os_proc_tree_kill_rec(ph, sig);
+ CloseHandle(ph);
+ }
+ }
+ } while (Process32Next(h, &pe));
+ CloseHandle(h);
+ }
+ }
+
+theend:
+ return (bool)TerminateProcess(process, (unsigned int)sig);
+}
+/// Kills process `pid` and its descendants recursively.
+bool os_proc_tree_kill(int pid, int sig)
+{
+ assert(sig >= 0);
+ assert(sig == SIGTERM || sig == SIGKILL);
+ if (pid > 0) {
+ ILOG("terminating process tree: %d", pid);
+ HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, (DWORD)pid);
+ return os_proc_tree_kill_rec(h, sig);
+ } else {
+ ELOG("invalid pid: %d", pid);
+ }
+ return false;
+}
+#else
+/// Kills process group where `pid` is the process group leader.
+bool os_proc_tree_kill(int pid, int sig)
+{
+ assert(sig == SIGTERM || sig == SIGKILL);
+ int pgid = getpgid(pid);
+ if (pgid > 0) { // Ignore error. Never kill self (pid=0).
+ if (pgid == pid) {
+ ILOG("sending %s to process group: -%d",
+ sig == SIGTERM ? "SIGTERM" : "SIGKILL", pgid);
+ int rv = uv_kill(-pgid, sig);
+ return rv == 0;
+ } else {
+ // Should never happen, because process_spawn() did setsid() in the child.
+ ELOG("pgid %d != pid %d", pgid, pid);
+ }
+ } else {
+ ELOG("getpgid(%d) returned %d", pid, pgid);
+ }
+ return false;
+}
+#endif
+
+/// Gets the process ids of the immediate children of process `ppid`.
+///
+/// @param ppid Process to inspect.
+/// @param[out,allocated] proc_list Child process ids.
+/// @param[out] proc_count Number of child processes.
+/// @return 0 on success, 1 if process not found, 2 on other error.
+int os_proc_children(int ppid, int **proc_list, size_t *proc_count)
+{
+ if (ppid < 0) {
+ return 2;
+ }
+
+ int *temp = NULL;
+ *proc_list = NULL;
+ *proc_count = 0;
+
+#ifdef WIN32
+ PROCESSENTRY32 pe;
+
+ // Snapshot of all processes.
+ HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h == INVALID_HANDLE_VALUE) {
+ return 2;
+ }
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ // Get root process.
+ if (!Process32First(h, &pe)) {
+ CloseHandle(h);
+ return 2;
+ }
+ // Collect processes whose parent matches `ppid`.
+ do {
+ if (pe.th32ParentProcessID == (DWORD)ppid) {
+ temp = xrealloc(temp, (*proc_count + 1) * sizeof(*temp));
+ temp[*proc_count] = (int)pe.th32ProcessID;
+ (*proc_count)++;
+ }
+ } while (Process32Next(h, &pe));
+ CloseHandle(h);
+
+#elif defined(__APPLE__) || defined(BSD)
+# if defined(__APPLE__)
+# define KP_PID(o) o.kp_proc.p_pid
+# define KP_PPID(o) o.kp_eproc.e_ppid
+# elif defined(__FreeBSD__)
+# define KP_PID(o) o.ki_pid
+# define KP_PPID(o) o.ki_ppid
+# else
+# define KP_PID(o) o.p_pid
+# define KP_PPID(o) o.p_ppid
+# endif
+# ifdef __NetBSD__
+ static int name[] = {
+ CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, (int)(sizeof(struct kinfo_proc2)), 0
+ };
+# else
+ static int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+# endif
+
+ // Get total process count.
+ size_t len = 0;
+ int rv = sysctl(name, ARRAY_SIZE(name) - 1, NULL, &len, NULL, 0);
+ if (rv) {
+ return 2;
+ }
+
+ // Get ALL processes.
+# ifdef __NetBSD__
+ struct kinfo_proc2 *p_list = xmalloc(len);
+# else
+ struct kinfo_proc *p_list = xmalloc(len);
+# endif
+ rv = sysctl(name, ARRAY_SIZE(name) - 1, p_list, &len, NULL, 0);
+ if (rv) {
+ xfree(p_list);
+ return 2;
+ }
+
+ // Collect processes whose parent matches `ppid`.
+ bool exists = false;
+ size_t p_count = len / sizeof(*p_list);
+ for (size_t i = 0; i < p_count; i++) {
+ exists = exists || KP_PID(p_list[i]) == ppid;
+ if (KP_PPID(p_list[i]) == ppid) {
+ temp = xrealloc(temp, (*proc_count + 1) * sizeof(*temp));
+ temp[*proc_count] = KP_PID(p_list[i]);
+ (*proc_count)++;
+ }
+ }
+ xfree(p_list);
+ if (!exists) {
+ return 1; // Process not found.
+ }
+
+#elif defined(__linux__)
+ char proc_p[256] = { 0 };
+ // Collect processes whose parent matches `ppid`.
+ // Rationale: children are defined in thread with same ID of process.
+ snprintf(proc_p, sizeof(proc_p), "/proc/%d/task/%d/children", ppid, ppid);
+ FILE *fp = fopen(proc_p, "r");
+ if (fp == NULL) {
+ return 2; // Process not found, or /proc/…/children not supported.
+ }
+ int match_pid;
+ while (fscanf(fp, "%d", &match_pid) > 0) {
+ temp = xrealloc(temp, (*proc_count + 1) * sizeof(*temp));
+ temp[*proc_count] = match_pid;
+ (*proc_count)++;
+ }
+ fclose(fp);
+#endif
+
+ *proc_list = temp;
+ return 0;
+}
+
+#ifdef WIN32
+/// Gets various properties of the process identified by `pid`.
+///
+/// @param pid Process to inspect.
+/// @return Map of process properties, empty on error.
+Dictionary os_proc_info(int pid)
+{
+ Dictionary pinfo = ARRAY_DICT_INIT;
+ PROCESSENTRY32 pe;
+
+ // Snapshot of all processes. This is used instead of:
+ // OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, …)
+ // to avoid ERROR_PARTIAL_COPY. https://stackoverflow.com/a/29942376
+ HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h == INVALID_HANDLE_VALUE) {
+ return pinfo; // Return empty.
+ }
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ // Get root process.
+ if (!Process32First(h, &pe)) {
+ CloseHandle(h);
+ return pinfo; // Return empty.
+ }
+ // Find the process.
+ do {
+ if (pe.th32ProcessID == (DWORD)pid) {
+ break;
+ }
+ } while (Process32Next(h, &pe));
+ CloseHandle(h);
+
+ if (pe.th32ProcessID == (DWORD)pid) {
+ PUT(pinfo, "pid", INTEGER_OBJ(pid));
+ PUT(pinfo, "ppid", INTEGER_OBJ((int)pe.th32ParentProcessID));
+ PUT(pinfo, "name", STRING_OBJ(cstr_to_string(pe.szExeFile)));
+ }
+
+ return pinfo;
+}
+#endif
diff --git a/src/nvim/os/process.h b/src/nvim/os/process.h
new file mode 100644
index 0000000000..1722d56bd3
--- /dev/null
+++ b/src/nvim/os/process.h
@@ -0,0 +1,11 @@
+#ifndef NVIM_OS_PROCESS_H
+#define NVIM_OS_PROCESS_H
+
+#include <stddef.h>
+#include "nvim/api/private/defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "os/process.h.generated.h"
+#endif
+
+#endif // NVIM_OS_PROCESS_H
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 855ca2ae47..dfe2cfbb8d 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -145,8 +145,12 @@ void pty_process_teardown(Loop *loop)
uv_signal_stop(&loop->children_watcher);
}
-static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
+static void init_child(PtyProcess *ptyproc)
+ FUNC_ATTR_NONNULL_ALL
{
+ // New session/process-group. #6530
+ setsid();
+
unsetenv("COLUMNS");
unsetenv("LINES");
unsetenv("TERMCAP");
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index f650a51fe7..04f59d7522 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -136,7 +136,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
xfree(input.data);
if (output) {
- (void)write_output(output, nread, true, true);
+ (void)write_output(output, nread, true);
xfree(output);
}
@@ -388,10 +388,10 @@ static bool out_data_decide_throttle(size_t size)
pulse_msg[1] = (tick == 0 || 1 == tick) ? ' ' : '.';
pulse_msg[2] = (tick == 0 || 1 == tick || 2 == tick) ? ' ' : '.';
if (visit == 1) {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ msg_putchar('\n');
}
- int lastrow = (int)Rows - 1;
- screen_puts_len((char_u *)pulse_msg, ARRAY_SIZE(pulse_msg), lastrow, 0, 0);
+ msg_putchar('\r'); // put cursor at start of line
+ msg_puts(pulse_msg);
ui_flush();
return true;
}
@@ -609,28 +609,20 @@ static void read_input(DynamicBuffer *buf)
}
}
-static size_t write_output(char *output, size_t remaining, bool to_buffer,
- bool eof)
+static size_t write_output(char *output, size_t remaining, bool eof)
{
if (!output) {
return 0;
}
- char replacement_NUL = to_buffer ? NL : 1;
char *start = output;
size_t off = 0;
- int lastrow = (int)Rows - 1;
while (off < remaining) {
if (output[off] == NL) {
// Insert the line
- if (to_buffer) {
- output[off] = NUL;
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
- false);
- } else {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0);
- }
+ output[off] = NUL;
+ ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
+ false);
size_t skip = off + 1;
output += skip;
remaining -= skip;
@@ -640,24 +632,19 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
if (output[off] == NUL) {
// Translate NUL to NL
- output[off] = replacement_NUL;
+ output[off] = NL;
}
off++;
}
if (eof) {
if (remaining) {
- if (to_buffer) {
- // append unfinished line
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
- // remember that the NL was missing
- curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
- } else {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- screen_puts_len((char_u *)output, (int)remaining, lastrow, 0, 0);
- }
+ // append unfinished line
+ ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
+ // remember that the NL was missing
+ curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
output += remaining;
- } else if (to_buffer) {
+ } else {
curbuf->b_no_eol_lnum = 0;
}
}
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 732be072e1..fc7f9cefd1 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -145,7 +145,7 @@ static void on_signal(SignalWatcher *handle, int signum, void *data)
case SIGPWR:
// Signal of a power failure(eg batteries low), flush the swap files to
// be safe
- ml_sync_all(false, false);
+ ml_sync_all(false, false, true);
break;
#endif
#ifdef SIGPIPE
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index a41fb7c621..866a005228 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -88,7 +88,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
///
/// In WIN32 get_xdg_home(kXDGDataHome) returns `{xdg_directory}/nvim-data` to
/// avoid storing configuration and data files in the same path.
-static char *get_xdg_home(const XDGVarType idx)
+char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index faee06304c..db93f016bf 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -32,11 +32,8 @@
// Windows defines a RGB macro that produces 0x00bbggrr color values for use
// with GDI. Our macro is different, and we don't use GDI.
-#if defined(RGB)
-# undef RGB
- // Duplicated from macros.h to avoid include-order sensitivity.
-# define RGB(r, g, b) ((r << 16) | (g << 8) | b)
-#endif
+// Duplicated from macros.h to avoid include-order sensitivity.
+#define RGB_(r, g, b) ((r << 16) | (g << 8) | b)
#ifdef _MSC_VER
# ifndef inline
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 21ac064c30..4f3f7c0661 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -452,10 +452,10 @@ char *FullName_save(const char *fname, bool force)
/// Saves the absolute path.
/// @param name An absolute or relative path.
/// @return The absolute path of `name`.
-char_u *save_absolute_path(const char_u *name)
+char_u *save_abs_path(const char_u *name)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- if (!path_is_absolute_path(name)) {
+ if (!path_is_absolute(name)) {
return (char_u *)FullName_save((char *)name, true);
}
return vim_strsave((char_u *) name);
@@ -673,11 +673,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
// Find all matching entries.
char_u *name;
scandir_next_with_dots(NULL); // initialize
- while ((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) {
+ while ((name = (char_u *)scandir_next_with_dots(&dir)) != NULL) {
if ((name[0] != '.'
|| starts_with_dot
|| ((flags & EW_DODOT)
- && name[1] != NUL && (name[1] != '.' || name[2] != NUL)))
+ && name[1] != NUL
+ && (name[1] != '.' || name[2] != NUL))) // -V557
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD)
&& fnamencmp(path + (s - buf), name, e - s) == 0))) {
@@ -814,7 +815,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
STRCPY(buf, curdir); // relative to current directory
} else if (path_with_url((char *)buf)) {
continue; // URL can't be used here
- } else if (!path_is_absolute_path(buf)) {
+ } else if (!path_is_absolute(buf)) {
// Expand relative path to their full path equivalent
size_t len = STRLEN(curdir);
if (len + STRLEN(buf) + 3 > MAXPATHL) {
@@ -949,19 +950,17 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
}
}
- if (path_is_absolute_path(path)) {
- /*
- * Last resort: shorten relative to curdir if possible.
- * 'possible' means:
- * 1. It is under the current directory.
- * 2. The result is actually shorter than the original.
- *
- * Before curdir After
- * /foo/bar/file.txt /foo/bar ./file.txt
- * c:\foo\bar\file.txt c:\foo\bar .\file.txt
- * /file.txt / /file.txt
- * c:\file.txt c:\ .\file.txt
- */
+ if (path_is_absolute(path)) {
+ // Last resort: shorten relative to curdir if possible.
+ // 'possible' means:
+ // 1. It is under the current directory.
+ // 2. The result is actually shorter than the original.
+ //
+ // Before curdir After
+ // /foo/bar/file.txt /foo/bar ./file.txt
+ // c:\foo\bar\file.txt c:\foo\bar .\file.txt
+ // /file.txt / /file.txt
+ // c:\file.txt c:\ .\file.txt
short_name = path_shorten_fname(path, curdir);
if (short_name != NULL && short_name > path + 1
) {
@@ -1221,7 +1220,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
*/
if (path_has_exp_wildcard(p)) {
if ((flags & EW_PATH)
- && !path_is_absolute_path(p)
+ && !path_is_absolute(p)
&& !(p[0] == '.'
&& (vim_ispathsep(p[1])
|| (p[1] == '.' && vim_ispathsep(p[2]))))
@@ -1667,7 +1666,7 @@ int path_with_url(const char *fname)
*/
bool vim_isAbsName(char_u *name)
{
- return path_with_url((char *)name) != 0 || path_is_absolute_path(name);
+ return path_with_url((char *)name) != 0 || path_is_absolute(name);
}
/// Save absolute file name to "buf[len]".
@@ -1701,7 +1700,7 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)
return OK;
}
- int rv = path_get_absolute_path((char_u *)fname, (char_u *)buf, len, force);
+ int rv = path_to_absolute((char_u *)fname, (char_u *)buf, len, force);
if (rv == FAIL) {
xstrlcpy(buf, fname, len); // something failed; use the filename
}
@@ -1910,7 +1909,7 @@ int pathcmp(const char *p, const char *q, int maxlen)
/// - Pointer into `full_path` if shortened.
/// - `full_path` unchanged if no shorter name is possible.
/// - NULL if `full_path` is NULL.
-char_u *path_shorten_fname_if_possible(char_u *full_path)
+char_u *path_try_shorten_fname(char_u *full_path)
{
char_u *dirname = xmalloc(MAXPATHL);
char_u *p = full_path;
@@ -2191,8 +2190,8 @@ int append_path(char *path, const char *to_append, size_t max_len)
/// @param force also expand when "fname" is already absolute.
///
/// @return FAIL for failure, OK for success.
-static int path_get_absolute_path(const char_u *fname, char_u *buf,
- size_t len, int force)
+static int path_to_absolute(const char_u *fname, char_u *buf, size_t len,
+ int force)
{
char_u *p;
*buf = NUL;
@@ -2201,7 +2200,7 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
char *end_of_path = (char *) fname;
// expand it if forced or not an absolute path
- if (force || !path_is_absolute_path(fname)) {
+ if (force || !path_is_absolute(fname)) {
p = vim_strrchr(fname, '/');
#ifdef WIN32
if (p == NULL) {
@@ -2234,10 +2233,10 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
return append_path((char *)buf, end_of_path, len);
}
-/// Check if the given file is absolute.
+/// Check if file `fname` is a full (absolute) path.
///
/// @return `TRUE` if "fname" is absolute.
-int path_is_absolute_path(const char_u *fname)
+int path_is_absolute(const char_u *fname)
{
#ifdef WIN32
// A name like "d:/foo" and "//server/share" is absolute
@@ -2262,7 +2261,7 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize)
{
char *path = getenv("PATH");
- if (path == NULL || path_is_absolute_path((char_u *)argv0)) {
+ if (path == NULL || path_is_absolute((char_u *)argv0)) {
xstrlcpy(buf, argv0, bufsize);
} else if (argv0[0] == '.' || strchr(argv0, PATHSEP)) {
// Relative to CWD.
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index 121f22129a..94cc63baea 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -2,10 +2,8 @@ find_package(Gettext)
find_program(XGETTEXT_PRG xgettext)
find_program(ICONV_PRG iconv)
-if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
- set(ENV{OLD_PO_FILE_INPUT} yes)
- set(ENV{OLD_PO_FILE_OUTPUT} yes)
-
+option(LANGUAGES "Localizations to build")
+if(NOT LANGUAGES)
set(LANGUAGES
af
ca
@@ -31,6 +29,12 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
vi
zh_CN.UTF-8
zh_TW.UTF-8)
+endif()
+
+if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
+ set(ENV{OLD_PO_FILE_INPUT} yes)
+ set(ENV{OLD_PO_FILE_OUTPUT} yes)
+
set(NVIM_RELATIVE_SOURCES)
foreach(SRC ${NVIM_SOURCES} ${NVIM_HEADERS})
@@ -135,22 +139,30 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
endmacro()
# Create some translations from others.
- BuildPoIconv(ja utf-8 euc-jp)
- BuildMo(ja.euc-jp)
+ if(";${LANGUAGES};" MATCHES ";ja;")
+ BuildPoIconv(ja utf-8 euc-jp)
+ BuildMo(ja.euc-jp)
+ endif()
- BuildPoIconv(cs ISO-8859-2 cp1250)
- BuildMo(cs.cp1250)
+ if(";${LANGUAGES};" MATCHES ";cs;")
+ BuildPoIconv(cs ISO-8859-2 cp1250)
+ BuildMo(cs.cp1250)
+ endif()
- BuildPoIconv(sk ISO-8859-2 cp1250)
- BuildMo(sk.cp1250)
+ if(";${LANGUAGES};" MATCHES ";sk;")
+ BuildPoIconv(sk ISO-8859-2 cp1250)
+ BuildMo(sk.cp1250)
+ endif()
add_custom_target(update-po-nb
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/no.po ${CMAKE_CURRENT_SOURCE_DIR}/nb.po
DEPENDS no.po)
list(APPEND UPDATE_PO_TARGETS update-po-nb)
- CheckPo(nb)
- BuildMo(nb)
+ if(";${LANGUAGES};" MATCHES ";no;")
+ CheckPo(nb)
+ BuildMo(nb)
+ endif()
foreach(LANGUAGE ${LANGUAGES})
set(poFile "${CMAKE_CURRENT_SOURCE_DIR}/${LANGUAGE}.po")
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 348daf028a..4c2fc6d906 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -387,7 +387,7 @@ void pum_redraw(void)
char_u saved = *p;
*p = NUL;
- st = transstr(s);
+ st = (char_u *)transstr((const char *)s);
*p = saved;
if (curwin->w_p_rl) {
diff --git a/src/nvim/pos.h b/src/nvim/pos.h
index 966255e6a4..0a2afd5847 100644
--- a/src/nvim/pos.h
+++ b/src/nvim/pos.h
@@ -10,8 +10,10 @@ typedef int colnr_T;
/// Format used to print values which have colnr_T type
#define PRIdCOLNR "d"
-#define MAXLNUM 0x7fffffff // maximum (invalid) line number
-#define MAXCOL 0x7fffffff // maximum column number, 31 bits
+/// Maximal (invalid) line number
+enum { MAXLNUM = 0x7fffffff };
+/// Maximal column number, 31 bits
+enum { MAXCOL = 0x7fffffff };
/*
* position in file or buffer
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 1aeadcec4a..1c3cb5d6b2 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -924,7 +924,7 @@ restofline:
if (qfprev == NULL) {
return QF_FAIL;
}
- if (*fields->errmsg && !qi->qf_multiignore) {
+ if (*fields->errmsg) {
size_t len = STRLEN(qfprev->qf_text);
qfprev->qf_text = xrealloc(qfprev->qf_text,
len + STRLEN(fields->errmsg) + 2);
@@ -2062,7 +2062,7 @@ win_found:
EMSG(_("E924: Current window was closed"));
is_abort = true;
opened_window = false;
- } else if (old_qf_curlist != qi->qf_curlist
+ } else if (old_qf_curlist != qi->qf_curlist // -V560
|| !is_qf_entry_present(qi, qf_ptr)) {
if (qi == &ql_info) {
EMSG(_("E925: Current quickfix was changed"));
@@ -3029,7 +3029,7 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
/*
* Return TRUE if "buf" is the quickfix buffer.
*/
-int bt_quickfix(buf_T *buf)
+int bt_quickfix(const buf_T *const buf)
{
return buf != NULL && buf->b_p_bt[0] == 'q';
}
@@ -3626,7 +3626,7 @@ void ex_vimgrep(exarg_T *eap)
&& eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd)
|| qi->qf_curlist == qi->qf_listcount) {
// make place for a new list
- qf_new_list(qi, title != NULL ? title : *eap->cmdlinep);
+ qf_new_list(qi, title);
}
/* parse the list of arguments */
@@ -3649,8 +3649,8 @@ void ex_vimgrep(exarg_T *eap)
cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start;
seconds = (time_t)0;
- for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) {
- fname = path_shorten_fname_if_possible(fnames[fi]);
+ for (fi = 0; fi < fcount && !got_int && tomatch > 0; fi++) {
+ fname = path_try_shorten_fname(fnames[fi]);
if (time(NULL) > seconds) {
/* Display the file name every second or so, show the user we are
* working on it. */
@@ -4205,11 +4205,9 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
if (qi->qf_lists[qf_idx].qf_ctx != NULL) {
di = tv_dict_item_alloc_len(S_LEN("context"));
- if (di != NULL) {
- tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv);
- if (tv_dict_add(retdict, di) == FAIL) {
- tv_dict_item_free(di);
- }
+ tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv);
+ if (tv_dict_add(retdict, di) == FAIL) {
+ tv_dict_item_free(di);
}
} else {
status = tv_dict_add_str(retdict, S_LEN("context"), "");
@@ -4740,15 +4738,7 @@ void ex_helpgrep(exarg_T *eap)
regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
regmatch.rm_ic = FALSE;
if (regmatch.regprog != NULL) {
- vimconv_T vc;
-
- /* Help files are in utf-8 or latin1, convert lines when 'encoding'
- * differs. */
- vc.vc_type = CONV_NONE;
- if (!enc_utf8)
- convert_setup(&vc, (char_u *)"utf-8", p_enc);
-
- /* create a new quickfix list */
+ // Create a new quickfix list.
qf_new_list(qi, *eap->cmdlinep);
/* Go through all directories in 'runtimepath' */
@@ -4780,15 +4770,6 @@ void ex_helpgrep(exarg_T *eap)
lnum = 1;
while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
char_u *line = IObuff;
- /* Convert a line if 'encoding' is not utf-8 and
- * the line contains a non-ASCII character. */
- if (vc.vc_type != CONV_NONE
- && has_non_ascii(IObuff)) {
- line = string_convert(&vc, IObuff, NULL);
- if (line == NULL)
- line = IObuff;
- }
-
if (vim_regexec(&regmatch, line, (colnr_T)0)) {
int l = (int)STRLEN(line);
@@ -4831,8 +4812,6 @@ void ex_helpgrep(exarg_T *eap)
}
vim_regfree(regmatch.regprog);
- if (vc.vc_type != CONV_NONE)
- convert_setup(&vc, NULL, NULL);
qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
qi->qf_lists[qi->qf_curlist].qf_ptr =
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index c520ef5fb9..98fae858f6 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -4117,7 +4117,7 @@ skip_add:
if (state->c == NFA_ZSTART) {
subidx = 0;
sub = &subs->norm;
- } else if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) {
+ } else if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { // -V560
subidx = state->c - NFA_ZOPEN;
sub = &subs->synt;
} else {
@@ -4169,11 +4169,12 @@ skip_add:
}
subs = addstate(l, state->out, subs, pim, off_arg);
- /* "subs" may have changed, need to set "sub" again */
- if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9)
+ // "subs" may have changed, need to set "sub" again.
+ if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { // -V560
sub = &subs->synt;
- else
+ } else {
sub = &subs->norm;
+ }
if (save_in_use == -1) {
if (REG_MULTI) {
@@ -4217,7 +4218,7 @@ skip_add:
if (state->c == NFA_ZEND) {
subidx = 0;
sub = &subs->norm;
- } else if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) {
+ } else if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { // -V560
subidx = state->c - NFA_ZCLOSE;
sub = &subs->synt;
} else {
@@ -4250,11 +4251,12 @@ skip_add:
}
subs = addstate(l, state->out, subs, pim, off_arg);
- /* "subs" may have changed, need to set "sub" again */
- if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9)
+ // "subs" may have changed, need to set "sub" again.
+ if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { // -V560
sub = &subs->synt;
- else
+ } else {
sub = &subs->norm;
+ }
if (REG_MULTI) {
sub->list.multi[subidx] = save_multipos;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index c13e68f8a1..f034ac33f1 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -24,8 +24,6 @@
* cells the next byte in ScreenLines[] is 0.
* ScreenLinesC[][] contain up to 'maxcombine' composing characters
* (drawn on top of the first character). There is 0 after the last one used.
- * ScreenLines2[] is only used for euc-jp to store the second byte if the
- * first byte is 0x8e (single-width character).
*
* The screen_*() functions write to the screen and handle updating
* ScreenLines[].
@@ -300,13 +298,28 @@ void update_screen(int type)
* if the screen was scrolled up when displaying a message, scroll it down
*/
if (msg_scrolled) {
- clear_cmdline = TRUE;
- if (msg_scrolled > Rows - 5) /* clearing is faster */
+ clear_cmdline = true;
+ if (dy_flags & DY_MSGSEP) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ int valid = Rows - msg_scrollsize();
+ if (wp->w_winrow + wp->w_height > valid) {
+ wp->w_redr_type = NOT_VALID;
+ wp->w_lines_valid = 0;
+ }
+ if (wp->w_winrow + wp->w_height + wp->w_status_height > valid) {
+ wp->w_redr_status = true;
+ }
+ if (valid == 0) {
+ redraw_tabline = true;
+ }
+ }
+ } else if (msg_scrolled > Rows - 5) { // clearing is faster
type = CLEAR;
- else if (type != CLEAR) {
- check_for_delay(FALSE);
- if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
+ } else if (type != CLEAR) {
+ check_for_delay(false);
+ if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL) {
type = CLEAR;
+ }
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_winrow < msg_scrolled) {
if (wp->w_winrow + wp->w_height > msg_scrolled
@@ -1582,6 +1595,20 @@ static void win_update(win_T *wp)
got_int = save_got_int;
}
+/// Returns width of the signcolumn that should be used for the whole window
+///
+/// @param wp window we want signcolumn width from
+/// @return max width of signcolumn (cell unit)
+///
+/// @note Returns a constant for now but hopefully we can improve neovim so that
+/// the returned value width adapts to the maximum number of marks to draw
+/// for the window
+/// TODO(teto)
+int win_signcol_width(win_T *wp)
+{
+ // 2 is vim default value
+ return 2;
+}
/*
* Clear the rest of the window and mark the unused lines with "c1". use "c2"
@@ -1609,7 +1636,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
}
if (signcolumn_on(wp)) {
- int nn = n + 2;
+ int nn = n + win_signcol_width(wp);
/* draw the sign column left of the fold column */
if (nn > wp->w_width) {
@@ -1650,7 +1677,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
}
if (signcolumn_on(wp)) {
- int nn = n + 2;
+ int nn = n + win_signcol_width(wp);
/* draw the sign column after the fold column */
if (nn > wp->w_width) {
@@ -1762,12 +1789,13 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
* text */
RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_width - col);
- // If signs are being displayed, add two spaces.
+ // If signs are being displayed, add spaces.
if (signcolumn_on(wp)) {
len = wp->w_width - col;
if (len > 0) {
- if (len > 2) {
- len = 2;
+ int len_max = win_signcol_width(wp);
+ if (len > len_max) {
+ len = len_max;
}
copy_text_attr(off + col, (char_u *)" ", len,
win_hl_attr(wp, HLF_FL));
@@ -1891,12 +1919,10 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
if (cells > 1)
ScreenLines[idx + 1] = 0;
- } else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
- /* double-byte single width character */
- ScreenLines2[idx] = p[1];
- else if (cells > 1)
- /* double-width character */
+ } else if (cells > 1) {
+ // Double-width character.
ScreenLines[idx + 1] = p[1];
+ }
col += cells;
idx += cells;
p += c_len;
@@ -2017,7 +2043,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width,
- wp->w_width, false, wp);
+ wp->w_width, false, wp, 0);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -2117,7 +2143,6 @@ win_line (
bool nochange /* not updating for changed text */
)
{
- int col = 0; // visual column on screen
unsigned off; // offset in ScreenLines/ScreenAttrs
int c = 0; // init for GCC
long vcol = 0; // virtual column (for tabs)
@@ -2438,10 +2463,6 @@ win_line (
line_attr = win_hl_attr(wp, HLF_QFL);
}
- if (wp->w_hl_attr_normal != 0) {
- line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
- }
-
if (line_attr != 0) {
area_highlighting = true;
}
@@ -2530,7 +2551,7 @@ win_line (
ptr = prev_ptr;
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
- if (((*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0) {
+ if (utf_ptr2cells(ptr) >= c || *ptr == TAB) {
n_skip = v - vcol;
}
}
@@ -2679,11 +2700,11 @@ win_line (
}
off = (unsigned)(current_ScreenLine - ScreenLines);
- col = 0;
+ int col = 0; // Visual column on screen.
if (wp->w_p_rl) {
- /* Rightleft window: process the text in the normal direction, but put
- * it in current_ScreenLine[] from right to left. Start at the
- * rightmost column of the window. */
+ // Rightleft window: process the text in the normal direction, but put
+ // it in current_ScreenLine[] from right to left. Start at the
+ // rightmost column of the window.
col = wp->w_width - 1;
off += col;
}
@@ -2735,18 +2756,25 @@ win_line (
* buffer or when using Netbeans. */
if (signcolumn_on(wp)) {
int text_sign;
- /* Draw two cells with the sign value or blank. */
+ // Draw cells with the sign value or blank.
c_extra = ' ';
char_attr = win_hl_attr(wp, HLF_SC);
- n_extra = 2;
+ n_extra = win_signcol_width(wp);
if (row == startrow + filler_lines && filler_todo <= 0) {
text_sign = buf_getsigntype(wp->w_buffer, lnum, SIGN_TEXT);
if (text_sign != 0) {
p_extra = sign_get_text(text_sign);
+ int symbol_blen = (int)STRLEN(p_extra);
if (p_extra != NULL) {
c_extra = NUL;
- n_extra = (int)STRLEN(p_extra);
+ // symbol(s) bytes + (filling spaces) (one byte each)
+ n_extra = symbol_blen +
+ (win_signcol_width(wp) - mb_string2cells(p_extra));
+ memset(extra, ' ', sizeof(extra));
+ STRNCPY(extra, p_extra, STRLEN(p_extra));
+ p_extra = extra;
+ p_extra[n_extra] = NUL;
}
char_attr = sign_get_attr(text_sign, FALSE);
}
@@ -2891,7 +2919,8 @@ 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, wp);
+ screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -3178,9 +3207,9 @@ win_line (
|| (mb_l > 1 && (!vim_isprintc(mb_c)))) {
// Illegal UTF-8 byte: display as <xx>.
// Non-BMP character : display as ? or fullwidth ?.
- transchar_hex(extra, mb_c);
- if (wp->w_p_rl) { // reverse
- rl_mirror(extra);
+ transchar_hex((char *)extra, mb_c);
+ if (wp->w_p_rl) { // reverse
+ rl_mirror(extra);
}
p_extra = extra;
@@ -3511,8 +3540,7 @@ win_line (
tab_len += vcol_off;
}
// boguscols before FIX_FOR_BOGUSCOLS macro from above.
- if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
- && n_extra > tab_len) {
+ if (lcs_tab1 && old_boguscols > 0 && n_extra > tab_len) {
tab_len += n_extra - tab_len;
}
@@ -3984,7 +4012,8 @@ win_line (
col++;
}
}
- screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp);
+ screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
row++;
/*
@@ -4057,24 +4086,19 @@ win_line (
--col;
}
ScreenLines[off] = c;
- if (enc_dbcs == DBCS_JPNU) {
- if ((mb_c & 0xff00) == 0x8e00)
- ScreenLines[off] = 0x8e;
- ScreenLines2[off] = mb_c & 0xff;
- } else if (enc_utf8) {
- if (mb_utf8) {
- int i;
-
- ScreenLinesUC[off] = mb_c;
- if ((c & 0xff) == 0)
- ScreenLines[off] = 0x80; /* avoid storing zero */
- for (i = 0; i < Screen_mco; ++i) {
- ScreenLinesC[i][off] = u8cc[i];
- if (u8cc[i] == 0)
- break;
+ if (mb_utf8) {
+ ScreenLinesUC[off] = mb_c;
+ if ((c & 0xff) == 0) {
+ ScreenLines[off] = 0x80; // Avoid storing zero.
+ }
+ for (int i = 0; i < Screen_mco; i++) {
+ ScreenLinesC[i][off] = u8cc[i];
+ if (u8cc[i] == 0) {
+ break;
}
- } else
- ScreenLinesUC[off] = 0;
+ }
+ } else {
+ ScreenLinesUC[off] = 0;
}
if (multi_attr) {
ScreenAttrs[off] = multi_attr;
@@ -4207,7 +4231,7 @@ win_line (
|| (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, wp);
+ wp->w_width, wp->w_p_rl, wp, wp->w_hl_attr_normal);
boguscols = 0;
++row;
++screen_row;
@@ -4346,23 +4370,14 @@ static int comp_char_differs(int off_from, int off_to)
static int char_needs_redraw(int off_from, int off_to, int cols)
{
return (cols > 0
- && ((ScreenLines[off_from] != ScreenLines[off_to]
- || ScreenAttrs[off_from] != ScreenAttrs[off_to])
-
- || (enc_dbcs != 0
- && MB_BYTE2LEN(ScreenLines[off_from]) > 1
- && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
- ? ScreenLines2[off_from] != ScreenLines2[off_to]
- : (cols > 1 && ScreenLines[off_from + 1]
- != ScreenLines[off_to + 1])))
- || (enc_utf8
- && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
- || (ScreenLinesUC[off_from] != 0
- && comp_char_differs(off_from, off_to))
- || ((*mb_off2cells)(off_from, off_from + cols) > 1
- && ScreenLines[off_from + 1]
- != ScreenLines[off_to + 1])))
- || p_wd < 0));
+ && (ScreenLines[off_from] != ScreenLines[off_to]
+ || ScreenAttrs[off_from] != ScreenAttrs[off_to]
+ || ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
+ || (ScreenLinesUC[off_from] != 0
+ && comp_char_differs(off_from, off_to))
+ || (utf_off2cells(off_from, off_from + cols) > 1
+ && ScreenLines[off_from + 1] != ScreenLines[off_to + 1])
+ || p_wd < 0));
}
/*
@@ -4377,7 +4392,7 @@ static int char_needs_redraw(int off_from, int off_to, int cols)
* 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, win_T *wp)
+ int clear_width, int rlflag, win_T *wp, int bg_attr)
{
unsigned off_from;
unsigned off_to;
@@ -4410,15 +4425,16 @@ static void screen_line(int row, int coloff, int endcol,
/* Clear rest first, because it's left of the text. */
if (clear_width > 0) {
while (col <= endcol && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
- if (col <= endcol)
- screen_fill(row, row + 1, col + coloff,
- endcol + coloff + 1, ' ', ' ', 0);
+ if (col <= endcol) {
+ screen_fill(row, row + 1, col + coloff, endcol + coloff + 1, ' ', ' ',
+ bg_attr);
+ }
}
col = endcol + 1;
off_to = LineOffset[row] + col + coloff;
@@ -4426,6 +4442,13 @@ static void screen_line(int row, int coloff, int endcol,
endcol = (clear_width > 0 ? clear_width : -clear_width);
}
+ if (bg_attr) {
+ for (int c = col; c < endcol; c++) {
+ ScreenAttrs[off_from+c] = hl_combine_attr(bg_attr,
+ ScreenAttrs[off_from+c]);
+ }
+ }
+
redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
while (col < endcol) {
@@ -4462,9 +4485,6 @@ static void screen_line(int row, int coloff, int endcol,
ScreenLines[off_to + 2] = 0;
redraw_next = TRUE;
}
-
- if (enc_dbcs == DBCS_JPNU)
- ScreenLines2[off_to] = ScreenLines2[off_from];
}
/* When writing a single-width character over a double-width
* character and at the end of the redrawn text, need to clear out
@@ -4524,15 +4544,15 @@ static void screen_line(int row, int coloff, int endcol,
/* blank out the rest of the line */
while (col < clear_width && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
if (col < clear_width) {
- screen_fill(row, row + 1, col + coloff, clear_width + coloff,
- ' ', ' ', 0);
+ screen_fill(row, row + 1, col + coloff, clear_width + coloff, ' ', ' ',
+ bg_attr);
off_to += clear_width - col;
col = clear_width;
}
@@ -5197,8 +5217,8 @@ win_redr_custom (
xfree(stl);
ewp->w_p_crb = p_crb_save;
- /* Make all characters printable. */
- p = transstr(buf);
+ // Make all characters printable.
+ p = (char_u *)transstr((const char *)buf);
len = STRLCPY(buf, p, sizeof(buf));
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
xfree(p);
@@ -5290,15 +5310,8 @@ void screen_getbytes(int row, int col, char_u *bytes, int *attrp)
bytes[0] = ScreenLines[off];
bytes[1] = NUL;
- if (enc_utf8 && ScreenLinesUC[off] != 0)
+ if (ScreenLinesUC[off] != 0) {
bytes[utfc_char2bytes(off, bytes)] = NUL;
- else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) {
- bytes[0] = ScreenLines[off];
- bytes[1] = ScreenLines2[off];
- bytes[2] = NUL;
- } else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1) {
- bytes[1] = ScreenLines[off + 1];
- bytes[2] = NUL;
}
}
}
@@ -5489,11 +5502,9 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr)
ScreenLines[off + 1] = ptr[1];
ScreenAttrs[off + 1] = attr;
screen_char_2(off, row, col);
- } else if (l_enc_dbcs == DBCS_JPNU && c == 0x8e) {
- ScreenLines2[off] = ptr[1];
- screen_char(off, row, col);
- } else
+ } else {
screen_char(off, row, col);
+ }
}
if (l_has_mbyte) {
off += mbyte_cells;
@@ -5866,7 +5877,7 @@ static void screen_char(unsigned off, int row, int col)
ui_cursor_goto(row, col);
ui_set_highlight(ScreenAttrs[off]);
- if (enc_utf8 && ScreenLinesUC[off] != 0) {
+ if (ScreenLinesUC[off] != 0) {
char_u buf[MB_MAXBYTES + 1];
// Convert UTF-8 character to bytes and write it.
@@ -5874,10 +5885,6 @@ static void screen_char(unsigned off, int row, int col)
ui_puts(buf);
} else {
ui_putc(ScreenLines[off]);
- // double-byte character in single-width cell
- if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) {
- ui_putc(ScreenLines2[off]);
- }
}
}
@@ -6069,40 +6076,25 @@ int screen_valid(int doclear)
void screenalloc(bool doclear)
{
int new_row, old_row;
- int outofmem = FALSE;
int len;
- schar_T *new_ScreenLines;
- u8char_T *new_ScreenLinesUC = NULL;
- u8char_T *new_ScreenLinesC[MAX_MCO];
- schar_T *new_ScreenLines2 = NULL;
- int i;
- sattr_T *new_ScreenAttrs;
- unsigned *new_LineOffset;
- char_u *new_LineWraps;
- StlClickDefinition *new_tab_page_click_defs;
static bool entered = false; // avoid recursiveness
static bool done_outofmem_msg = false;
int retry_count = 0;
- const bool l_enc_utf8 = enc_utf8;
- const int l_enc_dbcs = enc_dbcs;
retry:
- /*
- * Allocation of the screen buffers is done only when the size changes and
- * when Rows and Columns have been set and we have started doing full
- * screen stuff.
- */
+ // Allocation of the screen buffers is done only when the size changes and
+ // when Rows and Columns have been set and we have started doing full
+ // screen stuff.
if ((ScreenLines != NULL
&& Rows == screen_Rows
&& Columns == screen_Columns
- && l_enc_utf8 == (ScreenLinesUC != NULL)
- && (l_enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
- && p_mco == Screen_mco
- )
+ && ScreenLinesUC != NULL
+ && p_mco == Screen_mco)
|| Rows == 0
|| Columns == 0
- || (!full_screen && ScreenLines == NULL))
+ || (!full_screen && ScreenLines == NULL)) {
return;
+ }
/*
* It's possible that we produce an out-of-memory message below, which
@@ -6140,22 +6132,22 @@ retry:
if (aucmd_win != NULL)
win_free_lsize(aucmd_win);
- new_ScreenLines = xmalloc((size_t)((Rows + 1) * Columns * sizeof(schar_T)));
- memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
- if (l_enc_utf8) {
- new_ScreenLinesUC = xmalloc(
- (size_t)((Rows + 1) * Columns * sizeof(u8char_T)));
- for (i = 0; i < p_mco; ++i)
- new_ScreenLinesC[i] = xcalloc((Rows + 1) * Columns, sizeof(u8char_T));
- }
- if (l_enc_dbcs == DBCS_JPNU)
- new_ScreenLines2 = xmalloc(
- (size_t)((Rows + 1) * Columns * sizeof(schar_T)));
- new_ScreenAttrs = xmalloc((size_t)((Rows + 1) * Columns * sizeof(sattr_T)));
- new_LineOffset = xmalloc((size_t)(Rows * sizeof(unsigned)));
- new_LineWraps = xmalloc((size_t)(Rows * sizeof(char_u)));
- new_tab_page_click_defs = xcalloc(
- (size_t) Columns, sizeof(*new_tab_page_click_defs));
+ schar_T *new_ScreenLines = xmalloc(
+ (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLines)));
+ u8char_T *new_ScreenLinesC[MAX_MCO];
+ memset(new_ScreenLinesC, 0, sizeof(new_ScreenLinesC));
+ u8char_T *new_ScreenLinesUC = xmalloc(
+ (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLinesUC)));
+ for (int i = 0; i < p_mco; i++) {
+ new_ScreenLinesC[i] = xcalloc(
+ (size_t)((Rows + 1) * Columns), sizeof(new_ScreenLinesC[0][0]));
+ }
+ sattr_T *new_ScreenAttrs = xmalloc(
+ (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenAttrs)));
+ unsigned *new_LineOffset = xmalloc((size_t)(Rows * sizeof(*new_LineOffset)));
+ char_u *new_LineWraps = xmalloc((size_t)(Rows * sizeof(*new_LineWraps)));
+ StlClickDefinition *new_tab_page_click_defs = xcalloc(
+ (size_t)Columns, sizeof(*new_tab_page_click_defs));
FOR_ALL_TAB_WINDOWS(tp, wp) {
win_alloc_lines(wp);
@@ -6164,23 +6156,20 @@ retry:
win_alloc_lines(aucmd_win);
}
- for (i = 0; i < p_mco; ++i)
- if (new_ScreenLinesC[i] == NULL)
+ int i;
+ for (i = 0; i < p_mco; i++) {
+ if (new_ScreenLinesC[i] == NULL) {
break;
- if (new_ScreenLines == NULL
- || (new_ScreenLinesUC == NULL || i != p_mco)
- || new_ScreenAttrs == NULL
- || new_LineOffset == NULL
- || new_LineWraps == NULL
- || new_tab_page_click_defs == NULL
- || outofmem) {
+ }
+ }
+ if (i != p_mco) {
if (ScreenLines != NULL || !done_outofmem_msg) {
- /* guess the size */
+ // Guess the size.
do_outofmem_msg((Rows + 1) * Columns);
- /* Remember we did this to avoid getting outofmem messages over
- * and over again. */
- done_outofmem_msg = TRUE;
+ // Remember we did this to avoid getting outofmem messages over
+ // and over again.
+ done_outofmem_msg = true;
}
xfree(new_ScreenLines);
new_ScreenLines = NULL;
@@ -6190,8 +6179,6 @@ retry:
xfree(new_ScreenLinesC[i]);
new_ScreenLinesC[i] = NULL;
}
- xfree(new_ScreenLines2);
- new_ScreenLines2 = NULL;
xfree(new_ScreenAttrs);
new_ScreenAttrs = NULL;
xfree(new_LineOffset);
@@ -6214,53 +6201,42 @@ retry:
* executing an external command, for the GUI).
*/
if (!doclear) {
- (void)memset(new_ScreenLines + new_row * Columns,
- ' ', (size_t)Columns * sizeof(schar_T));
- if (l_enc_utf8) {
- (void)memset(new_ScreenLinesUC + new_row * Columns,
- 0, (size_t)Columns * sizeof(u8char_T));
- for (i = 0; i < p_mco; ++i)
- (void)memset(new_ScreenLinesC[i]
- + new_row * Columns,
- 0, (size_t)Columns * sizeof(u8char_T));
+ memset(new_ScreenLines + new_row * Columns,
+ ' ', (size_t)Columns * sizeof(new_ScreenLines[0]));
+ memset(new_ScreenLinesUC + new_row * Columns,
+ 0, (size_t)Columns * sizeof(new_ScreenLinesUC[0]));
+ for (i = 0; i < p_mco; i++) {
+ memset(new_ScreenLinesC[i] + new_row * Columns,
+ 0, (size_t)Columns * sizeof(new_ScreenLinesC[0][0]));
}
- if (l_enc_dbcs == DBCS_JPNU)
- (void)memset(new_ScreenLines2 + new_row * Columns,
- 0, (size_t)Columns * sizeof(schar_T));
- (void)memset(new_ScreenAttrs + new_row * Columns,
- 0, (size_t)Columns * sizeof(sattr_T));
+ memset(new_ScreenAttrs + new_row * Columns,
+ 0, (size_t)Columns * sizeof(new_ScreenAttrs[0]));
old_row = new_row + (screen_Rows - Rows);
if (old_row >= 0 && ScreenLines != NULL) {
if (screen_Columns < Columns)
len = screen_Columns;
else
len = Columns;
- /* When switching to utf-8 don't copy characters, they
- * may be invalid now. Also when p_mco changes. */
- if (!(l_enc_utf8 && ScreenLinesUC == NULL)
- && p_mco == Screen_mco)
+ // When switching to utf-8 don't copy characters, they
+ // may be invalid now. Also when p_mco changes.
+ if (ScreenLinesUC != NULL && p_mco == Screen_mco) {
memmove(new_ScreenLines + new_LineOffset[new_row],
- ScreenLines + LineOffset[old_row],
- (size_t)len * sizeof(schar_T));
- if (l_enc_utf8 && ScreenLinesUC != NULL
- && p_mco == Screen_mco) {
- memmove(new_ScreenLinesUC + new_LineOffset[new_row],
- ScreenLinesUC + LineOffset[old_row],
- (size_t)len * sizeof(u8char_T));
- for (i = 0; i < p_mco; ++i)
- memmove(new_ScreenLinesC[i]
- + new_LineOffset[new_row],
- ScreenLinesC[i] + LineOffset[old_row],
- (size_t)len * sizeof(u8char_T));
+ ScreenLines + LineOffset[old_row],
+ (size_t)len * sizeof(new_ScreenLines[0]));
}
- if (ScreenLines2 != NULL) {
- memmove(new_ScreenLines2 + new_LineOffset[new_row],
- ScreenLines2 + LineOffset[old_row],
- (size_t)len * sizeof(schar_T));
+ if (ScreenLinesUC != NULL && p_mco == Screen_mco) {
+ memmove(new_ScreenLinesUC + new_LineOffset[new_row],
+ ScreenLinesUC + LineOffset[old_row],
+ (size_t)len * sizeof(new_ScreenLinesUC[0]));
+ for (i = 0; i < p_mco; i++) {
+ memmove(new_ScreenLinesC[i] + new_LineOffset[new_row],
+ ScreenLinesC[i] + LineOffset[old_row],
+ (size_t)len * sizeof(new_ScreenLinesC[0][0]));
+ }
}
memmove(new_ScreenAttrs + new_LineOffset[new_row],
ScreenAttrs + LineOffset[old_row],
- (size_t)len * sizeof(sattr_T));
+ (size_t)len * sizeof(new_ScreenAttrs[0]));
}
}
}
@@ -6275,7 +6251,6 @@ retry:
for (i = 0; i < p_mco; ++i)
ScreenLinesC[i] = new_ScreenLinesC[i];
Screen_mco = p_mco;
- ScreenLines2 = new_ScreenLines2;
ScreenAttrs = new_ScreenAttrs;
LineOffset = new_LineOffset;
LineWraps = new_LineWraps;
@@ -6309,12 +6284,10 @@ retry:
void free_screenlines(void)
{
- int i;
-
xfree(ScreenLinesUC);
- for (i = 0; i < Screen_mco; ++i)
+ for (int i = 0; i < Screen_mco; i++) {
xfree(ScreenLinesC[i]);
- xfree(ScreenLines2);
+ }
xfree(ScreenLines);
xfree(ScreenAttrs);
xfree(LineOffset);
@@ -6398,25 +6371,21 @@ static void lineclear(unsigned off, int width)
*/
static void linecopy(int to, int from, win_T *wp)
{
- unsigned off_to = LineOffset[to] + wp->w_wincol;
- unsigned off_from = LineOffset[from] + wp->w_wincol;
+ const unsigned off_to = LineOffset[to] + wp->w_wincol;
+ const unsigned off_from = LineOffset[from] + wp->w_wincol;
memmove(ScreenLines + off_to, ScreenLines + off_from,
- wp->w_width * sizeof(schar_T));
- if (enc_utf8) {
- int i;
+ wp->w_width * sizeof(ScreenLines[0]));
- memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
- wp->w_width * sizeof(u8char_T));
- for (i = 0; i < p_mco; ++i)
- memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
- wp->w_width * sizeof(u8char_T));
+ memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
+ wp->w_width * sizeof(ScreenLinesUC[0]));
+ for (int i = 0; i < p_mco; i++) {
+ memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
+ wp->w_width * sizeof(ScreenLinesC[0]));
}
- if (enc_dbcs == DBCS_JPNU)
- memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
- wp->w_width * sizeof(schar_T));
+
memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
- wp->w_width * sizeof(sattr_T));
+ wp->w_width * sizeof(ScreenAttrs[0]));
}
/*
@@ -6725,16 +6694,20 @@ int showmode(void)
if (p_ri)
MSG_PUTS_ATTR(_(" REVERSE"), attr);
MSG_PUTS_ATTR(_(" INSERT"), attr);
- } else if (restart_edit == 'I')
+ } else if (restart_edit == 'I' || restart_edit == 'i'
+ || restart_edit == 'a') {
MSG_PUTS_ATTR(_(" (insert)"), attr);
- else if (restart_edit == 'R')
+ } else if (restart_edit == 'R') {
MSG_PUTS_ATTR(_(" (replace)"), attr);
- else if (restart_edit == 'V')
+ } else if (restart_edit == 'V') {
MSG_PUTS_ATTR(_(" (vreplace)"), attr);
- if (p_hkmap)
+ }
+ if (p_hkmap) {
MSG_PUTS_ATTR(_(" Hebrew"), attr);
- if (p_fkmap)
+ }
+ if (p_fkmap) {
MSG_PUTS_ATTR(farsi_text_5, attr);
+ }
if (State & LANGMAP) {
if (curwin->w_p_arab) {
MSG_PUTS_ATTR(_(" Arabic"), attr);
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 1943e2ca43..84782497a0 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1493,38 +1493,34 @@ static int check_prevcol(char_u *linep, int col, int ch, int *prevcol)
* Raw string start is found at linep[startpos.col - 1].
* Return true if the matching end can be found between startpos and endpos.
*/
-static int find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
+static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
{
char_u *p;
char_u *delim_copy;
size_t delim_len;
linenr_T lnum;
- int found = false;
- for (p = linep + startpos->col + 1; *p && *p != '('; ++p) {}
+ for (p = linep + startpos->col + 1; *p && *p != '('; p++) {}
delim_len = (p - linep) - startpos->col - 1;
delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len);
- if (delim_copy == NULL)
- return false;
- for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum)
- {
+ bool found = false;
+ for (lnum = startpos->lnum; lnum <= endpos->lnum; lnum++) {
char_u *line = ml_get(lnum);
- for (p = line + (lnum == startpos->lnum
- ? startpos->col + 1 : 0); *p; ++p)
- {
- if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col)
+ for (p = line + (lnum == startpos->lnum ? startpos->col + 1 : 0); *p; p++) {
+ if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) {
break;
+ }
if (*p == ')' && p[delim_len + 1] == '"'
- && STRNCMP(delim_copy, p + 1, delim_len) == 0)
- {
+ && STRNCMP(delim_copy, p + 1, delim_len) == 0) {
found = true;
break;
}
}
- if (found)
+ if (found) {
break;
+ }
}
xfree(delim_copy);
return found;
@@ -3396,11 +3392,13 @@ again:
goto again;
}
- if (do_include || r < 1) {
- /* Include up to the '>'. */
- while (*get_cursor_pos_ptr() != '>')
- if (inc_cursor() < 0)
+ if (do_include) {
+ // Include up to the '>'.
+ while (*get_cursor_pos_ptr() != '>') {
+ if (inc_cursor() < 0) {
break;
+ }
+ }
} else {
char_u *c = get_cursor_pos_ptr();
// Exclude the '<' of the end tag.
@@ -3944,15 +3942,15 @@ current_search (
if (VIsual_active) {
orig_pos = pos = curwin->w_cursor;
- /* make sure, searching further will extend the match */
- if (VIsual_active) {
- if (forward)
- incl(&pos);
- else
- decl(&pos);
+ // Searching further will extend the match.
+ if (forward) {
+ incl(&pos);
+ } else {
+ decl(&pos);
}
- } else
+ } else {
orig_pos = pos = curwin->w_cursor;
+ }
/* Is the pattern is zero-width? */
int one_char = is_one_char(spats[last_idx].pat, true);
@@ -4017,23 +4015,22 @@ current_search (
VIsual = start_pos;
curwin->w_cursor = pos;
- VIsual_active = TRUE;
+ VIsual_active = true;
VIsual_mode = 'v';
- if (VIsual_active) {
- redraw_curbuf_later(INVERTED); /* update the inversion */
- if (*p_sel == 'e') {
- /* Correction for exclusive selection depends on the direction. */
- if (forward && ltoreq(VIsual, curwin->w_cursor))
- inc_cursor();
- else if (!forward && ltoreq(curwin->w_cursor, VIsual))
- inc(&VIsual);
+ redraw_curbuf_later(INVERTED); // Update the inversion.
+ if (*p_sel == 'e') {
+ // Correction for exclusive selection depends on the direction.
+ if (forward && ltoreq(VIsual, curwin->w_cursor)) {
+ inc_cursor();
+ } else if (!forward && ltoreq(curwin->w_cursor, VIsual)) {
+ inc(&VIsual);
}
-
}
- if (fdo_flags & FDO_SEARCH && KeyTyped)
+ if (fdo_flags & FDO_SEARCH && KeyTyped) {
foldOpenCursor();
+ }
may_start_select('c');
setmouse();
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index a1ce00f665..f4454504a4 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -16,12 +16,14 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/vim.h"
+#include "nvim/pos.h"
#include "nvim/ascii.h"
#include "nvim/shada.h"
#include "nvim/message.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/mark.h"
+#include "nvim/macros.h"
#include "nvim/ops.h"
#include "nvim/garray.h"
#include "nvim/option.h"
@@ -76,8 +78,8 @@ KHASH_SET_INIT_STR(strset)
(vim_rename((char_u *)a, (char_u *)b))
#define mb_strnicmp(a, b, c) \
(mb_strnicmp((char_u *)a, (char_u *)b, c))
-#define path_shorten_fname_if_possible(b) \
- ((char *)path_shorten_fname_if_possible((char_u *)b))
+#define path_try_shorten_fname(b) \
+ ((char *)path_try_shorten_fname((char_u *)b))
#define buflist_new(ffname, sfname, ...) \
(buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
#define os_isdir(f) (os_isdir((char_u *) f))
@@ -375,7 +377,8 @@ KHASH_MAP_INIT_STR(file_marks, FileMarks)
/// Before actually writing most of the data is read to this structure.
typedef struct {
HistoryMergerState hms[HIST_COUNT]; ///< Structures for history merging.
- PossiblyFreedShadaEntry global_marks[NGLOBALMARKS]; ///< All global marks.
+ PossiblyFreedShadaEntry global_marks[NMARKS]; ///< Named global marks.
+ PossiblyFreedShadaEntry numbered_marks[EXTRA_MARKS]; ///< Numbered marks.
PossiblyFreedShadaEntry registers[NUM_SAVED_REGISTERS]; ///< All registers.
PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; ///< All dumped jumps.
size_t jumps_size; ///< Number of jumps occupied.
@@ -808,7 +811,7 @@ static int open_shada_file_for_reading(const char *const fname,
/// Wrapper for closing file descriptors
static void close_file(void *cookie)
{
- const int error = file_free(cookie, true);
+ const int error = file_free(cookie, !!p_fs);
if (error != 0) {
emsgf(_(SERR "System error while closing ShaDa file: %s"),
os_strerror(error));
@@ -1397,7 +1400,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
case kSDItemBufferList: {
for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
- char *const sfname = path_shorten_fname_if_possible(
+ char *const sfname = path_try_shorten_fname(
cur_entry.data.buffer_list.buffers[i].fname);
buf_T *const buf = buflist_new(
cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
@@ -2020,6 +2023,113 @@ shada_parse_msgpack_extra_bytes:
return ret;
}
+/// Format shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_entry(const ShadaEntry entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ static char ret[1024];
+ ret[0] = 0;
+ vim_snprintf(S_LEN(ret), "[ ] ts=%" PRIu64 " ");
+ // ^ Space for `can_free_entry`
+ switch (entry.type) {
+ case kSDItemMissing: {
+ vim_snprintf_add(S_LEN(ret), "Missing");
+ break;
+ }
+ case kSDItemHeader: {
+ vim_snprintf_add(S_LEN(ret), "Header { TODO }");
+ break;
+ }
+ case kSDItemBufferList: {
+ vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
+ break;
+ }
+ case kSDItemUnknown: {
+ vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
+ break;
+ }
+ case kSDItemSearchPattern: {
+ vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
+ break;
+ }
+ case kSDItemSubString: {
+ vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
+ break;
+ }
+ case kSDItemHistoryEntry: {
+ vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
+ break;
+ }
+ case kSDItemRegister: {
+ vim_snprintf_add(S_LEN(ret), "Register { TODO }");
+ break;
+ }
+ case kSDItemVariable: {
+ vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
+ break;
+ }
+#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
+ do { \
+ typval_T ad_tv = { \
+ .v_type = VAR_DICT, \
+ .vval.v_dict = entry.data.filemark.additional_data \
+ }; \
+ size_t ad_len; \
+ char *const ad = encode_tv2string(&ad_tv, &ad_len); \
+ vim_snprintf_add( \
+ S_LEN(ret), \
+ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
+ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
+ "ad={%p:[%zu]%.64s} }", \
+ name_fmt_arg, \
+ strlen(entry.data.filemark.fname), \
+ entry.data.filemark.fname, \
+ entry.data.filemark.mark.lnum, \
+ entry.data.filemark.mark.col, \
+ entry.data.filemark.mark.coladd, \
+ entry.data.filemark.additional_data, \
+ ad_len, \
+ ad); \
+ } while (0)
+ case kSDItemGlobalMark: {
+ FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemChange: {
+ FORMAT_MARK_ENTRY("Change", "%s", "");
+ break;
+ }
+ case kSDItemLocalMark: {
+ FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemJump: {
+ FORMAT_MARK_ENTRY("Jump", "%s", "");
+ break;
+ }
+#undef FORMAT_MARK_ENTRY
+ }
+ return ret;
+}
+
+/// Format possibly freed shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_pfreed_entry(
+ const PossiblyFreedShadaEntry pfs_entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ char *ret = (char *)shada_format_entry(pfs_entry.data);
+ ret[1] = (pfs_entry.can_free_entry ? 'T' : 'F');
+ return ret;
+}
+
/// Read and merge in ShaDa file, used when writing
///
/// @param[in] sd_reader Structure containing file reader definition.
@@ -2071,9 +2181,12 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data); \
} \
} \
- wms_entry->can_free_entry = true; \
- wms_entry->data = (entry); \
+ *wms_entry = pfs_entry; \
} while (0)
+ const PossiblyFreedShadaEntry pfs_entry = {
+ .can_free_entry = true,
+ .data = entry,
+ };
switch (entry.type) {
case kSDItemMissing: {
break;
@@ -2125,13 +2238,49 @@ static inline ShaDaWriteResult shada_read_when_writing(
break;
}
case kSDItemGlobalMark: {
- const int idx = mark_global_index(entry.data.filemark.name);
- if (idx < 0) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
+ if (ascii_isdigit(entry.data.filemark.name)) {
+ bool processed_mark = false;
+ // Completely ignore numbered mark names, make a list sorted by
+ // timestamp.
+ for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
+ ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
+ if (wms_entry.type != kSDItemGlobalMark) {
+ continue;
+ }
+ // Ignore duplicates.
+ if (wms_entry.timestamp == entry.timestamp
+ && (wms_entry.data.filemark.additional_data == NULL
+ && entry.data.filemark.additional_data == NULL)
+ && marks_equal(wms_entry.data.filemark.mark,
+ entry.data.filemark.mark)
+ && strcmp(wms_entry.data.filemark.fname,
+ entry.data.filemark.fname) == 0) {
+ shada_free_shada_entry(&entry);
+ processed_mark = true;
+ break;
+ }
+ if (wms_entry.timestamp >= entry.timestamp) {
+ processed_mark = true;
+ if (i < ARRAY_SIZE(wms->numbered_marks)) {
+ replace_numbered_mark(wms, i, pfs_entry);
+ } else {
+ shada_free_shada_entry(&entry);
+ }
+ break;
+ }
+ }
+ if (!processed_mark) {
+ replace_numbered_mark(wms, 0, pfs_entry);
+ }
+ } else {
+ const int idx = mark_global_index(entry.data.filemark.name);
+ if (idx < 0) {
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
+ break;
+ }
+ COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
}
- COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
break;
}
case kSDItemChange:
@@ -2175,8 +2324,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data);
}
}
- wms_entry->can_free_entry = true;
- wms_entry->data = entry;
+ *wms_entry = pfs_entry;
}
} else {
#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
@@ -2216,6 +2364,20 @@ static inline ShaDaWriteResult shada_read_when_writing(
return ret;
}
+/// Check whether buffer should be ignored
+///
+/// @param[in] buf buf_T* to check.
+/// @param[in] removable_bufs Cache of buffers ignored due to their location.
+///
+/// @return true or false.
+static inline bool ignore_buf(const buf_T *const buf,
+ khash_t(bufset) *const removable_bufs)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+{
+ return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
+ || in_bufset(removable_bufs, buf));
+}
+
/// Get list of buffers to write to the shada file
///
/// @param[in] removable_bufs Buffers which are ignored
@@ -2227,11 +2389,9 @@ static inline ShadaEntry shada_get_buflist(
{
int max_bufs = get_shada_parameter('%');
size_t buf_count = 0;
-#define IGNORE_BUF(buf)\
- (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
- || in_bufset(removable_bufs, buf)) // NOLINT(whitespace/indent)
FOR_ALL_BUFFERS(buf) {
- if (!IGNORE_BUF(buf) && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
+ if (!ignore_buf(buf, removable_bufs)
+ && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
buf_count++;
}
}
@@ -2249,7 +2409,7 @@ static inline ShadaEntry shada_get_buflist(
};
size_t i = 0;
FOR_ALL_BUFFERS(buf) {
- if (IGNORE_BUF(buf)) {
+ if (ignore_buf(buf, removable_bufs)) {
continue;
}
if (i >= buf_count) {
@@ -2263,7 +2423,6 @@ static inline ShadaEntry shada_get_buflist(
i++;
}
-#undef IGNORE_BUF
return buflist_entry;
}
@@ -2365,6 +2524,34 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
} while (reg_iter != NULL);
}
+/// Replace numbered mark in WriteMergerState
+///
+/// Frees the last mark, moves (including adjusting mark names) marks from idx
+/// to the last-but-one one and saves the new mark at given index.
+///
+/// @param[out] wms Merger state to adjust.
+/// @param[in] idx Index at which new mark should be placed.
+/// @param[in] entry New mark.
+static inline void replace_numbered_mark(WriteMergerState *const wms,
+ const size_t idx,
+ const PossiblyFreedShadaEntry entry)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
+{
+ if (ARRAY_LAST_ENTRY(wms->numbered_marks).can_free_entry) {
+ shada_free_shada_entry(&ARRAY_LAST_ENTRY(wms->numbered_marks).data);
+ }
+ for (size_t i = idx; i < ARRAY_SIZE(wms->numbered_marks) - 1; i++) {
+ if (wms->numbered_marks[i].data.type == kSDItemGlobalMark) {
+ wms->numbered_marks[i].data.data.filemark.name = (char)('0' + (int)i + 1);
+ }
+ }
+ memmove(wms->numbered_marks + idx + 1, wms->numbered_marks + idx,
+ sizeof(wms->numbered_marks[0])
+ * (ARRAY_SIZE(wms->numbered_marks) - 1 - idx));
+ wms->numbered_marks[idx] = entry;
+ wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx);
+}
+
/// Write ShaDa file
///
/// @param[in] sd_writer Structure containing file writer definition.
@@ -2597,6 +2784,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
// Initialize global marks
if (dump_global_marks) {
const void *global_mark_iter = NULL;
+ size_t digit_mark_idx = 0;
do {
char name = NUL;
xfmark_T fm;
@@ -2619,7 +2807,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
fname = (const char *) buf->b_ffname;
}
- wms->global_marks[mark_global_index(name)] = (PossiblyFreedShadaEntry) {
+ const PossiblyFreedShadaEntry pf_entry = {
.can_free_entry = false,
.data = {
.type = kSDItemGlobalMark,
@@ -2629,11 +2817,16 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.mark = fm.fmark.mark,
.name = name,
.additional_data = fm.fmark.additional_data,
- .fname = (char *) fname,
+ .fname = (char *)fname,
}
}
},
};
+ if (ascii_isdigit(name)) {
+ replace_numbered_mark(wms, digit_mark_idx++, pf_entry);
+ } else {
+ wms->global_marks[mark_global_index(name)] = pf_entry;
+ }
} while (global_mark_iter != NULL);
}
@@ -2715,6 +2908,26 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
}
+ // Update numbered marks: '0' should be replaced with the current position,
+ // '9' should be removed and all other marks shifted.
+ if (!ignore_buf(curbuf, &removable_bufs) && curwin->w_cursor.lnum != 0) {
+ replace_numbered_mark(wms, 0, (PossiblyFreedShadaEntry) {
+ .can_free_entry = false,
+ .data = {
+ .type = kSDItemGlobalMark,
+ .timestamp = os_time(),
+ .data = {
+ .filemark = {
+ .mark = curwin->w_cursor,
+ .name = '0',
+ .additional_data = NULL,
+ .fname = (char *)curbuf->b_ffname,
+ }
+ }
+ },
+ });
+ }
+
// Write the rest
#define PACK_WMS_ARRAY(wms_array) \
do { \
@@ -2729,6 +2942,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
} \
} while (0)
PACK_WMS_ARRAY(wms->global_marks);
+ PACK_WMS_ARRAY(wms->numbered_marks);
PACK_WMS_ARRAY(wms->registers);
for (size_t i = 0; i < wms->jumps_size; i++) {
if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte)
@@ -2823,6 +3037,7 @@ shada_write_exit:
return ret;
}
+#undef IGNORE_BUF
#undef PACK_STATIC_STR
/// Write ShaDa file to a given location
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 34eb2fdf1b..84aeeda2bf 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -7368,16 +7368,24 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int d
if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) {
STRCPY(badword, p);
STRCAT(badword, "/");
- if (keepcap)
+ if (keepcap) {
STRCAT(badword, "=");
- if (flags & WF_BANNED)
+ }
+ if (flags & WF_BANNED) {
STRCAT(badword, "!");
- else if (flags & WF_RARE)
+ } else if (flags & WF_RARE) {
STRCAT(badword, "?");
- if (flags & WF_REGION)
- for (i = 0; i < 7; ++i)
- if (flags & (0x10000 << i))
- sprintf((char *)badword + STRLEN(badword), "%d", i + 1);
+ }
+ if (flags & WF_REGION) {
+ for (i = 0; i < 7; i++) {
+ if (flags & (0x10000 << i)) {
+ const size_t badword_len = STRLEN(badword);
+ snprintf((char *)badword + badword_len,
+ sizeof(badword) - badword_len,
+ "%d", i + 1);
+ }
+ }
+ }
p = badword;
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index f5d5d408a1..dab9a2aacd 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -1644,7 +1644,7 @@ spell_read_tree (
if (len < 0) {
return SP_TRUNCERROR;
}
- if ((size_t)len >= SIZE_MAX / sizeof(int)) {
+ if ((size_t)len >= SIZE_MAX / sizeof(int)) { // -V547
// Invalid length, multiply with sizeof(int) would overflow.
return SP_FORMERROR;
}
@@ -1949,7 +1949,6 @@ static void spell_print_tree(wordnode_T *root)
static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
{
FILE *fd;
- afffile_T *aff;
char_u rline[MAXLINELEN];
char_u *line;
char_u *pc = NULL;
@@ -2006,11 +2005,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
do_mapline = GA_EMPTY(&spin->si_map);
// Allocate and init the afffile_T structure.
- aff = (afffile_T *)getroom(spin, sizeof(afffile_T), true);
- if (aff == NULL) {
- fclose(fd);
- return NULL;
- }
+ afffile_T *aff = getroom(spin, sizeof(*aff), true);
hash_init(&aff->af_pref);
hash_init(&aff->af_suff);
hash_init(&aff->af_comp);
@@ -2098,20 +2093,18 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
smsg(_("FLAG after using flags in %s line %d: %s"),
fname, lnum, items[1]);
} else if (spell_info_item(items[0]) && itemcnt > 1) {
- p = (char_u *)getroom(spin,
- (spin->si_info == NULL ? 0 : STRLEN(spin->si_info))
- + STRLEN(items[0])
- + STRLEN(items[1]) + 3, false);
- if (p != NULL) {
- if (spin->si_info != NULL) {
- STRCPY(p, spin->si_info);
- STRCAT(p, "\n");
- }
- STRCAT(p, items[0]);
- STRCAT(p, " ");
- STRCAT(p, items[1]);
- spin->si_info = p;
+ p = getroom(spin,
+ (spin->si_info == NULL ? 0 : STRLEN(spin->si_info))
+ + STRLEN(items[0])
+ + STRLEN(items[1]) + 3, false);
+ if (spin->si_info != NULL) {
+ STRCPY(p, spin->si_info);
+ STRCAT(p, "\n");
}
+ STRCAT(p, items[0]);
+ STRCAT(p, " ");
+ STRCAT(p, items[1]);
+ spin->si_info = p;
} else if (is_aff_rule(items, itemcnt, "MIDWORD", 2)
&& midword == NULL) {
midword = getroom_save(spin, items[1]);
@@ -2291,14 +2284,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
fname, lnum, items[1]);
} else {
// New affix letter.
- cur_aff = (affheader_T *)getroom(spin,
- sizeof(affheader_T), true);
- if (cur_aff == NULL)
- break;
+ cur_aff = getroom(spin, sizeof(*cur_aff), true);
cur_aff->ah_flag = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
- if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN)
+ fname, lnum);
+ if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN) {
break;
+ }
if (cur_aff->ah_flag == aff->af_bad
|| cur_aff->ah_flag == aff->af_rare
|| cur_aff->ah_flag == aff->af_keepcase
@@ -2306,11 +2297,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| cur_aff->ah_flag == aff->af_circumfix
|| cur_aff->ah_flag == aff->af_nosuggest
|| cur_aff->ah_flag == aff->af_needcomp
- || cur_aff->ah_flag == aff->af_comproot)
+ || cur_aff->ah_flag == aff->af_comproot) {
smsg(_("Affix also used for "
"BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST"
"in %s line %d: %s"),
- fname, lnum, items[1]);
+ fname, lnum, items[1]);
+ }
STRCPY(cur_aff->ah_key, items[1]);
hash_add(tp, cur_aff->ah_key);
@@ -2372,11 +2364,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
smsg(_(e_afftrailing), fname, lnum, items[lasti]);
// New item for an affix letter.
- --aff_todo;
- aff_entry = (affentry_T *)getroom(spin,
- sizeof(affentry_T), true);
- if (aff_entry == NULL)
- break;
+ aff_todo--;
+ aff_entry = getroom(spin, sizeof(*aff_entry), true);
if (STRCMP(items[2], "0") != 0)
aff_entry->ae_chop = getroom_save(spin, items[2]);
@@ -2848,12 +2837,10 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
// the existing ID. Otherwise add a new entry.
STRLCPY(key, prevp, p - prevp + 1);
hi = hash_find(&aff->af_comp, key);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
id = HI2CI(hi)->ci_newID;
- else {
- ci = (compitem_T *)getroom(spin, sizeof(compitem_T), true);
- if (ci == NULL)
- break;
+ } else {
+ ci = getroom(spin, sizeof(compitem_T), true);
STRCPY(ci->ci_key, key);
ci->ci_flag = flag;
// Avoid using a flag ID that has a special meaning in a
@@ -3737,12 +3724,8 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align)
// Returns NULL when out of memory.
static char_u *getroom_save(spellinfo_T *spin, char_u *s)
{
- char_u *sc;
-
- sc = (char_u *)getroom(spin, STRLEN(s) + 1, false);
- if (sc != NULL)
- STRCPY(sc, s);
- return sc;
+ const size_t s_size = STRLEN(s) + 1;
+ return memcpy(getroom(spin, s_size, false), s, s_size);
}
@@ -3761,6 +3744,7 @@ static void free_blocks(sblock_T *bl)
// Allocate the root of a word tree.
// Returns NULL when out of memory.
static wordnode_T *wordtree_alloc(spellinfo_T *spin)
+ FUNC_ATTR_NONNULL_RET
{
return (wordnode_T *)getroom(spin, sizeof(wordnode_T), true);
}
@@ -4794,8 +4778,6 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
// We use si_foldroot for the soundfolded trie.
spin->si_foldroot = wordtree_alloc(spin);
- if (spin->si_foldroot == NULL)
- return FAIL;
// Let tree_add_word() know we're adding to the soundfolded tree
spin->si_sugtree = true;
@@ -5183,12 +5165,6 @@ mkspell (
spin.si_foldroot = wordtree_alloc(&spin);
spin.si_keeproot = wordtree_alloc(&spin);
spin.si_prefroot = wordtree_alloc(&spin);
- if (spin.si_foldroot == NULL
- || spin.si_keeproot == NULL
- || spin.si_prefroot == NULL) {
- free_blocks(spin.si_blocks);
- goto theend;
- }
// When not producing a .add.spl file clear the character table when
// we encounter one in the .aff file. This means we dump the current
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index e3f6a8cbf6..b3a0e4816b 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -1145,8 +1145,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
f, uarg);
break;
}
- assert(str_arg_l < sizeof(tmp));
}
+ assert(str_arg_l < sizeof(tmp));
// include the optional minus sign and possible "0x" in the region
// before the zero padding insertion point
@@ -1376,16 +1376,14 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
}
// insert zero padding as requested by precision or min field width
- if (number_of_zeros_to_pad > 0) {
- size_t zn = number_of_zeros_to_pad;
- if (str_avail) {
- size_t avail = str_m - str_l;
- memset(str + str_l, '0', MIN(zn, avail));
- str_avail = zn < avail;
- }
- assert(zn <= SIZE_MAX - str_l);
- str_l += zn;
+ size_t zn = number_of_zeros_to_pad;
+ if (str_avail) {
+ size_t avail = str_m - str_l;
+ memset(str + str_l, '0', MIN(zn, avail));
+ str_avail = zn < avail;
}
+ assert(zn <= SIZE_MAX - str_l);
+ str_l += zn;
}
// insert formatted string
diff --git a/src/nvim/strings.h b/src/nvim/strings.h
index 59b8701a3f..f2876c6307 100644
--- a/src/nvim/strings.h
+++ b/src/nvim/strings.h
@@ -3,10 +3,28 @@
#include <stdbool.h>
#include <stdarg.h>
+#include <string.h>
#include "nvim/types.h"
#include "nvim/eval/typval.h"
+/// Append string to string and return pointer to the next byte
+///
+/// Unlike strcat, this one does *not* add NUL byte and returns pointer to the
+/// past of the added string.
+///
+/// @param[out] dst String to append to.
+/// @param[in] src String to append.
+///
+/// @return pointer to the byte just past the appended byte.
+static inline char *strappend(char *const dst, const char *const src)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_NONNULL_RET
+{
+ const size_t src_len = strlen(src);
+ return (char *)memmove(dst, src, src_len) + src_len;
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "strings.h.generated.h"
#endif
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index e2476f9b0b..26de519f3c 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -451,9 +451,10 @@ void syntax_start(win_T *wp, linenr_T lnum)
if (INVALID_STATE(&current_state) && syn_block->b_sst_array != NULL) {
/* Find last valid saved state before start_lnum. */
for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next) {
- if (p->sst_lnum > lnum)
+ if (p->sst_lnum > lnum) {
break;
- if (p->sst_lnum <= lnum && p->sst_change_lnum == 0) {
+ }
+ if (p->sst_change_lnum == 0) {
last_valid = p;
if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines)
last_min_valid = p;
@@ -2825,9 +2826,10 @@ syn_add_end_off (
if (off > 0) {
while (off-- > 0 && *p != NUL)
mb_ptr_adv(p);
- } else if (off < 0) {
- while (off++ < 0 && base < p)
+ } else {
+ while (off++ < 0 && base < p) {
mb_ptr_back(base, p);
+ }
}
col = (int)(p - base);
}
@@ -2870,11 +2872,13 @@ syn_add_start_off (
base = ml_get_buf(syn_buf, result->lnum, FALSE);
p = base + col;
if (off > 0) {
- while (off-- && *p != NUL)
+ while (off-- && *p != NUL) {
mb_ptr_adv(p);
- } else if (off < 0) {
- while (off++ && base < p)
+ }
+ } else {
+ while (off++ && base < p) {
mb_ptr_back(base, p);
+ }
}
col = (int)(p - base);
}
@@ -4239,11 +4243,11 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
*/
eap->argt |= (XFILE | NOSPC);
separate_nextcmd(eap);
- if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute_path(eap->arg)) {
- /* For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the
- * file. Need to expand the file name first. In other cases
- * ":runtime!" is used. */
- source = TRUE;
+ if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute(eap->arg)) {
+ // For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the
+ // file. Need to expand the file name first. In other cases
+ // ":runtime!" is used.
+ source = true;
if (expand_filename(eap, syn_cmdlinep, &errormsg) == FAIL) {
if (errormsg != NULL)
EMSG(errormsg);
@@ -4549,20 +4553,21 @@ syn_cmd_region (
++key_end;
xfree(key);
key = vim_strnsave_up(rest, (int)(key_end - rest));
- if (STRCMP(key, "MATCHGROUP") == 0)
+ if (STRCMP(key, "MATCHGROUP") == 0) {
item = ITEM_MATCHGROUP;
- else if (STRCMP(key, "START") == 0)
+ } else if (STRCMP(key, "START") == 0) {
item = ITEM_START;
- else if (STRCMP(key, "END") == 0)
+ } else if (STRCMP(key, "END") == 0) {
item = ITEM_END;
- else if (STRCMP(key, "SKIP") == 0) {
- if (pat_ptrs[ITEM_SKIP] != NULL) { /* one skip pattern allowed */
- illegal = TRUE;
+ } else if (STRCMP(key, "SKIP") == 0) {
+ if (pat_ptrs[ITEM_SKIP] != NULL) { // One skip pattern allowed.
+ illegal = true;
break;
}
item = ITEM_SKIP;
- } else
+ } else {
break;
+ }
rest = skipwhite(key_end);
if (*rest != '=') {
rest = NULL;
@@ -4598,21 +4603,23 @@ syn_cmd_region (
pat_ptrs[item] = ppp;
ppp->pp_synp = xcalloc(1, sizeof(synpat_T));
- /*
- * Get the syntax pattern and the following offset(s).
- */
- /* Enable the appropriate \z specials. */
- if (item == ITEM_START)
+ // Get the syntax pattern and the following offset(s).
+
+ // Enable the appropriate \z specials.
+ if (item == ITEM_START) {
reg_do_extmatch = REX_SET;
- else if (item == ITEM_SKIP || item == ITEM_END)
+ } else {
+ assert(item == ITEM_SKIP || item == ITEM_END);
reg_do_extmatch = REX_USE;
+ }
rest = get_syn_pattern(rest, ppp->pp_synp);
reg_do_extmatch = 0;
if (item == ITEM_END && vim_regcomp_had_eol()
- && !(syn_opt_arg.flags & HL_EXCLUDENL))
+ && !(syn_opt_arg.flags & HL_EXCLUDENL)) {
ppp->pp_synp->sp_flags |= HL_HAS_EOL;
+ }
ppp->pp_matchgroup_id = matchgroup_id;
- ++pat_count;
+ pat_count++;
}
}
xfree(key);
@@ -5321,18 +5328,19 @@ get_id_list (
for (int i = highlight_ga.ga_len; --i >= 0; ) {
if (vim_regexec(&regmatch, HL_TABLE()[i].sg_name, (colnr_T)0)) {
if (round == 2) {
- /* Got more items than expected; can happen
- * when adding items that match:
- * "contains=a.*b,axb".
- * Go back to first round */
+ // Got more items than expected; can happen
+ // when adding items that match:
+ // "contains=a.*b,axb".
+ // Go back to first round.
if (count >= total_count) {
xfree(retval);
round = 1;
- } else
- retval[count] = i + 1;
+ } else {
+ retval[count] = i + 1; // -V522
+ }
}
- ++count;
- id = -1; /* remember that we found one */
+ count++;
+ id = -1; // Remember that we found one.
}
}
vim_regfree(regmatch.regprog);
@@ -5346,12 +5354,13 @@ get_id_list (
}
if (id > 0) {
if (round == 2) {
- /* Got more items than expected, go back to first round */
+ // Got more items than expected, go back to first round.
if (count >= total_count) {
xfree(retval);
round = 1;
- } else
+ } else {
retval[count] = id;
+ }
}
++count;
}
@@ -5721,13 +5730,9 @@ int syn_get_id(
{
// When the position is not after the current position and in the same
// line of the same buffer, need to restart parsing.
- if (wp->w_buffer != syn_buf
- || lnum != current_lnum
- || col < current_col) {
+ if (wp->w_buffer != syn_buf || lnum != current_lnum || col < current_col) {
syntax_start(wp, lnum);
- } else if (wp->w_buffer == syn_buf
- && lnum == current_lnum
- && col > current_col) {
+ } else if (col > current_col) {
// next_match may not be correct when moving around, e.g. with the
// "skip" expression in searchpair()
next_match_idx = -1;
@@ -5999,6 +6004,7 @@ static const char *highlight_init_both[] = {
"default link QuickFixLine Search",
"default link Substitute Search",
"default link Whitespace NonText",
+ "default link MsgSeparator StatusLine",
NULL
};
@@ -7799,685 +7805,685 @@ const char *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared)
color_name_table_T color_name_table[] = {
// Colors from rgb.txt
- { "AliceBlue", RGB(0xf0, 0xf8, 0xff) },
- { "AntiqueWhite", RGB(0xfa, 0xeb, 0xd7) },
- { "AntiqueWhite1", RGB(0xff, 0xef, 0xdb) },
- { "AntiqueWhite2", RGB(0xee, 0xdf, 0xcc) },
- { "AntiqueWhite3", RGB(0xcd, 0xc0, 0xb0) },
- { "AntiqueWhite4", RGB(0x8b, 0x83, 0x78) },
- { "Aqua", RGB(0x00, 0xff, 0xff) },
- { "Aquamarine", RGB(0x7f, 0xff, 0xd4) },
- { "Aquamarine1", RGB(0x7f, 0xff, 0xd4) },
- { "Aquamarine2", RGB(0x76, 0xee, 0xc6) },
- { "Aquamarine3", RGB(0x66, 0xcd, 0xaa) },
- { "Aquamarine4", RGB(0x45, 0x8b, 0x74) },
- { "Azure", RGB(0xf0, 0xff, 0xff) },
- { "Azure1", RGB(0xf0, 0xff, 0xff) },
- { "Azure2", RGB(0xe0, 0xee, 0xee) },
- { "Azure3", RGB(0xc1, 0xcd, 0xcd) },
- { "Azure4", RGB(0x83, 0x8b, 0x8b) },
- { "Beige", RGB(0xf5, 0xf5, 0xdc) },
- { "Bisque", RGB(0xff, 0xe4, 0xc4) },
- { "Bisque1", RGB(0xff, 0xe4, 0xc4) },
- { "Bisque2", RGB(0xee, 0xd5, 0xb7) },
- { "Bisque3", RGB(0xcd, 0xb7, 0x9e) },
- { "Bisque4", RGB(0x8b, 0x7d, 0x6b) },
- { "Black", RGB(0x00, 0x00, 0x00) },
- { "BlanchedAlmond", RGB(0xff, 0xeb, 0xcd) },
- { "Blue", RGB(0x00, 0x00, 0xff) },
- { "Blue1", RGB(0x0, 0x0, 0xff) },
- { "Blue2", RGB(0x0, 0x0, 0xee) },
- { "Blue3", RGB(0x0, 0x0, 0xcd) },
- { "Blue4", RGB(0x0, 0x0, 0x8b) },
- { "BlueViolet", RGB(0x8a, 0x2b, 0xe2) },
- { "Brown", RGB(0xa5, 0x2a, 0x2a) },
- { "Brown1", RGB(0xff, 0x40, 0x40) },
- { "Brown2", RGB(0xee, 0x3b, 0x3b) },
- { "Brown3", RGB(0xcd, 0x33, 0x33) },
- { "Brown4", RGB(0x8b, 0x23, 0x23) },
- { "BurlyWood", RGB(0xde, 0xb8, 0x87) },
- { "Burlywood1", RGB(0xff, 0xd3, 0x9b) },
- { "Burlywood2", RGB(0xee, 0xc5, 0x91) },
- { "Burlywood3", RGB(0xcd, 0xaa, 0x7d) },
- { "Burlywood4", RGB(0x8b, 0x73, 0x55) },
- { "CadetBlue", RGB(0x5f, 0x9e, 0xa0) },
- { "CadetBlue1", RGB(0x98, 0xf5, 0xff) },
- { "CadetBlue2", RGB(0x8e, 0xe5, 0xee) },
- { "CadetBlue3", RGB(0x7a, 0xc5, 0xcd) },
- { "CadetBlue4", RGB(0x53, 0x86, 0x8b) },
- { "ChartReuse", RGB(0x7f, 0xff, 0x00) },
- { "Chartreuse1", RGB(0x7f, 0xff, 0x0) },
- { "Chartreuse2", RGB(0x76, 0xee, 0x0) },
- { "Chartreuse3", RGB(0x66, 0xcd, 0x0) },
- { "Chartreuse4", RGB(0x45, 0x8b, 0x0) },
- { "Chocolate", RGB(0xd2, 0x69, 0x1e) },
- { "Chocolate1", RGB(0xff, 0x7f, 0x24) },
- { "Chocolate2", RGB(0xee, 0x76, 0x21) },
- { "Chocolate3", RGB(0xcd, 0x66, 0x1d) },
- { "Chocolate4", RGB(0x8b, 0x45, 0x13) },
- { "Coral", RGB(0xff, 0x7f, 0x50) },
- { "Coral1", RGB(0xff, 0x72, 0x56) },
- { "Coral2", RGB(0xee, 0x6a, 0x50) },
- { "Coral3", RGB(0xcd, 0x5b, 0x45) },
- { "Coral4", RGB(0x8b, 0x3e, 0x2f) },
- { "CornFlowerBlue", RGB(0x64, 0x95, 0xed) },
- { "Cornsilk", RGB(0xff, 0xf8, 0xdc) },
- { "Cornsilk1", RGB(0xff, 0xf8, 0xdc) },
- { "Cornsilk2", RGB(0xee, 0xe8, 0xcd) },
- { "Cornsilk3", RGB(0xcd, 0xc8, 0xb1) },
- { "Cornsilk4", RGB(0x8b, 0x88, 0x78) },
- { "Crimson", RGB(0xdc, 0x14, 0x3c) },
- { "Cyan", RGB(0x00, 0xff, 0xff) },
- { "Cyan1", RGB(0x0, 0xff, 0xff) },
- { "Cyan2", RGB(0x0, 0xee, 0xee) },
- { "Cyan3", RGB(0x0, 0xcd, 0xcd) },
- { "Cyan4", RGB(0x0, 0x8b, 0x8b) },
- { "DarkBlue", RGB(0x00, 0x00, 0x8b) },
- { "DarkCyan", RGB(0x00, 0x8b, 0x8b) },
- { "DarkGoldenRod", RGB(0xb8, 0x86, 0x0b) },
- { "DarkGoldenrod1", RGB(0xff, 0xb9, 0xf) },
- { "DarkGoldenrod2", RGB(0xee, 0xad, 0xe) },
- { "DarkGoldenrod3", RGB(0xcd, 0x95, 0xc) },
- { "DarkGoldenrod4", RGB(0x8b, 0x65, 0x8) },
- { "DarkGray", RGB(0xa9, 0xa9, 0xa9) },
- { "DarkGreen", RGB(0x00, 0x64, 0x00) },
- { "DarkGrey", RGB(0xa9, 0xa9, 0xa9) },
- { "DarkKhaki", RGB(0xbd, 0xb7, 0x6b) },
- { "DarkMagenta", RGB(0x8b, 0x00, 0x8b) },
- { "DarkOliveGreen", RGB(0x55, 0x6b, 0x2f) },
- { "DarkOliveGreen1", RGB(0xca, 0xff, 0x70) },
- { "DarkOliveGreen2", RGB(0xbc, 0xee, 0x68) },
- { "DarkOliveGreen3", RGB(0xa2, 0xcd, 0x5a) },
- { "DarkOliveGreen4", RGB(0x6e, 0x8b, 0x3d) },
- { "DarkOrange", RGB(0xff, 0x8c, 0x00) },
- { "DarkOrange1", RGB(0xff, 0x7f, 0x0) },
- { "DarkOrange2", RGB(0xee, 0x76, 0x0) },
- { "DarkOrange3", RGB(0xcd, 0x66, 0x0) },
- { "DarkOrange4", RGB(0x8b, 0x45, 0x0) },
- { "DarkOrchid", RGB(0x99, 0x32, 0xcc) },
- { "DarkOrchid1", RGB(0xbf, 0x3e, 0xff) },
- { "DarkOrchid2", RGB(0xb2, 0x3a, 0xee) },
- { "DarkOrchid3", RGB(0x9a, 0x32, 0xcd) },
- { "DarkOrchid4", RGB(0x68, 0x22, 0x8b) },
- { "DarkRed", RGB(0x8b, 0x00, 0x00) },
- { "DarkSalmon", RGB(0xe9, 0x96, 0x7a) },
- { "DarkSeaGreen", RGB(0x8f, 0xbc, 0x8f) },
- { "DarkSeaGreen1", RGB(0xc1, 0xff, 0xc1) },
- { "DarkSeaGreen2", RGB(0xb4, 0xee, 0xb4) },
- { "DarkSeaGreen3", RGB(0x9b, 0xcd, 0x9b) },
- { "DarkSeaGreen4", RGB(0x69, 0x8b, 0x69) },
- { "DarkSlateBlue", RGB(0x48, 0x3d, 0x8b) },
- { "DarkSlateGray", RGB(0x2f, 0x4f, 0x4f) },
- { "DarkSlateGray1", RGB(0x97, 0xff, 0xff) },
- { "DarkSlateGray2", RGB(0x8d, 0xee, 0xee) },
- { "DarkSlateGray3", RGB(0x79, 0xcd, 0xcd) },
- { "DarkSlateGray4", RGB(0x52, 0x8b, 0x8b) },
- { "DarkSlateGrey", RGB(0x2f, 0x4f, 0x4f) },
- { "DarkTurquoise", RGB(0x00, 0xce, 0xd1) },
- { "DarkViolet", RGB(0x94, 0x00, 0xd3) },
- { "DarkYellow", RGB(0xbb, 0xbb, 0x00) },
- { "DeepPink", RGB(0xff, 0x14, 0x93) },
- { "DeepPink1", RGB(0xff, 0x14, 0x93) },
- { "DeepPink2", RGB(0xee, 0x12, 0x89) },
- { "DeepPink3", RGB(0xcd, 0x10, 0x76) },
- { "DeepPink4", RGB(0x8b, 0xa, 0x50) },
- { "DeepSkyBlue", RGB(0x00, 0xbf, 0xff) },
- { "DeepSkyBlue1", RGB(0x0, 0xbf, 0xff) },
- { "DeepSkyBlue2", RGB(0x0, 0xb2, 0xee) },
- { "DeepSkyBlue3", RGB(0x0, 0x9a, 0xcd) },
- { "DeepSkyBlue4", RGB(0x0, 0x68, 0x8b) },
- { "DimGray", RGB(0x69, 0x69, 0x69) },
- { "DimGrey", RGB(0x69, 0x69, 0x69) },
- { "DodgerBlue", RGB(0x1e, 0x90, 0xff) },
- { "DodgerBlue1", RGB(0x1e, 0x90, 0xff) },
- { "DodgerBlue2", RGB(0x1c, 0x86, 0xee) },
- { "DodgerBlue3", RGB(0x18, 0x74, 0xcd) },
- { "DodgerBlue4", RGB(0x10, 0x4e, 0x8b) },
- { "Firebrick", RGB(0xb2, 0x22, 0x22) },
- { "Firebrick1", RGB(0xff, 0x30, 0x30) },
- { "Firebrick2", RGB(0xee, 0x2c, 0x2c) },
- { "Firebrick3", RGB(0xcd, 0x26, 0x26) },
- { "Firebrick4", RGB(0x8b, 0x1a, 0x1a) },
- { "FloralWhite", RGB(0xff, 0xfa, 0xf0) },
- { "ForestGreen", RGB(0x22, 0x8b, 0x22) },
- { "Fuchsia", RGB(0xff, 0x00, 0xff) },
- { "Gainsboro", RGB(0xdc, 0xdc, 0xdc) },
- { "GhostWhite", RGB(0xf8, 0xf8, 0xff) },
- { "Gold", RGB(0xff, 0xd7, 0x00) },
- { "Gold1", RGB(0xff, 0xd7, 0x0) },
- { "Gold2", RGB(0xee, 0xc9, 0x0) },
- { "Gold3", RGB(0xcd, 0xad, 0x0) },
- { "Gold4", RGB(0x8b, 0x75, 0x0) },
- { "GoldenRod", RGB(0xda, 0xa5, 0x20) },
- { "Goldenrod1", RGB(0xff, 0xc1, 0x25) },
- { "Goldenrod2", RGB(0xee, 0xb4, 0x22) },
- { "Goldenrod3", RGB(0xcd, 0x9b, 0x1d) },
- { "Goldenrod4", RGB(0x8b, 0x69, 0x14) },
- { "Gray", RGB(0x80, 0x80, 0x80) },
- { "Gray0", RGB(0x0, 0x0, 0x0) },
- { "Gray1", RGB(0x3, 0x3, 0x3) },
- { "Gray10", RGB(0x1a, 0x1a, 0x1a) },
- { "Gray100", RGB(0xff, 0xff, 0xff) },
- { "Gray11", RGB(0x1c, 0x1c, 0x1c) },
- { "Gray12", RGB(0x1f, 0x1f, 0x1f) },
- { "Gray13", RGB(0x21, 0x21, 0x21) },
- { "Gray14", RGB(0x24, 0x24, 0x24) },
- { "Gray15", RGB(0x26, 0x26, 0x26) },
- { "Gray16", RGB(0x29, 0x29, 0x29) },
- { "Gray17", RGB(0x2b, 0x2b, 0x2b) },
- { "Gray18", RGB(0x2e, 0x2e, 0x2e) },
- { "Gray19", RGB(0x30, 0x30, 0x30) },
- { "Gray2", RGB(0x5, 0x5, 0x5) },
- { "Gray20", RGB(0x33, 0x33, 0x33) },
- { "Gray21", RGB(0x36, 0x36, 0x36) },
- { "Gray22", RGB(0x38, 0x38, 0x38) },
- { "Gray23", RGB(0x3b, 0x3b, 0x3b) },
- { "Gray24", RGB(0x3d, 0x3d, 0x3d) },
- { "Gray25", RGB(0x40, 0x40, 0x40) },
- { "Gray26", RGB(0x42, 0x42, 0x42) },
- { "Gray27", RGB(0x45, 0x45, 0x45) },
- { "Gray28", RGB(0x47, 0x47, 0x47) },
- { "Gray29", RGB(0x4a, 0x4a, 0x4a) },
- { "Gray3", RGB(0x8, 0x8, 0x8) },
- { "Gray30", RGB(0x4d, 0x4d, 0x4d) },
- { "Gray31", RGB(0x4f, 0x4f, 0x4f) },
- { "Gray32", RGB(0x52, 0x52, 0x52) },
- { "Gray33", RGB(0x54, 0x54, 0x54) },
- { "Gray34", RGB(0x57, 0x57, 0x57) },
- { "Gray35", RGB(0x59, 0x59, 0x59) },
- { "Gray36", RGB(0x5c, 0x5c, 0x5c) },
- { "Gray37", RGB(0x5e, 0x5e, 0x5e) },
- { "Gray38", RGB(0x61, 0x61, 0x61) },
- { "Gray39", RGB(0x63, 0x63, 0x63) },
- { "Gray4", RGB(0xa, 0xa, 0xa) },
- { "Gray40", RGB(0x66, 0x66, 0x66) },
- { "Gray41", RGB(0x69, 0x69, 0x69) },
- { "Gray42", RGB(0x6b, 0x6b, 0x6b) },
- { "Gray43", RGB(0x6e, 0x6e, 0x6e) },
- { "Gray44", RGB(0x70, 0x70, 0x70) },
- { "Gray45", RGB(0x73, 0x73, 0x73) },
- { "Gray46", RGB(0x75, 0x75, 0x75) },
- { "Gray47", RGB(0x78, 0x78, 0x78) },
- { "Gray48", RGB(0x7a, 0x7a, 0x7a) },
- { "Gray49", RGB(0x7d, 0x7d, 0x7d) },
- { "Gray5", RGB(0xd, 0xd, 0xd) },
- { "Gray50", RGB(0x7f, 0x7f, 0x7f) },
- { "Gray51", RGB(0x82, 0x82, 0x82) },
- { "Gray52", RGB(0x85, 0x85, 0x85) },
- { "Gray53", RGB(0x87, 0x87, 0x87) },
- { "Gray54", RGB(0x8a, 0x8a, 0x8a) },
- { "Gray55", RGB(0x8c, 0x8c, 0x8c) },
- { "Gray56", RGB(0x8f, 0x8f, 0x8f) },
- { "Gray57", RGB(0x91, 0x91, 0x91) },
- { "Gray58", RGB(0x94, 0x94, 0x94) },
- { "Gray59", RGB(0x96, 0x96, 0x96) },
- { "Gray6", RGB(0xf, 0xf, 0xf) },
- { "Gray60", RGB(0x99, 0x99, 0x99) },
- { "Gray61", RGB(0x9c, 0x9c, 0x9c) },
- { "Gray62", RGB(0x9e, 0x9e, 0x9e) },
- { "Gray63", RGB(0xa1, 0xa1, 0xa1) },
- { "Gray64", RGB(0xa3, 0xa3, 0xa3) },
- { "Gray65", RGB(0xa6, 0xa6, 0xa6) },
- { "Gray66", RGB(0xa8, 0xa8, 0xa8) },
- { "Gray67", RGB(0xab, 0xab, 0xab) },
- { "Gray68", RGB(0xad, 0xad, 0xad) },
- { "Gray69", RGB(0xb0, 0xb0, 0xb0) },
- { "Gray7", RGB(0x12, 0x12, 0x12) },
- { "Gray70", RGB(0xb3, 0xb3, 0xb3) },
- { "Gray71", RGB(0xb5, 0xb5, 0xb5) },
- { "Gray72", RGB(0xb8, 0xb8, 0xb8) },
- { "Gray73", RGB(0xba, 0xba, 0xba) },
- { "Gray74", RGB(0xbd, 0xbd, 0xbd) },
- { "Gray75", RGB(0xbf, 0xbf, 0xbf) },
- { "Gray76", RGB(0xc2, 0xc2, 0xc2) },
- { "Gray77", RGB(0xc4, 0xc4, 0xc4) },
- { "Gray78", RGB(0xc7, 0xc7, 0xc7) },
- { "Gray79", RGB(0xc9, 0xc9, 0xc9) },
- { "Gray8", RGB(0x14, 0x14, 0x14) },
- { "Gray80", RGB(0xcc, 0xcc, 0xcc) },
- { "Gray81", RGB(0xcf, 0xcf, 0xcf) },
- { "Gray82", RGB(0xd1, 0xd1, 0xd1) },
- { "Gray83", RGB(0xd4, 0xd4, 0xd4) },
- { "Gray84", RGB(0xd6, 0xd6, 0xd6) },
- { "Gray85", RGB(0xd9, 0xd9, 0xd9) },
- { "Gray86", RGB(0xdb, 0xdb, 0xdb) },
- { "Gray87", RGB(0xde, 0xde, 0xde) },
- { "Gray88", RGB(0xe0, 0xe0, 0xe0) },
- { "Gray89", RGB(0xe3, 0xe3, 0xe3) },
- { "Gray9", RGB(0x17, 0x17, 0x17) },
- { "Gray90", RGB(0xe5, 0xe5, 0xe5) },
- { "Gray91", RGB(0xe8, 0xe8, 0xe8) },
- { "Gray92", RGB(0xeb, 0xeb, 0xeb) },
- { "Gray93", RGB(0xed, 0xed, 0xed) },
- { "Gray94", RGB(0xf0, 0xf0, 0xf0) },
- { "Gray95", RGB(0xf2, 0xf2, 0xf2) },
- { "Gray96", RGB(0xf5, 0xf5, 0xf5) },
- { "Gray97", RGB(0xf7, 0xf7, 0xf7) },
- { "Gray98", RGB(0xfa, 0xfa, 0xfa) },
- { "Gray99", RGB(0xfc, 0xfc, 0xfc) },
- { "Green", RGB(0x00, 0x80, 0x00) },
- { "Green1", RGB(0x0, 0xff, 0x0) },
- { "Green2", RGB(0x0, 0xee, 0x0) },
- { "Green3", RGB(0x0, 0xcd, 0x0) },
- { "Green4", RGB(0x0, 0x8b, 0x0) },
- { "GreenYellow", RGB(0xad, 0xff, 0x2f) },
- { "Grey", RGB(0x80, 0x80, 0x80) },
- { "Grey0", RGB(0x0, 0x0, 0x0) },
- { "Grey1", RGB(0x3, 0x3, 0x3) },
- { "Grey10", RGB(0x1a, 0x1a, 0x1a) },
- { "Grey100", RGB(0xff, 0xff, 0xff) },
- { "Grey11", RGB(0x1c, 0x1c, 0x1c) },
- { "Grey12", RGB(0x1f, 0x1f, 0x1f) },
- { "Grey13", RGB(0x21, 0x21, 0x21) },
- { "Grey14", RGB(0x24, 0x24, 0x24) },
- { "Grey15", RGB(0x26, 0x26, 0x26) },
- { "Grey16", RGB(0x29, 0x29, 0x29) },
- { "Grey17", RGB(0x2b, 0x2b, 0x2b) },
- { "Grey18", RGB(0x2e, 0x2e, 0x2e) },
- { "Grey19", RGB(0x30, 0x30, 0x30) },
- { "Grey2", RGB(0x5, 0x5, 0x5) },
- { "Grey20", RGB(0x33, 0x33, 0x33) },
- { "Grey21", RGB(0x36, 0x36, 0x36) },
- { "Grey22", RGB(0x38, 0x38, 0x38) },
- { "Grey23", RGB(0x3b, 0x3b, 0x3b) },
- { "Grey24", RGB(0x3d, 0x3d, 0x3d) },
- { "Grey25", RGB(0x40, 0x40, 0x40) },
- { "Grey26", RGB(0x42, 0x42, 0x42) },
- { "Grey27", RGB(0x45, 0x45, 0x45) },
- { "Grey28", RGB(0x47, 0x47, 0x47) },
- { "Grey29", RGB(0x4a, 0x4a, 0x4a) },
- { "Grey3", RGB(0x8, 0x8, 0x8) },
- { "Grey30", RGB(0x4d, 0x4d, 0x4d) },
- { "Grey31", RGB(0x4f, 0x4f, 0x4f) },
- { "Grey32", RGB(0x52, 0x52, 0x52) },
- { "Grey33", RGB(0x54, 0x54, 0x54) },
- { "Grey34", RGB(0x57, 0x57, 0x57) },
- { "Grey35", RGB(0x59, 0x59, 0x59) },
- { "Grey36", RGB(0x5c, 0x5c, 0x5c) },
- { "Grey37", RGB(0x5e, 0x5e, 0x5e) },
- { "Grey38", RGB(0x61, 0x61, 0x61) },
- { "Grey39", RGB(0x63, 0x63, 0x63) },
- { "Grey4", RGB(0xa, 0xa, 0xa) },
- { "Grey40", RGB(0x66, 0x66, 0x66) },
- { "Grey41", RGB(0x69, 0x69, 0x69) },
- { "Grey42", RGB(0x6b, 0x6b, 0x6b) },
- { "Grey43", RGB(0x6e, 0x6e, 0x6e) },
- { "Grey44", RGB(0x70, 0x70, 0x70) },
- { "Grey45", RGB(0x73, 0x73, 0x73) },
- { "Grey46", RGB(0x75, 0x75, 0x75) },
- { "Grey47", RGB(0x78, 0x78, 0x78) },
- { "Grey48", RGB(0x7a, 0x7a, 0x7a) },
- { "Grey49", RGB(0x7d, 0x7d, 0x7d) },
- { "Grey5", RGB(0xd, 0xd, 0xd) },
- { "Grey50", RGB(0x7f, 0x7f, 0x7f) },
- { "Grey51", RGB(0x82, 0x82, 0x82) },
- { "Grey52", RGB(0x85, 0x85, 0x85) },
- { "Grey53", RGB(0x87, 0x87, 0x87) },
- { "Grey54", RGB(0x8a, 0x8a, 0x8a) },
- { "Grey55", RGB(0x8c, 0x8c, 0x8c) },
- { "Grey56", RGB(0x8f, 0x8f, 0x8f) },
- { "Grey57", RGB(0x91, 0x91, 0x91) },
- { "Grey58", RGB(0x94, 0x94, 0x94) },
- { "Grey59", RGB(0x96, 0x96, 0x96) },
- { "Grey6", RGB(0xf, 0xf, 0xf) },
- { "Grey60", RGB(0x99, 0x99, 0x99) },
- { "Grey61", RGB(0x9c, 0x9c, 0x9c) },
- { "Grey62", RGB(0x9e, 0x9e, 0x9e) },
- { "Grey63", RGB(0xa1, 0xa1, 0xa1) },
- { "Grey64", RGB(0xa3, 0xa3, 0xa3) },
- { "Grey65", RGB(0xa6, 0xa6, 0xa6) },
- { "Grey66", RGB(0xa8, 0xa8, 0xa8) },
- { "Grey67", RGB(0xab, 0xab, 0xab) },
- { "Grey68", RGB(0xad, 0xad, 0xad) },
- { "Grey69", RGB(0xb0, 0xb0, 0xb0) },
- { "Grey7", RGB(0x12, 0x12, 0x12) },
- { "Grey70", RGB(0xb3, 0xb3, 0xb3) },
- { "Grey71", RGB(0xb5, 0xb5, 0xb5) },
- { "Grey72", RGB(0xb8, 0xb8, 0xb8) },
- { "Grey73", RGB(0xba, 0xba, 0xba) },
- { "Grey74", RGB(0xbd, 0xbd, 0xbd) },
- { "Grey75", RGB(0xbf, 0xbf, 0xbf) },
- { "Grey76", RGB(0xc2, 0xc2, 0xc2) },
- { "Grey77", RGB(0xc4, 0xc4, 0xc4) },
- { "Grey78", RGB(0xc7, 0xc7, 0xc7) },
- { "Grey79", RGB(0xc9, 0xc9, 0xc9) },
- { "Grey8", RGB(0x14, 0x14, 0x14) },
- { "Grey80", RGB(0xcc, 0xcc, 0xcc) },
- { "Grey81", RGB(0xcf, 0xcf, 0xcf) },
- { "Grey82", RGB(0xd1, 0xd1, 0xd1) },
- { "Grey83", RGB(0xd4, 0xd4, 0xd4) },
- { "Grey84", RGB(0xd6, 0xd6, 0xd6) },
- { "Grey85", RGB(0xd9, 0xd9, 0xd9) },
- { "Grey86", RGB(0xdb, 0xdb, 0xdb) },
- { "Grey87", RGB(0xde, 0xde, 0xde) },
- { "Grey88", RGB(0xe0, 0xe0, 0xe0) },
- { "Grey89", RGB(0xe3, 0xe3, 0xe3) },
- { "Grey9", RGB(0x17, 0x17, 0x17) },
- { "Grey90", RGB(0xe5, 0xe5, 0xe5) },
- { "Grey91", RGB(0xe8, 0xe8, 0xe8) },
- { "Grey92", RGB(0xeb, 0xeb, 0xeb) },
- { "Grey93", RGB(0xed, 0xed, 0xed) },
- { "Grey94", RGB(0xf0, 0xf0, 0xf0) },
- { "Grey95", RGB(0xf2, 0xf2, 0xf2) },
- { "Grey96", RGB(0xf5, 0xf5, 0xf5) },
- { "Grey97", RGB(0xf7, 0xf7, 0xf7) },
- { "Grey98", RGB(0xfa, 0xfa, 0xfa) },
- { "Grey99", RGB(0xfc, 0xfc, 0xfc) },
- { "Honeydew", RGB(0xf0, 0xff, 0xf0) },
- { "Honeydew1", RGB(0xf0, 0xff, 0xf0) },
- { "Honeydew2", RGB(0xe0, 0xee, 0xe0) },
- { "Honeydew3", RGB(0xc1, 0xcd, 0xc1) },
- { "Honeydew4", RGB(0x83, 0x8b, 0x83) },
- { "HotPink", RGB(0xff, 0x69, 0xb4) },
- { "HotPink1", RGB(0xff, 0x6e, 0xb4) },
- { "HotPink2", RGB(0xee, 0x6a, 0xa7) },
- { "HotPink3", RGB(0xcd, 0x60, 0x90) },
- { "HotPink4", RGB(0x8b, 0x3a, 0x62) },
- { "IndianRed", RGB(0xcd, 0x5c, 0x5c) },
- { "IndianRed1", RGB(0xff, 0x6a, 0x6a) },
- { "IndianRed2", RGB(0xee, 0x63, 0x63) },
- { "IndianRed3", RGB(0xcd, 0x55, 0x55) },
- { "IndianRed4", RGB(0x8b, 0x3a, 0x3a) },
- { "Indigo", RGB(0x4b, 0x00, 0x82) },
- { "Ivory", RGB(0xff, 0xff, 0xf0) },
- { "Ivory1", RGB(0xff, 0xff, 0xf0) },
- { "Ivory2", RGB(0xee, 0xee, 0xe0) },
- { "Ivory3", RGB(0xcd, 0xcd, 0xc1) },
- { "Ivory4", RGB(0x8b, 0x8b, 0x83) },
- { "Khaki", RGB(0xf0, 0xe6, 0x8c) },
- { "Khaki1", RGB(0xff, 0xf6, 0x8f) },
- { "Khaki2", RGB(0xee, 0xe6, 0x85) },
- { "Khaki3", RGB(0xcd, 0xc6, 0x73) },
- { "Khaki4", RGB(0x8b, 0x86, 0x4e) },
- { "Lavender", RGB(0xe6, 0xe6, 0xfa) },
- { "LavenderBlush", RGB(0xff, 0xf0, 0xf5) },
- { "LavenderBlush1", RGB(0xff, 0xf0, 0xf5) },
- { "LavenderBlush2", RGB(0xee, 0xe0, 0xe5) },
- { "LavenderBlush3", RGB(0xcd, 0xc1, 0xc5) },
- { "LavenderBlush4", RGB(0x8b, 0x83, 0x86) },
- { "LawnGreen", RGB(0x7c, 0xfc, 0x00) },
- { "LemonChiffon", RGB(0xff, 0xfa, 0xcd) },
- { "LemonChiffon1", RGB(0xff, 0xfa, 0xcd) },
- { "LemonChiffon2", RGB(0xee, 0xe9, 0xbf) },
- { "LemonChiffon3", RGB(0xcd, 0xc9, 0xa5) },
- { "LemonChiffon4", RGB(0x8b, 0x89, 0x70) },
- { "LightBlue", RGB(0xad, 0xd8, 0xe6) },
- { "LightBlue1", RGB(0xbf, 0xef, 0xff) },
- { "LightBlue2", RGB(0xb2, 0xdf, 0xee) },
- { "LightBlue3", RGB(0x9a, 0xc0, 0xcd) },
- { "LightBlue4", RGB(0x68, 0x83, 0x8b) },
- { "LightCoral", RGB(0xf0, 0x80, 0x80) },
- { "LightCyan", RGB(0xe0, 0xff, 0xff) },
- { "LightCyan1", RGB(0xe0, 0xff, 0xff) },
- { "LightCyan2", RGB(0xd1, 0xee, 0xee) },
- { "LightCyan3", RGB(0xb4, 0xcd, 0xcd) },
- { "LightCyan4", RGB(0x7a, 0x8b, 0x8b) },
- { "LightGoldenrod", RGB(0xee, 0xdd, 0x82) },
- { "LightGoldenrod1", RGB(0xff, 0xec, 0x8b) },
- { "LightGoldenrod2", RGB(0xee, 0xdc, 0x82) },
- { "LightGoldenrod3", RGB(0xcd, 0xbe, 0x70) },
- { "LightGoldenrod4", RGB(0x8b, 0x81, 0x4c) },
- { "LightGoldenRodYellow", RGB(0xfa, 0xfa, 0xd2) },
- { "LightGray", RGB(0xd3, 0xd3, 0xd3) },
- { "LightGreen", RGB(0x90, 0xee, 0x90) },
- { "LightGrey", RGB(0xd3, 0xd3, 0xd3) },
- { "LightMagenta", RGB(0xff, 0xbb, 0xff) },
- { "LightPink", RGB(0xff, 0xb6, 0xc1) },
- { "LightPink1", RGB(0xff, 0xae, 0xb9) },
- { "LightPink2", RGB(0xee, 0xa2, 0xad) },
- { "LightPink3", RGB(0xcd, 0x8c, 0x95) },
- { "LightPink4", RGB(0x8b, 0x5f, 0x65) },
- { "LightRed", RGB(0xff, 0xbb, 0xbb) },
- { "LightSalmon", RGB(0xff, 0xa0, 0x7a) },
- { "LightSalmon1", RGB(0xff, 0xa0, 0x7a) },
- { "LightSalmon2", RGB(0xee, 0x95, 0x72) },
- { "LightSalmon3", RGB(0xcd, 0x81, 0x62) },
- { "LightSalmon4", RGB(0x8b, 0x57, 0x42) },
- { "LightSeaGreen", RGB(0x20, 0xb2, 0xaa) },
- { "LightSkyBlue", RGB(0x87, 0xce, 0xfa) },
- { "LightSkyBlue1", RGB(0xb0, 0xe2, 0xff) },
- { "LightSkyBlue2", RGB(0xa4, 0xd3, 0xee) },
- { "LightSkyBlue3", RGB(0x8d, 0xb6, 0xcd) },
- { "LightSkyBlue4", RGB(0x60, 0x7b, 0x8b) },
- { "LightSlateBlue", RGB(0x84, 0x70, 0xff) },
- { "LightSlateGray", RGB(0x77, 0x88, 0x99) },
- { "LightSlateGrey", RGB(0x77, 0x88, 0x99) },
- { "LightSteelBlue", RGB(0xb0, 0xc4, 0xde) },
- { "LightSteelBlue1", RGB(0xca, 0xe1, 0xff) },
- { "LightSteelBlue2", RGB(0xbc, 0xd2, 0xee) },
- { "LightSteelBlue3", RGB(0xa2, 0xb5, 0xcd) },
- { "LightSteelBlue4", RGB(0x6e, 0x7b, 0x8b) },
- { "LightYellow", RGB(0xff, 0xff, 0xe0) },
- { "LightYellow1", RGB(0xff, 0xff, 0xe0) },
- { "LightYellow2", RGB(0xee, 0xee, 0xd1) },
- { "LightYellow3", RGB(0xcd, 0xcd, 0xb4) },
- { "LightYellow4", RGB(0x8b, 0x8b, 0x7a) },
- { "Lime", RGB(0x00, 0xff, 0x00) },
- { "LimeGreen", RGB(0x32, 0xcd, 0x32) },
- { "Linen", RGB(0xfa, 0xf0, 0xe6) },
- { "Magenta", RGB(0xff, 0x00, 0xff) },
- { "Magenta1", RGB(0xff, 0x0, 0xff) },
- { "Magenta2", RGB(0xee, 0x0, 0xee) },
- { "Magenta3", RGB(0xcd, 0x0, 0xcd) },
- { "Magenta4", RGB(0x8b, 0x0, 0x8b) },
- { "Maroon", RGB(0x80, 0x00, 0x00) },
- { "Maroon1", RGB(0xff, 0x34, 0xb3) },
- { "Maroon2", RGB(0xee, 0x30, 0xa7) },
- { "Maroon3", RGB(0xcd, 0x29, 0x90) },
- { "Maroon4", RGB(0x8b, 0x1c, 0x62) },
- { "MediumAquamarine", RGB(0x66, 0xcd, 0xaa) },
- { "MediumBlue", RGB(0x00, 0x00, 0xcd) },
- { "MediumOrchid", RGB(0xba, 0x55, 0xd3) },
- { "MediumOrchid1", RGB(0xe0, 0x66, 0xff) },
- { "MediumOrchid2", RGB(0xd1, 0x5f, 0xee) },
- { "MediumOrchid3", RGB(0xb4, 0x52, 0xcd) },
- { "MediumOrchid4", RGB(0x7a, 0x37, 0x8b) },
- { "MediumPurple", RGB(0x93, 0x70, 0xdb) },
- { "MediumPurple1", RGB(0xab, 0x82, 0xff) },
- { "MediumPurple2", RGB(0x9f, 0x79, 0xee) },
- { "MediumPurple3", RGB(0x89, 0x68, 0xcd) },
- { "MediumPurple4", RGB(0x5d, 0x47, 0x8b) },
- { "MediumSeaGreen", RGB(0x3c, 0xb3, 0x71) },
- { "MediumSlateBlue", RGB(0x7b, 0x68, 0xee) },
- { "MediumSpringGreen", RGB(0x00, 0xfa, 0x9a) },
- { "MediumTurquoise", RGB(0x48, 0xd1, 0xcc) },
- { "MediumVioletRed", RGB(0xc7, 0x15, 0x85) },
- { "MidnightBlue", RGB(0x19, 0x19, 0x70) },
- { "MintCream", RGB(0xf5, 0xff, 0xfa) },
- { "MistyRose", RGB(0xff, 0xe4, 0xe1) },
- { "MistyRose1", RGB(0xff, 0xe4, 0xe1) },
- { "MistyRose2", RGB(0xee, 0xd5, 0xd2) },
- { "MistyRose3", RGB(0xcd, 0xb7, 0xb5) },
- { "MistyRose4", RGB(0x8b, 0x7d, 0x7b) },
- { "Moccasin", RGB(0xff, 0xe4, 0xb5) },
- { "NavajoWhite", RGB(0xff, 0xde, 0xad) },
- { "NavajoWhite1", RGB(0xff, 0xde, 0xad) },
- { "NavajoWhite2", RGB(0xee, 0xcf, 0xa1) },
- { "NavajoWhite3", RGB(0xcd, 0xb3, 0x8b) },
- { "NavajoWhite4", RGB(0x8b, 0x79, 0x5e) },
- { "Navy", RGB(0x00, 0x00, 0x80) },
- { "NavyBlue", RGB(0x0, 0x0, 0x80) },
- { "OldLace", RGB(0xfd, 0xf5, 0xe6) },
- { "Olive", RGB(0x80, 0x80, 0x00) },
- { "OliveDrab", RGB(0x6b, 0x8e, 0x23) },
- { "OliveDrab1", RGB(0xc0, 0xff, 0x3e) },
- { "OliveDrab2", RGB(0xb3, 0xee, 0x3a) },
- { "OliveDrab3", RGB(0x9a, 0xcd, 0x32) },
- { "OliveDrab4", RGB(0x69, 0x8b, 0x22) },
- { "Orange", RGB(0xff, 0xa5, 0x00) },
- { "Orange1", RGB(0xff, 0xa5, 0x0) },
- { "Orange2", RGB(0xee, 0x9a, 0x0) },
- { "Orange3", RGB(0xcd, 0x85, 0x0) },
- { "Orange4", RGB(0x8b, 0x5a, 0x0) },
- { "OrangeRed", RGB(0xff, 0x45, 0x00) },
- { "OrangeRed1", RGB(0xff, 0x45, 0x0) },
- { "OrangeRed2", RGB(0xee, 0x40, 0x0) },
- { "OrangeRed3", RGB(0xcd, 0x37, 0x0) },
- { "OrangeRed4", RGB(0x8b, 0x25, 0x0) },
- { "Orchid", RGB(0xda, 0x70, 0xd6) },
- { "Orchid1", RGB(0xff, 0x83, 0xfa) },
- { "Orchid2", RGB(0xee, 0x7a, 0xe9) },
- { "Orchid3", RGB(0xcd, 0x69, 0xc9) },
- { "Orchid4", RGB(0x8b, 0x47, 0x89) },
- { "PaleGoldenRod", RGB(0xee, 0xe8, 0xaa) },
- { "PaleGreen", RGB(0x98, 0xfb, 0x98) },
- { "PaleGreen1", RGB(0x9a, 0xff, 0x9a) },
- { "PaleGreen2", RGB(0x90, 0xee, 0x90) },
- { "PaleGreen3", RGB(0x7c, 0xcd, 0x7c) },
- { "PaleGreen4", RGB(0x54, 0x8b, 0x54) },
- { "PaleTurquoise", RGB(0xaf, 0xee, 0xee) },
- { "PaleTurquoise1", RGB(0xbb, 0xff, 0xff) },
- { "PaleTurquoise2", RGB(0xae, 0xee, 0xee) },
- { "PaleTurquoise3", RGB(0x96, 0xcd, 0xcd) },
- { "PaleTurquoise4", RGB(0x66, 0x8b, 0x8b) },
- { "PaleVioletRed", RGB(0xdb, 0x70, 0x93) },
- { "PaleVioletRed1", RGB(0xff, 0x82, 0xab) },
- { "PaleVioletRed2", RGB(0xee, 0x79, 0x9f) },
- { "PaleVioletRed3", RGB(0xcd, 0x68, 0x89) },
- { "PaleVioletRed4", RGB(0x8b, 0x47, 0x5d) },
- { "PapayaWhip", RGB(0xff, 0xef, 0xd5) },
- { "PeachPuff", RGB(0xff, 0xda, 0xb9) },
- { "PeachPuff1", RGB(0xff, 0xda, 0xb9) },
- { "PeachPuff2", RGB(0xee, 0xcb, 0xad) },
- { "PeachPuff3", RGB(0xcd, 0xaf, 0x95) },
- { "PeachPuff4", RGB(0x8b, 0x77, 0x65) },
- { "Peru", RGB(0xcd, 0x85, 0x3f) },
- { "Pink", RGB(0xff, 0xc0, 0xcb) },
- { "Pink1", RGB(0xff, 0xb5, 0xc5) },
- { "Pink2", RGB(0xee, 0xa9, 0xb8) },
- { "Pink3", RGB(0xcd, 0x91, 0x9e) },
- { "Pink4", RGB(0x8b, 0x63, 0x6c) },
- { "Plum", RGB(0xdd, 0xa0, 0xdd) },
- { "Plum1", RGB(0xff, 0xbb, 0xff) },
- { "Plum2", RGB(0xee, 0xae, 0xee) },
- { "Plum3", RGB(0xcd, 0x96, 0xcd) },
- { "Plum4", RGB(0x8b, 0x66, 0x8b) },
- { "PowderBlue", RGB(0xb0, 0xe0, 0xe6) },
- { "Purple", RGB(0x80, 0x00, 0x80) },
- { "Purple1", RGB(0x9b, 0x30, 0xff) },
- { "Purple2", RGB(0x91, 0x2c, 0xee) },
- { "Purple3", RGB(0x7d, 0x26, 0xcd) },
- { "Purple4", RGB(0x55, 0x1a, 0x8b) },
- { "RebeccaPurple", RGB(0x66, 0x33, 0x99) },
- { "Red", RGB(0xff, 0x00, 0x00) },
- { "Red1", RGB(0xff, 0x0, 0x0) },
- { "Red2", RGB(0xee, 0x0, 0x0) },
- { "Red3", RGB(0xcd, 0x0, 0x0) },
- { "Red4", RGB(0x8b, 0x0, 0x0) },
- { "RosyBrown", RGB(0xbc, 0x8f, 0x8f) },
- { "RosyBrown1", RGB(0xff, 0xc1, 0xc1) },
- { "RosyBrown2", RGB(0xee, 0xb4, 0xb4) },
- { "RosyBrown3", RGB(0xcd, 0x9b, 0x9b) },
- { "RosyBrown4", RGB(0x8b, 0x69, 0x69) },
- { "RoyalBlue", RGB(0x41, 0x69, 0xe1) },
- { "RoyalBlue1", RGB(0x48, 0x76, 0xff) },
- { "RoyalBlue2", RGB(0x43, 0x6e, 0xee) },
- { "RoyalBlue3", RGB(0x3a, 0x5f, 0xcd) },
- { "RoyalBlue4", RGB(0x27, 0x40, 0x8b) },
- { "SaddleBrown", RGB(0x8b, 0x45, 0x13) },
- { "Salmon", RGB(0xfa, 0x80, 0x72) },
- { "Salmon1", RGB(0xff, 0x8c, 0x69) },
- { "Salmon2", RGB(0xee, 0x82, 0x62) },
- { "Salmon3", RGB(0xcd, 0x70, 0x54) },
- { "Salmon4", RGB(0x8b, 0x4c, 0x39) },
- { "SandyBrown", RGB(0xf4, 0xa4, 0x60) },
- { "SeaGreen", RGB(0x2e, 0x8b, 0x57) },
- { "SeaGreen1", RGB(0x54, 0xff, 0x9f) },
- { "SeaGreen2", RGB(0x4e, 0xee, 0x94) },
- { "SeaGreen3", RGB(0x43, 0xcd, 0x80) },
- { "SeaGreen4", RGB(0x2e, 0x8b, 0x57) },
- { "SeaShell", RGB(0xff, 0xf5, 0xee) },
- { "Seashell1", RGB(0xff, 0xf5, 0xee) },
- { "Seashell2", RGB(0xee, 0xe5, 0xde) },
- { "Seashell3", RGB(0xcd, 0xc5, 0xbf) },
- { "Seashell4", RGB(0x8b, 0x86, 0x82) },
- { "Sienna", RGB(0xa0, 0x52, 0x2d) },
- { "Sienna1", RGB(0xff, 0x82, 0x47) },
- { "Sienna2", RGB(0xee, 0x79, 0x42) },
- { "Sienna3", RGB(0xcd, 0x68, 0x39) },
- { "Sienna4", RGB(0x8b, 0x47, 0x26) },
- { "Silver", RGB(0xc0, 0xc0, 0xc0) },
- { "SkyBlue", RGB(0x87, 0xce, 0xeb) },
- { "SkyBlue1", RGB(0x87, 0xce, 0xff) },
- { "SkyBlue2", RGB(0x7e, 0xc0, 0xee) },
- { "SkyBlue3", RGB(0x6c, 0xa6, 0xcd) },
- { "SkyBlue4", RGB(0x4a, 0x70, 0x8b) },
- { "SlateBlue", RGB(0x6a, 0x5a, 0xcd) },
- { "SlateBlue1", RGB(0x83, 0x6f, 0xff) },
- { "SlateBlue2", RGB(0x7a, 0x67, 0xee) },
- { "SlateBlue3", RGB(0x69, 0x59, 0xcd) },
- { "SlateBlue4", RGB(0x47, 0x3c, 0x8b) },
- { "SlateGray", RGB(0x70, 0x80, 0x90) },
- { "SlateGray1", RGB(0xc6, 0xe2, 0xff) },
- { "SlateGray2", RGB(0xb9, 0xd3, 0xee) },
- { "SlateGray3", RGB(0x9f, 0xb6, 0xcd) },
- { "SlateGray4", RGB(0x6c, 0x7b, 0x8b) },
- { "SlateGrey", RGB(0x70, 0x80, 0x90) },
- { "Snow", RGB(0xff, 0xfa, 0xfa) },
- { "Snow1", RGB(0xff, 0xfa, 0xfa) },
- { "Snow2", RGB(0xee, 0xe9, 0xe9) },
- { "Snow3", RGB(0xcd, 0xc9, 0xc9) },
- { "Snow4", RGB(0x8b, 0x89, 0x89) },
- { "SpringGreen", RGB(0x00, 0xff, 0x7f) },
- { "SpringGreen1", RGB(0x0, 0xff, 0x7f) },
- { "SpringGreen2", RGB(0x0, 0xee, 0x76) },
- { "SpringGreen3", RGB(0x0, 0xcd, 0x66) },
- { "SpringGreen4", RGB(0x0, 0x8b, 0x45) },
- { "SteelBlue", RGB(0x46, 0x82, 0xb4) },
- { "SteelBlue1", RGB(0x63, 0xb8, 0xff) },
- { "SteelBlue2", RGB(0x5c, 0xac, 0xee) },
- { "SteelBlue3", RGB(0x4f, 0x94, 0xcd) },
- { "SteelBlue4", RGB(0x36, 0x64, 0x8b) },
- { "Tan", RGB(0xd2, 0xb4, 0x8c) },
- { "Tan1", RGB(0xff, 0xa5, 0x4f) },
- { "Tan2", RGB(0xee, 0x9a, 0x49) },
- { "Tan3", RGB(0xcd, 0x85, 0x3f) },
- { "Tan4", RGB(0x8b, 0x5a, 0x2b) },
- { "Teal", RGB(0x00, 0x80, 0x80) },
- { "Thistle", RGB(0xd8, 0xbf, 0xd8) },
- { "Thistle1", RGB(0xff, 0xe1, 0xff) },
- { "Thistle2", RGB(0xee, 0xd2, 0xee) },
- { "Thistle3", RGB(0xcd, 0xb5, 0xcd) },
- { "Thistle4", RGB(0x8b, 0x7b, 0x8b) },
- { "Tomato", RGB(0xff, 0x63, 0x47) },
- { "Tomato1", RGB(0xff, 0x63, 0x47) },
- { "Tomato2", RGB(0xee, 0x5c, 0x42) },
- { "Tomato3", RGB(0xcd, 0x4f, 0x39) },
- { "Tomato4", RGB(0x8b, 0x36, 0x26) },
- { "Turquoise", RGB(0x40, 0xe0, 0xd0) },
- { "Turquoise1", RGB(0x0, 0xf5, 0xff) },
- { "Turquoise2", RGB(0x0, 0xe5, 0xee) },
- { "Turquoise3", RGB(0x0, 0xc5, 0xcd) },
- { "Turquoise4", RGB(0x0, 0x86, 0x8b) },
- { "Violet", RGB(0xee, 0x82, 0xee) },
- { "VioletRed", RGB(0xd0, 0x20, 0x90) },
- { "VioletRed1", RGB(0xff, 0x3e, 0x96) },
- { "VioletRed2", RGB(0xee, 0x3a, 0x8c) },
- { "VioletRed3", RGB(0xcd, 0x32, 0x78) },
- { "VioletRed4", RGB(0x8b, 0x22, 0x52) },
- { "WebGray", RGB(0x80, 0x80, 0x80) },
- { "WebGreen", RGB(0x0, 0x80, 0x0) },
- { "WebGrey", RGB(0x80, 0x80, 0x80) },
- { "WebMaroon", RGB(0x80, 0x0, 0x0) },
- { "WebPurple", RGB(0x80, 0x0, 0x80) },
- { "Wheat", RGB(0xf5, 0xde, 0xb3) },
- { "Wheat1", RGB(0xff, 0xe7, 0xba) },
- { "Wheat2", RGB(0xee, 0xd8, 0xae) },
- { "Wheat3", RGB(0xcd, 0xba, 0x96) },
- { "Wheat4", RGB(0x8b, 0x7e, 0x66) },
- { "White", RGB(0xff, 0xff, 0xff) },
- { "WhiteSmoke", RGB(0xf5, 0xf5, 0xf5) },
- { "X11Gray", RGB(0xbe, 0xbe, 0xbe) },
- { "X11Green", RGB(0x0, 0xff, 0x0) },
- { "X11Grey", RGB(0xbe, 0xbe, 0xbe) },
- { "X11Maroon", RGB(0xb0, 0x30, 0x60) },
- { "X11Purple", RGB(0xa0, 0x20, 0xf0) },
- { "Yellow", RGB(0xff, 0xff, 0x00) },
- { "Yellow1", RGB(0xff, 0xff, 0x0) },
- { "Yellow2", RGB(0xee, 0xee, 0x0) },
- { "Yellow3", RGB(0xcd, 0xcd, 0x0) },
- { "Yellow4", RGB(0x8b, 0x8b, 0x0) },
- { "YellowGreen", RGB(0x9a, 0xcd, 0x32) },
+ { "AliceBlue", RGB_(0xf0, 0xf8, 0xff) },
+ { "AntiqueWhite", RGB_(0xfa, 0xeb, 0xd7) },
+ { "AntiqueWhite1", RGB_(0xff, 0xef, 0xdb) },
+ { "AntiqueWhite2", RGB_(0xee, 0xdf, 0xcc) },
+ { "AntiqueWhite3", RGB_(0xcd, 0xc0, 0xb0) },
+ { "AntiqueWhite4", RGB_(0x8b, 0x83, 0x78) },
+ { "Aqua", RGB_(0x00, 0xff, 0xff) },
+ { "Aquamarine", RGB_(0x7f, 0xff, 0xd4) },
+ { "Aquamarine1", RGB_(0x7f, 0xff, 0xd4) },
+ { "Aquamarine2", RGB_(0x76, 0xee, 0xc6) },
+ { "Aquamarine3", RGB_(0x66, 0xcd, 0xaa) },
+ { "Aquamarine4", RGB_(0x45, 0x8b, 0x74) },
+ { "Azure", RGB_(0xf0, 0xff, 0xff) },
+ { "Azure1", RGB_(0xf0, 0xff, 0xff) },
+ { "Azure2", RGB_(0xe0, 0xee, 0xee) },
+ { "Azure3", RGB_(0xc1, 0xcd, 0xcd) },
+ { "Azure4", RGB_(0x83, 0x8b, 0x8b) },
+ { "Beige", RGB_(0xf5, 0xf5, 0xdc) },
+ { "Bisque", RGB_(0xff, 0xe4, 0xc4) },
+ { "Bisque1", RGB_(0xff, 0xe4, 0xc4) },
+ { "Bisque2", RGB_(0xee, 0xd5, 0xb7) },
+ { "Bisque3", RGB_(0xcd, 0xb7, 0x9e) },
+ { "Bisque4", RGB_(0x8b, 0x7d, 0x6b) },
+ { "Black", RGB_(0x00, 0x00, 0x00) },
+ { "BlanchedAlmond", RGB_(0xff, 0xeb, 0xcd) },
+ { "Blue", RGB_(0x00, 0x00, 0xff) },
+ { "Blue1", RGB_(0x0, 0x0, 0xff) },
+ { "Blue2", RGB_(0x0, 0x0, 0xee) },
+ { "Blue3", RGB_(0x0, 0x0, 0xcd) },
+ { "Blue4", RGB_(0x0, 0x0, 0x8b) },
+ { "BlueViolet", RGB_(0x8a, 0x2b, 0xe2) },
+ { "Brown", RGB_(0xa5, 0x2a, 0x2a) },
+ { "Brown1", RGB_(0xff, 0x40, 0x40) },
+ { "Brown2", RGB_(0xee, 0x3b, 0x3b) },
+ { "Brown3", RGB_(0xcd, 0x33, 0x33) },
+ { "Brown4", RGB_(0x8b, 0x23, 0x23) },
+ { "BurlyWood", RGB_(0xde, 0xb8, 0x87) },
+ { "Burlywood1", RGB_(0xff, 0xd3, 0x9b) },
+ { "Burlywood2", RGB_(0xee, 0xc5, 0x91) },
+ { "Burlywood3", RGB_(0xcd, 0xaa, 0x7d) },
+ { "Burlywood4", RGB_(0x8b, 0x73, 0x55) },
+ { "CadetBlue", RGB_(0x5f, 0x9e, 0xa0) },
+ { "CadetBlue1", RGB_(0x98, 0xf5, 0xff) },
+ { "CadetBlue2", RGB_(0x8e, 0xe5, 0xee) },
+ { "CadetBlue3", RGB_(0x7a, 0xc5, 0xcd) },
+ { "CadetBlue4", RGB_(0x53, 0x86, 0x8b) },
+ { "ChartReuse", RGB_(0x7f, 0xff, 0x00) },
+ { "Chartreuse1", RGB_(0x7f, 0xff, 0x0) },
+ { "Chartreuse2", RGB_(0x76, 0xee, 0x0) },
+ { "Chartreuse3", RGB_(0x66, 0xcd, 0x0) },
+ { "Chartreuse4", RGB_(0x45, 0x8b, 0x0) },
+ { "Chocolate", RGB_(0xd2, 0x69, 0x1e) },
+ { "Chocolate1", RGB_(0xff, 0x7f, 0x24) },
+ { "Chocolate2", RGB_(0xee, 0x76, 0x21) },
+ { "Chocolate3", RGB_(0xcd, 0x66, 0x1d) },
+ { "Chocolate4", RGB_(0x8b, 0x45, 0x13) },
+ { "Coral", RGB_(0xff, 0x7f, 0x50) },
+ { "Coral1", RGB_(0xff, 0x72, 0x56) },
+ { "Coral2", RGB_(0xee, 0x6a, 0x50) },
+ { "Coral3", RGB_(0xcd, 0x5b, 0x45) },
+ { "Coral4", RGB_(0x8b, 0x3e, 0x2f) },
+ { "CornFlowerBlue", RGB_(0x64, 0x95, 0xed) },
+ { "Cornsilk", RGB_(0xff, 0xf8, 0xdc) },
+ { "Cornsilk1", RGB_(0xff, 0xf8, 0xdc) },
+ { "Cornsilk2", RGB_(0xee, 0xe8, 0xcd) },
+ { "Cornsilk3", RGB_(0xcd, 0xc8, 0xb1) },
+ { "Cornsilk4", RGB_(0x8b, 0x88, 0x78) },
+ { "Crimson", RGB_(0xdc, 0x14, 0x3c) },
+ { "Cyan", RGB_(0x00, 0xff, 0xff) },
+ { "Cyan1", RGB_(0x0, 0xff, 0xff) },
+ { "Cyan2", RGB_(0x0, 0xee, 0xee) },
+ { "Cyan3", RGB_(0x0, 0xcd, 0xcd) },
+ { "Cyan4", RGB_(0x0, 0x8b, 0x8b) },
+ { "DarkBlue", RGB_(0x00, 0x00, 0x8b) },
+ { "DarkCyan", RGB_(0x00, 0x8b, 0x8b) },
+ { "DarkGoldenRod", RGB_(0xb8, 0x86, 0x0b) },
+ { "DarkGoldenrod1", RGB_(0xff, 0xb9, 0xf) },
+ { "DarkGoldenrod2", RGB_(0xee, 0xad, 0xe) },
+ { "DarkGoldenrod3", RGB_(0xcd, 0x95, 0xc) },
+ { "DarkGoldenrod4", RGB_(0x8b, 0x65, 0x8) },
+ { "DarkGray", RGB_(0xa9, 0xa9, 0xa9) },
+ { "DarkGreen", RGB_(0x00, 0x64, 0x00) },
+ { "DarkGrey", RGB_(0xa9, 0xa9, 0xa9) },
+ { "DarkKhaki", RGB_(0xbd, 0xb7, 0x6b) },
+ { "DarkMagenta", RGB_(0x8b, 0x00, 0x8b) },
+ { "DarkOliveGreen", RGB_(0x55, 0x6b, 0x2f) },
+ { "DarkOliveGreen1", RGB_(0xca, 0xff, 0x70) },
+ { "DarkOliveGreen2", RGB_(0xbc, 0xee, 0x68) },
+ { "DarkOliveGreen3", RGB_(0xa2, 0xcd, 0x5a) },
+ { "DarkOliveGreen4", RGB_(0x6e, 0x8b, 0x3d) },
+ { "DarkOrange", RGB_(0xff, 0x8c, 0x00) },
+ { "DarkOrange1", RGB_(0xff, 0x7f, 0x0) },
+ { "DarkOrange2", RGB_(0xee, 0x76, 0x0) },
+ { "DarkOrange3", RGB_(0xcd, 0x66, 0x0) },
+ { "DarkOrange4", RGB_(0x8b, 0x45, 0x0) },
+ { "DarkOrchid", RGB_(0x99, 0x32, 0xcc) },
+ { "DarkOrchid1", RGB_(0xbf, 0x3e, 0xff) },
+ { "DarkOrchid2", RGB_(0xb2, 0x3a, 0xee) },
+ { "DarkOrchid3", RGB_(0x9a, 0x32, 0xcd) },
+ { "DarkOrchid4", RGB_(0x68, 0x22, 0x8b) },
+ { "DarkRed", RGB_(0x8b, 0x00, 0x00) },
+ { "DarkSalmon", RGB_(0xe9, 0x96, 0x7a) },
+ { "DarkSeaGreen", RGB_(0x8f, 0xbc, 0x8f) },
+ { "DarkSeaGreen1", RGB_(0xc1, 0xff, 0xc1) },
+ { "DarkSeaGreen2", RGB_(0xb4, 0xee, 0xb4) },
+ { "DarkSeaGreen3", RGB_(0x9b, 0xcd, 0x9b) },
+ { "DarkSeaGreen4", RGB_(0x69, 0x8b, 0x69) },
+ { "DarkSlateBlue", RGB_(0x48, 0x3d, 0x8b) },
+ { "DarkSlateGray", RGB_(0x2f, 0x4f, 0x4f) },
+ { "DarkSlateGray1", RGB_(0x97, 0xff, 0xff) },
+ { "DarkSlateGray2", RGB_(0x8d, 0xee, 0xee) },
+ { "DarkSlateGray3", RGB_(0x79, 0xcd, 0xcd) },
+ { "DarkSlateGray4", RGB_(0x52, 0x8b, 0x8b) },
+ { "DarkSlateGrey", RGB_(0x2f, 0x4f, 0x4f) },
+ { "DarkTurquoise", RGB_(0x00, 0xce, 0xd1) },
+ { "DarkViolet", RGB_(0x94, 0x00, 0xd3) },
+ { "DarkYellow", RGB_(0xbb, 0xbb, 0x00) },
+ { "DeepPink", RGB_(0xff, 0x14, 0x93) },
+ { "DeepPink1", RGB_(0xff, 0x14, 0x93) },
+ { "DeepPink2", RGB_(0xee, 0x12, 0x89) },
+ { "DeepPink3", RGB_(0xcd, 0x10, 0x76) },
+ { "DeepPink4", RGB_(0x8b, 0xa, 0x50) },
+ { "DeepSkyBlue", RGB_(0x00, 0xbf, 0xff) },
+ { "DeepSkyBlue1", RGB_(0x0, 0xbf, 0xff) },
+ { "DeepSkyBlue2", RGB_(0x0, 0xb2, 0xee) },
+ { "DeepSkyBlue3", RGB_(0x0, 0x9a, 0xcd) },
+ { "DeepSkyBlue4", RGB_(0x0, 0x68, 0x8b) },
+ { "DimGray", RGB_(0x69, 0x69, 0x69) },
+ { "DimGrey", RGB_(0x69, 0x69, 0x69) },
+ { "DodgerBlue", RGB_(0x1e, 0x90, 0xff) },
+ { "DodgerBlue1", RGB_(0x1e, 0x90, 0xff) },
+ { "DodgerBlue2", RGB_(0x1c, 0x86, 0xee) },
+ { "DodgerBlue3", RGB_(0x18, 0x74, 0xcd) },
+ { "DodgerBlue4", RGB_(0x10, 0x4e, 0x8b) },
+ { "Firebrick", RGB_(0xb2, 0x22, 0x22) },
+ { "Firebrick1", RGB_(0xff, 0x30, 0x30) },
+ { "Firebrick2", RGB_(0xee, 0x2c, 0x2c) },
+ { "Firebrick3", RGB_(0xcd, 0x26, 0x26) },
+ { "Firebrick4", RGB_(0x8b, 0x1a, 0x1a) },
+ { "FloralWhite", RGB_(0xff, 0xfa, 0xf0) },
+ { "ForestGreen", RGB_(0x22, 0x8b, 0x22) },
+ { "Fuchsia", RGB_(0xff, 0x00, 0xff) },
+ { "Gainsboro", RGB_(0xdc, 0xdc, 0xdc) },
+ { "GhostWhite", RGB_(0xf8, 0xf8, 0xff) },
+ { "Gold", RGB_(0xff, 0xd7, 0x00) },
+ { "Gold1", RGB_(0xff, 0xd7, 0x0) },
+ { "Gold2", RGB_(0xee, 0xc9, 0x0) },
+ { "Gold3", RGB_(0xcd, 0xad, 0x0) },
+ { "Gold4", RGB_(0x8b, 0x75, 0x0) },
+ { "GoldenRod", RGB_(0xda, 0xa5, 0x20) },
+ { "Goldenrod1", RGB_(0xff, 0xc1, 0x25) },
+ { "Goldenrod2", RGB_(0xee, 0xb4, 0x22) },
+ { "Goldenrod3", RGB_(0xcd, 0x9b, 0x1d) },
+ { "Goldenrod4", RGB_(0x8b, 0x69, 0x14) },
+ { "Gray", RGB_(0x80, 0x80, 0x80) },
+ { "Gray0", RGB_(0x0, 0x0, 0x0) },
+ { "Gray1", RGB_(0x3, 0x3, 0x3) },
+ { "Gray10", RGB_(0x1a, 0x1a, 0x1a) },
+ { "Gray100", RGB_(0xff, 0xff, 0xff) },
+ { "Gray11", RGB_(0x1c, 0x1c, 0x1c) },
+ { "Gray12", RGB_(0x1f, 0x1f, 0x1f) },
+ { "Gray13", RGB_(0x21, 0x21, 0x21) },
+ { "Gray14", RGB_(0x24, 0x24, 0x24) },
+ { "Gray15", RGB_(0x26, 0x26, 0x26) },
+ { "Gray16", RGB_(0x29, 0x29, 0x29) },
+ { "Gray17", RGB_(0x2b, 0x2b, 0x2b) },
+ { "Gray18", RGB_(0x2e, 0x2e, 0x2e) },
+ { "Gray19", RGB_(0x30, 0x30, 0x30) },
+ { "Gray2", RGB_(0x5, 0x5, 0x5) },
+ { "Gray20", RGB_(0x33, 0x33, 0x33) },
+ { "Gray21", RGB_(0x36, 0x36, 0x36) },
+ { "Gray22", RGB_(0x38, 0x38, 0x38) },
+ { "Gray23", RGB_(0x3b, 0x3b, 0x3b) },
+ { "Gray24", RGB_(0x3d, 0x3d, 0x3d) },
+ { "Gray25", RGB_(0x40, 0x40, 0x40) },
+ { "Gray26", RGB_(0x42, 0x42, 0x42) },
+ { "Gray27", RGB_(0x45, 0x45, 0x45) },
+ { "Gray28", RGB_(0x47, 0x47, 0x47) },
+ { "Gray29", RGB_(0x4a, 0x4a, 0x4a) },
+ { "Gray3", RGB_(0x8, 0x8, 0x8) },
+ { "Gray30", RGB_(0x4d, 0x4d, 0x4d) },
+ { "Gray31", RGB_(0x4f, 0x4f, 0x4f) },
+ { "Gray32", RGB_(0x52, 0x52, 0x52) },
+ { "Gray33", RGB_(0x54, 0x54, 0x54) },
+ { "Gray34", RGB_(0x57, 0x57, 0x57) },
+ { "Gray35", RGB_(0x59, 0x59, 0x59) },
+ { "Gray36", RGB_(0x5c, 0x5c, 0x5c) },
+ { "Gray37", RGB_(0x5e, 0x5e, 0x5e) },
+ { "Gray38", RGB_(0x61, 0x61, 0x61) },
+ { "Gray39", RGB_(0x63, 0x63, 0x63) },
+ { "Gray4", RGB_(0xa, 0xa, 0xa) },
+ { "Gray40", RGB_(0x66, 0x66, 0x66) },
+ { "Gray41", RGB_(0x69, 0x69, 0x69) },
+ { "Gray42", RGB_(0x6b, 0x6b, 0x6b) },
+ { "Gray43", RGB_(0x6e, 0x6e, 0x6e) },
+ { "Gray44", RGB_(0x70, 0x70, 0x70) },
+ { "Gray45", RGB_(0x73, 0x73, 0x73) },
+ { "Gray46", RGB_(0x75, 0x75, 0x75) },
+ { "Gray47", RGB_(0x78, 0x78, 0x78) },
+ { "Gray48", RGB_(0x7a, 0x7a, 0x7a) },
+ { "Gray49", RGB_(0x7d, 0x7d, 0x7d) },
+ { "Gray5", RGB_(0xd, 0xd, 0xd) },
+ { "Gray50", RGB_(0x7f, 0x7f, 0x7f) },
+ { "Gray51", RGB_(0x82, 0x82, 0x82) },
+ { "Gray52", RGB_(0x85, 0x85, 0x85) },
+ { "Gray53", RGB_(0x87, 0x87, 0x87) },
+ { "Gray54", RGB_(0x8a, 0x8a, 0x8a) },
+ { "Gray55", RGB_(0x8c, 0x8c, 0x8c) },
+ { "Gray56", RGB_(0x8f, 0x8f, 0x8f) },
+ { "Gray57", RGB_(0x91, 0x91, 0x91) },
+ { "Gray58", RGB_(0x94, 0x94, 0x94) },
+ { "Gray59", RGB_(0x96, 0x96, 0x96) },
+ { "Gray6", RGB_(0xf, 0xf, 0xf) },
+ { "Gray60", RGB_(0x99, 0x99, 0x99) },
+ { "Gray61", RGB_(0x9c, 0x9c, 0x9c) },
+ { "Gray62", RGB_(0x9e, 0x9e, 0x9e) },
+ { "Gray63", RGB_(0xa1, 0xa1, 0xa1) },
+ { "Gray64", RGB_(0xa3, 0xa3, 0xa3) },
+ { "Gray65", RGB_(0xa6, 0xa6, 0xa6) },
+ { "Gray66", RGB_(0xa8, 0xa8, 0xa8) },
+ { "Gray67", RGB_(0xab, 0xab, 0xab) },
+ { "Gray68", RGB_(0xad, 0xad, 0xad) },
+ { "Gray69", RGB_(0xb0, 0xb0, 0xb0) },
+ { "Gray7", RGB_(0x12, 0x12, 0x12) },
+ { "Gray70", RGB_(0xb3, 0xb3, 0xb3) },
+ { "Gray71", RGB_(0xb5, 0xb5, 0xb5) },
+ { "Gray72", RGB_(0xb8, 0xb8, 0xb8) },
+ { "Gray73", RGB_(0xba, 0xba, 0xba) },
+ { "Gray74", RGB_(0xbd, 0xbd, 0xbd) },
+ { "Gray75", RGB_(0xbf, 0xbf, 0xbf) },
+ { "Gray76", RGB_(0xc2, 0xc2, 0xc2) },
+ { "Gray77", RGB_(0xc4, 0xc4, 0xc4) },
+ { "Gray78", RGB_(0xc7, 0xc7, 0xc7) },
+ { "Gray79", RGB_(0xc9, 0xc9, 0xc9) },
+ { "Gray8", RGB_(0x14, 0x14, 0x14) },
+ { "Gray80", RGB_(0xcc, 0xcc, 0xcc) },
+ { "Gray81", RGB_(0xcf, 0xcf, 0xcf) },
+ { "Gray82", RGB_(0xd1, 0xd1, 0xd1) },
+ { "Gray83", RGB_(0xd4, 0xd4, 0xd4) },
+ { "Gray84", RGB_(0xd6, 0xd6, 0xd6) },
+ { "Gray85", RGB_(0xd9, 0xd9, 0xd9) },
+ { "Gray86", RGB_(0xdb, 0xdb, 0xdb) },
+ { "Gray87", RGB_(0xde, 0xde, 0xde) },
+ { "Gray88", RGB_(0xe0, 0xe0, 0xe0) },
+ { "Gray89", RGB_(0xe3, 0xe3, 0xe3) },
+ { "Gray9", RGB_(0x17, 0x17, 0x17) },
+ { "Gray90", RGB_(0xe5, 0xe5, 0xe5) },
+ { "Gray91", RGB_(0xe8, 0xe8, 0xe8) },
+ { "Gray92", RGB_(0xeb, 0xeb, 0xeb) },
+ { "Gray93", RGB_(0xed, 0xed, 0xed) },
+ { "Gray94", RGB_(0xf0, 0xf0, 0xf0) },
+ { "Gray95", RGB_(0xf2, 0xf2, 0xf2) },
+ { "Gray96", RGB_(0xf5, 0xf5, 0xf5) },
+ { "Gray97", RGB_(0xf7, 0xf7, 0xf7) },
+ { "Gray98", RGB_(0xfa, 0xfa, 0xfa) },
+ { "Gray99", RGB_(0xfc, 0xfc, 0xfc) },
+ { "Green", RGB_(0x00, 0x80, 0x00) },
+ { "Green1", RGB_(0x0, 0xff, 0x0) },
+ { "Green2", RGB_(0x0, 0xee, 0x0) },
+ { "Green3", RGB_(0x0, 0xcd, 0x0) },
+ { "Green4", RGB_(0x0, 0x8b, 0x0) },
+ { "GreenYellow", RGB_(0xad, 0xff, 0x2f) },
+ { "Grey", RGB_(0x80, 0x80, 0x80) },
+ { "Grey0", RGB_(0x0, 0x0, 0x0) },
+ { "Grey1", RGB_(0x3, 0x3, 0x3) },
+ { "Grey10", RGB_(0x1a, 0x1a, 0x1a) },
+ { "Grey100", RGB_(0xff, 0xff, 0xff) },
+ { "Grey11", RGB_(0x1c, 0x1c, 0x1c) },
+ { "Grey12", RGB_(0x1f, 0x1f, 0x1f) },
+ { "Grey13", RGB_(0x21, 0x21, 0x21) },
+ { "Grey14", RGB_(0x24, 0x24, 0x24) },
+ { "Grey15", RGB_(0x26, 0x26, 0x26) },
+ { "Grey16", RGB_(0x29, 0x29, 0x29) },
+ { "Grey17", RGB_(0x2b, 0x2b, 0x2b) },
+ { "Grey18", RGB_(0x2e, 0x2e, 0x2e) },
+ { "Grey19", RGB_(0x30, 0x30, 0x30) },
+ { "Grey2", RGB_(0x5, 0x5, 0x5) },
+ { "Grey20", RGB_(0x33, 0x33, 0x33) },
+ { "Grey21", RGB_(0x36, 0x36, 0x36) },
+ { "Grey22", RGB_(0x38, 0x38, 0x38) },
+ { "Grey23", RGB_(0x3b, 0x3b, 0x3b) },
+ { "Grey24", RGB_(0x3d, 0x3d, 0x3d) },
+ { "Grey25", RGB_(0x40, 0x40, 0x40) },
+ { "Grey26", RGB_(0x42, 0x42, 0x42) },
+ { "Grey27", RGB_(0x45, 0x45, 0x45) },
+ { "Grey28", RGB_(0x47, 0x47, 0x47) },
+ { "Grey29", RGB_(0x4a, 0x4a, 0x4a) },
+ { "Grey3", RGB_(0x8, 0x8, 0x8) },
+ { "Grey30", RGB_(0x4d, 0x4d, 0x4d) },
+ { "Grey31", RGB_(0x4f, 0x4f, 0x4f) },
+ { "Grey32", RGB_(0x52, 0x52, 0x52) },
+ { "Grey33", RGB_(0x54, 0x54, 0x54) },
+ { "Grey34", RGB_(0x57, 0x57, 0x57) },
+ { "Grey35", RGB_(0x59, 0x59, 0x59) },
+ { "Grey36", RGB_(0x5c, 0x5c, 0x5c) },
+ { "Grey37", RGB_(0x5e, 0x5e, 0x5e) },
+ { "Grey38", RGB_(0x61, 0x61, 0x61) },
+ { "Grey39", RGB_(0x63, 0x63, 0x63) },
+ { "Grey4", RGB_(0xa, 0xa, 0xa) },
+ { "Grey40", RGB_(0x66, 0x66, 0x66) },
+ { "Grey41", RGB_(0x69, 0x69, 0x69) },
+ { "Grey42", RGB_(0x6b, 0x6b, 0x6b) },
+ { "Grey43", RGB_(0x6e, 0x6e, 0x6e) },
+ { "Grey44", RGB_(0x70, 0x70, 0x70) },
+ { "Grey45", RGB_(0x73, 0x73, 0x73) },
+ { "Grey46", RGB_(0x75, 0x75, 0x75) },
+ { "Grey47", RGB_(0x78, 0x78, 0x78) },
+ { "Grey48", RGB_(0x7a, 0x7a, 0x7a) },
+ { "Grey49", RGB_(0x7d, 0x7d, 0x7d) },
+ { "Grey5", RGB_(0xd, 0xd, 0xd) },
+ { "Grey50", RGB_(0x7f, 0x7f, 0x7f) },
+ { "Grey51", RGB_(0x82, 0x82, 0x82) },
+ { "Grey52", RGB_(0x85, 0x85, 0x85) },
+ { "Grey53", RGB_(0x87, 0x87, 0x87) },
+ { "Grey54", RGB_(0x8a, 0x8a, 0x8a) },
+ { "Grey55", RGB_(0x8c, 0x8c, 0x8c) },
+ { "Grey56", RGB_(0x8f, 0x8f, 0x8f) },
+ { "Grey57", RGB_(0x91, 0x91, 0x91) },
+ { "Grey58", RGB_(0x94, 0x94, 0x94) },
+ { "Grey59", RGB_(0x96, 0x96, 0x96) },
+ { "Grey6", RGB_(0xf, 0xf, 0xf) },
+ { "Grey60", RGB_(0x99, 0x99, 0x99) },
+ { "Grey61", RGB_(0x9c, 0x9c, 0x9c) },
+ { "Grey62", RGB_(0x9e, 0x9e, 0x9e) },
+ { "Grey63", RGB_(0xa1, 0xa1, 0xa1) },
+ { "Grey64", RGB_(0xa3, 0xa3, 0xa3) },
+ { "Grey65", RGB_(0xa6, 0xa6, 0xa6) },
+ { "Grey66", RGB_(0xa8, 0xa8, 0xa8) },
+ { "Grey67", RGB_(0xab, 0xab, 0xab) },
+ { "Grey68", RGB_(0xad, 0xad, 0xad) },
+ { "Grey69", RGB_(0xb0, 0xb0, 0xb0) },
+ { "Grey7", RGB_(0x12, 0x12, 0x12) },
+ { "Grey70", RGB_(0xb3, 0xb3, 0xb3) },
+ { "Grey71", RGB_(0xb5, 0xb5, 0xb5) },
+ { "Grey72", RGB_(0xb8, 0xb8, 0xb8) },
+ { "Grey73", RGB_(0xba, 0xba, 0xba) },
+ { "Grey74", RGB_(0xbd, 0xbd, 0xbd) },
+ { "Grey75", RGB_(0xbf, 0xbf, 0xbf) },
+ { "Grey76", RGB_(0xc2, 0xc2, 0xc2) },
+ { "Grey77", RGB_(0xc4, 0xc4, 0xc4) },
+ { "Grey78", RGB_(0xc7, 0xc7, 0xc7) },
+ { "Grey79", RGB_(0xc9, 0xc9, 0xc9) },
+ { "Grey8", RGB_(0x14, 0x14, 0x14) },
+ { "Grey80", RGB_(0xcc, 0xcc, 0xcc) },
+ { "Grey81", RGB_(0xcf, 0xcf, 0xcf) },
+ { "Grey82", RGB_(0xd1, 0xd1, 0xd1) },
+ { "Grey83", RGB_(0xd4, 0xd4, 0xd4) },
+ { "Grey84", RGB_(0xd6, 0xd6, 0xd6) },
+ { "Grey85", RGB_(0xd9, 0xd9, 0xd9) },
+ { "Grey86", RGB_(0xdb, 0xdb, 0xdb) },
+ { "Grey87", RGB_(0xde, 0xde, 0xde) },
+ { "Grey88", RGB_(0xe0, 0xe0, 0xe0) },
+ { "Grey89", RGB_(0xe3, 0xe3, 0xe3) },
+ { "Grey9", RGB_(0x17, 0x17, 0x17) },
+ { "Grey90", RGB_(0xe5, 0xe5, 0xe5) },
+ { "Grey91", RGB_(0xe8, 0xe8, 0xe8) },
+ { "Grey92", RGB_(0xeb, 0xeb, 0xeb) },
+ { "Grey93", RGB_(0xed, 0xed, 0xed) },
+ { "Grey94", RGB_(0xf0, 0xf0, 0xf0) },
+ { "Grey95", RGB_(0xf2, 0xf2, 0xf2) },
+ { "Grey96", RGB_(0xf5, 0xf5, 0xf5) },
+ { "Grey97", RGB_(0xf7, 0xf7, 0xf7) },
+ { "Grey98", RGB_(0xfa, 0xfa, 0xfa) },
+ { "Grey99", RGB_(0xfc, 0xfc, 0xfc) },
+ { "Honeydew", RGB_(0xf0, 0xff, 0xf0) },
+ { "Honeydew1", RGB_(0xf0, 0xff, 0xf0) },
+ { "Honeydew2", RGB_(0xe0, 0xee, 0xe0) },
+ { "Honeydew3", RGB_(0xc1, 0xcd, 0xc1) },
+ { "Honeydew4", RGB_(0x83, 0x8b, 0x83) },
+ { "HotPink", RGB_(0xff, 0x69, 0xb4) },
+ { "HotPink1", RGB_(0xff, 0x6e, 0xb4) },
+ { "HotPink2", RGB_(0xee, 0x6a, 0xa7) },
+ { "HotPink3", RGB_(0xcd, 0x60, 0x90) },
+ { "HotPink4", RGB_(0x8b, 0x3a, 0x62) },
+ { "IndianRed", RGB_(0xcd, 0x5c, 0x5c) },
+ { "IndianRed1", RGB_(0xff, 0x6a, 0x6a) },
+ { "IndianRed2", RGB_(0xee, 0x63, 0x63) },
+ { "IndianRed3", RGB_(0xcd, 0x55, 0x55) },
+ { "IndianRed4", RGB_(0x8b, 0x3a, 0x3a) },
+ { "Indigo", RGB_(0x4b, 0x00, 0x82) },
+ { "Ivory", RGB_(0xff, 0xff, 0xf0) },
+ { "Ivory1", RGB_(0xff, 0xff, 0xf0) },
+ { "Ivory2", RGB_(0xee, 0xee, 0xe0) },
+ { "Ivory3", RGB_(0xcd, 0xcd, 0xc1) },
+ { "Ivory4", RGB_(0x8b, 0x8b, 0x83) },
+ { "Khaki", RGB_(0xf0, 0xe6, 0x8c) },
+ { "Khaki1", RGB_(0xff, 0xf6, 0x8f) },
+ { "Khaki2", RGB_(0xee, 0xe6, 0x85) },
+ { "Khaki3", RGB_(0xcd, 0xc6, 0x73) },
+ { "Khaki4", RGB_(0x8b, 0x86, 0x4e) },
+ { "Lavender", RGB_(0xe6, 0xe6, 0xfa) },
+ { "LavenderBlush", RGB_(0xff, 0xf0, 0xf5) },
+ { "LavenderBlush1", RGB_(0xff, 0xf0, 0xf5) },
+ { "LavenderBlush2", RGB_(0xee, 0xe0, 0xe5) },
+ { "LavenderBlush3", RGB_(0xcd, 0xc1, 0xc5) },
+ { "LavenderBlush4", RGB_(0x8b, 0x83, 0x86) },
+ { "LawnGreen", RGB_(0x7c, 0xfc, 0x00) },
+ { "LemonChiffon", RGB_(0xff, 0xfa, 0xcd) },
+ { "LemonChiffon1", RGB_(0xff, 0xfa, 0xcd) },
+ { "LemonChiffon2", RGB_(0xee, 0xe9, 0xbf) },
+ { "LemonChiffon3", RGB_(0xcd, 0xc9, 0xa5) },
+ { "LemonChiffon4", RGB_(0x8b, 0x89, 0x70) },
+ { "LightBlue", RGB_(0xad, 0xd8, 0xe6) },
+ { "LightBlue1", RGB_(0xbf, 0xef, 0xff) },
+ { "LightBlue2", RGB_(0xb2, 0xdf, 0xee) },
+ { "LightBlue3", RGB_(0x9a, 0xc0, 0xcd) },
+ { "LightBlue4", RGB_(0x68, 0x83, 0x8b) },
+ { "LightCoral", RGB_(0xf0, 0x80, 0x80) },
+ { "LightCyan", RGB_(0xe0, 0xff, 0xff) },
+ { "LightCyan1", RGB_(0xe0, 0xff, 0xff) },
+ { "LightCyan2", RGB_(0xd1, 0xee, 0xee) },
+ { "LightCyan3", RGB_(0xb4, 0xcd, 0xcd) },
+ { "LightCyan4", RGB_(0x7a, 0x8b, 0x8b) },
+ { "LightGoldenrod", RGB_(0xee, 0xdd, 0x82) },
+ { "LightGoldenrod1", RGB_(0xff, 0xec, 0x8b) },
+ { "LightGoldenrod2", RGB_(0xee, 0xdc, 0x82) },
+ { "LightGoldenrod3", RGB_(0xcd, 0xbe, 0x70) },
+ { "LightGoldenrod4", RGB_(0x8b, 0x81, 0x4c) },
+ { "LightGoldenRodYellow", RGB_(0xfa, 0xfa, 0xd2) },
+ { "LightGray", RGB_(0xd3, 0xd3, 0xd3) },
+ { "LightGreen", RGB_(0x90, 0xee, 0x90) },
+ { "LightGrey", RGB_(0xd3, 0xd3, 0xd3) },
+ { "LightMagenta", RGB_(0xff, 0xbb, 0xff) },
+ { "LightPink", RGB_(0xff, 0xb6, 0xc1) },
+ { "LightPink1", RGB_(0xff, 0xae, 0xb9) },
+ { "LightPink2", RGB_(0xee, 0xa2, 0xad) },
+ { "LightPink3", RGB_(0xcd, 0x8c, 0x95) },
+ { "LightPink4", RGB_(0x8b, 0x5f, 0x65) },
+ { "LightRed", RGB_(0xff, 0xbb, 0xbb) },
+ { "LightSalmon", RGB_(0xff, 0xa0, 0x7a) },
+ { "LightSalmon1", RGB_(0xff, 0xa0, 0x7a) },
+ { "LightSalmon2", RGB_(0xee, 0x95, 0x72) },
+ { "LightSalmon3", RGB_(0xcd, 0x81, 0x62) },
+ { "LightSalmon4", RGB_(0x8b, 0x57, 0x42) },
+ { "LightSeaGreen", RGB_(0x20, 0xb2, 0xaa) },
+ { "LightSkyBlue", RGB_(0x87, 0xce, 0xfa) },
+ { "LightSkyBlue1", RGB_(0xb0, 0xe2, 0xff) },
+ { "LightSkyBlue2", RGB_(0xa4, 0xd3, 0xee) },
+ { "LightSkyBlue3", RGB_(0x8d, 0xb6, 0xcd) },
+ { "LightSkyBlue4", RGB_(0x60, 0x7b, 0x8b) },
+ { "LightSlateBlue", RGB_(0x84, 0x70, 0xff) },
+ { "LightSlateGray", RGB_(0x77, 0x88, 0x99) },
+ { "LightSlateGrey", RGB_(0x77, 0x88, 0x99) },
+ { "LightSteelBlue", RGB_(0xb0, 0xc4, 0xde) },
+ { "LightSteelBlue1", RGB_(0xca, 0xe1, 0xff) },
+ { "LightSteelBlue2", RGB_(0xbc, 0xd2, 0xee) },
+ { "LightSteelBlue3", RGB_(0xa2, 0xb5, 0xcd) },
+ { "LightSteelBlue4", RGB_(0x6e, 0x7b, 0x8b) },
+ { "LightYellow", RGB_(0xff, 0xff, 0xe0) },
+ { "LightYellow1", RGB_(0xff, 0xff, 0xe0) },
+ { "LightYellow2", RGB_(0xee, 0xee, 0xd1) },
+ { "LightYellow3", RGB_(0xcd, 0xcd, 0xb4) },
+ { "LightYellow4", RGB_(0x8b, 0x8b, 0x7a) },
+ { "Lime", RGB_(0x00, 0xff, 0x00) },
+ { "LimeGreen", RGB_(0x32, 0xcd, 0x32) },
+ { "Linen", RGB_(0xfa, 0xf0, 0xe6) },
+ { "Magenta", RGB_(0xff, 0x00, 0xff) },
+ { "Magenta1", RGB_(0xff, 0x0, 0xff) },
+ { "Magenta2", RGB_(0xee, 0x0, 0xee) },
+ { "Magenta3", RGB_(0xcd, 0x0, 0xcd) },
+ { "Magenta4", RGB_(0x8b, 0x0, 0x8b) },
+ { "Maroon", RGB_(0x80, 0x00, 0x00) },
+ { "Maroon1", RGB_(0xff, 0x34, 0xb3) },
+ { "Maroon2", RGB_(0xee, 0x30, 0xa7) },
+ { "Maroon3", RGB_(0xcd, 0x29, 0x90) },
+ { "Maroon4", RGB_(0x8b, 0x1c, 0x62) },
+ { "MediumAquamarine", RGB_(0x66, 0xcd, 0xaa) },
+ { "MediumBlue", RGB_(0x00, 0x00, 0xcd) },
+ { "MediumOrchid", RGB_(0xba, 0x55, 0xd3) },
+ { "MediumOrchid1", RGB_(0xe0, 0x66, 0xff) },
+ { "MediumOrchid2", RGB_(0xd1, 0x5f, 0xee) },
+ { "MediumOrchid3", RGB_(0xb4, 0x52, 0xcd) },
+ { "MediumOrchid4", RGB_(0x7a, 0x37, 0x8b) },
+ { "MediumPurple", RGB_(0x93, 0x70, 0xdb) },
+ { "MediumPurple1", RGB_(0xab, 0x82, 0xff) },
+ { "MediumPurple2", RGB_(0x9f, 0x79, 0xee) },
+ { "MediumPurple3", RGB_(0x89, 0x68, 0xcd) },
+ { "MediumPurple4", RGB_(0x5d, 0x47, 0x8b) },
+ { "MediumSeaGreen", RGB_(0x3c, 0xb3, 0x71) },
+ { "MediumSlateBlue", RGB_(0x7b, 0x68, 0xee) },
+ { "MediumSpringGreen", RGB_(0x00, 0xfa, 0x9a) },
+ { "MediumTurquoise", RGB_(0x48, 0xd1, 0xcc) },
+ { "MediumVioletRed", RGB_(0xc7, 0x15, 0x85) },
+ { "MidnightBlue", RGB_(0x19, 0x19, 0x70) },
+ { "MintCream", RGB_(0xf5, 0xff, 0xfa) },
+ { "MistyRose", RGB_(0xff, 0xe4, 0xe1) },
+ { "MistyRose1", RGB_(0xff, 0xe4, 0xe1) },
+ { "MistyRose2", RGB_(0xee, 0xd5, 0xd2) },
+ { "MistyRose3", RGB_(0xcd, 0xb7, 0xb5) },
+ { "MistyRose4", RGB_(0x8b, 0x7d, 0x7b) },
+ { "Moccasin", RGB_(0xff, 0xe4, 0xb5) },
+ { "NavajoWhite", RGB_(0xff, 0xde, 0xad) },
+ { "NavajoWhite1", RGB_(0xff, 0xde, 0xad) },
+ { "NavajoWhite2", RGB_(0xee, 0xcf, 0xa1) },
+ { "NavajoWhite3", RGB_(0xcd, 0xb3, 0x8b) },
+ { "NavajoWhite4", RGB_(0x8b, 0x79, 0x5e) },
+ { "Navy", RGB_(0x00, 0x00, 0x80) },
+ { "NavyBlue", RGB_(0x0, 0x0, 0x80) },
+ { "OldLace", RGB_(0xfd, 0xf5, 0xe6) },
+ { "Olive", RGB_(0x80, 0x80, 0x00) },
+ { "OliveDrab", RGB_(0x6b, 0x8e, 0x23) },
+ { "OliveDrab1", RGB_(0xc0, 0xff, 0x3e) },
+ { "OliveDrab2", RGB_(0xb3, 0xee, 0x3a) },
+ { "OliveDrab3", RGB_(0x9a, 0xcd, 0x32) },
+ { "OliveDrab4", RGB_(0x69, 0x8b, 0x22) },
+ { "Orange", RGB_(0xff, 0xa5, 0x00) },
+ { "Orange1", RGB_(0xff, 0xa5, 0x0) },
+ { "Orange2", RGB_(0xee, 0x9a, 0x0) },
+ { "Orange3", RGB_(0xcd, 0x85, 0x0) },
+ { "Orange4", RGB_(0x8b, 0x5a, 0x0) },
+ { "OrangeRed", RGB_(0xff, 0x45, 0x00) },
+ { "OrangeRed1", RGB_(0xff, 0x45, 0x0) },
+ { "OrangeRed2", RGB_(0xee, 0x40, 0x0) },
+ { "OrangeRed3", RGB_(0xcd, 0x37, 0x0) },
+ { "OrangeRed4", RGB_(0x8b, 0x25, 0x0) },
+ { "Orchid", RGB_(0xda, 0x70, 0xd6) },
+ { "Orchid1", RGB_(0xff, 0x83, 0xfa) },
+ { "Orchid2", RGB_(0xee, 0x7a, 0xe9) },
+ { "Orchid3", RGB_(0xcd, 0x69, 0xc9) },
+ { "Orchid4", RGB_(0x8b, 0x47, 0x89) },
+ { "PaleGoldenRod", RGB_(0xee, 0xe8, 0xaa) },
+ { "PaleGreen", RGB_(0x98, 0xfb, 0x98) },
+ { "PaleGreen1", RGB_(0x9a, 0xff, 0x9a) },
+ { "PaleGreen2", RGB_(0x90, 0xee, 0x90) },
+ { "PaleGreen3", RGB_(0x7c, 0xcd, 0x7c) },
+ { "PaleGreen4", RGB_(0x54, 0x8b, 0x54) },
+ { "PaleTurquoise", RGB_(0xaf, 0xee, 0xee) },
+ { "PaleTurquoise1", RGB_(0xbb, 0xff, 0xff) },
+ { "PaleTurquoise2", RGB_(0xae, 0xee, 0xee) },
+ { "PaleTurquoise3", RGB_(0x96, 0xcd, 0xcd) },
+ { "PaleTurquoise4", RGB_(0x66, 0x8b, 0x8b) },
+ { "PaleVioletRed", RGB_(0xdb, 0x70, 0x93) },
+ { "PaleVioletRed1", RGB_(0xff, 0x82, 0xab) },
+ { "PaleVioletRed2", RGB_(0xee, 0x79, 0x9f) },
+ { "PaleVioletRed3", RGB_(0xcd, 0x68, 0x89) },
+ { "PaleVioletRed4", RGB_(0x8b, 0x47, 0x5d) },
+ { "PapayaWhip", RGB_(0xff, 0xef, 0xd5) },
+ { "PeachPuff", RGB_(0xff, 0xda, 0xb9) },
+ { "PeachPuff1", RGB_(0xff, 0xda, 0xb9) },
+ { "PeachPuff2", RGB_(0xee, 0xcb, 0xad) },
+ { "PeachPuff3", RGB_(0xcd, 0xaf, 0x95) },
+ { "PeachPuff4", RGB_(0x8b, 0x77, 0x65) },
+ { "Peru", RGB_(0xcd, 0x85, 0x3f) },
+ { "Pink", RGB_(0xff, 0xc0, 0xcb) },
+ { "Pink1", RGB_(0xff, 0xb5, 0xc5) },
+ { "Pink2", RGB_(0xee, 0xa9, 0xb8) },
+ { "Pink3", RGB_(0xcd, 0x91, 0x9e) },
+ { "Pink4", RGB_(0x8b, 0x63, 0x6c) },
+ { "Plum", RGB_(0xdd, 0xa0, 0xdd) },
+ { "Plum1", RGB_(0xff, 0xbb, 0xff) },
+ { "Plum2", RGB_(0xee, 0xae, 0xee) },
+ { "Plum3", RGB_(0xcd, 0x96, 0xcd) },
+ { "Plum4", RGB_(0x8b, 0x66, 0x8b) },
+ { "PowderBlue", RGB_(0xb0, 0xe0, 0xe6) },
+ { "Purple", RGB_(0x80, 0x00, 0x80) },
+ { "Purple1", RGB_(0x9b, 0x30, 0xff) },
+ { "Purple2", RGB_(0x91, 0x2c, 0xee) },
+ { "Purple3", RGB_(0x7d, 0x26, 0xcd) },
+ { "Purple4", RGB_(0x55, 0x1a, 0x8b) },
+ { "RebeccaPurple", RGB_(0x66, 0x33, 0x99) },
+ { "Red", RGB_(0xff, 0x00, 0x00) },
+ { "Red1", RGB_(0xff, 0x0, 0x0) },
+ { "Red2", RGB_(0xee, 0x0, 0x0) },
+ { "Red3", RGB_(0xcd, 0x0, 0x0) },
+ { "Red4", RGB_(0x8b, 0x0, 0x0) },
+ { "RosyBrown", RGB_(0xbc, 0x8f, 0x8f) },
+ { "RosyBrown1", RGB_(0xff, 0xc1, 0xc1) },
+ { "RosyBrown2", RGB_(0xee, 0xb4, 0xb4) },
+ { "RosyBrown3", RGB_(0xcd, 0x9b, 0x9b) },
+ { "RosyBrown4", RGB_(0x8b, 0x69, 0x69) },
+ { "RoyalBlue", RGB_(0x41, 0x69, 0xe1) },
+ { "RoyalBlue1", RGB_(0x48, 0x76, 0xff) },
+ { "RoyalBlue2", RGB_(0x43, 0x6e, 0xee) },
+ { "RoyalBlue3", RGB_(0x3a, 0x5f, 0xcd) },
+ { "RoyalBlue4", RGB_(0x27, 0x40, 0x8b) },
+ { "SaddleBrown", RGB_(0x8b, 0x45, 0x13) },
+ { "Salmon", RGB_(0xfa, 0x80, 0x72) },
+ { "Salmon1", RGB_(0xff, 0x8c, 0x69) },
+ { "Salmon2", RGB_(0xee, 0x82, 0x62) },
+ { "Salmon3", RGB_(0xcd, 0x70, 0x54) },
+ { "Salmon4", RGB_(0x8b, 0x4c, 0x39) },
+ { "SandyBrown", RGB_(0xf4, 0xa4, 0x60) },
+ { "SeaGreen", RGB_(0x2e, 0x8b, 0x57) },
+ { "SeaGreen1", RGB_(0x54, 0xff, 0x9f) },
+ { "SeaGreen2", RGB_(0x4e, 0xee, 0x94) },
+ { "SeaGreen3", RGB_(0x43, 0xcd, 0x80) },
+ { "SeaGreen4", RGB_(0x2e, 0x8b, 0x57) },
+ { "SeaShell", RGB_(0xff, 0xf5, 0xee) },
+ { "Seashell1", RGB_(0xff, 0xf5, 0xee) },
+ { "Seashell2", RGB_(0xee, 0xe5, 0xde) },
+ { "Seashell3", RGB_(0xcd, 0xc5, 0xbf) },
+ { "Seashell4", RGB_(0x8b, 0x86, 0x82) },
+ { "Sienna", RGB_(0xa0, 0x52, 0x2d) },
+ { "Sienna1", RGB_(0xff, 0x82, 0x47) },
+ { "Sienna2", RGB_(0xee, 0x79, 0x42) },
+ { "Sienna3", RGB_(0xcd, 0x68, 0x39) },
+ { "Sienna4", RGB_(0x8b, 0x47, 0x26) },
+ { "Silver", RGB_(0xc0, 0xc0, 0xc0) },
+ { "SkyBlue", RGB_(0x87, 0xce, 0xeb) },
+ { "SkyBlue1", RGB_(0x87, 0xce, 0xff) },
+ { "SkyBlue2", RGB_(0x7e, 0xc0, 0xee) },
+ { "SkyBlue3", RGB_(0x6c, 0xa6, 0xcd) },
+ { "SkyBlue4", RGB_(0x4a, 0x70, 0x8b) },
+ { "SlateBlue", RGB_(0x6a, 0x5a, 0xcd) },
+ { "SlateBlue1", RGB_(0x83, 0x6f, 0xff) },
+ { "SlateBlue2", RGB_(0x7a, 0x67, 0xee) },
+ { "SlateBlue3", RGB_(0x69, 0x59, 0xcd) },
+ { "SlateBlue4", RGB_(0x47, 0x3c, 0x8b) },
+ { "SlateGray", RGB_(0x70, 0x80, 0x90) },
+ { "SlateGray1", RGB_(0xc6, 0xe2, 0xff) },
+ { "SlateGray2", RGB_(0xb9, 0xd3, 0xee) },
+ { "SlateGray3", RGB_(0x9f, 0xb6, 0xcd) },
+ { "SlateGray4", RGB_(0x6c, 0x7b, 0x8b) },
+ { "SlateGrey", RGB_(0x70, 0x80, 0x90) },
+ { "Snow", RGB_(0xff, 0xfa, 0xfa) },
+ { "Snow1", RGB_(0xff, 0xfa, 0xfa) },
+ { "Snow2", RGB_(0xee, 0xe9, 0xe9) },
+ { "Snow3", RGB_(0xcd, 0xc9, 0xc9) },
+ { "Snow4", RGB_(0x8b, 0x89, 0x89) },
+ { "SpringGreen", RGB_(0x00, 0xff, 0x7f) },
+ { "SpringGreen1", RGB_(0x0, 0xff, 0x7f) },
+ { "SpringGreen2", RGB_(0x0, 0xee, 0x76) },
+ { "SpringGreen3", RGB_(0x0, 0xcd, 0x66) },
+ { "SpringGreen4", RGB_(0x0, 0x8b, 0x45) },
+ { "SteelBlue", RGB_(0x46, 0x82, 0xb4) },
+ { "SteelBlue1", RGB_(0x63, 0xb8, 0xff) },
+ { "SteelBlue2", RGB_(0x5c, 0xac, 0xee) },
+ { "SteelBlue3", RGB_(0x4f, 0x94, 0xcd) },
+ { "SteelBlue4", RGB_(0x36, 0x64, 0x8b) },
+ { "Tan", RGB_(0xd2, 0xb4, 0x8c) },
+ { "Tan1", RGB_(0xff, 0xa5, 0x4f) },
+ { "Tan2", RGB_(0xee, 0x9a, 0x49) },
+ { "Tan3", RGB_(0xcd, 0x85, 0x3f) },
+ { "Tan4", RGB_(0x8b, 0x5a, 0x2b) },
+ { "Teal", RGB_(0x00, 0x80, 0x80) },
+ { "Thistle", RGB_(0xd8, 0xbf, 0xd8) },
+ { "Thistle1", RGB_(0xff, 0xe1, 0xff) },
+ { "Thistle2", RGB_(0xee, 0xd2, 0xee) },
+ { "Thistle3", RGB_(0xcd, 0xb5, 0xcd) },
+ { "Thistle4", RGB_(0x8b, 0x7b, 0x8b) },
+ { "Tomato", RGB_(0xff, 0x63, 0x47) },
+ { "Tomato1", RGB_(0xff, 0x63, 0x47) },
+ { "Tomato2", RGB_(0xee, 0x5c, 0x42) },
+ { "Tomato3", RGB_(0xcd, 0x4f, 0x39) },
+ { "Tomato4", RGB_(0x8b, 0x36, 0x26) },
+ { "Turquoise", RGB_(0x40, 0xe0, 0xd0) },
+ { "Turquoise1", RGB_(0x0, 0xf5, 0xff) },
+ { "Turquoise2", RGB_(0x0, 0xe5, 0xee) },
+ { "Turquoise3", RGB_(0x0, 0xc5, 0xcd) },
+ { "Turquoise4", RGB_(0x0, 0x86, 0x8b) },
+ { "Violet", RGB_(0xee, 0x82, 0xee) },
+ { "VioletRed", RGB_(0xd0, 0x20, 0x90) },
+ { "VioletRed1", RGB_(0xff, 0x3e, 0x96) },
+ { "VioletRed2", RGB_(0xee, 0x3a, 0x8c) },
+ { "VioletRed3", RGB_(0xcd, 0x32, 0x78) },
+ { "VioletRed4", RGB_(0x8b, 0x22, 0x52) },
+ { "WebGray", RGB_(0x80, 0x80, 0x80) },
+ { "WebGreen", RGB_(0x0, 0x80, 0x0) },
+ { "WebGrey", RGB_(0x80, 0x80, 0x80) },
+ { "WebMaroon", RGB_(0x80, 0x0, 0x0) },
+ { "WebPurple", RGB_(0x80, 0x0, 0x80) },
+ { "Wheat", RGB_(0xf5, 0xde, 0xb3) },
+ { "Wheat1", RGB_(0xff, 0xe7, 0xba) },
+ { "Wheat2", RGB_(0xee, 0xd8, 0xae) },
+ { "Wheat3", RGB_(0xcd, 0xba, 0x96) },
+ { "Wheat4", RGB_(0x8b, 0x7e, 0x66) },
+ { "White", RGB_(0xff, 0xff, 0xff) },
+ { "WhiteSmoke", RGB_(0xf5, 0xf5, 0xf5) },
+ { "X11Gray", RGB_(0xbe, 0xbe, 0xbe) },
+ { "X11Green", RGB_(0x0, 0xff, 0x0) },
+ { "X11Grey", RGB_(0xbe, 0xbe, 0xbe) },
+ { "X11Maroon", RGB_(0xb0, 0x30, 0x60) },
+ { "X11Purple", RGB_(0xa0, 0x20, 0xf0) },
+ { "Yellow", RGB_(0xff, 0xff, 0x00) },
+ { "Yellow1", RGB_(0xff, 0xff, 0x0) },
+ { "Yellow2", RGB_(0xee, 0xee, 0x0) },
+ { "Yellow3", RGB_(0xcd, 0xcd, 0x0) },
+ { "Yellow4", RGB_(0x8b, 0x8b, 0x0) },
+ { "YellowGreen", RGB_(0x9a, 0xcd, 0x32) },
{ NULL, 0 },
};
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index f3eb6883ce..f68bb2458d 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -180,13 +180,14 @@ void terminal_init(void)
vterm_state_get_palette_color(state, color_index, &color);
}
map_put(int, int)(color_indexes,
- RGB(color.red, color.green, color.blue), color_index + 1);
+ RGB_(color.red, color.green, color.blue),
+ color_index + 1);
}
VTermColor fg, bg;
vterm_state_get_default_colors(state, &fg, &bg);
- default_vt_fg = RGB(fg.red, fg.green, fg.blue);
- default_vt_bg = RGB(bg.red, bg.green, bg.blue);
+ default_vt_fg = RGB_(fg.red, fg.green, fg.blue);
+ default_vt_bg = RGB_(bg.red, bg.green, bg.blue);
default_vt_bg_rgb = bg;
vterm_free(vt);
}
@@ -358,6 +359,15 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
return;
}
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer && wp->w_buffer->terminal == term) {
+ const uint16_t win_width =
+ (uint16_t)(MAX(0, wp->w_width - win_col_off(wp)));
+ width = MAX(width, win_width);
+ height = (uint16_t)MAX(height, wp->w_height);
+ }
+ }
+
vterm_set_size(term->vt, height, width);
vterm_screen_flush_damage(term->vts);
term->pending_resize = true;
@@ -386,10 +396,8 @@ void terminal_enter(void)
win_T *save_curwin = curwin;
int save_w_p_cul = curwin->w_p_cul;
int save_w_p_cuc = curwin->w_p_cuc;
- int save_w_p_rnu = curwin->w_p_rnu;
curwin->w_p_cul = false;
curwin->w_p_cuc = false;
- curwin->w_p_rnu = false;
adjust_topline(s->term, buf, 0); // scroll to end
// erase the unfocused cursor
@@ -407,7 +415,6 @@ void terminal_enter(void)
if (save_curwin == curwin) { // save_curwin may be invalid (window closed)!
curwin->w_p_cul = save_w_p_cul;
curwin->w_p_cuc = save_w_p_cuc;
- curwin->w_p_rnu = save_w_p_rnu;
}
// draw the unfocused cursor
@@ -460,6 +467,10 @@ static int terminal_execute(VimState *state, int key)
}
break;
+ case K_COMMAND:
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
+
case Ctrl_N:
if (s->got_bsl) {
return 0;
@@ -565,8 +576,8 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
VTermScreenCell cell;
fetch_cell(term, row, col, &cell);
// Get the rgb value set by libvterm.
- int vt_fg = RGB(cell.fg.red, cell.fg.green, cell.fg.blue);
- int vt_bg = RGB(cell.bg.red, cell.bg.green, cell.bg.blue);
+ int vt_fg = RGB_(cell.fg.red, cell.fg.green, cell.fg.blue);
+ int vt_bg = RGB_(cell.bg.red, cell.bg.green, cell.bg.blue);
vt_fg = vt_fg != default_vt_fg ? vt_fg : - 1;
vt_bg = vt_bg != default_vt_bg ? vt_bg : - 1;
// Since libvterm does not expose the color index used by the program, we
@@ -1083,7 +1094,6 @@ static void refresh_terminal(Terminal *term)
refresh_size(term, buf);
refresh_scrollback(term, buf);
refresh_screen(term, buf);
- redraw_buf_later(buf, NOT_VALID);
});
long ml_added = buf->b_ml.ml_line_count - ml_before;
adjust_topline(term, buf, ml_added);
@@ -1093,6 +1103,7 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
{
refresh_pending = false;
if (exiting // Cannot redraw (requires event loop) during teardown/exit.
+ || (State & CMDPREVIEW)
// WM_LIST (^D) is not redrawn, unlike the normal wildmenu. So we must
// skip redraws to keep it visible.
|| wild_menu_showing == WM_LIST) {
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 418463a0ad..4bfcbf8e79 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -7,7 +7,7 @@ ifeq ($(OS),Windows_NT)
else
NVIM_PRG ?= ../../../build/bin/nvim
endif
-SCRIPTSOURCE := ../../../runtime
+ROOT := ../../..
export SHELL := sh
export NVIM_PRG := $(NVIM_PRG)
@@ -20,13 +20,13 @@ SCRIPTS_DEFAULT = \
test40.out \
test42.out \
test48.out \
- test49.out \
test52.out \
test64.out \
ifneq ($(OS),Windows_NT)
SCRIPTS_DEFAULTS := $(SCRIPTS_DEFAULT) \
test17.out \
+ test49.out \
endif
@@ -134,7 +134,7 @@ ifdef USE_VALGRIND
$(VALGRIND_TOOL) \
--suppressions=../../.valgrind.supp \
--error-exitcode=123 \
- --log-file=valgrind.\%p.$* \
+ --log-file=valgrind-\%p.$* \
$(VGDB) \
--trace-children=yes
else
@@ -152,7 +152,8 @@ nongui: nolog $(SCRIPTS) newtests report
gui: nolog $(SCRIPTS) $(SCRIPTS_GUI) newtests report
.gdbinit:
- echo 'set $$_exitcode = -1\nrun\nif $$_exitcode != -1\n quit\nend' > .gdbinit
+ @echo "[OLDTEST-PREP] Setting up .gdbinit"
+ @echo 'set $$_exitcode = -1\nrun\nif $$_exitcode != -1\n quit\nend' > .gdbinit
report:
@echo
@@ -171,7 +172,7 @@ $(SCRIPTS) $(SCRIPTS_GUI): $(NVIM_PRG) test1.out
RM_ON_RUN := test.out X* viminfo
RM_ON_START := test.ok
-RUN_VIM := VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in
+RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in
clean:
-rm -rf *.out \
@@ -179,6 +180,7 @@ clean:
*.res \
*.rej \
*.orig \
+ *.tlog \
test.log \
messages \
$(RM_ON_RUN) \
@@ -191,59 +193,32 @@ clean:
del
test1.out: .gdbinit test1.in
- -rm -rf $*.failed $(RM_ON_RUN) $(RM_ON_START) wrongtermsize
- mkdir -p $(TMPDIR)
- $(RUN_VIM) $*.in
- @/bin/sh -c "if test -e wrongtermsize; then \
- echo; \
- echo test1 FAILED - terminal size must be 80x24 or larger; \
- echo; exit 1; \
- elif diff test.out $*.ok; then \
- mv -f test.out $*.out; \
- else \
- echo; \
- echo test1 FAILED - Something basic is wrong; \
- echo; \
- exit 1; \
- fi"
- -rm -rf X* viminfo
+ @echo "[OLDTEST-PREP] Running test1"
+ @rm -rf $*.failed $(RM_ON_RUN) $(RM_ON_START) wrongtermsize
+ @mkdir -p $(TMPDIR)
+ @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIM) $*.in
+ @rm -f wrongtermsize
+ @rm -rf X* viminfo
%.out: %.in .gdbinit
- -rm -rf $*.failed test.ok $(RM_ON_RUN)
- mkdir -p $(TMPDIR)
- cp $*.ok test.ok
- # Sleep a moment to avoid that the xterm title is messed up.
- # 200 msec is sufficient, but only modern sleep supports a fraction of
- # a second, fall back to a second if it fails.
- @-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1"
- $(RUN_VIM) $*.in
-
- # Check if the test.out file matches test.ok.
- @/bin/sh -c "if test -f test.out; then \
- if diff -u test.out $*.ok; then \
- mv -f test.out $*.out; \
- else \
- echo $* FAILED >> test.log; \
- mv -f test.out $*.failed; \
- fi; \
- else \
- echo $* NO OUTPUT >>test.log; \
- fi"
- @/bin/sh -c "if test -f valgrind; then \
- mv -f valgrind valgrind.$*; \
- fi"
- -rm -rf X* test.ok viminfo
+ @echo "[OLDESTTEST] Running" $*
+ @rm -rf $*.failed test.ok $(RM_ON_RUN)
+ @mkdir -p $(TMPDIR)
+ @cp $*.ok test.ok
+ @/bin/sh runnvim.sh --oldesttest $(ROOT) $(NVIM_PRG) $* $(RUN_VIM) $*.in
+ @rm -rf X* test.ok viminfo
test49.out: test49.vim
nolog:
- -rm -f test.log messages
+ @echo "[OLDTEST-PREP] Removing test.log and messages"
+ @rm -f test.log messages
# New style of tests uses Vim script with assert calls. These are easier
# to write and a lot easier to read and debug.
# Limitation: Only works with the +eval feature.
-RUN_VIMTEST = VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE --headless --noplugin
+RUN_VIMTEST = $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE --headless --noplugin
newtests: newtestssilent
@/bin/sh -c "if test -f messages && grep -q 'FAILED' messages; then \
@@ -253,5 +228,6 @@ newtests: newtestssilent
newtestssilent: $(NEW_TESTS)
%.res: %.vim .gdbinit
- mkdir -p $(TMPDIR)
- $(RUN_VIMTEST) -u NONE -S runtest.vim $*.vim
+ @echo "[OLDTEST] Running" $*
+ @mkdir -p $(TMPDIR)
+ @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIMTEST) -u NONE -S runtest.vim $*.vim
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
new file mode 100755
index 0000000000..43556f3ad3
--- /dev/null
+++ b/src/nvim/testdir/runnvim.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+main() {(
+ local separator="================================================================================"
+ local oldesttest=
+ if test "$1" = "--oldesttest" ; then
+ shift
+ oldesttest=1
+ fi
+ local root="$1" ; shift
+ local nvim_prg="$1" ; shift
+ local test_name="$1" ; shift
+
+ local tlog="$test_name.tlog"
+
+ export NVIM_TEST_ARGC=$#
+ local arg
+ local i=0
+ for arg ; do
+ eval "export NVIM_TEST_ARG$i=\"\$arg\""
+ i=$(( i+1 ))
+ done
+
+ export CI_DIR="$root/ci"
+ export BUILD_DIR="$(dirname "$nvim_prg")/.."
+ export FAILED=0
+
+ . "$CI_DIR/common/suite.sh"
+ . "$CI_DIR/common/test.sh"
+
+ export VIMRUNTIME="$root/runtime"
+ if ! "$nvim_prg" \
+ -u NONE -i NONE \
+ --headless \
+ --cmd 'set shortmess+=I noswapfile noundofile nomore' \
+ -S runnvim.vim \
+ "$tlog" > "out-$tlog" 2> "err-$tlog"
+ then
+ fail "$test_name" F "Nvim exited with non-zero code"
+ fi
+ echo "Stdout of :terminal runner" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ cat "out-$tlog" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ echo "Stderr of :terminal runner" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ cat "err-$tlog" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ if test "$oldesttest" = 1 ; then
+ if ! diff -q test.out "$test_name.ok" > /dev/null 2>&1 ; then
+ if test -f test.out ; then
+ fail "$test_name" F "Oldest test .out file differs from .ok file"
+ echo "Diff between test.out and $test_name.ok" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ diff -a test.out "$test_name.ok" >> "$tlog"
+ echo "$separator" >> "$tlog"
+ else
+ echo "No output in test.out" >> "$tlog"
+ fi
+ fi
+ fi
+ if test "$FAILED" = 1 ; then
+ travis_fold start "$NVIM_TEST_CURRENT_SUITE/$test_name"
+ fi
+ valgrind_check .
+ if test -n "$LOG_DIR" ; then
+ asan_check "$LOG_DIR"
+ fi
+ check_core_dumps
+ if test "$FAILED" = 1 ; then
+ cat "$tlog"
+ fi
+ rm -f "$tlog"
+ if test "$FAILED" = 1 ; then
+ travis_fold end "$NVIM_TEST_CURRENT_SUITE/$test_name"
+ fi
+ if test "$FAILED" = 1 ; then
+ echo "Test $test_name failed, see output above and summary for more details" >> test.log
+ fi
+)}
+
+main "$@"
diff --git a/src/nvim/testdir/runnvim.vim b/src/nvim/testdir/runnvim.vim
new file mode 100644
index 0000000000..396a3a6477
--- /dev/null
+++ b/src/nvim/testdir/runnvim.vim
@@ -0,0 +1,55 @@
+let s:logger = {'d_events': []}
+function s:logger.on_stdout(id, data, event)
+ call add(self.d_events, [a:event, a:data])
+endfunction
+let s:logger.on_stderr = s:logger.on_stdout
+function s:logger.on_exit(id, data, event)
+ call add(self.d_events, [a:event, ['']])
+endfunction
+
+function Main()
+ let argc = +$NVIM_TEST_ARGC
+ let args = []
+ for i in range(argc)
+ call add(args, eval("$NVIM_TEST_ARG" . i))
+ endfor
+ set lines=25
+ set columns=80
+ enew
+ let job = termopen(args, s:logger)
+ let results = jobwait([job], 5 * 60 * 1000)
+ " TODO(ZyX-I): Get colors
+ let screen = getline(1, '$')
+ bwipeout!
+ let stringified_events = map(s:logger.d_events,
+ \'v:val[0] . ": " . ' .
+ \'join(map(v:val[1], '.
+ \ '''substitute(v:val, '.
+ \ '"\\v\\C(\\p@!.|\\<)", '.
+ \ '"\\=printf(\"<%x>\", '.
+ \ 'char2nr(submatch(0)))", '.
+ \ '"")''), '.
+ \ '''\n'')')
+ call setline(1, [
+ \ 'Job exited with code ' . results[0],
+ \ printf('Screen (%u lines)', len(screen)),
+ \ repeat('=', 80),
+ \] + screen + [
+ \ repeat('=', 80),
+ \ printf('Events (%u lines):', len(stringified_events)),
+ \ repeat('=', 80),
+ \] + stringified_events + [
+ \ repeat('=', 80),
+ \])
+ write
+ if results[0] != 0
+ if results[0] != -1
+ call jobstop(job)
+ endif
+ cquit
+ else
+ qall
+ endif
+endfunction
+
+call Main()
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 6a7b44a76f..5c98455909 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -61,7 +61,7 @@ set nomore
lang mess C
" Always use forward slashes.
-set shellslash
+" set shellslash
" Prepare for calling test_garbagecollect_now().
let v:testing = 1
@@ -237,6 +237,7 @@ let s:flaky = [
\ 'Test_oneshot()',
\ 'Test_out_cb()',
\ 'Test_paused()',
+ \ 'Test_quoteplus()',
\ 'Test_reltime()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index 7d6dd0c7ce..aac9fefef4 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -17,3 +17,11 @@ let &packpath = &rtp
" Make sure $HOME does not get read or written.
let $HOME = '/does/not/exist'
+
+" Use default shell on Windows to avoid segfault, caused by TUI
+if has('win32')
+ let $SHELL = ''
+ let $TERM = ''
+ let &shell = empty($COMSPEC) ? exepath('cmd.exe') : $COMSPEC
+ set shellcmdflag=/s/c shellxquote=\" shellredir=>%s\ 2>&1
+endif
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 673246e1fb..be68e9ff9d 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -154,7 +154,7 @@ func Test_getcompletion()
call assert_equal([], l)
let l = getcompletion('', 'dir')
- call assert_true(index(l, 'sautest/') >= 0)
+ call assert_true(index(l, expand('sautest/')) >= 0)
let l = getcompletion('NoMatch', 'dir')
call assert_equal([], l)
@@ -246,7 +246,7 @@ func Test_getcompletion()
" Command line completion tests
let l = getcompletion('cd ', 'cmdline')
- call assert_true(index(l, 'sautest/') >= 0)
+ call assert_true(index(l, expand('sautest/')) >= 0)
let l = getcompletion('cd NoMatch', 'cmdline')
call assert_equal([], l)
let l = getcompletion('let v:n', 'cmdline')
@@ -288,7 +288,7 @@ func Test_expand_star_star()
call mkdir('a/b', 'p')
call writefile(['asdfasdf'], 'a/b/fileXname')
call feedkeys(":find **/fileXname\<Tab>\<CR>", 'xt')
- call assert_equal('find a/b/fileXname', getreg(':'))
+ call assert_equal('find '.expand('a/b/fileXname'), getreg(':'))
bwipe!
call delete('a', 'rf')
endfunc
diff --git a/src/nvim/testdir/test_find_complete.vim b/src/nvim/testdir/test_find_complete.vim
index 4732109ed0..1019246404 100644
--- a/src/nvim/testdir/test_find_complete.vim
+++ b/src/nvim/testdir/test_find_complete.vim
@@ -3,6 +3,8 @@
" Do all the tests in a separate window to avoid E211 when we recursively
" delete the Xfind directory during cleanup
func Test_find_complete()
+ let shellslash = &shellslash
+ set shellslash
set belloff=all
" On windows a stale "Xfind" directory may exist, remove it so that
@@ -154,4 +156,5 @@ func Test_find_complete()
exe 'cd ' . cwd
call delete('Xfind', 'rf')
set path&
+ let &shellslash = shellslash
endfunc
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index 06c48d8e76..4d4a902031 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -30,7 +30,7 @@ func Test_help_tagjump()
help sp?it
call assert_equal("help", &filetype)
- call assert_true(getline('.') =~ '\*:split\*')
+ call assert_true(getline('.') =~ '\*'.(has('win32') ? 'split()' : ':split').'\*')
helpclose
help :?
diff --git a/src/nvim/testdir/test_makeencoding.vim b/src/nvim/testdir/test_makeencoding.vim
index a3d5538a47..6e4c7af821 100644
--- a/src/nvim/testdir/test_makeencoding.vim
+++ b/src/nvim/testdir/test_makeencoding.vim
@@ -13,12 +13,19 @@ endif
let s:script = 'test_makeencoding.py'
-let s:message_tbl = {
+if has('iconv')
+ let s:message_tbl = {
\ 'utf-8': 'ÀÈÌÒÙ こんにちは 你好',
\ 'latin1': 'ÀÈÌÒÙ',
\ 'cp932': 'こんにちは',
\ 'cp936': '你好',
\}
+else
+ let s:message_tbl = {
+ \ 'utf-8': 'ÀÈÌÒÙ こんにちは 你好',
+ \ 'latin1': 'ÀÈÌÒÙ',
+ \}
+endif
" Tests for :cgetfile and :lgetfile.
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 3c1b0050b5..f8c3161b40 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -158,6 +158,8 @@ func Test_set_completion()
call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:)
" Expand directories.
+ let shellslash = &shellslash
+ set shellslash
call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('./samples/ ', @:)
call assert_notmatch('./small.vim ', @:)
@@ -168,6 +170,7 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
+ let &shellslash = shellslash
endfunc
func Test_set_errors()
@@ -209,7 +212,14 @@ func Test_set_errors()
call assert_fails('set statusline=%{', 'E540:')
call assert_fails('set statusline=' . repeat("%p", 81), 'E541:')
call assert_fails('set statusline=%(', 'E542:')
- call assert_fails('set guicursor=x', 'E545:')
+ if has('cursorshape')
+ " This invalid value for 'guicursor' used to cause Vim to crash.
+ call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:')
+ call assert_fails('set guicursor=i-ci', 'E545:')
+ call assert_fails('set guicursor=x', 'E545:')
+ call assert_fails('set guicursor=r-cr:horx', 'E548:')
+ call assert_fails('set guicursor=r-cr:hor0', 'E549:')
+ endif
call assert_fails('set backupext=~ patchmode=~', 'E589:')
call assert_fails('set winminheight=10 winheight=9', 'E591:')
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index dd177fd633..85f93cf3da 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -850,17 +850,17 @@ func s:dir_stack_tests(cchar)
let qf = g:Xgetlist()
- call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr))
+ call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[1].bufnr))
call assert_equal(1, qf[1].lnum)
- call assert_equal('dir1/a/b/habits3.txt', bufname(qf[3].bufnr))
+ call assert_equal(expand('dir1/a/b/habits3.txt'), bufname(qf[3].bufnr))
call assert_equal(2, qf[3].lnum)
- call assert_equal('dir1/a/habits2.txt', bufname(qf[4].bufnr))
+ call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[4].bufnr))
call assert_equal(7, qf[4].lnum)
- call assert_equal('dir1/c/habits4.txt', bufname(qf[6].bufnr))
+ call assert_equal(expand('dir1/c/habits4.txt'), bufname(qf[6].bufnr))
call assert_equal(3, qf[6].lnum)
call assert_equal('habits1.txt', bufname(qf[9].bufnr))
call assert_equal(4, qf[9].lnum)
- call assert_equal('dir2/habits5.txt', bufname(qf[11].bufnr))
+ call assert_equal(expand('dir2/habits5.txt'), bufname(qf[11].bufnr))
call assert_equal(5, qf[11].lnum)
let &efm=save_efm
@@ -1065,7 +1065,7 @@ func Test_efm2()
call assert_equal(8, len(l))
call assert_equal(89, l[4].lnum)
call assert_equal(1, l[4].valid)
- call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
+ call assert_equal(expand('unittests/dbfacadeTest.py'), bufname(l[4].bufnr))
" The following sequence of commands used to crash Vim
set efm=%W%m
@@ -1609,11 +1609,11 @@ func Test_two_windows()
laddexpr 'one.txt:3:one one one'
let loc_one = getloclist(one_id)
- call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr))
+ call assert_equal(expand('Xone/a/one.txt'), bufname(loc_one[1].bufnr))
call assert_equal(3, loc_one[1].lnum)
let loc_two = getloclist(two_id)
- call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr))
+ call assert_equal(expand('Xtwo/a/two.txt'), bufname(loc_two[1].bufnr))
call assert_equal(5, loc_two[1].lnum)
call win_gotoid(one_id)
diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim
index 46d884a97c..beecb4cd0d 100644
--- a/src/nvim/testdir/test_recover.vim
+++ b/src/nvim/testdir/test_recover.vim
@@ -6,11 +6,6 @@ func Test_recover_root_dir()
set dir=/
call assert_fails('recover', 'E305:')
close!
-
- if has('win32') || filewritable('/') == 2
- " can write in / directory on MS-Windows
- set dir=/notexist/
- endif
call assert_fails('split Xtest', 'E303:')
set dir&
endfunc
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 21f2363731..a2828b21d2 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -315,7 +315,7 @@ endfunc
" Check using z= in new buffer (crash fixed by patch 7.4a.028).
func Test_zeq_crash()
new
- set maxmem=512 spell
+ set spell
call feedkeys('iasdz=:\"', 'tx')
bwipe!
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
index 1239fe9427..0a09130b0c 100644
--- a/src/nvim/testdir/test_stat.vim
+++ b/src/nvim/testdir/test_stat.vim
@@ -86,7 +86,7 @@ func Test_win32_symlink_dir()
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'))
+ call assert_equal('link', getftype('C:\Users\All Users'))
endif
endif
endfunc
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 0446bd9105..d3c0594c03 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -5,14 +5,12 @@ function! Test_System()
return
endif
let out = system('echo 123')
- " On Windows we may get a trailing space.
- if out != "123 \n"
- call assert_equal("123\n", out)
- endif
+ call assert_equal("123\n", out)
let out = systemlist('echo 123')
- " On Windows we may get a trailing space and CR.
- if out != ["123 \r"]
+ if &shell =~# 'cmd.exe$'
+ call assert_equal(["123\r"], out)
+ else
call assert_equal(['123'], out)
endif
@@ -46,3 +44,47 @@ function! Test_System()
call assert_fails('call system("wc -l", 99999)', 'E86:')
endfunction
+
+function! Test_system_exmode()
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es --headless -u NONE -c "source Xscript" +q; echo "result=$?"'
+ " Need to put this in a script, "catch" isn't found after an unknown
+ " function.
+ call writefile(['try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
+ let a = system(v:progpath . cmd)
+ call assert_match('result=0', a)
+ call assert_equal(0, v:shell_error)
+ endif
+
+ " Error before try does set error flag.
+ call writefile(['call nosuchfunction()', 'try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
+ if has('unix') " echo $? only works on Unix
+ let a = system(v:progpath . cmd)
+ call assert_notequal('0', a[0])
+ endif
+
+ let cmd = ' -es --headless -u NONE -c "source Xscript" +q'
+ let a = system(v:progpath . cmd)
+ call assert_notequal(0, v:shell_error)
+ call delete('Xscript')
+
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es --headless -u NONE -c "call doesnotexist()" +q; echo $?'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, a[0])
+ endif
+
+ let cmd = ' -es --headless -u NONE -c "call doesnotexist()" +q'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, v:shell_error)
+
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es --headless -u NONE -c "call doesnotexist()|let a=1" +q; echo $?'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, a[0])
+ endif
+
+ let cmd = ' -es --headless -u NONE -c "call doesnotexist()|let a=1" +q'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, v:shell_error)
+endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index d377062780..81ac2b6171 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -119,7 +119,7 @@ func Test_paused()
let slept = WaitFor('g:val == 1')
call assert_equal(1, g:val)
if has('reltime')
- call assert_inrange(0, 60, slept)
+ call assert_inrange(0, 100, slept)
else
call assert_inrange(0, 10, slept)
endif
diff --git a/src/nvim/testdir/test_unlet.vim b/src/nvim/testdir/test_unlet.vim
index 96ba752d9f..3f06058d03 100644
--- a/src/nvim/testdir/test_unlet.vim
+++ b/src/nvim/testdir/test_unlet.vim
@@ -24,3 +24,7 @@ func Test_not_existing()
call assert_true(v:exception =~ ':E108:')
endtry
endfunc
+
+func Test_unlet_fails()
+ call assert_fails('unlet v:["count"]', 'E46:')
+endfunc
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index b04a6ce4f9..0362820687 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -170,11 +170,21 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
char buf[64];
size_t len = 0;
int button, row, col;
+ static int last_pressed_button = 0;
TermKeyMouseEvent ev;
termkey_interpret_mouse(input->tk, key, &ev, &button, &row, &col);
- if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG
- && ev != TERMKEY_MOUSE_RELEASE) {
+ if ((ev == TERMKEY_MOUSE_RELEASE || ev == TERMKEY_MOUSE_DRAG)
+ && button == 0) {
+ // Some terminals (like urxvt) don't report which button was released.
+ // libtermkey reports button 0 in this case.
+ // For drag and release, we can reasonably infer the button to be the last
+ // pressed one.
+ button = last_pressed_button;
+ }
+
+ if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG
+ && ev != TERMKEY_MOUSE_RELEASE)) {
return;
}
@@ -210,6 +220,7 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
"ScrollWheelDown");
} else {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse");
+ last_pressed_button = button;
}
break;
case TERMKEY_MOUSE_DRAG:
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bfebe0442d..65957626cb 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -450,7 +450,8 @@ static void update_attrs(UI *ui, HlAttrs attrs)
int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
bool bold = attr & HL_BOLD;
bool italic = attr & HL_ITALIC;
- bool reverse = attr & (HL_INVERSE | HL_STANDOUT);
+ bool reverse = attr & HL_INVERSE;
+ bool standout = attr & HL_STANDOUT;
bool underline = attr & (HL_UNDERLINE), undercurl = attr & (HL_UNDERCURL);
if (unibi_get_str(data->ut, unibi_set_attributes)) {
@@ -478,6 +479,9 @@ static void update_attrs(UI *ui, HlAttrs attrs)
if (underline || undercurl) {
unibi_out(ui, unibi_enter_underline_mode);
}
+ if (standout) {
+ unibi_out(ui, unibi_enter_standout_mode);
+ }
if (reverse) {
unibi_out(ui, unibi_enter_reverse_mode);
}
@@ -601,8 +605,7 @@ static void cursor_goto(UI *ui, int row, int col)
int n = col - grid->col;
if (n <= (row == grid->row ? 4 : 2)
&& cheap_to_print(ui, grid->row, grid->col, n)) {
- UGRID_FOREACH_CELL(grid, grid->row, grid->row,
- grid->col, col - 1, {
+ UGRID_FOREACH_CELL(grid, grid->row, grid->row, grid->col, col - 1, {
print_cell(ui, cell);
});
}
@@ -826,7 +829,7 @@ static void tui_cursor_goto(UI *ui, Integer row, Integer col)
CursorShape tui_cursor_decode_shape(const char *shape_str)
{
- CursorShape shape = 0;
+ CursorShape shape;
if (strequal(shape_str, "block")) {
shape = SHAPE_BLOCK;
} else if (strequal(shape_str, "vertical")) {
@@ -834,7 +837,8 @@ CursorShape tui_cursor_decode_shape(const char *shape_str)
} else if (strequal(shape_str, "horizontal")) {
shape = SHAPE_HOR;
} else {
- EMSG2(_(e_invarg2), shape_str);
+ WLOG("Unknown shape value '%s'", shape_str);
+ shape = SHAPE_BLOCK;
}
return shape;
}
@@ -920,7 +924,6 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
TUIData *data = ui->data;
cursorentry_T c = data->cursor_shapes[mode];
- int shape = c.shape;
if (c.id != 0 && ui->rgb) {
int attr = syn_id2attr(c.id);
@@ -931,11 +934,12 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
}
- switch (shape) {
+ int shape;
+ switch (c.shape) {
+ default: abort(); break;
case SHAPE_BLOCK: shape = 1; break;
case SHAPE_HOR: shape = 3; break;
case SHAPE_VER: shape = 5; break;
- default: WLOG("Unknown shape value %d", shape); break;
}
UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
@@ -1766,7 +1770,8 @@ static void flush_buf(UI *ui)
bufp++;
}
- if (!data->busy && data->is_invisible) {
+ if (!data->busy) {
+ assert(data->is_invisible);
// not busy and the cursor is invisible. Write a "cursor normal" command
// after writing the buffer.
bufp->base = data->norm;
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index 60c9068eb1..035074846e 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -23,6 +23,8 @@ struct ugrid {
UCell **cells;
};
+// -V:UGRID_FOREACH_CELL:625
+
#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
do { \
for (int row = top; row <= bot; row++) { \
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index c70a02d960..42366fdb76 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -186,6 +186,10 @@ Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
PUT(hl, "bold", BOOLEAN_OBJ(true));
}
+ if (mask & HL_STANDOUT) {
+ PUT(hl, "standout", BOOLEAN_OBJ(true));
+ }
+
if (mask & HL_UNDERLINE) {
PUT(hl, "underline", BOOLEAN_OBJ(true));
}
@@ -198,7 +202,7 @@ Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
PUT(hl, "italic", BOOLEAN_OBJ(true));
}
- if (mask & (HL_INVERSE | HL_STANDOUT)) {
+ if (mask & HL_INVERSE) {
PUT(hl, "reverse", BOOLEAN_OBJ(true));
}
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 56e0c0c454..a8bbeea035 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -116,7 +116,7 @@ static void ui_bridge_stop(UI *b)
uv_mutex_lock(&bridge->mutex);
stopped = bridge->stopped;
uv_mutex_unlock(&bridge->mutex);
- if (stopped) {
+ if (stopped) { // -V547
break;
}
loop_poll_events(&main_loop, 10); // Process one event.
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 35857510fc..e1ae4b4cc0 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -972,7 +972,7 @@ static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error,
char_u **array = NULL;
if (uep->ue_size > 0) {
- if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char_u *)) {
+ if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char_u *)) { // -V547
array = xmalloc(sizeof(char_u *) * (size_t)uep->ue_size);
memset(array, 0, sizeof(char_u *) * (size_t)uep->ue_size);
}
@@ -1404,7 +1404,7 @@ void u_read_undo(char *name, char_u *hash, char_u *orig_name)
// sequence numbers of the headers.
// When there are no headers uhp_table is NULL.
if (num_head > 0) {
- if ((size_t)num_head < SIZE_MAX / sizeof(*uhp_table)) {
+ if ((size_t)num_head < SIZE_MAX / sizeof(*uhp_table)) { // -V547
uhp_table = xmalloc((size_t)num_head * sizeof(*uhp_table));
}
}
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 4196ecb9d2..1a7e55c11e 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -779,7 +779,8 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate,
eltkn_opt_scope_tab[token.data.opt.scope],
(int)token.data.opt.len, token.data.opt.name)
TKNARGS(kExprLexPlainIdentifier, "(scope=%s,autoload=%i)",
- intchar2str(token.data.var.scope), (int)token.data.var.autoload)
+ intchar2str((int)token.data.var.scope),
+ (int)token.data.var.autoload)
TKNARGS(kExprLexNumber, "(is_float=%i,base=%i,val=%lg)",
(int)token.data.num.is_float,
(int)token.data.num.base,
@@ -2415,11 +2416,6 @@ viml_pexpr_parse_valid_colon:
cur_token,
_("E15: Expected value, got closing bracket: %.*s"));
}
- } else {
- if (!kv_size(ast_stack)) {
- new_top_node_p = top_node_p;
- goto viml_pexpr_parse_bracket_closing_error;
- }
}
do {
new_top_node_p = kv_pop(ast_stack);
@@ -2534,11 +2530,6 @@ viml_pexpr_parse_bracket_closing_error:
cur_token,
_("E15: Expected value, got closing figure brace: %.*s"));
}
- } else {
- if (!kv_size(ast_stack)) {
- new_top_node_p = top_node_p;
- goto viml_pexpr_parse_figure_brace_closing_error;
- }
}
do {
new_top_node_p = kv_pop(ast_stack);
diff --git a/src/nvim/window.c b/src/nvim/window.c
index b4ef901d94..82fffe305c 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4466,8 +4466,7 @@ static void frame_setwidth(frame_T *curfrp, int width)
if (width <= room)
break;
if (run == 2 || curfrp->fr_height >= ROWS_AVAIL) {
- if (width > room)
- width = room;
+ width = room;
break;
}
frame_setwidth(curfrp->fr_parent, width
@@ -4807,7 +4806,7 @@ void win_new_height(win_T *wp, int height)
// call win_new_height() recursively.
validate_cursor();
}
- if (wp->w_height != prev_height) {
+ if (wp->w_height != prev_height) { // -V547
return; // Recursive call already changed the size, bail out.
}
if (wp->w_wrow != wp->w_prev_fraction_row) {