aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/nvim/CMakeLists.txt42
-rw-r--r--src/nvim/api/buffer.c6
-rw-r--r--src/nvim/api/command.c52
-rw-r--r--src/nvim/api/keysets.lua1
-rw-r--r--src/nvim/api/options.c28
-rw-r--r--src/nvim/api/private/defs.h1
-rw-r--r--src/nvim/api/private/helpers.h12
-rw-r--r--src/nvim/api/ui.c21
-rw-r--r--src/nvim/api/vim.c47
-rw-r--r--src/nvim/autocmd.c12
-rw-r--r--src/nvim/buffer.c13
-rw-r--r--src/nvim/buffer_defs.h35
-rw-r--r--src/nvim/buffer_updates.c32
-rw-r--r--src/nvim/change.c104
-rw-r--r--src/nvim/charset.c10
-rw-r--r--src/nvim/cursor_shape.c2
-rw-r--r--src/nvim/decoration_provider.c32
-rw-r--r--src/nvim/diff.c70
-rw-r--r--src/nvim/digraph.c16
-rw-r--r--src/nvim/digraph.h1
-rw-r--r--src/nvim/edit.c3805
-rw-r--r--src/nvim/edit.h20
-rw-r--r--src/nvim/eval.c1738
-rw-r--r--src/nvim/eval.c.orig9995
-rw-r--r--src/nvim/eval.h1
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/executor.c2
-rw-r--r--src/nvim/eval/funcs.c1186
-rw-r--r--src/nvim/eval/funcs.h2
-rw-r--r--src/nvim/eval/typval.c621
-rw-r--r--src/nvim/eval/userfunc.c5
-rw-r--r--src/nvim/eval/vars.c1822
-rw-r--r--src/nvim/eval/vars.h9
-rw-r--r--src/nvim/ex_cmds.c92
-rw-r--r--src/nvim/ex_cmds2.c11
-rw-r--r--src/nvim/ex_docmd.c120
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/ex_getln.c244
-rw-r--r--src/nvim/ex_session.c6
-rw-r--r--src/nvim/file_search.c46
-rw-r--r--src/nvim/fileio.c20
-rw-r--r--src/nvim/fold.h2
-rw-r--r--src/nvim/garray.c2
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua4
-rw-r--r--src/nvim/getchar.c22
-rw-r--r--src/nvim/globals.h13
-rw-r--r--src/nvim/grid.c21
-rw-r--r--src/nvim/grid_defs.h9
-rw-r--r--src/nvim/hardcopy.c2
-rw-r--r--src/nvim/highlight.c70
-rw-r--r--src/nvim/highlight_group.c11
-rw-r--r--src/nvim/indent_c.c4
-rw-r--r--src/nvim/insexpand.c3967
-rw-r--r--src/nvim/insexpand.h17
-rw-r--r--src/nvim/keycodes.c4
-rw-r--r--src/nvim/keycodes.h90
-rw-r--r--src/nvim/log.c2
-rw-r--r--src/nvim/lua/executor.c13
-rw-r--r--src/nvim/lua/stdlib.c4
-rw-r--r--src/nvim/lua/treesitter.c118
-rw-r--r--src/nvim/main.c3
-rw-r--r--src/nvim/mapping.c318
-rw-r--r--src/nvim/mapping.h9
-rw-r--r--src/nvim/mark.c13
-rw-r--r--src/nvim/match.c1
-rw-r--r--src/nvim/match.h1
-rw-r--r--src/nvim/mbyte.c105
-rw-r--r--src/nvim/memline.c242
-rw-r--r--src/nvim/memory.c4
-rw-r--r--src/nvim/menu.c2
-rw-r--r--src/nvim/message.c44
-rw-r--r--src/nvim/move.c8
-rw-r--r--src/nvim/msgpack_rpc/channel.c9
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c208
-rw-r--r--src/nvim/msgpack_rpc/unpacker.h7
-rw-r--r--src/nvim/normal.c18
-rw-r--r--src/nvim/ops.c35
-rw-r--r--src/nvim/option.c116
-rw-r--r--src/nvim/option.h11
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/os/shell.c28
-rw-r--r--src/nvim/path.c43
-rw-r--r--src/nvim/po/tr.po8965
-rw-r--r--src/nvim/po/zh_CN.UTF-8.po121
-rw-r--r--src/nvim/popupmnu.c6
-rw-r--r--src/nvim/quickfix.c485
-rw-r--r--src/nvim/rbuffer.c2
-rw-r--r--src/nvim/regexp.c112
-rw-r--r--src/nvim/regexp_bt.c82
-rw-r--r--src/nvim/regexp_nfa.c90
-rw-r--r--src/nvim/runtime.c55
-rw-r--r--src/nvim/screen.c215
-rw-r--r--src/nvim/search.c89
-rw-r--r--src/nvim/search.h1
-rw-r--r--src/nvim/sign.c1
-rw-r--r--src/nvim/sign.h1
-rw-r--r--src/nvim/spell.c198
-rw-r--r--src/nvim/spell_defs.h2
-rw-r--r--src/nvim/spellfile.c178
-rw-r--r--src/nvim/state.c9
-rw-r--r--src/nvim/strings.c44
-rw-r--r--src/nvim/syntax.c159
-rw-r--r--src/nvim/tag.c55
-rw-r--r--src/nvim/terminal.c32
-rw-r--r--src/nvim/testdir/README.txt121
-rw-r--r--src/nvim/testdir/setup.vim1
-rw-r--r--src/nvim/testdir/term_util.vim2
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_autocmd.vim155
-rw-r--r--src/nvim/testdir/test_changelist.vim69
-rw-r--r--src/nvim/testdir/test_clientserver.vim87
-rw-r--r--src/nvim/testdir/test_cmdline.vim29
-rw-r--r--src/nvim/testdir/test_diffmode.vim156
-rw-r--r--src/nvim/testdir/test_edit.vim91
-rw-r--r--src/nvim/testdir/test_ex_mode.vim28
-rw-r--r--src/nvim/testdir/test_excmd.vim136
-rw-r--r--src/nvim/testdir/test_expand.vim9
-rw-r--r--src/nvim/testdir/test_filetype.vim35
-rw-r--r--src/nvim/testdir/test_functions.vim20
-rw-r--r--src/nvim/testdir/test_gf.vim39
-rw-r--r--src/nvim/testdir/test_global.vim30
-rw-r--r--src/nvim/testdir/test_input.vim (renamed from src/nvim/testdir/test_feedkeys.vim)26
-rw-r--r--src/nvim/testdir/test_ins_complete.vim202
-rw-r--r--src/nvim/testdir/test_maparg.vim184
-rw-r--r--src/nvim/testdir/test_messages.vim70
-rw-r--r--src/nvim/testdir/test_normal.vim30
-rw-r--r--src/nvim/testdir/test_options.vim19
-rw-r--r--src/nvim/testdir/test_popup.vim19
-rw-r--r--src/nvim/testdir/test_quickfix.vim8
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim11
-rw-r--r--src/nvim/testdir/test_spell_utf8.vim8
-rw-r--r--src/nvim/testdir/test_startup.vim242
-rw-r--r--src/nvim/testdir/test_statusline.vim11
-rw-r--r--src/nvim/testdir/test_syn_attr.vim30
-rw-r--r--src/nvim/testdir/test_termcodes.vim23
-rw-r--r--src/nvim/testdir/test_textformat.vim66
-rw-r--r--src/nvim/testdir/test_timers.vim2
-rw-r--r--src/nvim/testdir/test_trycatch.vim6
-rw-r--r--src/nvim/testdir/test_vimscript.vim21
-rw-r--r--src/nvim/testdir/test_window_cmd.vim6
-rw-r--r--src/nvim/testing.h1
-rw-r--r--src/nvim/types.h2
-rw-r--r--src/nvim/ui.c12
-rw-r--r--src/nvim/ui_client.c137
-rw-r--r--src/nvim/ui_client.h6
-rw-r--r--src/nvim/undo.c2
-rw-r--r--src/nvim/window.c340
147 files changed, 23717 insertions, 15564 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 360993de68..017883a913 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -156,34 +156,10 @@ endforeach()
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
-# Legacy files that do not yet pass -Wconversion.
-set(CONV_SOURCES
- lua/treesitter.c
- mbyte.c
- memline.c
- regexp.c
- screen.c
- search.c
- spell.c
- spellfile.c
- syntax.c
- window.c)
-foreach(sfile ${CONV_SOURCES})
- if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${sfile}")
- message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
- endif()
-endforeach()
-
if(NOT MSVC)
- set_source_files_properties(
- ${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
-
# xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306
set_source_files_properties(
${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion")
-
- set_source_files_properties(
- eval/funcs.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
endif()
if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$")
@@ -230,6 +206,7 @@ add_custom_target(update_version_stamp
-DNVIM_VERSION_PATCH=${NVIM_VERSION_PATCH}
-DNVIM_VERSION_PRERELEASE=${NVIM_VERSION_PRERELEASE}
-DOUTPUT=${NVIM_VERSION_GIT_H}
+ -DCMAKE_MESSAGE_LOG_LEVEL=${CMAKE_MESSAGE_LOG_LEVEL}
-P ${PROJECT_SOURCE_DIR}/cmake/GenerateVersion.cmake
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
BYPRODUCTS ${NVIM_VERSION_GIT_H})
@@ -268,7 +245,7 @@ foreach(sfile ${NVIM_SOURCES}
set(depends "${HEADER_GENERATOR}" "${sfile}")
if("${f}" STREQUAL "version.c")
# Ensure auto/versiondef_git.h exists after "make clean".
- list(APPEND depends "${NVIM_VERSION_GIT_H}")
+ list(APPEND depends update_version_stamp "${NVIM_VERSION_GIT_H}")
endif()
add_custom_command(
OUTPUT "${gf_c_h}" "${gf_h_h}"
@@ -789,12 +766,27 @@ foreach(sfile ${LINT_NVIM_SOURCES})
endforeach()
add_custom_target(lintc DEPENDS ${LINT_TARGETS})
+add_custom_target(uncrustify-version
+ COMMAND ${CMAKE_COMMAND}
+ -D UNCRUSTIFY_PRG=${UNCRUSTIFY_PRG}
+ -D CONFIG_FILE=${PROJECT_SOURCE_DIR}/src/uncrustify.cfg
+ -P ${PROJECT_SOURCE_DIR}/cmake/CheckUncrustifyVersion.cmake)
+
add_glob_targets(
TARGET lintuncrustify
COMMAND ${UNCRUSTIFY_PRG}
FLAGS -c "${PROJECT_SOURCE_DIR}/src/uncrustify.cfg" -q --check
FILES ${LINT_NVIM_SOURCES}
)
+add_dependencies(lintuncrustify uncrustify-version)
+
+add_custom_target(formatc
+ COMMAND ${CMAKE_COMMAND}
+ -D FORMAT_PRG=${UNCRUSTIFY_PRG}
+ -D LANG=c
+ -P ${PROJECT_SOURCE_DIR}/cmake/Format.cmake
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
+add_dependencies(formatc uncrustify-version)
add_custom_target(
lintcfull
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 806b649ce6..1b1a161226 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -538,9 +538,9 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
Integer end_row, Integer end_col, ArrayOf(String) replacement, Error *err)
FUNC_API_SINCE(7)
{
- FIXED_TEMP_ARRAY(scratch, 1);
+ MAXSIZE_TEMP_ARRAY(scratch, 1);
if (replacement.size == 0) {
- scratch.items[0] = STRING_OBJ(STATIC_CSTR_AS_STRING(""));
+ ADD_C(scratch, STRING_OBJ(STATIC_CSTR_AS_STRING("")));
replacement = scratch;
}
@@ -932,7 +932,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @param buffer Buffer handle, or 0 for current buffer
/// @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(uint64_t channel_id, Buffer buffer, String mode, Error *err)
FUNC_API_SINCE(3)
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 4c2404a0d8..33efa6b326 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -306,7 +306,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
char *cmdline = NULL;
char *cmdname = NULL;
- char **args = NULL;
+ ArrayOf(String) args;
size_t argc = 0;
String retv = (String)STRING_INIT;
@@ -412,22 +412,15 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
if (!argc_valid) {
- argc = 0; // Ensure that args array isn't erroneously freed at the end.
VALIDATION_ERROR("Incorrect number of arguments supplied");
}
- if (argc != 0) {
- args = xcalloc(argc, sizeof(char *));
-
- for (size_t i = 0; i < argc; i++) {
- args[i] = string_to_cstr(cmd->args.data.array.items[i].data.string);
- }
- }
+ args = cmd->args.data.array;
}
// Simply pass the first argument (if it exists) as the arg pointer to `set_cmd_addr_type()`
// since it only ever checks the first argument.
- set_cmd_addr_type(&ea, argc > 0 ? args[0] : NULL);
+ set_cmd_addr_type(&ea, argc > 0 ? args.items[0].data.string.data : NULL);
if (HAS_KEY(cmd->range)) {
if (!(ea.argt & EX_RANGE)) {
@@ -600,7 +593,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
OBJ_TO_CMOD_FLAG(CMOD_SILENT, mods.silent, false, "'mods.silent'");
OBJ_TO_CMOD_FLAG(CMOD_ERRSILENT, mods.emsg_silent, false, "'mods.emsg_silent'");
- OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods.silent, false, "'mods.unsilent'");
+ OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods.unsilent, false, "'mods.unsilent'");
OBJ_TO_CMOD_FLAG(CMOD_SANDBOX, mods.sandbox, false, "'mods.sandbox'");
OBJ_TO_CMOD_FLAG(CMOD_NOAUTOCMD, mods.noautocmd, false, "'mods.noautocmd'");
OBJ_TO_CMOD_FLAG(CMOD_BROWSE, mods.browse, false, "'mods.browse'");
@@ -676,10 +669,6 @@ end:
xfree(cmdname);
xfree(ea.args);
xfree(ea.arglens);
- for (size_t i = 0; i < argc; i++) {
- xfree(args[i]);
- }
- xfree(args);
return retv;
@@ -704,12 +693,11 @@ static bool string_iswhite(String str)
}
/// Build cmdline string for command, used by `nvim_cmd()`.
-///
-/// @return OK or FAIL.
-static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdinfo, char **args,
- size_t argc)
+static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdinfo,
+ ArrayOf(String) args, size_t argc)
{
StringBuilder cmdline = KV_INITIAL_VALUE;
+ kv_resize(cmdline, 32); // Make it big enough to handle most typical commands
// Add command modifiers
if (cmdinfo->cmdmod.cmod_tab != 0) {
@@ -779,11 +767,11 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin
// Keep the index of the position where command name starts, so eap->cmd can point to it.
size_t cmdname_idx = cmdline.size;
- kv_printf(cmdline, "%s", eap->cmd);
+ kv_concat(cmdline, eap->cmd);
// Command bang.
if (eap->argt & EX_BANG && eap->forceit) {
- kv_printf(cmdline, "!");
+ kv_concat(cmdline, "!");
}
// Command register.
@@ -791,29 +779,35 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin
kv_printf(cmdline, " %c", eap->regname);
}
- // Iterate through each argument and store the starting index and length of each argument
- size_t *argidx = xcalloc(argc, sizeof(size_t));
eap->argc = argc;
eap->arglens = xcalloc(argc, sizeof(size_t));
+ size_t argstart_idx = cmdline.size;
for (size_t i = 0; i < argc; i++) {
- argidx[i] = cmdline.size + 1; // add 1 to account for the space.
- eap->arglens[i] = STRLEN(args[i]);
- kv_printf(cmdline, " %s", args[i]);
+ String s = args.items[i].data.string;
+ eap->arglens[i] = s.size;
+ kv_concat(cmdline, " ");
+ kv_concat_len(cmdline, s.data, s.size);
}
+ // Done appending to cmdline, ensure it is NUL terminated
+ kv_push(cmdline, NUL);
+
// Now that all the arguments are appended, use the command index and argument indices to set the
// values of eap->cmd, eap->arg and eap->args.
eap->cmd = cmdline.items + cmdname_idx;
eap->args = xcalloc(argc, sizeof(char *));
+ size_t offset = argstart_idx;
for (size_t i = 0; i < argc; i++) {
- eap->args[i] = cmdline.items + argidx[i];
+ offset++; // Account for space
+ eap->args[i] = cmdline.items + offset;
+ offset += eap->arglens[i];
}
// If there isn't an argument, make eap->arg point to end of cmdline.
- eap->arg = argc > 0 ? eap->args[0] : cmdline.items + cmdline.size;
+ eap->arg = argc > 0 ? eap->args[0] :
+ cmdline.items + cmdline.size - 1; // Subtract 1 to account for NUL
// Finally, make cmdlinep point to the cmdline string.
*cmdlinep = cmdline.items;
- xfree(argidx);
// Replace, :make and :grep with 'makeprg' and 'grepprg'.
char *p = replace_makeprg(eap, eap->arg, cmdlinep);
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 1f1fa1e63a..a764fb069b 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -39,6 +39,7 @@ return {
"unique";
"callback";
"desc";
+ "replace_keycodes";
};
get_commands = {
"builtin";
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 4ed676e613..867584dd71 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -104,20 +104,20 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
long numval = 0;
char *stringval = NULL;
- int result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type, from,
- true, err);
+ getoption_T result = access_option_value_for(name.data, &numval, &stringval, scope, opt_type,
+ from, true, err);
if (ERROR_SET(err)) {
return rv;
}
switch (result) {
- case 0:
+ case gov_string:
rv = STRING_OBJ(cstr_as_string(stringval));
break;
- case 1:
+ case gov_number:
rv = INTEGER_OBJ(numval);
break;
- case 2:
+ case gov_bool:
switch (numval) {
case 0:
case 1:
@@ -280,7 +280,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
return get_option_from(buf, SREQ_BUF, name, err);
}
-/// Sets a buffer option value. Passing 'nil' as value deletes the option (only
+/// Sets a buffer option value. Passing `nil` as value deletes the option (only
/// works if there's a global fallback)
///
/// @param channel_id
@@ -318,7 +318,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
return get_option_from(win, SREQ_WIN, name, err);
}
-/// Sets a window option value. Passing 'nil' as value deletes the option(only
+/// Sets a window option value. Passing `nil` as value deletes the option (only
/// works if there's a global fallback)
///
/// @param channel_id
@@ -338,7 +338,7 @@ void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object
set_option_to(channel_id, win, SREQ_WIN, name, value, err);
}
-/// Gets the value of a global or local(buffer, window) option.
+/// Gets the value of a global or local (buffer, window) option.
///
/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
/// to the window or buffer.
@@ -393,7 +393,7 @@ Object get_option_from(void *from, int type, String name, Error *err)
return rv;
}
-/// Sets the value of a global or local(buffer, window) option.
+/// Sets the value of a global or local (buffer, window) option.
///
/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
/// to the window or buffer.
@@ -483,8 +483,8 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object
});
}
-static int access_option_value(char *key, long *numval, char **stringval, int opt_flags, bool get,
- Error *err)
+static getoption_T access_option_value(char *key, long *numval, char **stringval, int opt_flags,
+ bool get, Error *err)
{
if (get) {
return get_option_value(key, numval, stringval, opt_flags);
@@ -501,13 +501,13 @@ static int access_option_value(char *key, long *numval, char **stringval, int op
}
}
-static int access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
- int opt_type, void *from, bool get, Error *err)
+static getoption_T access_option_value_for(char *key, long *numval, char **stringval, int opt_flags,
+ int opt_type, void *from, bool get, Error *err)
{
bool need_switch = false;
switchwin_T switchwin;
aco_save_T aco;
- int result = 0;
+ getoption_T result = 0;
try_start();
switch (opt_type) {
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index b1e0dd364c..9c7e59e4b3 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -36,6 +36,7 @@ typedef enum {
kMessageTypeRequest = 0,
kMessageTypeResponse = 1,
kMessageTypeNotification = 2,
+ kMessageTypeRedrawEvent = 3,
} MessageType;
/// Mask for all internal calls
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index a4348d8b44..1441da853c 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -74,18 +74,18 @@
#define ADD_C(array, item) \
kv_push_c(array, item)
-#define FIXED_TEMP_ARRAY(name, fixsize) \
- Array name = ARRAY_DICT_INIT; \
- Object name##__items[fixsize]; \
- name.size = fixsize; \
- name.items = name##__items; \
-
#define MAXSIZE_TEMP_ARRAY(name, maxsize) \
Array name = ARRAY_DICT_INIT; \
Object name##__items[maxsize]; \
name.capacity = maxsize; \
name.items = name##__items; \
+#define MAXSIZE_TEMP_DICT(name, maxsize) \
+ Dictionary name = ARRAY_DICT_INIT; \
+ KeyValuePair name##__items[maxsize]; \
+ name.capacity = maxsize; \
+ name.items = name##__items; \
+
#define cbuf_as_string(d, s) ((String) { .data = d, .size = s })
#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof(s) - 1 })
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 54ce838b9b..6239e414a7 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -27,7 +27,7 @@ typedef struct {
uint64_t channel_id;
#define UI_BUF_SIZE 4096 ///< total buffer size for pending msgpack data.
- /// guranteed size available for each new event (so packing of simple events
+ /// guaranteed size available for each new event (so packing of simple events
/// and the header of grid_line will never fail)
#define EVENT_BUF_SIZE 256
char buf[UI_BUF_SIZE]; ///< buffer of packed but not yet sent msgpack data
@@ -43,7 +43,7 @@ typedef struct {
// We start packing the two outermost msgpack arrays before knowing the total
// number of elements. Thus track the location where array size will need
- // to be written in the msgpack buffer, once the specifc array is finished.
+ // to be written in the msgpack buffer, once the specific array is finished.
char *nevents_pos;
char *ncalls_pos;
uint32_t nevents; ///< number of distinct events (top-level args to "redraw"
@@ -748,8 +748,10 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt
UIData *data = ui->data;
Array args = data->call_buf;
ADD_C(args, INTEGER_OBJ(id));
- ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs, true)));
- ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(cterm_attrs, false)));
+ MAXSIZE_TEMP_DICT(rgb, 16);
+ MAXSIZE_TEMP_DICT(cterm, 16);
+ ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&rgb, rgb_attrs, true)));
+ ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&cterm, cterm_attrs, false)));
if (ui->ui_ext[kUIHlState]) {
ADD_C(args, ARRAY_OBJ(info));
@@ -758,9 +760,6 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt
}
push_call(ui, "hl_attr_define", args);
- // TODO(bfredl): could be elided
- api_free_dictionary(kv_A(args, 1).data.dictionary);
- api_free_dictionary(kv_A(args, 2).data.dictionary);
}
static void remote_ui_highlight_set(UI *ui, int id)
@@ -772,11 +771,9 @@ static void remote_ui_highlight_set(UI *ui, int id)
return;
}
data->hl_id = id;
- Dictionary hl = hlattrs2dict(syn_attr2entry(id), ui->rgb);
-
- ADD_C(args, DICTIONARY_OBJ(hl));
+ MAXSIZE_TEMP_DICT(dict, 16);
+ ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb)));
push_call(ui, "highlight_set", args);
- api_free_dictionary(kv_A(args, 0).data.dictionary);
}
/// "true" cursor used only for input focus
@@ -963,7 +960,7 @@ static Array translate_contents(UI *ui, Array contents)
Array new_item = ARRAY_DICT_INIT;
int attr = (int)item.items[0].data.integer;
if (attr) {
- Dictionary rgb_attrs = hlattrs2dict(syn_attr2entry(attr), ui->rgb);
+ Dictionary rgb_attrs = hlattrs2dict(NULL, syn_attr2entry(attr), ui->rgb);
ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 56516b2ac7..e2f58dba62 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -37,6 +37,7 @@
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
@@ -472,10 +473,10 @@ Object nvim_exec_lua(String code, Array args, Error *err)
Object nvim_notify(String msg, Integer log_level, Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
- FIXED_TEMP_ARRAY(args, 3);
- args.items[0] = STRING_OBJ(msg);
- args.items[1] = INTEGER_OBJ(log_level);
- args.items[2] = DICTIONARY_OBJ(opts);
+ MAXSIZE_TEMP_ARRAY(args, 3);
+ ADD_C(args, STRING_OBJ(msg));
+ ADD_C(args, INTEGER_OBJ(log_level));
+ ADD_C(args, DICTIONARY_OBJ(opts));
return nlua_exec(STATIC_CSTR_AS_STRING("return vim.notify(...)"), args, err);
}
@@ -1009,10 +1010,10 @@ static void term_write(char *buf, size_t size, void *data)
if (cb == LUA_NOREF) {
return;
}
- FIXED_TEMP_ARRAY(args, 3);
- args.items[0] = INTEGER_OBJ((Integer)chan->id);
- args.items[1] = BUFFER_OBJ(terminal_buf(chan->term));
- args.items[2] = STRING_OBJ(((String){ .data = buf, .size = size }));
+ MAXSIZE_TEMP_ARRAY(args, 3);
+ ADD_C(args, INTEGER_OBJ((Integer)chan->id));
+ ADD_C(args, BUFFER_OBJ(terminal_buf(chan->term)));
+ ADD_C(args, STRING_OBJ(((String){ .data = buf, .size = size })));
textlock++;
nlua_call_ref(cb, "input", args, false, NULL);
textlock--;
@@ -1410,7 +1411,7 @@ Dictionary nvim_get_mode(void)
/// 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(uint64_t channel_id, String mode)
FUNC_API_SINCE(3)
@@ -1422,8 +1423,8 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
///
/// To set a buffer-local mapping, use |nvim_buf_set_keymap()|.
///
-/// Unlike |:map|, leading/trailing whitespace is accepted as part of the {lhs}
-/// or {rhs}. Empty {rhs} is |<Nop>|. |keycodes| are replaced as usual.
+/// Unlike |:map|, leading/trailing whitespace is accepted as part of the {lhs} or {rhs}.
+/// Empty {rhs} is |<Nop>|. |keycodes| are replaced as usual.
///
/// Example:
/// <pre>
@@ -1440,13 +1441,15 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
/// or "!" for |:map!|, or empty string for |:map|.
/// @param lhs Left-hand-side |{lhs}| of the mapping.
/// @param rhs Right-hand-side |{rhs}| of the mapping.
-/// @param opts Optional parameters map: keys are |:map-arguments|, values
-/// are booleans (default false). Accepts all |:map-arguments| as
-/// keys excluding |<buffer>| but including |noremap| and "desc".
-/// Unknown key is an error. "desc" can be used to give a
-/// description to the mapping. When called from Lua, also accepts a
-/// "callback" key that takes a Lua function to call when the
-/// mapping is executed.
+/// @param opts Optional parameters map: keys are |:map-arguments|, values are booleans (default
+/// false). Accepts all |:map-arguments| as keys excluding |<buffer>| but including
+/// |noremap| and "desc". Unknown key is an error.
+/// "desc" can be used to give a description to the mapping.
+/// When called from Lua, also accepts a "callback" key that takes a Lua function to
+/// call when the mapping is executed.
+/// When "expr" is true, "replace_keycodes" (boolean) can be used to replace keycodes
+/// in the resulting string (see |nvim_replace_termcodes()|), and a Lua callback
+/// returning `nil` is equivalent to returning an empty string.
/// @param[out] err Error details, if any.
void nvim_set_keymap(uint64_t channel_id, String mode, String lhs, String rhs, Dict(keymap) *opts,
Error *err)
@@ -2256,3 +2259,11 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
+
+void nvim_error_event(uint64_t channel_id, Integer lvl, String data)
+ FUNC_API_REMOTE_ONLY
+{
+ // TODO(bfredl): consider printing message to user, as will be relevant
+ // if we fork nvim processes as async workers
+ ELOG("async error on channel %" PRId64 ": %s", channel_id, data.size ? data.data : "");
+}
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index d51079b515..2b4c9c5b9c 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -14,10 +14,12 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/map.h"
#include "nvim/option.h"
@@ -1835,9 +1837,13 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
}
ap->last = true;
+ // Make sure cursor and topline are valid. The first time the current
+ // values are saved, restored by reset_lnums(). When nested only the
+ // values are corrected when needed.
if (nesting == 1) {
- // make sure cursor and topline are valid
check_lnums(true);
+ } else {
+ check_lnums_nested(true);
}
// Execute the autocmd. The `getnextac` callback handles iteration.
@@ -2051,8 +2057,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc)
break;
}
- FIXED_TEMP_ARRAY(args, 1);
- args.items[0] = DICTIONARY_OBJ(data);
+ MAXSIZE_TEMP_ARRAY(args, 1);
+ ADD_C(args, DICTIONARY_OBJ(data));
Object result = nlua_call_ref(callback.data.luaref, NULL, args, true, NULL);
if (result.type == kObjectTypeBoolean) {
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index f937450107..6dd71e92a6 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -37,6 +37,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/eval.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
@@ -2482,6 +2483,9 @@ void buflist_setfpos(buf_T *const buf, win_T *const win, linenr_T lnum, colnr_T
wip->wi_mark.view = mark_view_make(win->w_topline, wip->wi_mark.mark);
}
}
+ if (win != NULL) {
+ wip->wi_changelistidx = win->w_changelistidx;
+ }
if (copy_options && win != NULL) {
// Save the window-specific option values.
copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
@@ -2585,6 +2589,9 @@ void get_winopts(buf_T *buf)
} else {
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
}
+ if (wip != NULL) {
+ curwin->w_changelistidx = wip->wi_changelistidx;
+ }
if (curwin->w_float_config.style == kWinStyleMinimal) {
didset_window_options(curwin);
@@ -3281,7 +3288,7 @@ void maketitle(void)
len = (int)STRLEN(buf_p);
if (len > 100) {
len -= 100;
- len += mb_tail_off(buf_p, buf_p + len) + 1;
+ len += utf_cp_tail_off(buf_p, buf_p + len) + 1;
buf_p += len;
}
STRCPY(icon_str, buf_p);
@@ -3463,7 +3470,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
// Proceed character by character through the statusline format string
// fmt_p is the current position in the input buffer
- for (char *fmt_p = usefmt; *fmt_p;) {
+ for (char *fmt_p = usefmt; *fmt_p != NUL;) {
if (curitem == (int)stl_items_len) {
size_t new_len = stl_items_len * 3 / 2;
@@ -3477,7 +3484,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
stl_items_len = new_len;
}
- if (*fmt_p != NUL && *fmt_p != '%') {
+ if (*fmt_p != '%') {
prevchar_isflag = prevchar_isitem = false;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 4e890f7d10..b7f66e6dba 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -289,6 +289,7 @@ struct wininfo_S {
winopt_T wi_opt; // local window options
bool wi_fold_manual; // copy of w_fold_manual
garray_T wi_folds; // clone of w_folds
+ int wi_changelistidx; // copy of w_changelistidx
};
/*
@@ -368,6 +369,7 @@ struct mapblock {
char m_expr; // <expr> used, m_str is an expression
sctx_T m_script_ctx; // SCTX where map was defined
char *m_desc; // description of keymap
+ bool m_replace_keycodes; // replace termcodes in lua function
};
/// Used for highlighting in the status line.
@@ -444,11 +446,11 @@ typedef struct {
// "containedin" argument
int b_syn_sync_flags; // flags about how to sync
int16_t b_syn_sync_id; // group to sync on
- long b_syn_sync_minlines; // minimal sync lines offset
- long b_syn_sync_maxlines; // maximal sync lines offset
- long b_syn_sync_linebreaks; // offset for multi-line pattern
- char_u *b_syn_linecont_pat; // line continuation pattern
- regprog_T *b_syn_linecont_prog; // line continuation program
+ linenr_T b_syn_sync_minlines; // minimal sync lines offset
+ linenr_T b_syn_sync_maxlines; // maximal sync lines offset
+ linenr_T b_syn_sync_linebreaks; // offset for multi-line pattern
+ char_u *b_syn_linecont_pat; // line continuation pattern
+ regprog_T *b_syn_linecont_prog; // line continuation program
syn_time_T b_syn_linecont_time;
int b_syn_linecont_ic; // ignore-case flag for above
int b_syn_topgrp; // for ":syntax include"
@@ -582,9 +584,9 @@ struct file_buffer {
linenr_T b_mod_top; // topmost lnum that was changed
linenr_T b_mod_bot; // lnum below last changed line, AFTER the
// change
- long b_mod_xlines; // number of extra buffer lines inserted;
+ linenr_T b_mod_xlines; // number of extra buffer lines inserted;
// negative when lines were deleted
- wininfo_T *b_wininfo; // list of last used info for each window
+ wininfo_T *b_wininfo; // list of last used info for each window
disptick_T b_mod_tick_syn; // last display tick syntax was updated
disptick_T b_mod_tick_decor; // last display tick decoration providers
// where invoked
@@ -946,16 +948,15 @@ struct diffblock_S {
typedef struct tabpage_S tabpage_T;
struct tabpage_S {
handle_T handle;
- tabpage_T *tp_next; ///< next tabpage or NULL
- frame_T *tp_topframe; ///< topframe for the windows
- win_T *tp_curwin; ///< current window in this Tab page
- win_T *tp_prevwin; ///< previous window in this Tab page
- win_T *tp_firstwin; ///< first window in this Tab page
- win_T *tp_lastwin; ///< last window in this Tab page
- long tp_old_Rows; ///< Rows when Tab page was left
- long tp_old_Columns; ///< Columns when Tab page was left
- long tp_ch_used; ///< value of 'cmdheight' when frame size
- ///< was set
+ tabpage_T *tp_next; ///< next tabpage or NULL
+ frame_T *tp_topframe; ///< topframe for the windows
+ win_T *tp_curwin; ///< current window in this Tab page
+ win_T *tp_prevwin; ///< previous window in this Tab page
+ win_T *tp_firstwin; ///< first window in this Tab page
+ win_T *tp_lastwin; ///< last window in this Tab page
+ long tp_old_Rows_avail; ///< ROWS_AVAIL when Tab page was left
+ long tp_old_Columns; ///< Columns when Tab page was left
+ long tp_ch_used; ///< value of 'cmdheight' when frame size was set
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 47b88945c7..14973502ab 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -316,23 +316,23 @@ void buf_updates_send_splice(buf_T *buf, int start_row, colnr_T start_col, bcoun
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
bool keep = true;
if (cb.on_bytes != LUA_NOREF && (cb.preview || !cmdpreview)) {
- FIXED_TEMP_ARRAY(args, 11);
+ MAXSIZE_TEMP_ARRAY(args, 11);
// the first argument is always the buffer handle
- args.items[0] = BUFFER_OBJ(buf->handle);
+ ADD_C(args, BUFFER_OBJ(buf->handle));
// next argument is b:changedtick
- args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
-
- args.items[2] = INTEGER_OBJ(start_row);
- args.items[3] = INTEGER_OBJ(start_col);
- args.items[4] = INTEGER_OBJ(start_byte);
- args.items[5] = INTEGER_OBJ(old_row);
- args.items[6] = INTEGER_OBJ(old_col);
- args.items[7] = INTEGER_OBJ(old_byte);
- args.items[8] = INTEGER_OBJ(new_row);
- args.items[9] = INTEGER_OBJ(new_col);
- args.items[10] = INTEGER_OBJ(new_byte);
+ ADD_C(args, INTEGER_OBJ(buf_get_changedtick(buf)));
+
+ ADD_C(args, INTEGER_OBJ(start_row));
+ ADD_C(args, INTEGER_OBJ(start_col));
+ ADD_C(args, INTEGER_OBJ(start_byte));
+ ADD_C(args, INTEGER_OBJ(old_row));
+ ADD_C(args, INTEGER_OBJ(old_col));
+ ADD_C(args, INTEGER_OBJ(old_byte));
+ ADD_C(args, INTEGER_OBJ(new_row));
+ ADD_C(args, INTEGER_OBJ(new_col));
+ ADD_C(args, INTEGER_OBJ(new_byte));
textlock++;
Object res = nlua_call_ref(cb.on_bytes, "bytes", args, true, NULL);
@@ -361,13 +361,13 @@ void buf_updates_changedtick(buf_T *buf)
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
bool keep = true;
if (cb.on_changedtick != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 2);
+ MAXSIZE_TEMP_ARRAY(args, 2);
// the first argument is always the buffer handle
- args.items[0] = BUFFER_OBJ(buf->handle);
+ ADD_C(args, BUFFER_OBJ(buf->handle));
// next argument is b:changedtick
- args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
+ ADD_C(args, INTEGER_OBJ(buf_get_changedtick(buf)));
textlock++;
Object res = nlua_call_ref(cb.on_changedtick, "changedtick",
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 4568b71fd9..c063ece907 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -17,6 +17,7 @@
#include "nvim/fold.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/move.h"
@@ -966,10 +967,10 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
int extra_len = 0; // length of p_extra string
int lead_len; // length of comment leader
int comment_start = 0; // start index of the comment leader
- char_u *lead_flags; // position in 'comments' for comment leader
- char_u *leader = NULL; // copy of comment leader
+ char *lead_flags; // position in 'comments' for comment leader
+ char *leader = NULL; // copy of comment leader
char_u *allocated = NULL; // allocated memory
- char_u *p;
+ char *p;
char_u saved_char = NUL; // init for GCC
pos_T *pos;
bool do_si = may_do_si();
@@ -1007,9 +1008,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// autoindent etc) a bit later.
replace_push(NUL); // Call twice because BS over NL expects it
replace_push(NUL);
- p = saved_line + curwin->w_cursor.col;
+ p = (char *)saved_line + curwin->w_cursor.col;
while (*p != NUL) {
- p += replace_push_mb(p);
+ p += replace_push_mb((char_u *)p);
}
saved_line[curwin->w_cursor.col] = NUL;
}
@@ -1017,8 +1018,8 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if ((State & MODE_INSERT) && (State & VREPLACE_FLAG) == 0) {
p_extra = saved_line + curwin->w_cursor.col;
if (do_si) { // need first char after new line break
- p = (char_u *)skipwhite((char *)p_extra);
- first_char = *p;
+ p = skipwhite((char *)p_extra);
+ first_char = (unsigned char)(*p);
}
extra_len = (int)STRLEN(p_extra);
saved_char = *p_extra;
@@ -1054,12 +1055,12 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// "if (condition) {"
if (!trunc_line && do_si && *saved_line != NUL
&& (p_extra == NULL || first_char != '{')) {
- char_u *ptr;
+ char *ptr;
old_cursor = curwin->w_cursor;
- ptr = saved_line;
+ ptr = (char *)saved_line;
if (flags & OPENLINE_DO_COM) {
- lead_len = get_leader_len((char *)ptr, NULL, false, true);
+ lead_len = get_leader_len(ptr, NULL, false, true);
} else {
lead_len = 0;
}
@@ -1067,12 +1068,12 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Skip preprocessor directives, unless they are recognised as comments.
if (lead_len == 0 && ptr[0] == '#') {
while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) {
- ptr = ml_get(--curwin->w_cursor.lnum);
+ ptr = (char *)ml_get(--curwin->w_cursor.lnum);
}
newindent = get_indent();
}
if (flags & OPENLINE_DO_COM) {
- lead_len = get_leader_len((char *)ptr, NULL, false, true);
+ lead_len = get_leader_len(ptr, NULL, false, true);
} else {
lead_len = 0;
}
@@ -1083,7 +1084,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// */
// #define IN_THE_WAY
// This should line up here;
- p = (char_u *)skipwhite((char *)ptr);
+ p = skipwhite(ptr);
if (p[0] == '/' && p[1] == '*') {
p++;
}
@@ -1107,7 +1108,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
while (p > ptr && ascii_iswhite(*p)) {
p--;
}
- char_u last_char = *p;
+ char last_char = *p;
// find the character just before the '{' or ';'
if (last_char == '{' || last_char == ';') {
@@ -1129,7 +1130,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if ((pos = findmatch(NULL, '(')) != NULL) {
curwin->w_cursor.lnum = pos->lnum;
newindent = get_indent();
- ptr = get_cursor_line_ptr();
+ ptr = (char *)get_cursor_line_ptr();
}
}
// If last character is '{' do indent, without
@@ -1141,7 +1142,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Don't do this if the previous line ended in ';' or
// '}'.
} else if (last_char != ';' && last_char != '}'
- && cin_is_cinword(ptr)) {
+ && cin_is_cinword((char_u *)ptr)) {
did_si = true;
}
}
@@ -1158,7 +1159,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
} else {
was_backslashed = false;
}
- ptr = ml_get(++curwin->w_cursor.lnum);
+ ptr = (char *)ml_get(++curwin->w_cursor.lnum);
}
if (was_backslashed) {
newindent = 0; // Got to end of file
@@ -1166,7 +1167,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
newindent = get_indent();
}
}
- p = (char_u *)skipwhite((char *)ptr);
+ p = skipwhite(ptr);
if (*p == '}') { // if line starts with '}': do indent
did_si = true;
} else { // can delete indent when '{' typed
@@ -1191,14 +1192,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// This may then be inserted in front of the new line.
end_comment_pending = NUL;
if (flags & OPENLINE_DO_COM) {
- lead_len = get_leader_len((char *)saved_line, (char **)&lead_flags, dir == BACKWARD, true);
+ lead_len = get_leader_len((char *)saved_line, &lead_flags, dir == BACKWARD, true);
if (lead_len == 0 && curbuf->b_p_cin && do_cindent && dir == FORWARD
&& (!has_format_option(FO_NO_OPEN_COMS) || (flags & OPENLINE_FORMAT))) {
// Check for a line comment after code.
comment_start = check_linecomment(saved_line);
if (comment_start != MAXCOL) {
- lead_len = get_leader_len((char *)saved_line + comment_start,
- (char **)&lead_flags, false, true);
+ lead_len = get_leader_len((char *)saved_line + comment_start, &lead_flags, false, true);
if (lead_len != 0) {
lead_len += comment_start;
if (did_do_comment != NULL) {
@@ -1211,11 +1211,11 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
lead_len = 0;
}
if (lead_len > 0) {
- char_u *lead_repl = NULL; // replaces comment leader
+ char *lead_repl = NULL; // replaces comment leader
int lead_repl_len = 0; // length of *lead_repl
char_u lead_middle[COM_MAX_LEN]; // middle-comment string
char_u lead_end[COM_MAX_LEN]; // end-comment string
- char_u *comment_end = NULL; // where lead_end has been found
+ char_u *comment_end = NULL; // where lead_end has been found
int extra_space = false; // append extra space
int current_flag;
int require_blank = false; // requires blank after middle
@@ -1229,7 +1229,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
continue;
}
if (*p == COM_START || *p == COM_MIDDLE) {
- current_flag = *p;
+ current_flag = (unsigned char)(*p);
if (*p == COM_START) {
// Doing "O" on a start of comment does not insert leader.
if (dir == BACKWARD) {
@@ -1238,7 +1238,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// find start of middle part
- (void)copy_option_part((char **)&p, (char *)lead_middle, COM_MAX_LEN, ",");
+ (void)copy_option_part(&p, (char *)lead_middle, COM_MAX_LEN, ",");
require_blank = false;
}
@@ -1249,7 +1249,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
p++;
}
- (void)copy_option_part((char **)&p, (char *)lead_middle, COM_MAX_LEN, ",");
+ (void)copy_option_part(&p, (char *)lead_middle, COM_MAX_LEN, ",");
while (*p && p[-1] != ':') { // find end of end flags
// Check whether we allow automatic ending of comments
@@ -1258,7 +1258,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
p++;
}
- size_t n = copy_option_part((char **)&p, (char *)lead_end, COM_MAX_LEN, ",");
+ size_t n = copy_option_part(&p, (char *)lead_end, COM_MAX_LEN, ",");
if (end_comment_pending == -1) { // we can set it now
end_comment_pending = lead_end[n - 1];
@@ -1267,9 +1267,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// If the end of the comment is in the same line, don't use
// the comment leader.
if (dir == FORWARD) {
- for (p = saved_line + lead_len; *p; p++) {
+ for (p = (char *)saved_line + lead_len; *p; p++) {
if (STRNCMP(p, lead_end, n) == 0) {
- comment_end = p;
+ comment_end = (char_u *)p;
lead_len = 0;
break;
}
@@ -1279,7 +1279,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Doing "o" on a start of comment inserts the middle leader.
if (lead_len > 0) {
if (current_flag == COM_START) {
- lead_repl = lead_middle;
+ lead_repl = (char *)lead_middle;
lead_repl_len = (int)STRLEN(lead_middle);
}
@@ -1309,10 +1309,10 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Doing "O" on the end of a comment inserts the middle leader.
// Find the string for the middle leader, searching backwards.
- while (p > curbuf->b_p_com && *p != ',') {
+ while (p > (char *)curbuf->b_p_com && *p != ',') {
p--;
}
- for (lead_repl = p; lead_repl > curbuf->b_p_com
+ for (lead_repl = p; lead_repl > (char *)curbuf->b_p_com
&& lead_repl[-1] != ':'; lead_repl--) {}
lead_repl_len = (int)(p - lead_repl);
@@ -1321,7 +1321,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
extra_space = true;
// Check whether we allow automatic ending of comments
- for (p2 = p; *p2 && *p2 != ':'; p2++) {
+ for (p2 = (char_u *)p; *p2 && *p2 != ':'; p2++) {
if (*p2 == COM_AUTO_END) {
end_comment_pending = -1; // means we want to set it
}
@@ -1341,7 +1341,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if (dir == BACKWARD) {
lead_len = 0;
} else {
- lead_repl = (char_u *)"";
+ lead_repl = "";
lead_repl_len = 0;
}
break;
@@ -1357,7 +1357,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
+ 1;
assert(bytes >= 0);
leader = xmalloc((size_t)bytes);
- allocated = leader; // remember to free it later
+ allocated = (char_u *)leader; // remember to free it later
STRLCPY(leader, saved_line, lead_len + 1);
@@ -1375,9 +1375,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
for (p = lead_flags; *p != NUL && *p != ':';) {
if (*p == COM_RIGHT || *p == COM_LEFT) {
- c = *p++;
+ c = (unsigned char)(*p++);
} else if (ascii_isdigit(*p) || *p == '-') {
- off = getdigits_int((char **)&p, true, 0);
+ off = getdigits_int(&p, true, 0);
} else {
p++;
}
@@ -1391,15 +1391,14 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Compute the length of the replaced characters in
// screen characters, not bytes.
{
- int repl_size = vim_strnsize(lead_repl,
- lead_repl_len);
+ int repl_size = vim_strnsize((char_u *)lead_repl, lead_repl_len);
int old_size = 0;
- char_u *endp = p;
+ char *endp = p;
int l;
while (old_size < repl_size && p > leader) {
MB_PTR_BACK(leader, p);
- old_size += ptr2cells((char *)p);
+ old_size += ptr2cells(p);
}
l = lead_repl_len - (int)(endp - p);
if (l != 0) {
@@ -1415,11 +1414,11 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// blank-out any other chars from the old leader.
while (--p >= leader) {
- int l = utf_head_off(leader, p);
+ int l = utf_head_off((char_u *)leader, (char_u *)p);
if (l > 1) {
p -= l;
- if (ptr2cells((char *)p) > 1) {
+ if (ptr2cells(p) > 1) {
p[1] = ' ';
l--;
}
@@ -1432,19 +1431,18 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
}
} else { // left adjusted leader
- p = (char_u *)skipwhite((char *)leader);
+ p = skipwhite(leader);
// Compute the length of the replaced characters in
// screen characters, not bytes. Move the part that is
// not to be overwritten.
{
- int repl_size = vim_strnsize(lead_repl,
- lead_repl_len);
+ int repl_size = vim_strnsize((char_u *)lead_repl, lead_repl_len);
int i;
int l;
for (i = 0; i < lead_len && p[i] != NUL; i += l) {
- l = utfc_ptr2len((char *)p + i);
- if (vim_strnsize(p, i + l) > repl_size) {
+ l = utfc_ptr2len(p + i);
+ if (vim_strnsize((char_u *)p, i + l) > repl_size) {
break;
}
}
@@ -1466,10 +1464,10 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
lead_len--;
memmove(p, p + 1, (size_t)(leader + lead_len - p));
} else {
- int l = utfc_ptr2len((char *)p);
+ int l = utfc_ptr2len(p);
if (l > 1) {
- if (ptr2cells((char *)p) > 1) {
+ if (ptr2cells(p) > 1) {
// Replace a double-wide char with
// two spaces
l--;
@@ -1487,7 +1485,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Recompute the indent, it may have changed.
if (curbuf->b_p_ai || do_si) {
- newindent = get_indent_str_vtab(leader,
+ newindent = get_indent_str_vtab((char_u *)leader,
curbuf->b_p_ts,
curbuf->b_p_vts_array, false);
}
@@ -1505,7 +1503,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
while (off > 0 && lead_len > 0
&& leader[lead_len - 1] == ' ') {
// Don't do it when there is a tab before the space
- if (vim_strchr(skipwhite((char *)leader), '\t') != NULL) {
+ if (vim_strchr(skipwhite(leader), '\t') != NULL) {
break;
}
lead_len--;
@@ -1604,7 +1602,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
}
STRCAT(leader, p_extra);
- p_extra = leader;
+ p_extra = (char_u *)leader;
did_ai = true; // So truncating blanks works with comments
less_cols -= lead_len;
} else {
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 028dd70eb2..a26a7f6aaf 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1351,10 +1351,10 @@ bool try_getdigits(char **pp, intmax_t *nr)
/// @param def Default value, if parsing fails or overflow occurs.
///
/// @return Number read from the string, or `def` on parse failure or overflow.
-intmax_t getdigits(char_u **pp, bool strict, intmax_t def)
+intmax_t getdigits(char **pp, bool strict, intmax_t def)
{
intmax_t number;
- int ok = try_getdigits((char **)pp, &number);
+ int ok = try_getdigits(pp, &number);
if (strict && !ok) {
abort();
}
@@ -1366,7 +1366,7 @@ intmax_t getdigits(char_u **pp, bool strict, intmax_t def)
/// @see getdigits
int getdigits_int(char **pp, bool strict, int def)
{
- intmax_t number = getdigits((char_u **)pp, strict, def);
+ intmax_t number = getdigits(pp, strict, def);
#if SIZEOF_INTMAX_T > SIZEOF_INT
if (strict) {
assert(number >= INT_MIN && number <= INT_MAX);
@@ -1380,7 +1380,7 @@ int getdigits_int(char **pp, bool strict, int def)
/// Gets a long number from a string.
///
/// @see getdigits
-long getdigits_long(char_u **pp, bool strict, long def)
+long getdigits_long(char **pp, bool strict, long def)
{
intmax_t number = getdigits(pp, strict, def);
#if SIZEOF_INTMAX_T > SIZEOF_LONG
@@ -1398,7 +1398,7 @@ long getdigits_long(char_u **pp, bool strict, long def)
/// @see getdigits
int32_t getdigits_int32(char **pp, bool strict, long def)
{
- intmax_t number = getdigits((char_u **)pp, strict, def);
+ intmax_t number = getdigits(pp, strict, def);
#if SIZEOF_INTMAX_T > SIZEOF_INT32_T
if (strict) {
assert(number >= INT32_MIN && number <= INT32_MAX);
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index 62cf60e03b..9c33b1a806 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -43,7 +43,7 @@ cursorentry_T shape_table[SHAPE_IDX_COUNT] =
};
/// Converts cursor_shapes into an Array of Dictionaries
-/// @param arena initialized arena where memory will be alocated
+/// @param arena initialized arena where memory will be allocated
///
/// @return Array of the form {[ "cursor_shape": ... ], ...}
Array mode_style_array(Arena *arena)
diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c
index 0f6a260247..04d875c4e3 100644
--- a/src/nvim/decoration_provider.c
+++ b/src/nvim/decoration_provider.c
@@ -63,9 +63,9 @@ void decor_providers_start(DecorProviders *providers, int type, char **err)
bool active;
if (p->redraw_start != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 2);
- args.items[0] = INTEGER_OBJ((int)display_tick);
- args.items[1] = INTEGER_OBJ(type);
+ MAXSIZE_TEMP_ARRAY(args, 2);
+ ADD_C(args, INTEGER_OBJ((int)display_tick));
+ ADD_C(args, INTEGER_OBJ(type));
active = decor_provider_invoke(p->ns_id, "start", p->redraw_start, args, true, err);
} else {
active = true;
@@ -96,12 +96,12 @@ void decor_providers_invoke_win(win_T *wp, DecorProviders *providers,
for (size_t k = 0; k < kv_size(*providers); k++) {
DecorProvider *p = kv_A(*providers, k);
if (p && p->redraw_win != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 4);
- args.items[0] = WINDOW_OBJ(wp->handle);
- args.items[1] = BUFFER_OBJ(wp->w_buffer->handle);
+ MAXSIZE_TEMP_ARRAY(args, 4);
+ ADD_C(args, WINDOW_OBJ(wp->handle));
+ ADD_C(args, BUFFER_OBJ(wp->w_buffer->handle));
// TODO(bfredl): we are not using this, but should be first drawn line?
- args.items[2] = INTEGER_OBJ(wp->w_topline - 1);
- args.items[3] = INTEGER_OBJ(knownmax);
+ ADD_C(args, INTEGER_OBJ(wp->w_topline - 1));
+ ADD_C(args, INTEGER_OBJ(knownmax));
if (decor_provider_invoke(p->ns_id, "win", p->redraw_win, args, true, err)) {
kvi_push(*line_providers, p);
}
@@ -124,10 +124,10 @@ void providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *
for (size_t k = 0; k < kv_size(*providers); k++) {
DecorProvider *p = kv_A(*providers, k);
if (p && p->redraw_line != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 3);
- args.items[0] = WINDOW_OBJ(wp->handle);
- args.items[1] = BUFFER_OBJ(wp->w_buffer->handle);
- args.items[2] = INTEGER_OBJ(row);
+ MAXSIZE_TEMP_ARRAY(args, 3);
+ ADD_C(args, WINDOW_OBJ(wp->handle));
+ ADD_C(args, BUFFER_OBJ(wp->w_buffer->handle));
+ ADD_C(args, INTEGER_OBJ(row));
if (decor_provider_invoke(p->ns_id, "line", p->redraw_line, args, true, err)) {
*has_decor = true;
} else {
@@ -150,8 +150,8 @@ void decor_providers_invoke_buf(buf_T *buf, DecorProviders *providers, char **er
for (size_t i = 0; i < kv_size(*providers); i++) {
DecorProvider *p = kv_A(*providers, i);
if (p && p->redraw_buf != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 1);
- args.items[0] = BUFFER_OBJ(buf->handle);
+ MAXSIZE_TEMP_ARRAY(args, 1);
+ ADD_C(args, BUFFER_OBJ(buf->handle));
decor_provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true, err);
}
}
@@ -167,8 +167,8 @@ void decor_providers_invoke_end(DecorProviders *providers, char **err)
for (size_t i = 0; i < kv_size(*providers); i++) {
DecorProvider *p = kv_A(*providers, i);
if (p && p->active && p->redraw_end != LUA_NOREF) {
- FIXED_TEMP_ARRAY(args, 1);
- args.items[0] = INTEGER_OBJ((int)display_tick);
+ MAXSIZE_TEMP_ARRAY(args, 1);
+ ADD_C(args, INTEGER_OBJ((int)display_tick));
decor_provider_invoke(p->ns_id, "end", p->redraw_end, args, true, err);
}
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 75021e90d6..849204f789 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -115,7 +115,10 @@ void diff_buf_delete(buf_T *buf)
tp->tp_diff_invalid = true;
if (tp == curtab) {
- diff_redraw(true);
+ // don't redraw right away, more might change or buffer state
+ // is invalid right now
+ need_diff_redraw = true;
+ redraw_later(curwin, VALID);
}
}
}
@@ -369,9 +372,8 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
// 2. 3. 4. 5.: inserted/deleted lines touching this diff.
if (deleted > 0) {
+ off = 0;
if (dp->df_lnum[idx] >= line1) {
- off = dp->df_lnum[idx] - lnum_deleted;
-
if (last <= line2) {
// 4. delete all lines of diff
if ((dp->df_next != NULL)
@@ -388,14 +390,13 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
dp->df_count[idx] = 0;
} else {
// 5. delete lines at or just before top of diff
+ off = dp->df_lnum[idx] - lnum_deleted;
n = off;
dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1;
check_unchanged = true;
}
dp->df_lnum[idx] = line1;
} else {
- off = 0;
-
if (last < line2) {
// 2. delete at end of diff
dp->df_count[idx] -= last - lnum_deleted + 1;
@@ -418,10 +419,13 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
}
}
- int i;
- for (i = 0; i < DB_COUNT; i++) {
+ for (int i = 0; i < DB_COUNT; i++) {
if ((tp->tp_diffbuf[i] != NULL) && (i != idx)) {
- dp->df_lnum[i] -= off;
+ if (dp->df_lnum[i] > off) {
+ dp->df_lnum[i] -= off;
+ } else {
+ dp->df_lnum[i] = 1;
+ }
dp->df_count[i] += n;
}
}
@@ -648,9 +652,11 @@ void diff_redraw(bool dofold)
need_diff_redraw = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (!wp->w_p_diff) {
+ // when closing windows or wiping buffers skip invalid window
+ if (!wp->w_p_diff || !buf_valid(wp->w_buffer)) {
continue;
}
+
redraw_later(wp, SOME_VALID);
if (wp != curwin) {
wp_other = wp;
@@ -659,8 +665,8 @@ void diff_redraw(bool dofold)
foldUpdateAll(wp);
}
- // A change may have made filler lines invalid, need to take care
- // of that for other windows.
+ // A change may have made filler lines invalid, need to take care of
+ // that for other windows.
int n = diff_check(wp, wp->w_topline);
if (((wp != curwin) && (wp->w_topfill > 0)) || (n > 0)) {
@@ -677,6 +683,7 @@ void diff_redraw(bool dofold)
check_topfill(wp, false);
}
}
+
if (wp_other != NULL && curwin->w_p_scb) {
if (used_max_fill_curwin) {
// The current window was set to use the maximum number of filler
@@ -1421,7 +1428,7 @@ void diff_win_options(win_T *wp, int addbuf)
}
wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc);
}
- xfree(wp->w_p_fdc);
+ free_string_option(wp->w_p_fdc);
wp->w_p_fdc = (char_u *)xstrdup("2");
assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9);
snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn);
@@ -2485,6 +2492,17 @@ void nv_diffgetput(bool put, size_t count)
ex_diffgetput(&ea);
}
+/// Return true if "diff" appears in the list of diff blocks of the current tab.
+static bool valid_diff(diff_T *diff)
+{
+ for (diff_T *dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) {
+ if (dp == diff) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// ":diffget" and ":diffput"
///
/// @param eap
@@ -2694,8 +2712,9 @@ void ex_diffgetput(exarg_T *eap)
for (i = 0; i < count; i++) {
// remember deleting the last line of the buffer
buf_empty = curbuf->b_ml.ml_line_count == 1;
- ml_delete(lnum, false);
- added--;
+ if (ml_delete(lnum, false) == OK) {
+ added--;
+ }
}
for (i = 0; i < dp->df_count[idx_from] - start_skip - end_skip; i++) {
@@ -2742,10 +2761,9 @@ void ex_diffgetput(exarg_T *eap)
}
}
- // Adjust marks. This will change the following entries!
if (added != 0) {
- mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added,
- kExtmarkUndo);
+ // Adjust marks. This will change the following entries!
+ mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added, kExtmarkUndo);
if (curwin->w_cursor.lnum >= lnum) {
// Adjust the cursor position if it's in/after the changed
// lines.
@@ -2762,7 +2780,15 @@ void ex_diffgetput(exarg_T *eap)
// Diff is deleted, update folds in other windows.
diff_fold_update(dfree, idx_to);
xfree(dfree);
- } else {
+ }
+
+ // mark_adjust() may have made "dp" invalid. We don't know where
+ // to continue then, bail out.
+ if (added != 0 && !valid_diff(dp)) {
+ break;
+ }
+
+ if (dfree == NULL) {
// mark_adjust() may have changed the count in a wrong way
dp->df_count[idx_to] = new_count;
}
@@ -3042,8 +3068,8 @@ static int parse_diff_ed(char_u *line, diffhunk_T *hunk)
// change: {first}[,{last}]c{first}[,{last}]
// append: {first}a{first}[,{last}]
// delete: {first}[,{last}]d{first}
- char_u *p = line;
- linenr_T f1 = getdigits_int32((char **)&p, true, 0);
+ char *p = (char *)line;
+ linenr_T f1 = getdigits_int32(&p, true, 0);
if (*p == ',') {
p++;
l1 = getdigits(&p, true, 0);
@@ -3053,7 +3079,7 @@ static int parse_diff_ed(char_u *line, diffhunk_T *hunk)
if (*p != 'a' && *p != 'c' && *p != 'd') {
return FAIL; // invalid diff format
}
- int difftype = *p++;
+ int difftype = (uint8_t)(*p++);
long f2 = getdigits(&p, true, 0);
if (*p == ',') {
p++;
@@ -3090,7 +3116,7 @@ static int parse_diff_unified(char_u *line, diffhunk_T *hunk)
{
// Parse unified diff hunk header:
// @@ -oldline,oldcount +newline,newcount @@
- char_u *p = line;
+ char *p = (char *)line;
if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') {
long oldcount;
long newline;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 355900c93f..733b3d3d5d 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1662,28 +1662,28 @@ bool check_digraph_chars_valid(int char1, int char2)
/// format: {c1}{c2} char {c1}{c2} char ...
///
/// @param str
-void putdigraph(char_u *str)
+void putdigraph(char *str)
{
while (*str != NUL) {
- str = (char_u *)skipwhite((char *)str);
+ str = skipwhite(str);
if (*str == NUL) {
return;
}
- char_u char1 = *str++;
- char_u char2 = *str++;
+ uint8_t char1 = (uint8_t)(*str++);
+ uint8_t char2 = (uint8_t)(*str++);
if (!check_digraph_chars_valid(char1, char2)) {
return;
}
- str = (char_u *)skipwhite((char *)str);
+ str = skipwhite(str);
if (!ascii_isdigit(*str)) {
emsg(_(e_number_exp));
return;
}
- int n = getdigits_int((char **)&str, true, 0);
+ int n = getdigits_int(&str, true, 0);
registerdigraph(char1, char2, n);
}
@@ -2121,7 +2121,7 @@ void ex_loadkeymap(exarg_T *eap)
vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s",
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from,
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to);
- (void)do_map(0, buf, MODE_LANGMAP, false);
+ (void)do_map(MAPTYPE_MAP, buf, MODE_LANGMAP, false);
}
p_cpo = save_cpo;
@@ -2158,7 +2158,7 @@ static void keymap_unload(void)
for (int i = 0; i < curbuf->b_kmap_ga.ga_len; i++) {
vim_snprintf(buf, sizeof(buf), "<buffer> %s", kp[i].from);
- (void)do_map(1, (char_u *)buf, MODE_LANGMAP, false);
+ (void)do_map(MAPTYPE_UNMAP, (char_u *)buf, MODE_LANGMAP, false);
}
keymap_ga_clear(&curbuf->b_kmap_ga);
diff --git a/src/nvim/digraph.h b/src/nvim/digraph.h
index 039fc3370d..71330ae9b1 100644
--- a/src/nvim/digraph.h
+++ b/src/nvim/digraph.h
@@ -1,7 +1,6 @@
#ifndef NVIM_DIGRAPH_H
#define NVIM_DIGRAPH_H
-#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/types.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 0571e71cb5..5861e4c52b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -18,7 +18,6 @@
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
-#include "nvim/eval/typval.h"
#include "nvim/event/loop.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -29,6 +28,7 @@
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/main.h"
#include "nvim/mapping.h"
@@ -48,180 +48,18 @@
#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
-#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/tag.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
#include "nvim/window.h"
-// Definitions used for CTRL-X submode.
-// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
-// and ctrl_x_mode_names[].
-
-#define CTRL_X_WANT_IDENT 0x100
-
-#define CTRL_X_NORMAL 0 ///< CTRL-N CTRL-P completion, default
-#define CTRL_X_NOT_DEFINED_YET 1
-#define CTRL_X_SCROLL 2
-#define CTRL_X_WHOLE_LINE 3
-#define CTRL_X_FILES 4
-#define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
-#define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
-#define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
-#define CTRL_X_FINISHED 8
-#define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
-#define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
-#define CTRL_X_CMDLINE 11
-#define CTRL_X_FUNCTION 12
-#define CTRL_X_OMNI 13
-#define CTRL_X_SPELL 14
-#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
-#define CTRL_X_EVAL 16 ///< for builtin function complete()
-#define CTRL_X_CMDLINE_CTRL_X 17 ///< CTRL-X typed in CTRL_X_CMDLINE
-
-#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
-#define CTRL_X_MODE_LINE_OR_EVAL(m) \
- ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
-
-// Message for CTRL-X mode, index is ctrl_x_mode.
-static char *ctrl_x_msgs[] =
-{
- N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
- N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
- NULL, // CTRL_X_SCROLL: depends on state
- N_(" Whole line completion (^L^N^P)"),
- N_(" File name completion (^F^N^P)"),
- N_(" Tag completion (^]^N^P)"),
- N_(" Path pattern completion (^N^P)"),
- N_(" Definition completion (^D^N^P)"),
- NULL, // CTRL_X_FINISHED
- N_(" Dictionary completion (^K^N^P)"),
- N_(" Thesaurus completion (^T^N^P)"),
- N_(" Command-line completion (^V^N^P)"),
- N_(" User defined completion (^U^N^P)"),
- N_(" Omni completion (^O^N^P)"),
- N_(" Spelling suggestion (s^N^P)"),
- N_(" Keyword Local completion (^N^P)"),
- NULL, // CTRL_X_EVAL doesn't use msg.
- N_(" Command-line completion (^V^N^P)"),
-};
-
-static char *ctrl_x_mode_names[] = {
- "keyword",
- "ctrl_x",
- "scroll",
- "whole_line",
- "files",
- "tags",
- "path_patterns",
- "path_defines",
- "unknown", // CTRL_X_FINISHED
- "dictionary",
- "thesaurus",
- "cmdline",
- "function",
- "omni",
- "spell",
- NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
- "eval",
- "cmdline",
-};
-
-static char e_hitend[] = N_("Hit end of paragraph");
-static char e_compldel[] = N_("E840: Completion function deleted text");
-
-/*
- * Structure used to store one match for insert completion.
- */
-typedef struct compl_S compl_T;
-struct compl_S {
- compl_T *cp_next;
- compl_T *cp_prev;
- char_u *cp_str; // matched text
- char_u *(cp_text[CPT_COUNT]); // text for the menu
- typval_T cp_user_data;
- char_u *cp_fname; // file containing the match, allocated when
- // cp_flags has CP_FREE_FNAME
- int cp_flags; // CP_ values
- int cp_number; // sequence number
-};
-
-/*
- * All the current matches are stored in a list.
- * "compl_first_match" points to the start of the list.
- * "compl_curr_match" points to the currently selected entry.
- * "compl_shown_match" is different from compl_curr_match during
- * ins_compl_get_exp().
- */
-static compl_T *compl_first_match = NULL;
-static compl_T *compl_curr_match = NULL;
-static compl_T *compl_shown_match = NULL;
-static compl_T *compl_old_match = NULL;
-
-/* After using a cursor key <Enter> selects a match in the popup menu,
- * otherwise it inserts a line break. */
-static int compl_enter_selects = FALSE;
-
-/* When "compl_leader" is not NULL only matches that start with this string
- * are used. */
-static char_u *compl_leader = NULL;
-
-static bool compl_get_longest = false; // put longest common string in compl_leader
-
-static int compl_no_insert = FALSE; /* FALSE: select & insert
- TRUE: noinsert */
-static int compl_no_select = FALSE; /* FALSE: select & insert
- TRUE: noselect */
-
-static bool compl_used_match; // Selected one of the matches.
- // When false the match was edited or using
- // the longest common string.
-
-static int compl_was_interrupted = FALSE; /* didn't finish finding
- completions. */
-
-static bool compl_restarting = false; // don't insert match
-
-// When the first completion is done "compl_started" is set. When it's
-// false the word to be completed must be located.
-static bool compl_started = false;
-
-// Which Ctrl-X mode are we in?
-static int ctrl_x_mode = CTRL_X_NORMAL;
-
-static int compl_matches = 0;
-static char_u *compl_pattern = NULL;
-static Direction compl_direction = FORWARD;
-static Direction compl_shows_dir = FORWARD;
-static int compl_pending = 0; // > 1 for postponed CTRL-N
-static pos_T compl_startpos;
-static colnr_T compl_col = 0; /* column where the text starts
- * that is being completed */
-static char_u *compl_orig_text = NULL; /* text as it was before
- * completion started */
-static int compl_cont_mode = 0;
-static expand_T compl_xp;
-
-static bool compl_opt_refresh_always = false;
-
-static int pum_selected_item = -1;
-
-/// state for pum_ext_select_item.
-struct {
- bool active;
- int item;
- bool insert;
- bool finish;
-} pum_want;
-
typedef struct insert_state {
VimState state;
cmdarg_T *ca;
@@ -253,8 +91,6 @@ typedef struct insert_state {
#define BACKSPACE_WORD_NOT_SPACE 3
#define BACKSPACE_LINE 4
-static size_t spell_bad_len = 0; // length of located bad word
-
static colnr_T Insstart_textlen; // length of line when insert started
static colnr_T Insstart_blank_vcol; // vcol for first inserted blank
static bool update_Insstart_orig = true; // set Insstart_orig to Insstart
@@ -521,7 +357,7 @@ static int insert_check(VimState *state)
// If typed something may trigger CursorHoldI again.
if (s->c != K_EVENT
// but not in CTRL-X mode, a script can't restore the state
- && ctrl_x_mode == CTRL_X_NORMAL) {
+ && ctrl_x_mode_normal()) {
did_cursorhold = false;
}
@@ -532,8 +368,8 @@ static int insert_check(VimState *state)
if (can_cindent
&& cindent_on()
- && ctrl_x_mode == CTRL_X_NORMAL
- && !compl_started) {
+ && ctrl_x_mode_normal()
+ && !ins_compl_active()) {
insert_do_cindent(s);
}
@@ -551,7 +387,7 @@ static int insert_check(VimState *state)
Insstart_orig = Insstart;
}
- if (stop_insert_mode && !compl_started) {
+ if (stop_insert_mode && !ins_compl_active()) {
// ":stopinsert" used
s->count = 0;
return 0; // exit insert mode
@@ -688,29 +524,25 @@ static int insert_execute(VimState *state, int key)
// Special handling of keys while the popup menu is visible or wanted
// and the cursor is still in the completed word. Only when there is
// a match, skip this when no matches were found.
- if (compl_started
+ if (ins_compl_active()
&& pum_wanted()
- && curwin->w_cursor.col >= compl_col
- && (compl_shown_match == NULL
- || compl_shown_match != compl_shown_match->cp_next)) {
+ && curwin->w_cursor.col >= ins_compl_col()
+ && ins_compl_has_shown_match()) {
// BS: Delete one character from "compl_leader".
if ((s->c == K_BS || s->c == Ctrl_H)
- && curwin->w_cursor.col > compl_col
+ && curwin->w_cursor.col > ins_compl_col()
&& (s->c = ins_compl_bs()) == NUL) {
return 1; // continue
}
// When no match was selected or it was edited.
- if (!compl_used_match) {
+ if (!ins_compl_used_match()) {
// CTRL-L: Add one character from the current match to
// "compl_leader". Except when at the original match and
// there is nothing to add, CTRL-L works like CTRL-P then.
if (s->c == Ctrl_L
- && (!CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
- || (compl_shown_match != NULL
- && compl_shown_match->cp_str != NULL
- && (int)STRLEN(compl_shown_match->cp_str)
- > curwin->w_cursor.col - compl_col))) {
+ && (!ctrl_x_mode_line_or_eval()
+ || ins_compl_long_shown_match())) {
ins_compl_addfrommatch();
return 1; // continue
}
@@ -736,7 +568,7 @@ static int insert_execute(VimState *state, int key)
// Pressing CTRL-Y selects the current match. When
// compl_enter_selects is set the Enter key does the same.
if ((s->c == Ctrl_Y
- || (compl_enter_selects
+ || (ins_compl_enter_selects()
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
&& stop_arrow() == OK) {
ins_compl_delete();
@@ -747,7 +579,7 @@ static int insert_execute(VimState *state, int key)
// Prepare for or stop CTRL-X mode. This doesn't do completion, but it does
// fix up the text when finishing completion.
- compl_get_longest = false;
+ ins_compl_init_get_longest();
if (ins_compl_prep(s->c)) {
return 1; // continue
}
@@ -779,8 +611,7 @@ static int insert_execute(VimState *state, int key)
s->c = do_digraph(s->c);
- if ((s->c == Ctrl_V || s->c == Ctrl_Q)
- && (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X)) {
+ if ((s->c == Ctrl_V || s->c == Ctrl_Q) && ctrl_x_mode_cmdline()) {
insert_do_complete(s);
return 1;
}
@@ -791,8 +622,7 @@ static int insert_execute(VimState *state, int key)
return 1; // continue
}
- if (cindent_on()
- && ctrl_x_mode == 0) {
+ if (cindent_on() && ctrl_x_mode_none()) {
// A key name preceded by a bang means this key is not to be
// inserted. Skip ahead to the re-indenting below.
// A key name preceded by a star means that indenting has to be
@@ -873,7 +703,7 @@ static int insert_handle_key(InsertState *s)
goto normalchar; // insert CTRL-Z as normal char
case Ctrl_O: // execute one command
- if (ctrl_x_mode == CTRL_X_OMNI) {
+ if (ctrl_x_mode_omni()) {
insert_do_complete(s);
break;
}
@@ -946,14 +776,14 @@ static int insert_handle_key(InsertState *s)
break;
case Ctrl_D: // Make indent one shiftwidth smaller.
- if (ctrl_x_mode == CTRL_X_PATH_DEFINES) {
+ if (ctrl_x_mode_path_defines()) {
insert_do_complete(s);
break;
}
FALLTHROUGH;
case Ctrl_T: // Make indent one shiftwidth greater.
- if (s->c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS) {
+ if (s->c == Ctrl_T && ctrl_x_mode_thesaurus()) {
if (check_compl_option(false)) {
insert_do_complete(s);
}
@@ -992,7 +822,7 @@ static int insert_handle_key(InsertState *s)
case Ctrl_U: // delete all inserted text in current line
// CTRL-X CTRL-U completes with 'completefunc'.
- if (ctrl_x_mode == CTRL_X_FUNCTION) {
+ if (ctrl_x_mode_function()) {
insert_do_complete(s);
} else {
s->did_backspace = ins_bs(s->c, BACKSPACE_LINE, &s->inserted_space);
@@ -1157,7 +987,7 @@ check_pum:
FALLTHROUGH;
case TAB: // TAB or Complete patterns along path
- if (ctrl_x_mode == CTRL_X_PATH_PATTERNS) {
+ if (ctrl_x_mode_path_patterns()) {
insert_do_complete(s);
break;
}
@@ -1205,7 +1035,7 @@ check_pum:
break;
case Ctrl_K: // digraph or keyword completion
- if (ctrl_x_mode == CTRL_X_DICTIONARY) {
+ if (ctrl_x_mode_dictionary()) {
if (check_compl_option(true)) {
insert_do_complete(s);
}
@@ -1223,7 +1053,7 @@ check_pum:
break;
case Ctrl_RSB: // Tag name completion after ^X
- if (ctrl_x_mode != CTRL_X_TAGS) {
+ if (!ctrl_x_mode_tags()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1231,7 +1061,7 @@ check_pum:
break;
case Ctrl_F: // File name completion after ^X
- if (ctrl_x_mode != CTRL_X_FILES) {
+ if (!ctrl_x_mode_files()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1240,7 +1070,7 @@ check_pum:
case 's': // Spelling completion after ^X
case Ctrl_S:
- if (ctrl_x_mode != CTRL_X_SPELL) {
+ if (!ctrl_x_mode_spell()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1248,7 +1078,7 @@ check_pum:
break;
case Ctrl_L: // Whole line completion after ^X
- if (ctrl_x_mode != CTRL_X_WHOLE_LINE) {
+ if (!ctrl_x_mode_whole_line()) {
goto normalchar;
}
FALLTHROUGH;
@@ -1258,8 +1088,7 @@ check_pum:
// if 'complete' is empty then plain ^P is no longer special,
// but it is under other ^X modes
if (*curbuf->b_p_cpt == NUL
- && (ctrl_x_mode == CTRL_X_NORMAL
- || ctrl_x_mode == CTRL_X_WHOLE_LINE)
+ && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line())
&& !(compl_cont_status & CONT_LOCAL)) {
goto normalchar;
}
@@ -1394,10 +1223,10 @@ bool edit(int cmdchar, bool startln, long count)
// the value of `restart_edit` before `ex_normal` returns.
restart_edit = 'i';
force_restart_edit = true;
+ return false;
} else {
- terminal_enter();
+ return terminal_enter();
}
- return false;
}
// Don't allow inserting in the sandbox.
@@ -1409,7 +1238,7 @@ bool edit(int cmdchar, bool startln, long count)
// Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused.
// Don't allow recursive insert mode when busy with completion.
- if (textlock != 0 || compl_started || compl_busy || pum_visible()) {
+ if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) {
emsg(_(e_textlock));
return false;
}
@@ -1425,6 +1254,11 @@ bool edit(int cmdchar, bool startln, long count)
return s->c == Ctrl_O;
}
+bool ins_need_undo_get(void)
+{
+ return ins_need_undo;
+}
+
/// Redraw for Insert mode.
/// This is postponed until getting the next character to make '$' in the 'cpo'
/// option work correctly.
@@ -1432,7 +1266,7 @@ bool edit(int cmdchar, bool startln, long count)
/// inserting sequences of characters (e.g., for CTRL-R).
///
/// @param ready not busy with something
-static void ins_redraw(bool ready)
+void ins_redraw(bool ready)
{
if (char_avail()) {
return;
@@ -2019,3523 +1853,6 @@ static bool del_char_after_col(int limit_col)
return true;
}
-/*
- * CTRL-X pressed in Insert mode.
- */
-static void ins_ctrl_x(void)
-{
- if (ctrl_x_mode != CTRL_X_CMDLINE && ctrl_x_mode != CTRL_X_CMDLINE_CTRL_X) {
- // if the next ^X<> won't ADD nothing, then reset compl_cont_status
- if (compl_cont_status & CONT_N_ADDS) {
- compl_cont_status |= CONT_INTRPT;
- } else {
- compl_cont_status = 0;
- }
- // We're not sure which CTRL-X mode it will be yet
- ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
- edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
- edit_submode_pre = NULL;
- showmode();
- } else {
- // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
- // CTRL-V look like CTRL-N
- ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
- }
-
- may_trigger_modechanged();
-}
-
-// Whether other than default completion has been selected.
-bool ctrl_x_mode_not_default(void)
- FUNC_ATTR_PURE
-{
- return ctrl_x_mode != CTRL_X_NORMAL;
-}
-
-// Whether CTRL-X was typed without a following character,
-// not including when in CTRL-X CTRL-V mode.
-bool ctrl_x_mode_not_defined_yet(void)
- FUNC_ATTR_PURE
-{
- return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
-}
-
-/// Check that the "dict" or "tsr" option can be used.
-///
-/// @param dict_opt check "dict" when true, "tsr" when false.
-static bool check_compl_option(bool dict_opt)
-{
- if (dict_opt
- ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
- : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
- && *curbuf->b_p_tsrfu == NUL && *p_tsrfu == NUL)) {
- ctrl_x_mode = CTRL_X_NORMAL;
- edit_submode = NULL;
- msg_attr((dict_opt
- ? _("'dictionary' option is empty")
- : _("'thesaurus' option is empty")), HL_ATTR(HLF_E));
- if (emsg_silent == 0) {
- vim_beep(BO_COMPL);
- setcursor();
- ui_flush();
- os_delay(2004L, false);
- }
- return false;
- }
- return true;
-}
-
-/// Check that the character "c" a valid key to go to or keep us in CTRL-X mode?
-/// This depends on the current mode.
-///
-/// @param c character to check
-bool vim_is_ctrl_x_key(int c)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- // Always allow ^R - let its results then be checked
- if (c == Ctrl_R) {
- return true;
- }
-
- // Accept <PageUp> and <PageDown> if the popup menu is visible.
- if (ins_compl_pum_key(c)) {
- return true;
- }
-
- switch (ctrl_x_mode) {
- case 0: // Not in any CTRL-X mode
- return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
- case CTRL_X_NOT_DEFINED_YET:
- case CTRL_X_CMDLINE_CTRL_X:
- return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
- || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
- || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
- || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
- || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
- || c == Ctrl_S || c == Ctrl_K || c == 's'
- || c == Ctrl_Z;
- case CTRL_X_SCROLL:
- return c == Ctrl_Y || c == Ctrl_E;
- case CTRL_X_WHOLE_LINE:
- return c == Ctrl_L || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_FILES:
- return c == Ctrl_F || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_DICTIONARY:
- return c == Ctrl_K || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_THESAURUS:
- return c == Ctrl_T || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_TAGS:
- return c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_PATH_PATTERNS:
- return c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_PATH_DEFINES:
- return c == Ctrl_D || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_CMDLINE:
- return c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
- || c == Ctrl_X;
- case CTRL_X_FUNCTION:
- return c == Ctrl_U || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_OMNI:
- return c == Ctrl_O || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_SPELL:
- return c == Ctrl_S || c == Ctrl_P || c == Ctrl_N;
- case CTRL_X_EVAL:
- return (c == Ctrl_P || c == Ctrl_N);
- }
- internal_error("vim_is_ctrl_x_key()");
- return false;
-}
-
-/// Check that character "c" is part of the item currently being
-/// completed. Used to decide whether to abandon complete mode when the menu
-/// is visible.
-///
-/// @param c character to check
-static bool ins_compl_accept_char(int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (ctrl_x_mode & CTRL_X_WANT_IDENT) {
- // When expanding an identifier only accept identifier chars.
- return vim_isIDc(c);
- }
-
- switch (ctrl_x_mode) {
- case CTRL_X_FILES:
- // When expanding file name only accept file name chars. But not
- // path separators, so that "proto/<Tab>" expands files in
- // "proto", not "proto/" as a whole
- return vim_isfilec(c) && !vim_ispathsep(c);
-
- case CTRL_X_CMDLINE:
- case CTRL_X_CMDLINE_CTRL_X:
- case CTRL_X_OMNI:
- // Command line and Omni completion can work with just about any
- // printable character, but do stop at white space.
- return vim_isprintc(c) && !ascii_iswhite(c);
-
- case CTRL_X_WHOLE_LINE:
- // For while line completion a space can be part of the line.
- return vim_isprintc(c);
- }
- return vim_iswordc(c);
-}
-
-/// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
-/// case of the originally typed text is used, and the case of the completed
-/// text is inferred, ie this tries to work out what case you probably wanted
-/// the rest of the word to be in -- webb
-///
-/// @param[in] cont_s_ipos next ^X<> will set initial_pos
-int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, Direction dir,
- bool cont_s_ipos)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- char_u *str = str_arg;
- int i, c;
- int actual_len; // Take multi-byte characters
- int actual_compl_length; // into account.
- int min_len;
- bool has_lower = false;
- bool was_letter = false;
- int flags = 0;
-
- if (p_ic && curbuf->b_p_inf && len > 0) {
- // Infer case of completed part.
-
- // Find actual length of completion.
- {
- const char_u *p = str;
- actual_len = 0;
- while (*p != NUL) {
- MB_PTR_ADV(p);
- actual_len++;
- }
- }
-
- // Find actual length of original text.
- {
- const char_u *p = compl_orig_text;
- actual_compl_length = 0;
- while (*p != NUL) {
- MB_PTR_ADV(p);
- actual_compl_length++;
- }
- }
-
- /* "actual_len" may be smaller than "actual_compl_length" when using
- * thesaurus, only use the minimum when comparing. */
- min_len = actual_len < actual_compl_length
- ? actual_len : actual_compl_length;
-
- // Allocate wide character array for the completion and fill it.
- int *const wca = xmalloc((size_t)actual_len * sizeof(*wca));
- {
- const char_u *p = str;
- for (i = 0; i < actual_len; i++) {
- wca[i] = mb_ptr2char_adv(&p);
- }
- }
-
- // Rule 1: Were any chars converted to lower?
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (mb_islower(c)) {
- has_lower = true;
- if (mb_isupper(wca[i])) {
- // Rule 1 is satisfied.
- for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = mb_tolower(wca[i]);
- }
- break;
- }
- }
- }
- }
-
- /*
- * Rule 2: No lower case, 2nd consecutive letter converted to
- * upper case.
- */
- if (!has_lower) {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
- // Rule 2 is satisfied.
- for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = mb_toupper(wca[i]);
- }
- break;
- }
- was_letter = mb_islower(c) || mb_isupper(c);
- }
- }
-
- // Copy the original case of the part we typed.
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (mb_islower(c)) {
- wca[i] = mb_tolower(wca[i]);
- } else if (mb_isupper(c)) {
- wca[i] = mb_toupper(wca[i]);
- }
- }
- }
-
- // Generate encoding specific output from wide character array.
- // Multi-byte characters can occupy up to five bytes more than
- // ASCII characters, and we also need one byte for NUL, so stay
- // six bytes away from the edge of IObuff.
- {
- char_u *p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
- p += utf_char2bytes(wca[i++], (char *)p);
- }
- *p = NUL;
- }
-
- xfree(wca);
-
- str = IObuff;
- }
- if (cont_s_ipos) {
- flags |= CP_CONT_S_IPOS;
- }
- if (icase) {
- flags |= CP_ICASE;
- }
-
- return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false);
-}
-
-/// Add a match to the list of matches
-///
-/// @param[in] str Match to add.
-/// @param[in] len Match length, -1 to use #STRLEN.
-/// @param[in] fname File name match comes from. May be NULL.
-/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
-/// must have exactly #CPT_COUNT items.
-/// @param[in] cptext_allocated If true, will not copy cptext strings.
-///
-/// @note Will free strings in case of error.
-/// cptext itself will not be freed.
-/// @param[in] cdir Completion direction.
-/// @param[in] adup True if duplicate matches are to be accepted.
-///
-/// @return NOTDONE if the given string is already in the list of completions,
-/// otherwise it is added to the list and OK is returned. FAIL will be
-/// returned in case of error.
-static int ins_compl_add(char_u *const str, int len, char_u *const fname,
- char_u *const *const cptext, const bool cptext_allocated,
- typval_T *user_data, const Direction cdir, int flags_arg, const bool adup)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- compl_T *match;
- const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
- int flags = flags_arg;
-
- if (flags & CP_FAST) {
- fast_breakcheck();
- } else {
- os_breakcheck();
- }
-#define FREE_CPTEXT(cptext, cptext_allocated) \
- do { \
- if ((cptext) != NULL && (cptext_allocated)) { \
- for (size_t i = 0; i < CPT_COUNT; i++) { \
- xfree((cptext)[i]); \
- } \
- } \
- } while (0)
- if (got_int) {
- FREE_CPTEXT(cptext, cptext_allocated);
- return FAIL;
- }
- if (len < 0) {
- len = (int)STRLEN(str);
- }
-
- /*
- * If the same match is already present, don't add it.
- */
- if (compl_first_match != NULL && !adup) {
- match = compl_first_match;
- do {
- if (!(match->cp_flags & CP_ORIGINAL_TEXT)
- && STRNCMP(match->cp_str, str, len) == 0
- && match->cp_str[len] == NUL) {
- FREE_CPTEXT(cptext, cptext_allocated);
- return NOTDONE;
- }
- match = match->cp_next;
- } while (match != NULL && match != compl_first_match);
- }
-
- // Remove any popup menu before changing the list of matches.
- ins_compl_del_pum();
-
- /*
- * Allocate a new match structure.
- * Copy the values to the new match structure.
- */
- match = xcalloc(1, sizeof(compl_T));
- match->cp_number = -1;
- if (flags & CP_ORIGINAL_TEXT) {
- match->cp_number = 0;
- }
- match->cp_str = vim_strnsave(str, (size_t)len);
-
- // match-fname is:
- // - compl_curr_match->cp_fname if it is a string equal to fname.
- // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem.
- // - NULL otherwise. --Acevedo
- if (fname != NULL
- && compl_curr_match != NULL
- && compl_curr_match->cp_fname != NULL
- && STRCMP(fname, compl_curr_match->cp_fname) == 0) {
- match->cp_fname = compl_curr_match->cp_fname;
- } else if (fname != NULL) {
- match->cp_fname = vim_strsave(fname);
- flags |= CP_FREE_FNAME;
- } else {
- match->cp_fname = NULL;
- }
- match->cp_flags = flags;
-
- if (cptext != NULL) {
- int i;
-
- for (i = 0; i < CPT_COUNT; i++) {
- if (cptext[i] == NULL) {
- continue;
- }
- if (*cptext[i] != NUL) {
- match->cp_text[i] = (cptext_allocated
- ? cptext[i]
- : (char_u *)xstrdup((char *)cptext[i]));
- } else if (cptext_allocated) {
- xfree(cptext[i]);
- }
- }
- }
-
- if (user_data != NULL) {
- match->cp_user_data = *user_data;
- }
-
- /*
- * Link the new match structure in the list of matches.
- */
- if (compl_first_match == NULL) {
- match->cp_next = match->cp_prev = NULL;
- } else if (dir == FORWARD) {
- match->cp_next = compl_curr_match->cp_next;
- match->cp_prev = compl_curr_match;
- } else { // BACKWARD
- match->cp_next = compl_curr_match;
- match->cp_prev = compl_curr_match->cp_prev;
- }
- if (match->cp_next) {
- match->cp_next->cp_prev = match;
- }
- if (match->cp_prev) {
- match->cp_prev->cp_next = match;
- } else { // if there's nothing before, it is the first match
- compl_first_match = match;
- }
- compl_curr_match = match;
-
- /*
- * Find the longest common string if still doing that.
- */
- if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0) {
- ins_compl_longest_match(match);
- }
-
- return OK;
-}
-
-/// Check that "str[len]" matches with "match->cp_str", considering
-/// "match->cp_flags".
-///
-/// @param match completion match
-/// @param str character string to check
-/// @param len length of "str"
-static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
-{
- if (match->cp_flags & CP_EQUAL) {
- return true;
- }
- if (match->cp_flags & CP_ICASE) {
- return STRNICMP(match->cp_str, str, len) == 0;
- }
- return STRNCMP(match->cp_str, str, len) == 0;
-}
-
-/*
- * Reduce the longest common string for match "match".
- */
-static void ins_compl_longest_match(compl_T *match)
-{
- char_u *p, *s;
- int c1, c2;
- int had_match;
-
- if (compl_leader == NULL) {
- // First match, use it as a whole.
- compl_leader = vim_strsave(match->cp_str);
- had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + ins_compl_len());
- ins_redraw(FALSE);
-
- /* When the match isn't there (to avoid matching itself) remove it
- * again after redrawing. */
- if (!had_match) {
- ins_compl_delete();
- }
- compl_used_match = false;
- } else {
- // Reduce the text if this match differs from compl_leader.
- p = compl_leader;
- s = match->cp_str;
- while (*p != NUL) {
- c1 = utf_ptr2char((char *)p);
- c2 = utf_ptr2char((char *)s);
-
- if ((match->cp_flags & CP_ICASE)
- ? (mb_tolower(c1) != mb_tolower(c2))
- : (c1 != c2)) {
- break;
- }
- MB_PTR_ADV(p);
- MB_PTR_ADV(s);
- }
-
- if (*p != NUL) {
- // Leader was shortened, need to change the inserted text.
- *p = NUL;
- had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + ins_compl_len());
- ins_redraw(FALSE);
-
- /* When the match isn't there (to avoid matching itself) remove it
- * again after redrawing. */
- if (!had_match) {
- ins_compl_delete();
- }
- }
-
- compl_used_match = false;
- }
-}
-
-/*
- * Add an array of matches to the list of matches.
- * Frees matches[].
- */
-static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
- FUNC_ATTR_NONNULL_ALL
-{
- int add_r = OK;
- Direction dir = compl_direction;
-
- for (int i = 0; i < num_matches && add_r != FAIL; i++) {
- if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
- CP_FAST | (icase ? CP_ICASE : 0),
- false)) == OK) {
- // If dir was BACKWARD then honor it just once.
- dir = FORWARD;
- }
- }
- FreeWild(num_matches, matches);
-}
-
-/* Make the completion list cyclic.
- * Return the number of matches (excluding the original).
- */
-static int ins_compl_make_cyclic(void)
-{
- compl_T *match;
- int count = 0;
-
- if (compl_first_match != NULL) {
- /*
- * Find the end of the list.
- */
- match = compl_first_match;
- // there's always an entry for the compl_orig_text, it doesn't count.
- while (match->cp_next != NULL && match->cp_next != compl_first_match) {
- match = match->cp_next;
- ++count;
- }
- match->cp_next = compl_first_match;
- compl_first_match->cp_prev = match;
- }
- return count;
-}
-
-// Set variables that store noselect and noinsert behavior from the
-// 'completeopt' value.
-void completeopt_was_set(void)
-{
- compl_no_insert = false;
- compl_no_select = false;
- if (strstr((char *)p_cot, "noselect") != NULL) {
- compl_no_select = true;
- }
- if (strstr((char *)p_cot, "noinsert") != NULL) {
- compl_no_insert = true;
- }
-}
-
-/*
- * Start completion for the complete() function.
- * "startcol" is where the matched text starts (1 is first column).
- * "list" is the list of matches.
- */
-void set_completion(colnr_T startcol, list_T *list)
-{
- int flags = CP_ORIGINAL_TEXT;
-
- // If already doing completions stop it.
- if (ctrl_x_mode != CTRL_X_NORMAL) {
- ins_compl_prep(' ');
- }
- ins_compl_clear();
- ins_compl_free();
-
- compl_direction = FORWARD;
- if (startcol > curwin->w_cursor.col) {
- startcol = curwin->w_cursor.col;
- }
- compl_col = startcol;
- compl_length = (int)curwin->w_cursor.col - (int)startcol;
- // compl_pattern doesn't need to be set
- compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
- (size_t)compl_length);
- if (p_ic) {
- flags |= CP_ICASE;
- }
- if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags | CP_FAST, false) != OK) {
- return;
- }
-
- ctrl_x_mode = CTRL_X_EVAL;
-
- ins_compl_add_list(list);
- compl_matches = ins_compl_make_cyclic();
- compl_started = true;
- compl_used_match = true;
- compl_cont_status = 0;
- int save_w_wrow = curwin->w_wrow;
- int save_w_leftcol = curwin->w_leftcol;
-
- compl_curr_match = compl_first_match;
- if (compl_no_insert || compl_no_select) {
- ins_complete(K_DOWN, false);
- if (compl_no_select) {
- ins_complete(K_UP, false);
- }
- } else {
- ins_complete(Ctrl_N, false);
- }
- compl_enter_selects = compl_no_insert;
-
- // Lazily show the popup menu, unless we got interrupted.
- if (!compl_interrupted) {
- show_pum(save_w_wrow, save_w_leftcol);
- }
-
- may_trigger_modechanged();
- ui_flush();
-}
-
-/* "compl_match_array" points the currently displayed list of entries in the
- * popup menu. It is NULL when there is no popup menu. */
-static pumitem_T *compl_match_array = NULL;
-static int compl_match_arraysize;
-
-/*
- * Remove any popup menu.
- */
-static void ins_compl_del_pum(void)
-{
- if (compl_match_array != NULL) {
- pum_undisplay(false);
- XFREE_CLEAR(compl_match_array);
- }
-}
-
-/// Check if the popup menu should be displayed.
-static bool pum_wanted(void)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- // "completeopt" must contain "menu" or "menuone"
- return vim_strchr((char *)p_cot, 'm') != NULL;
-}
-
-/// Check that there are two or more matches to be shown in the popup menu.
-/// One if "completopt" contains "menuone".
-static bool pum_enough_matches(void)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- // Don't display the popup menu if there are no matches or there is only
- // one (ignoring the original text).
- compl_T *comp = compl_first_match;
- int i = 0;
- do {
- if (comp == NULL
- || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) {
- break;
- }
- comp = comp->cp_next;
- } while (comp != compl_first_match);
-
- if (strstr((char *)p_cot, "menuone") != NULL) {
- return i >= 1;
- }
- return i >= 2;
-}
-
-static void trigger_complete_changed_event(int cur)
-{
- static bool recursive = false;
- save_v_event_T save_v_event;
-
- if (recursive) {
- return;
- }
-
- dict_T *v_event = get_v_event(&save_v_event);
- if (cur < 0) {
- tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
- } else {
- dict_T *item = ins_compl_dict_alloc(compl_curr_match);
- tv_dict_add_dict(v_event, S_LEN("completed_item"), item);
- }
- pum_set_event_info(v_event);
- tv_dict_set_keys_readonly(v_event);
-
- recursive = true;
- textlock++;
- apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf);
- textlock--;
- recursive = false;
-
- restore_v_event(v_event, &save_v_event);
-}
-
-/// Show the popup menu for the list of matches.
-/// Also adjusts "compl_shown_match" to an entry that is actually displayed.
-void ins_compl_show_pum(void)
-{
- compl_T *compl;
- compl_T *shown_compl = NULL;
- bool did_find_shown_match = false;
- bool shown_match_ok = false;
- int i;
- int cur = -1;
- colnr_T col;
- int lead_len = 0;
- bool array_changed = false;
-
- if (!pum_wanted() || !pum_enough_matches()) {
- return;
- }
-
- // Dirty hard-coded hack: remove any matchparen highlighting.
- do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif");
-
- // Update the screen before drawing the popup menu over it.
- update_screen(0);
-
- if (compl_match_array == NULL) {
- array_changed = true;
- // Need to build the popup menu list.
- compl_match_arraysize = 0;
- compl = compl_first_match;
- //
- // If it's user complete function and refresh_always,
- // do not use "compl_leader" as prefix filter.
- //
- if (ins_compl_need_restart()) {
- XFREE_CLEAR(compl_leader);
- }
- if (compl_leader != NULL) {
- lead_len = (int)STRLEN(compl_leader);
- }
- do {
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
- && (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
- compl_match_arraysize++;
- }
- compl = compl->cp_next;
- } while (compl != NULL && compl != compl_first_match);
- if (compl_match_arraysize == 0) {
- return;
- }
-
- assert(compl_match_arraysize >= 0);
- compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
- // If the current match is the original text don't find the first
- // match after it, don't highlight anything.
- if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
- shown_match_ok = true;
- }
-
- i = 0;
- compl = compl_first_match;
- do {
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
- && (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
- if (!shown_match_ok) {
- if (compl == compl_shown_match || did_find_shown_match) {
- /* This item is the shown match or this is the
- * first displayed item after the shown match. */
- compl_shown_match = compl;
- did_find_shown_match = true;
- shown_match_ok = true;
- } else {
- // Remember this displayed match for when the
- // shown match is just below it.
- shown_compl = compl;
- }
- cur = i;
- }
-
- if (compl->cp_text[CPT_ABBR] != NULL) {
- compl_match_array[i].pum_text =
- compl->cp_text[CPT_ABBR];
- } else {
- compl_match_array[i].pum_text = compl->cp_str;
- }
- compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
- compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
- if (compl->cp_text[CPT_MENU] != NULL) {
- compl_match_array[i++].pum_extra =
- compl->cp_text[CPT_MENU];
- } else {
- compl_match_array[i++].pum_extra = compl->cp_fname;
- }
- }
-
- if (compl == compl_shown_match) {
- did_find_shown_match = true;
-
- /* When the original text is the shown match don't set
- * compl_shown_match. */
- if (compl->cp_flags & CP_ORIGINAL_TEXT) {
- shown_match_ok = true;
- }
-
- if (!shown_match_ok && shown_compl != NULL) {
- /* The shown match isn't displayed, set it to the
- * previously displayed match. */
- compl_shown_match = shown_compl;
- shown_match_ok = true;
- }
- }
- compl = compl->cp_next;
- } while (compl != NULL && compl != compl_first_match);
-
- if (!shown_match_ok) { // no displayed match at all
- cur = -1;
- }
- } else {
- // popup menu already exists, only need to find the current item.
- for (i = 0; i < compl_match_arraysize; i++) {
- if (compl_match_array[i].pum_text == compl_shown_match->cp_str
- || compl_match_array[i].pum_text
- == compl_shown_match->cp_text[CPT_ABBR]) {
- cur = i;
- break;
- }
- }
- }
-
- // In Replace mode when a $ is displayed at the end of the line only
- // part of the screen would be updated. We do need to redraw here.
- dollar_vcol = -1;
-
- // Compute the screen column of the start of the completed text.
- // Use the cursor to get all wrapping and other settings right.
- col = curwin->w_cursor.col;
- curwin->w_cursor.col = compl_col;
- pum_selected_item = cur;
- pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
- curwin->w_cursor.col = col;
-
- if (has_event(EVENT_COMPLETECHANGED)) {
- trigger_complete_changed_event(cur);
- }
-}
-
-#define DICT_FIRST (1) // use just first element in "dict"
-#define DICT_EXACT (2) // "dict" is the exact name of a file
-
-/// Add any identifiers that match the given pattern in the list of dictionary
-/// files "dict_start" to the list of completions.
-///
-/// @param flags DICT_FIRST and/or DICT_EXACT
-/// @param thesaurus Thesaurus completion
-static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, int thesaurus)
-{
- char_u *dict = dict_start;
- char_u *ptr;
- char_u *buf;
- regmatch_T regmatch;
- char_u **files;
- int count;
- int save_p_scs;
- Direction dir = compl_direction;
-
- if (*dict == NUL) {
- /* When 'dictionary' is empty and spell checking is enabled use
- * "spell". */
- if (!thesaurus && curwin->w_p_spell) {
- dict = (char_u *)"spell";
- } else {
- return;
- }
- }
-
- buf = xmalloc(LSIZE);
- regmatch.regprog = NULL; // so that we can goto theend
-
- // If 'infercase' is set, don't use 'smartcase' here
- save_p_scs = p_scs;
- if (curbuf->b_p_inf) {
- p_scs = FALSE;
- }
-
- /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
- * to only match at the start of a line. Otherwise just match the
- * pattern. Also need to double backslashes. */
- if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
- char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
-
- size_t len = STRLEN(pat_esc) + 10;
- ptr = xmalloc(len);
- vim_snprintf((char *)ptr, len, "^\\s*\\zs\\V%s", pat_esc);
- regmatch.regprog = vim_regcomp((char *)ptr, RE_MAGIC);
- xfree(pat_esc);
- xfree(ptr);
- } else {
- regmatch.regprog = vim_regcomp((char *)pat, p_magic ? RE_MAGIC : 0);
- if (regmatch.regprog == NULL) {
- goto theend;
- }
- }
-
- // ignore case depends on 'ignorecase', 'smartcase' and "pat"
- regmatch.rm_ic = ignorecase(pat);
- while (*dict != NUL && !got_int && !compl_interrupted) {
- // copy one dictionary file name into buf
- if (flags == DICT_EXACT) {
- count = 1;
- files = &dict;
- } else {
- /* Expand wildcards in the dictionary name, but do not allow
- * backticks (for security, the 'dict' option may have been set in
- * a modeline). */
- copy_option_part((char **)&dict, (char *)buf, LSIZE, ",");
- if (!thesaurus && STRCMP(buf, "spell") == 0) {
- count = -1;
- } else if (vim_strchr((char *)buf, '`') != NULL
- || expand_wildcards(1, &buf, &count, &files,
- EW_FILE|EW_SILENT) != OK) {
- count = 0;
- }
- }
-
- if (count == -1) {
- /* Complete from active spelling. Skip "\<" in the pattern, we
- * don't use it as a RE. */
- if (pat[0] == '\\' && pat[1] == '<') {
- ptr = pat + 2;
- } else {
- ptr = pat;
- }
- spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
- } else if (count > 0) { // avoid warning for using "files" uninit
- ins_compl_files(count, files, thesaurus, flags,
- &regmatch, buf, &dir);
- if (flags != DICT_EXACT) {
- FreeWild(count, files);
- }
- }
- if (flags != 0) {
- break;
- }
- }
-
-theend:
- p_scs = save_p_scs;
- vim_regfree(regmatch.regprog);
- xfree(buf);
-}
-
-static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
- regmatch_T *regmatch, char_u *buf, Direction *dir)
- FUNC_ATTR_NONNULL_ARG(2, 7)
-{
- char_u *ptr;
- int i;
- FILE *fp;
- int add_r;
-
- for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
- fp = os_fopen((char *)files[i], "r"); // open dictionary file
- if (flags != DICT_EXACT) {
- msg_hist_off = true; // reset in msg_trunc_attr()
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Scanning dictionary: %s"), (char *)files[i]);
- (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
- }
-
- if (fp == NULL) {
- continue;
- }
- /*
- * Read dictionary file line by line.
- * Check each line for a match.
- */
- while (!got_int && !compl_interrupted
- && !vim_fgets(buf, LSIZE, fp)) {
- ptr = buf;
- while (vim_regexec(regmatch, (char *)buf, (colnr_T)(ptr - buf))) {
- ptr = regmatch->startp[0];
- if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
- ptr = find_line_end(ptr);
- } else {
- ptr = find_word_end(ptr);
- }
- add_r = ins_compl_add_infercase(regmatch->startp[0],
- (int)(ptr - regmatch->startp[0]),
- p_ic, files[i], *dir, false);
- if (thesaurus) {
- char_u *wstart;
-
- /*
- * Add the other matches on the line
- */
- ptr = buf;
- while (!got_int) {
- /* Find start of the next word. Skip white
- * space and punctuation. */
- ptr = find_word_start(ptr);
- if (*ptr == NUL || *ptr == NL) {
- break;
- }
- wstart = ptr;
-
- // Find end of the word.
- // Japanese words may have characters in
- // different classes, only separate words
- // with single-byte non-word characters.
- while (*ptr != NUL) {
- const int l = utfc_ptr2len((char *)ptr);
-
- if (l < 2 && !vim_iswordc(*ptr)) {
- break;
- }
- ptr += l;
- }
-
- // Add the word. Skip the regexp match.
- if (wstart != regmatch->startp[0]) {
- add_r = ins_compl_add_infercase(wstart, (int)(ptr - wstart),
- p_ic, files[i], *dir, false);
- }
- }
- }
- if (add_r == OK) {
- // if dir was BACKWARD then honor it just once
- *dir = FORWARD;
- } else if (add_r == FAIL) {
- break;
- }
- // avoid expensive call to vim_regexec() when at end
- // of line
- if (*ptr == '\n' || got_int) {
- break;
- }
- }
- line_breakcheck();
- ins_compl_check_keys(50, false);
- }
- fclose(fp);
- }
-}
-
-/*
- * Find the start of the next word.
- * Returns a pointer to the first char of the word. Also stops at a NUL.
- */
-char_u *find_word_start(char_u *ptr)
- FUNC_ATTR_PURE
-{
- while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1) {
- ptr += utfc_ptr2len((char *)ptr);
- }
- return ptr;
-}
-
-/*
- * Find the end of the word. Assumes it starts inside a word.
- * Returns a pointer to just after the word.
- */
-char_u *find_word_end(char_u *ptr)
- FUNC_ATTR_PURE
-{
- const int start_class = mb_get_class(ptr);
- if (start_class > 1) {
- while (*ptr != NUL) {
- ptr += utfc_ptr2len((char *)ptr);
- if (mb_get_class(ptr) != start_class) {
- break;
- }
- }
- }
- return ptr;
-}
-
-/*
- * Find the end of the line, omitting CR and NL at the end.
- * Returns a pointer to just after the line.
- */
-static char_u *find_line_end(char_u *ptr)
-{
- char_u *s;
-
- s = ptr + STRLEN(ptr);
- while (s > ptr && (s[-1] == CAR || s[-1] == NL)) {
- --s;
- }
- return s;
-}
-
-/*
- * Free the list of completions
- */
-static void ins_compl_free(void)
-{
- compl_T *match;
-
- XFREE_CLEAR(compl_pattern);
- XFREE_CLEAR(compl_leader);
-
- if (compl_first_match == NULL) {
- return;
- }
-
- ins_compl_del_pum();
- pum_clear();
-
- compl_curr_match = compl_first_match;
- do {
- match = compl_curr_match;
- compl_curr_match = compl_curr_match->cp_next;
- xfree(match->cp_str);
- // several entries may use the same fname, free it just once.
- if (match->cp_flags & CP_FREE_FNAME) {
- xfree(match->cp_fname);
- }
- for (int i = 0; i < CPT_COUNT; i++) {
- xfree(match->cp_text[i]);
- }
- tv_clear(&match->cp_user_data);
- xfree(match);
- } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
- compl_first_match = compl_curr_match = NULL;
- compl_shown_match = NULL;
- compl_old_match = NULL;
-}
-
-static void ins_compl_clear(void)
-{
- compl_cont_status = 0;
- compl_started = false;
- compl_matches = 0;
- XFREE_CLEAR(compl_pattern);
- XFREE_CLEAR(compl_leader);
- edit_submode_extra = NULL;
- XFREE_CLEAR(compl_orig_text);
- compl_enter_selects = false;
- // clear v:completed_item
- set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
-}
-
-/// Check that Insert completion is active.
-bool ins_compl_active(void)
- FUNC_ATTR_PURE
-{
- return compl_started;
-}
-
-static void ins_compl_update_sequence_numbers(void)
-{
- int number = 0;
- compl_T *match;
-
- if (compl_direction == FORWARD) {
- // search backwards for the first valid (!= -1) number.
- // This should normally succeed already at the first loop
- // cycle, so it's fast!
- for (match = compl_curr_match->cp_prev;
- match != NULL && match != compl_first_match;
- match = match->cp_prev) {
- if (match->cp_number != -1) {
- number = match->cp_number;
- break;
- }
- }
- if (match != NULL) {
- // go up and assign all numbers which are not assigned yet
- for (match = match->cp_next;
- match != NULL && match->cp_number == -1;
- match = match->cp_next) {
- match->cp_number = ++number;
- }
- }
- } else { // BACKWARD
- assert(compl_direction == BACKWARD);
- // search forwards (upwards) for the first valid (!= -1)
- // number. This should normally succeed already at the
- // first loop cycle, so it's fast!
- for (match = compl_curr_match->cp_next;
- match != NULL && match != compl_first_match;
- match = match->cp_next) {
- if (match->cp_number != -1) {
- number = match->cp_number;
- break;
- }
- }
- if (match != NULL) {
- // go down and assign all numbers which are not
- // assigned yet
- for (match = match->cp_prev;
- match && match->cp_number == -1;
- match = match->cp_prev) {
- match->cp_number = ++number;
- }
- }
- }
-}
-
-// Get complete information
-void get_complete_info(list_T *what_list, dict_T *retdict)
-{
-#define CI_WHAT_MODE 0x01
-#define CI_WHAT_PUM_VISIBLE 0x02
-#define CI_WHAT_ITEMS 0x04
-#define CI_WHAT_SELECTED 0x08
-#define CI_WHAT_INSERTED 0x10
-#define CI_WHAT_ALL 0xff
- int what_flag;
-
- if (what_list == NULL) {
- what_flag = CI_WHAT_ALL;
- } else {
- what_flag = 0;
- for (listitem_T *item = tv_list_first(what_list)
- ; item != NULL
- ; item = TV_LIST_ITEM_NEXT(what_list, item)) {
- const char *what = tv_get_string(TV_LIST_ITEM_TV(item));
-
- if (STRCMP(what, "mode") == 0) {
- what_flag |= CI_WHAT_MODE;
- } else if (STRCMP(what, "pum_visible") == 0) {
- what_flag |= CI_WHAT_PUM_VISIBLE;
- } else if (STRCMP(what, "items") == 0) {
- what_flag |= CI_WHAT_ITEMS;
- } else if (STRCMP(what, "selected") == 0) {
- what_flag |= CI_WHAT_SELECTED;
- } else if (STRCMP(what, "inserted") == 0) {
- what_flag |= CI_WHAT_INSERTED;
- }
- }
- }
-
- int ret = OK;
- if (what_flag & CI_WHAT_MODE) {
- ret = tv_dict_add_str(retdict, S_LEN("mode"),
- (char *)ins_compl_mode());
- }
-
- if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) {
- ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
- }
-
- if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
- list_T *li = tv_list_alloc(ins_compl_len());
-
- ret = tv_dict_add_list(retdict, S_LEN("items"), li);
- if (ret == OK && compl_first_match != NULL) {
- compl_T *match = compl_first_match;
- do {
- if (!(match->cp_flags & CP_ORIGINAL_TEXT)) {
- dict_T *di = tv_dict_alloc();
-
- tv_list_append_dict(li, di);
- tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
- if (match->cp_user_data.v_type == VAR_UNKNOWN) {
- tv_dict_add_str(di, S_LEN("user_data"), "");
- } else {
- tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
- }
- }
- match = match->cp_next;
- } while (match != NULL && match != compl_first_match);
- }
- }
-
- if (ret == OK && (what_flag & CI_WHAT_SELECTED)) {
- if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) {
- ins_compl_update_sequence_numbers();
- }
- ret = tv_dict_add_nr(retdict, S_LEN("selected"),
- (compl_curr_match != NULL)
- ? compl_curr_match->cp_number - 1 : -1);
- }
-
- (void)ret;
- // TODO(vim):
- // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
-}
-
-// Return Insert completion mode name string
-static char_u *ins_compl_mode(void)
-{
- if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || ctrl_x_mode == CTRL_X_SCROLL || compl_started) {
- return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
- }
- return (char_u *)"";
-}
-
-/*
- * Delete one character before the cursor and show the subset of the matches
- * that match the word that is now before the cursor.
- * Returns the character to be used, NUL if the work is done and another char
- * to be got from the user.
- */
-static int ins_compl_bs(void)
-{
- char_u *line = get_cursor_line_ptr();
- char_u *p = line + curwin->w_cursor.col;
- MB_PTR_BACK(line, p);
- ptrdiff_t p_off = p - line;
-
- // Stop completion when the whole word was deleted. For Omni completion
- // allow the word to be deleted, we won't match everything.
- // Respect the 'backspace' option.
- if ((int)(p - line) - (int)compl_col < 0
- || ((int)(p - line) - (int)compl_col == 0 && ctrl_x_mode != CTRL_X_OMNI)
- || ctrl_x_mode == CTRL_X_EVAL
- || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col
- - compl_length < 0)) {
- return K_BS;
- }
-
- /* Deleted more than what was used to find matches or didn't finish
- * finding all matches: need to look for matches all over again. */
- if (curwin->w_cursor.col <= compl_col + compl_length
- || ins_compl_need_restart()) {
- ins_compl_restart();
- }
-
- // ins_compl_restart() calls update_screen(0) which may invalidate the pointer
- // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic
- line = get_cursor_line_ptr();
-
- xfree(compl_leader);
- compl_leader = vim_strnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col));
- ins_compl_new_leader();
- if (compl_shown_match != NULL) {
- // Make sure current match is not a hidden item.
- compl_curr_match = compl_shown_match;
- }
-
- return NUL;
-}
-
-/// Check that we need to find matches again, ins_compl_restart() is to
-/// be called.
-static bool ins_compl_need_restart(void)
- FUNC_ATTR_PURE
-{
- // Return true if we didn't complete finding matches or when the
- // "completefunc" returned "always" in the "refresh" dictionary item.
- return compl_was_interrupted
- || ((ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
- && compl_opt_refresh_always);
-}
-
-/*
- * Called after changing "compl_leader".
- * Show the popup menu with a different set of matches.
- * May also search for matches again if the previous search was interrupted.
- */
-static void ins_compl_new_leader(void)
-{
- ins_compl_del_pum();
- ins_compl_delete();
- ins_bytes(compl_leader + ins_compl_len());
- compl_used_match = false;
-
- if (compl_started) {
- ins_compl_set_original_text(compl_leader);
- } else {
- spell_bad_len = 0; // need to redetect bad word
- // Matches were cleared, need to search for them now.
- // Set "compl_restarting" to avoid that the first match is inserted.
- compl_restarting = true;
- if (ins_complete(Ctrl_N, true) == FAIL) {
- compl_cont_status = 0;
- }
- compl_restarting = false;
- }
-
- compl_enter_selects = !compl_used_match;
-
- // Show the popup menu with a different set of matches.
- ins_compl_show_pum();
-
- /* Don't let Enter select the original text when there is no popup menu.
- * Don't let Enter select when use user function and refresh_always is set */
- if (compl_match_array == NULL || ins_compl_need_restart()) {
- compl_enter_selects = FALSE;
- }
-}
-
-/*
- * Return the length of the completion, from the completion start column to
- * the cursor column. Making sure it never goes below zero.
- */
-static int ins_compl_len(void)
-{
- int off = (int)curwin->w_cursor.col - (int)compl_col;
-
- if (off < 0) {
- return 0;
- }
- return off;
-}
-
-/*
- * Append one character to the match leader. May reduce the number of
- * matches.
- */
-static void ins_compl_addleader(int c)
-{
- int cc;
-
- if (stop_arrow() == FAIL) {
- return;
- }
- if ((cc = utf_char2len(c)) > 1) {
- char buf[MB_MAXBYTES + 1];
-
- utf_char2bytes(c, (char *)buf);
- buf[cc] = NUL;
- ins_char_bytes((char_u *)buf, (size_t)cc);
- } else {
- ins_char(c);
- }
-
- // If we didn't complete finding matches we must search again.
- if (ins_compl_need_restart()) {
- ins_compl_restart();
- }
-
- xfree(compl_leader);
- compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col,
- (size_t)(curwin->w_cursor.col - compl_col));
- ins_compl_new_leader();
-}
-
-/*
- * Setup for finding completions again without leaving CTRL-X mode. Used when
- * BS or a key was typed while still searching for matches.
- */
-static void ins_compl_restart(void)
-{
- /* update screen before restart.
- * so if complete is blocked,
- * will stay to the last popup menu and reduce flicker */
- update_screen(0);
- ins_compl_free();
- compl_started = false;
- compl_matches = 0;
- compl_cont_status = 0;
- compl_cont_mode = 0;
-}
-
-/*
- * Set the first match, the original text.
- */
-static void ins_compl_set_original_text(char_u *str)
- FUNC_ATTR_NONNULL_ALL
-{
- // Replace the original text entry.
- // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly be
- // at the last item for backward completion
- if (compl_first_match->cp_flags & CP_ORIGINAL_TEXT) { // safety check
- xfree(compl_first_match->cp_str);
- compl_first_match->cp_str = vim_strsave(str);
- } else if (compl_first_match->cp_prev != NULL
- && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) {
- xfree(compl_first_match->cp_prev->cp_str);
- compl_first_match->cp_prev->cp_str = vim_strsave(str);
- }
-}
-
-/*
- * Append one character to the match leader. May reduce the number of
- * matches.
- */
-static void ins_compl_addfrommatch(void)
-{
- char_u *p;
- int len = (int)curwin->w_cursor.col - (int)compl_col;
- int c;
- compl_T *cp;
- assert(compl_shown_match != NULL);
- p = compl_shown_match->cp_str;
- if ((int)STRLEN(p) <= len) { // the match is too short
- // When still at the original match use the first entry that matches
- // the leader.
- if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
- p = NULL;
- for (cp = compl_shown_match->cp_next; cp != NULL
- && cp != compl_first_match; cp = cp->cp_next) {
- if (compl_leader == NULL
- || ins_compl_equal(cp, compl_leader, STRLEN(compl_leader))) {
- p = cp->cp_str;
- break;
- }
- }
- if (p == NULL || (int)STRLEN(p) <= len) {
- return;
- }
- } else {
- return;
- }
- }
- p += len;
- c = utf_ptr2char((char *)p);
- ins_compl_addleader(c);
-}
-
-/// Prepare for Insert mode completion, or stop it.
-/// Called just after typing a character in Insert mode.
-///
-/// @param c character that was typed
-///
-/// @return true when the character is not to be inserted;
-static bool ins_compl_prep(int c)
-{
- char_u *ptr;
- bool retval = false;
- const int prev_mode = ctrl_x_mode;
-
- /* Forget any previous 'special' messages if this is actually
- * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
- */
- if (c != Ctrl_R && vim_is_ctrl_x_key(c)) {
- edit_submode_extra = NULL;
- }
-
- // Ignore end of Select mode mapping and mouse scroll buttons.
- if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
- || c == K_COMMAND || c == K_LUA) {
- return retval;
- }
-
- if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
- if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
- || !vim_is_ctrl_x_key(c)) {
- // Not starting another completion mode.
- ctrl_x_mode = CTRL_X_CMDLINE;
-
- // CTRL-X CTRL-Z should stop completion without inserting anything
- if (c == Ctrl_Z) {
- retval = true;
- }
- } else {
- ctrl_x_mode = CTRL_X_CMDLINE;
-
- // Other CTRL-X keys first stop completion, then start another
- // completion mode.
- ins_compl_prep(' ');
- ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
- }
- }
-
- // Set "compl_get_longest" when finding the first matches.
- if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
- || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
- compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
- compl_used_match = true;
- }
-
- if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) {
- /*
- * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
- * it will be yet. Now we decide.
- */
- switch (c) {
- case Ctrl_E:
- case Ctrl_Y:
- ctrl_x_mode = CTRL_X_SCROLL;
- if (!(State & REPLACE_FLAG)) {
- edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
- } else {
- edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
- }
- edit_submode_pre = NULL;
- showmode();
- break;
- case Ctrl_L:
- ctrl_x_mode = CTRL_X_WHOLE_LINE;
- break;
- case Ctrl_F:
- ctrl_x_mode = CTRL_X_FILES;
- break;
- case Ctrl_K:
- ctrl_x_mode = CTRL_X_DICTIONARY;
- break;
- case Ctrl_R:
- // Simply allow ^R to happen without affecting ^X mode
- break;
- case Ctrl_T:
- ctrl_x_mode = CTRL_X_THESAURUS;
- break;
- case Ctrl_U:
- ctrl_x_mode = CTRL_X_FUNCTION;
- break;
- case Ctrl_O:
- ctrl_x_mode = CTRL_X_OMNI;
- break;
- case 's':
- case Ctrl_S:
- ctrl_x_mode = CTRL_X_SPELL;
- emsg_off++; // Avoid getting the E756 error twice.
- spell_back_to_badword();
- emsg_off--;
- break;
- case Ctrl_RSB:
- ctrl_x_mode = CTRL_X_TAGS;
- break;
- case Ctrl_I:
- case K_S_TAB:
- ctrl_x_mode = CTRL_X_PATH_PATTERNS;
- break;
- case Ctrl_D:
- ctrl_x_mode = CTRL_X_PATH_DEFINES;
- break;
- case Ctrl_V:
- case Ctrl_Q:
- ctrl_x_mode = CTRL_X_CMDLINE;
- break;
- case Ctrl_Z:
- ctrl_x_mode = CTRL_X_NORMAL;
- edit_submode = NULL;
- showmode();
- retval = true;
- break;
- case Ctrl_P:
- case Ctrl_N:
- /* ^X^P means LOCAL expansion if nothing interrupted (eg we
- * just started ^X mode, or there were enough ^X's to cancel
- * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
- * do normal expansion when interrupting a different mode (say
- * ^X^F^X^P or ^P^X^X^P, see below)
- * nothing changes if interrupting mode 0, (eg, the flag
- * doesn't change when going to ADDING mode -- Acevedo */
- if (!(compl_cont_status & CONT_INTRPT)) {
- compl_cont_status |= CONT_LOCAL;
- } else if (compl_cont_mode != 0) {
- compl_cont_status &= ~CONT_LOCAL;
- }
- FALLTHROUGH;
- default:
- /* If we have typed at least 2 ^X's... for modes != 0, we set
- * compl_cont_status = 0 (eg, as if we had just started ^X
- * mode).
- * For mode 0, we set "compl_cont_mode" to an impossible
- * value, in both cases ^X^X can be used to restart the same
- * mode (avoiding ADDING mode).
- * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
- * 'complete' and local ^P expansions respectively.
- * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
- * mode -- Acevedo */
- if (c == Ctrl_X) {
- if (compl_cont_mode != 0) {
- compl_cont_status = 0;
- } else {
- compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
- }
- }
- ctrl_x_mode = CTRL_X_NORMAL;
- edit_submode = NULL;
- showmode();
- break;
- }
- } else if (ctrl_x_mode != CTRL_X_NORMAL) {
- // We're already in CTRL-X mode, do we stay in it?
- if (!vim_is_ctrl_x_key(c)) {
- if (ctrl_x_mode == CTRL_X_SCROLL) {
- ctrl_x_mode = CTRL_X_NORMAL;
- } else {
- ctrl_x_mode = CTRL_X_FINISHED;
- }
- edit_submode = NULL;
- }
- showmode();
- }
-
- if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) {
- /* Show error message from attempted keyword completion (probably
- * 'Pattern not found') until another key is hit, then go back to
- * showing what mode we are in. */
- showmode();
- if ((ctrl_x_mode == CTRL_X_NORMAL
- && c != Ctrl_N
- && c != Ctrl_P
- && c != Ctrl_R
- && !ins_compl_pum_key(c))
- || ctrl_x_mode == CTRL_X_FINISHED) {
- /* Get here when we have finished typing a sequence of ^N and
- * ^P or other completion characters in CTRL-X mode. Free up
- * memory that was used, and make sure we can redo the insert. */
- if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) {
- /*
- * If any of the original typed text has been changed, eg when
- * ignorecase is set, we must add back-spaces to the redo
- * buffer. We add as few as necessary to delete just the part
- * of the original text that has changed.
- * When using the longest match, edited the match or used
- * CTRL-E then don't use the current match.
- */
- if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
- ptr = compl_curr_match->cp_str;
- } else {
- ptr = NULL;
- }
- ins_compl_fixRedoBufForLeader(ptr);
- }
-
- bool want_cindent = (can_cindent && cindent_on());
-
- // When completing whole lines: fix indent for 'cindent'.
- // Otherwise, break line if it's too long.
- if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
- // re-indent the current line
- if (want_cindent) {
- do_c_expr_indent();
- want_cindent = false; // don't do it again
- }
- } else {
- int prev_col = curwin->w_cursor.col;
-
- // put the cursor on the last char, for 'tw' formatting
- if (prev_col > 0) {
- dec_cursor();
- }
-
- if (!arrow_used && !ins_need_undo && c != Ctrl_E) {
- insertchar(NUL, 0, -1);
- }
-
- if (prev_col > 0
- && get_cursor_line_ptr()[curwin->w_cursor.col] != NUL) {
- inc_cursor();
- }
- }
-
- // If the popup menu is displayed pressing CTRL-Y means accepting
- // the selection without inserting anything. When
- // compl_enter_selects is set the Enter key does the same.
- if ((c == Ctrl_Y || (compl_enter_selects
- && (c == CAR || c == K_KENTER || c == NL)))
- && pum_visible()) {
- retval = true;
- }
-
- // CTRL-E means completion is Ended, go back to the typed text.
- // but only do this, if the Popup is still visible
- if (c == Ctrl_E) {
- ins_compl_delete();
- if (compl_leader != NULL) {
- ins_bytes(compl_leader + ins_compl_len());
- } else if (compl_first_match != NULL) {
- ins_bytes(compl_orig_text + ins_compl_len());
- }
- retval = true;
- }
-
- auto_format(false, true);
-
- // Trigger the CompleteDonePre event to give scripts a chance to
- // act upon the completion before clearing the info, and restore
- // ctrl_x_mode, so that complete_info() can be used.
- ctrl_x_mode = prev_mode;
- ins_apply_autocmds(EVENT_COMPLETEDONEPRE);
-
- ins_compl_free();
- compl_started = false;
- compl_matches = 0;
- if (!shortmess(SHM_COMPLETIONMENU)) {
- msg_clr_cmdline(); // necessary for "noshowmode"
- }
- ctrl_x_mode = CTRL_X_NORMAL;
- compl_enter_selects = false;
- if (edit_submode != NULL) {
- edit_submode = NULL;
- showmode();
- }
-
- // Avoid the popup menu remains displayed when leaving the
- // command line window.
- if (c == Ctrl_C && cmdwin_type != 0) {
- update_screen(0);
- }
-
- /*
- * Indent now if a key was typed that is in 'cinkeys'.
- */
- if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0))) {
- do_c_expr_indent();
- }
- // Trigger the CompleteDone event to give scripts a chance to act
- // upon the end of completion.
- ins_apply_autocmds(EVENT_COMPLETEDONE);
- }
- } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
- /* Trigger the CompleteDone event to give scripts a chance to act
- * upon the (possibly failed) completion. */
- ins_apply_autocmds(EVENT_COMPLETEDONE);
- }
-
- may_trigger_modechanged();
-
- /* reset continue_* if we left expansion-mode, if we stay they'll be
- * (re)set properly in ins_complete() */
- if (!vim_is_ctrl_x_key(c)) {
- compl_cont_status = 0;
- compl_cont_mode = 0;
- }
-
- return retval;
-}
-
-/*
- * Fix the redo buffer for the completion leader replacing some of the typed
- * text. This inserts backspaces and appends the changed text.
- * "ptr" is the known leader text or NUL.
- */
-static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
-{
- int len;
- char_u *p;
- char_u *ptr = ptr_arg;
-
- if (ptr == NULL) {
- if (compl_leader != NULL) {
- ptr = compl_leader;
- } else {
- return; // nothing to do
- }
- }
- if (compl_orig_text != NULL) {
- p = compl_orig_text;
- for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {}
- if (len > 0) {
- len -= utf_head_off(p, p + len);
- }
- for (p += len; *p != NUL; MB_PTR_ADV(p)) {
- AppendCharToRedobuff(K_BS);
- }
- } else {
- len = 0;
- }
- AppendToRedobuffLit((char *)ptr + len, -1);
-}
-
-/*
- * Loops through the list of windows, loaded-buffers or non-loaded-buffers
- * (depending on flag) starting from buf and looking for a non-scanned
- * buffer (other than curbuf). curbuf is special, if it is called with
- * buf=curbuf then it has to be the first call for a given flag/expansion.
- *
- * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
- */
-static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
-{
- static win_T *wp = NULL;
-
- if (flag == 'w') { // just windows
- if (buf == curbuf || wp == NULL) { // first call for this flag/expansion
- wp = curwin;
- }
- assert(wp);
- while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
- && wp->w_buffer->b_scanned) {}
- buf = wp->w_buffer;
- } else {
- /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
- * (unlisted buffers)
- * When completing whole lines skip unloaded buffers. */
- while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
- && ((flag == 'U'
- ? buf->b_p_bl
- : (!buf->b_p_bl
- || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
- || buf->b_scanned)) {}
- }
- return buf;
-}
-
-/// Get the user-defined completion function name for completion 'type'
-static char_u *get_complete_funcname(int type)
-{
- switch (type) {
- case CTRL_X_FUNCTION:
- return curbuf->b_p_cfu;
- case CTRL_X_OMNI:
- return curbuf->b_p_ofu;
- case CTRL_X_THESAURUS:
- return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu;
- default:
- return (char_u *)"";
- }
-}
-
-/// Execute user defined complete function 'completefunc' or 'omnifunc', and
-/// get matches in "matches".
-///
-/// @param type CTRL_X_OMNI or CTRL_X_FUNCTION
-static void expand_by_function(int type, char_u *base)
-{
- list_T *matchlist = NULL;
- dict_T *matchdict = NULL;
- char_u *funcname;
- pos_T pos;
- typval_T rettv;
- const int save_State = State;
-
- assert(curbuf != NULL);
- funcname = get_complete_funcname(type);
- if (*funcname == NUL) {
- return;
- }
-
- // Call 'completefunc' to obtain the list of matches.
- typval_T args[3];
- args[0].v_type = VAR_NUMBER;
- args[1].v_type = VAR_STRING;
- args[2].v_type = VAR_UNKNOWN;
- args[0].vval.v_number = 0;
- args[1].vval.v_string = base != NULL ? (char *)base : "";
-
- pos = curwin->w_cursor;
- // Lock the text to avoid weird things from happening. Also disallow
- // switching to another window, it should not be needed and may end up in
- // Insert mode in another buffer.
- textlock++;
-
- // Call a function, which returns a list or dict.
- if (call_vim_function((char *)funcname, 2, args, &rettv) == OK) {
- switch (rettv.v_type) {
- case VAR_LIST:
- matchlist = rettv.vval.v_list;
- break;
- case VAR_DICT:
- matchdict = rettv.vval.v_dict;
- break;
- case VAR_SPECIAL:
- FALLTHROUGH;
- default:
- // TODO(brammool): Give error message?
- tv_clear(&rettv);
- break;
- }
- }
- textlock--;
-
- curwin->w_cursor = pos; // restore the cursor position
- validate_cursor();
- if (!equalpos(curwin->w_cursor, pos)) {
- emsg(_(e_compldel));
- goto theend;
- }
-
- if (matchlist != NULL) {
- ins_compl_add_list(matchlist);
- } else if (matchdict != NULL) {
- ins_compl_add_dict(matchdict);
- }
-
-theend:
- // Restore State, it might have been changed.
- State = save_State;
-
- if (matchdict != NULL) {
- tv_dict_unref(matchdict);
- }
- if (matchlist != NULL) {
- tv_list_unref(matchlist);
- }
-}
-
-/*
- * Add completions from a list.
- */
-static void ins_compl_add_list(list_T *const list)
-{
- Direction dir = compl_direction;
-
- // Go through the List with matches and add each of them.
- TV_LIST_ITER(list, li, {
- if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir, true) == OK) {
- // If dir was BACKWARD then honor it just once.
- dir = FORWARD;
- } else if (did_emsg) {
- break;
- }
- });
-}
-
-/*
- * Add completions from a dict.
- */
-static void ins_compl_add_dict(dict_T *dict)
-{
- dictitem_T *di_refresh;
- dictitem_T *di_words;
-
- // Check for optional "refresh" item.
- compl_opt_refresh_always = false;
- di_refresh = tv_dict_find(dict, S_LEN("refresh"));
- if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
- const char *v = (const char *)di_refresh->di_tv.vval.v_string;
-
- if (v != NULL && strcmp(v, "always") == 0) {
- compl_opt_refresh_always = true;
- }
- }
-
- // Add completions from a "words" list.
- di_words = tv_dict_find(dict, S_LEN("words"));
- if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
- ins_compl_add_list(di_words->di_tv.vval.v_list);
- }
-}
-
-/// Add a match to the list of matches from VimL object
-///
-/// @param[in] tv Object to get matches from.
-/// @param[in] dir Completion direction.
-/// @param[in] fast use fast_breakcheck() instead of os_breakcheck().
-///
-/// @return NOTDONE if the given string is already in the list of completions,
-/// otherwise it is added to the list and OK is returned. FAIL will be
-/// returned in case of error.
-int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
- FUNC_ATTR_NONNULL_ALL
-{
- const char *word;
- bool dup = false;
- bool empty = false;
- int flags = fast ? CP_FAST : 0;
- char *(cptext[CPT_COUNT]);
- typval_T user_data;
-
- user_data.v_type = VAR_UNKNOWN;
- if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
- word = tv_dict_get_string(tv->vval.v_dict, "word", false);
- cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
- cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
- cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
- cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
- tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
-
- if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
- flags |= CP_ICASE;
- }
- dup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
- empty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
- if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL
- && tv_dict_get_number(tv->vval.v_dict, "equal")) {
- flags |= CP_EQUAL;
- }
- } else {
- word = tv_get_string_chk(tv);
- memset(cptext, 0, sizeof(cptext));
- }
- if (word == NULL || (!empty && *word == NUL)) {
- for (size_t i = 0; i < CPT_COUNT; i++) {
- xfree(cptext[i]);
- }
- return FAIL;
- }
- return ins_compl_add((char_u *)word, -1, NULL,
- (char_u **)cptext, true, &user_data, dir, flags, dup);
-}
-
-/// Returns true when using a user-defined function for thesaurus completion.
-static bool thesaurus_func_complete(int type)
-{
- return type == CTRL_X_THESAURUS
- && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
-}
-
-// Get the next expansion(s), using "compl_pattern".
-// The search starts at position "ini" in curbuf and in the direction
-// compl_direction.
-// When "compl_started" is false start at that position, otherwise continue
-// where we stopped searching before.
-// This may return before finding all the matches.
-// Return the total number of matches or -1 if still unknown -- Acevedo
-static int ins_compl_get_exp(pos_T *ini)
-{
- static pos_T first_match_pos;
- static pos_T last_match_pos;
- static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
- static bool found_all = false; // Found all matches of a
- // certain type.
- static buf_T *ins_buf = NULL; // buffer being scanned
-
- pos_T *pos;
- char_u **matches;
- int save_p_scs;
- bool save_p_ws;
- int save_p_ic;
- int i;
- int num_matches;
- int len;
- int found_new_match;
- int type = ctrl_x_mode;
- char_u *ptr;
- char_u *dict = NULL;
- int dict_f = 0;
- bool set_match_pos;
- pos_T prev_pos = { 0, 0, 0 };
- int l_ctrl_x_mode = ctrl_x_mode;
-
- assert(curbuf != NULL);
-
- if (!compl_started) {
- FOR_ALL_BUFFERS(buf) {
- buf->b_scanned = false;
- }
- found_all = false;
- ins_buf = curbuf;
- e_cpt = (compl_cont_status & CONT_LOCAL)
- ? (char_u *)"." : curbuf->b_p_cpt;
- last_match_pos = first_match_pos = *ini;
- } else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
- ins_buf = curbuf; // In case the buffer was wiped out.
- }
-
- compl_old_match = compl_curr_match; // remember the last current match
- pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
-
- // For ^N/^P loop over all the flags/windows/buffers in 'complete'
- for (;;) {
- found_new_match = FAIL;
- set_match_pos = false;
-
- assert(l_ctrl_x_mode == ctrl_x_mode);
-
- // For ^N/^P pick a new entry from e_cpt if compl_started is off,
- // or if found_all says this entry is done. For ^X^L only use the
- // entries from 'complete' that look in loaded buffers.
- if ((l_ctrl_x_mode == CTRL_X_NORMAL
- || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
- && (!compl_started || found_all)) {
- found_all = false;
- while (*e_cpt == ',' || *e_cpt == ' ') {
- e_cpt++;
- }
- if (*e_cpt == '.' && !curbuf->b_scanned) {
- ins_buf = curbuf;
- first_match_pos = *ini;
- // Move the cursor back one character so that ^N can match the
- // word immediately after the cursor.
- if (ctrl_x_mode == CTRL_X_NORMAL && dec(&first_match_pos) < 0) {
- // Move the cursor to after the last character in the
- // buffer, so that word at start of buffer is found
- // correctly.
- first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
- first_match_pos.col = (colnr_T)STRLEN(ml_get(first_match_pos.lnum));
- }
- last_match_pos = first_match_pos;
- type = 0;
-
- // Remember the first match so that the loop stops when we
- // wrap and come back there a second time.
- set_match_pos = true;
- } else if (vim_strchr("buwU", *e_cpt) != NULL
- && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
- // Scan a buffer, but not the current one.
- if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
- compl_started = true;
- first_match_pos.col = last_match_pos.col = 0;
- first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
- last_match_pos.lnum = 0;
- type = 0;
- } else { // unloaded buffer, scan like dictionary
- found_all = true;
- if (ins_buf->b_fname == NULL) {
- continue;
- }
- type = CTRL_X_DICTIONARY;
- dict = (char_u *)ins_buf->b_fname;
- dict_f = DICT_EXACT;
- }
- msg_hist_off = true; // reset in msg_trunc_attr()
- vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
- ins_buf->b_fname == NULL
- ? buf_spname(ins_buf)
- : ins_buf->b_sfname == NULL
- ? ins_buf->b_fname
- : ins_buf->b_sfname);
- (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
- } else if (*e_cpt == NUL) {
- break;
- } else {
- if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
- type = -1;
- } else if (*e_cpt == 'k' || *e_cpt == 's') {
- if (*e_cpt == 'k') {
- type = CTRL_X_DICTIONARY;
- } else {
- type = CTRL_X_THESAURUS;
- }
- if (*++e_cpt != ',' && *e_cpt != NUL) {
- dict = e_cpt;
- dict_f = DICT_FIRST;
- }
- } else if (*e_cpt == 'i') {
- type = CTRL_X_PATH_PATTERNS;
- } else if (*e_cpt == 'd') {
- type = CTRL_X_PATH_DEFINES;
- } else if (*e_cpt == ']' || *e_cpt == 't') {
- msg_hist_off = true; // reset in msg_trunc_attr()
- type = CTRL_X_TAGS;
- vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags."));
- (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
- } else {
- type = -1;
- }
-
- // in any case e_cpt is advanced to the next entry
- (void)copy_option_part((char **)&e_cpt, (char *)IObuff, IOSIZE, ",");
-
- found_all = true;
- if (type == -1) {
- continue;
- }
- }
- }
-
- // If complete() was called then compl_pattern has been reset.
- // The following won't work then, bail out.
- if (compl_pattern == NULL) {
- break;
- }
-
- switch (type) {
- case -1:
- break;
- case CTRL_X_PATH_PATTERNS:
- case CTRL_X_PATH_DEFINES:
- find_pattern_in_path(compl_pattern, compl_direction,
- STRLEN(compl_pattern), FALSE, FALSE,
- ((type == CTRL_X_PATH_DEFINES
- && !(compl_cont_status & CONT_SOL))
- ? FIND_DEFINE
- : FIND_ANY),
- 1L, ACTION_EXPAND, 1, MAXLNUM);
- break;
-
- case CTRL_X_DICTIONARY:
- case CTRL_X_THESAURUS:
- if (thesaurus_func_complete(type)) {
- expand_by_function(type, compl_pattern);
- } else {
- ins_compl_dictionaries(dict != NULL ? dict
- : (type == CTRL_X_THESAURUS
- ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
- : (*curbuf->b_p_dict ==
- NUL ? p_dict : curbuf->b_p_dict)),
- compl_pattern,
- dict != NULL ? dict_f : 0, type == CTRL_X_THESAURUS);
- }
- dict = NULL;
- break;
-
- case CTRL_X_TAGS:
- // set p_ic according to p_ic, p_scs and pat for find_tags().
- save_p_ic = p_ic;
- p_ic = ignorecase(compl_pattern);
-
- // Find up to TAG_MANY matches. Avoids that an enormous number
- // of matches is found when compl_pattern is empty
- g_tag_at_cursor = true;
- if (find_tags(compl_pattern, &num_matches, &matches,
- TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
- | (l_ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0),
- TAG_MANY, (char_u *)curbuf->b_ffname) == OK && num_matches > 0) {
- ins_compl_add_matches(num_matches, matches, p_ic);
- }
- g_tag_at_cursor = false;
- p_ic = save_p_ic;
- break;
-
- case CTRL_X_FILES:
- if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
- EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
- // May change home directory back to "~".
- tilde_replace(compl_pattern, num_matches, matches);
-#ifdef BACKSLASH_IN_FILENAME
- if (curbuf->b_p_csl[0] != NUL) {
- for (int i = 0; i < num_matches; i++) {
- char_u *ptr = matches[i];
- while (*ptr != NUL) {
- if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
- *ptr = '/';
- } else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
- *ptr = '\\';
- }
- ptr += utfc_ptr2len(ptr);
- }
- }
- }
-#endif
- ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
- }
- break;
-
- case CTRL_X_CMDLINE:
- case CTRL_X_CMDLINE_CTRL_X:
- if (expand_cmdline(&compl_xp, compl_pattern,
- (int)STRLEN(compl_pattern),
- &num_matches, &matches) == EXPAND_OK) {
- ins_compl_add_matches(num_matches, matches, false);
- }
- break;
-
- case CTRL_X_FUNCTION:
- case CTRL_X_OMNI:
- expand_by_function(type, compl_pattern);
- break;
-
- case CTRL_X_SPELL:
- num_matches = expand_spelling(first_match_pos.lnum,
- compl_pattern, &matches);
- if (num_matches > 0) {
- ins_compl_add_matches(num_matches, matches, p_ic);
- }
- break;
-
- default: // normal ^P/^N and ^X^L
- // If 'infercase' is set, don't use 'smartcase' here
- save_p_scs = p_scs;
- assert(ins_buf);
- if (ins_buf->b_p_inf) {
- p_scs = FALSE;
- }
-
- // Buffers other than curbuf are scanned from the beginning or the
- // end but never from the middle, thus setting nowrapscan in this
- // buffers is a good idea, on the other hand, we always set
- // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
- save_p_ws = p_ws;
- if (ins_buf != curbuf) {
- p_ws = false;
- } else if (*e_cpt == '.') {
- p_ws = true;
- }
- bool looped_around = false;
- for (;;) {
- bool cont_s_ipos = false;
-
- msg_silent++; // Don't want messages for wrapscan.
- // CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode) || word-wise search that
- // has added a word that was at the beginning of the line.
- if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)
- || (compl_cont_status & CONT_SOL)) {
- found_new_match = search_for_exact_line(ins_buf, pos,
- compl_direction,
- compl_pattern);
- } else {
- found_new_match = searchit(NULL, ins_buf, pos, NULL,
- compl_direction,
- compl_pattern, 1L,
- SEARCH_KEEP + SEARCH_NFMSG,
- RE_LAST, NULL);
- }
- msg_silent--;
- if (!compl_started || set_match_pos) {
- // set "compl_started" even on fail
- compl_started = true;
- first_match_pos = *pos;
- last_match_pos = *pos;
- set_match_pos = false;
- } else if (first_match_pos.lnum == last_match_pos.lnum
- && first_match_pos.col == last_match_pos.col) {
- found_new_match = FAIL;
- } else if ((compl_direction == FORWARD)
- && (prev_pos.lnum > pos->lnum
- || (prev_pos.lnum == pos->lnum
- && prev_pos.col >= pos->col))) {
- if (looped_around) {
- found_new_match = FAIL;
- } else {
- looped_around = true;
- }
- } else if ((compl_direction != FORWARD)
- && (prev_pos.lnum < pos->lnum
- || (prev_pos.lnum == pos->lnum
- && prev_pos.col <= pos->col))) {
- if (looped_around) {
- found_new_match = FAIL;
- } else {
- looped_around = true;
- }
- }
- prev_pos = *pos;
- if (found_new_match == FAIL) {
- if (ins_buf == curbuf) {
- found_all = true;
- }
- break;
- }
-
- // when ADDING, the text before the cursor matches, skip it
- if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
- && ini->lnum == pos->lnum
- && ini->col == pos->col) {
- continue;
- }
- ptr = ml_get_buf(ins_buf, pos->lnum, false) + pos->col;
- if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
- if (compl_cont_status & CONT_ADDING) {
- if (pos->lnum >= ins_buf->b_ml.ml_line_count) {
- continue;
- }
- ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
- if (!p_paste) {
- ptr = (char_u *)skipwhite((char *)ptr);
- }
- }
- len = (int)STRLEN(ptr);
- } else {
- char_u *tmp_ptr = ptr;
-
- if (compl_cont_status & CONT_ADDING) {
- tmp_ptr += compl_length;
- // Skip if already inside a word.
- if (vim_iswordp(tmp_ptr)) {
- continue;
- }
- // Find start of next word.
- tmp_ptr = find_word_start(tmp_ptr);
- }
- // Find end of this word.
- tmp_ptr = find_word_end(tmp_ptr);
- len = (int)(tmp_ptr - ptr);
-
- if ((compl_cont_status & CONT_ADDING)
- && len == compl_length) {
- if (pos->lnum < ins_buf->b_ml.ml_line_count) {
- // Try next line, if any. the new word will be "join" as if the
- // normal command "J" was used. IOSIZE is always greater than
- // compl_length, so the next STRNCPY always works -- Acevedo
- STRNCPY(IObuff, ptr, len);
- ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
- tmp_ptr = ptr = (char_u *)skipwhite((char *)ptr);
- // Find start of next word.
- tmp_ptr = find_word_start(tmp_ptr);
- // Find end of next word.
- tmp_ptr = find_word_end(tmp_ptr);
- if (tmp_ptr > ptr) {
- if (*ptr != ')' && IObuff[len - 1] != TAB) {
- if (IObuff[len - 1] != ' ') {
- IObuff[len++] = ' ';
- }
- // IObuf =~ "\k.* ", thus len >= 2
- if (p_js
- && (IObuff[len - 2] == '.'
- || IObuff[len - 2] == '?'
- || IObuff[len - 2] == '!')) {
- IObuff[len++] = ' ';
- }
- }
- // copy as much as possible of the new word
- if (tmp_ptr - ptr >= IOSIZE - len) {
- tmp_ptr = ptr + IOSIZE - len - 1;
- }
- STRLCPY(IObuff + len, ptr, IOSIZE - len);
- len += (int)(tmp_ptr - ptr);
- cont_s_ipos = true;
- }
- IObuff[len] = NUL;
- ptr = IObuff;
- }
- if (len == compl_length) {
- continue;
- }
- }
- }
- if (ins_compl_add_infercase(ptr, len, p_ic,
- ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
- 0, cont_s_ipos) != NOTDONE) {
- found_new_match = OK;
- break;
- }
- }
- p_scs = save_p_scs;
- p_ws = save_p_ws;
- }
-
- // check if compl_curr_match has changed, (e.g. other type of
- // expansion added something)
- if (type != 0 && compl_curr_match != compl_old_match) {
- found_new_match = OK;
- }
-
- // break the loop for specialized modes (use 'complete' just for the
- // generic l_ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match
- if ((l_ctrl_x_mode != CTRL_X_NORMAL
- && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
- || found_new_match != FAIL) {
- if (got_int) {
- break;
- }
- // Fill the popup menu as soon as possible.
- if (type != -1) {
- ins_compl_check_keys(0, false);
- }
-
- if ((l_ctrl_x_mode != CTRL_X_NORMAL
- && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
- || compl_interrupted) {
- break;
- }
- compl_started = true;
- } else {
- // Mark a buffer scanned when it has been scanned completely
- if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
- assert(ins_buf);
- ins_buf->b_scanned = true;
- }
-
- compl_started = false;
- }
- }
- compl_started = true;
-
- if ((l_ctrl_x_mode == CTRL_X_NORMAL
- || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
- && *e_cpt == NUL) { // Got to end of 'complete'
- found_new_match = FAIL;
- }
-
- i = -1; // total of matches, unknown
- if (found_new_match == FAIL
- || (l_ctrl_x_mode != CTRL_X_NORMAL
- && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))) {
- i = ins_compl_make_cyclic();
- }
-
- if (compl_old_match != NULL) {
- // If several matches were added (FORWARD) or the search failed and has
- // just been made cyclic then we have to move compl_curr_match to the
- // next or previous entry (if any) -- Acevedo
- compl_curr_match = compl_direction == FORWARD
- ? compl_old_match->cp_next
- : compl_old_match->cp_prev;
- if (compl_curr_match == NULL) {
- compl_curr_match = compl_old_match;
- }
- }
- may_trigger_modechanged();
-
- return i;
-}
-
-// Delete the old text being completed.
-static void ins_compl_delete(void)
-{
- int col;
-
- // In insert mode: Delete the typed part.
- // In replace mode: Put the old characters back, if any.
- col = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
- if ((int)curwin->w_cursor.col > col) {
- if (stop_arrow() == FAIL) {
- return;
- }
- backspace_until_column(col);
- }
-
- // TODO(vim): is this sufficient for redrawing? Redrawing everything
- // causes flicker, thus we can't do that.
- changed_cline_bef_curs();
- // clear v:completed_item
- set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
-}
-
-// Insert the new text being completed.
-// "in_compl_func" is TRUE when called from complete_check().
-static void ins_compl_insert(int in_compl_func)
-{
- ins_bytes(compl_shown_match->cp_str + ins_compl_len());
- compl_used_match = !(compl_shown_match->cp_flags & CP_ORIGINAL_TEXT);
-
- dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
- set_vim_var_dict(VV_COMPLETED_ITEM, dict);
- if (!in_compl_func) {
- compl_curr_match = compl_shown_match;
- }
-}
-
-// Convert to complete item dict
-static dict_T *ins_compl_dict_alloc(compl_T *match)
-{
- // { word, abbr, menu, kind, info }
- dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
- tv_dict_add_str(dict, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(dict, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(dict, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(dict, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(dict, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
- if (match->cp_user_data.v_type == VAR_UNKNOWN) {
- tv_dict_add_str(dict, S_LEN("user_data"), "");
- } else {
- tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data);
- }
- return dict;
-}
-
-/// Fill in the next completion in the current direction.
-/// If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
-/// get more completions. If it is FALSE, then we just do nothing when there
-/// are no more completions in a given direction. The latter case is used when
-/// we are still in the middle of finding completions, to allow browsing
-/// through the ones found so far.
-/// @return the total number of matches, or -1 if still unknown -- webb.
-///
-/// compl_curr_match is currently being used by ins_compl_get_exp(), so we use
-/// compl_shown_match here.
-///
-/// Note that this function may be called recursively once only. First with
-/// "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
-/// calls this function with "allow_get_expansion" FALSE.
-///
-/// @param count Repeat completion this many times; should be at least 1
-/// @param insert_match Insert the newly selected match
-/// @param in_compl_func Called from complete_check()
-static int ins_compl_next(int allow_get_expansion, int count, int insert_match, int in_compl_func)
-{
- int num_matches = -1;
- int todo = count;
- compl_T *found_compl = NULL;
- bool found_end = false;
- const bool started = compl_started;
-
- /* When user complete function return -1 for findstart which is next
- * time of 'always', compl_shown_match become NULL. */
- if (compl_shown_match == NULL) {
- return -1;
- }
-
- if (compl_leader != NULL
- && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
- // Set "compl_shown_match" to the actually shown match, it may differ
- // when "compl_leader" is used to omit some of the matches.
- while (!ins_compl_equal(compl_shown_match,
- compl_leader, STRLEN(compl_leader))
- && compl_shown_match->cp_next != NULL
- && compl_shown_match->cp_next != compl_first_match) {
- compl_shown_match = compl_shown_match->cp_next;
- }
-
- /* If we didn't find it searching forward, and compl_shows_dir is
- * backward, find the last match. */
- if (compl_shows_dir == BACKWARD
- && !ins_compl_equal(compl_shown_match, compl_leader, STRLEN(compl_leader))
- && (compl_shown_match->cp_next == NULL
- || compl_shown_match->cp_next == compl_first_match)) {
- while (!ins_compl_equal(compl_shown_match, compl_leader, STRLEN(compl_leader))
- && compl_shown_match->cp_prev != NULL
- && compl_shown_match->cp_prev != compl_first_match) {
- compl_shown_match = compl_shown_match->cp_prev;
- }
- }
- }
-
- if (allow_get_expansion && insert_match
- && (!(compl_get_longest || compl_restarting) || compl_used_match)) {
- // Delete old text to be replaced
- ins_compl_delete();
- }
-
- // When finding the longest common text we stick at the original text,
- // don't let CTRL-N or CTRL-P move to the first match.
- bool advance = count != 1 || !allow_get_expansion || !compl_get_longest;
-
- // When restarting the search don't insert the first match either.
- if (compl_restarting) {
- advance = false;
- compl_restarting = false;
- }
-
- /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
- * around. */
- while (--todo >= 0) {
- if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL) {
- compl_shown_match = compl_shown_match->cp_next;
- found_end = (compl_first_match != NULL
- && (compl_shown_match->cp_next == compl_first_match
- || compl_shown_match == compl_first_match));
- } else if (compl_shows_dir == BACKWARD
- && compl_shown_match->cp_prev != NULL) {
- found_end = (compl_shown_match == compl_first_match);
- compl_shown_match = compl_shown_match->cp_prev;
- found_end |= (compl_shown_match == compl_first_match);
- } else {
- if (!allow_get_expansion) {
- if (advance) {
- if (compl_shows_dir == BACKWARD) {
- compl_pending -= todo + 1;
- } else {
- compl_pending += todo + 1;
- }
- }
- return -1;
- }
-
- if (!compl_no_select && advance) {
- if (compl_shows_dir == BACKWARD) {
- --compl_pending;
- } else {
- ++compl_pending;
- }
- }
-
- // Find matches.
- num_matches = ins_compl_get_exp(&compl_startpos);
-
- // handle any pending completions
- while (compl_pending != 0 && compl_direction == compl_shows_dir
- && advance) {
- if (compl_pending > 0 && compl_shown_match->cp_next != NULL) {
- compl_shown_match = compl_shown_match->cp_next;
- --compl_pending;
- }
- if (compl_pending < 0 && compl_shown_match->cp_prev != NULL) {
- compl_shown_match = compl_shown_match->cp_prev;
- ++compl_pending;
- } else {
- break;
- }
- }
- found_end = false;
- }
- if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
- && compl_leader != NULL
- && !ins_compl_equal(compl_shown_match,
- compl_leader, STRLEN(compl_leader))) {
- todo++;
- } else {
- // Remember a matching item.
- found_compl = compl_shown_match;
- }
-
- // Stop at the end of the list when we found a usable match.
- if (found_end) {
- if (found_compl != NULL) {
- compl_shown_match = found_compl;
- break;
- }
- todo = 1; // use first usable match after wrapping around
- }
- }
-
- // Insert the text of the new completion, or the compl_leader.
- if (compl_no_insert && !started) {
- ins_bytes(compl_orig_text + ins_compl_len());
- compl_used_match = false;
- } else if (insert_match) {
- if (!compl_get_longest || compl_used_match) {
- ins_compl_insert(in_compl_func);
- } else {
- ins_bytes(compl_leader + ins_compl_len());
- }
- } else {
- compl_used_match = false;
- }
-
- if (!allow_get_expansion) {
- // redraw to show the user what was inserted
- update_screen(0);
-
- // display the updated popup menu
- ins_compl_show_pum();
-
- // Delete old text to be replaced, since we're still searching and
- // don't want to match ourselves!
- ins_compl_delete();
- }
-
- /* Enter will select a match when the match wasn't inserted and the popup
- * menu is visible. */
- if (compl_no_insert && !started) {
- compl_enter_selects = TRUE;
- } else {
- compl_enter_selects = !insert_match && compl_match_array != NULL;
- }
-
- /*
- * Show the file name for the match (if any)
- * Truncate the file name to avoid a wait for return.
- */
- if (compl_shown_match->cp_fname != NULL) {
- char *lead = _("match in file");
- int space = sc_col - vim_strsize(lead) - 2;
- char *s;
- char *e;
-
- if (space > 0) {
- // We need the tail that fits. With double-byte encoding going
- // back from the end is very slow, thus go from the start and keep
- // the text that fits in "space" between "s" and "e".
- for (s = e = (char *)compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e)) {
- space -= ptr2cells(e);
- while (space < 0) {
- space += ptr2cells(s);
- MB_PTR_ADV(s);
- }
- }
- msg_hist_off = true;
- vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
- (char_u *)s > compl_shown_match->cp_fname ? "<" : "", s);
- msg((char *)IObuff);
- msg_hist_off = false;
- redraw_cmdline = false; // don't overwrite!
- }
- }
-
- return num_matches;
-}
-
-void pum_ext_select_item(int item, bool insert, bool finish)
-{
- if (!pum_visible() || item < -1 || item >= compl_match_arraysize) {
- return;
- }
- pum_want.active = true;
- pum_want.item = item;
- pum_want.insert = insert;
- pum_want.finish = finish;
-}
-
-// Call this while finding completions, to check whether the user has hit a key
-// that should change the currently displayed completion, or exit completion
-// mode. Also, when compl_pending is not zero, show a completion as soon as
-// possible. -- webb
-// "frequency" specifies out of how many calls we actually check.
-// "in_compl_func" is TRUE when called from complete_check(), don't set
-// compl_curr_match.
-void ins_compl_check_keys(int frequency, int in_compl_func)
-{
- static int count = 0;
-
- // Don't check when reading keys from a script, :normal or feedkeys().
- // That would break the test scripts. But do check for keys when called
- // from complete_check().
- if (!in_compl_func && (using_script() || ex_normal_busy)) {
- return;
- }
-
- // Only do this at regular intervals
- if (++count < frequency) {
- return;
- }
- count = 0;
-
- /* Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
- * can't do its work correctly. */
- int c = vpeekc_any();
- if (c != NUL) {
- if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) {
- c = safe_vgetc(); // Eat the character
- compl_shows_dir = ins_compl_key2dir(c);
- (void)ins_compl_next(false, ins_compl_key2count(c),
- c != K_UP && c != K_DOWN, in_compl_func);
- } else {
- /* Need to get the character to have KeyTyped set. We'll put it
- * back with vungetc() below. But skip K_IGNORE. */
- c = safe_vgetc();
- if (c != K_IGNORE) {
- /* Don't interrupt completion when the character wasn't typed,
- * e.g., when doing @q to replay keys. */
- if (c != Ctrl_R && KeyTyped) {
- compl_interrupted = TRUE;
- }
-
- vungetc(c);
- }
- }
- }
- if (compl_pending != 0 && !got_int && !compl_no_insert) {
- int todo = compl_pending > 0 ? compl_pending : -compl_pending;
-
- compl_pending = 0;
- (void)ins_compl_next(false, todo, true, in_compl_func);
- }
-}
-
-/*
- * Decide the direction of Insert mode complete from the key typed.
- * Returns BACKWARD or FORWARD.
- */
-static int ins_compl_key2dir(int c)
-{
- if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- return pum_want.item < pum_selected_item ? BACKWARD : FORWARD;
- }
- if (c == Ctrl_P || c == Ctrl_L
- || c == K_PAGEUP || c == K_KPAGEUP
- || c == K_S_UP || c == K_UP) {
- return BACKWARD;
- }
- return FORWARD;
-}
-
-/// Check that "c" is a valid completion key only while the popup menu is shown
-///
-/// @param c character to check
-static bool ins_compl_pum_key(int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
- || c == K_PAGEDOWN || c == K_KPAGEDOWN
- || c == K_S_DOWN || c == K_UP || c == K_DOWN);
-}
-
-/*
- * Decide the number of completions to move forward.
- * Returns 1 for most keys, height of the popup menu for page-up/down keys.
- */
-static int ins_compl_key2count(int c)
-{
- int h;
-
- if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- int offset = pum_want.item - pum_selected_item;
- return abs(offset);
- }
-
- if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) {
- h = pum_get_height();
- if (h > 3) {
- h -= 2; // keep some context
- }
- return h;
- }
- return 1;
-}
-
-/// Check that completion with "c" should insert the match, false if only
-/// to change the currently selected completion.
-///
-/// @param c character to check
-static bool ins_compl_use_match(int c)
- FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
-{
- switch (c) {
- case K_UP:
- case K_DOWN:
- case K_PAGEDOWN:
- case K_KPAGEDOWN:
- case K_S_DOWN:
- case K_PAGEUP:
- case K_KPAGEUP:
- case K_S_UP:
- return false;
- case K_EVENT:
- case K_COMMAND:
- case K_LUA:
- return pum_want.active && pum_want.insert;
- }
- return true;
-}
-
-/*
- * Do Insert mode completion.
- * Called when character "c" was typed, which has a meaning for completion.
- * Returns OK if completion was done, FAIL if something failed.
- */
-static int ins_complete(int c, bool enable_pum)
-{
- char_u *line;
- int startcol = 0; // column where searched text starts
- colnr_T curs_col; // cursor column
- int n;
- int save_w_wrow;
- int save_w_leftcol;
- int insert_match;
- const bool save_did_ai = did_ai;
- int flags = CP_ORIGINAL_TEXT;
-
- compl_direction = ins_compl_key2dir(c);
- insert_match = ins_compl_use_match(c);
-
- if (!compl_started) {
- // First time we hit ^N or ^P (in a row, I mean)
-
- did_ai = false;
- did_si = false;
- can_si = false;
- can_si_back = false;
- if (stop_arrow() == FAIL) {
- return FAIL;
- }
-
- line = ml_get(curwin->w_cursor.lnum);
- curs_col = curwin->w_cursor.col;
- compl_pending = 0;
-
- /* If this same ctrl_x_mode has been interrupted use the text from
- * "compl_startpos" to the cursor as a pattern to add a new word
- * instead of expand the one before the cursor, in word-wise if
- * "compl_startpos" is not in the same line as the cursor then fix it
- * (the line has been split because it was longer than 'tw'). if SOL
- * is set then skip the previous pattern, a word at the beginning of
- * the line has been inserted, we'll look for that -- Acevedo. */
- if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
- && compl_cont_mode == ctrl_x_mode) {
- /*
- * it is a continued search
- */
- compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
- if (ctrl_x_mode == CTRL_X_NORMAL
- || ctrl_x_mode == CTRL_X_PATH_PATTERNS
- || ctrl_x_mode == CTRL_X_PATH_DEFINES) {
- if (compl_startpos.lnum != curwin->w_cursor.lnum) {
- // line (probably) wrapped, set compl_startpos to the
- // first non_blank in the line, if it is not a wordchar
- // include it to get a better pattern, but then we don't
- // want the "\\<" prefix, check it below.
- compl_col = (colnr_T)getwhitecols(line);
- compl_startpos.col = compl_col;
- compl_startpos.lnum = curwin->w_cursor.lnum;
- compl_cont_status &= ~CONT_SOL; // clear SOL if present
- } else {
- /* S_IPOS was set when we inserted a word that was at the
- * beginning of the line, which means that we'll go to SOL
- * mode but first we need to redefine compl_startpos */
- if (compl_cont_status & CONT_S_IPOS) {
- compl_cont_status |= CONT_SOL;
- compl_startpos.col = (colnr_T)((char_u *)skipwhite((char *)line
- + compl_length
- + compl_startpos.col) - line);
- }
- compl_col = compl_startpos.col;
- }
- compl_length = curwin->w_cursor.col - (int)compl_col;
- /* IObuff is used to add a "word from the next line" would we
- * have enough space? just being paranoid */
-#define MIN_SPACE 75
- if (compl_length > (IOSIZE - MIN_SPACE)) {
- compl_cont_status &= ~CONT_SOL;
- compl_length = (IOSIZE - MIN_SPACE);
- compl_col = curwin->w_cursor.col - compl_length;
- }
- compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
- if (compl_length < 1) {
- compl_cont_status &= CONT_LOCAL;
- }
- } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
- compl_cont_status = CONT_ADDING | CONT_N_ADDS;
- } else {
- compl_cont_status = 0;
- }
- } else {
- compl_cont_status &= CONT_LOCAL;
- }
-
- if (!(compl_cont_status & CONT_ADDING)) { // normal expansion
- compl_cont_mode = ctrl_x_mode;
- if (ctrl_x_mode != CTRL_X_NORMAL) {
- // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
- compl_cont_status = 0;
- }
- compl_cont_status |= CONT_N_ADDS;
- compl_startpos = curwin->w_cursor;
- startcol = (int)curs_col;
- compl_col = 0;
- }
-
- // Work out completion pattern and original text -- webb
- if (ctrl_x_mode == CTRL_X_NORMAL
- || (ctrl_x_mode & CTRL_X_WANT_IDENT
- && !thesaurus_func_complete(ctrl_x_mode))) {
- if ((compl_cont_status & CONT_SOL)
- || ctrl_x_mode == CTRL_X_PATH_DEFINES) {
- if (!(compl_cont_status & CONT_ADDING)) {
- while (--startcol >= 0 && vim_isIDc(line[startcol])) {}
- compl_col += ++startcol;
- compl_length = curs_col - startcol;
- }
- if (p_ic) {
- compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
- } else {
- compl_pattern = vim_strnsave(line + compl_col, (size_t)compl_length);
- }
- } else if (compl_cont_status & CONT_ADDING) {
- char_u *prefix = (char_u *)"\\<";
-
- // we need up to 2 extra chars for the prefix
- compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
- compl_length) + 2);
- if (!vim_iswordp(line + compl_col)
- || (compl_col > 0
- && (
- vim_iswordp(mb_prevptr(line, line + compl_col))
- ))) {
- prefix = (char_u *)"";
- }
- STRCPY(compl_pattern, prefix);
- (void)quote_meta(compl_pattern + STRLEN(prefix),
- line + compl_col, compl_length);
- } else if (--startcol < 0
- || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
- // Match any word of at least two chars
- compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
- compl_col += curs_col;
- compl_length = 0;
- } else {
- // Search the point of change class of multibyte character
- // or not a word single byte character backward.
- startcol -= utf_head_off(line, line + startcol);
- int base_class = mb_get_class(line + startcol);
- while (--startcol >= 0) {
- int head_off = utf_head_off(line, line + startcol);
- if (base_class != mb_get_class(line + startcol - head_off)) {
- break;
- }
- startcol -= head_off;
- }
- compl_col += ++startcol;
- compl_length = (int)curs_col - startcol;
- if (compl_length == 1) {
- /* Only match word with at least two chars -- webb
- * there's no need to call quote_meta,
- * xmalloc(7) is enough -- Acevedo
- */
- compl_pattern = xmalloc(7);
- STRCPY(compl_pattern, "\\<");
- (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
- STRCAT(compl_pattern, "\\k");
- } else {
- compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
- compl_length) + 2);
- STRCPY(compl_pattern, "\\<");
- (void)quote_meta(compl_pattern + 2, line + compl_col,
- compl_length);
- }
- }
- } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
- compl_col = (colnr_T)getwhitecols(line);
- compl_length = (int)curs_col - (int)compl_col;
- if (compl_length < 0) { // cursor in indent: empty pattern
- compl_length = 0;
- }
- if (p_ic) {
- compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
- } else {
- compl_pattern = vim_strnsave(line + compl_col, (size_t)compl_length);
- }
- } else if (ctrl_x_mode == CTRL_X_FILES) {
- // Go back to just before the first filename character.
- if (startcol > 0) {
- char_u *p = line + startcol;
-
- MB_PTR_BACK(line, p);
- while (p > line && vim_isfilec(utf_ptr2char((char *)p))) {
- MB_PTR_BACK(line, p);
- }
- if (p == line && vim_isfilec(utf_ptr2char((char *)p))) {
- startcol = 0;
- } else {
- startcol = (int)(p - line) + 1;
- }
- }
-
- compl_col += startcol;
- compl_length = (int)curs_col - startcol;
- compl_pattern = addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES);
- } else if (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X) {
- compl_pattern = vim_strnsave(line, (size_t)curs_col);
- set_cmd_context(&compl_xp, compl_pattern,
- (int)STRLEN(compl_pattern), curs_col, false);
- if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
- || compl_xp.xp_context == EXPAND_NOTHING) {
- // No completion possible, use an empty pattern to get a
- // "pattern not found" message.
- compl_col = curs_col;
- } else {
- compl_col = (int)((char_u *)compl_xp.xp_pattern - compl_pattern);
- }
- compl_length = curs_col - compl_col;
- } else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
- || thesaurus_func_complete(ctrl_x_mode)) {
- // Call user defined function 'completefunc' with "a:findstart"
- // set to 1 to obtain the length of text to use for completion.
- char_u *funcname;
- pos_T pos;
- const int save_State = State;
-
- // Call 'completefunc' or 'omnifunc' and get pattern length as a string
- funcname = get_complete_funcname(ctrl_x_mode);
- if (*funcname == NUL) {
- semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
- ? "completefunc" : "omnifunc");
- // restore did_ai, so that adding comment leader works
- did_ai = save_did_ai;
- return FAIL;
- }
-
- typval_T args[3];
- args[0].v_type = VAR_NUMBER;
- args[1].v_type = VAR_STRING;
- args[2].v_type = VAR_UNKNOWN;
- args[0].vval.v_number = 1;
- args[1].vval.v_string = "";
-
- pos = curwin->w_cursor;
- textlock++;
- colnr_T col = (colnr_T)call_func_retnr((char *)funcname, 2, args);
- textlock--;
-
- State = save_State;
- curwin->w_cursor = pos; // restore the cursor position
- validate_cursor();
- if (!equalpos(curwin->w_cursor, pos)) {
- emsg(_(e_compldel));
- return FAIL;
- }
-
- // Return value -2 means the user complete function wants to cancel the
- // complete without an error, do the same if the function did not execute
- // successfully.
- if (col == -2 || aborting()) {
- return FAIL;
- }
- // Return value -3 does the same as -2 and leaves CTRL-X mode.
- if (col == -3) {
- ctrl_x_mode = CTRL_X_NORMAL;
- edit_submode = NULL;
- if (!shortmess(SHM_COMPLETIONMENU)) {
- msg_clr_cmdline();
- }
- return FAIL;
- }
-
- // Reset extended parameters of completion, when start new
- // completion.
- compl_opt_refresh_always = false;
-
- if (col < 0) {
- col = curs_col;
- }
- compl_col = col;
- if (compl_col > curs_col) {
- compl_col = curs_col;
- }
-
- /* Setup variables for completion. Need to obtain "line" again,
- * it may have become invalid. */
- line = ml_get(curwin->w_cursor.lnum);
- compl_length = curs_col - compl_col;
- compl_pattern = vim_strnsave(line + compl_col, (size_t)compl_length);
- } else if (ctrl_x_mode == CTRL_X_SPELL) {
- if (spell_bad_len > 0) {
- assert(spell_bad_len <= INT_MAX);
- compl_col = curs_col - (int)spell_bad_len;
- } else {
- compl_col = spell_word_start(startcol);
- }
- if (compl_col >= (colnr_T)startcol) {
- compl_length = 0;
- compl_col = curs_col;
- } else {
- spell_expand_check_cap(compl_col);
- compl_length = (int)curs_col - compl_col;
- }
- // Need to obtain "line" again, it may have become invalid.
- line = ml_get(curwin->w_cursor.lnum);
- compl_pattern = vim_strnsave(line + compl_col, (size_t)compl_length);
- } else {
- internal_error("ins_complete()");
- return FAIL;
- }
-
- if (compl_cont_status & CONT_ADDING) {
- edit_submode_pre = (char_u *)_(" Adding");
- if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
- // Insert a new line, keep indentation but ignore 'comments'
- char_u *old = curbuf->b_p_com;
-
- curbuf->b_p_com = (char_u *)"";
- compl_startpos.lnum = curwin->w_cursor.lnum;
- compl_startpos.col = compl_col;
- ins_eol('\r');
- curbuf->b_p_com = old;
- compl_length = 0;
- compl_col = curwin->w_cursor.col;
- }
- } else {
- edit_submode_pre = NULL;
- compl_startpos.col = compl_col;
- }
-
- if (compl_cont_status & CONT_LOCAL) {
- edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
- } else {
- edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
- }
-
- /* If any of the original typed text has been changed we need to fix
- * the redo buffer. */
- ins_compl_fixRedoBufForLeader(NULL);
-
- // Always add completion for the original text.
- xfree(compl_orig_text);
- compl_orig_text = vim_strnsave(line + compl_col, (size_t)compl_length);
- if (p_ic) {
- flags |= CP_ICASE;
- }
- if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags, false) != OK) {
- XFREE_CLEAR(compl_pattern);
- XFREE_CLEAR(compl_orig_text);
- return FAIL;
- }
-
- /* showmode might reset the internal line pointers, so it must
- * be called before line = ml_get(), or when this address is no
- * longer needed. -- Acevedo.
- */
- edit_submode_extra = (char_u *)_("-- Searching...");
- edit_submode_highl = HLF_COUNT;
- showmode();
- edit_submode_extra = NULL;
- ui_flush();
- } else if (insert_match && stop_arrow() == FAIL) {
- return FAIL;
- }
-
- compl_shown_match = compl_curr_match;
- compl_shows_dir = compl_direction;
-
- /*
- * Find next match (and following matches).
- */
- save_w_wrow = curwin->w_wrow;
- save_w_leftcol = curwin->w_leftcol;
- n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
-
- if (n > 1) { // all matches have been found
- compl_matches = n;
- }
- compl_curr_match = compl_shown_match;
- compl_direction = compl_shows_dir;
-
- /* Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
- * mode. */
- if (got_int && !global_busy) {
- (void)vgetc();
- got_int = FALSE;
- }
-
- // we found no match if the list has only the "compl_orig_text"-entry
- if (compl_first_match == compl_first_match->cp_next) {
- edit_submode_extra = (compl_cont_status & CONT_ADDING)
- && compl_length > 1
- ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
- edit_submode_highl = HLF_E;
- /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
- * because we couldn't expand anything at first place, but if we used
- * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
- * (such as M in M'exico) if not tried already. -- Acevedo */
- if (compl_length > 1
- || (compl_cont_status & CONT_ADDING)
- || (ctrl_x_mode != CTRL_X_NORMAL
- && ctrl_x_mode != CTRL_X_PATH_PATTERNS
- && ctrl_x_mode != CTRL_X_PATH_DEFINES)) {
- compl_cont_status &= ~CONT_N_ADDS;
- }
- }
-
- if (compl_curr_match->cp_flags & CP_CONT_S_IPOS) {
- compl_cont_status |= CONT_S_IPOS;
- } else {
- compl_cont_status &= ~CONT_S_IPOS;
- }
-
- if (edit_submode_extra == NULL) {
- if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT) {
- edit_submode_extra = (char_u *)_("Back at original");
- edit_submode_highl = HLF_W;
- } else if (compl_cont_status & CONT_S_IPOS) {
- edit_submode_extra = (char_u *)_("Word from other line");
- edit_submode_highl = HLF_COUNT;
- } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) {
- edit_submode_extra = (char_u *)_("The only match");
- edit_submode_highl = HLF_COUNT;
- compl_curr_match->cp_number = 1;
- } else {
- // Update completion sequence number when needed.
- if (compl_curr_match->cp_number == -1) {
- ins_compl_update_sequence_numbers();
- }
-
- /* The match should always have a sequence number now, this is
- * just a safety check. */
- if (compl_curr_match->cp_number != -1) {
- /* Space for 10 text chars. + 2x10-digit no.s = 31.
- * Translations may need more than twice that. */
- static char_u match_ref[81];
-
- if (compl_matches > 0) {
- vim_snprintf((char *)match_ref, sizeof(match_ref),
- _("match %d of %d"),
- compl_curr_match->cp_number, compl_matches);
- } else {
- vim_snprintf((char *)match_ref, sizeof(match_ref),
- _("match %d"),
- compl_curr_match->cp_number);
- }
- edit_submode_extra = match_ref;
- edit_submode_highl = HLF_R;
- if (dollar_vcol >= 0) {
- curs_columns(curwin, false);
- }
- }
- }
- }
-
- // Show a message about what (completion) mode we're in.
- showmode();
- if (!shortmess(SHM_COMPLETIONMENU)) {
- if (edit_submode_extra != NULL) {
- if (!p_smd) {
- msg_hist_off = true;
- msg_attr((const char *)edit_submode_extra,
- (edit_submode_highl < HLF_COUNT
- ? HL_ATTR(edit_submode_highl) : 0));
- msg_hist_off = false;
- }
- } else {
- msg_clr_cmdline(); // necessary for "noshowmode"
- }
- }
-
- // Show the popup menu, unless we got interrupted.
- if (enable_pum && !compl_interrupted) {
- show_pum(save_w_wrow, save_w_leftcol);
- }
- compl_was_interrupted = compl_interrupted;
- compl_interrupted = FALSE;
-
- return OK;
-}
-
-/*
- * Looks in the first "len" chars. of "src" for search-metachars.
- * If dest is not NULL the chars. are copied there quoting (with
- * a backslash) the metachars, and dest would be NUL terminated.
- * Returns the length (needed) of dest
- */
-static unsigned quote_meta(char_u *dest, char_u *src, int len)
-{
- unsigned m = (unsigned)len + 1; // one extra for the NUL
-
- for (; --len >= 0; src++) {
- switch (*src) {
- case '.':
- case '*':
- case '[':
- if (ctrl_x_mode == CTRL_X_DICTIONARY
- || ctrl_x_mode == CTRL_X_THESAURUS) {
- break;
- }
- FALLTHROUGH;
- case '~':
- if (!p_magic) { // quote these only if magic is set
- break;
- }
- FALLTHROUGH;
- case '\\':
- if (ctrl_x_mode == CTRL_X_DICTIONARY
- || ctrl_x_mode == CTRL_X_THESAURUS) {
- break;
- }
- FALLTHROUGH;
- case '^': // currently it's not needed.
- case '$':
- m++;
- if (dest != NULL) {
- *dest++ = '\\';
- }
- break;
- }
- if (dest != NULL) {
- *dest++ = *src;
- }
- // Copy remaining bytes of a multibyte character.
- const int mb_len = utfc_ptr2len((char *)src) - 1;
- if (mb_len > 0 && len >= mb_len) {
- for (int i = 0; i < mb_len; i++) {
- len--;
- src++;
- if (dest != NULL) {
- *dest++ = *src;
- }
- }
- }
- }
- if (dest != NULL) {
- *dest = NUL;
- }
-
- return m;
-}
-
/// Next character is interpreted literally.
/// A one, two or three digit decimal number is interpreted as its byte value.
/// If one or two digits are entered, the next character is given to vungetc().
@@ -6500,7 +2817,7 @@ static void redo_literal(int c)
/// For undo/redo it resembles hitting the <ESC> key.
///
/// @param end_insert_pos can be NULL
-static void start_arrow(pos_T *end_insert_pos)
+void start_arrow(pos_T *end_insert_pos)
{
start_arrow_common(end_insert_pos, true);
}
@@ -6546,19 +2863,6 @@ static void check_spell_redraw(void)
}
/*
- * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
- * spelled word, if there is one.
- */
-static void spell_back_to_badword(void)
-{
- pos_T tpos = curwin->w_cursor;
- spell_bad_len = spell_move_to(curwin, BACKWARD, true, true, NULL);
- if (curwin->w_cursor.col != tpos.col) {
- start_arrow(&tpos);
- }
-}
-
-/*
* stop_arrow() is called before a change is made in insert mode.
* If an arrow key has been used, start a new insertion.
* Returns FAIL if undo is impossible, shouldn't insert then.
@@ -6748,9 +3052,7 @@ void set_last_insert(int c)
void free_last_insert(void)
{
XFREE_CLEAR(last_insert);
- XFREE_CLEAR(compl_orig_text);
}
-
#endif
/*
@@ -8009,8 +4311,8 @@ static bool ins_start_select(int c)
case K_S_DOWN:
case K_S_END:
case K_S_HOME:
- // Start selection right away, the cursor can move with
- // CTRL-O when beyond the end of the line.
+ // Start selection right away, the cursor can move with CTRL-O when
+ // beyond the end of the line.
start_selection();
// Execute the key in (insert) Select mode.
@@ -9016,7 +5318,7 @@ static bool ins_tab(void)
/// Handle CR or NL in insert mode.
///
/// @return false when it can't undo.
-static bool ins_eol(int c)
+bool ins_eol(int c)
{
if (echeck_abbr(c + ABBR_OFF)) {
return true;
@@ -9180,7 +5482,7 @@ static int ins_ctrl_ey(int tc)
{
int c = tc;
- if (ctrl_x_mode == CTRL_X_SCROLL) {
+ if (ctrl_x_mode_scroll()) {
if (c == Ctrl_Y) {
scrolldown_clamp();
} else {
@@ -9353,8 +5655,13 @@ static char_u *do_insert_char_pre(int c)
return res;
}
+bool can_cindent_get(void)
+{
+ return can_cindent;
+}
+
/// Trigger "event" and take care of fixing undo.
-static int ins_apply_autocmds(event_T event)
+int ins_apply_autocmds(event_T event)
{
varnumber_T tick = buf_get_changedtick(curbuf);
int r;
@@ -9370,21 +5677,3 @@ static int ins_apply_autocmds(event_T event)
return r;
}
-
-static void show_pum(int prev_w_wrow, int prev_w_leftcol)
-{
- // RedrawingDisabled may be set when invoked through complete().
- int n = RedrawingDisabled;
- RedrawingDisabled = 0;
-
- // If the cursor moved or the display scrolled we need to remove the pum
- // first.
- setcursor();
- if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol) {
- ins_compl_del_pum();
- }
-
- ins_compl_show_pum();
- setcursor();
- RedrawingDisabled = n;
-}
diff --git a/src/nvim/edit.h b/src/nvim/edit.h
index 894e23ee9f..eda6d8c9db 100644
--- a/src/nvim/edit.h
+++ b/src/nvim/edit.h
@@ -1,27 +1,9 @@
#ifndef NVIM_EDIT_H
#define NVIM_EDIT_H
+#include "nvim/autocmd.h"
#include "nvim/vim.h"
-/*
- * Array indexes used for cptext argument of ins_compl_add().
- */
-#define CPT_ABBR 0 // "abbr"
-#define CPT_MENU 1 // "menu"
-#define CPT_KIND 2 // "kind"
-#define CPT_INFO 3 // "info"
-#define CPT_COUNT 4 // Number of entries
-
-// values for cp_flags
-typedef enum {
- CP_ORIGINAL_TEXT = 1, // the original text when the expansion begun
- CP_FREE_FNAME = 2, // cp_fname is allocated
- CP_CONT_S_IPOS = 4, // use CONT_S_IPOS for compl_cont_status
- CP_EQUAL = 8, // ins_compl_equal() always returns true
- CP_ICASE = 16, // ins_compl_equal ignores case
- CP_FAST = 32, // use fast_breakcheck instead of os_breakcheck
-} cp_flags_T;
-
typedef int (*IndentGetter)(void);
// Values for in_cinkeys()
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 16c3e72c5b..9cc92cb62e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -27,6 +27,7 @@
#include "nvim/eval/gc.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
#include "nvim/ex_session.h"
@@ -58,20 +59,13 @@
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
-static char *e_letunexp = N_("E18: Unexpected characters in :let");
static char *e_missbrac = N_("E111: Missing ']'");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
-static char *e_illvar = N_("E461: Illegal variable name: %s");
-static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
static char *e_nowhitespace
= N_("E274: No white space allowed before parenthesis");
-static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s");
static char *e_write2 = N_("E80: Error while writing: %s");
static char *e_string_list_or_blob_required = N_("E1098: String, List or Blob required");
-// TODO(ZyX-I): move to eval/executor
-static char *e_letwrong = N_("E734: Wrong variable type for %s=");
-
static char * const namespace_char = "abglstvw";
/// Variable used for g:
@@ -212,7 +206,7 @@ static struct vimvar {
VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
- VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, VV_RO),
+ VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, 0),
VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
@@ -967,6 +961,30 @@ typval_T *eval_expr(char *arg)
return tv;
}
+/// List Vim variables.
+void list_vim_vars(int *first)
+{
+ list_hashtable_vars(&vimvarht, "v:", false, first);
+}
+
+/// List script-local variables, if there is a script.
+void list_script_vars(int *first)
+{
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
+ }
+}
+
+bool is_vimvarht(const hashtab_T *ht)
+{
+ return ht == &vimvarht;
+}
+
+bool is_compatht(const hashtab_T *ht)
+{
+ return ht == &compat_hashtab;
+}
+
/// Prepare v: variable "idx" to be used.
/// Save the current typeval in "save_tv".
/// When not used yet add the variable to the v: hashtable.
@@ -1251,723 +1269,6 @@ int eval_foldexpr(char *arg, int *cp)
return (int)retval;
}
-/// ":cons[t] var = expr1" define constant
-/// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
-/// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
-void ex_const(exarg_T *eap)
-{
- ex_let_const(eap, true);
-}
-
-/// Get a list of lines from a HERE document. The here document is a list of
-/// lines surrounded by a marker.
-/// cmd << {marker}
-/// {line1}
-/// {line2}
-/// ....
-/// {marker}
-///
-/// The {marker} is a string. If the optional 'trim' word is supplied before the
-/// marker, then the leading indentation before the lines (matching the
-/// indentation in the 'cmd' line) is stripped.
-///
-/// @return a List with {lines} or NULL.
-static list_T *heredoc_get(exarg_T *eap, char *cmd)
-{
- char *marker;
- char *p;
- int marker_indent_len = 0;
- int text_indent_len = 0;
- char *text_indent = NULL;
-
- if (eap->getline == NULL) {
- emsg(_("E991: cannot use =<< here"));
- return NULL;
- }
-
- // Check for the optional 'trim' word before the marker
- cmd = skipwhite(cmd);
- if (STRNCMP(cmd, "trim", 4) == 0
- && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
- cmd = skipwhite(cmd + 4);
-
- // Trim the indentation from all the lines in the here document.
- // The amount of indentation trimmed is the same as the indentation of
- // the first line after the :let command line. To find the end marker
- // the indent of the :let command line is trimmed.
- p = *eap->cmdlinep;
- while (ascii_iswhite(*p)) {
- p++;
- marker_indent_len++;
- }
- text_indent_len = -1;
- }
-
- // The marker is the next word.
- if (*cmd != NUL && *cmd != '"') {
- marker = skipwhite(cmd);
- p = (char *)skiptowhite((char_u *)marker);
- if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
- emsg(_(e_trailing));
- return NULL;
- }
- *p = NUL;
- if (islower(*marker)) {
- emsg(_("E221: Marker cannot start with lower case letter"));
- return NULL;
- }
- } else {
- emsg(_("E172: Missing marker"));
- return NULL;
- }
-
- list_T *l = tv_list_alloc(0);
- for (;;) {
- int mi = 0;
- int ti = 0;
-
- char *theline = eap->getline(NUL, eap->cookie, 0, false);
- if (theline == NULL) {
- semsg(_("E990: Missing end marker '%s'"), marker);
- break;
- }
-
- // with "trim": skip the indent matching the :let line to find the
- // marker
- if (marker_indent_len > 0
- && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
- mi = marker_indent_len;
- }
- if (STRCMP(marker, theline + mi) == 0) {
- xfree(theline);
- break;
- }
- if (text_indent_len == -1 && *theline != NUL) {
- // set the text indent from the first line.
- p = theline;
- text_indent_len = 0;
- while (ascii_iswhite(*p)) {
- p++;
- text_indent_len++;
- }
- text_indent = xstrnsave(theline, (size_t)text_indent_len);
- }
- // with "trim": skip the indent matching the first line
- if (text_indent != NULL) {
- for (ti = 0; ti < text_indent_len; ti++) {
- if (theline[ti] != text_indent[ti]) {
- break;
- }
- }
- }
-
- tv_list_append_string(l, theline + ti, -1);
- xfree(theline);
- }
- xfree(text_indent);
-
- return l;
-}
-
-/// ":let" list all variable values
-/// ":let var1 var2" list variable values
-/// ":let var = expr" assignment command.
-/// ":let var += expr" assignment command.
-/// ":let var -= expr" assignment command.
-/// ":let var *= expr" assignment command.
-/// ":let var /= expr" assignment command.
-/// ":let var %= expr" assignment command.
-/// ":let var .= expr" assignment command.
-/// ":let var ..= expr" assignment command.
-/// ":let [var1, var2] = expr" unpack list.
-/// ":let [name, ..., ; lastname] = expr" unpack list.
-void ex_let(exarg_T *eap)
-{
- ex_let_const(eap, false);
-}
-
-static void ex_let_const(exarg_T *eap, const bool is_const)
-{
- char *arg = eap->arg;
- char *expr = NULL;
- typval_T rettv;
- int i;
- int var_count = 0;
- int semicolon = 0;
- char op[2];
- char *argend;
- int first = true;
-
- argend = (char *)skip_var_list(arg, &var_count, &semicolon);
- if (argend == NULL) {
- return;
- }
- if (argend > arg && argend[-1] == '.') { // For var.='str'.
- argend--;
- }
- expr = skipwhite(argend);
- if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
- && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
- // ":let" without "=": list variables
- if (*arg == '[') {
- emsg(_(e_invarg));
- } else if (!ends_excmd(*arg)) {
- // ":let var1 var2"
- arg = (char *)list_arg_vars(eap, (const char *)arg, &first);
- } else if (!eap->skip) {
- // ":let"
- list_glob_vars(&first);
- list_buf_vars(&first);
- list_win_vars(&first);
- list_tab_vars(&first);
- list_script_vars(&first);
- list_func_vars(&first);
- list_vim_vars(&first);
- }
- eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
- } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
- // HERE document
- list_T *l = heredoc_get(eap, expr + 3);
- if (l != NULL) {
- tv_list_set_ret(&rettv, l);
- if (!eap->skip) {
- op[0] = '=';
- op[1] = NUL;
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
- is_const, (char *)op);
- }
- tv_clear(&rettv);
- }
- } else {
- op[0] = '=';
- op[1] = NUL;
- if (*expr != '=') {
- if (vim_strchr("+-*/%.", *expr) != NULL) {
- op[0] = *expr; // +=, -=, *=, /=, %= or .=
- if (expr[0] == '.' && expr[1] == '.') { // ..=
- expr++;
- }
- }
- expr = skipwhite(expr + 2);
- } else {
- expr = skipwhite(expr + 1);
- }
-
- if (eap->skip) {
- ++emsg_skip;
- }
- i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
- if (eap->skip) {
- if (i != FAIL) {
- tv_clear(&rettv);
- }
- emsg_skip--;
- } else if (i != FAIL) {
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
- is_const, (char *)op);
- tv_clear(&rettv);
- }
- }
-}
-
-/// Assign the typevalue "tv" to the variable or variables at "arg_start".
-/// Handles both "var" with any type and "[var, var; var]" with a list type.
-/// When "op" is not NULL it points to a string with characters that
-/// must appear after the variable(s). Use "+", "-" or "." for add, subtract
-/// or concatenate.
-///
-/// @param copy copy values from "tv", don't move
-/// @param semicolon from skip_var_list()
-/// @param var_count from skip_var_list()
-/// @param is_const lock variables for :const
-///
-/// @return OK or FAIL;
-static int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_count,
- int is_const, char *op)
-{
- char *arg = arg_start;
- typval_T ltv;
-
- if (*arg != '[') {
- /*
- * ":let var = expr" or ":for var in list"
- */
- if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL) {
- return FAIL;
- }
- return OK;
- }
-
- // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
- if (tv->v_type != VAR_LIST) {
- emsg(_(e_listreq));
- return FAIL;
- }
- list_T *const l = tv->vval.v_list;
-
- const int len = tv_list_len(l);
- if (semicolon == 0 && var_count < len) {
- emsg(_("E687: Less targets than List items"));
- return FAIL;
- }
- if (var_count - semicolon > len) {
- emsg(_("E688: More targets than List items"));
- return FAIL;
- }
- // List l may actually be NULL, but it should fail with E688 or even earlier
- // if you try to do ":let [] = v:_null_list".
- assert(l != NULL);
-
- listitem_T *item = tv_list_first(l);
- size_t rest_len = (size_t)tv_list_len(l);
- while (*arg != ']') {
- arg = skipwhite(arg + 1);
- arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const, ",;]", op);
- if (arg == NULL) {
- return FAIL;
- }
- rest_len--;
-
- item = TV_LIST_ITEM_NEXT(l, item);
- arg = skipwhite(arg);
- if (*arg == ';') {
- /* Put the rest of the list (may be empty) in the var after ';'.
- * Create a new list for this. */
- list_T *const rest_list = tv_list_alloc((ptrdiff_t)rest_len);
- while (item != NULL) {
- tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item));
- item = TV_LIST_ITEM_NEXT(l, item);
- }
-
- ltv.v_type = VAR_LIST;
- ltv.v_lock = VAR_UNLOCKED;
- ltv.vval.v_list = rest_list;
- tv_list_ref(rest_list);
-
- arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const, "]", op);
- tv_clear(&ltv);
- if (arg == NULL) {
- return FAIL;
- }
- break;
- } else if (*arg != ',' && *arg != ']') {
- internal_error("ex_let_vars()");
- return FAIL;
- }
- }
-
- return OK;
-}
-
-/// Skip over assignable variable "var" or list of variables "[var, var]".
-/// Used for ":let varvar = expr" and ":for varvar in expr".
-/// For "[var, var]" increment "*var_count" for each variable.
-/// for "[var, var; var]" set "semicolon".
-///
-/// @return NULL for an error.
-static const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
-{
- const char *p;
- const char *s;
-
- if (*arg == '[') {
- // "[var, var]": find the matching ']'.
- p = arg;
- for (;;) {
- p = skipwhite(p + 1); // skip whites after '[', ';' or ','
- s = skip_var_one((char *)p);
- if (s == p) {
- semsg(_(e_invarg2), p);
- return NULL;
- }
- ++*var_count;
-
- p = skipwhite(s);
- if (*p == ']') {
- break;
- } else if (*p == ';') {
- if (*semicolon == 1) {
- emsg(_("E452: Double ; in list of variables"));
- return NULL;
- }
- *semicolon = 1;
- } else if (*p != ',') {
- semsg(_(e_invarg2), p);
- return NULL;
- }
- }
- return p + 1;
- } else {
- return skip_var_one((char *)arg);
- }
-}
-
-/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
-/// l[idx].
-static const char *skip_var_one(const char *arg)
-{
- if (*arg == '@' && arg[1] != NUL) {
- return arg + 1 + utfc_ptr2len(arg + 1);
- }
- return (char *)find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
- NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
-}
-
-/// List variables for hashtab "ht" with prefix "prefix".
-///
-/// @param empty if TRUE also list NULL strings as empty strings.
-void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *first)
-{
- hashitem_T *hi;
- dictitem_T *di;
- int todo;
-
- todo = (int)ht->ht_used;
- for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- di = TV_DICT_HI2DI(hi);
- char buf[IOSIZE];
-
- // apply :filter /pat/ to variable name
- xstrlcpy(buf, prefix, IOSIZE);
- xstrlcat(buf, (char *)di->di_key, IOSIZE);
- if (message_filtered((char_u *)buf)) {
- continue;
- }
-
- if (empty || di->di_tv.v_type != VAR_STRING
- || di->di_tv.vval.v_string != NULL) {
- list_one_var(di, prefix, first);
- }
- }
- }
-}
-
-/// List global variables.
-static void list_glob_vars(int *first)
-{
- list_hashtable_vars(&globvarht, "", true, first);
-}
-
-/// List buffer variables.
-static void list_buf_vars(int *first)
-{
- list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", true, first);
-}
-
-/// List window variables.
-static void list_win_vars(int *first)
-{
- list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", true, first);
-}
-
-/// List tab page variables.
-static void list_tab_vars(int *first)
-{
- list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", true, first);
-}
-
-/// List Vim variables.
-static void list_vim_vars(int *first)
-{
- list_hashtable_vars(&vimvarht, "v:", false, first);
-}
-
-/// List script-local variables, if there is a script.
-static void list_script_vars(int *first)
-{
- if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) {
- list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
- }
-}
-
-/// List variables in "arg".
-static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
-{
- int error = FALSE;
- int len;
- const char *name;
- const char *name_start;
- typval_T tv;
-
- while (!ends_excmd(*arg) && !got_int) {
- if (error || eap->skip) {
- arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
- if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) {
- emsg_severe = true;
- emsg(_(e_trailing));
- break;
- }
- } else {
- // get_name_len() takes care of expanding curly braces
- name_start = name = arg;
- char *tofree;
- len = get_name_len(&arg, &tofree, true, true);
- if (len <= 0) {
- /* This is mainly to keep test 49 working: when expanding
- * curly braces fails overrule the exception error message. */
- if (len < 0 && !aborting()) {
- emsg_severe = true;
- semsg(_(e_invarg2), arg);
- break;
- }
- error = TRUE;
- } else {
- if (tofree != NULL) {
- name = tofree;
- }
- if (get_var_tv(name, len, &tv, NULL, true, false)
- == FAIL) {
- error = true;
- } else {
- // handle d.key, l[idx], f(expr)
- const char *const arg_subsc = arg;
- if (handle_subscript(&arg, &tv, true, true, name, &name) == FAIL) {
- error = true;
- } else {
- if (arg == arg_subsc && len == 2 && name[1] == ':') {
- switch (*name) {
- case 'g':
- list_glob_vars(first); break;
- case 'b':
- list_buf_vars(first); break;
- case 'w':
- list_win_vars(first); break;
- case 't':
- list_tab_vars(first); break;
- case 'v':
- list_vim_vars(first); break;
- case 's':
- list_script_vars(first); break;
- case 'l':
- list_func_vars(first); break;
- default:
- semsg(_("E738: Can't list variables for %s"), name);
- }
- } else {
- char *const s = encode_tv2echo(&tv, NULL);
- const char *const used_name = (arg == arg_subsc
- ? name
- : name_start);
- const ptrdiff_t name_size = (used_name == tofree
- ? (ptrdiff_t)strlen(used_name)
- : (arg - used_name));
- list_one_var_a("", used_name, name_size,
- tv.v_type, s == NULL ? "" : s, first);
- xfree(s);
- }
- tv_clear(&tv);
- }
- }
- }
-
- xfree(tofree);
- }
-
- arg = (const char *)skipwhite(arg);
- }
-
- return arg;
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
-///
-/// @param[in] arg Start of the variable name.
-/// @param[in] tv Value to assign to the variable.
-/// @param[in] copy If true, copy value from `tv`.
-/// @param[in] endchars Valid characters after variable name or NULL.
-/// @param[in] op Operation performed: *op is `+`, `-`, `.` for `+=`, etc.
-/// NULL for `=`.
-///
-/// @return a pointer to the char just after the var name or NULL in case of
-/// error.
-static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bool is_const,
- const char *const endchars, const char *const op)
- FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
-{
- char *arg_end = NULL;
- int len;
- int opt_flags;
- char *tofree = NULL;
-
- /*
- * ":let $VAR = expr": Set environment variable.
- */
- if (*arg == '$') {
- if (is_const) {
- emsg(_("E996: Cannot lock an environment variable"));
- return NULL;
- }
- // Find the end of the name.
- arg++;
- char *name = arg;
- len = get_env_len((const char **)&arg);
- if (len == 0) {
- semsg(_(e_invarg2), name - 1);
- } else {
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
- semsg(_(e_letwrong), op);
- } else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg)) == NULL) {
- emsg(_(e_letunexp));
- } else if (!check_secure()) {
- const char c1 = name[len];
- name[len] = NUL;
- const char *p = tv_get_string_chk(tv);
- if (p != NULL && op != NULL && *op == '.') {
- char *s = vim_getenv(name);
-
- if (s != NULL) {
- tofree = (char *)concat_str((const char_u *)s, (const char_u *)p);
- p = (const char *)tofree;
- xfree(s);
- }
- }
- if (p != NULL) {
- os_setenv(name, p, 1);
- if (STRICMP(name, "HOME") == 0) {
- init_homedir();
- } else if (didset_vim && STRICMP(name, "VIM") == 0) {
- didset_vim = false;
- } else if (didset_vimruntime
- && STRICMP(name, "VIMRUNTIME") == 0) {
- didset_vimruntime = false;
- }
- arg_end = arg;
- }
- name[len] = c1;
- xfree(tofree);
- }
- }
- // ":let &option = expr": Set option value.
- // ":let &l:option = expr": Set local option value.
- // ":let &g:option = expr": Set global option value.
- } else if (*arg == '&') {
- if (is_const) {
- emsg(_("E996: Cannot lock an option"));
- return NULL;
- }
- // Find the end of the name.
- char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
- if (p == NULL
- || (endchars != NULL
- && vim_strchr(endchars, *skipwhite(p)) == NULL)) {
- emsg(_(e_letunexp));
- } else {
- int opt_type;
- long numval;
- char *stringval = NULL;
- const char *s = NULL;
-
- const char c1 = *p;
- *p = NUL;
-
- varnumber_T n = tv_get_number(tv);
- if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
- s = tv_get_string_chk(tv); // != NULL if number or string.
- }
- if (s != NULL && op != NULL && *op != '=') {
- opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
- if ((opt_type == 1 && *op == '.')
- || (opt_type == 0 && *op != '.')) {
- semsg(_(e_letwrong), op);
- s = NULL; // don't set the value
- } else {
- if (opt_type == 1) { // number
- switch (*op) {
- case '+':
- n = numval + n; break;
- case '-':
- n = numval - n; break;
- case '*':
- n = numval * n; break;
- case '/':
- n = num_divide(numval, n); break;
- case '%':
- n = num_modulus(numval, n); break;
- }
- } else if (opt_type == 0 && stringval != NULL) { // string
- char *const oldstringval = stringval;
- stringval = (char *)concat_str((const char_u *)stringval,
- (const char_u *)s);
- xfree(oldstringval);
- s = stringval;
- }
- }
- }
- if (s != NULL || tv->v_type == VAR_BOOL
- || tv->v_type == VAR_SPECIAL) {
- set_option_value((const char *)arg, n, s, opt_flags);
- arg_end = p;
- }
- *p = c1;
- xfree(stringval);
- }
- // ":let @r = expr": Set register contents.
- } else if (*arg == '@') {
- if (is_const) {
- emsg(_("E996: Cannot lock a register"));
- return NULL;
- }
- arg++;
-
- int regname = utf_ptr2char(arg);
- int mblen = utf_ptr2len(arg);
-
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
- semsg(_(e_letwrong), op);
- } else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg + mblen)) == NULL) {
- emsg(_(e_letunexp));
- } else {
- char *s;
-
- char *ptofree = NULL;
- const char *p = tv_get_string_chk(tv);
- if (p != NULL && op != NULL && *op == '.') {
- s = get_reg_contents(regname == '@' ? '"' : regname, kGRegExprSrc);
- if (s != NULL) {
- ptofree = (char *)concat_str((char_u *)s, (const char_u *)p);
- p = (const char *)ptofree;
- xfree(s);
- }
- }
- if (p != NULL) {
-
- write_reg_contents(regname == '@' ? '"' : regname,
- (const char_u *)p, (ssize_t)STRLEN(p), false);
- arg_end = arg + mblen;
- }
- xfree(ptofree);
- }
- }
- /*
- * ":let var = expr": Set internal variable.
- * ":let {expr} = expr": Idem, name made with curly braces
- */
- else if (eval_isnamec1(*arg) || *arg == '{') {
- lval_T lv;
-
- char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
- if (p != NULL && lv.ll_name != NULL) {
- if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
- emsg(_(e_letunexp));
- } else {
- set_var_lval(&lv, p, tv, copy, is_const, op);
- arg_end = p;
- }
- }
- clear_lval(&lv);
- } else {
- semsg(_(e_invarg2), arg);
- }
-
- return arg_end;
-}
-
// TODO(ZyX-I): move to eval/executor
/// Get an lvalue
@@ -2357,8 +1658,8 @@ void clear_lval(lval_T *lp)
/// @param endp points to just after the parsed name.
/// @param op NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=",
/// "%" for "%=", "." for ".=" or "=" for "=".
-static void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool is_const,
- const char *op)
+void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool is_const,
+ const char *op)
{
int cc;
listitem_T *ri;
@@ -2810,327 +2111,6 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx)
xp->xp_pattern = arg;
}
-/// ":unlet[!] var1 ... " command.
-void ex_unlet(exarg_T *eap)
-{
- ex_unletlock(eap, eap->arg, 0, do_unlet_var);
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// ":lockvar" and ":unlockvar" commands
-void ex_lockvar(exarg_T *eap)
-{
- char *arg = eap->arg;
- int deep = 2;
-
- if (eap->forceit) {
- deep = -1;
- } else if (ascii_isdigit(*arg)) {
- deep = getdigits_int(&arg, false, -1);
- arg = skipwhite(arg);
- }
-
- ex_unletlock(eap, arg, deep, do_lock_var);
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// Common parsing logic for :unlet, :lockvar and :unlockvar.
-///
-/// Invokes `callback` afterwards if successful and `eap->skip == false`.
-///
-/// @param[in] eap Ex command arguments for the command.
-/// @param[in] argstart Start of the string argument for the command.
-/// @param[in] deep Levels to (un)lock for :(un)lockvar, -1 to (un)lock
-/// everything.
-/// @param[in] callback Appropriate handler for the command.
-static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_callback callback)
- FUNC_ATTR_NONNULL_ALL
-{
- char *arg = argstart;
- char *name_end;
- bool error = false;
- lval_T lv;
-
- do {
- if (*arg == '$') {
- lv.ll_name = (const char *)arg;
- lv.ll_tv = NULL;
- arg++;
- if (get_env_len((const char **)&arg) == 0) {
- semsg(_(e_invarg2), arg - 1);
- return;
- }
- if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) {
- error = true;
- }
- name_end = arg;
- } else {
- // Parse the name and find the end.
- name_end = get_lval(arg, NULL, &lv, true, eap->skip || error,
- 0, FNE_CHECK_START);
- if (lv.ll_name == NULL) {
- error = true; // error, but continue parsing.
- }
- if (name_end == NULL
- || (!ascii_iswhite(*name_end) && !ends_excmd(*name_end))) {
- if (name_end != NULL) {
- emsg_severe = true;
- emsg(_(e_trailing));
- }
- if (!(eap->skip || error)) {
- clear_lval(&lv);
- }
- break;
- }
-
- if (!error && !eap->skip && callback(&lv, name_end, eap, deep) == FAIL) {
- error = true;
- }
-
- if (!eap->skip) {
- clear_lval(&lv);
- }
- }
- arg = skipwhite(name_end);
- } while (!ends_excmd(*arg));
-
- eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// Unlet a variable indicated by `lp`.
-///
-/// @param[in] lp The lvalue.
-/// @param[in] name_end End of the string argument for the command.
-/// @param[in] eap Ex command arguments for :unlet.
-/// @param[in] deep Unused.
-///
-/// @return OK on success, or FAIL on failure.
-static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ATTR_UNUSED)
- FUNC_ATTR_NONNULL_ALL
-{
- int forceit = eap->forceit;
- int ret = OK;
- int cc;
-
- if (lp->ll_tv == NULL) {
- cc = (char_u)(*name_end);
- *name_end = NUL;
-
- // Environment variable, normal name or expanded name.
- if (*lp->ll_name == '$') {
- os_unsetenv(lp->ll_name + 1);
- } else if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) {
- ret = FAIL;
- }
- *name_end = (char)cc;
- } else if ((lp->ll_list != NULL
- // ll_list is not NULL when lvalue is not in a list, NULL lists
- // yield E689.
- && var_check_lock(tv_list_locked(lp->ll_list),
- lp->ll_name,
- lp->ll_name_len))
- || (lp->ll_dict != NULL
- && var_check_lock(lp->ll_dict->dv_lock,
- lp->ll_name,
- lp->ll_name_len))) {
- return FAIL;
- } else if (lp->ll_range) {
- assert(lp->ll_list != NULL);
- // Delete a range of List items.
- listitem_T *const first_li = lp->ll_li;
- listitem_T *last_li = first_li;
- for (;;) {
- listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
- if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
- lp->ll_name,
- lp->ll_name_len)) {
- return false;
- }
- lp->ll_li = li;
- lp->ll_n1++;
- if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) {
- break;
- } else {
- last_li = lp->ll_li;
- }
- }
- tv_list_remove_items(lp->ll_list, first_li, last_li);
- } else {
- if (lp->ll_list != NULL) {
- // unlet a List item.
- tv_list_item_remove(lp->ll_list, lp->ll_li);
- } else {
- // unlet a Dictionary item.
- dict_T *d = lp->ll_dict;
- assert(d != NULL);
- dictitem_T *di = lp->ll_di;
- bool watched = tv_dict_is_watched(d);
- char *key = NULL;
- typval_T oldtv;
-
- if (watched) {
- tv_copy(&di->di_tv, &oldtv);
- // need to save key because dictitem_remove will free it
- key = xstrdup((char *)di->di_key);
- }
-
- tv_dict_item_remove(d, di);
-
- if (watched) {
- tv_dict_watcher_notify(d, key, NULL, &oldtv);
- tv_clear(&oldtv);
- xfree(key);
- }
- }
- }
-
- return ret;
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// unlet a variable
-///
-/// @param[in] name Variable name to unlet.
-/// @param[in] name_len Variable name length.
-/// @param[in] forceit If true, do not complain if variable doesn’t exist.
-///
-/// @return OK if it existed, FAIL otherwise.
-int do_unlet(const char *const name, const size_t name_len, const bool forceit)
- FUNC_ATTR_NONNULL_ALL
-{
- const char *varname;
- dict_T *dict;
- hashtab_T *ht = find_var_ht_dict(name, name_len, &varname, &dict);
-
- if (ht != NULL && *varname != NUL) {
- dict_T *d = get_current_funccal_dict(ht);
- if (d == NULL) {
- if (ht == &globvarht) {
- d = &globvardict;
- } else if (ht == &compat_hashtab) {
- d = &vimvardict;
- } else {
- dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
- d = di->di_tv.vval.v_dict;
- }
- if (d == NULL) {
- internal_error("do_unlet()");
- return FAIL;
- }
- }
-
- hashitem_T *hi = hash_find(ht, varname);
- if (HASHITEM_EMPTY(hi)) {
- hi = find_hi_in_scoped_ht(name, &ht);
- }
- if (hi != NULL && !HASHITEM_EMPTY(hi)) {
- dictitem_T *const di = TV_DICT_HI2DI(hi);
- if (var_check_fixed(di->di_flags, name, TV_CSTRING)
- || var_check_ro(di->di_flags, name, TV_CSTRING)
- || var_check_lock(d->dv_lock, name, TV_CSTRING)) {
- return FAIL;
- }
-
- if (var_check_lock(d->dv_lock, name, TV_CSTRING)) {
- return FAIL;
- }
-
- typval_T oldtv;
- bool watched = tv_dict_is_watched(dict);
-
- if (watched) {
- tv_copy(&di->di_tv, &oldtv);
- }
-
- delete_var(ht, hi);
-
- if (watched) {
- tv_dict_watcher_notify(dict, varname, NULL, &oldtv);
- tv_clear(&oldtv);
- }
- return OK;
- }
- }
- if (forceit) {
- return OK;
- }
- semsg(_("E108: No such variable: \"%s\""), name);
- return FAIL;
-}
-
-// TODO(ZyX-I): move to eval/ex_cmds
-
-/// Lock or unlock variable indicated by `lp`.
-///
-/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
-///
-/// @param[in] lp The lvalue.
-/// @param[in] name_end Unused.
-/// @param[in] eap Ex command arguments for :(un)lockvar.
-/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
-///
-/// @return OK on success, or FAIL on failure.
-static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap, int deep)
- FUNC_ATTR_NONNULL_ARG(1, 3)
-{
- bool lock = eap->cmdidx == CMD_lockvar;
- int ret = OK;
-
- if (deep == 0) { // Nothing to do.
- return OK;
- }
-
- if (lp->ll_tv == NULL) {
- if (*lp->ll_name == '$') {
- semsg(_(e_lock_unlock), lp->ll_name);
- ret = FAIL;
- } else {
- // Normal name or expanded name.
- dictitem_T *const di = find_var(lp->ll_name, lp->ll_name_len, NULL,
- true);
- if (di == NULL) {
- ret = FAIL;
- } else if ((di->di_flags & DI_FLAGS_FIX)
- && di->di_tv.v_type != VAR_DICT
- && di->di_tv.v_type != VAR_LIST) {
- // For historical reasons this error is not given for Lists and
- // Dictionaries. E.g. b: dictionary may be locked/unlocked.
- semsg(_(e_lock_unlock), lp->ll_name);
- ret = FAIL;
- } else {
- if (lock) {
- di->di_flags |= DI_FLAGS_LOCK;
- } else {
- di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK);
- }
- tv_item_lock(&di->di_tv, deep, lock, false);
- }
- }
- } else if (lp->ll_range) {
- listitem_T *li = lp->ll_li;
-
- // (un)lock a range of List items.
- while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
- tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock, false);
- li = TV_LIST_ITEM_NEXT(lp->ll_list, li);
- lp->ll_n1++;
- }
- } else if (lp->ll_list != NULL) {
- // (un)lock a List item.
- tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock, false);
- } else {
- // (un)lock a Dictionary item.
- tv_item_lock(&lp->ll_di->di_tv, deep, lock, false);
- }
-
- return ret;
-}
-
/// Delete all "menutrans_" variables.
void del_menutrans_vars(void)
{
@@ -4795,7 +3775,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
{
long numval;
char *stringval;
- int opt_type;
+ getoption_T opt_type;
bool working = (**arg == '+'); // has("+option")
int ret = OK;
int opt_flags;
@@ -4819,26 +3799,28 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
opt_type = get_option_value(*arg, &numval,
rettv == NULL ? NULL : &stringval, opt_flags);
- if (opt_type == -3) { // invalid name
+ if (opt_type == gov_unknown) {
if (rettv != NULL) {
semsg(_("E113: Unknown option: %s"), *arg);
}
ret = FAIL;
} else if (rettv != NULL) {
- if (opt_type == -2) { // hidden string option
+ if (opt_type == gov_hidden_string) {
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- } else if (opt_type == -1) { // hidden number option
+ } else if (opt_type == gov_hidden_bool || opt_type == gov_hidden_number) {
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
- } else if (opt_type == 1 || opt_type == 2) { // number or boolean option
+ } else if (opt_type == gov_bool || opt_type == gov_number) {
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = numval;
} else { // string option
rettv->v_type = VAR_STRING;
rettv->vval.v_string = stringval;
}
- } else if (working && (opt_type == -2 || opt_type == -1)) {
+ } else if (working && (opt_type == gov_hidden_bool
+ || opt_type == gov_hidden_number
+ || opt_type == gov_hidden_string)) {
ret = FAIL;
}
@@ -5685,7 +4667,7 @@ static inline bool set_ref_dict(dict_T *dict, int copyID)
return false;
}
-/// Get the key for *{key: val} into "tv" and advance "arg".
+/// Get the key for #{key: val} into "tv" and advance "arg".
///
/// @return FAIL when there is no valid key.
static int get_literal_key(char **arg, typval_T *tv)
@@ -5705,7 +4687,7 @@ static int get_literal_key(char **arg, typval_T *tv)
}
/// Allocate a variable for a Dictionary and fill it from "*arg".
-/// "literal" is true for *{key: val}
+/// "literal" is true for #{key: val}
///
/// @return OK or FAIL. Returns NOTDONE for {expr}.
static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal)
@@ -6480,73 +5462,6 @@ win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
return wp;
}
-/// getwinvar() and gettabwinvar()
-///
-/// @param off 1 for gettabwinvar()
-void getwinvar(typval_T *argvars, typval_T *rettv, int off)
-{
- win_T *win;
- dictitem_T *v;
- tabpage_T *tp = NULL;
- bool done = false;
-
- if (off == 1) {
- tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- } else {
- tp = curtab;
- }
- win = find_win_by_nr(&argvars[off], tp);
- const char *varname = tv_get_string_chk(&argvars[off + 1]);
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- emsg_off++;
- if (win != NULL && varname != NULL) {
- // Set curwin to be our win, temporarily. Also set the tabpage,
- // otherwise the window is not valid. Only do this when needed,
- // autocommands get blocked.
- bool need_switch_win = tp != curtab || win != curwin;
- switchwin_T switchwin;
- if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
- if (*varname == '&') {
- if (varname[1] == NUL) {
- // get all window-local options in a dict
- dict_T *opts = get_winbuf_options(false);
-
- if (opts != NULL) {
- tv_dict_set_ret(rettv, opts);
- done = true;
- }
- } else if (get_option_tv(&varname, rettv, 1) == OK) {
- // window-local-option
- done = true;
- }
- } else {
- // Look up the variable.
- // Let getwinvar({nr}, "") return the "w:" dictionary.
- v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname,
- strlen(varname), false);
- if (v != NULL) {
- tv_copy(&v->di_tv, rettv);
- done = true;
- }
- }
- }
-
- if (need_switch_win) {
- // restore previous notion of curwin
- restore_win(&switchwin, true);
- }
- }
- emsg_off--;
-
- if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) {
- // use the default return value
- tv_copy(&argvars[off + 2], rettv);
- }
-}
-
/// This function is used by f_input() and f_inputdialog() functions. The third
/// argument to f_input() specifies the type of completion to use at the
/// prompt. The third argument to f_inputdialog() specifies the value to return
@@ -6677,58 +5592,6 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
cmd_silent = cmd_silent_save;
}
-/// Turn a dictionary into a list
-///
-/// @param[in] tv Dictionary to convert. Is checked for actually being
-/// a dictionary, will give an error if not.
-/// @param[out] rettv Location where result will be saved.
-/// @param[in] what What to save in rettv.
-void dict_list(typval_T *const tv, typval_T *const rettv, const DictListType what)
-{
- if (tv->v_type != VAR_DICT) {
- emsg(_(e_dictreq));
- return;
- }
- if (tv->vval.v_dict == NULL) {
- return;
- }
-
- tv_list_alloc_ret(rettv, tv_dict_len(tv->vval.v_dict));
-
- TV_DICT_ITER(tv->vval.v_dict, di, {
- typval_T tv_item = { .v_lock = VAR_UNLOCKED };
-
- switch (what) {
- case kDictListKeys:
- tv_item.v_type = VAR_STRING;
- tv_item.vval.v_string = (char *)vim_strsave(di->di_key);
- break;
- case kDictListValues:
- tv_copy(&di->di_tv, &tv_item);
- break;
- case kDictListItems: {
- // items()
- list_T *const sub_l = tv_list_alloc(2);
- tv_item.v_type = VAR_LIST;
- tv_item.vval.v_list = sub_l;
- tv_list_ref(sub_l);
-
- tv_list_append_owned_tv(sub_l, (typval_T) {
- .v_type = VAR_STRING,
- .v_lock = VAR_UNLOCKED,
- .vval.v_string = xstrdup((const char *)di->di_key),
- });
-
- tv_list_append_tv(sub_l, &di->di_tv);
-
- break;
- }
- }
-
- tv_list_append_owned_tv(rettv->vval.v_list, tv_item);
- });
-}
-
/// Builds a process argument vector from a VimL object (typval_T).
///
/// @param[in] cmd_tv VimL object
@@ -6940,56 +5803,6 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
}
}
-/*
- * "setwinvar()" and "settabwinvar()" functions
- */
-
-void setwinvar(typval_T *argvars, typval_T *rettv, int off)
-{
- if (check_secure()) {
- return;
- }
-
- tabpage_T *tp = NULL;
- if (off == 1) {
- tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- } else {
- tp = curtab;
- }
- win_T *const win = find_win_by_nr(&argvars[off], tp);
- const char *varname = tv_get_string_chk(&argvars[off + 1]);
- typval_T *varp = &argvars[off + 2];
-
- if (win != NULL && varname != NULL && varp != NULL) {
- bool need_switch_win = tp != curtab || win != curwin;
- switchwin_T switchwin;
- if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
- if (*varname == '&') {
- long numval;
- bool error = false;
-
- varname++;
- numval = tv_get_number_chk(varp, &error);
- char nbuf[NUMBUFLEN];
- const char *const strval = tv_get_string_buf_chk(varp, nbuf);
- if (!error && strval != NULL) {
- set_option_value(varname, numval, strval, OPT_LOCAL);
- }
- } else {
- const size_t varname_len = strlen(varname);
- char *const winvarname = xmalloc(varname_len + 3);
- memcpy(winvarname, "w:", 2);
- memcpy(winvarname + 2, varname, varname_len + 1);
- set_var(winvarname, varname_len + 2, varp, true);
- xfree(winvarname);
- }
- }
- if (need_switch_win) {
- restore_win(&switchwin, true);
- }
- }
-}
-
/// "stdpath()" helper for list results
void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
FUNC_ATTR_NONNULL_ALL
@@ -7877,7 +6690,7 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c
/// Advance "arg" to the first character after the name.
///
/// @return 0 for error.
-static int get_env_len(const char **arg)
+int get_env_len(const char **arg)
{
int len;
@@ -8410,41 +7223,6 @@ char *set_cmdarg(exarg_T *eap, char *oldarg)
return oldval;
}
-/// Get the value of internal variable "name".
-/// Return OK or FAIL. If OK is returned "rettv" must be cleared.
-///
-/// @param len length of "name"
-/// @param rettv NULL when only checking existence
-/// @param dip non-NULL when typval's dict item is needed
-/// @param verbose may give error message
-/// @param no_autoload do not use script autoloading
-int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, int verbose,
- int no_autoload)
-{
- int ret = OK;
- typval_T *tv = NULL;
- dictitem_T *v;
-
- v = find_var(name, (size_t)len, NULL, no_autoload);
- if (v != NULL) {
- tv = &v->di_tv;
- if (dip != NULL) {
- *dip = v;
- }
- }
-
- if (tv == NULL) {
- if (rettv != NULL && verbose) {
- semsg(_("E121: Undefined variable: %.*s"), len, name);
- }
- ret = FAIL;
- } else if (rettv != NULL) {
- tv_copy(tv, rettv);
- }
-
- return ret;
-}
-
/// Check if variable "name[len]" is a local variable or an argument.
/// If so, "*eval_lavars_used" is set to true.
static void check_vars(const char *name, size_t len)
@@ -8710,8 +7488,8 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va
/// @param[out] d Scope dictionary.
///
/// @return Scope hashtab, NULL if name is not valid.
-static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
- dict_T **d)
+hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
+ dict_T **d)
{
hashitem_T *hi;
funccall_T *funccal = get_funccal();
@@ -8814,21 +7592,6 @@ hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **var
return find_var_ht_dict(name, name_len, varname, &d);
}
-/// @return the string value of a (global/local) variable or
-/// NULL when it doesn't exist.
-///
-/// @see tv_get_string() for how long the pointer remains valid.
-char_u *get_var_value(const char *const name)
-{
- dictitem_T *v;
-
- v = find_var(name, strlen(name), NULL, false);
- if (v == NULL) {
- return NULL;
- }
- return (char_u *)tv_get_string(&v->di_tv);
-}
-
/// Allocate a new hashtab for a sourced script. It will be used while
/// sourcing this script and when executing functions defined in the script.
void new_script_vars(scid_T id)
@@ -8884,391 +7647,6 @@ void unref_var_dict(dict_T *dict)
tv_dict_unref(dict);
}
-/// Clean up a list of internal variables.
-/// Frees all allocated variables and the value they contain.
-/// Clears hashtab "ht", does not free it.
-void vars_clear(hashtab_T *ht)
-{
- vars_clear_ext(ht, TRUE);
-}
-
-/// Like vars_clear(), but only free the value if "free_val" is TRUE.
-void vars_clear_ext(hashtab_T *ht, int free_val)
-{
- int todo;
- hashitem_T *hi;
- dictitem_T *v;
-
- hash_lock(ht);
- todo = (int)ht->ht_used;
- for (hi = ht->ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
-
- // Free the variable. Don't remove it from the hashtab,
- // ht_array might change then. hash_clear() takes care of it
- // later.
- v = TV_DICT_HI2DI(hi);
- if (free_val) {
- tv_clear(&v->di_tv);
- }
- if (v->di_flags & DI_FLAGS_ALLOC) {
- xfree(v);
- }
- }
- }
- hash_clear(ht);
- ht->ht_used = 0;
-}
-
-/// Delete a variable from hashtab "ht" at item "hi".
-/// Clear the variable value and free the dictitem.
-static void delete_var(hashtab_T *ht, hashitem_T *hi)
-{
- dictitem_T *di = TV_DICT_HI2DI(hi);
-
- hash_remove(ht, hi);
- tv_clear(&di->di_tv);
- xfree(di);
-}
-
-/// List the value of one internal variable.
-static void list_one_var(dictitem_T *v, const char *prefix, int *first)
-{
- char *const s = encode_tv2echo(&v->di_tv, NULL);
- list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)STRLEN(v->di_key),
- v->di_tv.v_type, (s == NULL ? "" : s), first);
- xfree(s);
-}
-
-/// @param[in] name_len Length of the name. May be -1, in this case strlen()
-/// will be used.
-/// @param[in,out] first When true clear rest of screen and set to false.
-static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t name_len,
- const VarType type, const char *string, int *first)
-{
- // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
- msg_start();
- msg_puts(prefix);
- if (name != NULL) { // "a:" vars don't have a name stored
- msg_puts_attr_len(name, name_len, 0);
- }
- msg_putchar(' ');
- msg_advance(22);
- if (type == VAR_NUMBER) {
- msg_putchar('#');
- } else if (type == VAR_FUNC || type == VAR_PARTIAL) {
- msg_putchar('*');
- } else if (type == VAR_LIST) {
- msg_putchar('[');
- if (*string == '[') {
- ++string;
- }
- } else if (type == VAR_DICT) {
- msg_putchar('{');
- if (*string == '{') {
- ++string;
- }
- } else {
- msg_putchar(' ');
- }
-
- msg_outtrans((char *)string);
-
- if (type == VAR_FUNC || type == VAR_PARTIAL) {
- msg_puts("()");
- }
- if (*first) {
- msg_clr_eos();
- *first = FALSE;
- }
-}
-
-/// Set variable to the given value
-///
-/// If the variable already exists, the value is updated. Otherwise the variable
-/// is created.
-///
-/// @param[in] name Variable name to set.
-/// @param[in] name_len Length of the variable name.
-/// @param tv Variable value.
-/// @param[in] copy True if value in tv is to be copied.
-void set_var(const char *name, const size_t name_len, typval_T *const tv, const bool copy)
- FUNC_ATTR_NONNULL_ALL
-{
- set_var_const(name, name_len, tv, copy, false);
-}
-
-/// Set variable to the given value
-///
-/// If the variable already exists, the value is updated. Otherwise the variable
-/// is created.
-///
-/// @param[in] name Variable name to set.
-/// @param[in] name_len Length of the variable name.
-/// @param tv Variable value.
-/// @param[in] copy True if value in tv is to be copied.
-/// @param[in] is_const True if value in tv is to be locked.
-static void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
- const bool copy, const bool is_const)
- FUNC_ATTR_NONNULL_ALL
-{
- dictitem_T *v;
- hashtab_T *ht;
- dict_T *dict;
-
- const char *varname;
- ht = find_var_ht_dict(name, name_len, &varname, &dict);
- const bool watched = tv_dict_is_watched(dict);
-
- if (ht == NULL || *varname == NUL) {
- semsg(_(e_illvar), name);
- return;
- }
- v = find_var_in_ht(ht, 0, varname, name_len - (size_t)(varname - name), true);
-
- // Search in parent scope which is possible to reference from lambda
- if (v == NULL) {
- v = find_var_in_scoped_ht(name, name_len, true);
- }
-
- if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
- return;
- }
-
- typval_T oldtv = TV_INITIAL_VALUE;
- if (v != NULL) {
- if (is_const) {
- emsg(_(e_cannot_mod));
- return;
- }
-
- // existing variable, need to clear the value
- if (var_check_ro(v->di_flags, name, name_len)
- || var_check_lock(v->di_tv.v_lock, name, name_len)) {
- return;
- }
-
- // Handle setting internal v: variables separately where needed to
- // prevent changing the type.
- if (ht == &vimvarht) {
- if (v->di_tv.v_type == VAR_STRING) {
- XFREE_CLEAR(v->di_tv.vval.v_string);
- if (copy || tv->v_type != VAR_STRING) {
- const char *const val = tv_get_string(tv);
-
- // Careful: when assigning to v:errmsg and tv_get_string()
- // causes an error message the variable will already be set.
- if (v->di_tv.vval.v_string == NULL) {
- v->di_tv.vval.v_string = xstrdup(val);
- }
- } else {
- // Take over the string to avoid an extra alloc/free.
- v->di_tv.vval.v_string = tv->vval.v_string;
- tv->vval.v_string = NULL;
- }
- return;
- } else if (v->di_tv.v_type == VAR_NUMBER) {
- v->di_tv.vval.v_number = tv_get_number(tv);
- if (strcmp(varname, "searchforward") == 0) {
- set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
- } else if (strcmp(varname, "hlsearch") == 0) {
- no_hlsearch = !v->di_tv.vval.v_number;
- redraw_all_later(SOME_VALID);
- }
- return;
- } else if (v->di_tv.v_type != tv->v_type) {
- semsg(_("E963: setting %s to value with wrong type"), name);
- return;
- }
- }
-
- if (watched) {
- tv_copy(&v->di_tv, &oldtv);
- }
- tv_clear(&v->di_tv);
- } else { // Add a new variable.
- // Can't add "v:" or "a:" variable.
- if (ht == &vimvarht || ht == get_funccal_args_ht()) {
- semsg(_(e_illvar), name);
- return;
- }
-
- // Make sure the variable name is valid.
- if (!valid_varname(varname)) {
- return;
- }
-
- // Make sure dict is valid
- assert(dict != NULL);
-
- v = xmalloc(sizeof(dictitem_T) + strlen(varname));
- STRCPY(v->di_key, varname);
- if (tv_dict_add(dict, v) == FAIL) {
- xfree(v);
- return;
- }
- v->di_flags = DI_FLAGS_ALLOC;
- if (is_const) {
- v->di_flags |= DI_FLAGS_LOCK;
- }
- }
-
- if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
- tv_copy(tv, &v->di_tv);
- } else {
- v->di_tv = *tv;
- v->di_tv.v_lock = VAR_UNLOCKED;
- tv_init(tv);
- }
-
- if (watched) {
- if (oldtv.v_type == VAR_UNKNOWN) {
- tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
- } else {
- tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
- tv_clear(&oldtv);
- }
- }
-
- if (is_const) {
- // Like :lockvar! name: lock the value and what it contains, but only
- // if the reference count is up to one. That locks only literal
- // values.
- tv_item_lock(&v->di_tv, DICT_MAXNEST, true, true);
- }
-}
-
-/// Check whether variable is read-only (DI_FLAGS_RO, DI_FLAGS_RO_SBX)
-///
-/// Also gives an error message.
-///
-/// @param[in] flags di_flags attribute value.
-/// @param[in] name Variable name, for use in error message.
-/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
-/// variable name and compute the length. Use #TV_CSTRING
-/// to compute the length with strlen() without
-/// translating.
-///
-/// Both #TV_… values are used for optimization purposes:
-/// variable name with its length is needed only in case
-/// of error, when no error occurs computing them is
-/// a waste of CPU resources. This especially applies to
-/// gettext.
-///
-/// @return True if variable is read-only: either always or in sandbox when
-/// sandbox is enabled, false otherwise.
-bool var_check_ro(const int flags, const char *name, size_t name_len)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
-{
- const char *error_message = NULL;
- if (flags & DI_FLAGS_RO) {
- error_message = _(e_readonlyvar);
- } else if ((flags & DI_FLAGS_RO_SBX) && sandbox) {
- error_message = N_("E794: Cannot set variable in the sandbox: \"%.*s\"");
- }
-
- if (error_message == NULL) {
- return false;
- }
- if (name_len == TV_TRANSLATE) {
- name = _(name);
- name_len = strlen(name);
- } else if (name_len == TV_CSTRING) {
- name_len = strlen(name);
- }
-
- semsg(_(error_message), (int)name_len, name);
-
- return true;
-}
-
-/// Check whether variable is fixed (DI_FLAGS_FIX)
-///
-/// Also gives an error message.
-///
-/// @param[in] flags di_flags attribute value.
-/// @param[in] name Variable name, for use in error message.
-/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
-/// variable name and compute the length. Use #TV_CSTRING
-/// to compute the length with strlen() without
-/// translating.
-///
-/// Both #TV_… values are used for optimization purposes:
-/// variable name with its length is needed only in case
-/// of error, when no error occurs computing them is
-/// a waste of CPU resources. This especially applies to
-/// gettext.
-///
-/// @return True if variable is fixed, false otherwise.
-bool var_check_fixed(const int flags, const char *name, size_t name_len)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
-{
- if (flags & DI_FLAGS_FIX) {
- if (name_len == TV_TRANSLATE) {
- name = _(name);
- name_len = strlen(name);
- } else if (name_len == TV_CSTRING) {
- name_len = strlen(name);
- }
- semsg(_("E795: Cannot delete variable %.*s"), (int)name_len, name);
- return true;
- }
- return false;
-}
-
-// TODO(ZyX-I): move to eval/expressions
-
-/// Check if name is a valid name to assign funcref to
-///
-/// @param[in] name Possible function/funcref name.
-/// @param[in] new_var True if it is a name for a variable.
-///
-/// @return false in case of error, true in case of success. Also gives an
-/// error message if appropriate.
-bool var_check_func_name(const char *const name, const bool new_var)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
- // Allow for w: b: s: and t:.
- if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':')
- && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
- ? name[2] : name[0])) {
- semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
- return false;
- }
- // Don't allow hiding a function. When "v" is not NULL we might be
- // assigning another function to the same var, the type is checked
- // below.
- if (new_var && function_exists(name, false)) {
- semsg(_("E705: Variable name conflicts with existing function: %s"),
- name);
- return false;
- }
- return true;
-}
-
-// TODO(ZyX-I): move to eval/expressions
-
-/// Check if a variable name is valid
-///
-/// @param[in] varname Variable name to check.
-///
-/// @return false when variable name is not valid, true when it is. Also gives
-/// an error message if appropriate.
-bool valid_varname(const char *varname)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
- for (const char *p = varname; *p != NUL; p++) {
- if (!eval_isnamec1((int)(uint8_t)(*p))
- && (p == varname || !ascii_isdigit(*p))
- && *p != AUTOLOAD_CHAR) {
- semsg(_(e_illvar), varname);
- return false;
- }
- }
- return true;
-}
-
/// Make a copy of an item
///
/// Lists and Dictionaries are also copied.
@@ -9533,7 +7911,7 @@ void ex_execute(exarg_T *eap)
///
/// @return NULL when no option name found. Otherwise pointer to the char
/// after the option name.
-static const char *find_option_end(const char **const arg, int *const opt_flags)
+const char *find_option_end(const char **const arg, int *const opt_flags)
{
const char *p = *arg;
@@ -10895,35 +9273,3 @@ char *typval_tostring(typval_T *arg)
}
return encode_tv2string(arg, NULL);
}
-
-bool var_exists(const char *var)
- FUNC_ATTR_NONNULL_ALL
-{
- char *tofree;
- bool n = false;
-
- // get_name_len() takes care of expanding curly braces
- const char *name = var;
- const int len = get_name_len(&var, &tofree, true, false);
- if (len > 0) {
- typval_T tv;
-
- if (tofree != NULL) {
- name = tofree;
- }
- n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
- if (n) {
- // Handle d.key, l[idx], f(expr).
- n = handle_subscript(&var, &tv, true, false, name, &name) == OK;
- if (n) {
- tv_clear(&tv);
- }
- }
- }
- if (*var != NUL) {
- n = false;
- }
-
- xfree(tofree);
- return n;
-}
diff --git a/src/nvim/eval.c.orig b/src/nvim/eval.c.orig
new file mode 100644
index 0000000000..9bfb2cd7d6
--- /dev/null
+++ b/src/nvim/eval.c.orig
@@ -0,0 +1,9995 @@
+// 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
+
+/*
+ * eval.c: Expression evaluation.
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "auto/config.h"
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "nvim/ascii.h"
+#include "nvim/buffer.h"
+#include "nvim/change.h"
+#include "nvim/channel.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/edit.h"
+#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval/gc.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
+#include "nvim/ex_cmds2.h"
+#include "nvim/ex_getln.h"
+#include "nvim/ex_session.h"
+#include "nvim/fileio.h"
+#include "nvim/getchar.h"
+#include "nvim/highlight_group.h"
+#include "nvim/lua/executor.h"
+#include "nvim/mark.h"
+#include "nvim/memline.h"
+#include "nvim/move.h"
+#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/shell.h"
+#include "nvim/path.h"
+#include "nvim/quickfix.h"
+#include "nvim/regexp.h"
+#include "nvim/screen.h"
+#include "nvim/search.h"
+#include "nvim/sign.h"
+#include "nvim/syntax.h"
+#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
+#include "nvim/undo.h"
+#include "nvim/version.h"
+#include "nvim/window.h"
+
+// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
+
+#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
+
+static char *e_missbrac = N_("E111: Missing ']'");
+static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
+static char *e_nowhitespace
+ = N_("E274: No white space allowed before parenthesis");
+static char *e_write2 = N_("E80: Error while writing: %s");
+static char *e_string_list_or_blob_required = N_("E1098: String, List or Blob required");
+
+static char * const namespace_char = "abglstvw";
+
+/// Variable used for g:
+static ScopeDictDictItem globvars_var;
+
+/*
+ * Old Vim variables such as "v:version" are also available without the "v:".
+ * Also in functions. We need a special hashtable for them.
+ */
+static hashtab_T compat_hashtab;
+
+/// Used for checking if local variables or arguments used in a lambda.
+bool *eval_lavars_used = NULL;
+
+/*
+ * Array to hold the hashtab with variables local to each sourced script.
+ * Each item holds a variable (nameless) that points to the dict_T.
+ */
+typedef struct {
+ ScopeDictDictItem sv_var;
+ dict_T sv_dict;
+} scriptvar_T;
+
+static garray_T ga_scripts = { 0, 0, sizeof(scriptvar_T *), 4, NULL };
+#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1])
+#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
+
+static int echo_attr = 0; // attributes used for ":echo"
+
+// The names of packages that once were loaded are remembered.
+static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL };
+
+/*
+ * Info used by a ":for" loop.
+ */
+typedef struct {
+ int fi_semicolon; // TRUE if ending in '; var]'
+ int fi_varcount; // nr of variables in the list
+ listwatch_T fi_lw; // keep an eye on the item used.
+ list_T *fi_list; // list being used
+ int fi_bi; // index of blob
+ blob_T *fi_blob; // blob being used
+ char *fi_string; // copy of string being used
+ int fi_byte_idx; // byte index in fi_string
+} forinfo_T;
+
+// values for vv_flags:
+#define VV_COMPAT 1 // compatible, also used without "v:"
+#define VV_RO 2 // read-only
+#define VV_RO_SBX 4 // read-only in the sandbox
+
+#define VV(idx, name, type, flags) \
+ [idx] = { \
+ .vv_name = (name), \
+ .vv_di = { \
+ .di_tv = { .v_type = (type) }, \
+ .di_flags = 0, \
+ .di_key = { 0 }, \
+ }, \
+ .vv_flags = (flags), \
+ }
+
+#define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables
+
+// Array to hold the value of v: variables.
+// The value is in a dictitem, so that it can also be used in the v: scope.
+// The reason to use this table anyway is for very quick access to the
+// variables with the VV_ defines.
+static struct vimvar {
+ char *vv_name; ///< Name of the variable, without v:.
+ TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di; ///< Value and name for key (max 16 chars).
+ char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
+} vimvars[] =
+{
+ // VV_ tails differing from upcased string literals:
+ // VV_CC_FROM "charconvert_from"
+ // VV_CC_TO "charconvert_to"
+ // VV_SEND_SERVER "servername"
+ // VV_REG "register"
+ // VV_OP "operator"
+ VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
+ VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
+ VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
+ VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
+ VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
+ VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
+ VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
+ VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
+ VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT + VV_RO),
+ VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
+ VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
+ VV(VV_LANG, "lang", VAR_STRING, VV_RO),
+ VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
+ VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
+ VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
+ VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
+ VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
+ VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
+ VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
+ VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
+ VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
+ VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
+ VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
+ VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
+ VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
+ VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
+ VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
+ VV(VV_REG, "register", VAR_STRING, VV_RO),
+ VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
+ VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
+ VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
+ VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
+ VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
+ VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
+ VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
+ VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
+ VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
+ VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
+ VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
+ VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
+ VV(VV_CHAR, "char", VAR_STRING, 0),
+ VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
+ VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
+ VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
+ VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
+ VV(VV_OP, "operator", VAR_STRING, VV_RO),
+ VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
+ VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
+ VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
+ VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
+ VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, 0),
+ VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
+ VV(VV_OPTION_COMMAND, "option_command", VAR_STRING, VV_RO),
+ VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
+ VV(VV_ERRORS, "errors", VAR_LIST, 0),
+ VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
+ VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
+ VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
+ VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
+ VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
+ VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
+ VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
+ VV(VV_TESTING, "testing", VAR_NUMBER, 0),
+ VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
+ VV(VV_EVENT, "event", VAR_DICT, VV_RO),
+ VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
+ VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
+ VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
+ VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
+ // Neovim
+ VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
+ VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
+ VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
+ VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
+ VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
+ VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
+ VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
+};
+#undef VV
+
+// shorthand
+#define vv_type vv_di.di_tv.v_type
+#define vv_nr vv_di.di_tv.vval.v_number
+#define vv_bool vv_di.di_tv.vval.v_bool
+#define vv_special vv_di.di_tv.vval.v_special
+#define vv_float vv_di.di_tv.vval.v_float
+#define vv_str vv_di.di_tv.vval.v_string
+#define vv_list vv_di.di_tv.vval.v_list
+#define vv_dict vv_di.di_tv.vval.v_dict
+#define vv_blob vv_di.di_tv.vval.v_blob
+#define vv_partial vv_di.di_tv.vval.v_partial
+#define vv_tv vv_di.di_tv
+
+/// Variable used for v:
+static ScopeDictDictItem vimvars_var;
+
+static partial_T *vvlua_partial;
+
+/// v: hashtab
+#define vimvarht vimvardict.dv_hashtab
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval.c.generated.h"
+#endif
+
+static uint64_t last_timer_id = 1;
+static PMap(uint64_t) timers = MAP_INIT;
+
+static const char *const msgpack_type_names[] = {
+ [kMPNil] = "nil",
+ [kMPBoolean] = "boolean",
+ [kMPInteger] = "integer",
+ [kMPFloat] = "float",
+ [kMPString] = "string",
+ [kMPBinary] = "binary",
+ [kMPArray] = "array",
+ [kMPMap] = "map",
+ [kMPExt] = "ext",
+};
+const list_T *eval_msgpack_type_lists[] = {
+ [kMPNil] = NULL,
+ [kMPBoolean] = NULL,
+ [kMPInteger] = NULL,
+ [kMPFloat] = NULL,
+ [kMPString] = NULL,
+ [kMPBinary] = NULL,
+ [kMPArray] = NULL,
+ [kMPMap] = NULL,
+ [kMPExt] = NULL,
+};
+
+dict_T *get_v_event(save_v_event_T *sve)
+{
+ dict_T *v_event = get_vim_var_dict(VV_EVENT);
+
+ if (v_event->dv_hashtab.ht_used > 0) {
+ // recursive use of v:event, save, make empty and restore later
+ sve->sve_did_save = true;
+ sve->sve_hashtab = v_event->dv_hashtab;
+ hash_init(&v_event->dv_hashtab);
+ } else {
+ sve->sve_did_save = false;
+ }
+ return v_event;
+}
+
+void restore_v_event(dict_T *v_event, save_v_event_T *sve)
+{
+ tv_dict_free_contents(v_event);
+ if (sve->sve_did_save) {
+ v_event->dv_hashtab = sve->sve_hashtab;
+ } else {
+ hash_init(&v_event->dv_hashtab);
+ }
+}
+
+/// @return "n1" divided by "n2", taking care of dividing by zero.
+varnumber_T num_divide(varnumber_T n1, varnumber_T n2)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ varnumber_T result;
+
+ if (n2 == 0) { // give an error message?
+ if (n1 == 0) {
+ result = VARNUMBER_MIN; // similar to NaN
+ } else if (n1 < 0) {
+ result = -VARNUMBER_MAX;
+ } else {
+ result = VARNUMBER_MAX;
+ }
+ } else {
+ result = n1 / n2;
+ }
+
+ return result;
+}
+
+/// @return "n1" modulus "n2", taking care of dividing by zero.
+varnumber_T num_modulus(varnumber_T n1, varnumber_T n2)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Give an error when n2 is 0?
+ return (n2 == 0) ? 0 : (n1 % n2);
+}
+
+/// Initialize the global and v: variables.
+void eval_init(void)
+{
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+
+ struct vimvar *p;
+
+ init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
+ init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
+ vimvardict.dv_lock = VAR_FIXED;
+ hash_init(&compat_hashtab);
+ func_init();
+
+ for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
+ p = &vimvars[i];
+ assert(STRLEN(p->vv_name) <= VIMVAR_KEY_LEN);
+ STRCPY(p->vv_di.di_key, p->vv_name);
+ if (p->vv_flags & VV_RO) {
+ p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ } else if (p->vv_flags & VV_RO_SBX) {
+ p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
+ } else {
+ p->vv_di.di_flags = DI_FLAGS_FIX;
+ }
+
+ // add to v: scope dict, unless the value is not always available
+ if (p->vv_type != VAR_UNKNOWN) {
+ hash_add(&vimvarht, p->vv_di.di_key);
+ }
+ if (p->vv_flags & VV_COMPAT) {
+ // add to compat scope dict
+ hash_add(&compat_hashtab, p->vv_di.di_key);
+ }
+ }
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+
+ dict_T *const msgpack_types_dict = tv_dict_alloc();
+ for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
+ list_T *const type_list = tv_list_alloc(0);
+ tv_list_set_lock(type_list, VAR_FIXED);
+ tv_list_ref(type_list);
+ dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
+ di->di_flags |= DI_FLAGS_RO|DI_FLAGS_FIX;
+ di->di_tv = (typval_T) {
+ .v_type = VAR_LIST,
+ .vval = { .v_list = type_list, },
+ };
+ eval_msgpack_type_lists[i] = type_list;
+ if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
+ // There must not be duplicate items in this dictionary by definition.
+ abort();
+ }
+ }
+ msgpack_types_dict->dv_lock = VAR_FIXED;
+
+ set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
+
+ set_vim_var_dict(VV_EVENT, tv_dict_alloc_lock(VAR_FIXED));
+ set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
+ set_vim_var_nr(VV_STDERR, CHAN_STDERR);
+ set_vim_var_nr(VV_SEARCHFORWARD, 1L);
+ set_vim_var_nr(VV_HLSEARCH, 1L);
+ set_vim_var_nr(VV_COUNT1, 1);
+ set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
+ set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
+ set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
+ set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
+ set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
+ set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
+ set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
+ set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
+
+ set_vim_var_bool(VV_FALSE, kBoolVarFalse);
+ set_vim_var_bool(VV_TRUE, kBoolVarTrue);
+ set_vim_var_special(VV_NULL, kSpecialVarNull);
+ set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
+ set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
+ set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
+ set_vim_var_special(VV_EXITING, kSpecialVarNull);
+
+ set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
+
+ vimvars[VV_LUA].vv_type = VAR_PARTIAL;
+ vvlua_partial = xcalloc(1, sizeof(partial_T));
+ vimvars[VV_LUA].vv_partial = vvlua_partial;
+ // this value shouldn't be printed, but if it is, do not crash
+ vvlua_partial->pt_name = xmallocz(0);
+ vvlua_partial->pt_refcount++;
+
+ set_reg_var(0); // default for v:register is not 0 but '"'
+}
+
+#if defined(EXITFREE)
+void eval_clear(void)
+{
+ struct vimvar *p;
+
+ for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
+ p = &vimvars[i];
+ if (p->vv_di.di_tv.v_type == VAR_STRING) {
+ XFREE_CLEAR(p->vv_str);
+ } else if (p->vv_di.di_tv.v_type == VAR_LIST) {
+ tv_list_unref(p->vv_list);
+ p->vv_list = NULL;
+ }
+ }
+ hash_clear(&vimvarht);
+ hash_init(&vimvarht); // garbage_collect() will access it
+ hash_clear(&compat_hashtab);
+
+ free_scriptnames();
+# ifdef HAVE_WORKING_LIBINTL
+ free_locales();
+# endif
+
+ // global variables
+ vars_clear(&globvarht);
+
+ // autoloaded script names
+ ga_clear_strings(&ga_loaded);
+
+ /* Script-local variables. First clear all the variables and in a second
+ * loop free the scriptvar_T, because a variable in one script might hold
+ * a reference to the whole scope of another script. */
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
+ vars_clear(&SCRIPT_VARS(i));
+ }
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
+ xfree(SCRIPT_SV(i));
+ }
+ ga_clear(&ga_scripts);
+
+ // unreferenced lists and dicts
+ (void)garbage_collect(false);
+
+ // functions not garbage collected
+ free_all_functions();
+}
+
+#endif
+
+/// Set an internal variable to a string value. Creates the variable if it does
+/// not already exist.
+void set_internal_string_var(const char *name, char *value)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ typval_T tv = {
+ .v_type = VAR_STRING,
+ .vval.v_string = value,
+ };
+
+ set_var(name, strlen(name), &tv, true);
+}
+
+static lval_T *redir_lval = NULL;
+static garray_T redir_ga; // Only valid when redir_lval is not NULL.
+static char *redir_endp = NULL;
+static char *redir_varname = NULL;
+
+/// Start recording command output to a variable
+///
+/// @param append append to an existing variable
+///
+/// @return OK if successfully completed the setup. FAIL otherwise.
+int var_redir_start(char *name, int append)
+{
+ int save_emsg;
+ int err;
+ typval_T tv;
+
+ // Catch a bad name early.
+ if (!eval_isnamec1(*name)) {
+ emsg(_(e_invarg));
+ return FAIL;
+ }
+
+ // Make a copy of the name, it is used in redir_lval until redir ends.
+ redir_varname = xstrdup(name);
+
+ redir_lval = xcalloc(1, sizeof(lval_T));
+
+ // The output is stored in growarray "redir_ga" until redirection ends.
+ ga_init(&redir_ga, (int)sizeof(char), 500);
+
+ // Parse the variable name (can be a dict or list entry).
+ redir_endp = get_lval(redir_varname, NULL, redir_lval, false, false,
+ 0, FNE_CHECK_START);
+ if (redir_endp == NULL || redir_lval->ll_name == NULL
+ || *redir_endp != NUL) {
+ clear_lval(redir_lval);
+ if (redir_endp != NULL && *redir_endp != NUL) {
+ // Trailing characters are present after the variable name
+ emsg(_(e_trailing));
+ } else {
+ emsg(_(e_invarg));
+ }
+ redir_endp = NULL; // don't store a value, only cleanup
+ var_redir_stop();
+ return FAIL;
+ }
+
+ /* check if we can write to the variable: set it to or append an empty
+ * string */
+ save_emsg = did_emsg;
+ did_emsg = FALSE;
+ tv.v_type = VAR_STRING;
+ tv.vval.v_string = "";
+ if (append) {
+ set_var_lval(redir_lval, redir_endp, &tv, true, false, ".");
+ } else {
+ set_var_lval(redir_lval, redir_endp, &tv, true, false, "=");
+ }
+ clear_lval(redir_lval);
+ err = did_emsg;
+ did_emsg |= save_emsg;
+ if (err) {
+ redir_endp = NULL; // don't store a value, only cleanup
+ var_redir_stop();
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/// Append "value[value_len]" to the variable set by var_redir_start().
+/// The actual appending is postponed until redirection ends, because the value
+/// appended may in fact be the string we write to, changing it may cause freed
+/// memory to be used:
+/// :redir => foo
+/// :let foo
+/// :redir END
+void var_redir_str(char *value, int value_len)
+{
+ int len;
+
+ if (redir_lval == NULL) {
+ return;
+ }
+
+ if (value_len == -1) {
+ len = (int)STRLEN(value); // Append the entire string
+ } else {
+ len = value_len; // Append only "value_len" characters
+ }
+
+ ga_grow(&redir_ga, len);
+ memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, (size_t)len);
+ redir_ga.ga_len += len;
+}
+
+/// Stop redirecting command output to a variable.
+/// Frees the allocated memory.
+void var_redir_stop(void)
+{
+ typval_T tv;
+
+ if (redir_lval != NULL) {
+ // If there was no error: assign the text to the variable.
+ if (redir_endp != NULL) {
+ ga_append(&redir_ga, NUL); // Append the trailing NUL.
+ tv.v_type = VAR_STRING;
+ tv.vval.v_string = redir_ga.ga_data;
+ // Call get_lval() again, if it's inside a Dict or List it may
+ // have changed.
+ redir_endp = get_lval(redir_varname, NULL, redir_lval,
+ false, false, 0, FNE_CHECK_START);
+ if (redir_endp != NULL && redir_lval->ll_name != NULL) {
+ set_var_lval(redir_lval, redir_endp, &tv, false, false, ".");
+ }
+ clear_lval(redir_lval);
+ }
+
+ // free the collected output
+ XFREE_CLEAR(redir_ga.ga_data);
+
+ XFREE_CLEAR(redir_lval);
+ }
+ XFREE_CLEAR(redir_varname);
+}
+
+int eval_charconvert(const char *const enc_from, const char *const enc_to,
+ const char *const fname_from, const char *const fname_to)
+{
+ bool err = false;
+
+ set_vim_var_string(VV_CC_FROM, enc_from, -1);
+ set_vim_var_string(VV_CC_TO, enc_to, -1);
+ set_vim_var_string(VV_FNAME_IN, fname_from, -1);
+ set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
+ if (eval_to_bool((char *)p_ccv, &err, NULL, false)) {
+ err = true;
+ }
+ set_vim_var_string(VV_CC_FROM, NULL, -1);
+ set_vim_var_string(VV_CC_TO, NULL, -1);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+
+ if (err) {
+ return FAIL;
+ }
+ return OK;
+}
+
+int eval_printexpr(const char *const fname, const char *const args)
+{
+ bool err = false;
+
+ set_vim_var_string(VV_FNAME_IN, fname, -1);
+ set_vim_var_string(VV_CMDARG, args, -1);
+ if (eval_to_bool((char *)p_pexpr, &err, NULL, false)) {
+ err = true;
+ }
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_CMDARG, NULL, -1);
+
+ if (err) {
+ os_remove(fname);
+ return FAIL;
+ }
+ return OK;
+}
+
+void eval_diff(const char *const origfile, const char *const newfile, const char *const outfile)
+{
+ bool err = false;
+
+ set_vim_var_string(VV_FNAME_IN, origfile, -1);
+ set_vim_var_string(VV_FNAME_NEW, newfile, -1);
+ set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+ (void)eval_to_bool((char *)p_dex, &err, NULL, false);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_NEW, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+
+void eval_patch(const char *const origfile, const char *const difffile, const char *const outfile)
+{
+ bool err = false;
+
+ set_vim_var_string(VV_FNAME_IN, origfile, -1);
+ set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
+ set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+ (void)eval_to_bool((char *)p_pex, &err, NULL, false);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+
+/// Top level evaluation function, returning a boolean.
+/// Sets "error" to TRUE if there was an error.
+///
+/// @param skip only parse, don't execute
+///
+/// @return TRUE or FALSE.
+int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip)
+{
+ typval_T tv;
+ bool retval = false;
+
+ if (skip) {
+ emsg_skip++;
+ }
+ if (eval0(arg, &tv, nextcmd, !skip) == FAIL) {
+ *error = true;
+ } else {
+ *error = false;
+ if (!skip) {
+ retval = (tv_get_number_chk(&tv, error) != 0);
+ tv_clear(&tv);
+ }
+ }
+ if (skip) {
+ emsg_skip--;
+ }
+
+ return retval;
+}
+
+/// Call eval1() and give an error message if not done at a lower level.
+static int eval1_emsg(char **arg, typval_T *rettv, bool evaluate)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ const char *const start = *arg;
+ const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
+
+ const int ret = eval1(arg, rettv, evaluate);
+ if (ret == FAIL) {
+ // Report the invalid expression unless the expression evaluation has
+ // been cancelled due to an aborting error, an interrupt, or an
+ // exception, or we already gave a more specific error.
+ // Also check called_emsg for when using assert_fails().
+ if (!aborting()
+ && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before) {
+ semsg(_(e_invexpr2), start);
+ }
+ }
+ return ret;
+}
+
+/// @return whether a typval is a valid expression to pass to eval_expr_typval()
+/// or eval_expr_to_bool(). An empty string returns false;
+bool eval_expr_valid_arg(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_CONST
+{
+ return tv->v_type != VAR_UNKNOWN
+ && (tv->v_type != VAR_STRING || (tv->vval.v_string != NULL && *tv->vval.v_string != NUL));
+}
+
+int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
+{
+ funcexe_T funcexe = FUNCEXE_INIT;
+
+ if (expr->v_type == VAR_FUNC) {
+ const char *const s = expr->vval.v_string;
+ if (s == NULL || *s == NUL) {
+ return FAIL;
+ }
+ funcexe.evaluate = true;
+ if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
+ return FAIL;
+ }
+ } else if (expr->v_type == VAR_PARTIAL) {
+ partial_T *const partial = expr->vval.v_partial;
+ const char *const s = partial_name(partial);
+ if (s == NULL || *s == NUL) {
+ return FAIL;
+ }
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
+ return FAIL;
+ }
+ } else {
+ char buf[NUMBUFLEN];
+ char *s = (char *)tv_get_string_buf_chk(expr, buf);
+ if (s == NULL) {
+ return FAIL;
+ }
+ s = skipwhite(s);
+ if (eval1_emsg(&s, rettv, true) == FAIL) {
+ return FAIL;
+ }
+ if (*skipwhite(s) != NUL) { // check for trailing chars after expr
+ tv_clear(rettv);
+ semsg(_(e_invexpr2), s);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/// Like eval_to_bool() but using a typval_T instead of a string.
+/// Works for string, funcref and partial.
+bool eval_expr_to_bool(const typval_T *expr, bool *error)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ typval_T argv, rettv;
+
+ if (eval_expr_typval(expr, &argv, 0, &rettv) == FAIL) {
+ *error = true;
+ return false;
+ }
+ const bool res = (tv_get_number_chk(&rettv, error) != 0);
+ tv_clear(&rettv);
+ return res;
+}
+
+/// Top level evaluation function, returning a string
+///
+/// @param[in] arg String to evaluate.
+/// @param nextcmd Pointer to the start of the next Ex command.
+/// @param[in] skip If true, only do parsing to nextcmd without reporting
+/// errors or actually evaluating anything.
+///
+/// @return [allocated] string result of evaluation or NULL in case of error or
+/// when skipping.
+char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip)
+ FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ typval_T tv;
+ char *retval;
+
+ if (skip) {
+ emsg_skip++;
+ }
+ if (eval0((char *)arg, &tv, (char **)nextcmd, !skip) == FAIL || skip) {
+ retval = NULL;
+ } else {
+ retval = xstrdup(tv_get_string(&tv));
+ tv_clear(&tv);
+ }
+ if (skip) {
+ emsg_skip--;
+ }
+
+ return retval;
+}
+
+/// Skip over an expression at "*pp".
+///
+/// @return FAIL for an error, OK otherwise.
+int skip_expr(char **pp)
+{
+ typval_T rettv;
+
+ *pp = skipwhite(*pp);
+ return eval1(pp, &rettv, false);
+}
+
+/// Top level evaluation function, returning a string.
+///
+/// @param convert when true convert a List into a sequence of lines and convert
+/// a Float to a String.
+///
+/// @return pointer to allocated memory, or NULL for failure.
+char *eval_to_string(char *arg, char **nextcmd, bool convert)
+{
+ typval_T tv;
+ char *retval;
+ garray_T ga;
+
+ if (eval0(arg, &tv, nextcmd, true) == FAIL) {
+ retval = NULL;
+ } else {
+ if (convert && tv.v_type == VAR_LIST) {
+ ga_init(&ga, (int)sizeof(char), 80);
+ if (tv.vval.v_list != NULL) {
+ tv_list_join(&ga, tv.vval.v_list, "\n");
+ if (tv_list_len(tv.vval.v_list) > 0) {
+ ga_append(&ga, NL);
+ }
+ }
+ ga_append(&ga, NUL);
+ retval = (char *)ga.ga_data;
+ } else if (convert && tv.v_type == VAR_FLOAT) {
+ char numbuf[NUMBUFLEN];
+ vim_snprintf(numbuf, NUMBUFLEN, "%g", tv.vval.v_float);
+ retval = xstrdup(numbuf);
+ } else {
+ retval = xstrdup(tv_get_string(&tv));
+ }
+ tv_clear(&tv);
+ }
+
+ return retval;
+}
+
+/// Call eval_to_string() without using current local variables and using
+/// textlock.
+///
+/// @param use_sandbox when TRUE, use the sandbox.
+char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox)
+{
+ char *retval;
+ funccal_entry_T funccal_entry;
+
+ save_funccal(&funccal_entry);
+ if (use_sandbox) {
+ sandbox++;
+ }
+ textlock++;
+ retval = eval_to_string(arg, nextcmd, false);
+ if (use_sandbox) {
+ sandbox--;
+ }
+ textlock--;
+ restore_funccal();
+ return retval;
+}
+
+/// Top level evaluation function, returning a number.
+/// Evaluates "expr" silently.
+///
+/// @return -1 for an error.
+varnumber_T eval_to_number(char *expr)
+{
+ typval_T rettv;
+ varnumber_T retval;
+ char *p = skipwhite(expr);
+
+ ++emsg_off;
+
+ if (eval1(&p, &rettv, true) == FAIL) {
+ retval = -1;
+ } else {
+ retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
+ }
+ --emsg_off;
+
+ return retval;
+}
+
+/// Top level evaluation function.
+///
+/// @return an allocated typval_T with the result or
+/// NULL when there is an error.
+typval_T *eval_expr(char *arg)
+{
+ typval_T *tv = xmalloc(sizeof(*tv));
+ if (eval0(arg, tv, NULL, true) == FAIL) {
+ XFREE_CLEAR(tv);
+ }
+ return tv;
+}
+
+/// List Vim variables.
+void list_vim_vars(int *first)
+{
+ list_hashtable_vars(&vimvarht, "v:", false, first);
+}
+
+/// List script-local variables, if there is a script.
+void list_script_vars(int *first)
+{
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
+ }
+}
+
+bool is_vimvarht(const hashtab_T *ht)
+{
+ return ht == &vimvarht;
+}
+
+bool is_compatht(const hashtab_T *ht)
+{
+ return ht == &compat_hashtab;
+}
+
+/// Prepare v: variable "idx" to be used.
+/// Save the current typeval in "save_tv".
+/// When not used yet add the variable to the v: hashtable.
+void prepare_vimvar(int idx, typval_T *save_tv)
+{
+ *save_tv = vimvars[idx].vv_tv;
+ if (vimvars[idx].vv_type == VAR_UNKNOWN) {
+ hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
+ }
+}
+
+/// Restore v: variable "idx" to typeval "save_tv".
+/// When no longer defined, remove the variable from the v: hashtable.
+void restore_vimvar(int idx, typval_T *save_tv)
+{
+ hashitem_T *hi;
+
+ vimvars[idx].vv_tv = *save_tv;
+ if (vimvars[idx].vv_type == VAR_UNKNOWN) {
+ hi = hash_find(&vimvarht, (char *)vimvars[idx].vv_di.di_key);
+ if (HASHITEM_EMPTY(hi)) {
+ internal_error("restore_vimvar()");
+ } else {
+ hash_remove(&vimvarht, hi);
+ }
+ }
+}
+
+/// If there is a window for "curbuf", make it the current window.
+void find_win_for_curbuf(void)
+{
+ for (wininfo_T *wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) {
+ if (wip->wi_win != NULL) {
+ curwin = wip->wi_win;
+ break;
+ }
+ }
+}
+
+/// Evaluate an expression to a list with suggestions.
+/// For the "expr:" part of 'spellsuggest'.
+///
+/// @return NULL when there is an error.
+list_T *eval_spell_expr(char *badword, char *expr)
+{
+ typval_T save_val;
+ typval_T rettv;
+ list_T *list = NULL;
+ char *p = skipwhite(expr);
+
+ // Set "v:val" to the bad word.
+ prepare_vimvar(VV_VAL, &save_val);
+ vimvars[VV_VAL].vv_type = VAR_STRING;
+ vimvars[VV_VAL].vv_str = badword;
+ if (p_verbose == 0) {
+ ++emsg_off;
+ }
+
+ if (eval1(&p, &rettv, true) == OK) {
+ if (rettv.v_type != VAR_LIST) {
+ tv_clear(&rettv);
+ } else {
+ list = rettv.vval.v_list;
+ }
+ }
+
+ if (p_verbose == 0) {
+ --emsg_off;
+ }
+ restore_vimvar(VV_VAL, &save_val);
+
+ return list;
+}
+
+/// Get spell word from an entry from spellsuggest=expr:
+///
+/// Entry in question is supposed to be a list (to be checked by the caller)
+/// with two items: a word and a score represented as an unsigned number
+/// (whether it actually is unsigned is not checked).
+///
+/// Used to get the good word and score from the eval_spell_expr() result.
+///
+/// @param[in] list List to get values from.
+/// @param[out] ret_word Suggested word. Not initialized if return value is
+/// -1.
+///
+/// @return -1 in case of error, score otherwise.
+int get_spellword(list_T *const list, const char **ret_word)
+{
+ if (tv_list_len(list) != 2) {
+ emsg(_("E5700: Expression from 'spellsuggest' must yield lists with "
+ "exactly two values"));
+ return -1;
+ }
+ *ret_word = tv_list_find_str(list, 0);
+ if (*ret_word == NULL) {
+ return -1;
+ }
+ return (int)tv_list_find_nr(list, -1, NULL);
+}
+
+// Call some vim script function and return the result in "*rettv".
+// Uses argv[0] to argv[argc-1] for the function arguments. argv[argc]
+// should have type VAR_UNKNOWN.
+//
+// @return OK or FAIL.
+int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int ret;
+ int len = (int)STRLEN(func);
+ partial_T *pt = NULL;
+
+ if (len >= 6 && !memcmp(func, "v:lua.", 6)) {
+ func += 6;
+ len = check_luafunc_name(func, false);
+ if (len == 0) {
+ ret = FAIL;
+ goto fail;
+ }
+ pt = vvlua_partial;
+ }
+
+ rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = pt;
+ ret = call_func(func, len, rettv, argc, argv, &funcexe);
+
+fail:
+ if (ret == FAIL) {
+ tv_clear(rettv);
+ }
+
+ return ret;
+}
+/// Call Vim script function and return the result as a number
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with typval_T arguments.
+///
+/// @return -1 when calling function fails, result of function otherwise.
+varnumber_T call_func_retnr(const char *func, int argc, typval_T *argv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ typval_T rettv;
+ varnumber_T retval;
+
+ if (call_vim_function((char *)func, argc, argv, &rettv) == FAIL) {
+ return -1;
+ }
+ retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
+ return retval;
+}
+/// Call Vim script function and return the result as a string
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with typval_T arguments.
+///
+/// @return [allocated] NULL when calling function fails, allocated string
+/// otherwise.
+char *call_func_retstr(const char *const func, int argc, typval_T *argv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
+{
+ typval_T rettv;
+ // All arguments are passed as strings, no conversion to number.
+ if (call_vim_function(func, argc, argv, &rettv)
+ == FAIL) {
+ return NULL;
+ }
+
+ char *const retval = xstrdup(tv_get_string(&rettv));
+ tv_clear(&rettv);
+ return retval;
+}
+/// Call Vim script function and return the result as a List
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with typval_T arguments.
+///
+/// @return [allocated] NULL when calling function fails or return tv is not a
+/// List, allocated List otherwise.
+void *call_func_retlist(const char *func, int argc, typval_T *argv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ typval_T rettv;
+
+ // All arguments are passed as strings, no conversion to number.
+ if (call_vim_function((char *)func, argc, argv, &rettv) == FAIL) {
+ return NULL;
+ }
+
+ if (rettv.v_type != VAR_LIST) {
+ tv_clear(&rettv);
+ return NULL;
+ }
+
+ return rettv.vval.v_list;
+}
+
+/// Prepare profiling for entering a child or something else that is not
+/// counted for the script/function itself.
+/// Should always be called in pair with prof_child_exit().
+///
+/// @param tm place to store waittime
+void prof_child_enter(proftime_T *tm)
+{
+ funccall_T *fc = get_current_funccal();
+
+ if (fc != NULL && fc->func->uf_profiling) {
+ fc->prof_child = profile_start();
+ }
+
+ script_prof_save(tm);
+}
+
+/// Take care of time spent in a child.
+/// Should always be called after prof_child_enter().
+///
+/// @param tm where waittime was stored
+void prof_child_exit(proftime_T *tm)
+{
+ funccall_T *fc = get_current_funccal();
+
+ if (fc != NULL && fc->func->uf_profiling) {
+ fc->prof_child = profile_end(fc->prof_child);
+ // don't count waiting time
+ fc->prof_child = profile_sub_wait(*tm, fc->prof_child);
+ fc->func->uf_tm_children =
+ profile_add(fc->func->uf_tm_children, fc->prof_child);
+ fc->func->uf_tml_children =
+ profile_add(fc->func->uf_tml_children, fc->prof_child);
+ }
+ script_prof_restore(tm);
+}
+
+/// Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding
+/// it in "*cp". Doesn't give error messages.
+int eval_foldexpr(char *arg, int *cp)
+{
+ typval_T tv;
+ varnumber_T retval;
+ int use_sandbox = was_set_insecurely(curwin, "foldexpr", OPT_LOCAL);
+
+ ++emsg_off;
+ if (use_sandbox) {
+ ++sandbox;
+ }
+ ++textlock;
+ *cp = NUL;
+ if (eval0(arg, &tv, NULL, true) == FAIL) {
+ retval = 0;
+ } else {
+ // If the result is a number, just return the number.
+ if (tv.v_type == VAR_NUMBER) {
+ retval = tv.vval.v_number;
+ } else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) {
+ retval = 0;
+ } else {
+ // If the result is a string, check if there is a non-digit before
+ // the number.
+ char *s = tv.vval.v_string;
+ if (!ascii_isdigit(*s) && *s != '-') {
+ *cp = (char_u)(*s++);
+ }
+ retval = atol(s);
+ }
+ tv_clear(&tv);
+ }
+ --emsg_off;
+ if (use_sandbox) {
+ --sandbox;
+ }
+ --textlock;
+
+ return (int)retval;
+}
+
+<<<<<<< HEAD
+/// ":cons[t] var = expr1" define constant
+/// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
+/// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
+void ex_const(exarg_T *eap)
+{
+ ex_let_const(eap, true);
+}
+
+/// Get a list of lines from a HERE document. The here document is a list of
+/// lines surrounded by a marker.
+/// cmd << {marker}
+/// {line1}
+/// {line2}
+/// ....
+/// {marker}
+///
+/// The {marker} is a string. If the optional 'trim' word is supplied before the
+/// marker, then the leading indentation before the lines (matching the
+/// indentation in the 'cmd' line) is stripped.
+///
+/// @return a List with {lines} or NULL.
+static list_T *heredoc_get(exarg_T *eap, char *cmd)
+{
+ char *marker;
+ char *p;
+ int marker_indent_len = 0;
+ int text_indent_len = 0;
+ char *text_indent = NULL;
+
+ if (eap->getline == NULL) {
+ emsg(_("E991: cannot use =<< here"));
+ return NULL;
+ }
+
+ // Check for the optional 'trim' word before the marker
+ cmd = skipwhite(cmd);
+ if (STRNCMP(cmd, "trim", 4) == 0
+ && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
+ cmd = skipwhite(cmd + 4);
+
+ // Trim the indentation from all the lines in the here document.
+ // The amount of indentation trimmed is the same as the indentation of
+ // the first line after the :let command line. To find the end marker
+ // the indent of the :let command line is trimmed.
+ p = *eap->cmdlinep;
+ while (ascii_iswhite(*p)) {
+ p++;
+ marker_indent_len++;
+ }
+ text_indent_len = -1;
+ }
+
+ // The marker is the next word.
+ if (*cmd != NUL && *cmd != '"') {
+ marker = skipwhite(cmd);
+ p = (char *)skiptowhite((char_u *)marker);
+ if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
+ emsg(_(e_trailing));
+ return NULL;
+ }
+ *p = NUL;
+ if (islower(*marker)) {
+ emsg(_("E221: Marker cannot start with lower case letter"));
+ return NULL;
+ }
+ } else {
+ emsg(_("E172: Missing marker"));
+ return NULL;
+ }
+
+ list_T *l = tv_list_alloc(0);
+ for (;;) {
+ int mi = 0;
+ int ti = 0;
+
+ char *theline = eap->getline(NUL, eap->cookie, 0, false);
+ if (theline == NULL) {
+ semsg(_("E990: Missing end marker '%s'"), marker);
+ break;
+ }
+
+ // with "trim": skip the indent matching the :let line to find the
+ // marker
+ if (marker_indent_len > 0
+ && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
+ mi = marker_indent_len;
+ }
+ if (STRCMP(marker, theline + mi) == 0) {
+ xfree(theline);
+ break;
+ }
+ if (text_indent_len == -1 && *theline != NUL) {
+ // set the text indent from the first line.
+ p = theline;
+ text_indent_len = 0;
+ while (ascii_iswhite(*p)) {
+ p++;
+ text_indent_len++;
+ }
+ text_indent = xstrnsave(theline, (size_t)text_indent_len);
+ }
+ // with "trim": skip the indent matching the first line
+ if (text_indent != NULL) {
+ for (ti = 0; ti < text_indent_len; ti++) {
+ if (theline[ti] != text_indent[ti]) {
+ break;
+ }
+ }
+ }
+
+ tv_list_append_string(l, theline + ti, -1);
+ xfree(theline);
+ }
+ xfree(text_indent);
+
+ return l;
+}
+
+/// ":let" list all variable values
+/// ":let var1 var2" list variable values
+/// ":let var = expr" assignment command.
+/// ":let var += expr" assignment command.
+/// ":let var -= expr" assignment command.
+/// ":let var *= expr" assignment command.
+/// ":let var /= expr" assignment command.
+/// ":let var %= expr" assignment command.
+/// ":let var .= expr" assignment command.
+/// ":let var ..= expr" assignment command.
+/// ":let [var1, var2] = expr" unpack list.
+/// ":let [name, ..., ; lastname] = expr" unpack list.
+void ex_let(exarg_T *eap)
+{
+ ex_let_const(eap, false);
+}
+
+static void ex_let_const(exarg_T *eap, const bool is_const)
+{
+ char *arg = eap->arg;
+ char *expr = NULL;
+ typval_T rettv;
+ int i;
+ int var_count = 0;
+ int semicolon = 0;
+ char op[2];
+ char *argend;
+ int first = true;
+
+ argend = (char *)skip_var_list(arg, &var_count, &semicolon);
+ if (argend == NULL) {
+ return;
+ }
+ if (argend > arg && argend[-1] == '.') { // For var.='str'.
+ argend--;
+ }
+ expr = skipwhite(argend);
+ if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
+ && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
+ // ":let" without "=": list variables
+ if (*arg == '[') {
+ emsg(_(e_invarg));
+ } else if (!ends_excmd(*arg)) {
+ // ":let var1 var2"
+ arg = (char *)list_arg_vars(eap, (const char *)arg, &first);
+ } else if (!eap->skip) {
+ // ":let"
+ list_glob_vars(&first);
+ list_buf_vars(&first);
+ list_win_vars(&first);
+ list_tab_vars(&first);
+ list_script_vars(&first);
+ list_func_vars(&first);
+ list_vim_vars(&first);
+ }
+ eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+ } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
+ // HERE document
+ list_T *l = heredoc_get(eap, expr + 3);
+ if (l != NULL) {
+ tv_list_set_ret(&rettv, l);
+ if (!eap->skip) {
+ op[0] = '=';
+ op[1] = NUL;
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
+ is_const, (char *)op);
+ }
+ tv_clear(&rettv);
+ }
+ } else {
+ op[0] = '=';
+ op[1] = NUL;
+ if (*expr != '=') {
+ if (vim_strchr("+-*/%.", *expr) != NULL) {
+ op[0] = *expr; // +=, -=, *=, /=, %= or .=
+ if (expr[0] == '.' && expr[1] == '.') { // ..=
+ expr++;
+ }
+ }
+ expr = skipwhite(expr + 2);
+ } else {
+ expr = skipwhite(expr + 1);
+ }
+
+ if (eap->skip) {
+ ++emsg_skip;
+ }
+ i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
+ if (eap->skip) {
+ if (i != FAIL) {
+ tv_clear(&rettv);
+ }
+ emsg_skip--;
+ } else if (i != FAIL) {
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
+ is_const, (char *)op);
+ tv_clear(&rettv);
+ }
+ }
+}
+
+/// Assign the typevalue "tv" to the variable or variables at "arg_start".
+/// Handles both "var" with any type and "[var, var; var]" with a list type.
+/// When "op" is not NULL it points to a string with characters that
+/// must appear after the variable(s). Use "+", "-" or "." for add, subtract
+/// or concatenate.
+///
+/// @param copy copy values from "tv", don't move
+/// @param semicolon from skip_var_list()
+/// @param var_count from skip_var_list()
+/// @param is_const lock variables for :const
+///
+/// @return OK or FAIL;
+static int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_count,
+ int is_const, char *op)
+{
+ char *arg = arg_start;
+ typval_T ltv;
+
+ if (*arg != '[') {
+ /*
+ * ":let var = expr" or ":for var in list"
+ */
+ if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL) {
+ return FAIL;
+ }
+ return OK;
+ }
+
+ // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
+ if (tv->v_type != VAR_LIST) {
+ emsg(_(e_listreq));
+ return FAIL;
+ }
+ list_T *const l = tv->vval.v_list;
+
+ const int len = tv_list_len(l);
+ if (semicolon == 0 && var_count < len) {
+ emsg(_("E687: Less targets than List items"));
+ return FAIL;
+ }
+ if (var_count - semicolon > len) {
+ emsg(_("E688: More targets than List items"));
+ return FAIL;
+ }
+ // List l may actually be NULL, but it should fail with E688 or even earlier
+ // if you try to do ":let [] = v:_null_list".
+ assert(l != NULL);
+
+ listitem_T *item = tv_list_first(l);
+ size_t rest_len = (size_t)tv_list_len(l);
+ while (*arg != ']') {
+ arg = skipwhite(arg + 1);
+ arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const, ",;]", op);
+ if (arg == NULL) {
+ return FAIL;
+ }
+ rest_len--;
+
+ item = TV_LIST_ITEM_NEXT(l, item);
+ arg = skipwhite(arg);
+ if (*arg == ';') {
+ /* Put the rest of the list (may be empty) in the var after ';'.
+ * Create a new list for this. */
+ list_T *const rest_list = tv_list_alloc((ptrdiff_t)rest_len);
+ while (item != NULL) {
+ tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item));
+ item = TV_LIST_ITEM_NEXT(l, item);
+ }
+
+ ltv.v_type = VAR_LIST;
+ ltv.v_lock = VAR_UNLOCKED;
+ ltv.vval.v_list = rest_list;
+ tv_list_ref(rest_list);
+
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const, "]", op);
+ tv_clear(&ltv);
+ if (arg == NULL) {
+ return FAIL;
+ }
+ break;
+ } else if (*arg != ',' && *arg != ']') {
+ internal_error("ex_let_vars()");
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
+/// Skip over assignable variable "var" or list of variables "[var, var]".
+/// Used for ":let varvar = expr" and ":for varvar in expr".
+/// For "[var, var]" increment "*var_count" for each variable.
+/// for "[var, var; var]" set "semicolon".
+///
+/// @return NULL for an error.
+static const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
+{
+ const char *p;
+ const char *s;
+
+ if (*arg == '[') {
+ // "[var, var]": find the matching ']'.
+ p = arg;
+ for (;;) {
+ p = skipwhite(p + 1); // skip whites after '[', ';' or ','
+ s = skip_var_one((char *)p);
+ if (s == p) {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ ++*var_count;
+
+ p = skipwhite(s);
+ if (*p == ']') {
+ break;
+ } else if (*p == ';') {
+ if (*semicolon == 1) {
+ emsg(_("E452: Double ; in list of variables"));
+ return NULL;
+ }
+ *semicolon = 1;
+ } else if (*p != ',') {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ }
+ return p + 1;
+ } else {
+ return skip_var_one((char *)arg);
+ }
+}
+
+/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
+/// l[idx].
+static const char *skip_var_one(const char *arg)
+{
+ if (*arg == '@' && arg[1] != NUL) {
+ return arg + 1 + utfc_ptr2len(arg + 1);
+ }
+ return (char *)find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
+ NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+}
+
+/// List variables for hashtab "ht" with prefix "prefix".
+///
+/// @param empty if TRUE also list NULL strings as empty strings.
+void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *first)
+{
+ hashitem_T *hi;
+ dictitem_T *di;
+ int todo;
+
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) {
+ if (!HASHITEM_EMPTY(hi)) {
+ todo--;
+ di = TV_DICT_HI2DI(hi);
+ char buf[IOSIZE];
+
+ // apply :filter /pat/ to variable name
+ xstrlcpy(buf, prefix, IOSIZE);
+ xstrlcat(buf, (char *)di->di_key, IOSIZE);
+ if (message_filtered((char_u *)buf)) {
+ continue;
+ }
+
+ if (empty || di->di_tv.v_type != VAR_STRING
+ || di->di_tv.vval.v_string != NULL) {
+ list_one_var(di, prefix, first);
+ }
+ }
+ }
+}
+
+/// List global variables.
+static void list_glob_vars(int *first)
+{
+ list_hashtable_vars(&globvarht, "", true, first);
+}
+
+/// List buffer variables.
+static void list_buf_vars(int *first)
+{
+ list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", true, first);
+}
+
+/// List window variables.
+static void list_win_vars(int *first)
+{
+ list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", true, first);
+}
+
+/// List tab page variables.
+static void list_tab_vars(int *first)
+{
+ list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", true, first);
+}
+
+/// List Vim variables.
+static void list_vim_vars(int *first)
+{
+ list_hashtable_vars(&vimvarht, "v:", false, first);
+}
+
+/// List script-local variables, if there is a script.
+static void list_script_vars(int *first)
+{
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
+ }
+}
+
+/// List variables in "arg".
+static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
+{
+ int error = FALSE;
+ int len;
+ const char *name;
+ const char *name_start;
+ typval_T tv;
+
+ while (!ends_excmd(*arg) && !got_int) {
+ if (error || eap->skip) {
+ arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+ if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) {
+ emsg_severe = true;
+ emsg(_(e_trailing));
+ break;
+ }
+ } else {
+ // get_name_len() takes care of expanding curly braces
+ name_start = name = arg;
+ char *tofree;
+ len = get_name_len(&arg, &tofree, true, true);
+ if (len <= 0) {
+ /* This is mainly to keep test 49 working: when expanding
+ * curly braces fails overrule the exception error message. */
+ if (len < 0 && !aborting()) {
+ emsg_severe = true;
+ semsg(_(e_invarg2), arg);
+ break;
+ }
+ error = TRUE;
+ } else {
+ if (tofree != NULL) {
+ name = tofree;
+ }
+ if (get_var_tv(name, len, &tv, NULL, true, false)
+ == FAIL) {
+ error = true;
+ } else {
+ // handle d.key, l[idx], f(expr)
+ const char *const arg_subsc = arg;
+ if (handle_subscript(&arg, &tv, true, true, name, &name) == FAIL) {
+ error = true;
+ } else {
+ if (arg == arg_subsc && len == 2 && name[1] == ':') {
+ switch (*name) {
+ case 'g':
+ list_glob_vars(first); break;
+ case 'b':
+ list_buf_vars(first); break;
+ case 'w':
+ list_win_vars(first); break;
+ case 't':
+ list_tab_vars(first); break;
+ case 'v':
+ list_vim_vars(first); break;
+ case 's':
+ list_script_vars(first); break;
+ case 'l':
+ list_func_vars(first); break;
+ default:
+ semsg(_("E738: Can't list variables for %s"), name);
+ }
+ } else {
+ char *const s = encode_tv2echo(&tv, NULL);
+ const char *const used_name = (arg == arg_subsc
+ ? name
+ : name_start);
+ const ptrdiff_t name_size = (used_name == tofree
+ ? (ptrdiff_t)strlen(used_name)
+ : (arg - used_name));
+ list_one_var_a("", used_name, name_size,
+ tv.v_type, s == NULL ? "" : s, first);
+ xfree(s);
+ }
+ tv_clear(&tv);
+ }
+ }
+ }
+
+ xfree(tofree);
+ }
+
+ arg = (const char *)skipwhite(arg);
+ }
+
+ return arg;
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
+///
+/// @param[in] arg Start of the variable name.
+/// @param[in] tv Value to assign to the variable.
+/// @param[in] copy If true, copy value from `tv`.
+/// @param[in] endchars Valid characters after variable name or NULL.
+/// @param[in] op Operation performed: *op is `+`, `-`, `.` for `+=`, etc.
+/// NULL for `=`.
+///
+/// @return a pointer to the char just after the var name or NULL in case of
+/// error.
+static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bool is_const,
+ const char *const endchars, const char *const op)
+ FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ char *arg_end = NULL;
+ int len;
+ int opt_flags;
+ char *tofree = NULL;
+
+ /*
+ * ":let $VAR = expr": Set environment variable.
+ */
+ if (*arg == '$') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock an environment variable"));
+ return NULL;
+ }
+ // Find the end of the name.
+ arg++;
+ char *name = arg;
+ len = get_env_len((const char **)&arg);
+ if (len == 0) {
+ semsg(_(e_invarg2), name - 1);
+ } else {
+ if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ semsg(_(e_letwrong), op);
+ } else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg)) == NULL) {
+ emsg(_(e_letunexp));
+ } else if (!check_secure()) {
+ const char c1 = name[len];
+ name[len] = NUL;
+ const char *p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.') {
+ char *s = vim_getenv(name);
+
+ if (s != NULL) {
+ tofree = (char *)concat_str((const char_u *)s, (const char_u *)p);
+ p = (const char *)tofree;
+ xfree(s);
+ }
+ }
+ if (p != NULL) {
+ os_setenv(name, p, 1);
+ if (STRICMP(name, "HOME") == 0) {
+ init_homedir();
+ } else if (didset_vim && STRICMP(name, "VIM") == 0) {
+ didset_vim = false;
+ } else if (didset_vimruntime
+ && STRICMP(name, "VIMRUNTIME") == 0) {
+ didset_vimruntime = false;
+ }
+ arg_end = arg;
+ }
+ name[len] = c1;
+ xfree(tofree);
+ }
+ }
+ // ":let &option = expr": Set option value.
+ // ":let &l:option = expr": Set local option value.
+ // ":let &g:option = expr": Set global option value.
+ } else if (*arg == '&') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock an option"));
+ return NULL;
+ }
+ // Find the end of the name.
+ char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
+ if (p == NULL
+ || (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(p)) == NULL)) {
+ emsg(_(e_letunexp));
+ } else {
+ int opt_type;
+ long numval;
+ char *stringval = NULL;
+ const char *s = NULL;
+
+ const char c1 = *p;
+ *p = NUL;
+
+ varnumber_T n = tv_get_number(tv);
+ if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ s = tv_get_string_chk(tv); // != NULL if number or string.
+ }
+ if (s != NULL && op != NULL && *op != '=') {
+ opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ if ((opt_type == 1 && *op == '.')
+ || (opt_type == 0 && *op != '.')) {
+ semsg(_(e_letwrong), op);
+ s = NULL; // don't set the value
+ } else {
+ if (opt_type == 1) { // number
+ switch (*op) {
+ case '+':
+ n = numval + n; break;
+ case '-':
+ n = numval - n; break;
+ case '*':
+ n = numval * n; break;
+ case '/':
+ n = num_divide(numval, n); break;
+ case '%':
+ n = num_modulus(numval, n); break;
+ }
+ } else if (opt_type == 0 && stringval != NULL) { // string
+ char *const oldstringval = stringval;
+ stringval = (char *)concat_str((const char_u *)stringval,
+ (const char_u *)s);
+ xfree(oldstringval);
+ s = stringval;
+ }
+ }
+ }
+ if (s != NULL || tv->v_type == VAR_BOOL
+ || tv->v_type == VAR_SPECIAL) {
+ set_option_value((const char *)arg, n, s, opt_flags);
+ arg_end = p;
+ }
+ *p = c1;
+ xfree(stringval);
+ }
+ // ":let @r = expr": Set register contents.
+ } else if (*arg == '@') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock a register"));
+ return NULL;
+ }
+ arg++;
+
+ int regname = utf_ptr2char(arg);
+ int mblen = utf_ptr2len(arg);
+
+ if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ semsg(_(e_letwrong), op);
+ } else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg + mblen)) == NULL) {
+ emsg(_(e_letunexp));
+ } else {
+ char *s;
+
+ char *ptofree = NULL;
+ const char *p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.') {
+ s = get_reg_contents(regname == '@' ? '"' : regname, kGRegExprSrc);
+ if (s != NULL) {
+ ptofree = (char *)concat_str((char_u *)s, (const char_u *)p);
+ p = (const char *)ptofree;
+ xfree(s);
+ }
+ }
+ if (p != NULL) {
+
+ write_reg_contents(regname == '@' ? '"' : regname,
+ (const char_u *)p, (ssize_t)STRLEN(p), false);
+ arg_end = arg + mblen;
+ }
+ xfree(ptofree);
+ }
+ }
+ /*
+ * ":let var = expr": Set internal variable.
+ * ":let {expr} = expr": Idem, name made with curly braces
+ */
+ else if (eval_isnamec1(*arg) || *arg == '{') {
+ lval_T lv;
+
+ char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
+ if (p != NULL && lv.ll_name != NULL) {
+ if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
+ emsg(_(e_letunexp));
+ } else {
+ set_var_lval(&lv, p, tv, copy, is_const, op);
+ arg_end = p;
+ }
+ }
+ clear_lval(&lv);
+ } else {
+ semsg(_(e_invarg2), arg);
+ }
+
+ return arg_end;
+}
+
+=======
+>>>>>>> upstream/master
+// TODO(ZyX-I): move to eval/executor
+
+/// Get an lvalue
+///
+/// Lvalue may be
+/// - variable: "name", "na{me}"
+/// - dictionary item: "dict.key", "dict['key']"
+/// - list item: "list[expr]"
+/// - list slice: "list[expr:expr]"
+///
+/// Indexing only works if trying to use it with an existing List or Dictionary.
+///
+/// @param[in] name Name to parse.
+/// @param rettv Pointer to the value to be assigned or NULL.
+/// @param[out] lp Lvalue definition. When evaluation errors occur `->ll_name`
+/// is NULL.
+/// @param[in] unlet True if using `:unlet`. This results in slightly
+/// different behaviour when something is wrong; must end in
+/// space or cmd separator.
+/// @param[in] skip True when skipping.
+/// @param[in] flags @see GetLvalFlags.
+/// @param[in] fne_flags Flags for find_name_end().
+///
+/// @return A pointer to just after the name, including indexes. Returns NULL
+/// for a parsing error, but it is still needed to free items in lp.
+char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const bool unlet,
+ const bool skip, const int flags, const int fne_flags)
+ FUNC_ATTR_NONNULL_ARG(1, 3)
+{
+ dictitem_T *v;
+ typval_T var1;
+ typval_T var2;
+ int empty1 = FALSE;
+ listitem_T *ni;
+ hashtab_T *ht = NULL;
+ int quiet = flags & GLV_QUIET;
+
+ // Clear everything in "lp".
+ memset(lp, 0, sizeof(lval_T));
+
+ if (skip) {
+ // When skipping just find the end of the name.
+ lp->ll_name = (const char *)name;
+ return (char *)find_name_end(name, NULL, NULL,
+ FNE_INCL_BR | fne_flags);
+ }
+
+ // Find the end of the name.
+ char *expr_start;
+ char *expr_end;
+ char *p = (char *)find_name_end(name, (const char **)&expr_start,
+ (const char **)&expr_end,
+ fne_flags);
+ if (expr_start != NULL) {
+ // Don't expand the name when we already know there is an error.
+ if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p)
+ && *p != '[' && *p != '.') {
+ emsg(_(e_trailing));
+ return NULL;
+ }
+
+ lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p);
+ lp->ll_name = lp->ll_exp_name;
+ if (lp->ll_exp_name == NULL) {
+ // Report an invalid expression in braces, unless the
+ // expression evaluation has been cancelled due to an
+ // aborting error, an interrupt, or an exception.
+ if (!aborting() && !quiet) {
+ emsg_severe = true;
+ semsg(_(e_invarg2), name);
+ return NULL;
+ }
+ lp->ll_name_len = 0;
+ } else {
+ lp->ll_name_len = strlen(lp->ll_name);
+ }
+ } else {
+ lp->ll_name = (const char *)name;
+ lp->ll_name_len = (size_t)((const char *)p - lp->ll_name);
+ }
+
+ // Without [idx] or .key we are done.
+ if ((*p != '[' && *p != '.') || lp->ll_name == NULL) {
+ return p;
+ }
+
+ // Only pass &ht when we would write to the variable, it prevents autoload
+ // as well.
+ v = find_var(lp->ll_name, lp->ll_name_len,
+ (flags & GLV_READ_ONLY) ? NULL : &ht,
+ flags & GLV_NO_AUTOLOAD);
+ if (v == NULL && !quiet) {
+ semsg(_("E121: Undefined variable: %.*s"),
+ (int)lp->ll_name_len, lp->ll_name);
+ }
+ if (v == NULL) {
+ return NULL;
+ }
+
+ // Loop until no more [idx] or .key is following.
+ lp->ll_tv = &v->di_tv;
+ var1.v_type = VAR_UNKNOWN;
+ var2.v_type = VAR_UNKNOWN;
+ while (*p == '[' || (*p == '.' && lp->ll_tv->v_type == VAR_DICT)) {
+ if (!(lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list != NULL)
+ && !(lp->ll_tv->v_type == VAR_DICT && lp->ll_tv->vval.v_dict != NULL)
+ && !(lp->ll_tv->v_type == VAR_BLOB && lp->ll_tv->vval.v_blob != NULL)) {
+ if (!quiet) {
+ emsg(_("E689: Can only index a List, Dictionary or Blob"));
+ }
+ return NULL;
+ }
+ if (lp->ll_range) {
+ if (!quiet) {
+ emsg(_("E708: [:] must come last"));
+ }
+ return NULL;
+ }
+
+ int len = -1;
+ char *key = NULL;
+ if (*p == '.') {
+ key = p + 1;
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {}
+ if (len == 0) {
+ if (!quiet) {
+ emsg(_("E713: Cannot use empty key after ."));
+ }
+ return NULL;
+ }
+ p = key + len;
+ } else {
+ // Get the index [expr] or the first index [expr: ].
+ p = skipwhite(p + 1);
+ if (*p == ':') {
+ empty1 = true;
+ } else {
+ empty1 = false;
+ if (eval1(&p, &var1, true) == FAIL) { // Recursive!
+ return NULL;
+ }
+ if (!tv_check_str(&var1)) {
+ // Not a number or string.
+ tv_clear(&var1);
+ return NULL;
+ }
+ p = skipwhite(p);
+ }
+
+ // Optionally get the second index [ :expr].
+ if (*p == ':') {
+ if (lp->ll_tv->v_type == VAR_DICT) {
+ if (!quiet) {
+ emsg(_(e_dictrange));
+ }
+ tv_clear(&var1);
+ return NULL;
+ }
+ if (rettv != NULL
+ && !(rettv->v_type == VAR_LIST && rettv->vval.v_list != NULL)
+ && !(rettv->v_type == VAR_BLOB && rettv->vval.v_blob != NULL)) {
+ if (!quiet) {
+ emsg(_("E709: [:] requires a List or Blob value"));
+ }
+ tv_clear(&var1);
+ return NULL;
+ }
+ p = skipwhite(p + 1);
+ if (*p == ']') {
+ lp->ll_empty2 = true;
+ } else {
+ lp->ll_empty2 = false;
+ if (eval1(&p, &var2, true) == FAIL) { // Recursive!
+ tv_clear(&var1);
+ return NULL;
+ }
+ if (!tv_check_str(&var2)) {
+ // Not a number or string.
+ tv_clear(&var1);
+ tv_clear(&var2);
+ return NULL;
+ }
+ }
+ lp->ll_range = true;
+ } else {
+ lp->ll_range = false;
+ }
+
+ if (*p != ']') {
+ if (!quiet) {
+ emsg(_(e_missbrac));
+ }
+ tv_clear(&var1);
+ tv_clear(&var2);
+ return NULL;
+ }
+
+ // Skip to past ']'.
+ p++;
+ }
+
+ if (lp->ll_tv->v_type == VAR_DICT) {
+ if (len == -1) {
+ // "[key]": get key from "var1"
+ key = (char *)tv_get_string(&var1); // is number or string
+ }
+ lp->ll_list = NULL;
+ lp->ll_dict = lp->ll_tv->vval.v_dict;
+ lp->ll_di = tv_dict_find(lp->ll_dict, (const char *)key, len);
+
+ // When assigning to a scope dictionary check that a function and
+ // variable name is valid (only variable name unless it is l: or
+ // g: dictionary). Disallow overwriting a builtin function.
+ if (rettv != NULL && lp->ll_dict->dv_scope != 0) {
+ char prevval;
+ int wrong;
+
+ if (len != -1) {
+ prevval = key[len];
+ key[len] = NUL;
+ } else {
+ prevval = 0; // Avoid compiler warning.
+ }
+ wrong = ((lp->ll_dict->dv_scope == VAR_DEF_SCOPE
+ && tv_is_func(*rettv)
+ && !var_check_func_name((const char *)key, lp->ll_di == NULL))
+ || !valid_varname((const char *)key));
+ if (len != -1) {
+ key[len] = prevval;
+ }
+ if (wrong) {
+ return NULL;
+ }
+ }
+
+ if (lp->ll_di != NULL && tv_is_luafunc(&lp->ll_di->di_tv)
+ && len == -1 && rettv == NULL) {
+ tv_clear(&var1);
+ semsg(e_illvar, "v:['lua']");
+ return NULL;
+ }
+
+ if (lp->ll_di == NULL) {
+ // Can't add "v:" or "a:" variable.
+ if (lp->ll_dict == &vimvardict
+ || &lp->ll_dict->dv_hashtab == get_funccal_args_ht()) {
+ semsg(_(e_illvar), name);
+ tv_clear(&var1);
+ return NULL;
+ }
+
+ // Key does not exist in dict: may need to add it.
+ if (*p == '[' || *p == '.' || unlet) {
+ if (!quiet) {
+ semsg(_(e_dictkey), key);
+ }
+ tv_clear(&var1);
+ return NULL;
+ }
+ if (len == -1) {
+ lp->ll_newkey = xstrdup(key);
+ } else {
+ lp->ll_newkey = xstrnsave(key, (size_t)len);
+ }
+ tv_clear(&var1);
+ break;
+ // existing variable, need to check if it can be changed
+ } else if (!(flags & GLV_READ_ONLY) && var_check_ro(lp->ll_di->di_flags,
+ (const char *)name,
+ (size_t)(p - name))) {
+ tv_clear(&var1);
+ return NULL;
+ }
+
+ tv_clear(&var1);
+ lp->ll_tv = &lp->ll_di->di_tv;
+ } else if (lp->ll_tv->v_type == VAR_BLOB) {
+ // Get the number and item for the only or first index of the List.
+ if (empty1) {
+ lp->ll_n1 = 0;
+ } else {
+ // Is number or string.
+ lp->ll_n1 = (long)tv_get_number(&var1);
+ }
+ tv_clear(&var1);
+
+ const int bloblen = tv_blob_len(lp->ll_tv->vval.v_blob);
+ if (lp->ll_n1 < 0 || lp->ll_n1 > bloblen
+ || (lp->ll_range && lp->ll_n1 == bloblen)) {
+ if (!quiet) {
+ semsg(_(e_blobidx), (int64_t)lp->ll_n1);
+ }
+ tv_clear(&var2);
+ return NULL;
+ }
+ if (lp->ll_range && !lp->ll_empty2) {
+ lp->ll_n2 = (long)tv_get_number(&var2);
+ tv_clear(&var2);
+ if (lp->ll_n2 < 0 || lp->ll_n2 >= bloblen || lp->ll_n2 < lp->ll_n1) {
+ if (!quiet) {
+ semsg(_(e_blobidx), (int64_t)lp->ll_n2);
+ }
+ return NULL;
+ }
+ }
+ lp->ll_blob = lp->ll_tv->vval.v_blob;
+ lp->ll_tv = NULL;
+ break;
+ } else {
+ // Get the number and item for the only or first index of the List.
+ if (empty1) {
+ lp->ll_n1 = 0;
+ } else {
+ // Is number or string.
+ lp->ll_n1 = (long)tv_get_number(&var1);
+ }
+ tv_clear(&var1);
+
+ lp->ll_dict = NULL;
+ lp->ll_list = lp->ll_tv->vval.v_list;
+ lp->ll_li = tv_list_find(lp->ll_list, (int)lp->ll_n1);
+ if (lp->ll_li == NULL) {
+ if (lp->ll_n1 < 0) {
+ lp->ll_n1 = 0;
+ lp->ll_li = tv_list_find(lp->ll_list, (int)lp->ll_n1);
+ }
+ }
+ if (lp->ll_li == NULL) {
+ tv_clear(&var2);
+ if (!quiet) {
+ semsg(_(e_listidx), (int64_t)lp->ll_n1);
+ }
+ return NULL;
+ }
+
+ // May need to find the item or absolute index for the second
+ // index of a range.
+ // When no index given: "lp->ll_empty2" is true.
+ // Otherwise "lp->ll_n2" is set to the second index.
+ if (lp->ll_range && !lp->ll_empty2) {
+ lp->ll_n2 = (long)tv_get_number(&var2); // Is number or string.
+ tv_clear(&var2);
+ if (lp->ll_n2 < 0) {
+ ni = tv_list_find(lp->ll_list, (int)lp->ll_n2);
+ if (ni == NULL) {
+ if (!quiet) {
+ semsg(_(e_listidx), (int64_t)lp->ll_n2);
+ }
+ return NULL;
+ }
+ lp->ll_n2 = tv_list_idx_of_item(lp->ll_list, ni);
+ }
+
+ // Check that lp->ll_n2 isn't before lp->ll_n1.
+ if (lp->ll_n1 < 0) {
+ lp->ll_n1 = tv_list_idx_of_item(lp->ll_list, lp->ll_li);
+ }
+ if (lp->ll_n2 < lp->ll_n1) {
+ if (!quiet) {
+ semsg(_(e_listidx), (int64_t)lp->ll_n2);
+ }
+ return NULL;
+ }
+ }
+
+ lp->ll_tv = TV_LIST_ITEM_TV(lp->ll_li);
+ }
+ }
+
+ tv_clear(&var1);
+ return p;
+}
+
+// TODO(ZyX-I): move to eval/executor
+
+/// Clear lval "lp" that was filled by get_lval().
+void clear_lval(lval_T *lp)
+{
+ xfree(lp->ll_exp_name);
+ xfree(lp->ll_newkey);
+}
+
+// TODO(ZyX-I): move to eval/executor
+
+/// Set a variable that was parsed by get_lval() to "rettv".
+///
+/// @param endp points to just after the parsed name.
+/// @param op NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=",
+/// "%" for "%=", "." for ".=" or "=" for "=".
+void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool is_const,
+ const char *op)
+{
+ int cc;
+ listitem_T *ri;
+ dictitem_T *di;
+
+ if (lp->ll_tv == NULL) {
+ cc = (char_u)(*endp);
+ *endp = NUL;
+ if (lp->ll_blob != NULL) {
+ if (op != NULL && *op != '=') {
+ semsg(_(e_letwrong), op);
+ return;
+ }
+ if (var_check_lock(lp->ll_blob->bv_lock, lp->ll_name, TV_CSTRING)) {
+ return;
+ }
+
+ if (lp->ll_range && rettv->v_type == VAR_BLOB) {
+ if (lp->ll_empty2) {
+ lp->ll_n2 = tv_blob_len(lp->ll_blob) - 1;
+ }
+
+ if (lp->ll_n2 - lp->ll_n1 + 1 != tv_blob_len(rettv->vval.v_blob)) {
+ emsg(_("E972: Blob value does not have the right number of bytes"));
+ return;
+ }
+ if (lp->ll_empty2) {
+ lp->ll_n2 = tv_blob_len(lp->ll_blob);
+ }
+
+ for (int il = (int)lp->ll_n1, ir = 0; il <= (int)lp->ll_n2; il++) {
+ tv_blob_set(lp->ll_blob, il, tv_blob_get(rettv->vval.v_blob, ir++));
+ }
+ } else {
+ bool error = false;
+ const char val = (char)tv_get_number_chk(rettv, &error);
+ if (!error) {
+ garray_T *const gap = &lp->ll_blob->bv_ga;
+
+ // Allow for appending a byte. Setting a byte beyond
+ // the end is an error otherwise.
+ if (lp->ll_n1 < gap->ga_len || lp->ll_n1 == gap->ga_len) {
+ ga_grow(&lp->ll_blob->bv_ga, 1);
+ tv_blob_set(lp->ll_blob, (int)lp->ll_n1, (char_u)val);
+ if (lp->ll_n1 == gap->ga_len) {
+ gap->ga_len++;
+ }
+ }
+ // error for invalid range was already given in get_lval()
+ }
+ }
+ } else if (op != NULL && *op != '=') {
+ typval_T tv;
+
+ if (is_const) {
+ emsg(_(e_cannot_mod));
+ *endp = (char)cc;
+ return;
+ }
+
+ // handle +=, -=, *=, /=, %= and .=
+ di = NULL;
+ if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
+ &tv, &di, true, false) == OK) {
+ if ((di == NULL
+ || (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING)
+ && !tv_check_lock(&di->di_tv, lp->ll_name, TV_CSTRING)))
+ && eexe_mod_op(&tv, rettv, op) == OK) {
+ set_var(lp->ll_name, lp->ll_name_len, &tv, false);
+ }
+ tv_clear(&tv);
+ }
+ } else {
+ set_var_const(lp->ll_name, lp->ll_name_len, rettv, copy, is_const);
+ }
+ *endp = (char)cc;
+ } else if (var_check_lock(lp->ll_newkey == NULL
+ ? lp->ll_tv->v_lock
+ : lp->ll_tv->vval.v_dict->dv_lock,
+ lp->ll_name, TV_CSTRING)) {
+ // Skip
+ } else if (lp->ll_range) {
+ listitem_T *ll_li = lp->ll_li;
+ int ll_n1 = (int)lp->ll_n1;
+
+ if (is_const) {
+ emsg(_("E996: Cannot lock a range"));
+ return;
+ }
+
+ // Check whether any of the list items is locked
+ for (ri = tv_list_first(rettv->vval.v_list);
+ ri != NULL && ll_li != NULL;) {
+ if (var_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name,
+ TV_CSTRING)) {
+ return;
+ }
+ ri = TV_LIST_ITEM_NEXT(rettv->vval.v_list, ri);
+ if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == ll_n1)) {
+ break;
+ }
+ ll_li = TV_LIST_ITEM_NEXT(lp->ll_list, ll_li);
+ ll_n1++;
+ }
+
+ /*
+ * Assign the List values to the list items.
+ */
+ for (ri = tv_list_first(rettv->vval.v_list); ri != NULL;) {
+ if (op != NULL && *op != '=') {
+ eexe_mod_op(TV_LIST_ITEM_TV(lp->ll_li), TV_LIST_ITEM_TV(ri), op);
+ } else {
+ tv_clear(TV_LIST_ITEM_TV(lp->ll_li));
+ tv_copy(TV_LIST_ITEM_TV(ri), TV_LIST_ITEM_TV(lp->ll_li));
+ }
+ ri = TV_LIST_ITEM_NEXT(rettv->vval.v_list, ri);
+ if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == lp->ll_n1)) {
+ break;
+ }
+ assert(lp->ll_li != NULL);
+ if (TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li) == NULL) {
+ // Need to add an empty item.
+ tv_list_append_number(lp->ll_list, 0);
+ // ll_li may have become invalid after append, don’t use it.
+ lp->ll_li = tv_list_last(lp->ll_list); // Valid again.
+ } else {
+ lp->ll_li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
+ }
+ lp->ll_n1++;
+ }
+ if (ri != NULL) {
+ emsg(_("E710: List value has more items than target"));
+ } else if (lp->ll_empty2
+ ? (lp->ll_li != NULL
+ && TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li) != NULL)
+ : lp->ll_n1 != lp->ll_n2) {
+ emsg(_("E711: List value has not enough items"));
+ }
+ } else {
+ typval_T oldtv = TV_INITIAL_VALUE;
+ dict_T *dict = lp->ll_dict;
+ bool watched = tv_dict_is_watched(dict);
+
+ if (is_const) {
+ emsg(_("E996: Cannot lock a list or dict"));
+ return;
+ }
+
+ // Assign to a List or Dictionary item.
+ if (lp->ll_newkey != NULL) {
+ if (op != NULL && *op != '=') {
+ semsg(_(e_letwrong), op);
+ return;
+ }
+
+ // Need to add an item to the Dictionary.
+ di = tv_dict_item_alloc((const char *)lp->ll_newkey);
+ if (tv_dict_add(lp->ll_tv->vval.v_dict, di) == FAIL) {
+ xfree(di);
+ return;
+ }
+ lp->ll_tv = &di->di_tv;
+ } else {
+ if (watched) {
+ tv_copy(lp->ll_tv, &oldtv);
+ }
+
+ if (op != NULL && *op != '=') {
+ eexe_mod_op(lp->ll_tv, rettv, op);
+ goto notify;
+ } else {
+ tv_clear(lp->ll_tv);
+ }
+ }
+
+ // Assign the value to the variable or list item.
+ if (copy) {
+ tv_copy(rettv, lp->ll_tv);
+ } else {
+ *lp->ll_tv = *rettv;
+ lp->ll_tv->v_lock = VAR_UNLOCKED;
+ tv_init(rettv);
+ }
+
+notify:
+ if (watched) {
+ if (oldtv.v_type == VAR_UNKNOWN) {
+ assert(lp->ll_newkey != NULL);
+ tv_dict_watcher_notify(dict, lp->ll_newkey, lp->ll_tv, NULL);
+ } else {
+ dictitem_T *di_ = lp->ll_di;
+ assert(di_->di_key != NULL);
+ tv_dict_watcher_notify(dict, (char *)di_->di_key, lp->ll_tv, &oldtv);
+ tv_clear(&oldtv);
+ }
+ }
+ }
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Evaluate the expression used in a ":for var in expr" command.
+/// "arg" points to "var".
+///
+/// @param[out] *errp set to TRUE for an error, FALSE otherwise;
+///
+/// @return a pointer that holds the info. Null when there is an error.
+void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip)
+{
+ forinfo_T *fi = xcalloc(1, sizeof(forinfo_T));
+ const char *expr;
+ typval_T tv;
+ list_T *l;
+
+ *errp = true; // Default: there is an error.
+
+ expr = skip_var_list((char *)arg, &fi->fi_varcount, &fi->fi_semicolon);
+ if (expr == NULL) {
+ return fi;
+ }
+
+ expr = skipwhite(expr);
+ if (expr[0] != 'i' || expr[1] != 'n' || !ascii_iswhite(expr[2])) {
+ emsg(_("E690: Missing \"in\" after :for"));
+ return fi;
+ }
+
+ if (skip) {
+ ++emsg_skip;
+ }
+ if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) {
+ *errp = false;
+ if (!skip) {
+ if (tv.v_type == VAR_LIST) {
+ l = tv.vval.v_list;
+ if (l == NULL) {
+ // a null list is like an empty list: do nothing
+ tv_clear(&tv);
+ } else {
+ // No need to increment the refcount, it's already set for
+ // the list being used in "tv".
+ fi->fi_list = l;
+ tv_list_watch_add(l, &fi->fi_lw);
+ fi->fi_lw.lw_item = tv_list_first(l);
+ }
+ } else if (tv.v_type == VAR_BLOB) {
+ fi->fi_bi = 0;
+ if (tv.vval.v_blob != NULL) {
+ typval_T btv;
+
+ // Make a copy, so that the iteration still works when the
+ // blob is changed.
+ tv_blob_copy(&tv, &btv);
+ fi->fi_blob = btv.vval.v_blob;
+ }
+ tv_clear(&tv);
+ } else if (tv.v_type == VAR_STRING) {
+ fi->fi_byte_idx = 0;
+ fi->fi_string = tv.vval.v_string;
+ tv.vval.v_string = NULL;
+ if (fi->fi_string == NULL) {
+ fi->fi_string = xstrdup("");
+ }
+ } else {
+ emsg(_(e_string_list_or_blob_required));
+ tv_clear(&tv);
+ }
+ }
+ }
+ if (skip) {
+ --emsg_skip;
+ }
+
+ return fi;
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Use the first item in a ":for" list. Advance to the next.
+/// Assign the values to the variable (list). "arg" points to the first one.
+///
+/// @return true when a valid item was found, false when at end of list or
+/// something wrong.
+bool next_for_item(void *fi_void, char *arg)
+{
+ forinfo_T *fi = (forinfo_T *)fi_void;
+
+ if (fi->fi_blob != NULL) {
+ if (fi->fi_bi >= tv_blob_len(fi->fi_blob)) {
+ return false;
+ }
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ tv.v_lock = VAR_FIXED;
+ tv.vval.v_number = tv_blob_get(fi->fi_blob, fi->fi_bi);
+ fi->fi_bi++;
+ return ex_let_vars(arg, &tv, true, fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK;
+ }
+
+ if (fi->fi_string != NULL) {
+ const int len = utfc_ptr2len(fi->fi_string + fi->fi_byte_idx);
+ if (len == 0) {
+ return false;
+ }
+ typval_T tv;
+ tv.v_type = VAR_STRING;
+ tv.v_lock = VAR_FIXED;
+ tv.vval.v_string = xstrnsave(fi->fi_string + fi->fi_byte_idx, (size_t)len);
+ fi->fi_byte_idx += len;
+ const int result
+ = ex_let_vars(arg, &tv, true, fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK;
+ xfree(tv.vval.v_string);
+ return result;
+ }
+
+ listitem_T *item = fi->fi_lw.lw_item;
+ if (item == NULL) {
+ return false;
+ } else {
+ fi->fi_lw.lw_item = TV_LIST_ITEM_NEXT(fi->fi_list, item);
+ return (ex_let_vars(arg, TV_LIST_ITEM_TV(item), true,
+ fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK);
+ }
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Free the structure used to store info used by ":for".
+void free_for_info(void *fi_void)
+{
+ forinfo_T *fi = (forinfo_T *)fi_void;
+
+ if (fi == NULL) {
+ return;
+ }
+ if (fi->fi_list != NULL) {
+ tv_list_watch_remove(fi->fi_list, &fi->fi_lw);
+ tv_list_unref(fi->fi_list);
+ } else if (fi->fi_blob != NULL) {
+ tv_blob_unref(fi->fi_blob);
+ } else {
+ xfree(fi->fi_string);
+ }
+ xfree(fi);
+}
+
+void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int got_eq = FALSE;
+ int c;
+ char *p;
+
+ if (cmdidx == CMD_let || cmdidx == CMD_const) {
+ xp->xp_context = EXPAND_USER_VARS;
+ if (strpbrk(arg, "\"'+-*/%.=!?~|&$([<>,#") == NULL) {
+ // ":let var1 var2 ...": find last space.
+ for (p = arg + STRLEN(arg); p >= arg;) {
+ xp->xp_pattern = p;
+ MB_PTR_BACK(arg, p);
+ if (ascii_iswhite(*p)) {
+ break;
+ }
+ }
+ return;
+ }
+ } else {
+ xp->xp_context = cmdidx == CMD_call ? EXPAND_FUNCTIONS
+ : EXPAND_EXPRESSION;
+ }
+ while ((xp->xp_pattern = strpbrk(arg, "\"'+-*/%.=!?~|&$([<>,#")) != NULL) {
+ c = (uint8_t)(*xp->xp_pattern);
+ if (c == '&') {
+ c = (uint8_t)xp->xp_pattern[1];
+ if (c == '&') {
+ ++xp->xp_pattern;
+ xp->xp_context = cmdidx != CMD_let || got_eq
+ ? EXPAND_EXPRESSION : EXPAND_NOTHING;
+ } else if (c != ' ') {
+ xp->xp_context = EXPAND_SETTINGS;
+ if ((c == 'l' || c == 'g') && xp->xp_pattern[2] == ':') {
+ xp->xp_pattern += 2;
+ }
+ }
+ } else if (c == '$') {
+ // environment variable
+ xp->xp_context = EXPAND_ENV_VARS;
+ } else if (c == '=') {
+ got_eq = TRUE;
+ xp->xp_context = EXPAND_EXPRESSION;
+ } else if (c == '#'
+ && xp->xp_context == EXPAND_EXPRESSION) {
+ // Autoload function/variable contains '#'
+ break;
+ } else if ((c == '<' || c == '#')
+ && xp->xp_context == EXPAND_FUNCTIONS
+ && vim_strchr(xp->xp_pattern, '(') == NULL) {
+ // Function name can start with "<SNR>" and contain '#'.
+ break;
+ } else if (cmdidx != CMD_let || got_eq) {
+ if (c == '"') { // string
+ while ((c = (uint8_t)(*++xp->xp_pattern)) != NUL && c != '"') {
+ if (c == '\\' && xp->xp_pattern[1] != NUL) {
+ xp->xp_pattern++;
+ }
+ }
+ xp->xp_context = EXPAND_NOTHING;
+ } else if (c == '\'') { // literal string
+ // Trick: '' is like stopping and starting a literal string.
+ while ((c = (uint8_t)(*++xp->xp_pattern)) != NUL && c != '\'') {}
+ xp->xp_context = EXPAND_NOTHING;
+ } else if (c == '|') {
+ if (xp->xp_pattern[1] == '|') {
+ ++xp->xp_pattern;
+ xp->xp_context = EXPAND_EXPRESSION;
+ } else {
+ xp->xp_context = EXPAND_COMMANDS;
+ }
+ } else {
+ xp->xp_context = EXPAND_EXPRESSION;
+ }
+ } else {
+ // Doesn't look like something valid, expand as an expression
+ // anyway.
+ xp->xp_context = EXPAND_EXPRESSION;
+ }
+ arg = xp->xp_pattern;
+ if (*arg != NUL) {
+ while ((c = (char_u)(*++arg)) != NUL && (c == ' ' || c == '\t')) {}
+ }
+ }
+
+ // ":exe one two" completes "two"
+ if ((cmdidx == CMD_execute
+ || cmdidx == CMD_echo
+ || cmdidx == CMD_echon
+ || cmdidx == CMD_echomsg)
+ && xp->xp_context == EXPAND_EXPRESSION) {
+ for (;;) {
+ char *const n = (char *)skiptowhite((char_u *)arg);
+
+ if (n == arg || ascii_iswhite_or_nul(*skipwhite(n))) {
+ break;
+ }
+ arg = skipwhite(n);
+ }
+ }
+
+ xp->xp_pattern = arg;
+}
+
+/// Delete all "menutrans_" variables.
+void del_menutrans_vars(void)
+{
+ hash_lock(&globvarht);
+ HASHTAB_ITER(&globvarht, hi, {
+ if (STRNCMP(hi->hi_key, "menutrans_", 10) == 0) {
+ delete_var(&globvarht, hi);
+ }
+ });
+ hash_unlock(&globvarht);
+}
+
+/*
+ * Local string buffer for the next two functions to store a variable name
+ * with its prefix. Allocated in cat_prefix_varname(), freed later in
+ * get_user_var_name().
+ */
+
+static char *varnamebuf = NULL;
+static size_t varnamebuflen = 0;
+
+/// Function to concatenate a prefix and a variable name.
+char *cat_prefix_varname(int prefix, const char *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t len = STRLEN(name) + 3;
+
+ if (len > varnamebuflen) {
+ xfree(varnamebuf);
+ len += 10; // some additional space
+ varnamebuf = xmalloc(len);
+ varnamebuflen = len;
+ }
+ *varnamebuf = (char)prefix;
+ varnamebuf[1] = ':';
+ STRCPY(varnamebuf + 2, name);
+ return varnamebuf;
+}
+
+/// Function given to ExpandGeneric() to obtain the list of user defined
+/// (global/buffer/window/built-in) variable names.
+char *get_user_var_name(expand_T *xp, int idx)
+{
+ static size_t gdone;
+ static size_t bdone;
+ static size_t wdone;
+ static size_t tdone;
+ static size_t vidx;
+ static hashitem_T *hi;
+
+ if (idx == 0) {
+ gdone = bdone = wdone = vidx = 0;
+ tdone = 0;
+ }
+
+ // Global variables
+ if (gdone < globvarht.ht_used) {
+ if (gdone++ == 0) {
+ hi = globvarht.ht_array;
+ } else {
+ ++hi;
+ }
+ while (HASHITEM_EMPTY(hi)) {
+ ++hi;
+ }
+ if (STRNCMP("g:", xp->xp_pattern, 2) == 0) {
+ return cat_prefix_varname('g', (char *)hi->hi_key);
+ }
+ return (char *)hi->hi_key;
+ }
+
+ // b: variables
+ const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
+ if (bdone < ht->ht_used) {
+ if (bdone++ == 0) {
+ hi = ht->ht_array;
+ } else {
+ ++hi;
+ }
+ while (HASHITEM_EMPTY(hi)) {
+ ++hi;
+ }
+ return cat_prefix_varname('b', (char *)hi->hi_key);
+ }
+
+ // w: variables
+ ht = &prevwin_curwin()->w_vars->dv_hashtab;
+ if (wdone < ht->ht_used) {
+ if (wdone++ == 0) {
+ hi = ht->ht_array;
+ } else {
+ ++hi;
+ }
+ while (HASHITEM_EMPTY(hi)) {
+ ++hi;
+ }
+ return cat_prefix_varname('w', (char *)hi->hi_key);
+ }
+
+ // t: variables
+ ht = &curtab->tp_vars->dv_hashtab;
+ if (tdone < ht->ht_used) {
+ if (tdone++ == 0) {
+ hi = ht->ht_array;
+ } else {
+ ++hi;
+ }
+ while (HASHITEM_EMPTY(hi)) {
+ ++hi;
+ }
+ return cat_prefix_varname('t', (char *)hi->hi_key);
+ }
+
+ // v: variables
+ if (vidx < ARRAY_SIZE(vimvars)) {
+ return cat_prefix_varname('v', vimvars[vidx++].vv_name);
+ }
+
+ XFREE_CLEAR(varnamebuf);
+ varnamebuflen = 0;
+ return NULL;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Does not use 'cpo' and always uses 'magic'.
+///
+/// @return TRUE if "pat" matches "text".
+int pattern_match(char *pat, char *text, bool ic)
+{
+ int matches = 0;
+ regmatch_T regmatch;
+
+ // avoid 'l' flag in 'cpoptions'
+ char *save_cpo = p_cpo;
+ p_cpo = "";
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = ic;
+ matches = vim_regexec_nl(&regmatch, (char_u *)text, (colnr_T)0);
+ vim_regfree(regmatch.regprog);
+ }
+ p_cpo = save_cpo;
+ return matches;
+}
+
+/// Handle a name followed by "(". Both for just "name(arg)" and for
+/// "expr->name(arg)".
+///
+/// @param arg Points to "(", will be advanced
+/// @param basetv "expr" for "expr->name(arg)"
+///
+/// @return OK or FAIL.
+static int eval_func(char **const arg, char *const name, const int name_len, typval_T *const rettv,
+ const bool evaluate, typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
+{
+ char *s = name;
+ int len = name_len;
+
+ if (!evaluate) {
+ check_vars((const char *)s, (size_t)len);
+ }
+
+ // If "s" is the name of a variable of type VAR_FUNC
+ // use its contents.
+ partial_T *partial;
+ s = (char *)deref_func_name((const char *)s, &len, &partial, !evaluate);
+
+ // Need to make a copy, in case evaluating the arguments makes
+ // the name invalid.
+ s = xmemdupz(s, (size_t)len);
+
+ // Invoke the function.
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = evaluate;
+ funcexe.partial = partial;
+ funcexe.basetv = basetv;
+ int ret = get_func_tv((char_u *)s, len, rettv, (char_u **)arg, &funcexe);
+
+ xfree(s);
+
+ // If evaluate is false rettv->v_type was not set in
+ // get_func_tv, but it's needed in handle_subscript() to parse
+ // what follows. So set it here.
+ if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
+ rettv->vval.v_string = (char *)tv_empty_string;
+ rettv->v_type = VAR_FUNC;
+ }
+
+ // Stop the expression evaluation when immediately
+ // aborting on error, or when an interrupt occurred or
+ // an exception was thrown but not caught.
+ if (evaluate && aborting()) {
+ if (ret == OK) {
+ tv_clear(rettv);
+ }
+ ret = FAIL;
+ }
+ return ret;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/*
+ * The "evaluate" argument: When FALSE, the argument is only parsed but not
+ * executed. The function may return OK, but the rettv will be of type
+ * VAR_UNKNOWN. The function still returns FAIL for a syntax error.
+ */
+
+/// Handle zero level expression.
+/// This calls eval1() and handles error message and nextcmd.
+/// Put the result in "rettv" when returning OK and "evaluate" is TRUE.
+/// Note: "rettv.v_lock" is not set.
+///
+/// @return OK or FAIL.
+int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate)
+{
+ int ret;
+ char *p;
+ const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
+
+ p = skipwhite(arg);
+ ret = eval1(&p, rettv, evaluate);
+ if (ret == FAIL || !ends_excmd(*p)) {
+ if (ret != FAIL) {
+ tv_clear(rettv);
+ }
+ // Report the invalid expression unless the expression evaluation has
+ // been cancelled due to an aborting error, an interrupt, or an
+ // exception, or we already gave a more specific error.
+ // Also check called_emsg for when using assert_fails().
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before) {
+ semsg(_(e_invexpr2), arg);
+ }
+ ret = FAIL;
+ }
+ if (nextcmd != NULL) {
+ *nextcmd = (char *)check_nextcmd((char_u *)p);
+ }
+
+ return ret;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle top level expression:
+/// expr2 ? expr1 : expr1
+///
+/// "arg" must point to the first non-white of the expression.
+/// "arg" is advanced to the next non-white after the recognized expression.
+///
+/// Note: "rettv.v_lock" is not set.
+///
+/// @return OK or FAIL.
+int eval1(char **arg, typval_T *rettv, int evaluate)
+{
+ int result;
+ typval_T var2;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval2(arg, rettv, evaluate) == FAIL) {
+ return FAIL;
+ }
+
+ if ((*arg)[0] == '?') {
+ result = FALSE;
+ if (evaluate) {
+ bool error = false;
+
+ if (tv_get_number_chk(rettv, &error) != 0) {
+ result = true;
+ }
+ tv_clear(rettv);
+ if (error) {
+ return FAIL;
+ }
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive!
+ return FAIL;
+ }
+
+ /*
+ * Check for the ":".
+ */
+ if ((*arg)[0] != ':') {
+ emsg(_("E109: Missing ':' after '?'"));
+ if (evaluate && result) {
+ tv_clear(rettv);
+ }
+ return FAIL;
+ }
+
+ /*
+ * Get the third variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, &var2, evaluate && !result) == FAIL) { // Recursive!
+ if (evaluate && result) {
+ tv_clear(rettv);
+ }
+ return FAIL;
+ }
+ if (evaluate && !result) {
+ *rettv = var2;
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle first level expression:
+/// expr2 || expr2 || expr2 logical OR
+///
+/// "arg" must point to the first non-white of the expression.
+/// "arg" is advanced to the next non-white after the recognized expression.
+///
+/// @return OK or FAIL.
+static int eval2(char **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ long result;
+ int first;
+ bool error = false;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval3(arg, rettv, evaluate) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Repeat until there is no following "||".
+ */
+ first = TRUE;
+ result = FALSE;
+ while ((*arg)[0] == '|' && (*arg)[1] == '|') {
+ if (evaluate && first) {
+ if (tv_get_number_chk(rettv, &error) != 0) {
+ result = true;
+ }
+ tv_clear(rettv);
+ if (error) {
+ return FAIL;
+ }
+ first = false;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 2);
+ if (eval3(arg, &var2, evaluate && !result) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Compute the result.
+ */
+ if (evaluate && !result) {
+ if (tv_get_number_chk(&var2, &error) != 0) {
+ result = true;
+ }
+ tv_clear(&var2);
+ if (error) {
+ return FAIL;
+ }
+ }
+ if (evaluate) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = result;
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle second level expression:
+/// expr3 && expr3 && expr3 logical AND
+///
+/// @param arg must point to the first non-white of the expression.
+/// `arg` is advanced to the next non-white after the recognized expression.
+///
+/// @return OK or FAIL.
+static int eval3(char **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ long result;
+ int first;
+ bool error = false;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval4(arg, rettv, evaluate) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Repeat until there is no following "&&".
+ */
+ first = TRUE;
+ result = TRUE;
+ while ((*arg)[0] == '&' && (*arg)[1] == '&') {
+ if (evaluate && first) {
+ if (tv_get_number_chk(rettv, &error) == 0) {
+ result = false;
+ }
+ tv_clear(rettv);
+ if (error) {
+ return FAIL;
+ }
+ first = false;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 2);
+ if (eval4(arg, &var2, evaluate && result) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Compute the result.
+ */
+ if (evaluate && result) {
+ if (tv_get_number_chk(&var2, &error) == 0) {
+ result = false;
+ }
+ tv_clear(&var2);
+ if (error) {
+ return FAIL;
+ }
+ }
+ if (evaluate) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = result;
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle third level expression:
+/// var1 == var2
+/// var1 =~ var2
+/// var1 != var2
+/// var1 !~ var2
+/// var1 > var2
+/// var1 >= var2
+/// var1 < var2
+/// var1 <= var2
+/// var1 is var2
+/// var1 isnot var2
+///
+/// "arg" must point to the first non-white of the expression.
+/// "arg" is advanced to the next non-white after the recognized expression.
+///
+/// @return OK or FAIL.
+static int eval4(char **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ char *p;
+ exprtype_T type = EXPR_UNKNOWN;
+ int len = 2;
+ bool ic;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval5(arg, rettv, evaluate) == FAIL) {
+ return FAIL;
+ }
+
+ p = *arg;
+ switch (p[0]) {
+ case '=':
+ if (p[1] == '=') {
+ type = EXPR_EQUAL;
+ } else if (p[1] == '~') {
+ type = EXPR_MATCH;
+ }
+ break;
+ case '!':
+ if (p[1] == '=') {
+ type = EXPR_NEQUAL;
+ } else if (p[1] == '~') {
+ type = EXPR_NOMATCH;
+ }
+ break;
+ case '>':
+ if (p[1] != '=') {
+ type = EXPR_GREATER;
+ len = 1;
+ } else {
+ type = EXPR_GEQUAL;
+ }
+ break;
+ case '<':
+ if (p[1] != '=') {
+ type = EXPR_SMALLER;
+ len = 1;
+ } else {
+ type = EXPR_SEQUAL;
+ }
+ break;
+ case 'i':
+ if (p[1] == 's') {
+ if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') {
+ len = 5;
+ }
+ if (!isalnum(p[len]) && p[len] != '_') {
+ type = len == 2 ? EXPR_IS : EXPR_ISNOT;
+ }
+ }
+ break;
+ }
+
+ /*
+ * If there is a comparative operator, use it.
+ */
+ if (type != EXPR_UNKNOWN) {
+ // extra question mark appended: ignore case
+ if (p[len] == '?') {
+ ic = true;
+ len++;
+ } else if (p[len] == '#') { // extra '#' appended: match case
+ ic = false;
+ len++;
+ } else { // nothing appended: use 'ignorecase'
+ ic = p_ic;
+ }
+
+ // Get the second variable.
+ *arg = skipwhite(p + len);
+ if (eval5(arg, &var2, evaluate) == FAIL) {
+ tv_clear(rettv);
+ return FAIL;
+ }
+ if (evaluate) {
+ const int ret = typval_compare(rettv, &var2, type, ic);
+
+ tv_clear(&var2);
+ return ret;
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle fourth level expression:
+/// + number addition
+/// - number subtraction
+/// . string concatenation
+/// .. string concatenation
+///
+/// @param arg must point to the first non-white of the expression.
+/// `arg` is advanced to the next non-white after the recognized expression.
+///
+/// @return OK or FAIL.
+static int eval5(char **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ typval_T var3;
+ int op;
+ varnumber_T n1, n2;
+ float_T f1 = 0, f2 = 0;
+ char *p;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval6(arg, rettv, evaluate, FALSE) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Repeat computing, until no '+', '-' or '.' is following.
+ */
+ for (;;) {
+ op = (char_u)(**arg);
+ if (op != '+' && op != '-' && op != '.') {
+ break;
+ }
+
+ if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB))
+ && (op == '.' || rettv->v_type != VAR_FLOAT)) {
+ // For "list + ...", an illegal use of the first operand as
+ // a number cannot be determined before evaluating the 2nd
+ // operand: if this is also a list, all is ok.
+ // For "something . ...", "something - ..." or "non-list + ...",
+ // we know that the first operand needs to be a string or number
+ // without evaluating the 2nd operand. So check before to avoid
+ // side effects after an error.
+ if (evaluate && !tv_check_str(rettv)) {
+ tv_clear(rettv);
+ return FAIL;
+ }
+ }
+
+ /*
+ * Get the second variable.
+ */
+ if (op == '.' && *(*arg + 1) == '.') { // ..string concatenation
+ (*arg)++;
+ }
+ *arg = skipwhite(*arg + 1);
+ if (eval6(arg, &var2, evaluate, op == '.') == FAIL) {
+ tv_clear(rettv);
+ return FAIL;
+ }
+
+ if (evaluate) {
+ /*
+ * Compute the result.
+ */
+ if (op == '.') {
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ // s1 already checked
+ const char *const s1 = tv_get_string_buf(rettv, buf1);
+ const char *const s2 = tv_get_string_buf_chk(&var2, buf2);
+ if (s2 == NULL) { // Type error?
+ tv_clear(rettv);
+ tv_clear(&var2);
+ return FAIL;
+ }
+ p = (char *)concat_str((const char_u *)s1, (const char_u *)s2);
+ tv_clear(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = p;
+ } else if (op == '+' && rettv->v_type == VAR_BLOB
+ && var2.v_type == VAR_BLOB) {
+ const blob_T *const b1 = rettv->vval.v_blob;
+ const blob_T *const b2 = var2.vval.v_blob;
+ blob_T *const b = tv_blob_alloc();
+
+ for (int i = 0; i < tv_blob_len(b1); i++) {
+ ga_append(&b->bv_ga, (char)tv_blob_get(b1, i));
+ }
+ for (int i = 0; i < tv_blob_len(b2); i++) {
+ ga_append(&b->bv_ga, (char)tv_blob_get(b2, i));
+ }
+
+ tv_clear(rettv);
+ tv_blob_set_ret(rettv, b);
+ } else if (op == '+' && rettv->v_type == VAR_LIST
+ && var2.v_type == VAR_LIST) {
+ // Concatenate Lists.
+ if (tv_list_concat(rettv->vval.v_list, var2.vval.v_list, &var3)
+ == FAIL) {
+ tv_clear(rettv);
+ tv_clear(&var2);
+ return FAIL;
+ }
+ tv_clear(rettv);
+ *rettv = var3;
+ } else {
+ bool error = false;
+
+ if (rettv->v_type == VAR_FLOAT) {
+ f1 = rettv->vval.v_float;
+ n1 = 0;
+ } else {
+ n1 = tv_get_number_chk(rettv, &error);
+ if (error) {
+ // This can only happen for "list + non-list" or
+ // "blob + non-blob". For "non-list + ..." or
+ // "something - ...", we returned before evaluating the
+ // 2nd operand.
+ tv_clear(rettv);
+ tv_clear(&var2);
+ return FAIL;
+ }
+ if (var2.v_type == VAR_FLOAT) {
+ f1 = (float_T)n1;
+ }
+ }
+ if (var2.v_type == VAR_FLOAT) {
+ f2 = var2.vval.v_float;
+ n2 = 0;
+ } else {
+ n2 = tv_get_number_chk(&var2, &error);
+ if (error) {
+ tv_clear(rettv);
+ tv_clear(&var2);
+ return FAIL;
+ }
+ if (rettv->v_type == VAR_FLOAT) {
+ f2 = (float_T)n2;
+ }
+ }
+ tv_clear(rettv);
+
+ // If there is a float on either side the result is a float.
+ if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) {
+ if (op == '+') {
+ f1 = f1 + f2;
+ } else {
+ f1 = f1 - f2;
+ }
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f1;
+ } else {
+ if (op == '+') {
+ n1 = n1 + n2;
+ } else {
+ n1 = n1 - n2;
+ }
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n1;
+ }
+ }
+ tv_clear(&var2);
+ }
+ }
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle fifth level expression:
+/// - * number multiplication
+/// - / number division
+/// - % number modulo
+///
+/// @param[in,out] arg Points to the first non-whitespace character of the
+/// expression. Is advanced to the next non-whitespace
+/// character after the recognized expression.
+/// @param[out] rettv Location where result is saved.
+/// @param[in] evaluate If not true, rettv is not populated.
+/// @param[in] want_string True if "." is string_concatenation, otherwise
+/// float
+/// @return OK or FAIL.
+static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
+ FUNC_ATTR_NO_SANITIZE_UNDEFINED
+{
+ typval_T var2;
+ int op;
+ varnumber_T n1, n2;
+ bool use_float = false;
+ float_T f1 = 0, f2 = 0;
+ bool error = false;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval7(arg, rettv, evaluate, want_string) == FAIL) {
+ return FAIL;
+ }
+
+ /*
+ * Repeat computing, until no '*', '/' or '%' is following.
+ */
+ for (;;) {
+ op = (char_u)(**arg);
+ if (op != '*' && op != '/' && op != '%') {
+ break;
+ }
+
+ if (evaluate) {
+ if (rettv->v_type == VAR_FLOAT) {
+ f1 = rettv->vval.v_float;
+ use_float = true;
+ n1 = 0;
+ } else {
+ n1 = tv_get_number_chk(rettv, &error);
+ }
+ tv_clear(rettv);
+ if (error) {
+ return FAIL;
+ }
+ } else {
+ n1 = 0;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval7(arg, &var2, evaluate, false) == FAIL) {
+ return FAIL;
+ }
+
+ if (evaluate) {
+ if (var2.v_type == VAR_FLOAT) {
+ if (!use_float) {
+ f1 = (float_T)n1;
+ use_float = true;
+ }
+ f2 = var2.vval.v_float;
+ n2 = 0;
+ } else {
+ n2 = tv_get_number_chk(&var2, &error);
+ tv_clear(&var2);
+ if (error) {
+ return FAIL;
+ }
+ if (use_float) {
+ f2 = (float_T)n2;
+ }
+ }
+
+ /*
+ * Compute the result.
+ * When either side is a float the result is a float.
+ */
+ if (use_float) {
+ if (op == '*') {
+ f1 = f1 * f2;
+ } else if (op == '/') {
+ // uncrustify:off
+
+ // Division by zero triggers error from AddressSanitizer
+ f1 = (f2 == 0 ? (
+#ifdef NAN
+ f1 == 0 ? (float_T)NAN :
+#endif
+ (f1 > 0 ? (float_T)INFINITY : (float_T)-INFINITY)) : f1 / f2);
+
+ // uncrustify:on
+ } else {
+ emsg(_("E804: Cannot use '%' with Float"));
+ return FAIL;
+ }
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f1;
+ } else {
+ if (op == '*') {
+ n1 = n1 * n2;
+ } else if (op == '/') {
+ n1 = num_divide(n1, n2);
+ } else {
+ n1 = num_modulus(n1, n2);
+ }
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n1;
+ }
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Handle sixth level expression:
+/// number number constant
+/// 0zFFFFFFFF Blob constant
+/// "string" string constant
+/// 'string' literal string constant
+/// &option-name option value
+/// @r register contents
+/// identifier variable value
+/// function() function call
+/// $VAR environment variable
+/// (expression) nested expression
+/// [expr, expr] List
+/// {key: val, key: val} Dictionary
+/// #{key: val, key: val} Dictionary with literal keys
+///
+/// Also handle:
+/// ! in front logical NOT
+/// - in front unary minus
+/// + in front unary plus (ignored)
+/// trailing [] subscript in String or List
+/// trailing .name entry in Dictionary
+/// trailing ->name() method call
+///
+/// "arg" must point to the first non-white of the expression.
+/// "arg" is advanced to the next non-white after the recognized expression.
+///
+/// @param want_string after "." operator
+///
+/// @return OK or FAIL.
+static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
+{
+ varnumber_T n;
+ int len;
+ char *s;
+ const char *start_leader, *end_leader;
+ int ret = OK;
+ char *alias;
+
+ // Initialise variable so that tv_clear() can't mistake this for a
+ // string and free a string that isn't there.
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Skip '!', '-' and '+' characters. They are handled later.
+ start_leader = *arg;
+ while (**arg == '!' || **arg == '-' || **arg == '+') {
+ *arg = skipwhite(*arg + 1);
+ }
+ end_leader = *arg;
+
+ switch (**arg) {
+ // Number constant.
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ char *p = skipdigits(*arg + 1);
+ int get_float = false;
+
+ // We accept a float when the format matches
+ // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
+ // strict to avoid backwards compatibility problems.
+ // Don't look for a float after the "." operator, so that
+ // ":let vers = 1.2.3" doesn't fail.
+ if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
+ get_float = true;
+ p = skipdigits(p + 2);
+ if (*p == 'e' || *p == 'E') {
+ ++p;
+ if (*p == '-' || *p == '+') {
+ ++p;
+ }
+ if (!ascii_isdigit(*p)) {
+ get_float = false;
+ } else {
+ p = skipdigits(p + 1);
+ }
+ }
+ if (ASCII_ISALPHA(*p) || *p == '.') {
+ get_float = false;
+ }
+ }
+ if (get_float) {
+ float_T f;
+
+ *arg += string2float(*arg, &f);
+ if (evaluate) {
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f;
+ }
+ } else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) {
+ blob_T *blob = NULL;
+ // Blob constant: 0z0123456789abcdef
+ if (evaluate) {
+ blob = tv_blob_alloc();
+ }
+ char *bp;
+ for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) {
+ if (!ascii_isxdigit(bp[1])) {
+ if (blob != NULL) {
+ emsg(_("E973: Blob literal should have an even number of hex "
+ "characters"));
+ ga_clear(&blob->bv_ga);
+ XFREE_CLEAR(blob);
+ }
+ ret = FAIL;
+ break;
+ }
+ if (blob != NULL) {
+ ga_append(&blob->bv_ga, (char)((hex2nr(*bp) << 4) + hex2nr(*(bp + 1))));
+ }
+ if (bp[2] == '.' && ascii_isxdigit(bp[3])) {
+ bp++;
+ }
+ }
+ if (blob != NULL) {
+ tv_blob_set_ret(rettv, blob);
+ }
+ *arg = bp;
+ } else {
+ // decimal, hex or octal number
+ vim_str2nr((char_u *)(*arg), NULL, &len, STR2NR_ALL, &n, NULL, 0, true);
+ if (len == 0) {
+ semsg(_(e_invexpr2), *arg);
+ ret = FAIL;
+ break;
+ }
+ *arg += len;
+ if (evaluate) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n;
+ }
+ }
+ break;
+ }
+
+ // String constant: "string".
+ case '"':
+ ret = get_string_tv(arg, rettv, evaluate);
+ break;
+
+ // Literal string constant: 'str''ing'.
+ case '\'':
+ ret = get_lit_string_tv(arg, rettv, evaluate);
+ break;
+
+ // List: [expr, expr]
+ case '[':
+ ret = get_list_tv(arg, rettv, evaluate);
+ break;
+
+ // Dictionary: #{key: val, key: val}
+ case '#':
+ if ((*arg)[1] == '{') {
+ (*arg)++;
+ ret = dict_get_tv(arg, rettv, evaluate, true);
+ } else {
+ ret = NOTDONE;
+ }
+ break;
+
+ // Lambda: {arg, arg -> expr}
+ // Dictionary: {'key': val, 'key': val}
+ case '{':
+ ret = get_lambda_tv((char_u **)arg, rettv, evaluate);
+ if (ret == NOTDONE) {
+ ret = dict_get_tv(arg, rettv, evaluate, false);
+ }
+ break;
+
+ // Option value: &name
+ case '&':
+ ret = get_option_tv((const char **)arg, rettv, evaluate);
+ break;
+ // Environment variable: $VAR.
+ case '$':
+ ret = get_env_tv(arg, rettv, evaluate);
+ break;
+
+ // Register contents: @r.
+ case '@':
+ ++*arg;
+ int regname = mb_cptr2char_adv((const char_u**) arg);
+ if (evaluate) {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = get_reg_contents(regname, kGRegExprSrc);
+ }
+ // if (**arg != NUL) {
+ // ++*arg;
+ // }
+ break;
+
+ // nested expression: (expression).
+ case '(':
+ *arg = skipwhite(*arg + 1);
+ ret = eval1(arg, rettv, evaluate); // recursive!
+ if (**arg == ')') {
+ ++*arg;
+ } else if (ret == OK) {
+ emsg(_("E110: Missing ')'"));
+ tv_clear(rettv);
+ ret = FAIL;
+ }
+ break;
+
+ default:
+ ret = NOTDONE;
+ break;
+ }
+
+ if (ret == NOTDONE) {
+ // Must be a variable or function name.
+ // Can also be a curly-braces kind of name: {expr}.
+ s = *arg;
+ len = get_name_len((const char **)arg, &alias, evaluate, true);
+ if (alias != NULL) {
+ s = alias;
+ }
+
+ if (len <= 0) {
+ ret = FAIL;
+ } else {
+ if (**arg == '(') { // recursive!
+ ret = eval_func(arg, s, len, rettv, evaluate, NULL);
+ } else if (evaluate) {
+ ret = get_var_tv((const char *)s, len, rettv, NULL, true, false);
+ } else {
+ check_vars((const char *)s, (size_t)len);
+ ret = OK;
+ }
+ }
+ xfree(alias);
+ }
+
+ *arg = skipwhite(*arg);
+
+ // Handle following '[', '(' and '.' for expr[expr], expr.name,
+ // expr(expr), expr->name(expr)
+ if (ret == OK) {
+ ret = handle_subscript((const char **)arg, rettv, evaluate, true,
+ (char *)start_leader, &end_leader);
+ }
+
+ // Apply logical NOT and unary '-', from right to left, ignore '+'.
+ if (ret == OK && evaluate && end_leader > start_leader) {
+ ret = eval7_leader(rettv, (char *)start_leader, &end_leader);
+ }
+ return ret;
+}
+
+/// Apply the leading "!" and "-" before an eval7 expression to "rettv".
+/// Adjusts "end_leaderp" until it is at "start_leader".
+///
+/// @return OK on success, FAIL on failure.
+static int eval7_leader(typval_T *const rettv, const char *const start_leader,
+ const char **const end_leaderp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *end_leader = (char *)(*end_leaderp);
+ int ret = OK;
+ bool error = false;
+ varnumber_T val = 0;
+ float_T f = 0.0;
+
+ if (rettv->v_type == VAR_FLOAT) {
+ f = rettv->vval.v_float;
+ } else {
+ val = tv_get_number_chk(rettv, &error);
+ }
+ if (error) {
+ tv_clear(rettv);
+ ret = FAIL;
+ } else {
+ while (end_leader > start_leader) {
+ end_leader--;
+ if (*end_leader == '!') {
+ if (rettv->v_type == VAR_FLOAT) {
+ f = !(bool)f;
+ } else {
+ val = !val;
+ }
+ } else if (*end_leader == '-') {
+ if (rettv->v_type == VAR_FLOAT) {
+ f = -f;
+ } else {
+ val = -val;
+ }
+ }
+ }
+ if (rettv->v_type == VAR_FLOAT) {
+ tv_clear(rettv);
+ rettv->vval.v_float = f;
+ } else {
+ tv_clear(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = val;
+ }
+ }
+
+ *end_leaderp = end_leader;
+ return ret;
+}
+
+/// Call the function referred to in "rettv".
+/// @param lua_funcname If `rettv` refers to a v:lua function, this must point
+/// to the name of the Lua function to call (after the
+/// "v:lua." prefix).
+/// @return OK on success, FAIL on failure.
+static int call_func_rettv(char **const arg, typval_T *const rettv, const bool evaluate,
+ dict_T *const selfdict, typval_T *const basetv,
+ const char *const lua_funcname)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ partial_T *pt = NULL;
+ typval_T functv;
+ const char *funcname;
+ bool is_lua = false;
+
+ // need to copy the funcref so that we can clear rettv
+ if (evaluate) {
+ functv = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Invoke the function. Recursive!
+ if (functv.v_type == VAR_PARTIAL) {
+ pt = functv.vval.v_partial;
+ is_lua = is_luafunc(pt);
+ funcname = is_lua ? lua_funcname : partial_name(pt);
+ } else {
+ funcname = functv.vval.v_string;
+ }
+ } else {
+ funcname = "";
+ }
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = evaluate;
+ funcexe.partial = pt;
+ funcexe.selfdict = selfdict;
+ funcexe.basetv = basetv;
+ const int ret = get_func_tv((char_u *)funcname, is_lua ? (int)(*arg - funcname) : -1, rettv,
+ (char_u **)arg, &funcexe);
+
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&functv);
+ }
+
+ return ret;
+}
+
+/// Evaluate "->method()".
+///
+/// @param verbose if true, give error messages.
+/// @param *arg points to the '-'.
+///
+/// @return FAIL or OK.
+///
+/// @note "*arg" is advanced to after the ')'.
+static int eval_lambda(char **const arg, typval_T *const rettv, const bool evaluate,
+ const bool verbose)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Skip over the ->.
+ *arg += 2;
+ typval_T base = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ int ret = get_lambda_tv((char_u **)arg, rettv, evaluate);
+ if (ret != OK) {
+ return FAIL;
+ } else if (**arg != '(') {
+ if (verbose) {
+ if (*skipwhite(*arg) == '(') {
+ emsg(_(e_nowhitespace));
+ } else {
+ semsg(_(e_missingparen), "lambda");
+ }
+ }
+ tv_clear(rettv);
+ ret = FAIL;
+ } else {
+ ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, NULL);
+ }
+
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&base);
+ }
+
+ return ret;
+}
+
+/// Evaluate "->method()" or "->v:lua.method()".
+///
+/// @param *arg points to the '-'.
+///
+/// @return FAIL or OK. "*arg" is advanced to after the ')'.
+static int eval_method(char **const arg, typval_T *const rettv, const bool evaluate,
+ const bool verbose)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Skip over the ->.
+ *arg += 2;
+ typval_T base = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Locate the method name.
+ int len;
+ char *name = *arg;
+ char *lua_funcname = NULL;
+ if (STRNCMP(name, "v:lua.", 6) == 0) {
+ lua_funcname = name + 6;
+ *arg = (char *)skip_luafunc_name((const char *)lua_funcname);
+ *arg = skipwhite(*arg); // to detect trailing whitespace later
+ len = (int)(*arg - lua_funcname);
+ } else {
+ char *alias;
+ len = get_name_len((const char **)arg, &alias, evaluate, true);
+ if (alias != NULL) {
+ name = alias;
+ }
+ }
+
+ int ret;
+ if (len <= 0) {
+ if (verbose) {
+ if (lua_funcname == NULL) {
+ emsg(_("E260: Missing name after ->"));
+ } else {
+ semsg(_(e_invexpr2), name);
+ }
+ }
+ ret = FAIL;
+ } else {
+ if (**arg != '(') {
+ if (verbose) {
+ semsg(_(e_missingparen), name);
+ }
+ ret = FAIL;
+ } else if (ascii_iswhite((*arg)[-1])) {
+ if (verbose) {
+ emsg(_(e_nowhitespace));
+ }
+ ret = FAIL;
+ } else if (lua_funcname != NULL) {
+ if (evaluate) {
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = vvlua_partial;
+ rettv->vval.v_partial->pt_refcount++;
+ }
+ ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname);
+ } else {
+ ret = eval_func(arg, name, len, rettv, evaluate, &base);
+ }
+ }
+
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&base);
+ }
+
+ return ret;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
+/// "*arg" points to the '[' or '.'.
+///
+/// @param verbose give error messages
+///
+/// @returns FAIL or OK. "*arg" is advanced to after the ']'.
+static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose)
+{
+ bool empty1 = false;
+ bool empty2 = false;
+ long n1, n2 = 0;
+ ptrdiff_t len = -1;
+ int range = false;
+ char *key = NULL;
+
+ switch (rettv->v_type) {
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ if (verbose) {
+ emsg(_("E695: Cannot index a Funcref"));
+ }
+ return FAIL;
+ case VAR_FLOAT:
+ if (verbose) {
+ emsg(_(e_float_as_string));
+ }
+ return FAIL;
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ if (verbose) {
+ emsg(_("E909: Cannot index a special variable"));
+ }
+ return FAIL;
+ case VAR_UNKNOWN:
+ if (evaluate) {
+ return FAIL;
+ }
+ FALLTHROUGH;
+ case VAR_STRING:
+ case VAR_NUMBER:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_BLOB:
+ break;
+ }
+
+ typval_T var1 = TV_INITIAL_VALUE;
+ typval_T var2 = TV_INITIAL_VALUE;
+ if (**arg == '.') {
+ /*
+ * dict.name
+ */
+ key = *arg + 1;
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {}
+ if (len == 0) {
+ return FAIL;
+ }
+ *arg = skipwhite(key + len);
+ } else {
+ /*
+ * something[idx]
+ *
+ * Get the (first) variable from inside the [].
+ */
+ *arg = skipwhite(*arg + 1);
+ if (**arg == ':') {
+ empty1 = true;
+ } else if (eval1(arg, &var1, evaluate) == FAIL) { // Recursive!
+ return FAIL;
+ } else if (evaluate && !tv_check_str(&var1)) {
+ // Not a number or string.
+ tv_clear(&var1);
+ return FAIL;
+ }
+
+ /*
+ * Get the second variable from inside the [:].
+ */
+ if (**arg == ':') {
+ range = true;
+ *arg = skipwhite(*arg + 1);
+ if (**arg == ']') {
+ empty2 = true;
+ } else if (eval1(arg, &var2, evaluate) == FAIL) { // Recursive!
+ if (!empty1) {
+ tv_clear(&var1);
+ }
+ return FAIL;
+ } else if (evaluate && !tv_check_str(&var2)) {
+ // Not a number or string.
+ if (!empty1) {
+ tv_clear(&var1);
+ }
+ tv_clear(&var2);
+ return FAIL;
+ }
+ }
+
+ // Check for the ']'.
+ if (**arg != ']') {
+ if (verbose) {
+ emsg(_(e_missbrac));
+ }
+ tv_clear(&var1);
+ if (range) {
+ tv_clear(&var2);
+ }
+ return FAIL;
+ }
+ *arg = skipwhite(*arg + 1); // skip the ']'
+ }
+
+ if (evaluate) {
+ n1 = 0;
+ if (!empty1 && rettv->v_type != VAR_DICT && !tv_is_luafunc(rettv)) {
+ n1 = tv_get_number(&var1);
+ tv_clear(&var1);
+ }
+ if (range) {
+ if (empty2) {
+ n2 = -1;
+ } else {
+ n2 = tv_get_number(&var2);
+ tv_clear(&var2);
+ }
+ }
+
+ switch (rettv->v_type) {
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ const char *const s = tv_get_string(rettv);
+ char *v;
+ len = (ptrdiff_t)strlen(s);
+ if (range) {
+ // The resulting variable is a substring. If the indexes
+ // are out of range the result is empty.
+ if (n1 < 0) {
+ n1 = len + n1;
+ if (n1 < 0) {
+ n1 = 0;
+ }
+ }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len;
+ }
+ if (n1 >= len || n2 < 0 || n1 > n2) {
+ v = NULL;
+ } else {
+ v = xmemdupz(s + n1, (size_t)(n2 - n1 + 1));
+ }
+ } else {
+ // The resulting variable is a string of a single
+ // character. If the index is too big or negative the
+ // result is empty.
+ if (n1 >= len || n1 < 0) {
+ v = NULL;
+ } else {
+ v = xmemdupz(s + n1, 1);
+ }
+ }
+ tv_clear(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = v;
+ break;
+ }
+ case VAR_BLOB:
+ len = tv_blob_len(rettv->vval.v_blob);
+ if (range) {
+ // The resulting variable is a sub-blob. If the indexes
+ // are out of range the result is empty.
+ if (n1 < 0) {
+ n1 = len + n1;
+ if (n1 < 0) {
+ n1 = 0;
+ }
+ }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len - 1;
+ }
+ if (n1 >= len || n2 < 0 || n1 > n2) {
+ tv_clear(rettv);
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = NULL;
+ } else {
+ blob_T *const blob = tv_blob_alloc();
+ ga_grow(&blob->bv_ga, (int)(n2 - n1 + 1));
+ blob->bv_ga.ga_len = (int)(n2 - n1 + 1);
+ for (long i = n1; i <= n2; i++) {
+ tv_blob_set(blob, (int)(i - n1), tv_blob_get(rettv->vval.v_blob, (int)i));
+ }
+ tv_clear(rettv);
+ tv_blob_set_ret(rettv, blob);
+ }
+ } else {
+ // The resulting variable is a byte value.
+ // If the index is too big or negative that is an error.
+ if (n1 < 0) {
+ n1 = len + n1;
+ }
+ if (n1 < len && n1 >= 0) {
+ const int v = (int)tv_blob_get(rettv->vval.v_blob, (int)n1);
+ tv_clear(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = v;
+ } else {
+ semsg(_(e_blobidx), (int64_t)n1);
+ }
+ }
+ break;
+ case VAR_LIST:
+ len = tv_list_len(rettv->vval.v_list);
+ if (n1 < 0) {
+ n1 = len + n1;
+ }
+ if (!empty1 && (n1 < 0 || n1 >= len)) {
+ // For a range we allow invalid values and return an empty
+ // list. A list index out of range is an error.
+ if (!range) {
+ if (verbose) {
+ semsg(_(e_listidx), (int64_t)n1);
+ }
+ return FAIL;
+ }
+ n1 = len;
+ }
+ if (range) {
+ list_T *l;
+ listitem_T *item;
+
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len - 1;
+ }
+ if (!empty2 && (n2 < 0 || n2 + 1 < n1)) {
+ n2 = -1;
+ }
+ l = tv_list_alloc(n2 - n1 + 1);
+ item = tv_list_find(rettv->vval.v_list, (int)n1);
+ while (n1++ <= n2) {
+ tv_list_append_tv(l, TV_LIST_ITEM_TV(item));
+ item = TV_LIST_ITEM_NEXT(rettv->vval.v_list, item);
+ }
+ tv_clear(rettv);
+ tv_list_set_ret(rettv, l);
+ } else {
+ tv_copy(TV_LIST_ITEM_TV(tv_list_find(rettv->vval.v_list, (int)n1)), &var1);
+ tv_clear(rettv);
+ *rettv = var1;
+ }
+ break;
+ case VAR_DICT: {
+ if (range) {
+ if (verbose) {
+ emsg(_(e_dictrange));
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
+ return FAIL;
+ }
+
+ if (len == -1) {
+ key = (char *)tv_get_string_chk(&var1);
+ if (key == NULL) {
+ tv_clear(&var1);
+ return FAIL;
+ }
+ }
+
+ dictitem_T *const item = tv_dict_find(rettv->vval.v_dict,
+ (const char *)key, len);
+
+ if (item == NULL && verbose) {
+ semsg(_(e_dictkey), key);
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
+ if (item == NULL || tv_is_luafunc(&item->di_tv)) {
+ return FAIL;
+ }
+
+ tv_copy(&item->di_tv, &var1);
+ tv_clear(rettv);
+ *rettv = var1;
+ break;
+ }
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FUNC:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_UNKNOWN:
+ break; // Not evaluating, skipping over subscript
+ }
+ }
+
+ return OK;
+}
+
+// TODO(ZyX-I): move to eval/executor
+
+/// Get an option value
+///
+/// @param[in,out] arg Points to the '&' or '+' before the option name. Is
+/// advanced to the character after the option name.
+/// @param[out] rettv Location where result is saved.
+/// @param[in] evaluate If not true, rettv is not populated.
+///
+/// @return OK or FAIL.
+int get_option_tv(const char **const arg, typval_T *const rettv, const bool evaluate)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ long numval;
+ char *stringval;
+ getoption_T opt_type;
+ bool working = (**arg == '+'); // has("+option")
+ int ret = OK;
+ int opt_flags;
+
+ // Isolate the option name and find its value.
+ char *option_end = (char *)find_option_end(arg, &opt_flags);
+ if (option_end == NULL) {
+ if (rettv != NULL) {
+ semsg(_("E112: Option name missing: %s"), *arg);
+ }
+ return FAIL;
+ }
+
+ if (!evaluate) {
+ *arg = option_end;
+ return OK;
+ }
+
+ char c = *option_end;
+ *option_end = NUL;
+ opt_type = get_option_value(*arg, &numval,
+ rettv == NULL ? NULL : &stringval, opt_flags);
+
+ if (opt_type == gov_unknown) {
+ if (rettv != NULL) {
+ semsg(_("E113: Unknown option: %s"), *arg);
+ }
+ ret = FAIL;
+ } else if (rettv != NULL) {
+ if (opt_type == gov_hidden_string) {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ } else if (opt_type == gov_hidden_bool || opt_type == gov_hidden_number) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ } else if (opt_type == gov_bool || opt_type == gov_number) {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = numval;
+ } else { // string option
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = stringval;
+ }
+ } else if (working && (opt_type == gov_hidden_bool
+ || opt_type == gov_hidden_number
+ || opt_type == gov_hidden_string)) {
+ ret = FAIL;
+ }
+
+ *option_end = c; // put back for error messages
+ *arg = option_end;
+
+ return ret;
+}
+
+/// Allocate a variable for a string constant.
+///
+/// @return OK or FAIL.
+static int get_string_tv(char **arg, typval_T *rettv, int evaluate)
+{
+ char *p;
+ unsigned int extra = 0;
+
+ /*
+ * Find the end of the string, skipping backslashed characters.
+ */
+ for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) {
+ if (*p == '\\' && p[1] != NUL) {
+ p++;
+ // A "\<x>" form occupies at least 4 characters, and produces up
+ // to 9 characters (6 for the char and 3 for a modifier):
+ // reserve space for 5 extra.
+ if (*p == '<') {
+ extra += 5;
+ }
+ }
+ }
+
+ if (*p != '"') {
+ semsg(_("E114: Missing quote: %s"), *arg);
+ return FAIL;
+ }
+
+ // If only parsing, set *arg and return here
+ if (!evaluate) {
+ *arg = p + 1;
+ return OK;
+ }
+
+ /*
+ * Copy the string into allocated memory, handling backslashed
+ * characters.
+ */
+ const int len = (int)(p - *arg + extra);
+ char *name = xmalloc((size_t)len);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = name;
+
+ for (p = *arg + 1; *p != NUL && *p != '"';) {
+ if (*p == '\\') {
+ switch (*++p) {
+ case 'b':
+ *name++ = BS; ++p; break;
+ case 'e':
+ *name++ = ESC; ++p; break;
+ case 'f':
+ *name++ = FF; ++p; break;
+ case 'n':
+ *name++ = NL; ++p; break;
+ case 'r':
+ *name++ = CAR; ++p; break;
+ case 't':
+ *name++ = TAB; ++p; break;
+
+ case 'X': // hex: "\x1", "\x12"
+ case 'x':
+ case 'u': // Unicode: "\u0023"
+ case 'U':
+ if (ascii_isxdigit(p[1])) {
+ int n, nr;
+ int c = toupper(*p);
+
+ if (c == 'X') {
+ n = 2;
+ } else if (*p == 'u') {
+ n = 4;
+ } else {
+ n = 8;
+ }
+ nr = 0;
+ while (--n >= 0 && ascii_isxdigit(p[1])) {
+ ++p;
+ nr = (nr << 4) + hex2nr(*p);
+ }
+ p++;
+ // For "\u" store the number according to
+ // 'encoding'.
+ if (c != 'X') {
+ name += utf_char2bytes(nr, name);
+ } else {
+ *name++ = (char)nr;
+ }
+ }
+ break;
+
+ // octal: "\1", "\12", "\123"
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ *name = (char)(*p++ - '0');
+ if (*p >= '0' && *p <= '7') {
+ *name = (char)((*name << 3) + *p++ - '0');
+ if (*p >= '0' && *p <= '7') {
+ *name = (char)((*name << 3) + *p++ - '0');
+ }
+ }
+ ++name;
+ break;
+
+ // Special key, e.g.: "\<C-W>"
+ case '<': {
+ int flags = FSK_KEYCODE | FSK_IN_STRING;
+
+ if (p[1] != '*') {
+ flags |= FSK_SIMPLIFY;
+ }
+ extra = trans_special((const char_u **)&p, STRLEN(p), (char_u *)name, flags, false, NULL);
+ if (extra != 0) {
+ name += extra;
+ if (name >= rettv->vval.v_string + len) {
+ iemsg("get_string_tv() used more space than allocated");
+ }
+ break;
+ }
+ }
+ FALLTHROUGH;
+
+ default:
+ mb_copy_char((const char_u **)&p, (char_u **)&name);
+ break;
+ }
+ } else {
+ mb_copy_char((const char_u **)&p, (char_u **)&name);
+ }
+ }
+ *name = NUL;
+ if (*p != NUL) { // just in case
+ p++;
+ }
+ *arg = p;
+
+ return OK;
+}
+
+/// Allocate a variable for a 'str''ing' constant.
+///
+/// @return OK or FAIL.
+static int get_lit_string_tv(char **arg, typval_T *rettv, int evaluate)
+{
+ char *p;
+ char *str;
+ int reduce = 0;
+
+ /*
+ * Find the end of the string, skipping ''.
+ */
+ for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p)) {
+ if (*p == '\'') {
+ if (p[1] != '\'') {
+ break;
+ }
+ ++reduce;
+ ++p;
+ }
+ }
+
+ if (*p != '\'') {
+ semsg(_("E115: Missing quote: %s"), *arg);
+ return FAIL;
+ }
+
+ // If only parsing return after setting "*arg"
+ if (!evaluate) {
+ *arg = p + 1;
+ return OK;
+ }
+
+ /*
+ * Copy the string into allocated memory, handling '' to ' reduction.
+ */
+ str = xmalloc((size_t)((p - *arg) - reduce));
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = str;
+
+ for (p = *arg + 1; *p != NUL;) {
+ if (*p == '\'') {
+ if (p[1] != '\'') {
+ break;
+ }
+ ++p;
+ }
+ mb_copy_char((const char_u **)&p, (char_u **)&str);
+ }
+ *str = NUL;
+ *arg = p + 1;
+
+ return OK;
+}
+
+/// @return the function name of the partial.
+char *partial_name(partial_T *pt)
+ FUNC_ATTR_PURE
+{
+ if (pt->pt_name != NULL) {
+ return (char *)pt->pt_name;
+ }
+ return (char *)pt->pt_func->uf_name;
+}
+
+// TODO(ZyX-I): Move to eval/typval.h
+
+static void partial_free(partial_T *pt)
+{
+ for (int i = 0; i < pt->pt_argc; i++) {
+ tv_clear(&pt->pt_argv[i]);
+ }
+ xfree(pt->pt_argv);
+ tv_dict_unref(pt->pt_dict);
+ if (pt->pt_name != NULL) {
+ func_unref(pt->pt_name);
+ xfree(pt->pt_name);
+ } else {
+ func_ptr_unref(pt->pt_func);
+ }
+ xfree(pt);
+}
+
+// TODO(ZyX-I): Move to eval/typval.h
+
+/// Unreference a closure: decrement the reference count and free it when it
+/// becomes zero.
+void partial_unref(partial_T *pt)
+{
+ if (pt != NULL && --pt->pt_refcount <= 0) {
+ partial_free(pt);
+ }
+}
+
+/// Allocate a variable for a List and fill it from "*arg".
+///
+/// @return OK or FAIL.
+static int get_list_tv(char **arg, typval_T *rettv, int evaluate)
+{
+ list_T *l = NULL;
+
+ if (evaluate) {
+ l = tv_list_alloc(kListLenShouldKnow);
+ }
+
+ *arg = skipwhite(*arg + 1);
+ while (**arg != ']' && **arg != NUL) {
+ typval_T tv;
+ if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive!
+ goto failret;
+ }
+ if (evaluate) {
+ tv.v_lock = VAR_UNLOCKED;
+ tv_list_append_owned_tv(l, tv);
+ }
+
+ if (**arg == ']') {
+ break;
+ }
+ if (**arg != ',') {
+ semsg(_("E696: Missing comma in List: %s"), *arg);
+ goto failret;
+ }
+ *arg = skipwhite(*arg + 1);
+ }
+
+ if (**arg != ']') {
+ semsg(_("E697: Missing end of List ']': %s"), *arg);
+failret:
+ if (evaluate) {
+ tv_list_free(l);
+ }
+ return FAIL;
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (evaluate) {
+ tv_list_set_ret(rettv, l);
+ }
+
+ return OK;
+}
+
+/// @param ic ignore case
+bool func_equal(typval_T *tv1, typval_T *tv2, bool ic)
+{
+ char_u *s1, *s2;
+ dict_T *d1, *d2;
+ int a1, a2;
+
+ // empty and NULL function name considered the same
+ s1 = (char_u *)(tv1->v_type == VAR_FUNC ? tv1->vval.v_string : partial_name(tv1->vval.v_partial));
+ if (s1 != NULL && *s1 == NUL) {
+ s1 = NULL;
+ }
+ s2 = (char_u *)(tv2->v_type == VAR_FUNC ? tv2->vval.v_string : partial_name(tv2->vval.v_partial));
+ if (s2 != NULL && *s2 == NUL) {
+ s2 = NULL;
+ }
+ if (s1 == NULL || s2 == NULL) {
+ if (s1 != s2) {
+ return false;
+ }
+ } else if (STRCMP(s1, s2) != 0) {
+ return false;
+ }
+
+ // empty dict and NULL dict is different
+ d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict;
+ d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict;
+ if (d1 == NULL || d2 == NULL) {
+ if (d1 != d2) {
+ return false;
+ }
+ } else if (!tv_dict_equal(d1, d2, ic, true)) {
+ return false;
+ }
+
+ // empty list and no list considered the same
+ a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc;
+ a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc;
+ if (a1 != a2) {
+ return false;
+ }
+ for (int i = 0; i < a1; i++) {
+ if (!tv_equal(tv1->vval.v_partial->pt_argv + i,
+ tv2->vval.v_partial->pt_argv + i, ic, true)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Get next (unique) copy ID
+///
+/// Used for traversing nested structures e.g. when serializing them or garbage
+/// collecting.
+int get_copyID(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // CopyID for recursively traversing lists and dicts
+ //
+ // This value is needed to avoid endless recursiveness. Last bit is used for
+ // previous_funccal and normally ignored when comparing.
+ static int current_copyID = 0;
+ current_copyID += COPYID_INC;
+ return current_copyID;
+}
+
+/*
+ * Garbage collection for lists and dictionaries.
+ *
+ * We use reference counts to be able to free most items right away when they
+ * are no longer used. But for composite items it's possible that it becomes
+ * unused while the reference count is > 0: When there is a recursive
+ * reference. Example:
+ * :let l = [1, 2, 3]
+ * :let d = {9: l}
+ * :let l[1] = d
+ *
+ * Since this is quite unusual we handle this with garbage collection: every
+ * once in a while find out which lists and dicts are not referenced from any
+ * variable.
+ *
+ * Here is a good reference text about garbage collection (refers to Python
+ * but it applies to all reference-counting mechanisms):
+ * http://python.ca/nas/python/gc/
+ */
+
+/// Do garbage collection for lists and dicts.
+///
+/// @param testing true if called from test_garbagecollect_now().
+///
+/// @return true if some memory was freed.
+bool garbage_collect(bool testing)
+{
+ bool abort = false;
+#define ABORTING(func) abort = abort || func
+
+ if (!testing) {
+ // Only do this once.
+ want_garbage_collect = false;
+ may_garbage_collect = false;
+ garbage_collect_at_exit = false;
+ }
+
+ // We advance by two (COPYID_INC) because we add one for items referenced
+ // through previous_funccal.
+ const int copyID = get_copyID();
+
+ // 1. Go through all accessible variables and mark all lists and dicts
+ // with copyID.
+
+ // Don't free variables in the previous_funccal list unless they are only
+ // referenced through previous_funccal. This must be first, because if
+ // the item is referenced elsewhere the funccal must not be freed.
+ ABORTING(set_ref_in_previous_funccal)(copyID);
+
+ // script-local variables
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
+ ABORTING(set_ref_in_ht)(&SCRIPT_VARS(i), copyID, NULL);
+ }
+
+ FOR_ALL_BUFFERS(buf) {
+ // buffer-local variables
+ ABORTING(set_ref_in_item)(&buf->b_bufvar.di_tv, copyID, NULL, NULL);
+ // buffer marks (ShaDa additional data)
+ ABORTING(set_ref_in_fmark)(buf->b_last_cursor, copyID);
+ ABORTING(set_ref_in_fmark)(buf->b_last_insert, copyID);
+ ABORTING(set_ref_in_fmark)(buf->b_last_change, copyID);
+ for (size_t i = 0; i < NMARKS; i++) {
+ ABORTING(set_ref_in_fmark)(buf->b_namedm[i], copyID);
+ }
+ // buffer change list (ShaDa additional data)
+ for (int i = 0; i < buf->b_changelistlen; i++) {
+ ABORTING(set_ref_in_fmark)(buf->b_changelist[i], copyID);
+ }
+ // buffer ShaDa additional data
+ ABORTING(set_ref_dict)(buf->additional_data, copyID);
+
+ // buffer callback functions
+ set_ref_in_callback(&buf->b_prompt_callback, copyID, NULL, NULL);
+ set_ref_in_callback(&buf->b_prompt_interrupt, copyID, NULL, NULL);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ // window-local variables
+ ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL);
+ // window jump list (ShaDa additional data)
+ for (int i = 0; i < wp->w_jumplistlen; i++) {
+ ABORTING(set_ref_in_fmark)(wp->w_jumplist[i].fmark, copyID);
+ }
+ }
+ if (aucmd_win != NULL) {
+ ABORTING(set_ref_in_item)(&aucmd_win->w_winvar.di_tv, copyID, NULL, NULL);
+ }
+
+ // registers (ShaDa additional data)
+ {
+ iter_register_T reg_iter = ITER_REGISTER_NULL;
+ do {
+ yankreg_T reg;
+ char name = NUL;
+ bool is_unnamed = false;
+ reg_iter = op_global_reg_iter(reg_iter, &name, &reg, &is_unnamed);
+ if (name != NUL) {
+ ABORTING(set_ref_dict)(reg.additional_data, copyID);
+ }
+ } while (reg_iter != ITER_REGISTER_NULL);
+ }
+
+ // global marks (ShaDa additional data)
+ {
+ const void *mark_iter = NULL;
+ do {
+ xfmark_T fm;
+ char name = NUL;
+ mark_iter = mark_global_iter(mark_iter, &name, &fm);
+ if (name != NUL) {
+ ABORTING(set_ref_dict)(fm.fmark.additional_data, copyID);
+ }
+ } while (mark_iter != NULL);
+ }
+
+ // tabpage-local variables
+ FOR_ALL_TABS(tp) {
+ ABORTING(set_ref_in_item)(&tp->tp_winvar.di_tv, copyID, NULL, NULL);
+ }
+
+ // global variables
+ ABORTING(set_ref_in_ht)(&globvarht, copyID, NULL);
+
+ // function-local variables
+ ABORTING(set_ref_in_call_stack)(copyID);
+
+ // named functions (matters for closures)
+ ABORTING(set_ref_in_functions)(copyID);
+
+ // Channels
+ {
+ Channel *data;
+ map_foreach_value(&channels, data, {
+ set_ref_in_callback_reader(&data->on_data, copyID, NULL, NULL);
+ set_ref_in_callback_reader(&data->on_stderr, copyID, NULL, NULL);
+ set_ref_in_callback(&data->on_exit, copyID, NULL, NULL);
+ })
+ }
+
+ // Timers
+ {
+ timer_T *timer;
+ map_foreach_value(&timers, timer, {
+ set_ref_in_callback(&timer->callback, copyID, NULL, NULL);
+ })
+ }
+
+ // function call arguments, if v:testing is set.
+ ABORTING(set_ref_in_func_args)(copyID);
+
+ // v: vars
+ ABORTING(set_ref_in_ht)(&vimvarht, copyID, NULL);
+
+ // history items (ShaDa additional elements)
+ if (p_hi) {
+ for (uint8_t i = 0; i < HIST_COUNT; i++) {
+ const void *iter = NULL;
+ do {
+ histentry_T hist;
+ iter = hist_iter(iter, i, false, &hist);
+ if (hist.hisstr != NULL) {
+ ABORTING(set_ref_list)(hist.additional_elements, copyID);
+ }
+ } while (iter != NULL);
+ }
+ }
+
+ // previously used search/substitute patterns (ShaDa additional data)
+ {
+ SearchPattern pat;
+ get_search_pattern(&pat);
+ ABORTING(set_ref_dict)(pat.additional_data, copyID);
+ get_substitute_pattern(&pat);
+ ABORTING(set_ref_dict)(pat.additional_data, copyID);
+ }
+
+ // previously used replacement string
+ {
+ SubReplacementString sub;
+ sub_get_replacement(&sub);
+ ABORTING(set_ref_list)(sub.additional_elements, copyID);
+ }
+
+ ABORTING(set_ref_in_quickfix)(copyID);
+
+ bool did_free = false;
+ if (!abort) {
+ // 2. Free lists and dictionaries that are not referenced.
+ did_free = free_unref_items(copyID);
+
+ // 3. Check if any funccal can be freed now.
+ // This may call us back recursively.
+ did_free = free_unref_funccal(copyID, testing) || did_free;
+ } else if (p_verbose > 0) {
+ verb_msg(_("Not enough memory to set references, garbage collection aborted!"));
+ }
+#undef ABORTING
+ return did_free;
+}
+
+/// Free lists and dictionaries that are no longer referenced.
+///
+/// @note This function may only be called from garbage_collect().
+///
+/// @param copyID Free lists/dictionaries that don't have this ID.
+///
+/// @return true, if something was freed.
+static int free_unref_items(int copyID)
+{
+ bool did_free = false;
+
+ // Let all "free" functions know that we are here. This means no
+ // dictionaries, lists, or jobs are to be freed, because we will
+ // do that here.
+ tv_in_free_unref_items = true;
+
+ // PASS 1: free the contents of the items. We don't free the items
+ // themselves yet, so that it is possible to decrement refcount counters.
+
+ // Go through the list of dicts and free items without the copyID.
+ // Don't free dicts that are referenced internally.
+ for (dict_T *dd = gc_first_dict; dd != NULL; dd = dd->dv_used_next) {
+ if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) {
+ // Free the Dictionary and ordinary items it contains, but don't
+ // recurse into Lists and Dictionaries, they will be in the list
+ // of dicts or list of lists.
+ tv_dict_free_contents(dd);
+ did_free = true;
+ }
+ }
+
+ // Go through the list of lists and free items without the copyID.
+ // But don't free a list that has a watcher (used in a for loop), these
+ // are not referenced anywhere.
+ for (list_T *ll = gc_first_list; ll != NULL; ll = ll->lv_used_next) {
+ if ((tv_list_copyid(ll) & COPYID_MASK) != (copyID & COPYID_MASK)
+ && !tv_list_has_watchers(ll)) {
+ // Free the List and ordinary items it contains, but don't recurse
+ // into Lists and Dictionaries, they will be in the list of dicts
+ // or list of lists.
+ tv_list_free_contents(ll);
+ did_free = true;
+ }
+ }
+
+ // PASS 2: free the items themselves.
+ dict_T *dd_next;
+ for (dict_T *dd = gc_first_dict; dd != NULL; dd = dd_next) {
+ dd_next = dd->dv_used_next;
+ if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) {
+ tv_dict_free_dict(dd);
+ }
+ }
+
+ list_T *ll_next;
+ for (list_T *ll = gc_first_list; ll != NULL; ll = ll_next) {
+ ll_next = ll->lv_used_next;
+ if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
+ && !tv_list_has_watchers(ll)) {
+ // Free the List and ordinary items it contains, but don't recurse
+ // into Lists and Dictionaries, they will be in the list of dicts
+ // or list of lists.
+ tv_list_free_list(ll);
+ }
+ }
+ tv_in_free_unref_items = false;
+ return did_free;
+}
+
+/// Mark all lists and dicts referenced through hashtab "ht" with "copyID".
+///
+/// @param ht Hashtab content will be marked.
+/// @param copyID New mark for lists and dicts.
+/// @param list_stack Used to add lists to be marked. Can be NULL.
+///
+/// @returns true if setting references failed somehow.
+bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ bool abort = false;
+ ht_stack_T *ht_stack = NULL;
+
+ hashtab_T *cur_ht = ht;
+ for (;;) {
+ if (!abort) {
+ // Mark each item in the hashtab. If the item contains a hashtab
+ // it is added to ht_stack, if it contains a list it is added to
+ // list_stack.
+ HASHTAB_ITER(cur_ht, hi, {
+ abort = abort || set_ref_in_item(&TV_DICT_HI2DI(hi)->di_tv, copyID, &ht_stack, list_stack);
+ });
+ }
+
+ if (ht_stack == NULL) {
+ break;
+ }
+
+ // take an item from the stack
+ cur_ht = ht_stack->ht;
+ ht_stack_T *tempitem = ht_stack;
+ ht_stack = ht_stack->prev;
+ xfree(tempitem);
+ }
+
+ return abort;
+}
+
+/// Mark all lists and dicts referenced through list "l" with "copyID".
+///
+/// @param l List content will be marked.
+/// @param copyID New mark for lists and dicts.
+/// @param ht_stack Used to add hashtabs to be marked. Can be NULL.
+///
+/// @returns true if setting references failed somehow.
+bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ bool abort = false;
+ list_stack_T *list_stack = NULL;
+
+ list_T *cur_l = l;
+ for (;;) {
+ // Mark each item in the list. If the item contains a hashtab
+ // it is added to ht_stack, if it contains a list it is added to
+ // list_stack.
+ TV_LIST_ITER(cur_l, li, {
+ if (abort) {
+ break;
+ }
+ abort = set_ref_in_item(TV_LIST_ITEM_TV(li), copyID, ht_stack,
+ &list_stack);
+ });
+
+ if (list_stack == NULL) {
+ break;
+ }
+
+ // take an item from the stack
+ cur_l = list_stack->list;
+ list_stack_T *tempitem = list_stack;
+ list_stack = list_stack->prev;
+ xfree(tempitem);
+ }
+
+ return abort;
+}
+
+/// Mark all lists and dicts referenced through typval "tv" with "copyID".
+///
+/// @param tv Typval content will be marked.
+/// @param copyID New mark for lists and dicts.
+/// @param ht_stack Used to add hashtabs to be marked. Can be NULL.
+/// @param list_stack Used to add lists to be marked. Can be NULL.
+///
+/// @returns true if setting references failed somehow.
+bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ bool abort = false;
+
+ switch (tv->v_type) {
+ case VAR_DICT: {
+ dict_T *dd = tv->vval.v_dict;
+ if (dd != NULL && dd->dv_copyID != copyID) {
+ // Didn't see this dict yet.
+ dd->dv_copyID = copyID;
+ if (ht_stack == NULL) {
+ abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
+ } else {
+ ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T));
+ newitem->ht = &dd->dv_hashtab;
+ newitem->prev = *ht_stack;
+ *ht_stack = newitem;
+ }
+
+ QUEUE *w = NULL;
+ DictWatcher *watcher = NULL;
+ QUEUE_FOREACH(w, &dd->watchers, {
+ watcher = tv_dict_watcher_node_data(w);
+ set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack);
+ })
+ }
+ break;
+ }
+
+ case VAR_LIST: {
+ list_T *ll = tv->vval.v_list;
+ if (ll != NULL && ll->lv_copyID != copyID) {
+ // Didn't see this list yet.
+ ll->lv_copyID = copyID;
+ if (list_stack == NULL) {
+ abort = set_ref_in_list(ll, copyID, ht_stack);
+ } else {
+ list_stack_T *const newitem = xmalloc(sizeof(list_stack_T));
+ newitem->list = ll;
+ newitem->prev = *list_stack;
+ *list_stack = newitem;
+ }
+ }
+ break;
+ }
+
+ case VAR_PARTIAL: {
+ partial_T *pt = tv->vval.v_partial;
+
+ // A partial does not have a copyID, because it cannot contain itself.
+ if (pt != NULL) {
+ abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
+ if (pt->pt_dict != NULL) {
+ typval_T dtv;
+
+ dtv.v_type = VAR_DICT;
+ dtv.vval.v_dict = pt->pt_dict;
+ abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+
+ for (int i = 0; i < pt->pt_argc; i++) {
+ abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
+ ht_stack, list_stack);
+ }
+ }
+ break;
+ }
+ case VAR_FUNC:
+ abort = set_ref_in_func((char_u *)tv->vval.v_string, NULL, copyID);
+ break;
+ case VAR_UNKNOWN:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_NUMBER:
+ case VAR_STRING:
+ case VAR_BLOB:
+ break;
+ }
+ return abort;
+}
+
+/// Mark all lists and dicts referenced in given mark
+///
+/// @return true if setting references failed somehow.
+static inline bool set_ref_in_fmark(fmark_T fm, int copyID)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (fm.additional_data != NULL
+ && fm.additional_data->dv_copyID != copyID) {
+ fm.additional_data->dv_copyID = copyID;
+ return set_ref_in_ht(&fm.additional_data->dv_hashtab, copyID, NULL);
+ }
+ return false;
+}
+
+/// Mark all lists and dicts referenced in given list and the list itself
+///
+/// @return true if setting references failed somehow.
+static inline bool set_ref_list(list_T *list, int copyID)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (list != NULL) {
+ typval_T tv = (typval_T) {
+ .v_type = VAR_LIST,
+ .vval = { .v_list = list }
+ };
+ return set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return false;
+}
+
+/// Mark all lists and dicts referenced in given dict and the dict itself
+///
+/// @return true if setting references failed somehow.
+static inline bool set_ref_dict(dict_T *dict, int copyID)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (dict != NULL) {
+ typval_T tv = (typval_T) {
+ .v_type = VAR_DICT,
+ .vval = { .v_dict = dict }
+ };
+ return set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return false;
+}
+
+/// Get the key for #{key: val} into "tv" and advance "arg".
+///
+/// @return FAIL when there is no valid key.
+static int get_literal_key(char **arg, typval_T *tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char *p;
+
+ if (!ASCII_ISALNUM(**arg) && **arg != '_' && **arg != '-') {
+ return FAIL;
+ }
+ for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {}
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = xstrnsave(*arg, (size_t)(p - *arg));
+
+ *arg = skipwhite(p);
+ return OK;
+}
+
+/// Allocate a variable for a Dictionary and fill it from "*arg".
+/// "literal" is true for #{key: val}
+///
+/// @return OK or FAIL. Returns NOTDONE for {expr}.
+static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal)
+{
+ dict_T *d = NULL;
+ typval_T tvkey;
+ typval_T tv;
+ char *key = NULL;
+ dictitem_T *item;
+ char *start = skipwhite(*arg + 1);
+ char buf[NUMBUFLEN];
+
+ /*
+ * First check if it's not a curly-braces thing: {expr}.
+ * Must do this without evaluating, otherwise a function may be called
+ * twice. Unfortunately this means we need to call eval1() twice for the
+ * first item.
+ * But {} is an empty Dictionary.
+ */
+ if (*start != '}') {
+ if (eval1(&start, &tv, false) == FAIL) { // recursive!
+ return FAIL;
+ }
+ if (*skipwhite(start) == '}') {
+ return NOTDONE;
+ }
+ }
+
+ if (evaluate) {
+ d = tv_dict_alloc();
+ }
+ tvkey.v_type = VAR_UNKNOWN;
+ tv.v_type = VAR_UNKNOWN;
+
+ *arg = skipwhite(*arg + 1);
+ while (**arg != '}' && **arg != NUL) {
+ if ((literal
+ ? get_literal_key(arg, &tvkey)
+ : eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive!
+ goto failret;
+ }
+ if (**arg != ':') {
+ semsg(_("E720: Missing colon in Dictionary: %s"), *arg);
+ tv_clear(&tvkey);
+ goto failret;
+ }
+ if (evaluate) {
+ key = (char *)tv_get_string_buf_chk(&tvkey, buf);
+ if (key == NULL) {
+ // "key" is NULL when tv_get_string_buf_chk() gave an errmsg
+ tv_clear(&tvkey);
+ goto failret;
+ }
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive!
+ if (evaluate) {
+ tv_clear(&tvkey);
+ }
+ goto failret;
+ }
+ if (evaluate) {
+ item = tv_dict_find(d, (const char *)key, -1);
+ if (item != NULL) {
+ semsg(_("E721: Duplicate key in Dictionary: \"%s\""), key);
+ tv_clear(&tvkey);
+ tv_clear(&tv);
+ goto failret;
+ }
+ item = tv_dict_item_alloc((const char *)key);
+ item->di_tv = tv;
+ item->di_tv.v_lock = VAR_UNLOCKED;
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
+ }
+ }
+ tv_clear(&tvkey);
+
+ if (**arg == '}') {
+ break;
+ }
+ if (**arg != ',') {
+ semsg(_("E722: Missing comma in Dictionary: %s"), *arg);
+ goto failret;
+ }
+ *arg = skipwhite(*arg + 1);
+ }
+
+ if (**arg != '}') {
+ semsg(_("E723: Missing end of Dictionary '}': %s"), *arg);
+failret:
+ if (d != NULL) {
+ tv_dict_free(d);
+ }
+ return FAIL;
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (evaluate) {
+ tv_dict_set_ret(rettv, d);
+ }
+
+ return OK;
+}
+
+/// Convert the string to a floating point number
+///
+/// This uses strtod(). setlocale(LC_NUMERIC, "C") has been used earlier to
+/// make sure this always uses a decimal point.
+///
+/// @param[in] text String to convert.
+/// @param[out] ret_value Location where conversion result is saved.
+///
+/// @return Length of the text that was consumed.
+size_t string2float(const char *const text, float_T *const ret_value)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char *s = NULL;
+
+ // MS-Windows does not deal with "inf" and "nan" properly
+ if (STRNICMP(text, "inf", 3) == 0) {
+ *ret_value = (float_T)INFINITY;
+ return 3;
+ }
+ if (STRNICMP(text, "-inf", 3) == 0) {
+ *ret_value = (float_T) - INFINITY;
+ return 4;
+ }
+ if (STRNICMP(text, "nan", 3) == 0) {
+ *ret_value = (float_T)NAN;
+ return 3;
+ }
+ *ret_value = strtod(text, &s);
+ return (size_t)(s - text);
+}
+
+/// Get the value of an environment variable.
+///
+/// If the environment variable was not set, silently assume it is empty.
+///
+/// @param arg Points to the '$'. It is advanced to after the name.
+///
+/// @return FAIL if the name is invalid.
+static int get_env_tv(char **arg, typval_T *rettv, int evaluate)
+{
+ char *name;
+ char *string = NULL;
+ int len;
+ int cc;
+
+ ++*arg;
+ name = *arg;
+ len = get_env_len((const char **)arg);
+
+ if (evaluate) {
+ if (len == 0) {
+ return FAIL; // Invalid empty name.
+ }
+ cc = (char_u)name[len];
+ name[len] = NUL;
+ // First try vim_getenv(), fast for normal environment vars.
+ string = vim_getenv(name);
+ if (string == NULL || *string == NUL) {
+ xfree(string);
+
+ // Next try expanding things like $VIM and ${HOME}.
+ string = expand_env_save(name - 1);
+ if (string != NULL && *string == '$') {
+ XFREE_CLEAR(string);
+ }
+ }
+ name[len] = (char)cc;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = string;
+ }
+
+ return OK;
+}
+
+/// Get the argument list for a given window
+void get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
+{
+ tv_list_alloc_ret(rettv, argcount);
+ if (arglist != NULL) {
+ for (int idx = 0; idx < argcount; idx++) {
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)alist_name(&arglist[idx]), -1);
+ }
+ }
+}
+
+/// Add an assert error to v:errors.
+void assert_error(garray_T *gap)
+{
+ struct vimvar *vp = &vimvars[VV_ERRORS];
+
+ if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) {
+ // Make sure v:errors is a list.
+ set_vim_var_list(VV_ERRORS, tv_list_alloc(1));
+ }
+ tv_list_append_string(vimvars[VV_ERRORS].vv_list,
+ (const char *)gap->ga_data, (ptrdiff_t)gap->ga_len);
+}
+
+/// Find a window: When using a Window ID in any tab page, when using a number
+/// in the current tab page.
+win_T *find_win_by_nr_or_id(typval_T *vp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr >= LOWEST_WIN_ID) {
+ return win_id2wp((int)tv_get_number(vp));
+ }
+
+ return find_win_by_nr(vp, NULL);
+}
+
+/// Implementation of map() and filter().
+void filter_map(typval_T *argvars, typval_T *rettv, int map)
+{
+ typval_T *expr;
+ list_T *l = NULL;
+ dictitem_T *di;
+ hashtab_T *ht;
+ hashitem_T *hi;
+ dict_T *d = NULL;
+ typval_T save_val;
+ typval_T save_key;
+ blob_T *b = NULL;
+ int rem = false;
+ int todo;
+ char *ermsg = map ? "map()" : "filter()";
+ const char *const arg_errmsg = (map
+ ? N_("map() argument")
+ : N_("filter() argument"));
+ int save_did_emsg;
+ int idx = 0;
+
+ if (argvars[0].v_type == VAR_BLOB) {
+ tv_copy(&argvars[0], rettv);
+ if ((b = argvars[0].vval.v_blob) == NULL) {
+ return;
+ }
+ } else if (argvars[0].v_type == VAR_LIST) {
+ tv_copy(&argvars[0], rettv);
+ if ((l = argvars[0].vval.v_list) == NULL
+ || (!map
+ && var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE))) {
+ return;
+ }
+ } else if (argvars[0].v_type == VAR_DICT) {
+ tv_copy(&argvars[0], rettv);
+ if ((d = argvars[0].vval.v_dict) == NULL
+ || (!map && var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) {
+ return;
+ }
+ } else {
+ semsg(_(e_listdictblobarg), ermsg);
+ return;
+ }
+
+ expr = &argvars[1];
+ // On type errors, the preceding call has already displayed an error
+ // message. Avoid a misleading error message for an empty string that
+ // was not passed as argument.
+ if (expr->v_type != VAR_UNKNOWN) {
+ prepare_vimvar(VV_VAL, &save_val);
+
+ // We reset "did_emsg" to be able to detect whether an error
+ // occurred during evaluation of the expression.
+ save_did_emsg = did_emsg;
+ did_emsg = FALSE;
+
+ prepare_vimvar(VV_KEY, &save_key);
+ if (argvars[0].v_type == VAR_DICT) {
+ vimvars[VV_KEY].vv_type = VAR_STRING;
+
+ const VarLockStatus prev_lock = d->dv_lock;
+ if (map && d->dv_lock == VAR_UNLOCKED) {
+ d->dv_lock = VAR_LOCKED;
+ }
+ ht = &d->dv_hashtab;
+ hash_lock(ht);
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi) {
+ if (!HASHITEM_EMPTY(hi)) {
+ --todo;
+
+ di = TV_DICT_HI2DI(hi);
+ if (map
+ && (var_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE)
+ || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE))) {
+ break;
+ }
+
+ vimvars[VV_KEY].vv_str = (char *)vim_strsave(di->di_key);
+ int r = filter_map_one(&di->di_tv, expr, map, &rem);
+ tv_clear(&vimvars[VV_KEY].vv_tv);
+ if (r == FAIL || did_emsg) {
+ break;
+ }
+ if (!map && rem) {
+ if (var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE)
+ || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) {
+ break;
+ }
+ tv_dict_item_remove(d, di);
+ }
+ }
+ }
+ hash_unlock(ht);
+ d->dv_lock = prev_lock;
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ vimvars[VV_KEY].vv_type = VAR_NUMBER;
+
+ for (int i = 0; i < b->bv_ga.ga_len; i++) {
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ const varnumber_T val = tv_blob_get(b, i);
+ tv.vval.v_number = val;
+ vimvars[VV_KEY].vv_nr = idx;
+ if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg) {
+ break;
+ }
+ if (tv.v_type != VAR_NUMBER) {
+ emsg(_(e_invalblob));
+ return;
+ }
+ if (map) {
+ if (tv.vval.v_number != val) {
+ tv_blob_set(b, i, (char_u)tv.vval.v_number);
+ }
+ } else if (rem) {
+ char *const p = argvars[0].vval.v_blob->bv_ga.ga_data;
+ memmove(p + i, p + i + 1, (size_t)(b->bv_ga.ga_len - i - 1));
+ b->bv_ga.ga_len--;
+ i--;
+ }
+ idx++;
+ }
+ } else {
+ assert(argvars[0].v_type == VAR_LIST);
+ vimvars[VV_KEY].vv_type = VAR_NUMBER;
+
+ const VarLockStatus prev_lock = tv_list_locked(l);
+ if (map && tv_list_locked(l) == VAR_UNLOCKED) {
+ tv_list_set_lock(l, VAR_LOCKED);
+ }
+ for (listitem_T *li = tv_list_first(l); li != NULL;) {
+ if (map
+ && var_check_lock(TV_LIST_ITEM_TV(li)->v_lock, arg_errmsg,
+ TV_TRANSLATE)) {
+ break;
+ }
+ vimvars[VV_KEY].vv_nr = idx;
+ if (filter_map_one(TV_LIST_ITEM_TV(li), expr, map, &rem) == FAIL
+ || did_emsg) {
+ break;
+ }
+ if (!map && rem) {
+ li = tv_list_item_remove(l, li);
+ } else {
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+ idx++;
+ }
+ tv_list_set_lock(l, prev_lock);
+ }
+
+ restore_vimvar(VV_KEY, &save_key);
+ restore_vimvar(VV_VAL, &save_val);
+
+ did_emsg |= save_did_emsg;
+ }
+}
+
+static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ typval_T rettv;
+ typval_T argv[3];
+ int retval = FAIL;
+
+ tv_copy(tv, &vimvars[VV_VAL].vv_tv);
+ argv[0] = vimvars[VV_KEY].vv_tv;
+ argv[1] = vimvars[VV_VAL].vv_tv;
+ if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) {
+ goto theend;
+ }
+ if (map) {
+ // map(): replace the list item value.
+ tv_clear(tv);
+ rettv.v_lock = VAR_UNLOCKED;
+ *tv = rettv;
+ } else {
+ bool error = false;
+
+ // filter(): when expr is zero remove the item
+ *remp = (tv_get_number_chk(&rettv, &error) == 0);
+ tv_clear(&rettv);
+ // On type error, nothing has been removed; return FAIL to stop the
+ // loop. The error message was given by tv_get_number_chk().
+ if (error) {
+ goto theend;
+ }
+ }
+ retval = OK;
+theend:
+ tv_clear(&vimvars[VV_VAL].vv_tv);
+ return retval;
+}
+
+void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr fptr)
+{
+ char *s;
+ char *name;
+ bool use_string = false;
+ partial_T *arg_pt = NULL;
+ char *trans_name = NULL;
+
+ if (argvars[0].v_type == VAR_FUNC) {
+ // function(MyFunc, [arg], dict)
+ s = argvars[0].vval.v_string;
+ } else if (argvars[0].v_type == VAR_PARTIAL
+ && argvars[0].vval.v_partial != NULL) {
+ // function(dict.MyFunc, [arg])
+ arg_pt = argvars[0].vval.v_partial;
+ s = partial_name(arg_pt);
+ // TODO(bfredl): do the entire nlua_is_table_from_lua dance
+ } else {
+ // function('MyFunc', [arg], dict)
+ s = (char *)tv_get_string(&argvars[0]);
+ use_string = true;
+ }
+
+ if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) {
+ name = s;
+ trans_name = (char *)trans_function_name((char_u **)&name, false,
+ TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD
+ | TFN_NO_DEREF, NULL, NULL);
+ if (*name != NUL) {
+ s = NULL;
+ }
+ }
+ if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s))
+ || (is_funcref && trans_name == NULL)) {
+ semsg(_(e_invarg2), (use_string
+ ? tv_get_string(&argvars[0])
+ : (const char *)s));
+ // Don't check an autoload name for existence here.
+ } else if (trans_name != NULL
+ && (is_funcref
+ ? find_func((char_u *)trans_name) == NULL
+ : !translated_function_exists((const char *)trans_name))) {
+ semsg(_("E700: Unknown function: %s"), s);
+ } else {
+ int dict_idx = 0;
+ int arg_idx = 0;
+ list_T *list = NULL;
+ if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) {
+ char sid_buf[25];
+ int off = *s == 's' ? 2 : 5;
+
+ // Expand s: and <SID> into <SNR>nr_, so that the function can
+ // also be called from another script. Using trans_function_name()
+ // would also work, but some plugins depend on the name being
+ // printable text.
+ snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
+ (int64_t)current_sctx.sc_sid);
+ name = xmalloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
+ STRCPY(name, sid_buf);
+ STRCAT(name, s + off);
+ } else {
+ name = xstrdup(s);
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ // function(name, [args], dict)
+ arg_idx = 1;
+ dict_idx = 2;
+ } else if (argvars[1].v_type == VAR_DICT) {
+ // function(name, dict)
+ dict_idx = 1;
+ } else {
+ // function(name, [args])
+ arg_idx = 1;
+ }
+ if (dict_idx > 0) {
+ if (argvars[dict_idx].v_type != VAR_DICT) {
+ emsg(_("E922: expected a dict"));
+ xfree(name);
+ goto theend;
+ }
+ if (argvars[dict_idx].vval.v_dict == NULL) {
+ dict_idx = 0;
+ }
+ }
+ if (arg_idx > 0) {
+ if (argvars[arg_idx].v_type != VAR_LIST) {
+ emsg(_("E923: Second argument of function() must be "
+ "a list or a dict"));
+ xfree(name);
+ goto theend;
+ }
+ list = argvars[arg_idx].vval.v_list;
+ if (tv_list_len(list) == 0) {
+ arg_idx = 0;
+ } else if (tv_list_len(list) > MAX_FUNC_ARGS) {
+ emsg_funcname((char *)e_toomanyarg, (char_u *)s);
+ xfree(name);
+ goto theend;
+ }
+ }
+ }
+ if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) {
+ partial_T *const pt = xcalloc(1, sizeof(*pt));
+
+ // result is a VAR_PARTIAL
+ if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) {
+ const int arg_len = (arg_pt == NULL ? 0 : arg_pt->pt_argc);
+ const int lv_len = tv_list_len(list);
+
+ pt->pt_argc = arg_len + lv_len;
+ pt->pt_argv = xmalloc(sizeof(pt->pt_argv[0]) * (size_t)pt->pt_argc);
+ int i = 0;
+ for (; i < arg_len; i++) {
+ tv_copy(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
+ }
+ if (lv_len > 0) {
+ TV_LIST_ITER(list, li, {
+ tv_copy(TV_LIST_ITEM_TV(li), &pt->pt_argv[i++]);
+ });
+ }
+ }
+
+ // For "function(dict.func, [], dict)" and "func" is a partial
+ // use "dict". That is backwards compatible.
+ if (dict_idx > 0) {
+ // The dict is bound explicitly, pt_auto is false
+ pt->pt_dict = argvars[dict_idx].vval.v_dict;
+ (pt->pt_dict->dv_refcount)++;
+ } else if (arg_pt != NULL) {
+ // If the dict was bound automatically the result is also
+ // bound automatically.
+ pt->pt_dict = arg_pt->pt_dict;
+ pt->pt_auto = arg_pt->pt_auto;
+ if (pt->pt_dict != NULL) {
+ (pt->pt_dict->dv_refcount)++;
+ }
+ }
+
+ pt->pt_refcount = 1;
+ if (arg_pt != NULL && arg_pt->pt_func != NULL) {
+ pt->pt_func = arg_pt->pt_func;
+ func_ptr_ref(pt->pt_func);
+ xfree(name);
+ } else if (is_funcref) {
+ pt->pt_func = find_func((char_u *)trans_name);
+ func_ptr_ref(pt->pt_func);
+ xfree(name);
+ } else {
+ pt->pt_name = (char_u *)name;
+ func_ref((char_u *)name);
+ }
+
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+ } else {
+ // result is a VAR_FUNC
+ rettv->v_type = VAR_FUNC;
+ rettv->vval.v_string = name;
+ func_ref((char_u *)name);
+ }
+ }
+theend:
+ xfree(trans_name);
+}
+
+/// @return buffer options, variables and other attributes in a dictionary.
+dict_T *get_buffer_info(buf_T *buf)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
+ tv_dict_add_str(dict, S_LEN("name"),
+ buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
+ tv_dict_add_nr(dict, S_LEN("lnum"),
+ buf == curbuf ? curwin->w_cursor.lnum : buflist_findlnum(buf));
+ tv_dict_add_nr(dict, S_LEN("linecount"), buf->b_ml.ml_line_count);
+ tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
+ tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
+ tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
+ tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
+ tv_dict_add_nr(dict, S_LEN("hidden"),
+ buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
+
+ // Get a reference to buffer variables
+ tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
+
+ // List of windows displaying this buffer
+ list_T *const windows = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ tv_list_append_number(windows, (varnumber_T)wp->handle);
+ }
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), windows);
+
+ if (buf->b_signlist != NULL) {
+ // List of signs placed in this buffer
+ tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
+ }
+
+ tv_dict_add_nr(dict, S_LEN("lastused"), buf->b_last_used);
+
+ return dict;
+}
+
+/// Get the line number from VimL object
+///
+/// @note Unlike tv_get_lnum(), this one supports only "$" special string.
+///
+/// @param[in] tv Object to get value from. Is expected to be a number or
+/// a special string "$".
+/// @param[in] buf Buffer to take last line number from in case tv is "$". May
+/// be NULL, in this case "$" results in zero return.
+///
+/// @return Line number or 0 in case of error.
+linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (tv->v_type == VAR_STRING
+ && tv->vval.v_string != NULL
+ && tv->vval.v_string[0] == '$'
+ && buf != NULL) {
+ return buf->b_ml.ml_line_count;
+ }
+ return (linenr_T)tv_get_number_chk(tv, NULL);
+}
+
+void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
+{
+ if (what_arg->v_type == VAR_UNKNOWN) {
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ if (is_qf || wp != NULL) {
+ (void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
+ }
+ } else {
+ tv_dict_alloc_ret(rettv);
+ if (is_qf || wp != NULL) {
+ if (what_arg->v_type == VAR_DICT) {
+ dict_T *d = what_arg->vval.v_dict;
+
+ if (d != NULL) {
+ qf_get_properties(wp, d, rettv->vval.v_dict);
+ }
+ } else {
+ emsg(_(e_dictreq));
+ }
+ }
+ }
+}
+
+/// @return information (variables, options, etc.) about a tab page
+/// as a dictionary.
+dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
+
+ list_T *const l = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ tv_list_append_number(l, (varnumber_T)wp->handle);
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), l);
+
+ // Make a reference to tabpage variables
+ tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
+
+ return dict;
+}
+
+/// @return information about a window as a dictionary.
+dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ // make sure w_botline is valid
+ validate_botline(wp);
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
+ tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
+ tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
+ tv_dict_add_nr(dict, S_LEN("height"), wp->w_height);
+ tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
+ tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
+ tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
+ tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
+ tv_dict_add_nr(dict, S_LEN("width"), wp->w_width);
+ tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
+ tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
+ tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
+ tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("loclist"),
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
+
+ // Add a reference to window variables
+ tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
+
+ return dict;
+}
+
+/// Find window specified by "vp" in tabpage "tp".
+///
+/// @param tp NULL for current tab page
+win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr < 0) {
+ return NULL;
+ }
+
+ if (nr == 0) {
+ return curwin;
+ }
+
+ // This method accepts NULL as an alias for curtab.
+ if (tp == NULL) {
+ tp = curtab;
+ }
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ if (nr >= LOWEST_WIN_ID) {
+ if (wp->handle == nr) {
+ return wp;
+ }
+ } else if (--nr <= 0) {
+ return wp;
+ }
+ }
+ return NULL;
+}
+
+/// Find window specified by "wvp" in tabpage "tvp".
+win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
+{
+ win_T *wp = NULL;
+ tabpage_T *tp = NULL;
+
+ if (wvp->v_type != VAR_UNKNOWN) {
+ if (tvp->v_type != VAR_UNKNOWN) {
+ long n = tv_get_number(tvp);
+ if (n >= 0) {
+ tp = find_tabpage((int)n);
+ }
+ } else {
+ tp = curtab;
+ }
+
+ if (tp != NULL) {
+ wp = find_win_by_nr(wvp, tp);
+ }
+ } else {
+ wp = curwin;
+ }
+
+ return wp;
+}
+
+/// This function is used by f_input() and f_inputdialog() functions. The third
+/// argument to f_input() specifies the type of completion to use at the
+/// prompt. The third argument to f_inputdialog() specifies the value to return
+/// when the user cancels the prompt.
+void get_user_input(const typval_T *const argvars, typval_T *const rettv, const bool inputdialog,
+ const bool secret)
+ FUNC_ATTR_NONNULL_ALL
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ const char *prompt = "";
+ const char *defstr = "";
+ typval_T *cancelreturn = NULL;
+ typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE;
+ const char *xp_name = NULL;
+ Callback input_callback = { .type = kCallbackNone };
+ char prompt_buf[NUMBUFLEN];
+ char defstr_buf[NUMBUFLEN];
+ char cancelreturn_buf[NUMBUFLEN];
+ char xp_name_buf[NUMBUFLEN];
+ char def[1] = { 0 };
+ if (argvars[0].v_type == VAR_DICT) {
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ emsg(_("E5050: {opts} must be the only argument"));
+ return;
+ }
+ dict_T *const dict = argvars[0].vval.v_dict;
+ prompt = tv_dict_get_string_buf_chk(dict, S_LEN("prompt"), prompt_buf, "");
+ if (prompt == NULL) {
+ return;
+ }
+ defstr = tv_dict_get_string_buf_chk(dict, S_LEN("default"), defstr_buf, "");
+ if (defstr == NULL) {
+ return;
+ }
+ dictitem_T *cancelreturn_di = tv_dict_find(dict, S_LEN("cancelreturn"));
+ if (cancelreturn_di != NULL) {
+ cancelreturn = &cancelreturn_di->di_tv;
+ }
+ xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"),
+ xp_name_buf, def);
+ if (xp_name == NULL) { // error
+ return;
+ }
+ if (xp_name == def) { // default to NULL
+ xp_name = NULL;
+ }
+ if (!tv_dict_get_callback(dict, S_LEN("highlight"), &input_callback)) {
+ return;
+ }
+ } else {
+ prompt = tv_get_string_buf_chk(&argvars[0], prompt_buf);
+ if (prompt == NULL) {
+ return;
+ }
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ defstr = tv_get_string_buf_chk(&argvars[1], defstr_buf);
+ if (defstr == NULL) {
+ return;
+ }
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ const char *const strarg2 = tv_get_string_buf_chk(&argvars[2], cancelreturn_buf);
+ if (strarg2 == NULL) {
+ return;
+ }
+ if (inputdialog) {
+ cancelreturn_strarg2.v_type = VAR_STRING;
+ cancelreturn_strarg2.vval.v_string = (char *)strarg2;
+ cancelreturn = &cancelreturn_strarg2;
+ } else {
+ xp_name = strarg2;
+ }
+ }
+ }
+ }
+
+ int xp_type = EXPAND_NOTHING;
+ char *xp_arg = NULL;
+ if (xp_name != NULL) {
+ // input() with a third argument: completion
+ const int xp_namelen = (int)strlen(xp_name);
+
+ uint32_t argt = 0;
+ if (parse_compl_arg(xp_name, xp_namelen, &xp_type,
+ &argt, &xp_arg) == FAIL) {
+ return;
+ }
+ }
+
+ const bool cmd_silent_save = cmd_silent;
+
+ cmd_silent = false; // Want to see the prompt.
+ // Only the part of the message after the last NL is considered as
+ // prompt for the command line, unlsess cmdline is externalized
+ const char *p = prompt;
+ if (!ui_has(kUICmdline)) {
+ const char *lastnl = strrchr(prompt, '\n');
+ if (lastnl != NULL) {
+ p = lastnl + 1;
+ msg_start();
+ msg_clr_eos();
+ msg_puts_attr_len(prompt, p - prompt, echo_attr);
+ msg_didout = false;
+ msg_starthere();
+ }
+ }
+ cmdline_row = msg_row;
+
+ stuffReadbuffSpec(defstr);
+
+ const int save_ex_normal_busy = ex_normal_busy;
+ ex_normal_busy = 0;
+ rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, echo_attr, xp_type, xp_arg,
+ input_callback);
+ ex_normal_busy = save_ex_normal_busy;
+ callback_free(&input_callback);
+
+ if (rettv->vval.v_string == NULL && cancelreturn != NULL) {
+ tv_copy(cancelreturn, rettv);
+ }
+
+ xfree(xp_arg);
+
+ // Since the user typed this, no need to wait for return.
+ need_wait_return = false;
+ msg_didout = false;
+ cmd_silent = cmd_silent_save;
+}
+
+/// Builds a process argument vector from a VimL object (typval_T).
+///
+/// @param[in] cmd_tv VimL object
+/// @param[out] cmd Returns the command or executable name.
+/// @param[out] executable Returns `false` if argv[0] is not executable.
+///
+/// @return Result of `shell_build_argv()` if `cmd_tv` is a String.
+/// Else, string values of `cmd_tv` copied to a (char **) list with
+/// argv[0] resolved to full path ($PATHEXT-resolved on Windows).
+char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
+{
+ if (cmd_tv->v_type == VAR_STRING) { // String => "shell semantics".
+ const char *cmd_str = tv_get_string(cmd_tv);
+ if (cmd) {
+ *cmd = cmd_str;
+ }
+ return shell_build_argv(cmd_str, NULL);
+ }
+
+ if (cmd_tv->v_type != VAR_LIST) {
+ semsg(_(e_invarg2), "expected String or List");
+ return NULL;
+ }
+
+ list_T *argl = cmd_tv->vval.v_list;
+ int argc = tv_list_len(argl);
+ if (!argc) {
+ emsg(_(e_invarg)); // List must have at least one item.
+ return NULL;
+ }
+
+ const char *arg0 = tv_get_string_chk(TV_LIST_ITEM_TV(tv_list_first(argl)));
+ char *exe_resolved = NULL;
+ if (!arg0 || !os_can_exe(arg0, &exe_resolved, true)) {
+ if (arg0 && executable) {
+ char buf[IOSIZE];
+ snprintf(buf, sizeof(buf), "'%s' is not executable", arg0);
+ semsg(_(e_invargNval), "cmd", buf);
+ *executable = false;
+ }
+ return NULL;
+ }
+
+ if (cmd) {
+ *cmd = exe_resolved;
+ }
+
+ // Build the argument vector
+ int i = 0;
+ char **argv = xcalloc((size_t)argc + 1, sizeof(char *));
+ TV_LIST_ITER_CONST(argl, arg, {
+ const char *a = tv_get_string_chk(TV_LIST_ITEM_TV(arg));
+ if (!a) {
+ // Did emsg in tv_get_string_chk; just deallocate argv.
+ shell_free_argv(argv);
+ xfree(exe_resolved);
+ return NULL;
+ }
+ argv[i++] = xstrdup(a);
+ });
+ // Replace argv[0] with absolute path. The only reason for this is to make
+ // $PATHEXT work on Windows with jobstart([…]). #9569
+ xfree(argv[0]);
+ argv[0] = exe_resolved;
+
+ return argv;
+}
+
+void return_register(int regname, typval_T *rettv)
+{
+ char buf[2] = { (char)regname, 0 };
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = xstrdup(buf);
+}
+
+void screenchar_adjust(ScreenGrid **grid, int *row, int *col)
+{
+ // TODO(bfredl): this is a hack for legacy tests which use screenchar()
+ // to check printed messages on the screen (but not floats etc
+ // as these are not legacy features). If the compositor is refactored to
+ // have its own buffer, this should just read from it instead.
+ msg_scroll_flush();
+
+ *grid = ui_comp_get_grid_at_coord(*row, *col);
+
+ // Make `row` and `col` relative to the grid
+ *row -= (*grid)->comp_row;
+ *col -= (*grid)->comp_col;
+}
+
+/// Set line or list of lines in buffer "buf".
+void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T *lines,
+ typval_T *rettv)
+ FUNC_ATTR_NONNULL_ARG(4, 5)
+{
+ linenr_T lnum = lnum_arg + (append ? 1 : 0);
+ const char *line = NULL;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ long added = 0;
+ linenr_T append_lnum;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
+ const bool is_curbuf = buf == curbuf;
+ const bool save_VIsual_active = VIsual_active;
+
+ // When using the current buffer ml_mfp will be set if needed. Useful when
+ // setline() is used on startup. For other buffers the buffer must be
+ // loaded.
+ if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
+ rettv->vval.v_number = 1; // FAIL
+ return;
+ }
+
+ if (!is_curbuf) {
+ VIsual_active = false;
+ curbuf_save = curbuf;
+ curwin_save = curwin;
+ curbuf = buf;
+ find_win_for_curbuf();
+ }
+
+ if (append) {
+ // appendbufline() uses the line number below which we insert
+ append_lnum = lnum - 1;
+ } else {
+ // setbufline() uses the line number above which we insert, we only
+ // append if it's below the last line
+ append_lnum = curbuf->b_ml.ml_line_count;
+ }
+
+ if (lines->v_type == VAR_LIST) {
+ l = lines->vval.v_list;
+ li = tv_list_first(l);
+ } else {
+ line = tv_get_string_chk(lines);
+ }
+
+ // Default result is zero == OK.
+ for (;;) {
+ if (lines->v_type == VAR_LIST) {
+ // List argument, get next string.
+ if (li == NULL) {
+ break;
+ }
+ line = tv_get_string_chk(TV_LIST_ITEM_TV(li));
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+
+ rettv->vval.v_number = 1; // FAIL
+ if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
+ break;
+ }
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (!append && lnum <= curbuf->b_ml.ml_line_count) {
+ // Existing line, replace it.
+ int old_len = (int)STRLEN(ml_get(lnum));
+ if (u_savesub(lnum) == OK
+ && ml_replace(lnum, (char *)line, true) == OK) {
+ inserted_bytes(lnum, 0, old_len, (int)STRLEN(line));
+ if (is_curbuf && lnum == curwin->w_cursor.lnum) {
+ check_cursor_col();
+ }
+ rettv->vval.v_number = 0; // OK
+ }
+ } else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
+ // append the line.
+ added++;
+ if (ml_append(lnum - 1, (char *)line, 0, false) == OK) {
+ rettv->vval.v_number = 0; // OK
+ }
+ }
+
+ if (l == NULL) { // only one string argument
+ break;
+ }
+ lnum++;
+ }
+
+ if (added > 0) {
+ appended_lines_mark(append_lnum, added);
+
+ // Only adjust the cursor for buffers other than the current, unless it
+ // is the current window. For curbuf and other windows it has been done
+ // in mark_adjust_internal().
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf
+ && (wp->w_buffer != curbuf || wp == curwin)
+ && wp->w_cursor.lnum > append_lnum) {
+ wp->w_cursor.lnum += (linenr_T)added;
+ }
+ }
+ check_cursor_col();
+ update_topline(curwin);
+ }
+
+ if (!is_curbuf) {
+ curbuf = curbuf_save;
+ curwin = curwin_save;
+ VIsual_active = save_VIsual_active;
+ }
+}
+
+/// "stdpath()" helper for list results
+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);
+ if (dirs == NULL) {
+ return;
+ }
+ do {
+ size_t dir_len;
+ const char *dir;
+ iter = vim_env_iter(ENV_SEPCHAR, 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, (ssize_t)strlen(dir_with_nvim));
+ xfree(dir_with_nvim);
+ }
+ } while (iter != NULL);
+ xfree(dirs);
+}
+
+static list_T *string_to_list(const char *str, size_t len, const bool keepempty)
+{
+ if (!keepempty && str[len - 1] == NL) {
+ len--;
+ }
+ list_T *const list = tv_list_alloc(kListLenMayKnow);
+ encode_list_write(list, str, len);
+ return list;
+}
+
+/// os_system wrapper. Handles 'verbose', :profile, and v:shell_error.
+void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool retlist)
+{
+ proftime_T wait_time;
+ bool profiling = do_profiling == PROF_YES;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (check_secure()) {
+ return;
+ }
+
+ // get input to the shell command (if any), and its length
+ ptrdiff_t input_len;
+ char *input = save_tv_as_string(&argvars[1], &input_len, false);
+ if (input_len < 0) {
+ assert(input == NULL);
+ return;
+ }
+
+ // get shell command to execute
+ bool executable = true;
+ char **argv = tv_to_argv(&argvars[0], NULL, &executable);
+ if (!argv) {
+ if (!executable) {
+ set_vim_var_nr(VV_SHELL_ERROR, (long)-1);
+ }
+ xfree(input);
+ return; // Already did emsg.
+ }
+
+ if (p_verbose > 3) {
+ char *cmdstr = shell_argv_to_str(argv);
+ verbose_enter_scroll();
+ smsg(_("Executing command: \"%s\""), cmdstr);
+ msg_puts("\n\n");
+ verbose_leave_scroll();
+ xfree(cmdstr);
+ }
+
+ if (profiling) {
+ prof_child_enter(&wait_time);
+ }
+
+ // execute the command
+ size_t nread = 0;
+ char *res = NULL;
+ int status = os_system(argv, input, (size_t)input_len, &res, &nread);
+
+ if (profiling) {
+ prof_child_exit(&wait_time);
+ }
+
+ xfree(input);
+
+ set_vim_var_nr(VV_SHELL_ERROR, (long)status);
+
+ if (res == NULL) {
+ if (retlist) {
+ // return an empty list when there's no output
+ tv_list_alloc_ret(rettv, 0);
+ } else {
+ rettv->vval.v_string = xstrdup("");
+ }
+ return;
+ }
+
+ if (retlist) {
+ int keepempty = 0;
+ if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
+ keepempty = (int)tv_get_number(&argvars[2]);
+ }
+ rettv->vval.v_list = string_to_list(res, nread, (bool)keepempty);
+ tv_list_ref(rettv->vval.v_list);
+ rettv->v_type = VAR_LIST;
+
+ xfree(res);
+ } else {
+ // res may contain several NULs before the final terminating one.
+ // Replace them with SOH (1) like in get_cmd_output() to avoid truncation.
+ memchrsub(res, NUL, 1, nread);
+#ifdef USE_CRNL
+ // translate <CR><NL> into <NL>
+ char *d = res;
+ for (char *s = res; *s; ++s) {
+ if (s[0] == CAR && s[1] == NL) {
+ ++s;
+ }
+
+ *d++ = *s;
+ }
+
+ *d = NUL;
+#endif
+ rettv->vval.v_string = res;
+ }
+}
+
+bool callback_from_typval(Callback *const callback, typval_T *const arg)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ int r = OK;
+
+ if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) {
+ callback->data.partial = arg->vval.v_partial;
+ callback->data.partial->pt_refcount++;
+ callback->type = kCallbackPartial;
+ } else if (arg->v_type == VAR_STRING
+ && arg->vval.v_string != NULL
+ && ascii_isdigit(*arg->vval.v_string)) {
+ r = FAIL;
+ } else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) {
+ char *name = arg->vval.v_string;
+ if (name == NULL) {
+ r = FAIL;
+ } else if (*name == NUL) {
+ callback->type = kCallbackNone;
+ callback->data.funcref = NULL;
+ } else {
+ func_ref((char_u *)name);
+ callback->data.funcref = xstrdup(name);
+ callback->type = kCallbackFuncref;
+ }
+ } else if (nlua_is_table_from_lua(arg)) {
+ // TODO(tjdvries): UnifiedCallback
+ char *name = (char *)nlua_register_table_as_callable(arg);
+
+ if (name != NULL) {
+ callback->data.funcref = xstrdup(name);
+ callback->type = kCallbackFuncref;
+ } else {
+ r = FAIL;
+ }
+ } else if (arg->v_type == VAR_SPECIAL
+ || (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)) {
+ callback->type = kCallbackNone;
+ callback->data.funcref = NULL;
+ } else {
+ r = FAIL;
+ }
+
+ if (r == FAIL) {
+ emsg(_("E921: Invalid callback argument"));
+ return false;
+ }
+ return true;
+}
+
+bool callback_call(Callback *const callback, const int argcount_in, typval_T *const argvars_in,
+ typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ partial_T *partial;
+ char *name;
+ Array args = ARRAY_DICT_INIT;
+ Object rv;
+ switch (callback->type) {
+ case kCallbackFuncref:
+ name = callback->data.funcref;
+ partial = NULL;
+ break;
+
+ case kCallbackPartial:
+ partial = callback->data.partial;
+ name = partial_name(partial);
+ break;
+
+ case kCallbackLua:
+ rv = nlua_call_ref(callback->data.luaref, NULL, args, true, NULL);
+ switch (rv.type) {
+ case kObjectTypeBoolean:
+ return rv.data.boolean;
+ default:
+ return false;
+ }
+
+ case kCallbackNone:
+ return false;
+ break;
+
+ default:
+ abort();
+ }
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ return call_func(name, -1, rettv, argcount_in, argvars_in, &funcexe);
+}
+
+static bool set_ref_in_callback(Callback *callback, int copyID, ht_stack_T **ht_stack,
+ list_stack_T **list_stack)
+{
+ typval_T tv;
+ switch (callback->type) {
+ case kCallbackFuncref:
+ case kCallbackNone:
+ break;
+
+ case kCallbackPartial:
+ tv.v_type = VAR_PARTIAL;
+ tv.vval.v_partial = callback->data.partial;
+ return set_ref_in_item(&tv, copyID, ht_stack, list_stack);
+ break;
+
+ default:
+ abort();
+ }
+ return false;
+}
+
+static bool set_ref_in_callback_reader(CallbackReader *reader, int copyID, ht_stack_T **ht_stack,
+ list_stack_T **list_stack)
+{
+ if (set_ref_in_callback(&reader->cb, copyID, ht_stack, list_stack)) {
+ return true;
+ }
+
+ if (reader->self) {
+ typval_T tv;
+ tv.v_type = VAR_DICT;
+ tv.vval.v_dict = reader->self;
+ return set_ref_in_item(&tv, copyID, ht_stack, list_stack);
+ }
+ return false;
+}
+
+timer_T *find_timer_by_nr(varnumber_T xx)
+{
+ return pmap_get(uint64_t)(&timers, (uint64_t)xx);
+}
+
+void add_timer_info(typval_T *rettv, timer_T *timer)
+{
+ list_T *list = rettv->vval.v_list;
+ dict_T *dict = tv_dict_alloc();
+
+ tv_list_append_dict(list, dict);
+ tv_dict_add_nr(dict, S_LEN("id"), timer->timer_id);
+ tv_dict_add_nr(dict, S_LEN("time"), timer->timeout);
+ tv_dict_add_nr(dict, S_LEN("paused"), timer->paused);
+
+ tv_dict_add_nr(dict, S_LEN("repeat"),
+ (timer->repeat_count < 0 ? -1 : timer->repeat_count));
+
+ dictitem_T *di = tv_dict_item_alloc("callback");
+ if (tv_dict_add(dict, di) == FAIL) {
+ xfree(di);
+ return;
+ }
+
+ callback_put(&timer->callback, &di->di_tv);
+}
+
+void add_timer_info_all(typval_T *rettv)
+{
+ tv_list_alloc_ret(rettv, map_size(&timers));
+ timer_T *timer;
+ map_foreach_value(&timers, timer, {
+ if (!timer->stopped) {
+ add_timer_info(rettv, timer);
+ }
+ })
+}
+
+/// invoked on the main loop
+void timer_due_cb(TimeWatcher *tw, void *data)
+{
+ timer_T *timer = (timer_T *)data;
+ int save_did_emsg = did_emsg;
+ const int called_emsg_before = called_emsg;
+ const bool save_ex_pressedreturn = get_pressedreturn();
+
+ if (timer->stopped || timer->paused) {
+ return;
+ }
+
+ timer->refcount++;
+ // if repeat was negative repeat forever
+ if (timer->repeat_count >= 0 && --timer->repeat_count == 0) {
+ timer_stop(timer);
+ }
+
+ typval_T argv[2] = { TV_INITIAL_VALUE, TV_INITIAL_VALUE };
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = timer->timer_id;
+ typval_T rettv = TV_INITIAL_VALUE;
+
+ callback_call(&timer->callback, 1, argv, &rettv);
+
+ // Handle error message
+ if (called_emsg > called_emsg_before && did_emsg) {
+ timer->emsg_count++;
+ if (current_exception != NULL) {
+ discard_current_exception();
+ }
+ }
+ did_emsg = save_did_emsg;
+ set_pressedreturn(save_ex_pressedreturn);
+
+ if (timer->emsg_count >= 3) {
+ timer_stop(timer);
+ }
+
+ tv_clear(&rettv);
+
+ if (!timer->stopped && timer->timeout == 0) {
+ // special case: timeout=0 means the callback will be
+ // invoked again on the next event loop tick.
+ // we don't use uv_idle_t to not spin the event loop
+ // when the main loop is blocked.
+ time_watcher_start(&timer->tw, timer_due_cb, 0, 0);
+ }
+ timer_decref(timer);
+}
+
+uint64_t timer_start(const long timeout, const int repeat_count, const Callback *const callback)
+{
+ timer_T *timer = xmalloc(sizeof *timer);
+ timer->refcount = 1;
+ timer->stopped = false;
+ timer->paused = false;
+ timer->emsg_count = 0;
+ timer->repeat_count = repeat_count;
+ timer->timeout = timeout;
+ timer->timer_id = (int)last_timer_id++;
+ timer->callback = *callback;
+
+ time_watcher_init(&main_loop, &timer->tw, timer);
+ timer->tw.events = multiqueue_new_child(main_loop.events);
+ // if main loop is blocked, don't queue up multiple events
+ timer->tw.blockable = true;
+ time_watcher_start(&timer->tw, timer_due_cb, (uint64_t)timeout, (uint64_t)timeout);
+
+ pmap_put(uint64_t)(&timers, (uint64_t)timer->timer_id, timer);
+ return (uint64_t)timer->timer_id;
+}
+
+void timer_stop(timer_T *timer)
+{
+ if (timer->stopped) {
+ // avoid double free
+ return;
+ }
+ timer->stopped = true;
+ time_watcher_stop(&timer->tw);
+ time_watcher_close(&timer->tw, timer_close_cb);
+}
+
+/// 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;
+ multiqueue_free(timer->tw.events);
+ callback_free(&timer->callback);
+ pmap_del(uint64_t)(&timers, (uint64_t)timer->timer_id);
+ timer_decref(timer);
+}
+
+static void timer_decref(timer_T *timer)
+{
+ if (--timer->refcount == 0) {
+ xfree(timer);
+ }
+}
+
+void timer_stop_all(void)
+{
+ timer_T *timer;
+ map_foreach_value(&timers, timer, {
+ timer_stop(timer);
+ })
+}
+
+void timer_teardown(void)
+{
+ timer_stop_all();
+}
+
+/// Write "list" of strings to file "fd".
+///
+/// @param fp File to write to.
+/// @param[in] list List to write.
+/// @param[in] binary Whether to write in binary mode.
+///
+/// @return true in case of success, false otherwise.
+bool write_list(FileDescriptor *const fp, const list_T *const list, const bool binary)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ int error = 0;
+ TV_LIST_ITER_CONST(list, li, {
+ const char *const s = tv_get_string_chk(TV_LIST_ITEM_TV(li));
+ if (s == NULL) {
+ return false;
+ }
+ const char *hunk_start = s;
+ for (const char *p = hunk_start;; p++) {
+ if (*p == NUL || *p == NL) {
+ if (p != hunk_start) {
+ const ptrdiff_t written = file_write(fp, hunk_start,
+ (size_t)(p - hunk_start));
+ if (written < 0) {
+ error = (int)written;
+ goto write_list_error;
+ }
+ }
+ if (*p == NUL) {
+ break;
+ } else {
+ hunk_start = p + 1;
+ const ptrdiff_t written = file_write(fp, (char[]){ NUL }, 1);
+ if (written < 0) {
+ error = (int)written;
+ break;
+ }
+ }
+ }
+ }
+ if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) {
+ const ptrdiff_t written = file_write(fp, "\n", 1);
+ if (written < 0) {
+ error = (int)written;
+ goto write_list_error;
+ }
+ }
+ });
+ if ((error = file_flush(fp)) != 0) {
+ goto write_list_error;
+ }
+ return true;
+write_list_error:
+ semsg(_(e_write2), os_strerror(error));
+ return false;
+}
+
+/// Write a blob to file with descriptor `fp`.
+///
+/// @param[in] fp File to write to.
+/// @param[in] blob Blob to write.
+///
+/// @return true on success, or false on failure.
+bool write_blob(FileDescriptor *const fp, const blob_T *const blob)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ int error = 0;
+ const int len = tv_blob_len(blob);
+ if (len > 0) {
+ const ptrdiff_t written = file_write(fp, blob->bv_ga.ga_data, (size_t)len);
+ if (written < (ptrdiff_t)len) {
+ error = (int)written;
+ goto write_blob_error;
+ }
+ }
+ error = file_flush(fp);
+ if (error != 0) {
+ goto write_blob_error;
+ }
+ return true;
+write_blob_error:
+ semsg(_(e_write2), os_strerror(error));
+ return false;
+}
+
+/// Read a blob from a file `fd`.
+///
+/// @param[in] fd File to read from.
+/// @param[in,out] blob Blob to write to.
+///
+/// @return true on success, or false on failure.
+bool read_blob(FILE *const fd, blob_T *const blob)
+ FUNC_ATTR_NONNULL_ALL
+{
+ FileInfo file_info;
+ if (!os_fileinfo_fd(fileno(fd), &file_info)) {
+ return false;
+ }
+ const int size = (int)os_fileinfo_size(&file_info);
+ ga_grow(&blob->bv_ga, size);
+ blob->bv_ga.ga_len = size;
+ if (fread(blob->bv_ga.ga_data, 1, (size_t)blob->bv_ga.ga_len, fd)
+ < (size_t)blob->bv_ga.ga_len) {
+ return false;
+ }
+ return true;
+}
+
+/// Saves a typval_T as a string.
+///
+/// For lists or buffers, replaces NLs with NUL and separates items with NLs.
+///
+/// @param[in] tv Value to store as a string.
+/// @param[out] len Length of the resulting string or -1 on error.
+/// @param[in] endnl If true, the output will end in a newline (if a list).
+/// @returns an allocated string if `tv` represents a VimL string, list, or
+/// number; NULL otherwise.
+char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
+ FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
+{
+ *len = 0;
+ if (tv->v_type == VAR_UNKNOWN) {
+ return NULL;
+ }
+
+ // For other types, let tv_get_string_buf_chk() get the value or
+ // print an error.
+ if (tv->v_type != VAR_LIST && tv->v_type != VAR_NUMBER) {
+ const char *ret = tv_get_string_chk(tv);
+ if (ret) {
+ *len = (ptrdiff_t)strlen(ret);
+ return xmemdupz(ret, (size_t)(*len));
+ } else {
+ *len = -1;
+ return NULL;
+ }
+ }
+
+ if (tv->v_type == VAR_NUMBER) { // Treat number as a buffer-id.
+ buf_T *buf = buflist_findnr((int)tv->vval.v_number);
+ if (buf) {
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (char *p = (char *)ml_get_buf(buf, lnum, false); *p != NUL; p++) {
+ *len += 1;
+ }
+ *len += 1;
+ }
+ } else {
+ semsg(_(e_nobufnr), tv->vval.v_number);
+ *len = -1;
+ return NULL;
+ }
+
+ if (*len == 0) {
+ return NULL;
+ }
+
+ char *ret = xmalloc((size_t)(*len) + 1);
+ char *end = ret;
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (char *p = (char *)ml_get_buf(buf, lnum, false); *p != NUL; p++) {
+ *end++ = (*p == '\n') ? NUL : *p;
+ }
+ *end++ = '\n';
+ }
+ *end = NUL;
+ *len = end - ret;
+ return ret;
+ }
+
+ assert(tv->v_type == VAR_LIST);
+ // Pre-calculate the resulting length.
+ list_T *list = tv->vval.v_list;
+ TV_LIST_ITER_CONST(list, li, {
+ *len += (ptrdiff_t)strlen(tv_get_string(TV_LIST_ITEM_TV(li))) + 1;
+ });
+
+ if (*len == 0) {
+ return NULL;
+ }
+
+ char *ret = xmalloc((size_t)(*len) + endnl);
+ char *end = ret;
+ TV_LIST_ITER_CONST(list, li, {
+ for (const char *s = tv_get_string(TV_LIST_ITEM_TV(li)); *s != NUL; s++) {
+ *end++ = (*s == '\n') ? NUL : *s;
+ }
+ if (endnl || TV_LIST_ITEM_NEXT(list, li) != NULL) {
+ *end++ = '\n';
+ }
+ });
+ *end = NUL;
+ *len = end - ret;
+ return ret;
+}
+
+/// Convert the specified byte index of line 'lnum' in buffer 'buf' to a
+/// character index. Works only for loaded buffers. Returns -1 on failure.
+/// The index of the first byte and the first character is zero.
+int buf_byteidx_to_charidx(buf_T *buf, linenr_T lnum, int byteidx)
+{
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
+ return -1;
+ }
+
+ if (lnum > buf->b_ml.ml_line_count) {
+ lnum = buf->b_ml.ml_line_count;
+ }
+
+ char *str = (char *)ml_get_buf(buf, lnum, false);
+
+ if (*str == NUL) {
+ return 0;
+ }
+
+ // count the number of characters
+ char *t = str;
+ int count;
+ for (count = 0; *t != NUL && t <= str + byteidx; count++) {
+ t += utfc_ptr2len(t);
+ }
+
+ // In insert mode, when the cursor is at the end of a non-empty line,
+ // byteidx points to the NUL character immediately past the end of the
+ // string. In this case, add one to the character count.
+ if (*t == NUL && byteidx != 0 && t == str + byteidx) {
+ count++;
+ }
+
+ return count - 1;
+}
+
+/// Convert the specified character index of line 'lnum' in buffer 'buf' to a
+/// byte index. Works only for loaded buffers.
+/// The index of the first byte and the first character is zero.
+///
+/// @return -1 on failure.
+int buf_charidx_to_byteidx(buf_T *buf, linenr_T lnum, int charidx)
+{
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
+ return -1;
+ }
+
+ if (lnum > buf->b_ml.ml_line_count) {
+ lnum = buf->b_ml.ml_line_count;
+ }
+
+ char *str = (char *)ml_get_buf(buf, lnum, false);
+
+ // Convert the character offset to a byte offset
+ char *t = str;
+ while (*t != NUL && --charidx > 0) {
+ t += utfc_ptr2len(t);
+ }
+
+ return (int)(t - str);
+}
+
+/// Translate a VimL object into a position
+///
+/// Accepts VAR_LIST and VAR_STRING objects. Does not give an error for invalid
+/// type.
+///
+/// @param[in] tv Object to translate.
+/// @param[in] dollar_lnum True when "$" is last line.
+/// @param[out] ret_fnum Set to fnum for marks.
+/// @param[in] charcol True to return character column.
+///
+/// @return Pointer to position or NULL in case of error (e.g. invalid type).
+pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret_fnum,
+ const bool charcol)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ static pos_T pos;
+
+ // Argument can be [lnum, col, coladd].
+ if (tv->v_type == VAR_LIST) {
+ list_T *l;
+ int len;
+ bool error = false;
+ listitem_T *li;
+
+ l = tv->vval.v_list;
+ if (l == NULL) {
+ return NULL;
+ }
+
+ // Get the line number.
+ pos.lnum = (linenr_T)tv_list_find_nr(l, 0L, &error);
+ if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count) {
+ // Invalid line number.
+ return NULL;
+ }
+
+ // Get the column number.
+ pos.col = (colnr_T)tv_list_find_nr(l, 1L, &error);
+ if (error) {
+ return NULL;
+ }
+ if (charcol) {
+ len = mb_charlen(ml_get(pos.lnum));
+ } else {
+ len = (int)STRLEN(ml_get(pos.lnum));
+ }
+
+ // We accept "$" for the column number: last column.
+ li = tv_list_find(l, 1L);
+ if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING
+ && TV_LIST_ITEM_TV(li)->vval.v_string != NULL
+ && STRCMP(TV_LIST_ITEM_TV(li)->vval.v_string, "$") == 0) {
+ pos.col = len + 1;
+ }
+
+ // Accept a position up to the NUL after the line.
+ if (pos.col == 0 || (int)pos.col > len + 1) {
+ // Invalid column number.
+ return NULL;
+ }
+ pos.col--;
+
+ // Get the virtual offset. Defaults to zero.
+ pos.coladd = (colnr_T)tv_list_find_nr(l, 2L, &error);
+ if (error) {
+ pos.coladd = 0;
+ }
+
+ return &pos;
+ }
+
+ const char *const name = tv_get_string_chk(tv);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ pos.lnum = 0;
+ if (name[0] == '.') {
+ // cursor
+ pos = curwin->w_cursor;
+ } else if (name[0] == 'v' && name[1] == NUL) {
+ // Visual start
+ if (VIsual_active) {
+ pos = VIsual;
+ } else {
+ pos = curwin->w_cursor;
+ }
+ } else if (name[0] == '\'') {
+ // mark
+ int mname = (uint8_t)name[1];
+ const fmark_T *const fm = mark_get(curbuf, curwin, NULL, kMarkAll, mname);
+ if (fm == NULL || fm->mark.lnum <= 0) {
+ return NULL;
+ }
+ pos = fm->mark;
+ // Vimscript behavior, only provide fnum if mark is global.
+ *ret_fnum = ASCII_ISUPPER(mname) || ascii_isdigit(mname) ? fm->fnum: *ret_fnum;
+ }
+ if (pos.lnum != 0) {
+ if (charcol) {
+ pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col);
+ }
+ return &pos;
+ }
+
+ pos.coladd = 0;
+
+ if (name[0] == 'w' && dollar_lnum) {
+ pos.col = 0;
+ if (name[1] == '0') { // "w0": first visible line
+ update_topline(curwin);
+ // In silent Ex mode topline is zero, but that's not a valid line
+ // number; use one instead.
+ pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1;
+ return &pos;
+ } else if (name[1] == '$') { // "w$": last visible line
+ validate_botline(curwin);
+ // In silent Ex mode botline is zero, return zero then.
+ pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0;
+ return &pos;
+ }
+ } else if (name[0] == '$') { // last column or line
+ if (dollar_lnum) {
+ pos.lnum = curbuf->b_ml.ml_line_count;
+ pos.col = 0;
+ } else {
+ pos.lnum = curwin->w_cursor.lnum;
+ if (charcol) {
+ pos.col = (colnr_T)mb_charlen(get_cursor_line_ptr());
+ } else {
+ pos.col = (colnr_T)STRLEN(get_cursor_line_ptr());
+ }
+ }
+ return &pos;
+ }
+ return NULL;
+}
+
+/// Convert list in "arg" into a position and optional file number.
+/// When "fnump" is NULL there is no file number, only 3 items.
+/// Note that the column is passed on as-is, the caller may want to decrement
+/// it to use 1 for the first column.
+///
+/// @return FAIL when conversion is not possible, doesn't check the position for
+/// validity.
+int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool charcol)
+{
+ list_T *l;
+ int i = 0;
+ long n;
+
+ // List must be: [fnum, lnum, col, coladd, curswant], where "fnum" is only
+ // there when "fnump" isn't NULL; "coladd" and "curswant" are optional.
+ if (arg->v_type != VAR_LIST
+ || (l = arg->vval.v_list) == NULL
+ || tv_list_len(l) < (fnump == NULL ? 2 : 3)
+ || tv_list_len(l) > (fnump == NULL ? 4 : 5)) {
+ return FAIL;
+ }
+
+ if (fnump != NULL) {
+ n = tv_list_find_nr(l, i++, NULL); // fnum
+ if (n < 0) {
+ return FAIL;
+ }
+ if (n == 0) {
+ n = curbuf->b_fnum; // Current buffer.
+ }
+ *fnump = (int)n;
+ }
+
+ n = tv_list_find_nr(l, i++, NULL); // lnum
+ if (n < 0) {
+ return FAIL;
+ }
+ posp->lnum = (linenr_T)n;
+
+ n = tv_list_find_nr(l, i++, NULL); // col
+ if (n < 0) {
+ return FAIL;
+ }
+ // If character position is specified, then convert to byte position
+ if (charcol) {
+ // Get the text for the specified line in a loaded buffer
+ buf_T *buf = buflist_findnr(fnump == NULL ? curbuf->b_fnum : *fnump);
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
+ return FAIL;
+ }
+ n = buf_charidx_to_byteidx(buf, posp->lnum, (int)n) + 1;
+ }
+ posp->col = (colnr_T)n;
+
+ n = tv_list_find_nr(l, i, NULL); // off
+ if (n < 0) {
+ posp->coladd = 0;
+ } else {
+ posp->coladd = (colnr_T)n;
+ }
+
+ if (curswantp != NULL) {
+ *curswantp = (colnr_T)tv_list_find_nr(l, i + 1, NULL); // curswant
+ }
+
+ return OK;
+}
+
+/// Get the length of an environment variable name.
+/// Advance "arg" to the first character after the name.
+///
+/// @return 0 for error.
+int get_env_len(const char **arg)
+{
+ int len;
+
+ const char *p;
+ for (p = *arg; vim_isIDc(*p); p++) {}
+ if (p == *arg) { // No name found.
+ return 0;
+ }
+
+ len = (int)(p - *arg);
+ *arg = p;
+ return len;
+}
+
+/// Get the length of the name of a function or internal variable.
+///
+/// @param arg is advanced to the first non-white character after the name.
+///
+/// @return 0 if something is wrong.
+int get_id_len(const char **const arg)
+{
+ int len;
+
+ // Find the end of the name.
+ const char *p;
+ for (p = *arg; eval_isnamec(*p); p++) {
+ if (*p == ':') {
+ // "s:" is start of "s:var", but "n:" is not and can be used in
+ // slice "[n:]". Also "xx:" is not a namespace.
+ len = (int)(p - *arg);
+ if (len > 1
+ || (len == 1 && vim_strchr(namespace_char, **arg) == NULL)) {
+ break;
+ }
+ }
+ }
+ if (p == *arg) { // no name found
+ return 0;
+ }
+
+ len = (int)(p - *arg);
+ *arg = (const char *)skipwhite(p);
+
+ return len;
+}
+
+/// Get the length of the name of a variable or function.
+/// Only the name is recognized, does not handle ".key" or "[idx]".
+///
+/// @param arg is advanced to the first non-white character after the name.
+/// If the name contains 'magic' {}'s, expand them and return the
+/// expanded name in an allocated string via 'alias' - caller must free.
+///
+/// @return -1 if curly braces expansion failed or
+/// 0 if something else is wrong.
+int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbose)
+{
+ int len;
+
+ *alias = NULL; // default to no alias
+
+ if ((*arg)[0] == (char)K_SPECIAL && (*arg)[1] == (char)KS_EXTRA
+ && (*arg)[2] == (char)KE_SNR) {
+ // Hard coded <SNR>, already translated.
+ *arg += 3;
+ return get_id_len(arg) + 3;
+ }
+ len = eval_fname_script(*arg);
+ if (len > 0) {
+ // literal "<SID>", "s:" or "<SNR>"
+ *arg += len;
+ }
+
+ // Find the end of the name; check for {} construction.
+ char *expr_start;
+ char *expr_end;
+ const char *p = find_name_end((*arg), (const char **)&expr_start, (const char **)&expr_end,
+ len > 0 ? 0 : FNE_CHECK_START);
+ if (expr_start != NULL) {
+ if (!evaluate) {
+ len += (int)(p - *arg);
+ *arg = (const char *)skipwhite(p);
+ return len;
+ }
+
+ /*
+ * Include any <SID> etc in the expanded string:
+ * Thus the -len here.
+ */
+ char *temp_string = make_expanded_name(*arg - len, expr_start, expr_end, (char *)p);
+ if (temp_string == NULL) {
+ return -1;
+ }
+ *alias = temp_string;
+ *arg = (const char *)skipwhite(p);
+ return (int)STRLEN(temp_string);
+ }
+
+ len += get_id_len(arg);
+ // Only give an error when there is something, otherwise it will be
+ // reported at a higher level.
+ if (len == 0 && verbose && **arg != NUL) {
+ semsg(_(e_invexpr2), *arg);
+ }
+
+ return len;
+}
+
+/// Find the end of a variable or function name, taking care of magic braces.
+///
+/// @param expr_start if not NULL, then `expr_start` and `expr_end` are set to the
+/// start and end of the first magic braces item.
+///
+/// @param flags can have FNE_INCL_BR and FNE_CHECK_START.
+///
+/// @return a pointer to just after the name. Equal to "arg" if there is no
+/// valid name.
+const char *find_name_end(const char *arg, const char **expr_start, const char **expr_end,
+ int flags)
+{
+ int mb_nest = 0;
+ int br_nest = 0;
+ int len;
+
+ if (expr_start != NULL) {
+ *expr_start = NULL;
+ *expr_end = NULL;
+ }
+
+ // Quick check for valid starting character.
+ if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{') {
+ return arg;
+ }
+
+ const char *p;
+ for (p = arg; *p != NUL
+ && (eval_isnamec(*p)
+ || *p == '{'
+ || ((flags & FNE_INCL_BR) && (*p == '[' || *p == '.'))
+ || mb_nest != 0
+ || br_nest != 0); MB_PTR_ADV(p)) {
+ if (*p == '\'') {
+ // skip over 'string' to avoid counting [ and ] inside it.
+ for (p = p + 1; *p != NUL && *p != '\''; MB_PTR_ADV(p)) {}
+ if (*p == NUL) {
+ break;
+ }
+ } else if (*p == '"') {
+ // skip over "str\"ing" to avoid counting [ and ] inside it.
+ for (p = p + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) {
+ if (*p == '\\' && p[1] != NUL) {
+ ++p;
+ }
+ }
+ if (*p == NUL) {
+ break;
+ }
+ } else if (br_nest == 0 && mb_nest == 0 && *p == ':') {
+ // "s:" is start of "s:var", but "n:" is not and can be used in
+ // slice "[n:]". Also "xx:" is not a namespace. But {ns}: is.
+ len = (int)(p - arg);
+ if ((len > 1 && p[-1] != '}')
+ || (len == 1 && vim_strchr(namespace_char, *arg) == NULL)) {
+ break;
+ }
+ }
+
+ if (mb_nest == 0) {
+ if (*p == '[') {
+ ++br_nest;
+ } else if (*p == ']') {
+ --br_nest;
+ }
+ }
+
+ if (br_nest == 0) {
+ if (*p == '{') {
+ mb_nest++;
+ if (expr_start != NULL && *expr_start == NULL) {
+ *expr_start = p;
+ }
+ } else if (*p == '}') {
+ mb_nest--;
+ if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL) {
+ *expr_end = p;
+ }
+ }
+ }
+ }
+
+ return p;
+}
+
+/// Expands out the 'magic' {}'s in a variable/function name.
+/// Note that this can call itself recursively, to deal with
+/// constructs like foo{bar}{baz}{bam}
+/// The four pointer arguments point to "foo{expre}ss{ion}bar"
+/// "in_start" ^
+/// "expr_start" ^
+/// "expr_end" ^
+/// "in_end" ^
+///
+/// @return a new allocated string, which the caller must free or
+/// NULL for failure.
+static char *make_expanded_name(const char *in_start, char *expr_start, char *expr_end,
+ char *in_end)
+{
+ char c1;
+ char *retval = NULL;
+ char *temp_result;
+ char *nextcmd = NULL;
+
+ if (expr_end == NULL || in_end == NULL) {
+ return NULL;
+ }
+ *expr_start = NUL;
+ *expr_end = NUL;
+ c1 = *in_end;
+ *in_end = NUL;
+
+ temp_result = eval_to_string(expr_start + 1, &nextcmd, false);
+ if (temp_result != NULL && nextcmd == NULL) {
+ retval = xmalloc(STRLEN(temp_result) + (size_t)(expr_start - in_start)
+ + (size_t)(in_end - expr_end) + 1);
+ STRCPY(retval, in_start);
+ STRCAT(retval, temp_result);
+ STRCAT(retval, expr_end + 1);
+ }
+ xfree(temp_result);
+
+ *in_end = c1; // put char back for error messages
+ *expr_start = '{';
+ *expr_end = '}';
+
+ if (retval != NULL) {
+ temp_result = (char *)find_name_end(retval,
+ (const char **)&expr_start,
+ (const char **)&expr_end, 0);
+ if (expr_start != NULL) {
+ // Further expansion!
+ temp_result = make_expanded_name(retval, expr_start,
+ expr_end, temp_result);
+ xfree(retval);
+ retval = temp_result;
+ }
+ }
+
+ return retval;
+}
+
+/// @return TRUE if character "c" can be used in a variable or function name.
+/// Does not include '{' or '}' for magic braces.
+int eval_isnamec(int c)
+{
+ return ASCII_ISALNUM(c) || c == '_' || c == ':' || c == AUTOLOAD_CHAR;
+}
+
+/// @return TRUE if character "c" can be used as the first character in a
+/// variable or function name (excluding '{' and '}').
+int eval_isnamec1(int c)
+{
+ return ASCII_ISALPHA(c) || c == '_';
+}
+
+/// Get typval_T v: variable value.
+typval_T *get_vim_var_tv(int idx)
+{
+ return &vimvars[idx].vv_tv;
+}
+
+/// Get number v: variable value.
+varnumber_T get_vim_var_nr(int idx) FUNC_ATTR_PURE
+{
+ return vimvars[idx].vv_nr;
+}
+
+/// Get string v: variable value. Uses a static buffer, can only be used once.
+/// If the String variable has never been set, return an empty string.
+/// Never returns NULL.
+char *get_vim_var_str(int idx)
+ FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
+{
+ return (char *)tv_get_string(&vimvars[idx].vv_tv);
+}
+
+/// Get List v: variable value. Caller must take care of reference count when
+/// needed.
+list_T *get_vim_var_list(int idx) FUNC_ATTR_PURE
+{
+ return vimvars[idx].vv_list;
+}
+
+/// Get Dictionary v: variable value. Caller must take care of reference count
+/// when needed.
+dict_T *get_vim_var_dict(int idx) FUNC_ATTR_PURE
+{
+ return vimvars[idx].vv_dict;
+}
+
+/// Set v:char to character "c".
+void set_vim_var_char(int c)
+{
+ char buf[MB_MAXBYTES + 1];
+
+ buf[utf_char2bytes(c, buf)] = NUL;
+ set_vim_var_string(VV_CHAR, buf, -1);
+}
+
+/// Set v:count to "count" and v:count1 to "count1".
+///
+/// @param set_prevcount if TRUE, first set v:prevcount from v:count.
+void set_vcount(long count, long count1, int set_prevcount)
+{
+ if (set_prevcount) {
+ vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
+ }
+ vimvars[VV_COUNT].vv_nr = count;
+ vimvars[VV_COUNT1].vv_nr = count1;
+}
+
+/// Set number v: variable to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
+{
+ tv_clear(&vimvars[idx].vv_tv);
+ vimvars[idx].vv_type = VAR_NUMBER;
+ vimvars[idx].vv_nr = val;
+}
+
+/// Set boolean v: {true, false} to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_bool(const VimVarIndex idx, const BoolVarValue val)
+{
+ tv_clear(&vimvars[idx].vv_tv);
+ vimvars[idx].vv_type = VAR_BOOL;
+ vimvars[idx].vv_bool = val;
+}
+
+/// Set special v: variable to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
+{
+ tv_clear(&vimvars[idx].vv_tv);
+ vimvars[idx].vv_type = VAR_SPECIAL;
+ vimvars[idx].vv_special = val;
+}
+
+/// Set string v: variable to the given string
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to. Will be copied.
+/// @param[in] len Length of that value or -1 in which case strlen() will be
+/// used.
+void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len)
+{
+ tv_clear(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_STRING;
+ if (val == NULL) {
+ vimvars[idx].vv_str = NULL;
+ } else if (len == -1) {
+ vimvars[idx].vv_str = xstrdup(val);
+ } else {
+ vimvars[idx].vv_str = xstrndup(val, (size_t)len);
+ }
+}
+
+/// Set list v: variable to the given list
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in,out] val Value to set to. Reference count will be incremented.
+void set_vim_var_list(const VimVarIndex idx, list_T *const val)
+{
+ tv_clear(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_LIST;
+ vimvars[idx].vv_list = val;
+ if (val != NULL) {
+ tv_list_ref(val);
+ }
+}
+
+/// Set Dictionary v: variable to the given dictionary
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in,out] val Value to set to. Reference count will be incremented.
+/// Also keys of the dictionary will be made read-only.
+void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
+{
+ tv_clear(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_DICT;
+ vimvars[idx].vv_dict = val;
+
+ if (val != NULL) {
+ val->dv_refcount++;
+ // Set readonly
+ tv_dict_set_keys_readonly(val);
+ }
+}
+
+/// Set the v:argv list.
+void set_argv_var(char **argv, int argc)
+{
+ list_T *l = tv_list_alloc(argc);
+ int i;
+
+ tv_list_set_lock(l, VAR_FIXED);
+ for (i = 0; i < argc; i++) {
+ tv_list_append_string(l, (const char *const)argv[i], -1);
+ TV_LIST_ITEM_TV(tv_list_last(l))->v_lock = VAR_FIXED;
+ }
+ set_vim_var_list(VV_ARGV, l);
+}
+
+/// Set v:register if needed.
+void set_reg_var(int c)
+{
+ char regname;
+
+ if (c == 0 || c == ' ') {
+ regname = '"';
+ } else {
+ regname = (char)c;
+ }
+ // Avoid free/alloc when the value is already right.
+ if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c) {
+ set_vim_var_string(VV_REG, &regname, 1);
+ }
+}
+
+/// Get or set v:exception. If "oldval" == NULL, return the current value.
+/// Otherwise, restore the value to "oldval" and return NULL.
+/// Must always be called in pairs to save and restore v:exception! Does not
+/// take care of memory allocations.
+char *v_exception(char *oldval)
+{
+ if (oldval == NULL) {
+ return vimvars[VV_EXCEPTION].vv_str;
+ }
+
+ vimvars[VV_EXCEPTION].vv_str = oldval;
+ return NULL;
+}
+
+/// Get or set v:throwpoint. If "oldval" == NULL, return the current value.
+/// Otherwise, restore the value to "oldval" and return NULL.
+/// Must always be called in pairs to save and restore v:throwpoint! Does not
+/// take care of memory allocations.
+char *v_throwpoint(char *oldval)
+{
+ if (oldval == NULL) {
+ return vimvars[VV_THROWPOINT].vv_str;
+ }
+
+ vimvars[VV_THROWPOINT].vv_str = oldval;
+ return NULL;
+}
+
+/// Set v:cmdarg.
+/// If "eap" != NULL, use "eap" to generate the value and return the old value.
+/// If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
+/// Must always be called in pairs!
+char *set_cmdarg(exarg_T *eap, char *oldarg)
+{
+ char *oldval = vimvars[VV_CMDARG].vv_str;
+ if (eap == NULL) {
+ xfree(oldval);
+ vimvars[VV_CMDARG].vv_str = oldarg;
+ return NULL;
+ }
+
+ size_t len = 0;
+ if (eap->force_bin == FORCE_BIN) {
+ len = 6;
+ } else if (eap->force_bin == FORCE_NOBIN) {
+ len = 8;
+ }
+
+ if (eap->read_edit) {
+ len += 7;
+ }
+
+ if (eap->force_ff != 0) {
+ len += 10; // " ++ff=unix"
+ }
+ if (eap->force_enc != 0) {
+ len += STRLEN(eap->cmd + eap->force_enc) + 7;
+ }
+ if (eap->bad_char != 0) {
+ len += 7 + 4; // " ++bad=" + "keep" or "drop"
+ }
+
+ const size_t newval_len = len + 1;
+ char *newval = xmalloc(newval_len);
+
+ if (eap->force_bin == FORCE_BIN) {
+ snprintf(newval, newval_len, " ++bin");
+ } else if (eap->force_bin == FORCE_NOBIN) {
+ snprintf(newval, newval_len, " ++nobin");
+ } else {
+ *newval = NUL;
+ }
+
+ if (eap->read_edit) {
+ STRCAT(newval, " ++edit");
+ }
+
+ if (eap->force_ff != 0) {
+ snprintf(newval + STRLEN(newval), newval_len, " ++ff=%s",
+ eap->force_ff == 'u' ? "unix" :
+ eap->force_ff == 'd' ? "dos" : "mac");
+ }
+ if (eap->force_enc != 0) {
+ snprintf(newval + STRLEN(newval), newval_len, " ++enc=%s",
+ eap->cmd + eap->force_enc);
+ }
+ if (eap->bad_char == BAD_KEEP) {
+ STRCPY(newval + STRLEN(newval), " ++bad=keep");
+ } else if (eap->bad_char == BAD_DROP) {
+ STRCPY(newval + STRLEN(newval), " ++bad=drop");
+ } else if (eap->bad_char != 0) {
+ snprintf(newval + STRLEN(newval), newval_len, " ++bad=%c",
+ eap->bad_char);
+ }
+ vimvars[VV_CMDARG].vv_str = newval;
+ return oldval;
+}
+
+/// Check if variable "name[len]" is a local variable or an argument.
+/// If so, "*eval_lavars_used" is set to true.
+static void check_vars(const char *name, size_t len)
+{
+ if (eval_lavars_used == NULL) {
+ return;
+ }
+
+ const char *varname;
+ hashtab_T *ht = find_var_ht(name, len, &varname);
+
+ if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht()) {
+ if (find_var(name, len, NULL, true) != NULL) {
+ *eval_lavars_used = true;
+ }
+ }
+}
+
+/// check if special v:lua value for calling lua functions
+bool is_luafunc(partial_T *partial)
+ FUNC_ATTR_PURE
+{
+ return partial == vvlua_partial;
+}
+
+/// check if special v:lua value for calling lua functions
+static bool tv_is_luafunc(typval_T *tv)
+{
+ return tv->v_type == VAR_PARTIAL && is_luafunc(tv->vval.v_partial);
+}
+
+/// Skips one character past the end of the name of a v:lua function.
+/// @param p Pointer to the char AFTER the "v:lua." prefix.
+/// @return Pointer to the char one past the end of the function's name.
+const char *skip_luafunc_name(const char *p)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ while (ASCII_ISALNUM(*p) || *p == '_' || *p == '-' || *p == '.' || *p == '\'') {
+ p++;
+ }
+ return p;
+}
+
+/// check the function name after "v:lua."
+int check_luafunc_name(const char *const str, const bool paren)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const char *const p = skip_luafunc_name(str);
+ if (*p != (paren ? '(' : NUL)) {
+ return 0;
+ } else {
+ return (int)(p - str);
+ }
+}
+
+/// Handle:
+/// - expr[expr], expr[expr:expr] subscript
+/// - ".name" lookup
+/// - function call with Funcref variable: func(expr)
+/// - method call: var->method()
+///
+/// Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
+///
+/// @param evaluate do more than finding the end
+/// @param verbose give error messages
+/// @param start_leader start of '!' and '-' prefixes
+/// @param end_leaderp end of '!' and '-' prefixes
+int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose,
+ const char *const start_leader, const char **const end_leaderp)
+{
+ int ret = OK;
+ dict_T *selfdict = NULL;
+ const char *lua_funcname = NULL;
+
+ if (tv_is_luafunc(rettv)) {
+ if (**arg != '.') {
+ tv_clear(rettv);
+ ret = FAIL;
+ } else {
+ (*arg)++;
+
+ lua_funcname = *arg;
+ const int len = check_luafunc_name(*arg, true);
+ if (len == 0) {
+ tv_clear(rettv);
+ ret = FAIL;
+ }
+ (*arg) += len;
+ }
+ }
+
+ // "." is ".name" lookup when we found a dict.
+ while (ret == OK
+ && (((**arg == '[' || (**arg == '.' && rettv->v_type == VAR_DICT)
+ || (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
+ && !ascii_iswhite(*(*arg - 1)))
+ || (**arg == '-' && (*arg)[1] == '>'))) {
+ if (**arg == '(') {
+ ret = call_func_rettv((char **)arg, rettv, evaluate, selfdict, NULL, lua_funcname);
+
+ // Stop the expression evaluation when immediately aborting on
+ // error, or when an interrupt occurred or an exception was thrown
+ // but not caught.
+ if (aborting()) {
+ if (ret == OK) {
+ tv_clear(rettv);
+ }
+ ret = FAIL;
+ }
+ tv_dict_unref(selfdict);
+ selfdict = NULL;
+ } else if (**arg == '-') {
+ // Expression "-1.0->method()" applies the leader "-" before
+ // applying ->.
+ if (evaluate && *end_leaderp > start_leader) {
+ ret = eval7_leader(rettv, (char *)start_leader, end_leaderp);
+ }
+ if (ret == OK) {
+ if ((*arg)[2] == '{') {
+ // expr->{lambda}()
+ ret = eval_lambda((char **)arg, rettv, evaluate, verbose);
+ } else {
+ // expr->name()
+ ret = eval_method((char **)arg, rettv, evaluate, verbose);
+ }
+ }
+ } else { // **arg == '[' || **arg == '.'
+ tv_dict_unref(selfdict);
+ if (rettv->v_type == VAR_DICT) {
+ selfdict = rettv->vval.v_dict;
+ if (selfdict != NULL) {
+ ++selfdict->dv_refcount;
+ }
+ } else {
+ selfdict = NULL;
+ }
+ if (eval_index((char **)arg, rettv, evaluate, verbose) == FAIL) {
+ tv_clear(rettv);
+ ret = FAIL;
+ }
+ }
+ }
+
+ // Turn "dict.Func" into a partial for "Func" bound to "dict".
+ if (selfdict != NULL && tv_is_func(*rettv)) {
+ set_selfdict(rettv, selfdict);
+ }
+
+ tv_dict_unref(selfdict);
+ return ret;
+}
+
+void set_selfdict(typval_T *const rettv, dict_T *const selfdict)
+{
+ // Don't do this when "dict.Func" is already a partial that was bound
+ // explicitly (pt_auto is false).
+ if (rettv->v_type == VAR_PARTIAL && !rettv->vval.v_partial->pt_auto
+ && rettv->vval.v_partial->pt_dict != NULL) {
+ return;
+ }
+ make_partial(selfdict, rettv);
+}
+
+/// Find variable "name" in the list of variables.
+/// Careful: "a:0" variables don't have a name.
+/// When "htp" is not NULL we are writing to the variable, set "htp" to the
+/// hashtab_T used.
+///
+/// @return a pointer to it if found, NULL if not found.
+dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **htp,
+ int no_autoload)
+{
+ const char *varname;
+ hashtab_T *const ht = find_var_ht(name, name_len, &varname);
+ if (htp != NULL) {
+ *htp = ht;
+ }
+ if (ht == NULL) {
+ return NULL;
+ }
+ dictitem_T *const ret = find_var_in_ht(ht, *name,
+ varname,
+ name_len - (size_t)(varname - name),
+ no_autoload || htp != NULL);
+ if (ret != NULL) {
+ return ret;
+ }
+
+ // Search in parent scope for lambda
+ return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL);
+}
+
+/// Find variable in hashtab.
+/// When "varname" is empty returns curwin/curtab/etc vars dictionary.
+///
+/// @param[in] ht Hashtab to find variable in.
+/// @param[in] htname Hashtab name (first character).
+/// @param[in] varname Variable name.
+/// @param[in] varname_len Variable name length.
+/// @param[in] no_autoload If true then autoload scripts will not be sourced
+/// if autoload variable was not found.
+///
+/// @return pointer to the dictionary item with the found variable or NULL if it
+/// was not found.
+dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const varname,
+ const size_t varname_len, int no_autoload)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ hashitem_T *hi;
+
+ if (varname_len == 0) {
+ // Must be something like "s:", otherwise "ht" would be NULL.
+ switch (htname) {
+ case 's':
+ return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
+ case 'g':
+ return (dictitem_T *)&globvars_var;
+ case 'v':
+ return (dictitem_T *)&vimvars_var;
+ case 'b':
+ return (dictitem_T *)&curbuf->b_bufvar;
+ case 'w':
+ return (dictitem_T *)&curwin->w_winvar;
+ case 't':
+ return (dictitem_T *)&curtab->tp_winvar;
+ case 'l':
+ return get_funccal_local_var();
+ case 'a':
+ return get_funccal_args_var();
+ }
+ return NULL;
+ }
+
+ hi = hash_find_len(ht, varname, varname_len);
+ if (HASHITEM_EMPTY(hi)) {
+ // For global variables we may try auto-loading the script. If it
+ // worked find the variable again. Don't auto-load a script if it was
+ // loaded already, otherwise it would be loaded every time when
+ // checking if a function name is a Funcref variable.
+ if (ht == &globvarht && !no_autoload) {
+ // Note: script_autoload() may make "hi" invalid. It must either
+ // be obtained again or not used.
+ if (!script_autoload(varname, varname_len, false) || aborting()) {
+ return NULL;
+ }
+ hi = hash_find_len(ht, varname, varname_len);
+ }
+ if (HASHITEM_EMPTY(hi)) {
+ return NULL;
+ }
+ }
+ return TV_DICT_HI2DI(hi);
+}
+
+/// Finds the dict (g:, l:, s:, …) and hashtable used for a variable.
+///
+/// Assigns SID if s: scope is accessed from Lua or anonymous Vimscript. #15994
+///
+/// @param[in] name Variable name, possibly with scope prefix.
+/// @param[in] name_len Variable name length.
+/// @param[out] varname Will be set to the start of the name without scope
+/// prefix.
+/// @param[out] d Scope dictionary.
+///
+/// @return Scope hashtab, NULL if name is not valid.
+hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
+ dict_T **d)
+{
+ hashitem_T *hi;
+ funccall_T *funccal = get_funccal();
+ *d = NULL;
+
+ if (name_len == 0) {
+ return NULL;
+ }
+ 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 #.
+ return NULL;
+ }
+ *varname = name;
+
+ // "version" is "v:version" in all scopes
+ hi = hash_find_len(&compat_hashtab, name, name_len);
+ if (!HASHITEM_EMPTY(hi)) {
+ return &compat_hashtab;
+ }
+
+ if (funccal == NULL) { // global variable
+ *d = &globvardict;
+ } else { // l: variable
+ *d = &funccal->l_vars;
+ }
+ goto end;
+ }
+
+ *varname = name + 2;
+ if (*name == 'g') { // global variable
+ *d = &globvardict;
+ } else if (name_len > 2
+ && (memchr(name + 2, ':', name_len - 2) != NULL
+ || memchr(name + 2, AUTOLOAD_CHAR, name_len - 2) != NULL)) {
+ // There must be no ':' or '#' in the rest of the name if g: was not used
+ return NULL;
+ }
+
+ if (*name == 'b') { // buffer variable
+ *d = curbuf->b_vars;
+ } else if (*name == 'w') { // window variable
+ *d = curwin->w_vars;
+ } else if (*name == 't') { // tab page variable
+ *d = curtab->tp_vars;
+ } else if (*name == 'v') { // v: variable
+ *d = &vimvardict;
+ } else if (*name == 'a' && funccal != NULL) { // function argument
+ *d = &funccal->l_avars;
+ } else if (*name == 'l' && funccal != NULL) { // local variable
+ *d = &funccal->l_vars;
+ } else if (*name == 's' // script variable
+ && (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR
+ || current_sctx.sc_sid == SID_LUA)
+ && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ // For anonymous scripts without a script item, create one now so script vars can be used
+ if (current_sctx.sc_sid == SID_LUA) {
+ // try to resolve lua filename & line no so it can be shown in lastset messages.
+ nlua_set_sctx(&current_sctx);
+ if (current_sctx.sc_sid != SID_LUA) {
+ // Great we have valid location. Now here this out we'll create a new
+ // script context with the name and lineno of this one. why ?
+ // for behavioral consistency. With this different anonymous exec from
+ // same file can't access each others script local stuff. We need to do
+ // this all other cases except this will act like that otherwise.
+ const LastSet last_set = (LastSet){
+ .script_ctx = current_sctx,
+ .channel_id = LUA_INTERNAL_CALL,
+ };
+ bool should_free;
+ // should_free is ignored as script_sctx will be resolved to a fnmae
+ // & new_script_item will consume it.
+ char *sc_name = (char *)get_scriptname(last_set, &should_free);
+ new_script_item(sc_name, &current_sctx.sc_sid);
+ }
+ }
+ if (current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) {
+ // Create SID if s: scope is accessed from Lua or anon Vimscript. #15994
+ new_script_item(NULL, &current_sctx.sc_sid);
+ }
+ *d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
+ }
+
+end:
+ return *d ? &(*d)->dv_hashtab : NULL;
+}
+
+/// Find the hashtable used for a variable
+///
+/// @param[in] name Variable name, possibly with scope prefix.
+/// @param[in] name_len Variable name length.
+/// @param[out] varname Will be set to the start of the name without scope
+/// prefix.
+///
+/// @return Scope hashtab, NULL if name is not valid.
+hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **varname)
+{
+ dict_T *d;
+ return find_var_ht_dict(name, name_len, varname, &d);
+}
+
+/// Allocate a new hashtab for a sourced script. It will be used while
+/// sourcing this script and when executing functions defined in the script.
+void new_script_vars(scid_T id)
+{
+ hashtab_T *ht;
+ scriptvar_T *sv;
+
+ ga_grow(&ga_scripts, id - ga_scripts.ga_len);
+ {
+ /* Re-allocating ga_data means that an ht_array pointing to
+ * ht_smallarray becomes invalid. We can recognize this: ht_mask is
+ * at its init value. Also reset "v_dict", it's always the same. */
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
+ ht = &SCRIPT_VARS(i);
+ if (ht->ht_mask == HT_INIT_SIZE - 1) {
+ ht->ht_array = ht->ht_smallarray;
+ }
+ sv = SCRIPT_SV(i);
+ sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
+ }
+
+ while (ga_scripts.ga_len < id) {
+ sv = SCRIPT_SV(ga_scripts.ga_len + 1) = xcalloc(1, sizeof(scriptvar_T));
+ init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
+ ++ga_scripts.ga_len;
+ }
+ }
+}
+
+/// Initialize dictionary "dict" as a scope and set variable "dict_var" to
+/// point to it.
+void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, ScopeType scope)
+{
+ hash_init(&dict->dv_hashtab);
+ dict->dv_lock = VAR_UNLOCKED;
+ dict->dv_scope = scope;
+ dict->dv_refcount = DO_NOT_FREE_CNT;
+ dict->dv_copyID = 0;
+ dict_var->di_tv.vval.v_dict = dict;
+ dict_var->di_tv.v_type = VAR_DICT;
+ dict_var->di_tv.v_lock = VAR_FIXED;
+ dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ dict_var->di_key[0] = NUL;
+ QUEUE_INIT(&dict->watchers);
+}
+
+/// Unreference a dictionary initialized by init_var_dict().
+void unref_var_dict(dict_T *dict)
+{
+ /* Now the dict needs to be freed if no one else is using it, go back to
+ * normal reference counting. */
+ dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
+ tv_dict_unref(dict);
+}
+
+/// Make a copy of an item
+///
+/// Lists and Dictionaries are also copied.
+///
+/// @param[in] conv If not NULL, convert all copied strings.
+/// @param[in] from Value to copy.
+/// @param[out] to Location where to copy to.
+/// @param[in] deep If true, use copy the container and all of the contained
+/// containers (nested).
+/// @param[in] copyID If non-zero then when container is referenced more then
+/// once then copy of it that was already done is used. E.g.
+/// when copying list `list = [list2, list2]` (`list[0] is
+/// list[1]`) var_item_copy with zero copyID will emit
+/// a copy with (`copy[0] isnot copy[1]`), with non-zero it
+/// will emit a copy with (`copy[0] is copy[1]`) like in the
+/// original list. Not used when deep is false.
+int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *const to,
+ const bool deep, const int copyID)
+ FUNC_ATTR_NONNULL_ARG(2, 3)
+{
+ static int recurse = 0;
+ int ret = OK;
+
+ if (recurse >= DICT_MAXNEST) {
+ emsg(_("E698: variable nested too deep for making a copy"));
+ return FAIL;
+ }
+ ++recurse;
+
+ switch (from->v_type) {
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ tv_copy(from, to);
+ break;
+ case VAR_STRING:
+ if (conv == NULL || conv->vc_type == CONV_NONE
+ || from->vval.v_string == NULL) {
+ tv_copy(from, to);
+ } else {
+ to->v_type = VAR_STRING;
+ to->v_lock = VAR_UNLOCKED;
+ if ((to->vval.v_string = (char *)string_convert((vimconv_T *)conv,
+ (char_u *)from->vval.v_string,
+ NULL))
+ == NULL) {
+ to->vval.v_string = xstrdup(from->vval.v_string);
+ }
+ }
+ break;
+ case VAR_LIST:
+ to->v_type = VAR_LIST;
+ to->v_lock = VAR_UNLOCKED;
+ if (from->vval.v_list == NULL) {
+ to->vval.v_list = NULL;
+ } else if (copyID != 0 && tv_list_copyid(from->vval.v_list) == copyID) {
+ // Use the copy made earlier.
+ to->vval.v_list = tv_list_latest_copy(from->vval.v_list);
+ tv_list_ref(to->vval.v_list);
+ } else {
+ to->vval.v_list = tv_list_copy(conv, from->vval.v_list, deep, copyID);
+ }
+ if (to->vval.v_list == NULL && from->vval.v_list != NULL) {
+ ret = FAIL;
+ }
+ break;
+ case VAR_BLOB:
+ tv_blob_copy(from, to);
+ break;
+ case VAR_DICT:
+ to->v_type = VAR_DICT;
+ to->v_lock = VAR_UNLOCKED;
+ if (from->vval.v_dict == NULL) {
+ to->vval.v_dict = NULL;
+ } else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) {
+ // use the copy made earlier
+ to->vval.v_dict = from->vval.v_dict->dv_copydict;
+ ++to->vval.v_dict->dv_refcount;
+ } else {
+ to->vval.v_dict = tv_dict_copy(conv, from->vval.v_dict, deep, copyID);
+ }
+ if (to->vval.v_dict == NULL && from->vval.v_dict != NULL) {
+ ret = FAIL;
+ }
+ break;
+ case VAR_UNKNOWN:
+ internal_error("var_item_copy(UNKNOWN)");
+ ret = FAIL;
+ }
+ --recurse;
+ return ret;
+}
+
+/// ":echo expr1 ..." print each argument separated with a space, add a
+/// newline at the end.
+/// ":echon expr1 ..." print each argument plain.
+void ex_echo(exarg_T *eap)
+{
+ char *arg = eap->arg;
+ typval_T rettv;
+ bool atstart = true;
+ bool need_clear = true;
+ const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
+
+ if (eap->skip) {
+ ++emsg_skip;
+ }
+ while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int) {
+ // If eval1() causes an error message the text from the command may
+ // still need to be cleared. E.g., "echo 22,44".
+ need_clr_eos = true;
+
+ {
+ char *p = arg;
+ if (eval1(&arg, &rettv, !eap->skip) == FAIL) {
+ // Report the invalid expression unless the expression evaluation
+ // has been cancelled due to an aborting error, an interrupt, or an
+ // exception.
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before) {
+ semsg(_(e_invexpr2), p);
+ }
+ need_clr_eos = false;
+ break;
+ }
+ need_clr_eos = false;
+ }
+
+ if (!eap->skip) {
+ if (atstart) {
+ atstart = false;
+ // Call msg_start() after eval1(), evaluating the expression
+ // may cause a message to appear.
+ if (eap->cmdidx == CMD_echo) {
+ // Mark the saved text as finishing the line, so that what
+ // follows is displayed on a new line when scrolling back
+ // at the more prompt.
+ msg_sb_eol();
+ msg_start();
+ }
+ } else if (eap->cmdidx == CMD_echo) {
+ msg_puts_attr(" ", echo_attr);
+ }
+ char *tofree = encode_tv2echo(&rettv, NULL);
+ if (*tofree != NUL) {
+ msg_ext_set_kind("echo");
+ msg_multiline_attr(tofree, echo_attr, true, &need_clear);
+ }
+ xfree(tofree);
+ }
+ tv_clear(&rettv);
+ arg = skipwhite(arg);
+ }
+ eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+
+ if (eap->skip) {
+ emsg_skip--;
+ } else {
+ // remove text that may still be there from the command
+ if (need_clear) {
+ msg_clr_eos();
+ }
+ if (eap->cmdidx == CMD_echo) {
+ msg_end();
+ }
+ }
+}
+
+/// ":echohl {name}".
+void ex_echohl(exarg_T *eap)
+{
+ echo_attr = syn_name2attr((char_u *)eap->arg);
+}
+
+/// ":execute expr1 ..." execute the result of an expression.
+/// ":echomsg expr1 ..." Print a message
+/// ":echoerr expr1 ..." Print an error
+/// Each gets spaces around each argument and a newline at the end for
+/// echo commands
+void ex_execute(exarg_T *eap)
+{
+ char *arg = eap->arg;
+ typval_T rettv;
+ int ret = OK;
+ garray_T ga;
+ int save_did_emsg;
+
+ ga_init(&ga, 1, 80);
+
+ if (eap->skip) {
+ ++emsg_skip;
+ }
+ while (*arg != NUL && *arg != '|' && *arg != '\n') {
+ ret = eval1_emsg(&arg, &rettv, !eap->skip);
+ if (ret == FAIL) {
+ break;
+ }
+
+ if (!eap->skip) {
+ const char *const argstr = eap->cmdidx == CMD_execute
+ ? tv_get_string(&rettv)
+ : rettv.v_type == VAR_STRING
+ ? encode_tv2echo(&rettv, NULL)
+ : encode_tv2string(&rettv, NULL);
+ const size_t len = strlen(argstr);
+ ga_grow(&ga, (int)len + 2);
+ if (!GA_EMPTY(&ga)) {
+ ((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
+ }
+ memcpy((char_u *)(ga.ga_data) + ga.ga_len, argstr, len + 1);
+ if (eap->cmdidx != CMD_execute) {
+ xfree((void *)argstr);
+ }
+ ga.ga_len += (int)len;
+ }
+
+ tv_clear(&rettv);
+ arg = skipwhite(arg);
+ }
+
+ if (ret != FAIL && ga.ga_data != NULL) {
+ if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr) {
+ // Mark the already saved text as finishing the line, so that what
+ // follows is displayed on a new line when scrolling back at the
+ // more prompt.
+ msg_sb_eol();
+ }
+
+ if (eap->cmdidx == CMD_echomsg) {
+ msg_ext_set_kind("echomsg");
+ msg_attr(ga.ga_data, echo_attr);
+ ui_flush();
+ } else if (eap->cmdidx == CMD_echoerr) {
+ // We don't want to abort following commands, restore did_emsg.
+ save_did_emsg = did_emsg;
+ msg_ext_set_kind("echoerr");
+ emsg(ga.ga_data);
+ if (!force_abort) {
+ did_emsg = save_did_emsg;
+ }
+ } else if (eap->cmdidx == CMD_execute) {
+ do_cmdline(ga.ga_data, eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ }
+ }
+
+ ga_clear(&ga);
+
+ if (eap->skip) {
+ --emsg_skip;
+ }
+
+ eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+}
+
+/// Skip over the name of an option: "&option", "&g:option" or "&l:option".
+///
+/// @param arg points to the "&" or '+' when called, to "option" when returning.
+///
+/// @return NULL when no option name found. Otherwise pointer to the char
+/// after the option name.
+const char *find_option_end(const char **const arg, int *const opt_flags)
+{
+ const char *p = *arg;
+
+ ++p;
+ if (*p == 'g' && p[1] == ':') {
+ *opt_flags = OPT_GLOBAL;
+ p += 2;
+ } else if (*p == 'l' && p[1] == ':') {
+ *opt_flags = OPT_LOCAL;
+ p += 2;
+ } else {
+ *opt_flags = 0;
+ }
+
+ if (!ASCII_ISALPHA(*p)) {
+ return NULL;
+ }
+ *arg = p;
+
+ if (p[0] == 't' && p[1] == '_' && p[2] != NUL && p[3] != NUL) {
+ p += 4; // t_xx/termcap option
+ } else {
+ while (ASCII_ISALPHA(*p)) {
+ p++;
+ }
+ }
+ return p;
+}
+
+/// Start profiling function "fp".
+void func_do_profile(ufunc_T *fp)
+{
+ int len = fp->uf_lines.ga_len;
+
+ if (!fp->uf_prof_initialized) {
+ if (len == 0) {
+ len = 1; // avoid getting error for allocating zero bytes
+ }
+ fp->uf_tm_count = 0;
+ fp->uf_tm_self = profile_zero();
+ fp->uf_tm_total = profile_zero();
+
+ if (fp->uf_tml_count == NULL) {
+ fp->uf_tml_count = xcalloc((size_t)len, sizeof(int));
+ }
+
+ if (fp->uf_tml_total == NULL) {
+ fp->uf_tml_total = xcalloc((size_t)len, sizeof(proftime_T));
+ }
+
+ if (fp->uf_tml_self == NULL) {
+ fp->uf_tml_self = xcalloc((size_t)len, sizeof(proftime_T));
+ }
+
+ fp->uf_tml_idx = -1;
+ fp->uf_prof_initialized = true;
+ }
+
+ fp->uf_profiling = TRUE;
+}
+
+/// Dump the profiling results for all functions in file "fd".
+void func_dump_profile(FILE *fd)
+{
+ hashitem_T *hi;
+ int todo;
+ ufunc_T *fp;
+ ufunc_T **sorttab;
+ int st_len = 0;
+
+ todo = (int)func_hashtab.ht_used;
+ if (todo == 0) {
+ return; // nothing to dump
+ }
+
+ sorttab = xmalloc(sizeof(ufunc_T *) * (size_t)todo);
+
+ for (hi = func_hashtab.ht_array; todo > 0; ++hi) {
+ if (!HASHITEM_EMPTY(hi)) {
+ --todo;
+ fp = HI2UF(hi);
+ if (fp->uf_prof_initialized) {
+ sorttab[st_len++] = fp;
+
+ if (fp->uf_name[0] == K_SPECIAL) {
+ fprintf(fd, "FUNCTION <SNR>%s()\n", fp->uf_name + 3);
+ } else {
+ fprintf(fd, "FUNCTION %s()\n", fp->uf_name);
+ }
+ if (fp->uf_script_ctx.sc_sid != 0) {
+ bool should_free;
+ const LastSet last_set = (LastSet){
+ .script_ctx = fp->uf_script_ctx,
+ .channel_id = 0,
+ };
+ char *p = (char *)get_scriptname(last_set, &should_free);
+ fprintf(fd, " Defined: %s:%" PRIdLINENR "\n",
+ p, fp->uf_script_ctx.sc_lnum);
+ if (should_free) {
+ xfree(p);
+ }
+ }
+ if (fp->uf_tm_count == 1) {
+ fprintf(fd, "Called 1 time\n");
+ } else {
+ fprintf(fd, "Called %d times\n", fp->uf_tm_count);
+ }
+ fprintf(fd, "Total time: %s\n", profile_msg(fp->uf_tm_total));
+ fprintf(fd, " Self time: %s\n", profile_msg(fp->uf_tm_self));
+ fprintf(fd, "\n");
+ fprintf(fd, "count total (s) self (s)\n");
+
+ for (int i = 0; i < fp->uf_lines.ga_len; ++i) {
+ if (FUNCLINE(fp, i) == NULL) {
+ continue;
+ }
+ prof_func_line(fd, fp->uf_tml_count[i],
+ &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE);
+ fprintf(fd, "%s\n", FUNCLINE(fp, i));
+ }
+ fprintf(fd, "\n");
+ }
+ }
+ }
+
+ if (st_len > 0) {
+ qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
+ prof_total_cmp);
+ prof_sort_list(fd, sorttab, st_len, "TOTAL", FALSE);
+ qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
+ prof_self_cmp);
+ prof_sort_list(fd, sorttab, st_len, "SELF", TRUE);
+ }
+
+ xfree(sorttab);
+}
+
+/// @param prefer_self when equal print only self time
+static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self)
+{
+ int i;
+ ufunc_T *fp;
+
+ fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title);
+ fprintf(fd, "count total (s) self (s) function\n");
+ for (i = 0; i < 20 && i < st_len; ++i) {
+ fp = sorttab[i];
+ prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self,
+ prefer_self);
+ if (fp->uf_name[0] == K_SPECIAL) {
+ fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3);
+ } else {
+ fprintf(fd, " %s()\n", fp->uf_name);
+ }
+ }
+ fprintf(fd, "\n");
+}
+
+/// Print the count and times for one function or function line.
+///
+/// @param prefer_self when equal print only self time
+static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self,
+ int prefer_self)
+{
+ if (count > 0) {
+ fprintf(fd, "%5d ", count);
+ if (prefer_self && profile_equal(*total, *self)) {
+ fprintf(fd, " ");
+ } else {
+ fprintf(fd, "%s ", profile_msg(*total));
+ }
+ if (!prefer_self && profile_equal(*total, *self)) {
+ fprintf(fd, " ");
+ } else {
+ fprintf(fd, "%s ", profile_msg(*self));
+ }
+ } else {
+ fprintf(fd, " ");
+ }
+}
+
+/// Compare function for total time sorting.
+static int prof_total_cmp(const void *s1, const void *s2)
+{
+ ufunc_T *p1 = *(ufunc_T **)s1;
+ ufunc_T *p2 = *(ufunc_T **)s2;
+ return profile_cmp(p1->uf_tm_total, p2->uf_tm_total);
+}
+
+/// Compare function for self time sorting.
+static int prof_self_cmp(const void *s1, const void *s2)
+{
+ ufunc_T *p1 = *(ufunc_T **)s1;
+ ufunc_T *p2 = *(ufunc_T **)s2;
+ return profile_cmp(p1->uf_tm_self, p2->uf_tm_self);
+}
+
+/// Return the autoload script name for a function or variable name
+/// Caller must make sure that "name" contains AUTOLOAD_CHAR.
+///
+/// @param[in] name Variable/function name.
+/// @param[in] name_len Name length.
+///
+/// @return [allocated] autoload script name.
+char *autoload_name(const char *const name, const size_t name_len)
+ FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Get the script file name: replace '#' with '/', append ".vim".
+ char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim"));
+ memcpy(scriptname, "autoload/", sizeof("autoload/") - 1);
+ memcpy(scriptname + sizeof("autoload/") - 1, name, name_len);
+ size_t auchar_idx = 0;
+ for (size_t i = sizeof("autoload/") - 1;
+ i - sizeof("autoload/") + 1 < name_len;
+ i++) {
+ if (scriptname[i] == AUTOLOAD_CHAR) {
+ scriptname[i] = '/';
+ auchar_idx = i;
+ }
+ }
+ memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim"));
+
+ return scriptname;
+}
+
+/// If name has a package name try autoloading the script for it
+///
+/// @param[in] name Variable/function name.
+/// @param[in] name_len Name length.
+/// @param[in] reload If true, load script again when already loaded.
+///
+/// @return true if a package was loaded.
+bool script_autoload(const char *const name, const size_t name_len, const bool reload)
+{
+ // If there is no '#' after name[0] there is no package name.
+ const char *p = memchr(name, AUTOLOAD_CHAR, name_len);
+ if (p == NULL || p == name) {
+ return false;
+ }
+
+ bool ret = false;
+ char *tofree = autoload_name(name, name_len);
+ char *scriptname = tofree;
+
+ // Find the name in the list of previously loaded package names. Skip
+ // "autoload/", it's always the same.
+ int i = 0;
+ for (; i < ga_loaded.ga_len; i++) {
+ if (STRCMP(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) {
+ break;
+ }
+ }
+ if (!reload && i < ga_loaded.ga_len) {
+ ret = false; // Was loaded already.
+ } else {
+ // Remember the name if it wasn't loaded already.
+ if (i == ga_loaded.ga_len) {
+ GA_APPEND(char *, &ga_loaded, scriptname);
+ tofree = NULL;
+ }
+
+ // Try loading the package from $VIMRUNTIME/autoload/<name>.vim
+ if (source_runtime(scriptname, 0) == OK) {
+ ret = true;
+ }
+ }
+
+ xfree(tofree);
+ return ret;
+}
+
+/// Called when starting to read a function line.
+/// "sourcing_lnum" must be correct!
+/// When skipping lines it may not actually be executed, but we won't find out
+/// until later and we need to store the time now.
+void func_line_start(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && sourcing_lnum >= 1
+ && sourcing_lnum <= fp->uf_lines.ga_len) {
+ fp->uf_tml_idx = sourcing_lnum - 1;
+ // Skip continuation lines.
+ while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) {
+ fp->uf_tml_idx--;
+ }
+ fp->uf_tml_execed = false;
+ fp->uf_tml_start = profile_start();
+ fp->uf_tml_children = profile_zero();
+ fp->uf_tml_wait = profile_get_wait();
+ }
+}
+
+/// Called when actually executing a function line.
+void func_line_exec(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && fp->uf_tml_idx >= 0) {
+ fp->uf_tml_execed = TRUE;
+ }
+}
+
+/// Called when done with a function line.
+void func_line_end(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && fp->uf_tml_idx >= 0) {
+ if (fp->uf_tml_execed) {
+ ++fp->uf_tml_count[fp->uf_tml_idx];
+ fp->uf_tml_start = profile_end(fp->uf_tml_start);
+ fp->uf_tml_start = profile_sub_wait(fp->uf_tml_wait, fp->uf_tml_start);
+ fp->uf_tml_total[fp->uf_tml_idx] =
+ profile_add(fp->uf_tml_total[fp->uf_tml_idx], fp->uf_tml_start);
+ fp->uf_tml_self[fp->uf_tml_idx] =
+ profile_self(fp->uf_tml_self[fp->uf_tml_idx], fp->uf_tml_start,
+ fp->uf_tml_children);
+ }
+ fp->uf_tml_idx = -1;
+ }
+}
+
+static var_flavour_T var_flavour(char *varname)
+ FUNC_ATTR_PURE
+{
+ char *p = varname;
+
+ if (ASCII_ISUPPER(*p)) {
+ while (*(++p)) {
+ if (ASCII_ISLOWER(*p)) {
+ return VAR_FLAVOUR_SESSION;
+ }
+ }
+ return VAR_FLAVOUR_SHADA;
+ } else {
+ return VAR_FLAVOUR_DEFAULT;
+ }
+}
+
+/// Iterate over global variables
+///
+/// @warning No modifications to global variable dictionary must be performed
+/// while iteration is in progress.
+///
+/// @param[in] iter Iterator. Pass NULL to start iteration.
+/// @param[out] name Variable name.
+/// @param[out] rettv Variable value.
+///
+/// @return Pointer that needs to be passed to next `var_shada_iter` invocation
+/// or NULL to indicate that iteration is over.
+const void *var_shada_iter(const void *const iter, const char **const name, typval_T *rettv,
+ var_flavour_T flavour)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
+{
+ const hashitem_T *hi;
+ const hashitem_T *hifirst = globvarht.ht_array;
+ const size_t hinum = (size_t)globvarht.ht_mask + 1;
+ *name = NULL;
+ if (iter == NULL) {
+ hi = globvarht.ht_array;
+ while ((size_t)(hi - hifirst) < hinum
+ && (HASHITEM_EMPTY(hi)
+ || !(var_flavour((char *)hi->hi_key) & flavour))) {
+ hi++;
+ }
+ if ((size_t)(hi - hifirst) == hinum) {
+ return NULL;
+ }
+ } else {
+ hi = (const hashitem_T *)iter;
+ }
+ *name = (char *)TV_DICT_HI2DI(hi)->di_key;
+ tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
+ while ((size_t)(++hi - hifirst) < hinum) {
+ if (!HASHITEM_EMPTY(hi) && (var_flavour((char *)hi->hi_key) & flavour)) {
+ return hi;
+ }
+ }
+ return NULL;
+}
+
+void var_set_global(const char *const name, typval_T vartv)
+{
+ funccal_entry_T funccall_entry;
+
+ save_funccal(&funccall_entry);
+ set_var(name, strlen(name), &vartv, false);
+ restore_funccal();
+}
+
+int store_session_globals(FILE *fd)
+{
+ TV_DICT_ITER(&globvardict, this_var, {
+ if ((this_var->di_tv.v_type == VAR_NUMBER
+ || this_var->di_tv.v_type == VAR_STRING)
+ && var_flavour((char *)this_var->di_key) == VAR_FLAVOUR_SESSION) {
+ // Escape special characters with a backslash. Turn a LF and
+ // CR into \n and \r.
+ char *const p = (char *)vim_strsave_escaped((const char_u *)tv_get_string(&this_var->di_tv),
+ (const char_u *)"\\\"\n\r");
+ for (char *t = p; *t != NUL; t++) {
+ if (*t == '\n') {
+ *t = 'n';
+ } else if (*t == '\r') {
+ *t = 'r';
+ }
+ }
+ if ((fprintf(fd, "let %s = %c%s%c",
+ this_var->di_key,
+ ((this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' '),
+ p,
+ ((this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' ')) < 0)
+ || put_eol(fd) == FAIL) {
+ xfree(p);
+ return FAIL;
+ }
+ xfree(p);
+ } else if (this_var->di_tv.v_type == VAR_FLOAT
+ && var_flavour((char *)this_var->di_key) == VAR_FLAVOUR_SESSION) {
+ float_T f = this_var->di_tv.vval.v_float;
+ int sign = ' ';
+
+ if (f < 0) {
+ f = -f;
+ sign = '-';
+ }
+ if ((fprintf(fd, "let %s = %c%f", this_var->di_key, sign, f) < 0)
+ || put_eol(fd) == FAIL) {
+ return FAIL;
+ }
+ }
+ });
+ return OK;
+}
+
+/// Display script name where an item was last set.
+/// Should only be invoked when 'verbose' is non-zero.
+void last_set_msg(sctx_T script_ctx)
+{
+ const LastSet last_set = (LastSet){
+ .script_ctx = script_ctx,
+ .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_ctx.sc_sid != 0) {
+ bool should_free;
+ char *p = (char *)get_scriptname(last_set, &should_free);
+ verbose_enter();
+ msg_puts(_("\n\tLast set from "));
+ msg_puts(p);
+ if (last_set.script_ctx.sc_lnum > 0) {
+ msg_puts(_(line_msg));
+ msg_outnum((long)last_set.script_ctx.sc_lnum);
+ }
+ if (should_free) {
+ xfree(p);
+ }
+ verbose_leave();
+ }
+}
+
+// reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
+// v:option_type, and v:option_command.
+void reset_v_option_vars(void)
+{
+ set_vim_var_string(VV_OPTION_NEW, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
+ set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
+}
+
+/// Adjust a filename, according to a string of modifiers.
+/// *fnamep must be NUL terminated when called. When returning, the length is
+/// determined by *fnamelen.
+/// Returns VALID_ flags or -1 for failure.
+/// When there is an error, *fnamep is set to NULL.
+///
+/// @param src string with modifiers
+/// @param tilde_file "~" is a file name, not $HOME
+/// @param usedlen characters after src that are used
+/// @param fnamep file name so far
+/// @param bufp buffer for allocated file name or NULL
+/// @param fnamelen length of fnamep
+int modify_fname(char *src, bool tilde_file, size_t *usedlen, char **fnamep, char **bufp,
+ size_t *fnamelen)
+{
+ int valid = 0;
+ char *tail;
+ char *s, *p, *pbuf;
+ char dirname[MAXPATHL];
+ int c;
+ bool has_fullname = false;
+ bool has_homerelative = false;
+
+repeat:
+ // ":p" - full path/file_name
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') {
+ has_fullname = true;
+
+ valid |= VALID_PATH;
+ *usedlen += 2;
+
+ // Expand "~/path" for all systems and "~user/path" for Unix
+ if ((*fnamep)[0] == '~'
+#if !defined(UNIX)
+ && ((*fnamep)[1] == '/'
+# ifdef BACKSLASH_IN_FILENAME
+ || (*fnamep)[1] == '\\'
+# endif
+ || (*fnamep)[1] == NUL)
+#endif
+ && !(tilde_file && (*fnamep)[1] == NUL)) {
+ *fnamep = expand_env_save(*fnamep);
+ xfree(*bufp); // free any allocated file name
+ *bufp = *fnamep;
+ if (*fnamep == NULL) {
+ return -1;
+ }
+ }
+
+ // When "/." or "/.." is used: force expansion to get rid of it.
+ for (p = *fnamep; *p != NUL; MB_PTR_ADV(p)) {
+ if (vim_ispathsep(*p)
+ && p[1] == '.'
+ && (p[2] == NUL
+ || vim_ispathsep(p[2])
+ || (p[2] == '.'
+ && (p[3] == NUL || vim_ispathsep(p[3]))))) {
+ break;
+ }
+ }
+
+ // FullName_save() is slow, don't use it when not needed.
+ if (*p != NUL || !vim_isAbsName((char_u *)(*fnamep))) {
+ *fnamep = FullName_save((*fnamep), *p != NUL);
+ xfree(*bufp); // free any allocated file name
+ *bufp = *fnamep;
+ if (*fnamep == NULL) {
+ return -1;
+ }
+ }
+
+ // Append a path separator to a directory.
+ if (os_isdir((char_u *)(*fnamep))) {
+ // Make room for one or two extra characters.
+ *fnamep = xstrnsave(*fnamep, STRLEN(*fnamep) + 2);
+ xfree(*bufp); // free any allocated file name
+ *bufp = *fnamep;
+ add_pathsep(*fnamep);
+ }
+ }
+
+ // ":." - path relative to the current directory
+ // ":~" - path relative to the home directory
+ // ":8" - shortname path - postponed till after
+ while (src[*usedlen] == ':'
+ && ((c = (char_u)src[*usedlen + 1]) == '.' || c == '~' || c == '8')) {
+ *usedlen += 2;
+ if (c == '8') {
+ continue;
+ }
+ pbuf = NULL;
+ // Need full path first (use expand_env() to remove a "~/")
+ if (!has_fullname && !has_homerelative) {
+ if (**fnamep == '~') {
+ p = pbuf = expand_env_save(*fnamep);
+ } else {
+ p = pbuf = FullName_save(*fnamep, false);
+ }
+ } else {
+ p = *fnamep;
+ }
+
+ has_fullname = false;
+
+ if (p != NULL) {
+ if (c == '.') {
+ os_dirname((char_u *)dirname, MAXPATHL);
+ if (has_homerelative) {
+ s = xstrdup(dirname);
+ home_replace(NULL, s, dirname, MAXPATHL, true);
+ xfree(s);
+ }
+ size_t namelen = STRLEN(dirname);
+
+ // Do not call shorten_fname() here since it removes the prefix
+ // even though the path does not have a prefix.
+ if (FNAMENCMP(p, dirname, namelen) == 0) {
+ p += namelen;
+ if (vim_ispathsep(*p)) {
+ while (*p && vim_ispathsep(*p)) {
+ p++;
+ }
+ *fnamep = p;
+ if (pbuf != NULL) {
+ // free any allocated file name
+ xfree(*bufp);
+ *bufp = pbuf;
+ pbuf = NULL;
+ }
+ }
+ }
+ } else {
+ home_replace(NULL, p, dirname, MAXPATHL, true);
+ // Only replace it when it starts with '~'
+ if (*dirname == '~') {
+ s = xstrdup(dirname);
+ *fnamep = s;
+ xfree(*bufp);
+ *bufp = s;
+ has_homerelative = true;
+ }
+ }
+ xfree(pbuf);
+ }
+ }
+
+ tail = path_tail(*fnamep);
+ *fnamelen = STRLEN(*fnamep);
+
+ // ":h" - head, remove "/file_name", can be repeated
+ // Don't remove the first "/" or "c:\"
+ while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') {
+ valid |= VALID_HEAD;
+ *usedlen += 2;
+ s = (char *)get_past_head((char_u *)(*fnamep));
+ while (tail > s && after_pathsep(s, tail)) {
+ MB_PTR_BACK(*fnamep, tail);
+ }
+ *fnamelen = (size_t)(tail - *fnamep);
+ if (*fnamelen == 0) {
+ // Result is empty. Turn it into "." to make ":cd %:h" work.
+ xfree(*bufp);
+ *bufp = *fnamep = tail = xstrdup(".");
+ *fnamelen = 1;
+ } else {
+ while (tail > s && !after_pathsep(s, tail)) {
+ MB_PTR_BACK(*fnamep, tail);
+ }
+ }
+ }
+
+ // ":8" - shortname
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == '8') {
+ *usedlen += 2;
+ }
+
+ // ":t" - tail, just the basename
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 't') {
+ *usedlen += 2;
+ *fnamelen -= (size_t)(tail - *fnamep);
+ *fnamep = tail;
+ }
+
+ // ":e" - extension, can be repeated
+ // ":r" - root, without extension, can be repeated
+ while (src[*usedlen] == ':'
+ && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r')) {
+ /* find a '.' in the tail:
+ * - for second :e: before the current fname
+ * - otherwise: The last '.'
+ */
+ const bool is_second_e = *fnamep > tail;
+ if (src[*usedlen + 1] == 'e' && is_second_e) {
+ s = (*fnamep) - 2;
+ } else {
+ s = (*fnamep) + *fnamelen - 1;
+ }
+
+ for (; s > tail; s--) {
+ if (s[0] == '.') {
+ break;
+ }
+ }
+ if (src[*usedlen + 1] == 'e') {
+ if (s > tail || (0 && is_second_e && s == tail)) {
+ // we stopped at a '.' (so anchor to &'.' + 1)
+ char *newstart = s + 1;
+ size_t distance_stepped_back = (size_t)(*fnamep - newstart);
+ *fnamelen += distance_stepped_back;
+ *fnamep = newstart;
+ } else if (*fnamep <= tail) {
+ *fnamelen = 0;
+ }
+ } else {
+ // :r - Remove one extension
+ //
+ // Ensure that `s` doesn't go before `*fnamep`,
+ // since then we're taking too many roots:
+ //
+ // "path/to/this.file.ext" :e:e:r:r
+ // ^ ^-------- *fnamep
+ // +------------- tail
+ //
+ // Also ensure `s` doesn't go before `tail`,
+ // since then we're taking too many roots again:
+ //
+ // "path/to/this.file.ext" :r:r:r
+ // ^ ^------------- tail
+ // +--------------------- *fnamep
+ if (s > MAX(tail, (char *)(*fnamep))) {
+ *fnamelen = (size_t)(s - *fnamep);
+ }
+ }
+ *usedlen += 2;
+ }
+
+ // ":s?pat?foo?" - substitute
+ // ":gs?pat?foo?" - global substitute
+ if (src[*usedlen] == ':'
+ && (src[*usedlen + 1] == 's'
+ || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) {
+ int sep;
+ char *flags;
+ int didit = false;
+
+ flags = "";
+ s = src + *usedlen + 2;
+ if (src[*usedlen + 1] == 'g') {
+ flags = "g";
+ s++;
+ }
+
+ sep = (char_u)(*s++);
+ if (sep) {
+ // find end of pattern
+ p = vim_strchr(s, sep);
+ if (p != NULL) {
+ char *const pat = xstrnsave(s, (size_t)(p - s));
+ s = p + 1;
+ // find end of substitution
+ p = vim_strchr(s, sep);
+ if (p != NULL) {
+ char *const sub = xstrnsave(s, (size_t)(p - s));
+ char *const str = xstrnsave(*fnamep, *fnamelen);
+ *usedlen = (size_t)(p + 1 - src);
+ s = do_string_sub(str, pat, sub, NULL, flags);
+ *fnamep = s;
+ *fnamelen = STRLEN(s);
+ xfree(*bufp);
+ *bufp = s;
+ didit = TRUE;
+ xfree(sub);
+ xfree(str);
+ }
+ xfree(pat);
+ }
+ // after using ":s", repeat all the modifiers
+ if (didit) {
+ goto repeat;
+ }
+ }
+ }
+
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') {
+ // vim_strsave_shellescape() needs a NUL terminated string.
+ c = (char_u)(*fnamep)[*fnamelen];
+ if (c != NUL) {
+ (*fnamep)[*fnamelen] = NUL;
+ }
+ p = (char *)vim_strsave_shellescape((char_u *)(*fnamep), false, false);
+ if (c != NUL) {
+ (*fnamep)[*fnamelen] = (char)c;
+ }
+ xfree(*bufp);
+ *bufp = *fnamep = p;
+ *fnamelen = STRLEN(p);
+ *usedlen += 2;
+ }
+
+ return valid;
+}
+
+/// Perform a substitution on "str" with pattern "pat" and substitute "sub".
+/// When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
+/// "flags" can be "g" to do a global substitute.
+///
+/// @return an allocated string, NULL for error.
+char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags)
+{
+ int sublen;
+ regmatch_T regmatch;
+ int do_all;
+ char *tail;
+ char *end;
+ garray_T ga;
+ char *save_cpo;
+ char *zero_width = NULL;
+
+ // Make 'cpoptions' empty, so that the 'l' flag doesn't work here
+ save_cpo = p_cpo;
+ p_cpo = (char *)empty_option;
+
+ ga_init(&ga, 1, 200);
+
+ do_all = (flags[0] == 'g');
+
+ regmatch.rm_ic = p_ic;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL) {
+ tail = str;
+ end = str + STRLEN(str);
+ while (vim_regexec_nl(&regmatch, (char_u *)str, (colnr_T)(tail - str))) {
+ // Skip empty match except for first match.
+ if (regmatch.startp[0] == regmatch.endp[0]) {
+ if ((char_u *)zero_width == regmatch.startp[0]) {
+ // avoid getting stuck on a match with an empty string
+ int i = utfc_ptr2len(tail);
+ memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
+ ga.ga_len += i;
+ tail += i;
+ continue;
+ }
+ zero_width = (char *)regmatch.startp[0];
+ }
+
+ // Get some space for a temporary buffer to do the substitution
+ // into. It will contain:
+ // - The text up to where the match is.
+ // - The substituted text.
+ // - The text after the match.
+ sublen = vim_regsub(&regmatch, (char_u *)sub, expr, (char_u *)tail, 0, REGSUB_MAGIC);
+ ga_grow(&ga, (int)((end - tail) + sublen -
+ (regmatch.endp[0] - regmatch.startp[0])));
+
+ // copy the text up to where the match is
+ int i = (int)(regmatch.startp[0] - (char_u *)tail);
+ memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
+ // add the substituted text
+ (void)vim_regsub(&regmatch, (char_u *)sub, expr,
+ (char_u *)ga.ga_data + ga.ga_len + i, sublen,
+ REGSUB_COPY | REGSUB_MAGIC);
+ ga.ga_len += i + sublen - 1;
+ tail = (char *)regmatch.endp[0];
+ if (*tail == NUL) {
+ break;
+ }
+ if (!do_all) {
+ break;
+ }
+ }
+
+ if (ga.ga_data != NULL) {
+ STRCPY((char *)ga.ga_data + ga.ga_len, tail);
+ }
+
+ vim_regfree(regmatch.regprog);
+ }
+
+ char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data);
+ ga_clear(&ga);
+ if ((char_u *)p_cpo == empty_option) {
+ p_cpo = save_cpo;
+ } else {
+ // Darn, evaluating {sub} expression or {expr} changed the value.
+ free_string_option((char_u *)save_cpo);
+ }
+
+ return ret;
+}
+
+/// common code for getting job callbacks for jobstart, termopen and rpcstart
+///
+/// @return true/false on success/failure.
+bool common_job_callbacks(dict_T *vopts, CallbackReader *on_stdout, CallbackReader *on_stderr,
+ Callback *on_exit)
+{
+ if (tv_dict_get_callback(vopts, S_LEN("on_stdout"), &on_stdout->cb)
+ && tv_dict_get_callback(vopts, S_LEN("on_stderr"), &on_stderr->cb)
+ && tv_dict_get_callback(vopts, S_LEN("on_exit"), on_exit)) {
+ on_stdout->buffered = tv_dict_get_number(vopts, "stdout_buffered");
+ on_stderr->buffered = tv_dict_get_number(vopts, "stderr_buffered");
+ if (on_stdout->buffered && on_stdout->cb.type == kCallbackNone) {
+ on_stdout->self = vopts;
+ }
+ if (on_stderr->buffered && on_stderr->cb.type == kCallbackNone) {
+ on_stderr->self = vopts;
+ }
+ vopts->dv_refcount++;
+ return true;
+ }
+
+ callback_reader_free(on_stdout);
+ callback_reader_free(on_stderr);
+ callback_free(on_exit);
+ return false;
+}
+
+Channel *find_job(uint64_t id, bool show_error)
+{
+ Channel *data = find_channel(id);
+ if (!data || data->streamtype != kChannelStreamProc
+ || process_is_stopped(&data->stream.proc)) {
+ if (show_error) {
+ if (data && data->streamtype != kChannelStreamProc) {
+ emsg(_(e_invchanjob));
+ } else {
+ emsg(_(e_invchan));
+ }
+ }
+ return NULL;
+ }
+ return data;
+}
+
+void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
+{
+ if (check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_STRING) {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ list_T *args = tv_list_alloc(1);
+ tv_list_append_string(args, (const char *)argvars[0].vval.v_string, -1);
+ *rettv = eval_call_provider(name, "eval", args, false);
+}
+
+/// @param discard Clears the value returned by the provider and returns
+/// an empty typval_T.
+typval_T eval_call_provider(char *provider, char *method, list_T *arguments, bool discard)
+{
+ if (!eval_has_provider(provider)) {
+ semsg("E319: No \"%s\" provider found. Run \":checkhealth provider\"",
+ provider);
+ return (typval_T){
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_number = (varnumber_T)0
+ };
+ }
+
+ char func[256];
+ int name_len = snprintf(func, sizeof(func), "provider#%s#Call", provider);
+
+ // Save caller scope information
+ struct caller_scope saved_provider_caller_scope = provider_caller_scope;
+ provider_caller_scope = (struct caller_scope) {
+ .script_ctx = current_sctx,
+ .sourcing_name = sourcing_name,
+ .sourcing_lnum = sourcing_lnum,
+ .autocmd_fname = autocmd_fname,
+ .autocmd_match = autocmd_match,
+ .autocmd_bufnr = autocmd_bufnr,
+ .funccalp = (void *)get_current_funccal()
+ };
+ funccal_entry_T funccal_entry;
+ save_funccal(&funccal_entry);
+ provider_call_nesting++;
+
+ typval_T argvars[3] = {
+ { .v_type = VAR_STRING, .vval.v_string = method,
+ .v_lock = VAR_UNLOCKED },
+ { .v_type = VAR_LIST, .vval.v_list = arguments, .v_lock = VAR_UNLOCKED },
+ { .v_type = VAR_UNKNOWN }
+ };
+ typval_T rettv = { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
+ tv_list_ref(arguments);
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ (void)call_func(func, name_len, &rettv, 2, argvars, &funcexe);
+
+ tv_list_unref(arguments);
+ // Restore caller scope information
+ restore_funccal();
+ provider_caller_scope = saved_provider_caller_scope;
+ provider_call_nesting--;
+ assert(provider_call_nesting >= 0);
+
+ if (discard) {
+ tv_clear(&rettv);
+ }
+
+ return rettv;
+}
+
+/// Checks if provider for feature `feat` is enabled.
+bool eval_has_provider(const char *feat)
+{
+ if (!strequal(feat, "clipboard")
+ && !strequal(feat, "python3")
+ && !strequal(feat, "python3_compiled")
+ && !strequal(feat, "python3_dynamic")
+ && !strequal(feat, "perl")
+ && !strequal(feat, "ruby")
+ && !strequal(feat, "node")) {
+ // Avoid autoload for non-provider has() features.
+ return false;
+ }
+
+ char name[32]; // Normalized: "python_compiled" => "python".
+ snprintf(name, sizeof(name), "%s", feat);
+ strchrsub(name, '_', '\0'); // Chop any "_xx" suffix.
+
+ char buf[256];
+ typval_T tv;
+ // Get the g:loaded_xx_provider variable.
+ int len = snprintf(buf, sizeof(buf), "g:loaded_%s_provider", name);
+ if (get_var_tv(buf, len, &tv, NULL, false, true) == FAIL) {
+ // Trigger autoload once.
+ len = snprintf(buf, sizeof(buf), "provider#%s#bogus", name);
+ script_autoload(buf, (size_t)len, false);
+
+ // Retry the (non-autoload-style) variable.
+ len = snprintf(buf, sizeof(buf), "g:loaded_%s_provider", name);
+ if (get_var_tv(buf, len, &tv, NULL, false, true) == FAIL) {
+ // Show a hint if Call() is defined but g:loaded_xx_provider is missing.
+ snprintf(buf, sizeof(buf), "provider#%s#Call", name);
+ if (!!find_func((char_u *)buf) && p_lpl) {
+ semsg("provider: %s: missing required variable g:loaded_%s_provider",
+ name, name);
+ }
+ return false;
+ }
+ }
+
+ bool ok = (tv.v_type == VAR_NUMBER)
+ ? 2 == tv.vval.v_number // Value of 2 means "loaded and working".
+ : false;
+
+ if (ok) {
+ // Call() must be defined if provider claims to be working.
+ snprintf(buf, sizeof(buf), "provider#%s#Call", name);
+ if (!find_func((char_u *)buf)) {
+ semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
+ name, name, buf);
+ ok = false;
+ }
+ }
+
+ return ok;
+}
+
+/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
+void eval_fmt_source_name_line(char *buf, size_t bufsize)
+{
+ if (sourcing_name) {
+ snprintf(buf, bufsize, "%s:%" PRIdLINENR, sourcing_name, sourcing_lnum);
+ } else {
+ snprintf(buf, bufsize, "?");
+ }
+}
+
+/// ":checkhealth [plugins]"
+void ex_checkhealth(exarg_T *eap)
+{
+ bool found = !!find_func((char_u *)"health#check");
+ if (!found
+ && script_autoload("health#check", sizeof("health#check") - 1, false)) {
+ found = !!find_func((char_u *)"health#check");
+ }
+ if (!found) {
+ const char *vimruntime_env = os_getenv("VIMRUNTIME");
+ if (vimruntime_env == NULL) {
+ emsg(_("E5009: $VIMRUNTIME is empty or unset"));
+ } else {
+ bool rtp_ok = NULL != strstr((char *)p_rtp, vimruntime_env);
+ if (rtp_ok) {
+ semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env);
+ } else {
+ emsg(_("E5009: Invalid 'runtimepath'"));
+ }
+ }
+ return;
+ }
+
+ size_t bufsize = STRLEN(eap->arg) + sizeof("call health#check('')");
+ char *buf = xmalloc(bufsize);
+ snprintf(buf, bufsize, "call health#check('%s')", eap->arg);
+
+ do_cmdline_cmd(buf);
+
+ xfree(buf);
+}
+
+void invoke_prompt_callback(void)
+{
+ typval_T rettv;
+ typval_T argv[2];
+ char *text;
+ char *prompt;
+ linenr_T lnum = curbuf->b_ml.ml_line_count;
+
+ // Add a new line for the prompt before invoking the callback, so that
+ // text can always be inserted above the last line.
+ ml_append(lnum, "", 0, false);
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+
+ if (curbuf->b_prompt_callback.type == kCallbackNone) {
+ return;
+ }
+ text = (char *)ml_get(lnum);
+ prompt = (char *)prompt_text();
+ if (STRLEN(text) >= STRLEN(prompt)) {
+ text += STRLEN(prompt);
+ }
+ argv[0].v_type = VAR_STRING;
+ argv[0].vval.v_string = xstrdup(text);
+ argv[1].v_type = VAR_UNKNOWN;
+
+ callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
+ tv_clear(&argv[0]);
+ tv_clear(&rettv);
+}
+
+/// @return true when the interrupt callback was invoked.
+bool invoke_prompt_interrupt(void)
+{
+ typval_T rettv;
+ typval_T argv[1];
+
+ if (curbuf->b_prompt_interrupt.type == kCallbackNone) {
+ return false;
+ }
+ argv[0].v_type = VAR_UNKNOWN;
+
+ got_int = false; // don't skip executing commands
+ callback_call(&curbuf->b_prompt_interrupt, 0, argv, &rettv);
+ tv_clear(&rettv);
+ return true;
+}
+
+/// Compare "typ1" and "typ2". Put the result in "typ1".
+///
+/// @param typ1 first operand
+/// @param typ2 second operand
+/// @param type operator
+/// @param ic ignore case
+int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic)
+ FUNC_ATTR_NONNULL_ALL
+{
+ varnumber_T n1, n2;
+ const bool type_is = type == EXPR_IS || type == EXPR_ISNOT;
+
+ if (type_is && typ1->v_type != typ2->v_type) {
+ // For "is" a different type always means false, for "notis"
+ // it means true.
+ n1 = type == EXPR_ISNOT;
+ } else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB) {
+ if (type_is) {
+ n1 = typ1->v_type == typ2->v_type
+ && typ1->vval.v_blob == typ2->vval.v_blob;
+ if (type == EXPR_ISNOT) {
+ n1 = !n1;
+ }
+ } else if (typ1->v_type != typ2->v_type
+ || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) {
+ if (typ1->v_type != typ2->v_type) {
+ emsg(_("E977: Can only compare Blob with Blob"));
+ } else {
+ emsg(_(e_invalblob));
+ }
+ tv_clear(typ1);
+ return FAIL;
+ } else {
+ // Compare two Blobs for being equal or unequal.
+ n1 = tv_blob_equal(typ1->vval.v_blob, typ2->vval.v_blob);
+ if (type == EXPR_NEQUAL) {
+ n1 = !n1;
+ }
+ }
+ } else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST) {
+ if (type_is) {
+ n1 = typ1->v_type == typ2->v_type
+ && typ1->vval.v_list == typ2->vval.v_list;
+ if (type == EXPR_ISNOT) {
+ n1 = !n1;
+ }
+ } else if (typ1->v_type != typ2->v_type
+ || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) {
+ if (typ1->v_type != typ2->v_type) {
+ emsg(_("E691: Can only compare List with List"));
+ } else {
+ emsg(_("E692: Invalid operation for List"));
+ }
+ tv_clear(typ1);
+ return FAIL;
+ } else {
+ // Compare two Lists for being equal or unequal.
+ n1 = tv_list_equal(typ1->vval.v_list, typ2->vval.v_list, ic, false);
+ if (type == EXPR_NEQUAL) {
+ n1 = !n1;
+ }
+ }
+ } else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT) {
+ if (type_is) {
+ n1 = typ1->v_type == typ2->v_type
+ && typ1->vval.v_dict == typ2->vval.v_dict;
+ if (type == EXPR_ISNOT) {
+ n1 = !n1;
+ }
+ } else if (typ1->v_type != typ2->v_type
+ || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) {
+ if (typ1->v_type != typ2->v_type) {
+ emsg(_("E735: Can only compare Dictionary with Dictionary"));
+ } else {
+ emsg(_("E736: Invalid operation for Dictionary"));
+ }
+ tv_clear(typ1);
+ return FAIL;
+ } else {
+ // Compare two Dictionaries for being equal or unequal.
+ n1 = tv_dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ic, false);
+ if (type == EXPR_NEQUAL) {
+ n1 = !n1;
+ }
+ }
+ } else if (tv_is_func(*typ1) || tv_is_func(*typ2)) {
+ if (type != EXPR_EQUAL && type != EXPR_NEQUAL
+ && type != EXPR_IS && type != EXPR_ISNOT) {
+ emsg(_("E694: Invalid operation for Funcrefs"));
+ tv_clear(typ1);
+ return FAIL;
+ }
+ if ((typ1->v_type == VAR_PARTIAL && typ1->vval.v_partial == NULL)
+ || (typ2->v_type == VAR_PARTIAL && typ2->vval.v_partial == NULL)) {
+ // when a partial is NULL assume not equal
+ n1 = false;
+ } else if (type_is) {
+ if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) {
+ // strings are considered the same if their value is
+ // the same
+ n1 = tv_equal(typ1, typ2, ic, false);
+ } else if (typ1->v_type == VAR_PARTIAL && typ2->v_type == VAR_PARTIAL) {
+ n1 = typ1->vval.v_partial == typ2->vval.v_partial;
+ } else {
+ n1 = false;
+ }
+ } else {
+ n1 = tv_equal(typ1, typ2, ic, false);
+ }
+ if (type == EXPR_NEQUAL || type == EXPR_ISNOT) {
+ n1 = !n1;
+ }
+ } else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
+ && type != EXPR_MATCH && type != EXPR_NOMATCH) {
+ // If one of the two variables is a float, compare as a float.
+ // When using "=~" or "!~", always compare as string.
+ const float_T f1 = tv_get_float(typ1);
+ const float_T f2 = tv_get_float(typ2);
+ n1 = false;
+ switch (type) {
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = f1 == f2; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = f1 != f2; break;
+ case EXPR_GREATER:
+ n1 = f1 > f2; break;
+ case EXPR_GEQUAL:
+ n1 = f1 >= f2; break;
+ case EXPR_SMALLER:
+ n1 = f1 < f2; break;
+ case EXPR_SEQUAL:
+ n1 = f1 <= f2; break;
+ case EXPR_UNKNOWN:
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ break; // avoid gcc warning
+ }
+ } else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
+ && type != EXPR_MATCH && type != EXPR_NOMATCH) {
+ // If one of the two variables is a number, compare as a number.
+ // When using "=~" or "!~", always compare as string.
+ n1 = tv_get_number(typ1);
+ n2 = tv_get_number(typ2);
+ switch (type) {
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = n1 == n2; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = n1 != n2; break;
+ case EXPR_GREATER:
+ n1 = n1 > n2; break;
+ case EXPR_GEQUAL:
+ n1 = n1 >= n2; break;
+ case EXPR_SMALLER:
+ n1 = n1 < n2; break;
+ case EXPR_SEQUAL:
+ n1 = n1 <= n2; break;
+ case EXPR_UNKNOWN:
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ break; // avoid gcc warning
+ }
+ } else {
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *const s1 = tv_get_string_buf(typ1, buf1);
+ const char *const s2 = tv_get_string_buf(typ2, buf2);
+ int i;
+ if (type != EXPR_MATCH && type != EXPR_NOMATCH) {
+ i = mb_strcmp_ic(ic, s1, s2);
+ } else {
+ i = 0;
+ }
+ n1 = false;
+ switch (type) {
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = i == 0; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = i != 0; break;
+ case EXPR_GREATER:
+ n1 = i > 0; break;
+ case EXPR_GEQUAL:
+ n1 = i >= 0; break;
+ case EXPR_SMALLER:
+ n1 = i < 0; break;
+ case EXPR_SEQUAL:
+ n1 = i <= 0; break;
+
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ n1 = pattern_match((char *)s2, (char *)s1, ic);
+ if (type == EXPR_NOMATCH) {
+ n1 = !n1;
+ }
+ break;
+ case EXPR_UNKNOWN:
+ break; // avoid gcc warning
+ }
+ }
+ tv_clear(typ1);
+ typ1->v_type = VAR_NUMBER;
+ typ1->vval.v_number = n1;
+ return OK;
+}
+
+char *typval_tostring(typval_T *arg)
+{
+ if (arg == NULL) {
+ return xstrdup("(does not exist)");
+ }
+ return encode_tv2string(arg, NULL);
+}
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index fa02b1ea0f..7dbd18737a 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -3,7 +3,6 @@
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
-#include "nvim/eval/funcs.h" // For FunPtr
#include "nvim/event/time.h" // For TimeWatcher
#include "nvim/ex_cmds_defs.h" // For exarg_T
#include "nvim/os/fileio.h" // For FileDescriptor
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 3db0d27018..c8eb0334fa 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -250,6 +250,7 @@ return {
map={args=2, base=1},
maparg={args={1, 4}, base=1},
mapcheck={args={1, 3}, base=1},
+ mapset={args=3, base=1},
match={args={2, 4}, base=1},
matchadd={args={2, 5}, base=1},
matchaddpos={args={2, 5}, base=1},
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index 3e66150180..b461456a3a 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -12,8 +12,6 @@
# include "eval/executor.c.generated.h"
#endif
-static char *e_letwrong = N_("E734: Wrong variable type for %s=");
-
char *e_listidx = N_("E684: list index out of range: %" PRId64);
/// Handle tv1 += tv2, -=, *=, /=, %=, .=
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 7bed21e99b..691ccfe535 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -25,6 +25,7 @@
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/file_search.h"
@@ -36,6 +37,7 @@
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/input.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/mapping.h"
@@ -213,12 +215,11 @@ int call_internal_method(const char_u *const fname, const int argcount, typval_T
}
typval_T argv[MAX_FUNC_ARGS + 1];
- const ptrdiff_t base_index
- = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
- memcpy(argv, argvars, base_index * sizeof(typval_T));
+ const ptrdiff_t base_index = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
+ memcpy(argv, argvars, (size_t)base_index * sizeof(typval_T));
argv[base_index] = *basetv;
memcpy(argv + base_index + 1, argvars + base_index,
- (argcount - base_index) * sizeof(typval_T));
+ (size_t)(argcount - base_index) * sizeof(typval_T));
argv[argcount + 1].v_type = VAR_UNKNOWN;
fdef->func(argv, rettv, fdef->data);
@@ -326,7 +327,7 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
if (!error) {
- ga_append(&b->bv_ga, (int)n);
+ ga_append(&b->bv_ga, (char)n);
tv_copy(&argvars[0], rettv);
}
}
@@ -430,7 +431,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- int idx = tv_get_number_chk(&argvars[0], NULL);
+ int idx = (int)tv_get_number_chk(&argvars[0], NULL);
if (arglist != NULL && idx >= 0 && idx < argcount) {
rettv->vval.v_string = xstrdup((const char *)alist_name(&arglist[idx]));
} else if (idx == -1) {
@@ -831,7 +832,7 @@ static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
const char *error;
- rettv->vval.v_number = channel_close(argvars[0].vval.v_number, part, &error);
+ rettv->vval.v_number = channel_close((uint64_t)argvars[0].vval.v_number, part, &error);
if (!rettv->vval.v_number) {
emsg(error);
}
@@ -859,7 +860,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const blob_T *const b = argvars[1].vval.v_blob;
input_len = tv_blob_len(b);
if (input_len > 0) {
- input = xmemdup(b->bv_ga.ga_data, input_len);
+ input = xmemdup(b->bv_ga.ga_data, (size_t)input_len);
}
} else {
input = save_tv_as_string(&argvars[1], &input_len, false);
@@ -870,9 +871,9 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// or there is no input to send.
return;
}
- uint64_t id = argvars[0].vval.v_number;
+ uint64_t id = (uint64_t)argvars[0].vval.v_number;
const char *error = NULL;
- rettv->vval.v_number = channel_send(id, input, input_len, true, &error);
+ rettv->vval.v_number = (varnumber_T)channel_send(id, input, (size_t)input_len, true, &error);
if (error) {
emsg(error);
}
@@ -1054,64 +1055,6 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
get_col(argvars, rettv, false);
}
-/// "complete()" function
-static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- if ((State & MODE_INSERT) == 0) {
- emsg(_("E785: complete() can only be used in Insert mode"));
- return;
- }
-
- // Check for undo allowed here, because if something was already inserted
- // the line was already saved for undo and this check isn't done.
- if (!undo_allowed(curbuf)) {
- return;
- }
-
- if (argvars[1].v_type != VAR_LIST) {
- emsg(_(e_invarg));
- } else {
- const colnr_T startcol = tv_get_number_chk(&argvars[0], NULL);
- if (startcol > 0) {
- set_completion(startcol - 1, argvars[1].vval.v_list);
- }
- }
-}
-
-/// "complete_add()" function
-static void f_complete_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false);
-}
-
-/// "complete_check()" function
-static void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- int saved = RedrawingDisabled;
-
- RedrawingDisabled = 0;
- ins_compl_check_keys(0, true);
- rettv->vval.v_number = compl_interrupted;
- RedrawingDisabled = saved;
-}
-
-/// "complete_info()" function
-static void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- tv_dict_alloc_ret(rettv);
-
- list_T *what_list = NULL;
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- if (argvars[0].v_type != VAR_LIST) {
- emsg(_(e_listreq));
- return;
- }
- what_list = argvars[0].vval.v_list;
- }
- get_complete_info(what_list, rettv->vval.v_dict);
-}
-
/// "confirm(message, buttons[, default [, type]])" function
static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -1134,7 +1077,7 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
error = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- def = tv_get_number_chk(&argvars[2], &error);
+ def = (int)tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
typestr = tv_get_string_buf_chk(&argvars[3], buf2);
if (typestr == NULL) {
@@ -1181,7 +1124,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool error = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
- ic = tv_get_number_chk(&argvars[2], &error);
+ ic = (int)tv_get_number_chk(&argvars[2], &error);
}
if (argvars[0].v_type == VAR_STRING) {
@@ -1219,7 +1162,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[3].v_type != VAR_UNKNOWN) {
idx = tv_get_number_chk(&argvars[3], &error);
if (!error) {
- li = tv_list_find(l, idx);
+ li = tv_list_find(l, (int)idx);
if (li == NULL) {
semsg(_(e_listidx), (int64_t)idx);
}
@@ -1292,7 +1235,7 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
size_t index = 0;
if (argvars[0].v_type == VAR_NUMBER) {
- index = argvars[0].vval.v_number;
+ index = (size_t)argvars[0].vval.v_number;
} else if (argvars[0].v_type != VAR_UNKNOWN) {
semsg(_(e_invarg2), "expected nothing or a Number as an argument");
return;
@@ -1360,7 +1303,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
size_t index = 0;
if (argvars[1].v_type == VAR_NUMBER) {
- index = argvars[1].vval.v_number;
+ index = (size_t)argvars[1].vval.v_number;
} else if (argvars[1].v_type != VAR_UNKNOWN) {
semsg(_(e_invarg2), "expected nothing or a Number as second argument");
return;
@@ -1394,7 +1337,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = ctx_size();
+ rettv->vval.v_number = (varnumber_T)ctx_size();
}
/// Set the cursor position.
@@ -1428,7 +1371,7 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
line = tv_get_lnum(argvars);
col = (long)tv_get_number_chk(&argvars[1], NULL);
if (charcol) {
- col = buf_charidx_to_byteidx(curbuf, line, col) + 1;
+ col = buf_charidx_to_byteidx(curbuf, (linenr_T)line, (int)col) + 1;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
coladd = (long)tv_get_number_chk(&argvars[2], NULL);
@@ -1441,12 +1384,12 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
return; // type error; errmsg already given
}
if (line > 0) {
- curwin->w_cursor.lnum = line;
+ curwin->w_cursor.lnum = (linenr_T)line;
}
if (col > 0) {
- curwin->w_cursor.col = col - 1;
+ curwin->w_cursor.col = (colnr_T)col - 1;
}
- curwin->w_cursor.coladd = coladd;
+ curwin->w_cursor.coladd = (colnr_T)coladd;
// Make sure the cursor is in a valid position.
check_cursor();
@@ -1498,7 +1441,7 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int noref = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- noref = tv_get_number_chk(&argvars[1], NULL);
+ noref = (int)tv_get_number_chk(&argvars[1], NULL);
}
if (noref < 0 || noref > 1) {
emsg(_(e_invarg));
@@ -1675,7 +1618,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
if (wp->w_cursor.lnum > last) {
- wp->w_cursor.lnum -= count;
+ wp->w_cursor.lnum -= (linenr_T)count;
} else if (wp->w_cursor.lnum > first) {
wp->w_cursor.lnum = first;
}
@@ -1712,7 +1655,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
linenr_T lnum = tv_get_lnum(argvars);
static linenr_T prev_lnum = 0;
- static int changedtick = 0;
+ static varnumber_T changedtick = 0;
static int fnum = 0;
static int change_start = 0;
static int change_end = 0;
@@ -1749,7 +1692,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (hlID == HLF_CHD || hlID == HLF_TXD) {
- col = tv_get_number(&argvars[1]) - 1; // Ignore type error in {col}.
+ col = (int)tv_get_number(&argvars[1]) - 1; // Ignore type error in {col}.
if (col >= change_start && col <= change_end) {
hlID = HLF_TXD; // Changed text.
} else {
@@ -1820,7 +1763,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
os_copy_fullenv(env, env_size);
- for (ssize_t i = env_size - 1; i >= 0; i--) {
+ for (ssize_t i = (ssize_t)env_size - 1; i >= 0; i--) {
const char *str = env[i];
const char * const end = strchr(str + (str[0] == '=' ? 1 : 0),
'=');
@@ -1848,9 +1791,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
xfree(key);
continue;
}
- tv_dict_add_str(rettv->vval.v_dict,
- key, len,
- value);
+ tv_dict_add_str(rettv->vval.v_dict, key, (size_t)len, value);
xfree(key);
}
os_free_fullenv(env);
@@ -2029,7 +1970,7 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- int id = tv_get_number(argvars);
+ int id = (int)tv_get_number(argvars);
tabpage_T *tp;
win_T *wp = win_id2wp_tp(id, &tp);
if (wp != NULL && tp != NULL) {
@@ -2189,11 +2130,11 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char *errormsg = NULL;
rettv->v_type = VAR_STRING;
- char_u *cmdstr = (char_u *)xstrdup(tv_get_string(&argvars[0]));
+ char *cmdstr = xstrdup(tv_get_string(&argvars[0]));
exarg_T eap = {
- .cmd = (char *)cmdstr,
- .arg = (char *)cmdstr,
+ .cmd = cmdstr,
+ .arg = cmdstr,
.usefilter = false,
.nextcmd = NULL,
.cmdidx = CMD_USER,
@@ -2204,7 +2145,7 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (errormsg != NULL && *errormsg != NUL) {
emsg(errormsg);
}
- rettv->vval.v_string = (char *)cmdstr;
+ rettv->vval.v_string = cmdstr;
}
/// "flatten(list[, {maxdepth}])" function
@@ -2265,7 +2206,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (before == tv_list_len(l1)) {
item = NULL;
} else {
- item = tv_list_find(l1, before);
+ item = tv_list_find(l1, (int)before);
if (item == NULL) {
semsg(_(e_listidx), (int64_t)before);
return;
@@ -2382,7 +2323,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- count = tv_get_number_chk(&argvars[2], &error);
+ count = (int)tv_get_number_chk(&argvars[2], &error);
}
}
}
@@ -2577,7 +2518,7 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- unsigned long count = (unsigned long)foldend - foldstart + 1;
+ unsigned long count = (unsigned long)foldend - (unsigned long)foldstart + 1;
txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
r = xmalloc(STRLEN(txt)
+ STRLEN(dashes) // for %s
@@ -2613,7 +2554,7 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
foldinfo_T info = fold_info(curwin, lnum);
if (info.fi_lines > 0) {
- text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf);
+ text = get_foldtext(curwin, lnum, lnum + (linenr_T)info.fi_lines - 1, info, buf);
if (text == buf) {
text = vim_strsave(text);
}
@@ -2661,7 +2602,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_BLOB) {
bool error = false;
- int idx = tv_get_number_chk(&argvars[1], &error);
+ int idx = (int)tv_get_number_chk(&argvars[1], &error);
if (!error) {
rettv->v_type = VAR_NUMBER;
@@ -2679,7 +2620,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if ((l = argvars[0].vval.v_list) != NULL) {
bool error = false;
- li = tv_list_find(l, tv_get_number_chk(&argvars[1], &error));
+ li = tv_list_find(l, (int)tv_get_number_chk(&argvars[1], &error));
if (!error && li != NULL) {
tv = TV_LIST_ITEM_TV(li);
}
@@ -2860,66 +2801,6 @@ static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
get_buffer_lines(buf, lnum, end, true, rettv);
}
-/// "getbufvar()" function
-static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- bool done = false;
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- if (!tv_check_str_or_nr(&argvars[0])) {
- goto f_getbufvar_end;
- }
-
- const char *varname = tv_get_string_chk(&argvars[1]);
- emsg_off++;
- buf_T *const buf = tv_get_buf(&argvars[0], false);
-
- if (buf != NULL && varname != NULL) {
- if (*varname == '&') { // buffer-local-option
- buf_T *const save_curbuf = curbuf;
-
- // set curbuf to be our buf, temporarily
- curbuf = buf;
-
- if (varname[1] == NUL) {
- // get all buffer-local options in a dict
- dict_T *opts = get_winbuf_options(true);
-
- if (opts != NULL) {
- tv_dict_set_ret(rettv, opts);
- done = true;
- }
- } else if (get_option_tv(&varname, rettv, true) == OK) {
- // buffer-local-option
- done = true;
- }
-
- // restore previous notion of curbuf
- curbuf = save_curbuf;
- } else {
- // Look up the variable.
- // Let getbufvar({nr}, "") return the "b:" dictionary.
- dictitem_T *const v = *varname == NUL
- ? (dictitem_T *)&buf->b_bufvar
- : find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
- varname, strlen(varname), false);
- if (v != NULL) {
- tv_copy(&v->di_tv, rettv);
- done = true;
- }
- }
- }
- emsg_off--;
-
-f_getbufvar_end:
- if (!done && argvars[2].v_type != VAR_UNKNOWN) {
- // use the default value
- tv_copy(&argvars[2], rettv);
- }
-}
-
/// "getchangelist()" function
static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -2929,7 +2810,7 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) {
buf = curbuf;
} else {
- vim_ignored = tv_get_number(&argvars[0]); // issue errmsg if type error
+ vim_ignored = (int)tv_get_number(&argvars[0]); // issue errmsg if type error
emsg_off++;
buf = tv_get_buf(&argvars[0], false);
emsg_off--;
@@ -2940,13 +2821,23 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *const l = tv_list_alloc(buf->b_changelistlen);
tv_list_append_list(rettv->vval.v_list, l);
- // The current window change list index tracks only the position in the
- // current buffer change list. For other buffers, use the change list
- // length as the current index.
- tv_list_append_number(rettv->vval.v_list,
- (buf == curwin->w_buffer)
- ? curwin->w_changelistidx
- : buf->b_changelistlen);
+ // The current window change list index tracks only the position for the
+ // current buffer. For other buffers use the stored index for the current
+ // window, or, if that's not available, the change list length.
+ int changelistindex;
+ if (buf == curwin->w_buffer) {
+ changelistindex = curwin->w_changelistidx;
+ } else {
+ wininfo_T *wip;
+
+ FOR_ALL_BUF_WININFO(buf, wip) {
+ if (wip->wi_win == curwin) {
+ break;
+ }
+ }
+ changelistindex = wip != NULL ? wip->wi_changelistidx : buf->b_changelistlen;
+ }
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)changelistindex);
for (int i = 0; i < buf->b_changelistlen; i++) {
if (buf->b_changelist[i].mark.lnum == 0) {
@@ -3008,6 +2899,11 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
no_mapping--;
allow_keys--;
+ if (!ui_has_messages()) {
+ // redraw the screen after getchar()
+ update_screen(CLEAR);
+ }
+
set_vim_var_nr(VV_MOUSE_WIN, 0);
set_vim_var_nr(VV_MOUSE_WINID, 0);
set_vim_var_nr(VV_MOUSE_LNUM, 0);
@@ -3022,21 +2918,21 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
if (mod_mask != 0) {
temp[i++] = K_SPECIAL;
temp[i++] = KS_MODIFIER;
- temp[i++] = mod_mask;
+ temp[i++] = (char_u)mod_mask;
}
if (IS_SPECIAL(n)) {
temp[i++] = K_SPECIAL;
- temp[i++] = K_SECOND(n);
+ temp[i++] = (char_u)K_SECOND(n);
temp[i++] = K_THIRD(n);
} else {
- i += utf_char2bytes(n, (char *)temp + i);
+ i += utf_char2bytes((int)n, (char *)temp + i);
}
assert(i < 10);
temp[i++] = NUL;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char *)vim_strsave(temp);
- if (is_mouse_key(n)) {
+ if (is_mouse_key((int)n)) {
int row = mouse_row;
int col = mouse_col;
int grid = mouse_grid;
@@ -3081,7 +2977,7 @@ static void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int i = 0;
if (n != 0) {
- i += utf_char2bytes(n, (char *)temp);
+ i += utf_char2bytes((int)n, (char *)temp);
}
assert(i < 7);
temp[i++] = NUL;
@@ -3200,7 +3096,7 @@ static void f_getcmdtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = xmallocz(1);
- rettv->vval.v_string[0] = get_cmdline_type();
+ rettv->vval.v_string[0] = (char)get_cmdline_type();
}
/// "getcmdwintype()" function
@@ -3209,7 +3105,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
rettv->vval.v_string = xmallocz(1);
- rettv->vval.v_string[0] = cmdwin_type;
+ rettv->vval.v_string[0] = (char)cmdwin_type;
}
/// "getcompletion()" function
@@ -3249,7 +3145,7 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (strcmp(type, "cmdline") == 0) {
set_one_cmd_context(&xpc, pattern);
xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
- xpc.xp_col = STRLEN(pattern);
+ xpc.xp_col = (int)STRLEN(pattern);
goto theend;
}
@@ -3330,7 +3226,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_(e_invarg));
return;
}
- scope_number[i] = argvars[i].vval.v_number;
+ scope_number[i] = (int)argvars[i].vval.v_number;
// It is an error for the scope number to be less than `-1`.
if (scope_number[i] < -1) {
emsg(_(e_invarg));
@@ -3430,7 +3326,7 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
perm = xstrdup("---------");
for (int i = 0; i < 9; i++) {
if (file_perm & (1 << (8 - i))) {
- perm[i] = flags[i % 3];
+ perm[i] = (char)flags[i % 3];
}
}
}
@@ -3764,50 +3660,6 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "gettabvar()" function
-static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- bool done = false;
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- const char *const varname = tv_get_string_chk(&argvars[1]);
- tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- if (tp != NULL && varname != NULL) {
- // Set tp to be our tabpage, temporarily. Also set the window to the
- // first window in the tabpage, otherwise the window is not valid.
- win_T *const window = tp == curtab || tp->tp_firstwin == NULL
- ? firstwin
- : tp->tp_firstwin;
- switchwin_T switchwin;
- if (switch_win(&switchwin, window, tp, true) == OK) {
- // look up the variable
- // Let gettabvar({nr}, "") return the "t:" dictionary.
- const dictitem_T *const v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't',
- varname, strlen(varname),
- false);
- if (v != NULL) {
- tv_copy(&v->di_tv, rettv);
- done = true;
- }
- }
-
- // restore previous notion of curwin
- restore_win(&switchwin, true);
- }
-
- if (!done && argvars[2].v_type != VAR_UNKNOWN) {
- tv_copy(&argvars[2], rettv);
- }
-}
-
-/// "gettabwinvar()" function
-static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- getwinvar(argvars, rettv, 1);
-}
-
/// "gettagstack()" function
static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -3833,7 +3685,7 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_alloc_ret(rettv, kListLenMayKnow);
if (argvars[0].v_type != VAR_UNKNOWN) {
- wparg = win_id2wp(tv_get_number(&argvars[0]));
+ wparg = win_id2wp((int)tv_get_number(&argvars[0]));
if (wparg == NULL) {
return;
}
@@ -3886,10 +3738,10 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- int timeout = argvars[0].vval.v_number;
+ int timeout = (int)argvars[0].vval.v_number;
typval_T expr = argvars[1];
int interval = argvars[2].v_type == VAR_NUMBER
- ? argvars[2].vval.v_number
+ ? (int)argvars[2].vval.v_number
: 200; // Default.
TimeWatcher *tw = xmalloc(sizeof(TimeWatcher));
@@ -3897,7 +3749,7 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
time_watcher_init(&main_loop, tw, NULL);
tw->events = main_loop.events;
tw->blockable = true;
- time_watcher_start(tw, dummy_timer_due_cb, interval, interval);
+ time_watcher_start(tw, dummy_timer_due_cb, (uint64_t)interval, (uint64_t)interval);
typval_T argv = TV_INITIAL_VALUE;
typval_T exprval = TV_INITIAL_VALUE;
@@ -4005,7 +3857,7 @@ static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
}
- size = tv_dict_get_number(d, "size");
+ size = (int)tv_dict_get_number(d, "size");
}
win_move_into_split(wp, targetwin, size, flags);
@@ -4031,12 +3883,6 @@ static void f_getwinposy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
}
-/// "getwinvar()" function
-static void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- getwinvar(argvars, rettv, 0);
-}
-
/// "glob()" function
static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -4181,6 +4027,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"cindent",
"cmdline_compl",
"cmdline_hist",
+ "cmdwin",
"comments",
"conceal",
"cscope",
@@ -4282,7 +4129,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
};
// XXX: eval_has_provider() may shell out :(
- const int save_shell_error = get_vim_var_nr(VV_SHELL_ERROR);
+ const int save_shell_error = (int)get_vim_var_nr(VV_SHELL_ERROR);
bool n = false;
const char *const name = tv_get_string(&argvars[0]);
for (size_t i = 0; i < ARRAY_SIZE(has_list); i++) {
@@ -4359,22 +4206,6 @@ static bool has_wsl(void)
return has_wsl == kTrue;
}
-/// "has_key()" function
-static void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- if (argvars[0].v_type != VAR_DICT) {
- emsg(_(e_dictreq));
- return;
- }
- if (argvars[0].vval.v_dict == NULL) {
- return;
- }
-
- rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict,
- tv_get_string(&argvars[1]),
- -1) != NULL;
-}
-
/// `haslocaldir([{win}[, {tab}]])` function
///
/// Returns `1` if the scope object has a local directory, `0` otherwise. If a
@@ -4413,7 +4244,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_(e_invarg));
return;
}
- scope_number[i] = argvars[i].vval.v_number;
+ scope_number[i] = (int)argvars[i].vval.v_number;
if (scope_number[i] < -1) {
emsg(_(e_invarg));
return;
@@ -4629,7 +4460,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int start = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
- start = tv_get_number_chk(&argvars[2], &error);
+ start = (int)tv_get_number_chk(&argvars[2], &error);
if (error) {
return;
}
@@ -4647,7 +4478,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
for (idx = start; idx < tv_blob_len(b); idx++) {
typval_T tv;
tv.v_type = VAR_NUMBER;
- tv.vval.v_number = tv_blob_get(b, idx);
+ tv.vval.v_number = tv_blob_get(b, (int)idx);
if (tv_equal(&tv, &argvars[1], ic, false)) {
rettv->vval.v_number = idx;
return;
@@ -4665,11 +4496,11 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool error = false;
// Start at specified item.
- idx = tv_list_uidx(l, tv_get_number_chk(&argvars[2], &error));
+ idx = tv_list_uidx(l, (int)tv_get_number_chk(&argvars[2], &error));
if (error || idx == -1) {
item = NULL;
} else {
- item = tv_list_find(l, idx);
+ item = tv_list_find(l, (int)idx);
assert(item != NULL);
}
if (argvars[3].v_type != VAR_UNKNOWN) {
@@ -4797,7 +4628,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
}
- const int val = tv_get_number_chk(&argvars[1], &error);
+ const int val = (int)tv_get_number_chk(&argvars[1], &error);
if (error) {
return;
}
@@ -4808,8 +4639,8 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ga_grow(&b->bv_ga, 1);
char_u *const p = (char_u *)b->bv_ga.ga_data;
- memmove(p + before + 1, p + before, (size_t)len - before);
- *(p + before) = val;
+ memmove(p + before + 1, p + before, (size_t)(len - before));
+ *(p + before) = (char_u)val;
b->bv_ga.ga_len++;
tv_copy(&argvars[0], rettv);
@@ -4828,7 +4659,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
listitem_T *item = NULL;
if (before != tv_list_len(l)) {
- item = tv_list_find(l, before);
+ item = tv_list_find(l, (int)before);
if (item == NULL) {
semsg(_(e_listidx), (int64_t)before);
l = NULL;
@@ -4925,14 +4756,8 @@ static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const int len = vim_vsnprintf_typval(NULL, 0, "%p", dummy_ap, argvars);
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xmalloc(len + 1);
- vim_vsnprintf_typval(rettv->vval.v_string, len + 1, "%p", dummy_ap, argvars);
-}
-
-/// "items(dict)" function
-static void f_items(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- dict_list(argvars, rettv, 2);
+ rettv->vval.v_string = xmalloc((size_t)len + 1);
+ vim_vsnprintf_typval(rettv->vval.v_string, (size_t)len + 1, "%p", dummy_ap, argvars);
}
/// "jobpid(id)" function
@@ -4950,7 +4775,7 @@ static void f_jobpid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- Channel *data = find_job(argvars[0].vval.v_number, true);
+ Channel *data = find_job((uint64_t)argvars[0].vval.v_number, true);
if (!data) {
return;
}
@@ -4976,7 +4801,7 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- Channel *data = find_job(argvars[0].vval.v_number, true);
+ Channel *data = find_job((uint64_t)argvars[0].vval.v_number, true);
if (!data) {
return;
}
@@ -4986,8 +4811,8 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- pty_process_resize(&data->stream.pty, argvars[1].vval.v_number,
- argvars[2].vval.v_number);
+ pty_process_resize(&data->stream.pty, (uint16_t)argvars[1].vval.v_number,
+ (uint16_t)argvars[2].vval.v_number);
rettv->vval.v_number = 1;
}
@@ -5102,7 +4927,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
i < ARRAY_SIZE(required_env_vars) && required_env_vars[i];
i++) {
size_t len = strlen(required_env_vars[i]);
- dictitem_T *dv = tv_dict_find(env, required_env_vars[i], len);
+ dictitem_T *dv = tv_dict_find(env, required_env_vars[i], (ptrdiff_t)len);
if (!dv) {
const char *env_var = os_getenv(required_env_vars[i]);
if (env_var) {
@@ -5251,7 +5076,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- Channel *data = find_job(argvars[0].vval.v_number, false);
+ Channel *data = find_job((uint64_t)argvars[0].vval.v_number, false);
if (!data) {
return;
}
@@ -5285,7 +5110,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ui_busy_start();
list_T *args = argvars[0].vval.v_list;
- Channel **jobs = xcalloc(tv_list_len(args), sizeof(*jobs));
+ Channel **jobs = xcalloc((size_t)tv_list_len(args), sizeof(*jobs));
MultiQueue *waiting_jobs = multiqueue_new_parent(loop_on_put, &main_loop);
// Validate, prepare jobs for waiting.
@@ -5293,7 +5118,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(args, arg, {
Channel *chan = NULL;
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
- || !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number))
+ || !(chan = find_channel((uint64_t)TV_LIST_ITEM_TV(arg)->vval.v_number))
|| chan->streamtype != kChannelStreamProc) {
jobs[i] = NULL; // Invalid job.
} else if (process_is_stopped(&chan->stream.proc)) {
@@ -5316,7 +5141,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int remaining = -1;
uint64_t before = 0;
if (argvars[1].v_type == VAR_NUMBER && argvars[1].vval.v_number >= 0) {
- remaining = argvars[1].vval.v_number;
+ remaining = (int)argvars[1].vval.v_number;
before = os_hrtime();
}
@@ -5367,30 +5192,6 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_list = rv;
}
-/// "join()" function
-static void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- if (argvars[0].v_type != VAR_LIST) {
- emsg(_(e_listreq));
- return;
- }
- const char *const sep = (argvars[1].v_type == VAR_UNKNOWN
- ? " "
- : tv_get_string_chk(&argvars[1]));
-
- rettv->v_type = VAR_STRING;
-
- if (sep != NULL) {
- garray_T ga;
- ga_init(&ga, (int)sizeof(char), 80);
- tv_list_join(&ga, argvars[0].vval.v_list, sep);
- ga_append(&ga, NUL);
- rettv->vval.v_string = ga.ga_data;
- } else {
- rettv->vval.v_string = NULL;
- }
-}
-
/// json_decode() function
static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -5432,12 +5233,6 @@ static void f_json_encode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = encode_tv2json(&argvars[0], NULL);
}
-/// "keys()" function
-static void f_keys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- dict_list(argvars, rettv, 0);
-}
-
/// "last_buffer_nr()" function.
static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -5482,7 +5277,7 @@ static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
{
- rettv->v_type = out_type;
+ rettv->v_type = (VarType)out_type;
if (out_type != VAR_NUMBER) {
rettv->vval.v_string = NULL;
}
@@ -5503,7 +5298,7 @@ static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
// input variables
char *str_in = (in_type == VAR_STRING) ? argvars[2].vval.v_string : NULL;
- int int_in = argvars[2].vval.v_number;
+ int int_in = (int)argvars[2].vval.v_number;
// output variables
char **str_out = (out_type == VAR_STRING) ? &rettv->vval.v_string : NULL;
@@ -5594,35 +5389,6 @@ static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "list2str()" function
-static void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- garray_T ga;
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- if (argvars[0].v_type != VAR_LIST) {
- emsg(_(e_invarg));
- return;
- }
-
- list_T *const l = argvars[0].vval.v_list;
- if (l == NULL) {
- return; // empty list results in empty string
- }
-
- ga_init(&ga, 1, 80);
- char buf[MB_MAXBYTES + 1];
-
- TV_LIST_ITER_CONST(l, li, {
- buf[utf_char2bytes(tv_get_number(TV_LIST_ITEM_TV(li)), (char *)buf)] = NUL;
- ga_concat(&ga, (char *)buf);
- });
- ga_append(&ga, NUL);
-
- rettv->vval.v_string = ga.ga_data;
-}
-
/// "localtime()" function
static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -5716,11 +5482,11 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
goto theend;
}
if (l != NULL) {
- idx = tv_list_uidx(l, start);
+ idx = tv_list_uidx(l, (int)start);
if (idx == -1) {
goto theend;
}
- li = tv_list_find(l, idx);
+ li = tv_list_find(l, (int)idx);
} else {
if (start < 0) {
start = 0;
@@ -5732,7 +5498,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
// otherwise skip part of the string. Differs when pattern is "^"
// or "\<".
if (argvars[3].v_type != VAR_UNKNOWN) {
- startcol = start;
+ startcol = (colnr_T)start;
} else {
str += start;
len -= start;
@@ -5976,7 +5742,7 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (argvars[2].v_type != VAR_UNKNOWN) {
- prot = tv_get_number_chk(&argvars[2], NULL);
+ prot = (int)tv_get_number_chk(&argvars[2], NULL);
if (prot == -1) {
return;
}
@@ -6144,7 +5910,7 @@ static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret
msgpack_unpacked_init(&unpacked);
for (size_t offset = 0; offset < (size_t)len;) {
const msgpack_unpack_return result
- = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, len, &offset);
+ = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, (size_t)len, &offset);
if (msgpackparse_convert_item(unpacked.data, result, ret_list, true)
!= OK) {
break;
@@ -6290,9 +6056,9 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *fmt = tv_get_string_buf(&argvars[0], buf);
len = vim_vsnprintf_typval(NULL, 0, fmt, dummy_ap, argvars + 1);
if (!did_emsg) {
- char *s = xmalloc(len + 1);
+ char *s = xmalloc((size_t)len + 1);
rettv->vval.v_string = s;
- (void)vim_vsnprintf_typval(s, len + 1, fmt, dummy_ap, argvars + 1);
+ (void)vim_vsnprintf_typval(s, (size_t)len + 1, fmt, dummy_ap, argvars + 1);
}
did_emsg |= saved_did_emsg;
}
@@ -6436,7 +6202,7 @@ static void init_srand(uint32_t *const x)
// Reading /dev/urandom doesn't work, fall back to time().
#endif
// uncrustify:off
- *x = time(NULL);
+ *x = (uint32_t)time(NULL);
#ifndef MSWIN
}
#endif
@@ -6514,10 +6280,10 @@ static void f_rand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (tvw->v_type != VAR_NUMBER) {
goto theend;
}
- uint32_t x = tvx->vval.v_number;
- uint32_t y = tvy->vval.v_number;
- uint32_t z = tvz->vval.v_number;
- uint32_t w = tvw->vval.v_number;
+ uint32_t x = (uint32_t)tvx->vval.v_number;
+ uint32_t y = (uint32_t)tvy->vval.v_number;
+ uint32_t z = (uint32_t)tvz->vval.v_number;
+ uint32_t w = (uint32_t)tvw->vval.v_number;
result = shuffle_xoshiro128starstar(&x, &y, &z, &w);
@@ -6549,7 +6315,7 @@ static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
init_srand(&x);
} else {
bool error = false;
- x = tv_get_number_chk(&argvars[0], &error);
+ x = (uint32_t)tv_get_number_chk(&argvars[0], &error);
if (error) {
return;
}
@@ -6716,7 +6482,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
while (maxline < 0 || tv_list_len(l) < maxline) {
- readlen = (int)fread(buf, 1, io_size, fd);
+ readlen = (int)fread(buf, 1, (size_t)io_size, fd);
// This for loop processes what was read, but is also entered at end
// of file so that either:
@@ -6730,7 +6496,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p++) {
if (*p == '\n' || readlen <= 0) {
char_u *s = NULL;
- size_t len = p - start;
+ size_t len = (size_t)(p - start);
// Finished a line. Remove CRs before NL.
if (readlen > 0 && !binary) {
@@ -6751,9 +6517,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/* Change "prev" buffer to be the right size. This way
* the bytes are only copied once, and very long lines are
* allocated only once. */
- s = xrealloc(prev, prevlen + len + 1);
+ s = xrealloc(prev, (size_t)prevlen + len + 1);
memcpy(s + prevlen, start, len);
- s[prevlen + len] = NUL;
+ s[(size_t)prevlen + len] = NUL;
prev = NULL; // the list will own the string
prevlen = prevsize = 0;
}
@@ -6808,7 +6574,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dest = buf;
}
if (readlen > p - buf + 1) {
- memmove(dest, p + 1, readlen - (p - buf) - 1);
+ memmove(dest, p + 1, (size_t)readlen - (size_t)(p - buf) - 1);
}
readlen -= 3 - adjust_prevlen;
prevlen -= adjust_prevlen;
@@ -6835,10 +6601,10 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
long growmin = (long)((p - start) * 2 + prevlen);
prevsize = grow50pc > growmin ? grow50pc : growmin;
}
- prev = xrealloc(prev, prevsize);
+ prev = xrealloc(prev, (size_t)prevsize);
}
// Add the line part to end of "prev".
- memmove(prev + prevlen, start, p - start);
+ memmove(prev + prevlen, start, (size_t)(p - start));
prevlen += (long)(p - start);
}
} // while
@@ -6887,7 +6653,7 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
(void)tv_dict_add_str(dict, S_LEN("regtype"), buf);
- buf[0] = get_register_name(get_unname_register());
+ buf[0] = (char)get_register_name(get_unname_register());
buf[1] = NUL;
if (regname == '"') {
(void)tv_dict_add_str(dict, S_LEN("points_to"), buf);
@@ -6938,7 +6704,7 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL
union {
struct { int32_t low, high; } split;
proftime_T prof;
- } u = { .split.high = n1, .split.low = n2 };
+ } u = { .split.high = (int32_t)n1, .split.low = (int32_t)n2 };
*tm = u.prof;
@@ -7008,134 +6774,16 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "remove()" function
static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l;
- listitem_T *item, *item2;
- listitem_T *li;
- long idx;
- long end;
- dict_T *d;
- dictitem_T *di;
const char *const arg_errmsg = N_("remove() argument");
if (argvars[0].v_type == VAR_DICT) {
- if (argvars[2].v_type != VAR_UNKNOWN) {
- semsg(_(e_toomanyarg), "remove()");
- } else if ((d = argvars[0].vval.v_dict) != NULL
- && !var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
- const char *key = tv_get_string_chk(&argvars[1]);
- if (key != NULL) {
- di = tv_dict_find(d, key, -1);
- if (di == NULL) {
- semsg(_(e_dictkey), key);
- } else if (!var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE)
- && !var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) {
- *rettv = di->di_tv;
- di->di_tv = TV_INITIAL_VALUE;
- tv_dict_item_remove(d, di);
- if (tv_dict_is_watched(d)) {
- tv_dict_watcher_notify(d, key, NULL, rettv);
- }
- }
- }
- }
+ tv_dict_remove(argvars, rettv, arg_errmsg);
} else if (argvars[0].v_type == VAR_BLOB) {
- blob_T *const b = argvars[0].vval.v_blob;
-
- if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
- return;
- }
-
- bool error = false;
- idx = (long)tv_get_number_chk(&argvars[1], &error);
-
- if (!error) {
- const int len = tv_blob_len(b);
-
- if (idx < 0) {
- // count from the end
- idx = len + idx;
- }
- if (idx < 0 || idx >= len) {
- semsg(_(e_blobidx), (int64_t)idx);
- return;
- }
- if (argvars[2].v_type == VAR_UNKNOWN) {
- // Remove one item, return its value.
- char_u *const p = (char_u *)b->bv_ga.ga_data;
- rettv->vval.v_number = (varnumber_T)(*(p + idx));
- memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
- b->bv_ga.ga_len--;
- } else {
- // Remove range of items, return blob with values.
- end = (long)tv_get_number_chk(&argvars[2], &error);
- if (error) {
- return;
- }
- if (end < 0) {
- // count from the end
- end = len + end;
- }
- if (end >= len || idx > end) {
- semsg(_(e_blobidx), (int64_t)end);
- return;
- }
- blob_T *const blob = tv_blob_alloc();
- blob->bv_ga.ga_len = end - idx + 1;
- ga_grow(&blob->bv_ga, end - idx + 1);
-
- char_u *const p = (char_u *)b->bv_ga.ga_data;
- memmove((char_u *)blob->bv_ga.ga_data, p + idx,
- (size_t)(end - idx + 1));
- tv_blob_set_ret(rettv, blob);
-
- if (len - end - 1 > 0) {
- memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
- }
- b->bv_ga.ga_len -= end - idx + 1;
- }
- }
- } else if (argvars[0].v_type != VAR_LIST) {
+ tv_blob_remove(argvars, rettv, arg_errmsg);
+ } else if (argvars[0].v_type == VAR_LIST) {
+ tv_list_remove(argvars, rettv, arg_errmsg);
+ } else {
semsg(_(e_listdictblobarg), "remove()");
- } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- arg_errmsg, TV_TRANSLATE)) {
- bool error = false;
-
- idx = tv_get_number_chk(&argvars[1], &error);
- if (error) {
- // Type error: do nothing, errmsg already given.
- } else if ((item = tv_list_find(l, idx)) == NULL) {
- semsg(_(e_listidx), (int64_t)idx);
- } else {
- if (argvars[2].v_type == VAR_UNKNOWN) {
- // Remove one item, return its value.
- tv_list_drop_items(l, item, item);
- *rettv = *TV_LIST_ITEM_TV(item);
- xfree(item);
- } else {
- // Remove range of items, return list with values.
- end = tv_get_number_chk(&argvars[2], &error);
- if (error) {
- // Type error: do nothing.
- } else if ((item2 = tv_list_find(l, end)) == NULL) {
- semsg(_(e_listidx), (int64_t)end);
- } else {
- int cnt = 0;
-
- for (li = item; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
- cnt++;
- if (li == item2) {
- break;
- }
- }
- if (li == NULL) { // Didn't find "item2" after "item".
- emsg(_(e_invrange));
- } else {
- tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt),
- cnt);
- }
- }
- }
- }
}
}
@@ -7173,15 +6821,15 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (slen == 0) {
return;
}
- const size_t len = slen * n;
+ const size_t len = slen * (size_t)n;
// Detect overflow.
- if (len / n != slen) {
+ if (len / (size_t)n != slen) {
return;
}
char *const r = xmallocz(len);
for (varnumber_T i = 0; i < n; i++) {
- memmove(r + i * slen, p, slen);
+ memmove(r + (size_t)i * slen, p, slen);
}
rettv->vval.v_string = r;
@@ -7295,9 +6943,9 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
q = (char *)path_next_component(remain + 1);
len = q - remain - (*q != NUL);
const size_t p_len = strlen(p);
- cpy = xmallocz(p_len + len);
+ cpy = xmallocz(p_len + (size_t)len);
memcpy(cpy, p, p_len + 1);
- xstrlcat(cpy + p_len, remain, len + 1);
+ xstrlcat(cpy + p_len, remain, (size_t)len + 1);
xfree(p);
p = cpy;
@@ -7861,7 +7509,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Allocate extra memory for the argument vector and the NULL pointer
int argvl = argsl + 2;
- char **argv = xmalloc(sizeof(char_u *) * argvl);
+ char **argv = xmalloc(sizeof(char_u *) * (size_t)argvl);
// Copy program name
argv[0] = xstrdup(argvars[0].vval.v_string);
@@ -7904,13 +7552,13 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// if called with a job, stop it, else closes the channel
- uint64_t id = argvars[0].vval.v_number;
+ uint64_t id = (uint64_t)argvars[0].vval.v_number;
if (find_job(id, false)) {
f_jobstop(argvars, rettv, NULL);
} else {
const char *error;
- rettv->vval.v_number = channel_close(argvars[0].vval.v_number,
- kChannelPartRpc, &error);
+ rettv->vval.v_number =
+ channel_close((uint64_t)argvars[0].vval.v_number, kChannelPartRpc, &error);
if (!rettv->vval.v_number) {
emsg(error);
}
@@ -7931,7 +7579,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) {
c = -1;
} else {
- c = grid->attrs[grid->line_offset[row] + col];
+ c = grid->attrs[grid->line_offset[row] + (size_t)col];
}
rettv->vval.v_number = c;
}
@@ -7942,15 +7590,15 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int c;
ScreenGrid *grid;
- int row = tv_get_number_chk(&argvars[0], NULL) - 1;
- int col = tv_get_number_chk(&argvars[1], NULL) - 1;
+ int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
screenchar_adjust(&grid, &row, &col);
if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) {
c = -1;
} else {
- c = utf_ptr2char((char *)grid->chars[grid->line_offset[row] + col]);
+ c = utf_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col]);
}
rettv->vval.v_number = c;
}
@@ -7959,8 +7607,8 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
ScreenGrid *grid;
- int row = tv_get_number_chk(&argvars[0], NULL) - 1;
- int col = tv_get_number_chk(&argvars[1], NULL) - 1;
+ int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
screenchar_adjust(&grid, &row, &col);
@@ -7969,7 +7617,7 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
int pcc[MAX_MCO];
- int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + col], pcc);
+ int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + (size_t)col], pcc);
int composing_len = 0;
while (pcc[composing_len] != 0) {
composing_len++;
@@ -8004,8 +7652,8 @@ static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- pos.lnum = tv_get_number(&argvars[1]);
- pos.col = tv_get_number(&argvars[2]) - 1;
+ pos.lnum = (linenr_T)tv_get_number(&argvars[1]);
+ pos.col = (colnr_T)tv_get_number(&argvars[2]) - 1;
pos.coladd = 0;
textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol, false);
@@ -8028,8 +7676,8 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
ScreenGrid *grid;
- int row = tv_get_number_chk(&argvars[0], NULL) - 1;
- int col = tv_get_number_chk(&argvars[1], NULL) - 1;
+ int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
screenchar_adjust(&grid, &row, &col);
@@ -8037,7 +7685,7 @@ static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_string = (char *)vim_strsave(grid->chars[grid->line_offset[row] + col]);
+ rettv->vval.v_string = (char *)vim_strsave(grid->chars[grid->line_offset[row] + (size_t)col]);
}
/// "search()" function
@@ -8135,8 +7783,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
}
- retval = do_searchpair(spat, mpat, epat, dir, skip,
- flags, match_pos, lnum_stop, time_limit);
+ retval = (int)do_searchpair(spat, mpat, epat, dir, skip,
+ flags, match_pos, (linenr_T)lnum_stop, time_limit);
theend:
p_ws = save_p_ws;
@@ -8363,7 +8011,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char **addrs = server_address_list(&n);
// Copy addrs into a linked list.
- list_T *const l = tv_list_alloc_ret(rettv, n);
+ list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
for (size_t i = 0; i < n; i++) {
tv_list_append_allocated_string(l, addrs[i]);
}
@@ -8450,50 +8098,6 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "setbufvar()" function
-static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- if (check_secure()
- || !tv_check_str_or_nr(&argvars[0])) {
- return;
- }
- const char *varname = tv_get_string_chk(&argvars[1]);
- buf_T *const buf = tv_get_buf(&argvars[0], false);
- typval_T *varp = &argvars[2];
-
- if (buf != NULL && varname != NULL) {
- if (*varname == '&') {
- long numval;
- bool error = false;
- aco_save_T aco;
-
- // set curbuf to be our buf, temporarily
- aucmd_prepbuf(&aco, buf);
-
- varname++;
- numval = tv_get_number_chk(varp, &error);
- char nbuf[NUMBUFLEN];
- const char *const strval = tv_get_string_buf_chk(varp, nbuf);
- if (!error && strval != NULL) {
- set_option_value(varname, numval, strval, OPT_LOCAL);
- }
-
- // reset notion of buffer
- aucmd_restbuf(&aco);
- } else {
- const size_t varname_len = STRLEN(varname);
- char *const bufvarname = xmalloc(varname_len + 3);
- buf_T *const save_curbuf = curbuf;
- curbuf = buf;
- memcpy(bufvarname, "b:", 2);
- memcpy(bufvarname + 2, varname, varname_len + 1);
- set_var(bufvarname, varname_len + 2, varp, true);
- xfree(bufvarname);
- curbuf = save_curbuf;
- }
- }
-}
-
/// Set the cursor or mark position.
/// If 'charpos' is TRUE, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
@@ -8746,7 +8350,7 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *const block_len)
FUNC_ATTR_NONNULL_ALL
{
- char_u *stropt = *pp;
+ char *stropt = (char *)(*pp);
switch (*stropt) {
case 'v':
case 'c': // character-wise selection
@@ -8768,7 +8372,7 @@ static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *c
default:
return FAIL;
}
- *pp = stropt;
+ *pp = (char_u *)stropt;
return OK;
}
@@ -8788,7 +8392,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (strregname == NULL) {
return; // Type error; errmsg already given.
}
- char regname = (uint8_t)(*strregname);
+ char regname = *strregname;
if (regname == 0 || regname == '@') {
regname = '"';
}
@@ -8867,7 +8471,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// First half: use for pointers to result lines; second half: use for
// pointers to allocated copies.
- char **lstval = xmalloc(sizeof(char *) * ((len + 1) * 2));
+ char **lstval = xmalloc(sizeof(char *) * (((size_t)len + 1) * 2));
const char **curval = (const char **)lstval;
char **allocval = lstval + len + 2;
char **curallocval = allocval;
@@ -8889,8 +8493,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
});
*curval++ = NULL;
- write_reg_contents_lst(regname, (char_u **)lstval, append, yank_type,
- block_len);
+ write_reg_contents_lst(regname, (char_u **)lstval, append, yank_type, (colnr_T)block_len);
free_lstval:
while (curallocval > allocval) {
@@ -8902,8 +8505,8 @@ free_lstval:
if (strval == NULL) {
return;
}
- write_reg_contents_ex(regname, (const char_u *)strval, STRLEN(strval),
- append, yank_type, block_len);
+ write_reg_contents_ex(regname, (const char_u *)strval, (ssize_t)STRLEN(strval),
+ append, yank_type, (colnr_T)block_len);
}
if (pointreg != 0) {
get_yank_register(pointreg, YREG_YANK);
@@ -8916,43 +8519,6 @@ free_lstval:
}
}
-/// "settabvar()" function
-static void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- rettv->vval.v_number = 0;
-
- if (check_secure()) {
- return;
- }
-
- tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- const char *const varname = tv_get_string_chk(&argvars[1]);
- typval_T *const varp = &argvars[2];
-
- if (varname != NULL && tp != NULL) {
- tabpage_T *const save_curtab = curtab;
- goto_tabpage_tp(tp, false, false);
-
- const size_t varname_len = strlen(varname);
- char *const tabvarname = xmalloc(varname_len + 3);
- memcpy(tabvarname, "t:", 2);
- memcpy(tabvarname + 2, varname, varname_len + 1);
- set_var(tabvarname, varname_len + 2, varp, true);
- xfree(tabvarname);
-
- // Restore current tabpage.
- if (valid_tabpage(save_curtab)) {
- goto_tabpage_tp(save_curtab, false, false);
- }
- }
-}
-
-/// "settabwinvar()" function
-static void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- setwinvar(argvars, rettv, 1);
-}
-
/// "settagstack()" function
static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -9006,12 +8572,6 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "setwinvar()" function
-static void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- setwinvar(argvars, rettv, 0);
-}
-
/// f_sha256 - sha256({string}) function
static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -9046,7 +8606,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (col < 0) {
return; // type error; errmsg already given
}
- rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ rettv->vval.v_number = get_sw_value_col(curbuf, (colnr_T)col);
return;
}
rettv->vval.v_number = get_sw_value(curbuf);
@@ -9113,341 +8673,6 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_NUMBER;
}
-/// struct storing information about current sort
-typedef struct {
- int item_compare_ic;
- bool item_compare_lc;
- bool item_compare_numeric;
- bool item_compare_numbers;
- bool item_compare_float;
- const char *item_compare_func;
- partial_T *item_compare_partial;
- dict_T *item_compare_selfdict;
- bool item_compare_func_err;
-} sortinfo_T;
-static sortinfo_T *sortinfo = NULL;
-
-#define ITEM_COMPARE_FAIL 999
-
-/// Compare functions for f_sort() and f_uniq() below.
-static int item_compare(const void *s1, const void *s2, bool keep_zero)
-{
- ListSortItem *const si1 = (ListSortItem *)s1;
- ListSortItem *const si2 = (ListSortItem *)s2;
-
- typval_T *const tv1 = TV_LIST_ITEM_TV(si1->item);
- typval_T *const tv2 = TV_LIST_ITEM_TV(si2->item);
-
- int res;
-
- if (sortinfo->item_compare_numbers) {
- const varnumber_T v1 = tv_get_number(tv1);
- const varnumber_T v2 = tv_get_number(tv2);
-
- res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
- goto item_compare_end;
- }
-
- if (sortinfo->item_compare_float) {
- const float_T v1 = tv_get_float(tv1);
- const float_T v2 = tv_get_float(tv2);
-
- res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
- goto item_compare_end;
- }
-
- char *tofree1 = NULL;
- char *tofree2 = NULL;
- char *p1;
- char *p2;
-
- // encode_tv2string() puts quotes around a string and allocates memory. Don't
- // do that for string variables. Use a single quote when comparing with
- // a non-string to do what the docs promise.
- if (tv1->v_type == VAR_STRING) {
- if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
- p1 = "'";
- } else {
- p1 = tv1->vval.v_string;
- }
- } else {
- tofree1 = p1 = encode_tv2string(tv1, NULL);
- }
- if (tv2->v_type == VAR_STRING) {
- if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
- p2 = "'";
- } else {
- p2 = tv2->vval.v_string;
- }
- } else {
- tofree2 = p2 = encode_tv2string(tv2, NULL);
- }
- if (p1 == NULL) {
- p1 = "";
- }
- if (p2 == NULL) {
- p2 = "";
- }
- if (!sortinfo->item_compare_numeric) {
- if (sortinfo->item_compare_lc) {
- res = strcoll(p1, p2);
- } else {
- res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);
- }
- } else {
- double n1, n2;
- n1 = strtod(p1, &p1);
- n2 = strtod(p2, &p2);
- res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
- }
-
- xfree(tofree1);
- xfree(tofree2);
-
-item_compare_end:
- // When the result would be zero, compare the item indexes. Makes the
- // sort stable.
- if (res == 0 && !keep_zero) {
- // WARNING: When using uniq si1 and si2 are actually listitem_T **, no
- // indexes are there.
- res = si1->idx > si2->idx ? 1 : -1;
- }
- return res;
-}
-
-static int item_compare_keeping_zero(const void *s1, const void *s2)
-{
- return item_compare(s1, s2, true);
-}
-
-static int item_compare_not_keeping_zero(const void *s1, const void *s2)
-{
- return item_compare(s1, s2, false);
-}
-
-static int item_compare2(const void *s1, const void *s2, bool keep_zero)
-{
- ListSortItem *si1, *si2;
- int res;
- typval_T rettv;
- typval_T argv[3];
- const char *func_name;
- partial_T *partial = sortinfo->item_compare_partial;
-
- // shortcut after failure in previous call; compare all items equal
- if (sortinfo->item_compare_func_err) {
- return 0;
- }
-
- si1 = (ListSortItem *)s1;
- si2 = (ListSortItem *)s2;
-
- if (partial == NULL) {
- func_name = sortinfo->item_compare_func;
- } else {
- func_name = (const char *)partial_name(partial);
- }
-
- // Copy the values. This is needed to be able to set v_lock to VAR_FIXED
- // in the copy without changing the original list items.
- tv_copy(TV_LIST_ITEM_TV(si1->item), &argv[0]);
- tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
-
- rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.evaluate = true;
- funcexe.partial = partial;
- funcexe.selfdict = sortinfo->item_compare_selfdict;
- res = call_func(func_name, -1, &rettv, 2, argv, &funcexe);
- tv_clear(&argv[0]);
- tv_clear(&argv[1]);
-
- if (res == FAIL) {
- res = ITEM_COMPARE_FAIL;
- } else {
- res = tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
- if (res > 0) {
- res = 1;
- } else if (res < 0) {
- res = -1;
- }
- }
- if (sortinfo->item_compare_func_err) {
- res = ITEM_COMPARE_FAIL; // return value has wrong type
- }
- tv_clear(&rettv);
-
- // When the result would be zero, compare the pointers themselves. Makes
- // the sort stable.
- if (res == 0 && !keep_zero) {
- // WARNING: When using uniq si1 and si2 are actually listitem_T **, no
- // indexes are there.
- res = si1->idx > si2->idx ? 1 : -1;
- }
-
- return res;
-}
-
-static int item_compare2_keeping_zero(const void *s1, const void *s2)
-{
- return item_compare2(s1, s2, true);
-}
-
-static int item_compare2_not_keeping_zero(const void *s1, const void *s2)
-{
- return item_compare2(s1, s2, false);
-}
-
-/// "sort({list})" function
-static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
-{
- ListSortItem *ptrs;
- long len;
- long i;
-
- // Pointer to current info struct used in compare function. Save and restore
- // the current one for nested calls.
- sortinfo_T info;
- sortinfo_T *old_sortinfo = sortinfo;
- sortinfo = &info;
-
- const char *const arg_errmsg = (sort
- ? N_("sort() argument")
- : N_("uniq() argument"));
-
- if (argvars[0].v_type != VAR_LIST) {
- semsg(_(e_listarg), sort ? "sort()" : "uniq()");
- } else {
- list_T *const l = argvars[0].vval.v_list;
- if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
- goto theend;
- }
- tv_list_set_ret(rettv, l);
-
- len = tv_list_len(l);
- if (len <= 1) {
- goto theend; // short list sorts pretty quickly
- }
-
- info.item_compare_ic = false;
- info.item_compare_lc = false;
- info.item_compare_numeric = false;
- info.item_compare_numbers = false;
- info.item_compare_float = false;
- info.item_compare_func = NULL;
- info.item_compare_partial = NULL;
- info.item_compare_selfdict = NULL;
-
- if (argvars[1].v_type != VAR_UNKNOWN) {
- // optional second argument: {func}
- if (argvars[1].v_type == VAR_FUNC) {
- info.item_compare_func = (const char *)argvars[1].vval.v_string;
- } else if (argvars[1].v_type == VAR_PARTIAL) {
- info.item_compare_partial = argvars[1].vval.v_partial;
- } else {
- bool error = false;
-
- i = tv_get_number_chk(&argvars[1], &error);
- if (error) {
- goto theend; // type error; errmsg already given
- }
- if (i == 1) {
- info.item_compare_ic = true;
- } else if (argvars[1].v_type != VAR_NUMBER) {
- info.item_compare_func = tv_get_string(&argvars[1]);
- } else if (i != 0) {
- emsg(_(e_invarg));
- goto theend;
- }
- if (info.item_compare_func != NULL) {
- if (*info.item_compare_func == NUL) {
- // empty string means default sort
- info.item_compare_func = NULL;
- } else if (strcmp(info.item_compare_func, "n") == 0) {
- info.item_compare_func = NULL;
- info.item_compare_numeric = true;
- } else if (strcmp(info.item_compare_func, "N") == 0) {
- info.item_compare_func = NULL;
- info.item_compare_numbers = true;
- } else if (strcmp(info.item_compare_func, "f") == 0) {
- info.item_compare_func = NULL;
- info.item_compare_float = true;
- } else if (strcmp(info.item_compare_func, "i") == 0) {
- info.item_compare_func = NULL;
- info.item_compare_ic = true;
- } else if (strcmp(info.item_compare_func, "l") == 0) {
- info.item_compare_func = NULL;
- info.item_compare_lc = true;
- }
- }
- }
-
- if (argvars[2].v_type != VAR_UNKNOWN) {
- // optional third argument: {dict}
- if (argvars[2].v_type != VAR_DICT) {
- emsg(_(e_dictreq));
- goto theend;
- }
- info.item_compare_selfdict = argvars[2].vval.v_dict;
- }
- }
-
- // Make an array with each entry pointing to an item in the List.
- ptrs = xmalloc((size_t)(len * sizeof(ListSortItem)));
-
- if (sort) {
- info.item_compare_func_err = false;
- tv_list_item_sort(l, ptrs,
- ((info.item_compare_func == NULL
- && info.item_compare_partial == NULL)
- ? item_compare_not_keeping_zero
- : item_compare2_not_keeping_zero),
- &info.item_compare_func_err);
- if (info.item_compare_func_err) {
- emsg(_("E702: Sort compare function failed"));
- }
- } else {
- ListSorter item_compare_func_ptr;
-
- // f_uniq(): ptrs will be a stack of items to remove.
- info.item_compare_func_err = false;
- if (info.item_compare_func != NULL
- || info.item_compare_partial != NULL) {
- item_compare_func_ptr = item_compare2_keeping_zero;
- } else {
- item_compare_func_ptr = item_compare_keeping_zero;
- }
-
- int idx = 0;
- for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l))
- ; 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) { // -V547
- emsg(_("E882: Uniq compare function failed"));
- break;
- }
- li = tv_list_item_remove(l, li);
- } else {
- idx++;
- li = TV_LIST_ITEM_NEXT(l, li);
- }
- }
- }
-
- xfree(ptrs);
- }
-
-theend:
- sortinfo = old_sortinfo;
-}
-
-/// "sort"({list})" function
-static void f_sort(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- do_sort_uniq(argvars, rettv, true);
-}
-
/// "stdioopen()" function
static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -9483,12 +8708,6 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_NUMBER;
}
-/// "uniq({list})" function
-static void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- do_sort_uniq(argvars, rettv, false);
-}
-
/// "reltimefloat()" function
static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
@@ -9549,7 +8768,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
}
str += len;
- capcol -= len;
+ capcol -= (int)len;
len = 0;
}
}
@@ -9558,7 +8777,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
assert(len <= INT_MAX);
tv_list_alloc_ret(rettv, 2);
- tv_list_append_string(rettv->vval.v_list, word, len);
+ tv_list_append_string(rettv->vval.v_list, word, (ssize_t)len);
tv_list_append_string(rettv->vval.v_list,
(attr == HLF_SPB ? "bad"
: attr == HLF_SPR ? "rare"
@@ -9591,7 +8810,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const str = tv_get_string(&argvars[0]);
if (argvars[1].v_type != VAR_UNKNOWN) {
- maxcount = tv_get_number_chk(&argvars[1], &typeerr);
+ maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
if (maxcount <= 0) {
goto f_spellsuggest_return;
}
@@ -9763,7 +8982,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int what = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- base = tv_get_number(&argvars[1]);
+ base = (int)tv_get_number(&argvars[1]);
if (base != 2 && base != 8 && base != 10 && base != 16) {
emsg(_(e_invarg));
return;
@@ -9874,7 +9093,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
}
charidx--;
- byteidx += utf_ptr2len(str + byteidx);
+ byteidx += (size_t)utf_ptr2len(str + byteidx);
}
}
@@ -9932,7 +9151,7 @@ static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int (*func_mb_ptr2char_adv)(const char_u **pp);
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = tv_get_number_chk(&argvars[1], NULL);
+ skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
}
if (skipcc < 0 || skipcc > 1) {
emsg(_(e_invarg));
@@ -9953,7 +9172,7 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int col = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- col = tv_get_number(&argvars[1]);
+ col = (int)tv_get_number(&argvars[1]);
}
rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char_u *)s) - col);
@@ -9983,12 +9202,12 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
nchar--;
}
} else {
- nbyte = nchar;
+ nbyte = (int)nchar;
}
}
int len = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
- int charlen = tv_get_number(&argvars[2]);
+ int charlen = (int)tv_get_number(&argvars[2]);
while (charlen > 0 && nbyte + len < (int)slen) {
int off = nbyte + len;
@@ -10000,7 +9219,7 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
charlen--;
}
} else {
- len = slen - nbyte; // default: all bytes that are available.
+ len = (int)slen - nbyte; // default: all bytes that are available.
}
// Only return the overlap between the specified part and the actual
@@ -10009,12 +9228,12 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
len += nbyte;
nbyte = 0;
} else if ((size_t)nbyte > slen) {
- nbyte = slen;
+ nbyte = (int)slen;
}
if (len < 0) {
len = 0;
} else if (nbyte + len > (int)slen) {
- len = slen - nbyte;
+ len = (int)slen - nbyte;
}
rettv->v_type = VAR_STRING;
@@ -10036,7 +9255,7 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else if (argvars[2].v_type != VAR_UNKNOWN) {
len = tv_get_number(&argvars[2]);
} else {
- len = slen - n; // Default len: all bytes that are available.
+ len = (varnumber_T)slen - n; // Default len: all bytes that are available.
}
// Only return the overlap between the specified part and the actual
@@ -10045,19 +9264,19 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
len += n;
n = 0;
} else if (n > (varnumber_T)slen) {
- n = slen;
+ n = (varnumber_T)slen;
}
if (len < 0) {
len = 0;
} else if (n + len > (varnumber_T)slen) {
- len = slen - n;
+ len = (varnumber_T)slen - n;
}
if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) {
int off;
// length in characters
- for (off = n; off < (int)slen && len > 0; len--) {
+ for (off = (int)n; off < (int)slen && len > 0; len--) {
off += utfc_ptr2len(p + off);
}
len = off - n;
@@ -10165,7 +9384,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int retList = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- retList = tv_get_number_chk(&argvars[1], &error);
+ retList = (int)tv_get_number_chk(&argvars[1], &error);
if (error) {
return;
}
@@ -10238,7 +9457,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1;
bool transerr = false;
- const int trans = tv_get_number_chk(&argvars[2], &transerr);
+ const int trans = (int)tv_get_number_chk(&argvars[2], &transerr);
int id = 0;
if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
@@ -10287,8 +9506,12 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p = highlight_has_attr(id, HL_ITALIC, modec);
}
break;
- case 'n': // name
- p = get_highlight_name_ext(NULL, id - 1, false);
+ case 'n':
+ if (TOLOWER_ASC(what[1]) == 'o') { // nocombine
+ p = highlight_has_attr(id, HL_NOCOMBINE, modec);
+ } else { // name
+ p = get_highlight_name_ext(NULL, id - 1, false);
+ }
break;
case 'r': // reverse
p = highlight_has_attr(id, HL_INVERSE, modec);
@@ -10335,7 +9558,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "synIDtrans(id)" function
static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int id = tv_get_number(&argvars[0]);
+ int id = (int)tv_get_number(&argvars[0]);
if (id > 0) {
id = syn_get_final_id(id);
@@ -10662,10 +9885,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const bool overlapped = false;
const bool detach = false;
ChannelStdinMode stdin_mode = kChannelStdinPipe;
- uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin));
+ uint16_t term_width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin));
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
pty, rpc, overlapped, detach, stdin_mode,
- cwd, term_width, curwin->w_height_inner,
+ cwd, term_width, (uint16_t)curwin->w_height_inner,
env, &rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
return;
@@ -10699,7 +9922,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Error err = ERROR_INIT;
// deprecated: use 'channel' buffer option
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
- INTEGER_OBJ(chan->id), false, false, &err);
+ INTEGER_OBJ((Integer)chan->id), false, false, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
INTEGER_OBJ(pid), false, false, &err);
@@ -10740,8 +9963,8 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr)
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);
+ time_watcher_start(&timer->tw, timer_due_cb, (uint64_t)timer->timeout,
+ (uint64_t)timer->timeout);
}
timer->paused = paused;
}
@@ -10766,7 +9989,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
dictitem_T *const di = tv_dict_find(dict, S_LEN("repeat"));
if (di != NULL) {
- repeat = tv_get_number(&di->di_tv);
+ repeat = (int)tv_get_number(&di->di_tv);
if (repeat == 0) {
repeat = 1;
}
@@ -10777,8 +10000,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (!callback_from_typval(&callback, &argvars[1])) {
return;
}
- rettv->vval.v_number =
- timer_start(tv_get_number(&argvars[0]), repeat, &callback);
+ rettv->vval.v_number = (varnumber_T)timer_start(tv_get_number(&argvars[0]), repeat, &callback);
}
/// "timer_stop(timerid)" function
@@ -10975,7 +10197,7 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- rettv->vval.v_string = (char *)vim_strnsave(head, tail - head);
+ rettv->vval.v_string = (char *)vim_strnsave(head, (size_t)(tail - head));
}
/// "type(expr)" function
@@ -11047,12 +10269,6 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_list(dict, S_LEN("entries"), u_eval_tree(curbuf->b_u_oldhead));
}
-/// "values(dict)" function
-static void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr)
-{
- dict_list(argvars, rettv, 1);
-}
-
/// "virtcol(string)" function
static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -11085,7 +10301,7 @@ static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char_u str[2];
rettv->v_type = VAR_STRING;
- str[0] = curbuf->b_visual_mode_eval;
+ str[0] = (char_u)curbuf->b_visual_mode_eval;
str[1] = NUL;
rettv->vval.v_string = (char *)vim_strsave(str);
@@ -11299,29 +10515,29 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
dictitem_T *di;
if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
- curwin->w_cursor.lnum = tv_get_number(&di->di_tv);
+ curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
}
if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
- curwin->w_cursor.col = tv_get_number(&di->di_tv);
+ curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
}
if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
- curwin->w_cursor.coladd = tv_get_number(&di->di_tv);
+ curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
}
if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
- curwin->w_curswant = tv_get_number(&di->di_tv);
+ curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
curwin->w_set_curswant = false;
}
if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
- set_topline(curwin, tv_get_number(&di->di_tv));
+ set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
}
if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
- curwin->w_topfill = tv_get_number(&di->di_tv);
+ curwin->w_topfill = (int)tv_get_number(&di->di_tv);
}
if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
- curwin->w_leftcol = tv_get_number(&di->di_tv);
+ curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
}
if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
- curwin->w_skipcol = tv_get_number(&di->di_tv);
+ curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
}
check_cursor();
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index 5f8d81c989..583ee0e75e 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -4,8 +4,6 @@
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
-typedef void (*FunPtr)(void);
-
/// Prototype of C function that implements VimL function
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index e19cf411c0..fd57b45e86 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -19,6 +19,7 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/garray.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
@@ -829,6 +830,454 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
return retval;
}
+/// "join()" function
+void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if (argvars[0].v_type != VAR_LIST) {
+ emsg(_(e_listreq));
+ return;
+ }
+ const char *const sep = (argvars[1].v_type == VAR_UNKNOWN
+ ? " "
+ : tv_get_string_chk(&argvars[1]));
+
+ rettv->v_type = VAR_STRING;
+
+ if (sep != NULL) {
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 80);
+ tv_list_join(&ga, argvars[0].vval.v_list, sep);
+ ga_append(&ga, NUL);
+ rettv->vval.v_string = ga.ga_data;
+ } else {
+ rettv->vval.v_string = NULL;
+ }
+}
+
+/// "list2str()" function
+void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ garray_T ga;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (argvars[0].v_type != VAR_LIST) {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ list_T *const l = argvars[0].vval.v_list;
+ if (l == NULL) {
+ return; // empty list results in empty string
+ }
+
+ ga_init(&ga, 1, 80);
+ char buf[MB_MAXBYTES + 1];
+
+ TV_LIST_ITER_CONST(l, li, {
+ buf[utf_char2bytes((int)tv_get_number(TV_LIST_ITEM_TV(li)), (char *)buf)] = NUL;
+ ga_concat(&ga, (char *)buf);
+ });
+ ga_append(&ga, NUL);
+
+ rettv->vval.v_string = ga.ga_data;
+}
+
+/// "remove({list})" function
+void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
+{
+ list_T *l;
+ bool error = false;
+
+ if (var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
+
+ long idx = tv_get_number_chk(&argvars[1], &error);
+
+ listitem_T *item;
+
+ if (error) {
+ // Type error: do nothing, errmsg already given.
+ } else if ((item = tv_list_find(l, (int)idx)) == NULL) {
+ semsg(_(e_listidx), (int64_t)idx);
+ } else {
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ // Remove one item, return its value.
+ tv_list_drop_items(l, item, item);
+ *rettv = *TV_LIST_ITEM_TV(item);
+ xfree(item);
+ } else {
+ listitem_T *item2;
+ // Remove range of items, return list with values.
+ long end = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ // Type error: do nothing.
+ } else if ((item2 = tv_list_find(l, (int)end)) == NULL) {
+ semsg(_(e_listidx), (int64_t)end);
+ } else {
+ int cnt = 0;
+
+ listitem_T *li;
+ for (li = item; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
+ cnt++;
+ if (li == item2) {
+ break;
+ }
+ }
+ if (li == NULL) { // Didn't find "item2" after "item".
+ emsg(_(e_invrange));
+ } else {
+ tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt),
+ cnt);
+ }
+ }
+ }
+ }
+}
+
+/// struct storing information about current sort
+typedef struct {
+ int item_compare_ic;
+ bool item_compare_lc;
+ bool item_compare_numeric;
+ bool item_compare_numbers;
+ bool item_compare_float;
+ const char *item_compare_func;
+ partial_T *item_compare_partial;
+ dict_T *item_compare_selfdict;
+ bool item_compare_func_err;
+} sortinfo_T;
+static sortinfo_T *sortinfo = NULL;
+
+#define ITEM_COMPARE_FAIL 999
+
+/// Compare functions for f_sort() and f_uniq() below.
+static int item_compare(const void *s1, const void *s2, bool keep_zero)
+{
+ ListSortItem *const si1 = (ListSortItem *)s1;
+ ListSortItem *const si2 = (ListSortItem *)s2;
+
+ typval_T *const tv1 = TV_LIST_ITEM_TV(si1->item);
+ typval_T *const tv2 = TV_LIST_ITEM_TV(si2->item);
+
+ int res;
+
+ if (sortinfo->item_compare_numbers) {
+ const varnumber_T v1 = tv_get_number(tv1);
+ const varnumber_T v2 = tv_get_number(tv2);
+
+ res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ goto item_compare_end;
+ }
+
+ if (sortinfo->item_compare_float) {
+ const float_T v1 = tv_get_float(tv1);
+ const float_T v2 = tv_get_float(tv2);
+
+ res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ goto item_compare_end;
+ }
+
+ char *tofree1 = NULL;
+ char *tofree2 = NULL;
+ char *p1;
+ char *p2;
+
+ // encode_tv2string() puts quotes around a string and allocates memory. Don't
+ // do that for string variables. Use a single quote when comparing with
+ // a non-string to do what the docs promise.
+ if (tv1->v_type == VAR_STRING) {
+ if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
+ p1 = "'";
+ } else {
+ p1 = tv1->vval.v_string;
+ }
+ } else {
+ tofree1 = p1 = encode_tv2string(tv1, NULL);
+ }
+ if (tv2->v_type == VAR_STRING) {
+ if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
+ p2 = "'";
+ } else {
+ p2 = tv2->vval.v_string;
+ }
+ } else {
+ tofree2 = p2 = encode_tv2string(tv2, NULL);
+ }
+ if (p1 == NULL) {
+ p1 = "";
+ }
+ if (p2 == NULL) {
+ p2 = "";
+ }
+ if (!sortinfo->item_compare_numeric) {
+ if (sortinfo->item_compare_lc) {
+ res = strcoll(p1, p2);
+ } else {
+ res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);
+ }
+ } else {
+ double n1, n2;
+ n1 = strtod(p1, &p1);
+ n2 = strtod(p2, &p2);
+ res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
+ }
+
+ xfree(tofree1);
+ xfree(tofree2);
+
+item_compare_end:
+ // When the result would be zero, compare the item indexes. Makes the
+ // sort stable.
+ if (res == 0 && !keep_zero) {
+ // WARNING: When using uniq si1 and si2 are actually listitem_T **, no
+ // indexes are there.
+ res = si1->idx > si2->idx ? 1 : -1;
+ }
+ return res;
+}
+
+static int item_compare_keeping_zero(const void *s1, const void *s2)
+{
+ return item_compare(s1, s2, true);
+}
+
+static int item_compare_not_keeping_zero(const void *s1, const void *s2)
+{
+ return item_compare(s1, s2, false);
+}
+
+static int item_compare2(const void *s1, const void *s2, bool keep_zero)
+{
+ ListSortItem *si1, *si2;
+ int res;
+ typval_T rettv;
+ typval_T argv[3];
+ const char *func_name;
+ partial_T *partial = sortinfo->item_compare_partial;
+
+ // shortcut after failure in previous call; compare all items equal
+ if (sortinfo->item_compare_func_err) {
+ return 0;
+ }
+
+ si1 = (ListSortItem *)s1;
+ si2 = (ListSortItem *)s2;
+
+ if (partial == NULL) {
+ func_name = sortinfo->item_compare_func;
+ } else {
+ func_name = (const char *)partial_name(partial);
+ }
+
+ // Copy the values. This is needed to be able to set v_lock to VAR_FIXED
+ // in the copy without changing the original list items.
+ tv_copy(TV_LIST_ITEM_TV(si1->item), &argv[0]);
+ tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
+
+ rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = sortinfo->item_compare_selfdict;
+ res = call_func(func_name, -1, &rettv, 2, argv, &funcexe);
+ tv_clear(&argv[0]);
+ tv_clear(&argv[1]);
+
+ if (res == FAIL) {
+ res = ITEM_COMPARE_FAIL;
+ } else {
+ res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ if (res > 0) {
+ res = 1;
+ } else if (res < 0) {
+ res = -1;
+ }
+ }
+ if (sortinfo->item_compare_func_err) {
+ res = ITEM_COMPARE_FAIL; // return value has wrong type
+ }
+ tv_clear(&rettv);
+
+ // When the result would be zero, compare the pointers themselves. Makes
+ // the sort stable.
+ if (res == 0 && !keep_zero) {
+ // WARNING: When using uniq si1 and si2 are actually listitem_T **, no
+ // indexes are there.
+ res = si1->idx > si2->idx ? 1 : -1;
+ }
+
+ return res;
+}
+
+static int item_compare2_keeping_zero(const void *s1, const void *s2)
+{
+ return item_compare2(s1, s2, true);
+}
+
+static int item_compare2_not_keeping_zero(const void *s1, const void *s2)
+{
+ return item_compare2(s1, s2, false);
+}
+
+/// "sort({list})" function
+static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
+{
+ ListSortItem *ptrs;
+ long len;
+ long i;
+
+ // Pointer to current info struct used in compare function. Save and restore
+ // the current one for nested calls.
+ sortinfo_T info;
+ sortinfo_T *old_sortinfo = sortinfo;
+ sortinfo = &info;
+
+ const char *const arg_errmsg = (sort
+ ? N_("sort() argument")
+ : N_("uniq() argument"));
+
+ if (argvars[0].v_type != VAR_LIST) {
+ semsg(_(e_listarg), sort ? "sort()" : "uniq()");
+ } else {
+ list_T *const l = argvars[0].vval.v_list;
+ if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
+ goto theend;
+ }
+ tv_list_set_ret(rettv, l);
+
+ len = tv_list_len(l);
+ if (len <= 1) {
+ goto theend; // short list sorts pretty quickly
+ }
+
+ info.item_compare_ic = false;
+ info.item_compare_lc = false;
+ info.item_compare_numeric = false;
+ info.item_compare_numbers = false;
+ info.item_compare_float = false;
+ info.item_compare_func = NULL;
+ info.item_compare_partial = NULL;
+ info.item_compare_selfdict = NULL;
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ // optional second argument: {func}
+ if (argvars[1].v_type == VAR_FUNC) {
+ info.item_compare_func = (const char *)argvars[1].vval.v_string;
+ } else if (argvars[1].v_type == VAR_PARTIAL) {
+ info.item_compare_partial = argvars[1].vval.v_partial;
+ } else {
+ bool error = false;
+
+ i = tv_get_number_chk(&argvars[1], &error);
+ if (error) {
+ goto theend; // type error; errmsg already given
+ }
+ if (i == 1) {
+ info.item_compare_ic = true;
+ } else if (argvars[1].v_type != VAR_NUMBER) {
+ info.item_compare_func = tv_get_string(&argvars[1]);
+ } else if (i != 0) {
+ emsg(_(e_invarg));
+ goto theend;
+ }
+ if (info.item_compare_func != NULL) {
+ if (*info.item_compare_func == NUL) {
+ // empty string means default sort
+ info.item_compare_func = NULL;
+ } else if (strcmp(info.item_compare_func, "n") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numeric = true;
+ } else if (strcmp(info.item_compare_func, "N") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_numbers = true;
+ } else if (strcmp(info.item_compare_func, "f") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_float = true;
+ } else if (strcmp(info.item_compare_func, "i") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_ic = true;
+ } else if (strcmp(info.item_compare_func, "l") == 0) {
+ info.item_compare_func = NULL;
+ info.item_compare_lc = true;
+ }
+ }
+ }
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ // optional third argument: {dict}
+ if (argvars[2].v_type != VAR_DICT) {
+ emsg(_(e_dictreq));
+ goto theend;
+ }
+ info.item_compare_selfdict = argvars[2].vval.v_dict;
+ }
+ }
+
+ // Make an array with each entry pointing to an item in the List.
+ ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem)));
+
+ if (sort) {
+ info.item_compare_func_err = false;
+ tv_list_item_sort(l, ptrs,
+ ((info.item_compare_func == NULL
+ && info.item_compare_partial == NULL)
+ ? item_compare_not_keeping_zero
+ : item_compare2_not_keeping_zero),
+ &info.item_compare_func_err);
+ if (info.item_compare_func_err) {
+ emsg(_("E702: Sort compare function failed"));
+ }
+ } else {
+ ListSorter item_compare_func_ptr;
+
+ // f_uniq(): ptrs will be a stack of items to remove.
+ info.item_compare_func_err = false;
+ if (info.item_compare_func != NULL
+ || info.item_compare_partial != NULL) {
+ item_compare_func_ptr = item_compare2_keeping_zero;
+ } else {
+ item_compare_func_ptr = item_compare_keeping_zero;
+ }
+
+ int idx = 0;
+ for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l))
+ ; 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) { // -V547
+ emsg(_("E882: Uniq compare function failed"));
+ break;
+ }
+ li = tv_list_item_remove(l, li);
+ } else {
+ idx++;
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+ }
+ }
+
+ xfree(ptrs);
+ }
+
+theend:
+ sortinfo = old_sortinfo;
+}
+
+/// "sort"({list})" function
+void f_sort(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ do_sort_uniq(argvars, rettv, true);
+}
+
+/// "uniq({list})" function
+void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ do_sort_uniq(argvars, rettv, false);
+}
+
/// Check whether two lists are equal
///
/// @param[in] l1 First list to compare.
@@ -2199,6 +2648,66 @@ bool tv_blob_equal(const blob_T *const b1, const blob_T *const b2)
return true;
}
+/// "remove({blob})" function
+void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
+{
+ blob_T *const b = argvars[0].vval.v_blob;
+
+ if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
+
+ bool error = false;
+ long idx = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ const int len = tv_blob_len(b);
+
+ if (idx < 0) {
+ // count from the end
+ idx = len + idx;
+ }
+ if (idx < 0 || idx >= len) {
+ semsg(_(e_blobidx), (int64_t)idx);
+ return;
+ }
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ // Remove one item, return its value.
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ rettv->vval.v_number = (varnumber_T)(*(p + idx));
+ memmove(p + idx, p + idx + 1, (size_t)(len - idx - 1));
+ b->bv_ga.ga_len--;
+ } else {
+ // Remove range of items, return blob with values.
+ long end = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (end < 0) {
+ // count from the end
+ end = len + end;
+ }
+ if (end >= len || idx > end) {
+ semsg(_(e_blobidx), (int64_t)end);
+ return;
+ }
+ blob_T *const blob = tv_blob_alloc();
+ blob->bv_ga.ga_len = (int)(end - idx + 1);
+ ga_grow(&blob->bv_ga, (int)(end - idx + 1));
+
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ memmove((char_u *)blob->bv_ga.ga_data, p + idx,
+ (size_t)(end - idx + 1));
+ tv_blob_set_ret(rettv, blob);
+
+ if (len - end - 1 > 0) {
+ memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
+ }
+ b->bv_ga.ga_len -= (int)(end - idx + 1);
+ }
+ }
+}
+
//{{{1 Generic typval operations
//{{{2 Init/alloc/clear
//{{{3 Alloc
@@ -2243,6 +2752,118 @@ void tv_dict_alloc_ret(typval_T *const ret_tv)
tv_dict_set_ret(ret_tv, d);
}
+/// Turn a dictionary into a list
+///
+/// @param[in] tv Dictionary to convert. Is checked for actually being
+/// a dictionary, will give an error if not.
+/// @param[out] rettv Location where result will be saved.
+/// @param[in] what What to save in rettv.
+static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictListType what)
+{
+ if (tv->v_type != VAR_DICT) {
+ emsg(_(e_dictreq));
+ return;
+ }
+ if (tv->vval.v_dict == NULL) {
+ return;
+ }
+
+ tv_list_alloc_ret(rettv, tv_dict_len(tv->vval.v_dict));
+
+ TV_DICT_ITER(tv->vval.v_dict, di, {
+ typval_T tv_item = { .v_lock = VAR_UNLOCKED };
+
+ switch (what) {
+ case kDictListKeys:
+ tv_item.v_type = VAR_STRING;
+ tv_item.vval.v_string = (char *)vim_strsave(di->di_key);
+ break;
+ case kDictListValues:
+ tv_copy(&di->di_tv, &tv_item);
+ break;
+ case kDictListItems: {
+ // items()
+ list_T *const sub_l = tv_list_alloc(2);
+ tv_item.v_type = VAR_LIST;
+ tv_item.vval.v_list = sub_l;
+ tv_list_ref(sub_l);
+
+ tv_list_append_owned_tv(sub_l, (typval_T) {
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrdup((const char *)di->di_key),
+ });
+
+ tv_list_append_tv(sub_l, &di->di_tv);
+
+ break;
+ }
+ }
+
+ tv_list_append_owned_tv(rettv->vval.v_list, tv_item);
+ });
+}
+
+/// "items(dict)" function
+void f_items(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_list(argvars, rettv, 2);
+}
+
+/// "keys()" function
+void f_keys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_list(argvars, rettv, 0);
+}
+
+/// "values(dict)" function
+void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_list(argvars, rettv, 1);
+}
+
+/// "has_key()" function
+void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if (argvars[0].v_type != VAR_DICT) {
+ emsg(_(e_dictreq));
+ return;
+ }
+ if (argvars[0].vval.v_dict == NULL) {
+ return;
+ }
+
+ rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict,
+ tv_get_string(&argvars[1]),
+ -1) != NULL;
+}
+
+/// "remove({dict})" function
+void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
+{
+ dict_T *d;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ semsg(_(e_toomanyarg), "remove()");
+ } else if ((d = argvars[0].vval.v_dict) != NULL
+ && !var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ const char *key = tv_get_string_chk(&argvars[1]);
+ if (key != NULL) {
+ dictitem_T *di = tv_dict_find(d, key, -1);
+ if (di == NULL) {
+ semsg(_(e_dictkey), key);
+ } else if (!var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE)
+ && !var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) {
+ *rettv = di->di_tv;
+ di->di_tv = TV_INITIAL_VALUE;
+ tv_dict_item_remove(d, di);
+ if (tv_dict_is_watched(d)) {
+ tv_dict_watcher_notify(d, key, NULL, rettv);
+ }
+ }
+ }
+ }
+}
+
/// Allocate an empty blob for a return value.
///
/// Also sets reference count.
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index c2579944e4..a90148bf23 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -9,13 +9,16 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
+#include "nvim/eval/funcs.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/os/input.h"
#include "nvim/regexp.h"
@@ -1265,7 +1268,7 @@ void free_all_functions(void)
// Clean up the current_funccal chain and the funccal stack.
while (current_funccal != NULL) {
tv_clear(current_funccal->rettv);
- cleanup_function_call(current_funccal);
+ cleanup_function_call(current_funccal); // -V595
if (current_funccal == NULL && funccal_stack != NULL) {
restore_funccal();
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
new file mode 100644
index 0000000000..d01fff6b94
--- /dev/null
+++ b/src/nvim/eval/vars.c
@@ -0,0 +1,1822 @@
+// 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
+
+// eval/vars.c: functions for dealing with variables
+
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer.h"
+#include "nvim/charset.h"
+#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
+#include "nvim/ex_cmds.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/search.h"
+#include "nvim/window.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/vars.c.generated.h"
+#endif
+
+// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
+
+#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
+
+static char *e_letunexp = N_("E18: Unexpected characters in :let");
+static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s");
+
+/// Get a list of lines from a HERE document. The here document is a list of
+/// lines surrounded by a marker.
+/// cmd << {marker}
+/// {line1}
+/// {line2}
+/// ....
+/// {marker}
+///
+/// The {marker} is a string. If the optional 'trim' word is supplied before the
+/// marker, then the leading indentation before the lines (matching the
+/// indentation in the 'cmd' line) is stripped.
+///
+/// @return a List with {lines} or NULL.
+static list_T *heredoc_get(exarg_T *eap, char *cmd)
+{
+ char *marker;
+ char *p;
+ int marker_indent_len = 0;
+ int text_indent_len = 0;
+ char *text_indent = NULL;
+
+ if (eap->getline == NULL) {
+ emsg(_("E991: cannot use =<< here"));
+ return NULL;
+ }
+
+ // Check for the optional 'trim' word before the marker
+ cmd = skipwhite(cmd);
+ if (STRNCMP(cmd, "trim", 4) == 0
+ && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
+ cmd = skipwhite(cmd + 4);
+
+ // Trim the indentation from all the lines in the here document.
+ // The amount of indentation trimmed is the same as the indentation of
+ // the first line after the :let command line. To find the end marker
+ // the indent of the :let command line is trimmed.
+ p = *eap->cmdlinep;
+ while (ascii_iswhite(*p)) {
+ p++;
+ marker_indent_len++;
+ }
+ text_indent_len = -1;
+ }
+
+ // The marker is the next word.
+ if (*cmd != NUL && *cmd != '"') {
+ marker = skipwhite(cmd);
+ p = (char *)skiptowhite((char_u *)marker);
+ if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
+ emsg(_(e_trailing));
+ return NULL;
+ }
+ *p = NUL;
+ if (islower(*marker)) {
+ emsg(_("E221: Marker cannot start with lower case letter"));
+ return NULL;
+ }
+ } else {
+ emsg(_("E172: Missing marker"));
+ return NULL;
+ }
+
+ list_T *l = tv_list_alloc(0);
+ for (;;) {
+ int mi = 0;
+ int ti = 0;
+
+ char *theline = eap->getline(NUL, eap->cookie, 0, false);
+ if (theline == NULL) {
+ semsg(_("E990: Missing end marker '%s'"), marker);
+ break;
+ }
+
+ // with "trim": skip the indent matching the :let line to find the
+ // marker
+ if (marker_indent_len > 0
+ && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
+ mi = marker_indent_len;
+ }
+ if (STRCMP(marker, theline + mi) == 0) {
+ xfree(theline);
+ break;
+ }
+ if (text_indent_len == -1 && *theline != NUL) {
+ // set the text indent from the first line.
+ p = theline;
+ text_indent_len = 0;
+ while (ascii_iswhite(*p)) {
+ p++;
+ text_indent_len++;
+ }
+ text_indent = xstrnsave(theline, (size_t)text_indent_len);
+ }
+ // with "trim": skip the indent matching the first line
+ if (text_indent != NULL) {
+ for (ti = 0; ti < text_indent_len; ti++) {
+ if (theline[ti] != text_indent[ti]) {
+ break;
+ }
+ }
+ }
+
+ tv_list_append_string(l, theline + ti, -1);
+ xfree(theline);
+ }
+ xfree(text_indent);
+
+ return l;
+}
+
+/// ":let" list all variable values
+/// ":let var1 var2" list variable values
+/// ":let var = expr" assignment command.
+/// ":let var += expr" assignment command.
+/// ":let var -= expr" assignment command.
+/// ":let var *= expr" assignment command.
+/// ":let var /= expr" assignment command.
+/// ":let var %= expr" assignment command.
+/// ":let var .= expr" assignment command.
+/// ":let var ..= expr" assignment command.
+/// ":let [var1, var2] = expr" unpack list.
+/// ":let [name, ..., ; lastname] = expr" unpack list.
+void ex_let(exarg_T *eap)
+{
+ ex_let_const(eap, false);
+}
+
+/// ":cons[t] var = expr1" define constant
+/// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
+/// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
+void ex_const(exarg_T *eap)
+{
+ ex_let_const(eap, true);
+}
+
+static void ex_let_const(exarg_T *eap, const bool is_const)
+{
+ char *arg = eap->arg;
+ char *expr = NULL;
+ typval_T rettv;
+ int i;
+ int var_count = 0;
+ int semicolon = 0;
+ char op[2];
+ char *argend;
+ int first = true;
+
+ argend = (char *)skip_var_list(arg, &var_count, &semicolon);
+ if (argend == NULL) {
+ return;
+ }
+ if (argend > arg && argend[-1] == '.') { // For var.='str'.
+ argend--;
+ }
+ expr = skipwhite(argend);
+ if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
+ && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
+ // ":let" without "=": list variables
+ if (*arg == '[') {
+ emsg(_(e_invarg));
+ } else if (!ends_excmd(*arg)) {
+ // ":let var1 var2"
+ arg = (char *)list_arg_vars(eap, (const char *)arg, &first);
+ } else if (!eap->skip) {
+ // ":let"
+ list_glob_vars(&first);
+ list_buf_vars(&first);
+ list_win_vars(&first);
+ list_tab_vars(&first);
+ list_script_vars(&first);
+ list_func_vars(&first);
+ list_vim_vars(&first);
+ }
+ eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+ } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
+ // HERE document
+ list_T *l = heredoc_get(eap, expr + 3);
+ if (l != NULL) {
+ tv_list_set_ret(&rettv, l);
+ if (!eap->skip) {
+ op[0] = '=';
+ op[1] = NUL;
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
+ is_const, (char *)op);
+ }
+ tv_clear(&rettv);
+ }
+ } else {
+ op[0] = '=';
+ op[1] = NUL;
+ if (*expr != '=') {
+ if (vim_strchr("+-*/%.", *expr) != NULL) {
+ op[0] = *expr; // +=, -=, *=, /=, %= or .=
+ if (expr[0] == '.' && expr[1] == '.') { // ..=
+ expr++;
+ }
+ }
+ expr = skipwhite(expr + 2);
+ } else {
+ expr = skipwhite(expr + 1);
+ }
+
+ if (eap->skip) {
+ emsg_skip++;
+ }
+ i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
+ if (eap->skip) {
+ if (i != FAIL) {
+ tv_clear(&rettv);
+ }
+ emsg_skip--;
+ } else if (i != FAIL) {
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
+ is_const, (char *)op);
+ tv_clear(&rettv);
+ }
+ }
+}
+
+/// Assign the typevalue "tv" to the variable or variables at "arg_start".
+/// Handles both "var" with any type and "[var, var; var]" with a list type.
+/// When "op" is not NULL it points to a string with characters that
+/// must appear after the variable(s). Use "+", "-" or "." for add, subtract
+/// or concatenate.
+///
+/// @param copy copy values from "tv", don't move
+/// @param semicolon from skip_var_list()
+/// @param var_count from skip_var_list()
+/// @param is_const lock variables for :const
+///
+/// @return OK or FAIL;
+int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int is_const,
+ char *op)
+{
+ char *arg = arg_start;
+ typval_T ltv;
+
+ if (*arg != '[') {
+ // ":let var = expr" or ":for var in list"
+ if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL) {
+ return FAIL;
+ }
+ return OK;
+ }
+
+ // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
+ if (tv->v_type != VAR_LIST) {
+ emsg(_(e_listreq));
+ return FAIL;
+ }
+ list_T *const l = tv->vval.v_list;
+
+ const int len = tv_list_len(l);
+ if (semicolon == 0 && var_count < len) {
+ emsg(_("E687: Less targets than List items"));
+ return FAIL;
+ }
+ if (var_count - semicolon > len) {
+ emsg(_("E688: More targets than List items"));
+ return FAIL;
+ }
+ // List l may actually be NULL, but it should fail with E688 or even earlier
+ // if you try to do ":let [] = v:_null_list".
+ assert(l != NULL);
+
+ listitem_T *item = tv_list_first(l);
+ size_t rest_len = (size_t)tv_list_len(l);
+ while (*arg != ']') {
+ arg = skipwhite(arg + 1);
+ arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const, ",;]", op);
+ if (arg == NULL) {
+ return FAIL;
+ }
+ rest_len--;
+
+ item = TV_LIST_ITEM_NEXT(l, item);
+ arg = skipwhite(arg);
+ if (*arg == ';') {
+ // Put the rest of the list (may be empty) in the var after ';'.
+ // Create a new list for this.
+ list_T *const rest_list = tv_list_alloc((ptrdiff_t)rest_len);
+ while (item != NULL) {
+ tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item));
+ item = TV_LIST_ITEM_NEXT(l, item);
+ }
+
+ ltv.v_type = VAR_LIST;
+ ltv.v_lock = VAR_UNLOCKED;
+ ltv.vval.v_list = rest_list;
+ tv_list_ref(rest_list);
+
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const, "]", op);
+ tv_clear(&ltv);
+ if (arg == NULL) {
+ return FAIL;
+ }
+ break;
+ } else if (*arg != ',' && *arg != ']') {
+ internal_error("ex_let_vars()");
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
+/// Skip over assignable variable "var" or list of variables "[var, var]".
+/// Used for ":let varvar = expr" and ":for varvar in expr".
+/// For "[var, var]" increment "*var_count" for each variable.
+/// for "[var, var; var]" set "semicolon".
+///
+/// @return NULL for an error.
+const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
+{
+ const char *p;
+ const char *s;
+
+ if (*arg == '[') {
+ // "[var, var]": find the matching ']'.
+ p = arg;
+ for (;;) {
+ p = skipwhite(p + 1); // skip whites after '[', ';' or ','
+ s = skip_var_one((char *)p);
+ if (s == p) {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ (*var_count)++;
+
+ p = skipwhite(s);
+ if (*p == ']') {
+ break;
+ } else if (*p == ';') {
+ if (*semicolon == 1) {
+ emsg(_("E452: Double ; in list of variables"));
+ return NULL;
+ }
+ *semicolon = 1;
+ } else if (*p != ',') {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ }
+ return p + 1;
+ } else {
+ return skip_var_one((char *)arg);
+ }
+}
+
+/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
+/// l[idx].
+static const char *skip_var_one(const char *arg)
+{
+ if (*arg == '@' && arg[1] != NUL) {
+ return arg + 1 + utfc_ptr2len(arg + 1);
+ }
+ return (char *)find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
+ NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+}
+
+/// List variables for hashtab "ht" with prefix "prefix".
+///
+/// @param empty if true also list NULL strings as empty strings.
+void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *first)
+{
+ hashitem_T *hi;
+ dictitem_T *di;
+ int todo;
+
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0 && !got_int; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ todo--;
+ di = TV_DICT_HI2DI(hi);
+ char buf[IOSIZE];
+
+ // apply :filter /pat/ to variable name
+ xstrlcpy(buf, prefix, IOSIZE);
+ xstrlcat(buf, (char *)di->di_key, IOSIZE);
+ if (message_filtered((char_u *)buf)) {
+ continue;
+ }
+
+ if (empty || di->di_tv.v_type != VAR_STRING
+ || di->di_tv.vval.v_string != NULL) {
+ list_one_var(di, prefix, first);
+ }
+ }
+ }
+}
+
+/// List global variables.
+static void list_glob_vars(int *first)
+{
+ list_hashtable_vars(&globvarht, "", true, first);
+}
+
+/// List buffer variables.
+static void list_buf_vars(int *first)
+{
+ list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", true, first);
+}
+
+/// List window variables.
+static void list_win_vars(int *first)
+{
+ list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", true, first);
+}
+
+/// List tab page variables.
+static void list_tab_vars(int *first)
+{
+ list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", true, first);
+}
+
+/// List variables in "arg".
+static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
+{
+ int error = false;
+ int len;
+ const char *name;
+ const char *name_start;
+ typval_T tv;
+
+ while (!ends_excmd(*arg) && !got_int) {
+ if (error || eap->skip) {
+ arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+ if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) {
+ emsg_severe = true;
+ emsg(_(e_trailing));
+ break;
+ }
+ } else {
+ // get_name_len() takes care of expanding curly braces
+ name_start = name = arg;
+ char *tofree;
+ len = get_name_len(&arg, &tofree, true, true);
+ if (len <= 0) {
+ // This is mainly to keep test 49 working: when expanding
+ // curly braces fails overrule the exception error message.
+ if (len < 0 && !aborting()) {
+ emsg_severe = true;
+ semsg(_(e_invarg2), arg);
+ break;
+ }
+ error = true;
+ } else {
+ if (tofree != NULL) {
+ name = tofree;
+ }
+ if (get_var_tv(name, len, &tv, NULL, true, false)
+ == FAIL) {
+ error = true;
+ } else {
+ // handle d.key, l[idx], f(expr)
+ const char *const arg_subsc = arg;
+ if (handle_subscript(&arg, &tv, true, true, name, &name) == FAIL) {
+ error = true;
+ } else {
+ if (arg == arg_subsc && len == 2 && name[1] == ':') {
+ switch (*name) {
+ case 'g':
+ list_glob_vars(first); break;
+ case 'b':
+ list_buf_vars(first); break;
+ case 'w':
+ list_win_vars(first); break;
+ case 't':
+ list_tab_vars(first); break;
+ case 'v':
+ list_vim_vars(first); break;
+ case 's':
+ list_script_vars(first); break;
+ case 'l':
+ list_func_vars(first); break;
+ default:
+ semsg(_("E738: Can't list variables for %s"), name);
+ }
+ } else {
+ char *const s = encode_tv2echo(&tv, NULL);
+ const char *const used_name = (arg == arg_subsc
+ ? name
+ : name_start);
+ assert(used_name != NULL);
+ const ptrdiff_t name_size = (used_name == tofree
+ ? (ptrdiff_t)strlen(used_name)
+ : (arg - used_name));
+ list_one_var_a("", used_name, name_size,
+ tv.v_type, s == NULL ? "" : s, first);
+ xfree(s);
+ }
+ tv_clear(&tv);
+ }
+ }
+ }
+
+ xfree(tofree);
+ }
+
+ arg = (const char *)skipwhite(arg);
+ }
+
+ return arg;
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
+///
+/// @param[in] arg Start of the variable name.
+/// @param[in] tv Value to assign to the variable.
+/// @param[in] copy If true, copy value from `tv`.
+/// @param[in] endchars Valid characters after variable name or NULL.
+/// @param[in] op Operation performed: *op is `+`, `-`, `.` for `+=`, etc.
+/// NULL for `=`.
+///
+/// @return a pointer to the char just after the var name or NULL in case of
+/// error.
+static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bool is_const,
+ const char *const endchars, const char *const op)
+ FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ char *arg_end = NULL;
+ int len;
+ int opt_flags;
+ char *tofree = NULL;
+
+ // ":let $VAR = expr": Set environment variable.
+ if (*arg == '$') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock an environment variable"));
+ return NULL;
+ }
+ // Find the end of the name.
+ arg++;
+ char *name = arg;
+ len = get_env_len((const char **)&arg);
+ if (len == 0) {
+ semsg(_(e_invarg2), name - 1);
+ } else {
+ if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ semsg(_(e_letwrong), op);
+ } else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg)) == NULL) {
+ emsg(_(e_letunexp));
+ } else if (!check_secure()) {
+ const char c1 = name[len];
+ name[len] = NUL;
+ const char *p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.') {
+ char *s = vim_getenv(name);
+
+ if (s != NULL) {
+ tofree = (char *)concat_str((const char_u *)s, (const char_u *)p);
+ p = (const char *)tofree;
+ xfree(s);
+ }
+ }
+ if (p != NULL) {
+ os_setenv(name, p, 1);
+ if (STRICMP(name, "HOME") == 0) {
+ init_homedir();
+ } else if (didset_vim && STRICMP(name, "VIM") == 0) {
+ didset_vim = false;
+ } else if (didset_vimruntime
+ && STRICMP(name, "VIMRUNTIME") == 0) {
+ didset_vimruntime = false;
+ }
+ arg_end = arg;
+ }
+ name[len] = c1;
+ xfree(tofree);
+ }
+ }
+ // ":let &option = expr": Set option value.
+ // ":let &l:option = expr": Set local option value.
+ // ":let &g:option = expr": Set global option value.
+ } else if (*arg == '&') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock an option"));
+ return NULL;
+ }
+ // Find the end of the name.
+ char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
+ if (p == NULL
+ || (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(p)) == NULL)) {
+ emsg(_(e_letunexp));
+ } else {
+ varnumber_T n = 0;
+ getoption_T opt_type;
+ long numval;
+ char *stringval = NULL;
+ const char *s = NULL;
+ bool failed = false;
+
+ const char c1 = *p;
+ *p = NUL;
+
+ opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ if (opt_type == gov_bool
+ || opt_type == gov_number
+ || opt_type == gov_hidden_bool
+ || opt_type == gov_hidden_number) {
+ // number, possibly hidden
+ n = (long)tv_get_number(tv);
+ }
+
+ // Avoid setting a string option to the text "v:false" or similar.
+ if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ s = tv_get_string_chk(tv);
+ }
+
+ if (op != NULL && *op != '=') {
+ if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
+ || (opt_type == gov_string && *op != '.')) {
+ semsg(_(e_letwrong), op);
+ failed = true; // don't set the value
+ } else {
+ // number or bool
+ if (opt_type == gov_number || opt_type == gov_bool) {
+ switch (*op) {
+ case '+':
+ n = numval + n; break;
+ case '-':
+ n = numval - n; break;
+ case '*':
+ n = numval * n; break;
+ case '/':
+ n = num_divide(numval, n); break;
+ case '%':
+ n = num_modulus(numval, n); break;
+ }
+ s = NULL;
+ } else if (opt_type == gov_string && stringval != NULL && s != NULL) {
+ // string
+ char *const oldstringval = stringval;
+ stringval = (char *)concat_str((const char_u *)stringval,
+ (const char_u *)s);
+ xfree(oldstringval);
+ s = stringval;
+ }
+ }
+ }
+
+ if (!failed) {
+ if (opt_type != gov_string || s != NULL) {
+ set_option_value(arg, n, s, opt_flags);
+ arg_end = p;
+ } else {
+ emsg(_(e_stringreq));
+ }
+ }
+ *p = c1;
+ xfree(stringval);
+ }
+ // ":let @r = expr": Set register contents.
+ } else if (*arg == '@') {
+ if (is_const) {
+ emsg(_("E996: Cannot lock a register"));
+ return NULL;
+ }
+ arg++;
+
+ int regname = utf_ptr2char(arg);
+ int mblen = utf_ptr2len(arg);
+
+ if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ semsg(_(e_letwrong), op);
+ } else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg + mblen)) == NULL) {
+ emsg(_(e_letunexp));
+ } else {
+ char *s;
+
+ char *ptofree = NULL;
+ const char *p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.') {
+ s = get_reg_contents(*arg == '@' ? '"' : regname, kGRegExprSrc);
+ if (s != NULL) {
+ ptofree = (char *)concat_str((char_u *)s, (const char_u *)p);
+ p = (const char *)ptofree;
+ xfree(s);
+ }
+ }
+ if (p != NULL) {
+ write_reg_contents(*arg == '@' ? '"' : regname,
+ (const char_u *)p, (ssize_t)STRLEN(p), false);
+ arg_end = arg + mblen;
+ }
+ xfree(ptofree);
+ }
+ // ":let var = expr": Set internal variable.
+ // ":let {expr} = expr": Idem, name made with curly braces
+ } else if (eval_isnamec1(*arg) || *arg == '{') {
+ lval_T lv;
+
+ char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
+ if (p != NULL && lv.ll_name != NULL) {
+ if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
+ emsg(_(e_letunexp));
+ } else {
+ set_var_lval(&lv, p, tv, copy, is_const, op);
+ arg_end = p;
+ }
+ }
+ clear_lval(&lv);
+ } else {
+ semsg(_(e_invarg2), arg);
+ }
+
+ return arg_end;
+}
+
+/// ":unlet[!] var1 ... " command.
+void ex_unlet(exarg_T *eap)
+{
+ ex_unletlock(eap, eap->arg, 0, do_unlet_var);
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// ":lockvar" and ":unlockvar" commands
+void ex_lockvar(exarg_T *eap)
+{
+ char *arg = eap->arg;
+ int deep = 2;
+
+ if (eap->forceit) {
+ deep = -1;
+ } else if (ascii_isdigit(*arg)) {
+ deep = getdigits_int(&arg, false, -1);
+ arg = skipwhite(arg);
+ }
+
+ ex_unletlock(eap, arg, deep, do_lock_var);
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Common parsing logic for :unlet, :lockvar and :unlockvar.
+///
+/// Invokes `callback` afterwards if successful and `eap->skip == false`.
+///
+/// @param[in] eap Ex command arguments for the command.
+/// @param[in] argstart Start of the string argument for the command.
+/// @param[in] deep Levels to (un)lock for :(un)lockvar, -1 to (un)lock
+/// everything.
+/// @param[in] callback Appropriate handler for the command.
+static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_callback callback)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char *arg = argstart;
+ char *name_end;
+ bool error = false;
+ lval_T lv;
+
+ do {
+ if (*arg == '$') {
+ lv.ll_name = (const char *)arg;
+ lv.ll_tv = NULL;
+ arg++;
+ if (get_env_len((const char **)&arg) == 0) {
+ semsg(_(e_invarg2), arg - 1);
+ return;
+ }
+ if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) {
+ error = true;
+ }
+ name_end = arg;
+ } else {
+ // Parse the name and find the end.
+ name_end = get_lval(arg, NULL, &lv, true, eap->skip || error,
+ 0, FNE_CHECK_START);
+ if (lv.ll_name == NULL) {
+ error = true; // error, but continue parsing.
+ }
+ if (name_end == NULL
+ || (!ascii_iswhite(*name_end) && !ends_excmd(*name_end))) {
+ if (name_end != NULL) {
+ emsg_severe = true;
+ emsg(_(e_trailing));
+ }
+ if (!(eap->skip || error)) {
+ clear_lval(&lv);
+ }
+ break;
+ }
+
+ if (!error && !eap->skip && callback(&lv, name_end, eap, deep) == FAIL) {
+ error = true;
+ }
+
+ if (!eap->skip) {
+ clear_lval(&lv);
+ }
+ }
+ arg = skipwhite(name_end);
+ } while (!ends_excmd(*arg));
+
+ eap->nextcmd = (char *)check_nextcmd((char_u *)arg);
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Unlet a variable indicated by `lp`.
+///
+/// @param[in] lp The lvalue.
+/// @param[in] name_end End of the string argument for the command.
+/// @param[in] eap Ex command arguments for :unlet.
+/// @param[in] deep Unused.
+///
+/// @return OK on success, or FAIL on failure.
+static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ATTR_UNUSED)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int forceit = eap->forceit;
+ int ret = OK;
+ int cc;
+
+ if (lp->ll_tv == NULL) {
+ cc = (char_u)(*name_end);
+ *name_end = NUL;
+
+ // Environment variable, normal name or expanded name.
+ if (*lp->ll_name == '$') {
+ os_unsetenv(lp->ll_name + 1);
+ } else if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) {
+ ret = FAIL;
+ }
+ *name_end = (char)cc;
+ } else if ((lp->ll_list != NULL
+ // ll_list is not NULL when lvalue is not in a list, NULL lists
+ // yield E689.
+ && var_check_lock(tv_list_locked(lp->ll_list),
+ lp->ll_name,
+ lp->ll_name_len))
+ || (lp->ll_dict != NULL
+ && var_check_lock(lp->ll_dict->dv_lock,
+ lp->ll_name,
+ lp->ll_name_len))) {
+ return FAIL;
+ } else if (lp->ll_range) {
+ assert(lp->ll_list != NULL);
+ // Delete a range of List items.
+ listitem_T *const first_li = lp->ll_li;
+ listitem_T *last_li = first_li;
+ for (;;) {
+ listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
+ if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
+ lp->ll_name,
+ lp->ll_name_len)) {
+ return false;
+ }
+ lp->ll_li = li;
+ lp->ll_n1++;
+ if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) {
+ break;
+ } else {
+ last_li = lp->ll_li;
+ }
+ }
+ tv_list_remove_items(lp->ll_list, first_li, last_li);
+ } else {
+ if (lp->ll_list != NULL) {
+ // unlet a List item.
+ tv_list_item_remove(lp->ll_list, lp->ll_li);
+ } else {
+ // unlet a Dictionary item.
+ dict_T *d = lp->ll_dict;
+ assert(d != NULL);
+ dictitem_T *di = lp->ll_di;
+ bool watched = tv_dict_is_watched(d);
+ char *key = NULL;
+ typval_T oldtv;
+
+ if (watched) {
+ tv_copy(&di->di_tv, &oldtv);
+ // need to save key because dictitem_remove will free it
+ key = xstrdup((char *)di->di_key);
+ }
+
+ tv_dict_item_remove(d, di);
+
+ if (watched) {
+ tv_dict_watcher_notify(d, key, NULL, &oldtv);
+ tv_clear(&oldtv);
+ xfree(key);
+ }
+ }
+ }
+
+ return ret;
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// unlet a variable
+///
+/// @param[in] name Variable name to unlet.
+/// @param[in] name_len Variable name length.
+/// @param[in] forceit If true, do not complain if variable doesn’t exist.
+///
+/// @return OK if it existed, FAIL otherwise.
+int do_unlet(const char *const name, const size_t name_len, const bool forceit)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *varname;
+ dict_T *dict;
+ hashtab_T *ht = find_var_ht_dict(name, name_len, &varname, &dict);
+
+ if (ht != NULL && *varname != NUL) {
+ dict_T *d = get_current_funccal_dict(ht);
+ if (d == NULL) {
+ if (ht == &globvarht) {
+ d = &globvardict;
+ } else if (is_compatht(ht)) {
+ d = &vimvardict;
+ } else {
+ dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
+ d = di->di_tv.vval.v_dict;
+ }
+ if (d == NULL) {
+ internal_error("do_unlet()");
+ return FAIL;
+ }
+ }
+
+ hashitem_T *hi = hash_find(ht, varname);
+ if (HASHITEM_EMPTY(hi)) {
+ hi = find_hi_in_scoped_ht(name, &ht);
+ }
+ if (hi != NULL && !HASHITEM_EMPTY(hi)) {
+ dictitem_T *const di = TV_DICT_HI2DI(hi);
+ if (var_check_fixed(di->di_flags, name, TV_CSTRING)
+ || var_check_ro(di->di_flags, name, TV_CSTRING)
+ || var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ return FAIL;
+ }
+
+ if (var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ return FAIL;
+ }
+
+ typval_T oldtv;
+ bool watched = tv_dict_is_watched(dict);
+
+ if (watched) {
+ tv_copy(&di->di_tv, &oldtv);
+ }
+
+ delete_var(ht, hi);
+
+ if (watched) {
+ tv_dict_watcher_notify(dict, varname, NULL, &oldtv);
+ tv_clear(&oldtv);
+ }
+ return OK;
+ }
+ }
+ if (forceit) {
+ return OK;
+ }
+ semsg(_("E108: No such variable: \"%s\""), name);
+ return FAIL;
+}
+
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Lock or unlock variable indicated by `lp`.
+///
+/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
+///
+/// @param[in] lp The lvalue.
+/// @param[in] name_end Unused.
+/// @param[in] eap Ex command arguments for :(un)lockvar.
+/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
+///
+/// @return OK on success, or FAIL on failure.
+static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap, int deep)
+ FUNC_ATTR_NONNULL_ARG(1, 3)
+{
+ bool lock = eap->cmdidx == CMD_lockvar;
+ int ret = OK;
+
+ if (deep == 0) { // Nothing to do.
+ return OK;
+ }
+
+ if (lp->ll_tv == NULL) {
+ if (*lp->ll_name == '$') {
+ semsg(_(e_lock_unlock), lp->ll_name);
+ ret = FAIL;
+ } else {
+ // Normal name or expanded name.
+ dictitem_T *const di = find_var(lp->ll_name, lp->ll_name_len, NULL,
+ true);
+ if (di == NULL) {
+ ret = FAIL;
+ } else if ((di->di_flags & DI_FLAGS_FIX)
+ && di->di_tv.v_type != VAR_DICT
+ && di->di_tv.v_type != VAR_LIST) {
+ // For historical reasons this error is not given for Lists and
+ // Dictionaries. E.g. b: dictionary may be locked/unlocked.
+ semsg(_(e_lock_unlock), lp->ll_name);
+ ret = FAIL;
+ } else {
+ if (lock) {
+ di->di_flags |= DI_FLAGS_LOCK;
+ } else {
+ di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK);
+ }
+ tv_item_lock(&di->di_tv, deep, lock, false);
+ }
+ }
+ } else if (lp->ll_range) {
+ listitem_T *li = lp->ll_li;
+
+ // (un)lock a range of List items.
+ while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
+ tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock, false);
+ li = TV_LIST_ITEM_NEXT(lp->ll_list, li);
+ lp->ll_n1++;
+ }
+ } else if (lp->ll_list != NULL) {
+ // (un)lock a List item.
+ tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock, false);
+ } else {
+ // (un)lock a Dictionary item.
+ tv_item_lock(&lp->ll_di->di_tv, deep, lock, false);
+ }
+
+ return ret;
+}
+
+/// Get the value of internal variable "name".
+/// Return OK or FAIL. If OK is returned "rettv" must be cleared.
+///
+/// @param len length of "name"
+/// @param rettv NULL when only checking existence
+/// @param dip non-NULL when typval's dict item is needed
+/// @param verbose may give error message
+/// @param no_autoload do not use script autoloading
+int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, bool verbose,
+ bool no_autoload)
+{
+ int ret = OK;
+ typval_T *tv = NULL;
+ dictitem_T *v;
+
+ v = find_var(name, (size_t)len, NULL, no_autoload);
+ if (v != NULL) {
+ tv = &v->di_tv;
+ if (dip != NULL) {
+ *dip = v;
+ }
+ }
+
+ if (tv == NULL) {
+ if (rettv != NULL && verbose) {
+ semsg(_("E121: Undefined variable: %.*s"), len, name);
+ }
+ ret = FAIL;
+ } else if (rettv != NULL) {
+ tv_copy(tv, rettv);
+ }
+
+ return ret;
+}
+
+/// @return the string value of a (global/local) variable or
+/// NULL when it doesn't exist.
+///
+/// @see tv_get_string() for how long the pointer remains valid.
+char_u *get_var_value(const char *const name)
+{
+ dictitem_T *v;
+
+ v = find_var(name, strlen(name), NULL, false);
+ if (v == NULL) {
+ return NULL;
+ }
+ return (char_u *)tv_get_string(&v->di_tv);
+}
+
+/// Clean up a list of internal variables.
+/// Frees all allocated variables and the value they contain.
+/// Clears hashtab "ht", does not free it.
+void vars_clear(hashtab_T *ht)
+{
+ vars_clear_ext(ht, true);
+}
+
+/// Like vars_clear(), but only free the value if "free_val" is TRUE.
+void vars_clear_ext(hashtab_T *ht, int free_val)
+{
+ int todo;
+ hashitem_T *hi;
+ dictitem_T *v;
+
+ hash_lock(ht);
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ todo--;
+
+ // Free the variable. Don't remove it from the hashtab,
+ // ht_array might change then. hash_clear() takes care of it
+ // later.
+ v = TV_DICT_HI2DI(hi);
+ if (free_val) {
+ tv_clear(&v->di_tv);
+ }
+ if (v->di_flags & DI_FLAGS_ALLOC) {
+ xfree(v);
+ }
+ }
+ }
+ hash_clear(ht);
+ ht->ht_used = 0;
+}
+
+/// Delete a variable from hashtab "ht" at item "hi".
+/// Clear the variable value and free the dictitem.
+void delete_var(hashtab_T *ht, hashitem_T *hi)
+{
+ dictitem_T *di = TV_DICT_HI2DI(hi);
+
+ hash_remove(ht, hi);
+ tv_clear(&di->di_tv);
+ xfree(di);
+}
+
+/// List the value of one internal variable.
+static void list_one_var(dictitem_T *v, const char *prefix, int *first)
+{
+ char *const s = encode_tv2echo(&v->di_tv, NULL);
+ list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)STRLEN(v->di_key),
+ v->di_tv.v_type, (s == NULL ? "" : s), first);
+ xfree(s);
+}
+
+/// @param[in] name_len Length of the name. May be -1, in this case strlen()
+/// will be used.
+/// @param[in,out] first When true clear rest of screen and set to false.
+static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t name_len,
+ const VarType type, const char *string, int *first)
+{
+ // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
+ msg_start();
+ msg_puts(prefix);
+ if (name != NULL) { // "a:" vars don't have a name stored
+ msg_puts_attr_len(name, name_len, 0);
+ }
+ msg_putchar(' ');
+ msg_advance(22);
+ if (type == VAR_NUMBER) {
+ msg_putchar('#');
+ } else if (type == VAR_FUNC || type == VAR_PARTIAL) {
+ msg_putchar('*');
+ } else if (type == VAR_LIST) {
+ msg_putchar('[');
+ if (*string == '[') {
+ string++;
+ }
+ } else if (type == VAR_DICT) {
+ msg_putchar('{');
+ if (*string == '{') {
+ string++;
+ }
+ } else {
+ msg_putchar(' ');
+ }
+
+ msg_outtrans((char *)string);
+
+ if (type == VAR_FUNC || type == VAR_PARTIAL) {
+ msg_puts("()");
+ }
+ if (*first) {
+ msg_clr_eos();
+ *first = false;
+ }
+}
+
+/// Set variable to the given value
+///
+/// If the variable already exists, the value is updated. Otherwise the variable
+/// is created.
+///
+/// @param[in] name Variable name to set.
+/// @param[in] name_len Length of the variable name.
+/// @param tv Variable value.
+/// @param[in] copy True if value in tv is to be copied.
+void set_var(const char *name, const size_t name_len, typval_T *const tv, const bool copy)
+ FUNC_ATTR_NONNULL_ALL
+{
+ set_var_const(name, name_len, tv, copy, false);
+}
+
+/// Set variable to the given value
+///
+/// If the variable already exists, the value is updated. Otherwise the variable
+/// is created.
+///
+/// @param[in] name Variable name to set.
+/// @param[in] name_len Length of the variable name.
+/// @param tv Variable value.
+/// @param[in] copy True if value in tv is to be copied.
+/// @param[in] is_const True if value in tv is to be locked.
+void set_var_const(const char *name, const size_t name_len, typval_T *const tv, const bool copy,
+ const bool is_const)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dictitem_T *v;
+ hashtab_T *ht;
+ dict_T *dict;
+
+ const char *varname;
+ ht = find_var_ht_dict(name, name_len, &varname, &dict);
+ const bool watched = tv_dict_is_watched(dict);
+
+ if (ht == NULL || *varname == NUL) {
+ semsg(_(e_illvar), name);
+ return;
+ }
+ v = find_var_in_ht(ht, 0, varname, name_len - (size_t)(varname - name), true);
+
+ // Search in parent scope which is possible to reference from lambda
+ if (v == NULL) {
+ v = find_var_in_scoped_ht(name, name_len, true);
+ }
+
+ if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
+ return;
+ }
+
+ typval_T oldtv = TV_INITIAL_VALUE;
+ if (v != NULL) {
+ if (is_const) {
+ emsg(_(e_cannot_mod));
+ return;
+ }
+
+ // existing variable, need to clear the value
+ if (var_check_ro(v->di_flags, name, name_len)
+ || var_check_lock(v->di_tv.v_lock, name, name_len)) {
+ return;
+ }
+
+ // Handle setting internal v: variables separately where needed to
+ // prevent changing the type.
+ if (is_vimvarht(ht)) {
+ if (v->di_tv.v_type == VAR_STRING) {
+ XFREE_CLEAR(v->di_tv.vval.v_string);
+ if (copy || tv->v_type != VAR_STRING) {
+ const char *const val = tv_get_string(tv);
+
+ // Careful: when assigning to v:errmsg and tv_get_string()
+ // causes an error message the variable will already be set.
+ if (v->di_tv.vval.v_string == NULL) {
+ v->di_tv.vval.v_string = xstrdup(val);
+ }
+ } else {
+ // Take over the string to avoid an extra alloc/free.
+ v->di_tv.vval.v_string = tv->vval.v_string;
+ tv->vval.v_string = NULL;
+ }
+ return;
+ } else if (v->di_tv.v_type == VAR_NUMBER) {
+ v->di_tv.vval.v_number = tv_get_number(tv);
+ if (strcmp(varname, "searchforward") == 0) {
+ set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
+ } else if (strcmp(varname, "hlsearch") == 0) {
+ no_hlsearch = !v->di_tv.vval.v_number;
+ redraw_all_later(SOME_VALID);
+ }
+ return;
+ } else if (v->di_tv.v_type != tv->v_type) {
+ semsg(_("E963: setting %s to value with wrong type"), name);
+ return;
+ }
+ }
+
+ if (watched) {
+ tv_copy(&v->di_tv, &oldtv);
+ }
+ tv_clear(&v->di_tv);
+ } else { // Add a new variable.
+ // Can't add "v:" or "a:" variable.
+ if (is_vimvarht(ht) || ht == get_funccal_args_ht()) {
+ semsg(_(e_illvar), name);
+ return;
+ }
+
+ // Make sure the variable name is valid.
+ if (!valid_varname(varname)) {
+ return;
+ }
+
+ // Make sure dict is valid
+ assert(dict != NULL);
+
+ v = xmalloc(sizeof(dictitem_T) + strlen(varname));
+ STRCPY(v->di_key, varname);
+ if (tv_dict_add(dict, v) == FAIL) {
+ xfree(v);
+ return;
+ }
+ v->di_flags = DI_FLAGS_ALLOC;
+ if (is_const) {
+ v->di_flags |= DI_FLAGS_LOCK;
+ }
+ }
+
+ if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
+ tv_copy(tv, &v->di_tv);
+ } else {
+ v->di_tv = *tv;
+ v->di_tv.v_lock = VAR_UNLOCKED;
+ tv_init(tv);
+ }
+
+ if (watched) {
+ if (oldtv.v_type == VAR_UNKNOWN) {
+ tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
+ } else {
+ tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
+ tv_clear(&oldtv);
+ }
+ }
+
+ if (is_const) {
+ // Like :lockvar! name: lock the value and what it contains, but only
+ // if the reference count is up to one. That locks only literal
+ // values.
+ tv_item_lock(&v->di_tv, DICT_MAXNEST, true, true);
+ }
+}
+
+/// Check whether variable is read-only (DI_FLAGS_RO, DI_FLAGS_RO_SBX)
+///
+/// Also gives an error message.
+///
+/// @param[in] flags di_flags attribute value.
+/// @param[in] name Variable name, for use in error message.
+/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
+/// variable name and compute the length. Use #TV_CSTRING
+/// to compute the length with strlen() without
+/// translating.
+///
+/// Both #TV_… values are used for optimization purposes:
+/// variable name with its length is needed only in case
+/// of error, when no error occurs computing them is
+/// a waste of CPU resources. This especially applies to
+/// gettext.
+///
+/// @return True if variable is read-only: either always or in sandbox when
+/// sandbox is enabled, false otherwise.
+bool var_check_ro(const int flags, const char *name, size_t name_len)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ const char *error_message = NULL;
+ if (flags & DI_FLAGS_RO) {
+ error_message = _(e_readonlyvar);
+ } else if ((flags & DI_FLAGS_RO_SBX) && sandbox) {
+ error_message = N_("E794: Cannot set variable in the sandbox: \"%.*s\"");
+ }
+
+ if (error_message == NULL) {
+ return false;
+ }
+ if (name_len == TV_TRANSLATE) {
+ name = _(name);
+ name_len = strlen(name);
+ } else if (name_len == TV_CSTRING) {
+ name_len = strlen(name);
+ }
+
+ semsg(_(error_message), (int)name_len, name);
+
+ return true;
+}
+
+/// Check whether variable is fixed (DI_FLAGS_FIX)
+///
+/// Also gives an error message.
+///
+/// @param[in] flags di_flags attribute value.
+/// @param[in] name Variable name, for use in error message.
+/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
+/// variable name and compute the length. Use #TV_CSTRING
+/// to compute the length with strlen() without
+/// translating.
+///
+/// Both #TV_… values are used for optimization purposes:
+/// variable name with its length is needed only in case
+/// of error, when no error occurs computing them is
+/// a waste of CPU resources. This especially applies to
+/// gettext.
+///
+/// @return True if variable is fixed, false otherwise.
+bool var_check_fixed(const int flags, const char *name, size_t name_len)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ if (flags & DI_FLAGS_FIX) {
+ if (name_len == TV_TRANSLATE) {
+ name = _(name);
+ name_len = strlen(name);
+ } else if (name_len == TV_CSTRING) {
+ name_len = strlen(name);
+ }
+ semsg(_("E795: Cannot delete variable %.*s"), (int)name_len, name);
+ return true;
+ }
+ return false;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Check if name is a valid name to assign funcref to
+///
+/// @param[in] name Possible function/funcref name.
+/// @param[in] new_var True if it is a name for a variable.
+///
+/// @return false in case of error, true in case of success. Also gives an
+/// error message if appropriate.
+bool var_check_func_name(const char *const name, const bool new_var)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Allow for w: b: s: and t:.
+ if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':')
+ && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
+ ? name[2] : name[0])) {
+ semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
+ return false;
+ }
+ // Don't allow hiding a function. When "v" is not NULL we might be
+ // assigning another function to the same var, the type is checked
+ // below.
+ if (new_var && function_exists(name, false)) {
+ semsg(_("E705: Variable name conflicts with existing function: %s"), name);
+ return false;
+ }
+ return true;
+}
+
+// TODO(ZyX-I): move to eval/expressions
+
+/// Check if a variable name is valid
+///
+/// @param[in] varname Variable name to check.
+///
+/// @return false when variable name is not valid, true when it is. Also gives
+/// an error message if appropriate.
+bool valid_varname(const char *varname)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ for (const char *p = varname; *p != NUL; p++) {
+ if (!eval_isnamec1((int)(uint8_t)(*p))
+ && (p == varname || !ascii_isdigit(*p))
+ && *p != AUTOLOAD_CHAR) {
+ semsg(_(e_illvar), varname);
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Implements the logic to retrieve local variable and option values.
+/// Used by "getwinvar()" "gettabvar()" "gettabwinvar()" "getbufvar()".
+///
+/// @param deftv default value if not found
+/// @param htname 't'ab, 'w'indow or 'b'uffer local
+/// @param tp can be NULL
+/// @param buf ignored if htname is not 'b'
+static void get_var_from(const char *varname, typval_T *rettv, typval_T *deftv, int htname,
+ tabpage_T *tp, win_T *win, buf_T *buf)
+{
+ bool done = false;
+ const bool do_change_curbuf = buf != NULL && htname == 'b';
+
+ emsg_off++;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (varname != NULL && tp != NULL && win != NULL && (htname != 'b' || buf != NULL)) {
+ // Set curwin to be our win, temporarily. Also set the tabpage,
+ // otherwise the window is not valid. Only do this when needed,
+ // autocommands get blocked.
+ // If we have a buffer reference avoid the switching, we're saving and
+ // restoring curbuf directly.
+ const bool need_switch_win = !(tp == curtab && win == curwin) && !do_change_curbuf;
+ switchwin_T switchwin;
+ if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
+ if (*varname == '&' && htname != 't') {
+ buf_T *const save_curbuf = curbuf;
+
+ // Change curbuf so the option is read from the correct buffer.
+ if (do_change_curbuf) {
+ curbuf = buf;
+ }
+
+ if (varname[1] == NUL) {
+ // get all window-local or buffer-local options in a dict
+ dict_T *opts = get_winbuf_options(htname == 'b');
+
+ if (opts != NULL) {
+ tv_dict_set_ret(rettv, opts);
+ done = true;
+ }
+ } else if (get_option_tv(&varname, rettv, true) == OK) {
+ // Local option
+ done = true;
+ }
+
+ curbuf = save_curbuf;
+ } else if (*varname == NUL) {
+ const ScopeDictDictItem *v;
+ // Empty string: return a dict with all the local variables.
+ if (htname == 'b') {
+ v = &buf->b_bufvar;
+ } else if (htname == 'w') {
+ v = &win->w_winvar;
+ } else {
+ v = &tp->tp_winvar;
+ }
+ tv_copy(&v->di_tv, rettv);
+ done = true;
+ } else {
+ hashtab_T *ht;
+
+ if (htname == 'b') {
+ ht = &buf->b_vars->dv_hashtab;
+ } else if (htname == 'w') {
+ ht = &win->w_vars->dv_hashtab;
+ } else {
+ ht = &tp->tp_vars->dv_hashtab;
+ }
+
+ // Look up the variable.
+ const dictitem_T *const v = find_var_in_ht(ht, htname, varname, strlen(varname), false);
+ if (v != NULL) {
+ tv_copy(&v->di_tv, rettv);
+ done = true;
+ }
+ }
+ }
+
+ if (need_switch_win) {
+ // restore previous notion of curwin
+ restore_win(&switchwin, true);
+ }
+ }
+
+ if (!done && deftv->v_type != VAR_UNKNOWN) {
+ // use the default value
+ tv_copy(deftv, rettv);
+ }
+
+ emsg_off--;
+}
+
+/// getwinvar() and gettabwinvar()
+///
+/// @param off 1 for gettabwinvar()
+static void getwinvar(typval_T *argvars, typval_T *rettv, int off)
+{
+ tabpage_T *tp;
+
+ if (off == 1) {
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ } else {
+ tp = curtab;
+ }
+ win_T *const win = find_win_by_nr(&argvars[off], tp);
+ const char *const varname = tv_get_string_chk(&argvars[off + 1]);
+
+ get_var_from(varname, rettv, &argvars[off + 2], 'w', tp, win, NULL);
+}
+
+/// Set option "varname" to the value of "varp" for the current buffer/window.
+static void set_option_from_tv(const char *varname, typval_T *varp)
+{
+ long numval = 0;
+ const char *strval;
+ bool error = false;
+ char nbuf[NUMBUFLEN];
+
+ if (varp->v_type == VAR_BOOL) {
+ if (is_string_option(varname)) {
+ emsg(_(e_stringreq));
+ return;
+ }
+ numval = (long)varp->vval.v_number;
+ strval = "0"; // avoid using "false"
+ } else {
+ numval = (long)tv_get_number_chk(varp, &error);
+ strval = tv_get_string_buf_chk(varp, nbuf);
+ }
+ if (!error && strval != NULL) {
+ set_option_value(varname, numval, strval, OPT_LOCAL);
+ }
+}
+
+/// "setwinvar()" and "settabwinvar()" functions
+static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
+{
+ if (check_secure()) {
+ return;
+ }
+
+ tabpage_T *tp = NULL;
+ if (off == 1) {
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ } else {
+ tp = curtab;
+ }
+ win_T *const win = find_win_by_nr(&argvars[off], tp);
+ const char *varname = tv_get_string_chk(&argvars[off + 1]);
+ typval_T *varp = &argvars[off + 2];
+
+ if (win != NULL && varname != NULL && varp != NULL) {
+ bool need_switch_win = !(tp == curtab && win == curwin);
+ switchwin_T switchwin;
+ if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
+ if (*varname == '&') {
+ set_option_from_tv(varname + 1, varp);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const winvarname = xmalloc(varname_len + 3);
+ memcpy(winvarname, "w:", 2);
+ memcpy(winvarname + 2, varname, varname_len + 1);
+ set_var(winvarname, varname_len + 2, varp, true);
+ xfree(winvarname);
+ }
+ }
+ if (need_switch_win) {
+ restore_win(&switchwin, true);
+ }
+ }
+}
+
+bool var_exists(const char *var)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char *tofree;
+ bool n = false;
+
+ // get_name_len() takes care of expanding curly braces
+ const char *name = var;
+ const int len = get_name_len(&var, &tofree, true, false);
+ if (len > 0) {
+ typval_T tv;
+
+ if (tofree != NULL) {
+ name = tofree;
+ }
+ n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
+ if (n) {
+ // Handle d.key, l[idx], f(expr).
+ n = handle_subscript(&var, &tv, true, false, name, &name) == OK;
+ if (n) {
+ tv_clear(&tv);
+ }
+ }
+ }
+ if (*var != NUL) {
+ n = false;
+ }
+
+ xfree(tofree);
+ return n;
+}
+
+/// "gettabvar()" function
+void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *const varname = tv_get_string_chk(&argvars[1]);
+ tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ win_T *win = NULL;
+
+ if (tp != NULL) {
+ win = tp == curtab || tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin;
+ }
+
+ get_var_from(varname, rettv, &argvars[2], 't', tp, win, NULL);
+}
+
+/// "gettabwinvar()" function
+void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getwinvar(argvars, rettv, 1);
+}
+
+/// "getwinvar()" function
+void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getwinvar(argvars, rettv, 0);
+}
+
+/// "getbufvar()" function
+void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *const varname = tv_get_string_chk(&argvars[1]);
+ buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
+
+ get_var_from(varname, rettv, &argvars[2], 'b', curtab, curwin, buf);
+}
+
+/// "settabvar()" function
+void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->vval.v_number = 0;
+
+ if (check_secure()) {
+ return;
+ }
+
+ tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ const char *const varname = tv_get_string_chk(&argvars[1]);
+ typval_T *const varp = &argvars[2];
+
+ if (varname != NULL && tp != NULL) {
+ tabpage_T *const save_curtab = curtab;
+ goto_tabpage_tp(tp, false, false);
+
+ const size_t varname_len = strlen(varname);
+ char *const tabvarname = xmalloc(varname_len + 3);
+ memcpy(tabvarname, "t:", 2);
+ memcpy(tabvarname + 2, varname, varname_len + 1);
+ set_var(tabvarname, varname_len + 2, varp, true);
+ xfree(tabvarname);
+
+ // Restore current tabpage.
+ if (valid_tabpage(save_curtab)) {
+ goto_tabpage_tp(save_curtab, false, false);
+ }
+ }
+}
+
+/// "settabwinvar()" function
+void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ setwinvar(argvars, rettv, 1);
+}
+
+/// "setwinvar()" function
+void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ setwinvar(argvars, rettv, 0);
+}
+
+/// "setbufvar()" function
+void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if (check_secure()
+ || !tv_check_str_or_nr(&argvars[0])) {
+ return;
+ }
+ const char *varname = tv_get_string_chk(&argvars[1]);
+ buf_T *const buf = tv_get_buf(&argvars[0], false);
+ typval_T *varp = &argvars[2];
+
+ if (buf != NULL && varname != NULL) {
+ if (*varname == '&') {
+ aco_save_T aco;
+
+ // set curbuf to be our buf, temporarily
+ aucmd_prepbuf(&aco, buf);
+
+ set_option_from_tv(varname + 1, varp);
+
+ // reset notion of buffer
+ aucmd_restbuf(&aco);
+ } else {
+ const size_t varname_len = STRLEN(varname);
+ char *const bufvarname = xmalloc(varname_len + 3);
+ buf_T *const save_curbuf = curbuf;
+ curbuf = buf;
+ memcpy(bufvarname, "b:", 2);
+ memcpy(bufvarname + 2, varname, varname_len + 1);
+ set_var(bufvarname, varname_len + 2, varp, true);
+ xfree(bufvarname);
+ curbuf = save_curbuf;
+ }
+ }
+}
diff --git a/src/nvim/eval/vars.h b/src/nvim/eval/vars.h
new file mode 100644
index 0000000000..73efc4938a
--- /dev/null
+++ b/src/nvim/eval/vars.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_EVAL_VARS_H
+#define NVIM_EVAL_VARS_H
+
+#include "nvim/ex_cmds_defs.h" // For exarg_T
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/vars.h.generated.h"
+#endif
+#endif // NVIM_EVAL_VARS_H
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 28e1893b31..23e7660606 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1583,22 +1583,39 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
if (otmp != NULL) {
len += STRLEN(otmp) + STRLEN(p_srr) + 2; // two extra spaces (" "),
}
+
+ const char *const cmd_args = strchr(cmd, ' ');
+ len += (is_pwsh && cmd_args)
+ ? STRLEN(" -ArgumentList ") + 2 // two extra quotes
+ : 0;
+
char *const buf = xmalloc(len);
-#if defined(UNIX)
- // Put delimiters around the command (for concatenated commands) when
- // redirecting input and/or output.
if (is_pwsh) {
xstrlcpy(buf, "Start-Process ", len);
- xstrlcat(buf, cmd, len);
+ if (cmd_args == NULL) {
+ xstrlcat(buf, cmd, len);
+ } else {
+ xstrlcpy(buf + STRLEN(buf), cmd, (size_t)(cmd_args - cmd + 1));
+ xstrlcat(buf, " -ArgumentList \"", len);
+ xstrlcat(buf, cmd_args + 1, len); // +1 to skip the leading space.
+ xstrlcat(buf, "\"", len);
+ }
+#if defined(UNIX)
+ // Put delimiters around the command (for concatenated commands) when
+ // redirecting input and/or output.
} else if (itmp != NULL || otmp != NULL) {
char *fmt = is_fish_shell ? "begin; %s; end"
: "(%s)";
vim_snprintf(buf, len, fmt, cmd);
+#endif
+ // For shells that don't understand braces around commands, at least allow
+ // the use of commands in a pipe.
} else {
xstrlcpy(buf, cmd, len);
}
+#if defined(UNIX)
if (itmp != NULL) {
if (is_pwsh) {
xstrlcat(buf, " -RedirectStandardInput ", len - 1);
@@ -1608,14 +1625,6 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
xstrlcat(buf, itmp, len - 1);
}
#else
- // For shells that don't understand braces around commands, at least allow
- // the use of commands in a pipe.
- if (is_pwsh) {
- xstrlcpy(buf, "Start-Process ", len);
- xstrlcat(buf, cmd, len);
- } else {
- xstrlcpy(buf, cmd, len);
- }
if (itmp != NULL) {
// If there is a pipe, we have to put the '<' in front of it.
// Don't do this when 'shellquote' is not empty, otherwise the
@@ -2716,6 +2725,12 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
// Assume success now
retval = OK;
+ // If the file name was changed, reset the not-edit flag so that ":write"
+ // works.
+ if (!other_file) {
+ curbuf->b_flags &= ~BF_NOTEDITED;
+ }
+
/*
* Check if we are editing the w_arg_idx file in the argument list.
*/
@@ -3582,7 +3597,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
// check for a trailing count
cmd = skipwhite(cmd);
if (ascii_isdigit(*cmd)) {
- i = getdigits_long((char_u **)&cmd, true, 0);
+ i = getdigits_long(&cmd, true, 0);
if (i <= 0 && !eap->skip && subflags.do_error) {
emsg(_(e_zerocount));
return 0;
@@ -3635,7 +3650,6 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
assert(sub != NULL);
- bool sub_needs_free = false;
char *sub_copy = NULL;
// If the substitute pattern starts with "\=" then it's an expression.
@@ -3647,14 +3661,15 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
sub = xstrdup(sub);
sub_copy = sub;
} else {
- char *source = sub;
- sub = (char *)regtilde((char_u *)sub, p_magic, cmdpreview);
- // When previewing, the new pattern allocated by regtilde() needs to be freed
- // in this function because it will not be used or freed by regtilde() later.
- sub_needs_free = cmdpreview && sub != source;
+ char *newsub = (char *)regtilde((char_u *)sub, p_magic, cmdpreview);
+ if (newsub != sub) {
+ // newsub was allocated, free it later.
+ sub_copy = newsub;
+ sub = newsub;
+ }
}
- bool cmdheight0 = p_ch < 1 && !ui_has(kUIMessages);
+ const bool cmdheight0 = !ui_has_messages();
if (cmdheight0) {
// If cmdheight is 0, cmdheight must be set to 1 when we enter command line.
set_option_value("ch", 1L, NULL, 0);
@@ -4450,9 +4465,6 @@ skip:
vim_regfree(regmatch.regprog);
xfree(sub_copy);
- if (sub_needs_free) {
- xfree(sub);
- }
// Restore the flag values, they can be used for ":&&".
subflags.do_all = save_do_all;
@@ -4846,14 +4858,14 @@ void ex_help(exarg_T *eap)
semsg(_("E149: Sorry, no help for %s"), arg);
}
if (n != FAIL) {
- FreeWild(num_matches, (char_u **)matches);
+ FreeWild(num_matches, matches);
}
return;
}
// The first match (in the requested language) is the best match.
tag = xstrdup(matches[i]);
- FreeWild(num_matches, (char_u **)matches);
+ FreeWild(num_matches, matches);
/*
* Re-use an existing help window or open a new one.
@@ -5042,7 +5054,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep
int i;
// Specific tags that either have a specific replacement or won't go
- // throught the generic rules.
+ // through the generic rules.
static char *(except_tbl[][2]) = {
{ "*", "star" },
{ "g*", "gstar" },
@@ -5275,7 +5287,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep
if (keep_lang) {
flags |= TAG_KEEP_LANG;
}
- if (find_tags(IObuff, num_matches, (char_u ***)matches, flags, MAXCOL, NULL) == OK
+ if (find_tags(IObuff, num_matches, matches, flags, MAXCOL, NULL) == OK
&& *num_matches > 0) {
// Sort the matches found on the heuristic number that is after the
// tag name.
@@ -5412,8 +5424,8 @@ void fix_help_buffer(void)
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char *buff_list[1] = { (char *)NameBuff };
- if (gen_expand_wildcards(1, (char_u **)buff_list, &fcount,
- (char_u ***)&fnames, EW_FILE|EW_SILENT) == OK
+ if (gen_expand_wildcards(1, buff_list, &fcount,
+ &fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
// If foo.abx is found use it instead of foo.txt in
// the same directory.
@@ -5514,7 +5526,7 @@ void fix_help_buffer(void)
}
fclose(fd);
}
- FreeWild(fcount, (char_u **)fnames);
+ FreeWild(fcount, fnames);
}
}
xfree(rt);
@@ -5568,12 +5580,15 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char *buff_list[1] = { (char *)NameBuff };
- if (gen_expand_wildcards(1, (char_u **)buff_list, &filecount, (char_u ***)&files,
- EW_FILE|EW_SILENT) == FAIL
- || filecount == 0) {
+ const int res = gen_expand_wildcards(1, buff_list, &filecount, &files,
+ EW_FILE|EW_SILENT);
+ if (res == FAIL || filecount == 0) {
if (!got_int) {
semsg(_("E151: No match: %s"), NameBuff);
}
+ if (res != FAIL) {
+ FreeWild(filecount, files);
+ }
return;
}
@@ -5593,7 +5608,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
if (!ignore_writeerr) {
semsg(_("E152: Cannot open %s for writing"), NameBuff);
}
- FreeWild(filecount, (char_u **)files);
+ FreeWild(filecount, files);
return;
}
@@ -5683,11 +5698,11 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
fclose(fd);
}
- FreeWild(filecount, (char_u **)files);
+ FreeWild(filecount, files);
if (!got_int && ga.ga_data != NULL) {
// Sort the tags.
- sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ sort_strings(ga.ga_data, ga.ga_len);
// Check for duplicates.
for (int i = 1; i < ga.ga_len; i++) {
@@ -5762,7 +5777,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr)
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
char *buff_list[1] = { (char *)NameBuff };
- if (gen_expand_wildcards(1, (char_u **)buff_list, &filecount, (char_u ***)&files,
+ if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
semsg(_("E151: No match: %s"), NameBuff);
@@ -5778,6 +5793,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr)
if (len <= 4) {
continue;
}
+
if (STRICMP(files[i] + len - 4, ".txt") == 0) {
// ".txt" -> language "en"
lang[0] = 'e';
@@ -5828,7 +5844,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr)
}
ga_clear(&ga);
- FreeWild(filecount, (char_u **)files);
+ FreeWild(filecount, files);
}
static void helptags_cb(char *fname, void *cookie)
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index e57dc5d13f..730a2f1b69 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -24,6 +24,7 @@
#include "nvim/charset.h"
#include "nvim/debugger.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_eval.h"
@@ -856,7 +857,7 @@ static void get_arglist(garray_T *gap, char *str, int escaped)
/// "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'.
///
/// @return FAIL or OK.
-int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
+int get_arglist_exp(char_u *str, int *fcountp, char ***fnamesp, bool wig)
{
garray_T ga;
int i;
@@ -864,10 +865,10 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
get_arglist(&ga, (char *)str, true);
if (wig) {
- i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+ i = expand_wildcards(ga.ga_len, ga.ga_data,
fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD);
} else {
- i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+ i = gen_expand_wildcards(ga.ga_len, ga.ga_data,
fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD);
}
@@ -949,8 +950,8 @@ static int do_arglist(char *str, int what, int after, bool will_edit)
}
ga_clear(&new_ga);
} else {
- int i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
- &exp_count, (char_u ***)&exp_files,
+ int i = expand_wildcards(new_ga.ga_len, new_ga.ga_data,
+ &exp_count, &exp_files,
EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
ga_clear(&new_ga);
if (i == FAIL || exp_count == 0) {
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index c4d2821e79..a7d91a47d7 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -21,6 +21,7 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/eval/vars.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/ex_cmds.h"
@@ -1395,7 +1396,7 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate)
if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg)
&& (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL
|| ascii_iswhite(*p))) {
- n = getdigits_long((char_u **)&eap->arg, false, -1);
+ n = getdigits_long(&eap->arg, false, -1);
eap->arg = skipwhite(eap->arg);
if (n <= 0 && (eap->argt & EX_ZEROR) == 0) {
if (errormsg != NULL) {
@@ -1623,7 +1624,7 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
// If filename expansion is enabled, expand filenames
if (cmdinfo->magic.file) {
- if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) {
+ if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) {
goto end;
}
}
@@ -2289,7 +2290,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
}
if (ea.argt & EX_XFILE) {
- if (expand_filename(&ea, (char_u **)cmdlinep, &errormsg) == FAIL) {
+ if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) {
goto doend;
}
}
@@ -2852,11 +2853,13 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
if (!mark_check(fm)) {
goto theend;
}
+ assert(fm != NULL);
eap->line1 = fm->mark.lnum;
fm = mark_get_visual(curbuf, '>');
if (!mark_check(fm)) {
goto theend;
}
+ assert(fm != NULL);
eap->line2 = fm->mark.lnum;
eap->addr_count++;
}
@@ -3049,6 +3052,7 @@ char *find_ex_command(exarg_T *eap, int *full)
} else {
eap->cmdidx = CMD_bang;
}
+ assert(eap->cmdidx >= 0);
for (; (int)eap->cmdidx < CMD_SIZE;
eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) {
@@ -3268,6 +3272,7 @@ int cmd_exists(const char *const name)
// For ":2match" and ":3match" we need to skip the number.
ea.cmd = (char *)((*name == '2' || *name == '3') ? name + 1 : name);
ea.cmdidx = (cmdidx_T)0;
+ ea.flags = 0;
int full = false;
p = find_ex_command(&ea, &full);
if (p == NULL) {
@@ -3301,6 +3306,7 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name;
ea.cmdidx = (cmdidx_T)0;
+ ea.flags = 0;
char *p = find_ex_command(&ea, NULL);
if (p == NULL || ea.cmdidx == CMD_SIZE) {
return;
@@ -4390,6 +4396,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
cmd = NULL;
goto error;
}
+ assert(fm != NULL);
lnum = fm->mark.lnum;
}
}
@@ -4482,7 +4489,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
default:
if (ascii_isdigit(*cmd)) { // absolute line number
- lnum = (linenr_T)getdigits((char_u **)&cmd, false, 0);
+ lnum = (linenr_T)getdigits(&cmd, false, 0);
}
}
@@ -4731,78 +4738,46 @@ static char *skip_grep_pat(exarg_T *eap)
/// For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option
/// in the command line, so that things like % get expanded.
-char *replace_makeprg(exarg_T *eap, char *p, char **cmdlinep)
+char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep)
{
- char *new_cmdline;
- char *program;
- char *pos;
- char *ptr;
- int len;
- size_t i;
+ bool isgrep = eap->cmdidx == CMD_grep
+ || eap->cmdidx == CMD_lgrep
+ || eap->cmdidx == CMD_grepadd
+ || eap->cmdidx == CMD_lgrepadd;
- /*
- * Don't do it when ":vimgrep" is used for ":grep".
- */
- if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake
- || eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
- || eap->cmdidx == CMD_grepadd
- || eap->cmdidx == CMD_lgrepadd)
+ // Don't do it when ":vimgrep" is used for ":grep".
+ if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake || isgrep)
&& !grep_internal(eap->cmdidx)) {
- if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
- || eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) {
- if (*curbuf->b_p_gp == NUL) {
- program = (char *)p_gp;
- } else {
- program = (char *)curbuf->b_p_gp;
- }
- } else {
- if (*curbuf->b_p_mp == NUL) {
- program = (char *)p_mp;
- } else {
- program = (char *)curbuf->b_p_mp;
- }
- }
+ const char *program = isgrep ? (*curbuf->b_p_gp == NUL ? (char *)p_gp : (char *)curbuf->b_p_gp)
+ : (*curbuf->b_p_mp == NUL ? (char *)p_mp : (char *)curbuf->b_p_mp);
- p = skipwhite(p);
+ arg = skipwhite(arg);
- if ((pos = strstr(program, "$*")) != NULL) {
- // replace $* by given arguments
- i = 1;
- while ((pos = strstr(pos + 2, "$*")) != NULL) {
- i++;
- }
- len = (int)STRLEN(p);
- new_cmdline = xmalloc(STRLEN(program) + i * (size_t)(len - 2) + 1);
- ptr = new_cmdline;
- while ((pos = strstr(program, "$*")) != NULL) {
- i = (size_t)(pos - program);
- memcpy(ptr, program, i);
- STRCPY(ptr += i, p);
- ptr += len;
- program = pos + 2;
- }
- STRCPY(ptr, program);
- } else {
- new_cmdline = xmalloc(STRLEN(program) + STRLEN(p) + 2);
+ char *new_cmdline;
+ // Replace $* by given arguments
+ if ((new_cmdline = strrep(program, "$*", arg)) == NULL) {
+ // No $* in arg, build "<makeprg> <arg>" instead
+ new_cmdline = xmalloc(STRLEN(program) + STRLEN(arg) + 2);
STRCPY(new_cmdline, program);
STRCAT(new_cmdline, " ");
- STRCAT(new_cmdline, p);
+ STRCAT(new_cmdline, arg);
}
- msg_make((char_u *)p);
+
+ msg_make((char_u *)arg);
// 'eap->cmd' is not set here, because it is not used at CMD_make
xfree(*cmdlinep);
*cmdlinep = new_cmdline;
- p = new_cmdline;
+ arg = new_cmdline;
}
- return p;
+ return arg;
}
/// Expand file name in Ex command argument.
/// When an error is detected, "errormsgp" is set to a non-NULL pointer.
///
/// @return FAIL for failure, OK otherwise.
-int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
+int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp)
{
int has_wildcards; // need to expand wildcards
char *repl;
@@ -4908,7 +4883,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
repl = l;
}
- p = repl_cmdline(eap, p, srclen, repl, (char **)cmdlinep);
+ p = repl_cmdline(eap, p, srclen, repl, cmdlinep);
xfree(repl);
}
@@ -4935,7 +4910,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
p = NULL;
}
if (p != NULL) {
- (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, (char **)cmdlinep);
+ (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep);
}
}
@@ -4962,7 +4937,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
if (p == NULL) {
return FAIL;
}
- (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, (char **)cmdlinep);
+ (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep);
xfree(p);
}
}
@@ -5246,7 +5221,7 @@ static int get_tabpage_arg(exarg_T *eap)
}
p_save = p;
- tab_number = (int)getdigits((char_u **)&p, false, tab_number);
+ tab_number = (int)getdigits(&p, false, tab_number);
if (relative == 0) {
if (STRCMP(p, "$") == 0) {
@@ -5942,7 +5917,7 @@ two_count:
return FAIL;
}
- *def = getdigits_long((char_u **)&p, true, 0);
+ *def = getdigits_long(&p, true, 0);
*argt |= EX_ZEROR;
if (p != val + vallen || vallen == 0) {
@@ -5968,7 +5943,7 @@ invalid_count:
goto two_count;
}
- *def = getdigits_long((char_u **)&p, true, 0);
+ *def = getdigits_long(&p, true, 0);
if (p != val + vallen) {
goto invalid_count;
@@ -6783,9 +6758,18 @@ char *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx)
if (idx < buf->b_ucmds.ga_len) {
return (char *)USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
}
+
idx -= buf->b_ucmds.ga_len;
if (idx < ucmds.ga_len) {
- return (char *)USER_CMD(idx)->uc_name;
+ char *name = (char *)USER_CMD(idx)->uc_name;
+
+ for (int i = 0; i < buf->b_ucmds.ga_len; i++) {
+ if (STRCMP(name, USER_CMD_GA(&buf->b_ucmds, i)->uc_name) == 0) {
+ // global command is overruled by buffer-local one
+ return "";
+ }
+ }
+ return name;
}
return NULL;
}
@@ -7741,7 +7725,7 @@ static void ex_tabnext(exarg_T *eap)
if (eap->arg && *eap->arg != NUL) {
char *p = eap->arg;
char *p_save = p;
- tab_number = (int)getdigits((char_u **)&p, false, 0);
+ tab_number = (int)getdigits(&p, false, 0);
if (p == p_save || *p_save == '-' || *p_save == '+' || *p != NUL
|| tab_number == 0) {
// No numbers as argument.
@@ -8722,7 +8706,7 @@ static void ex_later(exarg_T *eap)
if (*p == NUL) {
count = 1;
} else if (isdigit(*p)) {
- count = getdigits_long((char_u **)&p, false, 0);
+ count = getdigits_long(&p, false, 0);
switch (*p) {
case 's':
++p; sec = true; break;
@@ -9239,7 +9223,7 @@ static void ex_findpat(exarg_T *eap)
n = 1;
if (ascii_isdigit(*eap->arg)) { // get count
- n = getdigits_long((char_u **)&eap->arg, false, 0);
+ n = getdigits_long(&eap->arg, false, 0);
eap->arg = skipwhite(eap->arg);
}
if (*eap->arg == '/') { // Match regexp, not just whole words
@@ -9997,7 +9981,7 @@ static void ex_setfiletype(exarg_T *eap)
static void ex_digraphs(exarg_T *eap)
{
if (*eap->arg != NUL) {
- putdigraph((char_u *)eap->arg);
+ putdigraph(eap->arg);
} else {
listdigraphs(eap->forceit);
}
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index 7e0d3016bc..ddb25c53e4 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -1,7 +1,6 @@
#ifndef NVIM_EX_DOCMD_H
#define NVIM_EX_DOCMD_H
-#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/globals.h"
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 4c26cfe500..6240ac6b37 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -24,6 +24,7 @@
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/funcs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/event/loop.h"
#include "nvim/ex_cmds.h"
@@ -688,12 +689,22 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool
/// @param init_ccline clear ccline first
static uint8_t *command_line_enter(int firstc, long count, int indent, bool init_ccline)
{
- bool cmdheight0 = p_ch < 1 && !ui_has(kUIMessages);
+ const bool cmdheight0 = !ui_has_messages();
if (cmdheight0) {
- // If cmdheight is 0, cmdheight must be set to 1 when we enter command line.
+ const long save_so = lastwin->w_p_so;
+
+ // If cmdheight is 0, cmdheight must be set to 1 when we enter the
+ // command line. Set "made_cmdheight_nonzero" and reset 'scrolloff' to
+ // avoid scrolling the last window.
+ made_cmdheight_nonzero = true;
+
+ lastwin->w_p_so = 0;
set_option_value("ch", 1L, NULL, 0);
update_screen(VALID); // redraw the screen NOW
+
+ made_cmdheight_nonzero = false;
+ lastwin->w_p_so = save_so;
}
// can be invoked recursively, identify each level
@@ -827,6 +838,36 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
setmouse();
ui_cursor_shape(); // may show different cursor shape
+ TryState tstate;
+ Error err = ERROR_INIT;
+ bool tl_ret = true;
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
+ char firstcbuf[2];
+ firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
+ firstcbuf[1] = 0;
+
+ if (has_event(EVENT_CMDLINEENTER)) {
+ // set v:event to a dictionary with information about the commandline
+ tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
+ tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
+ tv_dict_set_keys_readonly(dict);
+ try_enter(&tstate);
+
+ apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
+ restore_v_event(dict, &save_v_event);
+
+ tl_ret = try_leave(&tstate, &err);
+ if (!tl_ret && ERROR_SET(&err)) {
+ msg_putchar('\n');
+ msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
+ api_clear_error(&err);
+ redrawcmd();
+ }
+ tl_ret = true;
+ }
+ may_trigger_modechanged();
+
init_history();
s->hiscnt = hislen; // set hiscnt to impossible history value
s->histype = hist_char2type(s->firstc);
@@ -849,6 +890,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
found_one = true;
}
}
+
+ if (*p_tal != NUL) {
+ redraw_tabline = true;
+ found_one = true;
+ }
+
if (found_one) {
redraw_statuslines();
}
@@ -859,36 +906,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
s->state.check = command_line_check;
s->state.execute = command_line_execute;
- TryState tstate;
- Error err = ERROR_INIT;
- bool tl_ret = true;
- save_v_event_T save_v_event;
- dict_T *dict = get_v_event(&save_v_event);
- char firstcbuf[2];
- firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
- firstcbuf[1] = 0;
-
- if (has_event(EVENT_CMDLINEENTER)) {
- // set v:event to a dictionary with information about the commandline
- tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
- tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
- tv_dict_set_keys_readonly(dict);
- try_enter(&tstate);
-
- apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
- restore_v_event(dict, &save_v_event);
-
- tl_ret = try_leave(&tstate, &err);
- if (!tl_ret && ERROR_SET(&err)) {
- msg_putchar('\n');
- msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
- api_clear_error(&err);
- redrawcmd();
- }
- tl_ret = true;
- }
- may_trigger_modechanged();
-
state_enter(&s->state);
if (has_event(EVENT_CMDLINELEAVE)) {
@@ -958,6 +975,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
cmdpreview = save_cmdpreview; // restore preview state
redraw_all_later(SOME_VALID);
}
+ may_trigger_modechanged();
setmouse();
ui_cursor_shape(); // may show different cursor shape
sb_text_end_cmdline();
@@ -983,11 +1001,14 @@ theend:
}
if (cmdheight0) {
+ made_cmdheight_nonzero = true;
+
// Restore cmdheight
set_option_value("ch", 0L, NULL, 0);
-
// Redraw is needed for command line completion
redraw_all_later(CLEAR);
+
+ made_cmdheight_nonzero = false;
}
return p;
@@ -1066,7 +1087,8 @@ static int command_line_execute(VimState *state, int key)
// Don't ignore it for the input() function.
if ((s->c == Ctrl_C)
&& s->firstc != '@'
- && !s->break_ctrl_c
+ // do clear got_int in Ex mode to avoid infinite Ctrl-C loop
+ && (!s->break_ctrl_c || exmode_active)
&& !global_busy) {
got_int = false;
}
@@ -3327,7 +3349,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
{
Arena arena = ARENA_EMPTY;
arena_start(&arena, &ui_ext_fixblk);
- Array content = ARRAY_DICT_INIT;
+ Array content;
if (cmdline_star) {
content = arena_array(&arena, 1);
size_t len = 0;
@@ -3814,6 +3836,7 @@ void redrawcmd(void)
redrawing_cmdline = true;
+ sb_text_restart_cmdline();
msg_start();
redrawcmdprompt();
@@ -4142,8 +4165,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode
compl_selected = findex;
cmdline_pum_display(false);
} else if (p_wmnu) {
- win_redr_status_matches(xp, xp->xp_numfiles, (char_u **)xp->xp_files,
- findex, cmd_showtail);
+ win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, findex, cmd_showtail);
}
if (findex == -1) {
return vim_strsave(orig_save);
@@ -4163,7 +4185,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode
// free old names
if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) {
- FreeWild(xp->xp_numfiles, (char_u **)xp->xp_files);
+ FreeWild(xp->xp_numfiles, xp->xp_files);
xp->xp_numfiles = -1;
XFREE_CLEAR(orig_save);
}
@@ -4181,8 +4203,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode
/*
* Do the expansion.
*/
- if (ExpandFromContext(xp, str, &xp->xp_numfiles, (char_u ***)&xp->xp_files,
- options) == FAIL) {
+ if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files, options) == FAIL) {
#ifdef FNAME_ILLEGAL
/* Illegal file name has been silently skipped. But when there
* are wildcards, the real problem is that there was no match,
@@ -4198,7 +4219,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode
}
} else {
// Escape the matches for use on the command line.
- ExpandEscape(xp, str, xp->xp_numfiles, (char_u **)xp->xp_files, options);
+ ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
/*
* Check for matching suffixes in file names.
@@ -4323,12 +4344,12 @@ void ExpandInit(expand_T *xp)
void ExpandCleanup(expand_T *xp)
{
if (xp->xp_numfiles >= 0) {
- FreeWild(xp->xp_numfiles, (char_u **)xp->xp_files);
+ FreeWild(xp->xp_numfiles, xp->xp_files);
xp->xp_numfiles = -1;
}
}
-void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int options)
+void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char **files, int options)
{
int i;
char_u *p;
@@ -4354,9 +4375,9 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
for (i = 0; i < numfiles; ++i) {
// for ":set path=" we need to escape spaces twice
if (xp->xp_backslash == XP_BS_THREE) {
- p = vim_strsave_escaped(files[i], (char_u *)" ");
+ p = vim_strsave_escaped((char_u *)files[i], (char_u *)" ");
xfree(files[i]);
- files[i] = p;
+ files[i] = (char *)p;
#if defined(BACKSLASH_IN_FILENAME)
p = vim_strsave_escaped(files[i], (char_u *)" ");
xfree(files[i]);
@@ -4370,7 +4391,7 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
xp->xp_shell ? VSE_SHELL : vse_what);
#endif
xfree(files[i]);
- files[i] = p;
+ files[i] = (char *)p;
/* If 'str' starts with "\~", replace "~" at start of
* files[i] with "\~". */
@@ -4390,10 +4411,10 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
* Insert a backslash before characters in a tag name that
* would terminate the ":tag" command.
*/
- for (i = 0; i < numfiles; ++i) {
- p = vim_strsave_escaped(files[i], (char_u *)"\\|\"");
+ for (i = 0; i < numfiles; i++) {
+ p = vim_strsave_escaped((char_u *)files[i], (char_u *)"\\|\"");
xfree(files[i]);
- files[i] = p;
+ files[i] = (char *)p;
}
}
}
@@ -4449,7 +4470,7 @@ char *vim_strsave_fnameescape(const char *const fname, const int what)
// '>' and '+' are special at the start of some commands, e.g. ":edit" and
// ":write". "cd -" has a special meaning.
if (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)) {
- escape_fname((char_u **)&p);
+ escape_fname(&p);
}
return p;
@@ -4458,28 +4479,26 @@ char *vim_strsave_fnameescape(const char *const fname, const int what)
/*
* Put a backslash before the file name in "pp", which is in allocated memory.
*/
-static void escape_fname(char_u **pp)
+static void escape_fname(char **pp)
{
char_u *p = xmalloc(STRLEN(*pp) + 2);
p[0] = '\\';
STRCPY(p + 1, *pp);
xfree(*pp);
- *pp = p;
+ *pp = (char *)p;
}
-/*
- * For each file name in files[num_files]:
- * If 'orig_pat' starts with "~/", replace the home directory with "~".
- */
-void tilde_replace(char_u *orig_pat, int num_files, char_u **files)
+/// For each file name in files[num_files]:
+/// If 'orig_pat' starts with "~/", replace the home directory with "~".
+void tilde_replace(char_u *orig_pat, int num_files, char **files)
{
char *p;
if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1])) {
for (int i = 0; i < num_files; i++) {
- p = home_replace_save(NULL, (char *)files[i]);
+ p = home_replace_save(NULL, files[i]);
xfree(files[i]);
- files[i] = (char_u *)p;
+ files[i] = p;
}
}
}
@@ -4500,7 +4519,7 @@ static int showmatches(expand_T *xp, int wildmenu)
#define L_SHOWFILE(m) (showtail \
? sm_gettail(files_found[m], false) : files_found[m])
int num_files;
- char_u **files_found;
+ char **files_found;
int i, j, k;
int maxlen;
int lines;
@@ -4520,7 +4539,7 @@ static int showmatches(expand_T *xp, int wildmenu)
}
} else {
num_files = xp->xp_numfiles;
- files_found = (char_u **)xp->xp_files;
+ files_found = xp->xp_files;
showtail = cmd_showtail;
}
@@ -4535,10 +4554,9 @@ static int showmatches(expand_T *xp, int wildmenu)
compl_match_array = xcalloc((size_t)compl_match_arraysize,
sizeof(pumitem_T));
for (i = 0; i < num_files; i++) {
- compl_match_array[i].pum_text = L_SHOWFILE(i);
+ compl_match_array[i].pum_text = (char_u *)L_SHOWFILE(i);
}
- char_u *endpos = (showtail
- ? sm_gettail((char_u *)xp->xp_pattern, true) : (char_u *)xp->xp_pattern);
+ char_u *endpos = (char_u *)(showtail ? sm_gettail(xp->xp_pattern, true) : xp->xp_pattern);
if (ui_has(kUICmdline)) {
compl_startcol = (int)(endpos - ccline.cmdbuff);
} else {
@@ -4570,10 +4588,10 @@ static int showmatches(expand_T *xp, int wildmenu)
if (!showtail && (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS)) {
- home_replace(NULL, (char *)files_found[i], (char *)NameBuff, MAXPATHL, true);
+ home_replace(NULL, files_found[i], (char *)NameBuff, MAXPATHL, true);
j = vim_strsize((char *)NameBuff);
} else {
- j = vim_strsize((char *)L_SHOWFILE(i));
+ j = vim_strsize(L_SHOWFILE(i));
}
if (j > maxlen) {
maxlen = j;
@@ -4606,8 +4624,8 @@ static int showmatches(expand_T *xp, int wildmenu)
lastlen = 999;
for (k = i; k < num_files; k += lines) {
if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
- msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D));
- p = files_found[k] + STRLEN(files_found[k]) + 1;
+ msg_outtrans_attr((char_u *)files_found[k], HL_ATTR(HLF_D));
+ p = (char_u *)files_found[k] + STRLEN(files_found[k]) + 1;
msg_advance(maxlen + 1);
msg_puts((const char *)p);
msg_advance(maxlen + 3);
@@ -4625,8 +4643,8 @@ static int showmatches(expand_T *xp, int wildmenu)
// Expansion was done before and special characters
// were escaped, need to halve backslashes. Also
// $HOME has been replaced with ~/.
- char_u *exp_path = expand_env_save_opt(files_found[k], true);
- char_u *path = exp_path != NULL ? exp_path : files_found[k];
+ char_u *exp_path = expand_env_save_opt((char_u *)files_found[k], true);
+ char_u *path = exp_path != NULL ? exp_path : (char_u *)files_found[k];
char_u *halved_slash = backslash_halve_save(path);
j = os_isdir(halved_slash);
xfree(exp_path);
@@ -4635,17 +4653,17 @@ static int showmatches(expand_T *xp, int wildmenu)
}
} else {
// Expansion was done here, file names are literal.
- j = os_isdir(files_found[k]);
+ j = os_isdir((char_u *)files_found[k]);
}
if (showtail) {
- p = L_SHOWFILE(k);
+ p = (char_u *)L_SHOWFILE(k);
} else {
- home_replace(NULL, (char *)files_found[k], (char *)NameBuff, MAXPATHL, true);
+ home_replace(NULL, files_found[k], (char *)NameBuff, MAXPATHL, true);
p = NameBuff;
}
} else {
- j = FALSE;
- p = L_SHOWFILE(k);
+ j = false;
+ p = (char_u *)L_SHOWFILE(k);
}
lastlen = msg_outtrans_attr(p, j ? attr : 0);
}
@@ -4674,17 +4692,15 @@ static int showmatches(expand_T *xp, int wildmenu)
return EXPAND_OK;
}
-/*
- * Private path_tail for showmatches() (and win_redr_status_matches()):
- * Find tail of file name path, but ignore trailing "/".
- */
-char_u *sm_gettail(char_u *s, bool eager)
+/// Private path_tail for showmatches() (and win_redr_status_matches()):
+/// Find tail of file name path, but ignore trailing "/".
+char *sm_gettail(char *s, bool eager)
{
char_u *p;
- char_u *t = s;
- int had_sep = FALSE;
+ char_u *t = (char_u *)s;
+ int had_sep = false;
- for (p = s; *p != NUL;) {
+ for (p = (char_u *)s; *p != NUL;) {
if (vim_ispathsep(*p)
#ifdef BACKSLASH_IN_FILENAME
&& !rem_backslash(p)
@@ -4701,7 +4717,7 @@ char_u *sm_gettail(char_u *s, bool eager)
}
MB_PTR_ADV(p);
}
- return t;
+ return (char *)t;
}
/*
@@ -4979,7 +4995,7 @@ void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline
/// @param col position of cursor
/// @param matchcount return: nr of matches
/// @param matches return: array of pointers to matches
-int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u ***matches)
+int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char ***matches)
{
char_u *file_str = NULL;
int options = WILD_ADD_SLASH|WILD_SILENT;
@@ -5015,7 +5031,7 @@ int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u *
// Cleanup matches for help tags:
// Remove "@ab" if the top of 'helplang' is "ab" and the language of the first
// tag matches it. Otherwise remove "@en" if "en" is the only language.
-static void cleanup_help_tags(int num_file, char_u **file)
+static void cleanup_help_tags(int num_file, char **file)
{
char_u buf[4];
char_u *p = buf;
@@ -5069,7 +5085,7 @@ typedef char *(*ExpandFunc)(expand_T *, int);
/// Do the expansion based on xp->xp_context and "pat".
///
/// @param options WILD_ flags
-static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ***file, int options)
+static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***file, int options)
{
regmatch_T regmatch;
int ret;
@@ -5164,7 +5180,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
/* With an empty argument we would get all the help tags, which is
* very slow. Get matches for "help" instead. */
if (find_help_tags(*pat == NUL ? "help" : (char *)pat,
- num_file, (char ***)file, false) == OK) {
+ num_file, file, false) == OK) {
cleanup_help_tags(*num_file, *file);
return OK;
}
@@ -5181,10 +5197,10 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
return OK;
}
if (xp->xp_context == EXPAND_BUFFERS) {
- return ExpandBufnames((char *)pat, num_file, (char ***)file, options);
+ return ExpandBufnames((char *)pat, num_file, file, options);
}
if (xp->xp_context == EXPAND_DIFF_BUFFERS) {
- return ExpandBufnames((char *)pat, num_file, (char ***)file, options | BUF_DIFF_FILTER);
+ return ExpandBufnames((char *)pat, num_file, file, options | BUF_DIFF_FILTER);
}
if (xp->xp_context == EXPAND_TAGS
|| xp->xp_context == EXPAND_TAGS_LISTFILES) {
@@ -5192,8 +5208,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
}
if (xp->xp_context == EXPAND_COLORS) {
char *directories[] = { "colors", NULL };
- return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_LUA, num_file, file,
- directories);
+ return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_LUA, num_file, file, directories);
}
if (xp->xp_context == EXPAND_COMPILER) {
char *directories[] = { "compiler", NULL };
@@ -5300,8 +5315,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
if (tab[i].ic) {
regmatch.rm_ic = TRUE;
}
- ExpandGeneric(xp, &regmatch, num_file, file, tab[i].func,
- tab[i].escaped);
+ ExpandGeneric(xp, &regmatch, num_file, file, tab[i].func, tab[i].escaped);
ret = OK;
break;
}
@@ -5321,7 +5335,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
/// program. Matching strings are copied into an array, which is returned.
///
/// @param func returns a string from the list
-static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file,
+static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file,
CompleteListItemGetter func, int escaped)
{
int i;
@@ -5346,7 +5360,7 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
}
assert(count < INT_MAX);
*num_file = (int)count;
- *file = (char_u **)xmalloc(count * sizeof(char_u *));
+ *file = xmalloc(count * sizeof(char_u *));
// copy the matching names into allocated memory
count = 0;
@@ -5364,7 +5378,7 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
} else {
str = vim_strsave(str);
}
- (*file)[count++] = str;
+ (*file)[count++] = (char *)str;
if (func == get_menu_names) {
// Test for separator added by get_menu_names().
str += STRLEN(str) - 1;
@@ -5401,14 +5415,14 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
/// *file will either be set to NULL or point to
/// allocated memory.
/// @param flagsarg is a combination of EW_* flags.
-static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg)
+static void expand_shellcmd(char_u *filepat, int *num_file, char ***file, int flagsarg)
FUNC_ATTR_NONNULL_ALL
{
char_u *pat;
int i;
char_u *path = NULL;
garray_T ga;
- char_u *buf = xmalloc(MAXPATHL);
+ char *buf = xmalloc(MAXPATHL);
size_t l;
char_u *s, *e;
int flags = flagsarg;
@@ -5475,7 +5489,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int
break;
}
STRLCPY(buf, s, l + 1);
- add_pathsep((char *)buf);
+ add_pathsep(buf);
l = STRLEN(buf);
STRLCPY(buf + l, pat, MAXPATHL - l);
@@ -5485,7 +5499,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int
ga_grow(&ga, *num_file);
{
for (i = 0; i < *num_file; i++) {
- char_u *name = (*file)[i];
+ char_u *name = (char_u *)(*file)[i];
if (STRLEN(name) > l) {
// Check if this name was already found.
@@ -5524,7 +5538,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int
/// Call "user_expand_func()" to invoke a user defined Vim script function and
/// return the result (either a string, a List or NULL).
static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T *xp, int *num_file,
- char_u ***file)
+ char ***file)
FUNC_ATTR_NONNULL_ALL
{
char_u keep = 0;
@@ -5565,10 +5579,8 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
return ret;
}
-/*
- * Expand names with a function defined by the user.
- */
-static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)
+/// Expand names with a function defined by the user.
+static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file)
{
char_u *e;
garray_T ga;
@@ -5606,10 +5618,8 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
return OK;
}
-/*
- * Expand names with a list returned by a function defined by the user.
- */
-static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
+/// Expand names with a list returned by a function defined by the user.
+static int ExpandUserList(expand_T *xp, int *num_file, char ***file)
{
list_T *const retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp, num_file,
file);
@@ -5635,7 +5645,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
return OK;
}
-static int ExpandUserLua(expand_T *xp, int *num_file, char_u ***file)
+static int ExpandUserLua(expand_T *xp, int *num_file, char ***file)
{
typval_T rettv;
nlua_call_user_expand_func(xp, &rettv);
@@ -5673,7 +5683,7 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char_u ***file)
/// 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim
/// When "flags" has DIP_LUA: search also performed for .lua files
/// "dirnames" is an array with one or more directory names.
-static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirnames[])
+static int ExpandRTDir(char_u *pat, int flags, int *num_file, char ***file, char *dirnames[])
{
*num_file = 0;
*file = NULL;
@@ -5782,7 +5792,7 @@ static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, ch
/// Expand loadplugin names:
/// 'packpath'/pack/ * /opt/{pat}
-static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file)
+static int ExpandPackAddDir(char_u *pat, int *num_file, char ***file)
{
garray_T ga;
@@ -5836,7 +5846,7 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options)
add_pathsep((char *)buf);
STRCAT(buf, file); // NOLINT
- char_u **p;
+ char **p;
int num_p = 0;
(void)ExpandFromContext(&xpc, buf, &num_p, &p,
WILD_SILENT | expand_options);
@@ -5847,7 +5857,7 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options)
ga_grow(ga, num_p);
// take over the pointers and put them in "ga"
for (int i = 0; i < num_p; i++) {
- ((char_u **)ga->ga_data)[ga->ga_len] = p[i];
+ ((char_u **)ga->ga_data)[ga->ga_len] = (char_u *)p[i];
ga->ga_len++;
}
xfree(p);
@@ -6802,9 +6812,13 @@ static int open_cmdwin(void)
// Avoid command-line window first character being concealed.
curwin->w_p_cole = 0;
+ // First go back to the original window.
wp = curwin;
set_bufref(&bufref, curbuf);
win_goto(old_curwin);
+
+ // win_goto() may trigger an autocommand that already closes the
+ // cmdline window.
if (win_valid(wp) && wp != curwin) {
win_close(wp, true, false);
}
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 6ca6da9cd0..1d670afa6d 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -193,6 +193,9 @@ static int ses_do_win(win_T *wp)
if (bt_help(wp->w_buffer)) {
return ssop_flags & SSOP_HELP;
}
+ if (bt_terminal(wp->w_buffer)) {
+ return ssop_flags & SSOP_TERMINAL;
+ }
return true;
}
@@ -407,6 +410,8 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr
if ((flagp == &ssop_flags) && alt != NULL && alt->b_fname != NULL
&& *alt->b_fname != NUL
&& alt->b_p_bl
+ // do not set balt if buffer is terminal and "terminal" is not set in options
+ && !(bt_terminal(alt) && !(ssop_flags & SSOP_TERMINAL))
&& (fputs("balt ", fd) < 0
|| ses_fname(fd, alt, flagp, true) == FAIL)) {
return FAIL;
@@ -616,6 +621,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
FOR_ALL_BUFFERS(buf) {
if (!(only_save_windows && buf->b_nwindows == 0)
&& !(buf->b_help && !(ssop_flags & SSOP_HELP))
+ && !(bt_terminal(buf) && !(ssop_flags & SSOP_TERMINAL))
&& buf->b_fname != NULL
&& buf->b_p_bl) {
if (fprintf(fd, "badd +%" PRId64 " ",
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index ca276b8a40..ebefd1157c 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -82,12 +82,11 @@ typedef struct ff_stack {
char_u *ffs_fix_path;
char_u *ffs_wc_path;
- /* files/dirs found in the above directory, matched by the first wildcard
- * of wc_part
- */
- char_u **ffs_filearray;
+ // files/dirs found in the above directory, matched by the first wildcard
+ // of wc_part
+ char **ffs_filearray;
int ffs_filearray_size;
- char_u ffs_filearray_cur; // needed for partly handled dirs
+ int ffs_filearray_cur; // needed for partly handled dirs
/* to store status of partly handled directories
* 0: we work on this directory for the first time
@@ -683,12 +682,12 @@ char_u *vim_findfile(void *search_ctx_arg)
* to handle the expansion of '**' into an empty string.
*/
if (stackp->ffs_filearray == NULL) {
- char_u *dirptrs[2];
+ char *dirptrs[2];
/* we use filepath to build the path expand_wildcards() should
* expand.
*/
- dirptrs[0] = file_path;
+ dirptrs[0] = (char *)file_path;
dirptrs[1] = NULL;
// if we have a start dir copy it in
@@ -743,7 +742,7 @@ char_u *vim_findfile(void *search_ctx_arg)
if (stackp->ffs_star_star_empty == 0) {
// if not done before, expand '**' to empty
stackp->ffs_star_star_empty = 1;
- dirptrs[1] = stackp->ffs_fix_path;
+ dirptrs[1] = (char *)stackp->ffs_fix_path;
}
}
@@ -773,9 +772,9 @@ char_u *vim_findfile(void *search_ctx_arg)
* Expand wildcards like "*" and "$VAR".
* If the path is a URL don't try this.
*/
- if (path_with_url((char *)dirptrs[0])) {
+ if (path_with_url(dirptrs[0])) {
stackp->ffs_filearray = xmalloc(sizeof(char *));
- stackp->ffs_filearray[0] = vim_strsave(dirptrs[0]);
+ stackp->ffs_filearray[0] = xstrdup(dirptrs[0]);
stackp->ffs_filearray_size = 1;
} else {
/* Add EW_NOTWILD because the expanded path may contain
@@ -801,10 +800,9 @@ char_u *vim_findfile(void *search_ctx_arg)
* We don't have further wildcards to expand, so we have to
* check for the final file now.
*/
- for (int i = stackp->ffs_filearray_cur;
- i < stackp->ffs_filearray_size; ++i) {
- if (!path_with_url((char *)stackp->ffs_filearray[i])
- && !os_isdir(stackp->ffs_filearray[i])) {
+ for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) {
+ if (!path_with_url(stackp->ffs_filearray[i])
+ && !os_isdir((char_u *)stackp->ffs_filearray[i])) {
continue; // not a directory
}
// prepare the filename to be checked for existence below
@@ -862,8 +860,8 @@ char_u *vim_findfile(void *search_ctx_arg)
#endif
// push dir to examine rest of subdirs later
- assert(i < UCHAR_MAX - 1);
- stackp->ffs_filearray_cur = (char_u)(i + 1);
+ assert(i < INT_MAX);
+ stackp->ffs_filearray_cur = i + 1;
ff_push(search_ctx, stackp);
if (!path_with_url((char *)file_path)) {
@@ -897,17 +895,13 @@ char_u *vim_findfile(void *search_ctx_arg)
}
}
} else {
- /*
- * still wildcards left, push the directories for further
- * search
- */
- for (int i = stackp->ffs_filearray_cur;
- i < stackp->ffs_filearray_size; ++i) {
- if (!os_isdir(stackp->ffs_filearray[i])) {
+ // still wildcards left, push the directories for further search
+ for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) {
+ if (!os_isdir((char_u *)stackp->ffs_filearray[i])) {
continue; // not a directory
}
ff_push(search_ctx,
- ff_create_stack_element(stackp->ffs_filearray[i],
+ ff_create_stack_element((char_u *)stackp->ffs_filearray[i],
rest_of_wildcards,
stackp->ffs_level - 1, 0));
}
@@ -927,11 +921,11 @@ char_u *vim_findfile(void *search_ctx_arg)
stackp->ffs_fix_path) == 0) {
continue; // don't repush same directory
}
- if (!os_isdir(stackp->ffs_filearray[i])) {
+ if (!os_isdir((char_u *)stackp->ffs_filearray[i])) {
continue; // not a directory
}
ff_push(search_ctx,
- ff_create_stack_element(stackp->ffs_filearray[i],
+ ff_create_stack_element((char_u *)stackp->ffs_filearray[i],
stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 6782465ef1..b98984017b 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -710,7 +710,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
fenc_alloced = false;
} else {
fenc_next = (char *)p_fencs; // try items in 'fileencodings'
- fenc = (char *)next_fenc((char_u **)&fenc_next, &fenc_alloced);
+ fenc = (char *)next_fenc(&fenc_next, &fenc_alloced);
}
/*
@@ -804,7 +804,7 @@ retry:
xfree(fenc);
}
if (fenc_next != NULL) {
- fenc = (char *)next_fenc((char_u **)&fenc_next, &fenc_alloced);
+ fenc = (char *)next_fenc(&fenc_next, &fenc_alloced);
} else {
fenc = "";
fenc_alloced = false;
@@ -2060,7 +2060,7 @@ void set_forced_fenc(exarg_T *eap)
/// NULL.
/// When *pp is not set to NULL, the result is in allocated memory and "alloced"
/// is set to true.
-static char_u *next_fenc(char_u **pp, bool *alloced)
+static char_u *next_fenc(char **pp, bool *alloced)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
char_u *p;
@@ -2071,13 +2071,13 @@ static char_u *next_fenc(char_u **pp, bool *alloced)
*pp = NULL;
return (char_u *)"";
}
- p = (char_u *)vim_strchr((char *)(*pp), ',');
+ p = (char_u *)vim_strchr((*pp), ',');
if (p == NULL) {
- r = enc_canonize(*pp);
+ r = enc_canonize((char_u *)(*pp));
*pp += STRLEN(*pp);
} else {
- r = vim_strnsave(*pp, (size_t)(p - *pp));
- *pp = p + 1;
+ r = vim_strnsave((char_u *)(*pp), (size_t)(p - (char_u *)(*pp)));
+ *pp = (char *)p + 1;
p = enc_canonize(r);
xfree(r);
r = p;
@@ -5270,7 +5270,6 @@ void forward_slash(char_u *fname)
return;
}
for (p = fname; *p != NUL; p++) {
- // The Big5 encoding can have '\' in the trail byte.
if (*p == '\\') {
*p = '/';
}
@@ -5296,6 +5295,9 @@ static void vim_mktempdir(void)
char user[40] = { 0 };
(void)os_get_username(user, sizeof(user));
+ // Usernames may contain slashes! #19240
+ memchrsub(user, '/', '_', sizeof(user));
+ memchrsub(user, '\\', '_', sizeof(user));
// Make sure the umask doesn't remove the executable bit.
// "repl" has been reported to use "0177".
@@ -5398,7 +5400,7 @@ int readdir_core(garray_T *gap, const char *path, void *context, CheckItem check
os_closedir(&dir);
if (gap->ga_len > 0) {
- sort_strings((char_u **)gap->ga_data, gap->ga_len);
+ sort_strings(gap->ga_data, gap->ga_len);
}
return OK;
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index 60ea4b322e..f34e6d43c3 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -18,7 +18,7 @@ typedef struct foldinfo {
// other fields are invalid
int fi_low_level; // lowest fold level that starts in the same
// line
- long fi_lines;
+ linenr_T fi_lines;
} foldinfo_T;
#define FOLDINFO_INIT { 0, 0, 0, 0 }
diff --git a/src/nvim/garray.c b/src/nvim/garray.c
index 0c76e1a919..7a3c14b1bb 100644
--- a/src/nvim/garray.c
+++ b/src/nvim/garray.c
@@ -116,7 +116,7 @@ void ga_grow(garray_T *gap, int n)
/// @param gap
void ga_remove_duplicate_strings(garray_T *gap)
{
- char_u **fnames = gap->ga_data;
+ char **fnames = gap->ga_data;
// sort the growing array, which puts duplicates next to each other
sort_strings(fnames, gap->ga_len);
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 4cf282770d..b167767f7a 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -91,7 +91,7 @@ local deprecated_aliases = require("api.dispatch_deprecated")
for _,f in ipairs(shallowcopy(functions)) do
local ismethod = false
if startswith(f.name, "nvim_") then
- if startswith(f.name, "nvim__") then
+ if startswith(f.name, "nvim__") or f.name == "nvim_error_event" then
f.since = -1
elseif f.since == nil then
print("Function "..f.name.." lacks since field.\n")
@@ -149,7 +149,7 @@ local exported_attributes = {'name', 'return_type', 'method',
'since', 'deprecated_since'}
local exported_functions = {}
for _,f in ipairs(functions) do
- if not startswith(f.name, "nvim__") then
+ if not (startswith(f.name, "nvim__") or f.name == "nvim_error_event") then
local f_exported = {}
for _,attr in ipairs(exported_attributes) do
f_exported[attr] = f[attr]
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 00372d4f3d..28ff0cbd59 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -21,6 +21,7 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/input.h"
+#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
@@ -29,6 +30,7 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
@@ -1583,16 +1585,18 @@ int vgetc(void)
vgetc_char = c;
}
- // If mappings are enabled (i.e., not Ctrl-v) and the user directly typed
- // something with a meta- or alt- modifier that was not mapped, interpret
- // <M-x> as <Esc>x rather than as an unbound meta keypress. #8213
- // In Terminal mode, however, this is not desirable. #16220
- if (!no_mapping && KeyTyped && !(State & MODE_TERMINAL)
- && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) {
+ // If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed something with
+ // MOD_MASK_ALT (<M-/<A- modifier) that was not mapped, interpret <M-x> as <Esc>x rather
+ // than as an unbound <M-x> keypress. #8213
+ // In Terminal mode, however, this is not desirable. #16202 #16220
+ // Also do not do this for mouse keys, as terminals encode mouse events as CSI sequences, and
+ // MOD_MASK_ALT has a meaning even for unmapped mouse keys.
+ if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL)
+ && !is_mouse_key(c)) {
mod_mask = 0;
int len = ins_char_typebuf(c, 0);
(void)ins_char_typebuf(ESC, 0);
- ungetchars(len + 3); // The ALT/META modifier takes three more bytes
+ ungetchars(len + 3); // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes
continue;
}
@@ -1733,7 +1737,7 @@ static bool at_ins_compl_key(void)
|| ((compl_cont_status & CONT_LOCAL) && (c == Ctrl_N || c == Ctrl_P));
}
-/// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed
+/// Check if typebuf.tb_buf[] contains a modifier plus key that can be changed
/// into just a key, apply that.
/// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"].
/// @return the length of the replaced bytes, 0 if nothing changed, -1 for error.
@@ -1807,7 +1811,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
int local_State = get_real_state();
bool is_plug_map = false;
- // If typehead starts with <Plug> then remap, even for a "noremap" mapping.
+ // If typeahead starts with <Plug> then remap, even for a "noremap" mapping.
if (typebuf.tb_len >= 3
&& typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
&& typebuf.tb_buf[typebuf.tb_off + 1] == KS_EXTRA
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 8d896aef31..a41836353a 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -163,10 +163,6 @@ EXTERN colnr_T dollar_vcol INIT(= -1);
// by the match.)
EXTERN int compl_length INIT(= 0);
-// Set when character typed while looking for matches and it means we should
-// stop looking for matches.
-EXTERN int compl_interrupted INIT(= false);
-
// Set when doing something for completion that may call edit() recursively,
// which is not allowed. Also used to disable folding during completion
EXTERN bool compl_busy INIT(= false);
@@ -471,6 +467,9 @@ 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)
+#define FOR_ALL_BUF_WININFO(buf, wip) \
+ for ((wip) = (buf)->b_wininfo; (wip) != NULL; (wip) = (wip)->wi_next) // NOLINT
+
// Iterate through all the signs placed in a buffer
#define FOR_ALL_SIGNS_IN_BUF(buf, sign) \
for ((sign) = (buf)->b_signlist; (sign) != NULL; (sign) = (sign)->se_next) // NOLINT
@@ -945,6 +944,9 @@ EXTERN char e_loclist[] INIT(= N_("E776: No location list"));
EXTERN char e_re_damg[] INIT(= N_("E43: Damaged match string"));
EXTERN char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
EXTERN char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
+EXTERN char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s="));
+EXTERN char e_illvar[] INIT(= N_("E461: Illegal variable name: %s"));
+EXTERN char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable"));
EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\""));
EXTERN char e_stringreq[] INIT(= N_("E928: String required"));
EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required"));
@@ -1082,4 +1084,7 @@ EXTERN char windowsVersion[20] INIT(= { 0 });
EXTERN int exit_need_delay INIT(= 0);
+// Set when 'cmdheight' is changed from zero to one temporarily.
+EXTERN bool made_cmdheight_nonzero INIT(= false);
+
#endif // NVIM_GLOBALS_H
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 1268f987e1..72e85c425d 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -230,16 +230,12 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
&& *ptr != NUL) {
c = *ptr;
// check if this is the first byte of a multibyte
- if (len > 0) {
- mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
- } else {
- mbyte_blen = utfc_ptr2len((char *)ptr);
- }
- if (len >= 0) {
- u8c = utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr));
- } else {
- u8c = utfc_ptr2char(ptr, u8cc);
- }
+ mbyte_blen = len > 0
+ ? utfc_ptr2len_len(ptr, (int)((text + len) - ptr))
+ : utfc_ptr2len((char *)ptr);
+ u8c = len >= 0
+ ? utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr))
+ : utfc_ptr2char(ptr, u8cc);
mbyte_cells = utf_char2cells(u8c);
if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) {
// Do Arabic shaping.
@@ -248,8 +244,9 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
nc = NUL;
nc1 = NUL;
} else {
- nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
- (int)((text + len) - ptr - mbyte_blen));
+ nc = len >= 0
+ ? utfc_ptr2char_len(ptr + mbyte_blen, pcc, (int)((text + len) - ptr - mbyte_blen))
+ : utfc_ptr2char(ptr + mbyte_blen, pcc);
nc1 = pcc[0];
}
pc = prev_c;
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index 1571340849..9252b8a371 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -128,4 +128,13 @@ typedef struct {
const char *start; ///< Location where region starts.
} StlClickRecord;
+typedef struct {
+ int args[3];
+ int icell;
+ int ncells;
+ int coloff;
+ int cur_attr;
+ int clear_width;
+} GridLineEvent;
+
#endif // NVIM_GRID_DEFS_H
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index a4cf65e816..d7f7b8eb92 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -639,7 +639,7 @@ void ex_hardcopy(exarg_T *eap)
char *errormsg = NULL;
// Expand things like "%.ps".
- if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) {
+ if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) {
if (errormsg != NULL) {
emsg(errormsg);
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 0f20eb1905..71c7194479 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -183,10 +183,10 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)
bool valid_cache = it.version >= p->hl_valid;
if (!valid_cache && p->hl_def != LUA_NOREF && !recursive) {
- FIXED_TEMP_ARRAY(args, 3);
- args.items[0] = INTEGER_OBJ((Integer)ns_id);
- args.items[1] = STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id)));
- args.items[2] = BOOLEAN_OBJ(link);
+ MAXSIZE_TEMP_ARRAY(args, 3);
+ ADD_C(args, INTEGER_OBJ((Integer)ns_id));
+ ADD_C(args, STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id))));
+ ADD_C(args, BOOLEAN_OBJ(link));
// TODO(bfredl): preload the "global" attr dict?
Error err = ERROR_INIT;
@@ -719,93 +719,111 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
return dic;
}
- return hlattrs2dict(syn_attr2entry((int)attr_id), rgb);
+ return hlattrs2dict(NULL, syn_attr2entry((int)attr_id), rgb);
}
/// Converts an HlAttrs into Dictionary
///
+/// @param[out] hl optional pre-allocated dictionary for return value
+/// if present, must be allocated with at least 16 elements!
/// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
-Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
+Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb)
{
- Dictionary hl = ARRAY_DICT_INIT;
int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr;
+ Dictionary hl = ARRAY_DICT_INIT;
+ if (hl_alloc) {
+ hl = *hl_alloc;
+ } else {
+ kv_ensure_space(hl, 16);
+ }
if (mask & HL_BOLD) {
- PUT(hl, "bold", BOOLEAN_OBJ(true));
+ PUT_C(hl, "bold", BOOLEAN_OBJ(true));
}
if (mask & HL_STANDOUT) {
- PUT(hl, "standout", BOOLEAN_OBJ(true));
+ PUT_C(hl, "standout", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERLINE) {
- PUT(hl, "underline", BOOLEAN_OBJ(true));
+ PUT_C(hl, "underline", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERCURL) {
- PUT(hl, "undercurl", BOOLEAN_OBJ(true));
+ PUT_C(hl, "undercurl", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERDOUBLE) {
- PUT(hl, "underdouble", BOOLEAN_OBJ(true));
+ PUT_C(hl, "underdouble", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERDOTTED) {
- PUT(hl, "underdotted", BOOLEAN_OBJ(true));
+ PUT_C(hl, "underdotted", BOOLEAN_OBJ(true));
}
if (mask & HL_UNDERDASHED) {
- PUT(hl, "underdashed", BOOLEAN_OBJ(true));
+ PUT_C(hl, "underdashed", BOOLEAN_OBJ(true));
}
if (mask & HL_ITALIC) {
- PUT(hl, "italic", BOOLEAN_OBJ(true));
+ PUT_C(hl, "italic", BOOLEAN_OBJ(true));
}
if (mask & HL_INVERSE) {
- PUT(hl, "reverse", BOOLEAN_OBJ(true));
+ PUT_C(hl, "reverse", BOOLEAN_OBJ(true));
}
if (mask & HL_STRIKETHROUGH) {
- PUT(hl, "strikethrough", BOOLEAN_OBJ(true));
+ PUT_C(hl, "strikethrough", BOOLEAN_OBJ(true));
+ }
+
+ if (mask & HL_NOCOMBINE) {
+ PUT_C(hl, "nocombine", BOOLEAN_OBJ(true));
}
if (use_rgb) {
if (mask & HL_FG_INDEXED) {
- PUT(hl, "fg_indexed", BOOLEAN_OBJ(true));
+ PUT_C(hl, "fg_indexed", BOOLEAN_OBJ(true));
}
if (mask & HL_BG_INDEXED) {
- PUT(hl, "bg_indexed", BOOLEAN_OBJ(true));
+ PUT_C(hl, "bg_indexed", BOOLEAN_OBJ(true));
}
if (ae.rgb_fg_color != -1) {
- PUT(hl, "foreground", INTEGER_OBJ(ae.rgb_fg_color));
+ PUT_C(hl, "foreground", INTEGER_OBJ(ae.rgb_fg_color));
}
if (ae.rgb_bg_color != -1) {
- PUT(hl, "background", INTEGER_OBJ(ae.rgb_bg_color));
+ PUT_C(hl, "background", INTEGER_OBJ(ae.rgb_bg_color));
}
if (ae.rgb_sp_color != -1) {
- PUT(hl, "special", INTEGER_OBJ(ae.rgb_sp_color));
+ PUT_C(hl, "special", INTEGER_OBJ(ae.rgb_sp_color));
}
} else {
if (ae.cterm_fg_color != 0) {
- PUT(hl, "foreground", INTEGER_OBJ(ae.cterm_fg_color - 1));
+ PUT_C(hl, "foreground", INTEGER_OBJ(ae.cterm_fg_color - 1));
}
if (ae.cterm_bg_color != 0) {
- PUT(hl, "background", INTEGER_OBJ(ae.cterm_bg_color - 1));
+ PUT_C(hl, "background", INTEGER_OBJ(ae.cterm_bg_color - 1));
}
}
if (ae.hl_blend > -1) {
- PUT(hl, "blend", INTEGER_OBJ(ae.hl_blend));
+ PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend));
}
- return hl;
+ if (hl_alloc) {
+ *hl_alloc = hl;
+ return hl;
+ } else {
+ Dictionary allocated = copy_dictionary(hl);
+ kv_destroy(hl);
+ return allocated;
+ }
}
HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err)
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index d958b7b344..f6ec03fb14 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -9,6 +9,7 @@
#include "nvim/autocmd.h"
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
+#include "nvim/eval/vars.h"
#include "nvim/fold.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
@@ -955,8 +956,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
linep++;
}
size_t key_len = (size_t)(linep - key_start);
- if (key_len > sizeof key - 1) {
- semsg(_("E423: Illegal argument"));
+ if (key_len > sizeof(key) - 1) {
+ emsg(_("E423: Illegal argument"));
error = true;
break;
}
@@ -1003,8 +1004,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
break;
}
size_t arg_len = (size_t)(linep - arg_start);
- if (arg_len > sizeof arg - 1) {
- semsg(_("E423: Illegal argument"));
+ if (arg_len > sizeof(arg) - 1) {
+ emsg(_("E423: Illegal argument"));
error = true;
break;
}
@@ -1409,7 +1410,7 @@ Dictionary get_global_hl_defs(void)
Dictionary attrs = ARRAY_DICT_INIT;
HlGroup *h = &hl_table[i - 1];
if (h->sg_attr > 0) {
- attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true);
+ attrs = hlattrs2dict(NULL, syn_attr2entry(h->sg_attr), true);
} else if (h->sg_link > 0) {
const char *link = (const char *)hl_table[h->sg_link - 1].sg_name;
PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 3c74b4bd8d..c5e030ce25 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -2002,7 +2002,7 @@ int get_c_indent(void)
}
// #defines and so on go at the left when included in 'cinkeys',
- // exluding pragmas when customized in 'cinoptions'
+ // excluding pragmas when customized in 'cinoptions'
if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', true))) {
const char_u *const directive = (char_u *)skipwhite((char *)theline + 1);
if (curbuf->b_ind_pragma == 0 || STRNCMP(directive, "pragma", 6) != 0) {
@@ -3569,7 +3569,7 @@ term_again:
// Are we at the start of a cpp base class declaration or
// constructor initialization? XXX
n = 0;
- if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{') {
+ if (curbuf->b_ind_cpp_baseclass != 0) {
n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
l = get_cursor_line_ptr();
}
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
new file mode 100644
index 0000000000..2fc8f1dadc
--- /dev/null
+++ b/src/nvim/insexpand.c
@@ -0,0 +1,3967 @@
+// 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
+
+// insexpand.c: functions for Insert mode completion
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/buffer.h"
+#include "nvim/change.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/edit.h"
+#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/ex_getln.h"
+#include "nvim/fileio.h"
+#include "nvim/getchar.h"
+#include "nvim/indent.h"
+#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/move.h"
+#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/time.h"
+#include "nvim/path.h"
+#include "nvim/popupmnu.h"
+#include "nvim/regexp.h"
+#include "nvim/screen.h"
+#include "nvim/search.h"
+#include "nvim/spell.h"
+#include "nvim/state.h"
+#include "nvim/strings.h"
+#include "nvim/tag.h"
+#include "nvim/ui.h"
+#include "nvim/undo.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+// Definitions used for CTRL-X submode.
+// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
+// and ctrl_x_mode_names[].
+
+#define CTRL_X_WANT_IDENT 0x100
+
+#define CTRL_X_NORMAL 0 ///< CTRL-N CTRL-P completion, default
+#define CTRL_X_NOT_DEFINED_YET 1
+#define CTRL_X_SCROLL 2
+#define CTRL_X_WHOLE_LINE 3
+#define CTRL_X_FILES 4
+#define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
+#define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
+#define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
+#define CTRL_X_FINISHED 8
+#define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
+#define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
+#define CTRL_X_CMDLINE 11
+#define CTRL_X_FUNCTION 12
+#define CTRL_X_OMNI 13
+#define CTRL_X_SPELL 14
+#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
+#define CTRL_X_EVAL 16 ///< for builtin function complete()
+#define CTRL_X_CMDLINE_CTRL_X 17 ///< CTRL-X typed in CTRL_X_CMDLINE
+
+#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
+
+/// Message for CTRL-X mode, index is ctrl_x_mode.
+static char *ctrl_x_msgs[] =
+{
+ N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
+ N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
+ NULL, // CTRL_X_SCROLL: depends on state
+ N_(" Whole line completion (^L^N^P)"),
+ N_(" File name completion (^F^N^P)"),
+ N_(" Tag completion (^]^N^P)"),
+ N_(" Path pattern completion (^N^P)"),
+ N_(" Definition completion (^D^N^P)"),
+ NULL, // CTRL_X_FINISHED
+ N_(" Dictionary completion (^K^N^P)"),
+ N_(" Thesaurus completion (^T^N^P)"),
+ N_(" Command-line completion (^V^N^P)"),
+ N_(" User defined completion (^U^N^P)"),
+ N_(" Omni completion (^O^N^P)"),
+ N_(" Spelling suggestion (s^N^P)"),
+ N_(" Keyword Local completion (^N^P)"),
+ NULL, // CTRL_X_EVAL doesn't use msg.
+ N_(" Command-line completion (^V^N^P)"),
+};
+
+static char *ctrl_x_mode_names[] = {
+ "keyword",
+ "ctrl_x",
+ "scroll",
+ "whole_line",
+ "files",
+ "tags",
+ "path_patterns",
+ "path_defines",
+ "unknown", // CTRL_X_FINISHED
+ "dictionary",
+ "thesaurus",
+ "cmdline",
+ "function",
+ "omni",
+ "spell",
+ NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
+ "eval",
+ "cmdline",
+};
+
+// Array indexes used for cp_text[].
+#define CPT_ABBR 0 ///< "abbr"
+#define CPT_MENU 1 ///< "menu"
+#define CPT_KIND 2 ///< "kind"
+#define CPT_INFO 3 ///< "info"
+#define CPT_COUNT 4 ///< Number of entries
+
+/// Structure used to store one match for insert completion.
+typedef struct compl_S compl_T;
+struct compl_S {
+ compl_T *cp_next;
+ compl_T *cp_prev;
+ char_u *cp_str; ///< matched text
+ char_u *(cp_text[CPT_COUNT]); ///< text for the menu
+ typval_T cp_user_data;
+ char_u *cp_fname; ///< file containing the match, allocated when
+ ///< cp_flags has CP_FREE_FNAME
+ int cp_flags; ///< CP_ values
+ int cp_number; ///< sequence number
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "insexpand.c.generated.h"
+#endif
+
+/// values for cp_flags
+typedef enum {
+ CP_ORIGINAL_TEXT = 1, ///< the original text when the expansion begun
+ CP_FREE_FNAME = 2, ///< cp_fname is allocated
+ CP_CONT_S_IPOS = 4, ///< use CONT_S_IPOS for compl_cont_status
+ CP_EQUAL = 8, ///< ins_compl_equal() always returns true
+ CP_ICASE = 16, ///< ins_compl_equal ignores case
+ CP_FAST = 32, ///< use fast_breakcheck instead of os_breakcheck
+} cp_flags_T;
+
+static char e_hitend[] = N_("Hit end of paragraph");
+static char e_compldel[] = N_("E840: Completion function deleted text");
+
+// All the current matches are stored in a list.
+// "compl_first_match" points to the start of the list.
+// "compl_curr_match" points to the currently selected entry.
+// "compl_shown_match" is different from compl_curr_match during
+// ins_compl_get_exp().
+
+static compl_T *compl_first_match = NULL;
+static compl_T *compl_curr_match = NULL;
+static compl_T *compl_shown_match = NULL;
+static compl_T *compl_old_match = NULL;
+
+/// After using a cursor key <Enter> selects a match in the popup menu,
+/// otherwise it inserts a line break.
+static bool compl_enter_selects = false;
+
+/// When "compl_leader" is not NULL only matches that start with this string
+/// are used.
+static char_u *compl_leader = NULL;
+
+static bool compl_get_longest = false; ///< put longest common string in compl_leader
+
+static bool compl_no_insert = false; ///< false: select & insert
+ ///< true: noinsert
+static bool compl_no_select = false; ///< false: select & insert
+ ///< true: noselect
+
+/// Selected one of the matches. When false the match was edited or using the
+/// longest common string.
+static bool compl_used_match;
+
+/// didn't finish finding completions.
+static bool compl_was_interrupted = false;
+
+// Set when character typed while looking for matches and it means we should
+// stop looking for matches.
+static bool compl_interrupted = false;
+
+static bool compl_restarting = false; ///< don't insert match
+
+///< When the first completion is done "compl_started" is set. When it's
+///< false the word to be completed must be located.
+static bool compl_started = false;
+
+///< Which Ctrl-X mode are we in?
+static int ctrl_x_mode = CTRL_X_NORMAL;
+
+static int compl_matches = 0;
+static char *compl_pattern = NULL;
+static Direction compl_direction = FORWARD;
+static Direction compl_shows_dir = FORWARD;
+static int compl_pending = 0; ///< > 1 for postponed CTRL-N
+static pos_T compl_startpos;
+static colnr_T compl_col = 0; ///< column where the text starts
+ ///< that is being completed
+static char_u *compl_orig_text = NULL; ///< text as it was before
+ ///< completion started
+static int compl_cont_mode = 0;
+static expand_T compl_xp;
+
+static bool compl_opt_refresh_always = false;
+
+static size_t spell_bad_len = 0; // length of located bad word
+
+static int pum_selected_item = -1;
+
+/// CTRL-X pressed in Insert mode.
+void ins_ctrl_x(void)
+{
+ if (!ctrl_x_mode_cmdline()) {
+ // if the next ^X<> won't ADD nothing, then reset compl_cont_status
+ if (compl_cont_status & CONT_N_ADDS) {
+ compl_cont_status |= CONT_INTRPT;
+ } else {
+ compl_cont_status = 0;
+ }
+ // We're not sure which CTRL-X mode it will be yet
+ ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
+ edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
+ edit_submode_pre = NULL;
+ showmode();
+ } else {
+ // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
+ // CTRL-V look like CTRL-N
+ ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
+ }
+
+ may_trigger_modechanged();
+}
+
+// Functions to check the current CTRL-X mode.
+
+bool ctrl_x_mode_none(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == 0;
+}
+
+bool ctrl_x_mode_normal(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_NORMAL;
+}
+
+bool ctrl_x_mode_scroll(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_SCROLL;
+}
+
+bool ctrl_x_mode_whole_line(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_WHOLE_LINE;
+}
+
+bool ctrl_x_mode_files(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_FILES;
+}
+
+bool ctrl_x_mode_tags(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_TAGS;
+}
+
+bool ctrl_x_mode_path_patterns(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_PATH_PATTERNS;
+}
+
+bool ctrl_x_mode_path_defines(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_PATH_DEFINES;
+}
+
+bool ctrl_x_mode_dictionary(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_DICTIONARY;
+}
+
+bool ctrl_x_mode_thesaurus(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_THESAURUS;
+}
+
+bool ctrl_x_mode_cmdline(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X;
+}
+
+bool ctrl_x_mode_function(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_FUNCTION;
+}
+
+bool ctrl_x_mode_omni(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_OMNI;
+}
+
+bool ctrl_x_mode_spell(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_SPELL;
+}
+
+static bool ctrl_x_mode_eval(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_EVAL;
+}
+
+bool ctrl_x_mode_line_or_eval(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL;
+}
+
+/// Whether other than default completion has been selected.
+bool ctrl_x_mode_not_default(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode != CTRL_X_NORMAL;
+}
+
+/// Whether CTRL-X was typed without a following character,
+/// not including when in CTRL-X CTRL-V mode.
+bool ctrl_x_mode_not_defined_yet(void)
+ FUNC_ATTR_PURE
+{
+ return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
+}
+
+/// Check that the "dict" or "tsr" option can be used.
+///
+/// @param dict_opt check "dict" when true, "tsr" when false.
+bool check_compl_option(bool dict_opt)
+{
+ if (dict_opt
+ ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
+ : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
+ && *curbuf->b_p_tsrfu == NUL && *p_tsrfu == NUL)) {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ msg_attr((dict_opt
+ ? _("'dictionary' option is empty")
+ : _("'thesaurus' option is empty")), HL_ATTR(HLF_E));
+ if (emsg_silent == 0) {
+ vim_beep(BO_COMPL);
+ setcursor();
+ ui_flush();
+ os_delay(2004L, false);
+ }
+ return false;
+ }
+ return true;
+}
+
+/// Check that the character "c" a valid key to go to or keep us in CTRL-X mode?
+/// This depends on the current mode.
+///
+/// @param c character to check
+bool vim_is_ctrl_x_key(int c)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Always allow ^R - let its results then be checked
+ if (c == Ctrl_R) {
+ return true;
+ }
+
+ // Accept <PageUp> and <PageDown> if the popup menu is visible.
+ if (ins_compl_pum_key(c)) {
+ return true;
+ }
+
+ switch (ctrl_x_mode) {
+ case 0: // Not in any CTRL-X mode
+ return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
+ case CTRL_X_NOT_DEFINED_YET:
+ case CTRL_X_CMDLINE_CTRL_X:
+ return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
+ || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
+ || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
+ || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
+ || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
+ || c == Ctrl_S || c == Ctrl_K || c == 's'
+ || c == Ctrl_Z;
+ case CTRL_X_SCROLL:
+ return c == Ctrl_Y || c == Ctrl_E;
+ case CTRL_X_WHOLE_LINE:
+ return c == Ctrl_L || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_FILES:
+ return c == Ctrl_F || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_DICTIONARY:
+ return c == Ctrl_K || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_THESAURUS:
+ return c == Ctrl_T || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_TAGS:
+ return c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_PATH_PATTERNS:
+ return c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_PATH_DEFINES:
+ return c == Ctrl_D || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_CMDLINE:
+ return c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
+ || c == Ctrl_X;
+ case CTRL_X_FUNCTION:
+ return c == Ctrl_U || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_OMNI:
+ return c == Ctrl_O || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_SPELL:
+ return c == Ctrl_S || c == Ctrl_P || c == Ctrl_N;
+ case CTRL_X_EVAL:
+ return (c == Ctrl_P || c == Ctrl_N);
+ }
+ internal_error("vim_is_ctrl_x_key()");
+ return false;
+}
+
+/// Check that character "c" is part of the item currently being
+/// completed. Used to decide whether to abandon complete mode when the menu
+/// is visible.
+///
+/// @param c character to check
+bool ins_compl_accept_char(int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (ctrl_x_mode & CTRL_X_WANT_IDENT) {
+ // When expanding an identifier only accept identifier chars.
+ return vim_isIDc(c);
+ }
+
+ switch (ctrl_x_mode) {
+ case CTRL_X_FILES:
+ // When expanding file name only accept file name chars. But not
+ // path separators, so that "proto/<Tab>" expands files in
+ // "proto", not "proto/" as a whole
+ return vim_isfilec(c) && !vim_ispathsep(c);
+
+ case CTRL_X_CMDLINE:
+ case CTRL_X_CMDLINE_CTRL_X:
+ case CTRL_X_OMNI:
+ // Command line and Omni completion can work with just about any
+ // printable character, but do stop at white space.
+ return vim_isprintc(c) && !ascii_iswhite(c);
+
+ case CTRL_X_WHOLE_LINE:
+ // For while line completion a space can be part of the line.
+ return vim_isprintc(c);
+ }
+ return vim_iswordc(c);
+}
+
+/// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
+/// case of the originally typed text is used, and the case of the completed
+/// text is inferred, ie this tries to work out what case you probably wanted
+/// the rest of the word to be in -- webb
+///
+/// @param[in] cont_s_ipos next ^X<> will set initial_pos
+int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, Direction dir,
+ bool cont_s_ipos)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ char_u *str = str_arg;
+ int i, c;
+ int actual_len; // Take multi-byte characters
+ int actual_compl_length; // into account.
+ int min_len;
+ bool has_lower = false;
+ bool was_letter = false;
+ int flags = 0;
+
+ if (p_ic && curbuf->b_p_inf && len > 0) {
+ // Infer case of completed part.
+
+ // Find actual length of completion.
+ {
+ const char_u *p = str;
+ actual_len = 0;
+ while (*p != NUL) {
+ MB_PTR_ADV(p);
+ actual_len++;
+ }
+ }
+
+ // Find actual length of original text.
+ {
+ const char_u *p = compl_orig_text;
+ actual_compl_length = 0;
+ while (*p != NUL) {
+ MB_PTR_ADV(p);
+ actual_compl_length++;
+ }
+ }
+
+ // "actual_len" may be smaller than "actual_compl_length" when using
+ // thesaurus, only use the minimum when comparing.
+ min_len = actual_len < actual_compl_length
+ ? actual_len : actual_compl_length;
+
+ // Allocate wide character array for the completion and fill it.
+ int *const wca = xmalloc((size_t)actual_len * sizeof(*wca));
+ {
+ const char_u *p = str;
+ for (i = 0; i < actual_len; i++) {
+ wca[i] = mb_ptr2char_adv(&p);
+ }
+ }
+
+ // Rule 1: Were any chars converted to lower?
+ {
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ c = mb_ptr2char_adv(&p);
+ if (mb_islower(c)) {
+ has_lower = true;
+ if (mb_isupper(wca[i])) {
+ // Rule 1 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
+ wca[i] = mb_tolower(wca[i]);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Rule 2: No lower case, 2nd consecutive letter converted to
+ // upper case.
+ if (!has_lower) {
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ c = mb_ptr2char_adv(&p);
+ if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
+ // Rule 2 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
+ wca[i] = mb_toupper(wca[i]);
+ }
+ break;
+ }
+ was_letter = mb_islower(c) || mb_isupper(c);
+ }
+ }
+
+ // Copy the original case of the part we typed.
+ {
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ c = mb_ptr2char_adv(&p);
+ if (mb_islower(c)) {
+ wca[i] = mb_tolower(wca[i]);
+ } else if (mb_isupper(c)) {
+ wca[i] = mb_toupper(wca[i]);
+ }
+ }
+ }
+
+ // Generate encoding specific output from wide character array.
+ // Multi-byte characters can occupy up to five bytes more than
+ // ASCII characters, and we also need one byte for NUL, so stay
+ // six bytes away from the edge of IObuff.
+ {
+ char_u *p = IObuff;
+ i = 0;
+ while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
+ p += utf_char2bytes(wca[i++], (char *)p);
+ }
+ *p = NUL;
+ }
+
+ xfree(wca);
+
+ str = IObuff;
+ }
+ if (cont_s_ipos) {
+ flags |= CP_CONT_S_IPOS;
+ }
+ if (icase) {
+ flags |= CP_ICASE;
+ }
+
+ return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false);
+}
+
+/// Add a match to the list of matches
+///
+/// @param[in] str Match to add.
+/// @param[in] len Match length, -1 to use #STRLEN.
+/// @param[in] fname File name match comes from. May be NULL.
+/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
+/// must have exactly #CPT_COUNT items.
+/// @param[in] cptext_allocated If true, will not copy cptext strings.
+///
+/// @note Will free strings in case of error.
+/// cptext itself will not be freed.
+/// @param[in] cdir Completion direction.
+/// @param[in] adup True if duplicate matches are to be accepted.
+///
+/// @return NOTDONE if the given string is already in the list of completions,
+/// otherwise it is added to the list and OK is returned. FAIL will be
+/// returned in case of error.
+static int ins_compl_add(char_u *const str, int len, char_u *const fname,
+ char_u *const *const cptext, const bool cptext_allocated,
+ typval_T *user_data, const Direction cdir, int flags_arg, const bool adup)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ compl_T *match;
+ const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
+ int flags = flags_arg;
+
+ if (flags & CP_FAST) {
+ fast_breakcheck();
+ } else {
+ os_breakcheck();
+ }
+#define FREE_CPTEXT(cptext, cptext_allocated) \
+ do { \
+ if ((cptext) != NULL && (cptext_allocated)) { \
+ for (size_t i = 0; i < CPT_COUNT; i++) { \
+ xfree((cptext)[i]); \
+ } \
+ } \
+ } while (0)
+ if (got_int) {
+ FREE_CPTEXT(cptext, cptext_allocated);
+ return FAIL;
+ }
+ if (len < 0) {
+ len = (int)STRLEN(str);
+ }
+
+ // If the same match is already present, don't add it.
+ if (compl_first_match != NULL && !adup) {
+ match = compl_first_match;
+ do {
+ if (!(match->cp_flags & CP_ORIGINAL_TEXT)
+ && STRNCMP(match->cp_str, str, len) == 0
+ && match->cp_str[len] == NUL) {
+ FREE_CPTEXT(cptext, cptext_allocated);
+ return NOTDONE;
+ }
+ match = match->cp_next;
+ } while (match != NULL && match != compl_first_match);
+ }
+
+ // Remove any popup menu before changing the list of matches.
+ ins_compl_del_pum();
+
+ // Allocate a new match structure.
+ // Copy the values to the new match structure.
+ match = xcalloc(1, sizeof(compl_T));
+ match->cp_number = -1;
+ if (flags & CP_ORIGINAL_TEXT) {
+ match->cp_number = 0;
+ }
+ match->cp_str = vim_strnsave(str, (size_t)len);
+
+ // match-fname is:
+ // - compl_curr_match->cp_fname if it is a string equal to fname.
+ // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem.
+ // - NULL otherwise. --Acevedo
+ if (fname != NULL
+ && compl_curr_match != NULL
+ && compl_curr_match->cp_fname != NULL
+ && STRCMP(fname, compl_curr_match->cp_fname) == 0) {
+ match->cp_fname = compl_curr_match->cp_fname;
+ } else if (fname != NULL) {
+ match->cp_fname = vim_strsave(fname);
+ flags |= CP_FREE_FNAME;
+ } else {
+ match->cp_fname = NULL;
+ }
+ match->cp_flags = flags;
+
+ if (cptext != NULL) {
+ int i;
+
+ for (i = 0; i < CPT_COUNT; i++) {
+ if (cptext[i] == NULL) {
+ continue;
+ }
+ if (*cptext[i] != NUL) {
+ match->cp_text[i] = (cptext_allocated
+ ? cptext[i]
+ : (char_u *)xstrdup((char *)cptext[i]));
+ } else if (cptext_allocated) {
+ xfree(cptext[i]);
+ }
+ }
+ }
+
+ if (user_data != NULL) {
+ match->cp_user_data = *user_data;
+ }
+
+ // Link the new match structure in the list of matches.
+ if (compl_first_match == NULL) {
+ match->cp_next = match->cp_prev = NULL;
+ } else if (dir == FORWARD) {
+ match->cp_next = compl_curr_match->cp_next;
+ match->cp_prev = compl_curr_match;
+ } else { // BACKWARD
+ match->cp_next = compl_curr_match;
+ match->cp_prev = compl_curr_match->cp_prev;
+ }
+ if (match->cp_next) {
+ match->cp_next->cp_prev = match;
+ }
+ if (match->cp_prev) {
+ match->cp_prev->cp_next = match;
+ } else { // if there's nothing before, it is the first match
+ compl_first_match = match;
+ }
+ compl_curr_match = match;
+
+ // Find the longest common string if still doing that.
+ if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0) {
+ ins_compl_longest_match(match);
+ }
+
+ return OK;
+}
+
+/// Check that "str[len]" matches with "match->cp_str", considering
+/// "match->cp_flags".
+///
+/// @param match completion match
+/// @param str character string to check
+/// @param len length of "str"
+static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ if (match->cp_flags & CP_EQUAL) {
+ return true;
+ }
+ if (match->cp_flags & CP_ICASE) {
+ return STRNICMP(match->cp_str, str, len) == 0;
+ }
+ return STRNCMP(match->cp_str, str, len) == 0;
+}
+
+/// Reduce the longest common string for match "match".
+static void ins_compl_longest_match(compl_T *match)
+{
+ char_u *p, *s;
+ int c1, c2;
+ int had_match;
+
+ if (compl_leader == NULL) {
+ // First match, use it as a whole.
+ compl_leader = vim_strsave(match->cp_str);
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + get_compl_len());
+ ins_redraw(false);
+
+ // When the match isn't there (to avoid matching itself) remove it
+ // again after redrawing.
+ if (!had_match) {
+ ins_compl_delete();
+ }
+ compl_used_match = false;
+ } else {
+ // Reduce the text if this match differs from compl_leader.
+ p = compl_leader;
+ s = match->cp_str;
+ while (*p != NUL) {
+ c1 = utf_ptr2char((char *)p);
+ c2 = utf_ptr2char((char *)s);
+
+ if ((match->cp_flags & CP_ICASE)
+ ? (mb_tolower(c1) != mb_tolower(c2))
+ : (c1 != c2)) {
+ break;
+ }
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(s);
+ }
+
+ if (*p != NUL) {
+ // Leader was shortened, need to change the inserted text.
+ *p = NUL;
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + get_compl_len());
+ ins_redraw(false);
+
+ // When the match isn't there (to avoid matching itself) remove it
+ // again after redrawing.
+ if (!had_match) {
+ ins_compl_delete();
+ }
+ }
+
+ compl_used_match = false;
+ }
+}
+
+/// Add an array of matches to the list of matches.
+/// Frees matches[].
+static void ins_compl_add_matches(int num_matches, char **matches, int icase)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int add_r = OK;
+ Direction dir = compl_direction;
+
+ for (int i = 0; i < num_matches && add_r != FAIL; i++) {
+ if ((add_r = ins_compl_add((char_u *)matches[i], -1, NULL, NULL, false, NULL, dir,
+ CP_FAST | (icase ? CP_ICASE : 0),
+ false)) == OK) {
+ // If dir was BACKWARD then honor it just once.
+ dir = FORWARD;
+ }
+ }
+ FreeWild(num_matches, matches);
+}
+
+/// Make the completion list cyclic.
+/// Return the number of matches (excluding the original).
+static int ins_compl_make_cyclic(void)
+{
+ compl_T *match;
+ int count = 0;
+
+ if (compl_first_match != NULL) {
+ // Find the end of the list.
+ match = compl_first_match;
+ // there's always an entry for the compl_orig_text, it doesn't count.
+ while (match->cp_next != NULL && match->cp_next != compl_first_match) {
+ match = match->cp_next;
+ count++;
+ }
+ match->cp_next = compl_first_match;
+ compl_first_match->cp_prev = match;
+ }
+ return count;
+}
+
+/// Return whether there currently is a shown match.
+bool ins_compl_has_shown_match(void)
+{
+ return compl_shown_match == NULL || compl_shown_match != compl_shown_match->cp_next;
+}
+
+/// Return whether the shown match is long enough.
+bool ins_compl_long_shown_match(void)
+{
+ return compl_shown_match != NULL && compl_shown_match->cp_str != NULL
+ && (colnr_T)STRLEN(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col;
+}
+
+/// Set variables that store noselect and noinsert behavior from the
+/// 'completeopt' value.
+void completeopt_was_set(void)
+{
+ compl_no_insert = false;
+ compl_no_select = false;
+ if (strstr((char *)p_cot, "noselect") != NULL) {
+ compl_no_select = true;
+ }
+ if (strstr((char *)p_cot, "noinsert") != NULL) {
+ compl_no_insert = true;
+ }
+}
+
+/// "compl_match_array" points the currently displayed list of entries in the
+/// popup menu. It is NULL when there is no popup menu.
+static pumitem_T *compl_match_array = NULL;
+static int compl_match_arraysize;
+
+/// Remove any popup menu.
+static void ins_compl_del_pum(void)
+{
+ if (compl_match_array != NULL) {
+ pum_undisplay(false);
+ XFREE_CLEAR(compl_match_array);
+ }
+}
+
+/// Check if the popup menu should be displayed.
+bool pum_wanted(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // "completeopt" must contain "menu" or "menuone"
+ return vim_strchr((char *)p_cot, 'm') != NULL;
+}
+
+/// Check that there are two or more matches to be shown in the popup menu.
+/// One if "completopt" contains "menuone".
+static bool pum_enough_matches(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Don't display the popup menu if there are no matches or there is only
+ // one (ignoring the original text).
+ compl_T *comp = compl_first_match;
+ int i = 0;
+ do {
+ if (comp == NULL
+ || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) {
+ break;
+ }
+ comp = comp->cp_next;
+ } while (comp != compl_first_match);
+
+ if (strstr((char *)p_cot, "menuone") != NULL) {
+ return i >= 1;
+ }
+ return i >= 2;
+}
+
+/// Convert to complete item dict
+static dict_T *ins_compl_dict_alloc(compl_T *match)
+{
+ // { word, abbr, menu, kind, info }
+ dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
+ tv_dict_add_str(dict, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(dict, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(dict, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(dict, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(dict, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
+ if (match->cp_user_data.v_type == VAR_UNKNOWN) {
+ tv_dict_add_str(dict, S_LEN("user_data"), "");
+ } else {
+ tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data);
+ }
+ return dict;
+}
+
+static void trigger_complete_changed_event(int cur)
+{
+ static bool recursive = false;
+ save_v_event_T save_v_event;
+
+ if (recursive) {
+ return;
+ }
+
+ dict_T *v_event = get_v_event(&save_v_event);
+ if (cur < 0) {
+ tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
+ } else {
+ dict_T *item = ins_compl_dict_alloc(compl_curr_match);
+ tv_dict_add_dict(v_event, S_LEN("completed_item"), item);
+ }
+ pum_set_event_info(v_event);
+ tv_dict_set_keys_readonly(v_event);
+
+ recursive = true;
+ textlock++;
+ apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf);
+ textlock--;
+ recursive = false;
+
+ restore_v_event(v_event, &save_v_event);
+}
+
+/// Show the popup menu for the list of matches.
+/// Also adjusts "compl_shown_match" to an entry that is actually displayed.
+void ins_compl_show_pum(void)
+{
+ compl_T *compl;
+ compl_T *shown_compl = NULL;
+ bool did_find_shown_match = false;
+ bool shown_match_ok = false;
+ int i;
+ int cur = -1;
+ colnr_T col;
+ int lead_len = 0;
+ bool array_changed = false;
+
+ if (!pum_wanted() || !pum_enough_matches()) {
+ return;
+ }
+
+ // Dirty hard-coded hack: remove any matchparen highlighting.
+ do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif");
+
+ // Update the screen before drawing the popup menu over it.
+ update_screen(0);
+
+ if (compl_match_array == NULL) {
+ array_changed = true;
+ // Need to build the popup menu list.
+ compl_match_arraysize = 0;
+ compl = compl_first_match;
+ // If it's user complete function and refresh_always,
+ // do not use "compl_leader" as prefix filter.
+ if (ins_compl_need_restart()) {
+ XFREE_CLEAR(compl_leader);
+ }
+ if (compl_leader != NULL) {
+ lead_len = (int)STRLEN(compl_leader);
+ }
+ do {
+ if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
+ compl_match_arraysize++;
+ }
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
+ if (compl_match_arraysize == 0) {
+ return;
+ }
+
+ assert(compl_match_arraysize >= 0);
+ compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
+ // If the current match is the original text don't find the first
+ // match after it, don't highlight anything.
+ if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
+ shown_match_ok = true;
+ }
+
+ i = 0;
+ compl = compl_first_match;
+ do {
+ if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
+ if (!shown_match_ok) {
+ if (compl == compl_shown_match || did_find_shown_match) {
+ // This item is the shown match or this is the
+ // first displayed item after the shown match.
+ compl_shown_match = compl;
+ did_find_shown_match = true;
+ shown_match_ok = true;
+ } else {
+ // Remember this displayed match for when the
+ // shown match is just below it.
+ shown_compl = compl;
+ }
+ cur = i;
+ }
+
+ if (compl->cp_text[CPT_ABBR] != NULL) {
+ compl_match_array[i].pum_text =
+ compl->cp_text[CPT_ABBR];
+ } else {
+ compl_match_array[i].pum_text = compl->cp_str;
+ }
+ compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
+ if (compl->cp_text[CPT_MENU] != NULL) {
+ compl_match_array[i++].pum_extra =
+ compl->cp_text[CPT_MENU];
+ } else {
+ compl_match_array[i++].pum_extra = compl->cp_fname;
+ }
+ }
+
+ if (compl == compl_shown_match) {
+ did_find_shown_match = true;
+
+ // When the original text is the shown match don't set
+ // compl_shown_match.
+ if (compl->cp_flags & CP_ORIGINAL_TEXT) {
+ shown_match_ok = true;
+ }
+
+ if (!shown_match_ok && shown_compl != NULL) {
+ // The shown match isn't displayed, set it to the
+ // previously displayed match.
+ compl_shown_match = shown_compl;
+ shown_match_ok = true;
+ }
+ }
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
+
+ if (!shown_match_ok) { // no displayed match at all
+ cur = -1;
+ }
+ } else {
+ // popup menu already exists, only need to find the current item.
+ for (i = 0; i < compl_match_arraysize; i++) {
+ if (compl_match_array[i].pum_text == compl_shown_match->cp_str
+ || compl_match_array[i].pum_text
+ == compl_shown_match->cp_text[CPT_ABBR]) {
+ cur = i;
+ break;
+ }
+ }
+ }
+
+ // In Replace mode when a $ is displayed at the end of the line only
+ // part of the screen would be updated. We do need to redraw here.
+ dollar_vcol = -1;
+
+ // Compute the screen column of the start of the completed text.
+ // Use the cursor to get all wrapping and other settings right.
+ col = curwin->w_cursor.col;
+ curwin->w_cursor.col = compl_col;
+ pum_selected_item = cur;
+ pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
+ curwin->w_cursor.col = col;
+
+ if (has_event(EVENT_COMPLETECHANGED)) {
+ trigger_complete_changed_event(cur);
+ }
+}
+
+#define DICT_FIRST (1) ///< use just first element in "dict"
+#define DICT_EXACT (2) ///< "dict" is the exact name of a file
+
+/// Add any identifiers that match the given pattern in the list of dictionary
+/// files "dict_start" to the list of completions.
+///
+/// @param flags DICT_FIRST and/or DICT_EXACT
+/// @param thesaurus Thesaurus completion
+static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, int thesaurus)
+{
+ char *dict = (char *)dict_start;
+ char_u *ptr;
+ char *buf;
+ regmatch_T regmatch;
+ char **files;
+ int count;
+ int save_p_scs;
+ Direction dir = compl_direction;
+
+ if (*dict == NUL) {
+ // When 'dictionary' is empty and spell checking is enabled use
+ // "spell".
+ if (!thesaurus && curwin->w_p_spell) {
+ dict = "spell";
+ } else {
+ return;
+ }
+ }
+
+ buf = xmalloc(LSIZE);
+ regmatch.regprog = NULL; // so that we can goto theend
+
+ // If 'infercase' is set, don't use 'smartcase' here
+ save_p_scs = p_scs;
+ if (curbuf->b_p_inf) {
+ p_scs = false;
+ }
+
+ // When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
+ // to only match at the start of a line. Otherwise just match the
+ // pattern. Also need to double backslashes.
+ if (ctrl_x_mode_line_or_eval()) {
+ char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
+
+ size_t len = STRLEN(pat_esc) + 10;
+ ptr = xmalloc(len);
+ vim_snprintf((char *)ptr, len, "^\\s*\\zs\\V%s", pat_esc);
+ regmatch.regprog = vim_regcomp((char *)ptr, RE_MAGIC);
+ xfree(pat_esc);
+ xfree(ptr);
+ } else {
+ regmatch.regprog = vim_regcomp((char *)pat, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL) {
+ goto theend;
+ }
+ }
+
+ // ignore case depends on 'ignorecase', 'smartcase' and "pat"
+ regmatch.rm_ic = ignorecase(pat);
+ while (*dict != NUL && !got_int && !compl_interrupted) {
+ // copy one dictionary file name into buf
+ if (flags == DICT_EXACT) {
+ count = 1;
+ files = &dict;
+ } else {
+ // Expand wildcards in the dictionary name, but do not allow
+ // backticks (for security, the 'dict' option may have been set in
+ // a modeline).
+ copy_option_part(&dict, buf, LSIZE, ",");
+ if (!thesaurus && STRCMP(buf, "spell") == 0) {
+ count = -1;
+ } else if (vim_strchr(buf, '`') != NULL
+ || expand_wildcards(1, &buf, &count, &files,
+ EW_FILE|EW_SILENT) != OK) {
+ count = 0;
+ }
+ }
+
+ if (count == -1) {
+ // Complete from active spelling. Skip "\<" in the pattern, we
+ // don't use it as a RE.
+ if (pat[0] == '\\' && pat[1] == '<') {
+ ptr = pat + 2;
+ } else {
+ ptr = pat;
+ }
+ spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
+ } else if (count > 0) { // avoid warning for using "files" uninit
+ ins_compl_files(count, files, thesaurus, flags,
+ &regmatch, (char_u *)buf, &dir);
+ if (flags != DICT_EXACT) {
+ FreeWild(count, files);
+ }
+ }
+ if (flags != 0) {
+ break;
+ }
+ }
+
+theend:
+ p_scs = save_p_scs;
+ vim_regfree(regmatch.regprog);
+ xfree(buf);
+}
+
+static void ins_compl_files(int count, char **files, int thesaurus, int flags, regmatch_T *regmatch,
+ char_u *buf, Direction *dir)
+ FUNC_ATTR_NONNULL_ARG(2, 7)
+{
+ char_u *ptr;
+ int i;
+ FILE *fp;
+ int add_r;
+
+ for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
+ fp = os_fopen(files[i], "r"); // open dictionary file
+ if (flags != DICT_EXACT) {
+ msg_hist_off = true; // reset in msg_trunc_attr()
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Scanning dictionary: %s"), files[i]);
+ (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
+ }
+
+ if (fp == NULL) {
+ continue;
+ }
+
+ // Read dictionary file line by line.
+ // Check each line for a match.
+ while (!got_int && !compl_interrupted
+ && !vim_fgets(buf, LSIZE, fp)) {
+ ptr = buf;
+ while (vim_regexec(regmatch, (char *)buf, (colnr_T)(ptr - buf))) {
+ ptr = regmatch->startp[0];
+ if (ctrl_x_mode_line_or_eval()) {
+ ptr = find_line_end(ptr);
+ } else {
+ ptr = find_word_end(ptr);
+ }
+ add_r = ins_compl_add_infercase(regmatch->startp[0],
+ (int)(ptr - regmatch->startp[0]),
+ p_ic, (char_u *)files[i], *dir, false);
+ if (thesaurus) {
+ char_u *wstart;
+
+ // Add the other matches on the line
+ ptr = buf;
+ while (!got_int) {
+ // Find start of the next word. Skip white
+ // space and punctuation.
+ ptr = find_word_start(ptr);
+ if (*ptr == NUL || *ptr == NL) {
+ break;
+ }
+ wstart = ptr;
+
+ // Find end of the word.
+ // Japanese words may have characters in
+ // different classes, only separate words
+ // with single-byte non-word characters.
+ while (*ptr != NUL) {
+ const int l = utfc_ptr2len((char *)ptr);
+
+ if (l < 2 && !vim_iswordc(*ptr)) {
+ break;
+ }
+ ptr += l;
+ }
+
+ // Add the word. Skip the regexp match.
+ if (wstart != regmatch->startp[0]) {
+ add_r = ins_compl_add_infercase(wstart, (int)(ptr - wstart),
+ p_ic, (char_u *)files[i], *dir, false);
+ }
+ }
+ }
+ if (add_r == OK) {
+ // if dir was BACKWARD then honor it just once
+ *dir = FORWARD;
+ } else if (add_r == FAIL) {
+ break;
+ }
+ // avoid expensive call to vim_regexec() when at end
+ // of line
+ if (*ptr == '\n' || got_int) {
+ break;
+ }
+ }
+ line_breakcheck();
+ ins_compl_check_keys(50, false);
+ }
+ fclose(fp);
+ }
+}
+
+/// Find the start of the next word.
+/// Returns a pointer to the first char of the word. Also stops at a NUL.
+char_u *find_word_start(char_u *ptr)
+ FUNC_ATTR_PURE
+{
+ while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1) {
+ ptr += utfc_ptr2len((char *)ptr);
+ }
+ return ptr;
+}
+
+/// Find the end of the word. Assumes it starts inside a word.
+/// Returns a pointer to just after the word.
+char_u *find_word_end(char_u *ptr)
+ FUNC_ATTR_PURE
+{
+ const int start_class = mb_get_class(ptr);
+ if (start_class > 1) {
+ while (*ptr != NUL) {
+ ptr += utfc_ptr2len((char *)ptr);
+ if (mb_get_class(ptr) != start_class) {
+ break;
+ }
+ }
+ }
+ return ptr;
+}
+
+/// Find the end of the line, omitting CR and NL at the end.
+/// Returns a pointer to just after the line.
+static char_u *find_line_end(char_u *ptr)
+{
+ char_u *s;
+
+ s = ptr + STRLEN(ptr);
+ while (s > ptr && (s[-1] == CAR || s[-1] == NL)) {
+ s--;
+ }
+ return s;
+}
+
+/// Free the list of completions
+static void ins_compl_free(void)
+{
+ compl_T *match;
+
+ XFREE_CLEAR(compl_pattern);
+ XFREE_CLEAR(compl_leader);
+
+ if (compl_first_match == NULL) {
+ return;
+ }
+
+ ins_compl_del_pum();
+ pum_clear();
+
+ compl_curr_match = compl_first_match;
+ do {
+ match = compl_curr_match;
+ compl_curr_match = compl_curr_match->cp_next;
+ xfree(match->cp_str);
+ // several entries may use the same fname, free it just once.
+ if (match->cp_flags & CP_FREE_FNAME) {
+ xfree(match->cp_fname);
+ }
+ for (int i = 0; i < CPT_COUNT; i++) {
+ xfree(match->cp_text[i]);
+ }
+ tv_clear(&match->cp_user_data);
+ xfree(match);
+ } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
+ compl_first_match = compl_curr_match = NULL;
+ compl_shown_match = NULL;
+ compl_old_match = NULL;
+}
+
+void ins_compl_clear(void)
+{
+ compl_cont_status = 0;
+ compl_started = false;
+ compl_matches = 0;
+ XFREE_CLEAR(compl_pattern);
+ XFREE_CLEAR(compl_leader);
+ edit_submode_extra = NULL;
+ XFREE_CLEAR(compl_orig_text);
+ compl_enter_selects = false;
+ // clear v:completed_item
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
+}
+
+/// Check that Insert completion is active.
+bool ins_compl_active(void)
+ FUNC_ATTR_PURE
+{
+ return compl_started;
+}
+
+/// Selected one of the matches. When false the match was edited or using the
+/// longest common string.
+bool ins_compl_used_match(void)
+{
+ return compl_used_match;
+}
+
+/// Initialize get longest common string.
+void ins_compl_init_get_longest(void)
+{
+ compl_get_longest = false;
+}
+
+/// Returns true when insert completion is interrupted.
+bool ins_compl_interrupted(void)
+{
+ return compl_interrupted;
+}
+
+/// Returns true if the <Enter> key selects a match in the completion popup
+/// menu.
+bool ins_compl_enter_selects(void)
+{
+ return compl_enter_selects;
+}
+
+/// Return the column where the text starts that is being completed
+colnr_T ins_compl_col(void)
+{
+ return compl_col;
+}
+
+/// Delete one character before the cursor and show the subset of the matches
+/// that match the word that is now before the cursor.
+/// Returns the character to be used, NUL if the work is done and another char
+/// to be got from the user.
+int ins_compl_bs(void)
+{
+ char_u *line = get_cursor_line_ptr();
+ char_u *p = line + curwin->w_cursor.col;
+ MB_PTR_BACK(line, p);
+ ptrdiff_t p_off = p - line;
+
+ // Stop completion when the whole word was deleted. For Omni completion
+ // allow the word to be deleted, we won't match everything.
+ // Respect the 'backspace' option.
+ if ((int)(p - line) - (int)compl_col < 0
+ || ((int)(p - line) - (int)compl_col == 0 && !ctrl_x_mode_omni())
+ || ctrl_x_mode_eval()
+ || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col
+ - compl_length < 0)) {
+ return K_BS;
+ }
+
+ // Deleted more than what was used to find matches or didn't finish
+ // finding all matches: need to look for matches all over again.
+ if (curwin->w_cursor.col <= compl_col + compl_length
+ || ins_compl_need_restart()) {
+ ins_compl_restart();
+ }
+
+ // ins_compl_restart() calls update_screen(0) which may invalidate the pointer
+ // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic
+ line = get_cursor_line_ptr();
+
+ xfree(compl_leader);
+ compl_leader = vim_strnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col));
+ ins_compl_new_leader();
+ if (compl_shown_match != NULL) {
+ // Make sure current match is not a hidden item.
+ compl_curr_match = compl_shown_match;
+ }
+
+ return NUL;
+}
+
+/// Check that we need to find matches again, ins_compl_restart() is to
+/// be called.
+static bool ins_compl_need_restart(void)
+ FUNC_ATTR_PURE
+{
+ // Return true if we didn't complete finding matches or when the
+ // "completefunc" returned "always" in the "refresh" dictionary item.
+ return compl_was_interrupted
+ || ((ctrl_x_mode_function() || ctrl_x_mode_omni())
+ && compl_opt_refresh_always);
+}
+
+/// Called after changing "compl_leader".
+/// Show the popup menu with a different set of matches.
+/// May also search for matches again if the previous search was interrupted.
+static void ins_compl_new_leader(void)
+{
+ ins_compl_del_pum();
+ ins_compl_delete();
+ ins_bytes(compl_leader + get_compl_len());
+ compl_used_match = false;
+
+ if (compl_started) {
+ ins_compl_set_original_text(compl_leader);
+ } else {
+ spell_bad_len = 0; // need to redetect bad word
+ // Matches were cleared, need to search for them now.
+ // Set "compl_restarting" to avoid that the first match is inserted.
+ compl_restarting = true;
+ if (ins_complete(Ctrl_N, true) == FAIL) {
+ compl_cont_status = 0;
+ }
+ compl_restarting = false;
+ }
+
+ compl_enter_selects = !compl_used_match;
+
+ // Show the popup menu with a different set of matches.
+ ins_compl_show_pum();
+
+ // Don't let Enter select the original text when there is no popup menu.
+ // Don't let Enter select when use user function and refresh_always is set
+ if (compl_match_array == NULL || ins_compl_need_restart()) {
+ compl_enter_selects = false;
+ }
+}
+
+/// Return the length of the completion, from the completion start column to
+/// the cursor column. Making sure it never goes below zero.
+static int get_compl_len(void)
+{
+ int off = (int)curwin->w_cursor.col - (int)compl_col;
+
+ if (off < 0) {
+ return 0;
+ }
+ return off;
+}
+
+/// Append one character to the match leader. May reduce the number of
+/// matches.
+void ins_compl_addleader(int c)
+{
+ int cc;
+
+ if (stop_arrow() == FAIL) {
+ return;
+ }
+ if ((cc = utf_char2len(c)) > 1) {
+ char buf[MB_MAXBYTES + 1];
+
+ utf_char2bytes(c, (char *)buf);
+ buf[cc] = NUL;
+ ins_char_bytes((char_u *)buf, (size_t)cc);
+ } else {
+ ins_char(c);
+ }
+
+ // If we didn't complete finding matches we must search again.
+ if (ins_compl_need_restart()) {
+ ins_compl_restart();
+ }
+
+ xfree(compl_leader);
+ compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col,
+ (size_t)(curwin->w_cursor.col - compl_col));
+ ins_compl_new_leader();
+}
+
+/// Setup for finding completions again without leaving CTRL-X mode. Used when
+/// BS or a key was typed while still searching for matches.
+static void ins_compl_restart(void)
+{
+ // update screen before restart.
+ // so if complete is blocked,
+ // will stay to the last popup menu and reduce flicker
+ update_screen(0);
+ ins_compl_free();
+ compl_started = false;
+ compl_matches = 0;
+ compl_cont_status = 0;
+ compl_cont_mode = 0;
+}
+
+/// Set the first match, the original text.
+static void ins_compl_set_original_text(char_u *str)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Replace the original text entry.
+ // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly be
+ // at the last item for backward completion
+ if (compl_first_match->cp_flags & CP_ORIGINAL_TEXT) { // safety check
+ xfree(compl_first_match->cp_str);
+ compl_first_match->cp_str = vim_strsave(str);
+ } else if (compl_first_match->cp_prev != NULL
+ && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) {
+ xfree(compl_first_match->cp_prev->cp_str);
+ compl_first_match->cp_prev->cp_str = vim_strsave(str);
+ }
+}
+
+/// Append one character to the match leader. May reduce the number of
+/// matches.
+void ins_compl_addfrommatch(void)
+{
+ char_u *p;
+ int len = (int)curwin->w_cursor.col - (int)compl_col;
+ int c;
+ compl_T *cp;
+ assert(compl_shown_match != NULL);
+ p = compl_shown_match->cp_str;
+ if ((int)STRLEN(p) <= len) { // the match is too short
+ // When still at the original match use the first entry that matches
+ // the leader.
+ if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
+ p = NULL;
+ for (cp = compl_shown_match->cp_next; cp != NULL
+ && cp != compl_first_match; cp = cp->cp_next) {
+ if (compl_leader == NULL
+ || ins_compl_equal(cp, compl_leader, STRLEN(compl_leader))) {
+ p = cp->cp_str;
+ break;
+ }
+ }
+ if (p == NULL || (int)STRLEN(p) <= len) {
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+ p += len;
+ c = utf_ptr2char((char *)p);
+ ins_compl_addleader(c);
+}
+
+/// Prepare for Insert mode completion, or stop it.
+/// Called just after typing a character in Insert mode.
+///
+/// @param c character that was typed
+///
+/// @return true when the character is not to be inserted;
+bool ins_compl_prep(int c)
+{
+ char_u *ptr;
+ bool retval = false;
+ const int prev_mode = ctrl_x_mode;
+
+ // Forget any previous 'special' messages if this is actually
+ // a ^X mode key - bar ^R, in which case we wait to see what it gives us.
+ if (c != Ctrl_R && vim_is_ctrl_x_key(c)) {
+ edit_submode_extra = NULL;
+ }
+
+ // Ignore end of Select mode mapping and mouse scroll buttons.
+ if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
+ || c == K_COMMAND || c == K_LUA) {
+ return retval;
+ }
+
+ if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
+ if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
+ || !vim_is_ctrl_x_key(c)) {
+ // Not starting another completion mode.
+ ctrl_x_mode = CTRL_X_CMDLINE;
+
+ // CTRL-X CTRL-Z should stop completion without inserting anything
+ if (c == Ctrl_Z) {
+ retval = true;
+ }
+ } else {
+ ctrl_x_mode = CTRL_X_CMDLINE;
+
+ // Other CTRL-X keys first stop completion, then start another
+ // completion mode.
+ ins_compl_prep(' ');
+ ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
+ }
+ }
+
+ // Set "compl_get_longest" when finding the first matches.
+ if (ctrl_x_mode_not_defined_yet()
+ || (ctrl_x_mode_normal() && !compl_started)) {
+ compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
+ compl_used_match = true;
+ }
+
+ if (ctrl_x_mode_not_defined_yet()) {
+ // We have just typed CTRL-X and aren't quite sure which CTRL-X mode
+ // it will be yet. Now we decide.
+ switch (c) {
+ case Ctrl_E:
+ case Ctrl_Y:
+ ctrl_x_mode = CTRL_X_SCROLL;
+ if (!(State & REPLACE_FLAG)) {
+ edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
+ } else {
+ edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
+ }
+ edit_submode_pre = NULL;
+ showmode();
+ break;
+ case Ctrl_L:
+ ctrl_x_mode = CTRL_X_WHOLE_LINE;
+ break;
+ case Ctrl_F:
+ ctrl_x_mode = CTRL_X_FILES;
+ break;
+ case Ctrl_K:
+ ctrl_x_mode = CTRL_X_DICTIONARY;
+ break;
+ case Ctrl_R:
+ // Simply allow ^R to happen without affecting ^X mode
+ break;
+ case Ctrl_T:
+ ctrl_x_mode = CTRL_X_THESAURUS;
+ break;
+ case Ctrl_U:
+ ctrl_x_mode = CTRL_X_FUNCTION;
+ break;
+ case Ctrl_O:
+ ctrl_x_mode = CTRL_X_OMNI;
+ break;
+ case 's':
+ case Ctrl_S:
+ ctrl_x_mode = CTRL_X_SPELL;
+ emsg_off++; // Avoid getting the E756 error twice.
+ spell_back_to_badword();
+ emsg_off--;
+ break;
+ case Ctrl_RSB:
+ ctrl_x_mode = CTRL_X_TAGS;
+ break;
+ case Ctrl_I:
+ case K_S_TAB:
+ ctrl_x_mode = CTRL_X_PATH_PATTERNS;
+ break;
+ case Ctrl_D:
+ ctrl_x_mode = CTRL_X_PATH_DEFINES;
+ break;
+ case Ctrl_V:
+ case Ctrl_Q:
+ ctrl_x_mode = CTRL_X_CMDLINE;
+ break;
+ case Ctrl_Z:
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ retval = true;
+ break;
+ case Ctrl_P:
+ case Ctrl_N:
+ // ^X^P means LOCAL expansion if nothing interrupted (eg we
+ // just started ^X mode, or there were enough ^X's to cancel
+ // the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
+ // do normal expansion when interrupting a different mode (say
+ // ^X^F^X^P or ^P^X^X^P, see below)
+ // nothing changes if interrupting mode 0, (eg, the flag
+ // doesn't change when going to ADDING mode -- Acevedo
+ if (!(compl_cont_status & CONT_INTRPT)) {
+ compl_cont_status |= CONT_LOCAL;
+ } else if (compl_cont_mode != 0) {
+ compl_cont_status &= ~CONT_LOCAL;
+ }
+ FALLTHROUGH;
+ default:
+ // If we have typed at least 2 ^X's... for modes != 0, we set
+ // compl_cont_status = 0 (eg, as if we had just started ^X
+ // mode).
+ // For mode 0, we set "compl_cont_mode" to an impossible
+ // value, in both cases ^X^X can be used to restart the same
+ // mode (avoiding ADDING mode).
+ // Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
+ // 'complete' and local ^P expansions respectively.
+ // In mode 0 an extra ^X is needed since ^X^P goes to ADDING
+ // mode -- Acevedo
+ if (c == Ctrl_X) {
+ if (compl_cont_mode != 0) {
+ compl_cont_status = 0;
+ } else {
+ compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
+ }
+ }
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ break;
+ }
+ } else if (ctrl_x_mode_not_default()) {
+ // We're already in CTRL-X mode, do we stay in it?
+ if (!vim_is_ctrl_x_key(c)) {
+ if (ctrl_x_mode_scroll()) {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ } else {
+ ctrl_x_mode = CTRL_X_FINISHED;
+ }
+ edit_submode = NULL;
+ }
+ showmode();
+ }
+
+ if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) {
+ // Show error message from attempted keyword completion (probably
+ // 'Pattern not found') until another key is hit, then go back to
+ // showing what mode we are in.
+ showmode();
+ if ((ctrl_x_mode_normal()
+ && c != Ctrl_N
+ && c != Ctrl_P
+ && c != Ctrl_R
+ && !ins_compl_pum_key(c))
+ || ctrl_x_mode == CTRL_X_FINISHED) {
+ // Get here when we have finished typing a sequence of ^N and
+ // ^P or other completion characters in CTRL-X mode. Free up
+ // memory that was used, and make sure we can redo the insert.
+ if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) {
+ // If any of the original typed text has been changed, eg when
+ // ignorecase is set, we must add back-spaces to the redo
+ // buffer. We add as few as necessary to delete just the part
+ // of the original text that has changed.
+ // When using the longest match, edited the match or used
+ // CTRL-E then don't use the current match.
+ if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
+ ptr = compl_curr_match->cp_str;
+ } else {
+ ptr = NULL;
+ }
+ ins_compl_fixRedoBufForLeader(ptr);
+ }
+
+ bool want_cindent = (can_cindent_get() && cindent_on());
+
+ // When completing whole lines: fix indent for 'cindent'.
+ // Otherwise, break line if it's too long.
+ if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
+ // re-indent the current line
+ if (want_cindent) {
+ do_c_expr_indent();
+ want_cindent = false; // don't do it again
+ }
+ } else {
+ int prev_col = curwin->w_cursor.col;
+
+ // put the cursor on the last char, for 'tw' formatting
+ if (prev_col > 0) {
+ dec_cursor();
+ }
+
+ if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E) {
+ insertchar(NUL, 0, -1);
+ }
+
+ if (prev_col > 0
+ && get_cursor_line_ptr()[curwin->w_cursor.col] != NUL) {
+ inc_cursor();
+ }
+ }
+
+ // If the popup menu is displayed pressing CTRL-Y means accepting
+ // the selection without inserting anything. When
+ // compl_enter_selects is set the Enter key does the same.
+ if ((c == Ctrl_Y || (compl_enter_selects
+ && (c == CAR || c == K_KENTER || c == NL)))
+ && pum_visible()) {
+ retval = true;
+ }
+
+ // CTRL-E means completion is Ended, go back to the typed text.
+ // but only do this, if the Popup is still visible
+ if (c == Ctrl_E) {
+ ins_compl_delete();
+ if (compl_leader != NULL) {
+ ins_bytes(compl_leader + get_compl_len());
+ } else if (compl_first_match != NULL) {
+ ins_bytes(compl_orig_text + get_compl_len());
+ }
+ retval = true;
+ }
+
+ auto_format(false, true);
+
+ // Trigger the CompleteDonePre event to give scripts a chance to
+ // act upon the completion before clearing the info, and restore
+ // ctrl_x_mode, so that complete_info() can be used.
+ ctrl_x_mode = prev_mode;
+ ins_apply_autocmds(EVENT_COMPLETEDONEPRE);
+
+ ins_compl_free();
+ compl_started = false;
+ compl_matches = 0;
+ if (!shortmess(SHM_COMPLETIONMENU)) {
+ msg_clr_cmdline(); // necessary for "noshowmode"
+ }
+ ctrl_x_mode = CTRL_X_NORMAL;
+ compl_enter_selects = false;
+ if (edit_submode != NULL) {
+ edit_submode = NULL;
+ showmode();
+ }
+
+ // Avoid the popup menu remains displayed when leaving the
+ // command line window.
+ if (c == Ctrl_C && cmdwin_type != 0) {
+ update_screen(0);
+ }
+
+ // Indent now if a key was typed that is in 'cinkeys'.
+ if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0))) {
+ do_c_expr_indent();
+ }
+ // Trigger the CompleteDone event to give scripts a chance to act
+ // upon the end of completion.
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+ }
+ } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
+ // Trigger the CompleteDone event to give scripts a chance to act
+ // upon the (possibly failed) completion.
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+ }
+
+ may_trigger_modechanged();
+
+ // reset continue_* if we left expansion-mode, if we stay they'll be
+ // (re)set properly in ins_complete()
+ if (!vim_is_ctrl_x_key(c)) {
+ compl_cont_status = 0;
+ compl_cont_mode = 0;
+ }
+
+ return retval;
+}
+
+/// Fix the redo buffer for the completion leader replacing some of the typed
+/// text. This inserts backspaces and appends the changed text.
+/// "ptr" is the known leader text or NUL.
+static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
+{
+ int len;
+ char_u *p;
+ char_u *ptr = ptr_arg;
+
+ if (ptr == NULL) {
+ if (compl_leader != NULL) {
+ ptr = compl_leader;
+ } else {
+ return; // nothing to do
+ }
+ }
+ if (compl_orig_text != NULL) {
+ p = compl_orig_text;
+ for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {}
+ if (len > 0) {
+ len -= utf_head_off(p, p + len);
+ }
+ for (p += len; *p != NUL; MB_PTR_ADV(p)) {
+ AppendCharToRedobuff(K_BS);
+ }
+ } else {
+ len = 0;
+ }
+ AppendToRedobuffLit((char *)ptr + len, -1);
+}
+
+/// Loops through the list of windows, loaded-buffers or non-loaded-buffers
+/// (depending on flag) starting from buf and looking for a non-scanned
+/// buffer (other than curbuf). curbuf is special, if it is called with
+/// buf=curbuf then it has to be the first call for a given flag/expansion.
+///
+/// Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
+static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
+{
+ static win_T *wp = NULL;
+
+ if (flag == 'w') { // just windows
+ if (buf == curbuf || wp == NULL) { // first call for this flag/expansion
+ wp = curwin;
+ }
+ assert(wp);
+ while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
+ && wp->w_buffer->b_scanned) {}
+ buf = wp->w_buffer;
+ } else {
+ // 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
+ // (unlisted buffers)
+ // When completing whole lines skip unloaded buffers.
+ while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
+ && ((flag == 'U'
+ ? buf->b_p_bl
+ : (!buf->b_p_bl
+ || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
+ || buf->b_scanned)) {}
+ }
+ return buf;
+}
+
+/// Get the user-defined completion function name for completion 'type'
+static char_u *get_complete_funcname(int type)
+{
+ switch (type) {
+ case CTRL_X_FUNCTION:
+ return curbuf->b_p_cfu;
+ case CTRL_X_OMNI:
+ return curbuf->b_p_ofu;
+ case CTRL_X_THESAURUS:
+ return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu;
+ default:
+ return (char_u *)"";
+ }
+}
+
+/// Execute user defined complete function 'completefunc' or 'omnifunc', and
+/// get matches in "matches".
+///
+/// @param type CTRL_X_OMNI or CTRL_X_FUNCTION
+static void expand_by_function(int type, char_u *base)
+{
+ list_T *matchlist = NULL;
+ dict_T *matchdict = NULL;
+ char_u *funcname;
+ pos_T pos;
+ typval_T rettv;
+ const int save_State = State;
+
+ assert(curbuf != NULL);
+ funcname = get_complete_funcname(type);
+ if (*funcname == NUL) {
+ return;
+ }
+
+ // Call 'completefunc' to obtain the list of matches.
+ typval_T args[3];
+ args[0].v_type = VAR_NUMBER;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_UNKNOWN;
+ args[0].vval.v_number = 0;
+ args[1].vval.v_string = base != NULL ? (char *)base : "";
+
+ pos = curwin->w_cursor;
+ // Lock the text to avoid weird things from happening. Also disallow
+ // switching to another window, it should not be needed and may end up in
+ // Insert mode in another buffer.
+ textlock++;
+
+ // Call a function, which returns a list or dict.
+ if (call_vim_function((char *)funcname, 2, args, &rettv) == OK) {
+ switch (rettv.v_type) {
+ case VAR_LIST:
+ matchlist = rettv.vval.v_list;
+ break;
+ case VAR_DICT:
+ matchdict = rettv.vval.v_dict;
+ break;
+ case VAR_SPECIAL:
+ FALLTHROUGH;
+ default:
+ // TODO(brammool): Give error message?
+ tv_clear(&rettv);
+ break;
+ }
+ }
+ textlock--;
+
+ curwin->w_cursor = pos; // restore the cursor position
+ validate_cursor();
+ if (!equalpos(curwin->w_cursor, pos)) {
+ emsg(_(e_compldel));
+ goto theend;
+ }
+
+ if (matchlist != NULL) {
+ ins_compl_add_list(matchlist);
+ } else if (matchdict != NULL) {
+ ins_compl_add_dict(matchdict);
+ }
+
+theend:
+ // Restore State, it might have been changed.
+ State = save_State;
+
+ if (matchdict != NULL) {
+ tv_dict_unref(matchdict);
+ }
+ if (matchlist != NULL) {
+ tv_list_unref(matchlist);
+ }
+}
+
+/// Add a match to the list of matches from VimL object
+///
+/// @param[in] tv Object to get matches from.
+/// @param[in] dir Completion direction.
+/// @param[in] fast use fast_breakcheck() instead of os_breakcheck().
+///
+/// @return NOTDONE if the given string is already in the list of completions,
+/// otherwise it is added to the list and OK is returned. FAIL will be
+/// returned in case of error.
+static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *word;
+ bool dup = false;
+ bool empty = false;
+ int flags = fast ? CP_FAST : 0;
+ char *(cptext[CPT_COUNT]);
+ typval_T user_data;
+
+ user_data.v_type = VAR_UNKNOWN;
+ if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
+ word = tv_dict_get_string(tv->vval.v_dict, "word", false);
+ cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
+ cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
+ cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
+ cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
+ tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
+
+ if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
+ flags |= CP_ICASE;
+ }
+ dup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
+ empty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
+ if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL
+ && tv_dict_get_number(tv->vval.v_dict, "equal")) {
+ flags |= CP_EQUAL;
+ }
+ } else {
+ word = tv_get_string_chk(tv);
+ memset(cptext, 0, sizeof(cptext));
+ }
+ if (word == NULL || (!empty && *word == NUL)) {
+ for (size_t i = 0; i < CPT_COUNT; i++) {
+ xfree(cptext[i]);
+ }
+ return FAIL;
+ }
+ return ins_compl_add((char_u *)word, -1, NULL,
+ (char_u **)cptext, true, &user_data, dir, flags, dup);
+}
+
+/// Add completions from a list.
+static void ins_compl_add_list(list_T *const list)
+{
+ Direction dir = compl_direction;
+
+ // Go through the List with matches and add each of them.
+ TV_LIST_ITER(list, li, {
+ if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir, true) == OK) {
+ // If dir was BACKWARD then honor it just once.
+ dir = FORWARD;
+ } else if (did_emsg) {
+ break;
+ }
+ });
+}
+
+/// Add completions from a dict.
+static void ins_compl_add_dict(dict_T *dict)
+{
+ dictitem_T *di_refresh;
+ dictitem_T *di_words;
+
+ // Check for optional "refresh" item.
+ compl_opt_refresh_always = false;
+ di_refresh = tv_dict_find(dict, S_LEN("refresh"));
+ if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
+ const char *v = (const char *)di_refresh->di_tv.vval.v_string;
+
+ if (v != NULL && strcmp(v, "always") == 0) {
+ compl_opt_refresh_always = true;
+ }
+ }
+
+ // Add completions from a "words" list.
+ di_words = tv_dict_find(dict, S_LEN("words"));
+ if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
+ ins_compl_add_list(di_words->di_tv.vval.v_list);
+ }
+}
+
+/// Start completion for the complete() function.
+///
+/// @param startcol where the matched text starts (1 is first column).
+/// @param list the list of matches.
+static void set_completion(colnr_T startcol, list_T *list)
+{
+ int flags = CP_ORIGINAL_TEXT;
+
+ // If already doing completions stop it.
+ if (ctrl_x_mode_not_default()) {
+ ins_compl_prep(' ');
+ }
+ ins_compl_clear();
+ ins_compl_free();
+
+ compl_direction = FORWARD;
+ if (startcol > curwin->w_cursor.col) {
+ startcol = curwin->w_cursor.col;
+ }
+ compl_col = startcol;
+ compl_length = (int)curwin->w_cursor.col - (int)startcol;
+ // compl_pattern doesn't need to be set
+ compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
+ (size_t)compl_length);
+ if (p_ic) {
+ flags |= CP_ICASE;
+ }
+ if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
+ flags | CP_FAST, false) != OK) {
+ return;
+ }
+
+ ctrl_x_mode = CTRL_X_EVAL;
+
+ ins_compl_add_list(list);
+ compl_matches = ins_compl_make_cyclic();
+ compl_started = true;
+ compl_used_match = true;
+ compl_cont_status = 0;
+ int save_w_wrow = curwin->w_wrow;
+ int save_w_leftcol = curwin->w_leftcol;
+
+ compl_curr_match = compl_first_match;
+ if (compl_no_insert || compl_no_select) {
+ ins_complete(K_DOWN, false);
+ if (compl_no_select) {
+ ins_complete(K_UP, false);
+ }
+ } else {
+ ins_complete(Ctrl_N, false);
+ }
+ compl_enter_selects = compl_no_insert;
+
+ // Lazily show the popup menu, unless we got interrupted.
+ if (!compl_interrupted) {
+ show_pum(save_w_wrow, save_w_leftcol);
+ }
+
+ may_trigger_modechanged();
+ ui_flush();
+}
+
+/// "complete()" function
+void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if ((State & MODE_INSERT) == 0) {
+ emsg(_("E785: complete() can only be used in Insert mode"));
+ return;
+ }
+
+ // Check for undo allowed here, because if something was already inserted
+ // the line was already saved for undo and this check isn't done.
+ if (!undo_allowed(curbuf)) {
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_LIST) {
+ emsg(_(e_invarg));
+ } else {
+ const colnr_T startcol = (colnr_T)tv_get_number_chk(&argvars[0], NULL);
+ if (startcol > 0) {
+ set_completion(startcol - 1, argvars[1].vval.v_list);
+ }
+ }
+}
+
+/// "complete_add()" function
+void f_complete_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false);
+}
+
+/// "complete_check()" function
+void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ int saved = RedrawingDisabled;
+
+ RedrawingDisabled = 0;
+ ins_compl_check_keys(0, true);
+ rettv->vval.v_number = ins_compl_interrupted();
+ RedrawingDisabled = saved;
+}
+
+/// Return Insert completion mode name string
+static char_u *ins_compl_mode(void)
+{
+ if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started) {
+ return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
+ }
+ return (char_u *)"";
+}
+
+static void ins_compl_update_sequence_numbers(void)
+{
+ int number = 0;
+ compl_T *match;
+
+ if (compl_direction == FORWARD) {
+ // search backwards for the first valid (!= -1) number.
+ // This should normally succeed already at the first loop
+ // cycle, so it's fast!
+ for (match = compl_curr_match->cp_prev;
+ match != NULL && match != compl_first_match;
+ match = match->cp_prev) {
+ if (match->cp_number != -1) {
+ number = match->cp_number;
+ break;
+ }
+ }
+ if (match != NULL) {
+ // go up and assign all numbers which are not assigned yet
+ for (match = match->cp_next;
+ match != NULL && match->cp_number == -1;
+ match = match->cp_next) {
+ match->cp_number = ++number;
+ }
+ }
+ } else { // BACKWARD
+ assert(compl_direction == BACKWARD);
+ // search forwards (upwards) for the first valid (!= -1)
+ // number. This should normally succeed already at the
+ // first loop cycle, so it's fast!
+ for (match = compl_curr_match->cp_next;
+ match != NULL && match != compl_first_match;
+ match = match->cp_next) {
+ if (match->cp_number != -1) {
+ number = match->cp_number;
+ break;
+ }
+ }
+ if (match != NULL) {
+ // go down and assign all numbers which are not
+ // assigned yet
+ for (match = match->cp_prev;
+ match && match->cp_number == -1;
+ match = match->cp_prev) {
+ match->cp_number = ++number;
+ }
+ }
+ }
+}
+
+/// Get complete information
+static void get_complete_info(list_T *what_list, dict_T *retdict)
+{
+#define CI_WHAT_MODE 0x01
+#define CI_WHAT_PUM_VISIBLE 0x02
+#define CI_WHAT_ITEMS 0x04
+#define CI_WHAT_SELECTED 0x08
+#define CI_WHAT_INSERTED 0x10
+#define CI_WHAT_ALL 0xff
+ int what_flag;
+
+ if (what_list == NULL) {
+ what_flag = CI_WHAT_ALL;
+ } else {
+ what_flag = 0;
+ for (listitem_T *item = tv_list_first(what_list)
+ ; item != NULL
+ ; item = TV_LIST_ITEM_NEXT(what_list, item)) {
+ const char *what = tv_get_string(TV_LIST_ITEM_TV(item));
+
+ if (STRCMP(what, "mode") == 0) {
+ what_flag |= CI_WHAT_MODE;
+ } else if (STRCMP(what, "pum_visible") == 0) {
+ what_flag |= CI_WHAT_PUM_VISIBLE;
+ } else if (STRCMP(what, "items") == 0) {
+ what_flag |= CI_WHAT_ITEMS;
+ } else if (STRCMP(what, "selected") == 0) {
+ what_flag |= CI_WHAT_SELECTED;
+ } else if (STRCMP(what, "inserted") == 0) {
+ what_flag |= CI_WHAT_INSERTED;
+ }
+ }
+ }
+
+ int ret = OK;
+ if (what_flag & CI_WHAT_MODE) {
+ ret = tv_dict_add_str(retdict, S_LEN("mode"),
+ (char *)ins_compl_mode());
+ }
+
+ if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) {
+ ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
+ }
+
+ if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
+ list_T *li = tv_list_alloc(get_compl_len());
+
+ ret = tv_dict_add_list(retdict, S_LEN("items"), li);
+ if (ret == OK && compl_first_match != NULL) {
+ compl_T *match = compl_first_match;
+ do {
+ if (!(match->cp_flags & CP_ORIGINAL_TEXT)) {
+ dict_T *di = tv_dict_alloc();
+
+ tv_list_append_dict(li, di);
+ tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
+ if (match->cp_user_data.v_type == VAR_UNKNOWN) {
+ tv_dict_add_str(di, S_LEN("user_data"), "");
+ } else {
+ tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
+ }
+ }
+ match = match->cp_next;
+ } while (match != NULL && match != compl_first_match);
+ }
+ }
+
+ if (ret == OK && (what_flag & CI_WHAT_SELECTED)) {
+ if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) {
+ ins_compl_update_sequence_numbers();
+ }
+ ret = tv_dict_add_nr(retdict, S_LEN("selected"),
+ (compl_curr_match != NULL)
+ ? compl_curr_match->cp_number - 1 : -1);
+ }
+
+ (void)ret;
+ // TODO(vim):
+ // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
+}
+
+/// "complete_info()" function
+void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_alloc_ret(rettv);
+
+ list_T *what_list = NULL;
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ if (argvars[0].v_type != VAR_LIST) {
+ emsg(_(e_listreq));
+ return;
+ }
+ what_list = argvars[0].vval.v_list;
+ }
+ get_complete_info(what_list, rettv->vval.v_dict);
+}
+
+/// Returns true when using a user-defined function for thesaurus completion.
+static bool thesaurus_func_complete(int type)
+{
+ return type == CTRL_X_THESAURUS
+ && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
+}
+
+/// Get the next expansion(s), using "compl_pattern".
+/// The search starts at position "ini" in curbuf and in the direction
+/// compl_direction.
+/// When "compl_started" is false start at that position, otherwise continue
+/// where we stopped searching before.
+/// This may return before finding all the matches.
+/// Return the total number of matches or -1 if still unknown -- Acevedo
+static int ins_compl_get_exp(pos_T *ini)
+{
+ static pos_T first_match_pos;
+ static pos_T last_match_pos;
+ static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
+ static bool found_all = false; // Found all matches of a
+ // certain type.
+ static buf_T *ins_buf = NULL; // buffer being scanned
+
+ pos_T *pos;
+ char **matches;
+ int save_p_scs;
+ bool save_p_ws;
+ int save_p_ic;
+ int i;
+ int num_matches;
+ int len;
+ int found_new_match;
+ int type = ctrl_x_mode;
+ char_u *ptr;
+ char_u *dict = NULL;
+ int dict_f = 0;
+ bool set_match_pos;
+ pos_T prev_pos = { 0, 0, 0 };
+
+ assert(curbuf != NULL);
+
+ if (!compl_started) {
+ FOR_ALL_BUFFERS(buf) {
+ buf->b_scanned = false;
+ }
+ found_all = false;
+ ins_buf = curbuf;
+ e_cpt = (compl_cont_status & CONT_LOCAL)
+ ? (char_u *)"." : curbuf->b_p_cpt;
+ last_match_pos = first_match_pos = *ini;
+ } else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
+ ins_buf = curbuf; // In case the buffer was wiped out.
+ }
+ assert(ins_buf != NULL);
+
+ compl_old_match = compl_curr_match; // remember the last current match
+ pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
+
+ // For ^N/^P loop over all the flags/windows/buffers in 'complete'
+ for (;;) {
+ found_new_match = FAIL;
+ set_match_pos = false;
+
+ // For ^N/^P pick a new entry from e_cpt if compl_started is off,
+ // or if found_all says this entry is done. For ^X^L only use the
+ // entries from 'complete' that look in loaded buffers.
+ if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
+ && (!compl_started || found_all)) {
+ found_all = false;
+ while (*e_cpt == ',' || *e_cpt == ' ') {
+ e_cpt++;
+ }
+ if (*e_cpt == '.' && !curbuf->b_scanned) {
+ ins_buf = curbuf;
+ first_match_pos = *ini;
+ // Move the cursor back one character so that ^N can match the
+ // word immediately after the cursor.
+ if (ctrl_x_mode_normal() && dec(&first_match_pos) < 0) {
+ // Move the cursor to after the last character in the
+ // buffer, so that word at start of buffer is found
+ // correctly.
+ first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
+ first_match_pos.col = (colnr_T)STRLEN(ml_get(first_match_pos.lnum));
+ }
+ last_match_pos = first_match_pos;
+ type = 0;
+
+ // Remember the first match so that the loop stops when we
+ // wrap and come back there a second time.
+ set_match_pos = true;
+ } else if (vim_strchr("buwU", *e_cpt) != NULL
+ && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
+ // Scan a buffer, but not the current one.
+ if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
+ compl_started = true;
+ first_match_pos.col = last_match_pos.col = 0;
+ first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
+ last_match_pos.lnum = 0;
+ type = 0;
+ } else { // unloaded buffer, scan like dictionary
+ found_all = true;
+ if (ins_buf->b_fname == NULL) {
+ continue;
+ }
+ type = CTRL_X_DICTIONARY;
+ dict = (char_u *)ins_buf->b_fname;
+ dict_f = DICT_EXACT;
+ }
+ msg_hist_off = true; // reset in msg_trunc_attr()
+ vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
+ ins_buf->b_fname == NULL
+ ? buf_spname(ins_buf)
+ : ins_buf->b_sfname == NULL
+ ? ins_buf->b_fname
+ : ins_buf->b_sfname);
+ (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
+ } else if (*e_cpt == NUL) {
+ break;
+ } else {
+ if (ctrl_x_mode_line_or_eval()) {
+ type = -1;
+ } else if (*e_cpt == 'k' || *e_cpt == 's') {
+ if (*e_cpt == 'k') {
+ type = CTRL_X_DICTIONARY;
+ } else {
+ type = CTRL_X_THESAURUS;
+ }
+ if (*++e_cpt != ',' && *e_cpt != NUL) {
+ dict = e_cpt;
+ dict_f = DICT_FIRST;
+ }
+ } else if (*e_cpt == 'i') {
+ type = CTRL_X_PATH_PATTERNS;
+ } else if (*e_cpt == 'd') {
+ type = CTRL_X_PATH_DEFINES;
+ } else if (*e_cpt == ']' || *e_cpt == 't') {
+ msg_hist_off = true; // reset in msg_trunc_attr()
+ type = CTRL_X_TAGS;
+ vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags."));
+ (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
+ } else {
+ type = -1;
+ }
+
+ // in any case e_cpt is advanced to the next entry
+ (void)copy_option_part((char **)&e_cpt, (char *)IObuff, IOSIZE, ",");
+
+ found_all = true;
+ if (type == -1) {
+ continue;
+ }
+ }
+ }
+
+ // If complete() was called then compl_pattern has been reset.
+ // The following won't work then, bail out.
+ if (compl_pattern == NULL) {
+ break;
+ }
+
+ switch (type) {
+ case -1:
+ break;
+ case CTRL_X_PATH_PATTERNS:
+ case CTRL_X_PATH_DEFINES:
+ find_pattern_in_path((char_u *)compl_pattern, compl_direction,
+ STRLEN(compl_pattern), false, false,
+ ((type == CTRL_X_PATH_DEFINES
+ && !(compl_cont_status & CONT_SOL))
+ ? FIND_DEFINE
+ : FIND_ANY),
+ 1L, ACTION_EXPAND, 1, MAXLNUM);
+ break;
+
+ case CTRL_X_DICTIONARY:
+ case CTRL_X_THESAURUS:
+ if (thesaurus_func_complete(type)) {
+ expand_by_function(type, (char_u *)compl_pattern);
+ } else {
+ ins_compl_dictionaries(dict != NULL ? dict
+ : (type == CTRL_X_THESAURUS
+ ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
+ : (*curbuf->b_p_dict ==
+ NUL ? p_dict : curbuf->b_p_dict)),
+ (char_u *)compl_pattern,
+ dict != NULL ? dict_f : 0, type == CTRL_X_THESAURUS);
+ }
+ dict = NULL;
+ break;
+
+ case CTRL_X_TAGS:
+ // set p_ic according to p_ic, p_scs and pat for find_tags().
+ save_p_ic = p_ic;
+ p_ic = ignorecase((char_u *)compl_pattern);
+
+ // Find up to TAG_MANY matches. Avoids that an enormous number
+ // of matches is found when compl_pattern is empty
+ g_tag_at_cursor = true;
+ if (find_tags((char_u *)compl_pattern, &num_matches, &matches,
+ TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
+ | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
+ TAG_MANY, (char_u *)curbuf->b_ffname) == OK && num_matches > 0) {
+ ins_compl_add_matches(num_matches, matches, p_ic);
+ }
+ g_tag_at_cursor = false;
+ p_ic = save_p_ic;
+ break;
+
+ case CTRL_X_FILES:
+ if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
+ EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
+ // May change home directory back to "~".
+ tilde_replace((char_u *)compl_pattern, num_matches, matches);
+#ifdef BACKSLASH_IN_FILENAME
+ if (curbuf->b_p_csl[0] != NUL) {
+ for (int i = 0; i < num_matches; i++) {
+ char_u *ptr = matches[i];
+ while (*ptr != NUL) {
+ if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
+ *ptr = '/';
+ } else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
+ *ptr = '\\';
+ }
+ ptr += utfc_ptr2len(ptr);
+ }
+ }
+ }
+#endif
+ ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
+ }
+ break;
+
+ case CTRL_X_CMDLINE:
+ case CTRL_X_CMDLINE_CTRL_X:
+ if (expand_cmdline(&compl_xp, (char_u *)compl_pattern,
+ (int)STRLEN(compl_pattern),
+ &num_matches, &matches) == EXPAND_OK) {
+ ins_compl_add_matches(num_matches, matches, false);
+ }
+ break;
+
+ case CTRL_X_FUNCTION:
+ case CTRL_X_OMNI:
+ expand_by_function(type, (char_u *)compl_pattern);
+ break;
+
+ case CTRL_X_SPELL:
+ num_matches = expand_spelling(first_match_pos.lnum,
+ (char_u *)compl_pattern, &matches);
+ if (num_matches > 0) {
+ ins_compl_add_matches(num_matches, matches, p_ic);
+ }
+ break;
+
+ default: // normal ^P/^N and ^X^L
+ // If 'infercase' is set, don't use 'smartcase' here
+ save_p_scs = p_scs;
+ assert(ins_buf);
+ if (ins_buf->b_p_inf) {
+ p_scs = false;
+ }
+
+ // Buffers other than curbuf are scanned from the beginning or the
+ // end but never from the middle, thus setting nowrapscan in this
+ // buffers is a good idea, on the other hand, we always set
+ // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
+ save_p_ws = p_ws;
+ if (ins_buf != curbuf) {
+ p_ws = false;
+ } else if (*e_cpt == '.') {
+ p_ws = true;
+ }
+ bool looped_around = false;
+ for (;;) {
+ bool cont_s_ipos = false;
+
+ msg_silent++; // Don't want messages for wrapscan.
+ // ctrl_x_mode_line_or_eval() || word-wise search that
+ // has added a word that was at the beginning of the line.
+ if (ctrl_x_mode_line_or_eval()
+ || (compl_cont_status & CONT_SOL)) {
+ found_new_match = search_for_exact_line(ins_buf, pos,
+ compl_direction,
+ (char_u *)compl_pattern);
+ } else {
+ found_new_match = searchit(NULL, ins_buf, pos, NULL,
+ compl_direction,
+ (char_u *)compl_pattern, 1L,
+ SEARCH_KEEP + SEARCH_NFMSG,
+ RE_LAST, NULL);
+ }
+ msg_silent--;
+ if (!compl_started || set_match_pos) {
+ // set "compl_started" even on fail
+ compl_started = true;
+ first_match_pos = *pos;
+ last_match_pos = *pos;
+ set_match_pos = false;
+ } else if (first_match_pos.lnum == last_match_pos.lnum
+ && first_match_pos.col == last_match_pos.col) {
+ found_new_match = FAIL;
+ } else if ((compl_direction == FORWARD)
+ && (prev_pos.lnum > pos->lnum
+ || (prev_pos.lnum == pos->lnum
+ && prev_pos.col >= pos->col))) {
+ if (looped_around) {
+ found_new_match = FAIL;
+ } else {
+ looped_around = true;
+ }
+ } else if ((compl_direction != FORWARD)
+ && (prev_pos.lnum < pos->lnum
+ || (prev_pos.lnum == pos->lnum
+ && prev_pos.col <= pos->col))) {
+ if (looped_around) {
+ found_new_match = FAIL;
+ } else {
+ looped_around = true;
+ }
+ }
+ prev_pos = *pos;
+ if (found_new_match == FAIL) {
+ if (ins_buf == curbuf) {
+ found_all = true;
+ }
+ break;
+ }
+
+ // when ADDING, the text before the cursor matches, skip it
+ if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
+ && ini->lnum == pos->lnum
+ && ini->col == pos->col) {
+ continue;
+ }
+ ptr = ml_get_buf(ins_buf, pos->lnum, false) + pos->col;
+ if (ctrl_x_mode_line_or_eval()) {
+ if (compl_cont_status & CONT_ADDING) {
+ if (pos->lnum >= ins_buf->b_ml.ml_line_count) {
+ continue;
+ }
+ ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
+ if (!p_paste) {
+ ptr = (char_u *)skipwhite((char *)ptr);
+ }
+ }
+ len = (int)STRLEN(ptr);
+ } else {
+ char_u *tmp_ptr = ptr;
+
+ if (compl_cont_status & CONT_ADDING) {
+ tmp_ptr += compl_length;
+ // Skip if already inside a word.
+ if (vim_iswordp(tmp_ptr)) {
+ continue;
+ }
+ // Find start of next word.
+ tmp_ptr = find_word_start(tmp_ptr);
+ }
+ // Find end of this word.
+ tmp_ptr = find_word_end(tmp_ptr);
+ len = (int)(tmp_ptr - ptr);
+
+ if ((compl_cont_status & CONT_ADDING)
+ && len == compl_length) {
+ if (pos->lnum < ins_buf->b_ml.ml_line_count) {
+ // Try next line, if any. the new word will be "join" as if the
+ // normal command "J" was used. IOSIZE is always greater than
+ // compl_length, so the next STRNCPY always works -- Acevedo
+ STRNCPY(IObuff, ptr, len); // NOLINT(runtime/printf)
+ ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
+ tmp_ptr = ptr = (char_u *)skipwhite((char *)ptr);
+ // Find start of next word.
+ tmp_ptr = find_word_start(tmp_ptr);
+ // Find end of next word.
+ tmp_ptr = find_word_end(tmp_ptr);
+ if (tmp_ptr > ptr) {
+ if (*ptr != ')' && IObuff[len - 1] != TAB) {
+ if (IObuff[len - 1] != ' ') {
+ IObuff[len++] = ' ';
+ }
+ // IObuf =~ "\k.* ", thus len >= 2
+ if (p_js
+ && (IObuff[len - 2] == '.'
+ || IObuff[len - 2] == '?'
+ || IObuff[len - 2] == '!')) {
+ IObuff[len++] = ' ';
+ }
+ }
+ // copy as much as possible of the new word
+ if (tmp_ptr - ptr >= IOSIZE - len) {
+ tmp_ptr = ptr + IOSIZE - len - 1;
+ }
+ STRLCPY(IObuff + len, ptr, IOSIZE - len);
+ len += (int)(tmp_ptr - ptr);
+ cont_s_ipos = true;
+ }
+ IObuff[len] = NUL;
+ ptr = IObuff;
+ }
+ if (len == compl_length) {
+ continue;
+ }
+ }
+ }
+ if (ins_compl_add_infercase(ptr, len, p_ic,
+ ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
+ 0, cont_s_ipos) != NOTDONE) {
+ found_new_match = OK;
+ break;
+ }
+ }
+ p_scs = save_p_scs;
+ p_ws = save_p_ws;
+ }
+
+ // check if compl_curr_match has changed, (e.g. other type of
+ // expansion added something)
+ if (type != 0 && compl_curr_match != compl_old_match) {
+ found_new_match = OK;
+ }
+
+ // break the loop for specialized modes (use 'complete' just for the
+ // generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match
+ if ((ctrl_x_mode_not_default()
+ && !ctrl_x_mode_line_or_eval())
+ || found_new_match != FAIL) {
+ if (got_int) {
+ break;
+ }
+ // Fill the popup menu as soon as possible.
+ if (type != -1) {
+ ins_compl_check_keys(0, false);
+ }
+
+ if ((ctrl_x_mode_not_default()
+ && !ctrl_x_mode_line_or_eval())
+ || compl_interrupted) {
+ break;
+ }
+ compl_started = true;
+ } else {
+ // Mark a buffer scanned when it has been scanned completely
+ if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
+ assert(ins_buf);
+ ins_buf->b_scanned = true;
+ }
+
+ compl_started = false;
+ }
+ }
+ compl_started = true;
+
+ if ((ctrl_x_mode_normal()
+ || ctrl_x_mode_line_or_eval())
+ && *e_cpt == NUL) { // Got to end of 'complete'
+ found_new_match = FAIL;
+ }
+
+ i = -1; // total of matches, unknown
+ if (found_new_match == FAIL
+ || (ctrl_x_mode_not_default()
+ && !ctrl_x_mode_line_or_eval())) {
+ i = ins_compl_make_cyclic();
+ }
+
+ if (compl_old_match != NULL) {
+ // If several matches were added (FORWARD) or the search failed and has
+ // just been made cyclic then we have to move compl_curr_match to the
+ // next or previous entry (if any) -- Acevedo
+ compl_curr_match = compl_direction == FORWARD
+ ? compl_old_match->cp_next
+ : compl_old_match->cp_prev;
+ if (compl_curr_match == NULL) {
+ compl_curr_match = compl_old_match;
+ }
+ }
+ may_trigger_modechanged();
+
+ return i;
+}
+
+/// Delete the old text being completed.
+void ins_compl_delete(void)
+{
+ int col;
+
+ // In insert mode: Delete the typed part.
+ // In replace mode: Put the old characters back, if any.
+ col = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
+ if ((int)curwin->w_cursor.col > col) {
+ if (stop_arrow() == FAIL) {
+ return;
+ }
+ backspace_until_column(col);
+ }
+
+ // TODO(vim): is this sufficient for redrawing? Redrawing everything
+ // causes flicker, thus we can't do that.
+ changed_cline_bef_curs();
+ // clear v:completed_item
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
+}
+
+/// Insert the new text being completed.
+/// "in_compl_func" is true when called from complete_check().
+void ins_compl_insert(bool in_compl_func)
+{
+ ins_bytes(compl_shown_match->cp_str + get_compl_len());
+ compl_used_match = !(compl_shown_match->cp_flags & CP_ORIGINAL_TEXT);
+
+ dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict);
+ if (!in_compl_func) {
+ compl_curr_match = compl_shown_match;
+ }
+}
+
+/// Fill in the next completion in the current direction.
+/// If "allow_get_expansion" is true, then we may call ins_compl_get_exp() to
+/// get more completions. If it is false, then we just do nothing when there
+/// are no more completions in a given direction. The latter case is used when
+/// we are still in the middle of finding completions, to allow browsing
+/// through the ones found so far.
+/// @return the total number of matches, or -1 if still unknown -- webb.
+///
+/// compl_curr_match is currently being used by ins_compl_get_exp(), so we use
+/// compl_shown_match here.
+///
+/// Note that this function may be called recursively once only. First with
+/// "allow_get_expansion" true, which calls ins_compl_get_exp(), which in turn
+/// calls this function with "allow_get_expansion" false.
+///
+/// @param count Repeat completion this many times; should be at least 1
+/// @param insert_match Insert the newly selected match
+/// @param in_compl_func Called from complete_check()
+static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match,
+ bool in_compl_func)
+{
+ int num_matches = -1;
+ int todo = count;
+ compl_T *found_compl = NULL;
+ bool found_end = false;
+ const bool started = compl_started;
+
+ // When user complete function return -1 for findstart which is next
+ // time of 'always', compl_shown_match become NULL.
+ if (compl_shown_match == NULL) {
+ return -1;
+ }
+
+ if (compl_leader != NULL
+ && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
+ // Set "compl_shown_match" to the actually shown match, it may differ
+ // when "compl_leader" is used to omit some of the matches.
+ while (!ins_compl_equal(compl_shown_match,
+ compl_leader, STRLEN(compl_leader))
+ && compl_shown_match->cp_next != NULL
+ && compl_shown_match->cp_next != compl_first_match) {
+ compl_shown_match = compl_shown_match->cp_next;
+ }
+
+ // If we didn't find it searching forward, and compl_shows_dir is
+ // backward, find the last match.
+ if (compl_shows_dir == BACKWARD
+ && !ins_compl_equal(compl_shown_match, compl_leader, STRLEN(compl_leader))
+ && (compl_shown_match->cp_next == NULL
+ || compl_shown_match->cp_next == compl_first_match)) {
+ while (!ins_compl_equal(compl_shown_match, compl_leader, STRLEN(compl_leader))
+ && compl_shown_match->cp_prev != NULL
+ && compl_shown_match->cp_prev != compl_first_match) {
+ compl_shown_match = compl_shown_match->cp_prev;
+ }
+ }
+ }
+
+ if (allow_get_expansion && insert_match
+ && (!(compl_get_longest || compl_restarting) || compl_used_match)) {
+ // Delete old text to be replaced
+ ins_compl_delete();
+ }
+
+ // When finding the longest common text we stick at the original text,
+ // don't let CTRL-N or CTRL-P move to the first match.
+ bool advance = count != 1 || !allow_get_expansion || !compl_get_longest;
+
+ // When restarting the search don't insert the first match either.
+ if (compl_restarting) {
+ advance = false;
+ compl_restarting = false;
+ }
+
+ // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
+ // around.
+ while (--todo >= 0) {
+ if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL) {
+ compl_shown_match = compl_shown_match->cp_next;
+ found_end = (compl_first_match != NULL
+ && (compl_shown_match->cp_next == compl_first_match
+ || compl_shown_match == compl_first_match));
+ } else if (compl_shows_dir == BACKWARD
+ && compl_shown_match->cp_prev != NULL) {
+ found_end = (compl_shown_match == compl_first_match);
+ compl_shown_match = compl_shown_match->cp_prev;
+ found_end |= (compl_shown_match == compl_first_match);
+ } else {
+ if (!allow_get_expansion) {
+ if (advance) {
+ if (compl_shows_dir == BACKWARD) {
+ compl_pending -= todo + 1;
+ } else {
+ compl_pending += todo + 1;
+ }
+ }
+ return -1;
+ }
+
+ if (!compl_no_select && advance) {
+ if (compl_shows_dir == BACKWARD) {
+ compl_pending--;
+ } else {
+ compl_pending++;
+ }
+ }
+
+ // Find matches.
+ num_matches = ins_compl_get_exp(&compl_startpos);
+
+ // handle any pending completions
+ while (compl_pending != 0 && compl_direction == compl_shows_dir
+ && advance) {
+ if (compl_pending > 0 && compl_shown_match->cp_next != NULL) {
+ compl_shown_match = compl_shown_match->cp_next;
+ compl_pending--;
+ }
+ if (compl_pending < 0 && compl_shown_match->cp_prev != NULL) {
+ compl_shown_match = compl_shown_match->cp_prev;
+ compl_pending++;
+ } else {
+ break;
+ }
+ }
+ found_end = false;
+ }
+ if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
+ && compl_leader != NULL
+ && !ins_compl_equal(compl_shown_match,
+ compl_leader, STRLEN(compl_leader))) {
+ todo++;
+ } else {
+ // Remember a matching item.
+ found_compl = compl_shown_match;
+ }
+
+ // Stop at the end of the list when we found a usable match.
+ if (found_end) {
+ if (found_compl != NULL) {
+ compl_shown_match = found_compl;
+ break;
+ }
+ todo = 1; // use first usable match after wrapping around
+ }
+ }
+
+ // Insert the text of the new completion, or the compl_leader.
+ if (compl_no_insert && !started) {
+ ins_bytes(compl_orig_text + get_compl_len());
+ compl_used_match = false;
+ } else if (insert_match) {
+ if (!compl_get_longest || compl_used_match) {
+ ins_compl_insert(in_compl_func);
+ } else {
+ ins_bytes(compl_leader + get_compl_len());
+ }
+ } else {
+ compl_used_match = false;
+ }
+
+ if (!allow_get_expansion) {
+ // redraw to show the user what was inserted
+ update_screen(0);
+
+ // display the updated popup menu
+ ins_compl_show_pum();
+
+ // Delete old text to be replaced, since we're still searching and
+ // don't want to match ourselves!
+ ins_compl_delete();
+ }
+
+ // Enter will select a match when the match wasn't inserted and the popup
+ // menu is visible.
+ if (compl_no_insert && !started) {
+ compl_enter_selects = true;
+ } else {
+ compl_enter_selects = !insert_match && compl_match_array != NULL;
+ }
+
+ // Show the file name for the match (if any)
+ // Truncate the file name to avoid a wait for return.
+ if (compl_shown_match->cp_fname != NULL) {
+ char *lead = _("match in file");
+ int space = sc_col - vim_strsize(lead) - 2;
+ char *s;
+ char *e;
+
+ if (space > 0) {
+ // We need the tail that fits. With double-byte encoding going
+ // back from the end is very slow, thus go from the start and keep
+ // the text that fits in "space" between "s" and "e".
+ for (s = e = (char *)compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e)) {
+ space -= ptr2cells(e);
+ while (space < 0) {
+ space += ptr2cells(s);
+ MB_PTR_ADV(s);
+ }
+ }
+ msg_hist_off = true;
+ vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
+ (char_u *)s > compl_shown_match->cp_fname ? "<" : "", s);
+ msg((char *)IObuff);
+ msg_hist_off = false;
+ redraw_cmdline = false; // don't overwrite!
+ }
+ }
+
+ return num_matches;
+}
+
+void pum_ext_select_item(int item, bool insert, bool finish)
+{
+ if (!pum_visible() || item < -1 || item >= compl_match_arraysize) {
+ return;
+ }
+ pum_want.active = true;
+ pum_want.item = item;
+ pum_want.insert = insert;
+ pum_want.finish = finish;
+}
+
+/// Call this while finding completions, to check whether the user has hit a key
+/// that should change the currently displayed completion, or exit completion
+/// mode. Also, when compl_pending is not zero, show a completion as soon as
+/// possible. -- webb
+///
+/// @param frequency specifies out of how many calls we actually check.
+/// @param in_compl_func true when called from complete_check(), don't set
+/// compl_curr_match.
+void ins_compl_check_keys(int frequency, bool in_compl_func)
+{
+ static int count = 0;
+
+ // Don't check when reading keys from a script, :normal or feedkeys().
+ // That would break the test scripts. But do check for keys when called
+ // from complete_check().
+ if (!in_compl_func && (using_script() || ex_normal_busy)) {
+ return;
+ }
+
+ // Only do this at regular intervals
+ if (++count < frequency) {
+ return;
+ }
+ count = 0;
+
+ // Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
+ // can't do its work correctly.
+ int c = vpeekc_any();
+ if (c != NUL) {
+ if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) {
+ c = safe_vgetc(); // Eat the character
+ compl_shows_dir = ins_compl_key2dir(c);
+ (void)ins_compl_next(false, ins_compl_key2count(c),
+ c != K_UP && c != K_DOWN, in_compl_func);
+ } else {
+ // Need to get the character to have KeyTyped set. We'll put it
+ // back with vungetc() below. But skip K_IGNORE.
+ c = safe_vgetc();
+ if (c != K_IGNORE) {
+ // Don't interrupt completion when the character wasn't typed,
+ // e.g., when doing @q to replay keys.
+ if (c != Ctrl_R && KeyTyped) {
+ compl_interrupted = true;
+ }
+
+ vungetc(c);
+ }
+ }
+ }
+ if (compl_pending != 0 && !got_int && !compl_no_insert) {
+ int todo = compl_pending > 0 ? compl_pending : -compl_pending;
+
+ compl_pending = 0;
+ (void)ins_compl_next(false, todo, true, in_compl_func);
+ }
+}
+
+/// Decide the direction of Insert mode complete from the key typed.
+/// Returns BACKWARD or FORWARD.
+static int ins_compl_key2dir(int c)
+{
+ if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
+ return pum_want.item < pum_selected_item ? BACKWARD : FORWARD;
+ }
+ if (c == Ctrl_P || c == Ctrl_L
+ || c == K_PAGEUP || c == K_KPAGEUP
+ || c == K_S_UP || c == K_UP) {
+ return BACKWARD;
+ }
+ return FORWARD;
+}
+
+/// Check that "c" is a valid completion key only while the popup menu is shown
+///
+/// @param c character to check
+static bool ins_compl_pum_key(int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
+ || c == K_PAGEDOWN || c == K_KPAGEDOWN
+ || c == K_S_DOWN || c == K_UP || c == K_DOWN);
+}
+
+/// Decide the number of completions to move forward.
+/// Returns 1 for most keys, height of the popup menu for page-up/down keys.
+static int ins_compl_key2count(int c)
+{
+ int h;
+
+ if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
+ int offset = pum_want.item - pum_selected_item;
+ return abs(offset);
+ }
+
+ if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) {
+ h = pum_get_height();
+ if (h > 3) {
+ h -= 2; // keep some context
+ }
+ return h;
+ }
+ return 1;
+}
+
+/// Check that completion with "c" should insert the match, false if only
+/// to change the currently selected completion.
+///
+/// @param c character to check
+static bool ins_compl_use_match(int c)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (c) {
+ case K_UP:
+ case K_DOWN:
+ case K_PAGEDOWN:
+ case K_KPAGEDOWN:
+ case K_S_DOWN:
+ case K_PAGEUP:
+ case K_KPAGEUP:
+ case K_S_UP:
+ return false;
+ case K_EVENT:
+ case K_COMMAND:
+ case K_LUA:
+ return pum_want.active && pum_want.insert;
+ }
+ return true;
+}
+
+/// Get the pattern, column and length for normal completion (CTRL-N CTRL-P
+/// completion)
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+/// Uses the global variables: compl_cont_status and ctrl_x_mode
+static int get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col)
+{
+ if ((compl_cont_status & CONT_SOL) || ctrl_x_mode_path_defines()) {
+ if (!(compl_cont_status & CONT_ADDING)) {
+ while (--startcol >= 0 && vim_isIDc(line[startcol])) {}
+ compl_col += ++startcol;
+ compl_length = curs_col - startcol;
+ }
+ if (p_ic) {
+ compl_pattern = (char *)str_foldcase(line + compl_col, compl_length, NULL, 0);
+ } else {
+ compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length);
+ }
+ } else if (compl_cont_status & CONT_ADDING) {
+ char_u *prefix = (char_u *)"\\<";
+
+ // we need up to 2 extra chars for the prefix
+ compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
+ compl_length) + 2);
+ if (!vim_iswordp(line + compl_col)
+ || (compl_col > 0 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) {
+ prefix = (char_u *)"";
+ }
+ STRCPY(compl_pattern, prefix);
+ (void)quote_meta((char_u *)compl_pattern + STRLEN(prefix),
+ line + compl_col, compl_length);
+ } else if (--startcol < 0
+ || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
+ // Match any word of at least two chars
+ compl_pattern = (char *)vim_strsave((char_u *)"\\<\\k\\k");
+ compl_col += curs_col;
+ compl_length = 0;
+ } else {
+ // Search the point of change class of multibyte character
+ // or not a word single byte character backward.
+ startcol -= utf_head_off(line, line + startcol);
+ int base_class = mb_get_class(line + startcol);
+ while (--startcol >= 0) {
+ int head_off = utf_head_off(line, line + startcol);
+ if (base_class != mb_get_class(line + startcol - head_off)) {
+ break;
+ }
+ startcol -= head_off;
+ }
+ compl_col += ++startcol;
+ compl_length = (int)curs_col - startcol;
+ if (compl_length == 1) {
+ // Only match word with at least two chars -- webb
+ // there's no need to call quote_meta,
+ // xmalloc(7) is enough -- Acevedo
+ compl_pattern = xmalloc(7);
+ STRCPY(compl_pattern, "\\<");
+ (void)quote_meta((char_u *)compl_pattern + 2, line + compl_col, 1);
+ STRCAT(compl_pattern, "\\k");
+ } else {
+ compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
+ compl_length) + 2);
+ STRCPY(compl_pattern, "\\<");
+ (void)quote_meta((char_u *)compl_pattern + 2, line + compl_col, compl_length);
+ }
+ }
+
+ return OK;
+}
+
+/// Get the pattern, column and length for whole line completion or for the
+/// complete() function.
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+static int get_wholeline_compl_info(char_u *line, colnr_T curs_col)
+{
+ compl_col = (colnr_T)getwhitecols(line);
+ compl_length = (int)curs_col - (int)compl_col;
+ if (compl_length < 0) { // cursor in indent: empty pattern
+ compl_length = 0;
+ }
+ if (p_ic) {
+ compl_pattern = (char *)str_foldcase(line + compl_col, compl_length, NULL, 0);
+ } else {
+ compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length);
+ }
+
+ return OK;
+}
+
+/// Get the pattern, column and length for filename completion.
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+static int get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col)
+{
+ // Go back to just before the first filename character.
+ if (startcol > 0) {
+ char_u *p = line + startcol;
+
+ MB_PTR_BACK(line, p);
+ while (p > line && vim_isfilec(utf_ptr2char((char *)p))) {
+ MB_PTR_BACK(line, p);
+ }
+ if (p == line && vim_isfilec(utf_ptr2char((char *)p))) {
+ startcol = 0;
+ } else {
+ startcol = (int)(p - line) + 1;
+ }
+ }
+
+ compl_col += startcol;
+ compl_length = (int)curs_col - startcol;
+ compl_pattern = (char *)addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES);
+
+ return OK;
+}
+
+/// Get the pattern, column and length for command-line completion.
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+static int get_cmdline_compl_info(char_u *line, colnr_T curs_col)
+{
+ compl_pattern = (char *)vim_strnsave(line, (size_t)curs_col);
+ set_cmd_context(&compl_xp, (char_u *)compl_pattern, (int)STRLEN(compl_pattern), curs_col, false);
+ if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
+ || compl_xp.xp_context == EXPAND_NOTHING) {
+ // No completion possible, use an empty pattern to get a
+ // "pattern not found" message.
+ compl_col = curs_col;
+ } else {
+ compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
+ }
+ compl_length = curs_col - compl_col;
+
+ return OK;
+}
+
+/// Get the pattern, column and length for user defined completion ('omnifunc',
+/// 'completefunc' and 'thesaurusfunc')
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+/// Uses the global variable: spell_bad_len
+static int get_userdefined_compl_info(colnr_T curs_col)
+{
+ // Call user defined function 'completefunc' with "a:findstart"
+ // set to 1 to obtain the length of text to use for completion.
+ const int save_State = State;
+
+ // Call 'completefunc' or 'omnifunc' and get pattern length as a string
+ char_u *funcname = get_complete_funcname(ctrl_x_mode);
+ if (*funcname == NUL) {
+ semsg(_(e_notset), ctrl_x_mode_function() ? "completefunc" : "omnifunc");
+ return FAIL;
+ }
+
+ typval_T args[3];
+ args[0].v_type = VAR_NUMBER;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_UNKNOWN;
+ args[0].vval.v_number = 1;
+ args[1].vval.v_string = "";
+
+ pos_T pos = curwin->w_cursor;
+ textlock++;
+ colnr_T col = (colnr_T)call_func_retnr((char *)funcname, 2, args);
+ textlock--;
+
+ State = save_State;
+ curwin->w_cursor = pos; // restore the cursor position
+ validate_cursor();
+ if (!equalpos(curwin->w_cursor, pos)) {
+ emsg(_(e_compldel));
+ return FAIL;
+ }
+
+ // Return value -2 means the user complete function wants to cancel the
+ // complete without an error, do the same if the function did not execute
+ // successfully.
+ if (col == -2 || aborting()) {
+ return FAIL;
+ }
+ // Return value -3 does the same as -2 and leaves CTRL-X mode.
+ if (col == -3) {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ if (!shortmess(SHM_COMPLETIONMENU)) {
+ msg_clr_cmdline();
+ }
+ return FAIL;
+ }
+
+ // Reset extended parameters of completion, when start new
+ // completion.
+ compl_opt_refresh_always = false;
+
+ if (col < 0) {
+ col = curs_col;
+ }
+ compl_col = col;
+ if (compl_col > curs_col) {
+ compl_col = curs_col;
+ }
+
+ // Setup variables for completion. Need to obtain "line" again,
+ // it may have become invalid.
+ char_u *line = ml_get(curwin->w_cursor.lnum);
+ compl_length = curs_col - compl_col;
+ compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length);
+
+ return OK;
+}
+
+/// Get the pattern, column and length for spell completion.
+/// Sets the global variables: compl_col, compl_length and compl_pattern.
+/// Uses the global variable: spell_bad_len
+static int get_spell_compl_info(int startcol, colnr_T curs_col)
+{
+ if (spell_bad_len > 0) {
+ assert(spell_bad_len <= INT_MAX);
+ compl_col = curs_col - (int)spell_bad_len;
+ } else {
+ compl_col = spell_word_start(startcol);
+ }
+ if (compl_col >= (colnr_T)startcol) {
+ compl_length = 0;
+ compl_col = curs_col;
+ } else {
+ spell_expand_check_cap(compl_col);
+ compl_length = (int)curs_col - compl_col;
+ }
+ // Need to obtain "line" again, it may have become invalid.
+ char_u *line = ml_get(curwin->w_cursor.lnum);
+ compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length);
+
+ return OK;
+}
+
+/// Get the completion pattern, column and length.
+static int compl_get_info(char_u *line, int startcol, colnr_T curs_col, bool *line_invalid)
+{
+ if (ctrl_x_mode_normal()
+ || ((ctrl_x_mode & CTRL_X_WANT_IDENT)
+ && !thesaurus_func_complete(ctrl_x_mode))) {
+ return get_normal_compl_info(line, startcol, curs_col);
+ } else if (ctrl_x_mode_line_or_eval()) {
+ return get_wholeline_compl_info(line, curs_col);
+ } else if (ctrl_x_mode_files()) {
+ return get_filename_compl_info(line, startcol, curs_col);
+ } else if (ctrl_x_mode == CTRL_X_CMDLINE) {
+ return get_cmdline_compl_info(line, curs_col);
+ } else if (ctrl_x_mode_function() || ctrl_x_mode_omni()
+ || thesaurus_func_complete(ctrl_x_mode)) {
+ if (get_userdefined_compl_info(curs_col) == FAIL) {
+ return FAIL;
+ }
+ *line_invalid = true; // 'line' may have become invalid
+ } else if (ctrl_x_mode_spell()) {
+ if (get_spell_compl_info(startcol, curs_col) == FAIL) {
+ return FAIL;
+ }
+ *line_invalid = true; // 'line' may have become invalid
+ } else {
+ internal_error("ins_complete()");
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/// Do Insert mode completion.
+/// Called when character "c" was typed, which has a meaning for completion.
+/// Returns OK if completion was done, FAIL if something failed.
+int ins_complete(int c, bool enable_pum)
+{
+ char_u *line;
+ int startcol = 0; // column where searched text starts
+ colnr_T curs_col; // cursor column
+ int n;
+ int save_w_wrow;
+ int save_w_leftcol;
+ int insert_match;
+ const bool save_did_ai = did_ai;
+ int flags = CP_ORIGINAL_TEXT;
+ bool line_invalid = false;
+
+ compl_direction = ins_compl_key2dir(c);
+ insert_match = ins_compl_use_match(c);
+
+ if (!compl_started) {
+ // First time we hit ^N or ^P (in a row, I mean)
+
+ did_ai = false;
+ did_si = false;
+ can_si = false;
+ can_si_back = false;
+ if (stop_arrow() == FAIL) {
+ return FAIL;
+ }
+
+ line = ml_get(curwin->w_cursor.lnum);
+ curs_col = curwin->w_cursor.col;
+ compl_pending = 0;
+
+ // If this same ctrl_x_mode has been interrupted use the text from
+ // "compl_startpos" to the cursor as a pattern to add a new word
+ // instead of expand the one before the cursor, in word-wise if
+ // "compl_startpos" is not in the same line as the cursor then fix it
+ // (the line has been split because it was longer than 'tw'). if SOL
+ // is set then skip the previous pattern, a word at the beginning of
+ // the line has been inserted, we'll look for that -- Acevedo.
+ if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
+ && compl_cont_mode == ctrl_x_mode) {
+ // it is a continued search
+ compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
+ if (ctrl_x_mode_normal()
+ || ctrl_x_mode_path_patterns()
+ || ctrl_x_mode_path_defines()) {
+ if (compl_startpos.lnum != curwin->w_cursor.lnum) {
+ // line (probably) wrapped, set compl_startpos to the
+ // first non_blank in the line, if it is not a wordchar
+ // include it to get a better pattern, but then we don't
+ // want the "\\<" prefix, check it below.
+ compl_col = (colnr_T)getwhitecols(line);
+ compl_startpos.col = compl_col;
+ compl_startpos.lnum = curwin->w_cursor.lnum;
+ compl_cont_status &= ~CONT_SOL; // clear SOL if present
+ } else {
+ // S_IPOS was set when we inserted a word that was at the
+ // beginning of the line, which means that we'll go to SOL
+ // mode but first we need to redefine compl_startpos
+ if (compl_cont_status & CONT_S_IPOS) {
+ compl_cont_status |= CONT_SOL;
+ compl_startpos.col = (colnr_T)((char_u *)skipwhite((char *)line
+ + compl_length
+ + compl_startpos.col) - line);
+ }
+ compl_col = compl_startpos.col;
+ }
+ compl_length = curwin->w_cursor.col - (int)compl_col;
+ // IObuff is used to add a "word from the next line" would we
+ // have enough space? just being paranoid
+#define MIN_SPACE 75
+ if (compl_length > (IOSIZE - MIN_SPACE)) {
+ compl_cont_status &= ~CONT_SOL;
+ compl_length = (IOSIZE - MIN_SPACE);
+ compl_col = curwin->w_cursor.col - compl_length;
+ }
+ compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
+ if (compl_length < 1) {
+ compl_cont_status &= CONT_LOCAL;
+ }
+ } else if (ctrl_x_mode_line_or_eval()) {
+ compl_cont_status = CONT_ADDING | CONT_N_ADDS;
+ } else {
+ compl_cont_status = 0;
+ }
+ } else {
+ compl_cont_status &= CONT_LOCAL;
+ }
+
+ if (!(compl_cont_status & CONT_ADDING)) { // normal expansion
+ compl_cont_mode = ctrl_x_mode;
+ if (ctrl_x_mode_not_default()) {
+ // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
+ compl_cont_status = 0;
+ }
+ compl_cont_status |= CONT_N_ADDS;
+ compl_startpos = curwin->w_cursor;
+ startcol = (int)curs_col;
+ compl_col = 0;
+ }
+
+ // Work out completion pattern and original text -- webb
+ if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL) {
+ if (ctrl_x_mode_function() || ctrl_x_mode_omni()
+ || thesaurus_func_complete(ctrl_x_mode)) {
+ // restore did_ai, so that adding comment leader works
+ did_ai = save_did_ai;
+ }
+ return FAIL;
+ }
+ // If "line" was changed while getting completion info get it again.
+ if (line_invalid) {
+ line = ml_get(curwin->w_cursor.lnum);
+ }
+
+ if (compl_cont_status & CONT_ADDING) {
+ edit_submode_pre = (char_u *)_(" Adding");
+ if (ctrl_x_mode_line_or_eval()) {
+ // Insert a new line, keep indentation but ignore 'comments'.
+ char_u *old = curbuf->b_p_com;
+
+ curbuf->b_p_com = (char_u *)"";
+ compl_startpos.lnum = curwin->w_cursor.lnum;
+ compl_startpos.col = compl_col;
+ ins_eol('\r');
+ curbuf->b_p_com = old;
+ compl_length = 0;
+ compl_col = curwin->w_cursor.col;
+ }
+ } else {
+ edit_submode_pre = NULL;
+ compl_startpos.col = compl_col;
+ }
+
+ if (compl_cont_status & CONT_LOCAL) {
+ edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
+ } else {
+ edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
+ }
+
+ // If any of the original typed text has been changed we need to fix
+ // the redo buffer.
+ ins_compl_fixRedoBufForLeader(NULL);
+
+ // Always add completion for the original text.
+ xfree(compl_orig_text);
+ compl_orig_text = vim_strnsave(line + compl_col, (size_t)compl_length);
+ if (p_ic) {
+ flags |= CP_ICASE;
+ }
+ if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
+ flags, false) != OK) {
+ XFREE_CLEAR(compl_pattern);
+ XFREE_CLEAR(compl_orig_text);
+ return FAIL;
+ }
+
+ // showmode might reset the internal line pointers, so it must
+ // be called before line = ml_get(), or when this address is no
+ // longer needed. -- Acevedo.
+ edit_submode_extra = (char_u *)_("-- Searching...");
+ edit_submode_highl = HLF_COUNT;
+ showmode();
+ edit_submode_extra = NULL;
+ ui_flush();
+ } else if (insert_match && stop_arrow() == FAIL) {
+ return FAIL;
+ }
+
+ compl_shown_match = compl_curr_match;
+ compl_shows_dir = compl_direction;
+
+ // Find next match (and following matches).
+ save_w_wrow = curwin->w_wrow;
+ save_w_leftcol = curwin->w_leftcol;
+ n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
+
+ if (n > 1) { // all matches have been found
+ compl_matches = n;
+ }
+ compl_curr_match = compl_shown_match;
+ compl_direction = compl_shows_dir;
+
+ // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
+ // mode.
+ if (got_int && !global_busy) {
+ (void)vgetc();
+ got_int = false;
+ }
+
+ // we found no match if the list has only the "compl_orig_text"-entry
+ if (compl_first_match == compl_first_match->cp_next) {
+ edit_submode_extra = (compl_cont_status & CONT_ADDING)
+ && compl_length > 1
+ ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
+ edit_submode_highl = HLF_E;
+ // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
+ // because we couldn't expand anything at first place, but if we used
+ // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
+ // (such as M in M'exico) if not tried already. -- Acevedo
+ if (compl_length > 1
+ || (compl_cont_status & CONT_ADDING)
+ || (ctrl_x_mode_not_default()
+ && !ctrl_x_mode_path_patterns()
+ && !ctrl_x_mode_path_defines())) {
+ compl_cont_status &= ~CONT_N_ADDS;
+ }
+ }
+
+ if (compl_curr_match->cp_flags & CP_CONT_S_IPOS) {
+ compl_cont_status |= CONT_S_IPOS;
+ } else {
+ compl_cont_status &= ~CONT_S_IPOS;
+ }
+
+ if (edit_submode_extra == NULL) {
+ if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT) {
+ edit_submode_extra = (char_u *)_("Back at original");
+ edit_submode_highl = HLF_W;
+ } else if (compl_cont_status & CONT_S_IPOS) {
+ edit_submode_extra = (char_u *)_("Word from other line");
+ edit_submode_highl = HLF_COUNT;
+ } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) {
+ edit_submode_extra = (char_u *)_("The only match");
+ edit_submode_highl = HLF_COUNT;
+ compl_curr_match->cp_number = 1;
+ } else {
+ // Update completion sequence number when needed.
+ if (compl_curr_match->cp_number == -1) {
+ ins_compl_update_sequence_numbers();
+ }
+
+ // The match should always have a sequence number now, this is
+ // just a safety check.
+ if (compl_curr_match->cp_number != -1) {
+ // Space for 10 text chars. + 2x10-digit no.s = 31.
+ // Translations may need more than twice that.
+ static char_u match_ref[81];
+
+ if (compl_matches > 0) {
+ vim_snprintf((char *)match_ref, sizeof(match_ref),
+ _("match %d of %d"),
+ compl_curr_match->cp_number, compl_matches);
+ } else {
+ vim_snprintf((char *)match_ref, sizeof(match_ref),
+ _("match %d"),
+ compl_curr_match->cp_number);
+ }
+ edit_submode_extra = match_ref;
+ edit_submode_highl = HLF_R;
+ if (dollar_vcol >= 0) {
+ curs_columns(curwin, false);
+ }
+ }
+ }
+ }
+
+ // Show a message about what (completion) mode we're in.
+ showmode();
+ if (!shortmess(SHM_COMPLETIONMENU)) {
+ if (edit_submode_extra != NULL) {
+ if (!p_smd) {
+ msg_hist_off = true;
+ msg_attr((const char *)edit_submode_extra,
+ (edit_submode_highl < HLF_COUNT
+ ? HL_ATTR(edit_submode_highl) : 0));
+ msg_hist_off = false;
+ }
+ } else {
+ msg_clr_cmdline(); // necessary for "noshowmode"
+ }
+ }
+
+ // Show the popup menu, unless we got interrupted.
+ if (enable_pum && !compl_interrupted) {
+ show_pum(save_w_wrow, save_w_leftcol);
+ }
+ compl_was_interrupted = compl_interrupted;
+ compl_interrupted = false;
+
+ return OK;
+}
+
+static void show_pum(int prev_w_wrow, int prev_w_leftcol)
+{
+ // RedrawingDisabled may be set when invoked through complete().
+ int n = RedrawingDisabled;
+ RedrawingDisabled = 0;
+
+ // If the cursor moved or the display scrolled we need to remove the pum
+ // first.
+ setcursor();
+ if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol) {
+ ins_compl_del_pum();
+ }
+
+ ins_compl_show_pum();
+ setcursor();
+ RedrawingDisabled = n;
+}
+
+// Looks in the first "len" chars. of "src" for search-metachars.
+// If dest is not NULL the chars. are copied there quoting (with
+// a backslash) the metachars, and dest would be NUL terminated.
+// Returns the length (needed) of dest
+static unsigned quote_meta(char_u *dest, char_u *src, int len)
+{
+ unsigned m = (unsigned)len + 1; // one extra for the NUL
+
+ for (; --len >= 0; src++) {
+ switch (*src) {
+ case '.':
+ case '*':
+ case '[':
+ if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus()) {
+ break;
+ }
+ FALLTHROUGH;
+ case '~':
+ if (!p_magic) { // quote these only if magic is set
+ break;
+ }
+ FALLTHROUGH;
+ case '\\':
+ if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus()) {
+ break;
+ }
+ FALLTHROUGH;
+ case '^': // currently it's not needed.
+ case '$':
+ m++;
+ if (dest != NULL) {
+ *dest++ = '\\';
+ }
+ break;
+ }
+ if (dest != NULL) {
+ *dest++ = *src;
+ }
+ // Copy remaining bytes of a multibyte character.
+ const int mb_len = utfc_ptr2len((char *)src) - 1;
+ if (mb_len > 0 && len >= mb_len) {
+ for (int i = 0; i < mb_len; i++) {
+ len--;
+ src++;
+ if (dest != NULL) {
+ *dest++ = *src;
+ }
+ }
+ }
+ }
+ if (dest != NULL) {
+ *dest = NUL;
+ }
+
+ return m;
+}
+
+#if defined(EXITFREE)
+void free_insexpand_stuff(void)
+{
+ XFREE_CLEAR(compl_orig_text);
+}
+#endif
+
+/// Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
+/// spelled word, if there is one.
+static void spell_back_to_badword(void)
+{
+ pos_T tpos = curwin->w_cursor;
+ spell_bad_len = spell_move_to(curwin, BACKWARD, true, true, NULL);
+ if (curwin->w_cursor.col != tpos.col) {
+ start_arrow(&tpos);
+ }
+}
diff --git a/src/nvim/insexpand.h b/src/nvim/insexpand.h
new file mode 100644
index 0000000000..8e183455ca
--- /dev/null
+++ b/src/nvim/insexpand.h
@@ -0,0 +1,17 @@
+#ifndef NVIM_INSEXPAND_H
+#define NVIM_INSEXPAND_H
+
+#include "nvim/vim.h"
+
+/// state for pum_ext_select_item.
+EXTERN struct {
+ bool active;
+ int item;
+ bool insert;
+ bool finish;
+} pum_want;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "insexpand.h.generated.h"
+#endif
+#endif // NVIM_INSEXPAND_H
diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c
index cd3c7316bf..9899f10788 100644
--- a/src/nvim/keycodes.c
+++ b/src/nvim/keycodes.c
@@ -8,7 +8,7 @@
#include "nvim/ascii.h"
#include "nvim/charset.h"
#include "nvim/edit.h"
-#include "nvim/eval.h"
+#include "nvim/eval/vars.h"
#include "nvim/keycodes.h"
#include "nvim/memory.h"
#include "nvim/message.h"
@@ -392,7 +392,7 @@ static struct mousetable {
{ (int)KE_X2DRAG, MOUSE_X2, false, true },
{ (int)KE_X2RELEASE, MOUSE_X2, false, false },
// DRAG without CLICK
- { (int)K_MOUSEMOVE, MOUSE_RELEASE, false, true },
+ { (int)KE_MOUSEMOVE, MOUSE_RELEASE, false, true },
// RELEASE without CLICK
{ (int)KE_IGNORE, MOUSE_RELEASE, false, false },
{ 0, 0, 0, 0 },
diff --git a/src/nvim/keycodes.h b/src/nvim/keycodes.h
index 67ec092f60..943c127325 100644
--- a/src/nvim/keycodes.h
+++ b/src/nvim/keycodes.h
@@ -7,10 +7,8 @@
//
// Any special key code sequences are replaced by these codes.
-//
-// For MS-DOS some keys produce codes larger than 0xff. They are split into two
-// chars, the first one is K_NUL.
-//
+/// For MS-DOS some keys produce codes larger than 0xff. They are split into two
+/// chars, the first one is K_NUL.
#define K_NUL (0xce) // for MS-DOS: special key follows
/// K_SPECIAL is the first byte of a special key code and is always followed by
@@ -59,13 +57,13 @@
#define KS_SELECT 245
#define K_SELECT_STRING (char_u *)"\200\365X"
-// Used a termcap entry that produces a normal character.
+/// Used a termcap entry that produces a normal character.
#define KS_KEY 242
-// Used for click in a tab pages label.
+/// Used for click in a tab pages label.
#define KS_TABLINE 240
-// Used for menu in a tab pages line.
+/// Used for menu in a tab pages line.
#define KS_TABMENU 239
/// Filler used after KS_SPECIAL and others
@@ -89,18 +87,19 @@
#define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \
KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b))
-// Codes for keys that do not have a termcap name.
-// The numbers are fixed to make sure that recorded key sequences remain valid.
-// Add new entries at the end, not halfway.
-//
-// K_SPECIAL KS_EXTRA KE_xxx
-//
-// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL).
+/// Codes for keys that do not have a termcap name.
+/// The numbers are fixed to make sure that recorded key sequences remain valid.
+/// Add new entries at the end, not halfway.
+///
+/// K_SPECIAL KS_EXTRA KE_xxx
+///
+/// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL).
enum key_extra {
KE_S_UP = 4, // shift-up
- KE_S_DOWN = 5, // shift-down
+ KE_S_DOWN = 5, // shift-down
- KE_S_F1 = 6, // shifted function keys
+ // shifted function keys
+ KE_S_F1 = 6,
KE_S_F2 = 7,
KE_S_F3 = 8,
KE_S_F4 = 9,
@@ -141,7 +140,7 @@ enum key_extra {
KE_S_F36 = 41,
KE_S_F37 = 42,
- KE_MOUSE = 43, // mouse event start
+ KE_MOUSE = 43, // mouse event start
// Symbols for pseudo keys which are translated from the real key symbols
// above.
@@ -153,14 +152,14 @@ enum key_extra {
KE_MIDDLERELEASE = 49, // Middle mouse button release
KE_RIGHTMOUSE = 50, // Right mouse button click
KE_RIGHTDRAG = 51, // Drag with right mouse button down
- KE_RIGHTRELEASE = 52, // Right mouse button release
+ KE_RIGHTRELEASE = 52, // Right mouse button release
- KE_IGNORE = 53, // Ignored mouse drag/release
+ KE_IGNORE = 53, // Ignored mouse drag/release
KE_TAB = 54, // unshifted TAB key
- KE_S_TAB_OLD = 55, // shifted TAB key (no longer used)
+ KE_S_TAB_OLD = 55, // shifted TAB key (no longer used)
- // , KE_SNIFF_UNUSED = 56 // obsolete
+ // KE_SNIFF_UNUSED = 56, // obsolete
KE_XF1 = 57, // extra vt100 function keys for xterm
KE_XF2 = 58,
KE_XF3 = 59,
@@ -175,7 +174,7 @@ enum key_extra {
KE_XRIGHT = 68,
KE_LEFTMOUSE_NM = 69, // non-mappable Left mouse button click
- KE_LEFTRELEASE_NM = 70, // non-mappable left mouse button release
+ KE_LEFTRELEASE_NM = 70, // non-mappable left mouse button release
KE_S_XF1 = 71, // vt100 shifted function keys for xterm
KE_S_XF2 = 72,
@@ -188,20 +187,20 @@ enum key_extra {
KE_MOUSEDOWN = 75, // scroll wheel pseudo-button Down
KE_MOUSEUP = 76, // scroll wheel pseudo-button Up
KE_MOUSELEFT = 77, // scroll wheel pseudo-button Left
- KE_MOUSERIGHT = 78, // scroll wheel pseudo-button Right
+ KE_MOUSERIGHT = 78, // scroll wheel pseudo-button Right
KE_KINS = 79, // keypad Insert key
- KE_KDEL = 80, // keypad Delete key
+ KE_KDEL = 80, // keypad Delete key
// KE_CSI = 81, // Nvim doesn't need escaping CSI
KE_SNR = 82, // <SNR>
KE_PLUG = 83, // <Plug>
- KE_CMDWIN = 84, // open command-line window from Command-line Mode
+ KE_CMDWIN = 84, // open command-line window from Command-line Mode
KE_C_LEFT = 85, // control-left
KE_C_RIGHT = 86, // control-right
KE_C_HOME = 87, // control-home
- KE_C_END = 88, // control-end
+ KE_C_END = 88, // control-end
KE_X1MOUSE = 89, // X1/X2 mouse-buttons
KE_X1DRAG = 90,
@@ -210,16 +209,16 @@ enum key_extra {
KE_X2DRAG = 93,
KE_X2RELEASE = 94,
- KE_DROP = 95, // DnD data is available
- // , KE_CURSORHOLD = 96 // CursorHold event
- KE_NOP = 97, // no-op: does nothing
- // , KE_FOCUSGAINED = 98 // focus gained
- // , KE_FOCUSLOST = 99 // focus lost
- KE_MOUSEMOVE = 100, // mouse moved with no button down
- // , KE_CANCEL = 101 // return from vgetc
+ KE_DROP = 95, // DnD data is available
+ // KE_CURSORHOLD = 96, // CursorHold event
+ KE_NOP = 97, // no-op: does nothing
+ // KE_FOCUSGAINED = 98, // focus gained
+ // KE_FOCUSLOST = 99, // focus lost
+ KE_MOUSEMOVE = 100, // mouse moved with no button down
+ // KE_CANCEL = 101, // return from vgetc()
KE_EVENT = 102, // event
- KE_LUA = 103, // lua special key
- KE_COMMAND = 104, // <Cmd> special key
+ KE_LUA = 103, // Lua special key
+ KE_COMMAND = 104, // <Cmd> special key
};
// the three byte codes are replaced with the following int when using vgetc()
@@ -259,7 +258,8 @@ enum key_extra {
#define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT)
#define K_XRIGHT TERMCAP2KEY(KS_EXTRA, KE_XRIGHT)
-#define K_F1 TERMCAP2KEY('k', '1') // function keys
+// function keys
+#define K_F1 TERMCAP2KEY('k', '1')
#define K_F2 TERMCAP2KEY('k', '2')
#define K_F3 TERMCAP2KEY('k', '3')
#define K_F4 TERMCAP2KEY('k', '4')
@@ -490,13 +490,13 @@ enum key_extra {
/// Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and '>').
#define MAX_KEY_NAME_LEN 32
-// Maximum length of a special key event as tokens. This includes modifiers.
-// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
-// following string of tokens:
-//
-// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>.
-//
-// This is a total of 6 tokens, and is currently the longest one possible.
+/// Maximum length of a special key event as tokens. This includes modifiers.
+/// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
+/// following string of tokens:
+///
+/// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>.
+///
+/// This is a total of 6 tokens, and is currently the longest one possible.
#define MAX_KEY_CODE_LEN 6
#define FLAG_CPO_BSLASH 0x01
@@ -504,7 +504,7 @@ enum key_extra {
? 0 \
: FLAG_CPO_BSLASH)
-// Flags for replace_termcodes()
+/// Flags for replace_termcodes()
enum {
REPTERM_FROM_PART = 1,
REPTERM_DO_LT = 2,
@@ -512,7 +512,7 @@ enum {
REPTERM_NO_SIMPLIFY = 8,
};
-// Flags for find_special_key()
+/// Flags for find_special_key()
enum {
FSK_KEYCODE = 0x01, ///< prefer key code, e.g. K_DEL in place of DEL
FSK_KEEP_X_KEY = 0x02, ///< don’t translate xHome to Home key
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 57c7c4758b..99b17a612b 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -310,7 +310,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
const char *parent = path_tail(os_getenv(ENV_NVIM));
// Servername. Empty until starting=false.
const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER));
- if (parent && parent[0] != NUL) {
+ if (parent[0] != NUL) {
snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child.
} else if (serv[0] != NUL) {
snprintf(name, sizeof(name), "%s", serv);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index ad03ebd1ed..17157ccdc2 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -15,6 +15,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/change.h"
#include "nvim/cursor.h"
+#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/event/loop.h"
@@ -416,9 +417,9 @@ static int nlua_wait(lua_State *lstate)
LOOP_PROCESS_EVENTS_UNTIL(&main_loop,
loop_events,
(int)timeout,
- is_function ? nlua_wait_condition(lstate,
- &pcall_status,
- &callback_result) : false || got_int);
+ got_int || (is_function ? nlua_wait_condition(lstate,
+ &pcall_status,
+ &callback_result) : false));
// Stop dummy timer
time_watcher_stop(tw);
@@ -1673,7 +1674,7 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "_ts_get_minimum_language_version");
}
-int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char_u ***results)
+int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results)
{
lua_State *const lstate = global_lstate;
int ret = OK;
@@ -1685,7 +1686,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char_u ***resul
lua_getfield(lstate, -1, "_expand_pat");
luaL_checktype(lstate, -1, LUA_TFUNCTION);
- // [ vim, vim._on_key, buf ]
+ // [ vim, vim._expand_pat, buf ]
lua_pushlstring(lstate, (const char *)pat, STRLEN(pat));
if (nlua_pcall(lstate, 1, 2) != 0) {
@@ -1838,7 +1839,7 @@ void nlua_execute_on_key(int c)
// [ vim ]
lua_getglobal(lstate, "vim");
- // [ vim, vim._on_key]
+ // [ vim, vim._on_key ]
lua_getfield(lstate, -1, "_on_key");
luaL_checktype(lstate, -1, LUA_TFUNCTION);
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 8fde85b163..6ba0056f48 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -232,7 +232,7 @@ static int nlua_str_utf_start(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int head_offset = mb_head_off((char_u *)s1, (char_u *)s1 + offset - 1);
+ int head_offset = utf_cp_head_off((char_u *)s1, (char_u *)s1 + offset - 1);
lua_pushinteger(lstate, head_offset);
return 1;
}
@@ -252,7 +252,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int tail_offset = mb_tail_off(s1, s1 + offset - 1);
+ int tail_offset = utf_cp_tail_off(s1, s1 + offset - 1);
lua_pushinteger(lstate, tail_offset);
return 1;
}
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index b96193d199..f0d847e352 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -11,6 +11,7 @@
#include <lua.h>
#include <lualib.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -208,31 +209,32 @@ int tslua_inspect_lang(lua_State *L)
lua_createtable(L, 0, 2); // [retval]
- size_t nsymbols = (size_t)ts_language_symbol_count(lang);
+ uint32_t nsymbols = ts_language_symbol_count(lang);
+ assert(nsymbols < INT_MAX);
- lua_createtable(L, nsymbols - 1, 1); // [retval, symbols]
- for (size_t i = 0; i < nsymbols; i++) {
- TSSymbolType t = ts_language_symbol_type(lang, i);
+ lua_createtable(L, (int)(nsymbols - 1), 1); // [retval, symbols]
+ for (uint32_t i = 0; i < nsymbols; i++) {
+ TSSymbolType t = ts_language_symbol_type(lang, (TSSymbol)i);
if (t == TSSymbolTypeAuxiliary) {
// not used by the API
continue;
}
lua_createtable(L, 2, 0); // [retval, symbols, elem]
- lua_pushstring(L, ts_language_symbol_name(lang, i));
+ lua_pushstring(L, ts_language_symbol_name(lang, (TSSymbol)i));
lua_rawseti(L, -2, 1);
lua_pushboolean(L, t == TSSymbolTypeRegular);
lua_rawseti(L, -2, 2); // [retval, symbols, elem]
- lua_rawseti(L, -2, i); // [retval, symbols]
+ lua_rawseti(L, -2, (int)i); // [retval, symbols]
}
lua_setfield(L, -2, "symbols"); // [retval]
- size_t nfields = (size_t)ts_language_field_count(lang);
- lua_createtable(L, nfields, 1); // [retval, fields]
+ uint32_t nfields = ts_language_field_count(lang);
+ lua_createtable(L, (int)nfields, 1); // [retval, fields]
// Field IDs go from 1 to nfields inclusive (extra index 0 maps to NULL)
- for (size_t i = 1; i <= nfields; i++) {
- lua_pushstring(L, ts_language_field_name_for_id(lang, i));
- lua_rawseti(L, -2, i); // [retval, fields]
+ for (uint32_t i = 1; i <= nfields; i++) {
+ lua_pushstring(L, ts_language_field_name_for_id(lang, (TSFieldId)i));
+ lua_rawseti(L, -2, (int)i); // [retval, fields]
}
lua_setfield(L, -2, "fields"); // [retval]
@@ -300,7 +302,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
*bytes_read = 0;
return "";
}
- char_u *line = ml_get_buf(bp, position.row + 1, false);
+ char *line = (char *)ml_get_buf(bp, (linenr_T)position.row + 1, false);
size_t len = STRLEN(line);
if (position.column > len) {
*bytes_read = 0;
@@ -322,9 +324,9 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
#undef BUFSIZE
}
-static void push_ranges(lua_State *L, const TSRange *ranges, const unsigned int length)
+static void push_ranges(lua_State *L, const TSRange *ranges, const size_t length)
{
- lua_createtable(L, length, 0);
+ lua_createtable(L, (int)length, 0);
for (size_t i = 0; i < length; i++) {
lua_createtable(L, 4, 0);
lua_pushinteger(L, ranges[i].start_point.row);
@@ -336,7 +338,7 @@ static void push_ranges(lua_State *L, const TSRange *ranges, const unsigned int
lua_pushinteger(L, ranges[i].end_point.column);
lua_rawseti(L, -2, 4);
- lua_rawseti(L, -2, i + 1);
+ lua_rawseti(L, -2, (int)(i + 1));
}
}
@@ -365,15 +367,19 @@ static int parser_parse(lua_State *L)
switch (lua_type(L, 3)) {
case LUA_TSTRING:
str = lua_tolstring(L, 3, &len);
- new_tree = ts_parser_parse_string(*p, old_tree, str, len);
+ new_tree = ts_parser_parse_string(*p, old_tree, str, (uint32_t)len);
break;
case LUA_TNUMBER:
bufnr = lua_tointeger(L, 3);
- buf = handle_get_buffer(bufnr);
+ buf = handle_get_buffer((handle_T)bufnr);
if (!buf) {
- return luaL_error(L, "invalid buffer handle: %d", bufnr);
+#define BUFSIZE 256
+ char ebuf[BUFSIZE] = { 0 };
+ vim_snprintf(ebuf, BUFSIZE, "invalid buffer handle: %ld", bufnr);
+ return luaL_argerror(L, 3, ebuf);
+#undef BUFSIZE
}
input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
@@ -382,7 +388,7 @@ static int parser_parse(lua_State *L)
break;
default:
- return luaL_error(L, "invalid argument to parser:parse()");
+ return luaL_argerror(L, 3, "expected either string or buffer handle");
}
// Sometimes parsing fails (timeout, or wrong parser ABI)
@@ -429,12 +435,12 @@ static int tree_edit(lua_State *L)
return 0;
}
- long start_byte = lua_tointeger(L, 2);
- long old_end_byte = lua_tointeger(L, 3);
- long new_end_byte = lua_tointeger(L, 4);
- TSPoint start_point = { lua_tointeger(L, 5), lua_tointeger(L, 6) };
- TSPoint old_end_point = { lua_tointeger(L, 7), lua_tointeger(L, 8) };
- TSPoint new_end_point = { lua_tointeger(L, 9), lua_tointeger(L, 10) };
+ uint32_t start_byte = (uint32_t)luaL_checkint(L, 2);
+ uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3);
+ uint32_t new_end_byte = (uint32_t)luaL_checkint(L, 4);
+ TSPoint start_point = { (uint32_t)luaL_checkint(L, 5), (uint32_t)luaL_checkint(L, 6) };
+ TSPoint old_end_point = { (uint32_t)luaL_checkint(L, 7), (uint32_t)luaL_checkint(L, 8) };
+ TSPoint new_end_point = { (uint32_t)luaL_checkint(L, 9), (uint32_t)luaL_checkint(L, 10) };
TSInputEdit edit = { start_byte, old_end_byte, new_end_byte,
start_point, old_end_point, new_end_point };
@@ -456,29 +462,28 @@ static void range_from_lua(lua_State *L, TSRange *range)
goto error;
}
- uint32_t start_row, start_col, start_byte, end_row, end_col, end_byte;
lua_rawgeti(L, -1, 1); // [ range, start_row]
- start_row = luaL_checkinteger(L, -1);
+ uint32_t start_row = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 2); // [ range, start_col]
- start_col = luaL_checkinteger(L, -1);
+ uint32_t start_col = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 3); // [ range, start_byte]
- start_byte = luaL_checkinteger(L, -1);
+ uint32_t start_byte = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 4); // [ range, end_row]
- end_row = luaL_checkinteger(L, -1);
+ uint32_t end_row = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 5); // [ range, end_col]
- end_col = luaL_checkinteger(L, -1);
+ uint32_t end_col = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, -1, 6); // [ range, end_byte]
- end_byte = luaL_checkinteger(L, -1);
+ uint32_t end_byte = (uint32_t)luaL_checkinteger(L, -1);
lua_pop(L, 1); // [ range ]
*range = (TSRange) {
@@ -531,13 +536,13 @@ static int parser_set_ranges(lua_State *L)
// [ parser, ranges ]
for (size_t index = 0; index < tbl_len; index++) {
- lua_rawgeti(L, 2, index + 1); // [ parser, ranges, range ]
+ lua_rawgeti(L, 2, (int)index + 1); // [ parser, ranges, range ]
range_from_lua(L, ranges + index);
lua_pop(L, 1);
}
// This memcpies ranges, thus we can free it afterwards
- ts_parser_set_included_ranges(*p, ranges, tbl_len);
+ ts_parser_set_included_ranges(*p, ranges, (uint32_t)tbl_len);
xfree(ranges);
return 0;
@@ -550,7 +555,7 @@ static int parser_get_ranges(lua_State *L)
return 0;
}
- unsigned int len;
+ uint32_t len;
const TSRange *ranges = ts_parser_included_ranges(*p, &len);
push_ranges(L, ranges, len);
@@ -793,7 +798,7 @@ static int node_field(lua_State *L)
TSTreeCursor cursor = ts_tree_cursor_new(node);
lua_newtable(L); // [table]
- unsigned int curr_index = 0;
+ size_t curr_index = 0;
if (ts_tree_cursor_goto_first_child(&cursor)) {
do {
@@ -801,7 +806,7 @@ static int node_field(lua_State *L)
if (current_field != NULL && !STRCMP(field_name, current_field)) {
push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node]
- lua_rawseti(L, -2, ++curr_index);
+ lua_rawseti(L, -2, (int)++curr_index);
}
} while (ts_tree_cursor_goto_next_sibling(&cursor));
}
@@ -1036,7 +1041,7 @@ static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx)
{
for (int i = 0; i < match->capture_count; i++) {
push_node(L, match->captures[i].node, nodeidx);
- lua_rawseti(L, -2, match->captures[i].index + 1);
+ lua_rawseti(L, -2, (int)match->captures[i].index + 1);
}
}
@@ -1049,7 +1054,7 @@ static int query_next_match(lua_State *L)
TSQueryMatch match;
if (ts_query_cursor_next_match(cursor, &match)) {
lua_pushinteger(L, match.pattern_index + 1); // [index]
- lua_createtable(L, ts_query_capture_count(query), 2); // [index, match]
+ lua_createtable(L, (int)ts_query_capture_count(query), 2); // [index, match]
set_match(L, &match, lua_upvalueindex(2));
return 2;
}
@@ -1070,7 +1075,7 @@ static int query_next_capture(lua_State *L)
bool active = lua_toboolean(L, -1);
lua_pop(L, 1);
if (!active) {
- ts_query_cursor_remove_match(cursor, ud->predicated_match);
+ ts_query_cursor_remove_match(cursor, (uint32_t)ud->predicated_match);
}
ud->predicated_match = -1;
}
@@ -1080,6 +1085,7 @@ static int query_next_capture(lua_State *L)
if (ts_query_cursor_next_capture(cursor, &match, &capture_index)) {
TSQueryCapture capture = match.captures[capture_index];
+ // TODO(vigoux): handle capture quantifiers here
lua_pushinteger(L, capture.index + 1); // [index]
push_node(L, capture.node, lua_upvalueindex(2)); // [index, node]
@@ -1088,7 +1094,7 @@ static int query_next_capture(lua_State *L)
ts_query_predicates_for_pattern(query, match.pattern_index, &n_pred);
if (n_pred > 0 && (ud->max_match_id < (int)match.id)) {
- ud->max_match_id = match.id;
+ ud->max_match_id = (int)match.id;
lua_pushvalue(L, lua_upvalueindex(4)); // [index, node, match]
set_match(L, &match, lua_upvalueindex(2));
@@ -1096,7 +1102,7 @@ static int query_next_capture(lua_State *L)
lua_setfield(L, -2, "pattern");
if (match.capture_count > 1) {
- ud->predicated_match = match.id;
+ ud->predicated_match = (int)match.id;
lua_pushboolean(L, false);
lua_setfield(L, -2, "active");
}
@@ -1131,10 +1137,9 @@ static int node_rawquery(lua_State *L)
bool captures = lua_toboolean(L, 3);
if (lua_gettop(L) >= 4) {
- int start = luaL_checkinteger(L, 4);
- int end = lua_gettop(L) >= 5 ? luaL_checkinteger(L, 5) : MAXLNUM;
- ts_query_cursor_set_point_range(cursor,
- (TSPoint){ start, 0 }, (TSPoint){ end, 0 });
+ uint32_t start = (uint32_t)luaL_checkinteger(L, 4);
+ uint32_t end = lua_gettop(L) >= 5 ? (uint32_t)luaL_checkinteger(L, 5) : MAXLNUM;
+ ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 });
}
TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata]
@@ -1151,7 +1156,7 @@ static int node_rawquery(lua_State *L)
if (captures) {
// placeholder for match state
- lua_createtable(L, ts_query_capture_count(query), 2); // [u, n, q, match]
+ lua_createtable(L, (int)ts_query_capture_count(query), 2); // [u, n, q, match]
lua_pushcclosure(L, query_next_capture, 4); // [closure]
} else {
lua_pushcclosure(L, query_next_match, 3); // [closure]
@@ -1187,7 +1192,7 @@ int tslua_parse_query(lua_State *L)
uint32_t error_offset;
TSQueryError error_type;
- TSQuery *query = ts_query_new(lang, src, len, &error_offset, &error_type);
+ TSQuery *query = ts_query_new(lang, src, (uint32_t)len, &error_offset, &error_type);
if (!query) {
return luaL_error(L, "query: %s at position %d",
@@ -1212,6 +1217,8 @@ static const char *query_err_string(TSQueryError err)
return "invalid field";
case TSQueryErrorCapture:
return "invalid capture";
+ case TSQueryErrorStructure:
+ return "invalid structure";
default:
return "error";
}
@@ -1249,15 +1256,14 @@ static int query_inspect(lua_State *L)
uint32_t n_pat = ts_query_pattern_count(query);
lua_createtable(L, 0, 2); // [retval]
- lua_createtable(L, n_pat, 1); // [retval, patterns]
+ lua_createtable(L, (int)n_pat, 1); // [retval, patterns]
for (size_t i = 0; i < n_pat; i++) {
uint32_t len;
- const TSQueryPredicateStep *step = ts_query_predicates_for_pattern(query,
- i, &len);
+ const TSQueryPredicateStep *step = ts_query_predicates_for_pattern(query, (uint32_t)i, &len);
if (len == 0) {
continue;
}
- lua_createtable(L, len/4, 1); // [retval, patterns, pat]
+ lua_createtable(L, (int)len/4, 1); // [retval, patterns, pat]
lua_createtable(L, 3, 0); // [retval, patterns, pat, pred]
int nextpred = 1;
int nextitem = 1;
@@ -1283,17 +1289,17 @@ static int query_inspect(lua_State *L)
}
// last predicate should have ended with TypeDone
lua_pop(L, 1); // [retval, patters, pat]
- lua_rawseti(L, -2, i + 1); // [retval, patterns]
+ lua_rawseti(L, -2, (int)i + 1); // [retval, patterns]
}
lua_setfield(L, -2, "patterns"); // [retval]
uint32_t n_captures = ts_query_capture_count(query);
- lua_createtable(L, n_captures, 0); // [retval, captures]
+ lua_createtable(L, (int)n_captures, 0); // [retval, captures]
for (size_t i = 0; i < n_captures; i++) {
uint32_t strlen;
- const char *str = ts_query_capture_name_for_id(query, i, &strlen);
+ const char *str = ts_query_capture_name_for_id(query, (uint32_t)i, &strlen);
lua_pushlstring(L, str, strlen); // [retval, captures, capture]
- lua_rawseti(L, -2, i + 1);
+ lua_rawseti(L, -2, (int)i + 1);
}
lua_setfield(L, -2, "captures"); // [retval]
diff --git a/src/nvim/main.c b/src/nvim/main.c
index b06b9630e2..494ff0b4af 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -28,6 +28,7 @@
#include "nvim/highlight_group.h"
#include "nvim/iconv.h"
#include "nvim/if_cscope.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mapping.h"
@@ -202,7 +203,6 @@ void early_init(mparm_T *paramp)
set_lang_var(); // set v:lang and v:ctype
init_signs();
- ui_comp_syn_init();
}
#ifdef MAKE_LIB
@@ -320,6 +320,7 @@ int main(int argc, char **argv)
no_wait_return = true;
init_highlight(true, false); // Default highlight groups.
+ ui_comp_syn_init();
TIME_MSG("init highlight");
// Set the break level after the terminal is initialized.
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 5a11ac686e..1797bb0365 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -235,7 +235,7 @@ static void showmap(mapblock_T *mp, bool local)
/// @param[in] orig_lhs Original mapping LHS, with characters to replace.
/// @param[in] orig_lhs_len `strlen` of orig_lhs.
/// @param[in] orig_rhs Original mapping RHS, with characters to replace.
-/// @param[in] rhs_lua Lua reference for Lua maps.
+/// @param[in] rhs_lua Lua reference for Lua mappings.
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
/// @param[out] mapargs MapArguments struct holding the replaced strings.
@@ -428,6 +428,66 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma
return 0;
}
+/// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", "replace_keycodes" and
+/// and "desc" fields are used.
+/// "rhs", "rhs_lua", "orig_rhs" fields are cleared if "simplified" is false.
+/// @param sid -1 to use current_sctx
+static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char_u *keys,
+ MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid,
+ linenr_T lnum, bool simplified)
+{
+ mapblock_T *mp = xcalloc(1, sizeof(mapblock_T));
+
+ // If CTRL-C has been mapped, don't always use it for Interrupting.
+ if (*keys == Ctrl_C) {
+ if (map_table == buf->b_maphash) {
+ buf->b_mapped_ctrl_c |= mode;
+ } else {
+ mapped_ctrl_c |= mode;
+ }
+ }
+
+ mp->m_keys = vim_strsave(keys);
+ mp->m_str = args->rhs;
+ mp->m_orig_str = args->orig_rhs;
+ mp->m_luaref = args->rhs_lua;
+ if (!simplified) {
+ args->rhs = NULL;
+ args->orig_rhs = NULL;
+ args->rhs_lua = LUA_NOREF;
+ }
+ mp->m_keylen = (int)STRLEN(mp->m_keys);
+ mp->m_noremap = noremap;
+ mp->m_nowait = args->nowait;
+ mp->m_silent = args->silent;
+ mp->m_mode = mode;
+ mp->m_simplified = simplified;
+ mp->m_expr = args->expr;
+ mp->m_replace_keycodes = args->replace_keycodes;
+ if (sid >= 0) {
+ mp->m_script_ctx.sc_sid = sid;
+ mp->m_script_ctx.sc_lnum = lnum;
+ } else {
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&mp->m_script_ctx);
+ }
+ mp->m_desc = NULL;
+ if (args->desc != NULL) {
+ mp->m_desc = xstrdup(args->desc);
+ }
+
+ // add the new entry in front of the abbrlist or maphash[] list
+ if (is_abbr) {
+ mp->m_next = *abbr_table;
+ *abbr_table = mp;
+ } else {
+ const int n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ mp->m_next = map_table[n];
+ map_table[n] = mp;
+ }
+}
+
/// Sets or removes a mapping or abbreviation in buffer `buf`.
///
/// @param maptype @see do_map
@@ -452,7 +512,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
abbr_table = &first_abbr;
// For ":noremap" don't remap, otherwise do remap.
- if (maptype == 2) {
+ if (maptype == MAPTYPE_NOREMAP) {
noremap = REMAP_NONE;
} else {
noremap = REMAP_YES;
@@ -470,10 +530,10 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
const bool has_lhs = (args->lhs[0] != NUL);
const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
- const bool do_print = !has_lhs || (maptype != 1 && !has_rhs);
+ const bool do_print = !has_lhs || (maptype != MAPTYPE_UNMAP && !has_rhs);
// check for :unmap without argument
- if (maptype == 1 && !has_lhs) {
+ if (maptype == MAPTYPE_UNMAP && !has_lhs) {
retval = 1;
goto theend;
}
@@ -507,13 +567,11 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
goto theend;
}
- if (is_abbrev && maptype != 1) {
- //
+ if (is_abbrev && maptype != MAPTYPE_UNMAP) {
// If an abbreviation ends in a keyword character, the
// rest must be all keyword-char or all non-keyword-char.
// Otherwise we won't be able to find the start of it in a
// vi-compatible way.
- //
int same = -1;
const int first = vim_iswordp(lhs);
@@ -551,7 +609,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// Check if a new local mapping wasn't already defined globally.
- if (args->unique && map_table == buf->b_maphash && has_lhs && has_rhs && maptype != 1) {
+ if (args->unique && map_table == buf->b_maphash && has_lhs && has_rhs
+ && maptype != MAPTYPE_UNMAP) {
// need to loop over all global hash lists
for (int hash = 0; hash < 256 && !got_int; hash++) {
if (is_abbrev) {
@@ -581,7 +640,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// When listing global mappings, also list buffer-local ones here.
- if (map_table != buf->b_maphash && !has_rhs && maptype != 1) {
+ if (map_table != buf->b_maphash && !has_rhs && maptype != MAPTYPE_UNMAP) {
// need to loop over all global hash lists
for (int hash = 0; hash < 256 && !got_int; hash++) {
if (is_abbrev) {
@@ -616,7 +675,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
// entry with a matching 'to' part. This was done to allow ":ab foo bar"
// to be unmapped by typing ":unab foo", where "foo" will be replaced by
// "bar" because of the abbreviation.
- for (int round = 0; (round == 0 || maptype == 1) && round <= 1
+ for (int round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
&& !did_it && !got_int; round++) {
int hash_start, hash_end;
if (has_lhs || is_abbrev) {
@@ -650,7 +709,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
p = mp->m_keys;
}
if (STRNCMP(p, lhs, (size_t)(n < len ? n : len)) == 0) {
- if (maptype == 1) {
+ if (maptype == MAPTYPE_UNMAP) {
// Delete entry.
// Only accept a full match. For abbreviations
// we ignore trailing space when matching with
@@ -715,6 +774,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
mp->m_mode = mode;
mp->m_simplified = keyround1_simplified;
mp->m_expr = args->expr;
+ mp->m_replace_keycodes = args->replace_keycodes;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
nlua_set_sctx(&mp->m_script_ctx);
@@ -745,7 +805,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
}
- if (maptype == 1) {
+ if (maptype == MAPTYPE_UNMAP) {
// delete entry
if (!did_it) {
if (!keyround1_simplified) {
@@ -779,50 +839,10 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
}
// Get here when adding a new entry to the maphash[] list or abbrlist.
- mp = xmalloc(sizeof(mapblock_T));
-
- // If CTRL-C has been mapped, don't always use it for Interrupting.
- if (*lhs == Ctrl_C) {
- if (map_table == buf->b_maphash) {
- buf->b_mapped_ctrl_c |= mode;
- } else {
- mapped_ctrl_c |= mode;
- }
- }
-
- mp->m_keys = vim_strsave(lhs);
- mp->m_str = args->rhs;
- mp->m_orig_str = args->orig_rhs;
- mp->m_luaref = args->rhs_lua;
- if (!keyround1_simplified) {
- args->rhs = NULL;
- args->orig_rhs = NULL;
- args->rhs_lua = LUA_NOREF;
- }
- mp->m_keylen = (int)STRLEN(mp->m_keys);
- mp->m_noremap = noremap;
- mp->m_nowait = args->nowait;
- mp->m_silent = args->silent;
- mp->m_mode = mode;
- mp->m_simplified = keyround1_simplified; // Notice this when porting patch 8.2.0807
- mp->m_expr = args->expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&mp->m_script_ctx);
- mp->m_desc = NULL;
- if (args->desc != NULL) {
- mp->m_desc = xstrdup(args->desc);
- }
-
- // add the new entry in front of the abbrlist or maphash[] list
- if (is_abbrev) {
- mp->m_next = *abbr_table;
- *abbr_table = mp;
- } else {
- n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
- mp->m_next = map_table[n];
- map_table[n] = mp;
- }
+ map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev,
+ -1, // sid
+ 0, // lnum
+ keyround1_simplified);
}
theend:
@@ -861,7 +881,9 @@ theend:
/// for :cabbr mode is MODE_CMDLINE
/// ```
///
-/// @param maptype 0 for |:map|, 1 for |:unmap|, 2 for |noremap|.
+/// @param maptype MAPTYPE_MAP for |:map|
+/// MAPTYPE_UNMAP for |:unmap|
+/// MAPTYPE_NOREMAP for |noremap|.
/// @param arg C-string containing the arguments of the map/abbrev
/// command, i.e. everything except the initial `:[X][nore]map`.
/// - Cannot be a read-only string; it will be modified.
@@ -878,7 +900,7 @@ theend:
int do_map(int maptype, char_u *arg, int mode, bool is_abbrev)
{
MapArguments parsed_args;
- int result = str_to_mapargs(arg, maptype == 1, &parsed_args);
+ int result = str_to_mapargs(arg, maptype == MAPTYPE_UNMAP, &parsed_args);
switch (result) {
case 0:
break;
@@ -1230,7 +1252,7 @@ char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, bool forc
/// Find all mapping/abbreviation names that match regexp "regmatch".
/// For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
/// @return OK if matches found, FAIL otherwise.
-int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
+int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file)
{
mapblock_T *mp;
int hash;
@@ -1270,7 +1292,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
if (round == 1) {
count++;
} else {
- (*file)[count++] = vim_strsave(p);
+ (*file)[count++] = (char *)vim_strsave(p);
}
}
}
@@ -1293,7 +1315,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
if (round == 1) {
count++;
} else {
- (*file)[count++] = p;
+ (*file)[count++] = (char *)p;
p = NULL;
}
}
@@ -1307,22 +1329,18 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
}
if (round == 1) {
- *file = (char_u **)xmalloc((size_t)count * sizeof(char_u *));
+ *file = xmalloc((size_t)count * sizeof(char_u *));
}
} // for (round)
if (count > 1) {
- char_u **ptr1;
- char_u **ptr2;
- char_u **ptr3;
-
// Sort the matches
sort_strings(*file, count);
// Remove multiple entries
- ptr1 = *file;
- ptr2 = ptr1 + 1;
- ptr3 = ptr1 + count;
+ char **ptr1 = *file;
+ char **ptr2 = ptr1 + 1;
+ char **ptr3 = ptr1 + count;
while (ptr2 < ptr3) {
if (STRCMP(*ptr1, *ptr2)) {
@@ -1517,12 +1535,8 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
/// @param c NUL or typed character for abbreviation
char_u *eval_map_expr(mapblock_T *mp, int c)
{
- char_u *res;
char_u *p = NULL;
char_u *expr = NULL;
- pos_T save_cursor;
- int save_msg_col;
- int save_msg_row;
// Remove escaping of K_SPECIAL, because "str" is in a format to be used as
// typeahead.
@@ -1536,9 +1550,9 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
textlock++;
ex_normal_lock++;
set_vim_var_char(c); // set v:char to the typed character
- save_cursor = curwin->w_cursor;
- save_msg_col = msg_col;
- save_msg_row = msg_row;
+ const pos_T save_cursor = curwin->w_cursor;
+ const int save_msg_col = msg_col;
+ const int save_msg_row = msg_row;
if (mp->m_luaref != LUA_NOREF) {
Error err = ERROR_INIT;
Array args = ARRAY_DICT_INIT;
@@ -1564,8 +1578,15 @@ char_u *eval_map_expr(mapblock_T *mp, int c)
if (p == NULL) {
return NULL;
}
- // Escape K_SPECIAL in the result to be able to use the string as typeahead.
- res = (char_u *)vim_strsave_escape_ks((char *)p);
+
+ char_u *res = NULL;
+
+ if (mp->m_replace_keycodes) {
+ replace_termcodes((char *)p, STRLEN(p), (char **)&res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
+ } else {
+ // Escape K_SPECIAL in the result to be able to use the string as typeahead.
+ res = (char_u *)vim_strsave_escape_ks((char *)p);
+ }
xfree(p);
return res;
@@ -1612,7 +1633,7 @@ int makemap(FILE *fd, buf_T *buf)
continue;
}
- // skip lua mappings and mappings that contain a <SNR> (script-local thing),
+ // skip Lua mappings and mappings that contain a <SNR> (script-local thing),
// they probably don't work when loaded again
if (mp->m_luaref != LUA_NOREF) {
continue;
@@ -1973,9 +1994,9 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// @param mp The maphash that contains the mapping information
/// @param buffer_value The "buffer" value
/// @param compatible True for compatible with old maparg() dict
-static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buffer_value,
- bool compatible)
- FUNC_ATTR_NONNULL_ALL
+static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp,
+ const char *lhsrawalt, long buffer_value, bool compatible)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
char *const lhs = str2special_save((const char *)mp->m_keys,
compatible, !compatible);
@@ -2007,6 +2028,11 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, l
tv_dict_add_allocated_str(dict, S_LEN("desc"), xstrdup(mp->m_desc));
}
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
+ tv_dict_add_str(dict, S_LEN("lhsraw"), (const char *)mp->m_keys);
+ if (lhsrawalt != NULL) {
+ // Also add the value for the simplified entry.
+ tv_dict_add_str(dict, S_LEN("lhsrawalt"), lhsrawalt);
+ }
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
tv_dict_add_nr(dict, S_LEN("script"), mp->m_noremap == REMAP_SCRIPT ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
@@ -2015,23 +2041,14 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, l
tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)mp->m_script_ctx.sc_lnum);
tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value);
tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
+ if (mp->m_replace_keycodes) {
+ tv_dict_add_nr(dict, S_LEN("replace_keycodes"), 1);
+ }
tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
}
static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
{
- char *keys_buf = NULL;
- char_u *alt_keys_buf = NULL;
- bool did_simplify = false;
- char_u *rhs;
- LuaRef rhs_lua;
- int mode;
- bool abbr = false;
- bool get_dict = false;
- mapblock_T *mp;
- int buffer_local;
- int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
-
// Return empty string for failure.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -2041,8 +2058,11 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
return;
}
- char buf[NUMBUFLEN];
const char *which;
+ char buf[NUMBUFLEN];
+ bool abbr = false;
+ bool get_dict = false;
+
if (argvars[1].v_type != VAR_UNKNOWN) {
which = tv_get_string_buf_chk(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -2058,13 +2078,19 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
return;
}
- mode = get_map_mode((char **)&which, 0);
+ char *keys_buf = NULL;
+ char_u *alt_keys_buf = NULL;
+ bool did_simplify = false;
+ const int flags = REPTERM_FROM_PART | REPTERM_DO_LT;
+ const int mode = get_map_mode((char **)&which, 0);
char_u *keys_simplified
- = (char_u *)replace_termcodes(keys,
- STRLEN(keys), &keys_buf, flags, &did_simplify,
+ = (char_u *)replace_termcodes(keys, STRLEN(keys), &keys_buf, flags, &did_simplify,
CPO_TO_CPO_FLAGS);
- rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
+ mapblock_T *mp = NULL;
+ int buffer_local;
+ LuaRef rhs_lua;
+ char_u *rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
if (did_simplify) {
// When the lhs is being simplified the not-simplified keys are
// preferred for printing, like in do_map().
@@ -2093,7 +2119,8 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
tv_dict_alloc_ret(rettv);
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
// Return a dictionary.
- mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
+ mapblock_fill_dict(rettv->vval.v_dict, mp, did_simplify ? (char *)keys_simplified : NULL,
+ buffer_local, true);
}
}
@@ -2101,6 +2128,74 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
xfree(alt_keys_buf);
}
+/// "mapset()" function
+void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char buf[NUMBUFLEN];
+ const char *which = tv_get_string_buf_chk(&argvars[0], buf);
+ if (which == NULL) {
+ return;
+ }
+ const int mode = get_map_mode((char **)&which, 0);
+ const bool is_abbr = tv_get_number(&argvars[1]) != 0;
+
+ if (argvars[2].v_type != VAR_DICT) {
+ emsg(_(e_dictreq));
+ return;
+ }
+ dict_T *d = argvars[2].vval.v_dict;
+
+ // Get the values in the same order as above in get_maparg().
+ char *lhs = tv_dict_get_string(d, "lhs", false);
+ char *lhsraw = tv_dict_get_string(d, "lhsraw", false);
+ char *lhsrawalt = tv_dict_get_string(d, "lhsrawalt", false);
+ char *rhs = tv_dict_get_string(d, "rhs", false);
+ if (lhs == NULL || lhsraw == NULL || rhs == NULL) {
+ emsg(_("E460: entries missing in mapset() dict argument"));
+ return;
+ }
+ char *orig_rhs = rhs;
+ char *arg_buf = NULL;
+ rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
+
+ int noremap = tv_dict_get_number(d, "noremap") ? REMAP_NONE : 0;
+ if (tv_dict_get_number(d, "script") != 0) {
+ noremap = REMAP_SCRIPT;
+ }
+ MapArguments args = { // TODO(zeertzjq): support restoring "callback"?
+ .rhs = (char_u *)rhs,
+ .rhs_lua = LUA_NOREF,
+ .orig_rhs = vim_strsave((char_u *)orig_rhs),
+ .expr = tv_dict_get_number(d, "expr") != 0,
+ .silent = tv_dict_get_number(d, "silent") != 0,
+ .nowait = tv_dict_get_number(d, "nowait") != 0,
+ .replace_keycodes = tv_dict_get_number(d, "replace_keycodes") != 0,
+ .desc = tv_dict_get_string(d, "desc", false),
+ };
+ scid_T sid = (scid_T)tv_dict_get_number(d, "sid");
+ linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum");
+ bool buffer = tv_dict_get_number(d, "buffer") != 0;
+ // mode from the dict is not used
+
+ mapblock_T **map_table = buffer ? curbuf->b_maphash : maphash;
+ mapblock_T **abbr_table = buffer ? &curbuf->b_first_abbr : &first_abbr;
+
+ // Delete any existing mapping for this lhs and mode.
+ MapArguments unmap_args = MAP_ARGUMENTS_INIT;
+ set_maparg_lhs_rhs(lhs, strlen(lhs), rhs, strlen(rhs), LUA_NOREF, 0, &unmap_args);
+ unmap_args.buffer = buffer;
+ buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, false, curbuf);
+ xfree(unmap_args.rhs);
+ xfree(unmap_args.orig_rhs);
+
+ if (lhsrawalt != NULL) {
+ map_add(curbuf, map_table, abbr_table, (char_u *)lhsrawalt, &args, noremap, mode, is_abbr,
+ sid, lnum, true);
+ }
+ map_add(curbuf, map_table, abbr_table, (char_u *)lhsraw, &args, noremap, mode, is_abbr,
+ sid, lnum, false);
+}
+
/// "maparg()" function
void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -2123,11 +2218,11 @@ void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// @param buffer If true, make a buffer-local mapping for curbuf
void add_map(char *lhs, char *rhs, int mode, bool buffer)
{
- MapArguments args = { 0 };
+ MapArguments args = MAP_ARGUMENTS_INIT;
set_maparg_lhs_rhs(lhs, strlen(lhs), rhs, strlen(rhs), LUA_NOREF, 0, &args);
args.buffer = buffer;
- buf_do_map(2, &args, mode, false, curbuf);
+ buf_do_map(MAPTYPE_NOREMAP, &args, mode, false, curbuf);
xfree(args.rhs);
xfree(args.orig_rhs);
}
@@ -2307,7 +2402,8 @@ static void do_exmap(exarg_T *eap, int isabbrev)
char *cmdp = eap->cmd;
mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
- switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
+ switch (do_map((*cmdp == 'n') ? MAPTYPE_NOREMAP
+ : (*cmdp == 'u') ? MAPTYPE_UNMAP : MAPTYPE_MAP,
(char_u *)eap->arg, mode, isabbrev)) {
case 1:
emsg(_(e_invarg));
@@ -2396,10 +2492,16 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
KEY_TO_BOOL(script);
KEY_TO_BOOL(expr);
KEY_TO_BOOL(unique);
+ KEY_TO_BOOL(replace_keycodes);
#undef KEY_TO_BOOL
}
parsed_args.buffer = !global;
+ if (parsed_args.replace_keycodes && !parsed_args.expr) {
+ api_set_error(err, kErrorTypeValidation, "\"replace_keycodes\" requires \"expr\"");
+ goto fail_and_free;
+ }
+
if (!set_maparg_lhs_rhs(lhs.data, lhs.size,
rhs.data, rhs.size, lua_funcref,
CPO_TO_CPO_FLAGS, &parsed_args)) {
@@ -2461,11 +2563,11 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
}
// buf_do_map() reads noremap/unmap as its own argument.
- int maptype_val = 0;
+ int maptype_val = MAPTYPE_MAP;
if (is_unmap) {
- maptype_val = 1;
+ maptype_val = MAPTYPE_UNMAP;
} else if (is_noremap) {
- maptype_val = 2;
+ maptype_val = MAPTYPE_NOREMAP;
}
switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) {
@@ -2499,7 +2601,7 @@ fail_and_free:
///
/// @param mode The abbreviation for the mode
/// @param buf The buffer to get the mapping array. NULL for global
-/// @param from_lua Whether it is called from internal lua api.
+/// @param from_lua Whether it is called from internal Lua api.
/// @returns Array of maparg()-like dictionaries describing mappings
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
{
@@ -2523,7 +2625,7 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
}
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
- mapblock_fill_dict(dict, current_maphash, buffer_value, false);
+ mapblock_fill_dict(dict, current_maphash, NULL, buffer_value, false);
Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT,
.vval.v_dict = dict } });
if (from_lua) {
diff --git a/src/nvim/mapping.h b/src/nvim/mapping.h
index 4b0622ffa1..7c48c3bce2 100644
--- a/src/nvim/mapping.h
+++ b/src/nvim/mapping.h
@@ -2,7 +2,6 @@
#define NVIM_MAPPING_H
#include "nvim/buffer_defs.h"
-#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/types.h"
#include "nvim/vim.h"
@@ -22,6 +21,7 @@ struct map_arguments {
bool script;
bool silent;
bool unique;
+ bool replace_keycodes;
/// The {lhs} of the mapping.
///
@@ -45,9 +45,14 @@ struct map_arguments {
char *desc; /// map description
};
typedef struct map_arguments MapArguments;
-#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
+#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, false, \
{ 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
+// Used for the first argument of do_map()
+#define MAPTYPE_MAP 0
+#define MAPTYPE_UNMAP 1
+#define MAPTYPE_NOREMAP 2
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mapping.h.generated.h"
#endif
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 66855c66b5..1fe3327b29 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -339,11 +339,11 @@ fmark_T *mark_get(buf_T *buf, win_T *win, fmark_T *fmp, MarkGet flag, int name)
fmark_T *fm = NULL;
if (ASCII_ISUPPER(name) || ascii_isdigit(name)) {
// Global marks
- xfmark_T *xfm = mark_get_global(!(flag & kMarkAllNoResolve), name);
+ xfmark_T *xfm = mark_get_global(flag != kMarkAllNoResolve, name);
fm = &xfm->fmark;
- // Only wanted marks belonging to the buffer
- if ((flag & kMarkBufLocal) && xfm->fmark.fnum != buf->handle) {
- return NULL;
+ if (flag == kMarkBufLocal && xfm->fmark.fnum != buf->handle) {
+ // Only wanted marks belonging to the buffer
+ return pos_to_mark(buf, NULL, (pos_T){ .lnum = 0 });
}
} else if (name > 0 && name < NMARK_LOCAL_MAX) {
// Local Marks
@@ -491,7 +491,7 @@ fmark_T *mark_get_visual(buf_T *buf, int name)
mark = pos_to_mark(buf, NULL, endp);
}
- if (mark != NULL && buf->b_visual.vi_mode == 'V') {
+ if (buf->b_visual.vi_mode == 'V') {
if (name == '<') {
mark->mark.col = 0;
} else {
@@ -508,11 +508,12 @@ fmark_T *mark_get_visual(buf_T *buf, int name)
/// Pass an fmp if multiple c
/// @note view fields are set to 0.
/// @param buf for fmark->fnum.
-/// @param pos for fmrak->mark.
+/// @param pos for fmark->mark.
/// @param fmp pointer to save the mark.
///
/// @return[static] Mark with the given information.
fmark_T *pos_to_mark(buf_T *buf, fmark_T *fmp, pos_T pos)
+ FUNC_ATTR_NONNULL_RET
{
static fmark_T fms = INIT_FMARK;
fmark_T *fm = fmp == NULL ? &fms : fmp;
diff --git a/src/nvim/match.c b/src/nvim/match.c
index e17a95569c..8c72b13bc2 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -7,6 +7,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/eval/funcs.h"
#include "nvim/fold.h"
#include "nvim/highlight_group.h"
#include "nvim/match.h"
diff --git a/src/nvim/match.h b/src/nvim/match.h
index fdcec0ae05..22a848bfdf 100644
--- a/src/nvim/match.h
+++ b/src/nvim/match.h
@@ -2,7 +2,6 @@
#define NVIM_MATCH_H
#include "nvim/buffer_defs.h"
-#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index a9792cf1b9..223b4d6845 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -551,7 +551,7 @@ size_t mb_string2cells(const char *str)
size_t clen = 0;
for (const char_u *p = (char_u *)str; *p != NUL; p += utfc_ptr2len((char *)p)) {
- clen += utf_ptr2cells((char *)p);
+ clen += (size_t)utf_ptr2cells((char *)p);
}
return clen;
@@ -569,8 +569,8 @@ size_t mb_string2cells_len(const char *str, size_t size)
size_t clen = 0;
for (const char_u *p = (char_u *)str; *p != NUL && p < (char_u *)str + size;
- p += utfc_ptr2len_len(p, size + (p - (char_u *)str))) {
- clen += utf_ptr2cells((char *)p);
+ p += utfc_ptr2len_len(p, (int)size + (int)(p - (char_u *)str))) {
+ clen += (size_t)utf_ptr2cells((char *)p);
}
return clen;
@@ -994,37 +994,37 @@ int utf_char2len(const int c)
int utf_char2bytes(const int c, char *const buf)
{
if (c < 0x80) { // 7 bits
- buf[0] = c;
+ buf[0] = (char)c;
return 1;
} else if (c < 0x800) { // 11 bits
- buf[0] = 0xc0 + ((unsigned)c >> 6);
- buf[1] = 0x80 + (c & 0x3f);
+ buf[0] = (char)(0xc0 + ((unsigned)c >> 6));
+ buf[1] = (char)(0x80 + ((unsigned)c & 0x3f));
return 2;
} else if (c < 0x10000) { // 16 bits
- buf[0] = 0xe0 + ((unsigned)c >> 12);
- buf[1] = 0x80 + (((unsigned)c >> 6) & 0x3f);
- buf[2] = 0x80 + (c & 0x3f);
+ buf[0] = (char)(0xe0 + ((unsigned)c >> 12));
+ buf[1] = (char)(0x80 + (((unsigned)c >> 6) & 0x3f));
+ buf[2] = (char)(0x80 + ((unsigned)c & 0x3f));
return 3;
} else if (c < 0x200000) { // 21 bits
- buf[0] = 0xf0 + ((unsigned)c >> 18);
- buf[1] = 0x80 + (((unsigned)c >> 12) & 0x3f);
- buf[2] = 0x80 + (((unsigned)c >> 6) & 0x3f);
- buf[3] = 0x80 + (c & 0x3f);
+ buf[0] = (char)(0xf0 + ((unsigned)c >> 18));
+ buf[1] = (char)(0x80 + (((unsigned)c >> 12) & 0x3f));
+ buf[2] = (char)(0x80 + (((unsigned)c >> 6) & 0x3f));
+ buf[3] = (char)(0x80 + ((unsigned)c & 0x3f));
return 4;
} else if (c < 0x4000000) { // 26 bits
- buf[0] = 0xf8 + ((unsigned)c >> 24);
- buf[1] = 0x80 + (((unsigned)c >> 18) & 0x3f);
- buf[2] = 0x80 + (((unsigned)c >> 12) & 0x3f);
- buf[3] = 0x80 + (((unsigned)c >> 6) & 0x3f);
- buf[4] = 0x80 + (c & 0x3f);
+ buf[0] = (char)(0xf8 + ((unsigned)c >> 24));
+ buf[1] = (char)(0x80 + (((unsigned)c >> 18) & 0x3f));
+ buf[2] = (char)(0x80 + (((unsigned)c >> 12) & 0x3f));
+ buf[3] = (char)(0x80 + (((unsigned)c >> 6) & 0x3f));
+ buf[4] = (char)(0x80 + ((unsigned)c & 0x3f));
return 5;
} else { // 31 bits
- buf[0] = 0xfc + ((unsigned)c >> 30);
- buf[1] = 0x80 + (((unsigned)c >> 24) & 0x3f);
- buf[2] = 0x80 + (((unsigned)c >> 18) & 0x3f);
- buf[3] = 0x80 + (((unsigned)c >> 12) & 0x3f);
- buf[4] = 0x80 + (((unsigned)c >> 6) & 0x3f);
- buf[5] = 0x80 + (c & 0x3f);
+ buf[0] = (char)(0xfc + ((unsigned)c >> 30));
+ buf[1] = (char)(0x80 + (((unsigned)c >> 24) & 0x3f));
+ buf[2] = (char)(0x80 + (((unsigned)c >> 18) & 0x3f));
+ buf[3] = (char)(0x80 + (((unsigned)c >> 12) & 0x3f));
+ buf[4] = (char)(0x80 + (((unsigned)c >> 6) & 0x3f));
+ buf[5] = (char)(0x80 + ((unsigned)c & 0x3f));
return 6;
}
}
@@ -1251,7 +1251,7 @@ int mb_toupper(int a)
#if defined(__STDC_ISO_10646__)
// If towupper() is available and handles Unicode, use it.
if (!(cmp_flags & CMP_INTERNAL)) {
- return towupper(a);
+ return (int)towupper((wint_t)a);
}
#endif
@@ -1282,7 +1282,7 @@ int mb_tolower(int a)
#if defined(__STDC_ISO_10646__)
// If towlower() is available and handles Unicode, use it.
if (!(cmp_flags & CMP_INTERNAL)) {
- return towlower(a);
+ return (int)towlower((wint_t)a);
}
#endif
@@ -1347,10 +1347,10 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2
// to fold just one character to determine the result of comparison.
if (c1 != -1 && c2 == -1) {
- n1 = utf_char2bytes(utf_fold(c1), (char *)buffer);
+ n1 = (size_t)utf_char2bytes(utf_fold(c1), (char *)buffer);
s1 = (char_u *)buffer;
} else if (c2 != -1 && c1 == -1) {
- n2 = utf_char2bytes(utf_fold(c2), (char *)buffer);
+ n2 = (size_t)utf_char2bytes(utf_fold(c2), (char *)buffer);
s2 = (char_u *)buffer;
}
@@ -1487,7 +1487,7 @@ void mb_utflen(const char_u *s, size_t len, size_t *codepoints, size_t *codeunit
size_t count = 0, extra = 0;
size_t clen;
for (size_t i = 0; i < len && s[i] != NUL; i += clen) {
- clen = utf_ptr2len_len(s + i, len - i);
+ clen = (size_t)utf_ptr2len_len(s + i, (int)(len - i));
// NB: gets the byte value of invalid sequence bytes.
// we only care whether the char fits in the BMP or not
int c = (clen > 1) ? utf_ptr2char((char *)s + i) : s[i];
@@ -1509,7 +1509,7 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us
return 0;
}
for (i = 0; i < len && s[i] != NUL; i += clen) {
- clen = utf_ptr2len_len(s + i, len - i);
+ clen = (size_t)utf_ptr2len_len(s + i, (int)(len - i));
// NB: gets the byte value of invalid sequence bytes.
// we only care whether the char fits in the BMP or not
int c = (clen > 1) ? utf_ptr2char((char *)s + i) : s[i];
@@ -1518,7 +1518,7 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us
count++;
}
if (count >= index) {
- return i + clen;
+ return (ssize_t)(i + clen);
}
}
return -1;
@@ -1837,10 +1837,10 @@ int mb_off_next(const char_u *base, const char_u *p)
return i;
}
-/// Return the offset from "p" to the last byte of the character it points
-/// into. Can start anywhere in a stream of bytes.
-/// Composing characters are not included.
-int mb_tail_off(const char *base, const char *p_in)
+/// Return the offset from `p_in` to the last byte of the codepoint it points
+/// to. Can start anywhere in a stream of bytes.
+/// Note: Counts individual codepoints of composed characters separately.
+int utf_cp_tail_off(const char *base, const char *p_in)
{
const uint8_t *p = (uint8_t *)p_in;
int i;
@@ -1866,15 +1866,16 @@ int mb_tail_off(const char *base, const char *p_in)
return i;
}
-/// Return the offset from "p" to the first byte of the character it points
-/// into. Can start anywhere in a stream of bytes.
-/// Unlike utf_head_off() this doesn't include composing characters and returns a negative value.
+/// Return the offset from "p" to the first byte of the codepoint it points
+/// to. Can start anywhere in a stream of bytes.
+/// Note: Unlike `utf_head_off`, this counts individual codepoints of composed characters
+/// separately and returns a negative offset.
///
/// @param[in] base Pointer to start of string
/// @param[in] p Pointer to byte for which to return the offset to the previous codepoint
//
/// @return 0 if invalid sequence, else offset to previous codepoint
-int mb_head_off(const char_u *base, const char_u *p)
+int utf_cp_head_off(const char_u *base, const char_u *p)
{
int i;
int j;
@@ -2165,7 +2166,7 @@ char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET
if (*s == '_') {
*p++ = '-';
} else {
- *p++ = TOLOWER_ASC(*s);
+ *p++ = (char_u)TOLOWER_ASC(*s);
}
}
*p = NUL;
@@ -2269,8 +2270,8 @@ char_u *enc_locale(void)
&& !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') {
// 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[4] = (char)(ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0);
+ buf[5] = (char)(ASCII_ISALNUM(p[-1]) ? TOLOWER_ASC(p[-1]) : 0);
buf[6] = NUL;
} else {
s = p + 1;
@@ -2282,7 +2283,7 @@ enc_locale_copy_enc:
if (s[i] == '_' || s[i] == '-') {
buf[i] = '-';
} else if (ASCII_ISALNUM((uint8_t)s[i])) {
- buf[i] = TOLOWER_ASC(s[i]);
+ buf[i] = (char)TOLOWER_ASC(s[i]);
} else {
break;
}
@@ -2406,14 +2407,14 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen
}
l = utfc_ptr2len_len((const char_u *)from, (int)fromlen);
from += l;
- fromlen -= l;
+ fromlen -= (size_t)l;
} else if (ICONV_ERRNO != ICONV_E2BIG) {
// conversion failed
XFREE_CLEAR(result);
break;
}
// Not enough room or skipping illegal sequence.
- done = to - (char *)result;
+ done = (size_t)(to - (char *)result);
}
if (resultlenp != NULL && result != NULL) {
@@ -2550,10 +2551,10 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
for (size_t i = 0; i < len; ++i) {
c = ptr[i];
if (c < 0x80) {
- *d++ = c;
+ *d++ = (char_u)c;
} else {
- *d++ = 0xc0 + ((unsigned)c >> 6);
- *d++ = 0x80 + (c & 0x3f);
+ *d++ = (char_u)(0xc0 + (char_u)((unsigned)c >> 6));
+ *d++ = (char_u)(0x80 + (c & 0x3f));
}
}
*d = NUL;
@@ -2597,8 +2598,8 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
case CONV_TO_LATIN9: // utf-8 to latin9 conversion
retval = xmalloc(len + 1);
d = retval;
- for (size_t i = 0; i < len; ++i) {
- l = utf_ptr2len_len(ptr + i, len - i);
+ for (size_t i = 0; i < len; i++) {
+ l = utf_ptr2len_len(ptr + i, (int)(len - i));
if (l == 0) {
*d++ = NUL;
} else if (l == 1) {
@@ -2648,7 +2649,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
}
if (!utf_iscomposing(c)) { // skip composing chars
if (c < 0x100) {
- *d++ = c;
+ *d++ = (char_u)c;
} else if (vcp->vc_fail) {
xfree(retval);
return NULL;
@@ -2659,7 +2660,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
}
}
}
- i += l - 1;
+ i += (size_t)l - 1;
}
}
*d = NUL;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 5f74440747..fa3a400a68 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -309,7 +309,7 @@ int ml_open(buf_T *buf)
if (!buf->b_spell) {
b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
- b0p->b0_flags = get_fileformat(buf) + 1;
+ b0p->b0_flags = (uint8_t)(get_fileformat(buf) + 1);
set_b0_fname(b0p, buf);
(void)os_get_username((char *)b0p->b0_uname, B0_UNAME_SIZE);
b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
@@ -359,7 +359,7 @@ int ml_open(buf_T *buf)
dp = hp->bh_data;
dp->db_index[0] = --dp->db_txt_start; // at end of block
- dp->db_free -= 1 + INDEX_SIZE;
+ dp->db_free -= 1 + (unsigned)INDEX_SIZE;
dp->db_line_count = 1;
*((char_u *)dp + dp->db_txt_start) = NUL; // empty line
@@ -711,7 +711,7 @@ static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
if (same_directory(buf->b_ml.ml_mfp->mf_fname, (char_u *)buf->b_ffname)) {
b0p->b0_flags |= B0_SAME_DIR;
} else {
- b0p->b0_flags &= ~B0_SAME_DIR;
+ b0p->b0_flags &= (uint8_t) ~B0_SAME_DIR;
}
}
@@ -723,7 +723,7 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf)
n = (int)STRLEN(buf->b_p_fenc);
if ((int)STRLEN(b0p->b0_fname) + n + 1 > size) {
- b0p->b0_flags &= ~B0_HAS_FENC;
+ b0p->b0_flags &= (uint8_t) ~B0_HAS_FENC;
} else {
memmove((char *)b0p->b0_fname + size - n,
(char *)buf->b_p_fenc, (size_t)n);
@@ -750,7 +750,6 @@ void ml_recover(bool checkext)
DATA_BL *dp;
infoptr_T *ip;
blocknr_T bnum;
- int page_count;
int len;
bool directly;
linenr_T lnum;
@@ -971,7 +970,7 @@ void ml_recover(bool checkext)
int fnsize = B0_FNAME_SIZE_NOCRYPT;
for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; p--) {}
- b0_fenc = vim_strnsave(p, b0p->b0_fname + fnsize - p);
+ b0_fenc = vim_strnsave(p, (size_t)(b0p->b0_fname + fnsize - p));
}
mf_put(mfp, hp, false, false); // release block 0
@@ -1004,11 +1003,11 @@ void ml_recover(bool checkext)
}
unchanged(curbuf, true, true);
- bnum = 1; // start with block 1
- page_count = 1; // which is 1 page
- lnum = 0; // append after line 0 in curbuf
+ bnum = 1; // start with block 1
+ unsigned page_count = 1; // which is 1 page
+ lnum = 0; // append after line 0 in curbuf
line_count = 0;
- idx = 0; // start with first index in block 1
+ idx = 0; // start with first index in block 1
error = 0;
buf->b_ml.ml_stack_top = 0; // -V1048
buf->b_ml.ml_stack = NULL;
@@ -1091,7 +1090,7 @@ void ml_recover(bool checkext)
bnum = pp->pb_pointer[idx].pe_bnum;
line_count = pp->pb_pointer[idx].pe_line_count;
- page_count = pp->pb_pointer[idx].pe_page_count;
+ page_count = (unsigned)pp->pb_pointer[idx].pe_page_count;
idx = 0;
continue;
}
@@ -1267,12 +1266,12 @@ theend:
int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
{
int num_names;
- char_u *(names[6]);
+ char *(names[6]);
char_u *tail;
char_u *p;
int num_files;
int file_count = 0;
- char_u **files;
+ char **files;
char_u *dirp;
char_u *dir_name;
char_u *fname_res = NULL;
@@ -1309,22 +1308,22 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
if (dir_name[0] == '.' && dir_name[1] == NUL) { // check current dir
if (fname == NULL) {
- names[0] = vim_strsave((char_u *)"*.sw?");
+ names[0] = xstrdup("*.sw?");
// For Unix names starting with a dot are special. MS-Windows
// supports this too, on some file systems.
- names[1] = vim_strsave((char_u *)".*.sw?");
- names[2] = vim_strsave((char_u *)".sw?");
+ names[1] = xstrdup(".*.sw?");
+ names[2] = xstrdup(".sw?");
num_names = 3;
} else {
num_names = recov_file_names(names, fname_res, TRUE);
}
} else { // check directory dir_name
if (fname == NULL) {
- names[0] = (char_u *)concat_fnames((char *)dir_name, "*.sw?", true);
+ names[0] = concat_fnames((char *)dir_name, "*.sw?", true);
// For Unix names starting with a dot are special. MS-Windows
// supports this too, on some file systems.
- names[1] = (char_u *)concat_fnames((char *)dir_name, ".*.sw?", true);
- names[2] = (char_u *)concat_fnames((char *)dir_name, ".sw?", true);
+ names[1] = concat_fnames((char *)dir_name, ".*.sw?", true);
+ names[2] = concat_fnames((char *)dir_name, ".sw?", true);
num_names = 3;
} else {
int len = (int)STRLEN(dir_name);
@@ -1361,7 +1360,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
if (swapname != NULL) {
if (os_path_exists(swapname)) {
files = xmalloc(sizeof(char_u *));
- files[0] = swapname;
+ files[0] = (char *)swapname;
swapname = NULL;
num_files = 1;
}
@@ -1377,7 +1376,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
for (int i = 0; i < num_files; i++) {
// Do not expand wildcards, on Windows would try to expand
// "%tmp%" in "%tmp%file"
- if (path_full_compare((char *)p, (char *)files[i], true, false) & kEqualFiles) {
+ if (path_full_compare((char *)p, files[i], true, false) & kEqualFiles) {
// Remove the name from files[i]. Move further entries
// down. When the array becomes empty free it here, since
// FreeWild() won't be called below.
@@ -1395,7 +1394,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
if (nr > 0) {
file_count += num_files;
if (nr <= file_count) {
- *fname_out = vim_strsave(files[nr - 1 + num_files - file_count]);
+ *fname_out = vim_strsave((char_u *)files[nr - 1 + num_files - file_count]);
dirp = (char_u *)""; // stop searching
}
} else if (list) {
@@ -1416,9 +1415,9 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
// print the swap file name
msg_outnum((long)++file_count);
msg_puts(". ");
- msg_puts((const char *)path_tail((char *)files[i]));
+ msg_puts((const char *)path_tail(files[i]));
msg_putchar('\n');
- (void)swapfile_info(files[i]);
+ (void)swapfile_info((char_u *)files[i]);
}
} else {
msg_puts(_(" -- none --\n"));
@@ -1518,7 +1517,7 @@ static time_t swapfile_info(char_u *fname)
if (os_fileinfo((char *)fname, &file_info)) {
#ifdef UNIX
// print name of owner of the file
- if (os_get_uname(file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) {
+ if (os_get_uname((uv_uid_t)file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) {
msg_puts(_(" owned by: "));
msg_outtrans(uname);
msg_puts(_(" dated: "));
@@ -1637,7 +1636,7 @@ static bool swapfile_unchanged(char *fname)
return ret;
}
-static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
+static int recov_file_names(char **names, char_u *path, int prepend_dot)
FUNC_ATTR_NONNULL_ALL
{
int num_names = 0;
@@ -1645,7 +1644,7 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// May also add the file name with a dot prepended, for swap file in same
// dir as original file.
if (prepend_dot) {
- names[num_names] = (char_u *)modname((char *)path, ".sw?", true);
+ names[num_names] = modname((char *)path, ".sw?", true);
if (names[num_names] == NULL) {
return num_names;
}
@@ -1653,9 +1652,9 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
}
// Form the normal swap file name pattern by appending ".sw?".
- names[num_names] = (char_u *)concat_fnames((char *)path, ".sw?", FALSE);
+ names[num_names] = concat_fnames((char *)path, ".sw?", false);
if (num_names >= 1) { // check if we have the same name twice
- char_u *p = names[num_names - 1];
+ char_u *p = (char_u *)names[num_names - 1];
int i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
if (i > 0) {
p += i; // file name has been expanded to full path
@@ -1970,12 +1969,9 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
int line_count; // number of indexes in current block
int offset;
int from, to;
- int space_needed; // space needed for new line
- int page_size;
int page_count;
int db_idx; // index for lnum in data block
bhdr_T *hp;
- memfile_T *mfp;
DATA_BL *dp;
PTR_BL *pp;
infoptr_T *ip;
@@ -1992,10 +1988,10 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
if (len == 0) {
len = (colnr_T)STRLEN(line) + 1; // space needed for the text
}
- space_needed = len + INDEX_SIZE; // space needed for text + index
+ int space_needed = len + (int)INDEX_SIZE; // space needed for text + index
- mfp = buf->b_ml.ml_mfp;
- page_size = mfp->mf_page_size;
+ memfile_T *mfp = buf->b_ml.ml_mfp;
+ int page_size = (int)mfp->mf_page_size;
/*
* find the data block containing the previous line
@@ -2053,9 +2049,9 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
/*
* Insert new line in existing data block, or in data block allocated above.
*/
- dp->db_txt_start -= len;
- dp->db_free -= space_needed;
- ++(dp->db_line_count);
+ dp->db_txt_start -= (unsigned)len;
+ dp->db_free -= (unsigned)space_needed;
+ dp->db_line_count++;
/*
* move the text of the lines that follow to the front
@@ -2067,17 +2063,17 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
* This will become the character just after the new line.
*/
if (db_idx < 0) {
- offset = dp->db_txt_end;
+ offset = (int)dp->db_txt_end;
} else {
offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
}
memmove((char *)dp + dp->db_txt_start,
(char *)dp + dp->db_txt_start + len,
- (size_t)(offset - (dp->db_txt_start + len)));
- for (i = line_count - 1; i > db_idx; --i) {
- dp->db_index[i + 1] = dp->db_index[i] - len;
+ (size_t)offset - (dp->db_txt_start + (size_t)len));
+ for (i = line_count - 1; i > db_idx; i--) {
+ dp->db_index[i + 1] = dp->db_index[i] - (unsigned)len;
}
- dp->db_index[db_idx + 1] = offset - len;
+ dp->db_index[db_idx + 1] = (unsigned)(offset - len);
} else { // add line at the end
dp->db_index[db_idx + 1] = dp->db_txt_start;
}
@@ -2107,7 +2103,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
* The line counts in the pointer blocks have already been adjusted by
* ml_find_line().
*/
- long line_count_left, line_count_right;
+ int line_count_left, line_count_right;
int page_count_left, page_count_right;
bhdr_T *hp_left;
bhdr_T *hp_right;
@@ -2142,9 +2138,9 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
in_left = false; // put new line in right block
// space_needed does not change
} else {
- data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
- dp->db_txt_start;
- total_moved = data_moved + lines_moved * INDEX_SIZE;
+ data_moved = (int)(((dp->db_index[db_idx]) & DB_INDEX_MASK) -
+ dp->db_txt_start);
+ total_moved = data_moved + lines_moved * (int)INDEX_SIZE;
if ((int)dp->db_free + total_moved >= space_needed) {
in_left = true; // put new line in left block
space_needed = total_moved;
@@ -2155,7 +2151,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
}
}
- page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
+ page_count = ((space_needed + (int)HEADER_SIZE) + page_size - 1) / page_size;
hp_new = ml_new_data(mfp, newfile, page_count);
if (db_idx < 0) { // left block is new
hp_left = hp_new;
@@ -2172,15 +2168,15 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
dp_left = hp_left->bh_data;
bnum_left = hp_left->bh_bnum;
bnum_right = hp_right->bh_bnum;
- page_count_left = hp_left->bh_page_count;
- page_count_right = hp_right->bh_page_count;
+ page_count_left = (int)hp_left->bh_page_count;
+ page_count_right = (int)hp_right->bh_page_count;
/*
* May move the new line into the right/new block.
*/
if (!in_left) {
- dp_right->db_txt_start -= len;
- dp_right->db_free -= len + INDEX_SIZE;
+ dp_right->db_txt_start -= (unsigned)len;
+ dp_right->db_free -= (unsigned)len + (unsigned)INDEX_SIZE;
dp_right->db_index[0] = dp_right->db_txt_start;
if (mark) {
dp_right->db_index[0] |= DB_MARKED;
@@ -2196,21 +2192,21 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
if (lines_moved) {
/*
*/
- dp_right->db_txt_start -= data_moved;
- dp_right->db_free -= total_moved;
+ dp_right->db_txt_start -= (unsigned)data_moved;
+ dp_right->db_free -= (unsigned)total_moved;
memmove((char *)dp_right + dp_right->db_txt_start,
(char *)dp_left + dp_left->db_txt_start,
(size_t)data_moved);
- offset = dp_right->db_txt_start - dp_left->db_txt_start;
- dp_left->db_txt_start += data_moved;
- dp_left->db_free += total_moved;
+ offset = (int)(dp_right->db_txt_start - dp_left->db_txt_start);
+ dp_left->db_txt_start += (unsigned)data_moved;
+ dp_left->db_free += (unsigned)total_moved;
/*
* update indexes in the new block
*/
for (to = line_count_right, from = db_idx + 1;
- from < line_count_left; ++from, ++to) {
- dp_right->db_index[to] = dp->db_index[from] + offset;
+ from < line_count_left; from++, to++) {
+ dp_right->db_index[to] = dp->db_index[from] + (unsigned)offset;
}
line_count_right += lines_moved;
line_count_left -= lines_moved;
@@ -2220,8 +2216,8 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
* May move the new line into the left (old or new) block.
*/
if (in_left) {
- dp_left->db_txt_start -= len;
- dp_left->db_free -= len + INDEX_SIZE;
+ dp_left->db_txt_start -= (unsigned)len;
+ dp_left->db_free -= (unsigned)len + (unsigned)INDEX_SIZE;
dp_left->db_index[line_count_left] = dp_left->db_txt_start;
if (mark) {
dp_left->db_index[line_count_left] |= DB_MARKED;
@@ -2369,8 +2365,8 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
memmove(&pp_new->pb_pointer[0],
&pp->pb_pointer[pb_idx + 1],
(size_t)(total_moved) * sizeof(PTR_EN));
- pp_new->pb_count = total_moved;
- pp->pb_count -= total_moved - 1;
+ pp_new->pb_count = (uint16_t)total_moved;
+ pp->pb_count = (uint16_t)(pp->pb_count - (total_moved - 1));
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
@@ -2436,12 +2432,12 @@ void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len)
return;
}
if (len == -1) {
- len = STRLEN(ptr);
+ len = (ssize_t)STRLEN(ptr);
}
- curbuf->deleted_bytes += len + 1;
- curbuf->deleted_bytes2 += len + 1;
+ curbuf->deleted_bytes += (size_t)len + 1;
+ curbuf->deleted_bytes2 += (size_t)len + 1;
if (curbuf->update_need_codepoints) {
- mb_utflen(ptr, len, &curbuf->deleted_codepoints,
+ mb_utflen(ptr, (size_t)len, &curbuf->deleted_codepoints,
&curbuf->deleted_codeunits);
curbuf->deleted_codepoints++; // NL char
curbuf->deleted_codeunits++;
@@ -2525,7 +2521,6 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
int count; // number of entries in block
int idx;
int stack_idx;
- int text_start;
int line_start;
long line_size;
int i;
@@ -2568,17 +2563,16 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
dp = hp->bh_data;
// compute line count before the delete
- count = (long)(buf->b_ml.ml_locked_high)
- - (long)(buf->b_ml.ml_locked_low) + 2;
+ count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 2;
idx = lnum - buf->b_ml.ml_locked_low;
--buf->b_ml.ml_line_count;
line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
if (idx == 0) { // first line in block, text at the end
- line_size = dp->db_txt_end - line_start;
+ line_size = dp->db_txt_end - (unsigned)line_start;
} else {
- line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+ line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - (unsigned)line_start;
}
// Line should always have an NL char internally (represented as NUL),
@@ -2636,24 +2630,20 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
}
CHECK(stack_idx < 0, _("deleted block 1?"));
} else {
- /*
- * delete the text by moving the next lines forwards
- */
- text_start = dp->db_txt_start;
+ // delete the text by moving the next lines forwards
+ int text_start = (int)dp->db_txt_start;
memmove((char *)dp + text_start + line_size,
(char *)dp + text_start, (size_t)(line_start - text_start));
- /*
- * delete the index by moving the next indexes backwards
- * Adjust the indexes for the text movement.
- */
- for (i = idx; i < count - 1; ++i) {
- dp->db_index[i] = dp->db_index[i + 1] + line_size;
+ // delete the index by moving the next indexes backwards
+ // Adjust the indexes for the text movement.
+ for (i = idx; i < count - 1; i++) {
+ dp->db_index[i] = dp->db_index[i + 1] + (unsigned)line_size;
}
- dp->db_free += line_size + INDEX_SIZE;
- dp->db_txt_start += line_size;
- --(dp->db_line_count);
+ dp->db_free += (unsigned)line_size + (unsigned)INDEX_SIZE;
+ dp->db_txt_start += (unsigned)line_size;
+ dp->db_line_count--;
/*
* mark the block dirty and make sure it is in the file (for recovery)
@@ -2823,9 +2813,9 @@ static void ml_flush_line(buf_T *buf)
start = ((dp->db_index[idx]) & DB_INDEX_MASK);
old_line = (char_u *)dp + start;
if (idx == 0) { // line is last in block
- old_len = dp->db_txt_end - start;
+ old_len = (int)dp->db_txt_end - start;
} else { // text of previous line follows
- old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
+ old_len = (int)(dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
}
new_len = (colnr_T)STRLEN(new_line) + 1;
extra = new_len - old_len; // negative if lines gets smaller
@@ -2840,18 +2830,18 @@ static void ml_flush_line(buf_T *buf)
// move text of following lines
memmove((char *)dp + dp->db_txt_start - extra,
(char *)dp + dp->db_txt_start,
- (size_t)(start - dp->db_txt_start));
+ (size_t)(start - (int)dp->db_txt_start));
// adjust pointers of this and following lines
- for (i = idx + 1; i < count; ++i) {
- dp->db_index[i] -= extra;
+ for (i = idx + 1; i < count; i++) {
+ dp->db_index[i] -= (unsigned)extra;
}
}
- dp->db_index[idx] -= extra;
+ dp->db_index[idx] -= (unsigned)extra;
// adjust free space
- dp->db_free -= extra;
- dp->db_txt_start -= extra;
+ dp->db_free -= (unsigned)extra;
+ dp->db_txt_start -= (unsigned)extra;
// copy new line into the data block
memmove(old_line - extra, new_line, (size_t)new_len);
@@ -2866,7 +2856,7 @@ static void ml_flush_line(buf_T *buf)
// Don't forget to copy the mark!
// How about handling errors???
(void)ml_append_int(buf, lnum, new_line, new_len, false,
- (dp->db_index[idx] & DB_MARKED));
+ (int)(dp->db_index[idx] & DB_MARKED));
(void)ml_delete_int(buf, lnum, false);
}
}
@@ -2886,8 +2876,8 @@ static bhdr_T *ml_new_data(memfile_T *mfp, bool negative, int page_count)
bhdr_T *hp = mf_new(mfp, negative, (unsigned)page_count);
DATA_BL *dp = hp->bh_data;
dp->db_id = DATA_ID;
- dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
- dp->db_free = dp->db_txt_start - HEADER_SIZE;
+ dp->db_txt_start = dp->db_txt_end = (unsigned)page_count * mfp->mf_page_size;
+ dp->db_free = dp->db_txt_start - (unsigned)HEADER_SIZE;
dp->db_line_count = 0;
return hp;
@@ -2900,7 +2890,7 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp)
PTR_BL *pp = hp->bh_data;
pp->pb_id = PTR_ID;
pp->pb_count = 0;
- pp->pb_count_max = (mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1;
+ pp->pb_count_max = (uint16_t)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1);
return hp;
}
@@ -3000,7 +2990,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
* search downwards in the tree until a data block is found
*/
for (;;) {
- if ((hp = mf_get(mfp, bnum, page_count)) == NULL) {
+ if ((hp = mf_get(mfp, bnum, (unsigned)page_count)) == NULL) {
goto error_noblock;
}
@@ -3110,7 +3100,7 @@ static int ml_add_stack(buf_T *buf)
CHECK(top > 0, _("Stack size increases")); // more than 5 levels???
buf->b_ml.ml_stack_size += STACK_INCR;
- size_t new_size = sizeof(infoptr_T) * buf->b_ml.ml_stack_size;
+ size_t new_size = sizeof(infoptr_T) * (size_t)buf->b_ml.ml_stack_size;
buf->b_ml.ml_stack = xrealloc(buf->b_ml.ml_stack, new_size);
}
@@ -3179,7 +3169,7 @@ int resolve_symlink(const char_u *fname, char_u *buf)
return FAIL;
}
- ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
+ ret = (int)readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
if (ret <= 0) {
if (errno == EINVAL || errno == ENOENT) {
// Found non-symlink or not existing file, stop here.
@@ -3294,9 +3284,9 @@ char_u *get_file_in_dir(char_u *fname, char_u *dname)
} else {
save_char = *tail;
*tail = NUL;
- t = (char_u *)concat_fnames((char *)fname, (char *)dname + 2, TRUE);
- *tail = save_char;
- retval = (char_u *)concat_fnames((char *)t, (char *)tail, TRUE);
+ t = (char_u *)concat_fnames((char *)fname, (char *)dname + 2, true);
+ *tail = (uint8_t)save_char;
+ retval = (char_u *)concat_fnames((char *)t, (char *)tail, true);
xfree(t);
}
} else {
@@ -3798,8 +3788,7 @@ void ml_setflags(buf_T *buf)
if (hp->bh_bnum == 0) {
b0p = hp->bh_data;
b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
- b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
- | (get_fileformat(buf) + 1);
+ b0p->b0_flags = (uint8_t)((b0p->b0_flags & ~B0_FF_MASK) | (uint8_t)(get_fileformat(buf) + 1));
add_b0_fenc(b0p, buf);
hp->bh_flags |= BH_DIRTY;
mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
@@ -3887,7 +3876,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks) {
buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
buf->b_ml.ml_chunksize = xrealloc(buf->b_ml.ml_chunksize,
- sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
+ sizeof(chunksize_T) * (size_t)buf->b_ml.ml_numchunks);
}
if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL) {
@@ -3898,8 +3887,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
memmove(buf->b_ml.ml_chunksize + curix + 1,
buf->b_ml.ml_chunksize + curix,
- (buf->b_ml.ml_usedchunks - curix) *
- sizeof(chunksize_T));
+ (size_t)(buf->b_ml.ml_usedchunks - curix) * sizeof(chunksize_T));
// Compute length of first half of lines in the split chunk
size = 0;
linecnt = 0;
@@ -3910,12 +3898,11 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
return;
}
dp = hp->bh_data;
- count = (long)(buf->b_ml.ml_locked_high) -
- (long)(buf->b_ml.ml_locked_low) + 1;
+ count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
idx = curline - buf->b_ml.ml_locked_low;
curline = buf->b_ml.ml_locked_high + 1;
if (idx == 0) { // first line in block, text at the end
- text_end = dp->db_txt_end;
+ text_end = (int)dp->db_txt_end;
} else {
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
}
@@ -3928,7 +3915,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
idx = count - 1;
linecnt += rest;
}
- size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
+ size += text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK);
}
buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
@@ -3959,11 +3946,10 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
}
dp = hp->bh_data;
if (dp->db_line_count == 1) {
- rest = dp->db_txt_end - dp->db_txt_start;
+ rest = (int)(dp->db_txt_end - dp->db_txt_start);
} else {
- rest =
- ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
- - dp->db_txt_start;
+ rest = (int)((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
+ - (int)dp->db_txt_start;
}
curchnk->mlcs_totalsize = rest;
curchnk->mlcs_numlines = 1;
@@ -3982,7 +3968,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
} else if (curix == 0 && curchnk->mlcs_numlines <= 0) {
buf->b_ml.ml_usedchunks--;
memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
- buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
+ (size_t)buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
return;
} else if (curix == 0 || (curchnk->mlcs_numlines > 10
&& (curchnk->mlcs_numlines +
@@ -3998,8 +3984,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
if (curix < buf->b_ml.ml_usedchunks) {
memmove(buf->b_ml.ml_chunksize + curix,
buf->b_ml.ml_chunksize + curix + 1,
- (buf->b_ml.ml_usedchunks - curix) *
- sizeof(chunksize_T));
+ (size_t)(buf->b_ml.ml_usedchunks - curix) * sizeof(chunksize_T));
}
return;
}
@@ -4049,7 +4034,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
if (lnum == 0 || buf->b_ml.ml_line_lnum < lnum || !no_ff) {
ml_flush_line(curbuf);
} else if (can_cache && buf->b_ml.ml_line_offset > 0) {
- return buf->b_ml.ml_line_offset;
+ return (long)buf->b_ml.ml_line_offset;
}
if (buf->b_ml.ml_usedchunks == -1
@@ -4071,7 +4056,8 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
* special because it will never qualify
*/
curline = 1;
- curix = size = 0;
+ curix = 0;
+ size = 0;
while (curix < buf->b_ml.ml_usedchunks - 1
&& ((lnum != 0
&& lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
@@ -4093,11 +4079,10 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
return -1;
}
dp = hp->bh_data;
- count = (long)(buf->b_ml.ml_locked_high) -
- (long)(buf->b_ml.ml_locked_low) + 1;
+ count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
start_idx = idx = curline - buf->b_ml.ml_locked_low;
if (idx == 0) { // first line in block, text at the end
- text_end = dp->db_txt_end;
+ text_end = (int)dp->db_txt_end;
} else {
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
}
@@ -4123,7 +4108,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
idx++;
}
}
- len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
+ len = text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK);
size += len;
if (offset != 0 && size >= offset) {
if (size + ffdos == offset) {
@@ -4132,7 +4117,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
*offp = offset - size + len;
} else {
*offp = offset - size + len
- - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
+ - (text_end - (int)((dp->db_index[idx - 1]) & DB_INDEX_MASK));
}
curline += idx - start_idx + extra;
if (curline > buf->b_ml.ml_line_count) {
@@ -4158,7 +4143,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
}
if (can_cache && size > 0) {
- buf->b_ml.ml_line_offset = size;
+ buf->b_ml.ml_line_offset = (size_t)size;
}
return size;
@@ -4168,14 +4153,13 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
void goto_byte(long cnt)
{
long boff = cnt;
- linenr_T lnum;
ml_flush_line(curbuf); // cached line may be dirty
setpcmark();
if (boff) {
boff--;
}
- lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff, false);
+ linenr_T lnum = (linenr_T)ml_find_line_or_offset(curbuf, (linenr_T)0, &boff, false);
if (lnum < 1) { // past the end
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
curwin->w_curswant = MAXCOL;
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 4d5cf047f9..5ae7f7bbe3 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -14,6 +14,7 @@
#include "nvim/eval.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/mapping.h"
#include "nvim/memfile.h"
@@ -545,7 +546,7 @@ void arena_start(Arena *arena, ArenaMem *reuse_blk)
/// Finnish the allocations in an arena.
///
-/// This does not immedately free the memory, but leaves existing allocated
+/// This does not immediately free the memory, but leaves existing allocated
/// objects valid, and returns an opaque ArenaMem handle, which can be used to
/// free the allocations using `arena_mem_free`, when the objects allocated
/// from the arena are not needed anymore.
@@ -710,6 +711,7 @@ void free_all_mem(void)
free_search_patterns();
free_old_sub();
free_last_insert();
+ free_insexpand_stuff();
free_prev_shellcmd();
free_regexp_stuff();
free_tag_stuff();
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 018c62d604..febb66081a 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -121,7 +121,7 @@ void ex_menu(exarg_T *eap)
}
if (ascii_iswhite(*p)) {
for (i = 0; i < MENUDEPTH && !ascii_iswhite(*arg); i++) {
- pri_tab[i] = getdigits_long((char_u **)&arg, false, 0);
+ pri_tab[i] = getdigits_long(&arg, false, 0);
if (pri_tab[i] == 0) {
pri_tab[i] = 500;
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 2c96613bb3..621a9212df 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -493,6 +493,7 @@ int smsg(const char *s, ...)
va_start(arglist, s);
vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist);
va_end(arglist);
+
return msg((char *)IObuff);
}
@@ -1389,7 +1390,7 @@ void msg_start(void)
need_fileinfo = false;
}
- bool no_msg_area = !ui_has(kUIMessages) && p_ch < 1;
+ const bool no_msg_area = !ui_has_messages();
if (need_clr_eos || (no_msg_area && redrawing_cmdline)) {
// Halfway an ":echo" command and getting an (error) message: clear
@@ -2503,6 +2504,7 @@ static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int
if (do_clear_sb_text == SB_CLEAR_ALL
|| do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) {
clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL);
+ msg_sb_eol(); // prevent messages from overlapping
do_clear_sb_text = SB_CLEAR_NONE;
}
@@ -2537,14 +2539,44 @@ void may_clear_sb_text(void)
do_clear_sb_text = SB_CLEAR_ALL;
}
-/// Starting to edit the command line, do not clear messages now.
+/// Starting to edit the command line: do not clear messages now.
void sb_text_start_cmdline(void)
{
+ if (do_clear_sb_text == SB_CLEAR_CMDLINE_BUSY) {
+ // Invoking command line recursively: the previous-level command line
+ // doesn't need to be remembered as it will be redrawn when returning
+ // to that level.
+ sb_text_restart_cmdline();
+ } else {
+ msg_sb_eol();
+ do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
+ }
+}
+
+/// Redrawing the command line: clear the last unfinished line.
+void sb_text_restart_cmdline(void)
+{
+ // Needed when returning from nested command line.
do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
- msg_sb_eol();
+
+ if (last_msgchunk == NULL || last_msgchunk->sb_eol) {
+ // No unfinished line: don't clear anything.
+ return;
+ }
+
+ msgchunk_T *tofree = msg_sb_start(last_msgchunk);
+ last_msgchunk = tofree->sb_prev;
+ if (last_msgchunk != NULL) {
+ last_msgchunk->sb_next = NULL;
+ }
+ while (tofree != NULL) {
+ msgchunk_T *tofree_next = tofree->sb_next;
+ xfree(tofree);
+ tofree = tofree_next;
+ }
}
-/// Ending to edit the command line. Clear old lines but the last one later.
+/// Ending to edit the command line: clear old lines but the last one later.
void sb_text_end_cmdline(void)
{
do_clear_sb_text = SB_CLEAR_CMDLINE_DONE;
@@ -2564,7 +2596,7 @@ void clear_sb_text(int all)
if (last_msgchunk == NULL) {
return;
}
- lastp = &last_msgchunk->sb_prev;
+ lastp = &msg_sb_start(last_msgchunk)->sb_prev;
}
while (*lastp != NULL) {
@@ -3081,7 +3113,7 @@ void msg_clr_eos_force(void)
msg_row = msg_grid_pos;
}
- if (p_ch > 0) {
+ if (ui_has_messages()) {
grid_fill(&msg_grid_adj, msg_row, msg_row + 1, msg_startcol, msg_endcol,
' ', ' ', HL_ATTR(HLF_MSG));
grid_fill(&msg_grid_adj, msg_row + 1, Rows, 0, Columns,
diff --git a/src/nvim/move.c b/src/nvim/move.c
index bd68ad6f97..6d4eb8ef49 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -2271,7 +2271,13 @@ void do_check_cursorbind(void)
int restart_edit_save = restart_edit;
restart_edit = true;
check_cursor();
- validate_cursor();
+
+ // Avoid a scroll here for the cursor position, 'scrollbind' is
+ // more important.
+ if (!curwin->w_p_scb) {
+ validate_cursor();
+ }
+
restart_edit = restart_edit_save;
}
// Correct cursor for multi-byte character.
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index de01443313..1ca68979f4 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -239,7 +239,14 @@ static void parse_msgpack(Channel *channel)
{
Unpacker *p = channel->rpc.unpacker;
while (unpacker_advance(p)) {
- if (p->type == kMessageTypeResponse) {
+ if (p->type == kMessageTypeRedrawEvent) {
+ if (p->grid_line_event) {
+ ui_client_event_raw_line(p->grid_line_event);
+ } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) {
+ p->ui_handler.fn(p->result.data.array);
+ arena_mem_free(arena_finish(&p->arena), &p->reuse_blk);
+ }
+ } else if (p->type == kMessageTypeResponse) {
ChannelCallFrame *frame = kv_last(channel->rpc.call_stack);
if (p->request_id != frame->request_id) {
char buf[256];
diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c
index 26c1843026..c8e9fdd4c3 100644
--- a/src/nvim/msgpack_rpc/unpacker.c
+++ b/src/nvim/msgpack_rpc/unpacker.c
@@ -6,6 +6,7 @@
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/unpacker.h"
+#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/unpacker.c.generated.h"
@@ -280,10 +281,20 @@ error:
// is relatively small, just ~10 bytes + the method name. Thus we can simply refuse
// to advance the stream beyond the header until it can be parsed in its entirety.
//
-// Of course, later on, we want to specialize state 2 into sub-states depending
+// Later on, we want to specialize state 2 into more sub-states depending
// on the specific method. "nvim_exec_lua" should just decode direct into lua
-// objects, and "redraw/grid_line" should use a hand-rolled decoder to avoid
-// a blizzard of small objects for each screen cell.
+// objects. For the moment "redraw/grid_line" uses a hand-rolled decoder,
+// to avoid a blizzard of small objects for each screen cell.
+//
+// <0>[2, "redraw", <10>[{11}["method", <12>[args], <12>[args], ...], <11>[...], ...]]
+//
+// Where [args] gets unpacked as an Array. Note: first {11} is not saved as a state.
+//
+// When method is "grid_line", we furthermore decode a cell at a time like:
+//
+// <0>[2, "redraw", <10>[{11}["grid_line", <13>[g, r, c, [<14>[cell], <14>[cell], ...]], ...], <11>[...], ...]]
+//
+// where [cell] is [char, repeat, attr], where 'repeat' and 'attr' is optional
bool unpacker_advance(Unpacker *p)
{
@@ -292,8 +303,27 @@ bool unpacker_advance(Unpacker *p)
if (!unpacker_parse_header(p)) {
return false;
}
- p->state = p->type == kMessageTypeResponse ? 1 : 2;
- arena_start(&p->arena, &p->reuse_blk);
+ if (p->type == kMessageTypeNotification && p->handler.fn == handle_ui_client_redraw) {
+ p->type = kMessageTypeRedrawEvent;
+ p->state = 10;
+ } else {
+ p->state = p->type == kMessageTypeResponse ? 1 : 2;
+ arena_start(&p->arena, &p->reuse_blk);
+ }
+ }
+
+ if (p->state >= 10 && p->state != 12) {
+ if (!unpacker_parse_redraw(p)) {
+ return false;
+ }
+
+ if (p->state == 14) {
+ // grid_line event already unpacked
+ goto done;
+ } else {
+ // unpack other ui events using mpack_parse()
+ arena_start(&p->arena, &p->reuse_blk);
+ }
}
int result;
@@ -310,13 +340,173 @@ rerun:
return false;
}
- if (p->state == 1) {
+done:
+ switch (p->state) {
+ case 1:
p->error = p->result;
p->state = 2;
goto rerun;
- } else {
- assert(p->state == 2);
+ case 2:
p->state = 0;
+ return true;
+ case 12:
+ case 14:
+ p->ncalls--;
+ if (p->ncalls > 0) {
+ p->state = (p->state == 14) ? 13 : 12;
+ } else if (p->nevents > 0) {
+ p->state = 11;
+ } else {
+ p->state = 0;
+ }
+ return true;
+ default:
+ abort();
+ }
+}
+
+bool unpacker_parse_redraw(Unpacker *p)
+{
+ mpack_token_t tok;
+ int result;
+
+ const char *data = p->read_ptr;
+ size_t size = p->read_size;
+ GridLineEvent *g = p->grid_line_event;
+
+#define NEXT_TYPE(tok, typ) \
+ result = mpack_rtoken(&data, &size, &tok); \
+ if (result == MPACK_EOF) { \
+ return false; \
+ } else if (result || (tok.type != typ \
+ && !(typ == MPACK_TOKEN_STR && tok.type == MPACK_TOKEN_BIN) \
+ && !(typ == MPACK_TOKEN_SINT && tok.type == MPACK_TOKEN_UINT))) { \
+ p->state = -1; \
+ return false; \
+ }
+
+redo:
+ switch (p->state) {
+ case 10:
+ NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
+ p->nevents = (int)tok.length;
+ FALLTHROUGH;
+
+ case 11:
+ NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
+ p->ncalls = (int)tok.length;
+
+ if (p->ncalls-- == 0) {
+ p->state = -1;
+ return false;
+ }
+
+ NEXT_TYPE(tok, MPACK_TOKEN_STR);
+ if (tok.length > size) {
+ return false;
+ }
+
+ p->ui_handler = ui_client_get_redraw_handler(data, tok.length, NULL);
+ data += tok.length;
+ size -= tok.length;
+
+ p->nevents--;
+ p->read_ptr = data;
+ p->read_size = size;
+ if (p->ui_handler.fn != ui_client_event_grid_line) {
+ p->state = 12;
+ if (p->grid_line_event) {
+ arena_mem_free(arena_finish(&p->arena), &p->reuse_blk);
+ p->grid_line_event = NULL;
+ }
+ return true;
+ } else {
+ p->state = 13;
+ arena_start(&p->arena, &p->reuse_blk);
+ p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true);
+ g = p->grid_line_event;
+ }
+ FALLTHROUGH;
+
+ case 13:
+ NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
+ int eventarrsize = (int)tok.length;
+ if (eventarrsize != 4) {
+ p->state = -1;
+ return false;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ NEXT_TYPE(tok, MPACK_TOKEN_UINT);
+ g->args[i] = (int)tok.data.value.lo;
+ }
+
+ NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
+ g->ncells = (int)tok.length;
+ g->icell = 0;
+ g->coloff = 0;
+ g->cur_attr = -1;
+
+ p->read_ptr = data;
+ p->read_size = size;
+ p->state = 14;
+ FALLTHROUGH;
+
+ case 14:
+ assert(g->icell < g->ncells);
+
+ NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
+ int cellarrsize = (int)tok.length;
+ if (cellarrsize < 1 || cellarrsize > 3) {
+ p->state = -1;
+ return false;
+ }
+
+ NEXT_TYPE(tok, MPACK_TOKEN_STR);
+ if (tok.length > size) {
+ return false;
+ }
+
+ const char *cellbuf = data;
+ size_t cellsize = tok.length;
+ data += cellsize;
+ size -= cellsize;
+
+ if (cellarrsize >= 2) {
+ NEXT_TYPE(tok, MPACK_TOKEN_SINT);
+ g->cur_attr = (int)tok.data.value.lo;
+ }
+
+ int repeat = 1;
+ if (cellarrsize >= 3) {
+ NEXT_TYPE(tok, MPACK_TOKEN_UINT);
+ repeat = (int)tok.data.value.lo;
+ }
+
+ g->clear_width = 0;
+ if (g->icell == g->ncells - 1 && cellsize == 1 && cellbuf[0] == ' ' && repeat > 1) {
+ g->clear_width = repeat;
+ } else {
+ for (int r = 0; r < repeat; r++) {
+ if (g->coloff >= (int)grid_line_buf_size) {
+ p->state = -1;
+ return false;
+ }
+ memcpy(grid_line_buf_char[g->coloff], cellbuf, cellsize);
+ grid_line_buf_char[g->coloff][cellsize] = NUL;
+ grid_line_buf_attr[g->coloff++] = g->cur_attr;
+ }
+ }
+
+ g->icell++;
+ p->read_ptr = data;
+ p->read_size = size;
+ if (g->icell == g->ncells) {
+ return true;
+ }
+ goto redo;
+
+ default:
+ abort();
}
- return true;
}
diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h
index e0dc6f0a68..f39439be63 100644
--- a/src/nvim/msgpack_rpc/unpacker.h
+++ b/src/nvim/msgpack_rpc/unpacker.h
@@ -32,8 +32,13 @@ struct Unpacker {
Error unpack_error;
Arena arena;
- // one lenght free-list of reusable blocks
+ // one length free-list of reusable blocks
ArenaMem reuse_blk;
+
+ int nevents;
+ int ncalls;
+ UIClientHandler ui_handler;
+ GridLineEvent *grid_line_event;
};
// unrecovareble error. unpack_error should be set!
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index b675abfb7d..2d752eade7 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1908,6 +1908,13 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs
: wp->w_winbar_click_defs;
+ if (in_status_line && global_stl_height() > 0) {
+ // global statusline is displayed for the current window,
+ // and spans the whole screen.
+ click_defs = curwin->w_status_click_defs;
+ click_col = mouse_col;
+ }
+
if (click_defs != NULL) {
switch (click_defs[click_col].type) {
case kStlClickDisabled:
@@ -2474,7 +2481,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **te
col = 0;
// Search for point of changing multibyte character class.
this_class = mb_get_class(ptr);
- while (ptr[col] != NUL
+ while (ptr[col] != NUL // -V781
&& ((i == 0
? mb_get_class(ptr + col) == this_class
: mb_get_class(ptr + col) != 0)
@@ -2803,7 +2810,7 @@ void pop_showcmd(void)
static void display_showcmd(void)
{
- if (p_ch < 1 && !ui_has(kUIMessages)) {
+ if (!ui_has_messages()) {
return;
}
@@ -2915,10 +2922,11 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
curwin = wp;
curbuf = curwin->w_buffer;
- // skip original window and windows with 'noscrollbind'
+ // skip original window and windows with 'noscrollbind'
if (curwin == old_curwin || !curwin->w_p_scb) {
continue;
}
+
// do the vertical scroll
if (want_ver) {
if (old_curwin->w_p_diff && curwin->w_p_diff) {
@@ -3478,7 +3486,8 @@ void scroll_redraw(int up, long count)
redraw_later(curwin, VALID);
}
-/// Get the count specified after a 'z' command.
+/// Get the count specified after a 'z' command. Only the 'z<CR>', 'zl', 'zh',
+/// 'z<Left>', and 'z<Right>' commands accept a count after 'z'.
/// @return true to process the 'z' command and false to skip it.
static bool nv_z_get_count(cmdarg_T *cap, int *nchar_arg)
{
@@ -5094,6 +5103,7 @@ static void nv_brackets(cmdarg_T *cap)
} else if (cap->nchar == '\'' || cap->nchar == '`') {
// "['", "[`", "]'" and "]`": jump to next mark
fmark_T *fm = pos_to_mark(curbuf, NULL, curwin->w_cursor);
+ assert(fm != NULL);
fmark_T *prev_fm;
for (n = cap->count1; n > 0; n--) {
prev_fm = fm;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 3602eb2a3e..9a44c36d44 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -928,6 +928,7 @@ int do_record(int c)
{
char_u *p;
static int regname;
+ static bool changed_cmdheight = false;
yankreg_T *old_y_previous;
int retval;
@@ -941,6 +942,15 @@ int do_record(int c)
showmode();
regname = c;
retval = OK;
+
+ if (!ui_has_messages()) {
+ // Enable macro indicator temporarily
+ set_option_value("ch", 1L, NULL, 0);
+ update_screen(VALID);
+
+ changed_cmdheight = true;
+ }
+
apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf);
}
} else { // stop recording
@@ -986,6 +996,12 @@ int do_record(int c)
y_previous = old_y_previous;
}
+
+ if (changed_cmdheight) {
+ // Restore cmdheight
+ set_option_value("ch", 0L, NULL, 0);
+ redraw_all_later(CLEAR);
+ }
}
return retval;
}
@@ -1050,7 +1066,7 @@ static int execreg_lastc = NUL;
/// with a \. Lines that start with a comment "\ character are ignored.
/// @returns the concatenated line. The index of the line that should be
/// processed next is returned in idx.
-static char_u *execreg_line_continuation(char_u **lines, size_t *idx)
+static char_u *execreg_line_continuation(char **lines, size_t *idx)
{
size_t i = *idx;
assert(i > 0);
@@ -1065,7 +1081,7 @@ static char_u *execreg_line_continuation(char_u **lines, size_t *idx)
// Any line not starting with \ or "\ is the start of the
// command.
while (--i > 0) {
- p = (char_u *)skipwhite((char *)lines[i]);
+ p = (char_u *)skipwhite(lines[i]);
if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
break;
}
@@ -1073,9 +1089,9 @@ static char_u *execreg_line_continuation(char_u **lines, size_t *idx)
const size_t cmd_start = i;
// join all the lines
- ga_concat(&ga, (char *)lines[cmd_start]);
+ ga_concat(&ga, lines[cmd_start]);
for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
- p = (char_u *)skipwhite((char *)lines[j]);
+ p = (char_u *)skipwhite(lines[j]);
if (*p == '\\') {
// Adjust the growsize to the current length to
// speed up concatenating many lines.
@@ -1188,7 +1204,7 @@ int do_execreg(int regname, int colon, int addcr, int silent)
if (colon && i > 0) {
p = (char_u *)skipwhite((char *)str);
if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')) {
- str = execreg_line_continuation((char_u **)reg->y_array, &i);
+ str = execreg_line_continuation(reg->y_array, &i);
free_str = true;
}
}
@@ -1945,7 +1961,7 @@ static void mb_adjust_opend(oparg_T *oap)
{
if (oap->inclusive) {
char *p = (char *)ml_get(oap->end.lnum);
- oap->end.col += mb_tail_off(p, p + oap->end.col);
+ oap->end.col += utf_cp_tail_off(p, p + oap->end.col);
}
}
@@ -2936,7 +2952,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
xfree(reg->y_array);
}
- if (message && (p_ch > 0 || ui_has(kUIMessages))) { // Display message about yank?
+ if (message) { // Display message about yank?
if (yank_type == kMTCharWise && yanklines == 1) {
yanklines = 0;
}
@@ -4480,6 +4496,9 @@ static void op_format(oparg_T *oap, int keep_cursor)
if (keep_cursor) {
curwin->w_cursor = saved_cursor;
saved_cursor.lnum = 0;
+
+ // formatting may have made the cursor position invalid
+ check_cursor();
}
if (oap->is_VIsual) {
@@ -5017,7 +5036,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
linenr_T amount = Prenum1;
// do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
- // buffer is not completly updated yet. Postpone updating folds until before
+ // buffer is not completely updated yet. Postpone updating folds until before
// the call to changed_lines().
disable_fold_update++;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index cfd8248eb6..ba77d12a3d 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -37,6 +37,7 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -49,6 +50,7 @@
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/macros.h"
#include "nvim/mapping.h"
@@ -1325,7 +1327,6 @@ int do_set(char *arg, int opt_flags)
char *saved_newval = NULL;
unsigned newlen;
int comma;
- bool new_value_alloced = false; // new string option was allocated
// When using ":set opt=val" for a global option
// with a local value the local value will be
@@ -1365,7 +1366,6 @@ int do_set(char *arg, int opt_flags)
// default value was already expanded, only
// required when an environment variable was set
// later
- new_value_alloced = true;
if (newval == NULL) {
newval = empty_option;
} else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) {
@@ -1379,7 +1379,6 @@ int do_set(char *arg, int opt_flags)
}
} else if (nextchar == '<') { // set to global val
newval = vim_strsave(*(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL));
- new_value_alloced = true;
} else {
arg++; // jump to after the '=' or ':'
@@ -1624,7 +1623,6 @@ int do_set(char *arg, int opt_flags)
if (save_arg != NULL) { // number for 'whichwrap'
arg = (char *)save_arg;
}
- new_value_alloced = true;
}
// Set the new value.
@@ -1659,8 +1657,7 @@ int do_set(char *arg, int opt_flags)
// for ":set" on local options. Note: when setting
// 'syntax' or 'filetype' autocommands may be
// triggered that can cause havoc.
- errmsg = did_set_string_option(opt_idx, (char_u **)varp,
- new_value_alloced, oldval,
+ errmsg = did_set_string_option(opt_idx, (char_u **)varp, oldval,
errbuf, sizeof(errbuf),
opt_flags, &value_checked);
@@ -2299,9 +2296,9 @@ static char *set_string_option(const int opt_idx, const char *const value, const
char *const saved_newval = xstrdup(s);
int value_checked = false;
- char *const r = did_set_string_option(opt_idx, (char_u **)varp, true,
- (char_u *)oldval,
- NULL, 0, opt_flags, &value_checked);
+ char *const r = did_set_string_option(opt_idx, (char_u **)varp, (char_u *)oldval,
+ NULL, 0,
+ opt_flags, &value_checked);
if (r == NULL) {
did_set_option(opt_idx, opt_flags, true, value_checked);
}
@@ -2430,19 +2427,18 @@ static char *check_mousescroll(char *string)
}
/// Handle string options that need some action to perform when changed.
+/// The new value must be allocated.
/// Returns NULL for success, or an error message for an error.
///
/// @param opt_idx index in options[] table
/// @param varp pointer to the option variable
-/// @param new_value_alloced new value was allocated
/// @param oldval previous value of the option
/// @param errbuf buffer for errors, or NULL
/// @param errbuflen length of errors buffer
/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
/// @param value_checked value was checked to be safe, no need to set P_INSECURE
-static char *did_set_string_option(int opt_idx, char_u **varp, bool new_value_alloced,
- char_u *oldval, char *errbuf, size_t errbuflen, int opt_flags,
- int *value_checked)
+static char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *errbuf,
+ size_t errbuflen, int opt_flags, int *value_checked)
{
char *errmsg = NULL;
char_u *s, *p;
@@ -3021,7 +3017,7 @@ ambw_end:
}
// add / remove window bars for 'winbar'
if (gvarp == (char_u **)&p_wbr) {
- set_winbar();
+ set_winbar(true);
}
} else if (gvarp == &p_cpt) {
// check if it is a valid value for 'complete' -- Acevedo
@@ -3097,11 +3093,8 @@ ambw_end:
(char **)&p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL,
CPO_TO_CPO_FLAGS);
if (p != NULL) {
- if (new_value_alloced) {
- free_string_option(p_pt);
- }
+ free_string_option(p_pt);
p_pt = p;
- new_value_alloced = true;
}
}
} else if (varp == &p_bs) { // 'backspace'
@@ -3344,9 +3337,7 @@ ambw_end:
* If error detected, restore the previous value.
*/
if (errmsg != NULL) {
- if (new_value_alloced) {
- free_string_option(*varp);
- }
+ free_string_option(*varp);
*varp = oldval;
/*
* When resetting some values, need to act on it.
@@ -3363,11 +3354,7 @@ ambw_end:
if (free_oldval) {
free_string_option(oldval);
}
- if (new_value_alloced) {
- options[opt_idx].flags |= P_ALLOCED;
- } else {
- options[opt_idx].flags &= ~P_ALLOCED;
- }
+ options[opt_idx].flags |= P_ALLOCED;
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
&& ((int)options[opt_idx].indir & PV_BOTH)) {
@@ -5045,28 +5032,29 @@ static int findoption(const char *const arg)
/// @param stringval NULL when only checking existence
///
/// @returns:
-/// Toggle option: 2, *numval gets value.
-/// Number option: 1, *numval gets value.
-/// String option: 0, *stringval gets allocated string.
-/// Hidden Number or Toggle option: -1.
-/// hidden String option: -2.
-/// unknown option: -3.
-int get_option_value(const char *name, long *numval, char **stringval, int opt_flags)
+/// Number option: gov_number, *numval gets value.
+/// Tottle option: gov_bool, *numval gets value.
+/// String option: gov_string, *stringval gets allocated string.
+/// Hidden Number option: gov_hidden_number.
+/// Hidden Toggle option: gov_hidden_bool.
+/// Hidden String option: gov_hidden_string.
+/// Unknown option: gov_unknown.
+getoption_T get_option_value(const char *name, long *numval, char **stringval, int opt_flags)
{
if (get_tty_option(name, stringval)) {
- return 0;
+ return gov_string;
}
int opt_idx = findoption(name);
- if (opt_idx < 0) { // Unknown option.
- return -3;
+ if (opt_idx < 0) { // option not in the table
+ return gov_unknown;
}
char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags);
if (options[opt_idx].flags & P_STRING) {
if (varp == NULL) { // hidden option
- return -2;
+ return gov_hidden_string;
}
if (stringval != NULL) {
if ((char_u **)varp == &p_pt) { // 'pastetoggle'
@@ -5075,26 +5063,24 @@ int get_option_value(const char *name, long *numval, char **stringval, int opt_f
*stringval = xstrdup(*(char **)(varp));
}
}
- return 0;
+ return gov_string;
}
if (varp == NULL) { // hidden option
- return -1;
+ return (options[opt_idx].flags & P_NUM) ? gov_hidden_number : gov_hidden_bool;
}
if (options[opt_idx].flags & P_NUM) {
*numval = *(long *)varp;
- return 1;
- }
-
- // Special case: 'modified' is b_changed, but we also want to consider
- // it set when 'ff' or 'fenc' changed.
- if ((int *)varp == &curbuf->b_changed) {
- *numval = curbufIsChanged();
} else {
- *numval = (long)*(int *)varp; // NOLINT(whitespace/cast)
+ // Special case: 'modified' is b_changed, but we also want to consider
+ // it set when 'ff' or 'fenc' changed.
+ if ((int *)varp == &curbuf->b_changed) {
+ *numval = curbufIsChanged();
+ } else {
+ *numval = (long)(*(int *)varp);
+ }
}
-
- return 2;
+ return (options[opt_idx].flags & P_NUM) ? gov_number : gov_bool;
}
// Returns the option attributes and its value. Unlike the above function it
@@ -5301,6 +5287,14 @@ char *set_option_value(const char *const name, const long number, const char *co
return NULL;
}
+/// Return true if "name" is a string option.
+/// Returns false if option "name" does not exist.
+bool is_string_option(const char *name)
+{
+ int idx = findoption(name);
+ return idx >= 0 && (options[idx].flags & P_STRING);
+}
+
// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
// When "has_lt" is true there is a '<' before "*arg_arg".
// Returns 0 when the key is not recognized.
@@ -6457,6 +6451,7 @@ void didset_window_options(win_T *wp)
set_chars_option(wp, &wp->w_p_lcs, true);
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp);
+ set_winbar_win(wp, false);
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
}
@@ -6972,7 +6967,7 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags)
}
}
-int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)
+int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file)
{
int num_normal = 0; // Nr of matching non-term-code settings
int match;
@@ -6994,7 +6989,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***
if (loop == 0) {
num_normal++;
} else {
- (*file)[count++] = vim_strsave((char_u *)names[match]);
+ (*file)[count++] = xstrdup(names[match]);
}
}
}
@@ -7021,7 +7016,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***
if (loop == 0) {
num_normal++;
} else {
- (*file)[count++] = vim_strsave(str);
+ (*file)[count++] = (char *)vim_strsave(str);
}
}
}
@@ -7032,18 +7027,18 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***
} else {
return OK;
}
- *file = (char_u **)xmalloc((size_t)(*num_file) * sizeof(char_u *));
+ *file = xmalloc((size_t)(*num_file) * sizeof(char_u *));
}
}
return OK;
}
-void ExpandOldSetting(int *num_file, char_u ***file)
+void ExpandOldSetting(int *num_file, char ***file)
{
char_u *var = NULL;
*num_file = 0;
- *file = (char_u **)xmalloc(sizeof(char_u *));
+ *file = xmalloc(sizeof(char_u *));
/*
* For a terminal key code expand_option_idx is < 0.
@@ -7078,7 +7073,7 @@ void ExpandOldSetting(int *num_file, char_u ***file)
}
#endif
- *file[0] = buf;
+ *file[0] = (char *)buf;
*num_file = 1;
}
@@ -7890,16 +7885,15 @@ static bool briopt_check(win_T *wp)
bool bri_sbr = false;
int bri_list = 0;
- char_u *p = wp->w_p_briopt;
- while (*p != NUL)
- {
+ char *p = (char *)wp->w_p_briopt;
+ while (*p != NUL) {
if (STRNCMP(p, "shift:", 6) == 0
&& ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) {
p += 6;
- bri_shift = getdigits_int((char **)&p, true, 0);
+ bri_shift = getdigits_int(&p, true, 0);
} else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) {
p += 4;
- bri_min = getdigits_int((char **)&p, true, 0);
+ bri_min = getdigits_int(&p, true, 0);
} else if (STRNCMP(p, "sbr", 3) == 0) {
p += 3;
bri_sbr = true;
diff --git a/src/nvim/option.h b/src/nvim/option.h
index 9321dd5454..a5a57cc66d 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -3,6 +3,17 @@
#include "nvim/ex_cmds_defs.h" // for exarg_T
+/// Returned by get_option_value().
+typedef enum {
+ gov_unknown,
+ gov_bool,
+ gov_number,
+ gov_string,
+ gov_hidden_bool,
+ gov_hidden_number,
+ gov_hidden_string,
+} getoption_T;
+
// flags for buf_copy_options()
#define BCO_ENTER 1 // going to enter the buffer
#define BCO_ALWAYS 2 // always copy the options
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 37f3770506..fd4661f9f9 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2063,7 +2063,7 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_ssop',
- defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize"}
+ defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize,terminal"}
},
{
full_name='shada', abbreviation='sd',
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 9283ea2e42..8f2018c1f4 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -47,30 +47,30 @@ typedef struct {
# include "os/shell.c.generated.h"
#endif
-static void save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file)
+static void save_patterns(int num_pat, char **pat, int *num_file, char ***file)
{
*file = xmalloc((size_t)num_pat * sizeof(char_u *));
for (int i = 0; i < num_pat; i++) {
- char_u *s = vim_strsave(pat[i]);
+ char_u *s = vim_strsave((char_u *)pat[i]);
// Be compatible with expand_filename(): halve the number of
// backslashes.
backslash_halve(s);
- (*file)[i] = s;
+ (*file)[i] = (char *)s;
}
*num_file = num_pat;
}
-static bool have_wildcard(int num, char_u **file)
+static bool have_wildcard(int num, char **file)
{
for (int i = 0; i < num; i++) {
- if (path_has_wildcard(file[i])) {
+ if (path_has_wildcard((char_u *)file[i])) {
return true;
}
}
return false;
}
-static bool have_dollars(int num, char_u **file)
+static bool have_dollars(int num, char **file)
{
for (int i = 0; i < num; i++) {
if (vim_strchr((char *)file[i], '$') != NULL) {
@@ -98,7 +98,7 @@ static bool have_dollars(int num, char_u **file)
/// copied into *file.
///
/// @returns OK for success or FAIL for error.
-int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
+int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, int flags)
FUNC_ATTR_NONNULL_ARG(3)
FUNC_ATTR_NONNULL_ARG(4)
{
@@ -151,7 +151,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
// Don't allow the use of backticks in secure.
if (secure) {
for (i = 0; i < num_pat; i++) {
- if (vim_strchr((char *)pat[i], '`') != NULL
+ if (vim_strchr(pat[i], '`') != NULL
&& (check_secure())) {
return FAIL;
}
@@ -297,7 +297,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
}
// Copy one character.
- *p++ = pat[i][j];
+ *p++ = (char_u)pat[i][j];
}
*p = NUL;
}
@@ -471,7 +471,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
// Isolate the individual file names.
p = buffer;
for (i = 0; i < *num_file; i++) {
- (*file)[i] = p;
+ (*file)[i] = (char *)p;
// Space or NL separates
if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
|| shell_style == STYLE_VIMGLOB) {
@@ -496,19 +496,19 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
// Move the file names to allocated memory.
for (j = 0, i = 0; i < *num_file; i++) {
// Require the files to exist. Helps when using /bin/sh
- if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) {
+ if (!(flags & EW_NOTFOUND) && !os_path_exists((char_u *)(*file)[i])) {
continue;
}
// check if this entry should be included
- dir = (os_isdir((*file)[i]));
+ dir = (os_isdir((char_u *)(*file)[i]));
if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) {
continue;
}
// Skip files that are not executable if we check for that.
if (!dir && (flags & EW_EXEC)
- && !os_can_exe((char *)(*file)[i], NULL, !(flags & EW_SHELLCMD))) {
+ && !os_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD))) {
continue;
}
@@ -517,7 +517,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file
if (dir) {
add_pathsep((char *)p); // add '/' to a directory name
}
- (*file)[j++] = p;
+ (*file)[j++] = (char *)p;
}
xfree(buffer);
*num_file = j;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index b22c0a18bd..a0b09bcec2 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1211,7 +1211,7 @@ static bool has_special_wildchar(char_u *p)
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set
/// to NULL or points to "".
-int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
+int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, int flags)
{
garray_T ga;
char_u *p;
@@ -1240,8 +1240,8 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
* For `=expr` do use the internal function.
*/
for (int i = 0; i < num_pat; i++) {
- if (has_special_wildchar(pat[i])
- && !(vim_backtick(pat[i]) && pat[i][1] == '=')) {
+ if (has_special_wildchar((char_u *)pat[i])
+ && !(vim_backtick((char_u *)pat[i]) && pat[i][1] == '=')) {
return os_expand_wildcards(num_pat, pat, num_file, file, flags);
}
}
@@ -1256,13 +1256,13 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
for (int i = 0; i < num_pat; ++i) {
add_pat = -1;
- p = pat[i];
+ p = (char_u *)pat[i];
if (vim_backtick(p)) {
add_pat = expand_backtick(&ga, p, flags);
if (add_pat == -1) {
recursive = false;
- FreeWild(ga.ga_len, (char_u **)ga.ga_data);
+ FreeWild(ga.ga_len, ga.ga_data);
*num_file = 0;
*file = NULL;
return FAIL;
@@ -1272,7 +1272,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
if ((has_env_var(p) && !(flags & EW_NOTENV)) || *p == '~') {
p = expand_env_save_opt(p, true);
if (p == NULL) {
- p = pat[i];
+ p = (char_u *)pat[i];
}
#ifdef UNIX
/*
@@ -1338,13 +1338,13 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH)) {
uniquefy_paths(&ga, p);
}
- if (p != pat[i]) {
+ if (p != (char_u *)pat[i]) {
xfree(p);
}
}
*num_file = ga.ga_len;
- *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : NULL;
+ *file = (ga.ga_data != NULL) ? ga.ga_data : NULL;
recursive = false;
@@ -1352,7 +1352,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
}
/// Free the list of files returned by expand_wildcards() or other expansion functions.
-void FreeWild(int count, char_u **files)
+void FreeWild(int count, char **files)
{
if (count <= 0 || files == NULL) {
return;
@@ -2123,21 +2123,20 @@ char_u *path_shorten_fname(char_u *full_path, char_u *dir_name)
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set
/// to NULL or points to "".
-int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, int flags)
+int expand_wildcards_eval(char_u **pat, int *num_file, char ***file, int flags)
{
int ret = FAIL;
char_u *eval_pat = NULL;
- char_u *exp_pat = *pat;
+ char *exp_pat = (char *)(*pat);
char *ignored_msg;
size_t usedlen;
if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') {
- ++emsg_off;
- eval_pat = eval_vars(exp_pat, exp_pat, &usedlen,
- NULL, &ignored_msg, NULL);
- --emsg_off;
+ emsg_off++;
+ eval_pat = eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, NULL);
+ emsg_off--;
if (eval_pat != NULL) {
- exp_pat = concat_str(eval_pat, exp_pat + usedlen);
+ exp_pat = (char *)concat_str(eval_pat, (char_u *)exp_pat + usedlen);
}
}
@@ -2167,7 +2166,7 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, int flags
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set to
/// NULL or points to "".
-int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, int flags)
+int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int flags)
{
int retval;
int i, j;
@@ -2190,10 +2189,10 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files,
// check all files in (*files)[]
assert(*num_files == 0 || *files != NULL);
for (i = 0; i < *num_files; i++) {
- ffname = (char_u *)FullName_save((char *)(*files)[i], false);
+ ffname = (char_u *)FullName_save((*files)[i], false);
assert((*files)[i] != NULL);
assert(ffname != NULL);
- if (match_file_list(p_wig, (*files)[i], ffname)) {
+ if (match_file_list(p_wig, (char_u *)(*files)[i], ffname)) {
// remove this matching file from the list
xfree((*files)[i]);
for (j = i; j + 1 < *num_files; j++) {
@@ -2213,15 +2212,15 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files,
if (*num_files > 1) {
non_suf_match = 0;
for (i = 0; i < *num_files; i++) {
- if (!match_suffix((*files)[i])) {
+ if (!match_suffix((char_u *)(*files)[i])) {
//
// Move the name without matching suffix to the front of the list.
//
- p = (*files)[i];
+ p = (char_u *)(*files)[i];
for (j = i; j > non_suf_match; j--) {
(*files)[j] = (*files)[j - 1];
}
- (*files)[non_suf_match++] = p;
+ (*files)[non_suf_match++] = (char *)p;
}
}
}
diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po
index ac96b8b3e4..fae2fd4967 100644
--- a/src/nvim/po/tr.po
+++ b/src/nvim/po/tr.po
@@ -1,44 +1,29 @@
-# Turkish translations for Vim
-# Vim Türkçe çevirileri
-# Copyright (C) 2021 Emir SARI <emir_sari@msn.com>
+# Turkish translations for Neovim
+# Neovim Türkçe çevirileri
+# Copyright (C) 2019-2022 Emir SARI <emir_sari@icloud.com>
# This file is distributed under the same license as the Vim package.
-# Emir SARI <emir_sari@msn.com>, 2019-2021
+# Emir SARI <emir_sari@icloud.com>, 2019-2022
#
msgid ""
msgstr ""
-"Project-Id-Version: Vim Turkish Localization Project\n"
+"Project-Id-Version: Neovim Turkish Localization Project\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-07-16 17:56+0300\n"
-"PO-Revision-Date: 2021-07-16 20:00+0300\n"
-"Last-Translator: Emir SARI <emir_sari@msn.com>\n"
-"Language-Team: Turkish <https://github.com/bitigchi/vim>\n"
+"POT-Creation-Date: 2022-04-13 22:59+0300\n"
+"PO-Revision-Date: 2022-07-20 05:00+0300\n"
+"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
+"Language-Team: Turkish <https://github.com/bitigchi/neovim>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-msgid "E163: There is only one file to edit"
-msgstr "E163: Düzenlenecek yalnızca bir dosya var"
-
-msgid "E164: Cannot go before first file"
-msgstr "E164: İlk dosyadan öncesine gidilemez"
-
-msgid "E165: Cannot go beyond last file"
-msgstr "E165: Son dosyadan öteye gidilemez"
-
-msgid "E610: No argument to delete"
-msgstr "E610: Silinecek bir argüman yok"
-
-msgid "E249: window layout changed unexpectedly"
-msgstr "E249: Pencere yerleşimi beklenmedik bir biçimde değişti"
-
msgid "--Deleted--"
msgstr "--Silindi--"
#, c-format
msgid "auto-removing autocommand: %s <buffer=%d>"
-msgstr "otokomut kendiliğinden kaldırılıyor: %s <buffer=%d>"
+msgstr "otokomut kendiliğinden kaldırılıyor: %s <arabellek=%d>"
#, c-format
msgid "E367: No such group: \"%s\""
@@ -50,18 +35,6 @@ msgstr "E936: Geçerli grup silinemiyor"
msgid "W19: Deleting augroup that is still in use"
msgstr "W19: Kullanımda olan otokomut grubu siliniyor"
-#, c-format
-msgid "E215: Illegal character after *: %s"
-msgstr "E215: * sonrası izin verilmeyen karakter: %s"
-
-#, c-format
-msgid "E216: No such event: %s"
-msgstr "E216: Böyle bir olay yok: %s"
-
-#, c-format
-msgid "E216: No such group or event: %s"
-msgstr "E216: Böyle bir grup veya olay yok: %s"
-
msgid ""
"\n"
"--- Autocommands ---"
@@ -71,7 +44,7 @@ msgstr ""
#, c-format
msgid "E680: <buffer=%d>: invalid buffer number "
-msgstr "E680: <buffer=%d>: Geçersiz arabellek numarası"
+msgstr "E680: <arabellek=%d>: Geçersiz arabellek numarası "
msgid "E217: Can't execute autocommands for ALL events"
msgstr "E217: Otokomutlar TÜM olaylar için çalıştırılamıyor"
@@ -94,23 +67,17 @@ msgstr "%s çalıştırılıyor"
msgid "autocommand %s"
msgstr "%s otokomutu"
-msgid "E972: Blob value does not have the right number of bytes"
-msgstr "E972: İkili geniş nesne değeri doğru bayt sayısına sahip değil"
-
-msgid "E831: bf_key_init() called with empty password"
-msgstr "E831: bf_key_init() boş bir şifre ile çağrıldı"
-
-msgid "E820: sizeof(uint32_t) != 4"
-msgstr "E820: sizeof(uint32_t) != 4"
-
-msgid "E817: Blowfish big/little endian use wrong"
-msgstr "E817: Blowfish yüksek/düşük son haneli kullanımı yanlış"
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * sonrası izin verilmeyen karakter: %s"
-msgid "E818: sha256 test failed"
-msgstr "E818: sha256 testi başarısız oldu"
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Böyle bir olay yok: %s"
-msgid "E819: Blowfish test failed"
-msgstr "E819: Blowfish testi başarısız oldu"
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Böyle bir grup veya olay yok: %s"
msgid "[Location List]"
msgstr "[Konum Listesi]"
@@ -127,12 +94,17 @@ msgstr "E82: Arabellek ayrılamadı, çıkılıyor..."
msgid "E83: Cannot allocate buffer, using other one..."
msgstr "E83: Arabellek ayrılamadı, başka bir tane kullanılıyor..."
-msgid "E931: Buffer cannot be registered"
-msgstr "E931: Arabellek kaydedilemedi"
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Kullanımda olan bir arabellek silinmeye çalışılıyor"
-#, c-format
-msgid "E937: Attempt to delete a buffer that is in use: %s"
-msgstr "E937: Kullanımda olan bir arabellek silinmeye çalışılıyor: %s"
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Hiçbir arabellek bellekten kaldırılmadı"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Hiçbir arabellek silinmedi"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Hiçbir arabellek yok edilmedi"
msgid "E90: Cannot unload last buffer"
msgstr "E90: Son arabellek bellekten kaldırılamıyor"
@@ -150,37 +122,15 @@ msgid "E88: Cannot go before first buffer"
msgstr "E88: İlk arabellekten öncesine gidilemez"
#, c-format
-msgid "E89: No write since last change for buffer %d (add ! to override)"
+msgid ""
+"E89: No write since last change for buffer %<PRId64> (add ! to override)"
msgstr ""
-"E89: %d numaralı arabellek son değişiklikten sonra yazılmadı (geçersiz "
+"E89: %<PRId64> numaralı arabellek son değişiklikten sonra yazılmadı (geçersiz "
"kılmak için ! ekleyin)"
-msgid "E515: No buffers were unloaded"
-msgstr "E515: Hiçbir arabellek bellekten kaldırılmadı"
-
-msgid "E516: No buffers were deleted"
-msgstr "E516: Hiçbir arabellek silinmedi"
-
-msgid "E517: No buffers were wiped out"
-msgstr "E517: Hiçbir arabellek yok edilmedi"
-
-#, c-format
-msgid "%d buffer unloaded"
-msgid_plural "%d buffers unloaded"
-msgstr[0] "%d arabellek bellekten kaldırıldı"
-msgstr[1] "%d arabellek bellekten kaldırıldı"
-
-#, c-format
-msgid "%d buffer deleted"
-msgid_plural "%d buffers deleted"
-msgstr[0] "%d arabellek silindi"
-msgstr[1] "%d arabellek silindi"
-
#, c-format
-msgid "%d buffer wiped out"
-msgid_plural "%d buffers wiped out"
-msgstr[0] "%d arabellek yok edildi"
-msgstr[1] "%d arabellek yok edildi"
+msgid "E89: %s will be killed (add ! to override)"
+msgstr "E89: %s sonlandırılacak (geçersiz kılmak için ! ekleyin)"
msgid "E948: Job still running (add ! to end the job)"
msgstr "E948: İş hâlâ sürüyor (bitirmek için ! ekleyin)"
@@ -199,8 +149,8 @@ msgid "W14: Warning: List of file names overflow"
msgstr "W14: Uyarı: Dosya adları taşımı"
#, c-format
-msgid "E92: Buffer %d not found"
-msgstr "E92: %d numaralı arabellek bulunamadı"
+msgid "E92: Buffer %<PRId64> not found"
+msgstr "E92: %<PRId64> numaralı arabellek bulunamadı"
#, c-format
msgid "E93: More than one match for %s"
@@ -211,8 +161,8 @@ msgid "E94: No matching buffer for %s"
msgstr "E94: %s için eşleşen arabellek yok"
#, c-format
-msgid "line %ld"
-msgstr "%ld. satır"
+msgid "line %<PRId64>"
+msgstr "%<PRId64>. satır"
msgid "E95: Buffer with this name already exists"
msgstr "E95: Aynı adda bir arabellek hâlihazırda var"
@@ -233,14 +183,8 @@ msgid "[readonly]"
msgstr "[saltokunur]"
#, c-format
-msgid "%ld line --%d%%--"
-msgid_plural "%ld lines --%d%%--"
-msgstr[0] "%ld. satır --%d%%"
-msgstr[1] "%ld. satır --%d%%"
-
-#, c-format
-msgid "line %ld of %ld --%d%%-- col "
-msgstr "satır %ld/%ld --%d%%-- sütun "
+msgid "line %<PRId64> of %<PRId64> --%d%%-- col "
+msgstr "satır %<PRId64>/%<PRId64> --%d%%-- sütun "
msgid "[No Name]"
msgstr "[Adsız]"
@@ -269,270 +213,41 @@ msgstr "E382: Yazılamıyor, 'buftype' seçeneği ayarlanmamış"
msgid "[Prompt]"
msgstr "[İstem]"
-msgid "[Popup]"
-msgstr "[Açılır pencere]"
-
msgid "[Scratch]"
msgstr "[Geçici alan]"
-msgid "WARNING: The file has been changed since reading it!!!"
-msgstr "UYARI: Bu dosya açıldıktan sonra başkası tarafından değiştirilmiş!!!"
-
-msgid "Do you really want to write to it"
-msgstr "Yine de yazmak istiyor musunuz?"
-
-msgid "[New]"
-msgstr "[Yeni]"
-
-msgid "[New File]"
-msgstr "[Yeni Dosya]"
-
-msgid "E676: No matching autocommands for acwrite buffer"
-msgstr "E676: acwrite arabelleği için eşleşen bir otokomut yok"
-
-msgid "E203: Autocommands deleted or unloaded buffer to be written"
-msgstr "E203: Otokomutlar arabelleği silmiş veya yazılması için kaldırmışlar"
-
-msgid "E204: Autocommand changed number of lines in unexpected way"
-msgstr "E204: Otokomut satır sayısını beklenmeyen biçimde değiştirdi"
-
-msgid "NetBeans disallows writes of unmodified buffers"
-msgstr "NetBeans değiştirilmemiş arabelleklerin yazılmasına izin vermez"
-
-msgid "Partial writes disallowed for NetBeans buffers"
-msgstr "NetBeans arabellekleri için kısmî yazmalara izin verilmez"
-
-msgid "is a directory"
-msgstr "bir dizin"
-
-msgid "is not a file or writable device"
-msgstr "bir dosya veya yazılabilir aygıt değil"
-
-msgid "writing to device disabled with 'opendevice' option"
-msgstr "aygıta yazma 'opendevice' seçeneği ile kapatılmış"
-
-msgid "is read-only (add ! to override)"
-msgstr "saltokunur (geçersiz kılmak için ! ekleyin)"
-
-msgid "E506: Can't write to backup file (add ! to override)"
-msgstr "E506: Yedek dosyasına yazılamıyor (geçersiz kılmak için ! ekleyin)"
-
-msgid "E507: Close error for backup file (add ! to override)"
-msgstr "E507: Yedek dosya için kapatma hatası (geçersiz kılmak için ! ekleyin)"
-
-msgid "E508: Can't read file for backup (add ! to override)"
-msgstr "E508: Yedek dosyası okunamıyor (geçersiz kılmak için ! ekleyin)"
-
-msgid "E509: Cannot create backup file (add ! to override)"
-msgstr "E509: Yedek dosyası oluşturulamıyor (geçersiz kılmak için ! ekleyin)"
-
-msgid "E510: Can't make backup file (add ! to override)"
-msgstr "E510: Yedek dosyası yapılamıyor (geçersiz kılmak için ! ekleyin) "
-
-msgid "E214: Can't find temp file for writing"
-msgstr "E214: Yazma için geçici dosya bulunamıyor"
-
-msgid "E213: Cannot convert (add ! to write without conversion)"
-msgstr "E213: Dönüştürülemiyor (dönüştürmeden yazmak için ! ekleyin)"
-
-msgid "E166: Can't open linked file for writing"
-msgstr "E166: Bağlı dosya yazma için açılamıyor"
-
-msgid "E212: Can't open file for writing"
-msgstr "E212: Dosya yazma için açılamıyor"
-
-msgid "E949: File changed while writing"
-msgstr "E949: Dosya yazma sırasında değiştirildi"
-
-msgid "E512: Close failed"
-msgstr "E512: Kapatma başarısız oldu"
-
-msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
-msgstr ""
-"E513: Yazma hatası, dönüştürme başarısız (geçersiz kılmak için 'fenc'i boş "
-"bırakın)"
-
-#, c-format
-msgid ""
-"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
-"override)"
-msgstr ""
-"E513: Yazma hatası, %ld. satırda dönüştürme başarısız (geçersiz kılmak için "
-"'fenc'i boş bırakın)"
-
-msgid "E514: write error (file system full?)"
-msgstr "E514: Yazma hatası (dosya sistemi dolu mu?)"
-
-msgid " CONVERSION ERROR"
-msgstr " DÖNÜŞTÜRME HATASI"
-
-#, c-format
-msgid " in line %ld;"
-msgstr " %ld. satırda;"
-
-msgid "[NOT converted]"
-msgstr "[dönüştürülmedi]"
-
-msgid "[converted]"
-msgstr "[dönüştürüldü]"
-
-msgid "[Device]"
-msgstr "[Aygıt]"
-
-msgid " [a]"
-msgstr " [a]"
-
-msgid " appended"
-msgstr " iliştirildi"
-
-msgid " [w]"
-msgstr " [w]"
-
-msgid " written"
-msgstr " yazıldı"
-
-msgid "E205: Patchmode: can't save original file"
-msgstr "E205: Yama kipi: Orijinal dosya kaydedilemiyor"
-
-msgid "E206: patchmode: can't touch empty original file"
-msgstr "E206: Yama kipi: Orijinal boş dosyaya dokunulamıyor"
-
-msgid "E207: Can't delete backup file"
-msgstr "E207: Yedek dosyası silinemiyor"
-
-msgid ""
-"\n"
-"WARNING: Original file may be lost or damaged\n"
-msgstr ""
-"\n"
-"UYARI: Orijinal dosya kaybolmuş veya hasar görmüş olabilir\n"
-
-msgid "don't quit the editor until the file is successfully written!"
-msgstr "dosya başarılı bir biçimde yazılana kadar düzenleyiciden çıkmayın!"
-
msgid "W10: Warning: Changing a readonly file"
msgstr "W10: Uyarı: Saltokunur bir dosya değiştiriliyor"
-msgid "E902: Cannot connect to port"
-msgstr "E902: Kapıya bağlanılamıyor"
-
-msgid "E898: socket() in channel_connect()"
-msgstr "E898: channel_connect() içinde socket()"
-
-#, c-format
-msgid "E901: getaddrinfo() in channel_open(): %s"
-msgstr "E901: channel_open() içinde getaddrinfo(): %s"
-
-msgid "E901: gethostbyname() in channel_open()"
-msgstr "E901: channel_open() içinde gethostbyname()"
-
-msgid "E903: received command with non-string argument"
-msgstr "E903: Dizi olmayan argüman içeren komut alındı"
-
-msgid "E904: last argument for expr/call must be a number"
-msgstr "E904: İfadenin/çağrının son argüman bir sayı olmalıdır"
-
-msgid "E904: third argument for call must be a list"
-msgstr "E904: Çağrının üçüncü argümanı bir liste olmalıdır"
-
-#, c-format
-msgid "E905: received unknown command: %s"
-msgstr "E905: Bilinmeyen komut alındı: %s"
-
-msgid "E906: not an open channel"
-msgstr "E906: Açık bir kanal değil"
-
-#, c-format
-msgid "E630: %s(): write while not connected"
-msgstr "E630: %s(): Bağlantı yokken yazım"
-
-#, c-format
-msgid "E631: %s(): write failed"
-msgstr "E631: %s(): Yazma başarısız"
-
-#, c-format
-msgid "E917: Cannot use a callback with %s()"
-msgstr "E917: %s() ile geri çağırma kullanılamıyor"
+msgid "can only be opened in headless mode"
+msgstr "yalnızca başsız kipte açılabilir"
-msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
-msgstr "E912: ch_evalexpr()/ch_sendexpr() raw/nl kanalları ile kullanılamaz"
-
-msgid "No display"
-msgstr "Görüntü yok"
-
-msgid ": Send failed.\n"
-msgstr ": Gönderme başarısız oldu.\n"
-
-msgid ": Send failed. Trying to execute locally\n"
-msgstr ": Gönderme başarısız oldu. Yerel ortamda çalıştırma deneniyor\n"
-
-#, c-format
-msgid "%d of %d edited"
-msgstr "%d/%d düzenlendi"
+msgid "channel was already open"
+msgstr "kanal halihazırda açıktı"
-msgid "No display: Send expression failed.\n"
-msgstr "Görüntü yok: Gönderme başarısız oldu.\n"
+msgid "Can't send data to closed stream"
+msgstr "Kapalı akışa veri gönderilemez"
-msgid ": Send expression failed.\n"
-msgstr ": Gönderme başarısız oldu.\n"
+msgid "Can't send raw data to rpc channel"
+msgstr "rpc kanalına ham veri gönderilemez"
-msgid "E240: No connection to the X server"
-msgstr "E240: X sunucusuna bağlanılamadı"
+msgid "E474: Failed to convert list to msgpack string buffer"
+msgstr "E474: Liste, msgpack dizi arabelleğine dönüştürülemedi"
-#, c-format
-msgid "E241: Unable to send to %s"
-msgstr "E241: Şuraya gönderilemedi: %s"
-
-msgid "E277: Unable to read a server reply"
-msgstr "E277: Bir sunucu yanıtı okunamadı"
-
-msgid "E941: already started a server"
-msgstr "E941: Sunucu hâlihazırda çalışıyor"
-
-msgid "E942: +clientserver feature not available"
-msgstr "E942: +clientserver özelliği mevcut değil"
-
-msgid "E258: Unable to send to client"
-msgstr "E258: İstemciye gönderilemiyor"
-
-msgid "Used CUT_BUFFER0 instead of empty selection"
-msgstr "Boş seçim yerine CUT_BUFFER0 kullanıldı"
-
-msgid "tagname"
-msgstr "etiket adı"
-
-msgid " kind file\n"
-msgstr " dosya türü\n"
-
-msgid "'history' option is zero"
-msgstr "'history' seçeneği sıfır"
-
-msgid "E821: File is encrypted with unknown method"
-msgstr "E821: Dosya bilinmeyen bir yöntemle şifrelenmiş"
-
-msgid "Warning: Using a weak encryption method; see :help 'cm'"
-msgstr ""
-"Uyarı: Zayıf bir şifreleme yöntemi kullanılıyor; bilgi için: :help 'cm'"
-
-msgid ""
-"Note: Encryption of swapfile not supported, disabling swap- and undofile"
-msgstr "Takas dosyası şifrelemesi desteklenmiyor, takas ve geri al dosyası "
-"devre dışı bırakılıyor"
-
-msgid "Enter encryption key: "
-msgstr "Şifreleme anahtarı girin: "
+msgid "E545: Missing colon"
+msgstr "E545: İki nokta eksik"
-msgid "Enter same key again: "
-msgstr "Aynı anahtarı yeniden girin: "
+msgid "E546: Illegal mode"
+msgstr "E546: İzin verilmeyen kip"
-msgid "Keys don't match!"
-msgstr "Anahtarlar eşleşmiyor!"
+msgid "E548: digit expected"
+msgstr "E548: Basamak bekleniyordu"
-msgid "[crypted]"
-msgstr "[şifreli]"
+msgid "E549: Illegal percentage"
+msgstr "E549: İzin verilmeyen yüzde"
msgid "Entering Debug mode. Type \"cont\" to continue."
-msgstr "Hata Ayıklama kipine giriliyor. Sürdürmek için \"cont\" yazın."
+msgstr "Hata ayıklama kipine giriliyor. Sürdürmek için \"cont\" yazın."
#, c-format
msgid "Oldval = \"%s\""
@@ -544,8 +259,8 @@ msgid "Newval = \"%s\""
msgstr "Yeni değer = \"%s\""
#, c-format
-msgid "line %ld: %s"
-msgstr "%ld. satır: %s"
+msgid "line %<PRId64>: %s"
+msgstr "%<PRId64>. satır: %s"
#, c-format
msgid "cmd: %s"
@@ -559,8 +274,8 @@ msgid "frame at highest level: %d"
msgstr "çerçeve en yüksek düzeyde: %d"
#, c-format
-msgid "Breakpoint in \"%s%s\" line %ld"
-msgstr "\"%s%s\" içinde kesme noktası, %ld. satır"
+msgid "Breakpoint in \"%s%s\" line %<PRId64>"
+msgstr "\"%s%s\" içinde kesme noktası, %<PRId64>. satır"
#, c-format
msgid "E161: Breakpoint not found: %s"
@@ -570,23 +285,16 @@ msgid "No breakpoints defined"
msgstr "Hiçbir kesme noktası tanımlanmamış"
#, c-format
-msgid "%3d %s %s line %ld"
-msgstr "%3d %s %s %ld. satır"
+msgid "%3d %s %s line %<PRId64>"
+msgstr "%3d %s %s %<PRId64>. satır"
#, c-format
msgid "%3d expr %s"
msgstr "%3d ifade %s"
-msgid "extend() argument"
-msgstr "extend() argümanı"
-
#, c-format
-msgid "E737: Key already exists: %s"
-msgstr "E737: Anahtar hâlihazırda var: %s"
-
-#, c-format
-msgid "E96: Cannot diff more than %d buffers"
-msgstr "E96: %d arabellekten fazlasında karşılaştırma yapılamıyor"
+msgid "E96: Cannot diff more than %<PRId64> buffers"
+msgstr "E96: %<PRId64> arabellekten fazlasında karşılaştırma yapılamıyor"
#, c-format
msgid "Not enough memory to use internal diff for buffer \"%s\""
@@ -601,18 +309,12 @@ msgstr "E97: Karşılaştırma yapılamıyor"
msgid "E960: Problem creating the internal diff"
msgstr "E960: Karşılaştırma hazırlanırken sorun"
-msgid "Patch file"
-msgstr "Yama dosyası"
-
msgid "E816: Cannot read patch output"
msgstr "E816: Yama çıktısı okunamıyor"
msgid "E98: Cannot read diff output"
msgstr "E98: Karşılaştırma çıktısı okunamıyor"
-msgid "E959: Invalid diff format."
-msgstr "E959: Geçersiz karşılaştırma biçimi"
-
msgid "E99: Current buffer is not in diff mode"
msgstr "E99: Şu anki arabellek karşılaştırma kipinde değil"
@@ -639,6 +341,19 @@ msgstr "E103: Arabellek \"%s\" karşılaştırma kipinde değil"
msgid "E787: Buffer changed unexpectedly"
msgstr "E787: Arabellek beklenmeyen bir biçimde değiştirildi"
+#, c-format
+msgid "E1214: Digraph must be just two characters: %s"
+msgstr "E1214: İkili harf yalnızca iki karakter olmalıdır: %s"
+
+#, c-format
+msgid "E1215: Digraph must be one character: %s"
+msgstr "E1215: İkili harf tek bir karakter olmalıdır: %s"
+
+msgid ""
+"E1216: digraph_setlist() argument must be a list of lists with two items"
+msgstr ""
+"E1216: digraph_setlist() argümanı iki ögeli listelerin bir listesi olmalıdır"
+
msgid "E104: Escape not allowed in digraph"
msgstr "E104: Kaçan, ikili harflerde kullanılamaz"
@@ -726,6 +441,186 @@ msgstr "E105: :loadkeymap kaynak alınmayan bir dosyada kullanılıyor"
msgid "E791: Empty keymap entry"
msgstr "E791: Boş düğme eşlem girdisi"
+msgid " Keyword completion (^N^P)"
+msgstr " Anahtar sözcük tamamlaması (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X kipi (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Tam satır tamamlaması (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Dosya adı tamamlaması (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Etiket tamamlaması (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Yol dizgisi tamamlaması (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Tanım tamamlaması (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Sözlük tamamlaması (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Eşanlamlılar sözlüğü tamamlaması (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Komut satırı tamamlaması (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Kullanıcı tanımlı tamamlamalar (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni tamamlaması (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Yazım önerisi (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Dahili anahtar sözcük tamamlaması (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Paragrafın sonuna varıldı"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Tamamlama işlevi pencereyi değiştirdi"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Tamamlama işlevi metni sildi"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' seçeneği boş"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' seçeneği boş"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Sözlük taranıyor: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (ekle) Kaydır (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (değiştir) Kaydır (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Taranıyor: %s"
+
+msgid "Scanning tags."
+msgstr "Etiketler taranıyor..."
+
+msgid "match in file"
+msgstr "dosya içinde eşleşme"
+
+msgid " Adding"
+msgstr " Ekleniyor"
+
+msgid "-- Searching..."
+msgstr "-- Aranıyor..."
+
+msgid "Back at original"
+msgstr "Başlangıca geri dönüldü"
+
+msgid "Word from other line"
+msgstr "Sözcük diğer satırdan"
+
+msgid "The only match"
+msgstr "Tek eşleşen"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "eşleşme %d/%d"
+
+#, c-format
+msgid "match %d"
+msgstr "eşleşme %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: :let içinde beklenmeyen karakter"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' eksik"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: [:], bir Sözlük ile kullanılamaz"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: İzin verilmeyen değişken adı: %s"
+
+msgid "E995: Cannot modify existing variable"
+msgstr "E995: Mevcut değişken değiştirilemiyor"
+
+msgid "E274: No white space allowed before parenthesis"
+msgstr "E274: Ayraçtan önce boşluğa izin verilmiyor"
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Değişken %s kilitlenemiyor veya açılamıyor"
+
+#, c-format
+msgid "E80: Error while writing: %s"
+msgstr "E80: Yazma sırasında hata: %s"
+
+msgid "E1098: String, List or Blob required"
+msgstr "E1098: Dizi, Liste veya İkili Nesne gerekiyor"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s= için yanlış değişken türü"
+
+msgid ""
+"E5700: Expression from 'spellsuggest' must yield lists with exactly two "
+"values"
+msgstr ""
+"E5700: 'spellsuggest'ten olan ifade, yalnızca iki değerli listelere izin "
+"vermelidir"
+
+msgid "E991: cannot use =<< here"
+msgstr "E991: Burada =<< kullanılamaz"
+
+msgid "E221: Marker cannot start with lower case letter"
+msgstr "E221: İmleyici küçük harfle başlayamaz"
+
+msgid "E172: Missing marker"
+msgstr "E172: İmleyici eksik"
+
+#, c-format
+msgid "E990: Missing end marker '%s'"
+msgstr "E990: Son imleyici '%s' eksik"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Liste ögelerinden daha az hedef var"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Liste ögelerinden daha fazla hedef var"
+
+msgid "E452: Double ; in list of variables"
+msgstr "E452: Değişkenler listesinde çifte ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s için değişkenler listelenemiyor"
+
+msgid "E996: Cannot lock an environment variable"
+msgstr "E996: Ortam değişkeni kilitlenemiyor"
+
+msgid "E996: Cannot lock an option"
+msgstr "E996: Seçenek kilitlenemiyor"
+
+msgid "E996: Cannot lock a register"
+msgstr "E996: Yazmaç kilitlenemiyor"
+
+#, c-format
+msgid "E121: Undefined variable: %.*s"
+msgstr "E121: Tanımlanmamış değişken: %.*s"
+
msgid "E689: Can only index a List, Dictionary or Blob"
msgstr ""
"E689: Yalnızca bir liste, sözlük, veya ikili geniş nesne dizinlenebilir"
@@ -733,26 +628,144 @@ msgstr ""
msgid "E708: [:] must come last"
msgstr "E708: [:] en son gelmelidir"
+msgid "E713: Cannot use empty key after ."
+msgstr "E713: . sonrası boş anahtar kullanılamaz"
+
msgid "E709: [:] requires a List or Blob value"
msgstr "E709: [:] bir liste veya ikili geniş nesne değeri gerektirir"
+msgid "E972: Blob value does not have the right number of bytes"
+msgstr "E972: İkili geniş nesne değeri doğru bayt sayısına sahip değil"
+
msgid "E996: Cannot lock a range"
msgstr "E996: Erim kilitlenemiyor"
+msgid "E710: List value has more items than target"
+msgstr "E710: Liste değeri hedeften daha fazla ögeye sahip"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Liste değeri yeterli ögeye sahip değil"
+
msgid "E996: Cannot lock a list or dict"
msgstr "E996: Bir liste veya sözlük kilitlenemiyor"
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for sonrası \"in\" eksik"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Böyle bir değişken yok: \"%s\""
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' sonrası ':' eksik"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Bir kayan noktalı değer ile '%' kullanılamaz"
+
+msgid "E973: Blob literal should have an even number of hex characters"
+msgstr ""
+"E973: İkili geniş nesne hazır bilgisi çift onalt. karakterlere iye olmalıdır"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' eksik"
+
msgid "E260: Missing name after ->"
msgstr "E260: -> sonrası ad eksik"
msgid "E695: Cannot index a Funcref"
msgstr "E695: Bir Funcref dizinlenemiyor"
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Özel bir değişken dizinlenemiyor"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Seçenek adı eksik: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Bilinmeyen seçenek: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Tırnak eksik: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Tırnak eksik: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Listede virgül eksik: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Liste sonunda ']' eksik: %s"
+
msgid "Not enough memory to set references, garbage collection aborted!"
msgstr "Referansları ayarlamak için yetersiz bellek, atık toplama durduruldu"
-msgid "E724: variable nested too deep for displaying"
-msgstr "E724: Değişken çok iç içe geçtiğinden görüntülenemiyor"
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Sözlükte iki nokta eksik: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Sözlükte yinelenmiş anahtar: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Sözlükte virgül eksik: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Sözlük sonu '}' eksik: %s"
+
+msgid "map() argument"
+msgstr "map() argümanı"
+
+msgid "filter() argument"
+msgstr "filter() argümanı"
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Bilinmeyen işlev: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: Bir sözlük bekleniyordu"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function() ikinci argümanı bir liste veya sözlük olmalıdır"
+
+msgid "E5050: {opts} must be the only argument"
+msgstr "E5050: {opts}, tek argüman olmalıdır"
+
+#, c-format
+msgid "Executing command: \"%s\""
+msgstr "Komut çalıştırılıyor: \"%s\""
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Geçersiz geri çağırma argümanı"
+
+#, c-format
+msgid "E963: setting %s to value with wrong type"
+msgstr "E963: %s yanlış türe sahip değere ayarlanıyor"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%.*s\""
+msgstr "E794: Kum havuzunda değişken ayarlanamaz: \"%.*s\""
+
+#, c-format
+msgid "E795: Cannot delete variable %.*s"
+msgstr "E795: %.*s değişkeni silinemiyor"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref değişkeni BÜYÜK harf ile başlamalıdır: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Değişken adı mevcut işlevle çakışıyor: %s"
msgid "E698: variable nested too deep for making a copy"
msgstr "E698: Değişken kopyalama için çok iç içe geçmiş"
@@ -764,127 +777,705 @@ msgstr ""
"\n"
"\tEn son şuradan ayarlandı: "
+msgid "E5009: $VIMRUNTIME is empty or unset"
+msgstr "E5009: $VIMRUNTIME boş veya ayarlanmamış"
+
+#, c-format
+msgid "E5009: Invalid $VIMRUNTIME: %s"
+msgstr "E5009: Geçersiz VIMRUNTIME: %s"
+
+msgid "E5009: Invalid 'runtimepath'"
+msgstr "E5009: Geçersiz 'runtimepath'"
+
+msgid "E977: Can only compare Blob with Blob"
+msgstr ""
+"E977: Bir ikili geniş öğe yalnızca kendinden bir başkası ile "
+"karşılaştırılabilir"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Bir liste yalnızca başka bir liste ile karşılaştırılabilir"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Geçersiz liste işlemi"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Bir sözlük yalnızca başka bir sözlük ile karşılaştırılabilir"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Geçersiz sözlük işlemi"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Geçersiz Funcref işlemi"
+
+#, c-format
+msgid "E474: Expected comma before list item: %s"
+msgstr "E474: Liste ögesi öncesi virgül bekleniyordu: %s"
+
+#, c-format
+msgid "E474: Expected colon before dictionary value: %s"
+msgstr "E474: Sözlük değeri öncesi iki nokta bekleniyordu: %s"
+
+#, c-format
+msgid "E474: Expected string key: %s"
+msgstr "E474: Dizi anahtarı bekleniyordu: %s"
+
+#, c-format
+msgid "E474: Expected comma before dictionary key: %s"
+msgstr "E474: Sözlük anahtarı öncesi virgül bekleniyordu: %s"
+
+#, c-format
+msgid "E474: Unfinished escape sequence: %.*s"
+msgstr "E474: Bitirilmemiş kaçış sırası: %.*s"
+
+#, c-format
+msgid "E474: Unfinished unicode escape sequence: %.*s"
+msgstr "E474: Tamamlanmamış Unicode kaçış sıralaması: %.*s"
+
+#, c-format
+msgid "E474: Expected four hex digits after \\u: %.*s"
+msgstr "E474: \\u sonrası dört onaltılık basamak bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Unknown escape sequence: %.*s"
+msgstr "E474: Bilinmeyen kaçış sıralaması: %.*s"
+
+#, c-format
+msgid "E474: ASCII control characters cannot be present inside string: %.*s"
+msgstr "E474: ASCII denetim karakterleri, dizi içinde var olamaz: %.*s"
+
+#, c-format
+msgid "E474: Only UTF-8 strings allowed: %.*s"
+msgstr "E474: Yalnızca UTF-8 dizilere izin verilir: %.*s"
+
+#, c-format
+msgid ""
+"E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: "
+"%.*s"
+msgstr ""
+"E474: Yalnızca U+10FFFF'e kadar olan UTF-8 kod noktalarına kaçışsız "
+"var olma izni verilir: %.*s"
+
+#, c-format
+msgid "E474: Expected string end: %.*s"
+msgstr "E474: Dizi sonu bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Leading zeroes are not allowed: %.*s"
+msgstr "E474: Öncü sıfırlara zin verilmiyor: %.*s"
+
+#, c-format
+msgid "E474: Missing number after minus sign: %.*s"
+msgstr "E474: Eksi imi sonrası sayı eksik: %.*s"
+
+#, c-format
+msgid "E474: Missing number after decimal dot: %.*s"
+msgstr "E474: Ondalık noktası sonrası sayı eksik: %.*s"
+
+#, c-format
+msgid "E474: Missing exponent: %.*s"
+msgstr "E474: Argüman eksik: %.*s"
+
+#, c-format
+msgid ""
+"E685: internal error: while converting number \"%.*s\" to float string2float "
+"consumed %zu bytes in place of %zu"
+msgstr ""
+"E685: İçsel hata: \"%.*s\" sayısı kayan noktalı değere dönüştürülürken "
+"string2float %zu bayt harcadı, %zu bayt harcaması gerekiyordu"
+
+#, c-format
+msgid ""
+"E685: internal error: while converting number \"%.*s\" to integer vim_str2nr "
+"consumed %i bytes in place of %zu"
+msgstr ""
+"E685: İçsel hata: \"%.*s\" sayısı tamsayıya dönüştürülürken "
+"vim_str2nr %i bayt harcadı, %zu bayt harcaması gerekiyordu"
+
+msgid "E474: Attempt to decode a blank string"
+msgstr "E474: Boş bir dizinin kodu çözülmeye çalışılıyor"
+
+#, c-format
+msgid "E474: No container to close: %.*s"
+msgstr "E474: Kapatılacak kapsayıcı yok: %.*s"
+
+#, c-format
+msgid "E474: Closing list with curly bracket: %.*s"
+msgstr "E474: Liste, kıvrımlı ayraçla kapatılıyor: %.*s"
+
+#, c-format
+msgid "E474: Closing dictionary with square bracket: %.*s"
+msgstr "E474: Sözlük, bir kare ayraç ile kapatılıyor: %.*s"
+
+#, c-format
+msgid "E474: Trailing comma: %.*s"
+msgstr "E474: Sonda virgül: %.*s"
+
+#, c-format
+msgid "E474: Expected value after colon: %.*s"
+msgstr "E474: İki nokta sonrası değer bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Expected value: %.*s"
+msgstr "E474: Değer bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Comma not inside container: %.*s"
+msgstr "E474: Virgül, kapsayıcı içinde değil: %.*s"
+
+#, c-format
+msgid "E474: Duplicate comma: %.*s"
+msgstr "E474: Yinelenen virgül: %.*s"
+
+#, c-format
+msgid "E474: Comma after colon: %.*s"
+msgstr "E474: İki nokta sonrası virgül: %.*s"
+
+#, c-format
+msgid "E474: Using comma in place of colon: %.*s"
+msgstr "E474: İki nokta yerine virgül kullanılıyor: %.*s"
+
+#, c-format
+msgid "E474: Leading comma: %.*s"
+msgstr "E474: Öncü virgül: %.*s"
+
+#, c-format
+msgid "E474: Colon not inside container: %.*s"
+msgstr "E474: İki nokta, kapsayıcı içinde değil: %.*s"
+
+#, c-format
+msgid "E474: Using colon not in dictionary: %.*s"
+msgstr "E474: Sözlük dışında iki nokta kullanılıyor: %.*s"
+
+#, c-format
+msgid "E474: Unexpected colon: %.*s"
+msgstr "E474: Beklenmedik iki nokta: %.*s"
+
+#, c-format
+msgid "E474: Colon after comma: %.*s"
+msgstr "E474: Virgül sonrası iki nokta: %.*s"
+
+#, c-format
+msgid "E474: Duplicate colon: %.*s"
+msgstr "E474: Yinelenen iki nokta: %.*s"
+
+#, c-format
+msgid "E474: Expected null: %.*s"
+msgstr "E474: null bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Expected true: %.*s"
+msgstr "E474: true bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Expected false: %.*s"
+msgstr "E474: false bekleniyordu: %.*s"
+
+#, c-format
+msgid "E474: Unidentified byte: %.*s"
+msgstr "E474: Tanımlanmamış bayt: %.*s"
+
+#, c-format
+msgid "E474: Trailing characters: %.*s"
+msgstr "E474: Sonda fazladan karakterler: %.*s"
+
+#, c-format
+msgid "E474: Unexpected end of input: %.*s"
+msgstr "E474: Beklenmedik girdi sonu: %.*s"
+
+#, c-format
+msgid "key %s"
+msgstr "%s anahtarı"
+
+#, c-format
+msgid "key %s at index %i from special map"
+msgstr "özel eşlemden %s anahtarı, %i indeksinde"
+
+#, c-format
+msgid "index %i"
+msgstr "%i indeksi"
+
+msgid "partial"
+msgstr "kısımsal"
+
+#, c-format
+msgid "argument %i"
+msgstr "%i argümanı"
+
+msgid "partial self dictionary"
+msgstr "kısımsal öz sözlük"
+
+msgid "itself"
+msgstr "kendisi"
+
+msgid "E724: unable to correctly dump variable with self-referencing container"
+msgstr "E724: Özüne başvuran kapsayıcı ile değişken düzgünce dökülemiyor"
+
+msgid "E474: Unable to represent NaN value in JSON"
+msgstr "E474: JSON içinde NaN değer düzgünce temsil edilemiyor"
+
+msgid "E474: Unable to represent infinity in JSON"
+msgstr "E474: JSON içinde sonsuzluk temsil edilemiyor"
+
+#, c-format
+msgid ""
+"E474: String \"%.*s\" contains byte that does not start any UTF-8 character"
+msgstr "E474: \"%.*s\" dizisi, herhangi bir UTF-8 karakter başlatmayan bayt "
+"içeriyor"
+
+#, c-format
+msgid ""
+"E474: UTF-8 string contains code point which belongs to a surrogate pair: "
+"%.*s"
+msgstr "E474: UTF-8 dizisi, bir vekil çifte iye olan kod noktası içeriyor: "
+"%.*s"
+
+msgid "E474: Unable to convert EXT string to JSON"
+msgstr "E474: EXT dizisi, JSON'a dönüştürülemiyor"
+
+#, c-format
+msgid "E474: Error while dumping %s, %s: attempt to dump function reference"
+msgstr "E474: %s dökülürken hata, %s: İşlev başvurusu dökme girişimi"
+
+msgid "E474: Invalid key in special dictionary"
+msgstr "E474: Özel sözlükte geçersiz anahtar"
+
+msgid "encode_tv2string() argument"
+msgstr "encode_tv2string() argümanı"
+
+msgid ":echo argument"
+msgstr ":echo argümanı"
+
+msgid "encode_tv2json() argument"
+msgstr "encode_tv2json() argümanı"
+
+#, c-format
+msgid "E5004: Error while dumping %s, %s: attempt to dump function reference"
+msgstr "E5004: %s dökülürken hata, %s: İşlev başvurusu dökme girişimi"
+
+#, c-format
+msgid "E5005: Unable to dump %s: container references itself in %s"
+msgstr "E5005: %s dökülemiyor: Kapsayıcı, %s içinde özüne başvuruyor"
+
+#, c-format
+msgid "E684: list index out of range: %<PRId64>"
+msgstr "E684: Liste indeksi erim dışında: %<PRId64>"
+
+#, c-format
+msgid "E899: Argument of %s must be a List or Blob"
+msgstr "E899: %s argümanı bir liste veya ikili geniş nesne olmalıdır"
+
+msgid "E957: Invalid window number"
+msgstr "E957: Geçersiz pencere numarası"
+
+#, c-format
+msgid "E998: Reduce of an empty %s with no initial value"
+msgstr "E998: Başlangıç değeri olmayan boş bir %s için reduce() yapılamıyor"
+
+#, c-format
+msgid "Error converting the call result: %s"
+msgstr "Çağrı sonuçlarını dönüştürürken hata: %s"
+
+msgid "add() argument"
+msgstr "add() argümanı"
+
#, c-format
msgid "E158: Invalid buffer name: %s"
msgstr "E158: Geçersiz arabellek adı: %s"
+#, c-format
+msgid "Invalid channel stream \"%s\""
+msgstr "Geçersiz kanal akışı \"%s\""
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() yalnızca Ekleme kipinde kullanılabilir"
+
msgid "&Ok"
msgstr "&Tamam"
-msgid "E980: lowlevel input not supported"
-msgstr "E980: Alt düzey girdi desteklenmiyor"
+msgid "Context stack is empty"
+msgstr "Bağlam yığını boş"
-#, c-format
-msgid "E700: Unknown function: %s"
-msgstr "E700: Bilinmeyen işlev: %s"
+msgid "dictwatcheradd() argument"
+msgstr "dictwatcheradd() argümanı"
-msgid "E922: expected a dict"
-msgstr "E922: Bir sözlük bekleniyordu"
+msgid "E900: maxdepth must be non-negative number"
+msgstr "E900: maxdepth negatif olmayan bir sayı olmalı"
-msgid "E923: Second argument of function() must be a list or a dict"
-msgstr "E923: function() ikinci argümanı bir liste veya sözlük olmalıdır"
+msgid "flatten() argument"
+msgstr "flatten() argümanı"
-msgid ""
-"&OK\n"
-"&Cancel"
-msgstr ""
-"&Tamam\n"
-"İ&ptal"
+msgid "extend() argument"
+msgstr "extend() argümanı"
+
+msgid "E5000: Cannot find tab number."
+msgstr "E5000: Sekme numarası bulunamıyor."
+
+msgid "E5001: Higher scope cannot be -1 if lower scope is >= 0."
+msgstr "E5001: Daha yüksek kapsam, düşük kapsam >= 0 ise -1 olamaz."
+
+msgid "E5002: Cannot find window number."
+msgstr "E5002: Pencere numarası bulunamıyor."
msgid "called inputrestore() more often than inputsave()"
msgstr "inputrestore(), inputsave()'den daha fazla çağrıldı"
+msgid "insert() argument"
+msgstr "insert() argümanı"
+
msgid "E786: Range not allowed"
msgstr "E786: Erime izin verilmiyor"
+msgid "E474: Failed to convert list to string"
+msgstr "E474: Liste, diziye dönüştürülemedi"
+
+#, c-format
+msgid "E474: Failed to parse %.*s"
+msgstr "E474: %.*s ayrıştırılamadı"
+
msgid "E701: Invalid type for len()"
msgstr "E701: len() için geçersiz tür"
+#, c-format
+msgid "msgpackdump() argument, index %i"
+msgstr "msgpackdump() argümanı, %i indeksi"
+
+msgid "E5070: Character number must not be less than zero"
+msgstr "E5070: Karakter numarası sıfırdan küçük olmamalı"
+
+#, c-format
+msgid "E5071: Character number must not be greater than INT_MAX (%i)"
+msgstr "E5071: Karakter numarası INT_MAX (%i) değerinden büyük olmamalı"
+
msgid "E726: Stride is zero"
msgstr "E726: Sıfır adım"
msgid "E727: Start past end"
msgstr "E727: Başlangıç bitişten sonra"
+msgid "<empty>"
+msgstr "<boş>"
+
+msgid "remove() argument"
+msgstr "remove() argümanı"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Çok fazla sembolik bağlantı (çevrim?)"
+
+msgid "reverse() argument"
+msgstr "reverse() argümanı"
+
+#, c-format
+msgid "E5010: List item %d of the second argument is not a string"
+msgstr "E5010: İkinci argümanın %d liste ögesi bir dizi değil"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Geçersiz eylem: '%s'"
+
#, c-format
msgid "E962: Invalid action: '%s'"
msgstr "E962: Geçersiz eylem: '%s'"
#, c-format
+msgid "connection failed: %s"
+msgstr "bağlantı başarısız: %s"
+
+msgid "sort() argument"
+msgstr "sort() argümanı"
+
+msgid "uniq() argument"
+msgstr "uniq() argümanı"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sıralayıp karşılaştırma işlevi başarısız oldu"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Benzersizlik karşılaştırma işlevi başarısız oldu"
+
+#, c-format
+msgid "E6100: \"%s\" is not a valid stdpath"
+msgstr "E6100: \"%s\", geçerli bir stdpath değil"
+
+msgid "(Invalid)"
+msgstr "(Geçersiz)"
+
+#, c-format
msgid "E935: invalid submatch number: %d"
msgstr "E935: Geçersiz alteşleşme numarası: %d"
-msgid "E991: cannot use =<< here"
-msgstr "E991: Burada =<< kullanılamaz"
+msgid "Can only call this function in an unmodified buffer"
+msgstr "Bu işlev yalnızca değiştirilmemiş bir arabellekte çağrılabilir"
-msgid "E221: Marker cannot start with lower case letter"
-msgstr "E221: İmleyici küçük harfle başlayamaz"
-
-msgid "E172: Missing marker"
-msgstr "E172: İmleyici eksik"
+msgid "writefile() first argument must be a List or a Blob"
+msgstr "writefile() ilk argümanı bir liste veya ikili geniş nesne olmalıdır"
#, c-format
-msgid "E990: Missing end marker '%s'"
-msgstr "E990: Son imleyici '%s' eksik"
+msgid "E5060: Unknown flag: %s"
+msgstr "E5060: Bilinmeyen bayrak: %s"
-msgid "E985: .= is not supported with script version >= 2"
-msgstr "E985: .= betiğin ikinci sürümünden itibaren desteklenmiyor"
+msgid "E482: Can't open file with an empty name"
+msgstr "E482: Adı boş olan bir dosya açılamaz"
-msgid "E687: Less targets than List items"
-msgstr "E687: Liste ögelerinden daha az hedef var"
+#, c-format
+msgid "E482: Can't open file %s for writing: %s"
+msgstr "E482: %s dosyası yazma için açılamıyor: %s"
-msgid "E688: More targets than List items"
-msgstr "E688: Liste ögelerinden daha fazla hedef var"
+#, c-format
+msgid "E80: Error when closing file %s: %s"
+msgstr "E80: %s dosyası kapatılırken hata: %s"
-msgid "E452: Double ; in list of variables"
-msgstr "E452: Değişkenler listesinde çifte ;"
+#, c-format
+msgid "E5142: Failed to open file %s: %s"
+msgstr "E5142: %s dosyası açılamadı: %s"
#, c-format
-msgid "E738: Can't list variables for %s"
-msgstr "E738: %s için değişkenler listelenemiyor"
+msgid "E5143: Failed to write to file %s: %s"
+msgstr "E5143: %s dosyası yazılamadı: %s"
-msgid "E996: Cannot lock an environment variable"
-msgstr "E996: Ortam değişkeni kilitlenemiyor"
+#, c-format
+msgid "E5144: Failed to close file %s: %s"
+msgstr "E5144: %s dosyası kapatılamadı: %s"
-msgid "E996: Cannot lock a register"
-msgstr "E996: Yazmaç kilitlenemiyor"
+msgid "E6000: Argument is not a function or function name"
+msgstr "E6000: Argüman bir işlev veya işlev adı değil"
#, c-format
-msgid "E108: No such variable: \"%s\""
-msgstr "E108: Böyle bir değişken yok: \"%s\""
+msgid "E737: Key already exists: %s"
+msgstr "E737: Anahtar hâlihazırda var: %s"
msgid "E743: variable nested too deep for (un)lock"
msgstr "E743: Değişken kilitlenemez/kilidi açılamaz, çok iç içe geçmiş"
#, c-format
-msgid "E963: setting %s to value with wrong type"
-msgstr "E963: %s yanlış türe sahip değere ayarlanıyor"
+msgid "E741: Value is locked: %.*s"
+msgstr "E741: Değer kilitli: %.*s"
+
+#, c-format
+msgid "E742: Cannot change value of %.*s"
+msgstr "E742: %.*s ögesinin değeri değiştirilemiyor"
+
+msgid "Unknown"
+msgstr "Bilinmiyor"
+
+msgid "E805: Expected a Number or a String, Float found"
+msgstr "E805: Bir sayı veya dizi bekleniyordu, kayan noktalı değer bulundu"
+
+msgid "E703: Expected a Number or a String, Funcref found"
+msgstr "E703: Bir sayı veya dizi bekleniyordu, Funcref bulundu"
+
+msgid "E745: Expected a Number or a String, List found"
+msgstr "E745: Bir sayı veya dizi bekleniyordu, liste bulundu"
+
+msgid "E728: Expected a Number or a String, Dictionary found"
+msgstr "E728: Bir sayı veya dizi bekleniyordu, sözlük bulundu"
+
+msgid "E974: Expected a Number or a String, Blob found"
+msgstr "E974: Bir sayı veya dizi bekleniyordu, ikili geniş nesne bulundu"
+
+msgid "E5299: Expected a Number or a String, Boolean found"
+msgstr "E5299: Bir sayı veya dizi bekleniyordu, Boole bulundu"
+
+msgid "E5300: Expected a Number or a String"
+msgstr "E5300: Bir sayı veya dizi bekleniyordu"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Bir sayı olarak liste kullanılıyor"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Bir sayı olarak liste kullanılıyor"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Bir sayı olarak kayan noktalı değer kullanılıyor"
+
+msgid "E974: Using a Blob as a Number"
+msgstr "E974: Bir Sayı olarak ikili geniş nesne kullanılıyor"
+
+msgid "E685: using an invalid value as a Number"
+msgstr "E685: Bir sayı olarak geçersiz bir değer kullanılıyor"
+
+msgid "E730: using List as a String"
+msgstr "E730: Bir dizi olarak liste kullanılıyor"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Bir dizi olarak sözlük kullanılıyor"
+
+msgid "E976: using Blob as a String"
+msgstr "E976: Bir dizi olarak ikili geniş nesne kullanılıyor"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Bir dizi olarak geçersiz bir değer kullanılıyor"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Bir kayan noktalı değer olarak bir Funcref kullanılıyor"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Bir kayan noktalı değer olarak bir dizi kullanılıyor"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Bir kayan noktalı değer olarak bir liste kullanılıyor"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Bir kayan noktalı değer olarak bir sözlük kullanılıyor"
+
+msgid "E362: Using a boolean value as a Float"
+msgstr "E362: Bir kayan noktalı değer olarak bir Boole kullanılıyor"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Bir Kayan Noktalı Değer olarak bir özel değer kullanılıyor"
+
+msgid "E975: Using a Blob as a Float"
+msgstr "E975: Bir kayan noktalı değer olarak bir ikili geniş nesne kullanılıyor"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Sayı veya kayan noktalı değer gerekiyor"
#, c-format
-msgid "E795: Cannot delete variable %s"
-msgstr "E795: %s değişkeni silinemiyor"
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: %s işlevi hâlihazırda mevcut, değiştirmek için ! ekleyin"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Sözlük girdisi hâlihazırda mevcut"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref gerekiyor"
#, c-format
-msgid "E704: Funcref variable name must start with a capital: %s"
-msgstr "E704: Funcref değişkeni BÜYÜK harf ile başlamalıdır: %s"
+msgid "E130: Unknown function: %s"
+msgstr "E130: Bilinmeyen işlev: %s"
#, c-format
-msgid "E705: Variable name conflicts with existing function: %s"
-msgstr "E705: Değişken adı mevcut işlevle çakışıyor: %s"
+msgid "E125: Illegal argument: %s"
+msgstr "E125: İzin verilmeyen argüman: %s"
#, c-format
-msgid "E741: Value is locked: %s"
-msgstr "E741: Değer kilitli: %s"
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Yinelenen argüman adı: %s"
-msgid "Unknown"
-msgstr "Bilinmiyor"
+msgid "E989: Non-default argument follows default argument"
+msgstr "E989: Öntanımlı olmayan argüman öntanımlı argümandan sonra"
#, c-format
-msgid "E742: Cannot change value of %s"
-msgstr "E742: %s değeri değiştirilemiyor"
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: %s işlevi için pek fazla argüman"
-msgid "E921: Invalid callback argument"
-msgstr "E921: Geçersiz geri çağırma argümanı"
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: %s işlevi için geçersiz argümanlar"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: İşlevin çağırdığı derinlik 'maxfuncdepth'ten daha yüksek"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s çağrılıyor"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s durduruldu"
+
+#, c-format
+msgid "%s returning #%<PRId64>"
+msgstr "%s, #%<PRId64> döndürüyor"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s, %s döndürüyor"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%s içinde sürdürülüyor"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Çok fazla argüman"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Bilinmeyen işlev: %s"
+
+#, c-format
+msgid "E276: Cannot use function as a method: %s"
+msgstr "E276: İşlev bir yöntem olarak kullanılamaz: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: İşlev silinmiş: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Şu işlev için yetersiz sayıda argüman: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> bir betik bağlamında kullanılmıyor: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: dic işlevi bir sözlük olmadan çağrılıyor: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: İşlev adı gerekiyor"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: İşlev adı bir BÜYÜK harfle veya \"s:\" ile başlamalı: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: İşlev adı iki nokta içeremez: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Tanımlanmamış işlev: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' eksik: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: g: burada kullanılamaz"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Kapatma işlevi en üst düzeyde olmamalıdır: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction eksik"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction sonrası metin bulundu: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: İşlev adı şu değişken ile çakışıyor: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: %s işlevi yeniden tanımlanamıyor: Şu an kullanımda"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: İşlev adı betik dosyası adına eşleşmiyor: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: %s işlevi silinemiyor: Şu an kullanımda"
+
+#, c-format
+msgid "Cannot delete function %s: It is being used internally"
+msgstr "%s işlevi silinemiyor: Şu an program içinde kullanımda"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return bir işlev içinde değil"
+
+msgid "tcp address must be host:port"
+msgstr "tcp adresi makine:kapı olmalı"
+
+msgid "failed to lookup host or port"
+msgstr "makine veya kapı bulunamadı"
+
+msgid "connection refused"
+msgstr "bağlantı reddedildi"
#, c-format
msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
@@ -914,14 +1505,12 @@ msgid "E134: Cannot move a range of lines into itself"
msgstr "E134: Satırlardan oluşan erim kendi içine taşınamaz"
#, c-format
-msgid "%ld line moved"
-msgid_plural "%ld lines moved"
-msgstr[0] "%ld satır taşındı"
-msgstr[1] "%ld satır taşındı"
+msgid "E482: Can't create file %s"
+msgstr "E482: %s dosyası oluşturulamıyor"
#, c-format
-msgid "%ld lines filtered"
-msgstr "%ld satır süzüldü"
+msgid "%<PRId64> lines filtered"
+msgstr "%<PRId64> satır süzüldü"
msgid "E135: *Filter* Autocommands must not change current buffer"
msgstr "E135: *Süzgeç* otokomutları şu anki arabelleği değiştirmemelidir"
@@ -929,13 +1518,6 @@ msgstr "E135: *Süzgeç* otokomutları şu anki arabelleği değiştirmemelidir"
msgid "[No write since last change]\n"
msgstr "[Son değişiklikten sonra yazılmadı]\n"
-#, c-format
-msgid "E503: \"%s\" is not a file or writable device"
-msgstr "E503: \"%s\", bir dosya veya yazılabilir aygıt değil"
-
-msgid "Save As"
-msgstr "Farklı Kaydet"
-
msgid "Write partial file?"
msgstr "Dosyanın bir kısmı yazılsın mı?"
@@ -955,8 +1537,8 @@ msgid "E768: Swap file exists: %s (:silent! overrides)"
msgstr "E768: Takas dosyası mevcut: %s (:silent! geçersiz kılar)"
#, c-format
-msgid "E141: No file name for buffer %ld"
-msgstr "E141: %ld numaralı arabelleğin bir adı yok"
+msgid "E141: No file name for buffer %<PRId64>"
+msgstr "E141: %<PRId64> numaralı arabelleğin bir adı yok"
msgid "E142: File not written: Writing is disabled by 'write' option"
msgstr "E142: Dosya yazılamadı: Yazma 'write' seçeneği ile kapatılmış"
@@ -983,9 +1565,6 @@ msgstr ""
msgid "E505: \"%s\" is read-only (add ! to override)"
msgstr "E505: \"%s\" saltokunur (geçersiz kılmak için ! ekleyin)"
-msgid "Edit File"
-msgstr "Dosya Düzenle"
-
#, c-format
msgid "E143: Autocommands unexpectedly deleted new buffer %s"
msgstr "E143: yeni %s arabelleğini otokomutlar beklenmedik bir biçimde sildi"
@@ -993,9 +1572,6 @@ msgstr "E143: yeni %s arabelleğini otokomutlar beklenmedik bir biçimde sildi"
msgid "E144: non-numeric argument to :z"
msgstr "E144: :z için sayısal olmayan argüman"
-msgid "E145: Shell commands and some functionality not allowed in rvim"
-msgstr "E145: rvim içinde kabuk komutları ve bazı işlevselliğe izin verilmez"
-
msgid "E146: Regular expressions can't be delimited by letters"
msgstr "E146: Düzenli ifadeler harflerle sınırlandırılamaz"
@@ -1006,52 +1582,74 @@ msgstr "%s ile değiştir (y/n/a/q/l/^E/^Y)?"
msgid "(Interrupted) "
msgstr "(Yarıda kesildi) "
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global özyineli olarak bir erim ile yapılamaz"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Düzenli ifade :global'den eksik"
+
#, c-format
-msgid "%ld match on %ld line"
-msgid_plural "%ld matches on %ld line"
-msgstr[0] "%ld eşleşme, %ld satırda"
-msgstr[1] "%ld eşleşme, %ld satırda"
+msgid "Pattern found in every line: %s"
+msgstr "Dizginin bulunduğu her satır: %s"
#, c-format
-msgid "%ld substitution on %ld line"
-msgid_plural "%ld substitutions on %ld line"
-msgstr[0] "%ld değiştirme, %ld satırda"
-msgstr[1] "%ld değiştirme, %ld satırda"
+msgid "Pattern not found: %s"
+msgstr "Dizgi bulunamadı: %s"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Panik yok!"
#, c-format
-msgid "%ld match on %ld lines"
-msgid_plural "%ld matches on %ld lines"
-msgstr[0] "%ld eşleşme, %ld satırda"
-msgstr[1] "%ld eşleşme, %ld satırda"
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Üzgünüm, '%s' yardımı %s için mevcut değil"
#, c-format
-msgid "%ld substitution on %ld lines"
-msgid_plural "%ld substitutions on %ld lines"
-msgstr[0] "%ld değiştirme, %ld satırda"
-msgstr[1] "%ld değiştirme, %ld satırda"
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Üzgünüm, %s için yardım mevcut değil"
-msgid "E147: Cannot do :global recursive with a range"
-msgstr "E147: :global özyineli olarak bir erim ile yapılamaz"
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Üzgünüm, \"%s\" yardım dosyası bulunamadı"
-msgid "E148: Regular expression missing from global"
-msgstr "E148: Düzenli ifade eksik"
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Eşleşme bulunamadı: %s"
#, c-format
-msgid "Pattern found in every line: %s"
-msgstr "Dizginin bulunduğu her satır: %s"
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: %s yazma için açılamıyor"
#, c-format
-msgid "Pattern not found: %s"
-msgstr "Dizgi bulunamadı: %s"
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: %s okuma için açılamıyor"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Bir dilde yardım dosyası kodlamaları karıştı: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Şu dosyada yinelenen \"%s\" etiketi: %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s, bir dizin değil"
msgid "No old files"
msgstr "Eski dosya yok"
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: İlk kullanım \":profile start {dosyaadı}\""
+
#, c-format
msgid "Save changes to \"%s\"?"
msgstr "Değişiklikler şuraya kaydedilsin mi: \"%s\"?"
#, c-format
+msgid "Close \"%s\"?"
+msgstr "\"%s\" kapatılsın mı?"
+
+#, c-format
msgid "E947: Job still running in buffer \"%s\""
msgstr "E947: İş \"%s\" arabelleğinde hâlâ sürüyor"
@@ -1062,17 +1660,102 @@ msgstr "E162: \"%s\" arabelleği son değişiklikten sonra yazılmadı"
msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
msgstr "Uyarı: Diğer arabelleğe aniden girildi (otokomutları denetleyin)"
+msgid "E163: There is only one file to edit"
+msgstr "E163: Düzenlenecek yalnızca bir dosya var"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: İlk dosyadan öncesine gidilemez"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Son dosyadan öteye gidilemez"
+
+msgid "E610: No argument to delete"
+msgstr "E610: Silinecek bir argüman yok"
+
#, c-format
msgid "E666: compiler not supported: %s"
msgstr "E666: Derleyici desteklenmiyor: %s"
#, c-format
-msgid "W20: Required python version 2.x not supported, ignoring file: %s"
-msgstr "W20: Gerekli 2.x Python sürümü desteklenmiyor, dosya yok sayılıyor: %s"
+msgid "Cannot source a directory: \"%s\""
+msgstr "Dizin kaynak alınamıyor: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\" kaynak alınamadı"
+
+#, c-format
+msgid "line %<PRId64>: could not source \"%s\""
+msgstr "%<PRId64>. satır: \"%s\" kaynak alınamadı"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" kaynak alınıyor"
+
+#, c-format
+msgid "line %<PRId64>: sourcing \"%s\""
+msgstr "%<PRId64>. satır: \"%s\" kaynak alınıyor"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s kaynak alınması bitti"
+
+msgid "modeline"
+msgstr "kip satırı"
+
+msgid "--cmd argument"
+msgstr "--cmd argümanı"
+
+msgid "-c argument"
+msgstr "-c argümanı"
+
+msgid "environment variable"
+msgstr "ortam değişkeni"
+
+msgid "error handler"
+msgstr "hata işleyicisi"
+
+msgid "changed window size"
+msgstr "değiştirilen pencere boyutu"
+
+msgid "Lua"
+msgstr "Lua"
+
+#, c-format
+msgid "API client (channel id %<PRIu64>)"
+msgstr "API istemcisi (kanal kimliği %<PRIu64>"
+
+msgid "anonymous :source"
+msgstr "anonim :source"
+
+#, c-format
+msgid "anonymous :source (script id %d)"
+msgstr "anonim :source (betik kimliği %d)"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Uyarı: Yanlış satır ayırıcısı, ^M eksik olabilir"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding kaynak alınmış bir dosyanın dışında kullanıldı"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish kaynak alınmış bir dosyanın dışında kullanıldı"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Şu anki %sdil: \"%s\""
#, c-format
-msgid "W21: Required python version 3.x not supported, ignoring file: %s"
-msgstr "W21: Gerekli Python sürümü 3.x desteklenmiyor, dosya yok sayılıyor: %s"
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: \"%s\" diline ayarlanamıyor"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Böyle bir kullanıcı tanımlı komut yok: %s"
+
+#, c-format
+msgid "E1237: No such user-defined command in current buffer: %s"
+msgstr "E1237: Geçerli arabellekte böyle bir kullanıcı tanımlı komut yok: %s"
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
msgstr "Ex kipine giriliyor. Normal kipe geri dönmek için \"visual\" yazın."
@@ -1084,6 +1767,9 @@ msgstr "E501: Dosyanın sonunda"
msgid "Executing: %s"
msgstr "Çalıştırılıyor: %s"
+msgid "line %"
+msgstr "satır %"
+
msgid "E169: Command too recursive"
msgstr "E169: Komut çok özyineli"
@@ -1097,12 +1783,12 @@ msgstr "Kaynak alınan dosyanın sonu"
msgid "End of function"
msgstr "İşlevin sonu"
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Kullanıcı tanımlı komutun belirsiz kullanımı"
+
msgid "E492: Not an editor command"
msgstr "E492: Bir düzenleyici komutu değil"
-msgid "E981: Command not allowed in rvim"
-msgstr "E981: Bu komuta rvim'de izin verilmiyor"
-
msgid "E493: Backwards range given"
msgstr "E493: Geriye dönük erim verildi"
@@ -1112,33 +1798,79 @@ msgstr "Geriye dönük erim verildi, takas edilebilir"
msgid "E494: Use w or w>>"
msgstr "E494: w veya w>> kullanın"
-msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
-msgstr ""
-"E943: Komut tablosunun güncellenmesi gerekiyor, 'make cmdidxs' çalıştırın"
-
msgid ""
"INTERNAL: Cannot use EX_DFLALL with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"
msgstr ""
"DAHİLİ: EX_DFLALL; ADDR_NONE, ADDR_UNSIGNED veya ADDR_QUICKFIX ile birlikte "
"kullanılamaz"
-msgid "E319: Sorry, the command is not available in this version"
+msgid "E943: Command table needs to be updated, run 'make'"
+msgstr "E943: Komut tablosunun güncellenmesi gerekiyor, 'make' çalıştırın"
+
+msgid "E319: The command is not available in this version"
msgstr "E319: Üzgünüm, komut bu sürümde mevcut değil"
#, c-format
-msgid "%d more file to edit. Quit anyway?"
-msgid_plural "%d more files to edit. Quit anyway?"
-msgstr[0] "Düzenlenecek %d dosya daha var. Yine de çıkılsın mı?"
-msgstr[1] "Düzenlenecek %d dosya daha var. Yine de çıkılsın mı?"
+msgid "E174: Command already exists: add ! to replace it: %s"
+msgstr "E174: Komut zaten mevcut: Değiştirmek için ! ekleyin: %s"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Ad Dğkl Adres Tam Tanım"
+
+msgid "No user-defined commands found"
+msgstr "Kullanıcı tanımlı bir komut bulunamadı"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Bir öznitelik belirtilmemiş"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Geçersiz argüman sayısı"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Sayım iki defa belirtilemez"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Sayım için geçersiz öntanımlı değer"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete için argüman gerekiyor"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr için argüman gerekiyor"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Geçersiz öznitelik: %s"
+
+msgid "E1208: -complete used without -nargs"
+msgstr "E1208: -complete, -nargs olmadan kullanıldı"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Geçersiz komut adı"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Kullanıcı tanımlı komutlar BÜYÜK harfle başlamalıdır"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Ayrılmış ad, kullanıcı tanımlı komut için kullanılamaz"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Geçersiz adres türü değeri: %s"
#, c-format
-msgid "E173: %d more file to edit"
-msgid_plural "E173: %d more files to edit"
-msgstr[0] "E173: Düzenlenecek %d dosya daha var"
-msgstr[1] "E173: Düzenlenecek %d dosya daha var"
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Geçersiz tam değer: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Tamamlama argümanına yalnızca özel tamamlamalarda izin verilir"
-msgid "unknown"
-msgstr "bilinmeyen"
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Özel tamamlama bir işlev argümanı gerektirir"
#, c-format
msgid "E185: Cannot find color scheme '%s'"
@@ -1153,57 +1885,26 @@ msgstr "E784: Son sekme sayfası kapatılamıyor"
msgid "Already only one tab page"
msgstr "Zaten bir sekme sayfası var"
-msgid "Edit File in new tab page"
-msgstr "Dosyayı yeni sekme sayfasında düzenle"
-
-msgid "Edit File in new window"
-msgstr "Dosyayı yeni pencerede düzenle"
-
#, c-format
msgid "Tab page %d"
msgstr "Sekme sayfası %d"
+msgid "E25: Nvim does not have a built-in GUI"
+msgstr "E25: Nvim, bir grafik arabirim ile gelmez"
+
msgid "No swap file"
msgstr "Takas dosyası yok"
-msgid "Append File"
-msgstr "Dosya iliştir"
-
-msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
-msgstr ""
-"E747: Dizin değiştirilemiyor, arabellek değiştirilmiş (geçersiz kılmak "
-"için ! ekleyin)"
-
msgid "E186: No previous directory"
msgstr "E186: Öncesinde dizin yok"
msgid "E187: Unknown"
-msgstr "E187: Bilinmeyen"
+msgstr "E187: Bilinmiyor"
msgid "E465: :winsize requires two number arguments"
msgstr "E465: :winsize iki adet sayı argüman gerektirir"
#, c-format
-msgid "Window position: X %d, Y %d"
-msgstr "Pencere konumu: X %d, Y %d"
-
-msgid "E188: Obtaining window position not implemented for this platform"
-msgstr "E188: Pencere konumunu alma özelliği bu platformda mevcut değil"
-
-msgid "E466: :winpos requires two number arguments"
-msgstr "E466: :winpos iki adet sayı argüman gerektirir"
-
-msgid "E930: Cannot use :redir inside execute()"
-msgstr "E930: :redir, execute() içinde kullanılamaz"
-
-msgid "Save Redirection"
-msgstr "Yeniden yönlendirmeyi kaydet"
-
-#, c-format
-msgid "E739: Cannot create directory: %s"
-msgstr "E739: Dizin oluşturulamıyor: %s"
-
-#, c-format
msgid "E189: \"%s\" exists (add ! to override)"
msgstr "E189: \"%s\" zaten var (geçersiz kılmak için ! ekleyin)"
@@ -1212,31 +1913,26 @@ msgid "E190: Cannot open \"%s\" for writing"
msgstr "E190: \"%s\" yazma için açılamıyor"
msgid "E191: Argument must be a letter or forward/backward quote"
-msgstr "E191: Değişken bir harf veya açma/kapama tırnağı olmalıdır"
+msgstr "E191: Değişken bir harf veya açma/kapatma tırnağı olmalıdır"
msgid "E192: Recursive use of :normal too deep"
msgstr "E192: :normal'in özyineli kullanımı çok derinde"
-msgid "E809: #< is not available without the +eval feature"
-msgstr "E809: #<, +eval özelliği olmadan kullanılamaz"
-
msgid "E194: No alternate file name to substitute for '#'"
msgstr "E194: '#' yerine koymak için başka dosya adı yok"
msgid "E495: no autocommand file name to substitute for \"<afile>\""
-msgstr "E495: \"<afile>\" yerine koymak için otokomut dosya adı yok"
+msgstr "E495: \"<odosyası>\" yerine koymak için otokomut dosya adı yok"
msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
-msgstr "E496: \"<abuf>\" yerine koymak için otokomut arabellek numarası yok"
+msgstr ""
+"E496: \"<oarabelleği>\" yerine koymak için otokomut arabellek numarası yok"
msgid "E497: no autocommand match name to substitute for \"<amatch>\""
-msgstr "E497: \"<amatch>\" yerine koymak için otokomut eşleşme adı yok"
+msgstr "E497: \"<oeşi>\" yerine koymak için otokomut eşleşme adı yok"
msgid "E498: no :source file name to substitute for \"<sfile>\""
-msgstr "E498: \"<sfile>\" yerine koymak için :source dosya adı yok"
-
-msgid "E489: no call stack to substitute for \"<stack>\""
-msgstr "E489: \"<stack>\" yerine koymak için bir çağrı yığını yok"
+msgstr "E498: \"<kdosyası>\" yerine koymak için :source dosya adı yok"
msgid "E842: no line number to use for \"<slnum>\""
msgstr "E842: \"<slnum>\" kullanımı için satır numarası yok"
@@ -1254,9 +1950,6 @@ msgstr "E500: Boş bir satır olarak değer biçer"
msgid "Untitled"
msgstr "Adsız"
-msgid "E196: No digraphs in this version"
-msgstr "E196: Bu sürümde ikili harfler bulunmamaktadır"
-
msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
msgstr "E608: 'Vim' öneki ile kural dışı durumlar :throw edilemez"
@@ -1273,8 +1966,8 @@ msgid "Exception discarded: %s"
msgstr "Kural dışı durum kenara atıldı: %s"
#, c-format
-msgid "%s, line %ld"
-msgstr "%s, %ld. satır"
+msgid "%s, line %<PRId64>"
+msgstr "%s, %<PRId64>. satır"
#, c-format
msgid "Exception caught: %s"
@@ -1307,6 +2000,15 @@ msgstr "Yarıda Kesilme"
msgid "E579: :if nesting too deep"
msgstr "E579: :if'ler çok iç içe geçmiş"
+msgid "E580: :endif without :if"
+msgstr "E580: :if olmadan :endif"
+
+msgid "E581: :else without :if"
+msgstr "E581: :if olmadan :else"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :if olmadan :elseif"
+
msgid "E583: multiple :else"
msgstr "E583: Birden fazla :else"
@@ -1316,26 +2018,38 @@ msgstr "E584: :else sonrası :elseif"
msgid "E585: :while/:for nesting too deep"
msgstr "E585: :while/:for çok iç içe geçmiş"
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while veya :for olmadan :continue"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while veya :for olmadan :break"
+
msgid "E732: Using :endfor with :while"
msgstr "E732: :endfor, :while ile kullanılıyor"
msgid "E733: Using :endwhile with :for"
msgstr "E733: :endwhile, :for ile kullanılıyor"
-msgid "E579: block nesting too deep"
-msgstr "E579: İç içe geçmeler çok derin"
-
msgid "E601: :try nesting too deep"
msgstr "E601: :try çok iç içe geçmiş"
+msgid "E603: :catch without :try"
+msgstr "E603: :try olmadan :catch"
+
msgid "E604: :catch after :finally"
msgstr "E604: :finally sonrası :catch"
-msgid "E193: :enddef not inside a function"
-msgstr "E193: :enddef bir işlev içinde değil"
+msgid "E606: :finally without :try"
+msgstr "E606: :try olmadan :finally"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Birden fazla :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :try olmadan :endtry"
msgid "E193: :endfunction not inside a function"
-msgstr "E193: :endfunction bir işlev içinde değil"
+msgstr "E193: :endfunction, bir işlev içinde değil"
msgid "E788: Not allowed to edit another buffer now"
msgstr "E788: Şu anda başka bir arabellek düzenlenemez"
@@ -1343,24 +2057,91 @@ msgstr "E788: Şu anda başka bir arabellek düzenlenemez"
msgid "E811: Not allowed to change buffer information now"
msgstr "E811: Şu anda arabellek bilgisi değiştirilemez"
+#, c-format
+msgid "E5408: Unable to get g:Nvim_color_cmdline callback: %s"
+msgstr "E5408: g:Nvim_color_cmdline geri çağrısı alınamıyor: %s"
+
+#, c-format
+msgid "E5407: Callback has thrown an exception: %s"
+msgstr "E5407: Geri çağrı bir istisna döndürdü: %s"
+
+msgid "E5400: Callback should return list"
+msgstr "E5400: Geri çağrı, liste döndürmeli"
+
+#, c-format
+msgid "E5401: List item %i is not a List"
+msgstr "E5401: Liste ögesi %i, bir Liste değil"
+
+#, c-format
+msgid "E5402: List item %i has incorrect length: %d /= 3"
+msgstr "E5402: %i liste ögesinin uzunluğu yanlış: %d /= 3"
+
+msgid "E5403: Chunk %i start %"
+msgstr "E5403: %i parçası başlangıç %"
+
+msgid "E5405: Chunk %i start %"
+msgstr "E5405: %i parçası başlangıç %"
+
+msgid "E5404: Chunk %i end %"
+msgstr "E5404: %i parçası bitiş %"
+
+msgid "E5406: Chunk %i end %"
+msgstr "E5406: %i parçası bitiş %"
+
+msgid "tagname"
+msgstr "etiket adı"
+
+msgid " kind file\n"
+msgstr " dosya türü\n"
+
+msgid "'history' option is zero"
+msgstr "'history' seçeneği sıfır"
+
msgid "[Command Line]"
msgstr "[Komut Satırı]"
msgid "E199: Active window or buffer deleted"
msgstr "E199: Etkin pencere veya arabellek silinmiş"
+msgid "E854: path too long for completion"
+msgstr "E854: Yol tamamlama için çok uzun"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Geçersiz yol: '**[sayı]' yolun sonunda olmalı veya sonrasında '%s' "
+"gelmelidir"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: \"%s\" dizini cdpath içinde bulunamadı"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: \"%s\" dosyası yol içinde bulunamadı"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Başka bir \"%s\" dizini cdpath içinde bulunamadı"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Başka bir \"%s\" dosyası yol içinde bulunamadı"
+
msgid "E812: Autocommands changed buffer or buffer name"
msgstr "E812: Otokomutlar arabelleği veya arabellek adını değiştirdi"
+msgid "is a directory"
+msgstr "bir dizin"
+
msgid "Illegal file name"
msgstr "İzin verilmeyen dosya adı"
msgid "is not a file"
msgstr "bir dosya değil"
-msgid "is a device (disabled with 'opendevice' option)"
-msgstr "bir aygıt ('opendevice' seçeneği ile kapatılır)"
-
msgid "[New DIRECTORY]"
msgstr "[Yeni DİZİN]"
@@ -1376,17 +2157,11 @@ msgstr "E200: *ReadPre otokomutları dosyayı okunamaz hale getirdi"
msgid "E201: *ReadPre autocommands must not change current buffer"
msgstr "E201: *ReadPre otokomutları şu anki arabelleği değiştirmemeli"
-msgid "Vim: Reading from stdin...\n"
-msgstr "Vim: stdin'den okunuyor...\n"
-
-msgid "Reading from stdin..."
-msgstr "stdin'den okunuyor..."
-
msgid "E202: Conversion made file unreadable!"
msgstr "E202: Dönüştürme dosyayı okunamaz hale getirdi!"
msgid "[fifo]"
-msgstr "[fifo]"
+msgstr "[ilk giren ilk çıkar]"
msgid "[socket]"
msgstr "[uç nokta]"
@@ -1400,13 +2175,19 @@ msgstr "[Eksik CR]"
msgid "[long lines split]"
msgstr "[uzun satırlar bölünmüş]"
+msgid "[NOT converted]"
+msgstr "[dönüştürülmedi]"
+
+msgid "[converted]"
+msgstr "[dönüştürüldü]"
+
#, c-format
-msgid "[CONVERSION ERROR in line %ld]"
-msgstr "[%ld. satırda DÖNÜŞTÜRME HATASI]"
+msgid "[CONVERSION ERROR in line %<PRId64>]"
+msgstr "[%<PRId64>. satırda DÖNÜŞTÜRME HATASI]"
#, c-format
-msgid "[ILLEGAL BYTE in line %ld]"
-msgstr "[%ld. satırda GEÇERSİZ BAYT]"
+msgid "[ILLEGAL BYTE in line %<PRId64>]"
+msgstr "[%<PRId64>. satırda İZİN VERİLMEYEN BAYT]"
msgid "[READ ERRORS]"
msgstr "[OKUMA HATALARI]"
@@ -1420,41 +2201,138 @@ msgstr "'charconvert' ile dönüştürme başarısız"
msgid "can't read output of 'charconvert'"
msgstr "'charconvert' çıktısı okunamıyor"
-msgid "[dos]"
-msgstr "[dos]"
+msgid "[New File]"
+msgstr "[Yeni Dosya]"
+
+msgid "[New]"
+msgstr "[Yeni]"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwrite arabelleği için eşleşen bir otokomut yok"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Otokomutlar arabelleği silmiş veya yazılması için kaldırmışlar"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Otokomut satır sayısını beklenmeyen biçimde değiştirdi"
+
+msgid "is not a file or writable device"
+msgstr "bir dosya veya yazılabilir aygıt değil"
+
+msgid "is read-only (add ! to override)"
+msgstr "saltokunur (geçersiz kılmak için ! ekleyin)"
+
+#, c-format
+msgid "E303: Unable to create directory \"%s\" for backup file: %s"
+msgstr "E303: Yedek dosyası için \"%s\" dizini oluşturulamadı: %s"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Yedek dosyasına yazılamıyor (geçersiz kılmak için ! ekleyin)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Yedek dosyası oluşturulamıyor (geçersiz kılmak için ! ekleyin)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Yedek dosyası yapılamıyor (geçersiz kılmak için ! ekleyin)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Yazma için geçici dosya bulunamıyor"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Dönüştürülemiyor (dönüştürmeden yazmak için ! ekleyin)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Bağlı dosya yazma için açılamıyor"
+
+#, c-format
+msgid "E212: Can't open file for writing: %s"
+msgstr "E212: Dosya yazma için açılamıyor: %s"
+
+#, c-format
+msgid "E512: Close failed: %s"
+msgstr "E512: Kapatma başarısız oldu: %s"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Yazma hatası, dönüştürme başarısız (geçersiz kılmak için 'fenc'i boş "
+"bırakın)"
+
+msgid "E513: write error, conversion failed in line %"
+msgstr "E513: Yazma hatası, şu satırda dönüştürme başarısız: %"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Yazma hatası (dosya sistemi dolu mu?)"
+
+msgid " CONVERSION ERROR"
+msgstr " DÖNÜŞTÜRME HATASI"
+
+#, c-format
+msgid " in line %<PRId64>;"
+msgstr " %<PRId64>. satırda;"
+
+msgid "[Device]"
+msgstr "[Aygıt]"
+
+msgid " [a]"
+msgstr " [i]"
+
+msgid " appended"
+msgstr " iliştirildi"
+
+msgid " [w]"
+msgstr " [y]"
+
+msgid " written"
+msgstr " yazıldı"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Yama kipi: Orijinal dosya kaydedilemiyor"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Yama kipi: Orijinal boş dosyaya dokunulamıyor"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Yedek dosyası silinemiyor"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"UYARI: Orijinal dosya kaybolmuş veya hasar görmüş olabilir\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "dosya başarılı bir biçimde yazılana kadar düzenleyiciden çıkmayın!"
msgid "[dos format]"
msgstr "[dos biçimi]"
-msgid "[mac]"
-msgstr "[mac]"
+msgid "[dos]"
+msgstr "[dos]"
msgid "[mac format]"
msgstr "[mac biçimi]"
-msgid "[unix]"
-msgstr "[unix]"
+msgid "[mac]"
+msgstr "[mac]"
msgid "[unix format]"
msgstr "[unix biçimi]"
-#, c-format
-msgid "%ld line, "
-msgid_plural "%ld lines, "
-msgstr[0] "%ld satır, "
-msgstr[1] "%ld satır, "
+msgid "[unix]"
+msgstr "[unix]"
-#, c-format
-msgid "%lld byte"
-msgid_plural "%lld bytes"
-msgstr[0] "%lld bayt"
-msgstr[1] "%lld bayt"
+msgid "[Incomplete last line]"
+msgstr "[Tamamlanmamış son satır]"
msgid "[noeol]"
-msgstr "[noeol]"
+msgstr "[satır sonu yok]"
-msgid "[Incomplete last line]"
-msgstr "[Tamamlanmamış son satır]"
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "UYARI: Bu dosya açıldıktan sonra başkası tarafından değiştirilmiş!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Yine de yazmak istiyor musunuz?"
#, c-format
msgid "E208: Error writing to \"%s\""
@@ -1479,9 +2357,7 @@ msgstr "E211: \"%s\" dosyası artık mevcut değil"
msgid ""
"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
"well"
-msgstr ""
-"W12: Uyarı: \"%s\" dosyası Vim'deki arabellek de dahil olmak üzere "
-"değiştirildi"
+msgstr "W12: Uyarı: \"%s\" dosyası ve Vim'deki arabellek değişti"
msgid "See \":help W12\" for more info."
msgstr "Ek bilgi için \":help W12\" yazın."
@@ -1510,10 +2386,12 @@ msgstr "Uyarı"
msgid ""
"&OK\n"
-"&Load File"
+"&Load File\n"
+"Load File &and Options"
msgstr ""
"&Tamam\n"
-"&Dosya Yükle"
+"&Dosyayı Yükle\n"
+"Dosyayı ve &Seçenekleri Yükle"
#, c-format
msgid "E462: Could not prepare for reloading \"%s\""
@@ -1529,386 +2407,508 @@ msgstr "E219: { eksik."
msgid "E220: Missing }."
msgstr "E220: } eksik."
-msgid "<empty>"
-msgstr "<boş>"
-
-msgid "E655: Too many symbolic links (cycle?)"
-msgstr "E655: Çok fazla sembolik bağlantı (çevrim?)"
+msgid "E490: No fold found"
+msgstr "E490: Kıvırma bulunamadı"
-msgid "writefile() first argument must be a List or a Blob"
-msgstr "writefile() ilk argümanı bir liste veya ikili geniş nesne olmalıdır"
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Şu anki 'foldmethod' ile kıvırma oluşturulamıyor"
-msgid "Select Directory dialog"
-msgstr "Dizin Seç iletişim kutusu"
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Şu anki 'foldmethod' ile kıvırma silinemiyor"
-msgid "Save File dialog"
-msgstr "Dosya Kaydet iletişim kutusu"
+msgid "E222: Add to read buffer"
+msgstr "E222: Okunan arabelleğe ekle"
-msgid "Open File dialog"
-msgstr "Dosya Aç iletişim kutusu"
+msgid "E223: recursive mapping"
+msgstr "E223: Özyineli eşlemleme"
-msgid "E338: Sorry, no file browser in console mode"
-msgstr "E338: Üzgünüm, konsol kipinde dosya tarayıcı yoktur"
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s için global kısaltma hâlihazırda var"
-msgid "no matches"
-msgstr "eşleşme yok"
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s için global eşlemleme hâlihazırda var"
-msgid "E854: path too long for completion"
-msgstr "E854: Yol tamamlama için çok uzun"
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s için kısaltma hâlihazırda var"
#, c-format
-msgid ""
-"E343: Invalid path: '**[number]' must be at the end of the path or be "
-"followed by '%s'."
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s için eşlemleme hâlihazırda var"
+
+msgid "No abbreviation found"
+msgstr "Kısaltma bulunamadı"
+
+msgid "No mapping found"
+msgstr "Eşlemleme bulunamadı"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: İzin verilmeyen kip"
+
+msgid "--No lines in buffer--"
+msgstr "--Arabellek içinde satır yok--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Komut durduruldu"
+
+msgid "E905: Cannot set this option after startup"
+msgstr "E905: Bu seçenek, başlangıçtan sonra ayarlanamaz"
+
+msgid "E903: Could not spawn API job"
+msgstr "E903: API işi ortaya çıkarılamadı"
+
+msgid "E471: Argument required"
+msgstr "E471: Argüman gerekiyor"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ sonrasında /, ? veya & gelmeli"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Komut satırı penceresinde geçersiz; <CR> çalıştırır, CTRL-C çıkar"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
msgstr ""
-"E343: Geçersiz yol: '**[sayı]' yolun sonunda olmalı veya sonrasında '%s' "
-"gelmelidir"
+"E12: Geçerli dizin veya etiket aramasında exrc veya vimrc'den komutlara izin "
+"verilmiyor"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif eksik"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry eksik"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile eksik"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor eksik"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :while olmadan :endwhile"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :for olmadan :endfor"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Dosya mevcut (geçersiz kılmak için ! ekleyin)"
+
+msgid "E472: Command failed"
+msgstr "E472: Komut başarısız oldu"
+
+msgid "E473: Internal error"
+msgstr "E473: İçsel hata"
#, c-format
-msgid "E344: Can't find directory \"%s\" in cdpath"
-msgstr "E344: \"%s\" dizini cdpath içinde bulunamadı"
+msgid "E685: Internal error: %s"
+msgstr "E685: İçsel hata: %s"
+
+msgid "Interrupted"
+msgstr "Yarıda kesildi"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Geçersiz argüman"
#, c-format
-msgid "E345: Can't find file \"%s\" in path"
-msgstr "E345: \"%s\" dosyası yol içinde bulunamadı"
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Geçersiz argüman: %s"
#, c-format
-msgid "E346: No more directory \"%s\" found in cdpath"
-msgstr "E346: Başka bir \"%s\" dizini cdpath içinde bulunamadı"
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: %s argümanı için geçersiz değer"
#, c-format
-msgid "E347: No more file \"%s\" found in path"
-msgstr "E347: Başka bir \"%s\" dosyası yol içinde bulunamadı"
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: %s argümanı için geçersiz değer: %s"
-msgid "E446: No file name under cursor"
-msgstr "E446: İmleç altında bir dosya adı yok"
+#, c-format
+msgid "E983: Duplicate argument: %s"
+msgstr "E983: Yinelenen argüman: %s"
#, c-format
-msgid "E447: Can't find file \"%s\" in path"
-msgstr "E447: \"%s\" dosyası yol içinde bulunamadı"
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Geçersiz ifade: %s"
-msgid "E808: Number or Float required"
-msgstr "E808: Sayı veya kayan noktalı değer gerekiyor"
+msgid "E16: Invalid range"
+msgstr "E16: Geçersiz erim"
-msgid "E490: No fold found"
-msgstr "E490: Kıvırma bulunamadı"
+msgid "E476: Invalid command"
+msgstr "E476: Geçersiz komut"
-msgid "E350: Cannot create fold with current 'foldmethod'"
-msgstr "E350: Şu anki 'foldmethod' ile kıvırma oluşturulamıyor"
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" bir dizin"
-msgid "E351: Cannot delete fold with current 'foldmethod'"
-msgstr "E351: Şu anki 'foldmethod' ile kıvırma silinemiyor"
+msgid "E756: Spell checking is not possible"
+msgstr "E756: Yazım denetimi olanaklı değil"
+
+msgid "E900: Invalid channel id"
+msgstr "E900: Geçersiz kanal kimliği"
+
+msgid "E900: Invalid channel id: not a job"
+msgstr "E900: Geçersiz kanal kimliği: Bir iş değil"
+
+msgid "E901: Job table is full"
+msgstr "E901: İş tablosu dolu"
#, c-format
-msgid "+--%3ld line folded "
-msgid_plural "+--%3ld lines folded "
-msgstr[0] "+--%3ld satır kıvrıldı "
-msgstr[1] "+--%3ld satır kıvrıldı "
+msgid "E903: Process failed to start: %s: \"%s\""
+msgstr "E903: Süreç başlatılamadı: %s: \"%s\""
+
+msgid "E904: channel is not a pty"
+msgstr "E904: Kanal bir pty değil"
#, c-format
-msgid "+-%s%3ld line: "
-msgid_plural "+-%s%3ld lines: "
-msgstr[0] "+-%s%3ld satır: "
-msgstr[1] "+-%s%3ld satır: "
+msgid "E905: Couldn't open stdio channel: %s"
+msgstr "E905: stdio kanalı açılamadı: %s"
-msgid "E222: Add to read buffer"
-msgstr "E222: Okuma arabelleğine ekle"
+msgid "E906: invalid stream for channel"
+msgstr "E906: Kanal için geçersiz akış"
-msgid "E223: recursive mapping"
-msgstr "E223: Özyineli eşlemleme"
+msgid "E906: invalid stream for rpc channel, use 'rpc'"
+msgstr "E906: rpc kanalı için geçersiz akış, 'rpc' kullanın"
-msgid "E851: Failed to create a new process for the GUI"
-msgstr "E851: Grafik arabirim için yeni bir işlem yaratılamadı"
+#, c-format
+msgid ""
+"E5210: dict key '%s' already set for buffered stream in channel %<PRIu64>"
+msgstr "E5210: '%s' sözlük anahtarı, %<PRIu64> kanalında halihazırda "
+"arabelleklenmiş akış için ayarlandı"
-msgid "E852: The child process failed to start the GUI"
-msgstr "E852: Alt işlem grafik arabirimini başlatamadı"
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: \"%s()\" için kitaplık çağrısı başarısız oldu"
-msgid "E229: Cannot start the GUI"
-msgstr "E229: Grafik arabirimi başlatılamıyor"
+#, c-format
+msgid "E667: Fsync failed: %s"
+msgstr "E667: Fsync başarısız oldu: %s"
#, c-format
-msgid "E230: Cannot read from \"%s\""
-msgstr "E230: \"%s\" okunamıyor"
+msgid "E739: Cannot create directory %s: %s"
+msgstr "E739: Dizin oluşturulamıyor: %s: %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: İm satır numarası geçersiz"
-msgid "E665: Cannot start GUI, no valid font found"
-msgstr "E665: Grafik arabirim başlatılamıyor, geçerli bir font bulunamadı"
+msgid "E20: Mark not set"
+msgstr "E20: İm ayarlanmamış"
-msgid "E231: 'guifontwide' invalid"
-msgstr "E231: 'guifontwide' geçersiz"
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Değişiklik yapılamıyor, 'modifiable' kapalı"
-msgid "E599: Value of 'imactivatekey' is invalid"
-msgstr "E599: 'imactivatekey' değeri geçersiz"
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Betikler çok iç içe geçmiş"
-msgid "No match at cursor, finding next"
-msgstr "İmleç konumunda eşleşme bulunamadı, sonraki bulunuyor"
+msgid "E23: No alternate file"
+msgstr "E23: Başka bir dosya yok"
-msgid "<cannot open> "
-msgstr "<açılamıyor> "
+msgid "E24: No such abbreviation"
+msgstr "E24: Böyle bir kısaltma yok"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! imine izin verilmiyor"
#, c-format
-msgid "E616: vim_SelFile: can't get font %s"
-msgstr "E616: vim_SelFile: %s fontu bulunamıyor"
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Böyle bir vurgulama grup adı yok: %s"
-msgid "E614: vim_SelFile: can't return to current directory"
-msgstr "E614: vim_SelFile: Şu anki dizine dönülemiyor"
+msgid "E29: No inserted text yet"
+msgstr "E29: Henüz bir metin eklenmedi"
-msgid "Pathname:"
-msgstr "Yol adı:"
+msgid "E30: No previous command line"
+msgstr "E30: Öncesinde komut satırı yok"
-msgid "E615: vim_SelFile: can't get current directory"
-msgstr "E615: vim_SelFile: Şu anki dizin bulunamıyor"
+msgid "E31: No such mapping"
+msgstr "E31: Böyle bir eşlem yok"
-msgid "OK"
-msgstr "Tamam"
+msgid "E479: No match"
+msgstr "E479: Eşleşme yok"
-msgid "Cancel"
-msgstr "İptal"
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Eşleşme yok: %s"
-msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
-msgstr "Kaydırma Parçacığı: Kenar piksel haritası geometrisi bulunamadı"
+msgid "E32: No file name"
+msgstr "E32: Dosya adı yok"
-msgid "Vim dialog"
-msgstr "Vim"
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Öncesinde yerine geçen bir düzenli ifade yok"
-msgid "E232: Cannot create BalloonEval with both message and callback"
-msgstr "E232: Hem ileti hem de geri çağırma ile BallonEval oluşturulamıyor"
+msgid "E34: No previous command"
+msgstr "E34: Öncesinde komut yok"
-msgid "_Save"
-msgstr "_Kaydet"
+msgid "E35: No previous regular expression"
+msgstr "E35: Öncesinde düzenli ifade yok"
-msgid "_Open"
-msgstr "_Aç"
+msgid "E481: No range allowed"
+msgstr "E481: Erime izin verilmiyor"
-msgid "_Cancel"
-msgstr "İ_ptal"
+msgid "E36: Not enough room"
+msgstr "E36: Yeterli alan yok"
-msgid "_OK"
-msgstr "_Tamam"
+msgid "E483: Can't get temp file name"
+msgstr "E483: Geçici dosya adı alınamıyor"
-msgid ""
-"&Yes\n"
-"&No\n"
-"&Cancel"
-msgstr ""
-"&Evet\n"
-"&Hayır\n"
-"İ&ptal"
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: %s dosyası açılamıyor"
-msgid "Yes"
-msgstr "Evet"
+#, c-format
+msgid "E484: Can't open file %s: %s"
+msgstr "E484: %s dosyası açılamıyor: %s"
-msgid "No"
-msgstr "Hayır"
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: %s dosyası okunamıyor"
-msgid "Input _Methods"
-msgstr "Giriş _Yöntemleri"
+msgid "E38: Null argument"
+msgstr "E38: Anlamsız argüman"
-msgid "VIM - Search and Replace..."
-msgstr "VİM - Ara ve Değiştir..."
+msgid "E39: Number expected"
+msgstr "E39: Sayı bekleniyordu"
-msgid "VIM - Search..."
-msgstr "VİM - Ara..."
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Hata dosyası %s açılamıyor"
-msgid "Find what:"
-msgstr "Bulunacak nesne:"
+msgid "E41: Out of memory!"
+msgstr "E41: Bellek tükendi!"
-msgid "Replace with:"
-msgstr "Şununla değiştir:"
+msgid "Pattern not found"
+msgstr "Dizgi bulunamadı"
-msgid "Match whole word only"
-msgstr "Tam sözcükleri ara"
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Dizgi bulunamadı: %s"
-msgid "Match case"
-msgstr "BÜYÜK/küçük harf duyarlı"
+msgid "E487: Argument must be positive"
+msgstr "E487: Değişken pozitif olmalı"
-msgid "Direction"
-msgstr "Yön"
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Bir önceki dizine gidilemiyor"
-msgid "Up"
-msgstr "Yukarı"
+msgid "E42: No Errors"
+msgstr "E42: Hata yok"
-msgid "Down"
-msgstr "Aşağı"
+msgid "E776: No location list"
+msgstr "E776: Konum listesi yok"
-msgid "Find Next"
-msgstr "Sonrakini Bul"
+msgid "E43: Damaged match string"
+msgstr "E43: Hasarlı eşleşme dizisi"
-msgid "Replace"
-msgstr "Değiştir"
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Bozulmuş regexp programı"
-msgid "Replace All"
-msgstr "Tümünü Değiştir"
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' seçeneği ayarlanmış (geçersiz kılmak için ! ekleyin)"
-msgid "_Close"
-msgstr "K_apat"
+#, c-format
+msgid "E46: Cannot change read-only variable \"%.*s\""
+msgstr "E46: Saltokunur değişken \"%.*s\" değiştirilemiyor"
-msgid "Vim: Received \"die\" request from session manager\n"
-msgstr "Vim: Oturum yöneticisinden işi sonlandırma isteği geldi\n"
+msgid "E928: String required"
+msgstr "E928: Dizi gerekiyor"
-msgid "Close tab"
-msgstr "Sekmeyi kapat"
+msgid "E715: Dictionary required"
+msgstr "E715: Sözlük gerekiyor"
-msgid "New tab"
-msgstr "Yeni sekme"
+#, c-format
+msgid "E979: Blob index out of range: %<PRId64>"
+msgstr "E979: İkili geniş nesne indeksi erimin dışında: %<PRId64>"
-msgid "Open Tab..."
-msgstr "Sekme Aç..."
+msgid "E978: Invalid operation for Blob"
+msgstr "E978: İkili geniş nesne için geçersiz işlem"
-msgid "Vim: Main window unexpectedly destroyed\n"
-msgstr "Vim: Ana pencere beklenmedik bir biçimde gitti\n"
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: İşlev için pek fazla argüman: %s"
-msgid "&Filter"
-msgstr "&Süz"
+#, c-format
+msgid "E716: Key not present in Dictionary: \"%s\""
+msgstr "E716: Anahtar sözlükte mevcut değil: \"%s\""
-msgid "&Cancel"
-msgstr "İ&ptal"
+msgid "E714: List required"
+msgstr "E714: Liste gerekiyor"
-msgid "Directories"
-msgstr "Dizinler"
+msgid "E897: List or Blob required"
+msgstr "E897: Liste veya ikili geniş nesne gerekiyor"
-msgid "Filter"
-msgstr "Süzgeç"
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ögesinin argümanı bir liste veya sözlük olmalıdır"
-msgid "&Help"
-msgstr "&Yardım"
+#, c-format
+msgid "E896: Argument of %s must be a List, Dictionary or Blob"
+msgstr "E896: %s argümanı bir liste, sözlük veya ikili geniş nesne olmalıdır"
-msgid "Files"
-msgstr "Dosyalar"
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Hata dosyası okunurken hata"
-msgid "&OK"
-msgstr "&Tamam"
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Kum havuzunda izin verilmiyor"
-msgid "Selection"
-msgstr "Seçim"
+msgid "E523: Not allowed here"
+msgstr "E523: Burada izin verilmiyor"
-msgid "Find &Next"
-msgstr "Sonrakini &Bul"
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ekran kipi ayarı desteklenmiyor"
-msgid "&Replace"
-msgstr "&Değiştir"
+msgid "E49: Invalid scroll size"
+msgstr "E49: Geçersiz kaydırma boyutu"
-msgid "Replace &All"
-msgstr "Tümünü D&eğiştir"
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' seçeneği boş"
-msgid "&Undo"
-msgstr "&Geri al"
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: İşaret verisinde okunamadı!"
-msgid "Open tab..."
-msgstr "Sekme aç..."
+msgid "E72: Close error on swap file"
+msgstr "E72: Takas dosyasında kapatma hatası"
-msgid "Find string"
-msgstr "Dizi bul"
+msgid "E73: tag stack empty"
+msgstr "E73: Etiket yığını boş"
-msgid "Find & Replace"
-msgstr "Bul ve Değiştir"
+msgid "E74: Command too complex"
+msgstr "E74: Komut çok karmaşık"
-msgid "Not Used"
-msgstr "Kullanılmıyor"
+msgid "E75: Name too long"
+msgstr "E75: Ad çok uzun"
-msgid "Directory\t*.nothing\n"
-msgstr "Directory\t*.hiçbir şey\n"
+msgid "E76: Too many ["
+msgstr "E76: Çok fazla ["
-#, c-format
-msgid "E671: Cannot find window title \"%s\""
-msgstr "E671: Pencere başlığı \"%s\" bulunamıyor"
+msgid "E77: Too many file names"
+msgstr "E77: Çok fazla dosya adı"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Sonda fazladan karakterler"
#, c-format
-msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
-msgstr "E243: \"-%s\" argümanı desteklenmiyor; OLE sürümünü kullanın."
+msgid "E488: Trailing characters: %s"
+msgstr "E488: Sonda fazladan karakterler: %s"
-msgid "E988: GUI cannot be used. Cannot execute gvim.exe."
-msgstr "E988: Grafik arabirim kullanılamaz. gvim.exe çalıştırılamadı."
+msgid "E78: Unknown mark"
+msgstr "E78: Bilinmeyen im"
-msgid "E672: Unable to open window inside MDI application"
-msgstr "E672: MDI uygulaması içinde pencere açılamıyor"
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Joker karakterleri genişletilemiyor"
-msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
-msgstr ""
-"Vim E458: Renk eşlemi girdisi ayrılamadı, bazı renkler hatalı görünebilir"
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' değeri 'winminheight' değerinden küçük olamaz"
-#, c-format
-msgid "E250: Fonts for the following charsets are missing in fontset %s:"
-msgstr "E250: %s yazıtipi seti içinde şu karakter setleri için fontlar eksik:"
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' değeri 'winminwidth' değerinden küçük olamaz"
-#, c-format
-msgid "E252: Fontset name: %s"
-msgstr "E252: Yazıtipi seti adı: %s"
+msgid "E80: Error while writing"
+msgstr "E80: Yazma sırasında hata"
-#, c-format
-msgid "Font '%s' is not fixed-width"
-msgstr "'%s' yazıtipi sabit aralıklı değil"
+msgid "E939: Positive count required"
+msgstr "E939: Pozitif sayım gerekiyor"
-#, c-format
-msgid "E253: Fontset name: %s"
-msgstr "E253: Yazıtipi seti adı: %s"
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> bir betik bağlamında kullanılmıyor"
#, c-format
-msgid "Font0: %s"
-msgstr "Yazıtipi0: %s"
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Ayraç eksik: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Dizgi 'maxmempattern' ögesinden daha fazla bellek kullanıyor"
+
+msgid "E749: empty buffer"
+msgstr "E749: Boş arabellek"
#, c-format
-msgid "Font%d: %s"
-msgstr "Yazıtipi%d: %s"
+msgid "E86: Buffer %<PRId64> does not exist"
+msgstr "E86: Arabellek %<PRId64> mevcut değil"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Geçersiz arama dizgisi veya sınırlandırıcısı"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Dosya başka bir arabellekte yüklü"
#, c-format
-msgid "Font%d width is not twice that of font0"
-msgstr "Yazıtipi%d genişliği yazıtipi0 genişliğinin iki katı olmalıdır"
+msgid "E764: Option '%s' is not set"
+msgstr "E764: '%s' seçeneği ayarlanmamış"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Geçersiz yazmaç adı"
#, c-format
-msgid "Font0 width: %d"
-msgstr "Yazıtipi0 genişliği: %d"
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: '%s' içinde dizin bulunamadı: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Otokomut özyineli davranışa neden oldu"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Otokomut penceresi kapatılamıyor"
#, c-format
-msgid "Font%d width: %d"
-msgstr "Yazıtipi%d genişliği: %d"
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s argümanı bir liste olmalı"
+
+msgid "E519: Option not supported"
+msgstr "E519: Özellik desteklenmiyor"
-msgid "E284: Cannot set IC values"
-msgstr "E284: Girdi bağlamı değerleri ayarlanamıyor"
+msgid "E856: Filename too long"
+msgstr "E856: Dosya adı pek uzun"
-msgid "E285: Failed to create input context"
-msgstr "E285: Girdi bağlamı oluşturulamadı"
+msgid "E806: using Float as a String"
+msgstr "E806: Kayan Noktalı Değer, bir Dizi yerine kullanılıyor"
-msgid "E286: Failed to open input method"
-msgstr "E286: Giriş yöntemi açılamadı"
+#, c-format
+msgid "E5500: autocmd has thrown an exception: %s"
+msgstr "E5500: Otokomut, bir istisna attı: %s"
-msgid "E287: Warning: Could not set destroy callback to IM"
-msgstr "E287: Uyarı: Giriş yöntemine yok etme geri çağırması ayarlanamadı"
+msgid "E5520: <Cmd> mapping must end with <CR>"
+msgstr "E5520: <Cmd> eşlemlemesi <CR> ile bitmelidir"
-msgid "E288: input method doesn't support any style"
-msgstr "E288: Giriş yöntemi herhangi bir biçemi desteklemiyor"
+msgid "E5521: <Cmd> mapping must end with <CR> before second <Cmd>"
+msgstr "E5521: <Cmd> eşlemlemesi ikinci <Cmd>'den önce <CR> ile bitmelidir"
-msgid "E289: input method doesn't support my preedit type"
-msgstr "E289: Giriş yöntemi benim ön düzenleme türümü desteklemiyor"
+#, c-format
+msgid "E5522: <Cmd> mapping must not include %s key"
+msgstr "E5522: <Cmd> eşlemlemesi %s anahtarını içermemelidir"
-msgid "Invalid font specification"
-msgstr "Geçersiz yazıtipi belirtimi"
+#, c-format
+msgid "E5555: API call: %s"
+msgstr "E5555: API çağrısı: %s"
-msgid "&Dismiss"
-msgstr "So&nlandır"
+#, c-format
+msgid "E5560: %s must not be called in a lua loop callback"
+msgstr "E5560: %s, bir lua döngü geri çağrısında çağrılmamalıdır"
-msgid "no specific match"
-msgstr "belirli bir eşleşme yok"
+msgid "E5601: Cannot close window, only floating window would remain"
+msgstr "E5601: Pencere kapatılamıyor, yalnızca yüzen pencere açık kalır"
-msgid "Vim - Font Selector"
-msgstr "Vim - Yazıtipi Seçicisi"
+msgid "E5602: Cannot exchange or rotate float"
+msgstr "E5602: Kayan noktalı değer değiştirilemiyor veya döndürülemiyor"
-msgid "Name:"
-msgstr "Ad:"
+msgid "E1142: Non-empty string required"
+msgstr "E1142: Boş olmayan dizi gerekiyor"
-msgid "Show size in Points"
-msgstr "Büyüklüğü puntolarla göster"
+msgid "E1155: Cannot define autocommands for ALL events"
+msgstr "E1155: Otokomutlar TÜM olaylar için tanımlanamıyor"
-msgid "Encoding:"
-msgstr "Kodlama:"
+msgid "E1240: Resulting text too long"
+msgstr "E1240: Ortaya çıkan metin pek uzun"
-msgid "Font:"
-msgstr "Yazıtipi:"
+msgid "E1247: Line number out of range"
+msgstr "E1247: Satır numarası erim dışında"
-msgid "Style:"
-msgstr "Biçem:"
+msgid "E1249: Highlight group name too long"
+msgstr "E1249: Vurgulama grubu adı pek uzun"
-msgid "Size:"
-msgstr "Büyüklük:"
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Arama dosyanın BAŞINI geçti, dosyanın SONUNDAN sürüyor"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Arama dosyanın SONUNU geçti, dosyanın BAŞINDAN sürüyor"
+
+msgid " line "
+msgstr " satır "
msgid "E550: Missing colon"
msgstr "E550: İki nokta eksik"
@@ -1927,8 +2927,8 @@ msgid "No text to be printed"
msgstr "Yazdırılacak metin yok"
#, c-format
-msgid "Printing page %d (%d%%)"
-msgstr "Sayfa yazdırılıyor: %d (%d%%)"
+msgid "Printing page %d (%zu%%)"
+msgstr "Sayfa %d yazdırılıyor (%%%zu)"
#, c-format
msgid " Copy %d of %d"
@@ -1950,28 +2950,28 @@ msgstr "E624: \"%s\" dosyası açılamıyor"
#, c-format
msgid "E457: Can't read PostScript resource file \"%s\""
-msgstr "E457: PostScript kaynak dosyası \"%s\" okunamıyor"
+msgstr "E457: PostScript özkaynak dosyası \"%s\" okunamıyor"
#, c-format
msgid "E618: file \"%s\" is not a PostScript resource file"
-msgstr "E618: \"%s\" dosyası bir PostScript kaynak dosyası değil"
+msgstr "E618: \"%s\" dosyası bir PostScript özkaynak dosyası değil"
#, c-format
msgid "E619: file \"%s\" is not a supported PostScript resource file"
-msgstr "E619: \"%s\" dosyası desteklenen bir PostScript kaynak dosyası değil"
+msgstr "E619: \"%s\" dosyası desteklenen bir PostScript özkaynak dosyası değil"
#, c-format
msgid "E621: \"%s\" resource file has wrong version"
-msgstr "E621: \"%s\" kaynak dosyası sürümü hatalı"
+msgstr "E621: \"%s\" özkaynak dosyası sürümü hatalı"
msgid "E673: Incompatible multi-byte encoding and character set."
-msgstr "E673: Uyumsuz çoklu bit kodlaması ve karakter seti."
+msgstr "E673: Uyumsuz çoklu bayt kodlaması ve karakter kümesi."
msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
-msgstr "E674: printmbcharset çoklu bit kodlamada boş olamaz"
+msgstr "E674: printmbcharset çoklu bayt kodlamada boş olamaz."
msgid "E675: No default font specified for multi-byte printing."
-msgstr "E675: Çoklu bit yazdırma için öntanımlı yazıtipi ayarlanmamış."
+msgstr "E675: Çoklu bayt yazdırma için öntanımlı yazıtipi ayarlanmamış."
msgid "E324: Can't open PostScript output file"
msgstr "E324: PostScript çıktı dosyası açılamıyor"
@@ -1981,14 +2981,14 @@ msgid "E456: Can't open file \"%s\""
msgstr "E456: \"%s\" dosyası açılamıyor"
msgid "E456: Can't find PostScript resource file \"prolog.ps\""
-msgstr "E456: PostScript kaynak dosyası \"prolog.ps\" bulunamıyor"
+msgstr "E456: PostScript özkaynak dosyası \"prolog.ps\" bulunamıyor"
msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
-msgstr "E456: PostScript kaynak dosyası \"cidfont.ps\" bulunamıyor"
+msgstr "E456: PostScript özkaynak dosyası \"cidfont.ps\" bulunamıyor"
#, c-format
msgid "E456: Can't find PostScript resource file \"%s.ps\""
-msgstr "E456: PostScript kaynak dosyası \"%s.ps\" bulunamıyor"
+msgstr "E456: PostScript özkaynak dosyası \"%s.ps\" bulunamıyor"
#, c-format
msgid "E620: Unable to convert to print encoding \"%s\""
@@ -2001,49 +3001,10 @@ msgid "E365: Failed to print PostScript file"
msgstr "E365: PostScript dosyası yazdırılamadı"
msgid "Print job sent."
-msgstr "Yazdırma işi gönderildi"
-
-msgid "E478: Don't panic!"
-msgstr "E478: Panik yok!"
-
-#, c-format
-msgid "E661: Sorry, no '%s' help for %s"
-msgstr "E661: Üzgünüm, '%s' yardımı %s için mevcut değil"
-
-#, c-format
-msgid "E149: Sorry, no help for %s"
-msgstr "E149: Üzgünüm, %s için yardım mevcut değil"
-
-#, c-format
-msgid "Sorry, help file \"%s\" not found"
-msgstr "Üzgünüm, \"%s\" yardım dosyası bulunamadı"
-
-#, c-format
-msgid "E151: No match: %s"
-msgstr "E151: Eşleşme bulunamadı: %s"
-
-#, c-format
-msgid "E152: Cannot open %s for writing"
-msgstr "E152: %s yazma için açılamıyor"
+msgstr "Yazdırma işi gönderildi."
-#, c-format
-msgid "E153: Unable to open %s for reading"
-msgstr "E153: %s okuma için açılamıyor"
-
-#, c-format
-msgid "E670: Mix of help file encodings within a language: %s"
-msgstr "E670: Bir dilde yardım dosyası kodlamaları karıştı: %s"
-
-#, c-format
-msgid "E154: Duplicate tag \"%s\" in file %s/%s"
-msgstr "E154: Şu dosyada yinelenen \"%s\" etiketi: %s/%s"
-
-#, c-format
-msgid "E150: Not a directory: %s"
-msgstr "E150: %s bir dizin değil"
-
-msgid "E679: recursive loop loading syncolor.vim"
-msgstr "E679: syncolor.vim yüklenirken özyineli döngü"
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Çok fazla değişik vurgulama kuralları kullanılıyor"
#, c-format
msgid "E411: highlight group not found: %s"
@@ -2082,24 +3043,14 @@ msgstr "E419: Bilinmeyen metin rengi"
msgid "E420: BG color unknown"
msgstr "E420: Bilinmeyen ardalan rengi"
-msgid "E453: UL color unknown"
-msgstr "E453: Bilinmeyen alt çizme rengi"
-
#, c-format
msgid "E421: Color name or number not recognized: %s"
msgstr "E421: Renk adı veya numarası tanımlanamadı: %s"
#, c-format
-msgid "E422: terminal code too long: %s"
-msgstr "E422: Uçbirim kodu çok uzun: %s"
-
-#, c-format
msgid "E423: Illegal argument: %s"
msgstr "E423: İzin verilmeyen argüman: %s"
-msgid "E424: Too many different highlighting attributes in use"
-msgstr "E424: Çok fazla değişik vurgulama kuralları kullanılıyor"
-
msgid "E669: Unprintable character in group name"
msgstr "E669: Grup adında yazdırılamayan karakter"
@@ -2144,20 +3095,17 @@ msgstr "E257: cstag: Etiket bulunamadı"
msgid "E563: stat(%s) error: %d"
msgstr "E563: stat(%s) hatası: %d"
-msgid "E563: stat error"
-msgstr "E563: stat hatası"
-
#, c-format
msgid "E564: %s is not a directory or a valid cscope database"
-msgstr "E564: %s bir dizin veya geçerli bir cscope veritabanı değil"
+msgstr "E564: %s, bir dizin veya geçerli bir cscope veritabanı değil"
#, c-format
msgid "Added cscope database %s"
msgstr "cscope veritabanı %s eklendi"
#, c-format
-msgid "E262: error reading cscope connection %d"
-msgstr "E262: cscope bağlantısı %d okunurken hata"
+msgid "E262: error reading cscope connection %<PRIu64>"
+msgstr "E262: cscope bağlantısı %<PRIu64> okunurken hata"
msgid "E561: unknown cscope search type"
msgstr "E561: Bilinmeyen cscope arama türü"
@@ -2181,7 +3129,7 @@ msgid "cs_create_connection: fdopen for fr_fp failed"
msgstr "cs_create_connection: fr_fp için fdopen başarısız oldu"
msgid "E623: Could not spawn cscope process"
-msgstr "E623: cscope işlemi ortaya çıkarılamadı"
+msgstr "E623: cscope süreci ortaya çıkarılamadı"
msgid "E567: no cscope connections"
msgstr "E567: cscope bağlantıları yok"
@@ -2224,13 +3172,6 @@ msgstr ""
" s: Bu \"C\" sembolünü bul\n"
" t: Bu metin dizisini bul\n"
-#, c-format
-msgid "E625: cannot open cscope database: %s"
-msgstr "E625: cscope veritabanı açılamıyor: %s"
-
-msgid "E626: cannot get cscope database information"
-msgstr "E626: cscope veritabanı bilgisi alınamıyor"
-
msgid "E568: duplicate cscope database not added"
msgstr "E568: Yinelenen cscope veritabanı eklenmemiş"
@@ -2272,389 +3213,109 @@ msgstr "cscope bağlantısı yok\n"
msgid " # pid database name prepend path\n"
msgstr " # pid veritabanı adı başlangıç yolu\n"
-msgid "Lua library cannot be loaded."
-msgstr "Lua kitaplığı yüklenemedi."
-
-msgid "cannot save undo information"
-msgstr "Geri al bilgisi kaydedilemiyor"
-
-msgid ""
-"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
-"loaded."
-msgstr ""
-"E815: Üzgünüm, bu komut etkin değil, MzScheme kitaplıkları yüklenemedi."
-
-msgid ""
-"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
-"could not be loaded."
+msgid "Type number and <Enter> or click with the mouse (q or empty cancels): "
msgstr ""
-"E895: Üzgünüm, bu komut etkin değil, MzScheme'in racket/base birimi "
-"yüklenemedi."
-
-msgid "invalid expression"
-msgstr "geçersiz ifade"
-
-msgid "expressions disabled at compile time"
-msgstr "ifadeler derleme aşamasında kapatılmış"
-
-msgid "hidden option"
-msgstr "gizli seçenek"
-
-msgid "unknown option"
-msgstr "bilinmeyen seçenek"
-
-msgid "window index is out of range"
-msgstr "pencere sırası erimin dışında"
-
-msgid "couldn't open buffer"
-msgstr "arabellek açılamadı"
-
-msgid "cannot delete line"
-msgstr "satır silinemiyor"
-
-msgid "cannot replace line"
-msgstr "satır değiştirilemiyor"
-
-msgid "cannot insert line"
-msgstr "satır eklenemiyor"
-
-msgid "string cannot contain newlines"
-msgstr "dizi \"yeni satır\" imi içeremez"
-
-msgid "error converting Scheme values to Vim"
-msgstr "Scheme değerlerini Vim değerlerine dönüştürürken hata"
-
-msgid "Vim error: ~a"
-msgstr "Vim hatası: ~a"
-
-msgid "Vim error"
-msgstr "Vim hatası"
-
-msgid "buffer is invalid"
-msgstr "arabellek geçersiz"
-
-msgid "window is invalid"
-msgstr "pencere geçersiz"
-
-msgid "linenr out of range"
-msgstr "linenr erimin dışında"
-
-msgid "not allowed in the Vim sandbox"
-msgstr "Vim kum havuzunda izin verilmiyor"
+"Sayı girip <Enter>'a veya fare düğmesine basın (q veya boş iptal eder): "
-msgid "E836: This Vim cannot execute :python after using :py3"
-msgstr "E836: Bu Vim :py3 komutundan sonra :python komutunu çalıştıramaz"
+msgid "Type number and <Enter> (q or empty cancels): "
+msgstr "Sayı girip <Enter>'a basın (q veya boş iptal eder): "
-msgid ""
-"E263: Sorry, this command is disabled, the Python library could not be "
-"loaded."
-msgstr "E263: Üzgünüm, bu komut etkin değil, Python kitaplığı yüklenemedi"
+#, c-format
+msgid "E1502: Lua failed to grow stack to %i"
+msgstr "E1502: Lua, yığını %i olarak büyütemedi"
msgid ""
-"E887: Sorry, this command is disabled, the Python's site module could not be "
-"loaded."
+"E5100: Cannot convert given lua table: table should either have a sequence "
+"of positive integer keys or contain only string keys"
msgstr ""
-"E887: Üzgünüm, bu komut etkin değil, Python'un site birimi yüklenemedi."
-
-msgid "E659: Cannot invoke Python recursively"
-msgstr "E659: Python özyineli olarak çalıştırılamıyor"
-
-msgid "E837: This Vim cannot execute :py3 after using :python"
-msgstr "E837: Bu Vim :python komutundan sonra :py3 komutunu çalıştıramaz"
+"E5100: Verilen lua tablosu dönüştürülemiyor: Tabloda ya bir tamsayı anahtar "
+"sıramalası olmalı veya yalnızca dizi anahtarlar içermeli"
-msgid "E265: $_ must be an instance of String"
-msgstr "E265: $_ bir dizi örneği olmalıdır"
-
-msgid ""
-"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
-msgstr "E266: Üzgünüm, bu komut etkin değil, Ruby kitaplığı yüklenemedi."
-
-msgid "E267: unexpected return"
-msgstr "E267: Beklenmeyen dönüş"
-
-msgid "E268: unexpected next"
-msgstr "E268: Beklenmeyen sonraki"
-
-msgid "E269: unexpected break"
-msgstr "E269: Beklenmeyen kesme"
-
-msgid "E270: unexpected redo"
-msgstr "E270: Beklenmeyen yinele komutu"
-
-msgid "E271: retry outside of rescue clause"
-msgstr "E271: retry, rescue işlecinin dışında"
-
-msgid "E272: unhandled exception"
-msgstr "E272: İşletilemeyen kural dışı durum"
+msgid "E5101: Cannot convert given lua type"
+msgstr "E5101: Verilen lua türü dönüştürülemiyor"
#, c-format
-msgid "E273: unknown longjmp status %d"
-msgstr "E273: Bilinmeyen longjmp durumu %d"
-
-msgid "invalid buffer number"
-msgstr "Geçersiz arabellek numarası"
-
-msgid "not implemented yet"
-msgstr "henüz uygulanmadı"
-
-msgid "cannot set line(s)"
-msgstr "satır(lar) ayarlanamıyor"
-
-msgid "invalid mark name"
-msgstr "geçersiz im adı"
-
-msgid "mark not set"
-msgstr "im ayarlanmamış"
+msgid "E5102: Lua failed to grow stack to %i"
+msgstr "E5102: Lua, yığını %i olarak büyütemedi"
#, c-format
-msgid "row %d column %d"
-msgstr "satır %d sütun %d"
-
-msgid "cannot insert/append line"
-msgstr "satır eklenemiyor/iliştirilemiyor"
+msgid "Error executing vim.schedule lua callback: %.*s"
+msgstr "vim.schedule lua geri çağrısı çalıştırılırken hata: %.*s"
-msgid "line number out of range"
-msgstr "satır numarası erimin dışında"
+msgid "E970: Failed to initialize lua interpreter\n"
+msgstr "E970: lua yorumlayıcısı ilklendirilemedi\n"
-msgid "unknown flag: "
-msgstr "geçersiz bayrak: "
-
-msgid "unknown vimOption"
-msgstr "geçersiz vimOption"
-
-msgid "keyboard interrupt"
-msgstr "klavye araya girdi"
-
-msgid "cannot create buffer/window command: object is being deleted"
-msgstr "arabellek/pencere komutu oluşturulamadı: öge şu anda siliniyor"
-
-msgid ""
-"cannot register callback command: buffer/window is already being deleted"
-msgstr "geri çağırma komutu kaydedilemiyor: arabellek/pencere zaten siliniyor"
-
-msgid ""
-"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
-"org"
-msgstr ""
-"E280: ONULMAZ TCL HATASI: Başvuru listesi hasar görmüş! Lütfen bunu vim-"
-"dev@vim.org adresine bildirin"
-
-msgid "cannot register callback command: buffer/window reference not found"
-msgstr ""
-"geri çağırma komutu kaydedilemiyor: arabellek/pencere başvurusu bulunamadı"
-
-msgid ""
-"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
-msgstr "E571: Üzgünüm, bu komut etkin değil: Tcl kitaplığı yüklenemedi."
+msgid "E970: Failed to initialize builtin lua modules\n"
+msgstr "E970: Gömülü lua modülleri ilklendirilemedi\n"
#, c-format
-msgid "E572: exit code %d"
-msgstr "E572: %d çıkış kodu"
-
-msgid "cannot get line"
-msgstr "satır alınamıyor"
-
-msgid "Unable to register a command server name"
-msgstr "Bir komut sunucusu adı kaydedilemiyor"
-
-msgid "E248: Failed to send command to the destination program"
-msgstr "E248: Hedef programa komut gönderimi başarısız oldu"
+msgid "E5114: Error while converting print argument #%i: %.*s"
+msgstr "E5114: Yazdırma argümanı #%i dönüştürülürken hata: %.*s"
#, c-format
-msgid "E573: Invalid server id used: %s"
-msgstr "E573: Geçersiz sunucu kimliği kullanıldı: %s"
-
-msgid "E251: VIM instance registry property is badly formed. Deleted!"
-msgstr "E251: VİM oturumu kayıt değeri düzgün oluşturulmamış. Silindi!"
+msgid "E5115: Error while loading debug string: %.*s"
+msgstr "E5115: Hata ayıklama dizisi yüklenirken hata: %.*s"
#, c-format
-msgid "%ld lines to indent... "
-msgstr "girintilenecek %ld satır kaldı... "
+msgid "E5116: Error while calling debug string: %.*s"
+msgstr "E5116: Hata ayıklama dizisi çağrılırken hata: %.*s"
#, c-format
-msgid "%ld line indented "
-msgid_plural "%ld lines indented "
-msgstr[0] "%ld satır girintilendi "
-msgstr[1] "%ld satır girintilendi"
-
-msgid " Keyword completion (^N^P)"
-msgstr " Anahtar sözcük tamamlaması (^N^P)"
-
-msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
-msgstr " ^X kipi (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
-
-msgid " Whole line completion (^L^N^P)"
-msgstr " Tam satır tamamlaması (^L^N^P)"
-
-msgid " File name completion (^F^N^P)"
-msgstr " Dosya adı tamamlaması (^F^N^P)"
-
-msgid " Tag completion (^]^N^P)"
-msgstr " Etiket tamamlaması (^]^N^P)"
-
-msgid " Path pattern completion (^N^P)"
-msgstr " Yol dizgisi tamamlaması (^N^P)"
-
-msgid " Definition completion (^D^N^P)"
-msgstr " Tanım tamamlaması (^D^N^P)"
-
-msgid " Dictionary completion (^K^N^P)"
-msgstr " Sözlük tamamlaması (^K^N^P)"
-
-msgid " Thesaurus completion (^T^N^P)"
-msgstr " Eşanlamlılar sözlüğü tamamlaması (^T^N^P)"
-
-msgid " Command-line completion (^V^N^P)"
-msgstr " Komut satırı tamamlaması (^V^N^P)"
-
-msgid " User defined completion (^U^N^P)"
-msgstr " Kullanıcı tanımlı tamamlamalar (^U^N^P)"
-
-msgid " Omni completion (^O^N^P)"
-msgstr " Omni tamamlaması (^O^N^P)"
-
-msgid " Spelling suggestion (s^N^P)"
-msgstr " Yazım önerisi (s^N^P)"
-
-msgid " Keyword Local completion (^N^P)"
-msgstr " Dahili anahtar sözcük tamamlaması (^N^P)"
-
-msgid "Hit end of paragraph"
-msgstr "Paragrafın sonuna varıldı"
-
-msgid "E840: Completion function deleted text"
-msgstr "E840: Tamamlama işlevi metni sildi"
-
-msgid "'dictionary' option is empty"
-msgstr "'dictionary' seçeneği boş"
-
-msgid "'thesaurus' option is empty"
-msgstr "'thesaurus' seçeneği boş"
+msgid "E5108: Error executing Lua function: %.*s"
+msgstr "E5108: Lua işlevi çalıştırılırken hata: %.*s"
#, c-format
-msgid "Scanning dictionary: %s"
-msgstr "Sözlük taranıyor: %s"
-
-msgid " (insert) Scroll (^E/^Y)"
-msgstr " (ekle) Kaydır (^E/^Y)"
-
-msgid " (replace) Scroll (^E/^Y)"
-msgstr " (değiştir) Kaydır (^E/^Y)"
-
-msgid "E785: complete() can only be used in Insert mode"
-msgstr "E785: complete() yalnızca Ekleme kipinde kullanılabilir"
+msgid "E5107: Error loading lua %.*s"
+msgstr "E5107: lua %.*s yüklenirken hata"
#, c-format
-msgid "Scanning: %s"
-msgstr "Taranıyor: %s"
+msgid "E5108: Error executing lua %.*s"
+msgstr "E5108: lua %.*s çalıştırılırken hata"
-msgid "Scanning tags."
-msgstr "Etiketler taranıyor..."
-
-msgid "match in file"
-msgstr "dosya içinde eşleşme"
-
-msgid " Adding"
-msgstr " Ekleniyor"
-
-msgid "-- Searching..."
-msgstr "-- Aranıyor..."
-
-msgid "Back at original"
-msgstr "Başlangıca geri dönüldü"
-
-msgid "Word from other line"
-msgstr "Sözcük diğer satırdan"
+#, c-format
+msgid "Error executing lua callback: %.*s"
+msgstr "lua geri çağrısı çalıştırılırken hata: %.*s"
-msgid "The only match"
-msgstr "Tek eşleşen"
+msgid "cannot save undo information"
+msgstr "Geri al bilgisi kaydedilemiyor"
#, c-format
-msgid "match %d of %d"
-msgstr "eşleşme %d/%d"
+msgid "E5109: Error loading lua: %.*s"
+msgstr "E5109: lua yüklenirken hata: %.*s"
#, c-format
-msgid "match %d"
-msgstr "eşleşme %d"
-
-msgid "E920: _io file requires _name to be set"
-msgstr "E920: _io dosyası _name ayarlı olmasını gerektirir"
-
-msgid "E915: in_io buffer requires in_buf or in_name to be set"
-msgstr "E915: in_io arabelleği in_buf veya in_name ayarlı olmasını gerektirir"
+msgid "E5110: Error executing lua: %.*s"
+msgstr "E5110: lua çalıştırılırken hata: %.*s"
#, c-format
-msgid "E918: buffer must be loaded: %s"
-msgstr "E918: Arabellek yüklenmiş olmalıdır: %s"
-
-msgid "E916: not a valid job"
-msgstr "E916: Geçerli bir iş değil"
+msgid "E5111: Error calling lua: %.*s"
+msgstr "E5111: lua çağrılırken hata: %.*s"
#, c-format
-msgid "E491: json decode error at '%s'"
-msgstr "E491: '%s' konumunda json çözümü hatası"
+msgid "E5112: Error while creating lua chunk: %.*s"
+msgstr "E5112: lua parçası oluşturulurken hata: %.*s"
#, c-format
-msgid "E938: Duplicate key in JSON: \"%s\""
-msgstr "E938: JSON'da yinelenmiş anahtar: \"%s\""
+msgid "E5113: Error while calling lua chunk: %.*s"
+msgstr "E5113: lua parçası çağrılırken hata: %.*s"
#, c-format
-msgid "E899: Argument of %s must be a List or Blob"
-msgstr "E899: %s argümanı bir liste veya ikili geniş nesne olmalıdır"
-
-msgid "E900: maxdepth must be non-negative number"
-msgstr "E900: maxdepth negatif olmayan bir sayı olmalı"
-
-msgid "flatten() argument"
-msgstr "flatten() argümanı"
+msgid "Error executing vim._expand_pat: %.*s"
+msgstr "vim._expand_pat çalıştırılırken hata: %.*s"
#, c-format
-msgid "E696: Missing comma in List: %s"
-msgstr "E696: Listede virgül eksik: %s"
-
-msgid "sort() argument"
-msgstr "sort() argümanı"
-
-msgid "uniq() argument"
-msgstr "uniq() argümanı"
-
-msgid "E702: Sort compare function failed"
-msgstr "E702: Sıralayıp karşılaştırma işlevi başarısız oldu"
-
-msgid "E882: Uniq compare function failed"
-msgstr "E882: Benzersizlik karşılaştırma işlevi başarısız oldu"
-
-msgid "map() argument"
-msgstr "map() argümanı"
-
-msgid "mapnew() argument"
-msgstr "mapnew() argümanı"
-
-msgid "filter() argument"
-msgstr "filter() argümanı"
-
-msgid "add() argument"
-msgstr "add() argümanı"
-
-msgid "extendnew() argument"
-msgstr "extendnew() argümanı"
-
-msgid "insert() argument"
-msgstr "insert() argümanı"
-
-msgid "remove() argument"
-msgstr "remove() argümanı"
-
-msgid "reverse() argument"
-msgstr "reverse() argümanı"
+msgid "Error executing vim.on_key Lua callback: %.*s"
+msgstr "vim.on_key Lua geri çağrısı çalıştırılırken hata: %.*s"
#, c-format
-msgid "Current %slanguage: \"%s\""
-msgstr "Şu anki %sdil: \"%s\""
+msgid "Error executing Lua callback: %.*s"
+msgstr "Lua geri çağrısı çalıştırılırken hata: %.*s"
-#, c-format
-msgid "E197: Cannot set language to \"%s\""
-msgstr "E197: \"%s\" diline ayarlanamıyor"
+msgid "Argument missing after"
+msgstr "Şundan sonra argüman eksik:"
+
+msgid "Garbage after option argument"
+msgstr "Seçenek argümanından sonra anlamsız veri"
msgid "Unknown option argument"
msgstr "Bilinmeyen seçenek argümanı"
@@ -2662,440 +3323,202 @@ msgstr "Bilinmeyen seçenek argümanı"
msgid "Too many edit arguments"
msgstr "Çok fazla düzenleme argümanı"
-msgid "Argument missing after"
-msgstr "Şundan sonra argüman eksik:"
-
-msgid "Garbage after option argument"
-msgstr "Seçenek argümanından sonra anlamsız veri"
-
msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
msgstr "Çok fazla \"+komut\", \"-c komut\" veya \"--cmd komut\" argümanı"
-msgid "Invalid argument for"
-msgstr "Şunun için geçersiz argüman:"
-
#, c-format
-msgid "%d files to edit\n"
-msgstr "%d dosya düzenleniyor\n"
+msgid "E5421: Failed to open stdin: %s"
+msgstr "E5421: stdin açılamadı: %s"
-msgid "netbeans is not supported with this GUI\n"
-msgstr "NetBeans bu grafik arabirimde desteklenmiyor\n"
-
-msgid "'-nb' cannot be used: not enabled at compile time\n"
-msgstr "'-nb' kullanılamaz: Derleme sırasında etkinleştirilmemiş\n"
-
-msgid "This Vim was not compiled with the diff feature."
-msgstr "Bu Vim karşılaştırma özelliği ile derlenmemiş"
-
-msgid "Attempt to open script file again: \""
-msgstr "Betik dosyası yeniden açılmaya çalışılıyor: \""
+#, c-format
+msgid "Attempt to open script file again: \"%s %s\"\n"
+msgstr "Betik dosyası yeniden açılmaya çalışılıyor: \"%s %s\"\n"
-msgid "Cannot open for reading: \""
-msgstr "Okuma için açılamıyor: \""
+#, c-format
+msgid "Cannot open for reading: \"%s\": %s\n"
+msgstr "Okuma için açılamıyor: \"%s\": %s\n"
msgid "Cannot open for script output: \""
msgstr "Betik çıktısı için açılamıyor: \""
-msgid "Vim: Error: Failure to start gvim from NetBeans\n"
-msgstr "Vim: Hata: gvim'i NetBeans içinden başlatma başarısız oldu\n"
-
-msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
-msgstr "Vim: Hata: Vim'in bu sürümü bir Cygwin uçbirimi içinde çalışmaz\n"
-
-msgid "Vim: Warning: Output is not to a terminal\n"
-msgstr "Vim: Uyarı: Çıktı bir uçbirime değil\n"
-
-msgid "Vim: Warning: Input is not from a terminal\n"
-msgstr "Vim: Uyarı: Girdi bir uçbirimden değil\n"
+msgid "--embed conflicts with -es/-Es"
+msgstr "--embed, -es/-Es ile çakışıyor"
msgid "pre-vimrc command line"
msgstr "vimrc uygulanma öncesi komut satırı"
#, c-format
+msgid "E5422: Conflicting configs: \"%s\" \"%s\""
+msgstr "E5422: Çakışan yapılandırmalar: \"%s\" \"%s\""
+
+#, c-format
msgid "E282: Cannot read from \"%s\""
msgstr "E282: Şuradan okunamıyor: \"%s\""
msgid ""
"\n"
-"More info with: \"vim -h\"\n"
+"More info with \""
msgstr ""
"\n"
-"Daha fazla bilgi için: \"vim -h\"\n"
-
-msgid "[file ..] edit specified file(s)"
-msgstr "[dosya ..] belirlenen dosyaları düzenle"
-
-msgid "- read text from stdin"
-msgstr "- stdin'den metni oku"
+"Daha fazla bilgi için: \""
-msgid "-t tag edit file where tag is defined"
-msgstr "-t etiket etiket tanımlanan dosyaları düzenle"
+msgid "Usage:\n"
+msgstr "Kullanım:\n"
-msgid "-q [errorfile] edit file with first error"
-msgstr "-q [hatalıd.] hata içeren ilk dosyayı düzenle"
-
-msgid ""
-"\n"
-"\n"
-"Usage:"
+msgid " nvim [options] [file ...] Edit file(s)\n"
msgstr ""
-"\n"
-"\n"
-"Kullanım:"
-
-msgid " vim [arguments] "
-msgstr " vim [argümanlar] "
+"nvim [seçenekler] [dosya ...] Dosyaları düzenle\n"
-msgid ""
-"\n"
-" or:"
+msgid " nvim [options] -t <tag> Edit file where tag is defined\n"
msgstr ""
-"\n"
-" veya:"
+"nvim [seçenekler] -t <etiket> Etiketin tanımlandığı dosyayı düzenle\n"
-msgid ""
-"\n"
-"Where case is ignored prepend / to make flag upper case"
+msgid " nvim [options] -q [errorfile] Edit file with first error\n"
msgstr ""
-"\n"
-"BÜYÜK/küçük harfin yok sayıldığı yerde bayrağı BÜYÜK harfli yapmak için "
-"başına / koyun"
+"nvim [seçenekler] -q [hatadosyası] İlk hatalı dosyayı düzenle\n"
msgid ""
"\n"
-"\n"
-"Arguments:\n"
+"Options:\n"
msgstr ""
"\n"
-"\n"
-"Değişkenler:\n"
-
-msgid "--\t\t\tOnly file names after this"
-msgstr "--\t\t\tBundan sonra yalnızca dosya adları"
-
-msgid "--literal\t\tDon't expand wildcards"
-msgstr "--literal\t\tJoker karakterleri genişletme!"
-
-msgid "-register\t\tRegister this gvim for OLE"
-msgstr "-register\t\tBu gvim'i OLE için kaydet"
-
-msgid "-unregister\t\tUnregister gvim for OLE"
-msgstr "-unregister\t\tgvim'in OLE kaydını sil"
-
-msgid "-g\t\t\tRun using GUI (like \"gvim\")"
-msgstr "-g\t\t\tGrafik arabirim kullanarak çalıştır (\"gvim\" gibi)"
-
-msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
-msgstr "-f veya --nofork\tÖnalan: Grafik arabirim başlatılırken çatallama!"
-
-msgid "-v\t\t\tVi mode (like \"vi\")"
-msgstr "-v\t\t\tVi kipi (\"vi\" gibi)"
-
-msgid "-e\t\t\tEx mode (like \"ex\")"
-msgstr "-e\t\t\tEx kipi (\"ex\" gibi)"
-
-msgid "-E\t\t\tImproved Ex mode"
-msgstr "-E\t\t\tGeliştirilmiş Ex kipi"
-
-msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
-msgstr "-s\t\t\tSessiz (toplu iş) kipi (yalnızca \"ex\" için)"
-
-msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
-msgstr "-d\t\t\tKarşılaştırma kipi (like \"vimdiff\")"
-
-msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
-msgstr "-y\t\t\tKolay kip (\"evim\" gibi, kipsiz)"
-
-msgid "-R\t\t\tReadonly mode (like \"view\")"
-msgstr "-R\t\t\tSaltokunur kip (\"view\" gibi)"
-
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tKısıtlanmış kip (\"rvim\" gibi)"
-
-msgid "-m\t\t\tModifications (writing files) not allowed"
-msgstr "-m\t\t\tDeğişikliklere (dosya yazma) izin verilmez"
-
-msgid "-M\t\t\tModifications in text not allowed"
-msgstr "-M\t\t\tMetinde değişikliklere izin verilmez"
-
-msgid "-b\t\t\tBinary mode"
-msgstr "-b\t\t\tİkili kip"
-
-msgid "-l\t\t\tLisp mode"
-msgstr "-l\t\t\tLisp kipi"
-
-msgid "-C\t\t\tCompatible with Vi: 'compatible'"
-msgstr "-C\t\t\tVi ile uyumlu: 'compatible'"
+"Seçenekler:\n"
-msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
-msgstr "-N\t\t\tTümüyle Vi uyumlu değil: 'nocompatible'"
-
-msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
-msgstr "-V[N][dosya]\t\tAyrıntılı bilgi ver [N düzeyi] [iletileri dosyaya yaz]"
-
-msgid "-D\t\t\tDebugging mode"
-msgstr "-D\t\t\tHata ayıklama kipi"
-
-msgid "-n\t\t\tNo swap file, use memory only"
-msgstr "-n\t\t\tTakas dosyası kullanma, yalnızca belleğe yaz"
-
-msgid "-r\t\t\tList swap files and exit"
-msgstr "-r\t\t\tTakas dosyalarını listele ve çık"
-
-msgid "-r (with file name)\tRecover crashed session"
-msgstr "-r (dosya adı ile)\tÇöken oturumu kurtar"
-
-msgid "-L\t\t\tSame as -r"
-msgstr "-L\t\t\t-r ile aynı"
-
-msgid "-f\t\t\tDon't use newcli to open window"
-msgstr "-f\t\t\tPencere açmak için yeni komut satırı arabirimi kullanma"
-
-msgid "-dev <device>\t\tUse <device> for I/O"
-msgstr "-dev <aygıt>\t\tGirdi/Çıktı için <aygıt>'ı kullan"
-
-msgid "-A\t\t\tStart in Arabic mode"
-msgstr "-A\t\t\tArapça kipinde başla"
-
-msgid "-H\t\t\tStart in Hebrew mode"
-msgstr "-H\t\t\tİbranca kipinde başla"
-
-msgid "-T <terminal>\tSet terminal type to <terminal>"
-msgstr "-T <uçbirim>\t\tUçbirim türünü <uçbirim>'e ayarla"
-
-msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
-msgstr "--not-a-term\t\tGirdi/Çıktının bir uçbirime olmadığı uyarısını atla"
-
-msgid "--ttyfail\t\tExit if input or output is not a terminal"
-msgstr "--ttyfail\t\tGirdi veya çıktı bir uçbirime değilse çık"
-
-msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
-msgstr "-u <vimrc>\t\tHerhangi bir .vimrc yerine <vimrc> kullan"
-
-msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
-msgstr "-U <gvimrc>\t\tHerhangi bir .gvimrc yerine <gvimrc> kullan"
-
-msgid "--noplugin\t\tDon't load plugin scripts"
-msgstr "--noplugin\t\tEklenti betiklerini yükleme!"
-
-msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
-msgstr "-p[N]\t\tN sekme sayfası aç (öntanımlı: her dosya için bir sekme)"
-
-msgid "-o[N]\t\tOpen N windows (default: one for each file)"
-msgstr "-o[N]\t\tN pencere aç (öntanımlı: her dosya için bir pencere)"
-
-msgid "-O[N]\t\tLike -o but split vertically"
-msgstr "-O[N]\t\t-o gibi, yalnızca dikey bölerek"
-
-msgid "+\t\t\tStart at end of file"
-msgstr "+\t\t\tDosyanın sonunda başlat"
-
-msgid "+<lnum>\t\tStart at line <lnum>"
-msgstr "+<satırno>\t\t<satırno> numaralı satırda başlat"
+msgid " -- Only file names after this\n"
+msgstr ""
+"-- Yalnızca bundan sonraki dosya adları\n"
-msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
-msgstr "--cmd <komut>\tHerhangi bir vimrc dosyası yüklemeden <komut> çalıştır"
+msgid " + Start at end of file\n"
+msgstr ""
+"+ Dosyanın sonunda başlat\n"
-msgid "-c <command>\t\tExecute <command> after loading the first file"
-msgstr "-c <komut>\t\tİlk dosyayı yükleyip <komut> komutunu çalıştır"
+msgid " --cmd <cmd> Execute <cmd> before any config\n"
+msgstr ""
+"--cmd <komut> Herhangi bir yapılandırma öncesi <komut> çalıştır\n"
-msgid "-S <session>\t\tSource file <session> after loading the first file"
-msgstr "-S <oturum>\t\tİlk dosyayı yükleyip <oturum> dosyasını kaynak al"
+msgid " +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"
+msgstr ""
+"+<komut>, -c <komut> Yapılandırma ve ilk dosya sonrası <komut> çalıştır\n"
-msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
-msgstr "-s <betikgir>\tNormal kip komutlarını <betikgir> dosyasından oku"
+msgid " -b Binary mode\n"
+msgstr ""
+"-b İkili kip\n"
-msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
-msgstr "-w <betikçık>\tGirilen tüm komutları <betikçık> dosyasına iliştir"
+msgid " -d Diff mode\n"
+msgstr ""
+"-d Diff kipi\n"
-msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
-msgstr "-W <betikçık>\tGirilen tüm komutları <betikçık> dosyasına yaz"
+msgid " -e, -E Ex mode\n"
+msgstr ""
+"-e, -E Ex kipi\n"
-msgid "-x\t\t\tEdit encrypted files"
-msgstr "-x\t\t\tŞifrelenmiş dosyaları düzenle"
+msgid " -es, -Es Silent (batch) mode\n"
+msgstr ""
+"-es, -Es Sessiz (toplu iş) kipi\n"
-msgid "-display <display>\tConnect Vim to this particular X-server"
-msgstr "-display <ekran>\tVim'i bu belirtilen X sunucusuna bağla"
+msgid " -h, --help Print this help message\n"
+msgstr ""
+"-h, --help Bu yardım iletisini yazdır\n"
-msgid "-X\t\t\tDo not connect to X server"
-msgstr "-X\t\t\tX sunucusuna bağlama"
+msgid " -i <shada> Use this shada file\n"
+msgstr ""
+"-i <shada> Bu shada (paylaşılan veri) dosyasını kullan\n"
-msgid "--remote <files>\tEdit <files> in a Vim server if possible"
-msgstr "--remote <dosya>\tOlanaklıysa bir Vim sunucusuda <dosya> düzenler"
+msgid " -m Modifications (writing files) not allowed\n"
+msgstr ""
+"-m Değişikliklere (dosya yazmaya) izin verme\n"
-msgid "--remote-silent <files> Same, don't complain if there is no server"
-msgstr "--remote-silent <dosya> Aynısı, yalnızca sunucu yoksa şikayet etmez"
+msgid " -M Modifications in text not allowed\n"
+msgstr ""
+"-M Metinde değişikliklere izin verme\n"
-msgid ""
-"--remote-wait <files> As --remote but wait for files to have been edited"
+msgid " -n No swap file, use memory only\n"
msgstr ""
-"--remote-wait <dosya> ---remote gibi, yalnızca düzenlenme bitişini bekle"
+"-n Takas dosyası yok, yalnızca belleği kullan\n"
-msgid ""
-"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgid " -o[N] Open N windows (default: one per file)\n"
msgstr ""
-"--remote-wait-silent <dosya> Aynısı, yalnızca sunucu yoksa şikayet etmez"
+"-o[N] N pencere aç (öntanımlı: dosya başına bir tane)\n"
msgid ""
-"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+" -O[N] Open N vertical windows (default: one per file)\n"
msgstr ""
-"--remote-tab[-wait][-silent] <dosya> --remote, artı sekme sayfası kullanır"
+"-O[N] N dikey pencere aç (öntanımlı: dosya başına bir tane)\n"
-msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgid " -p[N] Open N tab pages (default: one per file)\n"
msgstr ""
-"--remote-send <anahtar>\tBir Vim sunucusuna <anahtar> gönderir ve çıkar"
+"-p[N] N sekme sayfası aç (öntanımlı: dosya başına bir tane)\n"
-msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgid " -r, -L List swap files\n"
msgstr ""
-"--remote-expr <ifade>\t<ifade>'leri bir Vim sunucusunda değerlendirir ve "
-"sonuçları yazdırır"
-
-msgid "--serverlist\t\tList available Vim server names and exit"
-msgstr "--serverlist\t\tMevcut Vim sunucu adlarını listeler ve çıkar"
-
-msgid "--servername <name>\tSend to/become the Vim server <name>"
-msgstr "--servername <ad>\t<ad> Vim sunucusuna gönder veya sunucu ol"
+"-r, -L Takas dosyalarını listele\n"
-msgid "--startuptime <file>\tWrite startup timing messages to <file>"
-msgstr "--startuptime <dsy>\tBaşlangıç zamanlama iletilerini <dsy>'ya yaz"
-
-msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
-msgstr "-i <viminfo>\t\t.viminfo yerine <viminfo> kullan"
-
-msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
-msgstr "--clean\t\t'nocompatible', Vim öntanımlıları, eklenti-viminfo yok"
-
-msgid "-h or --help\tPrint Help (this message) and exit"
-msgstr "-h veya --help\tYardımı (bu iletiyi) yazdırır ve çıkar"
-
-msgid "--version\t\tPrint version information and exit"
-msgstr "--version\t\tSürüm bilgisini yazdırır ve çıkar"
-
-msgid ""
-"\n"
-"Arguments recognised by gvim (Motif version):\n"
+msgid " -r <file> Recover edit state for this file\n"
msgstr ""
-"\n"
-"gvim tarafından tanınan argümanlar (Motif sürümü):\n"
+"-r <dosya> Bu dosyanın düzenleme durumunu kurtar\n"
-msgid ""
-"\n"
-"Arguments recognised by gvim (neXtaw version):\n"
+msgid " -R Read-only mode\n"
msgstr ""
-"\n"
-"gvim tarafından tanınan argümanlar (neXtaw sürümü):\n"
+"-R Saltokunur kip\n"
-msgid ""
-"\n"
-"Arguments recognised by gvim (Athena version):\n"
+msgid " -S <session> Source <session> after loading the first file\n"
msgstr ""
-"\n"
-"gvim tarafından tanınan argümanlar (Athena sürümü):\n"
-
-msgid "-display <display>\tRun Vim on <display>"
-msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır"
+"-S <oturum> İlk dosyayı yükledikten sonra <oturum>'u kaynak al\n"
-msgid "-iconic\t\tStart Vim iconified"
-msgstr "-iconic\t\tVim'i simge durumunda başlat"
-
-msgid "-background <color>\tUse <color> for the background (also: -bg)"
-msgstr "-background <renk>\tArdalanı <renk> yap (kısa: -bg)"
+msgid " -s <scriptin> Read Normal mode commands from <scriptin>\n"
+msgstr ""
+"-s <betikgir> Normal kip komutlarını <betikgir>'den oku\n"
-msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
-msgstr "-foreground <renk>\tNormal metin için <renk> kullan (kısa: -fg)"
+msgid " -u <config> Use this config file\n"
+msgstr ""
+"-u <yapılandırma> Bu yapılandırma dosyasını kullan\n"
-msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
-msgstr "-font <font>\t\tNormal metin için <font> yazıtipini kullan (kısa: -fn)"
+msgid " -v, --version Print version information\n"
+msgstr ""
+"-v, --version Sürüm bilgisini yazdır\n"
-msgid "-boldfont <font>\tUse <font> for bold text"
-msgstr "-boldfont <font>\tKalın metin için <font> yazıtipini kullan"
+msgid " -V[N][file] Verbose [level][file]\n"
+msgstr ""
+"-V[N][dosya] Ayrıntılı bilgi ver [düzey][dosya]\n"
-msgid "-italicfont <font>\tUse <font> for italic text"
-msgstr "-italicfont <font>\tEğik metin için <font> yazıtipini kullan"
+msgid " --api-info Write msgpack-encoded API metadata to stdout\n"
+msgstr ""
+"--api-info stdout'a msgpack kodlu API üstverisi yaz\n"
-msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
-msgstr "-geometry <geom>\tBaşlangıç boyutları için <geom> kullan (kısa -geom)"
+msgid " --embed Use stdin/stdout as a msgpack-rpc channel\n"
+msgstr ""
+"--embed stdin/stdout'u msgpack-rpc kanalı olarak kullan\n"
-msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
-msgstr "-borderwidth <gnşlk>\t<gnşlk> kenar genişliği kullan (kısa: -bw)"
+msgid " --headless Don't start a user interface\n"
+msgstr ""
+"--headless Bir kullanıcı arayüzü başlatma\n"
-msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgid " --listen <address> Serve RPC API from this address\n"
msgstr ""
-"-scrollbarwidth <gnşlk> Kaydırma çubuğu için <gnşlk> genişlik (kısa: -sw)"
+"--listen <adres> Bu adresten RPC API'si sun\n"
-msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgid " --noplugin Don't load plugins\n"
msgstr ""
-"-menuheight <yükseklik>\t<yükseklik> menü çubuğu yüksekliği (kısa: -mh)"
+"--noplugin Eklentileri yükleme\n"
-msgid "-reverse\t\tUse reverse video (also: -rv)"
-msgstr "-reverse\t\tTersine dönmüş video kullan (kısa: -rv)"
+msgid " --remote[-subcommand] Execute commands remotely on a server\n"
+msgstr ""
+"--remote[-subcommand] Bir sunucuda komutları uzaktan çalıştır\n"
-msgid "+reverse\t\tDon't use reverse video (also: +rv)"
-msgstr "+reverse\t\tTersine dönmüş video kullanma (kısa: +rv)"
+msgid " --server <address> Specify RPC server to send commands to\n"
+msgstr ""
+"--server <adres> Komut gönderilecek RPC sunucusunu belirt\n"
-msgid "-xrm <resource>\tSet the specified resource"
-msgstr "-xrm <kaynak>\tBelirtilen kaynağı ayarla"
+msgid " --startuptime <file> Write startup timing messages to <file>\n"
+msgstr ""
+"--startuptime <dosya> Başlangıç zamanlama iletilerini <dosya>'ya yaz\n"
msgid ""
"\n"
-"Arguments recognised by gvim (GTK+ version):\n"
+"See \":help startup-options\" for all options.\n"
msgstr ""
"\n"
-"gvim tarafından tanınan argümanlar (GTK+ sürümü):\n"
-
-msgid "-display <display>\tRun Vim on <display> (also: --display)"
-msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır (veya: --display)"
-
-msgid "--role <role>\tSet a unique role to identify the main window"
-msgstr "--role <rol>\tAna pencereyi tanımlamak için eşsiz bir rol ayarla"
-
-msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
-msgstr "--socketid <xid>\tBaşka bir GTK parçacığında Vim'i aç"
-
-msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
-msgstr "--echo-wid\t\tgvim'in pencere kimliğini stdout'ta echo yapmasını sağla"
-
-msgid "-P <parent title>\tOpen Vim inside parent application"
-msgstr "-P <üst başlık>\tVim'i üst uygulama içinde aç"
-
-msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
-msgstr "--windowid <HWND>\tVim'i başka bir win32 parçacığı içinde aç"
-
-#, c-format
-msgid "E224: global abbreviation already exists for %s"
-msgstr "E224: %s için global kısaltma hâlihazırda var"
-
-#, c-format
-msgid "E225: global mapping already exists for %s"
-msgstr "E225: %s için global eşlemleme hâlihazırda var "
-
-#, c-format
-msgid "E226: abbreviation already exists for %s"
-msgstr "E226: %s için kısaltma hâlihazırda var"
-
-#, c-format
-msgid "E227: mapping already exists for %s"
-msgstr "E227: %s için eşlemleme hâlihazırda var"
-
-msgid "No abbreviation found"
-msgstr "Kısaltma bulunamadı"
-
-msgid "No mapping found"
-msgstr "Eşlemleme bulunamadı"
-
-msgid "E228: makemap: Illegal mode"
-msgstr "E228: makemap: İzin verilmeyen kip"
-
-msgid "E460: entries missing in mapset() dict argument"
-msgstr "E460: mapset() sözlük argümanında eksik girdiler"
-
-#, c-format
-msgid "E357: 'langmap': Matching character missing for %s"
-msgstr "E357: 'langmap': %s için eşleşen karakter eksik"
-
-#, c-format
-msgid "E358: 'langmap': Extra characters after semicolon: %s"
-msgstr "E358: 'langmap': Noktalı virgülden sonra ek karakterler: %s"
+"Tüm seçenekler için \":help startup-options\" yazın.\n"
msgid "No marks set"
msgstr "İm ayarlanmamış"
@@ -3126,30 +3549,44 @@ msgstr ""
"dğşklk satr stn metin"
#, c-format
-msgid "E799: Invalid ID: %d (must be greater than or equal to 1)"
-msgstr "E799: Geçersiz ID: %d (1'e eşit veya 1'den büyük olmalıdır)"
+msgid "E799: Invalid ID: %<PRId64> (must be greater than or equal to 1)"
+msgstr "E799: Geçersiz kimlik: %<PRId64> (1'e eşit veya 1'den büyük olmalıdır)"
#, c-format
-msgid "E801: ID already taken: %d"
-msgstr "E801: Kullanımda olan ID: %d"
+msgid "E801: ID already taken: %<PRId64>"
+msgstr "E801: Kimlik halihazırda kullanımda: %<PRId64>"
-msgid "E290: List or number required"
-msgstr "E290: Liste veya numara gerekiyor"
+#, c-format
+msgid "E5030: Empty list at position %d"
+msgstr "E5030: %d konumunda boş liste"
#, c-format
-msgid "E802: Invalid ID: %d (must be greater than or equal to 1)"
-msgstr "E802: Geçersiz ID: %d (1'e eşit veya 1'den büyük olmalıdır)"
+msgid "E5031: List or number required at position %d"
+msgstr "E5031: %d konumunda liste veya numara gerekiyor"
#, c-format
-msgid "E803: ID not found: %d"
-msgstr "E803: ID bulunamadı: %d"
+msgid "E802: Invalid ID: %<PRId64> (must be greater than or equal to 1)"
+msgstr "E802: Geçersiz kimlik: %<PRId64> (1'e eşit veya 1'den büyük olmalıdır)"
#, c-format
-msgid "E798: ID is reserved for \":match\": %d"
-msgstr "E798: ID, \":match\" için ayrılmış: %d"
+msgid "E803: ID not found: %<PRId64>"
+msgstr "E803: Kimlik bulunamadı: %<PRId64>"
-msgid "E543: Not a valid codepage"
-msgstr "E543: Geçerli bir kod sayfası değil"
+#, c-format
+msgid "E474: List item %d is either not a dictionary or an empty one"
+msgstr "E474: Liste ögesi %d, ya bir sözlük değil ya da boş bir sözlük"
+
+#, c-format
+msgid "E474: List item %d is missing one of the required keys"
+msgstr "E474: Liste ögesi %d, gerekli anahtarlardan birini içermiyor"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %<PRId64>"
+msgstr "E798: Kimlik, \":match\" için ayrılmış: %<PRId64>"
+
+#, c-format
+msgid "E798: ID is reserved for \"match\": %<PRId64>"
+msgstr "E798: Kimlik, \":match\" için ayrılmış: %<PRId64>"
msgid "E293: block was not locked"
msgstr "E293: Blok kilitlenmemişti"
@@ -3178,9 +3615,6 @@ msgstr "E298: 1 numaralı blok alınmadı mı?"
msgid "E298: Didn't get block nr 2?"
msgstr "E298: 2 numaralı blok alınmadı mı?"
-msgid "E843: Error while updating swap file crypt"
-msgstr "E843: Takas dosyası şifrelemesi güncellenirken hata"
-
msgid "E301: Oops, lost the swap file!!!"
msgstr "E301: Hay aksi, takas dosyasını kaybettik!"
@@ -3213,7 +3647,7 @@ msgid ""
"Maybe no changes were made or Vim did not update the swap file."
msgstr ""
"\n"
-"Herhangi bir değişiklik yapılmadı veya Vim takas dosyasını güncellemedi"
+"Herhangi bir değişiklik yapılmadı veya Vim takas dosyasını güncellemedi."
msgid " cannot be used with this version of Vim.\n"
msgstr " Vim'in bu sürümüyle kullanılamaz.\n"
@@ -3236,12 +3670,7 @@ msgid ""
"or the file has been damaged."
msgstr ""
",\n"
-"veya dosya zarar görmüş"
-
-#, c-format
-msgid ""
-"E833: %s is encrypted and this version of Vim does not support encryption"
-msgstr "E833: %s şifrelenmiş ve Vim'in bu sürümü şifrelemeyi desteklemiyor"
+"veya dosya zarar görmüş."
msgid " has been damaged (page size is smaller than minimum value).\n"
msgstr " hasar görmüş (sayfa boyutu olabilecek en az değerden daha küçük).\n"
@@ -3258,39 +3687,6 @@ msgid "E308: Warning: Original file may have been changed"
msgstr "E308: Uyarı: Orijinal dosya değiştirilmiş olabilir"
#, c-format
-msgid "Swap file is encrypted: \"%s\""
-msgstr "Takas dosyası şifrelenmiş: \"%s\""
-
-msgid ""
-"\n"
-"If you entered a new crypt key but did not write the text file,"
-msgstr ""
-"\n"
-"Yeni bir şifreleme anahtarı girmiş, fakat metin dosyasını yazmamışsanız,"
-
-msgid ""
-"\n"
-"enter the new crypt key."
-msgstr ""
-"\n"
-"yeni şifreleme anahtarını girin"
-
-msgid ""
-"\n"
-"If you wrote the text file after changing the crypt key press enter"
-msgstr ""
-"\n"
-"Metin dosyasını şifreleme anahtarını değiştirdikten sonra yazdıysanız "
-"Enter'a basın"
-
-msgid ""
-"\n"
-"to use the same key for text file and swap file"
-msgstr ""
-"\n"
-"metin dosyası ve takas dosyası için aynı anahtarı kullanmak için"
-
-#, c-format
msgid "E309: Unable to read block 1 from %s"
msgstr "E309: Blok 1 %s içinden okunamıyor"
@@ -3352,27 +3748,17 @@ msgstr "Kurtarma tamamlandı. Arabellek içeriği dosya içeriğine eşit."
msgid ""
"\n"
-"You may want to delete the .swp file now."
-msgstr ""
-"\n"
-"Bu .swp dosyasını silmeniz iyi olur."
-
-msgid ""
+"You may want to delete the .swp file now.\n"
"\n"
-"Note: process STILL RUNNING: "
msgstr ""
"\n"
-"Not: İşlem HÂLÂ ÇALIŞIYOR: "
-
-msgid "Using crypt key from swap file for the text file.\n"
-msgstr ""
-"Metin dosyası için takas dosyasındaki şifreleme anahtarı kullanılıyor.\n"
+"Bu .swp dosyasını silmeniz iyi olur.\n"
msgid "Swap files found:"
msgstr "Takas dosyası bulundu:"
msgid " In current directory:\n"
-msgstr " Şu anki dizinde:\n"
+msgstr " Geçerli dizinde:\n"
msgid " Using specified name:\n"
msgstr " Belirtilen şu adla:\n"
@@ -3398,6 +3784,9 @@ msgstr " [Vim 3.0 sürümünden itibaren]"
msgid " [does not look like a Vim swap file]"
msgstr " [bir Vim takas dosyasına benzemiyor]"
+msgid " [garbled strings (not nul terminated)]"
+msgstr " [karışmış diziler (nul ile sonlandırılmamış)]"
+
msgid " file name: "
msgstr " dosya adı: "
@@ -3436,20 +3825,13 @@ msgid ""
" process ID: "
msgstr ""
"\n"
-" işlem kimliği: "
+" süreç kimliği: "
msgid " (STILL RUNNING)"
msgstr " (HÅLÅ ÇALIŞIYOR)"
msgid ""
"\n"
-" [not usable with this version of Vim]"
-msgstr ""
-"\n"
-" [Vim'in bu sürümüyle kullanılamaz]"
-
-msgid ""
-"\n"
" [not usable on this computer]"
msgstr ""
"\n"
@@ -3471,12 +3853,12 @@ msgid "E314: Preserve failed"
msgstr "E314: Koruma başarısız oldu"
#, c-format
-msgid "E315: ml_get: invalid lnum: %ld"
-msgstr "E315: ml_get: geçersiz satır numarası: %ld"
+msgid "E315: ml_get: invalid lnum: %<PRId64>"
+msgstr "E315: ml_get: Geçersiz satır numarası: %<PRId64>"
#, c-format
-msgid "E316: ml_get: cannot find line %ld in buffer %d %s"
-msgstr "E316: ml_get: %ld. satır %d %s arabelleğinde bulunamıyor"
+msgid "E316: ml_get: cannot find line %<PRId64> in buffer %d %s"
+msgstr "E316: ml_get: %<PRId64>. satır %d %s arabelleğinde bulunamıyor"
msgid "E317: pointer block id wrong 3"
msgstr "E317: Blok 3 gösterge kimliği yanlış"
@@ -3494,8 +3876,8 @@ msgid "deleted block 1?"
msgstr "Blok 1 mi silindi?"
#, c-format
-msgid "E320: Cannot find line %ld"
-msgstr "E320: %ld. satır bulunamıyor"
+msgid "E320: Cannot find line %<PRId64>"
+msgstr "E320: %<PRId64>. satır bulunamıyor"
msgid "E317: pointer block id wrong"
msgstr "E317: Gösterge blok kimliği yanlış"
@@ -3504,12 +3886,12 @@ msgid "pe_line_count is zero"
msgstr "pe_line_count sıfır"
#, c-format
-msgid "E322: line number out of range: %ld past the end"
-msgstr "E322: satır numarası erimin dışında: %ld en sonuncuyu geçmiş"
+msgid "E322: line number out of range: %<PRId64> past the end"
+msgstr "E322: Satır numarası erimin dışında: %<PRId64> en sonuncuyu geçmiş"
#, c-format
-msgid "E323: line count wrong in block %ld"
-msgstr "E323: %ld. blokta satır sayısı yanlış"
+msgid "E323: line count wrong in block %<PRId64>"
+msgstr "E323: %<PRId64>. blokta satır sayısı yanlış"
msgid "Stack size increases"
msgstr "Yığın boyutu artıyor"
@@ -3547,7 +3929,7 @@ msgid ""
" file when making changes. Quit, or continue with caution.\n"
msgstr ""
"\n"
-"(1) Bu dosya başka bir programda da açık olabilir. Eğer öyleyse, aynı\n"
+"(1) Bu dosya başka bir programda da açık olabilir. Eğer öyleyse aynı\n"
" dosyanın iki ayrı örneğiyle karşılaşmamak için değişiklik yaparken\n"
" lütfen dikkatli olun. Ya programdan çıkın ya da dikkatli ilerleyin.\n"
@@ -3555,7 +3937,7 @@ msgid "(2) An edit session for this file crashed.\n"
msgstr "(2) Bu dosya düzenleme oturumu çöktü.\n"
msgid " If this is the case, use \":recover\" or \"vim -r "
-msgstr " Durum buysa, \":recover\" veya \"vim -r "
+msgstr " Durum buysa \":recover\" veya \"vim -r "
msgid ""
"\"\n"
@@ -3565,7 +3947,7 @@ msgstr ""
" yapıp değişiklikleri kurtarın (ek bilgi için \":help recovery\").\n"
msgid " If you did this already, delete the swap file \""
-msgstr " Eğer bunu yaptıysanız, bu iletiyi bir daha görmemek için \""
+msgstr " Eğer bunu yaptıysanız bu iletiyi bir daha görmemek için \""
msgid ""
"\"\n"
@@ -3586,9 +3968,6 @@ msgstr "\" zaten var!"
msgid "VIM - ATTENTION"
msgstr "VİM - DİKKAT"
-msgid "Swap file already exists!"
-msgstr "Takas dosyası hâlihazırda var!"
-
msgid ""
"&Open Read-Only\n"
"&Edit anyway\n"
@@ -3620,9 +3999,26 @@ msgstr ""
msgid "E326: Too many swap files found"
msgstr "E326: Çok fazla takas dosyası bulundu"
+#, c-format
+msgid ""
+"E303: Unable to create directory \"%s\" for swap file, recovery impossible: "
+"%s"
+msgstr "E303: Takas dosyası için \"%s\" dizini oluşturulamadı, kurtarma "
+"olanaksız: %s"
+
+msgid "Vim: Data too large to fit into virtual memory space\n"
+msgstr "Vim: Veri, sanal bellek alanına sığmak için çok büyük\n"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %<PRIu64> bytes)"
+msgstr "E342: Bellek tükendi!! (%<PRIu64> bayt ayrılıyor)"
+
msgid "E327: Part of menu-item path is not sub-menu"
msgstr "E327: Menü öge yolunun bir kısmı alt menü değil"
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menü yalnızca başka bir kipte mevcut"
+
#, c-format
msgid "E329: No menu \"%s\""
msgstr "E329: Menü \"%s\" yok"
@@ -3646,9 +4042,6 @@ msgstr ""
"\n"
"--- Menüler ---"
-msgid "Tear off this menu"
-msgstr "Bu menüyü dışarıya al"
-
#, c-format
msgid "E335: Menu not defined for %s mode"
msgstr "E335: Menü %s kipi için tanımlanmamış"
@@ -3658,17 +4051,7 @@ msgstr "E333: Menü yolu bir menü ögesine çıkmalı"
#, c-format
msgid "E334: Menu not found: %s"
-msgstr "E334: Menü bulunamadı %s"
-
-msgid "E336: Menu path must lead to a sub-menu"
-msgstr "E336: Menü yolu bir alt menüye çıkmalı"
-
-msgid "E337: Menu not found - check menu names"
-msgstr "E337: Menü bulunamadı - menü adlarını denetle"
-
-#, c-format
-msgid "Error detected while compiling %s:"
-msgstr "%s derlenirken hata tespit edildi:"
+msgstr "E334: Menü bulunamadı: %s"
#, c-format
msgid "Error detected while processing %s:"
@@ -3682,18 +4065,18 @@ msgstr "satır %4ld:"
msgid "E354: Invalid register name: '%s'"
msgstr "E354: Geçersiz yazmaç adı: '%s'"
-msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
-msgstr "Türkçeye çeviren: Emir SARI <bitigchi@me.com>"
-
msgid "Interrupt: "
msgstr "Yarıda kes: "
msgid "Press ENTER or type command to continue"
msgstr "Sürdürmek için ENTER'a basın veya komut girin"
+msgid " (Interrupted)"
+msgstr " (Yarıda kesildi)"
+
#, c-format
-msgid "%s line %ld"
-msgstr "%s %ld. satır"
+msgid "%s line %<PRId64>"
+msgstr "%s %<PRId64>. satır"
msgid "-- More --"
msgstr "-- Daha fazla --"
@@ -3714,6 +4097,15 @@ msgstr ""
msgid ""
"&Yes\n"
"&No\n"
+"&Cancel"
+msgstr ""
+"&Evet\n"
+"&Hayır\n"
+"İ&ptal"
+
+msgid ""
+"&Yes\n"
+"&No\n"
"Save &All\n"
"&Discard All\n"
"&Cancel"
@@ -3724,113 +4116,9 @@ msgstr ""
"&Tümünü At\n"
"İ&ptal"
-msgid "E766: Insufficient arguments for printf()"
-msgstr "E766: printf() için yetersiz argüman"
-
-msgid "E807: Expected Float argument for printf()"
-msgstr "E807: printf() için kayan noktalı değer türünde argüman bekleniyordu"
-
-msgid "E767: Too many arguments to printf()"
-msgstr "E767: printf() için çok fazla argüman"
-
-msgid "Type number and <Enter> or click with the mouse (q or empty cancels): "
-msgstr ""
-"Sayı girip <Enter>'a veya fare düğmesine basın (q veya boş iptal eder): "
-
-msgid "Type number and <Enter> (q or empty cancels): "
-msgstr "Sayı girip <Enter>'a basın (q veya boş iptal eder): "
-
-#, c-format
-msgid "%ld more line"
-msgid_plural "%ld more lines"
-msgstr[0] "%ld daha fazla satır"
-msgstr[1] "%ld daha fazla satır"
-
-#, c-format
-msgid "%ld line less"
-msgid_plural "%ld fewer lines"
-msgstr[0] "%ld daha az satır"
-msgstr[1] "%ld daha az satır"
-
-msgid " (Interrupted)"
-msgstr " (Yarıda kesildi)"
-
-msgid "Beep!"
-msgstr "Bip!"
-
-msgid "E677: Error writing temp file"
-msgstr "E677: Geçici dosya yazılırken hata"
-
-msgid "ERROR: "
-msgstr "HATA: "
-
-#, c-format
-msgid ""
-"\n"
-"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
-msgstr ""
-"\n"
-"[bitler] toplam ayrılan/boşaltılan %lu-%lu, kullanımda %lu, doruk nokt. %lu\n"
-
-#, c-format
-msgid ""
-"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
-"\n"
-msgstr ""
-"[çağrılar] toplam re/malloc()'lar %lu, toplam free()'ler %lu\n"
-"\n"
-
-msgid "E341: Internal error: lalloc(0, )"
-msgstr "E341: İç hata: lalloc(0, )"
-
-#, c-format
-msgid "E342: Out of memory! (allocating %lu bytes)"
-msgstr "E342: Yetersiz bellek! (%lu bit ayrılıyor)"
-
-#, c-format
-msgid "Calling shell to execute: \"%s\""
-msgstr "Çalıştırmak için çağrılan kabuk: \"%s\""
-
-msgid "E545: Missing colon"
-msgstr "E545: İki nokta eksik"
-
-msgid "E546: Illegal mode"
-msgstr "E546: İzin verilmeyen kip"
-
-msgid "E547: Illegal mouseshape"
-msgstr "E547: İzin verilmeyen fare imleci türü"
-
-msgid "E548: digit expected"
-msgstr "E548: Basamak bekleniyordu"
-
-msgid "E549: Illegal percentage"
-msgstr "E549: İzin verilmeyen yüzde"
-
-#, c-format
-msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
-msgstr ""
-"E668: NetBeans bağlantı bilgisi dosyası için yanlış erişim kipi: \"%s\""
-
-#, c-format
-msgid "E658: NetBeans connection lost for buffer %d"
-msgstr "E658: Arabellek %d için NetBeans bağlantısı koptu"
-
-msgid "E838: netbeans is not supported with this GUI"
-msgstr "E838: NetBeans bu grafik arabirimde desteklenmiyor"
-
-msgid "E511: netbeans already connected"
-msgstr "E511: NetBeans hâlihazırda bağlı"
-
-#, c-format
-msgid "E505: %s is read-only (add ! to override)"
-msgstr "E505: %s saltokunur (geçersiz kılmak için ! ekleyin)"
-
msgid "E349: No identifier under cursor"
msgstr "E349: İmleç altında bir tanımlayıcı yok"
-msgid "Warning: terminal cannot highlight"
-msgstr "Uyarı: Uçbirim vurgulama yapamıyor"
-
msgid "E348: No string under cursor"
msgstr "E348: İmleç altında bir dizi yok"
@@ -3846,83 +4134,85 @@ msgstr "E662: Değişiklik listesinin başında"
msgid "E663: At end of changelist"
msgstr "E663: Değişiklik listesinin sonunda"
-msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Nvim"
msgstr ""
-"Değişikliklerden vazgeçip Vim'den çıkmak için :qa! yazıp <Enter>'a basın"
+"Değişikliklerden vazgeçip Nvim'den çıkmak için :qa! yazıp <Enter>'a basın"
-msgid "Type :qa and press <Enter> to exit Vim"
-msgstr "Vim'den çıkmak için :qa yazıp <Enter>'a basın"
+msgid "Type :qa and press <Enter> to exit Nvim"
+msgstr "Nvim'den çıkmak için :qa yazıp <Enter>'a basın"
#, c-format
-msgid "%ld line %sed %d time"
-msgid_plural "%ld line %sed %d times"
-msgstr[0] "%ld satır, %s %d kez"
-msgstr[1] "%ld satır, %s %d kez"
+msgid "%<PRId64> lines to indent... "
+msgstr "girintilenecek %<PRId64> satır kaldı... "
-#, c-format
-msgid "%ld lines %sed %d time"
-msgid_plural "%ld lines %sed %d times"
-msgstr[0] "%ld satır, %s %d kez"
-msgstr[1] "%ld satır, %s %d kez"
-
-msgid "cannot yank; delete anyway"
-msgstr "kopyalanamıyor, silindi"
+msgid "E748: No previously used register"
+msgstr "E748: Daha önce kullanılan bir yazmaç yok"
#, c-format
-msgid "%ld line changed"
-msgid_plural "%ld lines changed"
-msgstr[0] "%ld satır değiştirildi"
-msgstr[1] "%ld satır değiştirildi"
+msgid " into \"%c"
+msgstr " \"%c"
#, c-format
-msgid "%d line changed"
-msgid_plural "%d lines changed"
-msgstr[0] "%d satır değiştirildi"
-msgstr[1] "%d satır değiştirildi"
+msgid "E353: Nothing in register %s"
+msgstr "E353: Yazmaç %s boş"
+
+msgid ""
+"\n"
+"Type Name Content"
+msgstr ""
+"\n"
+"Tür Ad İçerik"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: Arama dizgisi ve ifade yazmacı iki veya daha fazla satır içeremez"
#, c-format
-msgid "%ld Cols; "
-msgstr "%ld Sütun; "
+msgid "%<PRId64> Cols; "
+msgstr "%<PRId64> Sütun; "
#, c-format
-msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
-msgstr "%s%ld/%ld satır; %lld/%lld sözcük; %lld/%lld bit seçildi"
+msgid ""
+"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
+"%<PRId64> of %<PRId64> Bytes"
+msgstr "%s%<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; "
+"%<PRId64>/%<PRId64> bayt seçildi"
#, c-format
msgid ""
-"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
-"%lld Bytes"
+"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
+"%<PRId64> of %<PRId64> Chars; %<PRId64> of %<PRId64> Bytes"
msgstr ""
-"%s%ld/%ld satır; %lld/%lld sözcük; %lld/%lld karakter; %lld/%lld bit seçildi"
+"%s%<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; "
+"%<PRId64>/%<PRId64> karakter; %<PRId64>/%<PRId64> bayt seçildi"
#, c-format
-msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
-msgstr "Sütun %s/%s; Satır %ld/%ld; Sözcük %lld/%lld; Bit %lld/%lld"
+msgid ""
+"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Byte "
+"%<PRId64> of %<PRId64>"
+msgstr "%s/%s sütun; %<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; "
+"%<PRId64>/%<PRId64> bayt"
#, c-format
msgid ""
-"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
-"%lld of %lld"
+"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Char "
+"%<PRId64> of %<PRId64>; Byte %<PRId64> of %<PRId64>"
msgstr ""
-"Sütun %s/%s; Satır %ld/%ld; Sözcük %lld/%lld; Karakter %lld/%lld; Bit %lld/"
-"%lld"
+"%s/%s sütun; %<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; "
+"%<PRId64>/%<PRId64> karakter; %<PRId64>/%<PRId64> bayt"
#, c-format
-msgid "(+%lld for BOM)"
-msgstr "(BOM için +%lld)"
+msgid "(+%<PRId64> for BOM)"
+msgstr "(BOM için +%<PRId64>)"
msgid "E774: 'operatorfunc' is empty"
msgstr "E774: 'operatorfunc' boş"
-msgid "E775: Eval feature not available"
-msgstr "E775: Eval özelliği mevcut değil"
-
msgid "E518: Unknown option"
msgstr "E518: Bilinmeyen seçenek"
-msgid "E519: Option not supported"
-msgstr "E519: Özellik desteklenmiyor"
-
msgid "E520: Not allowed in a modeline"
msgstr "E520: Bir kip satırında izin verilmiyor"
@@ -3935,68 +4225,6 @@ msgstr "E846: Anahtar kodu ayarlanmamış"
msgid "E521: Number required after ="
msgstr "E521: = sonrası sayı gerekiyor"
-msgid "E522: Not found in termcap"
-msgstr "E522: termcap içinde bulunamadı"
-
-msgid "E946: Cannot make a terminal with running job modifiable"
-msgstr "E946: Uçbirim bir iş çalışırken değiştirilebilir yapılamaz"
-
-msgid "E590: A preview window already exists"
-msgstr "E590: Bir önizleme penceresi hâlihazırda mevcut"
-
-msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
-msgstr "W17: Arapça UTF-8 gerektirir, ':set encoding=utf-8' yapın"
-
-msgid "E954: 24-bit colors are not supported on this environment"
-msgstr "E954: 24 bit renkler bu ortamda desteklenmiyor"
-
-#, c-format
-msgid "E593: Need at least %d lines"
-msgstr "E593: En azından %d satır gerekli"
-
-#, c-format
-msgid "E594: Need at least %d columns"
-msgstr "E594: En azından %d sütun gerekli"
-
-#, c-format
-msgid "E355: Unknown option: %s"
-msgstr "E355: Bilinmeyen seçenek: %s"
-
-#, c-format
-msgid "E521: Number required: &%s = '%s'"
-msgstr "E521: Sayı gerekiyor: &%s = '%s'"
-
-msgid ""
-"\n"
-"--- Terminal codes ---"
-msgstr ""
-"\n"
-"--- Uçbirim kodları ---"
-
-msgid ""
-"\n"
-"--- Global option values ---"
-msgstr ""
-"\n"
-"--- Global seçenek değerleri ---"
-
-msgid ""
-"\n"
-"--- Local option values ---"
-msgstr ""
-"\n"
-"--- Yerel seçenek değerleri ---"
-
-msgid ""
-"\n"
-"--- Options ---"
-msgstr ""
-"\n"
-"--- Seçenekler ---"
-
-msgid "E356: get_varp ERROR"
-msgstr "E356: get_varp HATASI"
-
#, c-format
msgid "E539: Illegal character <%s>"
msgstr "E539: İzin verilmeyen karakter <%s>"
@@ -4005,36 +4233,14 @@ msgstr "E539: İzin verilmeyen karakter <%s>"
msgid "For option %s"
msgstr "%s seçeneği için"
-msgid "E540: Unclosed expression sequence"
-msgstr "E540: Kapatılmamış ifade sıralaması"
-
-msgid "E542: unbalanced groups"
-msgstr "E542: Dengelenmemiş gruplar"
-
-msgid "E529: Cannot set 'term' to empty string"
-msgstr "E529: Boş dizi için 'term' ayarlanamıyor"
-
-msgid "E530: Cannot change term in GUI"
-msgstr "E530: Grafik arabirimde uçbirim değiştirilemez"
-
-msgid "E531: Use \":gui\" to start the GUI"
-msgstr "E531: Grafik arabirimi başlatmak için \":gui\" yazın"
-
msgid "E589: 'backupext' and 'patchmode' are equal"
msgstr "E589: 'backupext' ve 'patchmode' birbirine eşit"
-msgid "E835: Conflicts with value of 'fillchars'"
-msgstr "E835: 'fillchars' değeriyle çakışmalar var"
-
msgid "E834: Conflicts with value of 'listchars'"
msgstr "E834: 'listchars' değeriyle çakışmalar var"
-msgid "E617: Cannot be changed in the GTK+ 2 GUI"
-msgstr "E617: GTK+ 2 grafik arabiriminde değiştirilemez"
-
-#, c-format
-msgid "E950: Cannot convert between %s and %s"
-msgstr "E950: %s ve %s arasında dönüştürme yapılamıyor"
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars' değeriyle çakışmalar var"
msgid "E524: Missing colon"
msgstr "E524: İki nokta eksik"
@@ -4044,7 +4250,7 @@ msgstr "E525: Sıfır uzunlukta dizi"
#, c-format
msgid "E526: Missing number after <%s>"
-msgstr "E526: <%s> sonrasında sayı eksik"
+msgstr "E526: <%s> sonrası sayı eksik"
msgid "E527: Missing comma"
msgstr "E527: Virgül eksik"
@@ -4055,21 +4261,6 @@ msgstr "E528: Bir ' değeri belirtmeli"
msgid "E595: 'showbreak' contains unprintable or wide character"
msgstr "E595: 'showbreak' yazdırılamaz veya geniş karakter içeriyor"
-msgid "E596: Invalid font(s)"
-msgstr "E596: Geçersiz font(lar)"
-
-msgid "E597: can't select fontset"
-msgstr "E597: Yazıtipi seti seçilemiyor"
-
-msgid "E598: Invalid fontset"
-msgstr "E598: Geçersiz yazıtipi seti"
-
-msgid "E533: can't select wide font"
-msgstr "E533: Geniş yazıtipi seçilemiyor"
-
-msgid "E534: Invalid wide font"
-msgstr "E534: Geçersiz geniş yazıtipi"
-
#, c-format
msgid "E535: Illegal character after <%c>"
msgstr "E535: <%c> sonrası izin verilmeyen karakter"
@@ -4081,253 +4272,101 @@ msgstr "E536: Virgül gerekiyor"
msgid "E537: 'commentstring' must be empty or contain %s"
msgstr "E537: 'commentstring' boş olmalı veya %s içermeli"
-msgid "cannot open "
-msgstr "Açılamıyor: "
-
-msgid "VIM: Can't open window!\n"
-msgstr "VİM: Pencere açılamıyor!\n"
-
-msgid "Need Amigados version 2.04 or later\n"
-msgstr "AmigaDOS 2.04 sürümü veya sonrası gerekli\n"
-
-#, c-format
-msgid "Need %s version %ld\n"
-msgstr "%s %ld sürümü gerekli\n"
-
-msgid "Cannot open NIL:\n"
-msgstr "NIL açılamıyor:\n"
-
-msgid "Cannot create "
-msgstr "Oluşturulamıyor: "
-
-#, c-format
-msgid "Vim exiting with %d\n"
-msgstr "Vim %d ile çıkıyor\n"
-
-msgid "cannot change console mode ?!\n"
-msgstr "Konsol kipi değiştirilemiyor?!\n"
-
-msgid "mch_get_shellsize: not a console??\n"
-msgstr "mch_get_shellsize: Bir konsol değil??\n"
-
-msgid "E360: Cannot execute shell with -f option"
-msgstr "E360: Kabuk -f seçeneği ile çalıştırılamıyor"
-
-msgid "Cannot execute "
-msgstr "Çalıştırılamıyor: "
-
-msgid "shell "
-msgstr "kabuk "
-
-msgid " returned\n"
-msgstr " döndürüldü\n"
-
-msgid "ANCHOR_BUF_SIZE too small."
-msgstr "ANCHOR_BUF_SIZE çok küçük."
-
-msgid "I/O ERROR"
-msgstr "GİRDİ/ÇIKTI HATASI"
-
-msgid "Message"
-msgstr "İleti"
-
-msgid "E237: Printer selection failed"
-msgstr "E237: Yazıcı seçimi başarısız oldu"
-
-#, c-format
-msgid "to %s on %s"
-msgstr "%s, %s üzerinde"
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Kapatılmamış ifade sıralaması"
-#, c-format
-msgid "E613: Unknown printer font: %s"
-msgstr "E613: Bilinmeyen yazıcı fontu: %s"
+msgid "E542: unbalanced groups"
+msgstr "E542: Dengelenmemiş gruplar"
-#, c-format
-msgid "E238: Print error: %s"
-msgstr "E238: Yazdırma hatası: %s"
+msgid "E590: A preview window already exists"
+msgstr "E590: Bir önizleme penceresi hâlihazırda mevcut"
-#, c-format
-msgid "Printing '%s'"
-msgstr "'%s' yazdırılıyor"
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arapça, UTF-8 gerektirir; ':set encoding=utf-8' yapın"
#, c-format
-msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
-msgstr "E244: Geçersiz karakter adı \"%s\", bulunduğu yazıtipi: \"%s\""
+msgid "E593: Need at least %d lines"
+msgstr "E593: En azından %d satır gerekli"
#, c-format
-msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
-msgstr "E244: İzin verilmeyen nitelik adı: \"%s\", bulunduğu yazıtipi: \"%s\""
+msgid "E594: Need at least %d columns"
+msgstr "E594: En azından %d sütun gerekli"
#, c-format
-msgid "E245: Illegal char '%c' in font name \"%s\""
-msgstr ""
-"E245: İzin verilmeyen karakter '%c', bulunduğu yer: \"%s\" yazıtipi adı"
+msgid "E355: Unknown option: %s"
+msgstr "E355: Bilinmeyen seçenek: %s"
#, c-format
-msgid "Opening the X display took %ld msec"
-msgstr "X ekranını açma %ld milisaniye sürdü"
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Sayı gerekiyor: &%s = '%s'"
msgid ""
"\n"
-"Vim: Got X error\n"
+"--- Global option values ---"
msgstr ""
"\n"
-"Vim: X hatası alındı\n"
-
-#, c-format
-msgid "restoring display %s"
-msgstr "%s ekranı geri getiriliyor"
-
-msgid "Testing the X display failed"
-msgstr "X ekran testi başarısız oldu"
-
-msgid "Opening the X display timed out"
-msgstr "X ekran açılması zaman aşımına uğradı"
+"--- Global seçenek değerleri ---"
msgid ""
"\n"
-"Could not get security context for "
+"--- Local option values ---"
msgstr ""
"\n"
-"Şunun için güvenlik bağlamı alınamadı: "
+"--- Yerel seçenek değerleri ---"
msgid ""
"\n"
-"Could not set security context for "
+"--- Options ---"
msgstr ""
"\n"
-"Şunun için güvenlik bağlamı alınamadı: "
+"--- Seçenekler ---"
-#, c-format
-msgid "Could not set security context %s for %s"
-msgstr "Güvenlik bağlamı %s %s için alınamadı"
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp HATASI"
#, c-format
-msgid "Could not get security context %s for %s. Removing it!"
-msgstr "Güvenlik bağlamı %s %s için alınamadı. Kaldırılıyor!"
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %s için eşleşen karakter eksik"
-msgid ""
-"\n"
-"Cannot execute shell sh\n"
-msgstr ""
-"\n"
-"sh kabuğu çalıştırılamıyor\n"
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Noktalı virgülden sonra ek karakterler: %s"
-msgid ""
-"\n"
-"shell returned "
-msgstr ""
-"\n"
-"Program çıktı: "
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
-msgid ""
-"\n"
-"Cannot create pipes\n"
-msgstr ""
-"\n"
-"Veri yolları oluşturulamıyor\n"
+#, c-format
+msgid "E5420: Failed to write to file: %s"
+msgstr "E5420: Dosyaya yazılamadı: %s"
-msgid ""
-"\n"
-"Cannot fork\n"
-msgstr ""
-"\n"
-"Çatallanamıyor\n"
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Girdi okunurken hata, çıkılıyor...\n"
msgid ""
"\n"
-"Cannot execute shell "
+"shell returned "
msgstr ""
"\n"
-"Kabuk çalıştırılamıyor "
+"Program çıktı: "
msgid ""
"\n"
-"Command terminated\n"
+"shell failed to start: "
msgstr ""
"\n"
-"Komut sonlandırıldı\n"
-
-msgid "XSMP lost ICE connection"
-msgstr "XSMP, ICE bağlantısını kopardı"
-
-#, c-format
-msgid "dlerror = \"%s\""
-msgstr "dlerror = \"%s\""
-
-msgid "Opening the X display failed"
-msgstr "X ekran açılışı başarısız oldu"
-
-msgid "XSMP handling save-yourself request"
-msgstr "Kendini kurtarma isteği XSMP tarafından gerçekleştiriliyor"
-
-msgid "XSMP opening connection"
-msgstr "XSMP bağlantıyı açıyor"
-
-msgid "XSMP ICE connection watch failed"
-msgstr "XSMP ICE bağlantı izlemesi başarısız oldu"
-
-#, c-format
-msgid "XSMP SmcOpenConnection failed: %s"
-msgstr "XSMP SmcOpenConnection başarısız oldu: %s"
-
-msgid "At line"
-msgstr "Satırda"
-
-#, c-format
-msgid "Vim: Caught %s event\n"
-msgstr "Vim: %s olayı yakalandı\n"
-
-msgid "close"
-msgstr "kapat"
-
-msgid "logoff"
-msgstr "oturumu kapat"
-
-msgid "shutdown"
-msgstr "kapat"
-
-msgid "E371: Command not found"
-msgstr "E371: Komut bulunamadı"
-
-msgid ""
-"VIMRUN.EXE not found in your $PATH.\n"
-"External commands will not pause after completion.\n"
-"See :help win32-vimrun for more information."
-msgstr ""
-"VIMRUN.EXE $PATH üzerinde bulunamadı.\n"
-"Dış komutlar tamamlandıktan sonra duraklamayacak.\n"
-"Ek bilgi için :help win32-vimrun yazın."
-
-msgid "Vim Warning"
-msgstr "Vim - Uyarı"
+"kabuk başlatılamad: "
#, c-format
-msgid "shell returned %d"
-msgstr "Program %d numaralı kod ile çıktı"
-
-msgid "E861: Cannot open a second popup with a terminal"
-msgstr "E861: Bir uçbirimle ikinci bir açılır pencere açılamıyor"
+msgid "E5677: Error writing input to shell-command: %s"
+msgstr "E5677: Girdi, kabuk komutuna yazılırken hata: %s"
-msgid "E450: buffer number, text or a list required"
-msgstr "E450: Arabellek numarası, metin veya liste gerekiyor"
-
-#, c-format
-msgid "E997: Tabpage not found: %d"
-msgstr "E997: Sekme bulunamadı: %d"
+msgid "%a %b %d %H:%M:%S %Y"
+msgstr "%a %b %d %H:%M:%S %Y"
#, c-format
-msgid "E993: window %d is not a popup window"
-msgstr "E993: %d penceresi bir açılır pencere değil"
-
-msgid "E994: Not allowed in a popup window"
-msgstr "E994: Açılır pencere içinde izin verilmiyor"
-
-msgid "E863: Not allowed for a terminal in a popup window"
-msgstr "E863: Açılır pencere içinde uçbirime izin verilmiyor"
-
-msgid "E750: First use \":profile start {fname}\""
-msgstr "E750: İlk kullanım \":profile start {dosyaadı}\""
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: \"%s\" dosyası yol içinde bulunamadı"
msgid "E553: No more items"
msgstr "E553: Öge yok"
@@ -4340,7 +4379,7 @@ msgstr "E926: Geçerli konum listesi değiştirildi"
#, c-format
msgid "E372: Too many %%%c in format string"
-msgstr "E372: Biçim dizisinde çok fazla %%%c"
+msgstr "E372: Biçim dizisinde pek fazla %%%c"
#, c-format
msgid "E373: Unexpected %%%c in format string"
@@ -4390,9 +4429,6 @@ msgstr "E381: Hızlı düzelt yığınının en tepesinde"
msgid "No entries"
msgstr "Girdi yok"
-msgid "Error file"
-msgstr "Hata dosyası"
-
msgid "E683: File name missing or invalid pattern"
msgstr "E683: Dosya adı eksik veya geçersiz dizgi"
@@ -4410,16 +4446,12 @@ msgid "E777: String or List expected"
msgstr "E777: Dizi veya liste bekleniyordu"
#, c-format
-msgid "E927: Invalid action: '%s'"
-msgstr "E927: Geçersiz eylem: '%s'"
-
-#, c-format
msgid "E369: invalid item in %s%%[]"
msgstr "E369: %s%%[] içinde geçersiz öge"
#, c-format
msgid "E769: Missing ] after %s["
-msgstr "E769: %s[ sonrasında ] eksik"
+msgstr "E769: %s[ sonrası ] eksik"
msgid "E944: Reverse range in character class"
msgstr "E944: Karakter sınıfında geriye dönük erim"
@@ -4457,8 +4489,8 @@ msgid "E956: Cannot use pattern recursively"
msgstr "E956: Dizgi özyineli olarak kullanılamaz"
#, c-format
-msgid "E654: missing delimiter after search pattern: %s"
-msgstr "E654: Arama dizgisi sonrasında eksik sınırlandırıcı: %s"
+msgid "E1204: No Number allowed after .: '\\%%%c'"
+msgstr "E1204: . sonrası Sayıya izin verilmiyor: '\\%%%c'"
#, c-format
msgid "E554: Syntax error in %s{...}"
@@ -4466,175 +4498,40 @@ msgstr "E554: %s{...} içinde sözdizimi hatası"
#, c-format
msgid "E888: (NFA regexp) cannot repeat %s"
-msgstr "E888: (NFA regexp) %s tekrar edemiyor"
+msgstr "E888: (BSO düzenli ifadesi) %s tekrar edemiyor"
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
"used "
msgstr ""
-"E864: \\%#= sonrasında yalnızca 0, 1, veya 2 gelebilir. Otomatik motor "
+"E864: \\%#= sonrası yalnızca 0, 1, veya 2 gelebilir. Otomatik işletke "
"kullanılacak "
msgid "Switching to backtracking RE engine for pattern: "
msgstr "Şu dizgi için düzenli ifade iz sürme motoruna geçiliyor: "
-msgid "E65: Illegal back reference"
-msgstr "E65: Geçersiz dönüş başvurusu"
-
-msgid "E63: invalid use of \\_"
-msgstr "E63: Geçersiz kullanım: \\_"
-
-#, c-format
-msgid "E64: %s%c follows nothing"
-msgstr "E64: %s%c tek başına kullanılıyor"
-
-msgid "E68: Invalid character after \\z"
-msgstr "E68: \\z sonrası geçersiz karakter"
-
#, c-format
-msgid "E678: Invalid character after %s%%[dxouU]"
-msgstr "E678: %s%%[dxouU] sonrası geçersiz karakter"
-
-#, c-format
-msgid "E71: Invalid character after %s%%"
-msgstr "E71: %s%% sonrası geçersiz karakter"
-
-#, c-format
-msgid "E59: invalid character after %s@"
-msgstr "E59: %s@ sonrası geçersiz karakter"
-
-#, c-format
-msgid "E60: Too many complex %s{...}s"
-msgstr "E60: Çok fazla karmaşık %s{...}(lar)"
-
-#, c-format
-msgid "E61: Nested %s*"
-msgstr "E61: İç içe geçmiş %s*"
-
-#, c-format
-msgid "E62: Nested %s%c"
-msgstr "E62: İç içe geçmiş %s%c"
-
-msgid "E50: Too many \\z("
-msgstr "E50: Çok fazla \\z("
-
-#, c-format
-msgid "E51: Too many %s("
-msgstr "E51: Çok fazla %s("
-
-msgid "E52: Unmatched \\z("
-msgstr "E52: Eşleşmemiş \\z("
-
-msgid "E339: Pattern too long"
-msgstr "E339: Dizgi çok uzun"
-
-msgid "External submatches:\n"
-msgstr "Dış alteşleşmeler:\n"
-
-msgid "E865: (NFA) Regexp end encountered prematurely"
-msgstr "E865: (BSO) Düzenli ifade sonu çok erken geldi"
-
-#, c-format
-msgid "E866: (NFA regexp) Misplaced %c"
-msgstr "E866: (BSO düzenli ifadesi) Yanlış yere koyulmuş %c"
-
-#, c-format
-msgid "E877: (NFA regexp) Invalid character class: %d"
-msgstr "E877: (BSO düzenli ifadesi) Geçersiz karakter sınıfı: %d"
-
-msgid "E951: \\% value too large"
-msgstr "E951: \\% çok büyük bir değer"
-
-#, c-format
-msgid "E867: (NFA) Unknown operator '\\z%c'"
-msgstr "E867: (BSO) Bilinmeyen işleç '\\z%c'"
-
-#, c-format
-msgid "E867: (NFA) Unknown operator '\\%%%c'"
-msgstr "E867: (BSO) Bilinmeyen işleç '\\%%%c'"
-
-msgid "E868: Error building NFA with equivalence class!"
-msgstr "E868: Eşdeğerli sınıf ile BSO inşa ederken hata!"
-
-#, c-format
-msgid "E869: (NFA) Unknown operator '\\@%c'"
-msgstr "E869: (BSO) Bilinmeyen işleç '\\@%c'"
-
-msgid "E870: (NFA regexp) Error reading repetition limits"
-msgstr "E870: (BSO düzenli ifadesi) Yineleme sınırlarımı okurken hata"
-
-msgid "E871: (NFA regexp) Can't have a multi follow a multi"
-msgstr "E871: (BSO düzenli ifadesi) Bir çoklunun ardından çoklu gelemez"
-
-msgid "E872: (NFA regexp) Too many '('"
-msgstr "E872: (BSO düzenli ifadesi) Çok fazla '('"
-
-msgid "E879: (NFA regexp) Too many \\z("
-msgstr "E879: (BSO düzenli ifadesi) Çok fazla \\z("
-
-msgid "E873: (NFA regexp) proper termination error"
-msgstr "E873: (BSO düzenli ifadesi) Düzgün sonlandırma hatası"
-
-msgid "Could not open temporary log file for writing, displaying on stderr... "
-msgstr ""
-"Geçici günlük dosyası yazma için açılamıyor, stderr'de görüntüleniyor..."
-
-msgid "E874: (NFA) Could not pop the stack!"
-msgstr "E874: (BSO) Yığın çıkartılamadı!"
-
-msgid ""
-"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
-"left on stack"
-msgstr ""
-"E875: (BSO düzenli ifadesi) (Art takı'dan BSO'ya çevirirken), yığında çok "
-"fazla durum bırakıldı"
-
-msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
-msgstr ""
-"E876: (BSO düzenli ifadesi) Tüm BSO'yu depolamak için yeterli alan yok "
-
-msgid "E878: (NFA) Could not allocate memory for branch traversal!"
-msgstr "E878: (BSO) Dal gezinmesi için bellek ayrılamadı!"
-
-msgid "E748: No previously used register"
-msgstr "E748: Daha önce kullanılan bir yazmaç yok"
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\", \"%s\" içinde aranıyor"
#, c-format
-msgid "freeing %ld lines"
-msgstr "%ld satırlık yer açılıyor"
+msgid "Searching for \"%s\""
+msgstr "\"%s\" aranıyor"
#, c-format
-msgid " into \"%c"
-msgstr " \"%c"
+msgid "not found in '%s': \"%s\""
+msgstr "'%s' içinde bulunamadı: \"%s\""
#, c-format
-msgid "block of %ld line yanked%s"
-msgid_plural "block of %ld lines yanked%s"
-msgstr[0] "%ld satırlık blok şuraya kopyalandı:%s"
-msgstr[1] "%ld satırlık blok şuraya kopyalandı:%s"
+msgid "Searching for \"%s\" in runtime path"
+msgstr "\"%s\", çalışma zamanı yolu içinde aranıyor"
#, c-format
-msgid "%ld line yanked%s"
-msgid_plural "%ld lines yanked%s"
-msgstr[0] "%ld satır şuraya kopyalandı:%s"
-msgstr[1] "%ld satır şuraya kopyalandı:%s"
+msgid "not found in runtime path: \"%s\""
+msgstr "çalışma zamanı yolu içinde bulunamadı: \"%s\""
-#, c-format
-msgid "E353: Nothing in register %s"
-msgstr "E353: Yazmaç %s boş"
-
-msgid ""
-"\n"
-"Type Name Content"
-msgstr ""
-"\n"
-"Tür Ad İçerik"
-
-msgid ""
-"E883: search pattern and expression register may not contain two or more "
-"lines"
-msgstr ""
-"E883: Arama dizgisi ve ifade yazmacı iki veya daha fazla satır içeremez"
+msgid " TERMINAL"
+msgstr " UÇBİRİM"
msgid " VREPLACE"
msgstr " SANAL DEĞİŞTİR"
@@ -4688,146 +4585,264 @@ msgid "recording"
msgstr "kaydediliyor"
#, c-format
-msgid "Searching for \"%s\" in \"%s\""
-msgstr "\"%s\", \"%s\" içinde aranıyor"
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Geçersiz arama dizisi: %s"
#, c-format
-msgid "Searching for \"%s\""
-msgstr "\"%s\" aranıyor"
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Arama dosyanın BAŞINA vardı, %s bulunamadı"
#, c-format
-msgid "not found in '%s': \"%s\""
-msgstr "'%s' içinde bulunamadı: \"%s\""
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Arama dosyanın SONUNA vardı, %s bulunamadı"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' sonrasında '?' veya '/' bekleniyordu"
+
+msgid " (includes previously listed match)"
+msgstr " (daha önce listelenen eşleşmeyi içerir)"
-msgid "Source Vim script"
-msgstr "Vim betiği kaynak al"
+msgid "--- Included files "
+msgstr "--- İçerilen dosyalar "
+
+msgid "not found "
+msgstr "bulunamadı "
+
+msgid "in path ---\n"
+msgstr "yolda ---\n"
+
+msgid " (Already listed)"
+msgstr " (Hâlihazırda listelenmiş)"
+
+msgid " NOT FOUND"
+msgstr " BULUNAMADI"
#, c-format
-msgid "Cannot source a directory: \"%s\""
-msgstr "Dizin kaynak alınamıyor: \"%s\""
+msgid "Scanning included file: %s"
+msgstr "İçerilen dosya taranıyor: %s"
#, c-format
-msgid "could not source \"%s\""
-msgstr "\"%s\" kaynak alınamadı"
+msgid "Searching included file %s"
+msgstr "İçerilen dosya %s aranıyor"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Eşleşme şu anda bulunulan satırda"
+
+msgid "All included files were found"
+msgstr "Tüm içerilen dosyalar bulundu"
+
+msgid "No included files"
+msgstr "İçerilen dosya yok"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Tanım bulunamadı"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Dizgi bulunamadı"
+
+msgid "too few bytes read"
+msgstr "pek az bayt okundu"
#, c-format
-msgid "line %ld: could not source \"%s\""
-msgstr "%ld. satır: \"%s\" kaynak alınamadı"
+msgid "System error while skipping in ShaDa file: %s"
+msgstr "Paylaşılan veri dosyası içinde atlanırken sistem hatası: %s"
#, c-format
-msgid "sourcing \"%s\""
-msgstr "\"%s\" kaynak alınıyor"
+msgid ""
+"Error while reading ShaDa file: last entry specified that it occupies "
+"%<PRIu64> bytes, but file ended earlier"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: Son girdi, %<PRIu64> bayt tuttuğunu "
+"belirtti; ancak dosya daha erken sonlandı"
#, c-format
-msgid "line %ld: sourcing \"%s\""
-msgstr "%ld. satır: \"%s\" kaynak alınıyor"
+msgid "System error while closing ShaDa file: %s"
+msgstr "Paylaşılan veri dosyası kapatılırken sistem hatası: %s"
#, c-format
-msgid "finished sourcing %s"
-msgstr "%s kaynak alınması bitti"
+msgid "System error while writing ShaDa file: %s"
+msgstr "Paylaşılan veri dosyası yazılırken sistem hatası: %s"
#, c-format
-msgid "continuing in %s"
-msgstr "%s içinde sürdürülüyor"
+msgid "Reading ShaDa file \"%s\"%s%s%s%s"
+msgstr "Paylaşılan veri dosyası okunuyor: \"%s\"%s%s%s%s"
-msgid "modeline"
-msgstr "kip satırı"
+msgid " info"
+msgstr " bilgiler-"
-msgid "--cmd argument"
-msgstr "--cmd argümanı"
+msgid " marks"
+msgstr " imler-"
-msgid "-c argument"
-msgstr "-c argümanı"
+msgid " oldfiles"
+msgstr " düzenleme geçmişi"
-msgid "environment variable"
-msgstr "ortam değişkeni"
+msgid " FAILED"
+msgstr " BAŞARISIZ"
-msgid "error handler"
-msgstr "hata işleyicisi"
+#, c-format
+msgid "System error while opening ShaDa file %s for reading: %s"
+msgstr "%s paylaşılan veri dosyası açılırken sistem hatası: %s"
-msgid "changed window size"
-msgstr "değiştirilen pencere boyutu"
+msgid "additional elements of ShaDa "
+msgstr "paylaşılan verinin ek ögeleri "
-msgid "W15: Warning: Wrong line separator, ^M may be missing"
-msgstr "W15: Uyarı: Yanlış satır ayırıcısı, ^M eksik olabilir"
+msgid "additional data of ShaDa "
+msgstr "paylaşılan verinin ek verisi"
-msgid "E167: :scriptencoding used outside of a sourced file"
-msgstr "E167: :scriptencoding kaynak alınmış bir dosyanın dışında kullanıldı"
+#, c-format
+msgid "Failed to write variable %s"
+msgstr "%s değişkeni yazılamadı"
-msgid "E984: :scriptversion used outside of a sourced file"
-msgstr "E984: :scriptversion kaynak alınmış bir dosyanın dışında kullanıldı"
+#, c-format
+msgid ""
+"Failed to parse ShaDa file due to a msgpack parser error at position "
+"%<PRIu64>"
+msgstr ""
+"%<PRIu64> konumundaki bir msgpack ayrıştırıcı hatası nedeniyle paylaşılan "
+"veri dosyası ayrıştırılamadı"
#, c-format
-msgid "E999: scriptversion not supported: %d"
-msgstr "E999: desteklenmeyen scriptversion: %d"
+msgid ""
+"Failed to parse ShaDa file: incomplete msgpack string at position %<PRIu64>"
+msgstr ""
+"Paylaşılan veri dosyası ayrıştırılamadı: %<PRIu64> konumunda tam olmayan "
+"msgpack dizisi"
-msgid "E168: :finish used outside of a sourced file"
-msgstr "E168: :finish kaynak alınmış bir dosyanın dışında kullanıldı"
+#, c-format
+msgid ""
+"Failed to parse ShaDa file: extra bytes in msgpack string at position "
+"%<PRIu64>"
+msgstr ""
+"Paylaşılan veri dosyası ayrıştırılamadı: %<PRIu64> konumundaki msgpack "
+"dizisinde ek baytlar"
#, c-format
-msgid "E383: Invalid search string: %s"
-msgstr "E383: Geçersiz arama dizisi: %s"
+msgid ""
+"System error while opening ShaDa file %s for reading to merge before writing "
+"it: %s"
+msgstr ""
+"%s paylaşılan veri dosyasını yazmadan önce birleştirmek için okumak için "
+"açarken sistem hatası: %s"
#, c-format
-msgid "E384: search hit TOP without match for: %s"
-msgstr "E384: Arama dosyanın BAŞINA vardı, %s bulunamadı"
+msgid "E138: All %s.tmp.X files exist, cannot write ShaDa file!"
+msgstr "E138: Tüm %s.tmp.X dosyaları var, paylaşılan veri dosyası yazılamıyor!"
#, c-format
-msgid "E385: search hit BOTTOM without match for: %s"
-msgstr "E385: Arama dosyanın SONUNA vardı, %s bulunamadı"
+msgid "System error while opening temporary ShaDa file %s for writing: %s"
+msgstr ""
+"%s geçici paylaşılan veri dosyası yazma için açılırken sistem hatası: %s"
-msgid "E386: Expected '?' or '/' after ';'"
-msgstr "E386: ';' sonrasında '?' veya '/' bekleniyordu"
+#, c-format
+msgid "Failed to create directory %s for writing ShaDa file: %s"
+msgstr "Paylaşılan veri dosyasını yazma için %s dizini oluşturulamadı: %s"
-msgid " (includes previously listed match)"
-msgstr " (daha önce listelenen eşleşmeyi içerir)"
+#, c-format
+msgid "System error while opening ShaDa file %s for writing: %s"
+msgstr "%s paylaşılan veri dosyasını yazma için açarken sistem hatası: %s"
-msgid "--- Included files "
-msgstr "--- İçerilen dosyalar "
+#, c-format
+msgid "Writing ShaDa file \"%s\""
+msgstr "Paylaşılan veri dosyası \"%s\" yazılıyor"
-msgid "not found "
-msgstr "bulunamadı "
+#, c-format
+msgid "Failed setting uid and gid for file %s: %s"
+msgstr "%s dosyası için uid ve gid ayarlanamadı: %s"
-msgid "in path ---\n"
-msgstr "yolda ---\n"
+#, c-format
+msgid "E137: ShaDa file is not writable: %s"
+msgstr "E137: Paylaşılan veri dosyası yazılabilir değil: %s"
-msgid " (Already listed)"
-msgstr " (Hâlihazırda listelenmiş)"
+#, c-format
+msgid "Can't rename ShaDa file from %s to %s!"
+msgstr "Paylaşılan veri dosyası %s -> %s olarak yeniden adlandırılamıyor!"
-msgid " NOT FOUND"
-msgstr " BULUNAMADI"
+#, c-format
+msgid "Did not rename %s because %s does not look like a ShaDa file"
+msgstr ""
+"%s yeniden adlandırılmadı; çünkü %s bir paylaşılan veri dosyasına benzemiyor"
#, c-format
-msgid "Scanning included file: %s"
-msgstr "İçerilen dosya taranıyor: %s"
+msgid "Did not rename %s to %s because there were errors during writing it"
+msgstr "%s dosyasını %s olarak yeniden adlandırmanızın nedeni yazma sırasında "
+"hatalar olması mı?"
#, c-format
-msgid "Searching included file %s"
-msgstr "İçerilen dosya %s aranıyor"
+msgid "Do not forget to remove %s or rename it manually to %s."
+msgstr "%s dosyasını kaldırmayı veya el ile %s olarak yeniden adlandırmayı "
+"unutmayın."
-msgid "E387: Match is on current line"
-msgstr "E387: Eşleşme şu anda bulunulan satırda"
+#, c-format
+msgid "System error while reading ShaDa file: %s"
+msgstr "Paylaşılan veri dosyası okunurken sistem hatası: %s"
-msgid "All included files were found"
-msgstr "Tüm içerilen dosyalar bulundu"
+#, c-format
+msgid "System error while reading integer from ShaDa file: %s"
+msgstr "Paylaşılan veri dosyasından tamsayı okunurken sistem hatası: %s"
-msgid "No included files"
-msgstr "İçerilen dosya yok"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: expected positive integer at position "
+"%<PRIu64>, but got nothing"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumunda pozitif tamsayı "
+"bekleniyordu; ancak hiçbir şey alınmadı"
-msgid "E388: Couldn't find definition"
-msgstr "E388: Tanım bulunamadı"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: expected positive integer at position "
+"%<PRIu64>"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumunda pozitif tamsayı "
+"bekleniyordu"
-msgid "E389: Couldn't find pattern"
-msgstr "E389: Dizgi bulunamadı"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: there is an item at position %<PRIu64> that "
+"is stated to be too long"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumunda bir öge var; ancak"
+" pek uzun olduğu belirtildi"
-msgid "Save View"
-msgstr "Görünümü Kaydet"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: there is an item at position %<PRIu64> that "
+"must not be there: Missing items are for internal uses only"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumunda orada olmaması "
+"gereken bir öge var: Eksik ögeler yalnızca iç kullanım içindir"
+
+#, c-format
+msgid ""
+"Error while reading ShaDa file: buffer list at position %<PRIu64> contains "
+"entry that is not a dictionary"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumundaki arabellek "
+"listesi bir sözlük olmayan bir girdi içeriyor"
+
+#, c-format
+msgid ""
+"Error while reading ShaDa file: buffer list at position %<PRIu64> contains "
+"entry with invalid line number"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumundaki arabellek "
+"listesi geçersiz satır numaralı bir girdi içeriyor"
-msgid "Save Session"
-msgstr "Oturumu Kaydet"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: buffer list at position %<PRIu64> contains "
+"entry with invalid column number"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumundaki arabellek "
+"listesi geçersiz sütun numaralı bir girdi içeriyor"
-msgid "Save Setup"
-msgstr "Kurulumu Kaydet"
+#, c-format
+msgid ""
+"Error while reading ShaDa file: buffer list at position %<PRIu64> contains "
+"entry that does not have a file name"
+msgstr ""
+"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumundaki arabellek "
+"listesi bir dosya adına iye olmayan bir girdi içeriyor"
msgid "[Deleted]"
msgstr "[Silindi]"
@@ -4845,7 +4860,7 @@ msgstr "%s için işaretler:"
#, c-format
msgid " group=%s"
-msgstr " grup=%s"
+msgstr " grup=%s"
#, c-format
msgid " line=%ld id=%d%s name=%s priority=%d"
@@ -4870,8 +4885,8 @@ msgid "E159: Missing sign number"
msgstr "E159: İşaret numarası eksik"
#, c-format
-msgid "E157: Invalid sign ID: %d"
-msgstr "E157: Geçersiz işaret kimliği: %d"
+msgid "E157: Invalid sign ID: %<PRId64>"
+msgstr "E157: Geçersiz işaret kimliği: %<PRId64>"
msgid "E934: Cannot jump to a buffer that does not have a name"
msgstr "E934: Adı olmayan bir arabelleğe atlamak olanaklı değil"
@@ -4883,15 +4898,11 @@ msgstr "E160: Bilinmeyen işaret komutu: %s"
msgid "E156: Missing sign name"
msgstr "E156: İşaret adı eksik"
-msgid " (NOT FOUND)"
-msgstr " (BULUNAMADI)"
-
msgid " (not supported)"
msgstr " (desteklenmiyor)"
-#, c-format
-msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
-msgstr "Uyarı: Sözcük listesi \"%s_%s.spl\" veya \"%s_ascii.spl\" bulunamıyor"
+msgid "E759: Format error in spell file"
+msgstr "E759: Takas dosyasında biçim hatası"
#, c-format
msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
@@ -4904,6 +4915,21 @@ msgstr "E797: SpellFileMissing otokomutu arabelleği sildi"
msgid "Warning: region %s not supported"
msgstr "Uyarı: %s bölgesi desteklenmiyor"
+msgid "Sorry, no suggestions"
+msgstr "Üzgünüm, şu an için bir önerim yok"
+
+#, c-format
+msgid "Sorry, only %<PRId64> suggestions"
+msgstr "Üzgünüm, yalnızca %<PRId64> öneri"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "\"%.*s\" şuna değiştirilecek:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
msgid "E752: No previous spell replacement"
msgstr "E752: Öncesinde düzeltilmiş bir yazım yok"
@@ -4922,12 +4948,6 @@ msgstr "%s içinde %d. satır ucunda fazladan metin: %s"
msgid "Affix name too long in %s line %d: %s"
msgstr "%s içinde %d. satırda ek adı çok uzun: %s"
-msgid "E761: Format error in affix file FOL, LOW or UPP"
-msgstr "E761: Ekler dosyası FOL, LOW veya UPP içinde biçimlendirme hatası"
-
-msgid "E762: Character in FOL, LOW or UPP is out of range"
-msgstr "E762: FOL, LOW veya UPP içindeki karakterler erimin dışında"
-
msgid "Compressing word tree..."
msgstr "Sözcük soyağacı sıkıştırılıyor..."
@@ -4938,8 +4958,12 @@ msgstr "Yazım dosyası \"%s\" okunuyor"
msgid "E757: This does not look like a spell file"
msgstr "E757: Bu bir yazım dosyasına benzemiyor"
+#, c-format
+msgid "E5042: Failed to read spell file %s: %s"
+msgstr "E5042: %s yazım dosyası okunamadı: %s"
+
msgid "E771: Old spell file, needs to be updated"
-msgstr "E771: Eski yazım dosyası, güncellenmesi gerekiyor"
+msgstr "E771: Eski yazım dosyası; güncellenmesi gerekiyor"
msgid "E772: Spell file is for newer version of Vim"
msgstr "E772: Yazım dosyası Vim'in daha yeni bir sürümü için"
@@ -5034,7 +5058,7 @@ msgstr "%s içinde %d. satırda yinelenen ek: %s"
#, c-format
msgid ""
-"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGESTin %s "
"line %d: %s"
msgstr ""
"Ek aynı zamanda %s içinde %d. satırda BAD/RARE/KEEPCASE/NEEDAFFIX/"
@@ -5064,10 +5088,6 @@ msgstr "%s içinde %d. satırda MAP içinde yinelenen karakter"
msgid "Unrecognized or duplicate item in %s line %d: %s"
msgstr "%s içinde %d. satırda yinelenen veya tanınmayan öge: %s"
-#, c-format
-msgid "Missing FOL/LOW/UPP line in %s"
-msgstr "%s içinde FOL/LOW/UPP satırı eksik"
-
msgid "COMPOUNDSYLMAX used without SYLLABLE"
msgstr "COMPOUNDSYLMAX, SYLLABLE olmadan kullanılmış"
@@ -5151,7 +5171,7 @@ msgstr "%s içinde %ld. satırda yinelenen /regions= satırı yok sayıldı: %s"
#, c-format
msgid "Too many regions in %s line %ld: %s"
-msgstr "%s içinde %ld. satırda çok fazla bölge: %s"
+msgstr "%s içinde %ld. satırda pek fazla bölge: %s"
#, c-format
msgid "/ line ignored in %s line %ld: %s"
@@ -5169,12 +5189,9 @@ msgstr "%s içinde %ld. satırda tanınmayan bayraklar: %s"
msgid "Ignored %d words with non-ASCII characters"
msgstr "ASCII olmayan karakter içeren %d sözcük yok sayıldı"
-msgid "E845: Insufficient memory, word list will be incomplete"
-msgstr "E845: Yetersiz bellek, sözcük listesi tam olmayacak"
-
#, c-format
-msgid "Compressed %s: %ld of %ld nodes; %ld (%ld%%) remaining"
-msgstr "%s sıkıştırılıyor: %ld/%ld uç sıkıştırıldı; %ld (%%%ld) kalan"
+msgid "Compressed %s of %ld nodes; %ld (%ld%%) remaining"
+msgstr "%s/%ld uç sıkıştırıldı; %ld (%%%ld) kalan"
msgid "Reading back spell file..."
msgstr "Yazım dosyası yeniden okunuyor..."
@@ -5183,8 +5200,8 @@ msgid "Performing soundfolding..."
msgstr "Sesler evriştiriliyor..."
#, c-format
-msgid "Number of words after soundfolding: %ld"
-msgstr "Ses evriştirme sonrası sözcük sayısı: %ld"
+msgid "Number of words after soundfolding: %<PRId64>"
+msgstr "Ses evriştirme sonrası sözcük sayısı: %<PRId64>"
#, c-format
msgid "Total number of words: %d"
@@ -5196,7 +5213,7 @@ msgstr "Öneriler dosyası %s yazılıyor..."
#, c-format
msgid "Estimated runtime memory use: %d bytes"
-msgstr "Tahmini çalıştırılan bellek kullanımı: %d bit"
+msgstr "Tahmini çalışma bellek kullanımı: %d bayt"
msgid "E751: Output file name must not have region name"
msgstr "E751: Çıktı dosyası bir bölge adı içermemelidir"
@@ -5220,8 +5237,8 @@ msgid "Done!"
msgstr "Yapıldı!"
#, c-format
-msgid "E765: 'spellfile' does not have %d entries"
-msgstr "E765: 'spellfile' içinde %d adet girdi yok"
+msgid "E765: 'spellfile' does not have %<PRId64> entries"
+msgstr "E765: 'spellfile' içinde %<PRId64> adet girdi yok"
#, c-format
msgid "Word '%.*s' removed from %s"
@@ -5240,20 +5257,14 @@ msgstr "E763: Sözcük karakterleri yazım dosyaları arasında ayrım gösteriy
msgid "E783: duplicate char in MAP entry"
msgstr "E783: MAP girdisinde yinelenen karakter"
-msgid "Sorry, no suggestions"
-msgstr "Üzgünüm, şu an için bir önerim yok"
-
-#, c-format
-msgid "Sorry, only %ld suggestions"
-msgstr "Üzgünüm, yalnızca %ld öneri"
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() için yetersiz argüman"
-#, c-format
-msgid "Change \"%.*s\" to:"
-msgstr "\"%.*s\" şuna değiştirilecek:"
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf() için kayan noktalı değer türünde argüman bekleniyordu"
-#, c-format
-msgid " < \"%.*s\""
-msgstr " < \"%.*s\""
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() için pek fazla argüman"
#, c-format
msgid "E390: Illegal argument: %s"
@@ -5265,36 +5276,6 @@ msgstr "Bu arabellek için sözdizim ögeleri tanımlanmamış"
msgid "'redrawtime' exceeded, syntax highlighting disabled"
msgstr "'redrawtime' aşıldı, sözdizim vurgulaması kapatıldı"
-msgid "syntax conceal on"
-msgstr "sözdizim gizlemesi açık"
-
-msgid "syntax conceal off"
-msgstr "sözdizim gizlemesi kapalı"
-
-msgid "syntax case ignore"
-msgstr "sözdizim BÜYÜK/küçük harf yok say"
-
-msgid "syntax case match"
-msgstr "sözdizim BÜYÜK/küçük harfe duyarlı"
-
-msgid "syntax foldlevel start"
-msgstr "sözdizim kıvırma düzeyi başlangıcı"
-
-msgid "syntax foldlevel minimum"
-msgstr "sözdizim kıvırma düzeyi an az"
-
-msgid "syntax spell toplevel"
-msgstr "bir sözdizim içinde olmayan metinde yazım denetimi yap"
-
-msgid "syntax spell notoplevel"
-msgstr "bir sözdizim içinde olmayan metinde yazım denetimi yapma"
-
-msgid "syntax spell default"
-msgstr "@Spell kümesi varsa yazım denetimi yapma (öntanımlı)"
-
-msgid "syntax iskeyword "
-msgstr "sözdizim anahtar sözcük"
-
msgid "syntax iskeyword not set"
msgstr "sözdizim anahtar sözcük ayarlanmamış"
@@ -5479,7 +5460,7 @@ msgid " or more"
msgstr " veya daha fazla"
msgid " Using tag with different case!"
-msgstr " Etiket değişik bir durumla kullanılıyor!"
+msgstr " Etiket değişik bir durumla kullanılıyor!"
#, c-format
msgid "E429: File \"%s\" does not exist"
@@ -5503,16 +5484,12 @@ msgid "Searching tags file %s"
msgstr "Etiket dosyası %s aranıyor"
#, c-format
-msgid "E430: Tag file path truncated for %s\n"
-msgstr "E430: %s için etiket dosyası yolu kırpıldı\n"
-
-#, c-format
msgid "E431: Format error in tags file \"%s\""
msgstr "E431: Etiket dosyası \"%s\" içinde biçim hatası"
#, c-format
-msgid "Before byte %ld"
-msgstr "%ld bitinden önce"
+msgid "Before byte %<PRId64>"
+msgstr "%<PRId64> baytından önce"
#, c-format
msgid "E432: Tags file not sorted: %s"
@@ -5521,9 +5498,6 @@ msgstr "E432: Etiket dosyası sıralanmadı: %s"
msgid "E433: No tags file"
msgstr "E433: Etiket dosyası yok"
-msgid "Ignoring long line in tags file"
-msgstr "Etiket dosyasındaki uzun satır yok sayılıyor"
-
msgid "E434: Can't find tag pattern"
msgstr "E434: Etiket dizgisi bulunamıyor"
@@ -5534,237 +5508,21 @@ msgstr "E435: Etiket bulunamadı, tahmin ediliyor!"
msgid "Duplicate field name: %s"
msgstr "Yinelenen alan adı: %s"
-msgid "' not known. Available builtin terminals are:"
-msgstr "' bilinmiyor. Kullanılabilir uçbirimler şunlar:"
-
-msgid "defaulting to '"
-msgstr "öntanımlı olarak '"
-
-msgid "E557: Cannot open termcap file"
-msgstr "E557: termcap dosyası açılamıyor"
-
-msgid "E558: Terminal entry not found in terminfo"
-msgstr "E558: terminfo içinde uçbirim girdisi bulunamadı"
-
-msgid "E559: Terminal entry not found in termcap"
-msgstr "E559: termcap içinde uçbirim bilgisi bulunamadı"
-
-#, c-format
-msgid "E436: No \"%s\" entry in termcap"
-msgstr "E436: termcap içinde \"%s\" girdisi yok"
-
-msgid "E437: terminal capability \"cm\" required"
-msgstr "E437: \"cm\" uçbirim yeteneği gerekiyor"
-
-msgid ""
-"\n"
-"--- Terminal keys ---"
-msgstr ""
-"\n"
-"--- Uçbirim düğmeleri ---"
-
-#, c-format
-msgid "E181: Invalid attribute: %s"
-msgstr "E181: Geçersiz öznitelik: %s"
-
-msgid "E279: Sorry, ++shell is not supported on this system"
-msgstr "E279: Üzgünüm, ++shell bu sistemde desteklenmiyor"
-
-#, c-format
-msgid "Kill job in \"%s\"?"
-msgstr "\"%s\" içindeki iş sonlandırılsın mı?"
-
-msgid "Terminal"
-msgstr "Uçbirim"
-
-msgid "Terminal-finished"
-msgstr "Uçbirim-bitti"
-
-msgid "active"
-msgstr "etkin"
-
-msgid "running"
-msgstr "çalışıyor"
-
-msgid "finished"
-msgstr "bitti"
-
-msgid "E958: Job already finished"
-msgstr "E958: İş bitti bile"
-
-#, c-format
-msgid "E953: File exists: %s"
-msgstr "E953: Dosya mevcut: %s"
-
-msgid "E955: Not a terminal buffer"
-msgstr "E955: Bir uçbirim arabelleği değil"
-
-msgid "E982: ConPTY is not available"
-msgstr "E982: ConPTY mevcut değil"
-
-#, c-format
-msgid "E971: Property type %s does not exist"
-msgstr "E971: Özellik türü %s mevcut değil"
-
-#, c-format
-msgid "E964: Invalid column number: %ld"
-msgstr "E964: Geçersiz sütun numarası: %ld"
-
-#, c-format
-msgid "E966: Invalid line number: %ld"
-msgstr "E966: Geçersiz satır numarası: %ld"
-
-msgid "E965: missing property type name"
-msgstr "E965: Özellik tür adı eksik"
-
-msgid "E275: Cannot add text property to unloaded buffer"
-msgstr "E275: Bellekten kaldırılmış arabelleğe metin özelliği eklenemiyor"
-
-msgid "E967: text property info corrupted"
-msgstr "E967: Metin özellik bilgisi hasarlı"
-
-msgid "E968: Need at least one of 'id' or 'type'"
-msgstr "E968: En azından bir 'id' veya 'type' gerekli"
-
-msgid "E860: Need 'id' and 'type' with 'both'"
-msgstr "E860: 'both' ile 'id' ve 'type' gerekli"
-
-#, c-format
-msgid "E969: Property type %s already defined"
-msgstr "E969: Özellik türü %s hâlihazırda tanımlanmış"
-
-#, c-format
-msgid "E970: Unknown highlight group name: '%s'"
-msgstr "E970: Bilinmeyen vurgulama grup adı: '%s'"
-
-msgid "(Invalid)"
-msgstr "(Geçersiz)"
-
-msgid "%a %b %d %H:%M:%S %Y"
-msgstr "%a %b %d %H:%M:%S %Y"
-
-#, c-format
-msgid "%ld second ago"
-msgid_plural "%ld seconds ago"
-msgstr[0] "%ld saniye önce"
-msgstr[1] "%ld saniye önce"
-
-msgid "E805: Using a Float as a Number"
-msgstr "E805: Bir Kayan Noktalı Değer, Sayı yerine kullanılıyor"
-
-msgid "E703: Using a Funcref as a Number"
-msgstr "E703: Bir Funcref, Sayı yerine kullanılıyor"
-
-msgid "E745: Using a List as a Number"
-msgstr "E745: Bir Liste, Sayı yerine kullanılıyor"
-
-msgid "E728: Using a Dictionary as a Number"
-msgstr "E728: Bir Sözlük, Sayı yerine kullanılıyor"
-
-msgid "E611: Using a Special as a Number"
-msgstr "E611: Bir Özel, Sayı yerine kullanılıyor"
-
-msgid "E910: Using a Job as a Number"
-msgstr "E910: Bir İş, Sayı yerine kullanılıyor"
-
-msgid "E913: Using a Channel as a Number"
-msgstr "E913: Bir Kanal, Sayı yerine kullanılıyor"
-
-msgid "E974: Using a Blob as a Number"
-msgstr "E974: Bir İkili Geniş Nesne, Sayı yerine kullanılıyor"
-
-msgid "E891: Using a Funcref as a Float"
-msgstr "E891: Bir Funcref, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E892: Using a String as a Float"
-msgstr "E892: Bir Dizi, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E893: Using a List as a Float"
-msgstr "E893: Bir Liste, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E894: Using a Dictionary as a Float"
-msgstr "E894: Bir Sözlük, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E362: Using a boolean value as a Float"
-msgstr "E362: Bir Boole Değeri, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E907: Using a special value as a Float"
-msgstr "E907: Bir Özel Değer, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E911: Using a Job as a Float"
-msgstr "E911: Bir İş, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E914: Using a Channel as a Float"
-msgstr "E914: Bir Kanal, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E975: Using a Blob as a Float"
-msgstr "E975: Bir İkili Geniş Nesne, Kayan Noktalı Değer yerine kullanılıyor"
-
-msgid "E729: Using a Funcref as a String"
-msgstr "E729: Funcref bir Dizi yerine kullanılıyor"
-
-msgid "E730: Using a List as a String"
-msgstr "E730: Liste bir Dizi yerine kullanılıyor"
-
-msgid "E731: Using a Dictionary as a String"
-msgstr "E731: Sözlük bir Dizi yerine kullanılıyor"
-
-msgid "E976: Using a Blob as a String"
-msgstr "E976: İkili Geniş Nesne bir Dizi yerine kullanılıyor"
-
-msgid "E977: Can only compare Blob with Blob"
-msgstr ""
-"E977: Bir ikili geniş öğe yalnızca kendinden bir başkası ile "
-"karşılaştırılabilir"
-
-msgid "E691: Can only compare List with List"
-msgstr "E691: Bir liste yalnızca başka bir liste ile karşılaştırılabilir"
-
-msgid "E692: Invalid operation for List"
-msgstr "E692: Geçersiz liste işlemi"
-
-msgid "E735: Can only compare Dictionary with Dictionary"
-msgstr "E735: Bir sözlük yalnızca başka bir sözlük ile karşılaştırılabilir"
-
-msgid "E736: Invalid operation for Dictionary"
-msgstr "E736: Geçersiz sözlük işlemi"
-
-msgid "E694: Invalid operation for Funcrefs"
-msgstr "E694: Geçersiz Funcref işlemi"
-
-#, c-format
-msgid "E112: Option name missing: %s"
-msgstr "E112: Seçenek adı eksik: %s"
-
-msgid "E973: Blob literal should have an even number of hex characters"
-msgstr ""
-"E973: İkili geniş nesne hazır bilgisi çift onalt. karakterlere iye olmalıdır"
-
-#, c-format
-msgid "E114: Missing quote: %s"
-msgstr "E114: Tırnak imi eksik: %s"
-
-#, c-format
-msgid "E115: Missing quote: %s"
-msgstr "E115: Tırnak imi eksik: %s"
-
-msgid "new shell started\n"
-msgstr "yeni kabuk başlatıldı\n"
-
-msgid "Vim: Error reading input, exiting...\n"
-msgstr "Vim: Girdi okunurken hata, çıkılıyor...\n"
+msgid "Beep!"
+msgstr "Bip!"
msgid "E881: Line count changed unexpectedly"
msgstr "E881: Satır sayısı beklenmeyen bir biçimde değişti"
-msgid "No undo possible; continue anyway"
-msgstr "Geri alma olanaklı değil; bekleme yapma"
-
#, c-format
msgid "E828: Cannot open undo file for writing: %s"
msgstr "E828: Geri al dosyası yazma için açılamıyor: %s"
#, c-format
+msgid "E5003: Unable to create directory \"%s\" for undo file: %s"
+msgstr "E5003: \"%s\" dizini, geri al dosyası için oluşturulamadı: %s"
+
+#, c-format
msgid "E825: Corrupted undo file (%s): %s"
msgstr "E825: Hasarlı geri al dosyası (%s): %s"
@@ -5807,18 +5565,6 @@ msgid "E823: Not an undo file: %s"
msgstr "E823: Bir geri al dosyası değil: %s"
#, c-format
-msgid "E832: Non-encrypted file has encrypted undo file: %s"
-msgstr "E832: Şifrelenmemiş dosyanın şifrelenmiş bir geri al dosyası var: %s"
-
-#, c-format
-msgid "E826: Undo file decryption failed: %s"
-msgstr "E826: Geri al dosyası şifre çözümü başarısız oldu: %s"
-
-#, c-format
-msgid "E827: Undo file is encrypted: %s"
-msgstr "E827: Geri al dosyası şifrelenmiş: %s"
-
-#, c-format
msgid "E824: Incompatible undo file: %s"
msgstr "E824: Uyumsuz geri al dosyası: %s"
@@ -5836,8 +5582,8 @@ msgid "Already at newest change"
msgstr "Hâlihazırda en yeni değişiklik üzerinde"
#, c-format
-msgid "E830: Undo number %ld not found"
-msgstr "E830: %ld numaralı geri alma bulunamadı"
+msgid "E830: Undo number %<PRId64> not found"
+msgstr "E830: %<PRId64> numaralı geri alma bulunamadı"
msgid "E438: u_undo: line numbers wrong"
msgstr "E438: u_undo: Satır numaraları yanlış"
@@ -5861,15 +5607,15 @@ msgid "changes"
msgstr "değişiklik"
#, c-format
-msgid "%ld %s; %s #%ld %s"
-msgstr "%ld %s; %s #%ld %s"
-
-msgid "before"
-msgstr "şundan önce:"
+msgid "%<PRId64> %s; %s #%<PRId64> %s"
+msgstr "%<PRId64> %s; %s #%<PRId64> %s"
msgid "after"
msgstr "şundan sonra:"
+msgid "before"
+msgstr "şundan önce:"
+
msgid "Nothing to undo"
msgstr "Geri alınacak bir şey yok"
@@ -5887,275 +5633,12 @@ msgstr "E440: Geri al satırı eksik"
msgid ""
"\n"
-" Name Args Address Complete Definition"
-msgstr ""
"\n"
-" Ad Dğkl Adres Tam Tanım"
-
-msgid "No user-defined commands found"
-msgstr "Kullanıcı tanımlı bir komut bulunamadı"
-
-#, c-format
-msgid "E180: Invalid address type value: %s"
-msgstr "E180: Geçersiz adres türü değeri: %s"
-
-#, c-format
-msgid "E180: Invalid complete value: %s"
-msgstr "E180: Geçersiz tam değer: %s"
-
-msgid "E468: Completion argument only allowed for custom completion"
-msgstr "E468: Tamamlama argümanına yalnızca özel tamamlamalarda izin verilir"
-
-msgid "E467: Custom completion requires a function argument"
-msgstr "E467: Özel tamamlama bir işlev argümanı gerektirir"
-
-msgid "E175: No attribute specified"
-msgstr "E175: Bir öznitelik belirtilmemiş"
-
-msgid "E176: Invalid number of arguments"
-msgstr "E176: Geçersiz argüman sayısı"
-
-msgid "E177: Count cannot be specified twice"
-msgstr "E177: Sayım iki defa belirtilemez"
-
-msgid "E178: Invalid default value for count"
-msgstr "E178: Sayım için geçersiz öntanımlı değer"
-
-msgid "E179: argument required for -complete"
-msgstr "E179: -complete için argüman gerekiyor"
-
-msgid "E179: argument required for -addr"
-msgstr "E179: -addr için argüman gerekiyor"
-
-#, c-format
-msgid "E174: Command already exists: add ! to replace it: %s"
-msgstr "E174: Komut zaten mevcut: değiştirmek için ! ekleyin: %s"
-
-msgid "E182: Invalid command name"
-msgstr "E182: Geçersiz komut adı"
-
-msgid "E183: User defined commands must start with an uppercase letter"
-msgstr "E183: Kullanıcı tanımlı komutlar BÜYÜK harfle başlamalıdır"
-
-msgid "E841: Reserved name, cannot be used for user defined command"
-msgstr "E841: Ayrılmış ad, kullanıcı tanımlı komut için kullanılamaz"
-
-#, c-format
-msgid "E184: No such user-defined command: %s"
-msgstr "E184: Böyle bir kullanıcı tanımlı komut yok: %s"
-
-#, c-format
-msgid "E122: Function %s already exists, add ! to replace it"
-msgstr "E122: %s işlevi hâlihazırda mevcut, değiştirmek için ! ekleyin"
-
-msgid "E717: Dictionary entry already exists"
-msgstr "E717: Sözlük girdisi hâlihazırda mevcut"
-
-msgid "E718: Funcref required"
-msgstr "E718: Funcref gerekiyor"
-
-#, c-format
-msgid "E130: Unknown function: %s"
-msgstr "E130: Bilinmeyen işlev: %s"
-
-#, c-format
-msgid "E125: Illegal argument: %s"
-msgstr "E125: İzin verilmeyen argüman: %s"
-
-#, c-format
-msgid "E853: Duplicate argument name: %s"
-msgstr "E853: Yinelenen argüman adı: %s"
-
-msgid "E989: Non-default argument follows default argument"
-msgstr "E989: Öntanımlı olmayan argüman öntanımlı argümandan sonra"
-
-msgid "E126: Missing :endfunction"
-msgstr "E126: :endfunction eksik"
-
-#, c-format
-msgid "W22: Text found after :endfunction: %s"
-msgstr "W22: :endfunction sonrası metin bulundu: %s"
-
-#, c-format
-msgid "E451: Expected }: %s"
-msgstr "E451: } bekleniyordu: %s"
-
-#, c-format
-msgid "E740: Too many arguments for function %s"
-msgstr "E740: %s işlevi için çok fazla argüman"
-
-#, c-format
-msgid "E116: Invalid arguments for function %s"
-msgstr "E116: %s işlevi için geçersiz argümanlar"
-
-msgid "E132: Function call depth is higher than 'maxfuncdepth'"
-msgstr "E132: İşlevin çağırdığı derinlik 'maxfuncdepth'ten daha yüksek"
-
-#, c-format
-msgid "calling %s"
-msgstr "%s çağrılıyor"
-
-#, c-format
-msgid "%s aborted"
-msgstr "%s durduruldu"
-
-#, c-format
-msgid "%s returning #%ld"
-msgstr "%s, #%ld döndürüyor"
-
-#, c-format
-msgid "%s returning %s"
-msgstr "%s, %s döndürüyor"
-
-msgid "E699: Too many arguments"
-msgstr "E699: Çok fazla argüman"
-
-#, c-format
-msgid "E276: Cannot use function as a method: %s"
-msgstr "E276: İşlev bir yöntem olarak kullanılamaz: %s"
-
-#, c-format
-msgid "E120: Using <SID> not in a script context: %s"
-msgstr "E120: <SID> bir betik bağlamında kullanılmıyor: %s"
-
-#, c-format
-msgid "E725: Calling dict function without Dictionary: %s"
-msgstr "E725: dic işlevi bir sözlük olmadan çağrılıyor: %s"
-
-msgid "E129: Function name required"
-msgstr "E129: İşlev adı gerekiyor"
-
-#, c-format
-msgid "E128: Function name must start with a capital or \"s:\": %s"
-msgstr "E128: İşlev adı bir BÜYÜK harfle veya \"s:\" ile başlamalı: %s"
-
-#, c-format
-msgid "E884: Function name cannot contain a colon: %s"
-msgstr "E884: İşlev adı iki nokta içeremez: %s"
-
-msgid "E454: function list was modified"
-msgstr "E454: İşlev listesi değiştirilmiş"
-
-#, c-format
-msgid "E123: Undefined function: %s"
-msgstr "E123: Tanımlanmamış işlev: %s"
-
-#, c-format
-msgid "E124: Missing '(': %s"
-msgstr "E124: '(' eksik: %s"
-
-msgid "E862: Cannot use g: here"
-msgstr "E862: g: burada kullanılamaz"
-
-#, c-format
-msgid "E932: Closure function should not be at top level: %s"
-msgstr "E932: Kapatma işlevi en üst düzeyde olmamalıdır: %s"
-
-#, c-format
-msgid "E707: Function name conflicts with variable: %s"
-msgstr "E707: İşlev adı şu değişken ile çakışıyor: %s"
-
-#, c-format
-msgid "E127: Cannot redefine function %s: It is in use"
-msgstr "E127: %s işlevi yeniden tanımlanamıyor: Şu an kullanımda"
-
-#, c-format
-msgid "E746: Function name does not match script file name: %s"
-msgstr "E746: İşlev adı betik dosyası adına eşleşmiyor: %s"
-
-#, c-format
-msgid "E131: Cannot delete function %s: It is in use"
-msgstr "E131: %s işlevi silinemiyor: Şu an kullanımda"
-
-msgid "E133: :return not inside a function"
-msgstr "E133: :return bir işlev içinde değil"
-
-#, c-format
-msgid "%s (%s, compiled %s)"
-msgstr "%s (%s, %s tarihinde derlendi)"
-
-msgid ""
-"\n"
-"MS-Windows 64-bit GUI/console version"
-msgstr ""
-"\n"
-"MS-Windows 64-bit grafik arabirim/konsol sürümü"
-
-msgid ""
-"\n"
-"MS-Windows 32-bit GUI/console version"
-msgstr ""
-"\n"
-"MS-Windows 32-bit grafik arabirim/konsol sürümü"
-
-msgid ""
-"\n"
-"MS-Windows 64-bit GUI version"
-msgstr ""
-"\n"
-"MS-Windows 64-bit grafik arabirim sürümü"
-
-msgid ""
-"\n"
-"MS-Windows 32-bit GUI version"
-msgstr ""
-"\n"
-"MS-Windows 32-bit grafik arabirim sürümü"
-
-msgid " with OLE support"
-msgstr ", OLE desteği ile"
-
-msgid ""
-"\n"
-"MS-Windows 64-bit console version"
-msgstr ""
-"\n"
-"MS-Windows 64-bit konsol sürümü"
-
-msgid ""
-"\n"
-"MS-Windows 32-bit console version"
-msgstr ""
-"\n"
-"MS-Windows 32-bit konsol sürümü"
-
-msgid ""
-"\n"
-"macOS version"
-msgstr ""
-"\n"
-"macOS sürümü"
-
-msgid ""
-"\n"
-"macOS version w/o darwin feat."
+"Features: "
msgstr ""
"\n"
-"Darwin özellikleri olmayan macOS sürümü"
-
-msgid ""
-"\n"
-"OpenVMS version"
-msgstr ""
"\n"
-"OpenVMS sürümü"
-
-msgid ""
-"\n"
-"Included patches: "
-msgstr ""
-"\n"
-"İçerilen yamalar: "
-
-msgid ""
-"\n"
-"Extra patches: "
-msgstr ""
-"\n"
-"Ek yamalar: "
-
-msgid "Modified by "
-msgstr "Değiştirme: "
+"Özellikler: "
msgid ""
"\n"
@@ -6167,181 +5650,38 @@ msgstr ""
msgid "by "
msgstr " "
-msgid ""
-"\n"
-"Huge version "
-msgstr ""
-"\n"
-"Dev sürüm "
-
-msgid ""
-"\n"
-"Big version "
-msgstr ""
-"\n"
-"Büyük sürüm "
-
-msgid ""
-"\n"
-"Normal version "
-msgstr ""
-"\n"
-"Orta boy sürüm "
-
-msgid ""
-"\n"
-"Small version "
-msgstr ""
-"\n"
-"Küçük sürüm "
-
-msgid ""
-"\n"
-"Tiny version "
-msgstr ""
-"\n"
-"Ufak sürüm "
-
-msgid "without GUI."
-msgstr "(grafik arabirim içermez)."
-
-msgid "with GTK3 GUI."
-msgstr "(GTK3 grafik arabirim ile)."
-
-msgid "with GTK2-GNOME GUI."
-msgstr "(GTK2-GNOME grafik arabirim ile)."
-
-msgid "with GTK2 GUI."
-msgstr "(GTK2 grafik arabirim ile)."
-
-msgid "with X11-Motif GUI."
-msgstr "(X11-Motif grafik arabirim ile)."
-
-msgid "with X11-neXtaw GUI."
-msgstr "(X11-neXtaw grafik arabirim ile)."
-
-msgid "with X11-Athena GUI."
-msgstr "(X11-Athena grafik arabirim ile)."
-
-msgid "with Haiku GUI."
-msgstr "(Haiku grafik arabirimi ile)."
-
-msgid "with Photon GUI."
-msgstr "(Photon grafik arabirim ile)."
-
-msgid "with GUI."
-msgstr "(grafik arabirim ile)."
-
-msgid " Features included (+) or not (-):\n"
-msgstr " İçerilen özellikler (+), içerilmeyenler (-) ile gösterilir:\n"
-
msgid " system vimrc file: \""
msgstr " sistem vimrc dosyası: \""
-msgid " user vimrc file: \""
-msgstr " kullanıcı vimrc dosyası: \""
-
-msgid " 2nd user vimrc file: \""
-msgstr " kullanıcı 2. vimrc dosyası: \""
-
-msgid " 3rd user vimrc file: \""
-msgstr " kullanıcı 3. vimrc dosyası: \""
-
-msgid " user exrc file: \""
-msgstr " kullanıcı exrc dosyası: \""
-
-msgid " 2nd user exrc file: \""
-msgstr " kullanıcı 2. exrc dosyası: \""
-
-msgid " system gvimrc file: \""
-msgstr " sistem gvimrc dosyası: \""
-
-msgid " user gvimrc file: \""
-msgstr " kullanıcı gvimrc dosyası: \""
-
-msgid "2nd user gvimrc file: \""
-msgstr " kullanıcı 2. gvimrc dosyası: \""
-
-msgid "3rd user gvimrc file: \""
-msgstr " kullanıcı 3. gvimrc dosyası: \""
-
-msgid " defaults file: \""
-msgstr " öntanımlılar dosyası: \""
-
-msgid " system menu file: \""
-msgstr " sistem menü dosyaları: \""
-
msgid " fall-back for $VIM: \""
msgstr " $VIM öntanımlı konumu: \""
msgid " f-b for $VIMRUNTIME: \""
msgstr "$VIMRUNTIME öntanımlı konumu: \""
-msgid "Compilation: "
-msgstr "Derleme: "
-
-msgid "Compiler: "
-msgstr "Derleyici: "
-
-msgid "Linking: "
-msgstr "Bağlama: "
+msgid "Nvim is open source and freely distributable"
+msgstr "Nvim açık kaynaklıdır ve özgürce dağıtılabilir"
-msgid " DEBUG BUILD"
-msgstr " HATA AYIKLAMA AMAÇLI SÜRÜM"
+msgid "https://neovim.io/#chat"
+msgstr "https://neovim.io/#chat"
-msgid "VIM - Vi IMproved"
-msgstr "VİM - Vi IMproved"
+msgid "type :help nvim<Enter> if you are new! "
+msgstr "eğer yeniyseniz :help nvim<Enter> "
-msgid "version "
-msgstr "sürüm: "
+msgid "type :checkhealth<Enter> to optimize Nvim"
+msgstr "Nvim'i eniyilemek için :help checkhealth<Enter>"
-msgid "by Bram Moolenaar et al."
-msgstr "geliştirme: Bram Moolenaar ve diğerleri"
+msgid "type :q<Enter> to exit "
+msgstr "çıkmak için :q<Enter> "
-msgid "Vim is open source and freely distributable"
-msgstr "Vim açık kaynaklıdır ve özgürce dağıtılabilir"
+msgid "type :help<Enter> for help "
+msgstr "yardım için :help<Enter> "
msgid "Help poor children in Uganda!"
msgstr "Uganda'daki yoksul çocuklara yardım edin!"
msgid "type :help iccf<Enter> for information "
-msgstr "ek bilgi için :help iccf<Enter> "
-
-msgid "type :q<Enter> to exit "
-msgstr "çıkmak için :q<Enter> "
-
-msgid "type :help<Enter> or <F1> for on-line help"
-msgstr "yardım belgeleri için :help<Enter> veya <F1> "
-
-msgid "type :help version8<Enter> for version info"
-msgstr "sürüm bilgisi için :help version8<Enter> "
-
-msgid "Running in Vi compatible mode"
-msgstr "Vi uyumlu kipte çalışıyor"
-
-msgid "type :set nocp<Enter> for Vim defaults"
-msgstr "öntanımlı ayarlar için :set nocp<Enter> "
-
-msgid "type :help cp-default<Enter> for info on this"
-msgstr "ek bilgi için :help cp-default<Enter>"
-
-msgid "menu Help->Orphans for information "
-msgstr "bilgi için menü -> Yardım -> Yetimler"
-
-msgid "Running modeless, typed text is inserted"
-msgstr "Kipsiz çalışıyor, girilen metin doğrudan eklenir"
-
-msgid "menu Edit->Global Settings->Toggle Insert Mode "
-msgstr "menü -> Düzen -> Genel Ayarlar -> Ekleme Kipine Geç"
-
-msgid " for two modes "
-msgstr " iki kip için "
-
-msgid "menu Edit->Global Settings->Toggle Vi Compatible"
-msgstr "menü -> Düzen -> Genel Ayarlar -> Vi Uyumlu Kipi Aç/Kapat"
-
-msgid " for Vim defaults "
-msgstr " Vim öntanımlıları için "
+msgstr "ek bilgi için :help iccf<Enter> "
msgid "Sponsor Vim development!"
msgstr "Vim'in geliştirilmesine sponsor olun!"
@@ -6350,3303 +5690,200 @@ msgid "Become a registered Vim user!"
msgstr "Kayıtlı bir Vim kullanıcısı olun!"
msgid "type :help sponsor<Enter> for information "
-msgstr "bilgi için :help sponsor<Enter> "
+msgstr "bilgi için :help sponsor<Enter> "
msgid "type :help register<Enter> for information "
-msgstr "bilgi için :help register<Enter> "
+msgstr "bilgi için :help register<Enter> "
msgid "menu Help->Sponsor/Register for information "
-msgstr "bilgi için Yardım -> Sponsorluk/Kayıt"
-
-msgid "[end of lines]"
-msgstr "[satırların sonu]"
-
-msgid "global"
-msgstr "global"
-
-msgid "buffer"
-msgstr "arabellek"
-
-msgid "window"
-msgstr "pencere"
-
-msgid "tab"
-msgstr "sekme"
-
-msgid ""
-"\n"
-"# Buffer list:\n"
-msgstr ""
-"\n"
-"# Arabellek listesi:\n"
-
-#, c-format
-msgid ""
-"\n"
-"# %s History (newest to oldest):\n"
-msgstr ""
-"\n"
-"# %s Geçmişi (yeniden eskiye):\n"
-
-msgid "Command Line"
-msgstr "Komut Satırı"
-
-msgid "Search String"
-msgstr "Arama Dizisi"
-
-msgid "Expression"
-msgstr "İfade"
-
-msgid "Input Line"
-msgstr "Girdi Satırı"
-
-msgid "Debug Line"
-msgstr "Hata Ayıklama Satırı"
-
-msgid ""
-"\n"
-"# Bar lines, copied verbatim:\n"
-msgstr ""
-"\n"
-"# Tam sureti kopyalanan | satırları:\n"
-
-#, c-format
-msgid "%sviminfo: %s in line: "
-msgstr "%sviminfo: satırdaki %s: "
-
-msgid "E136: viminfo: Too many errors, skipping rest of file"
-msgstr "E136: viminfo: Çok fazla hata, dosyanın geri kalanı atlanıyor"
-
-msgid ""
-"\n"
-"# global variables:\n"
-msgstr ""
-"\n"
-"# global değişkenler:\n"
-
-msgid ""
-"\n"
-"# Last Substitute String:\n"
-"$"
-msgstr ""
-"\n"
-"# Son Değiştirilen Dizi:\n"
-"$"
-
-#, c-format
-msgid ""
-"\n"
-"# Last %sSearch Pattern:\n"
-"~"
-msgstr ""
-"\n"
-"# Son %sArama Dizgileri:\n"
-"~"
-
-msgid "Substitute "
-msgstr "Şunu değiştir: "
-
-msgid "Illegal register name"
-msgstr "İzin verilmeyen yazmaç adı"
-
-msgid ""
-"\n"
-"# Registers:\n"
-msgstr ""
-"\n"
-"# Yazmaçlar:\n"
-
-#, c-format
-msgid "E574: Unknown register type %d"
-msgstr "E574: Bilinmeyen yazmaç türü %d"
-
-msgid ""
-"\n"
-"# History of marks within files (newest to oldest):\n"
-msgstr ""
-"\n"
-"# Dosyalardaki imlerin geçmişi (yeniden eskiye):\n"
-
-msgid ""
-"\n"
-"# File marks:\n"
-msgstr ""
-"\n"
-"# Dosya imleri:\n"
-
-msgid ""
-"\n"
-"# Jumplist (newest first):\n"
-msgstr ""
-"\n"
-"# Atlama listesi (önce en yeniler):\n"
-
-msgid "Missing '>'"
-msgstr "'>' eksik"
-
-msgid "Illegal starting char"
-msgstr "İzin verilmeyen başlangıç karakteri"
-
-#, c-format
-msgid "# This viminfo file was generated by Vim %s.\n"
-msgstr "# Bu viminfo dosyası Vim %s tarafından oluşturulmuştur.\n"
-
-msgid ""
-"# You may edit it if you're careful!\n"
-"\n"
-msgstr ""
-"# Yapabileceğinizi düşünüyorsanız bu dosyayı düzenleyebilirsiniz!\n"
-"\n"
-
-msgid "# Value of 'encoding' when this file was written\n"
-msgstr "# Bu dosya yazıldığı sırada mevcut 'encoding'in değeri\n"
-
-#, c-format
-msgid "Reading viminfo file \"%s\"%s%s%s%s"
-msgstr "\"%s\" viminfo dosyası okunuyor...%s%s%s%s"
-
-msgid " info"
-msgstr " bilgiler-"
-
-msgid " marks"
-msgstr " imler-"
-
-msgid " oldfiles"
-msgstr " düzenleme geçmişi"
-
-msgid " FAILED"
-msgstr " BAŞARISIZ"
-
-#, c-format
-msgid "E137: Viminfo file is not writable: %s"
-msgstr "E137: Viminfo dosyası yazılabilir değil: %s"
-
-#, c-format
-msgid "E929: Too many viminfo temp files, like %s!"
-msgstr "E929: Çok fazla viminfo geçici dosyası, örneğin %s!"
-
-#, c-format
-msgid "E138: Can't write viminfo file %s!"
-msgstr "E138: viminfo dosyası %s yazılamıyor!"
-
-#, c-format
-msgid "Writing viminfo file \"%s\""
-msgstr "viminfo dosyası \"%s\" yazılıyor"
-
-#, c-format
-msgid "E886: Can't rename viminfo file to %s!"
-msgstr "E886: viminfo dosyasının adı %s olarak değiştirilemiyor!"
-
-msgid "E195: Cannot open viminfo file for reading"
-msgstr "E195: viminfo dosyası okuma için açılamıyor"
-
-msgid "Already only one window"
-msgstr "Zaten tek pencere"
-
-#, c-format
-msgid "E92: Buffer %ld not found"
-msgstr "E92: Arabellek %ld bulunamadı"
-
-msgid "E441: There is no preview window"
-msgstr "E441: Önizleme penceresi yok"
-
-msgid "E242: Can't split a window while closing another"
-msgstr "E242: Bir başka pencere kapatılırken pencere bölünemez"
-
-msgid "E442: Can't split topleft and botright at the same time"
-msgstr "E442: Üst sol ve alt sağ pencereler aynı anda bölünemez"
-
-msgid "E443: Cannot rotate when another window is split"
-msgstr "E443: Başka bir pencere bölünmüşken döndürme yapılamaz"
-
-msgid "E444: Cannot close last window"
-msgstr "E444: Son pencere kapatılamıyor"
-
-msgid "E814: Cannot close window, only autocmd window would remain"
-msgstr "E814: Pencere kapatılamıyor, yalnızca otokomut penceresi açık kalır"
-
-msgid "E445: Other window contains changes"
-msgstr "E445: Diğer pencerede değişiklikler var"
-
-msgid "E366: Not allowed to enter a popup window"
-msgstr "E366: Bir açılır pencereye girişe izin verilmiyor"
-
-#, c-format
-msgid "E370: Could not load library %s"
-msgstr "E370: %s kitaplığı yüklenemedi"
-
-msgid "Sorry, this command is disabled: the Perl library could not be loaded."
-msgstr "Üzgünüm, bu komut etkin değil: Perl kitaplığı yüklenemedi."
-
-msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
-msgstr ""
-"E299: Güvenli modül olmadan kum havuzu içinde Perl değerlendirmesine izin "
-"verilmiyor"
-
-msgid "Edit with &multiple Vims"
-msgstr "Birden &fazla Vim ile düzenle"
-
-msgid "Edit with single &Vim"
-msgstr "Tek bir &Vim ile düzenle"
-
-msgid "Diff with Vim"
-msgstr "Vim kullanarak karşılaştır"
-
-msgid "Edit with &Vim"
-msgstr "&Vim ile düzenle"
-
-msgid "Edit with existing Vim"
-msgstr "Mevcut Vim ile düzenle"
-
-msgid "Edit with existing Vim - "
-msgstr "Mevcut Vim ile düzenle - "
-
-msgid "Edits the selected file(s) with Vim"
-msgstr "Seçili dosyaları Vim ile düzenler"
-
-msgid "Error creating process: Check if gvim is in your path!"
-msgstr "İşlem oluşturulurken hata: gvim'in yol üzerinde olduğundan emin olun!"
-
-msgid "gvimext.dll error"
-msgstr "gvimext.dll hatası"
-
-msgid "Path length too long!"
-msgstr "Yol çok uzun!"
-
-msgid "E10: \\ should be followed by /, ? or &"
-msgstr "E10: \\ sonrasında /, ? veya & gelmeli"
-
-msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
-msgstr "E11: Komut satırı penceresinde geçersiz; <CR> çalıştırır, CTRL-C çıkar"
-
-msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
-msgstr ""
-"E12: Geçerli dizin veya etiket aramasında exrc veya vimrc'den komutlara izin "
-"verilmiyor"
-
-msgid "E13: File exists (add ! to override)"
-msgstr "E13: Dosya mevcut (geçersiz kılmak için ! ekleyin)"
-
-#, c-format
-msgid "E15: Invalid expression: \"%s\""
-msgstr "E15: Geçersiz ifade: \"%s\""
-
-msgid "E16: Invalid range"
-msgstr "E16: Geçersiz erim"
-
-#, c-format
-msgid "E17: \"%s\" is a directory"
-msgstr "E17: \"%s\" bir dizin"
-
-msgid "E18: Unexpected characters in :let"
-msgstr "E18: :let içinde beklenmeyen karakter"
-
-msgid "E18: Unexpected characters in assignment"
-msgstr "E18: Atama içerisinde beklenmedik karakterler"
-
-msgid "E19: Mark has invalid line number"
-msgstr "E19: İm satır numarası geçersiz"
-
-msgid "E20: Mark not set"
-msgstr "E20: İm ayarlanmamış"
-
-msgid "E21: Cannot make changes, 'modifiable' is off"
-msgstr "E21: Değişiklik yapılamıyor, 'modifiable' kapalı"
-
-msgid "E22: Scripts nested too deep"
-msgstr "E22: Betikler çok iç içe geçmiş"
-
-msgid "E23: No alternate file"
-msgstr "E23: Başka bir dosya yok"
-
-msgid "E24: No such abbreviation"
-msgstr "E24: Böyle bir kısaltma yok"
-
-#, c-format
-msgid "E121: Undefined variable: %s"
-msgstr "E121: Tanımlanmamış değişken: %s"
-
-#, c-format
-msgid "E121: Undefined variable: %c:%s"
-msgstr "E121: Tanımlanmamış değişken: %c:%s"
-
-msgid "E464: Ambiguous use of user-defined command"
-msgstr "E464: Kullanıcı tanımlı komutun belirsiz kullanımı"
-
-msgid "E476: Invalid command"
-msgstr "E476: Geçersiz komut"
-
-#, c-format
-msgid "E476: Invalid command: %s"
-msgstr "E476: Geçersiz komut: %s"
-
-msgid "E710: List value has more items than targets"
-msgstr "E710: Liste değeri hedeften daha fazla ögeye sahip"
-
-msgid "E711: List value does not have enough items"
-msgstr "E711: Liste değeri yeterli ögeye sahip değil"
-
-msgid "E719: Cannot slice a Dictionary"
-msgstr "E719: Bir Sözlük dilimlenemiyor"
-
-msgid ""
-"E856: \"assert_fails()\" second argument must be a string or a list with one "
-"or two strings"
-msgstr ""
-"E856: \"assert_fails()\" ikinci argüman bir dizi veya bir veya iki dizili "
-"bir liste olmalıdır"
-
-#, c-format
-msgid "E908: using an invalid value as a String: %s"
-msgstr "E908: Geçersiz bir değer bir Dizi yerine kullanılıyor: %s"
-
-msgid "E909: Cannot index a special variable"
-msgstr "E909: Özel bir değişken dizinlenemiyor"
-
-#, c-format
-msgid "E1100: Command not supported in Vim9 script (missing :var?): %s"
-msgstr "E1100: Komut Vim9 betiğinde desteklenmiyor (:var? eksik): %s"
-
-#, c-format
-msgid "E1001: Variable not found: %s"
-msgstr "E1001: Değişken bulunamadı: %s"
-
-#, c-format
-msgid "E1002: Syntax error at %s"
-msgstr "E1002: %s konumunda sözdizim hatası"
-
-msgid "E1003: Missing return value"
-msgstr "E1003: Dönüş değeri eksik"
-
-#, c-format
-msgid "E1004: White space required before and after '%s' at \"%s\""
-msgstr "E1004: Şu konumda '%s' öncesinde ve sonrasında boşluk gerekiyor: \"%s\""
-
-msgid "E1005: Too many argument types"
-msgstr "E1005: Çok fazla argüman türü"
-
-#, c-format
-msgid "E1006: %s is used as an argument"
-msgstr "E1006: %s bir argüman olarak kullanılıyor"
-
-msgid "E1007: Mandatory argument after optional argument"
-msgstr "E1007: İsteğe bağlı argüman sonrasında zorunlu argüman"
-
-msgid "E1008: Missing <type>"
-msgstr "E1008: <tür> eksik"
-
-msgid "E1009: Missing > after type"
-msgstr "E1009: Tür sonrasında > eksik"
-
-#, c-format
-msgid "E1010: Type not recognized: %s"
-msgstr "E1010: Tür tanımlanamadı: %s"
-
-#, c-format
-msgid "E1011: Name too long: %s"
-msgstr "E1011: Ad çok uzun: %s"
-
-#, c-format
-msgid "E1012: Type mismatch; expected %s but got %s"
-msgstr "E1012: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
-
-#, c-format
-msgid "E1013: Argument %d: type mismatch, expected %s but got %s"
-msgstr "E1013: %d argümanı: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
-
-#, c-format
-msgid "E1014: Invalid key: %s"
-msgstr "E1014: Geçersiz anahtar: %s"
-
-#, c-format
-msgid "E1015: Name expected: %s"
-msgstr "E1015: Ad bekleniyordu: %s"
-
-#, c-format
-msgid "E1016: Cannot declare a %s variable: %s"
-msgstr "E1016: Bir %s değişkeni tanımlanamıyor: %s"
-
-#, c-format
-msgid "E1016: Cannot declare an environment variable: %s"
-msgstr "E1016: Bir ortam değişkeni tanımlanamıyor: %s"
-
-#, c-format
-msgid "E1017: Variable already declared: %s"
-msgstr "E1017: Değişken halihazırda tanımlanmış: %s"
-
-#, c-format
-msgid "E1018: Cannot assign to a constant: %s"
-msgstr "E1018: Bir sabite atanamıyor: %s"
-
-msgid "E1019: Can only concatenate to string"
-msgstr "E1019: Yalnızca bir diziye birleştirilebilir"
+msgstr "bilgi için Yardım -> Sponsorluk/Kayıt"
#, c-format
-msgid "E1020: Cannot use an operator on a new variable: %s"
-msgstr "E1020: Yeni bir değişken üzerinde bir işleç kullanılamaz: %s"
-
-msgid "E1021: Const requires a value"
-msgstr "E1021: Sabit, bir değer gerektirir"
-
-msgid "E1022: Type or initialization required"
-msgstr "E1022: Tür veya ilklendirme gerekiyor"
+msgid "E15: Invalid control character present in input: %.*s"
+msgstr "E15: Girdide geçersiz denetim karakteri var: %.*s"
#, c-format
-msgid "E1023: Using a Number as a Bool: %lld"
-msgstr "E1023: Bir Sayı, bir Boole yerine kullanılıyor: %lld"
-
-msgid "E1024: Using a Number as a String"
-msgstr "E1024: Bir Sayı, bir Dizi yerine kullanılıyor"
-
-msgid "E1025: Using } outside of a block scope"
-msgstr "E1025: } bir blok kapsamı dışında kullanılıyor"
-
-msgid "E1026: Missing }"
-msgstr "E1026: } eksik"
-
-msgid "E1027: Missing return statement"
-msgstr "E1027: Dönüş ifadesi eksik"
-
-msgid "E1028: Compiling :def function failed"
-msgstr "E1028: :def işlevi derleme başarısız"
+msgid "E112: Option name missing: %.*s"
+msgstr "E112: Seçenek adı eksik: %.*s"
#, c-format
-msgid "E1029: Expected %s but got %s"
-msgstr "E1029: %s bekleniyordu ancak %s alındı"
+msgid "E15: Unexpected EOC character: %.*s"
+msgstr "E15: Beklenmedik EOC karakteri: %.*s"
#, c-format
-msgid "E1030: Using a String as a Number: \"%s\""
-msgstr "E1030: Bir Dizi, bir Sayı yerine kullanılıyor: \"%s\""
-
-msgid "E1031: Cannot use void value"
-msgstr "E1031: Boş değer kullanılamaz"
-
-msgid "E1032: Missing :catch or :finally"
-msgstr "E1032: :catch veya :finally eksik"
-
-msgid "E1033: Catch unreachable after catch-all"
-msgstr "E1033: catch-all sonrası catch ulaşılamıyor"
+msgid "E15: Unidentified character: %.*s"
+msgstr "E15: Tanımlanmamış karakter: %.*s"
#, c-format
-msgid "E1034: Cannot use reserved name %s"
-msgstr "E1034: Ayrılmış ad %s kullanılamaz"
-
-msgid "E1035: % requires number arguments"
-msgstr "E1035: %, sayı argümanları gerektirir"
+msgid "E15: Operator is not associative: %.*s"
+msgstr "E15: İşleç, çağrışımsal değil: %.*s"
#, c-format
-msgid "E1036: %c requires number or float arguments"
-msgstr "E1036: %c, sayı veya kayan noktalı değer argümanları gerektirir"
+msgid "E15: Missing operator: %.*s"
+msgstr "E15: İşleç eksik: %.*s"
#, c-format
-msgid "E1037: Cannot use \"%s\" with %s"
-msgstr "E1037: \"%s\", %s ile birlikte kullanılamaz"
-
-msgid "E1038: \"vim9script\" can only be used in a script"
-msgstr "E1038: \"vim9script\" yalnızca bir betikte kullanılabilir"
-
-msgid "E1039: \"vim9script\" must be the first command in a script"
-msgstr "E1039: \"vim9script\" bir betikteki ilk komut olmalıdır"
-
-msgid "E1040: Cannot use :scriptversion after :vim9script"
-msgstr "E1040: :vim9script sonrası :scriptversion kullanılamaz"
+msgid "E15: Expected lambda arguments list or arrow: %.*s"
+msgstr "E15: Lambda argümanlar listesi veya ok bekleniyordu: %.*s"
#, c-format
-msgid "E1041: Redefining script item %s"
-msgstr "E1041: Betik ögesi %s yeniden tanımlanıyor"
-
-msgid "E1042: Export can only be used in vim9script"
-msgstr "E1042: Dışa aktarım yalnızca vim9script içinde kullanılabilir"
-
-msgid "E1043: Invalid command after :export"
-msgstr "E1043: :export sonrası geçersiz komut"
-
-msgid "E1044: Export with invalid argument"
-msgstr "E1044: Geçersiz argümanla dışa aktarım"
-
-msgid "E1045: Missing \"as\" after *"
-msgstr "E1045: * sonrası \"as\" eksik"
-
-msgid "E1046: Missing comma in import"
-msgstr "E1046: İçe aktarımda virgül eksik"
-
-msgid "E1047: Syntax error in import"
-msgstr "E1047: İçe aktarımda sözdizim hatası"
-
-#, c-format
-msgid "E1048: Item not found in script: %s"
-msgstr "E1048: Betikte öge bulunamadı: %s"
-
-#, c-format
-msgid "E1049: Item not exported in script: %s"
-msgstr "E1049: Betikte öge dışa aktarılmadı: %s"
-
-#, c-format
-msgid "E1050: Colon required before a range: %s"
-msgstr "E1050: Bir erim öncesi iki nokta gerekiyor: %s"
-
-msgid "E1051: Wrong argument type for +"
-msgstr "E1051: + için hatalı argüman türü"
-
-#, c-format
-msgid "E1052: Cannot declare an option: %s"
-msgstr "E1052: Bir seçenek tanımlanamıyor: %s"
-
-#, c-format
-msgid "E1053: Could not import \"%s\""
-msgstr "E1053: \"%s\" içe aktarılamadı"
-
-#, c-format
-msgid "E1054: Variable already declared in the script: %s"
-msgstr "E1054: Betikte değişken halihazırda tanımlanmış: %s"
-
-msgid "E1055: Missing name after ..."
-msgstr "E1055: ... sonraki ad eksik"
-
-#, c-format
-msgid "E1056: Expected a type: %s"
-msgstr "E1056: Bir tür bekleniyordu: %s"
-
-msgid "E1057: Missing :enddef"
-msgstr "E1057: :enddef eksik"
-
-msgid "E1058: Function nesting too deep"
-msgstr "E1058: İşlev çok iç içe geçmiş"
+msgid "E15: Expected value part of assignment lvalue: %.*s"
+msgstr "E15: lvalue ataması değer kısmı bekleniyordu: %.*s"
#, c-format
-msgid "E1059: No white space allowed before colon: %s"
-msgstr "E1059: İki nokta öncesinde boşluğa izin verilmiyor: %s"
+msgid "E15: Expected assignment operator or subscript: %.*s"
+msgstr "E15: Atama işleci veya alt simgesi bekleniyordu: %.*s"
-#, c-format
-msgid "E1060: Expected dot after name: %s"
-msgstr "E1060: Ad sonrası nokta bekleniyordu: %s"
+msgid "E15: Unexpected "
+msgstr "E15: Beklenmedik "
#, c-format
-msgid "E1061: Cannot find function %s"
-msgstr "E1061: %s işlevi bulunamıyor"
-
-msgid "E1062: Cannot index a Number"
-msgstr "E1062: Bir Sayı dizinlenemiyor"
+msgid "E15: Unexpected multiplication-like operator: %.*s"
+msgstr "E15: Beklenmedik çarpma benzeri işleç: %.*s"
-msgid "E1063: Type mismatch for v: variable"
-msgstr "E1063: v: değişkeni için tür uyumsuzluğu"
+msgid "E15: Environment variable name missing"
+msgstr "E15: Çevre değişkeni adı eksik"
#, c-format
-msgid "E1066: Cannot declare a register: %s"
-msgstr "E1066: Bir yazmaç tanımlanamıyor: %s"
+msgid "E15: Expected value, got comparison operator: %.*s"
+msgstr "E15: Değer bekleniyordu, karşılaştırma işleci alındı: %.*s"
#, c-format
-msgid "E1067: Separator mismatch: %s"
-msgstr "E1067: Ayırıcı uyumsuzluğu: %s"
+msgid "E15: Expected value, got comma: %.*s"
+msgstr "E15: Değer bekleniyordu, virgül alındı: %.*s"
#, c-format
-msgid "E1068: No white space allowed before '%s': %s"
-msgstr "E1068: '%s' önce boşluğa izin verilmiyor: %s"
+msgid "E15: Comma outside of call, lambda or literal: %.*s"
+msgstr "E15: Çağrı, lambda veya düz veri dışı virgül: %.*s"
#, c-format
-msgid "E1069: White space required after '%s': %s"
-msgstr "E1069: '%s' sonrası boşluk gerekiyor: %s"
-
-msgid "E1070: Missing \"from\""
-msgstr "E1070: \"from\" eksik"
-
-msgid "E1071: Invalid string after \"from\""
-msgstr "E1071: \"from\" sonrası geçersiz dizi"
+msgid "E15: Colon outside of dictionary or ternary operator: %.*s"
+msgstr "E15: Sözlük veya üç terimli işlec dışı iki nokta: %.*s"
#, c-format
-msgid "E1072: Cannot compare %s with %s"
-msgstr "E1072: %s, %s ile karşılaştırılamıyor"
+msgid "E15: Expected value, got closing bracket: %.*s"
+msgstr "E15: Değer bekleniyordu, kapatma ayracı alındı: %.*s"
#, c-format
-msgid "E1073: Name already defined: %s"
-msgstr "E1073: Ad halihazırda tanımlanmış: %s"
-
-msgid "E1074: No white space allowed after dot"
-msgstr "E1074: Nokta sonrası boşluğa izin verilmiyor"
+msgid "E475: Unable to assign to empty list: %.*s"
+msgstr "E475: Boş listeye atanamadı: %.*s"
#, c-format
-msgid "E1075: Namespace not supported: %s"
-msgstr "E1075: Ad alanı desteklenmiyor: %s"
-
-msgid "E1076: This Vim is not compiled with float support"
-msgstr "E1076: Bu Vim kayan noktalı değer desteği ile derlenmemiş"
+msgid "E15: Unexpected closing figure brace: %.*s"
+msgstr "E15: Beklenmedik kapatma kıvrımlı ayracı: %.*s"
#, c-format
-msgid "E1077: Missing argument type for %s"
-msgstr "E1077: %s için argüman türü eksik"
+msgid "E475: Nested lists not allowed when assigning: %.*s"
+msgstr "E475: Atama sırasında iç içe geçmiş listelere izin verilmez: %.*s"
#, c-format
-msgid "E1081: Cannot unlet %s"
-msgstr "E1081: %s sabitten değişkene çevrilemiyor"
+msgid "E15: Expected value, got closing figure brace: %.*s"
+msgstr "E15: Değer bekleniyordu, kapatma kıvrımlı ayracı alındı: %.*s"
#, c-format
-msgid "E1082: Cannot use a namespaced variable: %s"
-msgstr "E1082: Ad alanına alınmış bir değişken kullanılamaz: %s"
-
-msgid "E1083: Missing backtick"
-msgstr "E1083: Ters eğik kesme imi eksik"
+msgid "E15: Don't know what figure brace means: %.*s"
+msgstr "E15: Kıvrımlı ayracın ne anlama geldiği bilinmiyor: %.*s"
#, c-format
-msgid "E1084: Cannot delete Vim9 script function %s"
-msgstr "E1084: Vim9 betik işlevi %s silinemiyor"
+msgid "E15: Unexpected arrow: %.*s"
+msgstr "E15: Beklenmedik ok: %.*s"
#, c-format
-msgid "E1085: Not a callable type: %s"
-msgstr "E1085: Çağrılabilir bir tür değil: %s"
-
-msgid "E1086: Cannot use :function inside :def"
-msgstr "E1086: :def içinde :function kullanılamaz"
-
-msgid "E1087: Cannot use an index when declaring a variable"
-msgstr "E1087: Bir değişken tanımlarken dizinleme kullanılamaz"
+msgid "E15: Arrow outside of lambda: %.*s"
+msgstr "E15: Ok, lambda dışında: %.*s"
#, c-format
-msgid "E1089: Unknown variable: %s"
-msgstr "E1089: Bilinmeyen değişken: %s"
+msgid "E15: Unexpected dot: %.*s"
+msgstr "E15: Beklenmedik nokta: %.*s"
#, c-format
-msgid "E1090: Cannot assign to argument %s"
-msgstr "E1090: %s argümanına atanamıyor"
+msgid "E15: Cannot concatenate in assignments: %.*s"
+msgstr "E15: Atamalarda uç uca eklenemiyor: %.*s"
#, c-format
-msgid "E1091: Function is not compiled: %s"
-msgstr "E1091: İşlev derlenmemiş: %s"
-
-msgid "E1092: Cannot use a list for a declaration"
-msgstr "E1092: Tanımlama için bir liste kullanılamaz"
+msgid "E15: Expected value, got parenthesis: %.*s"
+msgstr "E15: Değer bekleniyordu, ayraç alındı: %.*s"
#, c-format
-msgid "E1093: Expected %d items but got %d"
-msgstr "E1093: %d öge bekleniyordu, ancak %d alındı"
-
-msgid "E1094: Import can only be used in a script"
-msgstr "E1094: İçe aktarım yalnızca bir betikte kullanılabilir"
-
-msgid "E1095: Unreachable code after :return"
-msgstr "E1095: :return sonrası ulaşılamayan kod"
-
-msgid "E1096: Returning a value in a function without a return type"
-msgstr "E1096: Dönüş türü olmayan bir işlevde bir değer döndürülüyor"
-
-msgid "E1097: Line incomplete"
-msgstr "E1097: Satır tamamlanmamış"
+msgid "E15: Unexpected closing parenthesis: %.*s"
+msgstr "E15: Beklenmedik kapatma ayracı: %.*s"
#, c-format
-msgid "E1099: Unknown error while executing %s"
-msgstr "E1099: %s çalıştırılırken bilinmeyen hata"
+msgid "E15: Expected value, got question mark: %.*s"
+msgstr "E15: Değer bekleniyordu, soru imi alındı: %.*s"
#, c-format
-msgid "E1101: Cannot declare a script variable in a function: %s"
-msgstr "E1101: Bir işlevde bir betik değişkeni tanımlanamıyor: %s"
+msgid "E114: Missing double quote: %.*s"
+msgstr "E114: Çift tırnak eksik: %.*s"
#, c-format
-msgid "E1102: Lambda function not found: %s"
-msgstr "E1102: Lambda işlevi bulunamadı: %s"
-
-msgid "E1103: Dictionary not set"
-msgstr "E1103: Sözlük ayarlanmamış"
-
-msgid "E1104: Missing >"
-msgstr "E1104: > eksik"
+msgid "E115: Missing single quote: %.*s"
+msgstr "E115: Tek tırnak eksik: %.*s"
#, c-format
-msgid "E1105: Cannot convert %s to string"
-msgstr "E1105: %s bir diziye dönüştürülemiyor"
-
-msgid "E1106: One argument too many"
-msgstr "E1106: Bir argüman fazladan"
+msgid "E475: Expected closing bracket to end list assignment lvalue: %.*s"
+msgstr "E475: lvalue liste sonu atamasına kapatma ayracı bekleniyordu: %.*s"
#, c-format
-msgid "E1106: %d arguments too many"
-msgstr "E1106: %d argüman fazladan"
-
-msgid "E1107: String, List, Dict or Blob required"
-msgstr "E1107: Dizi, Liste, Sözlük veya İkili Nesne gerekiyor"
+msgid "E15: Misplaced assignment: %.*s"
+msgstr "E15: Yanlış konumlandırılmış atama: %.*s"
#, c-format
-msgid "E1108: Item not found: %s"
-msgstr "E1108: Öge bulunamadı: %s"
+msgid "E15: Unexpected assignment: %.*s"
+msgstr "E15: Beklenmedik atama: %.*s"
#, c-format
-msgid "E1109: List item %d is not a List"
-msgstr "E1109: Liste ögesi %d bir Liste değil"
+msgid "E15: Expected value, got EOC: %.*s"
+msgstr "E15: Değer bekleniyordu, EOC alındı: %.*s"
#, c-format
-msgid "E1110: List item %d does not contain 3 numbers"
-msgstr "E1110: Liste ögesi %d 3 sayı içermiyor"
+msgid "E116: Missing closing parenthesis for function call: %.*s"
+msgstr "E116: İşlev çağrısı için geçersiz kapatma ayracı: %.*s"
#, c-format
-msgid "E1111: List item %d range invalid"
-msgstr "E1111: Liste ögesi %d erimi geçersiz"
+msgid "E110: Missing closing parenthesis for nested expression: %.*s"
+msgstr "E110: İç içe geçmiş ifade için kapatma ayracı eksik: %.*s"
#, c-format
-msgid "E1112: List item %d cell width invalid"
-msgstr "E1112: Liste ögesi %d hücre genişliği geçersiz"
+msgid "E697: Missing end of List ']': %.*s"
+msgstr "E697: Liste sonunda ']' eksik: %.*s"
#, c-format
-msgid "E1113: Overlapping ranges for 0x%lx"
-msgstr "E1113: 0x%lx için üst üste binen erimler"
-
-msgid "E1114: Only values of 0x100 and higher supported"
-msgstr "E1114: Yalnızca 0x100 ve daha yüksek değerler destekleniyor"
-
-msgid "E1115: \"assert_fails()\" fourth argument must be a number"
-msgstr "E1115: \"assert_fails()\" dördüncü argüman bir sayı olmalıdır"
-
-msgid "E1116: \"assert_fails()\" fifth argument must be a string"
-msgstr "E1116: \"assert_fails()\" beşinci argüman bir dizi olmalıdır"
-
-msgid "E1117: Cannot use ! with nested :def"
-msgstr "E1117: !, iç içe geçmiş :def ile kullanılamaz"
-
-msgid "E1118: Cannot change list"
-msgstr "E1118: Liste değiştirilemez"
-
-msgid "E1119: Cannot change list item"
-msgstr "E1119: Liste ögesi değiştirilemez"
-
-msgid "E1120: Cannot change dict"
-msgstr "E1120: Sözlük değiştirilemez"
-
-msgid "E1121: Cannot change dict item"
-msgstr "E1121: Sözlük ögesi değiştirilemez"
+msgid "E723: Missing end of Dictionary '}': %.*s"
+msgstr "E723: Sözlük sonu '}' eksik: %.*s"
#, c-format
-msgid "E1122: Variable is locked: %s"
-msgstr "E1122: Değişken kilitli: %s"
+msgid "E15: Missing closing figure brace: %.*s"
+msgstr "E15: Kapatma kıvrımlı ayracı eksik: %.*s"
#, c-format
-msgid "E1123: Missing comma before argument: %s"
-msgstr "E1123: Değişken öncesi virgül eksik: %s"
+msgid "E15: Missing closing figure brace for lambda: %.*s"
+msgstr "E15: Lambda için kapatma kıvrımlı ayracı eksik: %.*s"
#, c-format
-msgid "E1124: \"%s\" cannot be used in legacy Vim script"
-msgstr "E1124: \"%s\" yalnızca eski Vim betiklerinde kullanılabilir"
-
-msgid "E1125: Final requires a value"
-msgstr "E1125: Final, bir değer gerektirir"
-
-msgid "E1126: Cannot use :let in Vim9 script"
-msgstr "E1126: :let, Vim9 betiğinde kullanılamaz"
-
-msgid "E1127: Missing name after dot"
-msgstr "E1127: Nokta sonrası ad eksik"
-
-msgid "E1128: } without {"
-msgstr "E1128: { olmadan }"
-
-msgid "E1129: Throw with empty string"
-msgstr "E1129: Boş dizi ile \"Throw\""
-
-msgid "E1130: Cannot add to null list"
-msgstr "E1130: Null listesine bir öge eklenemez"
-
-msgid "E1131: Cannot add to null blob"
-msgstr "E1131: Null ikili geniş nesnesine ekleme yapılamaz"
-
-msgid "E1132: Missing function argument"
-msgstr "E1132: İşlev argümanı eksik"
-
-msgid "E1133: Cannot extend a null dict"
-msgstr "E1133: Bir null sözlük genişletilemez"
-
-msgid "E1134: Cannot extend a null list"
-msgstr "E1134: Bir null listesi genişletilemez"
+msgid "E109: Missing ':' after '?': %.*s"
+msgstr "E109: '?' sonrası ':' eksik: %.*s"
-#, c-format
-msgid "E1135: Using a String as a Bool: \"%s\""
-msgstr "E1135: Bir Dizi, bir Boole yerine kullanılıyor: \"%s\""
-
-msgid "E1135: <Cmd> mapping must end with <CR>"
-msgstr "E1135: <Cmd> eşlemlemesi <CR> ile bitmelidir"
-
-msgid "E1136: <Cmd> mapping must end with <CR> before second <Cmd>"
-msgstr "E1136: <Cmd> eşlemlemesi ikinci <Cmd>'den önce <CR> ile bitmelidir"
-
-#, c-format
-msgid "E1137: <Cmd> mapping must not include %s key"
-msgstr "E1137: <Cmd> eşlemlemesi %s anahtarını içermemelidir"
-
-msgid "E1138: Using a Bool as a Number"
-msgstr "E1138: Bir Boole, Sayı yerine kullanılıyor"
-
-msgid "E1139: Missing matching bracket after dict key"
-msgstr "E1139: Sözlük anahtarı sonrası eşleşen ayraç eksik"
-
-msgid "E1140: :for argument must be a sequence of lists"
-msgstr "E1140: :for argümanı listelerin bir sıralaması olmalıdır"
-
-msgid "E1141: Indexable type required"
-msgstr "E1141: İndekslenebilir tür gerekiyor"
-
-msgid "E1142: Non-empty string required"
-msgstr "E1142: Boş olmayan dizi gerekiyor"
-
-#, c-format
-msgid "E1143: Empty expression: \"%s\""
-msgstr "E1143: Boş ifade: \"%s\""
-
-#, c-format
-msgid "E1144: Command \"%s\" is not followed by white space: %s"
-msgstr "E1144: \"%s\" komutu sonrasında boşluk gelmiyor: %s"
-
-#, c-format
-msgid "E1145: Missing heredoc end marker: %s"
-msgstr "E1145: Son imleyicisi eksik: %s"
-
-#, c-format
-msgid "E1146: Command not recognized: %s"
-msgstr "E1146: Komut tanınamadı: %s"
-
-msgid "E1147: List not set"
-msgstr "E1147: Liste ayarlanmamış"
-
-#, c-format
-msgid "E1148: Cannot index a %s"
-msgstr "E1148: Bir %s dizinlenemiyor"
-
-#, c-format
-msgid "E1149: Script variable is invalid after reload in function %s"
-msgstr "E1149: %s işlevindeki yeniden yüklemeden sonra betik değişkeni geçersiz"
-
-msgid "E1150: Script variable type changed"
-msgstr "E1150: Betik değişkeni türü değiştirildi"
-
-msgid "E1151: Mismatched endfunction"
-msgstr "E1151: Eşleşmeyen endfunction"
-
-msgid "E1152: Mismatched enddef"
-msgstr "E1152: Eşleşmeyen enddef"
-
-msgid "E1153: Invalid operation for bool"
-msgstr "E1153: Boole için geçersiz işlem"
-
-msgid "E1154: Divide by zero"
-msgstr "E1154: Sıfır ile bölüm"
-
-msgid "E1155: Cannot define autocommands for ALL events"
-msgstr "E1155: Otokomutlar TÜM olaylar için tanımlanamıyor"
-
-msgid "E1156: Cannot change the argument list recursively"
-msgstr "E1156: Değişken listesi özyineli olarak değiştirilemiyor"
-
-msgid "E1157: Missing return type"
-msgstr "E1157: Dönüş türü eksik"
-
-msgid "E1158: Cannot use flatten() in Vim9 script"
-msgstr "E1158: flatten(), Vim9 betiğinde kullanılamaz"
-
-msgid "E1159: Cannot split a window when closing the buffer"
-msgstr "E1159: Arabellek kapatılırken bir pencere bölünemez"
-
-msgid "E1160: Cannot use a default for variable arguments"
-msgstr "E1160: Değişken argümanları için bir öntanımlı kullanılamaz"
-
-#, c-format
-msgid "E1161: Cannot json encode a %s"
-msgstr "E1161: Bir %s JSON olarak kodlanamıyor"
-
-#, c-format
-msgid "E1162: Register name must be one character: %s"
-msgstr "E1162: Yazmaç adı tek bir karakter olmalıdır: %s"
-
-#, c-format
-msgid "E1163: Variable %d: type mismatch, expected %s but got %s"
-msgstr "E1163: %d değişkeni: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
-
-msgid "E1164: vim9cmd must be followed by a command"
-msgstr "E1164: vim9cmd sonrasında bir komut gelmelidir"
-
-#, c-format
-msgid "E1165: Cannot use a range with an assignment: %s"
-msgstr "E1165: Bir atama ile bir erim kullanılamıyor: %s"
-
-msgid "E1166: Cannot use a range with a dictionary"
-msgstr "E1166: Bir sözlük ile bir erim kullanılamıyor"
-
-#, c-format
-msgid "E1167: Argument name shadows existing variable: %s"
-msgstr "E1167: Argüman adı var olan değişkeni gölgeliyor: %s"
-
-#, c-format
-msgid "E1168: Argument already declared in the script: %s"
-msgstr "E1168: Betikte argüman halihazırda tanımlanmış: %s"
-
-msgid "E1169: 'import * as {name}' not supported here"
-msgstr "E1169: 'import * as {name} burada desteklenmiyor"
-
-msgid "E1170: Cannot use #{ to start a comment"
-msgstr "E1170: Bir yorum başlatmak için #{ kullanılamaz"
-
-msgid "E1171: Missing } after inline function"
-msgstr "E1171: Satıriçi işlevden sonra } eksik"
-
-msgid "E1172: Cannot use default values in a lambda"
-msgstr "E1172: Bir lambda içerisinde öntanımlı değerler kullanılamıyor"
-
-#, c-format
-msgid "E1173: Text found after enddef: %s"
-msgstr "E1173: :enddef sonrası metin bulundu: %s"
-
-#, c-format
-msgid "E1174: String required for argument %d"
-msgstr "E1174: %d argümanı için dizi gerekiyor"
-
-#, c-format
-msgid "E1175: Non-empty string required for argument %d"
-msgstr "E1175: %d argümanı için boş olmayan dizi gerekiyor"
-
-msgid "E1176: Misplaced command modifier"
-msgstr "E1176: Yanlış yere konulmuş komut değiştiricisi"
-
-#, c-format
-msgid "E1177: For loop on %s not supported"
-msgstr "E1177: %s üzerinde for döngüsü desteklenmiyor"
-
-msgid "E1178: Cannot lock or unlock a local variable"
-msgstr "E1178: Bir yerel değişken kilitlenemiyor/kilidi açılamıyor"
-
-#, c-format
-msgid ""
-"E1179: Failed to extract PWD from %s, check your shell's config related to "
-"OSC 7"
-msgstr ""
-"E1179: %s içinden PWD çıkarılamadı, kabuğunuzun OSC 7 ile ilgili "
-"yapılandırmasını denetleyin"
-
-#, c-format
-msgid "E1180: Variable arguments type must be a list: %s"
-msgstr "E1180: Değişken argümanları türü bir liste olmalıdır: %s"
-
-msgid "E1181: Cannot use an underscore here"
-msgstr "E1181: Alt çizgi burada kullanılamaz"
-
-msgid "E1182: Blob required"
-msgstr "E1182: İkili geniş nesne gerekiyor"
-
-#, c-format
-msgid "E1183: Cannot use a range with an assignment operator: %s"
-msgstr "E1183: Bir atama işleci ile bir erim kullanılamıyor: %s"
-
-msgid "E1184: Blob not set"
-msgstr "E1184: İkili geniş nesne ayarlanmamış"
-
-msgid "E1185: Cannot nest :redir"
-msgstr "E1185: :redir içe geçirilemiyor"
-
-msgid "E1185: Missing :redir END"
-msgstr "E1185: :redir END eksik"
-
-#, c-format
-msgid "E1186: Expression does not result in a value: %s"
-msgstr "E1186: İfade bir değer sonucu vermiyor: %s"
-
-msgid "E1187: Failed to source defaults.vim"
-msgstr "E1187: defaults.vim kaynaklanamadı"
-
-msgid "E1188: Cannot open a terminal from the command line window"
-msgstr "E1188: Komut satırı penceresinden bir uçbirim açılamıyor"
-
-#, c-format
-msgid "E1189: Cannot use :legacy with this command: %s"
-msgstr "E1189: :legacy, bu komut ile kullanılamıyor: %s"
-
-msgid "E1190: One argument too few"
-msgstr "E1190: Bir argüman daha gerekiyor"
-
-#, c-format
-msgid "E1190: %d arguments too few"
-msgstr "E1190: %d argüman daha gerekiyor"
-
-#, c-format
-msgid "E1191: Call to function that failed to compile: %s"
-msgstr "E1191: Derlenemeyen işlev çağrısı: %s"
-
-msgid "E1192: Empty function name"
-msgstr "E1192: Boş işlev adı"
-
-msgid "E1193: cryptmethod xchacha20 not built into this Vim"
-msgstr "E1193: cryptmethod xchacha20 bu Vim ile kullanılamıyor"
-
-msgid "E1194: Cannot encrypt header, not enough space"
-msgstr "E1194: Üstbilgi şifrelenemiyor, yetersiz alan"
-
-msgid "E1195: Cannot encrypt buffer, not enough space"
-msgstr "E1195: Arabellek şifrelenemiyor, yetersiz alan"
-
-msgid "E1196: Cannot decrypt header, not enough space"
-msgstr "E1196: Üstbilgi şifresi çözülemiyor, yetersiz alan"
-
-msgid "E1197: Cannot allocate_buffer for encryption"
-msgstr "E1197: Şifreleme için allocate_buffer yapılamıyor"
-
-msgid "E1198: Decryption failed: Header incomplete!"
-msgstr "E1198: Şifre çözümü başarısız: Üstbilgi tam değil!"
-
-msgid "E1199: Cannot decrypt buffer, not enough space"
-msgstr "E1199: Arabellek şifresi çözülemiyor, yetersiz alan"
-
-msgid "E1200: Decryption failed!"
-msgstr "E1200: Şifre çözümü başarısız!"
-
-msgid "E1201: Decryption failed: pre-mature end of file!"
-msgstr "E1201: Şifre çözümü başarısız: Beklenmedik dosya sonu!"
-
-#, c-format
-msgid "E1202: No white space allowed after '%s': %s"
-msgstr "E1202: '%s' sonrası boşluğa izin verilmiyor: %s"
-
-#, c-format
-msgid "E1203: Dot can only be used on a dictionary: %s"
-msgstr "E1203: Nokta yalnızca bir sözlükte kullanılabilir: %s"
-
-#, c-format
-msgid "E1204: No Number allowed after .: '\\%%%c'"
-msgstr "E1204: . sonrası Sayıya izin verilmiyor: '\\%%%c'"
-
-msgid "E1205: No white space allowed between option and"
-msgstr "E1205: and seçeneği arasında boşluğa izin verilmiyor"
-
-#, c-format
-msgid "E1206: Dictionary required for argument %d"
-msgstr "E1206: %d argümanı için sözlük gerekiyor"
-
-#, c-format
-msgid "E1207: Expression without an effect: %s"
-msgstr "E1207: Bir efekt olmadan ifade: %s"
-
-msgid "E1208: -complete used without -nargs"
-msgstr "E1208: -complete, -nargs olmadan kullanıldı"
-
-#, c-format
-msgid "E1209: Invalid value for a line number: \"%s\""
-msgstr "E1209: Satır numarası için geçersiz değer: \"%s\""
-
-#, c-format
-msgid "E1210: Number required for argument %d"
-msgstr "E1210: %d argümanı için sayı gerekiyor"
-
-msgid "--No lines in buffer--"
-msgstr "--Arabellek içinde satır yok--"
-
-msgid "E470: Command aborted"
-msgstr "E470: Komut durduruldu"
-
-msgid "E471: Argument required"
-msgstr "E471: Değişken gerekiyor"
-
-msgid "E171: Missing :endif"
-msgstr "E171: :endif eksik"
-
-msgid "E603: :catch without :try"
-msgstr "E603: :try olmadan :catch"
-
-msgid "E606: :finally without :try"
-msgstr "E606: :try olmadan :finally"
-
-msgid "E607: multiple :finally"
-msgstr "E607: Birden fazla :finally"
-
-msgid "E600: Missing :endtry"
-msgstr "E600: :endtry eksik"
-
-msgid "E602: :endtry without :try"
-msgstr "E602: :try olmadan :endtry"
-
-msgid "E170: Missing :endwhile"
-msgstr "E170: :endwhile eksik"
-
-msgid "E170: Missing :endfor"
-msgstr "E170: :endfor eksik"
-
-msgid "E588: :endwhile without :while"
-msgstr "E588: :while olmadan :endwhile"
-
-msgid "E588: :endfor without :for"
-msgstr "E588: :for olmadan :endfor"
-
-msgid "E472: Command failed"
-msgstr "E472: Komut başarısız oldu"
-
-#, c-format
-msgid "E234: Unknown fontset: %s"
-msgstr "E234: Bilinmeyen yazıtipi seti: %s"
-
-#, c-format
-msgid "E235: Unknown font: %s"
-msgstr "E235: Bilinmeyen yazıtipi: %s"
-
-#, c-format
-msgid "E236: Font \"%s\" is not fixed-width"
-msgstr "E236: \"%s\" yazıtipi sabit genişlikli değil"
-
-msgid "E473: Internal error"
-msgstr "E473: İç hata"
-
-#, c-format
-msgid "E685: Internal error: %s"
-msgstr "E685: İç hata: %s"
-
-msgid "Interrupted"
-msgstr "Yarıda kesildi"
-
-msgid "E474: Invalid argument"
-msgstr "E474: Geçersiz argüman"
-
-#, c-format
-msgid "E475: Invalid argument: %s"
-msgstr "E475: Geçersiz argüman: %s"
-
-#, c-format
-msgid "E983: Duplicate argument: %s"
-msgstr "E983: Yinelenen argüman: %s"
-
-#, c-format
-msgid "E475: Invalid value for argument %s"
-msgstr "E475: %s argümanı için geçersiz değer"
-
-#, c-format
-msgid "E475: Invalid value for argument %s: %s"
-msgstr "E475: %s argümanı için geçersiz değer: %s"
-
-msgid "E756: Spell checking is not possible"
-msgstr "E756: Yazım denetimi olanaklı değil"
-
-#, c-format
-msgid "E364: Library call failed for \"%s()\""
-msgstr "E364: \"%s()\" için kitaplık çağrısı başarısız oldu"
-
-msgid "E667: Fsync failed"
-msgstr "E667: Fsync başarısız oldu"
-
-#, c-format
-msgid "E448: Could not load library function %s"
-msgstr "E448: %s kitaplık işlevi yüklenemedi"
-
-msgid "E477: No ! allowed"
-msgstr "E477: ! imine izin verilmiyor"
-
-msgid "E25: GUI cannot be used: Not enabled at compile time"
-msgstr "E25: Grafik arabirim kullanılamaz: Derlenirken etkinleştirilmemiş"
-
-msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
-msgstr "E26: İbranca kullanılamaz: Derlenirken etkinleştirilmemiş\n"
-
-msgid "E27: Farsi support has been removed\n"
-msgstr "E27: Farsça desteği kaldırıldı\n"
-
-msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
-msgstr "E800: Arapça kullanılamaz: Derlenirken etkinleştirilmemiş\n"
-
-#, c-format
-msgid "E28: No such highlight group name: %s"
-msgstr "E28: Böyle bir vurgulama grup adı yok: %s"
-
-msgid "E29: No inserted text yet"
-msgstr "E29: Henüz bir metin eklenmedi"
-
-msgid "E30: No previous command line"
-msgstr "E30: Öncesinde komut satırı yok"
-
-msgid "E31: No such mapping"
-msgstr "E31: Böyle bir eşlem yok"
-
-msgid "E479: No match"
-msgstr "E479: Eşleşme yok"
-
-#, c-format
-msgid "E480: No match: %s"
-msgstr "E480: Eşleşme yok: %s"
-
-msgid "E32: No file name"
-msgstr "E32: Dosya adı yok"
-
-msgid "E33: No previous substitute regular expression"
-msgstr "E33: Öncesinde yerine geçen bir düzenli ifade yok"
-
-msgid "E34: No previous command"
-msgstr "E34: Öncesinde komut yok"
-
-msgid "E35: No previous regular expression"
-msgstr "E35: Öncesinde düzenli ifade yok"
-
-msgid "E481: No range allowed"
-msgstr "E481: Erime izin verilmiyor"
-
-msgid "E36: Not enough room"
-msgstr "E36: Yeterli alan yok"
-
-#, c-format
-msgid "E247: no registered server named \"%s\""
-msgstr "E247: \"%s\" adlı kayıtlı bir sunucu yok"
-
-#, c-format
-msgid "E482: Can't create file %s"
-msgstr "E482: %s dosyası oluşturulamıyor"
-
-msgid "E483: Can't get temp file name"
-msgstr "E483: Geçici dosya adı alınamıyor"
-
-#, c-format
-msgid "E484: Can't open file %s"
-msgstr "E484: %s dosyası açılamıyor"
-
-#, c-format
-msgid "E485: Can't read file %s"
-msgstr "E485: %s dosyası okunamıyor"
-
-msgid "E38: Null argument"
-msgstr "E38: Anlamsız argüman"
-
-msgid "E39: Number expected"
-msgstr "E39: Sayı bekleniyordu"
-
-#, c-format
-msgid "E40: Can't open errorfile %s"
-msgstr "E40: Hata dosyası %s açılamıyor"
-
-msgid "E233: cannot open display"
-msgstr "E233: Görüntü açılamıyor"
-
-msgid "E41: Out of memory!"
-msgstr "E41: Bellek yetersiz!"
-
-msgid "Pattern not found"
-msgstr "Dizgi bulunamadı"
-
-#, c-format
-msgid "E486: Pattern not found: %s"
-msgstr "E486: Dizgi bulunamadı: %s"
-
-msgid "E487: Argument must be positive"
-msgstr "E487: Değişken pozitif olmalı"
-
-msgid "E459: Cannot go back to previous directory"
-msgstr "E459: Bir önceki dizine gidilemiyor"
-
-msgid "E42: No Errors"
-msgstr "E42: Hata yok"
-
-msgid "E776: No location list"
-msgstr "E776: Konum listesi yok"
-
-msgid "E43: Damaged match string"
-msgstr "E43: Hasarlı eşleşme dizisi"
-
-msgid "E44: Corrupted regexp program"
-msgstr "E44: Bozulmuş regexp programı"
-
-msgid "E45: 'readonly' option is set (add ! to override)"
-msgstr "E45: 'readonly' seçeneği ayarlanmış (geçersiz kılmak için ! ekleyin)"
-
-#, c-format
-msgid "E734: Wrong variable type for %s="
-msgstr "E734: %s= için yanlış değişken türü"
-
-#, c-format
-msgid "E461: Illegal variable name: %s"
-msgstr "E461: İzin verilmeyen değişken adı: %s"
-
-msgid "E995: Cannot modify existing variable"
-msgstr "E995: Mevcut değişken değiştirilemiyor"
-
-#, c-format
-msgid "E46: Cannot change read-only variable \"%s\""
-msgstr "E46: Salt okunur değişken \"%s\" değiştirilemiyor"
-
-#, c-format
-msgid "E794: Cannot set variable in the sandbox: \"%s\""
-msgstr "E794: Değişken kum havuzunda ayarlanamıyor: \"%s\""
-
-msgid "E928: String required"
-msgstr "E928: Dizi gerekiyor"
-
-msgid "E889: Number required"
-msgstr "E889: Sayı gerekiyor"
-
-msgid "E713: Cannot use empty key for Dictionary"
-msgstr "E713: Sözlük için boş anahtar kullanılamaz"
-
-msgid "E715: Dictionary required"
-msgstr "E715: Sözlük gerekiyor"
-
-#, c-format
-msgid "E684: list index out of range: %ld"
-msgstr "E684: Liste sırası erimin dışında: %ld"
-
-#, c-format
-msgid "E979: Blob index out of range: %ld"
-msgstr "E979: İkili geniş nesne sırası erimin dışında: %ld"
-
-msgid "E978: Invalid operation for Blob"
-msgstr "E978: İkili geniş nesne için geçersiz işlem"
-
-#, c-format
-msgid "E118: Too many arguments for function: %s"
-msgstr "E118: İşlev için çok fazla argüman: %s"
-
-#, c-format
-msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: Şu işlev için yetersiz sayıda argüman: %s"
-
-#, c-format
-msgid "E933: Function was deleted: %s"
-msgstr "E933: İşlev silinmiş: %s"
-
-#, c-format
-msgid "E716: Key not present in Dictionary: \"%s\""
-msgstr "E716: Anahtar sözlükte mevcut değil: \"%s\""
-
-msgid "E714: List required"
-msgstr "E714: Liste gerekiyor"
-
-msgid "E897: List or Blob required"
-msgstr "E897: Liste veya ikili geniş nesne gerekiyor"
-
-#, c-format
-msgid "E697: Missing end of List ']': %s"
-msgstr "E697: Liste sonunda ']' eksik: %s"
-
-#, c-format
-msgid "E712: Argument of %s must be a List or Dictionary"
-msgstr "E712: %s ögesinin argümanı bir liste veya sözlük olmalıdır"
-
-#, c-format
-msgid "E896: Argument of %s must be a List, Dictionary or Blob"
-msgstr "E896: %s argümanı bir liste, sözlük veya ikili geniş nesne olmalıdır"
-
-msgid "E804: Cannot use '%' with Float"
-msgstr "E804: Bir kayan noktalı değer ile '%' kullanılamaz"
-
-msgid "E996: Cannot lock an option"
-msgstr "E996: Seçenek kilitlenemiyor"
-
-#, c-format
-msgid "E113: Unknown option: %s"
-msgstr "E113: Bilinmeyen seçenek: %s"
-
-#, c-format
-msgid "E998: Reduce of an empty %s with no initial value"
-msgstr "E998: Başlangıç değeri olmayan boş bir %s için reduce() yapılamıyor"
-
-#, c-format
-msgid "E857: Dictionary key \"%s\" required"
-msgstr "E857: Sözlük anahtarı \"%s\" gerekiyor"
-
-msgid "E47: Error while reading errorfile"
-msgstr "E47: Hata dosyası okunurken hata"
-
-msgid "E48: Not allowed in sandbox"
-msgstr "E48: Kum havuzunda izin verilmiyor"
-
-msgid "E523: Not allowed here"
-msgstr "E523: Burada izin verilmiyor"
-
-msgid "E578: Not allowed to change text here"
-msgstr "E578: Burada metin değişikliğine izin verilmiyor"
-
-msgid "E565: Not allowed to change text or change window"
-msgstr "E565: Pencere veya metin değişikliğine izin verilmiyor"
-
-msgid "E359: Screen mode setting not supported"
-msgstr "E359: Ekran kipi ayarı desteklenmiyor"
-
-msgid "E49: Invalid scroll size"
-msgstr "E49: Geçersiz kaydırma boyutu"
-
-msgid "E91: 'shell' option is empty"
-msgstr "E91: 'shell' seçeneği boş"
-
-msgid "E255: Couldn't read in sign data!"
-msgstr "E255: İşaret verisi okunamadı!"
-
-msgid "E72: Close error on swap file"
-msgstr "E72: Takas dosyasında kapama hatası"
-
-msgid "E73: tag stack empty"
-msgstr "E73: Etiket yığını boş"
-
-msgid "E74: Command too complex"
-msgstr "E74: Komut çok karmaşık"
-
-msgid "E75: Name too long"
-msgstr "E75: Ad çok uzun"
-
-msgid "E76: Too many ["
-msgstr "E76: Çok fazla ["
-
-msgid "E77: Too many file names"
-msgstr "E77: Çok fazla dosya adı"
-
-msgid "E488: Trailing characters"
-msgstr "E488: Sonda fazladan karakterler"
-
-#, c-format
-msgid "E488: Trailing characters: %s"
-msgstr "E488: Sonda fazladan karakterler: %s"
-
-msgid "E78: Unknown mark"
-msgstr "E78: Bilinmeyen im"
-
-msgid "E79: Cannot expand wildcards"
-msgstr "E79: Joker karakterleri genişletilemiyor"
-
-msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
-msgstr "E591: 'winheight' değeri 'winminheight' değerinden küçük olamaz"
-
-msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
-msgstr "E592: 'winwidth' değeri 'winminwidth' değerinden küçük olamaz"
-
-msgid "E80: Error while writing"
-msgstr "E80: Yazma sırasında hata"
-
-msgid "E939: Positive count required"
-msgstr "E939: Pozitif sayım gerekiyor"
-
-msgid "E81: Using <SID> not in a script context"
-msgstr "E81: <SID> bir betik bağlamında kullanılmıyor"
-
-#, c-format
-msgid "E107: Missing parentheses: %s"
-msgstr "E107: Ayraç eksik: %s"
-
-msgid "E110: Missing ')'"
-msgstr "E110: ')' eksik"
-
-#, c-format
-msgid "E720: Missing colon in Dictionary: %s"
-msgstr "E720: Sözlükte iki nokta eksik: %s"
-
-#, c-format
-msgid "E721: Duplicate key in Dictionary: \"%s\""
-msgstr "E721: Sözlükte yinelenmiş anahtar: \"%s\""
-
-#, c-format
-msgid "E722: Missing comma in Dictionary: %s"
-msgstr "E722: Sözlükte virgül eksik: %s"
-
-#, c-format
-msgid "E723: Missing end of Dictionary '}': %s"
-msgstr "E723: Sözlük sonu '}' eksik: %s"
-
-msgid "E449: Invalid expression received"
-msgstr "E449: Geçersiz ifade alındı"
-
-msgid "E463: Region is guarded, cannot modify"
-msgstr "E463: Bölge korunuyor, değiştirilemez"
-
-msgid "E744: NetBeans does not allow changes in read-only files"
-msgstr "E744: NetBeans salt okunur dosyalarda değişikliklere izin vermiyor"
-
-msgid "E363: pattern uses more memory than 'maxmempattern'"
-msgstr "E363: Dizgi 'maxmempattern' ögesinden daha fazla bellek kullanıyor"
-
-msgid "E749: empty buffer"
-msgstr "E749: Boş arabellek"
-
-#, c-format
-msgid "E86: Buffer %ld does not exist"
-msgstr "E86: Arabellek %ld mevcut değil"
-
-msgid "E682: Invalid search pattern or delimiter"
-msgstr "E682: Geçersiz arama dizgisi veya sınırlandırıcısı"
-
-msgid "E139: File is loaded in another buffer"
-msgstr "E139: Dosya başka bir arabellekte yüklü"
-
-#, c-format
-msgid "E764: Option '%s' is not set"
-msgstr "E764: '%s' seçeneği ayarlanmamış"
-
-msgid "E850: Invalid register name"
-msgstr "E850: Geçersiz yazmaç adı"
-
-msgid "E806: using Float as a String"
-msgstr "E806: Kayan Noktalı Değer, bir Dizi yerine kullanılıyor"
-
-#, c-format
-msgid "E919: Directory not found in '%s': \"%s\""
-msgstr "E919: '%s' içinde dizin bulunamadı: \"%s\""
-
-msgid "E952: Autocommand caused recursive behavior"
-msgstr "E952: Otokomut özyineli davranışa neden oldu"
-
-msgid "E813: Cannot close autocmd or popup window"
-msgstr "E813: Otokomut veya açılır pencere kapatılamıyor"
-
-msgid "E328: Menu only exists in another mode"
-msgstr "E328: Menü yalnızca başka bir kipte mevcut"
-
-msgid "E957: Invalid window number"
-msgstr "E957: Geçersiz pencere numarası"
-
-#, c-format
-msgid "E686: Argument of %s must be a List"
-msgstr "E686: %s argümanı bir liste olmalı"
-
-msgid "E109: Missing ':' after '?'"
-msgstr "E109: '?' sonrası ':' eksik"
-
-msgid "E690: Missing \"in\" after :for"
-msgstr "E690: :for sonrası \"in\" eksik"
-
-#, c-format
-msgid "E117: Unknown function: %s"
-msgstr "E117: Bilinmeyen işlev: %s"
-
-msgid "E111: Missing ']'"
-msgstr "E111: ']' eksik"
-
-msgid "E581: :else without :if"
-msgstr "E581: :if olmadan :else"
-
-msgid "E582: :elseif without :if"
-msgstr "E582: :if olmadan :elseif"
-
-msgid "E580: :endif without :if"
-msgstr "E580: :if olmadan :endif"
-
-msgid "E586: :continue without :while or :for"
-msgstr "E586: :while veya :for olmadan :continue"
-
-msgid "E587: :break without :while or :for"
-msgstr "E587: :while veya :for olmadan :break"
-
-msgid "E274: No white space allowed before parenthesis"
-msgstr "E274: Ayraçtan önce boşluğa izin verilmiyor"
-
-#, c-format
-msgid "E940: Cannot lock or unlock variable %s"
-msgstr "E940: Değişken %s kilitlenemiyor veya açılamıyor"
-
-#, c-format
-msgid "E254: Cannot allocate color %s"
-msgstr "E254: %s rengi ayrılamıyor"
-
-msgid "search hit TOP, continuing at BOTTOM"
-msgstr "Arama dosyanın BAŞINI geçti, dosyanın SONUNDAN sürüyor"
-
-msgid "search hit BOTTOM, continuing at TOP"
-msgstr "Arama dosyanın SONUNU geçti, dosyanın BAŞINDAN sürüyor"
-
-msgid " line "
-msgstr " satır "
-
-#, c-format
-msgid "Need encryption key for \"%s\""
-msgstr "\"%s\" için şifreleme anahtarı gerekli"
-
-msgid "empty keys are not allowed"
-msgstr "boş anahtarlara izin verilmiyor"
-
-msgid "dictionary is locked"
-msgstr "sözlük kilitli"
-
-msgid "list is locked"
-msgstr "liste kilitli"
-
-#, c-format
-msgid "failed to add key '%s' to dictionary"
-msgstr "'%s' anahtarı sözlüğe eklenemedi"
-
-#, c-format
-msgid "index must be int or slice, not %s"
-msgstr "sıra bir tamsayı veya dilim olmalıdır, %s olamaz"
-
-#, c-format
-msgid "expected str() or unicode() instance, but got %s"
-msgstr "str() veya unicode() örneği bekleniyordu, %s geldi"
-
-#, c-format
-msgid "expected bytes() or str() instance, but got %s"
-msgstr "bytes() veya str() örneği bekleniyordu, %s geldi"
-
-#, c-format
-msgid ""
-"expected int(), long() or something supporting coercing to long(), but got %s"
-msgstr ""
-"int(), long() veya long()'a baskıyı destekleyen bir şey bekleniyordu, %s "
-"geldi"
-
-#, c-format
-msgid "expected int() or something supporting coercing to int(), but got %s"
-msgstr "int() veya int()'e baskıyı destekleyen bir şey bekleniyordu, %s geldi"
-
-msgid "value is too large to fit into C int type"
-msgstr "değer C tamsayı türüne sığmak için çok büyük"
-
-msgid "value is too small to fit into C int type"
-msgstr "değer C tamsayı türüne sığmak için çok küçük"
-
-msgid "number must be greater than zero"
-msgstr "sayı sıfırdan büyük olmalı"
-
-msgid "number must be greater or equal to zero"
-msgstr "sayı sıfıra eşit veya sıfırdan büyük olmalı"
-
-msgid "can't delete OutputObject attributes"
-msgstr "OutputObject öznitelikleri silinemiyor"
-
-#, c-format
-msgid "invalid attribute: %s"
-msgstr "geçersiz öznitelik: %s"
-
-msgid "E264: Python: Error initialising I/O objects"
-msgstr "E264: Python: Girdi/Çıktı nesneleri başlatılırken hata"
-
-msgid "failed to change directory"
-msgstr "dizin değiştirilemedi"
-
-#, c-format
-msgid "expected 3-tuple as imp.find_module() result, but got %s"
-msgstr "imp.find_module() sonucu olarak 3 çoklu öge bekleniyordu, %s geldi"
-
-#, c-format
-msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
-msgstr ""
-"imp.find_module() sonucu olarak 3 tuple bekleniyordu, %d boyutlu çok öge "
-"geldi"
-
-msgid "internal error: imp.find_module returned tuple with NULL"
-msgstr "iç hata: imp.find_module BOŞ bir çoklu öge döndürdü"
-
-msgid "cannot delete vim.Dictionary attributes"
-msgstr "vim.Dictionary öznitelikleri silinemiyor"
-
-msgid "cannot modify fixed dictionary"
-msgstr "sabit sözlük değiştirilemiyor"
-
-#, c-format
-msgid "cannot set attribute %s"
-msgstr "%s özniteliği ayarlanamıyor"
-
-msgid "hashtab changed during iteration"
-msgstr "Sağlama tablosu dürüm sırasında değişti"
-
-#, c-format
-msgid "expected sequence element of size 2, but got sequence of size %d"
-msgstr "2 boyut bir sıralama bekleniyordu, ancak %d boyut bir sıralama geldi"
-
-msgid "list constructor does not accept keyword arguments"
-msgstr "liste yapıcısı anahtar sözcük argümanları kabul etmez"
-
-msgid "list index out of range"
-msgstr "liste sırası erimin dışında"
-
-#, c-format
-msgid "internal error: failed to get Vim list item %d"
-msgstr "iç hata: %d vim liste ögesi alınamadı"
-
-msgid "slice step cannot be zero"
-msgstr "dilim adımı sıfır olamaz"
-
-#, c-format
-msgid "attempt to assign sequence of size greater than %d to extended slice"
-msgstr "genişletilmiş dilime %d boyuttan büyük bir sıralamayı atama denemesi"
-
-#, c-format
-msgid "internal error: no Vim list item %d"
-msgstr "iç hata: %d vim liste ögesi yok"
-
-msgid "internal error: not enough list items"
-msgstr "iç hata: yeterli liste ögesi yok"
-
-msgid "internal error: failed to add item to list"
-msgstr "iç hata: öge listeye eklenemedi"
-
-#, c-format
-msgid "attempt to assign sequence of size %d to extended slice of size %d"
-msgstr "%d boyut sıralamayı %d boyut genişletilmiş dizine atama denemesi"
-
-msgid "failed to add item to list"
-msgstr "öge listeye eklenemedi"
-
-msgid "cannot delete vim.List attributes"
-msgstr "vim.List öznitelikleri silinemiyor"
-
-msgid "cannot modify fixed list"
-msgstr "sabit liste değiştirilemiyor"
-
-#, c-format
-msgid "unnamed function %s does not exist"
-msgstr "adsız %s işlevi mevcut değil"
-
-#, c-format
-msgid "function %s does not exist"
-msgstr "%s işlevi mevcut değil"
-
-#, c-format
-msgid "failed to run function %s"
-msgstr "%s işlevi çalıştırılamadı"
-
-msgid "unable to get option value"
-msgstr "seçenek değeri alınamadı"
-
-msgid "internal error: unknown option type"
-msgstr "iç hata: bilinmeyen seçenek türü"
-
-msgid "problem while switching windows"
-msgstr "pencereler arasında gezinirken hata"
-
-#, c-format
-msgid "unable to unset global option %s"
-msgstr "%s global seçenek ayarı kapatılamıyor"
-
-#, c-format
-msgid "unable to unset option %s which does not have global value"
-msgstr "global değeri olmayan %s seçenek ayarı kapatılamıyor"
-
-msgid "attempt to refer to deleted tab page"
-msgstr "silinmiş sekme sayfasına başvurma denemesi"
-
-msgid "no such tab page"
-msgstr "böyle bir sekme sayfası yok"
-
-msgid "attempt to refer to deleted window"
-msgstr "silinmiş pencereye başvurma denemesi"
-
-msgid "readonly attribute: buffer"
-msgstr "saltokunur öznitelik: arabellek"
-
-msgid "cursor position outside buffer"
-msgstr "imleç konumu arabelleğin dışında"
-
-msgid "no such window"
-msgstr "böyle bir pencere yok"
-
-msgid "attempt to refer to deleted buffer"
-msgstr "silinmiş arabelleğe başvurma denemesi"
-
-msgid "failed to rename buffer"
-msgstr "arabellek adı değiştirilemedi"
-
-msgid "mark name must be a single character"
-msgstr "im adı tek bir karakterden olmalıdır"
-
-#, c-format
-msgid "expected vim.Buffer object, but got %s"
-msgstr "vim.Buffer nesnesi bekleniyordu, %s geldi"
-
-#, c-format
-msgid "failed to switch to buffer %d"
-msgstr "%d arabelleğine geçilemedi"
-
-#, c-format
-msgid "expected vim.Window object, but got %s"
-msgstr "vim.Window nesnesi bekleniyordu, %s geldi"
-
-msgid "failed to find window in the current tab page"
-msgstr "mevcut sekme sayfasında pencere bulunamadı"
-
-msgid "did not switch to the specified window"
-msgstr "belirtilen pencereye geçilemedi"
-
-#, c-format
-msgid "expected vim.TabPage object, but got %s"
-msgstr "vim.TabPage nesnesi bekleniyordu, %s geldi"
-
-msgid "did not switch to the specified tab page"
-msgstr "belirtilen sekme sayfasına geçilemedi"
-
-msgid "failed to run the code"
-msgstr "kod çalıştırılamadı"
-
-msgid "E858: Eval did not return a valid python object"
-msgstr "E858: Eval geçerli bir python nesnesi döndürmedi"
-
-msgid "E859: Failed to convert returned python object to a Vim value"
-msgstr "E859: Döndürülen python nesnesi vim değerine dönüştürülemedi"
-
-#, c-format
-msgid "unable to convert %s to a Vim dictionary"
-msgstr "%s vim sözlüğüne dönüştürülemedi"
-
-#, c-format
-msgid "unable to convert %s to a Vim list"
-msgstr "%s vim listesine dönüştürülemedi"
-
-#, c-format
-msgid "unable to convert %s to a Vim structure"
-msgstr "%s vim yapısına dönüştürülemedi"
-
-msgid "internal error: NULL reference passed"
-msgstr "iç hata: BOŞ başvuru geçirildi"
-
-msgid "internal error: invalid value type"
-msgstr "iç hata: geçersiz değer türü"
-
-msgid ""
-"Failed to set path hook: sys.path_hooks is not a list\n"
-"You should now do the following:\n"
-"- append vim.path_hook to sys.path_hooks\n"
-"- append vim.VIM_SPECIAL_PATH to sys.path\n"
-msgstr ""
-"Yol kancası ayarlanamadı: sys.path_hooks bir liste değil\n"
-"Şimdi şunları yapmanız gerekiyor:\n"
-"- vim.path_hook'u sys.path_hooks'a iliştirmek\n"
-"- vim.VIM_SPECIAL_PATH'i sys.path'e iliştirmek\n"
-
-msgid ""
-"Failed to set path: sys.path is not a list\n"
-"You should now append vim.VIM_SPECIAL_PATH to sys.path"
-msgstr ""
-"Yol ayarlanamadı: sys.path bir liste değil\n"
-"Şimdi vim.VIM_SPECIAL_PATH'i sys.path'e iliştirmelisiniz"
-
-msgid ""
-"Vim macro files (*.vim)\t*.vim\n"
-"All Files (*.*)\t*.*\n"
-msgstr ""
-"Vim makro dosyaları (*.vim)\t*.vim\n"
-"Tüm Dosyalar (*.*)\t*.*\n"
-
-msgid "All Files (*.*)\t*.*\n"
-msgstr "Tüm Dosyalar (*.*)\t*.*\n"
-
-msgid ""
-"All Files (*.*)\t*.*\n"
-"C source (*.c, *.h)\t*.c;*.h\n"
-"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
-"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
-"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
-msgstr ""
-"Tüm Dosyalar (*.*)\t*.*\n"
-"C kaynak dosyaları (*.c, *.h)\t*.c;*.h\n"
-"C++ kaynak dosyaları (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
-"VB kodu (*.bas, *.frm)\t*.bas;*.frm\n"
-"Vim dosyaları (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
-
-msgid ""
-"Vim macro files (*.vim)\t*.vim\n"
-"All Files (*)\t*\n"
-msgstr ""
-"Vim makro dosyaları (*.vim)\t*.vim\n"
-"Tüm Dosyalar (*)\t*\n"
-
-msgid "All Files (*)\t*\n"
-msgstr "Tüm Dosyalar (*)\t*\n"
-
-msgid ""
-"All Files (*)\t*\n"
-"C source (*.c, *.h)\t*.c;*.h\n"
-"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
-"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
-msgstr ""
-"Tüm Dosyalar (*)\t*\n"
-"C kaynak dosyaları (*.c, *.h)\t*.c;*.h\n"
-"C++ kaynak dosyaları (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
-"Vim dosyaları (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
-
-msgid "GVim"
-msgstr "GVim"
-
-msgid "Text Editor"
-msgstr "Metin Düzenleyici"
-
-msgid "Edit text files"
-msgstr "Metin dosyaları düzenleyin"
-
-msgid "Text;editor;"
-msgstr "Metin;düzenleyici;"
-
-msgid "Vim"
-msgstr "Vim"
-
-msgid "(local to window)"
-msgstr "(pencereye yerel)"
-
-msgid "(local to buffer)"
-msgstr "(arabelleğe yerel)"
-
-msgid "(global or local to buffer)"
-msgstr "(arabelleğe global veya yerel)"
-
-msgid ""
-"\" Each \"set\" line shows the current value of an option (on the left)."
-msgstr "\" Her \"set\" satırı bir seçeneğin geçerli değerini gösterir (solda)."
-
-msgid "\" Hit <Enter> on a \"set\" line to execute it."
-msgstr "\" Değiştirmek için bir \"set\" satırında <Enter>'a basın."
-
-msgid "\" A boolean option will be toggled."
-msgstr "\" Bir Boole değeri işletilecektir."
-
-msgid ""
-"\" For other options you can edit the value before hitting "
-"<Enter>."
-msgstr ""
-"\" Diğer seçenekler için <Enter>'a basmadan önce değeri "
-"düzenleyebilirsiniz."
-
-msgid "\" Hit <Enter> on a help line to open a help window on this option."
-msgstr "\" Yardım penceresini açmak için seçenek adı üzerinde <Enter>'a basın."
-
-msgid "\" Hit <Enter> on an index line to jump there."
-msgstr ""
-"\" Bir seçeneğe atlamak için indeks satırının üzerinde <Enter>'a basın."
-
-msgid "\" Hit <Space> on a \"set\" line to refresh it."
-msgstr ""
-"\" Bir seçeneği yenilemek için bir \"set\" satırının üzerinde <Boşluk>'a "
-"basın."
-
-msgid "important"
-msgstr "önemli"
-
-msgid "behave very Vi compatible (not advisable)"
-msgstr "olabildiğince Vi uyumlu biçimde davran (önerilmez)"
-
-msgid "list of flags to specify Vi compatibility"
-msgstr "Vi uyumluluğu bayrakları listesi"
-
-msgid "use Insert mode as the default mode"
-msgstr "Ekleme kipini öntanımlı kip olarak kullan"
-
-msgid "paste mode, insert typed text literally"
-msgstr "yapıştır kipi, girilen metni doğrudan ekle"
-
-msgid "key sequence to toggle paste mode"
-msgstr "yapıştır kipini açıp/kapatmak için düğme sıralaması"
-
-msgid "list of directories used for runtime files and plugins"
-msgstr "çalışma zamanı dosyaları ve eklentileri için kullanılan dizinler"
-
-msgid "list of directories used for plugin packages"
-msgstr "eklenti paketleri için kullanılan dizinlerin listesi"
-
-msgid "name of the main help file"
-msgstr "ana yardım dosyasının adı"
-
-msgid "moving around, searching and patterns"
-msgstr "dolaşma, arama ve dizgeler"
-
-msgid "list of flags specifying which commands wrap to another line"
-msgstr ""
-"hangi komutların diğer satıra kaydırıldığını belirleyen bayraklar\n"
-"listesi"
-
-msgid ""
-"many jump commands move the cursor to the first non-blank\n"
-"character of a line"
-msgstr ""
-"çoğu atlama komutu, imleci satırın boş olmayan ilk\n"
-"karakterine taşır"
-
-msgid "nroff macro names that separate paragraphs"
-msgstr "paragrafları ayıran nroff makro adları"
-
-msgid "nroff macro names that separate sections"
-msgstr "bölümleri ayıran nroff makro adları"
-
-msgid "list of directory names used for file searching"
-msgstr "dosya arama için kullanılan dizin adları listesi"
-
-msgid "list of directory names used for :cd"
-msgstr ":cd için kullanılan dizin adları listesi"
-
-msgid "change to directory of file in buffer"
-msgstr "arabellekteki dosyanın olduğu dizine değiştir"
-
-msgid "change to pwd of shell in terminal buffer"
-msgstr "uçbirim arabelleğindeki kabuğun pwd'sine geç"
-
-msgid "search commands wrap around the end of the buffer"
-msgstr "arama komutları, arabelleğin sonunda kaydırılır"
-
-msgid "show match for partly typed search command"
-msgstr "bir kısmı yazılmış arama komutu ile eşleşeni göster"
-
-msgid "change the way backslashes are used in search patterns"
-msgstr "arama dizgilerinde ters eğik çizginin kullanımını değiştir"
-
-msgid "select the default regexp engine used"
-msgstr "öntanımlı kullanılan düzenli ifade motorunu seç"
-
-msgid "ignore case when using a search pattern"
-msgstr "bir arama dizgisinde BÜYÜK/küçük harf ayrımını yok say"
-
-msgid "override 'ignorecase' when pattern has upper case characters"
-msgstr "dizgide BÜYÜK harf varsa 'ignorecase'i geçersiz kıl"
-
-msgid "what method to use for changing case of letters"
-msgstr "BÜYÜK/küçük harf değiştirirken hangi yöntemin kullanılacağı"
-
-msgid "maximum amount of memory in Kbyte used for pattern matching"
-msgstr "dizgi eşleşme için kullanılabilecek en çok bellek miktarı (KiB)"
-
-msgid "pattern for a macro definition line"
-msgstr "bir makro tanım satırı için dizgi"
-
-msgid "pattern for an include-file line"
-msgstr "bir 'include-file' satırı için dizgi"
-
-msgid "expression used to transform an include line to a file name"
-msgstr "bir 'include' satırını dosya adına dönüştürmede kullanılan ifade"
-
-msgid "tags"
-msgstr "etiketler"
-
-msgid "use binary searching in tags files"
-msgstr "etiketler dosyasında ikili arama kullan"
-
-msgid "number of significant characters in a tag name or zero"
-msgstr "bir etiket adındaki belirgin karakterlerin sayısı veya sıfır"
-
-msgid "list of file names to search for tags"
-msgstr "etiketlerin aranacağı dosyaların listesi"
-
-msgid ""
-"how to handle case when searching in tags files:\n"
-"\"followic\" to follow 'ignorecase', \"ignore\" or \"match\""
-msgstr ""
-"etiket dosyalarında arama yaparken BÜYÜK/küçük harf kullanımı:\n"
-"'ignorecase', \"ignore\" veya \"match\"den sonra \"followic\" gelir"
-
-msgid "file names in a tags file are relative to the tags file"
-msgstr "bir etiket dosyasındaki dosya adları etiket dosyasına görelidir"
-
-msgid "a :tag command will use the tagstack"
-msgstr "bir :tag komutu etiket yığınını kullanır"
-
-msgid "when completing tags in Insert mode show more info"
-msgstr "Ekleme kipinde etiketleri tamamlarken daha çok bilgi göster"
-
-msgid "a function to be used to perform tag searches"
-msgstr "etiket aramaları gerçekleştirmek için bir işlev kullanılır"
-
-msgid "command for executing cscope"
-msgstr "cscope çalıştırmak için kullanılacak komut"
-
-msgid "use cscope for tag commands"
-msgstr "etiket komutları için cscope kullan"
-
-msgid "0 or 1; the order in which \":cstag\" performs a search"
-msgstr "0 veya 1; \":cstag\"in arama yaparken kullanacağı sıra"
-
-msgid "give messages when adding a cscope database"
-msgstr "bir cscope veritabanı eklerken iletiler göster"
-
-msgid "how many components of the path to show"
-msgstr "yolun kaç tane bileşeninin gösterileceği"
-
-msgid "when to open a quickfix window for cscope"
-msgstr "cscope için ne zaman bir hızlı düzelt penceresinin açılacağı"
-
-msgid "file names in a cscope file are relative to that file"
-msgstr "bir cscope dosyasındaki o dosyaya göreli olan dosya adları"
-
-msgid "displaying text"
-msgstr "metin görüntüleme"
-
-msgid "number of lines to scroll for CTRL-U and CTRL-D"
-msgstr "CTRL-U ve CTRL-D için kaydırılacak satır sayısı"
-
-msgid "number of screen lines to show around the cursor"
-msgstr "imleç etrafında gösterilecek ekran satırları sayısı"
-
-msgid "long lines wrap"
-msgstr "uzun satırları kaydır"
-
-msgid "wrap long lines at a character in 'breakat'"
-msgstr "'breakat' içindeki bir karakterde uzun satırları kaydır"
-
-msgid "preserve indentation in wrapped text"
-msgstr "kaydırılmış metindeki girintilemeyi koru"
-
-msgid "adjust breakindent behaviour"
-msgstr "'breakindent' davranışını ayarla"
-
-msgid "which characters might cause a line break"
-msgstr "hangi karakterler bir satır sonuna neden olabilir"
-
-msgid "string to put before wrapped screen lines"
-msgstr "kaydırılmış ekran satırlarından önce konumlanacak dizi"
-
-msgid "minimal number of columns to scroll horizontally"
-msgstr "en az yatay kaydırma sütunu sayısı"
-
-msgid "minimal number of columns to keep left and right of the cursor"
-msgstr "imlecin sağında ve solunda bırakılacak en az sütun sayısı"
-
-msgid ""
-"include \"lastline\" to show the last line even if it doesn't fit\n"
-"include \"uhex\" to show unprintable characters as a hex number"
-msgstr ""
-"eğer sığmasa bile son satırı göstermek için \"lastline\"ı içer\n"
-"yazdırılamayan karakterleri onaltılık olarak göstermek için\n"
-"\"uhex\" içer"
-
-msgid "characters to use for the status line, folds and filler lines"
-msgstr "durum satırı, kıvırma ve doldurucular için kullanılan karakterler"
-
-msgid "number of lines used for the command-line"
-msgstr "komut satırı için kullanılan satırların sayısı"
-
-msgid "width of the display"
-msgstr "ekranın genişliği"
-
-msgid "number of lines in the display"
-msgstr "ekrandaki satırların sayısı"
-
-msgid "number of lines to scroll for CTRL-F and CTRL-B"
-msgstr "CTRL-F ve CTRL-B için kaydırılacak satır sayısı"
-
-msgid "don't redraw while executing macros"
-msgstr "makroları çalıştırırken yenileme yapma"
-
-msgid "timeout for 'hlsearch' and :match highlighting in msec"
-msgstr "'hlsearch' ve : match vurgulaması için zaman aşımı (milisaniye)"
-
-msgid ""
-"delay in msec for each char written to the display\n"
-"(for debugging)"
-msgstr ""
-"ekrana yazılan her karakter için gecikme süresi (milisaniye)\n"
-"(hata ayıklama için)"
-
-msgid "show <Tab> as ^I and end-of-line as $"
-msgstr "<Tab>'ı ^I ve satır sonunu $ olarak göster"
-
-msgid "list of strings used for list mode"
-msgstr "liste kipi için kullanılan diziler listesi"
-
-msgid "show the line number for each line"
-msgstr "her satır için satır numarasını göster"
-
-msgid "show the relative line number for each line"
-msgstr "her satır için göreli satır numarasını göster"
-
-msgid "number of columns to use for the line number"
-msgstr "satır numarası için kullanılacak sütün sayısı"
-
-msgid "controls whether concealable text is hidden"
-msgstr "gizlenebilir metnin saklı olup olmadığını denetler"
-
-msgid "modes in which text in the cursor line can be concealed"
-msgstr "imleç satırındaki metnin gizlenebileceği kipler"
-
-msgid "syntax, highlighting and spelling"
-msgstr "sözdizim, vurgulama ve yazım denetimi"
-
-msgid "\"dark\" or \"light\"; the background color brightness"
-msgstr "\"dark\" veya \"light\"; arka plan renk parlaklığı"
-
-msgid "type of file; triggers the FileType event when set"
-msgstr "dosya türü; ayarlandığında FileType olayını tetikler"
-
-msgid "name of syntax highlighting used"
-msgstr "kullanılan sözdizim vurgulamanın adı"
-
-msgid "maximum column to look for syntax items"
-msgstr "sözdizim ögeleri için bakılacak en çok sütun sayısı"
-
-msgid "which highlighting to use for various occasions"
-msgstr "çeşitli durumlarda hangi vurgulamanın kullanılacağı"
-
-msgid "highlight all matches for the last used search pattern"
-msgstr "son kullanılan arama dizgisi için tüm eşleşmeleri vurgula"
-
-msgid "highlight group to use for the window"
-msgstr "pencere için kullanılacak vurgulama grubu"
-
-msgid "use GUI colors for the terminal"
-msgstr "uçbirim için grafik arabirim renklerini kullan"
-
-msgid "highlight the screen column of the cursor"
-msgstr "imlecin ekrandaki sütununu vurgula"
-
-msgid "highlight the screen line of the cursor"
-msgstr "imlecin ekrandaki satırını vurgula"
-
-msgid "specifies which area 'cursorline' highlights"
-msgstr "'cursorline'ın hangi alanı vurgulayacağı"
-
-msgid "columns to highlight"
-msgstr "vurgulanacak sütunlar"
-
-msgid "highlight spelling mistakes"
-msgstr "yazım yanlışlarını vurgula"
-
-msgid "list of accepted languages"
-msgstr "kabul edilen dillerin listesi"
-
-msgid "file that \"zg\" adds good words to"
-msgstr "\"zg\" komutunun düzgün sözcükleri ekleyeceği dosya"
-
-msgid "pattern to locate the end of a sentence"
-msgstr "bir tümcenin sonunu bulmak için kullanılan dizgi"
-
-msgid "flags to change how spell checking works"
-msgstr "yazım denetiminin nice çalıştığını değiştirmek için bayraklar"
-
-msgid "methods used to suggest corrections"
-msgstr "düzeltmeleri önermek için yöntemler"
-
-msgid "amount of memory used by :mkspell before compressing"
-msgstr "sıkıştırma öncesi :mkspell tarafından kullanılan bellek"
-
-msgid "multiple windows"
-msgstr "çoklu pencereler"
-
-msgid "0, 1 or 2; when to use a status line for the last window"
-msgstr ""
-"0, 1 veya 2; son pencere için ne zaman bir durum satırı\n"
-"kullanılacağı"
-
-msgid "alternate format to be used for a status line"
-msgstr "durum satırı için kullanılabilecek alternatif biçim"
-
-msgid "make all windows the same size when adding/removing windows"
-msgstr "pencere eklerken/kaldırırken tüm pencereleri aynı boyuta getir"
-
-msgid "in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\""
-msgstr "'equalalways'in hangi yönde çalıştığı: \"ver\", \"hor\" veya \"both\""
-
-msgid "minimal number of lines used for the current window"
-msgstr "geçerli pencere için kullanılan en az satır sayısı"
-
-msgid "minimal number of lines used for any window"
-msgstr "herhangi bir pencere için kullanılan en az satır sayısı"
-
-msgid "keep the height of the window"
-msgstr "pencerenin yüksekliğini tut"
-
-msgid "keep the width of the window"
-msgstr "pencerenin genişliğini tut"
-
-msgid "minimal number of columns used for the current window"
-msgstr "geçerli pencere için kullanılan en az sütun sayısı"
-
-msgid "minimal number of columns used for any window"
-msgstr "herhangi bir pencere için kullanılan en az sütun sayısı"
-
-msgid "initial height of the help window"
-msgstr "yardım penceresinin başlangıç yüksekliği"
-
-msgid "use a popup window for preview"
-msgstr "önizleme için bir açılır pencere kullan"
-
-msgid "default height for the preview window"
-msgstr "önizleme penceresi için öntanımlı yükseklik"
-
-msgid "identifies the preview window"
-msgstr "önizleme penceresini tanımlar"
-
-msgid "don't unload a buffer when no longer shown in a window"
-msgstr "arabellek artık pencerede görüntülenmiyorsa bellekten kaldırma"
-
-msgid ""
-"\"useopen\" and/or \"split\"; which window to use when jumping\n"
-"to a buffer"
-msgstr ""
-"\"useopen\" ve/veya \"split\"; bir belleğe atlarken hangi\n"
-"pencerenin kullanılacağı"
-
-msgid "a new window is put below the current one"
-msgstr "geçerli pencerenin altına yeni bir pencere koyulur"
-
-msgid "a new window is put right of the current one"
-msgstr "yeni bir pencere geçerli pencerenin sağına koyulur"
-
-msgid "this window scrolls together with other bound windows"
-msgstr "bu pencere, bağlı diğer pencerelerle birlikte kayar"
-
-msgid "\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'"
-msgstr ""
-"\"ver\", \"hor\" ve/veya \"jump\"; 'scrollbind' için seçenekler listesi"
-
-msgid "this window's cursor moves together with other bound windows"
-msgstr "bu pencerenin imleci bağlı diğer pencerelerle birlikte kayar"
-
-msgid "size of a terminal window"
-msgstr "bir uçbirim penceresinin boyutu"
-
-msgid "key that precedes Vim commands in a terminal window"
-msgstr "bir uçbirim penceresinde Vim komutlarından önce gelen düğme"
-
-msgid "max number of lines to keep for scrollback in a terminal window"
-msgstr ""
-"bir uçbirim penceresinde geri kaydırma için kullanılacak\n"
-"en çok satır sayısı"
-
-msgid "type of pty to use for a terminal window"
-msgstr "bir uçbirim penceresi için kullanılacak pty türü"
-
-msgid "name of the winpty dynamic library"
-msgstr "winpty devingen kitaplığının adı"
-
-msgid "multiple tab pages"
-msgstr "çoklu sekme sayfaları"
-
-msgid "0, 1 or 2; when to use a tab pages line"
-msgstr "0, 1 veya 2; ne zaman bir sekme sayfası satırının kullanılacağı"
-
-msgid "maximum number of tab pages to open for -p and \"tab all\""
-msgstr "-p ve \"tab all\"un açacağı en çok sekme sayfası sayısı"
-
-msgid "custom tab pages line"
-msgstr "özelleştirilmiş sekme sayfası satırı"
-
-msgid "custom tab page label for the GUI"
-msgstr "grafik arabirim için özelleştirilmiş sekme sayfası etiketi"
-
-msgid "custom tab page tooltip for the GUI"
-msgstr "grafik arabirim için özelleştirilmiş sekme sayfası bilgi kutusu"
-
-msgid "terminal"
-msgstr "uçbirim"
-
-msgid "name of the used terminal"
-msgstr "kullanılan uçbirimin adı"
-
-msgid "alias for 'term'"
-msgstr "'term' için arma"
-
-msgid "check built-in termcaps first"
-msgstr "önce iç termcaps'i denetle"
-
-msgid "terminal connection is fast"
-msgstr "uçbirim bağlantısı hızlı"
-
-msgid "terminal that requires extra redrawing"
-msgstr "ek yenileme gerektiren uçbirim"
-
-msgid "recognize keys that start with <Esc> in Insert mode"
-msgstr "Ekleme kipinde <Esc> ile başlayan düğmeleri tanı"
-
-msgid "minimal number of lines to scroll at a time"
-msgstr "herhangi bir zamanda kaydırılacak en az satır sayısı"
-
-msgid "maximum number of lines to use scrolling instead of redrawing"
-msgstr "yenileme yerine kaydırma kullanacak en çok satır sayısı"
-
-msgid "specifies what the cursor looks like in different modes"
-msgstr "imlecin farklı kiplerde nice göründüğünü belirler"
-
-msgid "show info in the window title"
-msgstr "pencere başlığında bilgi görüntüle"
-
-msgid "percentage of 'columns' used for the window title"
-msgstr "pencere başlığı için kullanılacak 'columns' yüzdesi"
-
-msgid "when not empty, string to be used for the window title"
-msgstr "boş değilken, pencere başlığı yerine kullanılacak dizi"
-
-msgid "string to restore the title to when exiting Vim"
-msgstr "Vim'den çıkarken başlığın döndürüleceği dizi"
-
-msgid "set the text of the icon for this window"
-msgstr "bu pencere için simgenin metnini ayarla"
-
-msgid "when not empty, text for the icon of this window"
-msgstr "boş değilken, bu pencerenin simgesi için metin"
-
-msgid "restore the screen contents when exiting Vim"
-msgstr "Vim'den çıkarken ekran içeriğini eski haline getir"
-
-msgid "using the mouse"
-msgstr "fare kullanımı"
-
-msgid "list of flags for using the mouse"
-msgstr "fare kullanımı için bayraklar listesi"
-
-msgid "the window with the mouse pointer becomes the current one"
-msgstr "fare imlecinin olduğu pencere geçerli pencere olur"
-
-msgid "the window with the mouse pointer scrolls with the mouse wheel"
-msgstr "fare imlecinin olduğu pencere fare tekerleği ile kaydırılabilir"
-
-msgid "hide the mouse pointer while typing"
-msgstr "yazı yazarken fare imlecini gizle"
-
-msgid ""
-"\"extend\", \"popup\" or \"popup_setpos\"; what the right\n"
-"mouse button is used for"
-msgstr ""
-"\"extend\", \"popup\" veya \"popup_setpos\"; sağ fare düğmesinin\"\n"
-"ne için kullanıldığı"
-
-msgid "maximum time in msec to recognize a double-click"
-msgstr "bir çif tıklamayı tanımak için en çok süre (milisaniye)"
-
-msgid "\"xterm\", \"xterm2\", \"sgr\", etc.; type of mouse"
-msgstr "\"xterm\", \"xterm2\", \"sgr\" vb.; fare türü"
-
-msgid "what the mouse pointer looks like in different modes"
-msgstr "farklı kiplerde fare imlecinin nice göründüğü"
-
-msgid "GUI"
-msgstr "grafik arabirim"
-
-msgid "list of font names to be used in the GUI"
-msgstr "grafik arabirimde kullanılacak yazıtiplerinin listesi"
-
-msgid "pair of fonts to be used, for multibyte editing"
-msgstr "çoklu bayt düzenlemede kullanılacak yazıtipi eşleşmeleri"
-
-msgid "list of font names to be used for double-wide characters"
-msgstr "çift genişlikli karakterler için kullanılacak yazıtiplerinin listesi"
-
-msgid "use smooth, antialiased fonts"
-msgstr "düzletilmiş yazıtipleri kullan"
-
-msgid "list of flags that specify how the GUI works"
-msgstr "grafik arabirimin nice çalıştığını belirleyen bayraklar listesi"
-
-msgid "\"icons\", \"text\" and/or \"tooltips\"; how to show the toolbar"
-msgstr "\"icons\", \"text\" ve/veya \"tooltips\"; araç çubuğu kipleri "
-
-msgid "size of toolbar icons"
-msgstr "araç çubuğu simgelerinin boyutu"
-
-msgid "room (in pixels) left above/below the window"
-msgstr "pencerenin altında/üstünde bırakılan alan (piksel)"
-
-msgid "options for text rendering"
-msgstr "metin dokuması için seçenekler"
-
-msgid "use a pseudo-tty for I/O to external commands"
-msgstr "dış komutlara, girdi çıktı için yalancı-tty kullan"
-
-msgid ""
-"\"last\", \"buffer\" or \"current\": which directory used for the file "
-"browser"
-msgstr ""
-"\"last\", \"buffer\" veya \"current\"; dosya tarayıcısı için hangi dizinin "
-"kullanıldığı"
-
-msgid "language to be used for the menus"
-msgstr "menüler için kullanılan dil"
-
-msgid "maximum number of items in one menu"
-msgstr "bir menüdeki en çok öge sayısı"
-
-msgid "\"no\", \"yes\" or \"menu\"; how to use the ALT key"
-msgstr "\"no\", \"yes\" veya \"menu\"; ALT düğmesinin nice kullanılacağı"
-
-msgid "number of pixel lines to use between characters"
-msgstr "karakterler arasında kullanılacak piksel satırları sayısı"
-
-msgid "delay in milliseconds before a balloon may pop up"
-msgstr "bir balonun patlamadan önceki gecikme (milisaniye)"
-
-msgid "use balloon evaluation in the GUI"
-msgstr "grafik arabirimde balon değerlendirme kullan"
-
-msgid "use balloon evaluation in the terminal"
-msgstr "uçbirimde balon değerlendirme kullan"
-
-msgid "expression to show in balloon eval"
-msgstr "balon değerlendirmesinde gösterilecek ifade"
-
-msgid "printing"
-msgstr "yazdırma"
-
-msgid "list of items that control the format of :hardcopy output"
-msgstr ":hardcopy çıktısının biçimini denetleyen ögelerin listesi"
-
-msgid "name of the printer to be used for :hardcopy"
-msgstr ":hardcopy için kullanılan yazıcının adı"
-
-msgid "expression used to print the PostScript file for :hardcopy"
-msgstr ":hardcopy için PostScript dosyasını yazdırmada kullanılan ifade"
-
-msgid "name of the font to be used for :hardcopy"
-msgstr ":hardcopy için kullanılan yazıtipinin adı"
-
-msgid "format of the header used for :hardcopy"
-msgstr ":hardcopy için kullanılan üstbilginin biçimi"
-
-msgid "encoding used to print the PostScript file for :hardcopy"
-msgstr ":hardcopy için Postscript dosyasını yazdırmada kullanılan kodlama"
-
-msgid "the CJK character set to be used for CJK output from :hardcopy"
-msgstr ":hardcopy'deki ÇJK çıktısında kullanılan ÇJK karakter seti"
-
-msgid "list of font names to be used for CJK output from :hardcopy"
-msgstr ":hardcopy'deki ÇJK çıktısında kullanılan ÇJK yazıtipi"
-
-msgid "messages and info"
-msgstr "iletiler ve bilgi"
-
-msgid "add 's' flag in 'shortmess' (don't show search message)"
-msgstr "'shortness'daki 's' bayrağını ekle (arama iletisini gösterme)"
-
-msgid "list of flags to make messages shorter"
-msgstr "iletileri kısalaştırmak için kullanılan bayraklar listesi"
-
-msgid "show (partial) command keys in the status line"
-msgstr "durum satırında (kısmi) komut düğmelerini göster"
-
-msgid "display the current mode in the status line"
-msgstr "durum satırında geçerli kipi görüntüle"
-
-msgid "show cursor position below each window"
-msgstr "her pencerenin altında imleç konumunu göster"
-
-msgid "alternate format to be used for the ruler"
-msgstr "cetvel için kullanılan alternatif biçim"
-
-msgid "threshold for reporting number of changed lines"
-msgstr "değiştirilmiş satırların sayısını raporlama eşiği"
-
-msgid "the higher the more messages are given"
-msgstr "ne kadar yüksek olursa o kadar çok ileti olur"
-
-msgid "file to write messages in"
-msgstr "iletilerin içine yazılacağı dosya"
-
-msgid "pause listings when the screen is full"
-msgstr "ekran doluyken listelemeleri duraklat"
-
-msgid "start a dialog when a command fails"
-msgstr "bir komut başarısız olursa iletişim kutusu göster"
-
-msgid "ring the bell for error messages"
-msgstr "hata iletilerinde zili çal"
-
-msgid "use a visual bell instead of beeping"
-msgstr "bipleme yerine görsel zil kullan"
-
-msgid "do not ring the bell for these reasons"
-msgstr "bu nedenlerle zili çalma"
-
-msgid "list of preferred languages for finding help"
-msgstr "yardım için yeğlenen diller listesi"
-
-msgid "selecting text"
-msgstr "metin seçme"
-
-msgid "\"old\", \"inclusive\" or \"exclusive\"; how selecting text behaves"
-msgstr "\"old\", \"inclusive\" veya \"exclusive\"; metin seçim davranışı"
-
-msgid ""
-"\"mouse\", \"key\" and/or \"cmd\"; when to start Select mode\n"
-"instead of Visual mode"
-msgstr ""
-"\"mouse\", \"key\", ve/veya \"cmd\"; Görsel kip yerine Seçim\n"
-"kipinin başlatılacağı zaman"
-
-msgid ""
-"\"unnamed\" to use the * register like unnamed register\n"
-"\"autoselect\" to always put selected text on the clipboard"
-msgstr ""
-"\"unnamed\": * yazmacını adsız yazmaç gibi kullan\n"
-"\"autoselect\": seçili metni her zaman panoya koy"
-
-msgid "\"startsel\" and/or \"stopsel\"; what special keys can do"
-msgstr "\"startsel\" ve/veya \"stopsel\"; özel düğmelerin işlevleri"
-
-msgid "editing text"
-msgstr "metin düzenleme"
-
-msgid "maximum number of changes that can be undone"
-msgstr "geri alınabilecek en çok değişiklik sayısı"
-
-msgid "automatically save and restore undo history"
-msgstr "geri al geçmişini kendiliğinden kaydet ve eski haline getir"
-
-msgid "list of directories for undo files"
-msgstr "geri al dosyaları için dizinler listesi"
-
-msgid "maximum number lines to save for undo on a buffer reload"
-msgstr ""
-"arabellek yeniden yüklemesinde geri al için kaydedilecek\n"
-"en çok satır sayısı"
-
-msgid "changes have been made and not written to a file"
-msgstr "yapılan; ancak bir dosyaya yazılmayan değişiklikler"
-
-msgid "buffer is not to be written"
-msgstr "arabellek, yazım için değil"
-
-msgid "changes to the text are possible"
-msgstr "metne değişiklik yapımı olanaklı"
-
-msgid "line length above which to break a line"
-msgstr "sonrasında yeni satır yapılacak satır uzunluğu"
-
-msgid "margin from the right in which to break a line"
-msgstr "sonrasında yeni satır yapılacak sağ kenar boşluğu"
-
-msgid "specifies what <BS>, CTRL-W, etc. can do in Insert mode"
-msgstr "<BS>, CTRL-W, vb. Ekleme kipinde ne yapabileceğini belirtir"
-
-msgid "definition of what comment lines look like"
-msgstr "yorum satırlarının nice görüneceğinin tanımı"
-
-msgid "list of flags that tell how automatic formatting works"
-msgstr ""
-"kendiliğinden biçimlendirmenin nice çalıştığını anlatan\n"
-"bayraklar listesi"
-
-msgid "pattern to recognize a numbered list"
-msgstr "numaralandırılmış bir listeyi tanımak için dizgi"
-
-msgid "expression used for \"gq\" to format lines"
-msgstr "satırları biçimlendirmek için \"gq\" için kullanılan ifade"
-
-msgid "specifies how Insert mode completion works for CTRL-N and CTRL-P"
-msgstr ""
-"Ekleme kipi tamamlamasının CTRL-N ve CTRL-P için nice çalıştığını\n"
-"belirler"
-
-msgid "whether to use a popup menu for Insert mode completion"
-msgstr "Ekleme kipi tamamlaması için açılır menü kullanımı"
-
-msgid "options for the Insert mode completion info popup"
-msgstr "Ekleme kipi tamamlama açılır penceresi için seçenekler"
-
-msgid "maximum height of the popup menu"
-msgstr "açılır menünün en çok yüksekliği"
-
-msgid "minimum width of the popup menu"
-msgstr "açılır menünün en çok genişliği"
-
-msgid "user defined function for Insert mode completion"
-msgstr "Ekleme kipi tamamlaması için kullanıcı tanımlı işlev"
-
-msgid "function for filetype-specific Insert mode completion"
-msgstr "dosya türüne özel Ekleme kipi tamamlaması için işlev"
-
-msgid "list of dictionary files for keyword completion"
-msgstr "anahtar sözcük tamamlaması için sözlük dosyaları listesi"
-
-msgid "list of thesaurus files for keyword completion"
-msgstr ""
-"anahtar sözcük tamamlaması için eşanlamlılar sözlüğü dosyaları\n"
-"listesi"
-
-msgid "adjust case of a keyword completion match"
-msgstr "anahtar sözcük tamamlama eşleşmesinin BÜYÜK/küçük harfini ayarla"
-
-msgid "enable entering digraphs with c1 <BS> c2"
-msgstr "c1 <BS> c2 ile ikili harflerin girilmesini etkinleştir"
-
-msgid "the \"~\" command behaves like an operator"
-msgstr "\"~\" komutu bir işleç gibi davranır"
-
-msgid "function called for the \"g@\" operator"
-msgstr "\"g@\" işleci için çağrılan işlev"
-
-msgid "when inserting a bracket, briefly jump to its match"
-msgstr "bir ayraç eklendiğinde hemen eşine atla"
-
-msgid "tenth of a second to show a match for 'showmatch'"
-msgstr "bir 'showmatch' eşleşmesini göstermek için saniyenin onda biri"
-
-msgid "list of pairs that match for the \"%\" command"
-msgstr "\"%\" komutu için eşleşen eşleşmelerin listesi"
-
-msgid "use two spaces after '.' when joining a line"
-msgstr "bir satırı birleştirirken '.' sonrası iki boşluk kullan"
-
-msgid ""
-"\"alpha\", \"octal\", \"hex\", \"bin\" and/or \"unsigned\"; number formats\n"
-"recognized for CTRL-A and CTRL-X commands"
-msgstr ""
-"\"alpha\", \"octal\", \"hex\", \"bin\" ve/veya \"unsigned\"; CTRL-A ve\n"
-"CTRL-X komutları için tanınan sayı biçimleri"
-
-msgid "tabs and indenting"
-msgstr "sekmeler ve girintileme"
-
-msgid "number of spaces a <Tab> in the text stands for"
-msgstr "metinde bir <Tab>'ın denk olduğu boşluk sayısı"
-
-msgid "number of spaces used for each step of (auto)indent"
-msgstr "her bir kendiliğinden girintileme için kullanılan boşluk sayısı"
-
-msgid "list of number of spaces a tab counts for"
-msgstr "bir sekmenin denk olduğu boşlukların sayısının listesi"
-
-msgid "list of number of spaces a soft tabsstop counts for"
-msgstr "bir yumuşak sekmedurağının denk olduğu boşlukların sayısı listesi"
-
-msgid "a <Tab> in an indent inserts 'shiftwidth' spaces"
-msgstr "bir girintideki <Tab>, 'shiftwidth' kadar boşluk ekler"
-
-msgid "if non-zero, number of spaces to insert for a <Tab>"
-msgstr "eğer sıfırdan farklıysa, bir <Tab> için eklenecek boşluk sayısı"
-
-msgid "round to 'shiftwidth' for \"<<\" and \">>\""
-msgstr "\"<<\" ve \">>\" için 'shiftwidth'e yuvarla"
-
-msgid "expand <Tab> to spaces in Insert mode"
-msgstr "Ekleme kipinde <Tab>'ı boşluklara genişlet"
-
-msgid "automatically set the indent of a new line"
-msgstr "yeni bir satırın girintisini kendiliğinden ayarla"
-
-msgid "do clever autoindenting"
-msgstr "akıllı kendiliğinden girintileme yap"
-
-msgid "enable specific indenting for C code"
-msgstr "C kodu için özel girintilemeyi etkinleştir"
-
-msgid "options for C-indenting"
-msgstr "C girintilemesi için seçenekler"
-
-msgid "keys that trigger C-indenting in Insert mode"
-msgstr "Ekleme kipinde C girintilemesini tetikleyen düğmeler"
-
-msgid "list of words that cause more C-indent"
-msgstr "daha çok C girintilemesine neden olan sözcüklerin listesi"
-
-msgid "expression used to obtain the indent of a line"
-msgstr "bir satırın girintisini elde etmek için kullanılan ifade"
-
-msgid "keys that trigger indenting with 'indentexpr' in Insert mode"
-msgstr "Ekleme kipinde 'indentexpr' ile girintilemeyi tetikleyen düğmeler"
-
-msgid "copy whitespace for indenting from previous line"
-msgstr "bir önceki satırdan girintileme için boşlukları kopyala"
-
-msgid "preserve kind of whitespace when changing indent"
-msgstr "girintilemeyi değiştirirken boşluk türünü koru"
-
-msgid "enable lisp mode"
-msgstr "lisp kipini etkinleştir"
-
-msgid "words that change how lisp indenting works"
-msgstr "lisp girintilemesinin nice çalıştığını değiştiren sözcükler"
-
-msgid "folding"
-msgstr "kıvırma"
-
-msgid "unset to display all folds open"
-msgstr "tüm kıvırmaları açık görüntülemek için ayarı kaldır"
-
-msgid "folds with a level higher than this number will be closed"
-msgstr "bu sayıdan daha yüksek düzeyli kıvırmalar kapatılacak"
-
-msgid "value for 'foldlevel' when starting to edit a file"
-msgstr "bir dosyayı düzenlemeye başlarkenki 'foldlevel' değeri"
-
-msgid "width of the column used to indicate folds"
-msgstr "kıvırmaları belirtmek için kullanılan sütunun genişliği"
-
-msgid "expression used to display the text of a closed fold"
-msgstr "kapalı bir kıvırmanın metnini görüntülemek için kullanılan ifade"
-
-msgid "set to \"all\" to close a fold when the cursor leaves it"
-msgstr "imleç ayrıldığında kıvırmayı kapatmak için \"all\" olarak ayarlayın"
-
-msgid "specifies for which commands a fold will be opened"
-msgstr "hangi komutlarda bir kıvırmanın açılacağını belirler"
-
-msgid "minimum number of screen lines for a fold to be closed"
-msgstr "bir kıvırmanın kapatılması için en az ekran satırı sayısı"
-
-msgid "template for comments; used to put the marker in"
-msgstr "yorumlar için şablon; imleyiciyi içine koymak için kullanılır"
-
-msgid ""
-"folding type: \"manual\", \"indent\", \"expr\", \"marker\",\n"
-"\"syntax\" or \"diff\""
-msgstr ""
-"kıvırma türü: \"manual\", \"indent\", \"expr\", \"marker\",\n"
-"\"syntax\" veya \"diff\""
-
-msgid "expression used when 'foldmethod' is \"expr\""
-msgstr "'foldmethod' \"expr\" olduğundan kullanılacak ifade"
-
-msgid "used to ignore lines when 'foldmethod' is \"indent\""
-msgstr "'foldmethod' \"indent\" olduğunda satırları yok saymada kullanılır"
-
-msgid "markers used when 'foldmethod' is \"marker\""
-msgstr "'foldmethod' \"marker\" olduğunda kullanılan imleyiciler"
-
-msgid "maximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\""
-msgstr ""
-"'foldmethod' \"indent\" veya \"syntax\" olduğunda kullanılan en çok\n"
-"kıvırma derinliği"
-
-msgid "diff mode"
-msgstr "diff kipi"
-
-msgid "use diff mode for the current window"
-msgstr "geçerli pencere için diff kipi kullan"
-
-msgid "options for using diff mode"
-msgstr "diff kipi kullanımı için seçenekler"
-
-msgid "expression used to obtain a diff file"
-msgstr "bir diff dosyası elde etmek için kullanılan ifade"
-
-msgid "expression used to patch a file"
-msgstr "bir dosyayı yamalamak için kullanılan ifade"
-
-msgid "mapping"
-msgstr "eşlemleme"
-
-msgid "maximum depth of mapping"
-msgstr "en çok eşlemleme derinliği"
-
-msgid "recognize mappings in mapped keys"
-msgstr "eşlemlenmiş düğmelerdeki eşlemlemeleri tanımla"
-
-msgid "allow timing out halfway into a mapping"
-msgstr "bir eşlemlemenin yarısında zaman aşımına izin ver"
-
-msgid "allow timing out halfway into a key code"
-msgstr "bir düğme kodunun yarısında zaman aşımına izin ver"
-
-msgid "time in msec for 'timeout'"
-msgstr "'timeout' için süre (milisaniye)"
-
-msgid "time in msec for 'ttimeout'"
-msgstr "'ttimeout' için süre (milisaniye)"
-
-msgid "reading and writing files"
-msgstr "dosyaları okuma ve yazma"
-
-msgid "enable using settings from modelines when reading a file"
-msgstr "dosya okurken ayarları kip satırından kullanımı etkinleştir"
-
-msgid "allow setting expression options from a modeline"
-msgstr "ifade seçeneklerini bir kip satırından ayarlamaya izin ver"
-
-msgid "number of lines to check for modelines"
-msgstr "kip satırlarını denetlemede kullanılacak satırların sayısı"
-
-msgid "binary file editing"
-msgstr "ikili dosya düzenleme"
-
-msgid "last line in the file has an end-of-line"
-msgstr "dosyanın son satırında bir satırsonu var"
-
-msgid "fixes missing end-of-line at end of text file"
-msgstr "bir metin dosyasının sonundaki eksik satırsonlarını onarır"
-
-msgid "prepend a Byte Order Mark to the file"
-msgstr "dosyanın önüne bir Bayt Sıralama İmi ekle"
-
-msgid "end-of-line format: \"dos\", \"unix\" or \"mac\""
-msgstr "satırsonu biçimi: \"dos\", \"unix\" veya \"mac\""
-
-msgid "list of file formats to look for when editing a file"
-msgstr "bir dosyayı düzenlerken bakılacak dosya biçimler listesi"
-
-msgid "obsolete, use 'fileformat'"
-msgstr "eskimiş, yerine 'fileformat' kullanın"
-
-msgid "obsolete, use 'fileformats'"
-msgstr "eskimiş, yerine 'fileformats' kullanın"
-
-msgid "writing files is allowed"
-msgstr "dosya yazımına izin verilir"
-
-msgid "write a backup file before overwriting a file"
-msgstr "bir dosyanın üzerine yazmadan önce bir yedek dosyası yaz"
-
-msgid "keep a backup after overwriting a file"
-msgstr "bir dosyanın üzerine yazdıktan sonra bir yedek tut"
-
-msgid "patterns that specify for which files a backup is not made"
-msgstr "bir yedeği yapılmayan dosyaları belirleyen dizgi"
-
-msgid "whether to make the backup as a copy or rename the existing file"
-msgstr "yedeğin kopya olarak mı yoksa ad değişikliği ile mi yapılacağı"
-
-msgid "list of directories to put backup files in"
-msgstr "yedek dosyalarının koyulacağı dizinlerin listesi"
-
-msgid "file name extension for the backup file"
-msgstr "yedek dosyası için dosya adı uzantısı"
-
-msgid "automatically write a file when leaving a modified buffer"
-msgstr "değiştirilmiş arabellekten çıkarken dosyayı kendiliğinden yaz"
-
-msgid "as 'autowrite', but works with more commands"
-msgstr "'autowrite' gibi, ancak daha çok komutla çalışır"
-
-msgid "always write without asking for confirmation"
-msgstr "onay beklemeden her zaman yaz"
-
-msgid "automatically read a file when it was modified outside of Vim"
-msgstr "Vim dışında değiştirildiğinde dosyayı kendiliğinden oku"
-
-msgid "keep oldest version of a file; specifies file name extension"
-msgstr "bir dosyanın en eski sürümünü tut; dosya adı uzantısı belirler"
-
-msgid "forcibly sync the file to disk after writing it"
-msgstr "yazımdan sonra dosyayı zorla diske eşitle"
-
-msgid "use 8.3 file names"
-msgstr "8.3 dosya adlarını kullan"
-
-msgid "encryption method for file writing: zip, blowfish or blowfish2"
-msgstr "dosya yazımı için şifreleme yöntemi: zip, blowfish veya blowfish2"
-
-msgid "the swap file"
-msgstr "takas dosyası"
-
-msgid "list of directories for the swap file"
-msgstr "takas dosyası için dizinler listesi"
-
-msgid "use a swap file for this buffer"
-msgstr "bu arabellek için bir takas dosyası kullan"
-
-msgid "\"sync\", \"fsync\" or empty; how to flush a swap file to disk"
-msgstr ""
-"\"sync\", \"fsync\", veya boş; bir takas dosyasının diske\n"
-"nice floşlanacağı"
-
-msgid "number of characters typed to cause a swap file update"
-msgstr "takas dosyası güncellemesi için yazılması gereken karakter sayısı"
-
-msgid "time in msec after which the swap file will be updated"
-msgstr "takas dosyasının güncelleneceği süre dilimi (milisaniye)"
-
-msgid "maximum amount of memory in Kbyte used for one buffer"
-msgstr "bir arabellek için kullanılacak en çok bellek miktarı (KiB)"
-
-msgid "maximum amount of memory in Kbyte used for all buffers"
-msgstr "tüm arabellekler için kullanılacak en çok bellek miktarı (KiB)"
-
-msgid "command line editing"
-msgstr "komut satırı düzenleme"
-
-msgid "how many command lines are remembered"
-msgstr "kaç tane komut satırının hatırlandığı"
-
-msgid "key that triggers command-line expansion"
-msgstr "komut satırı ifadesi tetikleyen düğme"
-
-msgid "like 'wildchar' but can also be used in a mapping"
-msgstr "'wildchar' gibi; ancak bir eşlemleme içinde kullanılabilir"
-
-msgid "specifies how command line completion works"
-msgstr "komut satırı tamamlamasının nasıl çalıştığını belirtir"
-
-msgid "empty or \"tagfile\" to list file name of matching tags"
-msgstr "eşleşen etiketlerin dosya adını listelemek için boş veya \"tagfile\""
-
-msgid "list of file name extensions that have a lower priority"
-msgstr "düşük öncelikli dosya adı uzantılarının listesi"
-
-msgid "list of file name extensions added when searching for a file"
-msgstr "bir dosya ararken eklenen dosya adı uzantılarının listesi"
-
-msgid "list of patterns to ignore files for file name completion"
-msgstr "dosya adı tamamlaması için yok sayılacak dizgelerin listesi"
-
-msgid "ignore case when using file names"
-msgstr "dosya adları kullanırken BÜYÜK/küçük harf yok say"
-
-msgid "ignore case when completing file names"
-msgstr "dosya adları tamamlarken BÜYÜK/küçük harf yok say"
-
-msgid "command-line completion shows a list of matches"
-msgstr "komut satırı tamamlaması, eşleşmelerin bir listesini gösterir"
-
-msgid "key used to open the command-line window"
-msgstr "komut satırı penceresini açmak için kullanılan düğme"
-
-msgid "height of the command-line window"
-msgstr "komut satırı penceresinin yüksekliği"
-
-msgid "executing external commands"
-msgstr "dış komutları çalıştırma"
-
-msgid "name of the shell program used for external commands"
-msgstr "dış komutlar için kullanılan kabuk programının adı"
-
-msgid "when to use the shell or directly execute a command"
-msgstr "ne zaman kabuğu kullanmalı veya doğrudan bir komut çalıştırmalı"
-
-msgid "character(s) to enclose a shell command in"
-msgstr "bir kabuk komutunu çevreleyen karakter(ler)"
-
-msgid "like 'shellquote' but include the redirection"
-msgstr "'shellquote' gibi; ancak yeniden yönlendirmeyi içer"
-
-msgid "characters to escape when 'shellxquote' is ("
-msgstr "'shellxquote' ( iken kaçırılacak karakterler"
-
-msgid "argument for 'shell' to execute a command"
-msgstr "bir komut çalıştırmak için 'shell' için argüman"
-
-msgid "used to redirect command output to a file"
-msgstr "komut çıktısını bir dosyaya yeniden yönlendirmek için kullanılır"
-
-msgid "use a temp file for shell commands instead of using a pipe"
-msgstr ""
-"bir veri yolu kullanımı yerine kabuk komutları için geçici\n"
-"bir dosya kullan"
-
-msgid "program used for \"=\" command"
-msgstr "\"=\" komutu için kullanılan program"
-
-msgid "program used to format lines with \"gq\" command"
-msgstr "\"gq\" komutu ile satır biçimlemek için kullanılan program"
-
-msgid "program used for the \"K\" command"
-msgstr "\"K\" komutu için kullanılan program"
-
-msgid "warn when using a shell command and a buffer has changes"
-msgstr ""
-"bir kabuk komutu kullanılıyorsa ve arabellekte değişiklikler\n"
-"varsa uyar"
-
-msgid "running make and jumping to errors (quickfix)"
-msgstr "make çalıştırma ve hatalara atlama (hızlı düzelt)"
-
-msgid "name of the file that contains error messages"
-msgstr "hata iletileri içeren dosyanın adı"
-
-msgid "list of formats for error messages"
-msgstr "hata iletileri için biçim listesi"
-
-msgid "program used for the \":make\" command"
-msgstr "\":make\" komutu için kullanılan program"
-
-msgid "string used to put the output of \":make\" in the error file"
-msgstr ""
-"\":make\" komutunun çıktısını hata dosyasına koymak için\n"
-"kullanılan dizi"
-
-msgid "name of the errorfile for the 'makeprg' command"
-msgstr "'makeprg' komutu için hata dosyası adı"
-
-msgid "program used for the \":grep\" command"
-msgstr "\":grep\" komutu için kullanılan program"
-
-msgid "list of formats for output of 'grepprg'"
-msgstr "'grepprg' çıktısı için kullanılan biçimlerin listesi"
-
-msgid "encoding of the \":make\" and \":grep\" output"
-msgstr "\":make\" ve \":grep\" çıktılarının kodlaması"
-
-msgid "function to display text in the quickfix window"
-msgstr "hızlı düzelt içinde metin düzenlemek için işlev"
-
-msgid "system specific"
-msgstr "sisteme özel"
-
-msgid "use forward slashes in file names; for Unix-like shells"
-msgstr "dosya adlarında eğik çizgi kullan; Unix tarzı kabuklar için"
-
-msgid "specifies slash/backslash used for completion"
-msgstr "tamamlama için kullanılan eğik/ters eğik çizgiyi belirler"
-
-msgid "language specific"
-msgstr "dile özel ayarlar"
-
-msgid "specifies the characters in a file name"
-msgstr "bir dosya adındaki karakterleri belirtir"
-
-msgid "specifies the characters in an identifier"
-msgstr "bir tanımlayıcıdaki karakterleri belirler"
-
-msgid "specifies the characters in a keyword"
-msgstr "bir anahtar sözcükteki karakterleri belirler"
-
-msgid "specifies printable characters"
-msgstr "yazdırılabilir karakterleri belirler"
-
-msgid "specifies escape characters in a string"
-msgstr "bir dizideki kaçış karakterlerini belirler"
-
-msgid "display the buffer right-to-left"
-msgstr "arabelleği sağdan sola görüntüle"
-
-msgid "when to edit the command-line right-to-left"
-msgstr "komut satırının ne zaman sağdan sola düzenleneceği"
-
-msgid "insert characters backwards"
-msgstr "karakterleri geriye doğru ekle"
-
-msgid "allow CTRL-_ in Insert and Command-line mode to toggle 'revins'"
-msgstr ""
-"'revins' açıp kapatmak için Ekleme ve Komut Satırı kipinde\n"
-"CTRL-_ izin ver"
-
-msgid "the ASCII code for the first letter of the Hebrew alphabet"
-msgstr "İbran abecesinin ilk harfinin ASCII kodu"
-
-msgid "use Hebrew keyboard mapping"
-msgstr "İbranca klavye eşlemlemesini kullan"
-
-msgid "use phonetic Hebrew keyboard mapping"
-msgstr "fonetik İbranca klavye eşlemlemesini kullan"
-
-msgid "prepare for editing Arabic text"
-msgstr "Arapça metni düzenleme için hazırlan"
-
-msgid "perform shaping of Arabic characters"
-msgstr "Arapça karakterlerin şekillendirmesini gerçekleştir"
-
-msgid "terminal will perform bidi handling"
-msgstr "sağdan sola yazımı uçbirim gerçekleştirecek"
-
-msgid "name of a keyboard mapping"
-msgstr "bir klavye eşlemlemesinin adı"
-
-msgid "list of characters that are translated in Normal mode"
-msgstr "Normal kipte çevrilen karakterlerin listesi"
-
-msgid "apply 'langmap' to mapped characters"
-msgstr "eşlemlenen karakterlere 'langmap' uygula"
-
-msgid "when set never use IM; overrules following IM options"
-msgstr ""
-"ayarlandığında hiçbir zaman IM kullanma; aşağıdaki IM seçeneklerini geçersiz "
-"kılar"
-
-msgid "in Insert mode: 1: use :lmap; 2: use IM; 0: neither"
-msgstr "Ekleme kipinde: 1: :lmap kullan; 2; IM kullan; 0: hiçbiri"
-
-msgid "input method style, 0: on-the-spot, 1: over-the-spot"
-msgstr "girdi yöntemi stili, 0: on-the-spot, 1: over-the-spot"
-
-msgid "entering a search pattern: 1: use :lmap; 2: use IM; 0: neither"
-msgstr "bir arama dizgisi gir: 1: :lmap kullan; 2: IM kullan; 0: hiçbiri"
-
-msgid "when set always use IM when starting to edit a command line"
-msgstr ""
-"ayarlandığında, bir komut satırı düzenlemeye başlarken her zaman IM kullan"
-
-msgid "function to obtain IME status"
-msgstr "IME durumunu elde etmek için işlev"
-
-msgid "function to enable/disable IME"
-msgstr "IME'yi etkinleştirmek/devre dışı bırakmak için işlev"
-
-msgid "multi-byte characters"
-msgstr "çoklu bayt karakterler"
-
-msgid ""
-"character encoding used in Vim: \"latin1\", \"utf-8\",\n"
-"\"euc-jp\", \"big5\", etc."
-msgstr ""
-"Vim'de kullanılan karakter kodlamaları: \"latin1\", \"utf-8\",\n"
-"\"euc-jp\", \"big5\" gibi"
-
-msgid "character encoding for the current file"
-msgstr "geçerli dosya için karakter kodlaması"
-
-msgid "automatically detected character encodings"
-msgstr "karakter kodlamasını kendiliğinden algıla"
-
-msgid "character encoding used by the terminal"
-msgstr "uçbirim tarafından kullanılan karakter kodlaması"
-
-msgid "expression used for character encoding conversion"
-msgstr "karakter kodlaması dönüşümü için kullanılan ifade"
-
-msgid "delete combining (composing) characters on their own"
-msgstr "birleştiren (oluşturucu) karakterleri kendi başına kullan"
-
-msgid "maximum number of combining (composing) characters displayed"
-msgstr "en çok görüntülenen birleştiren (oluşturucu) karakterlerin sayısı"
-
-msgid "key that activates the X input method"
-msgstr "X girdi yöntemini etkinleştiren düğme"
-
-msgid "width of ambiguous width characters"
-msgstr "belirsiz genişlikli karakterlerin genişliği"
-
-msgid "emoji characters are full width"
-msgstr "emoji karakterleri tam genişliklidir"
-
-msgid "various"
-msgstr "çeşitli"
-
-msgid ""
-"when to use virtual editing: \"block\", \"insert\", \"all\"\n"
-"and/or \"onemore\""
-msgstr ""
-"ne zaman sanal düzenleme kullanmalı: \"block\", \"insert\",\n"
-"\"all\" ve/veya \"onemore\""
-
-msgid "list of autocommand events which are to be ignored"
-msgstr "yok sayılacak otokomut olayları"
-
-msgid "load plugin scripts when starting up"
-msgstr "başlarken eklenti betiklerini yükle"
-
-msgid "enable reading .vimrc/.exrc/.gvimrc in the current directory"
-msgstr "geçerli dizinde .vimrc/.exrc/.gvimrc okumayı etkinleştir"
-
-msgid "safer working with script files in the current directory"
-msgstr "geçerli dizinde betik dosyalarıyla daha güvenli çalışma"
-
-msgid "use the 'g' flag for \":substitute\""
-msgstr "\":substitute\" için 'g' bayrağını kullan"
-
-msgid "'g' and 'c' flags of \":substitute\" toggle"
-msgstr "\":substitute\" açma/kapama düğmesinin 'g' ve 'c' bayrakları"
-
-msgid "allow reading/writing devices"
-msgstr "aygıtları okumaya/yazmaya izin ver"
-
-msgid "maximum depth of function calls"
-msgstr "işlev çağrılarının en çok derinliği"
-
-msgid "list of words that specifies what to put in a session file"
-msgstr "bir oturum dosyasına ne koyulacağını belirleyen sözcükler listesi"
-
-msgid "list of words that specifies what to save for :mkview"
-msgstr ":mkview için neyin kaydedileceğini belirleyen sözcükler listesi"
-
-msgid "directory where to store files with :mkview"
-msgstr ":mkview ile dosyaların depolanacağı dizin"
-
-msgid "list that specifies what to write in the viminfo file"
-msgstr "viminfo dosyasına nelerin yazılacağını belirleyen liste"
-
-msgid "file name used for the viminfo file"
-msgstr "viminfo dosyası için kullanılan dosya adı"
-
-msgid "what happens with a buffer when it's no longer in a window"
-msgstr "bir arabellek artık bir pencerede değilken ne olacağı"
-
-msgid "empty, \"nofile\", \"nowrite\", \"quickfix\", etc.: type of buffer"
-msgstr "boş, \"nofile\", \"nowrite\", \"quickfix\" vb.: arabellek türü"
-
-msgid "whether the buffer shows up in the buffer list"
-msgstr "arabelleğin, arabellek listesinde görünüp görünmeyeceği"
-
-msgid "set to \"msg\" to see all error messages"
-msgstr "tüm hata iletilerini görmek için \"msg\" olarak ayarlayın"
-
-msgid "whether to show the signcolumn"
-msgstr "işaret sütununun görünüp görünmeyeceği"
-
-msgid "interval in milliseconds between polls for MzScheme threads"
-msgstr "MzScheme iş parçacıkları için anketler arasındaki süre (milisaniye)"
-
-msgid "name of the Lua dynamic library"
-msgstr "Lua devingen kitaplığının adı"
-
-msgid "name of the Perl dynamic library"
-msgstr "Perl devingen kitaplığının adı"
-
-msgid "whether to use Python 2 or 3"
-msgstr "Python 2 veya 3 mü kullanılacağı"
-
-msgid "name of the Python 2 dynamic library"
-msgstr "Python 2 devingen kitaplığının adı"
+msgid "Already only one window"
+msgstr "Zaten tek pencere"
-msgid "name of the Python 2 home directory"
-msgstr "Python 2 ev dizininin adı"
+msgid "E441: There is no preview window"
+msgstr "E441: Önizleme penceresi yok"
-msgid "name of the Python 3 dynamic library"
-msgstr "Python 3 devingen kitaplığının adı"
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Üst sol ve alt sağ pencereler aynı anda bölünemez"
-msgid "name of the Python 3 home directory"
-msgstr "Python 3 ev dizininin adı"
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Başka bir pencere bölünmüşken döndürme yapılamaz"
-msgid "name of the Ruby dynamic library"
-msgstr "Ruby devingen kitaplığının adı"
+msgid "E444: Cannot close last window"
+msgstr "E444: Son pencere kapatılamıyor"
-msgid "name of the Tcl dynamic library"
-msgstr "Tcl devingen kitaplığının adı"
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Pencere kapatılamıyor, yalnızca otokomut penceresi açık kalır"
-msgid "name of the MzScheme dynamic library"
-msgstr "MzScheme devingen kitaplığının adı"
+msgid "E445: Other window contains changes"
+msgstr "E445: Diğer pencerede değişiklikler var"
-msgid "name of the MzScheme GC dynamic library"
-msgstr "MzScheme GC devingen kitaplığının adı"
+msgid "E446: No file name under cursor"
+msgstr "E446: İmleç altında bir dosya adı yok"
diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po
index 9a8cd38f5e..70c1389d7f 100644
--- a/src/nvim/po/zh_CN.UTF-8.po
+++ b/src/nvim/po/zh_CN.UTF-8.po
@@ -32,7 +32,7 @@ msgstr "选项参数后的内容无效"
#: ../api/private/helpers.c:204
msgid "internal error: unknown option type"
-msgstr ""
+msgstr "内部错误:未知的选项类型"
#: ../buffer.c:92
msgid "[Location List]"
@@ -44,7 +44,7 @@ msgstr "[Quickfix 列表]"
#: ../buffer.c:94
msgid "E855: Autocommands caused command to abort"
-msgstr ""
+msgstr "E855: 自动命令导致命令被停止"
#: ../buffer.c:135
msgid "E82: Cannot allocate any buffer, exiting..."
@@ -336,7 +336,7 @@ msgstr "E105: 不是在脚本文件中使用 :loadkeymap "
#: ../digraph.c:1821
msgid "E791: Empty keymap entry"
-msgstr ""
+msgstr "E791: 空的键位映射项"
#: ../edit.c:82
msgid " Keyword completion (^N^P)"
@@ -401,11 +401,11 @@ msgstr "已到段落结尾"
#: ../edit.c:101
msgid "E839: Completion function changed window"
-msgstr ""
+msgstr "E839: 补全函数更改了窗口"
#: ../edit.c:102
msgid "E840: Completion function deleted text"
-msgstr ""
+msgstr "E840: 补全函数删除了文本"
#: ../edit.c:1847
msgid "'dictionary' option is empty"
@@ -1209,6 +1209,9 @@ msgid ""
"It may still be possible to write it.\n"
"Do you wish to try?"
msgstr ""
+"此文件权限 \"%s\" 是只读的。\n"
+"它仍然有可能被写入。\n"
+"你想继续尝试吗?"
#: ../ex_cmds.c:2451
#, fuzzy, c-format
@@ -1519,7 +1522,7 @@ msgstr "环境变量"
#: ../ex_cmds2.c:2773
msgid "error handler"
-msgstr ""
+msgstr "错误的处理程序"
#: ../ex_cmds2.c:3020
msgid "W15: Warning: Wrong line separator, ^M may be missing"
@@ -1836,7 +1839,7 @@ msgstr "捕获异常: %s"
#: ../ex_eval.c:676
#, c-format
msgid "%s made pending"
-msgstr ""
+msgstr "%s 待定"
#: ../ex_eval.c:679
#, fuzzy, c-format
@@ -1846,7 +1849,7 @@ msgstr " 已返回\n"
#: ../ex_eval.c:683
#, c-format
msgid "%s discarded"
-msgstr ""
+msgstr "%s 舍弃"
#: ../ex_eval.c:708
msgid "Exception"
@@ -2005,7 +2008,7 @@ msgstr "E199: 活动窗口或缓冲区已被删除"
#: ../file_search.c:203
msgid "E854: path too long for completion"
-msgstr ""
+msgstr "E854: 补全用的路径太长"
#: ../file_search.c:446
#, c-format
@@ -2432,7 +2435,7 @@ msgstr "--已删除--"
#: ../fileio.c:5732
#, c-format
msgid "auto-removing autocommand: %s <buffer=%d>"
-msgstr ""
+msgstr "自动删除自动命令: %s <buffer=%d>"
#. the group doesn't exist
#: ../fileio.c:5772
@@ -2671,7 +2674,7 @@ msgstr "E49: 无效的滚动大小"
#: ../globals.h:1021
msgid "E901: Job table is full"
-msgstr ""
+msgstr "E901: 任务表已经满"
#: ../globals.h:1024
#, c-format
@@ -3215,6 +3218,7 @@ msgstr "%-5s: %-30s (用法: %s)"
#: ../if_cscope.c:1155
msgid ""
"\n"
+" a: Find assignments to this symbol\n"
" c: Find functions calling this function\n"
" d: Find functions called by this function\n"
" e: Find this egrep pattern\n"
@@ -3224,6 +3228,16 @@ msgid ""
" s: Find this C symbol\n"
" t: Find this text string\n"
msgstr ""
+"\n"
+" a: 搜索对此符号的赋值\n"
+" c: 搜索调用此函数的函数\n"
+" d: 搜索此函数调用的函数\n"
+" e: 搜索此 egrep 模式\n"
+" f: 搜索此文件\n"
+" g: 搜索此定义\n"
+" i: 搜索包含此文件的文件\n"
+" s: 搜索此 C 符号\n"
+" t: 搜索此文本字符串\n"
#: ../if_cscope.c:1226
msgid "E568: duplicate cscope database not added"
@@ -3455,7 +3469,7 @@ msgstr "-N\t\t\t不完全兼容传统的 Vi: 'nocompatible'"
#: ../main.c:2215
msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
-msgstr ""
+msgstr "-V[N][fname]\t\t详细 [level N] [log messages to fname]"
#: ../main.c:2216
msgid "-D\t\t\tDebugging mode"
@@ -3547,7 +3561,7 @@ msgstr "-W <scriptout>\t将所有输入的命令写入到文件 <scriptout>"
#: ../main.c:2240
msgid "--startuptime <file>\tWrite startup timing messages to <file>"
-msgstr ""
+msgstr "--startuptime <file>\t将启动时间信息写入到文件 <file>"
#: ../main.c:2242
msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
@@ -3738,7 +3752,7 @@ msgstr ""
#: ../memline.c:945
msgid " has been damaged (page size is smaller than minimum value).\n"
-msgstr ""
+msgstr "已损坏(页面大小小于最小值)。\n"
#: ../memline.c:974
#, c-format
@@ -3844,7 +3858,7 @@ msgstr "再运行 diff 与原文件比较以检查是否有改变)\n"
#: ../memline.c:1254
msgid "Recovery completed. Buffer contents equals file contents."
-msgstr ""
+msgstr "恢复完成。缓冲区内容与文件内容相同。"
#: ../memline.c:1255
#, fuzzy
@@ -4553,7 +4567,7 @@ msgstr ""
#: ../option.c:1238
msgid "%<%f%h%m%=Page %N"
-msgstr ""
+msgstr "%<%f%h%m%=页 %N"
#: ../option.c:1574
msgid "Thanks for flying Vim"
@@ -4574,7 +4588,7 @@ msgstr "E520: 不允许在 modeline 中使用"
#: ../option.c:2815
msgid "E846: Key code not set"
-msgstr ""
+msgstr "E846: 未设置键位代码"
#: ../option.c:2924
msgid "E521: Number required after ="
@@ -4599,11 +4613,11 @@ msgstr "E589: 'backupext' 和 'patchmode' 相等"
#: ../option.c:3964
msgid "E834: Conflicts with value of 'listchars'"
-msgstr ""
+msgstr "E834: 与'listchars'中的值发生冲突"
#: ../option.c:3966
msgid "E835: Conflicts with value of 'fillchars'"
-msgstr ""
+msgstr "E835: 与'fillchars'中的值冲突"
#: ../option.c:4163
msgid "E524: Missing colon"
@@ -4978,49 +4992,50 @@ msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
"used "
msgstr ""
+"E864: \\%#= 后面只能是0,1,或者2。自动引擎将会被使用"
#: ../regexp_nfa.c:239
msgid "E865: (NFA) Regexp end encountered prematurely"
-msgstr ""
+msgstr "E865: (NFA) 过早地遇到了正则表达式的结尾"
#: ../regexp_nfa.c:240
#, c-format
msgid "E866: (NFA regexp) Misplaced %c"
-msgstr ""
+msgstr "E866: (NFA regexp) %c 放错了位置"
#: ../regexp_nfa.c:242
#, c-format
msgid "E877: (NFA regexp) Invalid character class: %<PRId64>"
-msgstr ""
+msgstr "E877: (NFA regexp) 不可用的字符类: %<PRId64>"
#: ../regexp_nfa.c:1261
#, c-format
msgid "E867: (NFA) Unknown operator '\\z%c'"
-msgstr ""
+msgstr "E867: (NFA) 未知的操作符 '\\z%c'"
#: ../regexp_nfa.c:1387
#, c-format
msgid "E867: (NFA) Unknown operator '\\%%%c'"
-msgstr ""
+msgstr "E867: (NFA) 未知的操作符 '\\%%%c'"
#: ../regexp_nfa.c:1802
#, c-format
msgid "E869: (NFA) Unknown operator '\\@%c'"
-msgstr ""
+msgstr "E869: (NFA) 未知的操作符 '\\@%c'"
#: ../regexp_nfa.c:1831
msgid "E870: (NFA regexp) Error reading repetition limits"
-msgstr ""
+msgstr "E870: (NFA regexp) 读取重复限制时出错"
#. Can't have a multi follow a multi.
#: ../regexp_nfa.c:1895
msgid "E871: (NFA regexp) Can't have a multi follow a multi !"
-msgstr ""
+msgstr "E871: (NFA regexp) 不能多个跟多个!"
#. Too many `('
#: ../regexp_nfa.c:2037
msgid "E872: (NFA regexp) Too many '('"
-msgstr ""
+msgstr "E872: (NFA regexp) 太多 '('"
#: ../regexp_nfa.c:2042
#, fuzzy
@@ -5029,31 +5044,32 @@ msgstr "E50: 太多 \\z("
#: ../regexp_nfa.c:2066
msgid "E873: (NFA regexp) proper termination error"
-msgstr ""
+msgstr "E873: (NFA regexp) 未适当终止"
#: ../regexp_nfa.c:2599
msgid "E874: (NFA) Could not pop the stack !"
-msgstr ""
+msgstr "E874: (NFA) 无法出栈!"
#: ../regexp_nfa.c:3298
msgid ""
"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
"left on stack"
-msgstr ""
+msgstr "E875: (NFA regexp) (从后缀转换到 NFA 时),栈上遗留了太多状态"
#: ../regexp_nfa.c:3302
msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
-msgstr ""
+msgstr "E876: (NFA regexp) 没有足够的空间存储整个NFA "
#: ../regexp_nfa.c:4571 ../regexp_nfa.c:4869
msgid ""
"Could not open temporary log file for writing, displaying on stderr ... "
msgstr ""
+"无法打开临时日志文件进行写入,显示在 stderr 中..."
#: ../regexp_nfa.c:4840
#, c-format
msgid "(NFA) COULD NOT OPEN %s !"
-msgstr ""
+msgstr "(NFA) 不能打开 %s !"
#: ../regexp_nfa.c:6049
#, fuzzy
@@ -5218,6 +5234,9 @@ msgid ""
"# Last %sSearch Pattern:\n"
"~"
msgstr ""
+"\n"
+"# 最后 %s搜索模式:\n"
+"~"
#: ../spell.c:951
msgid "E759: Format error in spell file"
@@ -5314,14 +5333,16 @@ msgstr "%s 第 %d 行,在使用标志后出现 FLAG: %s"
msgid ""
"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
"%d"
-msgstr ""
+msgstr "在 PFX 项之后定义 COMPOUNDFORBIDFLAG (%s 第%d行)可能会给出错误的结果"
+"%d"
#: ../spell.c:4731
#, c-format
msgid ""
"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
"%d"
-msgstr ""
+msgstr "在 PFX 项之后定义 COMPOUNDPERMITFLAG (%s 第%d行)可能会给出错误的结果"
+"%d"
#: ../spell.c:4747
#, fuzzy, c-format
@@ -5486,7 +5507,7 @@ msgstr "读取单词文件 %s ……"
#: ../spell.c:6155
#, c-format
msgid "Duplicate /encoding= line ignored in %s line %d: %s"
-msgstr ""
+msgstr "%s 第 %ld 行,重复的 /encoding= 行已被忽略: %s"
#: ../spell.c:6159
#, c-format
@@ -5641,17 +5662,17 @@ msgstr "E778: 看起来不像是 .sug 文件: %s"
#: ../spell.c:9282
#, c-format
msgid "E779: Old .sug file, needs to be updated: %s"
-msgstr ""
+msgstr "E779: 旧的.sug 文件,需要更新: %s"
#: ../spell.c:9286
#, c-format
msgid "E780: .sug file is for newer version of Vim: %s"
-msgstr ""
+msgstr "E780: .sug 文件适用于较新的vim 版本: %s"
#: ../spell.c:9295
#, c-format
msgid "E781: .sug file doesn't match .spl file: %s"
-msgstr ""
+msgstr "E781: .sug 文件不能匹配 .spl 文件: %s"
#: ../spell.c:9305
#, fuzzy, c-format
@@ -5662,7 +5683,7 @@ msgstr "E47: 读取错误文件失败"
#. file.
#: ../spell.c:11575
msgid "E783: duplicate char in MAP entry"
-msgstr ""
+msgstr "E783: MAP 条目中有重复的字符"
#: ../syntax.c:266
msgid "No Syntax items defined for this buffer"
@@ -5927,7 +5948,7 @@ msgstr "W18: 组名中含有无效字符"
#: ../syntax.c:7448
msgid "E849: Too many highlight and syntax groups"
-msgstr ""
+msgstr "E849: 高亮和语法组过多"
#: ../tag.c:104
msgid "E555: at bottom of tag stack"
@@ -6002,7 +6023,7 @@ msgstr "查找 tag 文件 %s"
#: ../tag.c:1545
msgid "Ignoring long line in tags file"
-msgstr ""
+msgstr "忽略较长的行在 tags 文件中"
#: ../tag.c:1915
#, c-format
@@ -6094,25 +6115,25 @@ msgstr "E212: 无法打开并写入文件"
#: ../undo.c:717
#, c-format
msgid "E825: Corrupted undo file (%s): %s"
-msgstr ""
+msgstr "E825: 已损坏的撤销文件 (%s): %s"
#: ../undo.c:1039
msgid "Cannot write undo file in any directory in 'undodir'"
-msgstr ""
+msgstr "不能写入撤销文件到 'undodir' 中的任何文件夹"
#: ../undo.c:1074
#, c-format
msgid "Will not overwrite with undo file, cannot read: %s"
-msgstr ""
+msgstr "不能重写撤销文件, 不可读取: %s"
#: ../undo.c:1092
#, c-format
msgid "Will not overwrite, this is not an undo file: %s"
-msgstr ""
+msgstr "这个文件: %s 不是撤销文件,不可以重写"
#: ../undo.c:1108
msgid "Skipping undo file write, nothing to undo"
-msgstr ""
+msgstr "跳过写入撤销文件,没有任何撤销"
#: ../undo.c:1121
#, fuzzy, c-format
@@ -6127,7 +6148,7 @@ msgstr "E297: 交换文件写入错误"
#: ../undo.c:1280
#, c-format
msgid "Not reading undo file, owner differs: %s"
-msgstr ""
+msgstr "不能读取撤销文件, 所有者不同: %s"
#: ../undo.c:1292
#, fuzzy, c-format
@@ -6151,7 +6172,7 @@ msgstr "E484: 无法打开文件 %s"
#: ../undo.c:1328
msgid "File contents changed, cannot use undo info"
-msgstr ""
+msgstr "文件内容已改变,不能使用撤销信息"
#: ../undo.c:1497
#, fuzzy, c-format
@@ -6218,7 +6239,7 @@ msgstr "无可撤销"
#: ../undo.c:2330
msgid "number changes when saved"
-msgstr ""
+msgstr " 编号 变更 时间 保存"
#: ../undo.c:2360
#, fuzzy, c-format
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 625fd15886..4accddfce0 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -19,6 +19,7 @@
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/highlight.h"
+#include "nvim/insexpand.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/menu.h"
@@ -1105,7 +1106,10 @@ void pum_show_popupmenu(vimmenu_T *menu)
ui_flush();
int c = vgetc();
- if (c == ESC || c == Ctrl_C) {
+
+ // Bail out when typing Esc, CTRL-C or some callback or <expr> mapping
+ // closed the popup menu.
+ if (c == ESC || c == Ctrl_C || pum_array == NULL) {
break;
} else if (c == CAR || c == NL) {
// enter: select current item, if any, and close
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2138437b29..9b46fad67a 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -270,10 +270,8 @@ static qf_delq_T *qf_delq_head = NULL;
static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T *state,
qffields_T *fields)
{
- int status;
-
// Get the next line from a file/buffer/list/string
- status = qf_get_nextline(state);
+ int status = qf_get_nextline(state);
if (status != QF_OK) {
return status;
}
@@ -547,9 +545,7 @@ static void free_efm_list(efm_T **efm_first)
/// a regular expression pattern.
static size_t efm_regpat_bufsz(char *efm)
{
- size_t sz;
-
- sz = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2);
+ size_t sz = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2);
for (int i = FMT_PATTERNS - 1; i >= 0;) {
sz += STRLEN(fmt_pat[i--].pattern);
}
@@ -581,10 +577,8 @@ static int efm_option_part_len(char *efm)
/// the parsed 'errorformat' option.
static efm_T *parse_efm_option(char *efm)
{
- efm_T *fmt_ptr = NULL;
efm_T *fmt_first = NULL;
efm_T *fmt_last = NULL;
- int len;
// Get some space to modify the format string into.
size_t sz = efm_regpat_bufsz(efm);
@@ -592,7 +586,7 @@ static efm_T *parse_efm_option(char *efm)
while (efm[0] != NUL) {
// Allocate a new eformat structure and put it at the end of the list
- fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T));
+ efm_T *fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T));
if (fmt_first == NULL) { // first one
fmt_first = fmt_ptr;
} else {
@@ -601,7 +595,7 @@ static efm_T *parse_efm_option(char *efm)
fmt_last = fmt_ptr;
// Isolate one part in the 'errorformat' option
- len = efm_option_part_len(efm);
+ int len = efm_option_part_len(efm);
if (efm_to_regpat(efm, len, fmt_ptr, fmtstr) == FAIL) {
goto parse_efm_error;
@@ -649,19 +643,13 @@ static int qf_get_next_str_line(qfstate_T *state)
{
// Get the next line from the supplied string
char *p_str = state->p_str;
- char *p;
- size_t len;
if (*p_str == NUL) { // Reached the end of the string
return QF_END_OF_INPUT;
}
- p = vim_strchr(p_str, '\n');
- if (p != NULL) {
- len = (size_t)(p - p_str) + 1;
- } else {
- len = STRLEN(p_str);
- }
+ char *p = vim_strchr(p_str, '\n');
+ size_t len = (p != NULL) ? (size_t)(p - p_str) + 1 : STRLEN(p_str);
if (len > IOSIZE - 2) {
state->linebuf = qf_grow_linebuf(state, len);
@@ -684,7 +672,6 @@ static int qf_get_next_str_line(qfstate_T *state)
static int qf_get_next_list_line(qfstate_T *state)
{
listitem_T *p_li = state->p_li;
- size_t len;
// Get the next line from the supplied list
while (p_li != NULL
@@ -698,7 +685,7 @@ static int qf_get_next_list_line(qfstate_T *state)
return QF_END_OF_INPUT;
}
- len = STRLEN(TV_LIST_ITEM_TV(p_li)->vval.v_string);
+ size_t len = STRLEN(TV_LIST_ITEM_TV(p_li)->vval.v_string);
if (len > IOSIZE - 2) {
state->linebuf = qf_grow_linebuf(state, len);
} else {
@@ -716,17 +703,14 @@ static int qf_get_next_list_line(qfstate_T *state)
/// Get the next string from state->buf.
static int qf_get_next_buf_line(qfstate_T *state)
{
- char *p_buf = NULL;
- size_t len;
-
// Get the next line from the supplied buffer
if (state->buflnum > state->lnumlast) {
return QF_END_OF_INPUT;
}
- p_buf = (char *)ml_get_buf(state->buf, state->buflnum, false);
+ char *p_buf = (char *)ml_get_buf(state->buf, state->buflnum, false);
state->buflnum += 1;
- len = STRLEN(p_buf);
+ size_t len = STRLEN(p_buf);
if (len > IOSIZE - 2) {
state->linebuf = qf_grow_linebuf(state, len);
} else {
@@ -741,8 +725,6 @@ static int qf_get_next_buf_line(qfstate_T *state)
/// Get the next string from file state->fd.
static int qf_get_next_file_line(qfstate_T *state)
{
- size_t growbuflen;
-
retry:
errno = 0;
if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
@@ -765,7 +747,7 @@ retry:
// Copy the read part of the line, excluding null-terminator
memcpy(state->growbuf, IObuff, IOSIZE - 1);
- growbuflen = state->linelen;
+ size_t growbuflen = state->linelen;
for (;;) {
errno = 0;
@@ -1071,16 +1053,11 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu
linenr_T lnumlast, const char *restrict qf_title, char *restrict enc)
FUNC_ATTR_NONNULL_ARG(1)
{
- qf_list_T *qfl;
qfstate_T state = { 0 };
qffields_T fields = { 0 };
- qfline_T *old_last = NULL;
- bool adding = false;
static efm_T *fmt_first = NULL;
- char *efm;
static char *last_efm = NULL;
int retval = -1; // default: return error flag
- int status;
// Do not used the cached buffer, it may have been wiped out.
XFREE_CLEAR(qf_last_bufname);
@@ -1090,6 +1067,9 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu
goto qf_init_end;
}
+ qf_list_T *qfl;
+ qfline_T *old_last = NULL;
+ bool adding = false;
if (newlist || qf_idx == qi->qf_listcount) {
// make place for a new list
qf_new_list(qi, qf_title);
@@ -1104,6 +1084,8 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu
}
}
+ char *efm;
+
// Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
efm = (char *)buf->b_p_efm;
@@ -1136,7 +1118,7 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu
// Read the lines in the error file one by one.
// Try to recognize one of the error formats in each line.
while (!got_int) {
- status = qf_init_process_nextline(qfl, fmt_first, &state, &fields);
+ int status = qf_init_process_nextline(qfl, fmt_first, &state, &fields);
if (status == QF_END_OF_INPUT) { // end of input
break;
}
@@ -1223,9 +1205,6 @@ static qf_list_T *qf_get_curlist(qf_info_T *qi)
/// the new list is added.
static void qf_new_list(qf_info_T *qi, const char *qf_title)
{
- int i;
- qf_list_T *qfl;
-
// If the current entry is not the last entry, delete entries beyond
// the current entry. This makes it possible to browse in a tree-like
// way with ":grep".
@@ -1237,14 +1216,14 @@ static void qf_new_list(qf_info_T *qi, const char *qf_title)
// Otherwise, add a new entry.
if (qi->qf_listcount == LISTCOUNT) {
qf_free(&qi->qf_lists[0]);
- for (i = 1; i < LISTCOUNT; i++) {
+ for (int i = 1; i < LISTCOUNT; i++) {
qi->qf_lists[i - 1] = qi->qf_lists[i];
}
qi->qf_curlist = LISTCOUNT - 1;
} else {
qi->qf_curlist = qi->qf_listcount++;
}
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
memset(qfl, 0, sizeof(qf_list_T));
qf_store_title(qfl, qf_title);
qfl->qfl_type = qi->qfl_type;
@@ -1255,14 +1234,12 @@ static void qf_new_list(qf_info_T *qi, const char *qf_title)
/// Return the matched value in "fields->namebuf".
static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
{
- char c;
-
if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) {
return QF_FAIL;
}
// Expand ~/file and $HOME/file to full path.
- c = (char)(*rmp->endp[midx]);
+ char c = (char)(*rmp->endp[midx]);
*rmp->endp[midx] = NUL;
expand_env(rmp->startp[midx], (char_u *)fields->namebuf, CMDBUFFSIZE);
*rmp->endp[midx] = (char_u)c;
@@ -1360,12 +1337,10 @@ static void qf_parse_fmt_plus(const char *linebuf, size_t linelen, qffields_T *f
/// Return the matched value in "fields->errmsg".
static int qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields)
{
- size_t len;
-
if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) {
return QF_FAIL;
}
- len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
+ size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
if (len >= fields->errmsglen) {
// len + null terminator
fields->errmsg = xrealloc(fields->errmsg, len + 1);
@@ -1390,13 +1365,11 @@ static int qf_parse_fmt_r(regmatch_T *rmp, int midx, char **tail)
/// Return the matched value in "fields->col".
static int qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields)
{
- char *match_ptr;
-
if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) {
return QF_FAIL;
}
fields->col = 0;
- for (match_ptr = (char *)rmp->startp[midx]; (char_u *)match_ptr != rmp->endp[midx];
+ for (char *match_ptr = (char *)rmp->startp[midx]; (char_u *)match_ptr != rmp->endp[midx];
match_ptr++) {
fields->col++;
if (*match_ptr == TAB) {
@@ -1425,12 +1398,10 @@ static int qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields)
/// Return the matched value in "fields->pattern".
static int qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
{
- size_t len;
-
if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) {
return QF_FAIL;
}
- len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
+ size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
if (len > CMDBUFFSIZE - 5) {
len = CMDBUFFSIZE - 5;
}
@@ -1446,14 +1417,11 @@ static int qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
/// Return the matched value in "fields->module".
static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
{
- size_t len;
- size_t dsize;
-
if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) {
return QF_FAIL;
}
- len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
- dsize = STRLEN(fields->module) + len + 1;
+ size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]);
+ size_t dsize = STRLEN(fields->module) + len + 1;
if (dsize > CMDBUFFSIZE) {
dsize = CMDBUFFSIZE;
}
@@ -1489,9 +1457,6 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc
qffields_T *fields, int qf_multiline, int qf_multiscan, char **tail)
{
char idx = fmt_ptr->prefix;
- int i;
- int midx;
- int status;
if ((idx == 'C' || idx == 'Z') && !qf_multiline) {
return QF_FAIL;
@@ -1505,9 +1470,9 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc
// Extract error message data from matched line.
// We check for an actual submatch, because "\[" and "\]" in
// the 'errorformat' may cause the wrong submatch to be used.
- for (i = 0; i < FMT_PATTERNS; i++) {
- status = QF_OK;
- midx = (int)fmt_ptr->addr[i];
+ for (int i = 0; i < FMT_PATTERNS; i++) {
+ int status = QF_OK;
+ int midx = (int)fmt_ptr->addr[i];
if (i == 0 && midx > 0) { // %f
status = qf_parse_fmt_f(regmatch, midx, fields, idx);
} else if (i == FMT_PATTERN_M) {
@@ -1537,10 +1502,6 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc
static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qffields_T *fields,
int qf_multiline, int qf_multiscan, char **tail)
{
- regmatch_T regmatch;
- int status = QF_FAIL;
- int r;
-
if (qf_multiscan && vim_strchr("OPQ", fmt_ptr->prefix) == NULL) {
return QF_FAIL;
}
@@ -1560,11 +1521,13 @@ static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qf
fields->type = 0;
*tail = NULL;
+ regmatch_T regmatch;
// Always ignore case when looking for a matching error.
regmatch.rm_ic = true;
regmatch.regprog = fmt_ptr->prog;
- r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
+ int r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
fmt_ptr->prog = regmatch.regprog;
+ int status = QF_FAIL;
if (r) {
status = qf_parse_match(linebuf, linelen, fmt_ptr, &regmatch, fields,
qf_multiline, qf_multiscan, tail);
@@ -1689,9 +1652,7 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
/// Queue location list stack delete request.
static void locstack_queue_delreq(qf_info_T *qi)
{
- qf_delq_T *q;
-
- q = xmalloc(sizeof(qf_delq_T));
+ qf_delq_T *q = xmalloc(sizeof(qf_delq_T));
q->qi = qi;
q->next = qf_delq_head;
qf_delq_head = q;
@@ -1722,10 +1683,7 @@ static void wipe_qf_buffer(qf_info_T *qi)
/// Free a location list stack
static void ll_free_all(qf_info_T **pqi)
{
- int i;
- qf_info_T *qi;
-
- qi = *pqi;
+ qf_info_T *qi = *pqi;
if (qi == NULL) {
return;
}
@@ -1744,7 +1702,7 @@ static void ll_free_all(qf_info_T **pqi)
// If the quickfix window buffer is loaded, then wipe it
wipe_qf_buffer(qi);
- for (i = 0; i < qi->qf_listcount; i++) {
+ for (int i = 0; i < qi->qf_listcount; i++) {
qf_free(qf_get_list(qi, i));
}
xfree(qi);
@@ -1754,16 +1712,14 @@ static void ll_free_all(qf_info_T **pqi)
/// Free all the quickfix/location lists in the stack.
void qf_free_all(win_T *wp)
{
- int i;
- qf_info_T *qi = &ql_info;
-
if (wp != NULL) {
// location list
ll_free_all(&wp->w_llist);
ll_free_all(&wp->w_llist_ref);
} else {
// quickfix list
- for (i = 0; i < qi->qf_listcount; i++) {
+ qf_info_T *qi = &ql_info;
+ for (int i = 0; i < qi->qf_listcount; i++) {
qf_free(qf_get_list(qi, i));
}
}
@@ -1837,7 +1793,6 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in
char vis_col, char *pattern, int nr, char type, char valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
- qfline_T **lastp; // pointer to qf_last or NULL
if (bufnum != 0) {
buf_T *buf = buflist_findnr(bufnum);
@@ -1873,7 +1828,7 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in
qfp->qf_type = type;
qfp->qf_valid = valid;
- lastp = &qfl->qf_last;
+ qfline_T **lastp = &qfl->qf_last;
if (qf_list_empty(qfl)) {
// first element in the list
qfl->qf_start = qfp;
@@ -2060,16 +2015,10 @@ static int copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
void copy_loclist_stack(win_T *from, win_T *to)
FUNC_ATTR_NONNULL_ALL
{
- qf_info_T *qi;
-
// When copying from a location list window, copy the referenced
// location list. For other windows, copy the location list for
// that window.
- if (IS_LL_WINDOW(from)) {
- qi = from->w_llist_ref;
- } else {
- qi = from->w_llist;
- }
+ qf_info_T *qi = IS_LL_WINDOW(from) ? from->w_llist_ref : from->w_llist;
if (qi == NULL) { // no location list to copy
return;
@@ -2213,14 +2162,12 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi
// stack is empty
static char *qf_pop_dir(struct dir_stack_T **stackptr)
{
- struct dir_stack_T *ds_ptr;
-
// TODO(vim): Should we check if dirbuf is the directory on top of the stack?
// What to do if it isn't?
// pop top element and free it
if (*stackptr != NULL) {
- ds_ptr = *stackptr;
+ struct dir_stack_T *ds_ptr = *stackptr;
*stackptr = (*stackptr)->next;
xfree(ds_ptr->dirname);
xfree(ds_ptr);
@@ -2262,17 +2209,13 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
/// qf_guess_filepath will return NULL.
static char *qf_guess_filepath(qf_list_T *qfl, char *filename)
{
- struct dir_stack_T *ds_ptr;
- struct dir_stack_T *ds_tmp;
- char *fullname;
-
// no dirs on the stack - there's nothing we can do
if (qfl->qf_dir_stack == NULL) {
return NULL;
}
- ds_ptr = qfl->qf_dir_stack->next;
- fullname = NULL;
+ struct dir_stack_T *ds_ptr = qfl->qf_dir_stack->next;
+ char *fullname = NULL;
while (ds_ptr) {
xfree(fullname);
fullname = concat_fnames(ds_ptr->dirname, filename, true);
@@ -2288,7 +2231,7 @@ static char *qf_guess_filepath(qf_list_T *qfl, char *filename)
// clean up all dirs we already left
while (qfl->qf_dir_stack->next != ds_ptr) {
- ds_tmp = qfl->qf_dir_stack->next;
+ struct dir_stack_T *ds_tmp = qfl->qf_dir_stack->next;
qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
xfree(ds_tmp->dirname);
xfree(ds_tmp);
@@ -2392,13 +2335,11 @@ static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr, int dir, int *
{
qfline_T *qf_ptr = qfl->qf_ptr;
int qf_idx = qfl->qf_index;
- qfline_T *prev_qf_ptr;
- int prev_index;
char *err = e_no_more_items;
while (errornr--) {
- prev_qf_ptr = qf_ptr;
- prev_index = qf_idx;
+ qfline_T *prev_qf_ptr = qf_ptr;
+ int prev_index = qf_idx;
if (dir == FORWARD || dir == FORWARD_FILE) {
qf_ptr = get_next_valid_entry(qfl, qf_ptr, &qf_idx, dir);
@@ -2802,11 +2743,9 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
/// a search pattern.
static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char *qf_pattern)
{
- linenr_T i;
-
if (qf_pattern == NULL) {
// Go to line with error, unless qf_lnum is 0.
- i = qf_lnum;
+ linenr_T i = qf_lnum;
if (i > 0) {
if (i > curbuf->b_ml.ml_line_count) {
i = curbuf->b_ml.ml_line_count;
@@ -2933,14 +2872,11 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int
static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int forceit,
int prev_winid, int *opened_window, int openfold, int print_message)
{
- buf_T *old_curbuf;
- linenr_T old_lnum;
- int retval = OK;
-
// If there is a file name, read the wanted file if needed, and check
// autowrite etc.
- old_curbuf = curbuf;
- old_lnum = curwin->w_cursor.lnum;
+ buf_T *old_curbuf = curbuf;
+ linenr_T old_lnum = curwin->w_cursor.lnum;
+ int retval = OK;
if (qf_ptr->qf_fnum != 0) {
retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, prev_winid,
@@ -2984,18 +2920,9 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
// If 'newwin' is true, then open the file in a new window.
static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, bool newwin)
{
- qf_list_T *qfl;
- qfline_T *qf_ptr;
- qfline_T *old_qf_ptr;
- int qf_index;
- int old_qf_index;
char *old_swb = (char *)p_swb;
unsigned old_swb_flags = swb_flags;
- int prev_winid;
- int opened_window = false;
- int print_message = true;
const bool old_KeyTyped = KeyTyped; // getting file may reset it
- int retval = OK;
if (qi == NULL) {
qi = &ql_info;
@@ -3008,12 +2935,12 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo
incr_quickfix_busy();
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
- qf_ptr = qfl->qf_ptr;
- old_qf_ptr = qf_ptr;
- qf_index = qfl->qf_index;
- old_qf_index = qf_index;
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ qfline_T *old_qf_ptr = qf_ptr;
+ int qf_index = qfl->qf_index;
+ int old_qf_index = qf_index;
qf_ptr = qf_get_entry(qfl, errornr, dir, &qf_index);
if (qf_ptr == NULL) {
@@ -3024,15 +2951,14 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo
qfl->qf_index = qf_index;
qfl->qf_ptr = qf_ptr;
- if (qf_win_pos_update(qi, old_qf_index)) {
- // No need to print the error message if it's visible in the error
- // window
- print_message = false;
- }
- prev_winid = curwin->handle;
+ // No need to print the error message if it's visible in the error window
+ bool print_message = !qf_win_pos_update(qi, old_qf_index);
+
+ int prev_winid = curwin->handle;
- retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
+ int opened_window = false;
+ int retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
if (retval == FAIL) {
goto failed;
}
@@ -3085,13 +3011,11 @@ static int qfLineAttr;
/// quickfix list.
static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
{
- char *fname;
- buf_T *buf;
-
- fname = NULL;
+ char *fname = NULL;
if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, qfp->qf_module);
} else {
+ buf_T *buf;
if (qfp->qf_fnum != 0
&& (buf = buflist_findnr(qfp->qf_fnum)) != NULL) {
fname = buf->b_fname;
@@ -3147,13 +3071,27 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
}
msg_puts(" ");
+ char_u *tbuf = IObuff;
+ size_t tbuflen = IOSIZE;
+ size_t len = STRLEN(qfp->qf_text) + 3;
+
+ if (len > IOSIZE) {
+ tbuf = xmalloc(len);
+ tbuflen = len;
+ }
+
// Remove newlines and leading whitespace from the text. For an
// unrecognized line keep the indent, the compiler may mark a word
- // with ^^^^. */
+ // with ^^^^.
qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
? skipwhite(qfp->qf_text) : qfp->qf_text,
- (char *)IObuff, IOSIZE);
- msg_prt_line(IObuff, false);
+ (char *)tbuf, (int)tbuflen);
+ msg_prt_line(tbuf, false);
+
+ if (tbuf != IObuff) {
+ xfree(tbuf);
+ }
+
ui_flush(); // show one line at a time
}
@@ -3161,17 +3099,11 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
// ":llist": list all locations
void qf_list(exarg_T *eap)
{
- qf_list_T *qfl;
- qfline_T *qfp;
- int i;
- int idx1 = 1;
- int idx2 = -1;
char *arg = eap->arg;
- int all = eap->forceit; // if not :cl!, only show
- // recognised errors
- qf_info_T *qi;
+ int all = eap->forceit; // if not :cl!, only show recognised errors
+ qf_info_T *qi = qf_cmd_get_stack(eap, true);
- if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
+ if (qi == NULL) {
return;
}
@@ -3185,11 +3117,14 @@ void qf_list(exarg_T *eap)
arg++;
plus = true;
}
+ int idx1 = 1;
+ int idx2 = -1;
if (!get_list_range((char_u **)&arg, &idx1, &idx2) || *arg != NUL) {
emsg(_(e_trailing));
return;
}
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
+ int i;
if (plus) {
i = qfl->qf_index;
idx2 = i + idx1;
@@ -3225,6 +3160,7 @@ void qf_list(exarg_T *eap)
if (qfl->qf_nonevalid) {
all = true;
}
+ qfline_T *qfp;
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) {
qf_list_entry(qfp, i, i == qfl->qf_index);
@@ -3312,17 +3248,12 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
void qf_age(exarg_T *eap)
{
qf_info_T *qi;
- int count;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
}
- if (eap->addr_count != 0) {
- count = (int)eap->line2;
- } else {
- count = 1;
- }
+ int count = (eap->addr_count != 0) ? (int)eap->line2 : 1;
while (count--) {
if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder) {
if (qi->qf_curlist == 0) {
@@ -3346,7 +3277,6 @@ void qf_age(exarg_T *eap)
void qf_history(exarg_T *eap)
{
qf_info_T *qi = qf_cmd_get_stack(eap, false);
- int i;
if (eap->addr_count > 0) {
if (qi == NULL) {
@@ -3369,7 +3299,7 @@ void qf_history(exarg_T *eap)
if (qf_stack_empty(qi)) {
msg(_("No entries"));
} else {
- for (i = 0; i < qi->qf_listcount; i++) {
+ for (int i = 0; i < qi->qf_listcount; i++) {
qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
}
}
@@ -3379,13 +3309,11 @@ void qf_history(exarg_T *eap)
/// associated with the list like context and title are not freed.
static void qf_free_items(qf_list_T *qfl)
{
- qfline_T *qfp;
- qfline_T *qfpnext;
bool stop = false;
while (qfl->qf_count && qfl->qf_start != NULL) {
- qfp = qfl->qf_start;
- qfpnext = qfp->qf_next;
+ qfline_T *qfp = qfl->qf_start;
+ qfline_T *qfpnext = qfp->qf_next;
if (!stop) {
xfree(qfp->qf_module);
xfree(qfp->qf_text);
@@ -3438,11 +3366,7 @@ static void qf_free(qf_list_T *qfl)
bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after)
{
- int i;
- qfline_T *qfp;
- int idx;
qf_info_T *qi = &ql_info;
- bool found_one = false;
int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
@@ -3455,7 +3379,10 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
qi = wp->w_llist;
}
- for (idx = 0; idx < qi->qf_listcount; idx++) {
+ int i;
+ qfline_T *qfp;
+ bool found_one = false;
+ for (int idx = 0; idx < qi->qf_listcount; idx++) {
qf_list_T *qfl = qf_get_list(qi, idx);
if (!qf_list_empty(qfl)) {
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
@@ -3495,7 +3422,6 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
// 1 x "" :helpgrep
static char *qf_types(int c, int nr)
{
- static char buf[20];
static char cc[3];
char *p;
@@ -3520,6 +3446,7 @@ static char *qf_types(int c, int nr)
return p;
}
+ static char buf[20];
snprintf((char *)buf, sizeof(buf), "%s %3d", p, nr);
return buf;
}
@@ -3558,17 +3485,15 @@ void qf_view_result(bool split)
void ex_cwindow(exarg_T *eap)
{
qf_info_T *qi;
- qf_list_T *qfl;
- win_T *win;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
}
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
// Look for an existing quickfix window.
- win = qf_find_win(qi);
+ win_T *win = qf_find_win(qi);
// If a quickfix window is open but we have no errors to display,
// close the window. If a quickfix window is not open, then open
@@ -3588,7 +3513,6 @@ void ex_cwindow(exarg_T *eap)
// ":lclose": close the window showing the location list
void ex_cclose(exarg_T *eap)
{
- win_T *win = NULL;
qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, false)) == NULL) {
@@ -3596,7 +3520,7 @@ void ex_cclose(exarg_T *eap)
}
// Find existing quickfix window and close it.
- win = qf_find_win(qi);
+ win_T *win = qf_find_win(qi);
if (win != NULL) {
win_close(win, false, false);
}
@@ -3726,10 +3650,6 @@ static void qf_set_title_var(qf_list_T *qfl)
void ex_copen(exarg_T *eap)
{
qf_info_T *qi;
- qf_list_T *qfl;
- int height;
- int status = FAIL;
- int lnum;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
@@ -3737,6 +3657,7 @@ void ex_copen(exarg_T *eap)
incr_quickfix_busy();
+ int height;
if (eap->addr_count != 0) {
height = (int)eap->line2;
} else {
@@ -3745,6 +3666,7 @@ void ex_copen(exarg_T *eap)
reset_VIsual_and_resel(); // stop Visual mode
// Find an existing quickfix window, or open a new one.
+ int status = FAIL;
if (cmdmod.cmod_tab == 0) {
status = qf_goto_cwindow(qi, eap->addr_count != 0, height,
cmdmod.cmod_split & WSP_VERT);
@@ -3756,11 +3678,11 @@ void ex_copen(exarg_T *eap)
}
}
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
qf_set_title_var(qfl);
// Save the current index here, as updating the quickfix buffer may free
// the quickfix list
- lnum = qfl->qf_index;
+ int lnum = qfl->qf_index;
// Fill the buffer with the quickfix list.
qf_fill_buffer(qfl, curbuf, NULL, curwin->handle);
@@ -3825,14 +3747,13 @@ linenr_T qf_current_entry(win_T *wp)
/// Return TRUE if there is a quickfix window.
///
/// @param old_qf_index previous qf_index or zero
-static int qf_win_pos_update(qf_info_T *qi, int old_qf_index)
+static bool qf_win_pos_update(qf_info_T *qi, int old_qf_index)
{
- win_T *win;
int qf_index = qf_get_curlist(qi)->qf_index;
// Put the cursor on the current error in the quickfix window, so that
// it's viewable.
- win = qf_find_win(qi);
+ win_T *win = qf_find_win(qi);
if (win != NULL
&& qf_index <= win->w_buffer->b_ml.ml_line_count
&& old_qf_index != qf_index) {
@@ -3909,14 +3830,12 @@ static buf_T *qf_find_buf(qf_info_T *qi)
// Process the 'quickfixtextfunc' option value.
bool qf_process_qftf_option(void)
{
- typval_T *tv;
- Callback cb;
-
if (p_qftf == NULL || *p_qftf == NUL) {
callback_free(&qftf_cb);
return true;
}
+ typval_T *tv;
if (*p_qftf == '{') {
// Lambda expression
tv = eval_expr((char *)p_qftf);
@@ -3930,6 +3849,7 @@ bool qf_process_qftf_option(void)
tv->vval.v_string = (char *)vim_strsave(p_qftf);
}
+ Callback cb;
if (!callback_from_typval(&cb, tv)) {
tv_free(tv);
return false;
@@ -3961,16 +3881,13 @@ static void qf_update_win_titlevar(qf_info_T *qi)
// Find the quickfix buffer. If it exists, update the contents.
static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
{
- buf_T *buf;
- win_T *win;
- aco_save_T aco;
-
// Check if a buffer for the quickfix list exists. Update it.
- buf = qf_find_buf(qi);
+ buf_T *buf = qf_find_buf(qi);
if (buf != NULL) {
linenr_T old_line_count = buf->b_ml.ml_line_count;
int qf_winid = 0;
+ win_T *win;
if (IS_LL_STACK(qi)) {
if (curwin->w_llist == qi) {
win = curwin;
@@ -3983,6 +3900,8 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
qf_winid = (int)win->handle;
}
+ aco_save_T aco;
+
if (old_last == NULL) {
// set curwin/curbuf to buf and save a few things
aucmd_prepbuf(&aco, buf);
@@ -4013,14 +3932,13 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli
char *dirname, char *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{
- int len;
- buf_T *errbuf;
-
// If the 'quickfixtextfunc' function returned a non-empty custom string
// for this entry, then use it.
if (qftf_str != NULL && *qftf_str != NUL) {
STRLCPY(IObuff, qftf_str, IOSIZE);
} else {
+ buf_T *errbuf;
+ int len;
if (qfp->qf_module != NULL) {
STRLCPY(IObuff, qfp->qf_module, IOSIZE);
len = (int)STRLEN(IObuff);
@@ -4109,8 +4027,6 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long
args[0].v_type = VAR_DICT;
args[0].vval.v_dict = dict;
- qftf_list = NULL;
-
if (callback_call(cb, 1, args, &rettv)) {
if (rettv.v_type == VAR_LIST) {
qftf_list = rettv.vval.v_list;
@@ -4132,11 +4048,7 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long
static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
FUNC_ATTR_NONNULL_ARG(2)
{
- linenr_T lnum;
- qfline_T *qfp;
const bool old_KeyTyped = KeyTyped;
- list_T *qftf_list = NULL;
- listitem_T *qftf_li = NULL;
if (old_last == NULL) {
if (buf != curbuf) {
@@ -4153,11 +4065,12 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// Check if there is anything to display
if (qfl != NULL) {
char dirname[MAXPATHL];
- int prev_bufnr = -1;
- bool invalid_val = false;
*dirname = NUL;
+ linenr_T lnum;
+ qfline_T *qfp;
+
// Add one line for each error
if (old_last == NULL) {
qfp = qfl->qf_start;
@@ -4171,8 +4084,11 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
lnum = buf->b_ml.ml_line_count;
}
- qftf_list = call_qftf_func(qfl, qf_winid, lnum + 1, (long)qfl->qf_count);
- qftf_li = tv_list_first(qftf_list);
+ list_T *qftf_list = call_qftf_func(qfl, qf_winid, lnum + 1, (long)qfl->qf_count);
+ listitem_T *qftf_li = tv_list_first(qftf_list);
+
+ int prev_bufnr = -1;
+ bool invalid_val = false;
while (lnum < qfl->qf_count) {
char *qftf_str = NULL;
@@ -4349,10 +4265,6 @@ static char *make_get_fullcmd(const char *makecmd, const char *fname)
// Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
void ex_make(exarg_T *eap)
{
- char *fname;
- win_T *wp = NULL;
- qf_info_T *qi = &ql_info;
- int res;
char *enc = (*curbuf->b_p_menc != NUL) ? (char *)curbuf->b_p_menc : (char *)p_menc;
// Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal".
@@ -4369,12 +4281,13 @@ void ex_make(exarg_T *eap)
}
}
+ win_T *wp = NULL;
if (is_loclist_cmd(eap->cmdidx)) {
wp = curwin;
}
autowrite_all();
- fname = get_mef_name();
+ char *fname = get_mef_name();
if (fname == NULL) {
return;
}
@@ -4386,10 +4299,12 @@ void ex_make(exarg_T *eap)
incr_quickfix_busy();
- res = qf_init(wp, fname, (eap->cmdidx != CMD_make
- && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
- (eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd),
- qf_cmdtitle(*eap->cmdlinep), enc);
+ int res = qf_init(wp, fname, (eap->cmdidx != CMD_make
+ && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
+ (eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd),
+ qf_cmdtitle(*eap->cmdlinep), enc);
+
+ qf_info_T *qi = &ql_info;
if (wp != NULL) {
qi = GET_LOC_LIST(wp);
if (qi == NULL) {
@@ -4423,7 +4338,6 @@ cleanup:
// Returns NULL for error.
static char *get_mef_name(void)
{
- char *p;
char *name;
static int start = -1;
static int off = 0;
@@ -4436,6 +4350,8 @@ static char *get_mef_name(void)
return name;
}
+ char *p;
+
for (p = p_mef; *p; ++p) {
if (p[0] == '#' && p[1] == '#') {
break;
@@ -4484,7 +4400,6 @@ size_t qf_get_size(exarg_T *eap)
size_t qf_get_valid_size(exarg_T *eap)
{
qf_info_T *qi;
- qf_list_T *qfl;
if ((qi = qf_cmd_get_stack(eap, false)) == NULL) {
return 0;
@@ -4495,7 +4410,7 @@ size_t qf_get_valid_size(exarg_T *eap)
qfline_T *qfp;
int i;
assert(qf_get_curlist(qi)->qf_count >= 0);
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
if (!qfp->qf_valid) {
continue;
@@ -4894,12 +4809,10 @@ static qfline_T *qf_find_closest_entry(qf_list_T *qfl, int bnr, const pos_T *pos
bool linewise, int *errornr)
FUNC_ATTR_NONNULL_ALL
{
- qfline_T *qfp;
-
*errornr = 0;
// Find the first entry in this file
- qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr);
+ qfline_T *qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr);
if (qfp == NULL) {
return NULL; // no entry in this file
}
@@ -4997,48 +4910,39 @@ static int qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, pos_T *pos, linenr_T n
/// ":lafter" and ":lbefore" commands
void ex_cbelow(exarg_T *eap)
{
- qf_info_T *qi;
- qf_list_T *qfl;
- int dir;
- int buf_has_flag;
-
if (eap->addr_count > 0 && eap->line2 <= 0) {
emsg(_(e_invrange));
return;
}
// Check whether the current buffer has any quickfix entries
- if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow
- || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter) {
- buf_has_flag = BUF_HAS_QF_ENTRY;
- } else {
- buf_has_flag = BUF_HAS_LL_ENTRY;
- }
+ int buf_has_flag = (eap->cmdidx == CMD_cabove
+ || eap->cmdidx == CMD_cbelow
+ || eap->cmdidx == CMD_cbefore
+ || eap->cmdidx == CMD_cafter) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
+
if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
emsg(_(e_quickfix));
return;
}
+ qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
}
- qfl = qf_get_curlist(qi);
+ qf_list_T *qfl = qf_get_curlist(qi);
// check if the list has valid errors
if (!qf_list_has_valid_entries(qfl)) {
emsg(_(e_quickfix));
return;
}
- if (eap->cmdidx == CMD_cbelow
- || eap->cmdidx == CMD_lbelow
- || eap->cmdidx == CMD_cafter
- || eap->cmdidx == CMD_lafter) {
- // Forward motion commands
- dir = FORWARD;
- } else {
- dir = BACKWARD;
- }
+ // Forward motion commands
+ int dir = (eap->cmdidx == CMD_cbelow
+ || eap->cmdidx == CMD_lbelow
+ || eap->cmdidx == CMD_cafter
+ || eap->cmdidx == CMD_lafter) ? FORWARD : BACKWARD;
pos_T pos = curwin->w_cursor;
// A quickfix entry column number is 1 based whereas cursor column
@@ -5425,7 +5329,7 @@ static int vgr_process_args(exarg_T *eap, vgr_args_T *args)
}
// Parse the list of arguments, wildcards have already been expanded.
- if (get_arglist_exp((char_u *)p, &args->fcount, (char_u ***)&args->fnames, true) == FAIL) {
+ if (get_arglist_exp((char_u *)p, &args->fcount, &args->fnames, true) == FAIL) {
return FAIL;
}
if (args->fcount == 0) {
@@ -5601,12 +5505,12 @@ void ex_vimgrep(exarg_T *eap)
int status = vgr_process_files(wp, qi, &args, &redraw_for_dummy, &first_match_buf, &target_dir);
if (status != OK) {
- FreeWild(args.fcount, (char_u **)args.fnames);
+ FreeWild(args.fcount, args.fnames);
decr_quickfix_busy();
goto theend;
}
- FreeWild(args.fcount, (char_u **)args.fnames);
+ FreeWild(args.fcount, args.fnames);
qf_list_T *qfl = qf_get_curlist(qi);
qfl->qf_nonevalid = false;
@@ -5689,18 +5593,14 @@ static void restore_start_dir(char *dirname_start)
/// @return NULL if it fails.
static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resulting_dir)
{
- buf_T *newbuf;
- bufref_T newbufref;
- bufref_T newbuf_to_wipe;
- int failed = true;
- aco_save_T aco;
- int readfile_result;
-
// Allocate a buffer without putting it in the buffer list.
- newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ buf_T *newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
if (newbuf == NULL) {
return NULL;
}
+
+ int failed = true;
+ bufref_T newbufref;
set_bufref(&newbufref, newbuf);
// Init the options.
@@ -5711,6 +5611,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin
// Make sure this buffer isn't wiped out by autocommands.
newbuf->b_locked++;
// set curwin/curbuf to buf and save a few things
+ aco_save_T aco;
aucmd_prepbuf(&aco, newbuf);
// Need to set the filename for autocommands.
@@ -5723,10 +5624,11 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin
// work.
curbuf->b_flags &= ~BF_DUMMY;
+ bufref_T newbuf_to_wipe;
newbuf_to_wipe.br_buf = NULL;
- readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0,
- (linenr_T)MAXLNUM, NULL,
- READ_NEW | READ_DUMMY, false);
+ int readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0,
+ (linenr_T)MAXLNUM, NULL,
+ READ_NEW | READ_DUMMY, false);
newbuf->b_locked--;
if (readfile_result == OK
&& !got_int
@@ -5830,11 +5732,8 @@ static void unload_dummy_buffer(buf_T *buf, char *dirname_start)
/// to 'list'. Returns OK on success.
static int get_qfline_items(qfline_T *qfp, list_T *list)
{
- char buf[2];
- int bufnum;
-
// Handle entries with a non-existing buffer number.
- bufnum = qfp->qf_fnum;
+ int bufnum = qfp->qf_fnum;
if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) {
bufnum = 0;
}
@@ -5842,6 +5741,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
dict_T *const dict = tv_dict_alloc();
tv_list_append_dict(list, dict);
+ char buf[2];
buf[0] = qfp->qf_type;
buf[1] = NUL;
if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
@@ -5882,9 +5782,6 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx, list_T *list)
{
qf_info_T *qi = qi_arg;
- qf_list_T *qfl;
- qfline_T *qfp;
- int i;
if (qi == NULL) {
qi = &ql_info;
@@ -5908,11 +5805,13 @@ int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx, list_T *li
return FAIL;
}
- qfl = qf_get_list(qi, qf_idx);
+ qf_list_T *qfl = qf_get_list(qi, qf_idx);
if (qf_list_empty(qfl)) {
return FAIL;
}
+ qfline_T *qfp;
+ int i;
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
if (eidx > 0) {
if (eidx == i) {
@@ -5949,11 +5848,11 @@ enum {
static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
{
int status = FAIL;
- char *errorformat = p_efm;
- dictitem_T *efm_di;
// Only a List value is supported
if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
+ char *errorformat = p_efm;
+ dictitem_T *efm_di;
// If errorformat is supplied then use it, otherwise use the 'efm'
// option setting
if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
@@ -6253,11 +6152,9 @@ static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
{
qf_info_T *qi = &ql_info;
- qf_list_T *qfl;
dictitem_T *di = NULL;
int status = OK;
int qf_idx = INVALID_QFIDX;
- int eidx = 0;
if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
return qf_get_list_from_lines(what, di, retdict);
@@ -6278,7 +6175,8 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
return qf_getprop_defaults(qi, flags, wp != NULL, retdict);
}
- qfl = qf_get_list(qi, qf_idx);
+ qf_list_T *qfl = qf_get_list(qi, qf_idx);
+ int eidx = 0;
// If an entry index is specified, use that
if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
@@ -6665,9 +6563,6 @@ static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di
static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char *title)
FUNC_ATTR_NONNULL_ALL
{
- qf_list_T *qfl;
- dictitem_T *di;
- int retval = FAIL;
bool newlist = action == ' ' || qf_stack_empty(qi);
int qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
if (qf_idx == INVALID_QFIDX) { // List not found
@@ -6680,7 +6575,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char
qf_idx = qi->qf_curlist;
}
- qfl = qf_get_list(qi, qf_idx);
+ qf_list_T *qfl = qf_get_list(qi, qf_idx);
+ dictitem_T *di;
+ int retval = FAIL;
if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) {
retval = qf_setprop_title(qi, qf_idx, what, di);
}
@@ -6761,7 +6658,6 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what)
{
qf_info_T *qi = &ql_info;
- int retval = OK;
if (wp != NULL) {
qi = ll_get_or_alloc_list(wp);
@@ -6781,6 +6677,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char *title, dict_T *what
incr_quickfix_busy();
+ int retval = OK;
if (what != NULL) {
retval = qf_set_properties(qi, what, action, title);
} else {
@@ -6911,14 +6808,7 @@ static int cbuffer_process_args(exarg_T *eap, buf_T **bufp, linenr_T *line1, lin
// ":[range]lgetbuffer [bufnr]" command.
void ex_cbuffer(exarg_T *eap)
{
- buf_T *buf = NULL;
- char *au_name = NULL;
- win_T *wp = NULL;
- char *qf_title;
- linenr_T line1;
- linenr_T line2;
-
- au_name = cbuffer_get_auname(eap->cmdidx);
+ char *au_name = cbuffer_get_auname(eap->cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, true, curbuf)) {
if (aborting()) {
@@ -6927,13 +6817,17 @@ void ex_cbuffer(exarg_T *eap)
}
// Must come after autocommands.
+ win_T *wp = NULL;
qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp);
+ buf_T *buf = NULL;
+ linenr_T line1;
+ linenr_T line2;
if (cbuffer_process_args(eap, &buf, &line1, &line2) == FAIL) {
return;
}
- qf_title = qf_cmdtitle(*eap->cmdlinep);
+ char *qf_title = qf_cmdtitle(*eap->cmdlinep);
if (buf->b_sfname) {
vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)", qf_title, buf->b_sfname);
@@ -7001,10 +6895,7 @@ static char *cexpr_get_auname(cmdidx_T cmdidx)
/// ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
void ex_cexpr(exarg_T *eap)
{
- char *au_name = NULL;
- win_T *wp = NULL;
-
- au_name = cexpr_get_auname(eap->cmdidx);
+ char *au_name = cexpr_get_auname(eap->cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, true, curbuf)) {
if (aborting()) {
@@ -7012,6 +6903,7 @@ void ex_cexpr(exarg_T *eap)
}
}
+ win_T *wp = NULL;
qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp);
// Evaluate the expression. When the result is a string or a list we can
@@ -7060,22 +6952,10 @@ cleanup:
static qf_info_T *hgr_get_ll(bool *new_ll)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
- win_T *wp;
- qf_info_T *qi;
-
- // If the current window is a help window, then use it
- if (bt_help(curwin->w_buffer)) {
- wp = curwin;
- } else {
- // Find an existing help window
- wp = qf_find_help_win();
- }
+ // If the current window is a help window, then use it, else find an existing help window
+ win_T *wp = bt_help(curwin->w_buffer) ? curwin : qf_find_help_win();
- if (wp == NULL) { // Help window not found
- qi = NULL;
- } else {
- qi = wp->w_llist;
- }
+ qf_info_T *qi = wp == NULL ? NULL : wp->w_llist;
if (qi == NULL) {
// Allocate a new location list for help text matches
qi = qf_alloc_stack(QFLT_LOCATION);
@@ -7151,8 +7031,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p
// Find all "*.txt" and "*.??x" files in the "doc" directory.
add_pathsep(dirname);
STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT
- if (gen_expand_wildcards(1, (char_u **)&dirname, &fcount,
- (char_u ***)&fnames, EW_FILE|EW_SILENT) == OK
+ if (gen_expand_wildcards(1, &dirname, &fcount, &fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
for (int fi = 0; fi < fcount && !got_int; fi++) {
// Skip files for a different language.
@@ -7166,7 +7045,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p
hgr_search_file(qfl, fnames[fi], p_regmatch);
}
- FreeWild(fcount, (char_u **)fnames);
+ FreeWild(fcount, fnames);
}
}
@@ -7190,7 +7069,6 @@ static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char
void ex_helpgrep(exarg_T *eap)
{
qf_info_T *qi = &ql_info;
- bool new_qi = false;
char *au_name = NULL;
switch (eap->cmdidx) {
@@ -7212,6 +7090,7 @@ void ex_helpgrep(exarg_T *eap)
char *const save_cpo = p_cpo;
p_cpo = (char *)empty_option;
+ bool new_qi = false;
if (is_loclist_cmd(eap->cmdidx)) {
qi = hgr_get_ll(&new_qi);
}
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
index 6407ac172e..2f718e9c2e 100644
--- a/src/nvim/rbuffer.c
+++ b/src/nvim/rbuffer.c
@@ -156,7 +156,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count)
/// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion.
///
-/// This is generally usefull if we can guarantee to parse all input
+/// This is generally useful if we can guarantee to parse all input
/// except some small incomplete token, like when parsing msgpack.
void rbuffer_consumed_compact(RBuffer *buf, size_t count)
FUNC_ATTR_NONNULL_ALL
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 4c49d30819..fbbf904f8b 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -176,12 +176,10 @@ static int backslash_trans(int c)
return c;
}
-/*
- * Check for a character class name "[:name:]". "pp" points to the '['.
- * Returns one of the CLASS_ items. CLASS_NONE means that no item was
- * recognized. Otherwise "pp" is advanced to after the item.
- */
-static int get_char_class(char_u **pp)
+/// Check for a character class name "[:name:]". "pp" points to the '['.
+/// Returns one of the CLASS_ items. CLASS_NONE means that no item was
+/// recognized. Otherwise "pp" is advanced to after the item.
+static int get_char_class(char **pp)
{
static const char *(class_names[]) =
{
@@ -306,7 +304,7 @@ static void init_class_tab(void)
// Global work variables for vim_regcomp().
-static char_u *regparse; ///< Input-scan pointer.
+static char *regparse; ///< Input-scan pointer.
static int regnpar; ///< () count.
static bool wants_nfa; ///< regex should use NFA engine
static int regnzpar; ///< \z() count.
@@ -395,11 +393,11 @@ int re_multiline(const regprog_T *prog)
* Returns a character representing the class. Zero means that no item was
* recognized. Otherwise "pp" is advanced to after the item.
*/
-static int get_equi_class(char_u **pp)
+static int get_equi_class(char **pp)
{
int c;
int l = 1;
- char_u *p = *pp;
+ char_u *p = (char_u *)(*pp);
if (p[1] == '=' && p[2] != NUL) {
l = utfc_ptr2len((char *)p + 2);
@@ -418,11 +416,11 @@ static int get_equi_class(char_u **pp)
* "pp" is advanced to after the item.
* Currently only single characters are recognized!
*/
-static int get_coll_element(char_u **pp)
+static int get_coll_element(char **pp)
{
int c;
int l = 1;
- char_u *p = *pp;
+ char_u *p = (char_u *)(*pp);
if (p[0] != NUL && p[1] == '.' && p[2] != NUL) {
l = utfc_ptr2len((char *)p + 2);
@@ -442,12 +440,10 @@ static void get_cpo_flags(void)
reg_cpo_lit = vim_strchr(p_cpo, CPO_LITERAL) != NULL;
}
-/*
- * Skip over a "[]" range.
- * "p" must point to the character after the '['.
- * The returned pointer is on the matching ']', or the terminating NUL.
- */
-static char_u *skip_anyof(char_u *p)
+/// Skip over a "[]" range.
+/// "p" must point to the character after the '['.
+/// The returned pointer is on the matching ']', or the terminating NUL.
+static char_u *skip_anyof(char *p)
{
int l;
@@ -458,7 +454,7 @@ static char_u *skip_anyof(char_u *p)
p++;
}
while (*p != NUL && *p != ']') {
- if ((l = utfc_ptr2len((char *)p)) > 1) {
+ if ((l = utfc_ptr2len(p)) > 1) {
p += l;
} else if (*p == '-') {
p++;
@@ -482,7 +478,7 @@ static char_u *skip_anyof(char_u *p)
}
}
- return p;
+ return (char_u *)p;
}
/*
@@ -512,7 +508,7 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp)
}
if ((p[0] == '[' && mymagic >= MAGIC_ON)
|| (p[0] == '\\' && p[1] == '[' && mymagic <= MAGIC_OFF)) {
- p = skip_anyof(p + 1);
+ p = skip_anyof((char *)p + 1);
if (p[0] == NUL) {
break;
}
@@ -547,7 +543,7 @@ static int prev_at_start; // True when on the second character
*/
static void initchr(char_u *str)
{
- regparse = str;
+ regparse = (char *)str;
prevchr_len = 0;
curchr = prevprevchr = prevchr = nextchr = -1;
at_start = true;
@@ -560,7 +556,7 @@ static void initchr(char_u *str)
*/
static void save_parse_state(parse_state_T *ps)
{
- ps->regparse = regparse;
+ ps->regparse = (char_u *)regparse;
ps->prevchr_len = prevchr_len;
ps->curchr = curchr;
ps->prevchr = prevchr;
@@ -576,7 +572,7 @@ static void save_parse_state(parse_state_T *ps)
*/
static void restore_parse_state(parse_state_T *ps)
{
- regparse = ps->regparse;
+ regparse = (char *)ps->regparse;
prevchr_len = ps->prevchr_len;
curchr = ps->curchr;
prevchr = ps->prevchr;
@@ -598,7 +594,7 @@ static int peekchr(void)
return curchr;
}
- switch (curchr = regparse[0]) {
+ switch (curchr = (uint8_t)regparse[0]) {
case '.':
case '[':
case '~':
@@ -669,7 +665,7 @@ static int peekchr(void)
// '$' is only magic as the very last char and if it's in front of
// either "\|", "\)", "\&", or "\n"
if (reg_magic >= MAGIC_OFF) {
- char_u *p = regparse + 1;
+ char_u *p = (char_u *)regparse + 1;
bool is_magic_all = (reg_magic == MAGIC_ALL);
// ignore \c \C \m \M \v \V and \Z after '$'
@@ -696,7 +692,7 @@ static int peekchr(void)
}
break;
case '\\': {
- int c = regparse[1];
+ int c = (uint8_t)regparse[1];
if (c == NUL) {
curchr = '\\'; // trailing '\'
@@ -725,13 +721,13 @@ static int peekchr(void)
} else {
// Next character can never be (made) magic?
// Then backslashing it won't do anything.
- curchr = utf_ptr2char((char *)regparse + 1);
+ curchr = utf_ptr2char(regparse + 1);
}
break;
}
default:
- curchr = utf_ptr2char((char *)regparse);
+ curchr = utf_ptr2char(regparse);
}
return curchr;
@@ -750,7 +746,7 @@ static void skipchr(void)
}
if (regparse[prevchr_len] != NUL) {
// Exclude composing chars that utfc_ptr2len does include.
- prevchr_len += utf_ptr2len((char *)regparse + prevchr_len);
+ prevchr_len += utf_ptr2len(regparse + prevchr_len);
}
regparse += prevchr_len;
prev_at_start = at_start;
@@ -820,8 +816,8 @@ static int64_t gethexchrs(int maxinputlen)
int c;
int i;
- for (i = 0; i < maxinputlen; ++i) {
- c = regparse[0];
+ for (i = 0; i < maxinputlen; i++) {
+ c = (uint8_t)regparse[0];
if (!ascii_isxdigit(c)) {
break;
}
@@ -846,8 +842,8 @@ static int64_t getdecchrs(void)
int c;
int i;
- for (i = 0;; ++i) {
- c = regparse[0];
+ for (i = 0;; i++) {
+ c = (uint8_t)regparse[0];
if (c < '0' || c > '9') {
break;
}
@@ -878,7 +874,7 @@ static int64_t getoctchrs(void)
int i;
for (i = 0; i < 3 && nr < 040; i++) { // -V536
- c = regparse[0];
+ c = (uint8_t)regparse[0];
if (c < '0' || c > '7') {
break;
}
@@ -910,7 +906,7 @@ static int read_limits(long *minval, long *maxval)
regparse++;
reverse = true;
}
- first_char = regparse;
+ first_char = (char_u *)regparse;
*minval = getdigits_long(&regparse, false, 0);
if (*regparse == ',') { // There is a comma.
if (ascii_isdigit(*++regparse)) {
@@ -1270,8 +1266,8 @@ static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T e
if (reg_tofree == NULL || len >= (int)reg_tofreelen) {
len += 50; // get some extra
xfree(reg_tofree);
- reg_tofree = xmalloc(len);
- reg_tofreelen = len;
+ reg_tofree = xmalloc((size_t)len);
+ reg_tofreelen = (unsigned)len;
}
STRCPY(reg_tofree, rex.line);
rex.input = reg_tofree + (rex.input - rex.line);
@@ -1554,7 +1550,7 @@ char_u *regtilde(char_u *source, int magic, bool preview)
if (reg_prev_sub != NULL) {
// length = len(newsub) - 1 + len(prev_sub) + 1
prevlen = (int)STRLEN(reg_prev_sub);
- tmpsub = xmalloc(STRLEN(newsub) + prevlen);
+ tmpsub = xmalloc(STRLEN(newsub) + (size_t)prevlen);
// copy prefix
len = (int)(p - newsub); // not including ~
memmove(tmpsub, newsub, (size_t)len);
@@ -1587,12 +1583,10 @@ char_u *regtilde(char_u *source, int magic, bool preview)
// Only change reg_prev_sub when not previewing.
if (!preview) {
+ // Store a copy of newsub in reg_prev_sub. It is always allocated,
+ // because recursive calls may make the returned string invalid.
xfree(reg_prev_sub);
- if (newsub != source) { // newsub was allocated, just keep it
- reg_prev_sub = newsub;
- } else { // no ~ found, need to save newsub
- reg_prev_sub = vim_strsave(newsub);
- }
+ reg_prev_sub = vim_strsave(newsub);
}
return newsub;
@@ -1635,7 +1629,7 @@ static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, int arg
if (s == NULL || rsm.sm_match->endp[i] == NULL) {
s = NULL;
} else {
- s = vim_strnsave(s, rsm.sm_match->endp[i] - s);
+ s = vim_strnsave(s, (size_t)(rsm.sm_match->endp[i] - s));
}
TV_LIST_ITEM_TV(li)->v_type = VAR_STRING;
TV_LIST_ITEM_TV(li)->vval.v_string = (char *)s;
@@ -1655,7 +1649,7 @@ static void clear_submatch_list(staticList10_T *sl)
/// vim_regexec_multi() match.
///
/// If "flags" has REGSUB_COPY really copy into "dest[destlen]".
-/// Oterwise nothing is copied, only compue the length of the result.
+/// Otherwise nothing is copied, only compute the length of the result.
///
/// If "flags" has REGSUB_MAGIC then behave like 'magic' is set.
///
@@ -1922,7 +1916,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
iemsg("vim_regsub_both(): not enough space");
return 0;
}
- *dst++ = c;
+ *dst++ = (char_u)c;
*dst++ = *src++;
*dst++ = *src++;
} else {
@@ -2197,7 +2191,7 @@ char_u *reg_submatch(int no)
if (round == 2) {
STRCPY(retval + len, s);
}
- len += STRLEN(s);
+ len += (ssize_t)STRLEN(s);
if (round == 2) {
retval[len] = '\n';
}
@@ -2215,7 +2209,7 @@ char_u *reg_submatch(int no)
}
if (retval == NULL) {
- retval = xmalloc(len);
+ retval = xmalloc((size_t)len);
}
}
} else {
@@ -2223,7 +2217,7 @@ char_u *reg_submatch(int no)
if (s == NULL || rsm.sm_match->endp[no] == NULL) {
retval = NULL;
} else {
- retval = vim_strnsave(s, rsm.sm_match->endp[no] - s);
+ retval = vim_strnsave(s, (size_t)(rsm.sm_match->endp[no] - s));
}
}
@@ -2328,7 +2322,7 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags)
regprog_T *prog = NULL;
char_u *expr = (char_u *)expr_arg;
- regexp_engine = p_re;
+ regexp_engine = (int)p_re;
// Check for prefix "\%#=", that sets the regexp engine
if (STRNCMP(expr, "\\%#=", 4) == 0) {
@@ -2396,8 +2390,8 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags)
if (prog != NULL) {
// Store the info needed to call regcomp() again when the engine turns out
// to be very slow when executing it.
- prog->re_engine = regexp_engine;
- prog->re_flags = re_flags;
+ prog->re_engine = (unsigned)regexp_engine;
+ prog->re_flags = (unsigned)re_flags;
}
return prog;
@@ -2475,8 +2469,8 @@ static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool
// NFA engine aborted because it's very slow, use backtracking engine instead.
if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
&& result == NFA_TOO_EXPENSIVE) {
- int save_p_re = p_re;
- int re_flags = rmp->regprog->re_flags;
+ int save_p_re = (int)p_re;
+ int re_flags = (int)rmp->regprog->re_flags;
char_u *pat = vim_strsave(((nfa_regprog_T *)rmp->regprog)->pattern);
p_re = BACKTRACKING_ENGINE;
@@ -2560,15 +2554,14 @@ long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum,
}
rex_in_use = true;
- int result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
- tm, timed_out);
+ long result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col, tm, timed_out);
rmp->regprog->re_in_use = false;
// NFA engine aborted because it's very slow, use backtracking engine instead.
if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
&& result == NFA_TOO_EXPENSIVE) {
- int save_p_re = p_re;
- int re_flags = rmp->regprog->re_flags;
+ int save_p_re = (int)p_re;
+ int re_flags = (int)rmp->regprog->re_flags;
char_u *pat = vim_strsave(((nfa_regprog_T *)rmp->regprog)->pattern);
p_re = BACKTRACKING_ENGINE;
@@ -2589,8 +2582,7 @@ long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum,
vim_regfree(prev_prog);
rmp->regprog->re_in_use = true;
- result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
- tm, timed_out);
+ result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col, tm, timed_out);
rmp->regprog->re_in_use = false;
}
diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c
index 272429bb91..fff5ae9b7f 100644
--- a/src/nvim/regexp_bt.c
+++ b/src/nvim/regexp_bt.c
@@ -492,7 +492,7 @@ static void regc(int b)
if (regcode == JUST_CALC_SIZE) {
regsize++;
} else {
- *regcode++ = b;
+ *regcode++ = (char_u)b;
}
}
@@ -1493,7 +1493,7 @@ static char_u *regnode(int op)
if (ret == JUST_CALC_SIZE) {
regsize += 3;
} else {
- *regcode++ = op;
+ *regcode++ = (char_u)op;
*regcode++ = NUL; // Null "next" pointer.
*regcode++ = NUL;
}
@@ -1610,7 +1610,7 @@ static void reginsert(int op, char_u *opnd)
}
place = opnd; // Op node, where operand used to be.
- *place++ = op;
+ *place++ = (char_u)op;
*place++ = NUL;
*place = NUL;
}
@@ -1637,7 +1637,7 @@ static void reginsert_nr(int op, long val, char_u *opnd)
}
place = opnd; // Op node, where operand used to be.
- *place++ = op;
+ *place++ = (char_u)op;
*place++ = NUL;
*place++ = NUL;
assert(val >= 0 && (uintmax_t)val <= UINT32_MAX);
@@ -1668,7 +1668,7 @@ static void reginsert_limits(int op, long minval, long maxval, char_u *opnd)
}
place = opnd; // Op node, where operand used to be.
- *place++ = op;
+ *place++ = (char_u)op;
*place++ = NUL;
*place++ = NUL;
assert(minval >= 0 && (uintmax_t)minval <= UINT32_MAX);
@@ -1689,7 +1689,7 @@ static int seen_endbrace(int refnum)
// Trick: check if "@<=" or "@<!" follows, in which case
// the \1 can appear before the referenced match.
- for (p = regparse; *p != NUL; p++) {
+ for (p = (char_u *)regparse; *p != NUL; p++) {
if (p[0] == '@' && p[1] == '<' && (p[2] == '!' || p[2] == '=')) {
break;
}
@@ -2071,7 +2071,7 @@ static char_u *regatom(int *flagp)
EMSG2_RET_NULL(_("E678: Invalid character after %s%%[dxouU]"),
reg_magic == MAGIC_ALL);
}
- if (use_multibytecode(i)) {
+ if (use_multibytecode((int)i)) {
ret = regnode(MULTIBYTECODE);
} else {
ret = regnode(EXACTLY);
@@ -2079,7 +2079,7 @@ static char_u *regatom(int *flagp)
if (i == 0) {
regc(0x0a);
} else {
- regmbc(i);
+ regmbc((int)i);
}
regc(NUL);
*flagp |= HASWIDTH;
@@ -2111,8 +2111,8 @@ static char_u *regatom(int *flagp)
if (ret == JUST_CALC_SIZE) {
regsize += 2;
} else {
- *regcode++ = c;
- *regcode++ = cmp;
+ *regcode++ = (char_u)c;
+ *regcode++ = (char_u)cmp;
}
break;
} else if (c == 'l' || c == 'c' || c == 'v') {
@@ -2123,7 +2123,7 @@ static char_u *regatom(int *flagp)
}
if (c == 'l') {
if (cur) {
- n = curwin->w_cursor.lnum;
+ n = (uint32_t)curwin->w_cursor.lnum;
}
ret = regnode(RE_LNUM);
if (save_prev_at_start) {
@@ -2131,7 +2131,7 @@ static char_u *regatom(int *flagp)
}
} else if (c == 'c') {
if (cur) {
- n = curwin->w_cursor.col;
+ n = (uint32_t)curwin->w_cursor.col;
n++;
}
ret = regnode(RE_COL);
@@ -2139,7 +2139,7 @@ static char_u *regatom(int *flagp)
if (cur) {
colnr_T vcol = 0;
getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol);
- n = ++vcol;
+ n = (uint32_t)(++vcol);
}
ret = regnode(RE_VCOL);
}
@@ -2149,7 +2149,7 @@ static char_u *regatom(int *flagp)
// put the number and the optional
// comparator after the opcode
regcode = re_put_uint32(regcode, n);
- *regcode++ = cmp;
+ *regcode++ = (char_u)cmp;
}
break;
}
@@ -2469,7 +2469,7 @@ do_multibyte:
// Need to get composing character too.
for (;;) {
l = utf_ptr2len((char *)regparse);
- if (!utf_composinglike(regparse, regparse + l)) {
+ if (!utf_composinglike((char_u *)regparse, (char_u *)regparse + l)) {
break;
}
regmbc(utf_ptr2char((char *)regparse));
@@ -2910,7 +2910,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags)
}
// Allocate space.
- bt_regprog_T *r = xmalloc(sizeof(bt_regprog_T) + regsize);
+ bt_regprog_T *r = xmalloc(sizeof(bt_regprog_T) + (size_t)regsize);
r->re_in_use = false;
// Second pass: emit code.
@@ -2938,7 +2938,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags)
r->regflags |= RF_LOOKBH;
}
// Remember whether this pattern has any \z specials in it.
- r->reghasz = re_has_z;
+ r->reghasz = (char_u)re_has_z;
scan = r->program + 1; // First BRANCH.
if (OP(regnext(scan)) == END) { // Only one top-level choice.
scan = OPERAND(scan);
@@ -3027,7 +3027,7 @@ static int coll_get_char(void)
regparse--;
nr = '\\';
}
- return nr;
+ return (int)nr;
}
/*
@@ -3505,7 +3505,7 @@ static regitem_T *regstack_push(regstate_T state, char_u *scan)
rp->rs_state = state;
rp->rs_scan = scan;
- regstack.ga_len += sizeof(regitem_T);
+ regstack.ga_len += (int)sizeof(regitem_T);
return rp;
}
@@ -3519,7 +3519,7 @@ static void regstack_pop(char_u **scan)
rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
*scan = rp->rs_scan;
- regstack.ga_len -= sizeof(regitem_T);
+ regstack.ga_len -= (int)sizeof(regitem_T);
}
// Save the current subexpr to "bp", so that they can be restored
@@ -3704,9 +3704,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
int mark = OPERAND(scan)[0];
int cmp = OPERAND(scan)[1];
pos_T *pos;
- size_t col = REG_MULTI ? rex.input - rex.line : 0;
-
- // fm will be NULL if the mark is not set in reg_buf
+ size_t col = REG_MULTI ? (size_t)(rex.input - rex.line) : 0;
fmark_T *fm = mark_get(rex.reg_buf, curwin, NULL, kMarkBufLocal, mark);
// Line may have been freed, get it again.
@@ -4170,7 +4168,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
save_se(&rp->rs_un.sesave, &rex.reg_startpos[no],
&rex.reg_startp[no]);
// We simply continue and handle the result when done.
@@ -4200,7 +4198,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
save_se(&rp->rs_un.sesave, &reg_startzpos[no],
&reg_startzp[no]);
// We simply continue and handle the result when done.
@@ -4223,7 +4221,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
save_se(&rp->rs_un.sesave, &rex.reg_endpos[no], &rex.reg_endp[no]);
// We simply continue and handle the result when done.
}
@@ -4244,7 +4242,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
save_se(&rp->rs_un.sesave, &reg_endzpos[no],
&reg_endzp[no]);
// We simply continue and handle the result when done.
@@ -4380,7 +4378,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
reg_save(&rp->rs_un.regsave, &backpos);
next = OPERAND(scan);
// We continue and handle the result when done.
@@ -4396,7 +4394,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = no;
+ rp->rs_no = (int16_t)no;
reg_save(&rp->rs_un.regsave, &backpos);
next = OPERAND(scan);
// We continue and handle the result when done.
@@ -4465,7 +4463,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
status = RA_FAIL;
} else {
ga_grow(&regstack, sizeof(regstar_T));
- regstack.ga_len += sizeof(regstar_T);
+ regstack.ga_len += (int)sizeof(regstar_T);
rp = regstack_push(rst.minval <= rst.maxval ? RS_STAR_LONG : RS_STAR_SHORT, scan);
if (rp == NULL) {
status = RA_FAIL;
@@ -4487,7 +4485,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (rp == NULL) {
status = RA_FAIL;
} else {
- rp->rs_no = op;
+ rp->rs_no = (int16_t)op;
reg_save(&rp->rs_un.regsave, &backpos);
next = OPERAND(scan);
// We continue and handle the result when done.
@@ -4502,7 +4500,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
status = RA_FAIL;
} else {
ga_grow(&regstack, sizeof(regbehind_T));
- regstack.ga_len += sizeof(regbehind_T);
+ regstack.ga_len += (int)sizeof(regbehind_T);
rp = regstack_push(RS_BEHIND1, scan);
if (rp == NULL) {
status = RA_FAIL;
@@ -4511,7 +4509,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
// when there is a match but we don't use it.
save_subexpr(((regbehind_T *)rp) - 1);
- rp->rs_no = op;
+ rp->rs_no = (int16_t)op;
reg_save(&rp->rs_un.regsave, &backpos);
// First try if what follows matches. If it does then we
// check the behind match by looping.
@@ -4691,7 +4689,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
case RS_BEHIND1:
if (status == RA_NOMATCH) {
regstack_pop(&scan);
- regstack.ga_len -= sizeof(regbehind_T);
+ regstack.ga_len -= (int)sizeof(regbehind_T);
} else {
// The stuff after BEHIND/NOBEHIND matches. Now try if
// the behind part does (not) match before the current
@@ -4734,7 +4732,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
restore_subexpr(((regbehind_T *)rp) - 1);
}
regstack_pop(&scan);
- regstack.ga_len -= sizeof(regbehind_T);
+ regstack.ga_len -= (int)sizeof(regbehind_T);
} else {
long limit;
@@ -4808,7 +4806,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
}
}
regstack_pop(&scan);
- regstack.ga_len -= sizeof(regbehind_T);
+ regstack.ga_len -= (int)sizeof(regbehind_T);
}
}
break;
@@ -4819,7 +4817,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (status == RA_MATCH) {
regstack_pop(&scan);
- regstack.ga_len -= sizeof(regstar_T);
+ regstack.ga_len -= (int)sizeof(regstar_T);
break;
}
@@ -4885,7 +4883,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out)
if (status != RA_CONT) {
// Failed.
regstack_pop(&scan);
- regstack.ga_len -= sizeof(regstar_T);
+ regstack.ga_len -= (int)sizeof(regstar_T);
status = RA_NOMATCH;
}
}
@@ -4976,15 +4974,13 @@ static long regtry(bt_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_o
&& reg_endzpos[i].lnum == reg_startzpos[i].lnum
&& reg_endzpos[i].col >= reg_startzpos[i].col) {
re_extmatch_out->matches[i] =
- vim_strnsave(reg_getline(reg_startzpos[i].lnum)
- + reg_startzpos[i].col,
- reg_endzpos[i].col
- - reg_startzpos[i].col);
+ vim_strnsave(reg_getline(reg_startzpos[i].lnum) + reg_startzpos[i].col,
+ (size_t)(reg_endzpos[i].col - reg_startzpos[i].col));
}
} else {
if (reg_startzp[i] != NULL && reg_endzp[i] != NULL) {
re_extmatch_out->matches[i] =
- vim_strnsave(reg_startzp[i], reg_endzp[i] - reg_startzp[i]);
+ vim_strnsave(reg_startzp[i], (size_t)(reg_endzp[i] - reg_startzp[i]));
}
}
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 870af3eafc..1a5c250664 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -545,7 +545,7 @@ static char_u *nfa_get_match_text(nfa_state_T *start)
return NULL;
}
- ret = xmalloc(len);
+ ret = xmalloc((size_t)len);
p = start->out->out; // skip first char, it goes into regstart
s = ret;
while (p->c > 0) {
@@ -565,7 +565,7 @@ static void realloc_post_list(void)
{
// For weird patterns the number of states can be very high. Increasing by
// 50% seems a reasonable compromise between memory use and speed.
- const size_t new_max = (post_end - post_start) * 3 / 2;
+ const size_t new_max = (size_t)(post_end - post_start) * 3 / 2;
int *new_start = xrealloc(post_start, new_max * sizeof(int));
post_ptr = new_start + (post_ptr - post_start);
post_end = new_start + new_max;
@@ -1807,7 +1807,7 @@ static int nfa_regatom(void)
int got_coll_char;
char_u *p;
char_u *endp;
- char_u *old_regparse = regparse;
+ char_u *old_regparse = (char_u *)regparse;
int extra = 0;
int emit_range;
int negated;
@@ -1905,7 +1905,7 @@ static int nfa_regatom(void)
// When '.' is followed by a composing char ignore the dot, so that
// the composing char is matched here.
if (c == Magic('.') && utf_iscomposing(peekchr())) {
- old_regparse = regparse;
+ old_regparse = (char_u *)regparse;
c = getchr();
goto nfa_do_multibyte;
}
@@ -2079,7 +2079,7 @@ static int nfa_regatom(void)
}
// A NUL is stored in the text as NL
// TODO(vim): what if a composing character follows?
- EMIT(nr == 0 ? 0x0a : nr);
+ EMIT(nr == 0 ? 0x0a : (int)nr);
}
break;
@@ -2226,16 +2226,15 @@ collection:
* - ranges, two characters followed by NFA_RANGE.
*/
- p = regparse;
- endp = skip_anyof(p);
+ p = (char_u *)regparse;
+ endp = skip_anyof((char *)p);
if (*endp == ']') {
/*
* Try to reverse engineer character classes. For example,
* recognize that [0-9] stands for \d and [A-Za-z_] for \h,
* and perform the necessary substitutions in the NFA.
*/
- int result = nfa_recognize_char_class(regparse, endp,
- extra == NFA_ADD_NL);
+ int result = nfa_recognize_char_class((char_u *)regparse, endp, extra == NFA_ADD_NL);
if (result != FAIL) {
if (result >= NFA_FIRST_NL && result <= NFA_LAST_NL) {
EMIT(result - NFA_ADD_NL);
@@ -2244,7 +2243,7 @@ collection:
} else {
EMIT(result);
}
- regparse = endp;
+ regparse = (char *)endp;
MB_PTR_ADV(regparse);
return OK;
}
@@ -2269,7 +2268,7 @@ collection:
}
// Emit the OR branches for each character in the []
emit_range = false;
- while (regparse < endp) {
+ while ((char_u *)regparse < endp) {
int oldstartc = startc;
startc = -1;
got_coll_char = false;
@@ -2376,7 +2375,7 @@ collection:
// accepts "\t", "\e", etc., but only when the 'l' flag in
// 'cpoptions' is not included.
if (*regparse == '\\'
- && regparse + 1 <= endp
+ && (char_u *)regparse + 1 <= endp
&& (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
|| (!reg_cpo_lit
&& vim_strchr(REGEXP_ABBR, regparse[1])
@@ -2479,7 +2478,7 @@ collection:
}
// skip the trailing ]
- regparse = endp;
+ regparse = (char *)endp;
MB_PTR_ADV(regparse);
// Mark end of the collection.
@@ -2531,7 +2530,7 @@ nfa_do_multibyte:
c = utf_ptr2char((char *)old_regparse + i);
}
EMIT(NFA_COMPOSING);
- regparse = old_regparse + plen;
+ regparse = (char *)old_regparse + plen;
} else {
c = no_Magic(c);
EMIT(c);
@@ -2646,7 +2645,7 @@ static int nfa_regpiece(void)
EMIT(i);
if (i == NFA_PREV_ATOM_JUST_BEFORE
|| i == NFA_PREV_ATOM_JUST_BEFORE_NEG) {
- EMIT(c2);
+ EMIT((int)c2);
}
break;
@@ -3850,7 +3849,7 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size)
if (nfa_calc_size == false) {
// Allocate space for the stack. Max states on the stack: "nstate".
- stack = xmalloc((nstate + 1) * sizeof(Frag_T));
+ stack = xmalloc((size_t)(nstate + 1) * sizeof(Frag_T));
stackp = stack;
stack_end = stack + (nstate + 1);
}
@@ -4472,10 +4471,9 @@ static void clear_sub(regsub_T *sub)
{
if (REG_MULTI) {
// Use 0xff to set lnum to -1
- memset(sub->list.multi, 0xff,
- sizeof(struct multipos) * rex.nfa_nsubexpr);
+ memset(sub->list.multi, 0xff, sizeof(struct multipos) * (size_t)rex.nfa_nsubexpr);
} else {
- memset(sub->list.line, 0, sizeof(struct linepos) * rex.nfa_nsubexpr);
+ memset(sub->list.line, 0, sizeof(struct linepos) * (size_t)rex.nfa_nsubexpr);
}
sub->in_use = 0;
}
@@ -4489,13 +4487,11 @@ static void copy_sub(regsub_T *to, regsub_T *from)
if (from->in_use > 0) {
// Copy the match start and end positions.
if (REG_MULTI) {
- memmove(&to->list.multi[0],
- &from->list.multi[0],
- sizeof(struct multipos) * from->in_use);
+ memmove(&to->list.multi[0], &from->list.multi[0],
+ sizeof(struct multipos) * (size_t)from->in_use);
} else {
- memmove(&to->list.line[0],
- &from->list.line[0],
- sizeof(struct linepos) * from->in_use);
+ memmove(&to->list.line[0], &from->list.line[0],
+ sizeof(struct linepos) * (size_t)from->in_use);
}
}
}
@@ -4511,13 +4507,11 @@ static void copy_sub_off(regsub_T *to, regsub_T *from)
if (from->in_use > 1) {
// Copy the match start and end positions.
if (REG_MULTI) {
- memmove(&to->list.multi[1],
- &from->list.multi[1],
- sizeof(struct multipos) * (from->in_use - 1));
+ memmove(&to->list.multi[1], &from->list.multi[1],
+ sizeof(struct multipos) * (size_t)(from->in_use - 1));
} else {
- memmove(&to->list.line[1],
- &from->list.line[1],
- sizeof(struct linepos) * (from->in_use - 1));
+ memmove(&to->list.line[1], &from->list.line[1],
+ sizeof(struct linepos) * (size_t)(from->in_use - 1));
}
}
}
@@ -4964,7 +4958,7 @@ skip_add:
// be (a lot) bigger than anticipated.
if (l->n == l->len) {
const int newlen = l->len * 3 / 2 + 50;
- const size_t newsize = newlen * sizeof(nfa_thread_T);
+ const size_t newsize = (size_t)newlen * sizeof(nfa_thread_T);
if ((long)(newsize >> 10) >= p_mmp) {
emsg(_(e_maxmempat));
@@ -5255,7 +5249,7 @@ static regsubs_T *addstate_here(nfa_list_T *l, nfa_state_T *state, regsubs_T *su
// not enough space to move the new states, reallocate the list
// and move the states to the right position
const int newlen = l->len * 3 / 2 + 50;
- const size_t newsize = newlen * sizeof(nfa_thread_T);
+ const size_t newsize = (size_t)newlen * sizeof(nfa_thread_T);
if ((long)(newsize >> 10) >= p_mmp) {
emsg(_(e_maxmempat));
@@ -5265,13 +5259,13 @@ static regsubs_T *addstate_here(nfa_list_T *l, nfa_state_T *state, regsubs_T *su
l->len = newlen;
memmove(&(newl[0]),
&(l->t[0]),
- sizeof(nfa_thread_T) * listidx);
+ sizeof(nfa_thread_T) * (size_t)listidx);
memmove(&(newl[listidx]),
&(l->t[l->n - count]),
- sizeof(nfa_thread_T) * count);
+ sizeof(nfa_thread_T) * (size_t)count);
memmove(&(newl[listidx + count]),
&(l->t[listidx + 1]),
- sizeof(nfa_thread_T) * (l->n - count - listidx - 1));
+ sizeof(nfa_thread_T) * (size_t)(l->n - count - listidx - 1));
xfree(l->t);
l->t = newl;
} else {
@@ -5279,10 +5273,10 @@ static regsubs_T *addstate_here(nfa_list_T *l, nfa_state_T *state, regsubs_T *su
// end to the current position
memmove(&(l->t[listidx + count]),
&(l->t[listidx + 1]),
- sizeof(nfa_thread_T) * (l->n - listidx - 1));
+ sizeof(nfa_thread_T) * (size_t)(l->n - listidx - 1));
memmove(&(l->t[listidx]),
&(l->t[l->n - 1]),
- sizeof(nfa_thread_T) * count);
+ sizeof(nfa_thread_T) * (size_t)count);
}
}
--l->n;
@@ -5621,7 +5615,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T
// values and clear them.
if (*listids == NULL || *listids_len < prog->nstate) {
xfree(*listids);
- *listids = xmalloc(sizeof(**listids) * prog->nstate);
+ *listids = xmalloc(sizeof(**listids) * (size_t)prog->nstate);
*listids_len = prog->nstate;
}
nfa_save_listids(prog, *listids);
@@ -5888,7 +5882,7 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
rex.reg_startpos[0].lnum = rex.lnum;
rex.reg_startpos[0].col = col;
rex.reg_endpos[0].lnum = rex.lnum;
- rex.reg_endpos[0].col = s2 - rex.line;
+ rex.reg_endpos[0].col = (colnr_T)(s2 - rex.line);
} else {
rex.reg_startp[0] = rex.line + col;
rex.reg_endp[0] = s2;
@@ -5969,7 +5963,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
nfa_match = false;
// Allocate memory for the lists of nodes.
- size_t size = (prog->nstate + 1) * sizeof(nfa_thread_T);
+ size_t size = (size_t)(prog->nstate + 1) * sizeof(nfa_thread_T);
list[0].t = xmalloc(size);
list[0].len = prog->nstate + 1;
list[1].t = xmalloc(size);
@@ -6930,10 +6924,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
case NFA_MARK:
case NFA_MARK_GT:
case NFA_MARK_LT: {
- fmark_T *fm;
- size_t col = REG_MULTI ? rex.input - rex.line : 0;
- // fm will be NULL if the mark is not set, doesn't belong to reg_buf
- fm = mark_get(rex.reg_buf, curwin, NULL, kMarkBufLocal, t->state->val);
+ size_t col = REG_MULTI ? (size_t)(rex.input - rex.line) : 0;
+ fmark_T *fm = mark_get(rex.reg_buf, curwin, NULL, kMarkBufLocal, t->state->val);
// Line may have been freed, get it again.
if (REG_MULTI) {
@@ -7371,14 +7363,14 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm, int *ti
&& mpos->end_col >= mpos->start_col) {
re_extmatch_out->matches[i] =
vim_strnsave(reg_getline(mpos->start_lnum) + mpos->start_col,
- mpos->end_col - mpos->start_col);
+ (size_t)(mpos->end_col - mpos->start_col));
}
} else {
struct linepos *lpos = &subs.synt.list.line[i];
if (lpos->start != NULL && lpos->end != NULL) {
re_extmatch_out->matches[i] =
- vim_strnsave(lpos->start, lpos->end - lpos->start);
+ vim_strnsave(lpos->start, (size_t)(lpos->end - lpos->start));
}
}
}
@@ -7569,7 +7561,7 @@ static regprog_T *nfa_regcomp(char_u *expr, int re_flags)
post2nfa(postfix, post_ptr, true);
// allocate the regprog with space for the compiled regexp
- size_t prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (nstate - 1);
+ size_t prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (size_t)(nstate - 1);
prog = xmalloc(prog_size);
state_ptr = prog->state;
prog->re_in_use = false;
@@ -7653,7 +7645,7 @@ static int nfa_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col, bool line_
rex.reg_ic = rmp->rm_ic;
rex.reg_icombine = false;
rex.reg_maxcol = 0;
- return nfa_regexec_both(line, col, NULL, NULL);
+ return (int)nfa_regexec_both(line, col, NULL, NULL);
}
/// Matches a regexp against multiple lines.
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 045cee2439..5d28d624fe 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -74,14 +74,14 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback,
{
char_u *tail;
int num_files;
- char_u **files;
+ char **files;
int i;
bool did_one = false;
// Make a copy of 'runtimepath'. Invoking the callback may change the
// value.
char_u *rtp_copy = vim_strsave(path);
- char_u *buf = xmallocz(MAXPATHL);
+ char *buf = xmallocz(MAXPATHL);
{
if (p_verbose > 10 && name != NULL) {
verbose_enter();
@@ -93,7 +93,7 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback,
char_u *rtp = rtp_copy;
while (*rtp != NUL && ((flags & DIP_ALL) || !did_one)) {
// Copy the path from 'runtimepath' to buf[].
- copy_option_part((char **)&rtp, (char *)buf, MAXPATHL, ",");
+ copy_option_part((char **)&rtp, buf, MAXPATHL, ",");
size_t buflen = STRLEN(buf);
// Skip after or non-after directories.
@@ -107,18 +107,19 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback,
}
if (name == NULL) {
- (*callback)((char *)buf, cookie);
+ (*callback)(buf, cookie);
did_one = true;
} else if (buflen + STRLEN(name) + 2 < MAXPATHL) {
- add_pathsep((char *)buf);
- tail = buf + STRLEN(buf);
+ add_pathsep(buf);
+ tail = (char_u *)buf + STRLEN(buf);
// Loop over all patterns in "name"
char_u *np = (char_u *)name;
while (*np != NUL && ((flags & DIP_ALL) || !did_one)) {
// Append the pattern from "name" to buf[].
- assert(MAXPATHL >= (tail - buf));
- copy_option_part((char **)&np, (char *)tail, (size_t)(MAXPATHL - (tail - buf)), "\t ");
+ assert(MAXPATHL >= (tail - (char_u *)buf));
+ copy_option_part((char **)&np, (char *)tail, (size_t)(MAXPATHL - (tail - (char_u *)buf)),
+ "\t ");
if (p_verbose > 10) {
verbose_enter();
@@ -132,7 +133,7 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback,
// Expand wildcards, invoke the callback for each match.
if (gen_expand_wildcards(1, &buf, &num_files, &files, ew_flags) == OK) {
for (i = 0; i < num_files; i++) {
- (*callback)((char *)files[i], cookie);
+ (*callback)(files[i], cookie);
did_one = true;
if (!(flags & DIP_ALL)) {
break;
@@ -211,7 +212,7 @@ int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void
{
char_u *tail;
int num_files;
- char_u **files;
+ char **files;
int i;
bool did_one = false;
@@ -263,10 +264,10 @@ int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void
| (flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0;
// Expand wildcards, invoke the callback for each match.
- char_u *(pat[]) = { buf };
+ char *(pat[]) = { (char *)buf };
if (gen_expand_wildcards(1, pat, &num_files, &files, ew_flags) == OK) {
for (i = 0; i < num_files; i++) {
- (*callback)((char *)files[i], cookie);
+ (*callback)(files[i], cookie);
did_one = true;
if (!(flags & DIP_ALL)) {
break;
@@ -458,11 +459,11 @@ static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_
}
int num_files;
- char_u **files;
- char_u *(pat[]) = { (char_u *)entry };
+ char **files;
+ char *(pat[]) = { entry };
if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) {
for (int i = 0; i < num_files; i++) {
- push_path(search_path, rtp_used, (char *)files[i], after);
+ push_path(search_path, rtp_used, files[i], after);
}
FreeWild(num_files, files);
}
@@ -488,7 +489,7 @@ static void expand_pack_entry(RuntimeSearchPath *search_path, Map(String, handle
}
}
-static bool path_is_after(char_u *buf, size_t buflen)
+static bool path_is_after(char *buf, size_t buflen)
{
// NOTE: we only consider dirs exactly matching "after" to be an AFTER dir.
// vim8 considers all dirs like "foo/bar_after", "Xafter" etc, as an
@@ -525,7 +526,7 @@ RuntimeSearchPath runtime_search_path_build(void)
copy_option_part(&rtp_entry, (char *)buf, MAXPATHL, ",");
size_t buflen = STRLEN(buf);
- if (path_is_after(buf, buflen)) {
+ if (path_is_after((char *)buf, buflen)) {
rtp_entry = cur_entry;
break;
}
@@ -557,7 +558,7 @@ RuntimeSearchPath runtime_search_path_build(void)
// "after" dirs in rtp
for (; *rtp_entry != NUL;) {
copy_option_part(&rtp_entry, (char *)buf, MAXPATHL, ",");
- expand_rtp_entry(&search_path, &rtp_used, (char *)buf, path_is_after(buf, STRLEN(buf)));
+ expand_rtp_entry(&search_path, &rtp_used, (char *)buf, path_is_after((char *)buf, STRLEN(buf)));
}
// strings are not owned
@@ -640,14 +641,14 @@ int source_in_path(char_u *path, char_u *name, int flags)
// Expand wildcards in "pat" and invoke do_source()/nlua_exec_file()
// for each match.
-static void source_all_matches(char_u *pat)
+static void source_all_matches(char *pat)
{
int num_files;
- char_u **files;
+ char **files;
if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK) {
for (int i = 0; i < num_files; i++) {
- (void)do_source((char *)files[i], false, DOSO_NONE);
+ (void)do_source(files[i], false, DOSO_NONE);
}
FreeWild(num_files, files);
}
@@ -811,9 +812,9 @@ static int load_pack_plugin(bool opt, char_u *fname)
char_u *pat = xmallocz(len);
vim_snprintf((char *)pat, len, "%s/plugin/**/*.vim", ffname); // NOLINT
- source_all_matches(pat);
+ source_all_matches((char *)pat);
vim_snprintf((char *)pat, len, "%s/plugin/**/*.lua", ffname); // NOLINT
- source_all_matches(pat);
+ source_all_matches((char *)pat);
char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
@@ -822,9 +823,9 @@ static int load_pack_plugin(bool opt, char_u *fname)
if (opt && eval_to_number((char *)cmd) > 0) {
do_cmdline_cmd("augroup filetypedetect");
vim_snprintf((char *)pat, len, ftpat, ffname);
- source_all_matches(pat);
+ source_all_matches((char *)pat);
vim_snprintf((char *)pat, len, "%s/ftdetect/*.lua", ffname); // NOLINT
- source_all_matches(pat);
+ source_all_matches((char *)pat);
do_cmdline_cmd("augroup END");
}
xfree(cmd);
@@ -886,8 +887,8 @@ void add_pack_start_dirs(void)
static bool pack_has_entries(char_u *buf)
{
int num_files;
- char_u **files;
- char_u *(pat[]) = { buf };
+ char **files;
+ char *(pat[]) = { (char *)buf };
if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) {
FreeWild(num_files, files);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index e99f9b9153..0b7b58dc40 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -92,6 +92,7 @@
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
+#include "nvim/insexpand.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/lua/executor.h"
@@ -406,7 +407,7 @@ int update_screen(int type)
curwin->w_redr_status = true;
}
}
- msg_grid_set_pos(Rows - p_ch, false);
+ msg_grid_set_pos(Rows - (int)p_ch, false);
msg_grid_invalid = false;
} else if (msg_scrolled > Rows - 5) { // clearing is faster
type = CLEAR;
@@ -470,7 +471,7 @@ int update_screen(int type)
// After disabling msgsep the grid might not have been deallocated yet,
// hence we also need to check msg_grid.chars
if (type == NOT_VALID && (msg_use_grid() || msg_grid.chars)) {
- grid_fill(&default_grid, Rows - p_ch, Rows, 0, Columns, ' ', ' ', 0);
+ grid_fill(&default_grid, Rows - (int)p_ch, Rows, 0, Columns, ' ', ' ', 0);
}
ui_comp_set_screen_valid(true);
@@ -904,7 +905,7 @@ win_update_start:
for (i = 0; i < wp->w_lines_valid; ++i) {
j += wp->w_lines[i].wl_size;
if (j >= wp->w_upd_rows) {
- top_end = j;
+ top_end = (int)j;
break;
}
}
@@ -977,7 +978,7 @@ win_update_start:
// Move the entries that were scrolled, disable
// the entries for the lines to be redrawn.
- if ((wp->w_lines_valid += j) > wp->w_grid.rows) {
+ if ((wp->w_lines_valid += (linenr_T)j) > wp->w_grid.rows) {
wp->w_lines_valid = wp->w_grid.rows;
}
for (idx = wp->w_lines_valid; idx - j >= 0; idx--) {
@@ -1063,8 +1064,8 @@ win_update_start:
// Correct the first entry for filler lines at the top
// when it won't get updated below.
if (win_may_fill(wp) && bot_start > 0) {
- wp->w_lines[0].wl_size = (plines_win_nofill(wp, wp->w_topline, true)
- + wp->w_topfill);
+ wp->w_lines[0].wl_size = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true)
+ + wp->w_topfill);
}
}
}
@@ -1183,7 +1184,7 @@ win_update_start:
pos.lnum += cursor_above ? 1 : -1) {
colnr_T t;
- pos.col = STRLEN(ml_get_buf(wp->w_buffer, pos.lnum, false));
+ pos.col = (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, pos.lnum, false));
getvvcol(wp, &pos, NULL, NULL, &t);
if (toc < t) {
toc = t;
@@ -1284,7 +1285,7 @@ win_update_start:
}
if (VIsual_active && buf == curwin->w_buffer) {
- wp->w_old_visual_mode = VIsual_mode;
+ wp->w_old_visual_mode = (char)VIsual_mode;
wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
wp->w_old_visual_lnum = VIsual.lnum;
wp->w_old_visual_col = VIsual.col;
@@ -1480,14 +1481,14 @@ win_update_start:
for (;;) {
// stop at last valid entry in w_lines[]
if (i >= wp->w_lines_valid) {
- wp->w_lines_valid = j;
+ wp->w_lines_valid = (int)j;
break;
}
wp->w_lines[j] = wp->w_lines[i];
// stop at a line that won't fit
if (x + (int)wp->w_lines[j].wl_size
> wp->w_grid.rows) {
- wp->w_lines_valid = j + 1;
+ wp->w_lines_valid = (int)j + 1;
break;
}
x += wp->w_lines[j++].wl_size;
@@ -1499,7 +1500,7 @@ win_update_start:
} else { // j > i
// move entries in w_lines[] downwards
j -= i;
- wp->w_lines_valid += j;
+ wp->w_lines_valid += (linenr_T)j;
if (wp->w_lines_valid > wp->w_grid.rows) {
wp->w_lines_valid = wp->w_grid.rows;
}
@@ -1569,13 +1570,13 @@ win_update_start:
if (row > wp->w_grid.rows) { // past end of grid
// we may need the size of that too long line later on
if (dollar_vcol == -1) {
- wp->w_lines[idx].wl_size = plines_win(wp, lnum, true);
+ wp->w_lines[idx].wl_size = (uint16_t)plines_win(wp, lnum, true);
}
idx++;
break;
}
if (dollar_vcol == -1) {
- wp->w_lines[idx].wl_size = row - srow;
+ wp->w_lines[idx].wl_size = (uint16_t)(row - srow);
}
idx++;
lnum += foldinfo.fi_lines + 1;
@@ -1702,7 +1703,7 @@ win_update_start:
// Send win_extmarks if needed
for (size_t n = 0; n < kv_size(win_extmark_arr); n++) {
ui_call_win_extmark(wp->w_grid_alloc.handle, wp->handle,
- kv_A(win_extmark_arr, n).ns_id, kv_A(win_extmark_arr, n).mark_id,
+ kv_A(win_extmark_arr, n).ns_id, (Integer)kv_A(win_extmark_arr, n).mark_id,
kv_A(win_extmark_arr, n).win_row, kv_A(win_extmark_arr, n).win_col);
}
@@ -1807,7 +1808,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, i
}
}
- int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl));
+ int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, (int)hl));
if (wp->w_p_rl) {
grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n,
@@ -1837,7 +1838,7 @@ static bool advance_color_col(int vcol, int **color_cols)
static int compute_foldcolumn(win_T *wp, int col)
{
int fdc = win_fdccol_count(wp);
- int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
+ int wmw = wp == curwin && p_wmw == 0 ? 1 : (int)p_wmw;
int wwidth = wp->w_grid.cols;
if (fdc > wwidth - (col + wmw)) {
@@ -1866,7 +1867,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
}
goto done;
} else if (*p < 0x80 && u8cc[0] == 0) {
- schar_from_ascii(dest[0], *p);
+ schar_from_ascii(dest[0], (char)(*p));
s->prev_c = u8c;
} else {
if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) {
@@ -1923,7 +1924,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
int len = 0;
bool closed = foldinfo.fi_lines > 0;
// Init to all spaces.
- memset(p, ' ', MAX_MCO * fdc + 1);
+ memset(p, ' ', MAX_MCO * (size_t)fdc + 1);
level = foldinfo.fi_level;
@@ -1947,7 +1948,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
}
len = utf_char2bytes(symbol, (char *)&p[char_counter]);
- char_counter += len;
+ char_counter += (size_t)len;
if (first_level + i >= level) {
i++;
break;
@@ -1957,14 +1958,14 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
if (closed) {
if (symbol != 0) {
// rollback previous write
- char_counter -= len;
- memset(&p[char_counter], ' ', len);
+ char_counter -= (size_t)len;
+ memset(&p[char_counter], ' ', (size_t)len);
}
len = utf_char2bytes(wp->w_p_fcs_chars.foldclosed, (char *)&p[char_counter]);
- char_counter += len;
+ char_counter += (size_t)len;
}
- return MAX(char_counter + (fdc - i), (size_t)fdc);
+ return MAX(char_counter + (size_t)(fdc - i), (size_t)fdc);
}
static inline void provider_err_virt_text(linenr_T lnum, char *err)
@@ -1974,7 +1975,7 @@ static inline void provider_err_virt_text(linenr_T lnum, char *err)
kv_push(err_decor.virt_text,
((VirtTextChunk){ .text = provider_err,
.hl_id = hl_err }));
- err_decor.virt_text_width = mb_string2cells(err);
+ err_decor.virt_text_width = (int)mb_string2cells(err);
decor_add_ephemeral(lnum - 1, 0, lnum - 1, 0, &err_decor, 0, 0);
}
@@ -2118,7 +2119,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
bool has_decor = false; // this buffer has decoration
int win_col_offset = 0; // offset for window columns
- char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
+ char_u buf_fold[FOLD_TEXT_LEN]; // Hold value returned by get_foldtext
bool area_active = false;
@@ -2211,7 +2212,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Check for columns to display for 'colorcolumn'.
color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols;
if (color_cols != NULL) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols);
}
if (wp->w_p_spell
@@ -2447,10 +2448,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
nextlinecol = 0;
memmove(nextline, line, (size_t)v);
STRMOVE(nextline + v, nextline + SPWORDLEN);
- nextline_idx = v + 1;
+ nextline_idx = (int)v + 1;
} else {
// Long line, use only the last SPWORDLEN bytes.
- nextlinecol = v - SPWORDLEN;
+ nextlinecol = (int)v - SPWORDLEN;
memmove(nextline, line + nextlinecol, SPWORDLEN); // -V512
nextline_idx = SPWORDLEN + 1;
}
@@ -2529,7 +2530,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
if (utf_ptr2cells((char *)ptr) >= c || *ptr == TAB) {
- n_skip = v - vcol;
+ n_skip = (int)(v - vcol);
}
}
@@ -2540,7 +2541,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (tocol <= vcol) {
fromcol = 0;
} else if (fromcol >= 0 && fromcol < vcol) {
- fromcol = vcol;
+ fromcol = (int)vcol;
}
// When w_skipcol is non-zero, first line needs 'showbreak'
@@ -2616,7 +2617,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
ptr = line + v; // "line" may have been updated
}
- unsigned off = 0; // Offset relative start of line
+ int off = 0; // Offset relative start of line
int col = 0; // Visual column on screen.
if (wp->w_p_rl) {
// Rightleft window: process the text in the normal direction, but put
@@ -2668,7 +2669,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// Draw the 'foldcolumn'. Allocate a buffer, "extra" may
// already be in use.
xfree(p_extra_free);
- p_extra_free = xmalloc(MAX_MCO * fdc + 1);
+ p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1);
n_extra = (int)fill_foldcolumn(p_extra_free, wp, foldinfo, lnum);
p_extra_free[n_extra] = NUL;
p_extra = p_extra_free;
@@ -2731,7 +2732,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
char_u *p2 = (char_u *)skipwhite((char *)extra);
p2 = skiptowhite(p2) - 1;
for (char_u *p1 = (char_u *)skipwhite((char *)extra); p1 < p2; p1++, p2--) {
- const int t = *p1;
+ const char_u t = *p1;
*p1 = *p2;
*p2 = t;
}
@@ -2770,7 +2771,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
char_attr = 0;
if (diff_hlf != (hlf_T)0) {
- char_attr = win_hl_attr(wp, diff_hlf);
+ char_attr = win_hl_attr(wp, (int)diff_hlf);
}
p_extra = NULL;
c_extra = ' ';
@@ -2853,7 +2854,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (has_decor && row == startrow + filler_lines) {
// hide virt_text on text hidden by 'nowrap'
- decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state);
+ decor_redraw_col(wp->w_buffer, (int)vcol, off, true, &decor_state);
}
if (saved_n_extra) {
@@ -2908,7 +2909,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_LINE
&& has_fold
- && vcol == 0
+ && col == win_col_offset
&& n_extra == 0
&& row == startrow) {
char_attr = win_hl_attr(wp, HLF_FL);
@@ -2916,7 +2917,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
memset(buf_fold, ' ', FOLD_TEXT_LEN);
p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold);
- n_extra = STRLEN(p_extra);
+ n_extra = (int)STRLEN(p_extra);
if (p_extra != buf_fold) {
xfree(p_extra_free);
@@ -2992,7 +2993,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& n_extra == 0) {
diff_hlf = HLF_CHD; // changed line
}
- line_attr = win_hl_attr(wp, diff_hlf);
+ line_attr = win_hl_attr(wp, (int)diff_hlf);
// Overlay CursorLine onto diff-mode highlight.
if (cul_attr) {
line_attr = 0 != line_attr_lowprio // Low-priority CursorLine
@@ -3299,7 +3300,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange);
assert(tmplen <= INT_MAX);
len = (int)tmplen;
- word_end = v + len;
+ word_end = (int)v + len;
/* In Insert mode only highlight a word that
* doesn't touch the cursor. */
@@ -3390,7 +3391,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
if (c == TAB && n_extra + col > grid->cols) {
- n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
+ n_extra = tabstop_padding((colnr_T)vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
}
c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
@@ -3494,7 +3495,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
vcol_adjusted = vcol - mb_charlen(sbr);
}
// tab amount depends on current column
- tab_len = tabstop_padding(vcol_adjusted,
+ tab_len = tabstop_padding((colnr_T)vcol_adjusted,
wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
@@ -3526,8 +3527,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
len += n_extra - tab_len;
}
c = wp->w_p_lcs_chars.tab1;
- p = xmalloc(len + 1);
- memset(p, ' ', len);
+ p = xmalloc((size_t)len + 1);
+ memset(p, ' ', (size_t)len);
p[len] = NUL;
xfree(p_extra_free);
p_extra_free = p;
@@ -3657,9 +3658,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
char_u *p;
c = *p_extra;
- p = xmalloc(n_extra + 1);
- memset(p, ' ', n_extra);
- STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
+ p = xmalloc((size_t)n_extra + 1);
+ memset(p, ' ', (size_t)n_extra);
+ STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1); // NOLINT(runtime/printf)
p[n_extra] = NUL;
xfree(p_extra_free);
p_extra_free = p_extra = p;
@@ -3835,8 +3836,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
}
if (n != 0) {
- /* At the window boundary, highlight the last character
- * instead (better than nothing). */
+ // At the window boundary, highlight the last character
+ // instead (better than nothing).
off += n;
col += n;
} else {
@@ -3881,7 +3882,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// boguscols = 0; // Disabled because value never read after this
if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols);
}
bool has_virttext = false;
@@ -3926,7 +3927,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
diff_hlf = HLF_CHD;
}
if (diff_hlf != 0) {
- diff_attr = win_hl_attr(wp, diff_hlf);
+ diff_attr = win_hl_attr(wp, (int)diff_hlf);
}
int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr);
@@ -3940,7 +3941,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
schar_from_ascii(linebuf_char[off], ' ');
col += col_stride;
if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols);
}
int col_attr = base_attr;
@@ -4026,7 +4027,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// advance to the next 'colorcolumn'
if (draw_color_col) {
- draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols);
}
// Highlight the cursor column if 'cursorcolumn' is set. But don't
@@ -4073,7 +4074,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (mb_utf8) {
schar_from_cc(linebuf_char[off], mb_c, u8cc);
} else {
- schar_from_ascii(linebuf_char[off], c);
+ schar_from_ascii(linebuf_char[off], (char)c);
}
if (multi_attr) {
linebuf_attr[off] = multi_attr;
@@ -4217,7 +4218,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (filler_todo > 0) {
int index = filler_todo - (filler_lines - n_virt_lines);
if (index > 0) {
- int i = kv_size(virt_lines) - index;
+ int i = (int)kv_size(virt_lines) - index;
assert(i >= 0);
int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset;
draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line,
@@ -4331,7 +4332,7 @@ void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int max_co
if (item->decor.ui_watched) {
// send mark position to UI
col = item->win_col;
- WinExtmark m = { item->ns_id, item->mark_id, win_row, col };
+ WinExtmark m = { (NS)item->ns_id, item->mark_id, win_row, col };
kv_push(win_extmark_arr, m);
}
if (kv_size(item->decor.virt_text)) {
@@ -4505,12 +4506,12 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att
// full cell width?
assert((size_t)win_signcol_width(wp) >= mb_string2cells((char *)(*pp_extra)));
// symbol(s) bytes + (filling spaces) (one byte each)
- *n_extrap = symbol_blen +
- (win_signcol_width(wp) - mb_string2cells((char *)(*pp_extra)));
+ *n_extrap = symbol_blen + win_signcol_width(wp) -
+ (int)mb_string2cells((char *)(*pp_extra));
assert(extra_size > (size_t)symbol_blen);
memset(extra, ' ', extra_size);
- memcpy(extra, *pp_extra, symbol_blen);
+ memcpy(extra, *pp_extra, (size_t)symbol_blen);
*pp_extra = extra;
(*pp_extra)[*n_extrap] = NUL;
@@ -4533,7 +4534,7 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_att
void rl_mirror(char_u *str)
{
char_u *p1, *p2;
- int t;
+ char_u t;
for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2) {
t = *p1;
@@ -4763,8 +4764,7 @@ static int skip_status_match_char(expand_T *xp, char_u *s)
/// If inversion is possible we use it. Else '=' characters are used.
///
/// @param matches list of matches
-void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match,
- int showtail)
+void win_redr_status_matches(expand_T *xp, int num_matches, char **matches, int match, int showtail)
{
#define L_MATCH(m) (showtail ? sm_gettail(matches[m], false) : matches[m])
int row;
@@ -4788,14 +4788,14 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
return;
}
- buf = xmalloc(Columns * MB_MAXBYTES + 1);
+ buf = xmalloc((size_t)Columns * MB_MAXBYTES + 1);
if (match == -1) { // don't show match but original text
match = 0;
highlight = false;
}
// count 1 for the ending ">"
- clen = status_match_len(xp, L_MATCH(match)) + 3;
+ clen = status_match_len(xp, (char_u *)L_MATCH(match)) + 3;
if (match == 0) {
first_match = 0;
} else if (match < first_match) {
@@ -4804,8 +4804,8 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
add_left = true;
} else {
// check if match fits on the screen
- for (i = first_match; i < match; ++i) {
- clen += status_match_len(xp, L_MATCH(i)) + 2;
+ for (i = first_match; i < match; i++) {
+ clen += status_match_len(xp, (char_u *)L_MATCH(i)) + 2;
}
if (first_match > 0) {
clen += 2;
@@ -4815,8 +4815,8 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
first_match = match;
// if showing the last match, we can add some on the left
clen = 2;
- for (i = match; i < num_matches; ++i) {
- clen += status_match_len(xp, L_MATCH(i)) + 2;
+ for (i = match; i < num_matches; i++) {
+ clen += status_match_len(xp, (char_u *)L_MATCH(i)) + 2;
if ((long)clen >= Columns) {
break;
}
@@ -4828,7 +4828,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
}
if (add_left) {
while (first_match > 0) {
- clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
+ clen += status_match_len(xp, (char_u *)L_MATCH(first_match - 1)) + 2;
if ((long)clen >= Columns) {
break;
}
@@ -4848,13 +4848,13 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
clen = len;
i = first_match;
- while (clen + status_match_len(xp, L_MATCH(i)) + 2 < Columns) {
+ while (clen + status_match_len(xp, (char_u *)L_MATCH(i)) + 2 < Columns) {
if (i == match) {
selstart = buf + len;
selstart_col = clen;
}
- s = L_MATCH(i);
+ s = (char_u *)L_MATCH(i);
// Check for menu separators - replace with '|'
emenu = (xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES);
@@ -4915,8 +4915,8 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
// Set 'winminheight' to zero to avoid that the window is
// resized.
if (lastwin->w_status_height == 0 && global_stl_height() == 0) {
- save_p_ls = p_ls;
- save_p_wmh = p_wmh;
+ save_p_ls = (int)p_ls;
+ save_p_wmh = (int)p_wmh;
p_ls = 2;
p_wmh = 0;
last_status(false);
@@ -4995,19 +4995,19 @@ static void win_redr_status(win_T *wp)
*(p + len++) = ' ';
}
if (bt_help(wp->w_buffer)) {
- snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Help]"));
+ snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[Help]"));
len += (int)STRLEN(p + len);
}
if (wp->w_p_pvw) {
- snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Preview]"));
+ snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[Preview]"));
len += (int)STRLEN(p + len);
}
if (bufIsChanged(wp->w_buffer)) {
- snprintf((char *)p + len, MAXPATHL - len, "%s", "[+]");
+ snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", "[+]");
len += (int)STRLEN(p + len);
}
if (wp->w_buffer->b_p_ro) {
- snprintf((char *)p + len, MAXPATHL - len, "%s", _("[RO]"));
+ snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[RO]"));
// len += (int)STRLEN(p + len); // dead assignment
}
@@ -5038,7 +5038,7 @@ static void win_redr_status(win_T *wp)
}
}
- row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
+ row = is_stl_global ? (Rows - (int)p_ch - 1) : W_ENDROW(wp);
col = is_stl_global ? 0 : wp->w_wincol;
grid_puts(&default_grid, p, row, col, attr);
grid_fill(&default_grid, row, row + 1, len + col,
@@ -5047,7 +5047,7 @@ static void win_redr_status(win_T *wp)
if (get_keymap_str(wp, "<%s>", (char *)NameBuff, MAXPATHL)
&& this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
grid_puts(&default_grid, NameBuff, row,
- (int)(this_ru_col - STRLEN(NameBuff) - 1), attr);
+ (int)((size_t)this_ru_col - STRLEN(NameBuff) - 1), attr);
}
win_redr_ruler(wp, true);
@@ -5256,7 +5256,7 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len)
p = "lang";
}
}
- if (vim_snprintf(buf, len, fmt, p) > len - 1) {
+ if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) {
buf[0] = NUL;
}
xfree(s);
@@ -5323,7 +5323,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
maxwidth = wp->w_width_inner;
use_sandbox = was_set_insecurely(wp, "winbar", 0);
- stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ stl_clear_click_defs(wp->w_winbar_click_defs, (long)wp->w_winbar_click_defs_size);
// Allocate / resize the click definitions array for winbar if needed.
if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
xfree(wp->w_winbar_click_defs);
@@ -5331,15 +5331,15 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
}
} else {
- row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
+ row = is_stl_global ? (Rows - (int)p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
maxwidth = is_stl_global ? Columns : wp->w_width;
- stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ stl_clear_click_defs(wp->w_status_click_defs, (long)wp->w_status_click_defs_size);
// Allocate / resize the click definitions array for statusline if needed.
if (wp->w_status_click_defs_size < (size_t)maxwidth) {
xfree(wp->w_status_click_defs);
- wp->w_status_click_defs_size = maxwidth;
+ wp->w_status_click_defs_size = (size_t)maxwidth;
wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
}
@@ -5406,7 +5406,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
// Make all characters printable.
p = transstr(buf, true);
- len = STRLCPY(buf, p, sizeof(buf));
+ len = (int)STRLCPY(buf, p, sizeof(buf));
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
xfree(p);
@@ -5799,13 +5799,11 @@ void screenclear(void)
/// Copy part of a grid line for vertically split window.
static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
{
- unsigned off_to = grid->line_offset[to] + col;
- unsigned off_from = grid->line_offset[from] + col;
+ unsigned off_to = (unsigned)(grid->line_offset[to] + (size_t)col);
+ unsigned off_from = (unsigned)(grid->line_offset[from] + (size_t)col);
- memmove(grid->chars + off_to, grid->chars + off_from,
- width * sizeof(schar_T));
- memmove(grid->attrs + off_to, grid->attrs + off_from,
- width * sizeof(sattr_T));
+ memmove(grid->chars + off_to, grid->chars + off_from, (size_t)width * sizeof(schar_T));
+ memmove(grid->attrs + off_to, grid->attrs + off_from, (size_t)width * sizeof(sattr_T));
}
/// Set cursor to its position in the current window.
@@ -5902,11 +5900,11 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
linecopy(grid, j + line_count, j, col, width);
}
j += line_count;
- grid_clear_line(grid, grid->line_offset[j] + col, width, false);
+ grid_clear_line(grid, grid->line_offset[j] + (size_t)col, width, false);
grid->line_wraps[j] = false;
} else {
j = end - 1 - i;
- temp = grid->line_offset[j];
+ temp = (unsigned)grid->line_offset[j];
while ((j -= line_count) >= row) {
grid->line_offset[j + line_count] = grid->line_offset[j];
grid->line_wraps[j + line_count] = grid->line_wraps[j];
@@ -5951,12 +5949,12 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
linecopy(grid, j - line_count, j, col, width);
}
j -= line_count;
- grid_clear_line(grid, grid->line_offset[j] + col, width, false);
+ grid_clear_line(grid, grid->line_offset[j] + (size_t)col, width, false);
grid->line_wraps[j] = false;
} else {
// whole width, moving the line pointers is faster
j = row + i;
- temp = grid->line_offset[j];
+ temp = (unsigned)grid->line_offset[j];
while ((j += line_count) <= end - 1) {
grid->line_offset[j - line_count] = grid->line_offset[j];
grid->line_wraps[j - line_count] = grid->line_wraps[j];
@@ -6058,7 +6056,7 @@ int showmode(void)
if (edit_submode_extra != NULL) {
msg_puts_attr(" ", attr); // Add a space in between.
if ((int)edit_submode_highl < HLF_COUNT) {
- sub_attr = win_hl_attr(curwin, edit_submode_highl);
+ sub_attr = win_hl_attr(curwin, (int)edit_submode_highl);
} else {
sub_attr = attr;
}
@@ -6079,7 +6077,11 @@ int showmode(void)
msg_puts_attr(_(" INSERT"), attr);
} else if (restart_edit == 'I' || restart_edit == 'i'
|| restart_edit == 'a' || restart_edit == 'A') {
- msg_puts_attr(_(" (insert)"), attr);
+ if (curbuf->terminal) {
+ msg_puts_attr(_(" (terminal)"), attr);
+ } else {
+ msg_puts_attr(_(" (insert)"), attr);
+ }
} else if (restart_edit == 'R') {
msg_puts_attr(_(" (replace)"), attr);
} else if (restart_edit == 'V') {
@@ -6195,10 +6197,6 @@ void unshowmode(bool force)
// Clear the mode message.
void clearmode(void)
{
- if (p_ch <= 0 && !ui_has(kUIMessages)) {
- return;
- }
-
const int save_msg_row = msg_row;
const int save_msg_col = msg_col;
@@ -6216,10 +6214,6 @@ void clearmode(void)
static void recording_mode(int attr)
{
- if (p_ch <= 0 && !ui_has(kUIMessages)) {
- return;
- }
-
msg_puts_attr(_("recording"), attr);
if (!shortmess(SHM_RECORDING)) {
char s[4];
@@ -6524,8 +6518,7 @@ int redrawing(void)
*/
int messaging(void)
{
- return !(p_lz && char_avail() && !KeyTyped)
- && (p_ch > 0 || ui_has(kUIMessages));
+ return !(p_lz && char_avail() && !KeyTyped) && ui_has_messages();
}
/// Show current status info in ruler and various other places
@@ -6562,7 +6555,7 @@ static void win_redr_ruler(win_T *wp, bool always)
bool is_stl_global = global_stl_height() > 0;
static bool did_show_ext_ruler = false;
- // If 'ruler' off or redrawing disabled, don't do anything
+ // If 'ruler' off, don't do anything
if (!p_ru) {
return;
}
@@ -6626,7 +6619,7 @@ static void win_redr_ruler(win_T *wp, bool always)
width = wp->w_width;
part_of_status = true;
} else if (is_stl_global) {
- row = Rows - p_ch - 1;
+ row = Rows - (int)p_ch - 1;
fillchar = fillchar_status(&attr, wp);
off = 0;
width = Columns;
@@ -6639,7 +6632,7 @@ static void win_redr_ruler(win_T *wp, bool always)
off = 0;
}
- if (!part_of_status && p_ch < 1 && !ui_has(kUIMessages)) {
+ if (!part_of_status && !ui_has_messages()) {
return;
}
@@ -6727,7 +6720,7 @@ static void win_redr_ruler(win_T *wp, bool always)
wp->w_ru_cursor = wp->w_cursor;
wp->w_ru_virtcol = wp->w_virtcol;
- wp->w_ru_empty = empty_line;
+ wp->w_ru_empty = (char)empty_line;
wp->w_ru_topline = wp->w_topline;
wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
wp->w_ru_topfill = wp->w_topfill;
@@ -6765,7 +6758,7 @@ int number_width(win_T *wp)
// 'numberwidth' gives the minimal width plus one
if (n < wp->w_p_nuw - 1) {
- n = wp->w_p_nuw - 1;
+ n = (int)wp->w_p_nuw - 1;
}
// If 'signcolumn' is set to 'number' and there is a sign to display, then
diff --git a/src/nvim/search.c b/src/nvim/search.c
index f3061b4dc4..403e2f3aa4 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -18,6 +18,7 @@
#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
@@ -27,6 +28,7 @@
#include "nvim/getchar.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -424,10 +426,10 @@ int last_csearch_until(void)
void set_last_csearch(int c, char_u *s, int len)
{
- *lastc = c;
+ *lastc = (char_u)c;
lastc_bytelen = len;
if (len) {
- memcpy(lastc_bytes, s, len);
+ memcpy(lastc_bytes, s, (size_t)len);
} else {
memset(lastc_bytes, 0, sizeof(lastc_bytes));
}
@@ -973,7 +975,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
void set_search_direction(int cdir)
{
- spats[0].off.dir = cdir;
+ spats[0].off.dir = (char)cdir;
}
static void set_vv_searchforward(void)
@@ -1062,7 +1064,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
if (dirc == 0) {
dirc = (char_u)spats[0].off.dir;
} else {
- spats[0].off.dir = dirc;
+ spats[0].off.dir = (char)dirc;
set_vv_searchforward();
}
if (options & SEARCH_REV) {
@@ -1183,7 +1185,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
if (!cmd_silent
&& (spats[0].off.line || spats[0].off.end || spats[0].off.off)) {
p = off_buf; // -V507
- *p++ = dirc;
+ *p++ = (char_u)dirc;
if (spats[0].off.end) {
*p++ = 'e';
} else if (!spats[0].off.line) {
@@ -1194,7 +1196,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
}
*p = NUL;
if (spats[0].off.off != 0 || spats[0].off.line) {
- snprintf((char *)p, sizeof(off_buf) - 1 - (p - off_buf),
+ snprintf((char *)p, sizeof(off_buf) - 1 - (size_t)(p - off_buf),
"%" PRId64, spats[0].off.off);
}
off_len = STRLEN(off_buf);
@@ -1215,10 +1217,10 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
len = 0; // adjusted below
} else if (msg_scrolled != 0 && !cmd_silent) {
// Use all the columns.
- len = (Rows - msg_row) * Columns - 1;
+ len = (size_t)((Rows - msg_row) * Columns - 1);
} else {
// Use up to 'showcmd' column.
- len = (Rows - msg_row - 1) * Columns + sc_col - 1;
+ len = (size_t)((Rows - msg_row - 1) * Columns + sc_col - 1);
}
if (len < STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3) {
len = STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3;
@@ -1236,7 +1238,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
// do not fill the msgbuf buffer, if cmd_silent is set, leave it
// empty for the search_stat feature.
if (!cmd_silent) {
- msgbuf[0] = dirc;
+ msgbuf[0] = (char_u)dirc;
if (utf_iscomposing(utf_ptr2char((char *)p))) {
// Use a space to draw the composing char on.
msgbuf[1] = ' ';
@@ -1266,13 +1268,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
while (*r == ' ') {
r++;
}
- size_t pat_len = msgbuf + STRLEN(msgbuf) - r;
+ size_t pat_len = (size_t)(msgbuf + STRLEN(msgbuf) - r);
memmove(msgbuf, r, pat_len);
// overwrite old text
if ((size_t)(r - msgbuf) >= pat_len) {
memset(r, ' ', pat_len);
} else {
- memset(msgbuf + pat_len, ' ', r - msgbuf);
+ memset(msgbuf + pat_len, ' ', (size_t)(r - msgbuf));
}
}
msg_outtrans((char *)msgbuf);
@@ -1326,7 +1328,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
RE_LAST, sia);
if (dircp != NULL) {
- *dircp = search_delim; // restore second '/' or '?' for normal_cmd()
+ *dircp = (char_u)search_delim; // restore second '/' or '?' for normal_cmd()
}
if (!shortmess(SHM_SEARCH)
@@ -1361,7 +1363,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
} else if (c > curbuf->b_ml.ml_line_count) {
pos.lnum = curbuf->b_ml.ml_line_count;
} else {
- pos.lnum = c;
+ pos.lnum = (linenr_T)c;
}
pos.col = 0;
@@ -1535,7 +1537,7 @@ int searchc(cmdarg_T *cap, int t_cmd)
if (c != NUL) { // normal search: remember args for repeat
if (!KeyStuffed) { // don't remember when redoing
- *lastc = c;
+ *lastc = (char_u)c;
set_csearch_direction(dir);
set_csearch_until(t_cmd);
lastc_bytelen = utf_char2bytes(c, (char *)lastc_bytes);
@@ -1657,14 +1659,12 @@ static bool check_prevcol(char_u *linep, int col, int ch, int *prevcol)
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;
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);
+ size_t delim_len = (size_t)((p - linep) - startpos->col - 1);
+ char_u *delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len);
bool found = false;
for (lnum = startpos->lnum; lnum <= endpos->lnum; lnum++) {
char_u *line = ml_get(lnum);
@@ -2434,9 +2434,9 @@ void showmatch(int c)
* available.
*/
if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL) {
- os_delay(p_mat * 100L + 8, true);
+ os_delay((uint64_t)p_mat * 100L + 8, true);
} else if (!char_avail()) {
- os_delay(p_mat * 100L + 9, false);
+ os_delay((uint64_t)p_mat * 100L + 9, false);
}
curwin->w_cursor = save_cursor; // restore cursor position
*so = save_so;
@@ -3665,16 +3665,15 @@ again:
curwin->w_cursor = old_pos;
goto theend;
}
- const size_t spat_len = len + 39;
+ const size_t spat_len = (size_t)len + 39;
char *const spat = xmalloc(spat_len);
- const size_t epat_len = len + 9;
+ const size_t epat_len = (size_t)len + 9;
char *const epat = xmalloc(epat_len);
snprintf(spat, spat_len,
"<%.*s\\>\\%%(\\_s\\_[^>]\\{-}\\_[^/]>\\|\\_s\\?>\\)\\c", len, p);
snprintf(epat, epat_len, "</%.*s>\\c", len, p);
- const int r = do_searchpair(spat, "", epat, FORWARD, NULL,
- 0, NULL, (linenr_T)0, 0L);
+ const int r = (int)do_searchpair(spat, "", epat, FORWARD, NULL, 0, NULL, (linenr_T)0, 0L);
xfree(spat);
xfree(epat);
@@ -3795,7 +3794,7 @@ extend:
} else {
dir = FORWARD;
}
- for (i = count; --i >= 0;) {
+ for (i = (int)count; --i >= 0;) {
if (start_lnum ==
(dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) {
retval = FAIL;
@@ -3863,8 +3862,8 @@ extend:
++end_lnum;
}
- --end_lnum;
- i = count;
+ end_lnum--;
+ i = (int)count;
if (!include && white_in_front) {
--i;
}
@@ -4435,9 +4434,9 @@ static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direct
// start and end are in the same position.
do {
regmatch.startpos[0].col++;
- nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
- pos.lnum, regmatch.startpos[0].col,
- NULL, NULL);
+ nmatched = (int)vim_regexec_multi(&regmatch, curwin, curbuf,
+ pos.lnum, regmatch.startpos[0].col,
+ NULL, NULL);
if (nmatched != 0) {
break;
}
@@ -4624,7 +4623,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst
if (done_search) {
xfree(lastpat);
lastpat = vim_strsave(spats[last_idx].pat);
- chgtick = buf_get_changedtick(curbuf);
+ chgtick = (int)buf_get_changedtick(curbuf);
lbuf = curbuf;
lastpos = p;
}
@@ -4704,21 +4703,21 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
li = tv_list_find(di->di_tv.vval.v_list, 0L);
if (li != NULL) {
- pos.lnum = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
+ pos.lnum = (linenr_T)tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
if (error) {
return;
}
}
li = tv_list_find(di->di_tv.vval.v_list, 1L);
if (li != NULL) {
- pos.col = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error) - 1;
+ pos.col = (colnr_T)tv_get_number_chk(TV_LIST_ITEM_TV(li), &error) - 1;
if (error) {
return;
}
}
li = tv_list_find(di->di_tv.vval.v_list, 2L);
if (li != NULL) {
- pos.coladd = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
+ pos.coladd = (colnr_T)tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
if (error) {
return;
}
@@ -4841,7 +4840,7 @@ static int fuzzy_match_compute_score(const char_u *const str, const int strSz,
int score = 100;
// Apply leading letter penalty
- int penalty = LEADING_LETTER_PENALTY * matches[0];
+ int penalty = LEADING_LETTER_PENALTY * (int)matches[0];
if (penalty < MAX_LEADING_LETTER_PENALTY) {
penalty = MAX_LEADING_LETTER_PENALTY;
}
@@ -4862,7 +4861,7 @@ static int fuzzy_match_compute_score(const char_u *const str, const int strSz,
if (currIdx == prevIdx + 1) {
score += SEQUENTIAL_BONUS;
} else {
- score += GAP_PENALTY * (currIdx - prevIdx);
+ score += GAP_PENALTY * (int)(currIdx - prevIdx);
}
}
@@ -4936,7 +4935,7 @@ static int fuzzy_match_recursive(const char_u *fuzpat, const char_u *str, uint32
// "Copy-on-Write" srcMatches into matches
if (first_match && srcMatches != NULL) {
- memcpy(matches, srcMatches, nextMatch * sizeof(srcMatches[0]));
+ memcpy(matches, srcMatches, (size_t)nextMatch * sizeof(srcMatches[0]));
first_match = false;
}
@@ -4976,7 +4975,7 @@ static int fuzzy_match_recursive(const char_u *fuzpat, const char_u *str, uint32
// Return best result
if (recursiveMatch && (!matched || bestRecursiveScore > *outScore)) {
// Recursive score is better than "this"
- memcpy(matches, bestRecursiveMatches, maxMatches * sizeof(matches[0]));
+ memcpy(matches, bestRecursiveMatches, (size_t)maxMatches * sizeof(matches[0]));
*outScore = bestRecursiveScore;
return nextMatch;
} else if (matched) {
@@ -5095,7 +5094,7 @@ static void fuzzy_match_in_list(list_T *const l, char_u *const str, const bool m
len = max_matches;
}
- fuzzyItem_T *const items = xcalloc(len, sizeof(fuzzyItem_T));
+ fuzzyItem_T *const items = xcalloc((size_t)len, sizeof(fuzzyItem_T));
long match_count = 0;
uint32_t matches[MAX_FUZZY_MATCHES];
@@ -5136,7 +5135,7 @@ static void fuzzy_match_in_list(list_T *const l, char_u *const str, const bool m
int score;
if (itemstr != NULL && fuzzy_match(itemstr, str, matchseq, &score, matches,
MAX_FUZZY_MATCHES)) {
- items[match_count].idx = match_count;
+ items[match_count].idx = (int)match_count;
items[match_count].item = li;
items[match_count].score = score;
@@ -5161,7 +5160,7 @@ static void fuzzy_match_in_list(list_T *const l, char_u *const str, const bool m
if (match_count > 0) {
// Sort the list by the descending order of the match score
- qsort(items, match_count, sizeof(fuzzyItem_T), fuzzy_match_item_compare);
+ qsort(items, (size_t)match_count, sizeof(fuzzyItem_T), fuzzy_match_item_compare);
// For matchfuzzy(), return a list of matched strings.
// ['str1', 'str2', 'str3']
@@ -5394,7 +5393,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo
}
def_regmatch.rm_ic = FALSE; // don't ignore case in define pat.
}
- files = xcalloc(max_path_depth, sizeof(SearchedFile));
+ files = xcalloc((size_t)max_path_depth, sizeof(SearchedFile));
old_files = max_path_depth;
depth = depth_displayed = -1;
@@ -5537,7 +5536,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo
if (new_fname != NULL) {
// Push the new file onto the file stack
if (depth + 1 == old_files) {
- bigger = xmalloc(max_path_depth * 2 * sizeof(SearchedFile));
+ bigger = xmalloc((size_t)max_path_depth * 2 * sizeof(SearchedFile));
for (i = 0; i <= depth; i++) {
bigger[i] = files[i];
}
@@ -5849,7 +5848,7 @@ exit_matched:
if (action == ACTION_EXPAND) {
ins_compl_check_keys(30, false);
}
- if (got_int || compl_interrupted) {
+ if (got_int || ins_compl_interrupted()) {
break;
}
@@ -5911,7 +5910,7 @@ exit_matched:
}
} else if (!found
&& action != ACTION_EXPAND) {
- if (got_int || compl_interrupted) {
+ if (got_int || ins_compl_interrupted()) {
emsg(_(e_interr));
} else if (type == FIND_DEFINE) {
emsg(_("E388: Couldn't find definition"));
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 53059cc1ea..ff843bb59e 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -5,7 +5,6 @@
#include <stdint.h>
#include "nvim/buffer_defs.h"
-#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/normal.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 9a4b304d6c..1640d0167e 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -10,6 +10,7 @@
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
+#include "nvim/eval/funcs.h"
#include "nvim/ex_docmd.h"
#include "nvim/fold.h"
#include "nvim/highlight_group.h"
diff --git a/src/nvim/sign.h b/src/nvim/sign.h
index c61e5d20ef..ba84cd71a4 100644
--- a/src/nvim/sign.h
+++ b/src/nvim/sign.h
@@ -4,7 +4,6 @@
#include <stdbool.h>
#include "nvim/buffer_defs.h"
-#include "nvim/eval/funcs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/sign_defs.h"
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 2aadc2258e..ceb35af4b8 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -95,6 +95,7 @@
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/input.h"
+#include "nvim/insexpand.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -291,7 +292,7 @@ int did_set_spelltab;
// structure used to store soundfolded words that add_sound_suggest() has
// handled already.
typedef struct {
- short sft_score; // lowest score used
+ int16_t sft_score; // lowest score used
char_u sft_word[1]; // soundfolded word, actually longer
} sftword_T;
@@ -743,9 +744,8 @@ static void find_word(matchinf_T *mip, int mode)
// prefix ID.
// Repeat this if there are more flags/region alternatives until there
// is a match.
- for (len = byts[arridx - 1]; len > 0 && byts[arridx] == 0;
- --len, ++arridx) {
- uint32_t flags = idxs[arridx];
+ for (len = byts[arridx - 1]; len > 0 && byts[arridx] == 0; len--, arridx++) {
+ uint32_t flags = (uint32_t)idxs[arridx];
// For the fold-case tree check that the case of the checked word
// matches with what the word in the tree requires.
@@ -760,7 +760,7 @@ static void find_word(matchinf_T *mip, int mode)
}
if (mip->mi_capflags == WF_KEEPCAP
- || !spell_valid_case(mip->mi_capflags, flags)) {
+ || !spell_valid_case(mip->mi_capflags, (int)flags)) {
continue;
}
}
@@ -769,7 +769,7 @@ static void find_word(matchinf_T *mip, int mode)
// mip->mi_prefarridx that find_prefix() filled.
else if (mode == FIND_PREFIX && !prefix_found) {
c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
- flags,
+ (int)flags,
mip->mi_word + mip->mi_cprefixlen, slang,
false);
if (c == 0) {
@@ -828,10 +828,8 @@ static void find_word(matchinf_T *mip, int mode)
}
// Quickly check if compounding is possible with this flag.
- if (!byte_in_str(mip->mi_complen == 0
- ? slang->sl_compstartflags
- : slang->sl_compallflags,
- ((unsigned)flags >> 24))) {
+ if (!byte_in_str(mip->mi_complen == 0 ? slang->sl_compstartflags : slang->sl_compallflags,
+ (int)((unsigned)flags >> 24))) {
continue;
}
@@ -879,7 +877,7 @@ static void find_word(matchinf_T *mip, int mode)
// If the word ends the sequence of compound flags of the
// words must match with one of the COMPOUNDRULE items and
// the number of syllables must not be too large.
- mip->mi_compflags[mip->mi_complen] = ((unsigned)flags >> 24);
+ mip->mi_compflags[mip->mi_complen] = (char_u)((unsigned)flags >> 24);
mip->mi_compflags[mip->mi_complen + 1] = NUL;
if (word_ends) {
char_u fword[MAXWLEN] = { 0 };
@@ -1005,7 +1003,7 @@ static void find_word(matchinf_T *mip, int mode)
res = SP_BANNED;
} else if (flags & WF_REGION) {
// Check region.
- if ((mip->mi_lp->lp_region & (flags >> 16)) != 0) {
+ if (((unsigned)mip->mi_lp->lp_region & (flags >> 16)) != 0) {
res = SP_OK;
} else {
res = SP_LOCAL;
@@ -1119,7 +1117,7 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i
// possibly can form a match with COMPOUNDRULE patterns. This only
// makes sense when we have two or more words.
if (slang->sl_comprules != NULL && sp->ts_complen > sp->ts_compsplit) {
- compflags[sp->ts_complen] = flag;
+ compflags[sp->ts_complen] = (char_u)flag;
compflags[sp->ts_complen + 1] = NUL;
bool v = match_compoundrule(slang, compflags + sp->ts_compsplit);
compflags[sp->ts_complen] = NUL;
@@ -1195,10 +1193,9 @@ static int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word
{
int prefcnt;
int pidx;
- int prefid;
- prefid = (unsigned)flags >> 24;
- for (prefcnt = totprefcnt - 1; prefcnt >= 0; --prefcnt) {
+ int prefid = (int)((unsigned)flags >> 24);
+ for (prefcnt = totprefcnt - 1; prefcnt >= 0; prefcnt--) {
pidx = slang->sl_pidxs[arridx + prefcnt];
// Check the prefix ID.
@@ -1646,7 +1643,7 @@ void spell_cat_line(char_u *buf, char_u *line, int maxlen)
// concatenate.
n = (int)(p - line) + 1;
if (n < maxlen - 1) {
- memset(buf, ' ', n);
+ memset(buf, ' ', (size_t)n);
STRLCPY(buf + n, p, maxlen - n);
}
}
@@ -1872,7 +1869,7 @@ static void spell_load_cb(char *fname, void *cookie)
/// @param[in] word added to common words hashtable
/// @param[in] len length of word or -1 for NUL terminated
/// @param[in] count 1 to count once, 10 to init
-void count_common_word(slang_T *lp, char_u *word, int len, int count)
+void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count)
{
hash_T hash;
hashitem_T *hi;
@@ -1899,7 +1896,8 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
} else {
wc = HI2WC(hi);
- if ((wc->wc_count += count) < (unsigned)count) { // check for overflow
+ wc->wc_count = (uint16_t)(wc->wc_count + count);
+ if (wc->wc_count < count) { // check for overflow
wc->wc_count = MAXWORDCOUNT;
}
}
@@ -2108,7 +2106,7 @@ char *did_set_spelllang(win_T *wp)
if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2])
&& !ASCII_ISALPHA(p[3])) {
STRLCPY(region_cp, p + 1, 3);
- memmove(p, p + 3, len - (p - lang) - 2);
+ memmove(p, p + 3, (size_t)(len - (p - lang) - 2));
region = region_cp;
} else {
dont_use_region = true;
@@ -2360,11 +2358,11 @@ static void use_midword(slang_T *lp, win_T *wp)
wp->w_s->b_spell_ismw[c] = true;
} else if (wp->w_s->b_spell_ismw_mb == NULL) {
// First multi-byte char in "b_spell_ismw_mb".
- wp->w_s->b_spell_ismw_mb = vim_strnsave(p, l);
+ wp->w_s->b_spell_ismw_mb = vim_strnsave(p, (size_t)l);
} else {
// Append multi-byte chars to "b_spell_ismw_mb".
const int n = (int)STRLEN(wp->w_s->b_spell_ismw_mb);
- char_u *bp = vim_strnsave(wp->w_s->b_spell_ismw_mb, n + l);
+ char_u *bp = vim_strnsave(wp->w_s->b_spell_ismw_mb, (size_t)n + (size_t)l);
xfree(wp->w_s->b_spell_ismw_mb);
wp->w_s->b_spell_ismw_mb = bp;
STRLCPY(bp + n, p, l + 1);
@@ -2616,9 +2614,9 @@ void clear_spell_chartab(spelltab_T *sp)
memset(sp->st_isw, false, sizeof(sp->st_isw));
memset(sp->st_isu, false, sizeof(sp->st_isu));
- for (i = 0; i < 256; ++i) {
- sp->st_fold[i] = i;
- sp->st_upper[i] = i;
+ for (i = 0; i < 256; i++) {
+ sp->st_fold[i] = (char_u)i;
+ sp->st_upper[i] = (char_u)i;
}
// We include digits. A word shouldn't start with a digit, but handling
@@ -2629,11 +2627,11 @@ void clear_spell_chartab(spelltab_T *sp)
for (i = 'A'; i <= 'Z'; ++i) {
sp->st_isw[i] = true;
sp->st_isu[i] = true;
- sp->st_fold[i] = i + 0x20;
+ sp->st_fold[i] = (char_u)(i + 0x20);
}
for (i = 'a'; i <= 'z'; ++i) {
sp->st_isw[i] = true;
- sp->st_upper[i] = i - 0x20;
+ sp->st_upper[i] = (char_u)(i - 0x20);
}
}
@@ -2656,8 +2654,8 @@ void init_spell_chartab(void)
// The folded/upper-cased value is different between latin1 and
// utf8 for 0xb5, causing E763 for no good reason. Use the latin1
// value for utf-8 to avoid this.
- spelltab.st_fold[i] = (f < 256) ? f : i;
- spelltab.st_upper[i] = (u < 256) ? u : i;
+ spelltab.st_fold[i] = (f < 256) ? (char_u)f : (char_u)i;
+ spelltab.st_upper[i] = (u < 256) ? (char_u)u : (char_u)i;
}
}
@@ -2967,12 +2965,11 @@ void spell_suggest(int count)
stp = &SUG(sug.su_ga, i);
// The suggested word may replace only part of the bad word, add
- // the not replaced part.
+ // the not replaced part. But only when it's not getting too long.
STRLCPY(wcopy, stp->st_word, MAXWLEN + 1);
- if (sug.su_badlen > stp->st_orglen) {
- STRLCPY(wcopy + stp->st_wordlen,
- sug.su_badptr + stp->st_orglen,
- sug.su_badlen - stp->st_orglen + 1);
+ int el = sug.su_badlen - stp->st_orglen;
+ if (el > 0 && stp->st_wordlen + el <= MAXWLEN) {
+ STRLCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen, el + 1);
}
vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
@@ -3036,21 +3033,21 @@ void spell_suggest(int count)
if (sug.su_badlen > stp->st_orglen) {
// Replacing less than "su_badlen", append the remainder to
// repl_to.
- repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
+ repl_from = vim_strnsave(sug.su_badptr, (size_t)sug.su_badlen);
vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
sug.su_badlen - stp->st_orglen,
sug.su_badptr + stp->st_orglen);
repl_to = vim_strsave(IObuff);
} else {
// Replacing su_badlen or more, use the whole word.
- repl_from = vim_strnsave(sug.su_badptr, stp->st_orglen);
+ repl_from = vim_strnsave(sug.su_badptr, (size_t)stp->st_orglen);
repl_to = vim_strsave(stp->st_word);
}
// Replace the word.
- p = xmalloc(STRLEN(line) - stp->st_orglen + stp->st_wordlen + 1);
+ p = xmalloc(STRLEN(line) - (size_t)stp->st_orglen + (size_t)stp->st_wordlen + 1);
c = (int)(sug.su_badptr - line);
- memmove(p, line, c);
+ memmove(p, line, (size_t)c);
STRCPY(p + c, stp->st_word);
STRCAT(p, sug.su_badptr + stp->st_orglen);
@@ -3171,8 +3168,8 @@ void ex_spellrepall(exarg_T *eap)
line = get_cursor_line_ptr();
if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
repl_to, STRLEN(repl_to)) != 0) {
- p = xmalloc(STRLEN(line) + addlen + 1);
- memmove(p, line, curwin->w_cursor.col);
+ p = xmalloc(STRLEN(line) + (size_t)addlen + 1);
+ memmove(p, line, (size_t)curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
STRCAT(p, line + curwin->w_cursor.col + STRLEN(repl_from));
ml_replace(curwin->w_cursor.lnum, (char *)p, false);
@@ -3219,8 +3216,7 @@ void spell_suggest_list(garray_T *gap, char_u *word, int maxcount, bool need_cap
// The suggested word may replace only part of "word", add the not
// replaced part.
- wcopy = xmalloc(stp->st_wordlen
- + STRLEN(sug.su_badptr + stp->st_orglen) + 1);
+ wcopy = xmalloc((size_t)stp->st_wordlen + STRLEN(sug.su_badptr + stp->st_orglen) + 1);
STRCPY(wcopy, stp->st_word);
STRCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen);
((char_u **)gap->ga_data)[gap->ga_len++] = wcopy;
@@ -3562,7 +3558,7 @@ static void allcap_copy(char_u *word, char_u *wcopy)
if (d - wcopy >= MAXWLEN - 1) {
break;
}
- *d++ = c;
+ *d++ = (char_u)c;
} else {
c = SPELL_TOUPPER(c);
}
@@ -3578,14 +3574,12 @@ static void allcap_copy(char_u *word, char_u *wcopy)
// Try finding suggestions by recognizing specific situations.
static void suggest_try_special(suginfo_T *su)
{
- char_u *p;
- size_t len;
int c;
char_u word[MAXWLEN];
// Recognize a word that is repeated: "the the".
- p = skiptowhite(su->su_fbadword);
- len = p - su->su_fbadword;
+ char_u *p = skiptowhite(su->su_fbadword);
+ size_t len = (size_t)(p - su->su_fbadword);
p = (char_u *)skipwhite((char *)p);
if (STRLEN(p) == len && STRNCMP(su->su_fbadword, p, len) == 0) {
// Include badflags: if the badword is onecap or allcap
@@ -3593,7 +3587,7 @@ static void suggest_try_special(suginfo_T *su)
c = su->su_fbadword[len];
su->su_fbadword[len] = NUL;
make_case_word(su->su_fbadword, word, su->su_badflags);
- su->su_fbadword[len] = c;
+ su->su_fbadword[len] = (char_u)c;
// Give a soundalike score of 0, compute the score as if deleting one
// character.
@@ -3820,13 +3814,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_prefixdepth == PFD_PREFIXTREE) {
// Skip over the NUL bytes, we use them later.
for (n = 0; n < len && byts[arridx + n] == 0; n++) {}
- sp->ts_curi += n;
+ sp->ts_curi = (int16_t)(sp->ts_curi + n);
// Always past NUL bytes now.
n = (int)sp->ts_state;
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_ENDNUL;
- sp->ts_save_badflags = su->su_badflags;
+ sp->ts_save_badflags = (char_u)su->su_badflags;
// At end of a prefix or at start of prefixtree: check for
// following word.
@@ -3843,7 +3837,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
go_deeper(stack, depth, 0);
++depth;
sp = &stack[depth];
- sp->ts_prefixdepth = depth - 1;
+ sp->ts_prefixdepth = (char_u)(depth - 1);
byts = fbyts;
idxs = fidxs;
sp->ts_arridx = 0;
@@ -3863,7 +3857,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Past bytes in node and/or past NUL bytes.
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_ENDNUL;
- sp->ts_save_badflags = su->su_badflags;
+ sp->ts_save_badflags = (char_u)su->su_badflags;
break;
}
@@ -3966,7 +3960,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
break;
}
- compflags[sp->ts_complen] = ((unsigned)flags >> 24);
+ compflags[sp->ts_complen] = (char_u)((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
STRLCPY(preword + sp->ts_prewordlen,
tword + sp->ts_splitoff,
@@ -4048,7 +4042,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
newscore = 0;
if (!soundfold) { // soundfold words don't have flags
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
+ && (((unsigned)flags >> 16) & (unsigned)lp->lp_region) == 0) {
newscore += SCORE_REGION;
}
if (flags & WF_RARE) {
@@ -4166,10 +4160,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
&& (slang->sl_compsylmax < MAXWLEN
|| sp->ts_complen + 1 - sp->ts_compsplit
< slang->sl_compmax)
- && (can_be_compound(sp, slang,
- compflags, ((unsigned)flags >> 24)))) {
+ && (can_be_compound(sp, slang, compflags, (int)((unsigned)flags >> 24)))) {
try_compound = true;
- compflags[sp->ts_complen] = ((unsigned)flags >> 24);
+ compflags[sp->ts_complen] = (char_u)((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
}
@@ -4188,7 +4181,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
--sp->ts_curi; // do the same NUL again
compflags[sp->ts_complen] = NUL;
} else {
- sp->ts_flags &= ~TSF_DIDSPLIT;
+ sp->ts_flags &= (char_u) ~TSF_DIDSPLIT;
}
if (try_split || try_compound) {
@@ -4234,7 +4227,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
}
#endif
// Save things to be restored at STATE_SPLITUNDO.
- sp->ts_save_badflags = su->su_badflags;
+ sp->ts_save_badflags = (char_u)su->su_badflags;
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_SPLITUNDO;
@@ -4265,14 +4258,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
l = utfc_ptr2len((char *)fword + sp->ts_fidx);
if (fword_ends) {
// Copy the skipped character to preword.
- memmove(preword + sp->ts_prewordlen,
- fword + sp->ts_fidx, l);
- sp->ts_prewordlen += l;
+ memmove(preword + sp->ts_prewordlen, fword + sp->ts_fidx, (size_t)l);
+ sp->ts_prewordlen = (char_u)(sp->ts_prewordlen + l);
preword[sp->ts_prewordlen] = NUL;
} else {
sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
}
- sp->ts_fidx += l;
+ sp->ts_fidx = (char_u)(sp->ts_fidx + l);
}
// When compounding include compound flag in
@@ -4385,7 +4377,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (fword[sp->ts_fidx] != NUL) {
sp->ts_fidx++;
}
- tword[sp->ts_twordlen++] = c;
+ tword[sp->ts_twordlen++] = (char_u)c;
sp->ts_arridx = idxs[arridx];
if (newscore == SCORE_SUBST) {
sp->ts_isdiff = DIFF_YES;
@@ -4397,7 +4389,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// First byte.
sp->ts_tcharidx = 0;
sp->ts_tcharlen = MB_BYTE2LEN(c);
- sp->ts_fcharstart = sp->ts_fidx - 1;
+ sp->ts_fcharstart = (char_u)(sp->ts_fidx - 1);
sp->ts_isdiff = (newscore != 0)
? DIFF_YES : DIFF_NONE;
} else if (sp->ts_isdiff == DIFF_INSERT && sp->ts_fidx > 0) {
@@ -4410,8 +4402,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_isdiff == DIFF_YES) {
// Correct ts_fidx for the byte length of the
// character (we didn't check that before).
- sp->ts_fidx = sp->ts_fcharstart
- + utfc_ptr2len((char *)fword + sp->ts_fcharstart);
+ sp->ts_fidx = (char_u)(sp->ts_fcharstart
+ + utfc_ptr2len((char *)fword + sp->ts_fcharstart));
// For changing a composing character adjust
// the score from SCORE_SUBST to
@@ -4498,7 +4490,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// a bit illogical for soundfold tree but it does give better
// results.
c = utf_ptr2char((char *)fword + sp->ts_fidx);
- stack[depth].ts_fidx += utfc_ptr2len((char *)fword + sp->ts_fidx);
+ stack[depth].ts_fidx =
+ (char_u)(stack[depth].ts_fidx + utfc_ptr2len((char *)fword + sp->ts_fidx));
if (utf_iscomposing(c)) {
stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP;
} else if (c == utf_ptr2char((char *)fword + stack[depth].ts_fidx)) {
@@ -4571,14 +4564,14 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#endif
++depth;
sp = &stack[depth];
- tword[sp->ts_twordlen++] = c;
+ tword[sp->ts_twordlen++] = (char_u)c;
sp->ts_arridx = idxs[n];
fl = MB_BYTE2LEN(c);
if (fl > 1) {
// There are following bytes for the same character.
// We must find all bytes before trying
// delete/insert/swap/etc.
- sp->ts_tcharlen = fl;
+ sp->ts_tcharlen = (char_u)fl;
sp->ts_tcharidx = 1;
sp->ts_isdiff = DIFF_INSERT;
}
@@ -4652,9 +4645,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_state = STATE_UNSWAP;
depth++;
fl = utf_char2len(c2);
- memmove(p, p + n, fl);
+ memmove(p, p + n, (size_t)fl);
utf_char2bytes(c, (char *)p + fl);
- stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
+ stack[depth].ts_fidxtry = (char_u)(sp->ts_fidx + n + fl);
} else {
// If this swap doesn't work then SWAP3 won't either.
PROF_STORE(sp->ts_state)
@@ -4667,7 +4660,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
p = fword + sp->ts_fidx;
n = utfc_ptr2len((char *)p);
c = utf_ptr2char((char *)p + n);
- memmove(p + utfc_ptr2len((char *)p + n), p, n);
+ memmove(p + utfc_ptr2len((char *)p + n), p, (size_t)n);
utf_char2bytes(c, (char *)p);
FALLTHROUGH;
@@ -4708,10 +4701,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_state = STATE_UNSWAP3;
depth++;
tl = utf_char2len(c3);
- memmove(p, p + n + fl, tl);
+ memmove(p, p + n + fl, (size_t)tl);
utf_char2bytes(c2, (char *)p + tl);
utf_char2bytes(c, (char *)p + fl + tl);
- stack[depth].ts_fidxtry = sp->ts_fidx + n + fl + tl;
+ stack[depth].ts_fidxtry = (char_u)(sp->ts_fidx + n + fl + tl);
} else {
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
@@ -4726,7 +4719,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
fl = utfc_ptr2len((char *)p + n);
c = utf_ptr2char((char *)p + n + fl);
tl = utfc_ptr2len((char *)p + n + fl);
- memmove(p + fl + tl, p, n);
+ memmove(p + fl + tl, p, (size_t)n);
utf_char2bytes(c, (char *)p);
utf_char2bytes(c2, (char *)p + tl);
p = p + tl;
@@ -4757,9 +4750,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
c = utf_ptr2char((char *)p);
fl = utf_ptr2len((char *)p + n);
fl += utf_ptr2len((char *)p + n + fl);
- memmove(p, p + n, fl);
+ memmove(p, p + n, (size_t)fl);
utf_char2bytes(c, (char *)p + fl);
- stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
+ stack[depth].ts_fidxtry = (char_u)(sp->ts_fidx + n + fl);
} else {
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
@@ -4773,7 +4766,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
n += utfc_ptr2len((char *)p + n);
c = utf_ptr2char((char *)p + n);
tl = utfc_ptr2len((char *)p + n);
- memmove(p + tl, p, n);
+ memmove(p + tl, p, (size_t)n);
utf_char2bytes(c, (char *)p);
// Rotate three bytes right: "123" -> "312". We change "fword"
@@ -4794,9 +4787,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
n += utf_ptr2len((char *)p + n);
c = utf_ptr2char((char *)p + n);
tl = utf_ptr2len((char *)p + n);
- memmove(p + tl, p, n);
+ memmove(p + tl, p, (size_t)n);
utf_char2bytes(c, (char *)p);
- stack[depth].ts_fidxtry = sp->ts_fidx + n + tl;
+ stack[depth].ts_fidxtry = (char_u)(sp->ts_fidx + n + tl);
} else {
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP_INI;
@@ -4810,7 +4803,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
tl = utfc_ptr2len((char *)p);
n = utfc_ptr2len((char *)p + tl);
n += utfc_ptr2len((char *)p + tl + n);
- memmove(p, p + tl, n);
+ memmove(p, p + tl, (size_t)n);
utf_char2bytes(c, (char *)p + n);
FALLTHROUGH;
@@ -4862,7 +4855,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
if (*ftp->ft_from != *p) {
// past possible matching entries
- sp->ts_curi = gap->ga_len;
+ sp->ts_curi = (char_u)gap->ga_len;
break;
}
if (STRNCMP(ftp->ft_from, p, STRLEN(ftp->ft_from)) == 0
@@ -4885,8 +4878,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
STRMOVE(p + tl, p + fl);
repextra += tl - fl;
}
- memmove(p, ftp->ft_to, tl);
- stack[depth].ts_fidxtry = sp->ts_fidx + tl;
+ memmove(p, ftp->ft_to, (size_t)tl);
+ stack[depth].ts_fidxtry = (char_u)(sp->ts_fidx + tl);
stack[depth].ts_tcharlen = 0;
break;
}
@@ -4915,7 +4908,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
STRMOVE(p + fl, p + tl);
repextra -= tl - fl;
}
- memmove(p, ftp->ft_from, fl);
+ memmove(p, ftp->ft_from, (size_t)fl);
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_REP;
break;
@@ -5410,7 +5403,7 @@ static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_
hash);
if (HASHITEM_EMPTY(hi)) {
sft = xmalloc(sizeof(sftword_T) + goodword_len);
- sft->sft_score = score;
+ sft->sft_score = (int16_t)score;
memcpy(sft->sft_word, goodword, goodword_len + 1);
hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
} else {
@@ -5418,7 +5411,7 @@ static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_
if (score >= sft->sft_score) {
return;
}
- sft->sft_score = score;
+ sft->sft_score = (int16_t)score;
}
// Find the word nr in the soundfold tree.
@@ -5511,7 +5504,7 @@ badword:
} else {
// Add a penalty for words in another region.
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
+ && (((unsigned)flags >> 16) & (unsigned)lp->lp_region) == 0) {
goodscore = SCORE_REGION;
} else {
goodscore = 0;
@@ -5781,7 +5774,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword,
if (i < 0) {
// Add a suggestion.
stp = GA_APPEND_VIA_PTR(suggest_T, gap);
- stp->st_word = vim_strnsave(goodword, goodlen);
+ stp->st_word = vim_strnsave(goodword, (size_t)goodlen);
stp->st_wordlen = goodlen;
stp->st_score = score;
stp->st_altscore = altscore;
@@ -5831,8 +5824,7 @@ static void check_suggestions(suginfo_T *su, garray_T *gap)
xfree(stp[i].st_word);
--gap->ga_len;
if (i < gap->ga_len) {
- memmove(stp + i, stp + i + 1,
- sizeof(suggest_T) * (gap->ga_len - i));
+ memmove(stp + i, stp + i + 1, sizeof(suggest_T) * (size_t)(gap->ga_len - i));
}
}
}
@@ -6281,8 +6273,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
}
}
if (k > k0) {
- memmove(word + i + k0, word + i + k,
- sizeof(int) * (wordlen - (i + k) + 1));
+ memmove(word + i + k0, word + i + k, sizeof(int) * (size_t)(wordlen - (i + k) + 1));
}
// new "actual letter"
@@ -6310,8 +6301,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
if (c != NUL) {
wres[reslen++] = c;
}
- memmove(word, word + i + 1,
- sizeof(int) * (wordlen - (i + 1) + 1));
+ memmove(word, word + i + 1, sizeof(int) * (size_t)(wordlen - (i + 1) + 1));
i = 0;
z0 = 1;
}
@@ -6610,7 +6600,7 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
// We use "cnt" as an array: CNT(badword_idx, goodword_idx).
#define CNT(a, b) cnt[(a) + (b) * (badlen + 1)]
- cnt = xmalloc(sizeof(int) * (badlen + 1) * (goodlen + 1));
+ cnt = xmalloc(sizeof(int) * ((size_t)badlen + 1) * ((size_t)goodlen + 1));
CNT(0, 0) = 0;
for (j = 1; j <= goodlen; ++j) {
@@ -6879,7 +6869,7 @@ void ex_spelldump(exarg_T *eap)
if (no_spell_checking(curwin)) {
return;
}
- get_option_value("spl", &dummy, &spl, OPT_LOCAL);
+ (void)get_option_value("spl", &dummy, &spl, OPT_LOCAL);
// Create a new empty buffer in a new window.
do_cmdline_cmd("new");
@@ -7012,7 +7002,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
arridx[0] = 0;
curi[0] = 1;
while (depth >= 0 && !got_int
- && (pat == NULL || !compl_interrupted)) {
+ && (pat == NULL || !ins_compl_interrupted())) {
if (curi[depth] > byts[arridx[depth]]) {
// Done all bytes at this node, go up one level.
--depth;
@@ -7035,7 +7025,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
&& (do_region
|| (flags & WF_REGION) == 0
|| (((unsigned)flags >> 16)
- & lp->lp_region) != 0)) {
+ & (unsigned)lp->lp_region) != 0)) {
word[depth] = NUL;
if (!do_region) {
flags &= ~WF_REGION;
@@ -7043,7 +7033,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
// Dump the basic word if there is no prefix or
// when it's the first one.
- c = (unsigned)flags >> 24;
+ c = (int)((unsigned)flags >> 24);
if (c == 0 || curi[depth] == 2) {
dump_word(slang, word, pat, dir,
dumpflags, flags, lnum);
@@ -7060,7 +7050,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
}
} else {
// Normal char, go one level deeper.
- word[depth++] = c;
+ word[depth++] = (char_u)c;
arridx[depth] = idxs[n];
curi[depth] = 1;
@@ -7256,7 +7246,7 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi
}
} else {
// Normal char, go one level deeper.
- prefix[depth++] = c;
+ prefix[depth++] = (char_u)c;
arridx[depth] = idxs[n];
curi[depth] = 1;
}
@@ -7329,7 +7319,7 @@ void spell_expand_check_cap(colnr_T col)
// Used for Insert mode completion CTRL-X ?.
// Returns the number of matches. The matches are in "matchp[]", array of
// allocated strings.
-int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp)
+int expand_spelling(linenr_T lnum, char_u *pat, char ***matchp)
{
garray_T ga;
diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h
index 7e85b5bf03..222d103f5d 100644
--- a/src/nvim/spell_defs.h
+++ b/src/nvim/spell_defs.h
@@ -237,7 +237,7 @@ typedef struct trystate_S {
state_T ts_state; // state at this level, STATE_
int ts_score; // score
idx_T ts_arridx; // index in tree array, start of node
- short ts_curi; // index in list of child nodes
+ int16_t ts_curi; // index in list of child nodes
char_u ts_fidx; // index in fword[], case-folded bad word
char_u ts_fidxtry; // ts_fidx at which bytes may be changed
char_u ts_twordlen; // valid length of tword[]
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 9d2fd2637d..9f21e24d4c 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -903,8 +903,8 @@ void suggest_load_files(void)
}
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
- for (i = 0; i < VIMSUGMAGICL; ++i) {
- buf[i] = getc(fd); // <fileID>
+ for (i = 0; i < VIMSUGMAGICL; i++) {
+ buf[i] = (char_u)getc(fd); // <fileID>
}
if (STRNCMP(buf, VIMSUGMAGIC, VIMSUGMAGICL) != 0) {
semsg(_("E778: This does not look like a .sug file: %s"),
@@ -965,7 +965,7 @@ someerror:
if (c < 0) {
goto someerror;
}
- GA_APPEND(char_u, &ga, c);
+ GA_APPEND(char_u, &ga, (char_u)c);
if (c == NUL) {
break;
}
@@ -1009,7 +1009,7 @@ static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
*cntp = SP_TRUNCERROR;
return NULL;
}
- cnt = (cnt << 8) + (unsigned)c;
+ cnt = (int)(((unsigned)cnt << 8) + (unsigned)c);
}
*cntp = cnt;
if (cnt == 0) {
@@ -1081,7 +1081,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
return SP_FORMERROR;
}
- lp->sl_prefprog = xcalloc(cnt, sizeof(regprog_T *));
+ lp->sl_prefprog = xcalloc((size_t)cnt, sizeof(regprog_T *));
lp->sl_prefixcnt = cnt;
for (int i = 0; i < cnt; i++) {
@@ -1146,7 +1146,7 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
for (int i = 0; i < gap->ga_len; ++i) {
ftp = &((fromto_T *)gap->ga_data)[i];
if (first[*ftp->ft_from] == -1) {
- first[*ftp->ft_from] = i;
+ first[*ftp->ft_from] = (int16_t)i;
}
}
return 0;
@@ -1193,7 +1193,7 @@ static int read_sal_section(FILE *fd, slang_T *slang)
if (ccnt < 0) {
return SP_TRUNCERROR;
}
- p = xmalloc(ccnt + 2);
+ p = xmalloc((size_t)ccnt + 2);
smp->sm_lead = p;
// Read up to the first special char into sm_lead.
@@ -1203,7 +1203,7 @@ static int read_sal_section(FILE *fd, slang_T *slang)
if (vim_strchr("0123456789(-<^$", c) != NULL) {
break;
}
- *p++ = c;
+ *p++ = (char_u)c;
}
smp->sm_leadlen = (int)(p - smp->sm_lead);
*p++ = NUL;
@@ -1216,7 +1216,7 @@ static int read_sal_section(FILE *fd, slang_T *slang)
if (c == ')') {
break;
}
- *p++ = c;
+ *p++ = (char_u)c;
}
*p++ = NUL;
if (++i < ccnt) {
@@ -1230,7 +1230,7 @@ static int read_sal_section(FILE *fd, slang_T *slang)
smp->sm_rules = p;
if (i < ccnt) {
// store the char we got while checking for end of sm_lead
- *p++ = c;
+ *p++ = (char_u)c;
}
i++;
if (i < ccnt) {
@@ -1302,7 +1302,7 @@ static int read_words_section(FILE *fd, slang_T *lp, int len)
if (c == EOF) {
return SP_TRUNCERROR;
}
- word[i] = c;
+ word[i] = (char_u)c;
if (word[i] == NUL) {
break;
}
@@ -1363,11 +1363,6 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
int todo = len;
int c;
int atstart;
- char_u *pat;
- char_u *pp;
- char_u *cp;
- char_u *ap;
- char_u *crp;
int cnt;
garray_T *gap;
@@ -1432,25 +1427,25 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
// Conversion to utf-8 may double the size.
c = todo * 2 + 7;
c += todo * 2;
- pat = xmalloc(c);
+ char_u *pat = xmalloc((size_t)c);
// We also need a list of all flags that can appear at the start and one
// for all flags.
- cp = xmalloc(todo + 1);
+ char_u *cp = xmalloc((size_t)todo + 1);
slang->sl_compstartflags = cp;
*cp = NUL;
- ap = xmalloc(todo + 1);
+ char_u *ap = xmalloc((size_t)todo + 1);
slang->sl_compallflags = ap;
*ap = NUL;
// And a list of all patterns in their original form, for checking whether
// compounding may work in match_compoundrule(). This is freed when we
// encounter a wildcard, the check doesn't work then.
- crp = xmalloc(todo + 1);
+ char_u *crp = xmalloc((size_t)todo + 1);
slang->sl_comprules = crp;
- pp = pat;
+ char_u *pp = pat;
*pp++ = '^';
*pp++ = '\\';
*pp++ = '(';
@@ -1466,7 +1461,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
// Add all flags to "sl_compallflags".
if (vim_strchr("?*+[]/", c) == NULL
&& !byte_in_str(slang->sl_compallflags, c)) {
- *ap++ = c;
+ *ap++ = (char_u)c;
*ap = NUL;
}
@@ -1479,7 +1474,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
atstart = 0;
} else {
if (!byte_in_str(slang->sl_compstartflags, c)) {
- *cp++ = c;
+ *cp++ = (char_u)c;
*cp = NUL;
}
if (atstart == 1) {
@@ -1494,7 +1489,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
XFREE_CLEAR(slang->sl_comprules);
crp = NULL;
} else {
- *crp++ = c;
+ *crp++ = (char_u)c;
}
}
@@ -1561,7 +1556,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// Allocate the lists.
for (int i = 0; i < 256; i++) {
if (lp->sl_sal_first[i] > 0) {
- p = xmalloc(sizeof(int) * (lp->sl_sal_first[i] * 2 + 1));
+ p = xmalloc(sizeof(int) * (size_t)(lp->sl_sal_first[i] * 2 + 1));
((int **)gap->ga_data)[i] = (int *)p;
*(int *)p = 0;
}
@@ -1631,7 +1626,7 @@ static void set_sal_first(slang_T *lp)
i++;
n--;
tsal = smp[i + n];
- memmove(smp + i + 1, smp + i, sizeof(salitem_T) * n);
+ memmove(smp + i + 1, smp + i, sizeof(salitem_T) * (size_t)n);
smp[i] = tsal;
}
}
@@ -1645,7 +1640,7 @@ static int *mb_str2wide(char_u *s)
{
int i = 0;
- int *res = xmalloc((mb_charlen(s) + 1) * sizeof(int));
+ int *res = xmalloc(((size_t)mb_charlen(s) + 1) * sizeof(int));
for (char_u *p = s; *p != NUL;) {
res[i++] = mb_ptr2char_adv((const char_u **)&p);
}
@@ -1682,18 +1677,18 @@ static int spell_read_tree(FILE *fd, char_u **bytsp, long *bytsp_len, idx_T **id
}
if (len > 0) {
// Allocate the byte array.
- bp = xmalloc(len);
+ bp = xmalloc((size_t)len);
*bytsp = bp;
if (bytsp_len != NULL) {
*bytsp_len = len;
}
// Allocate the index array.
- ip = xcalloc(len, sizeof(*ip));
+ ip = xcalloc((size_t)len, sizeof(*ip));
*idxsp = ip;
// Recursively read the tree and store it in the array.
- idx = read_tree_node(fd, bp, ip, len, 0, prefixtree, prefixcnt);
+ idx = read_tree_node(fd, bp, ip, (int)len, 0, prefixtree, prefixcnt);
if (idx < 0) {
return idx;
}
@@ -1733,7 +1728,7 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx
if (startidx + len >= maxidx) {
return SP_FORMERROR;
}
- byts[idx++] = len;
+ byts[idx++] = (char_u)len;
// Read the byte values, flag/region bytes and shared indexes.
for (i = 1; i <= len; ++i) {
@@ -1793,7 +1788,7 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx
c = getc(fd); // <xbyte>
}
}
- byts[idx++] = c;
+ byts[idx++] = (char_u)c;
}
// Recursively read the children for non-shared siblings.
@@ -1867,7 +1862,7 @@ static long compress_added = 500000; // word count
// Sets "sps_flags".
int spell_check_msm(void)
{
- char_u *p = p_msm;
+ char *p = (char *)p_msm;
long start = 0;
long incr = 0;
long added = 0;
@@ -2257,7 +2252,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (compflags != NULL) {
l += (int)STRLEN(compflags) + 1;
}
- p = getroom(spin, l, false);
+ p = getroom(spin, (size_t)l, false);
if (compflags != NULL) {
STRCPY(p, compflags);
STRCAT(p, "/");
@@ -2885,7 +2880,7 @@ static unsigned get_affitem(int flagtype, char_u **pp)
res = mb_ptr2char_adv((const char_u **)pp) + (res << 16);
}
}
- return res;
+ return (unsigned)res;
}
// Process the "compflags" string used in an affix file and append it to
@@ -2911,7 +2906,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
if (spin->si_compflags != NULL) {
len += (int)STRLEN(spin->si_compflags) + 1;
}
- p = getroom(spin, len, false);
+ p = getroom(spin, (size_t)len, false);
if (spin->si_compflags != NULL) {
STRCPY(p, spin->si_compflags);
STRCAT(p, "/");
@@ -2947,7 +2942,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
ci->ci_newID = id;
hash_add(&aff->af_comp, ci->ci_key);
}
- *tp++ = id;
+ *tp++ = (char_u)id;
}
if (aff->af_flagtype == AFT_NUM && *p == ',') {
++p;
@@ -2978,15 +2973,15 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
switch (flagtype) {
case AFT_CHAR:
- return vim_strchr((char *)afflist, flag) != NULL;
+ return vim_strchr((char *)afflist, (int)flag) != NULL;
case AFT_CAPLONG:
case AFT_LONG:
for (p = afflist; *p != NUL;) {
- n = mb_ptr2char_adv((const char_u **)&p);
+ n = (unsigned)mb_ptr2char_adv((const char_u **)&p);
if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z'))
&& *p != NUL) {
- n = mb_ptr2char_adv((const char_u **)&p) + (n << 16);
+ n = (unsigned)mb_ptr2char_adv((const char_u **)&p) + (n << 16);
}
if (n == flag) {
return true;
@@ -3362,7 +3357,7 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
if (!HASHITEM_EMPTY(hi)) {
id = HI2AH(hi)->ah_newID;
if (id != 0) {
- store_afflist[cnt++] = id;
+ store_afflist[cnt++] = (char_u)id;
}
}
}
@@ -3393,7 +3388,7 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl
STRLCPY(key, prevp, p - prevp + 1);
hi = hash_find(&affile->af_comp, (char *)key);
if (!HASHITEM_EMPTY(hi)) {
- store_afflist[cnt++] = HI2CI(hi)->ci_newID;
+ store_afflist[cnt++] = (char_u)HI2CI(hi)->ci_newID;
}
}
if (affile->af_flagtype == AFT_NUM && *p == ',') {
@@ -3856,11 +3851,10 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align)
if (align && bl != NULL) {
// Round size up for alignment. On some systems structures need to be
// aligned to the size of a pointer (e.g., SPARC).
- bl->sb_used = (bl->sb_used + sizeof(char *) - 1)
- & ~(sizeof(char *) - 1);
+ bl->sb_used = (int)(((size_t)bl->sb_used + sizeof(char *) - 1) & ~(sizeof(char *) - 1));
}
- if (bl == NULL || bl->sb_used + len > SBLOCKSIZE) {
+ if (bl == NULL || (size_t)bl->sb_used + len > SBLOCKSIZE) {
// Allocate a block of memory. It is not freed until much later.
bl = xcalloc(1, (sizeof(sblock_T) + SBLOCKSIZE));
bl->sb_next = spin->si_blocks;
@@ -4072,9 +4066,9 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
}
if (word[i] == NUL) {
- node->wn_flags = flags;
- node->wn_region |= region;
- node->wn_affixID = affixID;
+ node->wn_flags = (uint16_t)flags;
+ node->wn_region |= (int16_t)region;
+ node->wn_affixID = (char_u)affixID;
break;
}
prev = &node->wn_child;
@@ -4298,12 +4292,12 @@ static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, lo
// Make a hash key for the node and its siblings, so that we can quickly
// find a lookalike node. This must be done after compressing the sibling
// list, otherwise the hash key would become invalid by the compression.
- node->wn_u1.hashkey[0] = len;
+ node->wn_u1.hashkey[0] = (char_u)len;
nr = 0;
for (np = node; np != NULL; np = np->wn_sibling) {
if (np->wn_byte == NUL) {
// end node: use wn_flags, wn_region and wn_affixID
- n = np->wn_flags + (np->wn_region << 8) + (np->wn_affixID << 16);
+ n = (unsigned)(np->wn_flags + (np->wn_region << 8) + (np->wn_affixID << 16));
} else {
// byte node: use the byte value and the child pointer
n = (unsigned)(np->wn_byte + ((uintptr_t)np->wn_child << 8));
@@ -4313,13 +4307,13 @@ static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, lo
// Avoid NUL bytes, it terminates the hash key.
n = nr & 0xff;
- node->wn_u1.hashkey[1] = n == 0 ? 1 : n;
+ node->wn_u1.hashkey[1] = n == 0 ? 1 : (char_u)n;
n = (nr >> 8) & 0xff;
- node->wn_u1.hashkey[2] = n == 0 ? 1 : n;
+ node->wn_u1.hashkey[2] = n == 0 ? 1 : (char_u)n;
n = (nr >> 16) & 0xff;
- node->wn_u1.hashkey[3] = n == 0 ? 1 : n;
+ node->wn_u1.hashkey[3] = n == 0 ? 1 : (char_u)n;
n = (nr >> 24) & 0xff;
- node->wn_u1.hashkey[4] = n == 0 ? 1 : n;
+ node->wn_u1.hashkey[4] = n == 0 ? 1 : (char_u)n;
node->wn_u1.hashkey[5] = NUL;
// Check for CTRL-C pressed now and then.
@@ -4885,7 +4879,7 @@ static int put_node(FILE *fd, wordnode_T *node, int idx, int regionmask, bool pr
void ex_mkspell(exarg_T *eap)
{
int fcount;
- char_u **fnames;
+ char **fnames;
char_u *arg = (char_u *)eap->arg;
bool ascii = false;
@@ -5034,7 +5028,7 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
// We use the "flags" field for the MSB of the wordnr,
// "region" for the LSB of the wordnr.
if (tree_add_word(spin, tsalword, spin->si_foldroot,
- words_done >> 16, words_done & 0xffff,
+ (int)(words_done >> 16), words_done & 0xffff,
0) == FAIL) {
return FAIL;
}
@@ -5054,7 +5048,7 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
}
} else {
// Normal char, go one level deeper.
- tword[depth++] = c;
+ tword[depth++] = (char_u)c;
arridx[depth] = idxs[n];
curi[depth] = 1;
wordcount[depth] = 0;
@@ -5170,25 +5164,25 @@ static int offset2bytes(int nr, char_u *buf)
b4 = rem / 255 + 1;
if (b4 > 1 || b3 > 0x1f) { // 4 bytes
- buf[0] = 0xe0 + b4;
- buf[1] = b3;
- buf[2] = b2;
- buf[3] = b1;
+ buf[0] = (char_u)(0xe0 + b4);
+ buf[1] = (char_u)b3;
+ buf[2] = (char_u)b2;
+ buf[3] = (char_u)b1;
return 4;
}
if (b3 > 1 || b2 > 0x3f) { // 3 bytes
- buf[0] = 0xc0 + b3;
- buf[1] = b2;
- buf[2] = b1;
+ buf[0] = (char_u)(0xc0 + b3);
+ buf[1] = (char_u)b2;
+ buf[2] = (char_u)b1;
return 3;
}
if (b2 > 1 || b1 > 0x7f) { // 2 bytes
- buf[0] = 0x80 + b2;
- buf[1] = b1;
+ buf[0] = (char_u)(0x80 + b2);
+ buf[1] = (char_u)b1;
return 2;
}
// 1 byte
- buf[0] = b1;
+ buf[0] = (char_u)b1;
return 1;
}
@@ -5276,11 +5270,11 @@ theend:
/// @param ascii -ascii argument given
/// @param over_write overwrite existing output file
/// @param added_word invoked through "zg"
-static void mkspell(int fcount, char_u **fnames, bool ascii, bool over_write, bool added_word)
+static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool added_word)
{
char_u *fname = NULL;
char_u *wfname;
- char_u **innames;
+ char **innames;
int incount;
afffile_T *(afile[MAXREGIONS]);
int i;
@@ -5373,9 +5367,8 @@ static void mkspell(int fcount, char_u **fnames, bool ascii, bool over_write, bo
semsg(_("E755: Invalid region in %s"), innames[i]);
goto theend;
}
- spin.si_region_name[i * 2] = TOLOWER_ASC(innames[i][len - 2]);
- spin.si_region_name[i * 2 + 1] =
- TOLOWER_ASC(innames[i][len - 1]);
+ spin.si_region_name[i * 2] = (char_u)TOLOWER_ASC(innames[i][len - 2]);
+ spin.si_region_name[i * 2 + 1] = (char_u)TOLOWER_ASC(innames[i][len - 1]);
}
}
spin.si_region_count = incount;
@@ -5418,7 +5411,7 @@ static void mkspell(int fcount, char_u **fnames, bool ascii, bool over_write, bo
} else {
// No .aff file, try reading the file as a word list. Store
// the words in the trees.
- if (spell_read_wordfile(&spin, innames[i]) == FAIL) {
+ if (spell_read_wordfile(&spin, (char_u *)innames[i]) == FAIL) {
error = true;
}
}
@@ -5529,7 +5522,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
FILE *fd = NULL;
buf_T *buf = NULL;
bool new_spf = false;
- char_u *fname;
+ char *fname;
char_u *fnamebuf = NULL;
char_u line[MAXWLEN * 2];
long fpos, fpos_next = 0;
@@ -5548,7 +5541,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
return;
}
}
- fname = int_wordlist;
+ fname = (char *)int_wordlist;
} else {
// If 'spellfile' isn't set figure out a good default value.
if (*curwin->w_s->b_p_spf == NUL) {
@@ -5585,13 +5578,13 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
return;
}
- fname = fnamebuf;
+ fname = (char *)fnamebuf;
}
if (what == SPELL_ADD_BAD || undo) {
// When the word appears as good word we need to remove that one,
// since its flags sort before the one with WF_BANNED.
- fd = os_fopen((char *)fname, "r");
+ fd = os_fopen(fname, "r");
if (fd != NULL) {
while (!vim_fgets(line, MAXWLEN * 2, fd)) {
fpos = fpos_next;
@@ -5605,14 +5598,14 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
// the start of the line. Mixing reading and writing
// doesn't work for all systems, close the file first.
fclose(fd);
- fd = os_fopen((char *)fname, "r+");
+ fd = os_fopen(fname, "r+");
if (fd == NULL) {
break;
}
if (fseek(fd, fpos, SEEK_SET) == 0) {
fputc('#', fd);
if (undo) {
- home_replace(NULL, (char *)fname, (char *)NameBuff, MAXPATHL, true);
+ home_replace(NULL, fname, (char *)NameBuff, MAXPATHL, true);
smsg(_("Word '%.*s' removed from %s"), len, word, NameBuff);
}
}
@@ -5629,7 +5622,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
}
if (!undo) {
- fd = os_fopen((char *)fname, "a");
+ fd = os_fopen(fname, "a");
if (fd == NULL && new_spf) {
char_u *p;
@@ -5637,16 +5630,16 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
// file. We may need to create the "spell" directory first. We
// already checked the runtime directory is writable in
// init_spellfile().
- if (!dir_of_file_exists(fname)
- && (p = (char_u *)path_tail_with_sep((char *)fname)) != fname) {
+ if (!dir_of_file_exists((char_u *)fname)
+ && (p = (char_u *)path_tail_with_sep(fname)) != (char_u *)fname) {
int c = *p;
// The directory doesn't exist. Try creating it and opening
// the file again.
*p = NUL;
- os_mkdir((char *)fname, 0755);
- *p = c;
- fd = os_fopen((char *)fname, "a");
+ os_mkdir(fname, 0755);
+ *p = (char_u)c;
+ fd = os_fopen(fname, "a");
}
}
@@ -5662,7 +5655,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
}
fclose(fd);
- home_replace(NULL, (char *)fname, (char *)NameBuff, MAXPATHL, true);
+ home_replace(NULL, fname, (char *)NameBuff, MAXPATHL, true);
smsg(_("Word '%.*s' added to %s"), len, word, NameBuff);
}
}
@@ -5727,19 +5720,19 @@ static void init_spellfile(void)
} else {
// Create the "spell" directory if it doesn't exist yet.
l = (int)STRLEN(buf);
- vim_snprintf((char *)buf + l, MAXPATHL - l, "/spell");
+ vim_snprintf((char *)buf + l, MAXPATHL - (size_t)l, "/spell");
if (os_file_is_writable((char *)buf) != 2) {
os_mkdir((char *)buf, 0755);
}
l = (int)STRLEN(buf);
- vim_snprintf((char *)buf + l, MAXPATHL - l,
+ vim_snprintf((char *)buf + l, MAXPATHL - (size_t)l,
"/%.*s", (int)(lend - lstart), lstart);
}
l = (int)STRLEN(buf);
fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
->lp_slang->sl_fname;
- vim_snprintf((char *)buf + l, MAXPATHL - l, ".%s.add",
+ vim_snprintf((char *)buf + l, MAXPATHL - (size_t)l, ".%s.add",
((fname != NULL
&& strstr(path_tail((char *)fname), ".ascii.") != NULL)
? "ascii"
@@ -5776,9 +5769,9 @@ static void set_spell_charflags(char_u *flags, int cnt, char_u *fol)
if (*p != NUL) {
c = mb_ptr2char_adv((const char_u **)&p);
- new_st.st_fold[i + 128] = c;
+ new_st.st_fold[i + 128] = (char_u)c;
if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) {
- new_st.st_upper[c] = i + 128;
+ new_st.st_upper[c] = (char_u)(i + 128);
}
}
}
@@ -5878,11 +5871,10 @@ static void set_map_str(slang_T *lp, char_u *map)
if (c >= 256) {
int cl = utf_char2len(c);
int headcl = utf_char2len(headc);
- char *b;
hash_T hash;
hashitem_T *hi;
- b = xmalloc(cl + headcl + 2);
+ char *b = xmalloc((size_t)(cl + headcl) + 2);
utf_char2bytes(c, b);
b[cl] = NUL;
utf_char2bytes(headc, b + cl + 1);
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 6475105192..d6cca71ad8 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -5,10 +5,10 @@
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
-#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/getchar.h"
+#include "nvim/insexpand.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/main.h"
@@ -211,12 +211,15 @@ void get_mode(char *buf)
buf[i++] = 'o';
// to be able to detect force-linewise/blockwise/charwise operations
buf[i++] = (char)motion_force;
+ } else if (curbuf->terminal) {
+ buf[i++] = 't';
+ if (restart_edit == 'I') {
+ buf[i++] = 'T';
+ }
} else if (restart_edit == 'I' || restart_edit == 'R'
|| restart_edit == 'V') {
buf[i++] = 'i';
buf[i++] = (char)restart_edit;
- } else if (curbuf->terminal) {
- buf[i++] = 't';
}
}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 5c2721536d..22effaade0 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -501,7 +501,7 @@ static int sort_compare(const void *s1, const void *s2)
return STRCMP(*(char **)s1, *(char **)s2);
}
-void sort_strings(char_u **files, int count)
+void sort_strings(char **files, int count)
{
qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
}
@@ -1528,3 +1528,45 @@ char_u *reverse_text(char_u *s)
return rev;
}
+
+/// Replace all occurrences of "what" with "rep" in "src". If no replacement happens then NULL is
+/// returned otherwise return a newly allocated string.
+///
+/// @param[in] src Source text
+/// @param[in] what Substring to replace
+/// @param[in] rep Substring to replace with
+///
+/// @return [allocated] Copy of the string.
+char *strrep(const char *src, const char *what, const char *rep)
+{
+ char *pos = (char *)src;
+ size_t whatlen = STRLEN(what);
+
+ // Count occurrences
+ size_t count = 0;
+ while ((pos = strstr(pos, what)) != NULL) {
+ count++;
+ pos += whatlen;
+ }
+
+ if (count == 0) {
+ return NULL;
+ }
+
+ size_t replen = STRLEN(rep);
+ char *ret = xmalloc(STRLEN(src) + count * (replen - whatlen) + 1);
+ char *ptr = ret;
+ while ((pos = strstr(src, what)) != NULL) {
+ size_t idx = (size_t)(pos - src);
+ memcpy(ptr, src, idx);
+ ptr += idx;
+ STRCPY(ptr, rep);
+ ptr += replen;
+ src = pos + whatlen;
+ }
+
+ // Copy remaining
+ STRCPY(ptr, src);
+
+ return ret;
+}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 43dbeccf01..4ec4a57d68 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -18,6 +18,7 @@
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
#include "nvim/eval.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
@@ -226,12 +227,10 @@ static int current_sub_char = 0;
#define MAX_SYN_INC_TAG 999 // maximum before the above overflow
#define MAX_CLUSTER_ID (32767 - SYNID_CLUSTER)
-/*
- * Annoying Hack(TM): ":syn include" needs this pointer to pass to
- * expand_filename(). Most of the other syntax commands don't need it, so
- * instead of passing it to them, we stow it here.
- */
-static char_u **syn_cmdlinep;
+// Annoying Hack(TM): ":syn include" needs this pointer to pass to
+// expand_filename(). Most of the other syntax commands don't need it, so
+// instead of passing it to them, we stow it here.
+static char **syn_cmdlinep;
/*
* Another Annoying Hack(TM): To prevent rules from other ":syn include"'d
@@ -343,7 +342,7 @@ void syntax_start(win_T *wp, linenr_T lnum)
linenr_T parsed_lnum;
linenr_T first_stored;
int dist;
- static int changedtick = 0; // remember the last change ID
+ static varnumber_T changedtick = 0; // remember the last change ID
current_sub_char = NUL;
@@ -993,11 +992,10 @@ void syn_stack_free_all(synblock_T *block)
*/
static void syn_stack_alloc(void)
{
- long len;
synstate_T *to, *from;
synstate_T *sstp;
- len = syn_buf->b_ml.ml_line_count / SST_DIST + Rows * 2;
+ int len = syn_buf->b_ml.ml_line_count / SST_DIST + Rows * 2;
if (len < SST_MIN_ENTRIES) {
len = SST_MIN_ENTRIES;
} else if (len > SST_MAX_ENTRIES) {
@@ -1024,7 +1022,7 @@ static void syn_stack_alloc(void)
}
assert(len >= 0);
- sstp = xcalloc(len, sizeof(synstate_T));
+ sstp = xcalloc((size_t)len, sizeof(synstate_T));
to = sstp - 1;
if (syn_block->b_sst_array != NULL) {
@@ -1304,7 +1302,7 @@ static synstate_T *store_current_state(void)
}
for (i = 0; i < sp->sst_stacksize; ++i) {
bp[i].bs_idx = CUR_STATE(i).si_idx;
- bp[i].bs_flags = CUR_STATE(i).si_flags;
+ bp[i].bs_flags = (int)CUR_STATE(i).si_flags;
bp[i].bs_seqnr = CUR_STATE(i).si_seqnr;
bp[i].bs_cchar = CUR_STATE(i).si_cchar;
bp[i].bs_extmatch = ref_extmatch(CUR_STATE(i).si_extmatch);
@@ -1392,24 +1390,21 @@ static bool syn_stack_equal(synstate_T *sp)
if (bp[i].bs_extmatch == CUR_STATE(i).si_extmatch) {
continue;
}
- // When the extmatch pointers are different, the strings in
- // them can still be the same. Check if the extmatch
- // references are equal.
+ // When the extmatch pointers are different, the strings in them can
+ // still be the same. Check if the extmatch references are equal.
bsx = bp[i].bs_extmatch;
six = CUR_STATE(i).si_extmatch;
- // If one of the extmatch pointers is NULL the states are
- // different.
+ // If one of the extmatch pointers is NULL the states are different.
if (bsx == NULL || six == NULL) {
break;
}
int j;
for (j = 0; j < NSUBEXP; j++) {
- // Check each referenced match string. They must all be
- // equal.
+ // Check each referenced match string. They must all be equal.
if (bsx->matches[j] != six->matches[j]) {
- // If the pointer is different it can still be the
- // same text. Compare the strings, ignore case when
- // the start item has the sp_ic flag set.
+ // If the pointer is different it can still be the same text.
+ // Compare the strings, ignore case when the start item has the
+ // sp_ic flag set.
if (bsx->matches[j] == NULL || six->matches[j] == NULL) {
break;
}
@@ -1424,11 +1419,7 @@ static bool syn_stack_equal(synstate_T *sp)
break;
}
}
- if (i < 0) {
- return true;
- }
-
- return false;
+ return i < 0 ? true : false;
}
/*
@@ -2043,7 +2034,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
current_attr = sip->si_attr;
current_id = sip->si_id;
current_trans_id = sip->si_trans_id;
- current_flags = sip->si_flags;
+ current_flags = (int)sip->si_flags;
current_seqnr = sip->si_seqnr;
current_sub_char = sip->si_cchar;
break;
@@ -2065,7 +2056,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
*can_spell = (syn_block->b_syn_spell != SYNSPL_NOTOP);
} else {
sps.inc_tag = 0;
- sps.id = syn_block->b_nospell_cluster_id;
+ sps.id = (int16_t)syn_block->b_nospell_cluster_id;
sps.cont_in_list = NULL;
*can_spell = !in_id_list(sip, sip->si_cont_list, &sps, 0);
}
@@ -2078,12 +2069,12 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
*can_spell = (syn_block->b_syn_spell == SYNSPL_TOP);
} else {
sps.inc_tag = 0;
- sps.id = syn_block->b_spell_cluster_id;
+ sps.id = (int16_t)syn_block->b_spell_cluster_id;
sps.cont_in_list = NULL;
*can_spell = in_id_list(sip, sip->si_cont_list, &sps, 0);
if (syn_block->b_nospell_cluster_id != 0) {
- sps.id = syn_block->b_nospell_cluster_id;
+ sps.id = (int16_t)syn_block->b_nospell_cluster_id;
if (in_id_list(sip, sip->si_cont_list, &sps, 0)) {
*can_spell = false;
}
@@ -2289,7 +2280,7 @@ static void check_state_ends(void)
// handle next_list, unless at end of line and no "skipnl" or
// "skipempty"
current_next_list = cur_si->si_next_list;
- current_next_flags = cur_si->si_flags;
+ current_next_flags = (int)cur_si->si_flags;
if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))
&& syn_getcurline()[current_col] == NUL) {
current_next_list = NULL;
@@ -2899,7 +2890,6 @@ static char_u *syn_getcurline(void)
*/
static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st)
{
- int r;
int timed_out = 0;
proftime_T pt;
const bool l_syn_time_on = syn_time_on;
@@ -2915,9 +2905,8 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
return false;
}
- rmp->rmm_maxcol = syn_buf->b_p_smc;
- r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
- syn_tm, &timed_out);
+ rmp->rmm_maxcol = (colnr_T)syn_buf->b_p_smc;
+ long r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, syn_tm, &timed_out);
if (l_syn_time_on) {
pt = profile_end(pt);
@@ -3294,9 +3283,8 @@ static void syn_remove_pattern(synblock_T *block, int idx)
--block->b_syn_folditems;
}
syn_clear_pattern(block, idx);
- memmove(spp, spp + 1,
- sizeof(synpat_T) * (block->b_syn_patterns.ga_len - idx - 1));
- --block->b_syn_patterns.ga_len;
+ memmove(spp, spp + 1, sizeof(synpat_T) * (size_t)(block->b_syn_patterns.ga_len - idx - 1));
+ block->b_syn_patterns.ga_len--;
}
/*
@@ -3382,7 +3370,7 @@ static void syn_cmd_clear(exarg_T *eap, int syncing)
XFREE_CLEAR(SYN_CLSTR(curwin->w_s)[scl_id].scl_list);
}
} else {
- id = syn_name2id_len((char *)arg, (int)(arg_end - arg));
+ id = syn_name2id_len((char *)arg, (size_t)(arg_end - arg));
if (id == 0) {
semsg(_(e_nogroup), arg);
break;
@@ -3553,7 +3541,7 @@ static void syn_cmd_list(exarg_T *eap, int syncing)
syn_list_cluster(id - SYNID_CLUSTER);
}
} else {
- int id = syn_name2id_len((char *)arg, (int)(arg_end - arg));
+ int id = syn_name2id_len((char *)arg, (size_t)(arg_end - arg));
if (id == 0) {
semsg(_(e_nogroup), arg);
} else {
@@ -4010,7 +3998,7 @@ static void add_keyword(char_u *const name, const int id, const int flags,
keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + STRLEN(name_ic));
STRCPY(kp->keyword, name_ic);
- kp->k_syn.id = id;
+ kp->k_syn.id = (int16_t)id;
kp->k_syn.inc_tag = current_syn_inc_tag;
kp->flags = flags;
kp->k_char = conceal_char;
@@ -4193,7 +4181,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha
if (gname_start == arg) {
return NULL;
}
- gname = vim_strnsave(gname_start, arg - gname_start);
+ gname = vim_strnsave(gname_start, (size_t)(arg - gname_start));
if (STRCMP(gname, "NONE") == 0) {
*opt->sync_idx = NONE_IDX;
} else {
@@ -4242,7 +4230,7 @@ static void syn_incl_toplevel(int id, int *flagsp)
int16_t *grp_list = xmalloc(2 * sizeof(*grp_list));
int tlg_id = curwin->w_s->b_syn_topgrp - SYNID_CLUSTER;
- grp_list[0] = id;
+ grp_list[0] = (int16_t)id;
grp_list[1] = 0;
syn_combine_list(&SYN_CLSTR(curwin->w_s)[tlg_id].scl_list, &grp_list,
CLUSTER_ADD);
@@ -4345,7 +4333,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
if (eap->skip) {
syn_id = -1;
} else {
- syn_id = syn_check_group((char *)arg, (int)(group_name_end - arg));
+ syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg));
}
if (syn_id != 0) {
// Allocate a buffer, for removing backslashes in the keyword.
@@ -4411,7 +4399,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
}
const int l = utfc_ptr2len((char *)p + 1);
- memmove(p, p + 1, l);
+ memmove(p, p + 1, (size_t)l);
p += l;
}
}
@@ -4482,7 +4470,7 @@ static void syn_cmd_match(exarg_T *eap, int syncing)
if (!ends_excmd(*rest) || eap->skip) {
rest = NULL;
} else {
- if ((syn_id = syn_check_group((char *)arg, (int)(group_name_end - arg))) != 0) {
+ if ((syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg))) != 0) {
syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
/*
* Store the pattern in the syn_items list
@@ -4492,7 +4480,7 @@ static void syn_cmd_match(exarg_T *eap, int syncing)
*spp = item;
spp->sp_syncing = syncing;
spp->sp_type = SPTYPE_MATCH;
- spp->sp_syn.id = syn_id;
+ spp->sp_syn.id = (int16_t)syn_id;
spp->sp_syn.inc_tag = current_syn_inc_tag;
spp->sp_flags = syn_opt_arg.flags;
spp->sp_sync_idx = sync_idx;
@@ -4598,7 +4586,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
++key_end;
}
xfree(key);
- key = vim_strnsave_up(rest, key_end - rest);
+ key = vim_strnsave_up(rest, (size_t)(key_end - rest));
if (STRCMP(key, "MATCHGROUP") == 0) {
item = ITEM_MATCHGROUP;
} else if (STRCMP(key, "START") == 0) {
@@ -4631,7 +4619,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip) {
matchgroup_id = 0;
} else {
- matchgroup_id = syn_check_group((char *)rest, (int)(p - rest));
+ matchgroup_id = syn_check_group((char *)rest, (size_t)(p - rest));
if (matchgroup_id == 0) {
illegal = true;
break;
@@ -4690,7 +4678,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
rest = NULL;
} else {
ga_grow(&(curwin->w_s->b_syn_patterns), pat_count);
- if ((syn_id = syn_check_group((char *)arg, (int)(group_name_end - arg))) != 0) {
+ if ((syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg))) != 0) {
syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
/*
* Store the start/skip/end in the syn_items list
@@ -4704,11 +4692,10 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
(item == ITEM_START) ? SPTYPE_START :
(item == ITEM_SKIP) ? SPTYPE_SKIP : SPTYPE_END;
SYN_ITEMS(curwin->w_s)[idx].sp_flags |= syn_opt_arg.flags;
- SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = (int16_t)syn_id;
SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag =
current_syn_inc_tag;
- SYN_ITEMS(curwin->w_s)[idx].sp_syn_match_id =
- ppp->pp_matchgroup_id;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn_match_id = (int16_t)ppp->pp_matchgroup_id;
SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char;
if (item == ITEM_START) {
SYN_ITEMS(curwin->w_s)[idx].sp_cont_list =
@@ -4878,7 +4865,7 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con
clstr = NULL;
break;
}
- clstr = xmalloc((count + 1) * sizeof(*clstr));
+ clstr = xmalloc(((size_t)count + 1) * sizeof(*clstr));
clstr[count] = 0;
}
}
@@ -4913,7 +4900,7 @@ static int syn_scl_name2id(char_u *name)
*/
static int syn_scl_namen2id(char_u *linep, int len)
{
- char_u *name = vim_strnsave(linep, len);
+ char_u *name = vim_strnsave(linep, (size_t)len);
int id = syn_scl_name2id(name);
xfree(name);
@@ -4926,12 +4913,8 @@ static int syn_scl_namen2id(char_u *linep, int len)
// Return 0 for failure.
static int syn_check_cluster(char_u *pp, int len)
{
- int id;
- char_u *name;
-
- name = vim_strnsave(pp, len);
-
- id = syn_scl_name2id(name);
+ char_u *name = vim_strnsave(pp, (size_t)len);
+ int id = syn_scl_name2id(name);
if (id == 0) { // doesn't exist yet
id = syn_add_cluster(name);
} else {
@@ -5081,7 +5064,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
return NULL;
}
// store the pattern and compiled regexp program
- ci->sp_pattern = vim_strnsave(arg + 1, end - arg - 1);
+ ci->sp_pattern = vim_strnsave(arg + 1, (size_t)(end - arg) - 1);
// Make 'cpoptions' empty, to avoid the 'l' flag
cpo_save = p_cpo;
@@ -5120,7 +5103,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
}
}
if (idx >= 0) {
- ci->sp_off_flags |= (1 << idx);
+ ci->sp_off_flags |= (int16_t)(1 << idx);
if (idx == SPO_LC_OFF) { // lc=99
end += 3;
*p = getdigits_int((char **)&end, true, 0);
@@ -5164,9 +5147,8 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
char_u *arg_end;
char_u *key = NULL;
char_u *next_arg;
- int illegal = FALSE;
- int finished = FALSE;
- long n;
+ int illegal = false;
+ int finished = false;
char *cpo_save;
if (ends_excmd(*arg_start)) {
@@ -5178,7 +5160,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
arg_end = skiptowhite(arg_start);
next_arg = (char_u *)skipwhite((char *)arg_end);
xfree(key);
- key = vim_strnsave_up(arg_start, arg_end - arg_start);
+ key = vim_strnsave_up(arg_start, (size_t)(arg_end - arg_start));
if (STRCMP(key, "CCOMMENT") == 0) {
if (!eap->skip) {
curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT;
@@ -5186,11 +5168,12 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
if (!ends_excmd(*next_arg)) {
arg_end = skiptowhite(next_arg);
if (!eap->skip) {
- curwin->w_s->b_syn_sync_id = syn_check_group((char *)next_arg, (int)(arg_end - next_arg));
+ curwin->w_s->b_syn_sync_id =
+ (int16_t)syn_check_group((char *)next_arg, (size_t)(arg_end - next_arg));
}
next_arg = (char_u *)skipwhite((char *)arg_end);
} else if (!eap->skip) {
- curwin->w_s->b_syn_sync_id = syn_name2id("Comment");
+ curwin->w_s->b_syn_sync_id = (int16_t)syn_name2id("Comment");
}
} else if (STRNCMP(key, "LINES", 5) == 0
|| STRNCMP(key, "MINLINES", 8) == 0
@@ -5207,7 +5190,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
illegal = TRUE;
break;
}
- n = getdigits_long(&arg_end, false, 0);
+ linenr_T n = getdigits_int32((char **)&arg_end, false, 0);
if (!eap->skip) {
if (key[4] == 'B') {
curwin->w_s->b_syn_sync_linebreaks = n;
@@ -5241,7 +5224,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
if (!eap->skip) {
// store the pattern and compiled regexp program
curwin->w_s->b_syn_linecont_pat =
- vim_strnsave(next_arg + 1, arg_end - next_arg - 1);
+ vim_strnsave(next_arg + 1, (size_t)(arg_end - next_arg) - 1);
curwin->w_s->b_syn_linecont_ic = curwin->w_s->b_syn_ic;
// Make 'cpoptions' empty, to avoid the 'l' flag
@@ -5326,7 +5309,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
int count = 0;
do {
for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) {}
- char *const name = xmalloc(end - p + 3); // leave room for "^$"
+ char *const name = xmalloc((size_t)(end - p) + 3); // leave room for "^$"
STRLCPY(name + 1, p, end - p + 1);
if (STRCMP(name + 1, "ALLBUT") == 0
|| STRCMP(name + 1, "ALL") == 0
@@ -5367,7 +5350,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
* Handle full group name.
*/
if (strpbrk(name + 1, "\\.*^$~[") == NULL) {
- id = syn_check_group((name + 1), (int)(end - p));
+ id = syn_check_group((name + 1), (size_t)(end - p));
} else {
// Handle match of regexp with group names.
*name = '^';
@@ -5392,7 +5375,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
xfree(retval);
round = 1;
} else {
- retval[count] = i + 1; // -V522
+ retval[count] = (int16_t)(i + 1); // -V522
}
}
count++;
@@ -5415,7 +5398,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
xfree(retval);
round = 1;
} else {
- retval[count] = id;
+ retval[count] = (int16_t)id;
}
}
++count;
@@ -5430,7 +5413,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
break;
}
if (round == 1) {
- retval = xmalloc((count + 1) * sizeof(*retval));
+ retval = xmalloc(((size_t)count + 1) * sizeof(*retval));
retval[count] = 0; // zero means end of the list
total_count = count;
}
@@ -5461,7 +5444,7 @@ static int16_t *copy_id_list(const int16_t *const list)
int count;
for (count = 0; list[count]; count++) {}
- const size_t len = (count + 1) * sizeof(int16_t);
+ const size_t len = ((size_t)count + 1) * sizeof(int16_t);
int16_t *const retval = xmalloc(len);
memmove(retval, list, len);
@@ -5610,11 +5593,11 @@ void ex_syntax(exarg_T *eap)
char_u *arg = (char_u *)eap->arg;
char_u *subcmd_end;
- syn_cmdlinep = (char_u **)eap->cmdlinep;
+ syn_cmdlinep = eap->cmdlinep;
// isolate subcommand name
for (subcmd_end = arg; ASCII_ISALPHA(*subcmd_end); subcmd_end++) {}
- char_u *const subcmd_name = vim_strnsave(arg, subcmd_end - arg);
+ char_u *const subcmd_name = vim_strnsave(arg, (size_t)(subcmd_end - arg));
if (eap->skip) { // skip error messages for all subcommands
emsg_skip++;
}
@@ -5785,7 +5768,7 @@ char *get_syntax_name(expand_T *xp, int idx)
/// @param trans remove transparency
/// @param spellp return: can do spell checking
/// @param keep_state keep state of char at "col"
-int syn_get_id(win_T *wp, long lnum, colnr_T col, int trans, bool *spellp, int keep_state)
+int syn_get_id(win_T *wp, linenr_T lnum, colnr_T col, int trans, bool *spellp, int keep_state)
{
// When the position is not after the current position and in the same
// line of the same window with the same buffer, need to restart parsing.
@@ -5867,10 +5850,8 @@ static int syn_cur_foldlevel(void)
return level;
}
-/*
- * Function called to get folding level for line "lnum" in window "wp".
- */
-int syn_get_foldlevel(win_T *wp, long lnum)
+/// Function called to get folding level for line "lnum" in window "wp".
+int syn_get_foldlevel(win_T *wp, linenr_T lnum)
{
int level = 0;
@@ -5900,7 +5881,7 @@ int syn_get_foldlevel(win_T *wp, long lnum)
}
}
if (level > wp->w_p_fdn) {
- level = wp->w_p_fdn;
+ level = (int)wp->w_p_fdn;
if (level < 0) {
level = 0;
}
@@ -6000,11 +5981,11 @@ static void syntime_report(void)
p = GA_APPEND_VIA_PTR(time_entry_T, &ga);
p->total = spp->sp_time.total;
total_total = profile_add(total_total, spp->sp_time.total);
- p->count = spp->sp_time.count;
- p->match = spp->sp_time.match;
- total_count += spp->sp_time.count;
+ p->count = (int)spp->sp_time.count;
+ p->match = (int)spp->sp_time.match;
+ total_count += (int)spp->sp_time.count;
p->slowest = spp->sp_time.slowest;
- proftime_T tm = profile_divide(spp->sp_time.total, spp->sp_time.count);
+ proftime_T tm = profile_divide(spp->sp_time.total, (int)spp->sp_time.count);
p->average = tm;
p->id = spp->sp_syn.id;
p->pattern = spp->sp_pattern;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 28b3b6c1ef..5b799be381 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -26,6 +26,7 @@
#include "nvim/garray.h"
#include "nvim/if_cscope.h"
#include "nvim/input.h"
+#include "nvim/insexpand.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
@@ -164,7 +165,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
fmark_T saved_fmark;
bool jumped_to_tag = false;
int new_num_matches;
- char_u **new_matches;
+ char **new_matches;
int use_tagstack;
int skip_msg = false;
char_u *buf_ffname = (char_u *)curbuf->b_ffname; // name for priority computation
@@ -173,7 +174,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
// remember the matches for the last used tag
static int num_matches = 0;
static int max_num_matches = 0; // limit used for match search
- static char_u **matches = NULL;
+ static char **matches = NULL;
static int flags;
if (tfu_in_use) {
@@ -497,15 +498,15 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
// Find the position of each old match in the new list. Need
// to use parse_match() to find the tag line.
for (j = 0; j < num_matches; j++) {
- parse_match(matches[j], &tagp);
- for (i = idx; i < new_num_matches; ++i) {
- parse_match(new_matches[i], &tagp2);
+ parse_match((char_u *)matches[j], &tagp);
+ for (i = idx; i < new_num_matches; i++) {
+ parse_match((char_u *)new_matches[i], &tagp2);
if (STRCMP(tagp.tagname, tagp2.tagname) == 0) {
- char_u *p = new_matches[i];
+ char_u *p = (char_u *)new_matches[i];
for (k = i; k > idx; k--) {
new_matches[k] = new_matches[k - 1];
}
- new_matches[idx++] = p;
+ new_matches[idx++] = (char *)p;
break;
}
}
@@ -580,7 +581,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
tagstack[tagstackidx].cur_fnum = cur_fnum;
// store user-provided data originating from tagfunc
- if (use_tfu && parse_match(matches[cur_match], &tagp2) == OK
+ if (use_tfu && parse_match((char_u *)matches[cur_match], &tagp2) == OK
&& tagp2.user_data) {
XFREE_CLEAR(tagstack[tagstackidx].user_data);
tagstack[tagstackidx].user_data = vim_strnsave(tagp2.user_data,
@@ -639,7 +640,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
/*
* Jump to the desired match.
*/
- i = jumpto_tag(matches[cur_match], forceit, type != DT_CSCOPE);
+ i = jumpto_tag((char_u *)matches[cur_match], forceit, type != DT_CSCOPE);
set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
@@ -686,10 +687,8 @@ end_do_tag:
return jumped_to_tag;
}
-//
// List all the matching tags.
-//
-static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_u **matches)
+static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char **matches)
{
taggy_T *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
@@ -702,7 +701,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_
// Assume that the first match indicates how long the tags can
// be, and align the file names to that.
- parse_match(matches[0], &tagp);
+ parse_match((char_u *)matches[0], &tagp);
taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
if (taglen < 18) {
taglen = 18;
@@ -720,7 +719,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_
msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
for (i = 0; i < num_matches && !got_int; i++) {
- parse_match(matches[i], &tagp);
+ parse_match((char_u *)matches[i], &tagp);
if (!new_tag && (
(g_do_tagpreview != 0
&& i == ptag_entry.cur_match)
@@ -873,11 +872,9 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_
}
}
-//
-// Add the matching tags to the location list for the current
-// window.
-//
-static int add_llist_tags(char_u *tag, int num_matches, char_u **matches)
+/// Add the matching tags to the location list for the current
+/// window.
+static int add_llist_tags(char_u *tag, int num_matches, char **matches)
{
list_T *list;
char_u tag_name[128 + 1];
@@ -896,7 +893,7 @@ static int add_llist_tags(char_u *tag, int num_matches, char_u **matches)
long lnum;
dict_T *dict;
- parse_match(matches[i], &tagp);
+ parse_match((char_u *)matches[i], &tagp);
// Save the tag name
len = (int)(tagp.tagname_end - tagp.tagname);
@@ -1365,7 +1362,7 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl
/// @param matchesp return: array of matches found
/// @param mincount MAXCOL: find all matches other: minimal number of matches */
/// @param buf_ffname name of buffer for priority
-int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int mincount,
+int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mincount,
char_u *buf_ffname)
{
FILE *fp;
@@ -1419,7 +1416,7 @@ int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int
hashtab_T ht_match[MT_COUNT]; // stores matches by key
hash_T hash = 0;
int match_count = 0; // number of matches found
- char_u **matches;
+ char **matches;
int mtt;
int help_save;
int help_pri = 0;
@@ -1648,7 +1645,7 @@ int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int
if ((flags & TAG_INS_COMP)) { // Double brackets for gcc
ins_compl_check_keys(30, false);
}
- if (got_int || compl_interrupted) {
+ if (got_int || ins_compl_interrupted()) {
stop_searching = true;
break;
}
@@ -2283,7 +2280,7 @@ findtag_end:
}
}
}
- matches[match_count++] = mfp;
+ matches[match_count++] = (char *)mfp;
}
}
@@ -3093,7 +3090,7 @@ static void tagstack_clear_entry(taggy_T *item)
}
/// @param tagnames expand tag names
-int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file)
+int expand_tags(int tagnames, char_u *pat, int *num_file, char ***file)
{
int i;
int extra_flag;
@@ -3124,7 +3121,7 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file)
for (i = 0; i < *num_file; i++) {
size_t len;
- parse_match((*file)[i], &t_p);
+ parse_match((char_u *)(*file)[i], &t_p);
len = (size_t)(t_p.tagname_end - t_p.tagname);
if (len > name_buf_size - 3) {
char_u *buf;
@@ -3195,7 +3192,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char_u *sta
int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
{
int num_matches, i, ret;
- char_u **matches;
+ char **matches;
char_u *full_fname;
dict_T *dict;
tagptrs_T tp;
@@ -3204,8 +3201,8 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
ret = find_tags(pat, &num_matches, &matches,
TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname);
if (ret == OK && num_matches > 0) {
- for (i = 0; i < num_matches; ++i) {
- int parse_result = parse_match(matches[i], &tp);
+ for (i = 0; i < num_matches; i++) {
+ int parse_result = parse_match((char_u *)matches[i], &tp);
// Avoid an unused variable warning in release builds.
(void)parse_result;
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index be49048aec..c23aff00cb 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -82,6 +82,7 @@ typedef struct terminal_state {
int save_rd; // saved value of RedrawingDisabled
bool close;
bool got_bsl; // if the last input was <C-\>
+ bool got_bsl_o; // if left terminal mode with <c-\><c-o>
} TerminalState;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -388,12 +389,11 @@ void terminal_check_size(Terminal *term)
}
/// Implements MODE_TERMINAL state. :help Terminal-mode
-void terminal_enter(void)
+bool terminal_enter(void)
{
buf_T *buf = curbuf;
assert(buf->terminal); // Should only be called when curbuf has a terminal.
- TerminalState state, *s = &state;
- memset(s, 0, sizeof(TerminalState));
+ TerminalState s[1] = { 0 };
s->term = buf->terminal;
stop_insert_mode = false;
@@ -443,7 +443,9 @@ void terminal_enter(void)
s->state.check = terminal_check;
state_enter(&s->state);
- restart_edit = 0;
+ if (!s->got_bsl_o) {
+ restart_edit = 0;
+ }
State = save_state;
RedrawingDisabled = s->save_rd;
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
@@ -451,7 +453,7 @@ void terminal_enter(void)
if (save_curwin == curwin->handle) { // Else: window was closed.
curwin->w_p_cul = save_w_p_cul;
if (save_w_p_culopt) {
- xfree(curwin->w_p_culopt);
+ free_string_option(curwin->w_p_culopt);
curwin->w_p_culopt = save_w_p_culopt;
}
curwin->w_p_culopt_flags = save_w_p_culopt_flags;
@@ -459,7 +461,7 @@ void terminal_enter(void)
curwin->w_p_so = save_w_p_so;
curwin->w_p_siso = save_w_p_siso;
} else if (save_w_p_culopt) {
- xfree(save_w_p_culopt);
+ free_string_option(save_w_p_culopt);
}
// draw the unfocused cursor
@@ -467,7 +469,11 @@ void terminal_enter(void)
if (curbuf->terminal == s->term && !s->close) {
terminal_check_cursor();
}
- unshowmode(true);
+ if (restart_edit) {
+ showmode();
+ } else {
+ unshowmode(true);
+ }
ui_busy_stop();
if (s->close) {
bool wipe = s->term->buf_handle != 0;
@@ -477,6 +483,8 @@ void terminal_enter(void)
do_cmdline_cmd("bwipeout!");
}
}
+
+ return s->got_bsl_o;
}
static void terminal_check_cursor(void)
@@ -564,6 +572,14 @@ static int terminal_execute(VimState *state, int key)
}
FALLTHROUGH;
+ case Ctrl_O:
+ if (s->got_bsl) {
+ s->got_bsl_o = true;
+ restart_edit = 'I';
+ return 0;
+ }
+ FALLTHROUGH;
+
default:
if (key == Ctrl_BSL && !s->got_bsl) {
s->got_bsl = true;
@@ -1384,7 +1400,7 @@ static void fetch_row(Terminal *term, int row, int end_col)
fetch_cell(term, row, col, &cell);
if (cell.chars[0]) {
int cell_len = 0;
- for (int i = 0; cell.chars[i]; i++) {
+ for (int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell.chars[i]; i++) {
cell_len += utf_char2bytes((int)cell.chars[i], ptr + cell_len);
}
ptr += cell_len;
diff --git a/src/nvim/testdir/README.txt b/src/nvim/testdir/README.txt
new file mode 100644
index 0000000000..b8bc52f1e6
--- /dev/null
+++ b/src/nvim/testdir/README.txt
@@ -0,0 +1,121 @@
+This directory contains tests for various Vim features.
+For testing an indent script see runtime/indent/testdir/README.txt.
+
+If it makes sense, add a new test method to an already existing file. You may
+want to separate it from other tests with comment lines.
+
+TO ADD A NEW STYLE TEST:
+
+1) Create a test_<subject>.vim file.
+2) Add test_<subject>.res to NEW_TESTS_RES in Make_all.mak in alphabetical
+ order.
+3) Also add an entry "test_<subject>" to NEW_TESTS in Make_all.mak.
+4) Use make test_<subject> to run a single test.
+
+At 2), instead of running the test separately, it can be included in
+"test_alot". Do this for quick tests without side effects. The test runs a
+bit faster, because Vim doesn't have to be started, one Vim instance runs many
+tests.
+
+At 4), to run a test in GUI, add "GUI_FLAG=-g" to the make command.
+
+
+What you can use (see test_assert.vim for an example):
+
+- Call assert_equal(), assert_true(), assert_false(), etc.
+
+- Use assert_fails() to check for expected errors.
+
+- Use try/catch to avoid an exception aborts the test.
+
+- Use test_alloc_fail() to have memory allocation fail. This makes it possible
+ to check memory allocation failures are handled gracefully. You need to
+ change the source code to add an ID to the allocation. Add a new one to
+ alloc_id_T, before aid_last.
+
+- Use test_override() to make Vim behave differently, e.g. if char_avail()
+ must return FALSE for a while. E.g. to trigger the CursorMovedI autocommand
+ event. See test_cursor_func.vim for an example.
+
+- If the bug that is being tested isn't fixed yet, you can throw an exception
+ with "Skipped" so that it's clear this still needs work. E.g.: throw
+ "Skipped: Bug with <c-e> and popupmenu not fixed yet"
+
+- The following environment variables are recognized and can be set to
+ influence the behavior of the test suite (see runtest.vim for details)
+
+ - $TEST_MAY_FAIL=Test_channel_one - ignore those failing tests
+ - $TEST_FILTER=Test_channel - only run test that match this pattern
+ - $TEST_SKIP_PAT=Test_channel - skip tests that match this pattern
+ - $TEST_NO_RETRY=yes - do not try to re-run failing tests
+ You can also set them in Vim:
+ :let $TEST_MAY_FAIL = 'Test_channel_one'
+ :let $TEST_FILTER = '_set_mode'
+ :let $TEST_SKIP_PAT = 'Test_loop_forever'
+ :let $TEST_NO_RETRY = 'yes'
+ Use an empty string to revert, e.g.:
+ :let $TEST_FILTER = ''
+
+- See the start of runtest.vim for more help.
+
+
+TO ADD A SCREEN DUMP TEST:
+
+Mostly the same as writing a new style test. Additionally, see help on
+"terminal-dumptest". Put the reference dump in "dumps/Test_func_name.dump".
+
+
+OLD STYLE TESTS:
+
+There are a few tests that are used when Vim was built without the +eval
+feature. These cannot use the "assert" functions, therefore they consist of a
+.in file that contains Normal mode commands between STARTTEST and ENDTEST.
+They modify the file and the result gets written in the test.out file. This
+is then compared with the .ok file. If they are equal the test passed. If
+they differ the test failed.
+
+
+RUNNING THE TESTS:
+
+To run a single test from the src directory:
+
+ $ make test_<name>
+
+The below commands should be run from the src/testdir directory.
+
+To run a single test:
+
+ $ make test_<name>.res
+
+The file 'messages' contains the messages generated by the test script. If a
+test fails, then the test.log file contains the error messages. If all the
+tests are successful, then this file will be an empty file.
+
+- To run a single test function from a test script:
+
+ $ ../vim -u NONE -S runtest.vim <test_file>.vim <function_name>
+
+- To execute only specific test functions, add a second argument:
+
+ $ ../vim -u NONE -S runtest.vim test_channel.vim open_delay
+
+
+- To run all the tests:
+
+ $ make
+
+- To run the test on MS-Windows using the MSVC nmake:
+
+ > nmake -f Make_dos.mak
+
+- To run the tests with GUI Vim:
+
+ $ make GUI_FLAG=-g
+
+ or
+
+ $ make VIMPROG=../gvim
+
+- To cleanup the temporary files after running the tests:
+
+ $ make clean
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index e6c0762729..9d6fc5e526 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -4,6 +4,7 @@ if exists('s:did_load')
set complete=.,w,b,u,t,i
set directory&
set directory^=.
+ set display=
set fillchars=vert:\|,fold:-
set formatoptions=tcq
set fsync
diff --git a/src/nvim/testdir/term_util.vim b/src/nvim/testdir/term_util.vim
index 3a838a3a1f..5ff09e25b4 100644
--- a/src/nvim/testdir/term_util.vim
+++ b/src/nvim/testdir/term_util.vim
@@ -9,3 +9,5 @@ func CanRunVimInTerminal()
" Nvim: always false, we use Lua screen-tests instead.
return 0
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 43a519bc84..966b8ef571 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -10,7 +10,6 @@ source test_ex_z.vim
source test_ex_mode.vim
source test_expand.vim
source test_expand_func.vim
-source test_feedkeys.vim
source test_file_perm.vim
source test_fnamemodify.vim
source test_ga.vim
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 438851a0ad..1c2f86a584 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -2170,6 +2170,57 @@ func Test_autocmd_nested()
call assert_fails('au WinNew * nested nested echo bad', 'E983:')
endfunc
+func Test_autocmd_nested_cursor_invalid()
+ set laststatus=0
+ copen
+ cclose
+ call setline(1, ['foo', 'bar', 'baz'])
+ 3
+ augroup nested_inv
+ autocmd User foo ++nested copen
+ autocmd BufAdd * let &laststatus = 2 - &laststatus
+ augroup END
+ doautocmd User foo
+
+ augroup nested_inv
+ au!
+ augroup END
+ set laststatus&
+ cclose
+ bwipe!
+endfunc
+
+func Test_autocmd_nested_keeps_cursor_pos()
+ enew
+ call setline(1, 'foo')
+ autocmd User foo ++nested normal! $a
+ autocmd InsertLeave * :
+ doautocmd User foo
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ bwipe!
+endfunc
+
+func Test_autocmd_nested_switch_window()
+ " run this in a separate Vim so that SafeState works
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ vim9script
+ ['()']->writefile('Xautofile')
+ autocmd VimEnter * ++nested edit Xautofile | split
+ autocmd BufReadPost * autocmd SafeState * ++once foldclosed('.')
+ autocmd WinEnter * matchadd('ErrorMsg', 'pat')
+ END
+ call writefile(lines, 'Xautoscript')
+ let buf = RunVimInTerminal('-S Xautoscript', {'rows': 10})
+ call VerifyScreenDump(buf, 'Test_autocmd_nested_switch', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xautofile')
+ call delete('Xautoscript')
+endfunc
+
func Test_autocmd_once()
" Without ++once WinNew triggers twice
let g:did_split = 0
@@ -2851,6 +2902,110 @@ func Test_v_event_readonly()
au! TextYankPost
endfunc
+" Test for ModeChanged pattern
+func Test_mode_changes()
+ let g:index = 0
+ let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'n', 'V', 'v', 's', 'n']
+ func! TestMode()
+ call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode"))
+ call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode"))
+ call assert_equal(mode(1), get(v:event, "new_mode"))
+ let g:index += 1
+ endfunc
+
+ au ModeChanged * :call TestMode()
+ let g:n_to_any = 0
+ au ModeChanged n:* let g:n_to_any += 1
+ call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdG", 'tnix')
+
+ let g:V_to_v = 0
+ au ModeChanged V:v let g:V_to_v += 1
+ call feedkeys("Vv\<C-G>\<esc>", 'tnix')
+ call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any)
+ call assert_equal(1, g:V_to_v)
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+
+ let g:n_to_i = 0
+ au ModeChanged n:i let g:n_to_i += 1
+ let g:n_to_niI = 0
+ au ModeChanged i:niI let g:n_to_niI += 1
+ let g:niI_to_i = 0
+ au ModeChanged niI:i let g:niI_to_i += 1
+ let g:nany_to_i = 0
+ au ModeChanged n*:i let g:nany_to_i += 1
+ let g:i_to_n = 0
+ au ModeChanged i:n let g:i_to_n += 1
+ let g:nori_to_any = 0
+ au ModeChanged [ni]:* let g:nori_to_any += 1
+ let g:i_to_any = 0
+ au ModeChanged i:* let g:i_to_any += 1
+ let g:index = 0
+ let g:mode_seq = ['n', 'i', 'niI', 'i', 'n']
+ call feedkeys("a\<C-O>l\<esc>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(1, g:n_to_i)
+ call assert_equal(1, g:n_to_niI)
+ call assert_equal(1, g:niI_to_i)
+ call assert_equal(2, g:nany_to_i)
+ call assert_equal(1, g:i_to_n)
+ call assert_equal(2, g:i_to_any)
+ call assert_equal(3, g:nori_to_any)
+
+ if has('terminal')
+ let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n']
+ call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(1, g:n_to_i)
+ call assert_equal(1, g:n_to_niI)
+ call assert_equal(1, g:niI_to_i)
+ call assert_equal(2, g:nany_to_i)
+ call assert_equal(1, g:i_to_n)
+ call assert_equal(2, g:i_to_any)
+ call assert_equal(5, g:nori_to_any)
+ endif
+
+ if has('cmdwin')
+ let g:n_to_c = 0
+ au ModeChanged n:c let g:n_to_c += 1
+ let g:c_to_n = 0
+ au ModeChanged c:n let g:c_to_n += 1
+ let g:mode_seq += ['c', 'n', 'c', 'n']
+ call feedkeys("q:\<C-C>\<Esc>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(2, g:n_to_c)
+ call assert_equal(2, g:c_to_n)
+ unlet g:n_to_c
+ unlet g:c_to_n
+ endif
+
+ au! ModeChanged
+ delfunc TestMode
+ unlet! g:mode_seq
+ unlet! g:index
+ unlet! g:n_to_any
+ unlet! g:V_to_v
+ unlet! g:n_to_i
+ unlet! g:n_to_niI
+ unlet! g:niI_to_i
+ unlet! g:nany_to_i
+ unlet! g:i_to_n
+ unlet! g:nori_to_any
+ unlet! g:i_to_any
+endfunc
+
+func Test_recursive_ModeChanged()
+ au! ModeChanged * norm 0u
+ sil! norm 
+ au! ModeChanged
+endfunc
+
+func Test_ModeChanged_starts_visual()
+ " This was triggering ModeChanged before setting VIsual, causing a crash.
+ au! ModeChanged * norm 0u
+ sil! norm 
+
+ au! ModeChanged
+endfunc
func Test_noname_autocmd()
augroup test_noname_autocmd_group
diff --git a/src/nvim/testdir/test_changelist.vim b/src/nvim/testdir/test_changelist.vim
index 3741f32e69..3bb22a89b8 100644
--- a/src/nvim/testdir/test_changelist.vim
+++ b/src/nvim/testdir/test_changelist.vim
@@ -1,12 +1,65 @@
" Tests for the changelist functionality
+" When splitting a window the changelist position is wrong.
+" Test the changelist position after splitting a window.
+" Test for the bug fixed by 7.4.386
+func Test_changelist()
+ let save_ul = &ul
+ enew!
+ call append('$', ['1', '2'])
+ exe "normal i\<C-G>u"
+ exe "normal Gkylpa\<C-G>u"
+ set ul=100
+ exe "normal Gylpa\<C-G>u"
+ set ul=100
+ normal gg
+ vsplit
+ normal g;
+ call assert_equal([3, 2], [line('.'), col('.')])
+ normal g;
+ call assert_equal([2, 2], [line('.'), col('.')])
+ call assert_fails('normal g;', 'E662:')
+ new
+ call assert_fails('normal g;', 'E664:')
+ %bwipe!
+ let &ul = save_ul
+endfunc
+
+" Moving a split should not change its changelist index.
+func Test_changelist_index_move_split()
+ exe "norm! iabc\<C-G>u\ndef\<C-G>u\nghi"
+ vsplit
+ normal 99g;
+ call assert_equal(0, getchangelist('%')[1])
+ wincmd L
+ call assert_equal(0, getchangelist('%')[1])
+endfunc
+
" Tests for the getchangelist() function
-func Test_getchangelist()
- if !has("jumplist")
- return
- endif
+func Test_changelist_index()
+ edit Xfile1.txt
+ exe "normal iabc\<C-G>u\ndef\<C-G>u\nghi"
+ call assert_equal(3, getchangelist('%')[1])
+ " Move one step back in the changelist.
+ normal 2g;
+
+ hide edit Xfile2.txt
+ exe "normal iabcd\<C-G>u\ndefg\<C-G>u\nghij"
+ call assert_equal(3, getchangelist('%')[1])
+ " Move to the beginning of the changelist.
+ normal 99g;
+
+ " Check the changelist indices.
+ call assert_equal(0, getchangelist('%')[1])
+ call assert_equal(1, getchangelist('#')[1])
bwipe!
+ call delete('Xfile1.txt')
+ call delete('Xfile2.txt')
+endfunc
+
+func Test_getchangelist()
+ bwipe!
enew
call assert_equal([], 10->getchangelist())
call assert_equal([[], 0], getchangelist())
@@ -15,6 +68,7 @@ func Test_getchangelist()
call writefile(['line1', 'line2', 'line3'], 'Xfile2.txt')
edit Xfile1.txt
+ let buf_1 = bufnr()
exe "normal 1Goline\<C-G>u1.1"
exe "normal 3Goline\<C-G>u2.1"
exe "normal 5Goline\<C-G>u3.1"
@@ -26,6 +80,7 @@ func Test_getchangelist()
\ getchangelist('%'))
hide edit Xfile2.txt
+ let buf_2 = bufnr()
exe "normal 1GOline\<C-G>u1.0"
exe "normal 2Goline\<C-G>u2.0"
call assert_equal([[
@@ -37,10 +92,12 @@ func Test_getchangelist()
call assert_equal([[
\ {'lnum' : 2, 'col' : 4, 'coladd' : 0},
\ {'lnum' : 4, 'col' : 4, 'coladd' : 0},
- \ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 3], getchangelist(2))
+ \ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 2],
+ \ getchangelist(buf_1))
call assert_equal([[
\ {'lnum' : 1, 'col' : 6, 'coladd' : 0},
- \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2], getchangelist(3))
+ \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2],
+ \ getchangelist(buf_2))
bwipe!
call delete('Xfile1.txt')
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index db62fe5fa6..edf36b413b 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -1,16 +1,12 @@
" Tests for the +clientserver feature.
-if !has('job') || !has('clientserver')
- throw 'Skipped: job and/or clientserver feature missing'
-endif
+source check.vim
+CheckFeature job
+CheckFeature clientserver
source shared.vim
-func Test_client_server()
- let cmd = GetVimCommand()
- if cmd == ''
- return
- endif
+func Check_X11_Connection()
if has('x11')
if empty($DISPLAY)
throw 'Skipped: $DISPLAY is not set'
@@ -19,11 +15,19 @@ func Test_client_server()
call remote_send('xxx', '')
catch
if v:exception =~ 'E240:'
- throw 'Skipped: no connection to the X server'
+ throw 'Skipped: no connection to the X server'
endif
" ignore other errors
endtry
endif
+endfunc
+
+func Test_client_server()
+ let cmd = GetVimCommand()
+ if cmd == ''
+ return
+ endif
+ call Check_X11_Connection()
let name = 'XVIMTEST'
let cmd .= ' --servername ' . name
@@ -34,6 +38,14 @@ func Test_client_server()
" When using valgrind it takes much longer.
call WaitForAssert({-> assert_match(name, serverlist())})
+ if !has('win32')
+ if RunVim([], [], '--serverlist >Xtest_serverlist')
+ let lines = readfile('Xtest_serverlist')
+ call assert_true(index(lines, 'XVIMTEST') >= 0)
+ endif
+ call delete('Xtest_serverlist')
+ endif
+
eval name->remote_foreground()
call remote_send(name, ":let testvar = 'yes'\<CR>")
@@ -81,6 +93,10 @@ func Test_client_server()
endif
let g:testvar = 'myself'
call assert_equal('myself', remote_expr(v:servername, 'testvar'))
+ call remote_send(v:servername, ":let g:testvar2 = 75\<CR>")
+ call feedkeys('', 'x')
+ call assert_equal(75, g:testvar2)
+ call assert_fails('let v = remote_expr(v:servername, "/2")', 'E449:')
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
call assert_equal('got it', g:myserverid->remote_read(2))
@@ -101,6 +117,55 @@ func Test_client_server()
call assert_equal('another', g:peek_result)
call assert_equal('another', remote_read(g:myserverid, 2))
+ if !has('gui_running')
+ " In GUI vim, the following tests display a dialog box
+
+ let cmd = GetVimProg() .. ' --servername ' .. name
+
+ " Run a separate instance to send a command to the server
+ call remote_expr(name, 'execute("only")')
+ call system(cmd .. ' --remote-send ":new Xfile<CR>"')
+ call assert_equal('2', remote_expr(name, 'winnr("$")'))
+ call assert_equal('Xfile', remote_expr(name, 'winbufnr(1)->bufname()'))
+ call remote_expr(name, 'execute("only")')
+
+ " Invoke a remote-expr. On MS-Windows, the returned value has a carriage
+ " return.
+ let l = system(cmd .. ' --remote-expr "2 + 2"')
+ call assert_equal(['4'], split(l, "\n"))
+
+ " Edit multiple files using --remote
+ call system(cmd .. ' --remote Xfile1 Xfile2 Xfile3')
+ call assert_equal("Xfile1\nXfile2\nXfile3\n", remote_expr(name, 'argv()'))
+ eval name->remote_send(":%bw!\<CR>")
+
+ " Edit files in separate tab pages
+ call system(cmd .. ' --remote-tab Xfile1 Xfile2 Xfile3')
+ call assert_equal('3', remote_expr(name, 'tabpagenr("$")'))
+ call assert_equal('Xfile2', remote_expr(name, 'bufname(tabpagebuflist(2)[0])'))
+ eval name->remote_send(":%bw!\<CR>")
+
+ " Edit a file using --remote-wait
+ eval name->remote_send(":source $VIMRUNTIME/plugin/rrhelper.vim\<CR>")
+ call system(cmd .. ' --remote-wait +enew Xfile1')
+ call assert_equal("Xfile1", remote_expr(name, 'bufname("#")'))
+ eval name->remote_send(":%bw!\<CR>")
+
+ " Edit files using --remote-tab-wait
+ call system(cmd .. ' --remote-tabwait +tabonly\|enew Xfile1 Xfile2')
+ call assert_equal('1', remote_expr(name, 'tabpagenr("$")'))
+ eval name->remote_send(":%bw!\<CR>")
+
+ " Error cases
+ if v:lang == "C" || v:lang =~ '^[Ee]n'
+ let l = split(system(cmd .. ' --remote +pwd'), "\n")
+ call assert_equal("Argument missing after: \"+pwd\"", l[1])
+ endif
+ let l = system(cmd .. ' --remote-expr "abcd"')
+ call assert_match('^E449: ', l)
+ endif
+
+ eval name->remote_send(":%bw!\<CR>")
eval name->remote_send(":qa!\<CR>")
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
@@ -111,8 +176,8 @@ func Test_client_server()
endif
endtry
- call assert_fails("let x=remote_peek([])", 'E730:')
- call assert_fails("let x=remote_read('vim10')", 'E277:')
+ call assert_fails("let x = remote_peek([])", 'E730:')
+ call assert_fails("let x = remote_read('vim10')", 'E277:')
endfunc
" Uncomment this line to get a debugging log
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 276bb7fb71..7aac731709 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -642,6 +642,9 @@ func Test_cmdline_remove_char()
call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
call assert_equal('"def', @:, e)
+
+ " This was going before the start in latin1.
+ call feedkeys(": \<C-W>\<CR>", 'tx')
endfor
let &encoding = encoding_save
@@ -704,6 +707,16 @@ func Test_cmdline_complete_user_cmd()
delcommand Foo
endfunc
+func Test_complete_user_cmd()
+ command FooBar echo 'global'
+ command -buffer FooBar echo 'local'
+ call feedkeys(":Foo\<C-A>\<Home>\"\<CR>", 'tx')
+ call assert_equal('"FooBar', @:)
+
+ delcommand -buffer FooBar
+ delcommand FooBar
+endfunc
+
func s:ScriptLocalFunction()
echo 'yes'
endfunc
@@ -1846,4 +1859,20 @@ func Test_long_error_message()
silent! norm Q00000000000000     000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                                                                                                                                                                        
endfunc
+func Test_cmdline_redraw_tabline()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set showtabline=2
+ autocmd CmdlineEnter * set tabline=foo
+ END
+ call writefile(lines, 'Xcmdline_redraw_tabline')
+ let buf = RunVimInTerminal('-S Xcmdline_redraw_tabline', #{rows: 6})
+ call term_sendkeys(buf, ':')
+ call WaitForAssert({-> assert_match('^foo', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+ call delete('Xcmdline_redraw_tabline')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 8c20c647f1..1dbbe578c5 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -33,7 +33,8 @@ func Test_diff_fold_sync()
call win_gotoid(winone)
call assert_equal(23, getcurpos()[1])
- call assert_equal(1, g:update_count)
+ " depending on how redraw is done DiffUpdated may be triggered once or twice
+ call assert_inrange(1, 2, g:update_count)
au! DiffUpdated
windo diffoff
@@ -1332,4 +1333,157 @@ func Test_diff_binary()
set diffopt&vim
endfunc
+" Test for using the 'zi' command to invert 'foldenable' in diff windows (test
+" for the issue fixed by patch 6.2.317)
+func Test_diff_foldinvert()
+ %bw!
+ edit Xfile1
+ new Xfile2
+ new Xfile3
+ windo diffthis
+ " open a non-diff window
+ botright new
+ 1wincmd w
+ call assert_true(getwinvar(1, '&foldenable'))
+ call assert_true(getwinvar(2, '&foldenable'))
+ call assert_true(getwinvar(3, '&foldenable'))
+ normal zi
+ call assert_false(getwinvar(1, '&foldenable'))
+ call assert_false(getwinvar(2, '&foldenable'))
+ call assert_false(getwinvar(3, '&foldenable'))
+ normal zi
+ call assert_true(getwinvar(1, '&foldenable'))
+ call assert_true(getwinvar(2, '&foldenable'))
+ call assert_true(getwinvar(3, '&foldenable'))
+
+ " If the current window has 'noscrollbind', then 'zi' should not change
+ " 'foldenable' in other windows.
+ 1wincmd w
+ set noscrollbind
+ normal zi
+ call assert_false(getwinvar(1, '&foldenable'))
+ call assert_true(getwinvar(2, '&foldenable'))
+ call assert_true(getwinvar(3, '&foldenable'))
+
+ " 'zi' should not change the 'foldenable' for windows with 'noscrollbind'
+ 1wincmd w
+ set scrollbind
+ normal zi
+ call setwinvar(2, '&scrollbind', v:false)
+ normal zi
+ call assert_false(getwinvar(1, '&foldenable'))
+ call assert_true(getwinvar(2, '&foldenable'))
+ call assert_false(getwinvar(3, '&foldenable'))
+
+ %bw!
+ set scrollbind&
+endfunc
+
+" This was scrolling for 'cursorbind' but 'scrollbind' is more important
+func Test_diff_scroll()
+ CheckScreendump
+
+ let left =<< trim END
+ line 1
+ line 2
+ line 3
+ line 4
+
+ // Common block
+ // one
+ // containing
+ // four lines
+
+ // Common block
+ // two
+ // containing
+ // four lines
+ END
+ call writefile(left, 'Xleft')
+ let right =<< trim END
+ line 1
+ line 2
+ line 3
+ line 4
+
+ Lorem
+ ipsum
+ dolor
+ sit
+ amet,
+ consectetur
+ adipiscing
+ elit.
+ Etiam
+ luctus
+ lectus
+ sodales,
+ dictum
+
+ // Common block
+ // one
+ // containing
+ // four lines
+
+ Vestibulum
+ tincidunt
+ aliquet
+ nulla.
+
+ // Common block
+ // two
+ // containing
+ // four lines
+ END
+ call writefile(right, 'Xright')
+ let buf = RunVimInTerminal('-d Xleft Xright', {'rows': 12})
+ call term_sendkeys(buf, "\<C-W>\<C-W>jjjj")
+ call VerifyScreenDump(buf, 'Test_diff_scroll_1', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_scroll_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xleft')
+ call delete('Xright')
+endfunc
+
+" This was trying to update diffs for a buffer being closed
+func Test_diff_only()
+ silent! lfile
+ set diff
+ lopen
+ norm o
+ silent! norm o
+
+ set nodiff
+ %bwipe!
+endfunc
+
+" This was causing invalid diff block values
+" FIXME: somehow this causes a valgrind error when run directly but not when
+" run as a test.
+func Test_diff_manipulations()
+ set diff
+ split 0
+ sil! norm R doobdeuR doobdeuR doobdeu
+
+ set nodiff
+ %bwipe!
+endfunc
+
+" This was causing the line number in the diff block to go below one.
+" FIXME: somehow this causes a valgrind error when run directly but not when
+" run as a test.
+func Test_diff_put_and_undo()
+ set diff
+ next 0
+ split 00
+ sil! norm o0gguudpo0ggJuudp
+
+ bwipe!
+ bwipe!
+ set nodiff
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 42c77518e4..a09346a595 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1811,95 +1811,4 @@ func Test_read_invalid()
set encoding=utf-8
endfunc
-" Test for ModeChanged pattern
-func Test_mode_changes()
- let g:index = 0
- let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'n', 'V', 'v', 's', 'n']
- func! TestMode()
- call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode"))
- call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode"))
- call assert_equal(mode(1), get(v:event, "new_mode"))
- let g:index += 1
- endfunc
-
- au ModeChanged * :call TestMode()
- let g:n_to_any = 0
- au ModeChanged n:* let g:n_to_any += 1
- call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdG", 'tnix')
-
- let g:V_to_v = 0
- au ModeChanged V:v let g:V_to_v += 1
- call feedkeys("Vv\<C-G>\<esc>", 'tnix')
- call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any)
- call assert_equal(1, g:V_to_v)
- call assert_equal(len(g:mode_seq) - 1, g:index)
-
- let g:n_to_i = 0
- au ModeChanged n:i let g:n_to_i += 1
- let g:n_to_niI = 0
- au ModeChanged i:niI let g:n_to_niI += 1
- let g:niI_to_i = 0
- au ModeChanged niI:i let g:niI_to_i += 1
- let g:nany_to_i = 0
- au ModeChanged n*:i let g:nany_to_i += 1
- let g:i_to_n = 0
- au ModeChanged i:n let g:i_to_n += 1
- let g:nori_to_any = 0
- au ModeChanged [ni]:* let g:nori_to_any += 1
- let g:i_to_any = 0
- au ModeChanged i:* let g:i_to_any += 1
- let g:index = 0
- let g:mode_seq = ['n', 'i', 'niI', 'i', 'n']
- call feedkeys("a\<C-O>l\<esc>", 'tnix')
- call assert_equal(len(g:mode_seq) - 1, g:index)
- call assert_equal(1, g:n_to_i)
- call assert_equal(1, g:n_to_niI)
- call assert_equal(1, g:niI_to_i)
- call assert_equal(2, g:nany_to_i)
- call assert_equal(1, g:i_to_n)
- call assert_equal(2, g:i_to_any)
- call assert_equal(3, g:nori_to_any)
-
- if has('terminal')
- let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n']
- call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix')
- call assert_equal(len(g:mode_seq) - 1, g:index)
- call assert_equal(1, g:n_to_i)
- call assert_equal(1, g:n_to_niI)
- call assert_equal(1, g:niI_to_i)
- call assert_equal(2, g:nany_to_i)
- call assert_equal(1, g:i_to_n)
- call assert_equal(2, g:i_to_any)
- call assert_equal(5, g:nori_to_any)
- endif
-
- au! ModeChanged
- delfunc TestMode
- unlet! g:mode_seq
- unlet! g:index
- unlet! g:n_to_any
- unlet! g:V_to_v
- unlet! g:n_to_i
- unlet! g:n_to_niI
- unlet! g:niI_to_i
- unlet! g:nany_to_i
- unlet! g:i_to_n
- unlet! g:nori_to_any
- unlet! g:i_to_any
-endfunc
-
-func Test_recursive_ModeChanged()
- au! ModeChanged * norm 0u
- sil! norm 
- au!
-endfunc
-
-func Test_ModeChanged_starts_visual()
- " This was triggering ModeChanged before setting VIsual, causing a crash.
- au! ModeChanged * norm 0u
- sil! norm 
-
- au! ModeChanged
-endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 122572f32a..2f734cba26 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -135,6 +135,30 @@ func Test_Ex_global()
bwipe!
endfunc
+" Test for pressing Ctrl-C in :append inside a loop in Ex mode
+" This used to hang Vim
+func Test_Ex_append_in_loop()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+
+ call term_sendkeys(buf, "gQ")
+ call term_sendkeys(buf, "for i in range(1)\<CR>")
+ call term_sendkeys(buf, "append\<CR>")
+ call WaitForAssert({-> assert_match(': append', term_getline(buf, 5))}, 1000)
+ call term_sendkeys(buf, "\<C-C>")
+ " Wait for input to be flushed
+ call term_wait(buf)
+ call term_sendkeys(buf, "foo\<CR>")
+ call WaitForAssert({-> assert_match('foo', term_getline(buf, 5))}, 1000)
+ call term_sendkeys(buf, ".\<CR>")
+ call WaitForAssert({-> assert_match('.', term_getline(buf, 5))}, 1000)
+ call term_sendkeys(buf, "endfor\<CR>")
+ call term_sendkeys(buf, "vi\<CR>")
+ call WaitForAssert({-> assert_match('foo', term_getline(buf, 1))}, 1000)
+
+ call StopVimInTerminal(buf)
+endfunc
+
" In Ex-mode, a backslash escapes a newline
func Test_Ex_escape_enter()
call feedkeys("gQlet l = \"a\\\<kEnter>b\"\<cr>vi\<cr>", 'xt')
@@ -155,9 +179,7 @@ endfunc
func Test_Ex_echo_backslash()
throw 'Skipped: Nvim only supports Vim Ex mode'
" This test works only when the language is English
- if v:lang != "C" && v:lang !~ '^[Ee]n'
- return
- endif
+ CheckEnglish
let bsl = '\\\\'
let bsl2 = '\\\'
call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index 7d581d5efd..dac7a6989d 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -242,49 +242,58 @@ func Test_confirm_cmd()
CheckNotGui
CheckRunVimInTerminal
- call writefile(['foo1'], 'foo')
- call writefile(['bar1'], 'bar')
+ call writefile(['foo1'], 'Xfoo')
+ call writefile(['bar1'], 'Xbar')
" Test for saving all the modified buffers
- let buf = RunVimInTerminal('', {'rows': 20})
- call term_sendkeys(buf, ":set nomore\n")
- call term_sendkeys(buf, ":new foo\n")
- call term_sendkeys(buf, ":call setline(1, 'foo2')\n")
- call term_sendkeys(buf, ":new bar\n")
- call term_sendkeys(buf, ":call setline(1, 'bar2')\n")
- call term_sendkeys(buf, ":wincmd b\n")
+ let lines =<< trim END
+ set nomore
+ new Xfoo
+ call setline(1, 'foo2')
+ new Xbar
+ call setline(1, 'bar2')
+ wincmd b
+ END
+ call writefile(lines, 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
call term_sendkeys(buf, ":confirm qall\n")
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "A")
call StopVimInTerminal(buf)
- call assert_equal(['foo2'], readfile('foo'))
- call assert_equal(['bar2'], readfile('bar'))
+ call assert_equal(['foo2'], readfile('Xfoo'))
+ call assert_equal(['bar2'], readfile('Xbar'))
" Test for discarding all the changes to modified buffers
- let buf = RunVimInTerminal('', {'rows': 20})
- call term_sendkeys(buf, ":set nomore\n")
- call term_sendkeys(buf, ":new foo\n")
- call term_sendkeys(buf, ":call setline(1, 'foo3')\n")
- call term_sendkeys(buf, ":new bar\n")
- call term_sendkeys(buf, ":call setline(1, 'bar3')\n")
- call term_sendkeys(buf, ":wincmd b\n")
+ let lines =<< trim END
+ set nomore
+ new Xfoo
+ call setline(1, 'foo3')
+ new Xbar
+ call setline(1, 'bar3')
+ wincmd b
+ END
+ call writefile(lines, 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
call term_sendkeys(buf, ":confirm qall\n")
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "D")
call StopVimInTerminal(buf)
- call assert_equal(['foo2'], readfile('foo'))
- call assert_equal(['bar2'], readfile('bar'))
+ call assert_equal(['foo2'], readfile('Xfoo'))
+ call assert_equal(['bar2'], readfile('Xbar'))
" Test for saving and discarding changes to some buffers
- let buf = RunVimInTerminal('', {'rows': 20})
- call term_sendkeys(buf, ":set nomore\n")
- call term_sendkeys(buf, ":new foo\n")
- call term_sendkeys(buf, ":call setline(1, 'foo4')\n")
- call term_sendkeys(buf, ":new bar\n")
- call term_sendkeys(buf, ":call setline(1, 'bar4')\n")
- call term_sendkeys(buf, ":wincmd b\n")
+ let lines =<< trim END
+ set nomore
+ new Xfoo
+ call setline(1, 'foo4')
+ new Xbar
+ call setline(1, 'bar4')
+ wincmd b
+ END
+ call writefile(lines, 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
call term_sendkeys(buf, ":confirm qall\n")
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "N")
@@ -292,11 +301,12 @@ func Test_confirm_cmd()
call term_sendkeys(buf, "Y")
call StopVimInTerminal(buf)
- call assert_equal(['foo4'], readfile('foo'))
- call assert_equal(['bar2'], readfile('bar'))
+ call assert_equal(['foo4'], readfile('Xfoo'))
+ call assert_equal(['bar2'], readfile('Xbar'))
- call delete('foo')
- call delete('bar')
+ call delete('Xscript')
+ call delete('Xfoo')
+ call delete('Xbar')
endfunc
func Test_confirm_cmd_cancel()
@@ -304,10 +314,13 @@ func Test_confirm_cmd_cancel()
CheckRunVimInTerminal
" Test for closing a window with a modified buffer
- let buf = RunVimInTerminal('', {'rows': 20})
- call term_sendkeys(buf, ":set nomore\n")
- call term_sendkeys(buf, ":new\n")
- call term_sendkeys(buf, ":call setline(1, 'abc')\n")
+ let lines =<< trim END
+ set nomore
+ new
+ call setline(1, 'abc')
+ END
+ call writefile(lines, 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
call term_sendkeys(buf, ":confirm close\n")
call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$',
\ term_getline(buf, 20))}, 1000)
@@ -320,6 +333,43 @@ func Test_confirm_cmd_cancel()
call WaitForAssert({-> assert_match('^ *0,0-1 All$',
\ term_getline(buf, 20))}, 1000)
call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
+
+" The ":confirm" prompt was sometimes used with the terminal in cooked mode.
+" This test verifies that a "\<CR>" character is NOT required to respond to a
+" prompt from the ":conf q" and ":conf wq" commands.
+func Test_confirm_q_wq()
+ CheckNotGui
+ CheckRunVimInTerminal
+
+ call writefile(['foo'], 'Xfoo')
+
+ let lines =<< trim END
+ set hidden nomore
+ call setline(1, 'abc')
+ edit Xfoo
+ END
+ call writefile(lines, 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
+ call term_sendkeys(buf, ":confirm q\n")
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$',
+ \ term_getline(buf, 20))}, 1000)
+ call term_sendkeys(buf, 'C')
+ call WaitForAssert({-> assert_notmatch('^\[Y\]es, (N)o, (C)ancel: C*$',
+ \ term_getline(buf, 20))}, 1000)
+
+ call term_sendkeys(buf, ":edit Xfoo\n")
+ call term_sendkeys(buf, ":confirm wq\n")
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$',
+ \ term_getline(buf, 20))}, 1000)
+ call term_sendkeys(buf, 'C')
+ call WaitForAssert({-> assert_notmatch('^\[Y\]es, (N)o, (C)ancel: C*$',
+ \ term_getline(buf, 20))}, 1000)
+ call StopVimInTerminal(buf)
+
+ call delete('Xscript')
+ call delete('Xfoo')
endfunc
func Test_confirm_write_ro()
@@ -646,5 +696,21 @@ func Test_using_zero_in_range()
bwipe!
endfunc
+" Test :write after changing name with :file and loading it with :edit
+func Test_write_after_rename()
+ call writefile(['text'], 'Xfile')
+
+ enew
+ file Xfile
+ call assert_fails('write', 'E13: File exists (add ! to override)')
+
+ " works OK after ":edit"
+ edit
+ write
+
+ call delete('Xfile')
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
index d86fea4f45..383921bb82 100644
--- a/src/nvim/testdir/test_expand.vim
+++ b/src/nvim/testdir/test_expand.vim
@@ -84,6 +84,15 @@ func Test_expandcmd()
let $FOO="blue\tsky"
call setline(1, "$FOO")
call assert_equal("grep pat blue\tsky", expandcmd('grep pat <cfile>'))
+
+ " Test for expression expansion `=
+ let $FOO= "blue"
+ call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
+
+ " Test for env variable with spaces
+ let $FOO= "foo bar baz"
+ call assert_equal("e foo bar baz", expandcmd("e $FOO"))
+
unlet $FOO
close!
endfunc
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 59b272d563..eedad15e9e 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -43,7 +43,9 @@ func Test_other_type()
endfunc
" Filetypes detected just from matching the file name.
+" First one is checking that these files have no filetype.
let s:filename_checks = {
+ \ 'none': ['bsd', 'some-bsd'],
\ '8th': ['file.8th'],
\ 'a2ps': ['/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc', 'any/etc/a2ps.cfg', 'any/etc/a2ps/file.cfg'],
\ 'a65': ['file.a65'],
@@ -85,7 +87,7 @@ let s:filename_checks = {
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
\ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'],
\ 'blank': ['file.bl'],
- \ 'bsdl': ['file.bsd', 'file.bsdl', 'bsd', 'some-bsd'],
+ \ 'bsdl': ['file.bsd', 'file.bsdl'],
\ 'bst': ['file.bst'],
\ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
@@ -532,6 +534,7 @@ let s:filename_checks = {
\ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
+ \ 'swayconfig': ['/home/user/.sway/config', '/home/user/.config/sway/config', '/etc/sway/config', '/etc/xdg/sway/config'],
\ 'swift': ['file.swift'],
\ 'swiftgyb': ['file.swift.gyb'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'],
@@ -546,7 +549,7 @@ let s:filename_checks = {
\ 'template': ['file.tmpl'],
\ 'teraterm': ['file.ttl'],
\ 'terminfo': ['file.ti'],
- \ 'terraform': ['file.tfvars'],
+ \ 'terraform-vars': ['file.tfvars'],
\ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'],
\ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'],
\ 'texmf': ['texmf.cnf'],
@@ -647,7 +650,8 @@ func CheckItems(checks)
if &filetype == '' && &readonly
" File exists but not able to edit it (permission denied)
else
- call assert_equal(ft, &filetype, 'with file name: ' . names[i])
+ let expected = ft == 'none' ? '' : ft
+ call assert_equal(expected, &filetype, 'with file name: ' . names[i])
endif
bwipe!
endfor
@@ -1858,6 +1862,31 @@ func Test_inc_file()
call assert_equal('bitbake', &filetype)
bwipe!
+ call writefile(['S = "${WORKDIR}"'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
+ bwipe!
+
+ call writefile(['DEPENDS:append = " somedep"'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
+ bwipe!
+
+ call writefile(['MACHINE ??= "qemu"'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
+ bwipe!
+
+ call writefile(['PROVIDES := "test"'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
+ bwipe!
+
+ call writefile(['RDEPENDS_${PN} += "bar"'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
+ bwipe!
+
" asm
call writefile(['asmsyntax=bar'], 'Xfile.inc')
split Xfile.inc
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 9b8d740efb..c11e7b4fea 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -547,6 +547,7 @@ func Save_mode()
return ''
endfunc
+" Test for the mode() function
func Test_mode()
new
call append(0, ["Blue Ball Black", "Brown Band Bowl", ""])
@@ -717,6 +718,8 @@ func Test_mode()
call assert_equal('c-c', g:current_modes)
call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt')
call assert_equal('c-cv', g:current_modes)
+ " call feedkeys("Qcall Save_mode()\<CR>vi\<CR>", 'xt')
+ " call assert_equal('c-ce', g:current_modes)
" How to test Ex mode?
" Test mode in operatorfunc (it used to be Operator-pending).
@@ -1262,6 +1265,23 @@ func Test_inputlist()
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>5q", 'tx')
call assert_equal(0, c)
+ " Use backspace to delete characters in the prompt
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>1\<BS>3\<BS>2\<cr>", 'tx')
+ call assert_equal(2, c)
+
+ " Use mouse to make a selection
+ " call test_setmouse(&lines - 3, 2)
+ call nvim_input_mouse('left', 'press', '', 0, &lines - 4, 1) " set mouse position
+ call getchar() " discard mouse event but keep mouse position
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
+ call assert_equal(1, c)
+ " Mouse click outside of the list
+ " call test_setmouse(&lines - 6, 2)
+ call nvim_input_mouse('left', 'press', '', 0, &lines - 7, 1) " set mouse position
+ call getchar() " discard mouse event but keep mouse position
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
+ call assert_equal(-2, c)
+
call assert_fails('call inputlist("")', 'E686:')
endfunc
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index 1569177d66..feae44e5ee 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -138,6 +138,22 @@ func Test_gf_visual()
call assert_equal('Xtest_gf_visual', bufname('%'))
call assert_equal(3, getcurpos()[1])
+ " do not include the NUL at the end
+ call writefile(['x'], 'X')
+ let save_enc = &enc
+ " for enc in ['latin1', 'utf-8']
+ for enc in ['utf-8']
+ exe "set enc=" .. enc
+ new
+ call setline(1, 'X')
+ set nomodified
+ exe "normal \<C-V>$gf"
+ call assert_equal('X', bufname())
+ bwipe!
+ endfor
+ let &enc = save_enc
+ call delete('X')
+
" line number in visual area is used for file name
if has('unix')
bwipe!
@@ -194,4 +210,27 @@ func Test_gf_includeexpr()
delfunc IncFunc
endfunc
+" Check that expanding directories can handle more than 255 entries.
+func Test_gf_subdirs_wildcard()
+ let cwd = getcwd()
+ let dir = 'Xtestgf_dir'
+ call mkdir(dir)
+ call chdir(dir)
+ for i in range(300)
+ call mkdir(i)
+ call writefile([], i .. '/' .. i, 'S')
+ endfor
+ set path=./**
+
+ new | only
+ call setline(1, '99')
+ w! Xtest1
+ normal gf
+ call assert_equal('99', fnamemodify(bufname(''), ":t"))
+
+ call chdir(cwd)
+ call delete(dir, 'rf')
+ set path&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index feddf85346..947f7efc7c 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -1,4 +1,7 @@
+" Test for :global and :vglobal
+
source check.vim
+source term_util.vim
func Test_yank_put_clipboard()
new
@@ -82,4 +85,31 @@ func Test_wrong_delimiter()
call assert_fails('g x^bxd', 'E146:')
endfunc
+" Test for interrupting :global using Ctrl-C
+func Test_interrupt_global()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ cnoremap ; <Cmd>sleep 10<CR>
+ call setline(1, repeat(['foo'], 5))
+ END
+ call writefile(lines, 'Xtest_interrupt_global')
+ let buf = RunVimInTerminal('-S Xtest_interrupt_global', {'rows': 6})
+
+ call term_sendkeys(buf, ":g/foo/norm :\<C-V>;\<CR>")
+ " Wait for :sleep to start
+ call term_wait(buf)
+ call term_sendkeys(buf, "\<C-C>")
+ call WaitForAssert({-> assert_match('Interrupted', term_getline(buf, 6))}, 1000)
+
+ " Also test in Ex mode
+ call term_sendkeys(buf, "gQg/foo/norm :\<C-V>;\<CR>")
+ " Wait for :sleep to start
+ call term_wait(buf)
+ call term_sendkeys(buf, "\<C-C>")
+ call WaitForAssert({-> assert_match('Interrupted', term_getline(buf, 5))}, 1000)
+
+ call StopVimInTerminal(buf)
+ call delete('Xtest_interrupt_global')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_feedkeys.vim b/src/nvim/testdir/test_input.vim
index fb64711863..3b1e2eb2df 100644
--- a/src/nvim/testdir/test_feedkeys.vim
+++ b/src/nvim/testdir/test_input.vim
@@ -1,4 +1,4 @@
-" Test feedkeys() function.
+" Tests for character input and feedkeys() function.
func Test_feedkeys_x_with_empty_string()
new
@@ -34,4 +34,28 @@ func Test_feedkeys_escape_special()
nunmap …
endfunc
+func Test_input_simplify_ctrl_at()
+ new
+ " feeding unsimplified CTRL-@ should still trigger i_CTRL-@
+ call feedkeys("ifoo\<Esc>A\<*C-@>x", 'xt')
+ call assert_equal('foofo', getline(1))
+ bw!
+endfunc
+
+func Test_input_simplify_noremap()
+ call feedkeys("i\<*C-M>", 'nx')
+ call assert_equal('', getline(1))
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ bw!
+endfunc
+
+func Test_input_simplify_timedout()
+ inoremap <C-M>a b
+ call feedkeys("i\<*C-M>", 'xt')
+ call assert_equal('', getline(1))
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ iunmap <C-M>a
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 93ab17955d..179218e48a 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -100,6 +100,74 @@ func Test_ins_complete()
call delete('Xdir', 'rf')
endfunc
+func Test_omni_dash()
+ func Omni(findstart, base)
+ if a:findstart
+ return 5
+ else
+ echom a:base
+ return ['-help', '-v']
+ endif
+ endfunc
+ set omnifunc=Omni
+ new
+ exe "normal Gofind -\<C-x>\<C-o>"
+ call assert_equal("find -help", getline('$'))
+
+ bwipe!
+ delfunc Omni
+ set omnifunc=
+endfunc
+
+func Test_omni_throw()
+ let g:CallCount = 0
+ func Omni(findstart, base)
+ let g:CallCount += 1
+ if a:findstart
+ throw "he he he"
+ endif
+ endfunc
+ set omnifunc=Omni
+ new
+ try
+ exe "normal ifoo\<C-x>\<C-o>"
+ call assert_false(v:true, 'command should have failed')
+ catch
+ call assert_exception('he he he')
+ call assert_equal(1, g:CallCount)
+ endtry
+
+ bwipe!
+ delfunc Omni
+ unlet g:CallCount
+ set omnifunc=
+endfunc
+
+func Test_completefunc_args()
+ let s:args = []
+ func! CompleteFunc(findstart, base)
+ let s:args += [[a:findstart, empty(a:base)]]
+ endfunc
+ new
+
+ set completefunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set completefunc=
+
+ let s:args = []
+ set omnifunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set omnifunc=
+
+ bwipe!
+ unlet s:args
+ delfunc CompleteFunc
+endfunc
+
func s:CompleteDone_CompleteFuncNone( findstart, base )
throw 'skipped: Nvim does not support v:none'
if a:findstart
@@ -179,19 +247,6 @@ func Test_CompleteDoneDict()
au! CompleteDone
endfunc
-func Test_CompleteDone_undo()
- au CompleteDone * call append(0, "prepend1")
- new
- call setline(1, ["line1", "line2"])
- call feedkeys("Go\<C-X>\<C-N>\<CR>\<ESC>", "tx")
- call assert_equal(["prepend1", "line1", "line2", "line1", ""],
- \ getline(1, '$'))
- undo
- call assert_equal(["line1", "line2"], getline(1, '$'))
- bwipe!
- au! CompleteDone
-endfunc
-
func s:CompleteDone_CompleteFuncDictNoUserData(findstart, base)
if a:findstart
return 0
@@ -268,72 +323,30 @@ func Test_CompleteDoneList()
au! CompleteDone
endfunc
-func Test_omni_dash()
- func Omni(findstart, base)
- if a:findstart
- return 5
- else
- echom a:base
- return ['-help', '-v']
- endif
- endfunc
- set omnifunc=Omni
- new
- exe "normal Gofind -\<C-x>\<C-o>"
- call assert_equal("find -help", getline('$'))
-
- bwipe!
- delfunc Omni
- set omnifunc=
-endfunc
-
-func Test_omni_throw()
- let g:CallCount = 0
- func Omni(findstart, base)
- let g:CallCount += 1
- if a:findstart
- throw "he he he"
- endif
- endfunc
- set omnifunc=Omni
+func Test_CompleteDone_undo()
+ au CompleteDone * call append(0, "prepend1")
new
- try
- exe "normal ifoo\<C-x>\<C-o>"
- call assert_false(v:true, 'command should have failed')
- catch
- call assert_exception('he he he')
- call assert_equal(1, g:CallCount)
- endtry
-
+ call setline(1, ["line1", "line2"])
+ call feedkeys("Go\<C-X>\<C-N>\<CR>\<ESC>", "tx")
+ call assert_equal(["prepend1", "line1", "line2", "line1", ""],
+ \ getline(1, '$'))
+ undo
+ call assert_equal(["line1", "line2"], getline(1, '$'))
bwipe!
- delfunc Omni
- unlet g:CallCount
- set omnifunc=
+ au! CompleteDone
endfunc
-func Test_completefunc_args()
- let s:args = []
- func! CompleteFunc(findstart, base)
- let s:args += [[a:findstart, empty(a:base)]]
- endfunc
- new
-
- set completefunc=CompleteFunc
- call feedkeys("i\<C-X>\<C-U>\<Esc>", 'x')
- call assert_equal([1, 1], s:args[0])
- call assert_equal(0, s:args[1][0])
- set completefunc=
-
- let s:args = []
- set omnifunc=CompleteFunc
- call feedkeys("i\<C-X>\<C-O>\<Esc>", 'x')
- call assert_equal([1, 1], s:args[0])
- call assert_equal(0, s:args[1][0])
- set omnifunc=
-
- bwipe!
- unlet s:args
- delfunc CompleteFunc
+func Test_CompleteDone_modify()
+ let value = {
+ \ 'word': '',
+ \ 'abbr': '',
+ \ 'menu': '',
+ \ 'info': '',
+ \ 'kind': '',
+ \ 'user_data': '',
+ \ }
+ let v:completed_item = value
+ call assert_equal(value, v:completed_item)
endfunc
func CompleteTest(findstart, query)
@@ -505,19 +518,6 @@ func Test_ins_completeslash()
set completeslash=
endfunc
-func Test_issue_7021()
- CheckMSWindows
-
- let orig_shellslash = &shellslash
- set noshellslash
-
- set completeslash=slash
- call assert_false(expand('~') =~ '/')
-
- let &shellslash = orig_shellslash
- set completeslash=
-endfunc
-
func Test_pum_stopped_by_timer()
CheckScreendump
@@ -829,6 +829,19 @@ func Test_complete_stop()
close!
endfunc
+func Test_issue_7021()
+ CheckMSWindows
+
+ let orig_shellslash = &shellslash
+ set noshellslash
+
+ set completeslash=slash
+ call assert_false(expand('~') =~ '/')
+
+ let &shellslash = orig_shellslash
+ set completeslash=
+endfunc
+
" Test to ensure 'Scanning...' messages are not recorded in messages history
func Test_z1_complete_no_history()
new
@@ -838,7 +851,18 @@ func Test_z1_complete_no_history()
exe "normal owh\<C-X>\<C-K>"
exe "normal owh\<C-N>"
call assert_equal(currmess, execute('messages'))
- close!
+ bwipe!
+endfunc
+
+" A mapping is not used for the key after CTRL-X.
+func Test_no_mapping_for_ctrl_x_key()
+ new
+ inoremap <C-K> <Cmd>let was_mapped = 'yes'<CR>
+ setlocal dictionary=README.txt
+ call feedkeys("aexam\<C-X>\<C-K> ", 'xt')
+ call assert_equal('example ', getline(1))
+ call assert_false(exists('was_mapped'))
+ bwipe!
endfunc
func FooBarComplete(findstart, base)
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index f9429a8020..dad4c81a7b 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -1,12 +1,12 @@
-" Tests for maparg().
+" Tests for maparg(), mapcheck() and mapset().
" Also test utf8 map with a 0x80 byte.
" Also test mapcheck()
-function s:SID()
+func s:SID()
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
-endfun
+endfunc
-function Test_maparg()
+func Test_maparg()
new
set cpo-=<
set encoding=utf8
@@ -17,24 +17,28 @@ function Test_maparg()
vnoremap <script> <buffer> <expr> <silent> bar isbar
call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>',
- \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
- \ 'rhs': 'is<F4>foo', 'buffer': 0},
- \ maparg('foo<C-V>', '', 0, 1))
- call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v',
+ \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16",
+ \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
+ \ 'rhs': 'is<F4>foo', 'buffer': 0},
+ \ maparg('foo<C-V>', '', 0, 1))
+ call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar',
+ \ 'lhsraw': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
- \ 'rhs': 'isbar', 'buffer': 1},
+ \ 'rhs': 'isbar', 'buffer': 1},
\ 'bar'->maparg('', 0, 1))
let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar
- call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ',
+ call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo',
+ \ 'lhsraw': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
- \ 'buffer': 1},
+ \ 'buffer': 1},
\ maparg('foo', '', 0, 1))
let lnum = expand('<sflnum>')
tmap baz foo
- call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't',
+ call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz',
+ \ 'lhsraw': 'baz', 'mode': 't',
\ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
- \ 'buffer': 0},
+ \ 'buffer': 0},
\ maparg('baz', 't', 0, 1))
map abc x<char-114>x
@@ -81,6 +85,12 @@ function Test_maparg()
call assert_equal(['{', 'w', 's'], [d.lhs, d.rhs, d.mode])
sunmap {
+ map <C-I> foo
+ unmap <Tab>
+ " This used to cause a segfault
+ call maparg('<C-I>', '', 0, 1)
+ unmap <C-I>
+
map abc <Nop>
call assert_equal("<Nop>", maparg('abc'))
unmap abc
@@ -89,7 +99,8 @@ function Test_maparg()
let d = maparg('esc', 'i', 1, 1)
call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode])
abclear
-endfunction
+ unlet d
+endfunc
func Test_mapcheck()
call assert_equal('', mapcheck('a'))
@@ -130,7 +141,7 @@ func Test_mapcheck()
unabbr ab
endfunc
-function Test_range_map()
+func Test_range_map()
new
" Outside of the range, minimum
inoremap <Char-0x1040> a
@@ -145,6 +156,147 @@ function Test_range_map()
inoremap <Char-0xf040> d
execute "normal a\uf040\<Esc>"
call assert_equal("abcd", getline(1))
-endfunction
+endfunc
+
+func One_mapset_test(keys)
+ exe 'nnoremap ' .. a:keys .. ' original<CR>'
+ let orig = maparg(a:keys, 'n', 0, 1)
+ call assert_equal(a:keys, orig.lhs)
+ call assert_equal('original<CR>', orig.rhs)
+ call assert_equal('n', orig.mode)
+
+ exe 'nunmap ' .. a:keys
+ let d = maparg(a:keys, 'n', 0, 1)
+ call assert_equal({}, d)
+
+ call mapset('n', 0, orig)
+ let d = maparg(a:keys, 'n', 0, 1)
+ call assert_equal(a:keys, d.lhs)
+ call assert_equal('original<CR>', d.rhs)
+ call assert_equal('n', d.mode)
+
+ exe 'nunmap ' .. a:keys
+endfunc
+
+func Test_mapset()
+ call One_mapset_test('K')
+ call One_mapset_test('<F3>')
+
+ " Check <> key conversion
+ new
+ inoremap K one<Left>x
+ call feedkeys("iK\<Esc>", 'xt')
+ call assert_equal('onxe', getline(1))
+
+ let orig = maparg('K', 'i', 0, 1)
+ call assert_equal('K', orig.lhs)
+ call assert_equal('one<Left>x', orig.rhs)
+ call assert_equal('i', orig.mode)
+
+ iunmap K
+ let d = maparg('K', 'i', 0, 1)
+ call assert_equal({}, d)
+
+ call mapset('i', 0, orig)
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('onxe', getline(1))
+
+ iunmap K
+
+ " Test literal <CR> using a backslash
+ let cpo_save = &cpo
+ set cpo-=B
+ inoremap K one\<CR>two
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('one<CR>two', getline(1))
+
+ let orig = maparg('K', 'i', 0, 1)
+ call assert_equal('K', orig.lhs)
+ call assert_equal('one\<CR>two', orig.rhs)
+ call assert_equal('i', orig.mode)
+
+ iunmap K
+ let d = maparg('K', 'i', 0, 1)
+ call assert_equal({}, d)
+
+ call mapset('i', 0, orig)
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('one<CR>two', getline(1))
+
+ iunmap K
+
+ " Test literal <CR> using CTRL-V
+ inoremap K one<CR>two
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('one<CR>two', getline(1))
+
+ let orig = maparg('K', 'i', 0, 1)
+ call assert_equal('K', orig.lhs)
+ call assert_equal("one\x16<CR>two", orig.rhs)
+ call assert_equal('i', orig.mode)
+
+ iunmap K
+ let d = maparg('K', 'i', 0, 1)
+ call assert_equal({}, d)
+
+ call mapset('i', 0, orig)
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('one<CR>two', getline(1))
+
+ iunmap K
+ let &cpo = cpo_save
+ bwipe!
+
+ call assert_fails('call mapset([], v:false, {})', 'E730:')
+endfunc
+
+func Check_ctrlb_map(d, check_alt)
+ call assert_equal('<C-B>', a:d.lhs)
+ if a:check_alt
+ call assert_equal("\x80\xfc\x04B", a:d.lhsraw)
+ call assert_equal("\x02", a:d.lhsrawalt)
+ else
+ call assert_equal("\x02", a:d.lhsraw)
+ endif
+endfunc
+
+func Test_map_local()
+ nmap a global
+ nmap <buffer>a local
+
+ let prev_map_list = split(execute('nmap a'), "\n")
+ call assert_match('n\s*a\s*@local', prev_map_list[0])
+ call assert_match('n\s*a\s*global', prev_map_list[1])
+
+ let mapping = maparg('a', 'n', 0, 1)
+ call assert_equal(1, mapping.buffer)
+ let mapping.rhs = 'new_local'
+ call mapset('n', 0, mapping)
+
+ " Check that the global mapping is left untouched.
+ let map_list = split(execute('nmap a'), "\n")
+ call assert_match('n\s*a\s*@new_local', map_list[0])
+ call assert_match('n\s*a\s*global', map_list[1])
+
+ nunmap a
+endfunc
+
+func Test_map_restore()
+ " Test restoring map with alternate keycode
+ nmap <C-B> back
+ let d = maparg('<C-B>', 'n', 0, 1)
+ call Check_ctrlb_map(d, 1)
+ let dsimp = maparg("\x02", 'n', 0, 1)
+ call Check_ctrlb_map(dsimp, 0)
+ nunmap <C-B>
+ call mapset('n', 0, d)
+ let d = maparg('<C-B>', 'n', 0, 1)
+ call Check_ctrlb_map(d, 1)
+ let dsimp = maparg("\x02", 'n', 0, 1)
+ call Check_ctrlb_map(dsimp, 0)
+
+ nunmap <C-B>
+
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 5670368936..a02d23b409 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -118,7 +118,9 @@ func Test_message_more()
let buf = RunVimInTerminal('', {'rows': 6})
call term_sendkeys(buf, ":call setline(1, range(1, 100))\n")
- call term_sendkeys(buf, ":%p#\n")
+ call term_sendkeys(buf, ":%pfoo\<C-H>\<C-H>\<C-H>#")
+ call WaitForAssert({-> assert_equal(':%p#', term_getline(buf, 6))})
+ call term_sendkeys(buf, "\n")
call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
@@ -175,7 +177,8 @@ func Test_message_more()
" Up all the way with 'g'.
call term_sendkeys(buf, 'g')
- call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal(' 4 4', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal(':%p#', term_getline(buf, 1))})
call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
" All the way down. Pressing f should do nothing but pressing
@@ -193,6 +196,13 @@ func Test_message_more()
call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+ " A command line that doesn't print text is appended to scrollback,
+ " even if it invokes a nested command line.
+ call term_sendkeys(buf, ":\<C-R>=':'\<CR>:\<CR>g<")
+ call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 4))})
+ call WaitForAssert({-> assert_equal(':::', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
call term_sendkeys(buf, ":%p#\n")
call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
@@ -306,4 +316,60 @@ func Test_fileinfo_after_echo()
call delete('b.txt')
endfunc
+func Test_cmdheight_zero()
+ set cmdheight=0
+ set showcmd
+ redraw!
+
+ echo 'test echo'
+ call assert_equal(116, screenchar(&lines, 1))
+ redraw!
+
+ echomsg 'test echomsg'
+ call assert_equal(116, screenchar(&lines, 1))
+ redraw!
+
+ call feedkeys(":ls\<CR>", "xt")
+ call assert_equal(':ls', Screenline(&lines - 1))
+ redraw!
+
+ let char = getchar(0)
+ call assert_match(char, 0)
+
+ " Check change/restore cmdheight when macro
+ call feedkeys("qa", "xt")
+ call assert_equal(1, &cmdheight)
+ call feedkeys("q", "xt")
+ call assert_equal(0, &cmdheight)
+
+ call setline(1, 'somestring')
+ call feedkeys("y", "n")
+ %s/somestring/otherstring/gc
+ call assert_equal('otherstring', getline(1))
+
+ call feedkeys("g\<C-g>", "xt")
+ call assert_match(
+ \ 'Col 1 of 11; Line 1 of 1; Word 1 of 1',
+ \ Screenline(&lines))
+
+ " Check split behavior
+ for i in range(1, 10)
+ split
+ endfor
+ only
+ call assert_equal(0, &cmdheight)
+
+ " Check that pressing ":" should not scroll a window
+ " Check for what patch 9.0.0115 fixes
+ botright 10new
+ call setline(1, range(12))
+ 7
+ call feedkeys(":\"\<C-R>=line('w0')\<CR>\<CR>", "xt")
+ call assert_equal('"1', @:)
+ bwipe!
+
+ set cmdheight&
+ set showcmd&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 9fbd1f774a..f18ddb274c 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -580,6 +580,7 @@ endfunc
func Test_normal_z_error()
call assert_beeps('normal! z2p')
call assert_beeps('normal! zq')
+ call assert_beeps('normal! cz1')
endfunc
func Test_normal15_z_scroll_vert()
@@ -619,7 +620,7 @@ func Test_normal15_z_scroll_vert()
call assert_equal(10, winheight(0))
exe "norm! z12\<cr>"
call assert_equal(12, winheight(0))
- exe "norm! z10\<cr>"
+ exe "norm! z15\<Del>0\<cr>"
call assert_equal(10, winheight(0))
" Test for z.
@@ -2849,35 +2850,10 @@ func Test_gr_command()
enew!
endfunc
-" When splitting a window the changelist position is wrong.
-" Test the changelist position after splitting a window.
-" Test for the bug fixed by 7.4.386
-func Test_changelist()
- let save_ul = &ul
- enew!
- call append('$', ['1', '2'])
- exe "normal i\<C-G>u"
- exe "normal Gkylpa\<C-G>u"
- set ul=100
- exe "normal Gylpa\<C-G>u"
- set ul=100
- normal gg
- vsplit
- normal g;
- call assert_equal([3, 2], [line('.'), col('.')])
- normal g;
- call assert_equal([2, 2], [line('.'), col('.')])
- call assert_fails('normal g;', 'E662:')
- new
- call assert_fails('normal g;', 'E664:')
- %bwipe!
- let &ul = save_ul
-endfunc
-
func Test_nv_hat_count()
%bwipeout!
let l:nr = bufnr('%') + 1
- call assert_fails(':execute "normal! ' . l:nr . '\<C-^>"', 'E92')
+ call assert_fails(':execute "normal! ' . l:nr . '\<C-^>"', 'E92:')
edit Xfoo
let l:foo_nr = bufnr('Xfoo')
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 1f003041e6..c5b1266689 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -1,6 +1,7 @@
" Test for options
source check.vim
+source view_util.vim
func Test_whichwrap()
set whichwrap=b,s
@@ -48,7 +49,9 @@ func Test_pastetoggle()
let &pastetoggle = str
call assert_equal(str, &pastetoggle)
call assert_equal("\n pastetoggle=" .. strtrans(str), execute('set pastetoggle?'))
+
unlet str
+ set pastetoggle&
endfunc
func Test_wildchar()
@@ -782,7 +785,6 @@ endfunc
func Test_rightleftcmd()
CheckFeature rightleft
set rightleft
- set rightleftcmd
let g:l = []
func AddPos()
@@ -791,6 +793,13 @@ func Test_rightleftcmd()
endfunc
cmap <expr> <F2> AddPos()
+ set rightleftcmd=
+ call feedkeys("/\<F2>abc\<Right>\<F2>\<Left>\<Left>\<F2>" ..
+ \ "\<Right>\<F2>\<Esc>", 'xt')
+ call assert_equal([2, 5, 3, 4], g:l)
+
+ let g:l = []
+ set rightleftcmd=search
call feedkeys("/\<F2>abc\<Left>\<F2>\<Right>\<Right>\<F2>" ..
\ "\<Left>\<F2>\<Esc>", 'xt')
call assert_equal([&co - 1, &co - 4, &co - 2, &co - 3], g:l)
@@ -801,6 +810,14 @@ func Test_rightleftcmd()
set rightleft&
endfunc
+" Test for the "debug" option
+func Test_debug_option()
+ set debug=beep
+ exe "normal \<C-c>"
+ call assert_equal('Beep!', Screenline(&lines))
+ set debug&
+endfunc
+
" Test for setting option values using v:false and v:true
func Test_opt_boolean()
set number&
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index a5e4be49f4..0486ed83ad 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -955,6 +955,25 @@ func Test_menu_only_exists_in_terminal()
endtry
endfunc
+" This used to crash before patch 8.1.1424
+func Test_popup_delete_when_shown()
+ CheckFeature menu
+ CheckNotGui
+
+ func Func()
+ popup Foo
+ return "\<Ignore>"
+ endfunc
+
+ nmenu Foo.Bar :
+ nnoremap <expr> <F2> Func()
+ call feedkeys("\<F2>\<F2>\<Esc>", 'xt')
+
+ delfunc Func
+ nunmenu Foo.Bar
+ nunmap <F2>
+endfunc
+
func Test_popup_complete_info_01()
new
inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index ddd4229f17..f6d573d76b 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -172,6 +172,14 @@ func XlistTests(cchar)
\ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
\ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
+ " Very long line should be displayed.
+ let text = 'Line' .. repeat('1234567890', 130)
+ let lines = ['Xtestfile9:2:9:' .. text]
+ Xgetexpr lines
+
+ let l = split(execute('Xlist', ''), "\n")
+ call assert_equal([' 1 Xtestfile9:2 col 9: ' .. text] , l)
+
" For help entries in the quickfix list, only the filename without directory
" should be displayed
Xhelpgrep setqflist()
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index 82d250e8b3..d08a980787 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -1027,4 +1027,15 @@ func Test_using_invalid_visual_position()
bwipe!
endfunc
+func Test_recursive_substitute_expr()
+ new
+ func Repl()
+ s
+ endfunc
+ silent! s/\%')/~\=Repl()
+
+ bwipe!
+ delfunc Repl
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_spell_utf8.vim b/src/nvim/testdir/test_spell_utf8.vim
index b7e3da37cb..7c588d736a 100644
--- a/src/nvim/testdir/test_spell_utf8.vim
+++ b/src/nvim/testdir/test_spell_utf8.vim
@@ -820,5 +820,13 @@ func Test_check_empty_line()
bwipe!
endfunc
+func Test_spell_suggest_too_long()
+ " this was creating a word longer than MAXWLEN
+ new
+ call setline(1, 'a' .. repeat("\u0333", 150))
+ norm! z=
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index d830f5216d..39fafbf7b4 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -12,6 +12,9 @@ func Test_startup_script()
source $VIMRUNTIME/defaults.vim
call assert_equal(0, &compatible)
+ " Restore some options, so that the following tests doesn't break
+ set nomore
+ set noshowmode
endfunc
" Verify the order in which plugins are loaded:
@@ -814,6 +817,25 @@ func Test_v_argv()
call assert_equal(['arg1', '--cmd', 'echo v:argv', '--cmd', 'q'']'], list[idx:])
endfunc
+" Test for the "-r" recovery mode option
+func Test_r_arg()
+ throw 'Skipped: Nvim has different directories'
+ " Can't catch the output of gvim.
+ CheckNotGui
+ CheckUnix
+ CheckEnglish
+ let cmd = GetVimCommand()
+ " There can be swap files anywhere, only check for the headers.
+ let expected =<< trim END
+ Swap files found:.*
+ In current directory:.*
+ In directory \~/tmp:.*
+ In directory /var/tmp:.*
+ In directory /tmp:.*
+ END
+ call assert_match(join(expected, ""), system(cmd .. " -r")->substitute("[\r\n]\\+", '', ''))
+endfunc
+
" Test for the '-t' option to jump to a tag
func Test_t_arg()
let before =<< trim [CODE]
@@ -824,6 +846,7 @@ func Test_t_arg()
call writefile([s], "Xtestout")
qall
[CODE]
+
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfile1\t/^ \\zsfirst$/",
\ "second\tXfile1\t/^ \\zssecond$/",
@@ -890,6 +913,138 @@ func Test_x_arg()
call delete('Xtest_x_arg')
endfunc
+" Test for entering the insert mode on startup
+func Test_start_insertmode()
+ throw "Skipped: Nvim does not support setting 'insertmode'"
+ let before =<< trim [CODE]
+ set insertmode
+ [CODE]
+ let after =<< trim [CODE]
+ call writefile(['insertmode=' .. &insertmode], 'Xtestout')
+ qall
+ [CODE]
+ if RunVim(before, after, '')
+ call assert_equal(['insertmode=1'], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for enabling the binary mode on startup
+func Test_b_arg()
+ let after =<< trim [CODE]
+ call writefile(['binary=' .. &binary], 'Xtestout')
+ qall
+ [CODE]
+ if RunVim([], after, '-b')
+ call assert_equal(['binary=1'], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for enabling the lisp mode on startup
+func Test_l_arg()
+ let after =<< trim [CODE]
+ let s = 'lisp=' .. &lisp .. ', showmatch=' .. &showmatch
+ call writefile([s], 'Xtestout')
+ qall
+ [CODE]
+ if RunVim([], after, '-l')
+ call assert_equal(['lisp=1, showmatch=1'], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for specifying a non-existing vimrc file using "-u"
+func Test_missing_vimrc()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run vim in terminal'
+ endif
+ let after =<< trim [CODE]
+ call assert_match('^E282:', v:errmsg)
+ call writefile(v:errors, 'Xtestout')
+ [CODE]
+ call writefile(after, 'Xafter')
+
+ let cmd = GetVimCommandCleanTerm() . ' -u Xvimrc_missing -S Xafter'
+ let buf = term_start(cmd, {'term_rows' : 10})
+ call WaitForAssert({-> assert_equal("running", term_getstatus(buf))})
+ call term_wait(buf)
+ call term_sendkeys(buf, "\n:")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 10))})
+ call StopVimInTerminal(buf)
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xafter')
+ call delete('Xtestout')
+endfunc
+
+" Test for using the $VIMINIT environment variable
+func Test_VIMINIT()
+ let after =<< trim [CODE]
+ call assert_equal(1, exists('viminit_found'))
+ call assert_equal('yes', viminit_found)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ call writefile(after, 'Xafter')
+ " let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
+ let cmd = GetVimProg() . ' -S Xafter --cmd "set enc=utf8"'
+ call setenv('VIMINIT', 'let viminit_found="yes"')
+ exe "silent !" . cmd
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ call delete('Xafter')
+endfunc
+
+" Test for using the $EXINIT environment variable
+func Test_EXINIT()
+ let after =<< trim [CODE]
+ call assert_equal(1, exists('exinit_found'))
+ call assert_equal('yes', exinit_found)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ call writefile(after, 'Xafter')
+ " let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
+ let cmd = GetVimProg() . ' -S Xafter --cmd "set enc=utf8"'
+ call setenv('EXINIT', 'let exinit_found="yes"')
+ exe "silent !" . cmd
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ call delete('Xafter')
+endfunc
+
+" Test for using the 'exrc' option
+func Test_exrc()
+ let after =<< trim [CODE]
+ call assert_equal(1, &exrc)
+ call assert_equal(1, &secure)
+ call assert_equal(37, exrc_found)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ call mkdir('Xdir')
+ call writefile(['let exrc_found=37'], 'Xdir/.exrc')
+ call writefile(after, 'Xdir/Xafter')
+ " let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "cd Xdir" --cmd "set enc=utf8 exrc secure"'
+ let cmd = GetVimProg() . ' -S Xafter --cmd "cd Xdir" --cmd "set enc=utf8 exrc secure"'
+ exe "silent !" . cmd
+ call assert_equal([], readfile('Xdir/Xtestout'))
+ call delete('Xdir', 'rf')
+endfunc
+
+" Test for starting Vim with a non-terminal as input/output
+func Test_io_not_a_terminal()
+ throw 'Skipped: Nvim does not support --ttyfail'
+ " Can't catch the output of gvim.
+ CheckNotGui
+ CheckUnix
+ CheckEnglish
+ let l = systemlist(GetVimProg() .. ' --ttyfail')
+ call assert_equal(['Vim: Warning: Output is not to a terminal',
+ \ 'Vim: Warning: Input is not from a terminal'], l)
+endfunc
+
" Test for --not-a-term avoiding escape codes.
func Test_not_a_term()
CheckUnix
@@ -948,6 +1103,93 @@ func Test_w_arg()
call delete('Xscriptin')
endfunc
+" Test for the "-s scriptin" argument
+func Test_s_arg()
+ " Can't catch the output of gvim.
+ CheckNotGui
+ CheckEnglish
+ " Test for failing to open the script input file.
+ let m = system(GetVimCommand() .. " -s abcxyz")
+ " call assert_equal("Cannot open for reading: \"abcxyz\"\n", m)
+ call assert_equal("Cannot open for reading: \"abcxyz\": no such file or directory\n", m)
+
+ call writefile([], 'Xinput')
+ let m = system(GetVimCommand() .. " -s Xinput -s Xinput")
+ call assert_equal("Attempt to open script file again: \"-s Xinput\"\n", m)
+ call delete('Xinput')
+endfunc
+
+" Test for the "-n" (no swap file) argument
+func Test_n_arg()
+ let after =<< trim [CODE]
+ call assert_equal(0, &updatecount)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ if RunVim([], after, '-n')
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for the "-h" (help) argument
+func Test_h_arg()
+ throw 'Skipped: Nvim has different output for "-h" argument'
+ " Can't catch the output of gvim.
+ CheckNotGui
+ let l = systemlist(GetVimProg() .. ' -h')
+ call assert_match('^VIM - Vi IMproved', l[0])
+ let l = systemlist(GetVimProg() .. ' -?')
+ call assert_match('^VIM - Vi IMproved', l[0])
+endfunc
+
+" Test for the "-F" (farsi) argument
+func Test_F_arg()
+ throw 'Skipped: Nvim does not recognize "-F" argument'
+ " Can't catch the output of gvim.
+ CheckNotGui
+ let l = systemlist(GetVimProg() .. ' -F')
+ call assert_match('^E27:', l[0])
+endfunc
+
+" Test for the "-E" (improved Ex mode) argument
+func Test_E_arg()
+ let after =<< trim [CODE]
+ call assert_equal('cv', mode(1))
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ if RunVim([], after, '-E')
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for the "-D" (debugger) argument
+func Test_D_arg()
+ CheckRunVimInTerminal
+
+ let cmd = GetVimCommandCleanTerm() .. ' -D'
+ let buf = term_start(cmd, {'term_rows' : 10})
+ call WaitForAssert({-> assert_equal("running", term_getstatus(buf))})
+
+ call WaitForAssert({-> assert_equal('Entering Debug mode. Type "cont" to continue.',
+ \ term_getline(buf, 7))})
+ call WaitForAssert({-> assert_equal('>', term_getline(buf, 10))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test for too many edit argument errors
+func Test_too_many_edit_args()
+ throw 'Skipped: N/A'
+ " Can't catch the output of gvim.
+ CheckNotGui
+ CheckEnglish
+ let l = systemlist(GetVimProg() .. ' - -')
+ call assert_match('^Too many edit arguments: "-"', l[1])
+endfunc
+
" Test starting vim with various names: vim, ex, view, evim, etc.
func Test_progname()
CheckUnix
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index ec35fac964..6bde052442 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -11,6 +11,10 @@ func SetUp()
set laststatus=2
endfunc
+func TearDown()
+ set laststatus&
+endfunc
+
func s:get_statusline()
return ScreenLines(&lines - 1, &columns)[0]
endfunc
@@ -39,7 +43,6 @@ endfunc
func Test_caught_error_in_statusline()
let s:func_in_statusline_called = 0
- set laststatus=2
let statusline = '%{StatuslineWithCaughtError()}'
let &statusline = statusline
redrawstatus
@@ -50,7 +53,6 @@ endfunc
func Test_statusline_will_be_disabled_with_error()
let s:func_in_statusline_called = 0
- set laststatus=2
let statusline = '%{StatuslineWithError()}'
try
let &statusline = statusline
@@ -77,7 +79,6 @@ func Test_statusline()
call assert_match('^ ((2) of 2)\s*$', s:get_statusline())
only
- set laststatus=2
set splitbelow
call setline(1, range(1, 10000))
@@ -436,7 +437,6 @@ func Test_statusline()
%bw!
call delete('Xstatusline')
set statusline&
- set laststatus&
set splitbelow&
endfunc
@@ -524,7 +524,6 @@ endfunc
" with a custom 'statusline'
func Test_statusline_mbyte_fillchar()
only
- set laststatus=2
set fillchars=vert:\|,fold:-,stl:━,stlnc:═
set statusline=a%=b
call assert_match('^a\+━\+b$', s:get_statusline())
@@ -532,7 +531,7 @@ func Test_statusline_mbyte_fillchar()
call assert_match('^a\+━\+b━a\+═\+b$', s:get_statusline())
wincmd w
call assert_match('^a\+═\+b═a\+━\+b$', s:get_statusline())
- set statusline& fillchars& laststatus&
+ set statusline& fillchars&
%bw!
endfunc
diff --git a/src/nvim/testdir/test_syn_attr.vim b/src/nvim/testdir/test_syn_attr.vim
index fa0b08fde5..88f9d0d84d 100644
--- a/src/nvim/testdir/test_syn_attr.vim
+++ b/src/nvim/testdir/test_syn_attr.vim
@@ -1,19 +1,39 @@
" Test syntax highlighting functions.
func Test_missing_attr()
- hi Mine cterm=italic
+ throw 'Skipped: use test/functional/legacy/syn_attr_spec.lua'
+
+ hi Mine term=bold cterm=italic
call assert_equal('Mine', synIDattr(hlID("Mine"), "name"))
+ call assert_equal('', synIDattr("Mine"->hlID(), "bg", 'term'))
+ call assert_equal('', synIDattr("Mine"->hlID(), "fg", 'term'))
+ call assert_equal('', synIDattr("Mine"->hlID(), "sp", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "bold", 'term'))
call assert_equal('1', synIDattr(hlID("Mine"), "italic", 'cterm'))
- hi Mine cterm=inverse
+ hi Mine term=reverse cterm=inverse
+ call assert_equal('1', synIDattr(hlID("Mine"), "reverse", 'term'))
call assert_equal('1', synIDattr(hlID("Mine"), "inverse", 'cterm'))
- hi Mine cterm=standout gui=undercurl
+
+ hi Mine term=underline cterm=standout gui=undercurl
+ call assert_equal('1', synIDattr(hlID("Mine"), "underline", 'term'))
call assert_equal('1', synIDattr(hlID("Mine"), "standout", 'cterm'))
call assert_equal('1', synIDattr("Mine"->hlID(), "undercurl", 'gui'))
- hi Mine gui=strikethrough
+
+ hi Mine term=underdouble cterm=underdotted gui=underdashed
+ call assert_equal('1', synIDattr(hlID("Mine"), "underdouble", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "underdotted", 'cterm'))
+ call assert_equal('1', synIDattr("Mine"->hlID(), "underdashed", 'gui'))
+
+ hi Mine term=nocombine gui=strikethrough
call assert_equal('1', synIDattr(hlID("Mine"), "strikethrough", 'gui'))
- hi Mine cterm=NONE gui=NONE
+ call assert_equal('1', synIDattr(hlID("Mine"), "nocombine", 'term'))
+ call assert_equal('', synIDattr(hlID("Mine"), "nocombine", 'gui'))
+ hi Mine term=NONE cterm=NONE gui=NONE
+ call assert_equal('', synIDattr(hlID("Mine"), "bold", 'term'))
call assert_equal('', synIDattr(hlID("Mine"), "italic", 'cterm'))
+ call assert_equal('', synIDattr(hlID("Mine"), "reverse", 'term'))
call assert_equal('', synIDattr(hlID("Mine"), "inverse", 'cterm'))
+ call assert_equal('', synIDattr(hlID("Mine"), "underline", 'term'))
call assert_equal('', synIDattr(hlID("Mine"), "standout", 'cterm'))
call assert_equal('', synIDattr(hlID("Mine"), "undercurl", 'gui'))
call assert_equal('', synIDattr(hlID("Mine"), "strikethrough", 'gui'))
diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim
index c0712aa892..eda485c512 100644
--- a/src/nvim/testdir/test_termcodes.vim
+++ b/src/nvim/testdir/test_termcodes.vim
@@ -33,28 +33,5 @@ func Test_special_term_keycodes()
bw!
endfunc
-func Test_simplify_ctrl_at()
- " feeding unsimplified CTRL-@ should still trigger i_CTRL-@
- call feedkeys("ifoo\<Esc>A\<*C-@>x", 'xt')
- call assert_equal('foofo', getline(1))
- bw!
-endfunc
-
-func Test_simplify_noremap()
- call feedkeys("i\<*C-M>", 'nx')
- call assert_equal('', getline(1))
- call assert_equal([0, 2, 1, 0, 1], getcurpos())
- bw!
-endfunc
-
-func Test_simplify_timedout()
- inoremap <C-M>a b
- call feedkeys("i\<*C-M>", 'xt')
- call assert_equal('', getline(1))
- call assert_equal([0, 2, 1, 0, 1], getcurpos())
- iunmap <C-M>a
- bw!
-endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 970f5ae0d0..0fc56083aa 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -1260,6 +1260,41 @@ func Test_comment_nested()
%bw!
endfunc
+" Test for a space character in 'comments' setting
+func Test_comment_space()
+ new
+ setlocal comments=b:\ > fo+=ro
+ exe "normal i> B\nD\<C-C>ggOA\<C-C>joC"
+ exe "normal Go > F\nH\<C-C>kOE\<C-C>joG"
+ let expected =<< trim END
+ A
+ > B
+ C
+ D
+ > E
+ > F
+ > G
+ > H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ %bw!
+endfunc
+
+" Test for the 'O' flag in 'comments'
+func Test_comment_O()
+ new
+ setlocal comments=Ob:* fo+=ro
+ exe "normal i* B\nD\<C-C>kOA\<C-C>joC"
+ let expected =<< trim END
+ A
+ * B
+ * C
+ * D
+ END
+ call assert_equal(expected, getline(1, '$'))
+ %bw!
+endfunc
+
" Test for 'a' and 'w' flags in 'formatoptions'
func Test_fo_a_w()
new
@@ -1299,6 +1334,25 @@ func Test_fo_a_w()
%bw!
endfunc
+" Test for 'j' flag in 'formatoptions'
+func Test_fo_j()
+ new
+ setlocal fo+=j comments=://
+ call setline(1, ['i++; // comment1', ' // comment2'])
+ normal J
+ call assert_equal('i++; // comment1 comment2', getline(1))
+ setlocal fo-=j
+ call setline(1, ['i++; // comment1', ' // comment2'])
+ normal J
+ call assert_equal('i++; // comment1 // comment2', getline(1))
+ " Test with nested comments
+ setlocal fo+=j comments=n:>,n:)
+ call setline(1, ['i++; > ) > ) comment1', ' > ) comment2'])
+ normal J
+ call assert_equal('i++; > ) > ) comment1 comment2', getline(1))
+ %bw!
+endfunc
+
" Test for formatting lines using gq in visual mode
func Test_visual_gq_format()
new
@@ -1480,4 +1534,16 @@ func Test_autoformat_comments()
close!
endfunc
+" This was leaving the cursor after the end of a line. Complicated way to
+" have the problem show up with valgrind.
+func Test_correct_cursor_position()
+ " set encoding=iso8859
+ new
+ norm a000“0
+ sil! norm gggg0i0gw0gg
+
+ bwipe!
+ set encoding=utf8
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 56a5ec96af..6adf503f14 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -337,7 +337,7 @@ endfunc
" Test that the garbage collector isn't triggered if a timer callback invokes
" vgetc().
-func Test_timer_nocatch_garbage_collect()
+func Test_nocatch_timer_garbage_collect()
" skipped: Nvim does not support test_garbagecollect_soon(), test_override()
return
" 'uptimetime. must be bigger than the timer timeout
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index 598402fafe..646594e482 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -2014,11 +2014,11 @@ endfunc
" Test for verbose messages with :try :catch, and :finally {{{1
func Test_try_catch_verbose()
" This test works only when the language is English
- if v:lang != "C" && v:lang !~ '^[Ee]n'
- return
- endif
+ CheckEnglish
set verbose=14
+
+ " Test for verbose messages displayed when an exception is caught
redir => msg
try
echo i
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index 1323288676..de4629451b 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1661,16 +1661,25 @@ func Test_compound_assignment_operators()
call assert_equal(6, &scrolljump)
let &scrolljump %= 5
call assert_equal(1, &scrolljump)
- call assert_fails('let &scrolljump .= "j"', 'E734')
+ call assert_fails('let &scrolljump .= "j"', 'E734:')
set scrolljump&vim
+ let &foldlevelstart = 2
+ let &foldlevelstart -= 1
+ call assert_equal(1, &foldlevelstart)
+ let &foldlevelstart -= 1
+ call assert_equal(0, &foldlevelstart)
+ let &foldlevelstart = 2
+ let &foldlevelstart -= 2
+ call assert_equal(0, &foldlevelstart)
+
" Test for register
let @/ = 1
- call assert_fails('let @/ += 1', 'E734')
- call assert_fails('let @/ -= 1', 'E734')
- call assert_fails('let @/ *= 1', 'E734')
- call assert_fails('let @/ /= 1', 'E734')
- call assert_fails('let @/ %= 1', 'E734')
+ call assert_fails('let @/ += 1', 'E734:')
+ call assert_fails('let @/ -= 1', 'E734:')
+ call assert_fails('let @/ *= 1', 'E734:')
+ call assert_fails('let @/ /= 1', 'E734:')
+ call assert_fails('let @/ %= 1', 'E734:')
let @/ .= 's'
call assert_equal('1s', @/)
let @/ = ''
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 7decac2c36..83a3216534 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -1074,7 +1074,6 @@ func Test_split_cmds_with_no_room()
endfunc
func Test_window_resize()
- throw 'Skipped: Nvim supports cmdheight=0'
" Vertical :resize (absolute, relative, min and max size).
vsplit
vert resize 8
@@ -1360,7 +1359,6 @@ func Test_win_move_separator()
endfunc
func Test_win_move_statusline()
- redraw " This test fails in Nvim without a redraw to clear messages.
edit a
leftabove split b
let h = winheight(0)
@@ -1391,11 +1389,9 @@ func Test_win_move_statusline()
call assert_equal(h0, winheight(0))
call assert_equal(1, &cmdheight)
endfor
- " Nvim supports cmdheight=0
+ " supports cmdheight=0
set cmdheight=0
call assert_true(win_move_statusline(0, 1))
- "call assert_equal(h0, winheight(0))
- "call assert_equal(1, &cmdheight)
call assert_equal(h0 + 1, winheight(0))
call assert_equal(0, &cmdheight)
set cmdheight&
diff --git a/src/nvim/testing.h b/src/nvim/testing.h
index 1522ebc7b7..69596d725c 100644
--- a/src/nvim/testing.h
+++ b/src/nvim/testing.h
@@ -1,7 +1,6 @@
#ifndef NVIM_TESTING_H
#define NVIM_TESTING_H
-#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/types.h b/src/nvim/types.h
index 73cd2204d6..00b9e6fc09 100644
--- a/src/nvim/types.h
+++ b/src/nvim/types.h
@@ -22,6 +22,8 @@ typedef int handle_T;
// absent callback etc.
typedef int LuaRef;
+typedef void (*FunPtr)(void);
+
typedef handle_T NS;
typedef struct expand expand_T;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index a49e9df9ee..4fcfee1192 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -348,7 +348,8 @@ void ui_attach_impl(UI *ui, uint64_t chanid)
if (ui_count == MAX_UI_COUNT) {
abort();
}
- if (!ui->ui_ext[kUIMultigrid] && !ui->ui_ext[kUIFloatDebug]) {
+ if (!ui->ui_ext[kUIMultigrid] && !ui->ui_ext[kUIFloatDebug]
+ && !ui_client_channel_id) {
ui_comp_attach(ui);
}
@@ -502,6 +503,9 @@ handle_T ui_cursor_grid(void)
void ui_flush(void)
{
+ if (!ui_active()) {
+ return;
+ }
cmdline_ui_flush();
win_ui_flush();
msg_ext_ui_flush();
@@ -608,6 +612,12 @@ bool ui_has(UIExtension ext)
return ui_ext[ext];
}
+/// Returns true if the UI has messages area.
+bool ui_has_messages(void)
+{
+ return p_ch > 0 || ui_has(kUIMessages);
+}
+
Array ui_array(void)
{
Array all_uis = ARRAY_DICT_INIT;
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index be01538f67..a586fec3bf 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -22,11 +22,6 @@
# include "ui_events_client.generated.h"
#endif
-// Temporary buffer for converting a single grid_line event
-static size_t buf_size = 0;
-static schar_T *buf_char = NULL;
-static sattr_T *buf_attr = NULL;
-
void ui_client_init(uint64_t chan)
{
Array args = ARRAY_DICT_INIT;
@@ -46,37 +41,23 @@ void ui_client_init(uint64_t chan)
ui_client_channel_id = chan;
}
-/// Handler for "redraw" events sent by the NVIM server
-///
-/// This function will be called by handle_request (in msgpack_rpc/channel.c)
-/// The individual ui_events sent by the server are individually handled
-/// by their respective handlers defined in ui_events_client.generated.h
-///
-/// @note The "flush" event is called only once and only after handling all
-/// the other events
-/// @param channel_id: The id of the rpc channel
-/// @param uidata: The dense array containing the ui_events sent by the server
-/// @param[out] err Error details, if any
-Object handle_ui_client_redraw(uint64_t channel_id, Array args, Error *error)
+UIClientHandler ui_client_get_redraw_handler(const char *name, size_t name_len, Error *error)
{
- for (size_t i = 0; i < args.size; i++) {
- Array call = args.items[i].data.array;
- String name = call.items[0].data.string;
-
- int hash = ui_client_handler_hash(name.data, name.size);
- if (hash < 0) {
- ELOG("No ui client handler for %s", name.size ? name.data : "<empty>");
- continue;
- }
- UIClientHandler handler = event_handlers[hash];
-
- // fprintf(stderr, "%s: %zu\n", name.data, call.size-1);
- DLOG("Invoke ui client handler for %s", name.data);
- for (size_t j = 1; j < call.size; j++) {
- handler.fn(call.items[j].data.array);
- }
+ int hash = ui_client_handler_hash(name, name_len);
+ if (hash < 0) {
+ return (UIClientHandler){ NULL, NULL };
}
+ return event_handlers[hash];
+}
+/// Placeholder for _sync_ requests with 'redraw' method name
+///
+/// async 'redraw' events, which are expected when nvim acts as an ui client.
+/// get handled in msgpack_rpc/unpacker.c and directly dispatched to handlers
+/// of specific ui events, like ui_client_event_grid_resize and so on.
+Object handle_ui_client_redraw(uint64_t channel_id, Array args, Error *error)
+{
+ api_set_error(error, kErrorTypeValidation, "'redraw' cannot be sent as a request");
return NIL;
}
@@ -120,88 +101,30 @@ void ui_client_event_grid_resize(Array args)
Integer height = args.items[2].data.integer;
ui_call_grid_resize(grid, width, height);
- if (buf_size < (size_t)width) {
- xfree(buf_char);
- xfree(buf_attr);
- buf_size = (size_t)width;
- buf_char = xmalloc(buf_size * sizeof(schar_T));
- buf_attr = xmalloc(buf_size * sizeof(sattr_T));
+ if (grid_line_buf_size < (size_t)width) {
+ xfree(grid_line_buf_char);
+ xfree(grid_line_buf_attr);
+ grid_line_buf_size = (size_t)width;
+ grid_line_buf_char = xmalloc(grid_line_buf_size * sizeof(schar_T));
+ grid_line_buf_attr = xmalloc(grid_line_buf_size * sizeof(sattr_T));
}
}
void ui_client_event_grid_line(Array args)
+ FUNC_ATTR_NORETURN
{
- if (args.size < 4
- || args.items[0].type != kObjectTypeInteger
- || args.items[1].type != kObjectTypeInteger
- || args.items[2].type != kObjectTypeInteger
- || args.items[3].type != kObjectTypeArray) {
- goto error;
- }
+ abort(); // unreachable
+}
- Integer grid = args.items[0].data.integer;
- Integer row = args.items[1].data.integer;
- Integer startcol = args.items[2].data.integer;
- Array cells = args.items[3].data.array;
+void ui_client_event_raw_line(GridLineEvent *g)
+{
+ int grid = g->args[0], row = g->args[1], startcol = g->args[2];
+ Integer endcol = startcol + g->coloff;
+ Integer clearcol = endcol + g->clear_width;
// TODO(hlpr98): Accommodate other LineFlags when included in grid_line
LineFlags lineflags = 0;
- size_t j = 0;
- int cur_attr = 0;
- int clear_attr = 0;
- int clear_width = 0;
- for (size_t i = 0; i < cells.size; i++) {
- if (cells.items[i].type != kObjectTypeArray) {
- goto error;
- }
- Array cell = cells.items[i].data.array;
-
- if (cell.size < 1 || cell.items[0].type != kObjectTypeString) {
- goto error;
- }
- String sstring = cell.items[0].data.string;
-
- char *schar = sstring.data;
- int repeat = 1;
- if (cell.size >= 2) {
- if (cell.items[1].type != kObjectTypeInteger
- || cell.items[1].data.integer < 0) {
- goto error;
- }
- cur_attr = (int)cell.items[1].data.integer;
- }
-
- if (cell.size >= 3) {
- if (cell.items[2].type != kObjectTypeInteger
- || cell.items[2].data.integer < 0) {
- goto error;
- }
- repeat = (int)cell.items[2].data.integer;
- }
-
- if (i == cells.size - 1 && sstring.size == 1 && sstring.data[0] == ' ' && repeat > 1) {
- clear_width = repeat;
- break;
- }
-
- for (int r = 0; r < repeat; r++) {
- if (j >= buf_size) {
- goto error; // _YIKES_
- }
- STRLCPY(buf_char[j], schar, sizeof(schar_T));
- buf_attr[j++] = cur_attr;
- }
- }
-
- Integer endcol = startcol + (int)j;
- Integer clearcol = endcol + clear_width;
- clear_attr = cur_attr;
-
- ui_call_raw_line(grid, row, startcol, endcol, clearcol, clear_attr, lineflags,
- (const schar_T *)buf_char, (const sattr_T *)buf_attr);
- return;
-
-error:
- ELOG("Error handling ui event 'grid_line'");
+ ui_call_raw_line(grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
+ (const schar_T *)grid_line_buf_char, grid_line_buf_attr);
}
diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h
index 41d9fa6227..311dafaa0b 100644
--- a/src/nvim/ui_client.h
+++ b/src/nvim/ui_client.h
@@ -2,12 +2,18 @@
#define NVIM_UI_CLIENT_H
#include "nvim/api/private/defs.h"
+#include "nvim/grid_defs.h"
typedef struct {
const char *name;
void (*fn)(Array args);
} UIClientHandler;
+// Temporary buffer for converting a single grid_line event
+EXTERN size_t grid_line_buf_size INIT(= 0);
+EXTERN schar_T *grid_line_buf_char INIT(= NULL);
+EXTERN sattr_T *grid_line_buf_attr INIT(= NULL);
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_client.h.generated.h"
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 8324db37c6..45c083b034 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2765,7 +2765,7 @@ void ex_undolist(exarg_T *eap)
if (GA_EMPTY(&ga)) {
msg(_("Nothing to undo"));
} else {
- sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ sort_strings(ga.ga_data, ga.ga_len);
msg_start();
msg_puts_attr(_("number changes when saved"),
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 2bffe2055f..abb277bd23 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -13,6 +13,7 @@
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
@@ -171,7 +172,7 @@ void do_window(int nchar, long Prenum, int xchar)
CHECK_CMDWIN;
reset_VIsual_and_resel(); // stop Visual mode
- if (buflist_findnr(Prenum == 0 ? curwin->w_alt_fnum : Prenum) == NULL) {
+ if (buflist_findnr(Prenum == 0 ? curwin->w_alt_fnum : (int)Prenum) == NULL) {
if (Prenum == 0) {
emsg(_(e_noalt));
} else {
@@ -181,7 +182,7 @@ void do_window(int nchar, long Prenum, int xchar)
}
if (!curbuf_locked() && win_split(0, 0) == OK) {
- (void)buflist_getfile(Prenum == 0 ? curwin->w_alt_fnum : Prenum,
+ (void)buflist_getfile(Prenum == 0 ? curwin->w_alt_fnum : (int)Prenum,
(linenr_T)0, GETF_ALT, false);
}
break;
@@ -451,9 +452,9 @@ newwindow:
case '}':
CHECK_CMDWIN;
if (Prenum) {
- g_do_tagpreview = Prenum;
+ g_do_tagpreview = (int)Prenum;
} else {
- g_do_tagpreview = p_pvh;
+ g_do_tagpreview = (int)p_pvh;
}
FALLTHROUGH;
case ']':
@@ -461,7 +462,7 @@ newwindow:
CHECK_CMDWIN;
// Keep visual mode, can select words to use as a tag.
if (Prenum) {
- postponed_split = Prenum;
+ postponed_split = (int)Prenum;
} else {
postponed_split = -1;
}
@@ -550,16 +551,16 @@ wingotofile:
case '}':
xchar = Ctrl_RSB;
if (Prenum) {
- g_do_tagpreview = Prenum;
+ g_do_tagpreview = (int)Prenum;
} else {
- g_do_tagpreview = p_pvh;
+ g_do_tagpreview = (int)p_pvh;
}
FALLTHROUGH;
case ']':
case Ctrl_RSB:
// Keep visual mode, can select words to use as a tag.
if (Prenum) {
- postponed_split = Prenum;
+ postponed_split = (int)Prenum;
} else {
postponed_split = -1;
}
@@ -725,31 +726,31 @@ void win_set_minimal_style(win_T *wp)
wp->w_p_fcs = ((*old == NUL)
? (char_u *)xstrdup("eob: ")
: concat_str(old, (char_u *)",eob: "));
- xfree(old);
+ free_string_option(old);
}
if (wp->w_hl_ids[HLF_EOB] != -1) {
char_u *old = wp->w_p_winhl;
wp->w_p_winhl = ((*old == NUL)
? (char_u *)xstrdup("EndOfBuffer:")
: concat_str(old, (char_u *)",EndOfBuffer:"));
- xfree(old);
+ free_string_option(old);
}
// signcolumn: use 'auto'
if (wp->w_p_scl[0] != 'a' || STRLEN(wp->w_p_scl) >= 8) {
- xfree(wp->w_p_scl);
+ free_string_option(wp->w_p_scl);
wp->w_p_scl = (char_u *)xstrdup("auto");
}
// foldcolumn: use '0'
if (wp->w_p_fdc[0] != '0') {
- xfree(wp->w_p_fdc);
+ free_string_option(wp->w_p_fdc);
wp->w_p_fdc = (char_u *)xstrdup("0");
}
// colorcolumn: cleared
if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) {
- xfree(wp->w_p_cc);
+ free_string_option(wp->w_p_cc);
wp->w_p_cc = (char_u *)xstrdup("");
}
}
@@ -799,8 +800,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
// compute initial position
if (wp->w_float_config.relative == kFloatRelativeWindow) {
- int row = wp->w_float_config.row;
- int col = wp->w_float_config.col;
+ int row = (int)wp->w_float_config.row;
+ int col = (int)wp->w_float_config.col;
Error dummy = ERROR_INIT;
win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
if (parent) {
@@ -824,8 +825,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
wp->w_winrow = row;
wp->w_wincol = col;
} else {
- wp->w_winrow = fconfig.row;
- wp->w_wincol = fconfig.col;
+ wp->w_winrow = (int)fconfig.row;
+ wp->w_wincol = (int)fconfig.col;
}
// changing border style while keeping border only requires redrawing border
@@ -1064,10 +1065,10 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
* width.
*/
// Current window requires at least 1 space.
- wmw1 = (p_wmw == 0 ? 1 : p_wmw);
+ wmw1 = (p_wmw == 0 ? 1 : (int)p_wmw);
needed = wmw1 + 1;
if (flags & WSP_ROOM) {
- needed += p_wiw - wmw1;
+ needed += (int)p_wiw - wmw1;
}
if (flags & (WSP_BOT | WSP_TOP)) {
minwidth = frame_minwidth(topframe, NOWIN);
@@ -1141,10 +1142,10 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// Check if we are able to split the current window and compute its height.
// Current window requires at least 1 space plus space for the window bar.
- wmh1 = MAX(p_wmh, 1) + oldwin->w_winbar_height;
+ wmh1 = MAX((int)p_wmh, 1) + oldwin->w_winbar_height;
needed = wmh1 + STATUS_HEIGHT;
if (flags & WSP_ROOM) {
- needed += p_wh - wmh1 + oldwin->w_winbar_height;
+ needed += (int)p_wh - wmh1 + oldwin->w_winbar_height;
}
if (p_ch < 1) {
needed += 1; // Adjust for cmdheight=0.
@@ -1304,7 +1305,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// Need to create a new frame in the tree to make a branch.
frp = xcalloc(1, sizeof(frame_T));
*frp = *curfrp;
- curfrp->fr_layout = layout;
+ curfrp->fr_layout = (char)layout;
frp->fr_parent = curfrp;
frp->fr_next = NULL;
frp->fr_prev = NULL;
@@ -1489,20 +1490,17 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// Don't change the window height/width to 'winheight' / 'winwidth' if a
// size was given.
if (flags & WSP_VERT) {
- i = p_wiw;
+ i = (int)p_wiw;
if (size != 0) {
p_wiw = size;
}
} else {
- i = p_wh;
+ i = (int)p_wh;
if (size != 0) {
p_wh = size;
}
}
- // Keep same changelist position in new window.
- wp->w_changelistidx = oldwin->w_changelistidx;
-
// make the new window the current window
win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS
| WEE_TRIGGER_LEAVE_AUTOCMDS);
@@ -1573,6 +1571,10 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
}
newp->w_tagstackidx = oldp->w_tagstackidx;
newp->w_tagstacklen = oldp->w_tagstacklen;
+
+ // Keep same changelist position in new window.
+ newp->w_changelistidx = oldp->w_changelistidx;
+
copyFoldingState(oldp, newp);
win_init_some(newp, oldp);
@@ -1687,14 +1689,14 @@ int make_windows(int count, bool vertical)
if (vertical) {
// Each window needs at least 'winminwidth' lines and a separator column.
- maxcount = (curwin->w_width + curwin->w_vsep_width
- - (p_wiw - p_wmw)) / (p_wmw + 1);
+ maxcount = (int)(curwin->w_width + curwin->w_vsep_width
+ - (p_wiw - p_wmw)) / ((int)p_wmw + 1);
} else {
// Each window needs at least 'winminheight' lines.
// If statusline isn't global, each window also needs a statusline.
// If 'winbar' is set, each window also needs a winbar.
- maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT + global_winbar_height());
+ maxcount = (int)(curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
+ - (p_wh - p_wmh)) / ((int)p_wmh + STATUS_HEIGHT + global_winbar_height());
}
if (maxcount < 2) {
@@ -2037,10 +2039,10 @@ void win_move_after(win_T *win1, win_T *win2)
static int get_maximum_wincount(frame_T *fr, int height)
{
if (fr->fr_layout != FR_COL) {
- return (height / (p_wmh + STATUS_HEIGHT + frame2win(fr)->w_winbar_height));
+ return (height / ((int)p_wmh + STATUS_HEIGHT + frame2win(fr)->w_winbar_height));
} else if (global_winbar_height()) {
// If winbar is globally enabled, no need to check each window for it.
- return (height / (p_wmh + STATUS_HEIGHT + 1));
+ return (height / ((int)p_wmh + STATUS_HEIGHT + 1));
}
frame_T *frp;
@@ -2053,13 +2055,13 @@ static int get_maximum_wincount(frame_T *fr, int height)
if (height < (p_wmh + STATUS_HEIGHT + wp->w_winbar_height)) {
break;
}
- height -= p_wmh + STATUS_HEIGHT + wp->w_winbar_height;
+ height -= (int)p_wmh + STATUS_HEIGHT + wp->w_winbar_height;
total_wincount += 1;
}
// If we still have enough room for more windows, just use the default winbar height (which is 0)
// in order to get the amount of windows that'd fit in the remaining space
- total_wincount += height / (p_wmh + STATUS_HEIGHT);
+ total_wincount += height / ((int)p_wmh + STATUS_HEIGHT);
return total_wincount;
}
@@ -2132,7 +2134,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmw + 1);
+ totwincount = (n + extra_sep) / ((int)p_wmw + 1);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2143,29 +2145,27 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
m = frame_minwidth(topfr, next_curwin);
room = width - m;
if (room < 0) {
- next_curwin_size = p_wiw + room;
+ next_curwin_size = (int)p_wiw + room;
room = 0;
} else {
next_curwin_size = -1;
FOR_ALL_FRAMES(fr, topfr->fr_child) {
- // If 'winfixwidth' set keep the window width if
- // possible.
- // Watch out for this window being the next_curwin.
if (!frame_fixed_width(fr)) {
continue;
}
+ // If 'winfixwidth' set keep the window width if possible.
+ // Watch out for this window being the next_curwin.
n = frame_minwidth(fr, NOWIN);
new_size = fr->fr_width;
if (frame_has_win(fr, next_curwin)) {
- room += p_wiw - p_wmw;
+ room += (int)p_wiw - (int)p_wmw;
next_curwin_size = 0;
if (new_size < p_wiw) {
- new_size = p_wiw;
+ new_size = (int)p_wiw;
}
} else {
// These windows don't use up room.
- totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmw + 1);
+ totwincount -= (n + (fr->fr_next == NULL ? extra_sep : 0)) / ((int)p_wmw + 1);
}
room -= new_size - n;
if (room < 0) {
@@ -2182,12 +2182,12 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
/ (totwincount - 1) > p_wiw) {
// Can make all windows wider than 'winwidth', spread
// the room equally.
- next_curwin_size = (room + p_wiw
- + (totwincount - 1) * p_wmw
- + (totwincount - 1)) / totwincount;
- room -= next_curwin_size - p_wiw;
+ next_curwin_size = (int)(room + p_wiw
+ + (totwincount - 1) * p_wmw
+ + (totwincount - 1)) / totwincount;
+ room -= next_curwin_size - (int)p_wiw;
} else {
- next_curwin_size = p_wiw;
+ next_curwin_size = (int)p_wiw;
}
}
}
@@ -2210,8 +2210,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// Compute the maximum number of windows horiz. in "fr".
n = frame_minwidth(fr, NOWIN);
- wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmw + 1);
+ wincount = (n + (fr->fr_next == NULL ? extra_sep : 0)) / ((int)p_wmw + 1);
m = frame_minwidth(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -2227,7 +2226,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
new_size = (wincount * room + (totwincount / 2)) / totwincount;
}
if (hnc) { // add next_curwin size
- next_curwin_size -= p_wiw - (m - n);
+ next_curwin_size -= (int)p_wiw - (m - n);
new_size += next_curwin_size;
room -= new_size - next_curwin_size;
} else {
@@ -2276,24 +2275,23 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
if (room < 0) {
// The room is less than 'winheight', use all space for the
// current window.
- next_curwin_size = p_wh + room;
+ next_curwin_size = (int)p_wh + room;
room = 0;
} else {
next_curwin_size = -1;
FOR_ALL_FRAMES(fr, topfr->fr_child) {
- // If 'winfixheight' set keep the window height if
- // possible.
- // Watch out for this window being the next_curwin.
if (!frame_fixed_height(fr)) {
continue;
}
+ // If 'winfixheight' set keep the window height if possible.
+ // Watch out for this window being the next_curwin.
n = frame_minheight(fr, NOWIN);
new_size = fr->fr_height;
if (frame_has_win(fr, next_curwin)) {
- room += p_wh - p_wmh;
+ room += (int)p_wh - (int)p_wmh;
next_curwin_size = 0;
if (new_size < p_wh) {
- new_size = p_wh;
+ new_size = (int)p_wh;
}
} else {
// These windows don't use up room.
@@ -2314,12 +2312,12 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
/ (totwincount - 1) > p_wh) {
// can make all windows higher than 'winheight',
// spread the room equally.
- next_curwin_size = (room + p_wh
- + (totwincount - 1) * p_wmh
- + (totwincount - 1)) / totwincount;
- room -= next_curwin_size - p_wh;
+ next_curwin_size = (int)(room + p_wh
+ + (totwincount - 1) * p_wmh
+ + (totwincount - 1)) / totwincount;
+ room -= next_curwin_size - (int)p_wh;
} else {
- next_curwin_size = p_wh;
+ next_curwin_size = (int)p_wh;
}
}
}
@@ -2358,7 +2356,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
new_size = (wincount * room + (totwincount / 2)) / totwincount;
}
if (hnc) { // add next_curwin size
- next_curwin_size -= p_wh - (m - n);
+ next_curwin_size -= (int)p_wh - (m - n);
new_size += next_curwin_size;
room -= new_size - next_curwin_size;
} else {
@@ -3778,9 +3776,9 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
+ topfrp->fr_win->w_status_height;
if (topfrp->fr_win == next_curwin) {
- m = p_wh + extra_height;
+ m = (int)p_wh + extra_height;
} else {
- m = p_wmh + extra_height;
+ m = (int)p_wmh + extra_height;
if (topfrp->fr_win == curwin && next_curwin == NULL) {
// Current window is minimal one line high.
if (p_wmh == 0) {
@@ -3821,10 +3819,10 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin)
if (topfrp->fr_win != NULL) {
if (topfrp->fr_win == next_curwin) {
- m = p_wiw + topfrp->fr_win->w_vsep_width;
+ m = (int)p_wiw + topfrp->fr_win->w_vsep_width;
} else {
// window: minimal width of the window plus separator column
- m = p_wmw + topfrp->fr_win->w_vsep_width;
+ m = (int)p_wmw + topfrp->fr_win->w_vsep_width;
// Current window is minimal one column wide
if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL) {
++m;
@@ -3903,9 +3901,7 @@ void close_others(int message, int forceit)
continue;
}
}
- win_close(wp,
- !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer),
- false);
+ win_close(wp, !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer), false);
}
if (message && !ONE_WINDOW) {
@@ -3981,7 +3977,7 @@ static int win_alloc_firstwin(win_T *oldwin)
new_frame(curwin);
topframe = curwin->w_frame;
topframe->fr_width = Columns;
- topframe->fr_height = Rows - p_ch - global_stl_height();
+ topframe->fr_height = Rows - (int)p_ch - global_stl_height();
return OK;
}
@@ -4003,11 +3999,11 @@ static void new_frame(win_T *wp)
*/
void win_init_size(void)
{
- firstwin->w_height = ROWS_AVAIL;
+ firstwin->w_height = (int)ROWS_AVAIL;
firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
firstwin->w_height_outer = firstwin->w_height;
firstwin->w_winrow_off = firstwin->w_winbar_height;
- topframe->fr_height = ROWS_AVAIL;
+ topframe->fr_height = (int)ROWS_AVAIL;
firstwin->w_width = Columns;
firstwin->w_width_inner = firstwin->w_width;
firstwin->w_width_outer = firstwin->w_width;
@@ -4116,7 +4112,6 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_topframe = topframe;
last_status(false);
- set_winbar();
redraw_all_later(NOT_VALID);
@@ -4167,7 +4162,7 @@ int make_tabpages(int maxcount)
// Limit to 'tabpagemax' tabs.
if (count > p_tpm) {
- count = p_tpm;
+ count = (int)p_tpm;
}
/*
@@ -4303,7 +4298,7 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds)
tp->tp_prevwin = prevwin;
tp->tp_firstwin = firstwin;
tp->tp_lastwin = lastwin;
- tp->tp_old_Rows = Rows;
+ tp->tp_old_Rows_avail = ROWS_AVAIL;
tp->tp_old_Columns = Columns;
firstwin = NULL;
lastwin = NULL;
@@ -4343,10 +4338,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a
const int row = win_comp_pos(); // recompute w_winrow for all windows
diff_need_scrollbind = true;
- // The tabpage line may have appeared or disappeared, may need to resize
- // the frames for that. When the Vim window was resized need to update
- // frame sizes too. Use the stored value of p_ch, so that it can be
- // different for each tab page.
+ // Use the stored value of p_ch, so that it can be different for each tab page.
if (p_ch != curtab->tp_ch_used) {
clear_cmdline = true;
}
@@ -4359,7 +4351,9 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a
clear_cmdline = true;
}
- if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow)) {
+ // The tabpage line may have appeared or disappeared, may need to resize the frames for that.
+ // When the Vim window was resized or ROWS_AVAIL changed need to update frame sizes too.
+ if (curtab->tp_old_Rows_avail != ROWS_AVAIL || (old_off != firstwin->w_winrow)) {
win_new_screen_rows();
}
if (curtab->tp_old_Columns != Columns && starting == 0) {
@@ -5118,10 +5112,10 @@ static void win_free(win_T *wp, tabpage_T *tp)
xfree(wp->w_localdir);
xfree(wp->w_prevdir);
- stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ stl_clear_click_defs(wp->w_status_click_defs, (long)wp->w_status_click_defs_size);
xfree(wp->w_status_click_defs);
- stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ stl_clear_click_defs(wp->w_winbar_click_defs, (long)wp->w_winbar_click_defs_size);
xfree(wp->w_winbar_click_defs);
// Remove the window from the b_wininfo lists, it may happen that the
@@ -5503,7 +5497,7 @@ void win_setheight_win(int height, win_T *win)
{
// Always keep current window at least one line high, even when 'winminheight' is zero.
// Keep window at least two lines high if 'winbar' is enabled.
- height = MAX(height, (win == curwin ? MAX(p_wmh, 1) : p_wmh) + win->w_winbar_height);
+ height = MAX(height, (int)(win == curwin ? MAX(p_wmh, 1) : p_wmh) + win->w_winbar_height);
if (win->w_floating) {
win->w_float_config.height = height;
@@ -5566,7 +5560,7 @@ static void frame_setheight(frame_T *curfrp, int height)
// If height is greater than the available space, try to create space for
// the frame by reducing 'cmdheight' if possible, while making sure
// `cmdheight` doesn't go below 1.
- height = MIN((p_ch > 0 ? ROWS_AVAIL + (p_ch - 1) : ROWS_AVAIL), height);
+ height = (int)MIN((p_ch > 0 ? ROWS_AVAIL + (p_ch - 1) : ROWS_AVAIL), height);
}
if (height > 0) {
frame_new_height(curfrp, height, false, false);
@@ -5608,7 +5602,7 @@ static void frame_setheight(frame_T *curfrp, int height)
room_cmdline = 0;
} else {
win_T *wp = lastwin_nofloating();
- room_cmdline = Rows - p_ch - global_stl_height()
+ room_cmdline = Rows - (int)p_ch - global_stl_height()
- (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height);
if (room_cmdline < 0) {
room_cmdline = 0;
@@ -5718,7 +5712,7 @@ void win_setwidth_win(int width, win_T *wp)
// 'winminwidth' is zero.
if (wp == curwin) {
if (width < p_wmw) {
- width = p_wmw;
+ width = (int)p_wmw;
}
if (width == 0) {
width = 1;
@@ -5882,8 +5876,8 @@ void win_setminheight(void)
// loop until there is a 'winminheight' that is possible
while (p_wmh > 0) {
- const int room = Rows - p_ch;
- const int needed = min_rows() - 1; // 1 was added for the cmdline
+ const int room = Rows - (int)p_ch;
+ const int needed = min_rows();
if (room >= needed) {
break;
}
@@ -5973,7 +5967,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
// Only dragging the last status line can reduce p_ch.
room = Rows - cmdline_row;
if (curfr->fr_next != NULL) {
- room -= p_ch + global_stl_height();
+ room -= (int)p_ch + global_stl_height();
}
if (room < 0) {
room = 0;
@@ -6151,8 +6145,7 @@ void set_fraction(win_T *wp)
// When cursor is in the first line the percentage is computed as if
// it's halfway that line. Thus with two lines it is 25%, with three
// lines 17%, etc. Similarly for the last line: 75%, 83%, etc.
- wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + FRACTION_MULT / 2)
- / (long)wp->w_height_inner;
+ wp->w_fraction = (int)(wp->w_wrow * FRACTION_MULT + FRACTION_MULT / 2) / wp->w_height_inner;
}
}
@@ -6199,7 +6192,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
if (lnum < 1) { // can happen when starting up
lnum = 1;
}
- wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
+ wp->w_wrow = (int)((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
sline = wp->w_wrow - line_size;
@@ -6314,7 +6307,8 @@ void win_set_inner_size(win_T *wp)
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
- if (!exiting) {
+ // Skip scroll_to_fraction() when 'cmdheight' was set to one from zero.
+ if (!exiting && !made_cmdheight_nonzero) {
scroll_to_fraction(wp, prev_height);
}
redraw_later(wp, NOT_VALID); // SOME_VALID??
@@ -6384,7 +6378,7 @@ void command_height(void)
{
int h;
frame_T *frp;
- int old_p_ch = curtab->tp_ch_used;
+ int old_p_ch = (int)curtab->tp_ch_used;
// Use the value of p_ch that we remembered. This is needed for when the
// GUI starts up, we can't be sure in what order things happen. And when
@@ -6404,7 +6398,7 @@ void command_height(void)
}
if (starting != NO_SCREEN) {
- cmdline_row = Rows - p_ch;
+ cmdline_row = Rows - (int)p_ch;
if (p_ch > old_p_ch) { // p_ch got bigger
while (p_ch > old_p_ch) {
@@ -6412,12 +6406,12 @@ void command_height(void)
emsg(_(e_noroom));
p_ch = old_p_ch;
curtab->tp_ch_used = p_ch;
- cmdline_row = Rows - p_ch;
+ cmdline_row = Rows - (int)p_ch;
break;
}
h = frp->fr_height - frame_minheight(frp, NULL);
if (h > p_ch - old_p_ch) {
- h = p_ch - old_p_ch;
+ h = (int)p_ch - old_p_ch;
}
old_p_ch += h;
frame_add_height(frp, -h);
@@ -6481,9 +6475,9 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
}
// Only recognize ":123" here
if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) {
- char_u *p = ptr + len + 1;
+ char *p = (char *)ptr + len + 1;
- *file_lnum = getdigits_long(&p, false, 0);
+ *file_lnum = (linenr_T)getdigits_long(&p, false, 0);
}
return find_file_name_in_path(ptr, len, options, count, (char_u *)curbuf->b_ffname);
}
@@ -6607,7 +6601,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
}
p = skipwhite(p);
if (isdigit(*p)) {
- *file_lnum = getdigits_long((char_u **)&p, false, 0);
+ *file_lnum = (linenr_T)getdigits_long(&p, false, 0);
}
}
}
@@ -6637,7 +6631,7 @@ static void win_remove_status_line(win_T *wp, bool add_hsep)
}
comp_col();
- stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ stl_clear_click_defs(wp->w_status_click_defs, (long)wp->w_status_click_defs_size);
xfree(wp->w_status_click_defs);
wp->w_status_click_defs_size = 0;
wp->w_status_click_defs = NULL;
@@ -6745,34 +6739,50 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
}
}
-// Add or remove window bars from windows depending on the value of 'winbar'.
-void set_winbar(void)
-{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- // Require the local value to be set in order to show winbar on a floating window.
- int winbar_height = wp->w_floating ? ((*wp->w_p_wbr != NUL) ? 1 : 0)
- : ((*p_wbr != NUL || *wp->w_p_wbr != NUL) ? 1 : 0);
-
- if (wp->w_winbar_height != winbar_height) {
- if (winbar_height == 1 && wp->w_height_inner <= 1) {
- if (wp->w_floating) {
- emsg(_(e_noroom));
- continue;
- } else if (!resize_frame_for_winbar(wp->w_frame)) {
- return;
- }
+/// Add or remove window bar from window "wp".
+///
+/// @param make_room Whether to resize frames to make room for winbar.
+///
+/// @return Success status.
+int set_winbar_win(win_T *wp, bool make_room)
+{
+ // Require the local value to be set in order to show winbar on a floating window.
+ int winbar_height = wp->w_floating ? ((*wp->w_p_wbr != NUL) ? 1 : 0)
+ : ((*p_wbr != NUL || *wp->w_p_wbr != NUL) ? 1 : 0);
+
+ if (wp->w_winbar_height != winbar_height) {
+ if (winbar_height == 1 && wp->w_height_inner <= 1) {
+ if (wp->w_floating) {
+ emsg(_(e_noroom));
+ return NOTDONE;
+ } else if (!make_room || !resize_frame_for_winbar(wp->w_frame)) {
+ return FAIL;
}
- wp->w_winbar_height = winbar_height;
- win_set_inner_size(wp);
- wp->w_redr_status = wp->w_redr_status || winbar_height;
+ }
+ wp->w_winbar_height = winbar_height;
+ win_set_inner_size(wp);
+ wp->w_redr_status = wp->w_redr_status || winbar_height;
- if (winbar_height == 0) {
- // When removing winbar, deallocate the w_winbar_click_defs array
- stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
- xfree(wp->w_winbar_click_defs);
- wp->w_winbar_click_defs_size = 0;
- wp->w_winbar_click_defs = NULL;
- }
+ if (winbar_height == 0) {
+ // When removing winbar, deallocate the w_winbar_click_defs array
+ stl_clear_click_defs(wp->w_winbar_click_defs, (long)wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = 0;
+ wp->w_winbar_click_defs = NULL;
+ }
+ }
+
+ return OK;
+}
+
+/// Add or remove window bars from all windows in tab depending on the value of 'winbar'.
+///
+/// @param make_room Whether to resize frames to make room for winbar.
+void set_winbar(bool make_room)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (set_winbar_win(wp, make_room) == FAIL) {
+ break;
}
}
}
@@ -6821,7 +6831,9 @@ int min_rows(void)
}
}
total += tabline_height() + global_stl_height();
- total += 1; // count the room for the command line
+ if (p_ch > 0) {
+ total += 1; // count the room for the command line
+ }
return total;
}
@@ -6846,43 +6858,67 @@ bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return count <= 1;
}
-/// Correct the cursor line number in other windows. Used after changing the
-/// current buffer, and before applying autocommands.
-///
-/// @param do_curwin when true, also check current window.
-void check_lnums(bool do_curwin)
+/// Implementation of check_lnums() and check_lnums_nested().
+static void check_lnums_both(bool do_curwin, bool nested)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf) {
- // save the original cursor position and topline
- wp->w_save_cursor.w_cursor_save = wp->w_cursor;
- wp->w_save_cursor.w_topline_save = wp->w_topline;
+ if (!nested) {
+ // save the original cursor position and topline
+ wp->w_save_cursor.w_cursor_save = wp->w_cursor;
+ wp->w_save_cursor.w_topline_save = wp->w_topline;
+ }
- if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
+ bool need_adjust = wp->w_cursor.lnum > curbuf->b_ml.ml_line_count;
+ if (need_adjust) {
wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
}
- if (wp->w_topline > curbuf->b_ml.ml_line_count) {
- wp->w_topline = curbuf->b_ml.ml_line_count;
+ if (need_adjust || !nested) {
+ // save the (corrected) cursor position
+ wp->w_save_cursor.w_cursor_corr = wp->w_cursor;
}
- // save the corrected cursor position and topline
- wp->w_save_cursor.w_cursor_corr = wp->w_cursor;
- wp->w_save_cursor.w_topline_corr = wp->w_topline;
+ need_adjust = wp->w_topline > curbuf->b_ml.ml_line_count;
+ if (need_adjust) {
+ wp->w_topline = curbuf->b_ml.ml_line_count;
+ }
+ if (need_adjust || !nested) {
+ // save the (corrected) topline
+ wp->w_save_cursor.w_topline_corr = wp->w_topline;
+ }
}
}
}
+/// Correct the cursor line number in other windows. Used after changing the
+/// current buffer, and before applying autocommands.
+///
+/// @param do_curwin when true, also check current window.
+void check_lnums(bool do_curwin)
+{
+ check_lnums_both(do_curwin, false);
+}
+
+/// Like check_lnums() but for when check_lnums() was already called.
+void check_lnums_nested(bool do_curwin)
+{
+ check_lnums_both(do_curwin, true);
+}
+
/// Reset cursor and topline to its stored values from check_lnums().
/// check_lnums() must have been called first!
void reset_lnums(void)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == curbuf) {
- // Restore the value if the autocommand didn't change it.
- if (equalpos(wp->w_save_cursor.w_cursor_corr, wp->w_cursor)) {
+ // Restore the value if the autocommand didn't change it and it was
+ // set.
+ if (equalpos(wp->w_save_cursor.w_cursor_corr, wp->w_cursor)
+ && wp->w_save_cursor.w_cursor_save.lnum != 0) {
wp->w_cursor = wp->w_save_cursor.w_cursor_save;
}
- if (wp->w_save_cursor.w_topline_corr == wp->w_topline) {
+ if (wp->w_save_cursor.w_topline_corr == wp->w_topline
+ && wp->w_save_cursor.w_topline_save != 0) {
wp->w_topline = wp->w_save_cursor.w_topline_save;
}
}
@@ -7201,14 +7237,14 @@ int win_getid(typval_T *argvars)
if (argvars[0].v_type == VAR_UNKNOWN) {
return curwin->handle;
}
- int winnr = tv_get_number(&argvars[0]);
+ int winnr = (int)tv_get_number(&argvars[0]);
win_T *wp;
if (winnr > 0) {
if (argvars[1].v_type == VAR_UNKNOWN) {
wp = firstwin;
} else {
tabpage_T *tp = NULL;
- int tabnr = tv_get_number(&argvars[1]);
+ int tabnr = (int)tv_get_number(&argvars[1]);
FOR_ALL_TABS(tp2) {
if (--tabnr == 0) {
tp = tp2;
@@ -7235,7 +7271,7 @@ int win_getid(typval_T *argvars)
int win_gotoid(typval_T *argvars)
{
- int id = tv_get_number(&argvars[0]);
+ int id = (int)tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->handle == id) {
@@ -7302,7 +7338,7 @@ win_T *win_id2wp_tp(int id, tabpage_T **tpp)
int win_id2win(typval_T *argvars)
{
int nr = 1;
- int id = tv_get_number(&argvars[0]);
+ int id = (int)tv_get_number(&argvars[0]);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->handle == id) {
@@ -7315,7 +7351,7 @@ int win_id2win(typval_T *argvars)
void win_findbuf(typval_T *argvars, list_T *list)
{
- int bufnr = tv_get_number(&argvars[0]);
+ int bufnr = (int)tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer->b_fnum == bufnr) {