diff options
author | Josh Rahm <rahm@google.com> | 2022-10-11 19:00:52 +0000 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2022-10-11 19:00:52 +0000 |
commit | 21e2e46242033c7aaa6ccfb23e256680816c063c (patch) | |
tree | f089522cfb145d6e9c8a86a01d8e454ce5501e20 /src/nvim | |
parent | 179d3ed87b17988f5fe00d8b99f2611a28212be7 (diff) | |
parent | 760b399f6c0c6470daa0663752bd22886997f9e6 (diff) | |
download | rneovim-floattitle.tar.gz rneovim-floattitle.tar.bz2 rneovim-floattitle.zip |
Merge remote-tracking branch 'upstream/master' into floattitlefloattitle
Diffstat (limited to 'src/nvim')
338 files changed, 26759 insertions, 25839 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 635833748d..2960e6d9d2 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -96,8 +96,8 @@ file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src) glob_wrapper(NVIM_SOURCES *.c) glob_wrapper(NVIM_HEADERS *.h) -glob_wrapper(EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c ../cjson/*.c) -glob_wrapper(EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h ../cjson/*.h) +glob_wrapper(EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c) +glob_wrapper(EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h) foreach(subdir os @@ -159,14 +159,14 @@ list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) if(NOT MSVC) # 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") + ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion -Wno-strict-prototypes") endif() if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$") add_definitions(-DMIN_LOG_LEVEL=${MIN_LOG_LEVEL}) endif() -if(DEBUG OR CLANG_ASAN_UBSAN OR CLANG_MSAN OR CLANG_TSAN) +if(CLANG_ASAN_UBSAN OR CLANG_MSAN OR CLANG_TSAN) add_definitions(-DEXITFREE) endif() @@ -443,14 +443,18 @@ endif() set(NVIM_EXEC_LINK_LIBRARIES ${NVIM_LINK_LIBRARIES} ${LUA_PREFERRED_LIBRARIES}) -# Add IPO flags (for LTO), or error if CMake does not know the flags. #8654 -if(POLICY CMP0069) - cmake_policy(SET CMP0069 NEW) -endif() - add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) + +set_target_properties(nvim + PROPERTIES + EXPORT_COMPILE_COMMANDS ON) + +if(${CMAKE_VERSION} VERSION_LESS 3.20) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +endif() + target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES}) install_helper(TARGETS nvim) if(MSVC) @@ -461,7 +465,7 @@ set_property(TARGET nvim APPEND PROPERTY INCLUDE_DIRECTORIES ${LUA_PREFERRED_INCLUDE_DIRS}) set_property(TARGET nvim PROPERTY ENABLE_EXPORTS TRUE) -if(ENABLE_LTO AND (POLICY CMP0069)) +if(ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT IPO_SUPPORTED) if(IPO_SUPPORTED AND (NOT CMAKE_BUILD_TYPE MATCHES Debug)) @@ -537,8 +541,8 @@ if(WIN32) translations/qt_uk.qm D3Dcompiler_47.dll libEGL.dll - libgcc_s_dw2-1.dll - libGLESV2.dll + libgcc_s_seh-1.dll + libGLESv2.dll libstdc++-6.dll libwinpthread-1.dll nvim-qt.exe diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 79ae7994f7..b5c695b9ce 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -59,6 +59,9 @@ static int64_t next_autocmd_id = 1; /// - group (string|integer): the autocommand group name or id to match against. /// - event (string|array): event or events to match against |autocmd-events|. /// - pattern (string|array): pattern or patterns to match against |autocmd-pattern|. +/// Cannot be used with {buffer} +/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands +/// |autocmd-buflocal|. Cannot be used with {pattern} /// @return Array of autocommands matching the criteria, with each item /// containing the following fields: /// - id (number): the autocommand id (only when defined with the API). @@ -240,7 +243,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) assert(pattern_filters[i]); char *pat = pattern_filters[i]; - int patlen = (int)STRLEN(pat); + int patlen = (int)strlen(pat); if (aupat_is_buflocal(pat, patlen)) { aupat_normalize_buflocal_pat(pattern_buflocal, @@ -596,7 +599,7 @@ void nvim_del_autocmd(Integer id, Error *err) } /// Clear all autocommands that match the corresponding {opts}. To delete -/// a particular autocmd, see |nvim_del_autocmd|. +/// a particular autocmd, see |nvim_del_autocmd()|. /// @param opts Parameters /// - event: (string|table) /// Examples: @@ -725,7 +728,7 @@ Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augrou /// /// To get a group id one can use |nvim_get_autocmds()|. /// -/// NOTE: behavior differs from |augroup-delete|. When deleting a group, autocommands contained in +/// NOTE: behavior differs from |:augroup-delete|. When deleting a group, autocommands contained in /// this group will also be deleted and cleared. This group will no longer exist. /// @param id Integer The id of the group. /// @see |nvim_del_augroup_by_name()| @@ -743,10 +746,10 @@ void nvim_del_augroup_by_id(Integer id, Error *err) /// Delete an autocommand group by name. /// -/// NOTE: behavior differs from |augroup-delete|. When deleting a group, autocommands contained in +/// NOTE: behavior differs from |:augroup-delete|. When deleting a group, autocommands contained in /// this group will also be deleted and cleared. This group will no longer exist. /// @param name String The name of the group. -/// @see |autocommand-groups| +/// @see |autocmd-groups| void nvim_del_augroup_by_name(String name, Error *err) FUNC_API_SINCE(9) { @@ -887,12 +890,12 @@ static bool check_autocmd_string_array(Array arr, char *k, Error *err) static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err) { if (v->type == kObjectTypeString) { - ADD(*array, copy_object(*v)); + ADD(*array, copy_object(*v, NULL)); } else if (v->type == kObjectTypeArray) { if (!check_autocmd_string_array(v->data.array, k, err)) { return false; } - *array = copy_array(v->data.array); + *array = copy_array(v->data.array, NULL); } else { if (required) { api_set_error(err, diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5e90e40dd3..51fedb302a 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -355,6 +355,8 @@ static bool check_string_array(Array arr, bool disallow_nl, Error *err) /// Out-of-bounds indices are clamped to the nearest valid value, unless /// `strict_indexing` is set. /// +/// @see |nvim_buf_set_text()| +/// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index @@ -527,6 +529,8 @@ end: /// /// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines. /// +/// @see |nvim_buf_set_lines()| +/// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start_row First line index @@ -570,7 +574,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In char *str_at_end = NULL; // Another call to ml_get_buf() may free the line, so make a copy. - str_at_start = xstrdup((char *)ml_get_buf(buf, (linenr_T)start_row, false)); + str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); if (start_col < 0 || (size_t)start_col > len_at_start) { api_set_error(err, kErrorTypeValidation, "start_col out of bounds"); @@ -578,7 +582,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In } // Another call to ml_get_buf() may free the line, so make a copy. - str_at_end = xstrdup((char *)ml_get_buf(buf, (linenr_T)end_row, false)); + str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); if (end_col < 0 || (size_t)end_col > len_at_end) { api_set_error(err, kErrorTypeValidation, "end_col out of bounds"); @@ -608,7 +612,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (int64_t i = 1; i < end_row - start_row; i++) { int64_t lnum = start_row + i; - const char *bufline = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufline = ml_get_buf(buf, (linenr_T)lnum, false); old_byte += (bcount_t)(strlen(bufline)) + 1; } old_byte += (bcount_t)end_col + 1; @@ -945,7 +949,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) /// @param[out] err Error details, if any /// @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) +ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) FUNC_API_SINCE(3) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -954,7 +958,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, Stri return (Array)ARRAY_DICT_INIT; } - return keymap_array(mode, buf, channel_id == LUA_INTERNAL_CALL); + return keymap_array(mode, buf); } /// Sets a buffer-local |mapping| for the given mode. @@ -1021,7 +1025,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err) /// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// @return Buffer name -String nvim_buf_get_name(Buffer buffer, Error *err) +String nvim_buf_get_name(Buffer buffer, Arena *arena, Error *err) FUNC_API_SINCE(1) { String rv = STRING_INIT; @@ -1031,7 +1035,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err) return rv; } - return cstr_to_string((char *)buf->b_ffname); + return cstr_as_string(buf->b_ffname); } /// Sets the full file name for a buffer diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 1323fc347b..8cd2c0f8b8 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -31,14 +31,15 @@ /// @param[out] err Error details, if any. /// @return Dictionary containing command information, with these keys: /// - cmd: (string) Command name. -/// - range: (array) Command <range>. Can have 0-2 elements depending on how many items the -/// range contains. Has no elements if command doesn't accept a range or if -/// no range was specified, one element if only a single range item was -/// specified and two elements if both range items were specified. -/// - count: (number) Any |<count>| that was supplied to the command. -1 if command cannot -/// take a count. -/// - reg: (number) The optional command |<register>|, if specified. Empty string if not -/// specified or if command cannot take a register. +/// - range: (array) (optional) Command range (|<line1>| |<line2>|). +/// Omitted if command doesn't accept a range. +/// Otherwise, has no elements if no range was specified, one element if +/// only a single range item was specified, or two elements if both range +/// items were specified. +/// - count: (number) (optional) Command |<count>|. +/// Omitted if command cannot take a count. +/// - reg: (string) (optional) Command |<register>|. +/// Omitted if command cannot take a register. /// - bang: (boolean) Whether command contains a |<bang>| (!) modifier. /// - args: (array) Command arguments. /// - addr: (string) Value of |:command-addr|. Uses short name. @@ -62,13 +63,14 @@ /// - browse: (boolean) |:browse|. /// - confirm: (boolean) |:confirm|. /// - hide: (boolean) |:hide|. +/// - horizontal: (boolean) |:horizontal|. /// - keepalt: (boolean) |:keepalt|. /// - keepjumps: (boolean) |:keepjumps|. /// - keepmarks: (boolean) |:keepmarks|. /// - keeppatterns: (boolean) |:keeppatterns|. /// - lockmarks: (boolean) |:lockmarks|. /// - noswapfile: (boolean) |:noswapfile|. -/// - tab: (integer) |:tab|. +/// - tab: (integer) |:tab|. -1 when omitted. /// - verbose: (integer) |:verbose|. -1 when omitted. /// - vertical: (boolean) |:vertical|. /// - split: (string) Split modifier string, is an empty string when there's no split @@ -104,7 +106,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) // Parse arguments Array args = ARRAY_DICT_INIT; - size_t length = STRLEN(ea.arg); + size_t length = strlen(ea.arg); // For nargs = 1 or '?', pass the entire argument list as a single argument, // otherwise split arguments by whitespace. @@ -141,15 +143,15 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); } - if ((ea.argt & EX_RANGE) && ea.addr_count > 0) { + if (ea.argt & EX_RANGE) { Array range = ARRAY_DICT_INIT; - if (ea.addr_count > 1) { - ADD(range, INTEGER_OBJ(ea.line1)); + if (ea.addr_count > 0) { + if (ea.addr_count > 1) { + ADD(range, INTEGER_OBJ(ea.line1)); + } + ADD(range, INTEGER_OBJ(ea.line2)); } - ADD(range, INTEGER_OBJ(ea.line2)); PUT(result, "range", ARRAY_OBJ(range)); - } else { - PUT(result, "range", ARRAY_OBJ(ARRAY_DICT_INIT)); } if (ea.argt & EX_COUNT) { @@ -160,14 +162,12 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) } else { PUT(result, "count", INTEGER_OBJ(0)); } - } else { - PUT(result, "count", INTEGER_OBJ(-1)); } - char reg[2]; - reg[0] = (char)ea.regname; - reg[1] = '\0'; - PUT(result, "reg", CSTR_TO_OBJ(reg)); + if (ea.argt & EX_REGSTR) { + char reg[2] = { (char)ea.regname, NUL }; + PUT(result, "reg", CSTR_TO_OBJ(reg)); + } PUT(result, "bang", BOOLEAN_OBJ(ea.forceit)); PUT(result, "args", ARRAY_OBJ(args)); @@ -238,7 +238,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) PUT(mods, "unsilent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_UNSILENT)); PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX)); PUT(mods, "noautocmd", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_NOAUTOCMD)); - PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.cmod_tab)); + PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.cmod_tab - 1)); PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.cmdmod.cmod_verbose - 1)); PUT(mods, "browse", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_BROWSE)); PUT(mods, "confirm", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_CONFIRM)); @@ -250,6 +250,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_LOCKMARKS)); PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_NOSWAPFILE)); PUT(mods, "vertical", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_split & WSP_VERT)); + PUT(mods, "horizontal", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_split & WSP_HOR)); const char *split; if (cmdinfo.cmdmod.cmod_split & WSP_BOT) { @@ -283,7 +284,11 @@ end: /// Unlike |nvim_command()| this command takes a structured Dictionary instead of a String. This /// allows for easier construction and manipulation of an Ex command. This also allows for things /// such as having spaces inside a command argument, expanding filenames in a command that otherwise -/// doesn't expand filenames, etc. +/// doesn't expand filenames, etc. Command arguments may also be Number, Boolean or String. +/// +/// The first argument may also be used instead of count for commands that support it in order to +/// make their usage simpler with |vim.cmd()|. For example, instead of +/// `vim.cmd.bdelete{ count = 2 }`, you may do `vim.cmd.bdelete(2)`. /// /// On execution error: fails with VimL error, updates v:errmsg. /// @@ -308,8 +313,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error char *cmdline = NULL; char *cmdname = NULL; - ArrayOf(String) args; - size_t argc = 0; + ArrayOf(String) args = ARRAY_DICT_INIT; String retv = (String)STRING_INIT; @@ -381,48 +385,70 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error if (cmd->args.type != kObjectTypeArray) { VALIDATION_ERROR("'args' must be an Array"); } - // Check if every argument is valid + + // Process all arguments. Convert non-String arguments to String and check if String arguments + // have non-whitespace characters. for (size_t i = 0; i < cmd->args.data.array.size; i++) { Object elem = cmd->args.data.array.items[i]; - if (elem.type != kObjectTypeString) { - VALIDATION_ERROR("Command argument must be a String"); - } else if (string_iswhite(elem.data.string)) { - VALIDATION_ERROR("Command argument must have non-whitespace characters"); + char *data_str; + + switch (elem.type) { + case kObjectTypeBoolean: + data_str = xcalloc(2, sizeof(char)); + data_str[0] = elem.data.boolean ? '1' : '0'; + data_str[1] = '\0'; + break; + case kObjectTypeBuffer: + case kObjectTypeWindow: + case kObjectTypeTabpage: + case kObjectTypeInteger: + data_str = xcalloc(NUMBUFLEN, sizeof(char)); + snprintf(data_str, NUMBUFLEN, "%" PRId64, elem.data.integer); + break; + case kObjectTypeString: + if (string_iswhite(elem.data.string)) { + VALIDATION_ERROR("String command argument must have at least one non-whitespace " + "character"); + } + data_str = xstrndup(elem.data.string.data, elem.data.string.size); + break; + default: + VALIDATION_ERROR("Invalid type for command argument"); + break; } + + ADD(args, STRING_OBJ(cstr_as_string(data_str))); } - argc = cmd->args.data.array.size; bool argc_valid; // Check if correct number of arguments is used. switch (ea.argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { case EX_EXTRA | EX_NOSPC | EX_NEEDARG: - argc_valid = argc == 1; + argc_valid = args.size == 1; break; case EX_EXTRA | EX_NOSPC: - argc_valid = argc <= 1; + argc_valid = args.size <= 1; break; case EX_EXTRA | EX_NEEDARG: - argc_valid = argc >= 1; + argc_valid = args.size >= 1; break; case EX_EXTRA: argc_valid = true; break; default: - argc_valid = argc == 0; + argc_valid = args.size == 0; break; } if (!argc_valid) { VALIDATION_ERROR("Incorrect number of arguments supplied"); } - - 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.items[0].data.string.data : NULL); + set_cmd_addr_type(&ea, args.size > 0 ? args.items[0].data.string.data : NULL); if (HAS_KEY(cmd->range)) { if (!(ea.argt & EX_RANGE)) { @@ -557,15 +583,17 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.tab)) { - if (mods.tab.type != kObjectTypeInteger || mods.tab.data.integer < 0) { - VALIDATION_ERROR("'mods.tab' must be a non-negative Integer"); + if (mods.tab.type != kObjectTypeInteger) { + VALIDATION_ERROR("'mods.tab' must be an Integer"); + } else if ((int)mods.tab.data.integer >= 0) { + // Silently ignore negative integers to allow mods.tab to be set to -1. + cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } - cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } if (HAS_KEY(mods.verbose)) { if (mods.verbose.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.verbose' must be a Integer"); + VALIDATION_ERROR("'mods.verbose' must be an Integer"); } else if ((int)mods.verbose.data.integer >= 0) { // Silently ignore negative integers to allow mods.verbose to be set to -1. cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1; @@ -576,6 +604,10 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'"); cmdinfo.cmdmod.cmod_split |= (vertical ? WSP_VERT : 0); + bool horizontal; + OBJ_TO_BOOL(horizontal, mods.horizontal, false, "'mods.horizontal'"); + cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0); + if (HAS_KEY(mods.split)) { if (mods.split.type != kObjectTypeString) { VALIDATION_ERROR("'mods.split' must be a String"); @@ -583,15 +615,15 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error if (*mods.split.data.string.data == NUL) { // Empty string, do nothing. - } else if (STRCMP(mods.split.data.string.data, "aboveleft") == 0 - || STRCMP(mods.split.data.string.data, "leftabove") == 0) { + } else if (strcmp(mods.split.data.string.data, "aboveleft") == 0 + || strcmp(mods.split.data.string.data, "leftabove") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_ABOVE; - } else if (STRCMP(mods.split.data.string.data, "belowright") == 0 - || STRCMP(mods.split.data.string.data, "rightbelow") == 0) { + } else if (strcmp(mods.split.data.string.data, "belowright") == 0 + || strcmp(mods.split.data.string.data, "rightbelow") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BELOW; - } else if (STRCMP(mods.split.data.string.data, "topleft") == 0) { + } else if (strcmp(mods.split.data.string.data, "topleft") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_TOP; - } else if (STRCMP(mods.split.data.string.data, "botright") == 0) { + } else if (strcmp(mods.split.data.string.data, "botright") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BOT; } else { VALIDATION_ERROR("Invalid value for 'mods.split'"); @@ -620,7 +652,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error // Finally, build the command line string that will be stored inside ea.cmdlinep. // This also sets the values of ea.cmd, ea.arg, ea.args and ea.arglens. - build_cmdline_str(&cmdline, &ea, &cmdinfo, args, argc); + build_cmdline_str(&cmdline, &ea, &cmdinfo, args); ea.cmdlinep = &cmdline; garray_T capture_local; @@ -676,6 +708,7 @@ clear_ga: ga_clear(&capture_local); } end: + api_free_array(args); xfree(cmdline); xfree(cmdname); xfree(ea.args); @@ -705,8 +738,9 @@ static bool string_iswhite(String str) /// Build cmdline string for command, used by `nvim_cmd()`. static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdinfo, - ArrayOf(String) args, size_t argc) + ArrayOf(String) args) { + size_t argc = args.size; StringBuilder cmdline = KV_INITIAL_VALUE; kv_resize(cmdline, 32); // Make it big enough to handle most typical commands @@ -753,6 +787,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin } while (0) CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_split & WSP_VERT, "vertical "); + CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_split & WSP_HOR, "horizontal "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_SANDBOX, "sandbox "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_NOAUTOCMD, "noautocmd "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_BROWSE, "browse "); @@ -791,7 +826,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin } eap->argc = argc; - eap->arglens = xcalloc(argc, sizeof(size_t)); + eap->arglens = eap->argc > 0 ? xcalloc(argc, sizeof(size_t)) : NULL; size_t argstart_idx = cmdline.size; for (size_t i = 0; i < argc; i++) { String s = args.items[i].data.string; @@ -806,7 +841,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin // 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 *)); + eap->args = eap->argc > 0 ? xcalloc(argc, sizeof(char *)) : NULL; size_t offset = argstart_idx; for (size_t i = 0; i < argc; i++) { offset++; // Account for space @@ -823,13 +858,12 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin // Replace, :make and :grep with 'makeprg' and 'grepprg'. char *p = replace_makeprg(eap, eap->arg, cmdlinep); if (p != eap->arg) { - // If replace_makeprg modified the cmdline string, correct the argument pointers. + // If replace_makeprg() modified the cmdline string, correct the eap->arg pointer. eap->arg = p; - // We can only know the position of the first argument because the argument list can be used - // multiple times in makeprg / grepprg. - if (argc >= 1) { - eap->args[0] = p; - } + // This cannot be a user command, so eap->args will not be used. + XFREE_CLEAR(eap->args); + XFREE_CLEAR(eap->arglens); + eap->argc = 0; } } @@ -929,7 +963,7 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) for (int i = 0; i < gap->ga_len; i++) { ucmd_T *cmd = USER_CMD_GA(gap, i); - if (!STRCMP(name.data, cmd->uc_name)) { + if (!strcmp(name.data, cmd->uc_name)) { free_ucmd(cmd); gap->ga_len -= 1; diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 933aa85530..3b1b470629 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -51,7 +51,7 @@ Integer nvim_create_namespace(String name) } id = next_namespace_id++; if (name.size > 0) { - String name_alloc = copy_string(name); + String name_alloc = copy_string(name, NULL); map_put(String, handle_T)(&namespace_ids, name_alloc, id); } return (Integer)id; @@ -87,7 +87,7 @@ const char *describe_ns(NS ns_id) } // Is the Namespace in use? -static bool ns_initialized(uint32_t ns) +bool ns_initialized(uint32_t ns) { if (ns < 1) { return false; @@ -389,11 +389,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// - virt_text : virtual text to link to this mark. /// A list of [text, highlight] tuples, each representing a /// text chunk with specified highlight. `highlight` element -/// can either be a a single highlight group, or an array of +/// can either be a single highlight group, or an array of /// multiple highlight groups that will be stacked /// (highest priority last). A highlight group can be supplied /// either as a string or as an integer, the latter which -/// can be obtained using |nvim_get_hl_id_by_name|. +/// can be obtained using |nvim_get_hl_id_by_name()|. /// - virt_text_pos : position of virtual text. Possible values: /// - "eol": right after eol character (default) /// - "overlay": display over the specified column, without @@ -430,7 +430,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// column of the window, bypassing /// sign and number columns. /// -/// - ephemeral : for use with |nvim_set_decoration_provider| +/// - ephemeral : for use with |nvim_set_decoration_provider()| /// callbacks. The mark will only be used for the current /// redraw cycle, and not be permantently stored in the /// buffer. @@ -473,6 +473,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// When a character is supplied it is used as |:syn-cchar|. /// "hl_group" is used as highlight for the cchar if provided, /// otherwise it defaults to |hl-Conceal|. +/// - spell: boolean indicating that spell checking should be +/// performed within this extmark /// - ui_watched: boolean that indicates the mark should be drawn /// by a UI. When set, the UI will receive win_extmark events. /// Note: the mark is positioned by virt_text attributes. Can be @@ -719,6 +721,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool ephemeral = false; OPTION_TO_BOOL(ephemeral, ephemeral, false); + OPTION_TO_BOOL(decor.spell, spell, false); + if (decor.spell) { + has_decor = true; + } + OPTION_TO_BOOL(decor.ui_watched, ui_watched, false); if (decor.ui_watched) { has_decor = true; @@ -735,7 +742,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer line = buf->b_ml.ml_line_count; } } else if (line < buf->b_ml.ml_line_count) { - len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line + 1, false)); + len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false)); } if (col == -1) { @@ -754,7 +761,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col2 >= 0) { if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { - len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false)); + len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line2 + 1, false)); } else if (line2 == buf->b_ml.ml_line_count) { // We are trying to add an extmark past final newline len = 0; @@ -951,7 +958,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// being triggered during the redraw code. /// /// The expected usage is to set extmarks for the currently -/// redrawn buffer. |nvim_buf_set_extmark| can be called to add marks +/// redrawn buffer. |nvim_buf_set_extmark()| can be called to add marks /// on a per-window or per-lines basis. Use the `ephemeral` key to only /// use the mark for the current screen redraw (the callback will be called /// again for the next redraw ). @@ -972,20 +979,21 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// for the moment. /// /// @param ns_id Namespace id from |nvim_create_namespace()| -/// @param opts Callbacks invoked during redraw: +/// @param opts Table of callbacks: /// - on_start: called first on each screen redraw /// ["start", tick] -/// - on_buf: called for each buffer being redrawn (before window -/// callbacks) +/// - on_buf: called for each buffer being redrawn (before +/// window callbacks) /// ["buf", bufnr, tick] -/// - on_win: called when starting to redraw a specific window. +/// - on_win: called when starting to redraw a +/// specific window. /// ["win", winid, bufnr, topline, botline_guess] -/// - on_line: called for each buffer line being redrawn. (The -/// interaction with fold lines is subject to change) +/// - on_line: called for each buffer line being redrawn. +/// (The interaction with fold lines is subject to change) /// ["win", winid, bufnr, row] /// - on_end: called at the end of a redraw cycle /// ["end", tick] -void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Error *err) +void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *opts, Error *err) FUNC_API_SINCE(7) FUNC_API_LUA_ONLY { DecorProvider *p = get_decor_provider((NS)ns_id, true); @@ -993,41 +1001,36 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro decor_provider_clear(p); // regardless of what happens, it seems good idea to redraw - redraw_all_later(NOT_VALID); // TODO(bfredl): too soon? + redraw_all_later(UPD_NOT_VALID); // TODO(bfredl): too soon? struct { const char *name; + Object *source; LuaRef *dest; } cbs[] = { - { "on_start", &p->redraw_start }, - { "on_buf", &p->redraw_buf }, - { "on_win", &p->redraw_win }, - { "on_line", &p->redraw_line }, - { "on_end", &p->redraw_end }, - { "_on_hl_def", &p->hl_def }, - { NULL, NULL }, + { "on_start", &opts->on_start, &p->redraw_start }, + { "on_buf", &opts->on_buf, &p->redraw_buf }, + { "on_win", &opts->on_win, &p->redraw_win }, + { "on_line", &opts->on_line, &p->redraw_line }, + { "on_end", &opts->on_end, &p->redraw_end }, + { "_on_hl_def", &opts->_on_hl_def, &p->hl_def }, + { "_on_spell_nav", &opts->_on_spell_nav, &p->spell_nav }, + { NULL, NULL, NULL }, }; - for (size_t i = 0; i < opts.size; i++) { - String k = opts.items[i].key; - Object *v = &opts.items[i].value; - size_t j; - for (j = 0; cbs[j].name && cbs[j].dest; j++) { - if (strequal(cbs[j].name, k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[j].name); - goto error; - } - *(cbs[j].dest) = v->data.luaref; - v->data.luaref = LUA_NOREF; - break; - } + for (size_t i = 0; cbs[i].source && cbs[i].dest && cbs[i].name; i++) { + Object *v = cbs[i].source; + if (v->type == kObjectTypeNil) { + continue; } - if (!cbs[j].name) { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + + if (v->type != kObjectTypeLuaRef) { + api_set_error(err, kErrorTypeValidation, + "%s is not a function", cbs[i].name); goto error; } + *(cbs[i].dest) = v->data.luaref; + v->data.luaref = LUA_NOREF; } p->active = true; @@ -1103,7 +1106,7 @@ static int init_sign_text(char **sign_text, char *text) { char *s; - char *endp = text + (int)STRLEN(text); + char *endp = text + (int)strlen(text); // Count cells and check for non-printable chars int cells = 0; diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 32104ef6dc..d9d9c7ee1d 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -2,6 +2,15 @@ return { context = { "types"; }; + set_decoration_provider = { + "on_start"; + "on_buf"; + "on_win"; + "on_line"; + "on_end"; + "_on_hl_def"; + "_on_spell_nav"; + }; set_extmark = { "id"; "end_line"; @@ -28,6 +37,7 @@ return { "line_hl_group"; "cursorline_hl_group"; "conceal"; + "spell"; "ui_watched"; }; keymap = { @@ -190,6 +200,7 @@ return { "browse"; "confirm"; "hide"; + "horizontal"; "keepalt"; "keepjumps"; "keepmarks"; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 867584dd71..ec1f19cf6a 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -147,7 +147,7 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) /// @param name Option name /// @param value New option value /// @param opts Optional parameters -/// - scope: One of 'global' or 'local'. Analogous to +/// - scope: One of "global" or "local". Analogous to /// |:setglobal| and |:setlocal|, respectively. /// - win: |window-ID|. Used for setting window local option. /// - buf: Buffer number. Used for setting buffer local option. @@ -202,7 +202,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error /// Gets the option information for all options. /// /// The dictionary has the full option names as keys and option metadata -/// dictionaries as detailed at |nvim_get_option_info|. +/// dictionaries as detailed at |nvim_get_option_info()|. /// /// @return dictionary of all options Dictionary nvim_get_all_options_info(Error *err) diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 8724ef4432..b6b3c83f3c 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -65,8 +65,8 @@ typedef struct { #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ ufunc_T *fp = find_func(fun); \ - if (fp != NULL && fp->uf_cb == nlua_CFunction_func_call) { \ - LuaRef ref = api_new_luaref(((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \ + if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { \ + LuaRef ref = api_new_luaref(fp->uf_luaref); \ kvi_push(edata->stack, LUAREF_OBJ(ref)); \ } else { \ TYPVAL_ENCODE_CONV_NIL(tv); \ @@ -351,10 +351,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) } case kObjectTypeLuaRef: { - LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = api_new_luaref(obj.data.luaref); - char *name = - (char *)register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, state); + char *name = (char *)register_luafunc(api_new_luaref(obj.data.luaref)); tv->v_type = VAR_FUNC; tv->vval.v_string = xstrdup(name); break; diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 9c7e59e4b3..2ae3ee6c7c 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,8 +5,8 @@ #include <stdint.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/func_attr.h" -#include "nvim/lib/kvec.h" #include "nvim/types.h" #define ARRAY_DICT_INIT KV_INITIAL_VALUE diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 4b7c394944..f92b205531 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -5,18 +5,23 @@ typedef Object (*ApiDispatchWrapper)(uint64_t channel_id, Array args, + Arena *arena, Error *error); /// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores /// functions of this type. -typedef struct { +struct MsgpackRpcRequestHandler { const char *name; ApiDispatchWrapper fn; bool fast; // Function is safe to be executed immediately while running the // uv loop (the loop is run very frequently due to breakcheck). // If "fast" is false, the function is deferred, i e the call will // be put in the event queue, for safe handling later. -} MsgpackRpcRequestHandler; + bool arena_return; // return value is allocated in the arena (or statically) + // and should not be freed as such. +}; + +extern const MsgpackRpcRequestHandler method_handlers[]; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/dispatch.h.generated.h" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index c466fc53e1..73b5489d5c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" @@ -22,7 +23,6 @@ #include "nvim/ex_eval.h" #include "nvim/extmark.h" #include "nvim/highlight_group.h" -#include "nvim/lib/kvec.h" #include "nvim/lua/executor.h" #include "nvim/map.h" #include "nvim/map_defs.h" @@ -58,6 +58,7 @@ void try_enter(TryState *const tstate) .private_msg_list = NULL, .trylevel = trylevel, .got_int = got_int, + .did_throw = did_throw, .need_rethrow = need_rethrow, .did_emsg = did_emsg, }; @@ -65,6 +66,7 @@ void try_enter(TryState *const tstate) current_exception = NULL; trylevel = 1; got_int = false; + did_throw = false; need_rethrow = false; did_emsg = false; } @@ -85,6 +87,7 @@ bool try_leave(const TryState *const tstate, Error *const err) assert(trylevel == 0); assert(!need_rethrow); assert(!got_int); + assert(!did_throw); assert(!did_emsg); assert(msg_list == &tstate->private_msg_list); assert(*msg_list == NULL); @@ -93,6 +96,7 @@ bool try_leave(const TryState *const tstate, Error *const err) current_exception = tstate->current_exception; trylevel = tstate->trylevel; got_int = tstate->got_int; + did_throw = tstate->did_throw; need_rethrow = tstate->need_rethrow; did_emsg = tstate->did_emsg; return ret; @@ -127,7 +131,7 @@ bool try_end(Error *err) force_abort = false; if (got_int) { - if (current_exception) { + if (did_throw) { // If we got an interrupt, discard the current exception discard_current_exception(); } @@ -146,7 +150,7 @@ bool try_end(Error *err) if (should_free) { xfree(msg); } - } else if (current_exception) { + } else if (did_throw) { api_set_error(err, kErrorTypeException, "%s", current_exception->value); discard_current_exception(); } @@ -214,6 +218,8 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva return rv; } + bool watched = tv_dict_is_watched(dict); + if (del) { // Delete the key if (di == NULL) { @@ -221,6 +227,10 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data); } else { + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv); + } // Return the old value if (retval) { rv = vim_to_object(&di->di_tv); @@ -237,11 +247,16 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva return rv; } + typval_T oldtv = TV_INITIAL_VALUE; + if (di == NULL) { // Need to create an entry di = tv_dict_item_alloc_len(key.data, key.size); tv_dict_add(dict, di); } else { + if (watched) { + tv_copy(&di->di_tv, &oldtv); + } // Return the old value if (retval) { rv = vim_to_object(&di->di_tv); @@ -251,6 +266,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva // Update the value tv_copy(&tv, &di->di_tv); + + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, &tv, &oldtv); + tv_clear(&oldtv); + } + // Clear the temporary variable tv_clear(&tv); } @@ -462,7 +484,7 @@ bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl, Arr return false; } - const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); Object str = STRING_OBJ(cstr_to_string(bufstr)); if (replace_nl) { @@ -495,7 +517,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); size_t line_length = strlen(bufstr); start_col = start_col < 0 ? (int64_t)line_length + start_col + 1 : start_col; @@ -618,6 +640,7 @@ void api_clear_error(Error *value) value->type = kErrorTypeNone; } +/// @returns a shared value. caller must not modify it! Dictionary api_metadata(void) { static Dictionary metadata = ARRAY_DICT_INIT; @@ -630,7 +653,7 @@ Dictionary api_metadata(void) init_type_metadata(&metadata); } - return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary; + return metadata; } static void init_function_metadata(Dictionary *metadata) @@ -715,36 +738,40 @@ static void init_type_metadata(Dictionary *metadata) PUT(*metadata, "types", DICTIONARY_OBJ(types)); } -String copy_string(String str) +// all the copy_[object] functions allow arena=NULL, +// then global allocations are used, and the resulting object +// should be freed with an api_free_[object] function + +String copy_string(String str, Arena *arena) { if (str.data != NULL) { - return (String){ .data = xmemdupz(str.data, str.size), .size = str.size }; + return (String){ .data = arena_memdupz(arena, str.data, str.size), .size = str.size }; } else { return (String)STRING_INIT; } } -Array copy_array(Array array) +Array copy_array(Array array, Arena *arena) { - Array rv = ARRAY_DICT_INIT; + Array rv = arena_array(arena, array.size); for (size_t i = 0; i < array.size; i++) { - ADD(rv, copy_object(array.items[i])); + ADD(rv, copy_object(array.items[i], arena)); } return rv; } -Dictionary copy_dictionary(Dictionary dict) +Dictionary copy_dictionary(Dictionary dict, Arena *arena) { - Dictionary rv = ARRAY_DICT_INIT; + Dictionary rv = arena_dict(arena, dict.size); for (size_t i = 0; i < dict.size; i++) { KeyValuePair item = dict.items[i]; - PUT(rv, item.key.data, copy_object(item.value)); + PUT_C(rv, copy_string(item.key, arena).data, copy_object(item.value, arena)); } return rv; } /// Creates a deep clone of an object -Object copy_object(Object obj) +Object copy_object(Object obj, Arena *arena) { switch (obj.type) { case kObjectTypeBuffer: @@ -757,13 +784,13 @@ Object copy_object(Object obj) return obj; case kObjectTypeString: - return STRING_OBJ(copy_string(obj.data.string)); + return STRING_OBJ(copy_string(obj.data.string, arena)); case kObjectTypeArray: - return ARRAY_OBJ(copy_array(obj.data.array)); + return ARRAY_OBJ(copy_array(obj.data.array, arena)); case kObjectTypeDictionary: - return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary)); + return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary, arena)); case kObjectTypeLuaRef: return LUAREF_OBJ(api_new_luaref(obj.data.luaref)); @@ -844,7 +871,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err) goto free_exit; } - String str = copy_string(chunk.items[0].data.string); + String str = copy_string(chunk.items[0].data.string, NULL); int attr = 0; if (chunk.size == 2) { diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 4608554448..65215fa8c8 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -1,11 +1,11 @@ #ifndef NVIM_API_PRIVATE_HELPERS_H #define NVIM_API_PRIVATE_HELPERS_H +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/decoration.h" #include "nvim/ex_eval_defs.h" #include "nvim/getchar.h" -#include "nvim/lib/kvec.h" #include "nvim/memory.h" #include "nvim/vim.h" @@ -134,6 +134,7 @@ typedef struct { const msglist_T *const *msg_list; int trylevel; int got_int; + bool did_throw; int need_rethrow; int did_emsg; } TryState; diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 6f7bfa244a..e6d8cb2fdb 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -122,7 +122,7 @@ static char *mpack_array_dyn16(char **buf) static void mpack_str(char **buf, const char *str) { assert(sizeof(schar_T) - 1 < 0x20); - size_t len = STRLEN(str); + size_t len = strlen(str); mpack_w(buf, 0xa0 | len); memcpy(*buf, str, len); *buf += len; @@ -223,6 +223,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona ui->msg_set_pos = remote_ui_msg_set_pos; ui->event = remote_ui_event; ui->inspect = remote_ui_inspect; + ui->win_viewport = remote_ui_win_viewport; CLEAR_FIELD(ui->ui_ext); @@ -452,7 +453,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I } } -/// Tells Nvim the number of elements displaying in the popumenu, to decide +/// Tells Nvim the number of elements displaying in the popupmenu, to decide /// <PageUp> and <PageDown> movement. /// /// @param channel_id @@ -482,7 +483,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err) ui->pum_nlines = (int)height; } -/// Tells Nvim the geometry of the popumenu, to align floating windows with an +/// Tells Nvim the geometry of the popupmenu, to align floating windows with an /// external popup menu. /// /// Note that this method is not to be confused with |nvim_ui_pum_set_height()|, @@ -748,10 +749,12 @@ 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)); - 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))); + MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE); + MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE); + hlattrs2dict(&rgb, rgb_attrs, true); + hlattrs2dict(&cterm, rgb_attrs, false); + ADD_C(args, DICTIONARY_OBJ(rgb)); + ADD_C(args, DICTIONARY_OBJ(cterm)); if (ui->ui_ext[kUIHlState]) { ADD_C(args, ARRAY_OBJ(info)); @@ -771,8 +774,9 @@ static void remote_ui_highlight_set(UI *ui, int id) return; } data->hl_id = id; - MAXSIZE_TEMP_DICT(dict, 16); - ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb))); + MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); + hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb); + ADD_C(args, DICTIONARY_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -841,7 +845,7 @@ static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startc for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] - || STRCMP(chunk[i], chunk[i + 1])) { + || strcmp(chunk[i], chunk[i + 1])) { if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5)) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. @@ -952,65 +956,63 @@ static void remote_ui_flush(UI *ui) } } -static Array translate_contents(UI *ui, Array contents) +static Array translate_contents(UI *ui, Array contents, Arena *arena) { - Array new_contents = ARRAY_DICT_INIT; + Array new_contents = arena_array(arena, contents.size); for (size_t i = 0; i < contents.size; i++) { Array item = contents.items[i].data.array; - Array new_item = ARRAY_DICT_INIT; + Array new_item = arena_array(arena, 2); int attr = (int)item.items[0].data.integer; if (attr) { - Dictionary rgb_attrs = hlattrs2dict(NULL, syn_attr2entry(attr), ui->rgb); + Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); + hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb); ADD(new_item, DICTIONARY_OBJ(rgb_attrs)); } else { ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); } - ADD(new_item, copy_object(item.items[1])); + ADD(new_item, item.items[1]); ADD(new_contents, ARRAY_OBJ(new_item)); } return new_contents; } -static Array translate_firstarg(UI *ui, Array args) +static Array translate_firstarg(UI *ui, Array args, Arena *arena) { - Array new_args = ARRAY_DICT_INIT; + Array new_args = arena_array(arena, args.size); Array contents = args.items[0].data.array; - ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents))); + ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena))); for (size_t i = 1; i < args.size; i++) { - ADD(new_args, copy_object(args.items[i])); + ADD(new_args, args.items[i]); } return new_args; } static void remote_ui_event(UI *ui, char *name, Array args) { + Arena arena = ARENA_EMPTY; UIData *data = ui->data; if (!ui->ui_ext[kUILinegrid]) { // the representation of highlights in cmdline changed, translate back // never consumes args if (strequal(name, "cmdline_show")) { - Array new_args = translate_firstarg(ui, args); + Array new_args = translate_firstarg(ui, args, &arena); push_call(ui, name, new_args); - api_free_array(new_args); - return; + goto free_ret; } else if (strequal(name, "cmdline_block_show")) { Array new_args = data->call_buf; Array block = args.items[0].data.array; - Array new_block = ARRAY_DICT_INIT; + Array new_block = arena_array(&arena, block.size); for (size_t i = 0; i < block.size; i++) { - ADD(new_block, - ARRAY_OBJ(translate_contents(ui, block.items[i].data.array))); + ADD_C(new_block, ARRAY_OBJ(translate_contents(ui, block.items[i].data.array, &arena))); } ADD_C(new_args, ARRAY_OBJ(new_block)); push_call(ui, name, new_args); - api_free_array(new_block); - return; + goto free_ret; } else if (strequal(name, "cmdline_block_append")) { - Array new_args = translate_firstarg(ui, args); + Array new_args = translate_firstarg(ui, args, &arena); push_call(ui, name, new_args); - api_free_array(new_args); - return; + goto free_ret; } } @@ -1022,19 +1024,18 @@ static void remote_ui_event(UI *ui, char *name, Array args) if (data->wildmenu_active) { Array new_args = data->call_buf; Array items = args.items[0].data.array; - Array new_items = ARRAY_DICT_INIT; + Array new_items = arena_array(&arena, items.size); for (size_t i = 0; i < items.size; i++) { - ADD(new_items, copy_object(items.items[i].data.array.items[0])); + ADD_C(new_items, items.items[i].data.array.items[0]); } ADD_C(new_args, ARRAY_OBJ(new_items)); push_call(ui, "wildmenu_show", new_args); - api_free_array(new_items); if (args.items[1].data.integer != -1) { Array new_args2 = data->call_buf; ADD_C(new_args2, args.items[1]); push_call(ui, "wildmenu_select", new_args2); } - return; + goto free_ret; } } else if (strequal(name, "popupmenu_select")) { if (data->wildmenu_active) { @@ -1048,6 +1049,10 @@ static void remote_ui_event(UI *ui, char *name, Array args) } push_call(ui, name, args); + return; + +free_ret: + arena_mem_free(arena_finish(&arena)); } static void remote_ui_inspect(UI *ui, Dictionary *info) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 8b7e01e1c3..17930dca85 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -100,7 +100,7 @@ void raw_line(Integer grid, Integer row, Integer startcol, FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; void event(char *name, Array args) - FUNC_API_NOEXPORT; + FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; void win_pos(Integer grid, Window win, Integer startrow, Integer startcol, Integer width, Integer height) @@ -121,7 +121,7 @@ void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char) void win_viewport(Integer grid, Window win, Integer topline, Integer botline, Integer curline, Integer curcol, Integer line_count) - FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(7) FUNC_API_BRIDGE_IMPL; void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, Integer row, Integer col) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ce91c1b4af..fa8d26914a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -66,7 +66,7 @@ #include "nvim/viml/parser/parser.h" #include "nvim/window.h" -#define LINE_BUFFER_SIZE 4096 +#define LINE_BUFFER_MIN_SIZE 4096 #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/vim.c.generated.h" @@ -79,19 +79,17 @@ /// @param[out] err Error details, if any /// @return Highlight definition map /// @see nvim_get_hl_by_id -Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err) +Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err) FUNC_API_SINCE(3) { Dictionary result = ARRAY_DICT_INIT; int id = syn_name2id(name.data); if (id == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", - name.data); + api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); return result; } - result = nvim_get_hl_by_id(id, rgb, err); - return result; + return nvim_get_hl_by_id(id, rgb, arena, err); } /// Gets a highlight definition by id. |hlID()| @@ -100,17 +98,16 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err) /// @param[out] err Error details, if any /// @return Highlight definition map /// @see nvim_get_hl_by_name -Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) +Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err) FUNC_API_SINCE(3) { Dictionary dic = ARRAY_DICT_INIT; if (syn_get_final_id((int)hl_id) == 0) { - api_set_error(err, kErrorTypeException, - "Invalid highlight id: %" PRId64, hl_id); + api_set_error(err, kErrorTypeException, "Invalid highlight id: %" PRId64, hl_id); return dic; } int attrcode = syn_id2attr((int)hl_id); - return hl_get_attr_by_id(attrcode, rgb, err); + return hl_get_attr_by_id(attrcode, rgb, arena, err); } /// Gets a highlight group by name @@ -122,10 +119,10 @@ Integer nvim_get_hl_id_by_name(String name) return syn_check_group(name.data, name.size); } -Dictionary nvim__get_hl_defs(Integer ns_id, Error *err) +Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err) { if (ns_id == 0) { - return get_global_hl_defs(); + return get_global_hl_defs(arena); } abort(); } @@ -163,8 +160,8 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err) /// - nocombine: boolean /// - link: name of another highlight group to link to, see |:hi-link|. /// - default: Don't override existing definition |:hi-default| -/// - ctermfg: Sets foreground of cterm color |highlight-ctermfg| -/// - ctermbg: Sets background of cterm color |highlight-ctermbg| +/// - ctermfg: Sets foreground of cterm color |ctermfg| +/// - ctermbg: Sets background of cterm color |ctermbg| /// - cterm: cterm attribute map, like |highlight-args|. If not set, /// cterm attributes will match those from the attribute map /// documented above. @@ -175,6 +172,10 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) FUNC_API_SINCE(7) { int hl_id = syn_check_group(name.data, name.size); + if (hl_id == 0) { + api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); + return; + } int link_id = -1; HlAttrs attrs = dict2hlattrs(val, true, &link_id, err); @@ -184,7 +185,7 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) } /// Set active namespace for highlights. This can be set for a single window, -/// see |nvim_win_set_hl_ns|. +/// see |nvim_win_set_hl_ns()|. /// /// @param ns_id the namespace to use /// @param[out] err Error details, if any @@ -198,13 +199,13 @@ void nvim_set_hl_ns(Integer ns_id, Error *err) ns_hl_global = (NS)ns_id; hl_check_ns(); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } /// Set active namespace for highlights while redrawing. /// /// This function meant to be called while redrawing, primarily from -/// |nvim_set_decoration_provider| on_win and on_line callbacks, which +/// |nvim_set_decoration_provider()| on_win and on_line callbacks, which /// are allowed to change the namespace during a redraw cycle. /// /// @param ns_id the namespace to activate @@ -335,9 +336,9 @@ Integer nvim_input(String keys) /// mouse input in a GUI. The deprecated pseudokey form /// ("<LeftMouse><col,row>") of |nvim_input()| has the same limitation. /// -/// @param button Mouse button: one of "left", "right", "middle", "wheel". +/// @param button Mouse button: one of "left", "right", "middle", "wheel", "move". /// @param action For ordinary buttons, one of "press", "drag", "release". -/// For the wheel, one of "up", "down", "left", "right". +/// For the wheel, one of "up", "down", "left", "right". Ignored for "move". /// @param modifier String of modifiers each represented by a single char. /// The same specifiers are used as for a key press, except /// that the "-" separator is optional, so "C-A-", "c-a" @@ -364,6 +365,8 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri code = KE_RIGHTMOUSE; } else if (strequal(button.data, "wheel")) { code = KE_MOUSEDOWN; + } else if (strequal(button.data, "move")) { + code = KE_MOUSEMOVE; } else { goto error; } @@ -380,7 +383,7 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri } else { goto error; } - } else { + } else if (code != KE_MOUSEMOVE) { if (strequal(action.data, "press")) { // pass } else if (strequal(action.data, "drag")) { @@ -520,7 +523,7 @@ Array nvim__runtime_inspect(void) /// Find files in runtime directories /// -/// 'name' can contain wildcards. For example +/// "name" can contain wildcards. For example /// nvim_get_runtime_file("colors/*.vim", true) will return all color /// scheme files. Always use forward slashes (/) in the search pattern for /// subdirectories regardless of platform. @@ -961,7 +964,7 @@ fail: /// mode. Note: keypresses are sent raw as they would be to the pty /// master end. For instance, a carriage return is sent /// as a "\r", not as a "\n". |textlock| applies. It is possible -/// to call |nvim_chan_send| directly in the callback however. +/// to call |nvim_chan_send()| directly in the callback however. /// ["input", term, bufnr, data] /// @param[out] err Error details, if any /// @return Channel id, or 0 on error @@ -1419,10 +1422,10 @@ Dictionary nvim_get_mode(void) /// @param mode Mode short-name ("n", "i", "v", ...) /// @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) +ArrayOf(Dictionary) nvim_get_keymap(String mode) FUNC_API_SINCE(3) { - return keymap_array(mode, NULL, channel_id == LUA_INTERNAL_CALL); + return keymap_array(mode, NULL); } /// Sets a global |mapping| for the given mode. @@ -1449,7 +1452,7 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode) /// @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. +/// |: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. @@ -1479,14 +1482,14 @@ void nvim_del_keymap(uint64_t channel_id, String mode, String lhs, Error *err) /// 1 is the |api-metadata| map (Dictionary). /// /// @returns 2-tuple [{channel-id}, {api-metadata}] -Array nvim_get_api_info(uint64_t channel_id) +Array nvim_get_api_info(uint64_t channel_id, Arena *arena) FUNC_API_SINCE(1) FUNC_API_FAST FUNC_API_REMOTE_ONLY { - Array rv = ARRAY_DICT_INIT; + Array rv = arena_array(arena, 2); assert(channel_id <= INT64_MAX); - ADD(rv, INTEGER_OBJ((int64_t)channel_id)); - ADD(rv, DICTIONARY_OBJ(api_metadata())); + ADD_C(rv, INTEGER_OBJ((int64_t)channel_id)); + ADD_C(rv, DICTIONARY_OBJ(api_metadata())); return rv; } @@ -1545,9 +1548,9 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY { Dictionary info = ARRAY_DICT_INIT; - PUT(info, "name", copy_object(STRING_OBJ(name))); + PUT(info, "name", copy_object(STRING_OBJ(name), NULL)); - version = copy_dictionary(version); + version = copy_dictionary(version, NULL); bool has_major = false; for (size_t i = 0; i < version.size; i++) { if (strequal(version.items[i].key.data, "major")) { @@ -1560,9 +1563,9 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, } PUT(info, "version", DICTIONARY_OBJ(version)); - PUT(info, "type", copy_object(STRING_OBJ(type))); - PUT(info, "methods", DICTIONARY_OBJ(copy_dictionary(methods))); - PUT(info, "attributes", DICTIONARY_OBJ(copy_dictionary(attributes))); + PUT(info, "type", copy_object(STRING_OBJ(type), NULL)); + PUT(info, "methods", DICTIONARY_OBJ(copy_dictionary(methods, NULL))); + PUT(info, "attributes", DICTIONARY_OBJ(copy_dictionary(attributes, NULL))); rpc_set_client_info(channel_id, info); } @@ -1629,11 +1632,11 @@ Array nvim_list_chans(void) /// an error, it is a three-element array with the zero-based index of the call /// which resulted in an error, the error type and the error message. If an /// error occurred, the values from all preceding calls will still be returned. -Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) +Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - Array rv = ARRAY_DICT_INIT; - Array results = ARRAY_DICT_INIT; + Array rv = arena_array(arena, 2); + Array results = arena_array(arena, calls.size); Error nested_error = ERROR_INIT; size_t i; // also used for freeing the variables @@ -1642,21 +1645,21 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) api_set_error(err, kErrorTypeValidation, "Items in calls array must be arrays"); - goto validation_error; + goto theend; } Array call = calls.items[i].data.array; if (call.size != 2) { api_set_error(err, kErrorTypeValidation, "Items in calls array must be arrays of size 2"); - goto validation_error; + goto theend; } if (call.items[0].type != kObjectTypeString) { api_set_error(err, kErrorTypeValidation, "Name must be String"); - goto validation_error; + goto theend; } String name = call.items[0].data.string; @@ -1664,7 +1667,7 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) api_set_error(err, kErrorTypeValidation, "Args must be Array"); - goto validation_error; + goto theend; } Array args = call.items[1].data.array; @@ -1676,29 +1679,32 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) if (ERROR_SET(&nested_error)) { break; } - Object result = handler.fn(channel_id, args, &nested_error); + + Object result = handler.fn(channel_id, args, arena, &nested_error); if (ERROR_SET(&nested_error)) { // error handled after loop break; } - - ADD(results, result); + // TODO(bfredl): wastefull copy. It could be avoided to encoding to msgpack + // directly here. But `result` might become invalid when next api function + // is called in the loop. + ADD_C(results, copy_object(result, arena)); + if (!handler.arena_return) { + api_free_object(result); + } } - ADD(rv, ARRAY_OBJ(results)); + ADD_C(rv, ARRAY_OBJ(results)); if (ERROR_SET(&nested_error)) { - Array errval = ARRAY_DICT_INIT; - ADD(errval, INTEGER_OBJ((Integer)i)); - ADD(errval, INTEGER_OBJ(nested_error.type)); - ADD(errval, STRING_OBJ(cstr_to_string(nested_error.msg))); - ADD(rv, ARRAY_OBJ(errval)); + Array errval = arena_array(arena, 3); + ADD_C(errval, INTEGER_OBJ((Integer)i)); + ADD_C(errval, INTEGER_OBJ(nested_error.type)); + ADD_C(errval, STRING_OBJ(copy_string(cstr_as_string(nested_error.msg), arena))); + ADD_C(rv, ARRAY_OBJ(errval)); } else { - ADD(rv, NIL); + ADD_C(rv, NIL); } - goto theend; -validation_error: - api_free_array(results); theend: api_clear_error(&nested_error); return rv; @@ -1712,17 +1718,21 @@ theend: /// @param to_err true: message is an error (uses `emsg` instead of `msg`) static void write_msg(String message, bool to_err) { - static size_t out_pos = 0, err_pos = 0; - static char out_line_buf[LINE_BUFFER_SIZE], err_line_buf[LINE_BUFFER_SIZE]; + static StringBuilder out_line_buf = KV_INITIAL_VALUE; + static StringBuilder err_line_buf = KV_INITIAL_VALUE; -#define PUSH_CHAR(i, pos, line_buf, msg) \ - if (message.data[i] == NL || (pos) == LINE_BUFFER_SIZE - 1) { \ - (line_buf)[pos] = NUL; \ - msg(line_buf); \ - (pos) = 0; \ +#define PUSH_CHAR(i, line_buf, msg) \ + if (kv_max(line_buf) == 0) { \ + kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ + } \ + if (message.data[i] == NL) { \ + kv_push(line_buf, NUL); \ + msg(line_buf.items); \ + kv_drop(line_buf, kv_size(line_buf)); \ + kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \ continue; \ } \ - (line_buf)[(pos)++] = message.data[i]; + kv_push(line_buf, message.data[i]); no_wait_return++; for (uint32_t i = 0; i < message.size; i++) { @@ -1730,9 +1740,9 @@ static void write_msg(String message, bool to_err) break; } if (to_err) { - PUSH_CHAR(i, err_pos, err_line_buf, emsg); + PUSH_CHAR(i, err_line_buf, emsg); } else { - PUSH_CHAR(i, out_pos, out_line_buf, msg); + PUSH_CHAR(i, out_line_buf, msg); } } no_wait_return--; @@ -1751,7 +1761,7 @@ static void write_msg(String message, bool to_err) /// @return its argument. Object nvim__id(Object obj) { - return copy_object(obj); + return copy_object(obj, NULL); } /// Returns array given as argument. @@ -1764,7 +1774,7 @@ Object nvim__id(Object obj) /// @return its argument. Array nvim__id_array(Array arr) { - return copy_object(ARRAY_OBJ(arr)).data.array; + return copy_array(arr, NULL); } /// Returns dictionary given as argument. @@ -1777,7 +1787,7 @@ Array nvim__id_array(Array arr) /// @return its argument. Dictionary nvim__id_dictionary(Dictionary dct) { - return copy_object(DICTIONARY_OBJ(dct)).data.dictionary; + return copy_dictionary(dct, NULL); } /// Returns floating-point value given as argument. @@ -1803,6 +1813,7 @@ Dictionary nvim__stats(void) PUT(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip)); PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count())); PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw)); + PUT(rv, "arena_alloc_count", INTEGER_OBJ((Integer)arena_alloc_count)); return rv; } @@ -1875,7 +1886,7 @@ Object nvim_get_proc(Integer pid, Error *err) api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid); return NIL; } -#ifdef WIN32 +#ifdef MSWIN rvobj.data.dictionary = os_proc_info((int)pid); if (rvobj.data.dictionary.size == 0) { // Process not found. return NIL; @@ -1928,7 +1939,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di } /// NB: if your UI doesn't use hlstate, this will not return hlstate first time -Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err) +Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, Error *err) { Array ret = ARRAY_DICT_INIT; @@ -1952,13 +1963,14 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err) || col < 0 || col >= g->cols) { return ret; } + ret = arena_array(arena, 3); size_t off = g->line_offset[(size_t)row] + (size_t)col; - ADD(ret, STRING_OBJ(cstr_to_string((char *)g->chars[off]))); + ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off]))); int attr = g->attrs[off]; - ADD(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, err))); + ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err))); // will not work first time if (!highlight_use_hlstate()) { - ADD(ret, ARRAY_OBJ(hl_inspect(attr))); + ADD_C(ret, ARRAY_OBJ(hl_inspect(attr))); } return ret; } @@ -2040,7 +2052,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) // Marks are from an open buffer it fnum is non zero if (mark->fmark.fnum != 0) { bufnr = mark->fmark.fnum; - filename = (char *)buflist_nr2name(bufnr, true, true); + filename = buflist_nr2name(bufnr, true, true); allocated = true; // Marks comes from shada } else { @@ -2088,7 +2100,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) /// 'fillchars'). Treated as single-width even if it isn't. /// - highlights: (boolean) Return highlight information. /// - use_winbar: (boolean) Evaluate winbar instead of statusline. -/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When |TRUE|, {winid} +/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} /// is ignored. Mutually exclusive with {use_winbar}. /// /// @param[out] err Error details, if any. @@ -2096,7 +2108,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) /// - str: (string) Characters that will be displayed on the statusline. /// - width: (number) Display width of the statusline. /// - highlights: Array containing highlight information of the statusline. Only included when -/// the "highlights" key in {opts} is |TRUE|. Each element of the array is a +/// the "highlights" key in {opts} is true. Each element of the array is a /// |Dictionary| with these keys: /// - start: (number) Byte index (0-based) of first character that uses the highlight. /// - group: (string) Name of highlight group. @@ -2228,7 +2240,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * // If first character doesn't have a defined highlight, // add the default highlight at the beginning of the highlight list - if (hltab->start == NULL || ((char *)hltab->start - buf) != 0) { + if (hltab->start == NULL || (hltab->start - buf) != 0) { Dictionary hl_info = ARRAY_DICT_INIT; grpname = get_default_stl_hl(wp, use_winbar); diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index a28bfd2ab9..71209c9ab6 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -137,7 +137,7 @@ Object nvim_eval(String expr, Error *err) if (!recursive) { force_abort = false; suppress_errthrow = false; - current_exception = NULL; + did_throw = false; // `did_emsg` is set by emsg(), which cancels execution. did_emsg = false; } @@ -196,7 +196,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err) if (!recursive) { force_abort = false; suppress_errthrow = false; - current_exception = NULL; + did_throw = false; // `did_emsg` is set by emsg(), which cancels execution. did_emsg = false; } @@ -204,10 +204,10 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err) try_start(); typval_T rettv; funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = true; - funcexe.selfdict = self; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; + funcexe.fe_selfdict = self; // call_func() retval is deceptive, ignore it. Instead we set `msg_list` // (see above) to capture abort-causing non-exception errors. (void)call_func(fn.data, (int)fn.size, &rettv, (int)args.size, @@ -304,7 +304,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err) } fn = (String) { .data = di->di_tv.vval.v_string, - .size = STRLEN(di->di_tv.vval.v_string), + .size = strlen(di->di_tv.vval.v_string), }; } diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 0c89726d71..7523ff301d 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -109,7 +109,7 @@ /// is changed to `auto` and 'colorcolumn' is cleared. The /// end-of-buffer region is hidden by setting `eob` flag of /// 'fillchars' to a space char, and clearing the -/// |EndOfBuffer| region in 'winhighlight'. +/// |hl-EndOfBuffer| region in 'winhighlight'. /// - border: Style of (optional) window border. This can either be a string /// or an array. The string values are /// - "none": No border (default). @@ -202,7 +202,7 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) if (!win_new_float(win, false, fconfig, err)) { return; } - redraw_later(win, NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } else { win_config_float(win, fconfig); win->w_pos_changed = true; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 580dfd8639..08dcc113da 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -51,7 +51,9 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) win_set_buf(window, buffer, false, err); } -/// Gets the (1,0)-indexed cursor position in the window. |api-indexing| +/// Gets the (1,0)-indexed, buffer-relative cursor position for a given window +/// (different windows showing the same buffer have independent cursor +/// positions). |api-indexing| /// /// @param window Window handle, or 0 for current window /// @param[out] err Error details, if any @@ -118,7 +120,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) // make sure cursor is in visible range even if win != curwin update_topline_win(win); - redraw_later(win, VALID); + redraw_later(win, UPD_VALID); win->w_redr_status = true; } @@ -340,7 +342,7 @@ Boolean nvim_win_is_valid(Window window) /// /// Like |:hide| the buffer becomes hidden unless another window is editing it, /// or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to |:close| or -/// |nvim_win_close|, which will close the buffer. +/// |nvim_win_close()|, which will close the buffer. /// /// @param window Window handle, or 0 for current window /// @param[out] err Error details, if any @@ -430,7 +432,7 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err) /// Set highlight namespace for a window. This will use highlights defined in /// this namespace, but fall back to global highlights (ns=0) when missing. /// -/// This takes predecence over the 'winhighlight' option. +/// This takes precedence over the 'winhighlight' option. /// /// @param ns_id the namespace to use /// @param[out] err Error details, if any @@ -449,5 +451,5 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) win->w_ns_hl = (NS)ns_id; win->w_hl_needs_update = true; - redraw_later(win, NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c index 06536e6e2b..b57019286f 100644 --- a/src/nvim/arabic.c +++ b/src/nvim/arabic.c @@ -320,22 +320,22 @@ int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1, int next_c) int backward_combine = !prev_laa && can_join(prev_c, c); int forward_combine = can_join(c, next_c); - if (backward_combine && forward_combine) { - curr_c = (int)curr_a->medial; - } - if (backward_combine && !forward_combine) { - curr_c = (int)curr_a->final; - } - if (!backward_combine && forward_combine) { - curr_c = (int)curr_a->initial; - } - if (!backward_combine && !forward_combine) { - curr_c = (int)curr_a->isolated; + if (backward_combine) { + if (forward_combine) { + curr_c = (int)curr_a->medial; + } else { + curr_c = (int)curr_a->final; + } + } else { + if (forward_combine) { + curr_c = (int)curr_a->initial; + } else { + curr_c = (int)curr_a->isolated; + } } } - // Sanity check -- curr_c should, in the future, never be 0. - // We should, in the future, insert a fatal error here. + // Character missing from the table means using original character. if (curr_c == NUL) { curr_c = c; } diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index 0be83f0c05..c7af1a71be 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -27,19 +27,57 @@ #include "nvim/vim.h" #include "nvim/window.h" +/// State used by the :all command to open all the files in the argument list in +/// separate windows. +typedef struct { + alist_T *alist; ///< argument list to be used + int had_tab; + bool keep_tabs; + bool forceit; + + bool use_firstwin; ///< use first window for arglist + uint8_t *opened; ///< Array of weight for which args are open: + ///< 0: not opened + ///< 1: opened in other tab + ///< 2: opened in curtab + ///< 3: opened in curtab and curwin + int opened_len; ///< length of opened[] + win_T *new_curwin; + tabpage_T *new_curtab; +} arg_all_state_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "arglist.c.generated.h" #endif +static char e_cannot_change_arglist_recursively[] + = N_("E1156: Cannot change the argument list recursively"); + enum { AL_SET = 1, AL_ADD = 2, AL_DEL = 3, }; +/// This flag is set whenever the argument list is being changed and calling a +/// function that might trigger an autocommand. +static bool arglist_locked = false; + +static int check_arglist_locked(void) +{ + if (arglist_locked) { + emsg(_(e_cannot_change_arglist_recursively)); + return FAIL; + } + return OK; +} + /// Clear an argument list: free all file names and reset it to zero entries. void alist_clear(alist_T *al) { + if (check_arglist_locked() == FAIL) { + return; + } #define FREE_AENTRY_FNAME(arg) xfree((arg)->ae_fname) GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME); } @@ -79,13 +117,14 @@ void alist_expand(int *fnum_list, int fnum_len) { char *save_p_su = p_su; + char **old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT); + // Don't use 'suffixes' here. This should work like the shell did the // expansion. Also, the vimrc file isn't read yet, thus the user // can't set the options. p_su = empty_option; - char **old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT); for (int i = 0; i < GARGCOUNT; i++) { - old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname); + old_arg_files[i] = xstrdup(GARGLIST[i].ae_fname); } int old_arg_count = GARGCOUNT; char **new_arg_files; @@ -106,13 +145,9 @@ void alist_expand(int *fnum_list, int fnum_len) /// Takes over the allocated files[] and the allocated fnames in it. void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_list, int fnum_len) { - static int recursive = 0; - - if (recursive) { - emsg(_(e_au_recursive)); + if (check_arglist_locked() == FAIL) { return; } - recursive++; alist_clear(al); ga_grow(&al->al_ga, count); @@ -130,7 +165,9 @@ void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_l // May set buffer name of a buffer previously used for the // argument list, so that it's re-used by alist_add. if (fnum_list != NULL && i < fnum_len) { + arglist_locked = true; buf_set_name(fnum_list[i], files[i]); + arglist_locked = false; } alist_add(al, files[i], use_curbuf ? 2 : 1); @@ -142,7 +179,6 @@ void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_l if (al == &global_alist) { arg_had_last = false; } - recursive--; } /// Add file "fname" to argument list "al". @@ -154,15 +190,22 @@ void alist_add(alist_T *al, char *fname, int set_fnum) if (fname == NULL) { // don't add NULL file names return; } + if (check_arglist_locked() == FAIL) { + return; + } + arglist_locked = true; + #ifdef BACKSLASH_IN_FILENAME slash_adjust(fname); #endif - AARGLIST(al)[al->al_ga.ga_len].ae_fname = (char_u *)fname; + AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; if (set_fnum > 0) { AARGLIST(al)[al->al_ga.ga_len].ae_fnum = buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); } al->al_ga.ga_len++; + + arglist_locked = false; } #if defined(BACKSLASH_IN_FILENAME) @@ -202,7 +245,7 @@ static char *do_one_arg(char *str) for (p = str; *str; str++) { // When the backslash is used for escaping the special meaning of a // character we need to keep it until wildcard expansion. - if (rem_backslash((char_u *)str)) { + if (rem_backslash(str)) { *p++ = *str++; *p++ = *str; } else { @@ -226,7 +269,7 @@ static char *do_one_arg(char *str) /// growarray "gap". static void get_arglist(garray_T *gap, char *str, int escaped) { - ga_init(gap, (int)sizeof(char_u *), 20); + ga_init(gap, (int)sizeof(char *), 20); while (*str != NUL) { GA_APPEND(char *, gap, str); @@ -244,12 +287,12 @@ 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 ***fnamesp, bool wig) +int get_arglist_exp(char *str, int *fcountp, char ***fnamesp, bool wig) { garray_T ga; int i; - get_arglist(&ga, (char *)str, true); + get_arglist(&ga, str, true); if (wig) { i = expand_wildcards(ga.ga_len, ga.ga_data, @@ -284,7 +327,7 @@ static void alist_add_list(int count, char **files, int after, bool will_edit) { int old_argcount = ARGCOUNT; ga_grow(&ALIST(curwin)->al_ga, count); - { + if (check_arglist_locked() != FAIL) { if (after < 0) { after = 0; } @@ -295,11 +338,13 @@ static void alist_add_list(int count, char **files, int after, bool will_edit) memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), (size_t)(ARGCOUNT - after) * sizeof(aentry_T)); } + arglist_locked = true; for (int i = 0; i < count; i++) { const int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); - ARGLIST[after + i].ae_fname = (char_u *)files[i]; + ARGLIST[after + i].ae_fname = files[i]; ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); } + arglist_locked = false; ALIST(curwin)->al_ga.ga_len += count; if (old_argcount > 0 && curwin->w_arg_idx >= after) { curwin->w_arg_idx += count; @@ -308,6 +353,50 @@ static void alist_add_list(int count, char **files, int after, bool will_edit) } } +/// Delete the file names in "alist_ga" from the argument list. +static void arglist_del_files(garray_T *alist_ga) +{ + regmatch_T regmatch; + + // Delete the items: use each item as a regexp and find a match in the + // argument list. + regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set + for (int i = 0; i < alist_ga->ga_len && !got_int; i++) { + char *p = ((char **)alist_ga->ga_data)[i]; + p = file_pat_to_reg_pat(p, NULL, NULL, false); + if (p == NULL) { + break; + } + regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); + if (regmatch.regprog == NULL) { + xfree(p); + break; + } + + bool didone = false; + for (int match = 0; match < ARGCOUNT; match++) { + if (vim_regexec(®match, alist_name(&ARGLIST[match]), (colnr_T)0)) { + didone = true; + xfree(ARGLIST[match].ae_fname); + memmove(ARGLIST + match, ARGLIST + match + 1, + (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T)); + ALIST(curwin)->al_ga.ga_len--; + if (curwin->w_arg_idx > match) { + curwin->w_arg_idx--; + } + match--; + } + } + + vim_regfree(regmatch.regprog); + xfree(p); + if (!didone) { + semsg(_(e_nomatch2), ((char **)alist_ga->ga_data)[i]); + } + } + ga_clear(alist_ga); +} + /// @param str /// @param what /// AL_SET: Redefine the argument list to 'str'. @@ -324,10 +413,12 @@ static int do_arglist(char *str, int what, int after, bool will_edit) garray_T new_ga; int exp_count; char **exp_files; - char *p; - int match; int arg_escaped = true; + if (check_arglist_locked() == FAIL) { + return FAIL; + } + // Set default argument for ":argadd" command. if (what == AL_ADD && *str == NUL) { if (curbuf->b_ffname == NULL) { @@ -341,46 +432,7 @@ static int do_arglist(char *str, int what, int after, bool will_edit) get_arglist(&new_ga, str, arg_escaped); if (what == AL_DEL) { - regmatch_T regmatch; - bool didone; - - // Delete the items: use each item as a regexp and find a match in the - // argument list. - regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set - for (int i = 0; i < new_ga.ga_len && !got_int; i++) { - p = ((char **)new_ga.ga_data)[i]; - p = file_pat_to_reg_pat(p, NULL, NULL, false); - if (p == NULL) { - break; - } - regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); - if (regmatch.regprog == NULL) { - xfree(p); - break; - } - - didone = false; - for (match = 0; match < ARGCOUNT; match++) { - if (vim_regexec(®match, alist_name(&ARGLIST[match]), (colnr_T)0)) { - didone = true; - xfree(ARGLIST[match].ae_fname); - memmove(ARGLIST + match, ARGLIST + match + 1, - (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T)); - ALIST(curwin)->al_ga.ga_len--; - if (curwin->w_arg_idx > match) { - curwin->w_arg_idx--; - } - match--; - } - } - - vim_regfree(regmatch.regprog); - xfree(p); - if (!didone) { - semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]); - } - } - ga_clear(&new_ga); + arglist_del_files(&new_ga); } else { int i = expand_wildcards(new_ga.ga_len, new_ga.ga_data, &exp_count, &exp_files, @@ -457,6 +509,9 @@ void check_arg_idx(win_T *win) void ex_args(exarg_T *eap) { if (eap->cmdidx != CMD_args) { + if (check_arglist_locked() == FAIL) { + return; + } alist_unlink(ALIST(curwin)); if (eap->cmdidx == CMD_argglobal) { ALIST(curwin) = &global_alist; @@ -465,34 +520,47 @@ void ex_args(exarg_T *eap) } } + // ":args file ..": define new argument list, handle like ":next" + // Also for ":argslocal file .." and ":argsglobal file ..". if (*eap->arg != NUL) { - // ":args file ..": define new argument list, handle like ":next" - // Also for ":argslocal file .." and ":argsglobal file ..". + if (check_arglist_locked() == FAIL) { + return; + } ex_next(eap); - } else if (eap->cmdidx == CMD_args) { - // ":args": list arguments. - if (ARGCOUNT > 0) { - char **items = xmalloc(sizeof(char_u *) * (size_t)ARGCOUNT); - // Overwrite the command, for a short list there is no scrolling - // required and no wait_return(). - gotocmdline(true); - for (int i = 0; i < ARGCOUNT; i++) { - items[i] = alist_name(&ARGLIST[i]); - } - list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); - xfree(items); + return; + } + + // ":args": list arguments. + if (eap->cmdidx == CMD_args) { + if (ARGCOUNT <= 0) { + return; // empty argument list } - } else if (eap->cmdidx == CMD_arglocal) { + + char **items = xmalloc(sizeof(char *) * (size_t)ARGCOUNT); + + // Overwrite the command, for a short list there is no scrolling + // required and no wait_return(). + gotocmdline(true); + + for (int i = 0; i < ARGCOUNT; i++) { + items[i] = alist_name(&ARGLIST[i]); + } + list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); + xfree(items); + + return; + } + + // ":argslocal": make a local copy of the global argument list. + if (eap->cmdidx == CMD_arglocal) { garray_T *gap = &curwin->w_alist->al_ga; - // ":argslocal": make a local copy of the global argument list. ga_grow(gap, GARGCOUNT); + for (int i = 0; i < GARGCOUNT; i++) { if (GARGLIST[i].ae_fname != NULL) { - AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = - vim_strsave(GARGLIST[i].ae_fname); - AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = - GARGLIST[i].ae_fnum; + AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = xstrdup(GARGLIST[i].ae_fname); + AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = GARGLIST[i].ae_fnum; gap->ga_len++; } } @@ -626,7 +694,7 @@ void ex_argdedupe(exarg_T *eap FUNC_ATTR_UNUSED) { for (int i = 0; i < ARGCOUNT; i++) { for (int j = i + 1; j < ARGCOUNT; j++) { - if (FNAMECMP(ARGLIST[i].ae_fname, ARGLIST[j].ae_fname) == 0) { + if (path_fnamecmp(ARGLIST[i].ae_fname, ARGLIST[j].ae_fname) == 0) { xfree(ARGLIST[j].ae_fname); memmove(ARGLIST + j, ARGLIST + j + 1, (size_t)(ARGCOUNT - j - 1) * sizeof(aentry_T)); @@ -679,6 +747,10 @@ void ex_argadd(exarg_T *eap) /// ":argdelete" void ex_argdelete(exarg_T *eap) { + if (check_arglist_locked() == FAIL) { + return; + } + if (eap->addr_count > 0 || *eap->arg == NUL) { // ":argdel" works like ":.argdel" if (eap->addr_count == 0) { @@ -742,81 +814,37 @@ char *alist_name(aentry_T *aep) // Use the name from the associated buffer if it exists. bp = buflist_findnr(aep->ae_fnum); if (bp == NULL || bp->b_fname == NULL) { - return (char *)aep->ae_fname; + return aep->ae_fname; } return bp->b_fname; } -/// do_arg_all(): Open up to 'count' windows, one for each argument. -/// -/// @param forceit hide buffers in current windows -/// @param keep_tabs keep current tabs, for ":tab drop file" -static void do_arg_all(int count, int forceit, int keep_tabs) +/// Close all the windows containing files which are not in the argument list. +/// Used by the ":all" command. +static void arg_all_close_unused_windows(arg_all_state_T *aall) { - uint8_t *opened; // Array of weight for which args are open: - // 0: not opened - // 1: opened in other tab - // 2: opened in curtab - // 3: opened in curtab and curwin - - int opened_len; // length of opened[] - int use_firstwin = false; // use first window for arglist - bool tab_drop_empty_window = false; - int split_ret = OK; - bool p_ea_save; - alist_T *alist; // argument list to be used - buf_T *buf; - tabpage_T *tpnext; - int had_tab = cmdmod.cmod_tab; - win_T *old_curwin, *last_curwin; - tabpage_T *old_curtab, *last_curtab; - win_T *new_curwin = NULL; - tabpage_T *new_curtab = NULL; - - assert(firstwin != NULL); // satisfy coverity + win_T *old_curwin = curwin; + tabpage_T *old_curtab = curtab; - if (ARGCOUNT <= 0) { - // Don't give an error message. We don't want it when the ":all" command is in the .vimrc. - return; - } - setpcmark(); - - opened_len = ARGCOUNT; - opened = xcalloc((size_t)opened_len, 1); - - // Autocommands may do anything to the argument list. Make sure it's not - // freed while we are working here by "locking" it. We still have to - // watch out for its size to be changed. - alist = curwin->w_alist; - alist->al_refcount++; - - old_curwin = curwin; - old_curtab = curtab; - - // Try closing all windows that are not in the argument list. - // Also close windows that are not full width; - // When 'hidden' or "forceit" set the buffer becomes hidden. - // Windows that have a changed buffer and can't be hidden won't be closed. - // When the ":tab" modifier was used do this for all tab pages. - if (had_tab > 0) { + if (aall->had_tab > 0) { goto_tabpage_tp(first_tabpage, true, true); } for (;;) { win_T *wpnext = NULL; - tpnext = curtab->tp_next; + tabpage_T *tpnext = curtab->tp_next; for (win_T *wp = firstwin; wp != NULL; wp = wpnext) { int i; wpnext = wp->w_next; - buf = wp->w_buffer; + buf_T *buf = wp->w_buffer; if (buf->b_ffname == NULL - || (!keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) { - i = opened_len; + || (!aall->keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) { + i = aall->opened_len; } else { // check if the buffer in this window is in the arglist - for (i = 0; i < opened_len; i++) { - if (i < alist->al_ga.ga_len - && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum - || path_full_compare(alist_name(&AARGLIST(alist)[i]), + for (i = 0; i < aall->opened_len; i++) { + if (i < aall->alist->al_ga.ga_len + && (AARGLIST(aall->alist)[i].ae_fnum == buf->b_fnum + || path_full_compare(alist_name(&AARGLIST(aall->alist)[i]), buf->b_ffname, true, true) & kEqualFiles)) { int weight = 1; @@ -828,23 +856,24 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } } - if (weight > (int)opened[i]) { - opened[i] = (uint8_t)weight; + if (weight > (int)aall->opened[i]) { + aall->opened[i] = (uint8_t)weight; if (i == 0) { - if (new_curwin != NULL) { - new_curwin->w_arg_idx = opened_len; + if (aall->new_curwin != NULL) { + aall->new_curwin->w_arg_idx = aall->opened_len; } - new_curwin = wp; - new_curtab = curtab; + aall->new_curwin = wp; + aall->new_curtab = curtab; } - } else if (keep_tabs) { - i = opened_len; + } else if (aall->keep_tabs) { + i = aall->opened_len; } - if (wp->w_alist != alist) { - // Use the current argument list for all windows containing a file from it. + if (wp->w_alist != aall->alist) { + // Use the current argument list for all windows + // containing a file from it. alist_unlink(wp->w_alist); - wp->w_alist = alist; + wp->w_alist = aall->alist; wp->w_alist->al_refcount++; } break; @@ -853,8 +882,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } wp->w_arg_idx = i; - if (i == opened_len && !keep_tabs) { // close this window - if (buf_hide(buf) || forceit || buf->b_nwindows > 1 + if (i == aall->opened_len && !aall->keep_tabs) { // close this window + if (buf_hide(buf) || aall->forceit || buf->b_nwindows > 1 || !bufIsChanged(buf)) { // If the buffer was changed, and we would like to hide it, try autowriting. if (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { @@ -869,8 +898,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } // don't close last window if (ONE_WINDOW - && (first_tabpage->tp_next == NULL || !had_tab)) { - use_firstwin = true; + && (first_tabpage->tp_next == NULL || !aall->had_tab)) { + aall->use_firstwin = true; } else { win_close(wp, !buf_hide(buf) && !bufIsChanged(buf), false); // check if autocommands removed the next window @@ -884,7 +913,7 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } // Without the ":tab" modifier only do the current tab page. - if (had_tab == 0 || tpnext == NULL) { + if (aall->had_tab == 0 || tpnext == NULL) { break; } @@ -894,39 +923,35 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } goto_tabpage_tp(tpnext, true, true); } +} - // Open a window for files in the argument list that don't have one. - // ARGCOUNT may change while doing this, because of autocommands. - if (count > opened_len || count <= 0) { - count = opened_len; - } +/// Open up to "count" windows for the files in the argument list "aall->alist". +static void arg_all_open_windows(arg_all_state_T *aall, int count) +{ + bool tab_drop_empty_window = false; - // Don't execute Win/Buf Enter/Leave autocommands here. - autocmd_no_enter++; - autocmd_no_leave++; - last_curwin = curwin; - last_curtab = curtab; - win_enter(lastwin, false); // ":tab drop file" should re-use an empty window to avoid "--remote-tab" // leaving an empty tab page when executed locally. - if (keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1 + if (aall->keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1 && curbuf->b_ffname == NULL && !curbuf->b_changed) { - use_firstwin = true; + aall->use_firstwin = true; tab_drop_empty_window = true; } + int split_ret = OK; + for (int i = 0; i < count && !got_int; i++) { - if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) { + if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1) { arg_had_last = true; } - if (opened[i] > 0) { + if (aall->opened[i] > 0) { // Move the already present window to below the current window if (curwin->w_arg_idx != i) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_arg_idx == i) { - if (keep_tabs) { - new_curwin = wp; - new_curtab = curtab; + if (aall->keep_tabs) { + aall->new_curwin = wp; + aall->new_curtab = curtab; } else if (wp->w_frame->fr_parent != curwin->w_frame->fr_parent) { emsg(_("E249: window layout changed unexpectedly")); i = count; @@ -943,8 +968,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs) if (tab_drop_empty_window && i == count - 1) { autocmd_no_enter--; } - if (!use_firstwin) { // split current window - p_ea_save = p_ea; + if (!aall->use_firstwin) { // split current window + bool p_ea_save = p_ea; p_ea = true; // use space from all windows split_ret = win_split(0, WSP_ROOM | WSP_BELOW); p_ea = p_ea_save; @@ -958,36 +983,102 @@ static void do_arg_all(int count, int forceit, int keep_tabs) // edit file "i" curwin->w_arg_idx = i; if (i == 0) { - new_curwin = curwin; - new_curtab = curtab; + aall->new_curwin = curwin; + aall->new_curtab = curtab; } - (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE, + (void)do_ecmd(0, alist_name(&AARGLIST(aall->alist)[i]), NULL, NULL, ECMD_ONE, ((buf_hide(curwin->w_buffer) - || bufIsChanged(curwin->w_buffer)) - ? ECMD_HIDE : 0) + ECMD_OLDBUF, + || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + ECMD_OLDBUF, curwin); if (tab_drop_empty_window && i == count - 1) { autocmd_no_enter++; } - if (use_firstwin) { + if (aall->use_firstwin) { autocmd_no_leave++; } - use_firstwin = false; + aall->use_firstwin = false; } os_breakcheck(); // When ":tab" was used open a new tab for a new window repeatedly. - if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) { + if (aall->had_tab > 0 && tabpage_index(NULL) <= p_tpm) { cmdmod.cmod_tab = 9999; } } +} + +/// do_arg_all(): Open up to 'count' windows, one for each argument. +/// +/// @param forceit hide buffers in current windows +/// @param keep_tabs keep current tabs, for ":tab drop file" +static void do_arg_all(int count, int forceit, int keep_tabs) +{ + win_T *last_curwin; + tabpage_T *last_curtab; + bool prev_arglist_locked = arglist_locked; + + assert(firstwin != NULL); // satisfy coverity + + if (cmdwin_type != 0) { + emsg(_(e_cmdwin)); + return; + } + if (ARGCOUNT <= 0) { + // Don't give an error message. We don't want it when the ":all" + // command is in the .vimrc. + return; + } + setpcmark(); + + arg_all_state_T aall = { + .use_firstwin = false, + .had_tab = cmdmod.cmod_tab, + .new_curwin = NULL, + .new_curtab = NULL, + .forceit = forceit, + .keep_tabs = keep_tabs, + .opened_len = ARGCOUNT, + .opened = xcalloc((size_t)ARGCOUNT, 1), + }; + + // Autocommands may do anything to the argument list. Make sure it's not + // freed while we are working here by "locking" it. We still have to + // watch out for its size to be changed. + aall.alist = curwin->w_alist; + aall.alist->al_refcount++; + arglist_locked = true; + + // Try closing all windows that are not in the argument list. + // Also close windows that are not full width; + // When 'hidden' or "forceit" set the buffer becomes hidden. + // Windows that have a changed buffer and can't be hidden won't be closed. + // When the ":tab" modifier was used do this for all tab pages. + arg_all_close_unused_windows(&aall); + + // Open a window for files in the argument list that don't have one. + // ARGCOUNT may change while doing this, because of autocommands. + if (count > aall.opened_len || count <= 0) { + count = aall.opened_len; + } + + // Don't execute Win/Buf Enter/Leave autocommands here. + autocmd_no_enter++; + autocmd_no_leave++; + last_curwin = curwin; + last_curtab = curtab; + win_enter(lastwin, false); + + // Open upto "count" windows. + arg_all_open_windows(&aall, count); // Remove the "lock" on the argument list. - alist_unlink(alist); + alist_unlink(aall.alist); + arglist_locked = prev_arglist_locked; autocmd_no_enter--; + // restore last referenced tabpage's curwin - if (last_curtab != new_curtab) { + if (last_curtab != aall.new_curtab) { if (valid_tabpage(last_curtab)) { goto_tabpage_tp(last_curtab, true, true); } @@ -996,15 +1087,15 @@ static void do_arg_all(int count, int forceit, int keep_tabs) } } // to window with first arg - if (valid_tabpage(new_curtab)) { - goto_tabpage_tp(new_curtab, true, true); + if (valid_tabpage(aall.new_curtab)) { + goto_tabpage_tp(aall.new_curtab, true, true); } - if (win_valid(new_curwin)) { - win_enter(new_curwin, false); + if (win_valid(aall.new_curwin)) { + win_enter(aall.new_curwin, false); } autocmd_no_leave--; - xfree(opened); + xfree(aall.opened); } /// ":all" and ":sall". @@ -1074,7 +1165,7 @@ char *arg_all(void) } /// "argc([window id])" function -void f_argc(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_argc(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type == VAR_UNKNOWN) { // use the current window @@ -1095,13 +1186,13 @@ void f_argc(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "argidx()" function -void f_argidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_argidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = curwin->w_arg_idx; } /// "arglistid()" function -void f_arglistid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_arglistid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; win_T *wp = find_tabwin(&argvars[0], &argvars[1]); @@ -1123,36 +1214,38 @@ static void get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rett } /// "argv(nr)" function -void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_argv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { aentry_T *arglist = NULL; int argcount = -1; - if (argvars[0].v_type != VAR_UNKNOWN) { - if (argvars[1].v_type == VAR_UNKNOWN) { - arglist = ARGLIST; - argcount = ARGCOUNT; - } else if (argvars[1].v_type == VAR_NUMBER - && tv_get_number(&argvars[1]) == -1) { - arglist = GARGLIST; - argcount = GARGCOUNT; - } else { - win_T *wp = find_win_by_nr_or_id(&argvars[1]); - if (wp != NULL) { - // Use the argument list of the specified window - arglist = WARGLIST(wp); - argcount = WARGCOUNT(wp); - } - } - rettv->v_type = VAR_STRING; - rettv->vval.v_string = 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) { - get_arglist_as_rettv(arglist, argcount, rettv); - } - } else { + if (argvars[0].v_type == VAR_UNKNOWN) { get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv); + return; + } + + if (argvars[1].v_type == VAR_UNKNOWN) { + arglist = ARGLIST; + argcount = ARGCOUNT; + } else if (argvars[1].v_type == VAR_NUMBER + && tv_get_number(&argvars[1]) == -1) { + arglist = GARGLIST; + argcount = GARGCOUNT; + } else { + win_T *wp = find_win_by_nr_or_id(&argvars[1]); + if (wp != NULL) { + // Use the argument list of the specified window + arglist = WARGLIST(wp); + argcount = WARGCOUNT(wp); + } + } + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = 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) { + get_arglist_as_rettv(arglist, argcount, rettv); } } diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 579c6c029f..5b5ea43d86 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -266,7 +266,7 @@ static void au_show_for_event(int group, event_T event, char *pat) // normalize pat into standard "<buffer>#N" form aupat_normalize_buflocal_pat(buflocal_pat, pat, patlen, aupat_get_buflocal_nr(pat, patlen)); pat = (char *)buflocal_pat; - patlen = (int)STRLEN(buflocal_pat); + patlen = (int)strlen(buflocal_pat); } assert(*pat != NUL); @@ -478,34 +478,37 @@ void augroup_del(char *name, bool stupid_legacy_mode) int i = augroup_find(name); if (i == AUGROUP_ERROR) { // the group doesn't exist semsg(_("E367: No such group: \"%s\""), name); - } else if (i == current_augroup) { + return; + } + if (i == current_augroup) { emsg(_("E936: Cannot delete the current group")); - } else { - if (stupid_legacy_mode) { - FOR_ALL_AUEVENTS(event) { - FOR_ALL_AUPATS_IN_EVENT(event, ap) { - if (ap->group == i && ap->pat != NULL) { - give_warning(_("W19: Deleting augroup that is still in use"), true); - map_put(String, int)(&map_augroup_name_to_id, cstr_as_string(name), AUGROUP_DELETED); - augroup_map_del(ap->group, NULL); - return; - } + return; + } + + if (stupid_legacy_mode) { + FOR_ALL_AUEVENTS(event) { + FOR_ALL_AUPATS_IN_EVENT(event, ap) { + if (ap->group == i && ap->pat != NULL) { + give_warning(_("W19: Deleting augroup that is still in use"), true); + map_put(String, int)(&map_augroup_name_to_id, cstr_as_string(name), AUGROUP_DELETED); + augroup_map_del(ap->group, NULL); + return; } } - } else { - FOR_ALL_AUEVENTS(event) { - FOR_ALL_AUPATS_IN_EVENT(event, ap) { - if (ap->group == i) { - aupat_del(ap); - } + } + } else { + FOR_ALL_AUEVENTS(event) { + FOR_ALL_AUPATS_IN_EVENT(event, ap) { + if (ap->group == i) { + aupat_del(ap); } } } - - // Remove the group because it's not currently in use. - augroup_map_del(i, name); - au_cleanup(); } + + // Remove the group because it's not currently in use. + augroup_map_del(i, name); + au_cleanup(); } /// Find the ID of an autocmd group name. @@ -686,7 +689,7 @@ const char *event_nr2name(event_T event) static bool event_ignored(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - char *p = (char *)p_ei; + char *p = p_ei; while (*p != NUL) { if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) { @@ -703,7 +706,7 @@ static bool event_ignored(event_T event) // Return OK when the contents of p_ei is valid, FAIL otherwise. int check_ei(void) { - char *p = (char *)p_ei; + char *p = p_ei; while (*p) { if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) { @@ -724,8 +727,8 @@ int check_ei(void) // Returns the old value of 'eventignore' in allocated memory. char *au_event_disable(char *what) { - char *save_ei = (char *)vim_strsave(p_ei); - char *new_ei = (char *)vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what)); + char *save_ei = xstrdup(p_ei); + char *new_ei = xstrnsave(p_ei, strlen(p_ei) + strlen(what)); if (*what == ',' && *p_ei == NUL) { STRCPY(new_ei, what + 1); } else { @@ -733,7 +736,6 @@ char *au_event_disable(char *what) } set_string_option_direct("ei", -1, new_ei, OPT_FREE, SID_NONE); xfree(new_ei); - return save_ei; } @@ -837,13 +839,15 @@ void do_autocmd(char *arg_in, int forceit) bool invalid_flags = false; for (size_t i = 0; i < 2; i++) { - if (*cmd != NUL) { - invalid_flags |= arg_autocmd_flag_get(&once, &cmd, "++once", 6); - invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "++nested", 8); - - // Check the deprecated "nested" flag. - invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "nested", 6); + if (*cmd == NUL) { + continue; } + + invalid_flags |= arg_autocmd_flag_get(&once, &cmd, "++once", 6); + invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "++nested", 8); + + // Check the deprecated "nested" flag. + invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "nested", 6); } if (invalid_flags) { @@ -877,7 +881,7 @@ void do_autocmd(char *arg_in, int forceit) } } else { if (*arg == '*' || *arg == NUL || *arg == '|') { - if (!forceit && *cmd != NUL) { + if (*cmd != NUL) { emsg(_(e_cannot_define_autocommands_for_all_events)); } else { do_all_autocmd_events(pat, once, nested, cmd, forceit, group); @@ -957,7 +961,7 @@ int do_autocmd_event(event_T event, char *pat, bool once, int nested, char *cmd, aupat_normalize_buflocal_pat(buflocal_pat, pat, patlen, buflocal_nr); pat = buflocal_pat; - patlen = (int)STRLEN(buflocal_pat); + patlen = (int)strlen(buflocal_pat); } if (delete) { @@ -1018,7 +1022,7 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group int findgroup; char buflocal_pat[BUFLOCAL_PAT_LEN]; // for "<buffer=X>" - if (patlen > (int)STRLEN(pat)) { + if (patlen > (int)strlen(pat)) { return FAIL; } @@ -1039,7 +1043,7 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group aupat_normalize_buflocal_pat(buflocal_pat, pat, patlen, buflocal_nr); pat = buflocal_pat; - patlen = (int)STRLEN(buflocal_pat); + patlen = (int)strlen(buflocal_pat); } // always goes at or after the last one, so start at the end. @@ -1119,6 +1123,7 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group if (event == EVENT_WINSCROLLED && !has_event(EVENT_WINSCROLLED)) { curwin->w_last_topline = curwin->w_topline; curwin->w_last_leftcol = curwin->w_leftcol; + curwin->w_last_skipcol = curwin->w_skipcol; curwin->w_last_width = curwin->w_width; curwin->w_last_height = curwin->w_height; } @@ -1192,7 +1197,7 @@ size_t aucmd_pattern_length(char *pat) return (size_t)(endpat - pat); } - return STRLEN(pat); + return strlen(pat); } char *aucmd_next_pattern(char *pat, size_t patlen) @@ -1274,6 +1279,7 @@ void ex_doautoall(exarg_T *eap) if (buf->b_ml.ml_mfp == NULL || buf == curbuf) { continue; } + // Find a window for this buffer and save some values. aucmd_prepbuf(&aco, buf); set_bufref(&bufref, buf); @@ -1444,7 +1450,6 @@ win_found: } aucmd_win_used = false; - last_status(false); // may need to remove last status line if (!valid_tabpage_win(curtab)) { // no valid window in current tabpage @@ -1720,9 +1725,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force fname = NULL; } else { if (event == EVENT_SYNTAX) { - fname = (char *)buf->b_p_syn; + fname = buf->b_p_syn; } else if (event == EVENT_FILETYPE) { - fname = (char *)buf->b_p_ft; + fname = buf->b_p_ft; } else { if (buf->b_sfname != NULL) { sfname = xstrdup(buf->b_sfname); @@ -1738,17 +1743,18 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force sfname = xstrdup(fname); // Don't try expanding the following events. if (event == EVENT_CMDLINECHANGED || event == EVENT_CMDLINEENTER - || event == EVENT_CMDLINELEAVE || event == EVENT_CMDWINENTER - || event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED + || event == EVENT_CMDLINELEAVE || event == EVENT_CMDUNDEFINED + || event == EVENT_CMDWINENTER || event == EVENT_CMDWINLEAVE || event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE || event == EVENT_DIRCHANGED || event == EVENT_DIRCHANGEDPRE || event == EVENT_FILETYPE || event == EVENT_FUNCUNDEFINED - || event == EVENT_MODECHANGED || event == EVENT_OPTIONSET - || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE - || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING - || event == EVENT_SYNTAX || event == EVENT_SIGNAL - || event == EVENT_TABCLOSED || event == EVENT_USER - || event == EVENT_WINCLOSED || event == EVENT_WINSCROLLED) { + || event == EVENT_MENUPOPUP || event == EVENT_MODECHANGED + || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST + || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY + || event == EVENT_SIGNAL || event == EVENT_SPELLFILEMISSING + || event == EVENT_SYNTAX || event == EVENT_TABCLOSED + || event == EVENT_USER || event == EVENT_WINCLOSED + || event == EVENT_WINSCROLLED) { fname = xstrdup(fname); } else { fname = FullName_save(fname, false); @@ -1811,16 +1817,15 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force char *tail = path_tail(fname); // Find first autocommand that matches - AutoPatCmd patcmd; - patcmd.curpat = first_autopat[(int)event]; - patcmd.nextcmd = NULL; - patcmd.group = group; - patcmd.fname = fname; - patcmd.sfname = sfname; - patcmd.tail = tail; - patcmd.event = event; - patcmd.arg_bufnr = autocmd_bufnr; - patcmd.next = NULL; + AutoPatCmd patcmd = { + .curpat = first_autopat[(int)event], + .group = group, + .fname = fname, + .sfname = sfname, + .tail = tail, + .event = event, + .arg_bufnr = autocmd_bufnr, + }; auto_next_pat(&patcmd, false); // found one, start executing the autocommands @@ -1984,9 +1989,12 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last) AutoPat *ap; AutoCmd *cp; char *s; - char **const sourcing_namep = &SOURCING_NAME; - XFREE_CLEAR(*sourcing_namep); + estack_T *const entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + + // Clear the exestack entry for this ETYPE_AUCMD entry. + XFREE_CLEAR(entry->es_name); + entry->es_info.aucmd = NULL; for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) { apc->curpat = NULL; @@ -2009,16 +2017,20 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last) s = _("%s Autocommands for \"%s\""); const size_t sourcing_name_len - = (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1); + = (strlen(s) + strlen(name) + (size_t)ap->patlen + 1); - *sourcing_namep = xmalloc(sourcing_name_len); - snprintf(*sourcing_namep, sourcing_name_len, s, name, ap->pat); + char *const namep = xmalloc(sourcing_name_len); + snprintf(namep, sourcing_name_len, s, name, ap->pat); if (p_verbose >= 8) { verbose_enter(); - smsg(_("Executing %s"), *sourcing_namep); + smsg(_("Executing %s"), namep); verbose_leave(); } + // Update the exestack entry for this autocmd. + entry->es_name = namep; + entry->es_info.aucmd = apc; + apc->curpat = ap; apc->nextcmd = ap->cmds; // mark last command @@ -2051,7 +2063,7 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) PUT(data, "buf", INTEGER_OBJ(autocmd_bufnr)); if (apc->data) { - PUT(data, "data", copy_object(*apc->data)); + PUT(data, "data", copy_object(*apc->data, NULL)); } int group = apc->curpat->group; @@ -2150,6 +2162,7 @@ char *getnextac(int c, void *cookie, int indent, bool do_concat) // lua code, so that it works properly autocmd_nested = ac->nested; current_sctx = ac->script_ctx; + acp->script_ctx = current_sctx; if (ac->exec.type == CALLABLE_CB) { if (call_autocmd_callback(ac, acp)) { @@ -2206,7 +2219,7 @@ bool has_autocmd(event_T event, char *sfname, buf_T *buf) #ifdef BACKSLASH_IN_FILENAME // Replace all backslashes with forward slashes. This makes the // autocommand patterns portable between Unix and Windows. - sfname = vim_strsave(sfname); + sfname = xstrdup(sfname); forward_slash(sfname); forward_slash(fname); #endif @@ -2388,7 +2401,7 @@ bool au_exists(const char *const arg) FUNC_ATTR_WARN_UNUSED_RESULT } // if pattern is "<buffer>", special handling is needed which uses curbuf - // for pattern "<buffer=N>, FNAMECMP() will work fine + // for pattern "<buffer=N>, path_fnamecmp() will work fine if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0) { buflocal_buf = curbuf; } @@ -2396,12 +2409,12 @@ bool au_exists(const char *const arg) FUNC_ATTR_WARN_UNUSED_RESULT // Check if there is an autocommand with the given pattern. for (; ap != NULL; ap = ap->next) { // only use a pattern when it has not been removed and has commands. - // For buffer-local autocommands, FNAMECMP() works fine. + // For buffer-local autocommands, path_fnamecmp() works fine. if (ap->pat != NULL && ap->cmds != NULL && (group == AUGROUP_ALL || ap->group == group) && (pattern == NULL || (buflocal_buf == NULL - ? FNAMECMP(ap->pat, pattern) == 0 + ? path_fnamecmp(ap->pat, pattern) == 0 : ap->buflocal_nr == buflocal_buf->b_fnum))) { retval = true; break; @@ -2708,7 +2721,7 @@ static void do_autocmd_focusgained(bool gained) redrawcmdline(); } else if ((State & MODE_NORMAL) || (State & MODE_INSERT)) { if (must_redraw != 0) { - update_screen(0); + update_screen(); } setcursor(); diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h index d559d8c3d2..75a8a7aaa1 100644 --- a/src/nvim/autocmd.h +++ b/src/nvim/autocmd.h @@ -29,7 +29,7 @@ struct AutoCmd_S { bool nested; // If autocommands nest here bool last; // last command in list int64_t id; // ID used for uniquely tracking an autocmd. - sctx_T script_ctx; // script context where defined + sctx_T script_ctx; // script context where it is defined char *desc; // Description for the autocmd. AutoCmd *next; // Next AutoCmd in list }; @@ -59,6 +59,7 @@ struct AutoPatCmd_S { char *sfname; // sfname to match with char *tail; // tail of fname event_T event; // current event + sctx_T script_ctx; // script context where it is defined int arg_bufnr; // initially equal to <abuf>, set to zero when buf is deleted Object *data; // arbitrary data AutoPatCmd *next; // chain of active apc-s for auto-invalidation diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ab5b32bf3e..85f79deb2f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -165,11 +165,12 @@ static int read_buffer(int read_stdin, exarg_T *eap, int flags) /// /// @param read_stdin read file from stdin /// @param eap for forced 'ff' and 'fenc' or NULL -/// @param flags extra flags for readfile() +/// @param flags_arg extra flags for readfile() /// /// @return FAIL for failure, OK otherwise. -int open_buffer(int read_stdin, exarg_T *eap, int flags) +int open_buffer(int read_stdin, exarg_T *eap, int flags_arg) { + int flags = flags_arg; int retval = OK; bufref_T old_curbuf; long old_tw = curbuf->b_p_tw; @@ -224,6 +225,13 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags) // mark cursor position as being invalid curwin->w_valid = 0; + // A buffer without an actual file should not use the buffer name to read a + // file. + if (bt_nofileread(curbuf)) { + flags |= READ_NOFILE; + } + + // Read the file if there is one. if (curbuf->b_ffname != NULL) { #ifdef UNIX int save_bin = curbuf->b_p_bin; @@ -804,6 +812,18 @@ static void free_buffer(buf_T *buf) } } +/// Free the b_wininfo list for buffer "buf". +static void clear_wininfo(buf_T *buf) +{ + wininfo_T *wip; + + while (buf->b_wininfo != NULL) { + wip = buf->b_wininfo; + buf->b_wininfo = wip->wi_next; + free_wininfo(wip, buf); + } +} + /// Free stuff in the buffer for ":bdel" and when wiping out the buffer. /// /// @param buf Buffer pointer @@ -838,18 +858,6 @@ static void free_buffer_stuff(buf_T *buf, int free_flags) buf_updates_unload(buf, false); } -/// Free the b_wininfo list for buffer "buf". -static void clear_wininfo(buf_T *buf) -{ - wininfo_T *wip; - - while (buf->b_wininfo != NULL) { - wip = buf->b_wininfo; - buf->b_wininfo = wip->wi_next; - free_wininfo(wip, buf); - } -} - /// Go to another buffer. Handles the result of the ATTENTION dialog. void goto_buffer(exarg_T *eap, int start, int dir, int count) { @@ -1623,7 +1631,7 @@ void enter_buffer(buf_T *buf) } curbuf->b_last_used = time(NULL); - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } /// Change to the directory of the current buffer. @@ -2162,7 +2170,7 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, if (pat == NULL) { return -1; } - patend = pat + STRLEN(pat) - 1; + patend = pat + strlen(pat) - 1; toggledollar = (patend > pat && *patend == '$'); // First try finding a listed buffer. If not found and "unlisted" @@ -2276,7 +2284,7 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) // Make a copy of "pat" and change "^" to "\(^\|[\/]\)". if (*pat == '^') { - patc = xmalloc(STRLEN(pat) + 11); + patc = xmalloc(strlen(pat) + 11); STRCPY(patc, "\\(^\\|[\\/]\\)"); STRCPY(patc + 11, pat + 1); } else { @@ -2725,7 +2733,7 @@ void buflist_list(exarg_T *eap) IObuff[len++] = ' '; } while (--i > 0 && len < IOSIZE - 18); if (vim_strchr(eap->arg, 't') && buf->b_last_used) { - undo_fmt_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used); + undo_fmt_time((char_u *)IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used); } else { vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), _("line %" PRId64), buf == curbuf ? (int64_t)curwin->w_cursor.lnum : (int64_t)buflist_findlnum(buf)); @@ -2957,7 +2965,7 @@ static bool otherfile_buf(buf_T *buf, char *ffname, FileID *file_id_p, bool file if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) { return true; } - if (FNAMECMP(ffname, buf->b_ffname) == 0) { + if (path_fnamecmp(ffname, buf->b_ffname) == 0) { return false; } { @@ -3029,7 +3037,7 @@ void fileinfo(int fullname, int shorthelp, int dont_truncate) if (fullname > 1) { // 2 CTRL-G: include buffer number vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); - p = buffer + STRLEN(buffer); + p = buffer + strlen(buffer); } else { p = buffer; } @@ -3088,7 +3096,7 @@ void fileinfo(int fullname, int shorthelp, int dont_truncate) (int64_t)curbuf->b_ml.ml_line_count, n); validate_virtcol(); - len = STRLEN(buffer); + len = strlen(buffer); col_print(buffer + len, IOSIZE - len, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); } @@ -3166,14 +3174,14 @@ void maketitle(void) use_sandbox = was_set_insecurely(curwin, "titlestring", 0); build_stl_str_hl(curwin, buf, sizeof(buf), - (char *)p_titlestring, use_sandbox, + p_titlestring, use_sandbox, 0, maxlen, NULL, NULL); title_str = buf; if (called_emsg > called_emsg_before) { set_string_option_direct("titlestring", -1, "", OPT_FREE, SID_ERROR); } } else { - title_str = (char *)p_titlestring; + title_str = p_titlestring; } } else { // Format: "fname + (path) (1 of 2) - VIM". @@ -3280,13 +3288,13 @@ void maketitle(void) use_sandbox = was_set_insecurely(curwin, "iconstring", 0); build_stl_str_hl(curwin, icon_str, sizeof(buf), - (char *)p_iconstring, use_sandbox, + p_iconstring, use_sandbox, 0, 0, NULL, NULL); if (called_emsg > called_emsg_before) { set_string_option_direct("iconstring", -1, "", OPT_FREE, SID_ERROR); } } else { - icon_str = (char *)p_iconstring; + icon_str = p_iconstring; } } else { char *buf_p; @@ -3297,7 +3305,7 @@ void maketitle(void) } *icon_str = NUL; // Truncate name at 100 bytes. - len = (int)STRLEN(buf_p); + len = (int)strlen(buf_p); if (len > 100) { len -= 100; len += utf_cp_tail_off(buf_p, buf_p + len) + 1; @@ -3327,7 +3335,7 @@ static bool value_change(char *str, char **last) FUNC_ATTR_WARN_UNUSED_RESULT { if ((str == NULL) != (*last == NULL) - || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) { + || (str != NULL && *last != NULL && strcmp(str, *last) != 0)) { xfree(*last); if (str == NULL) { *last = NULL; @@ -3404,7 +3412,7 @@ bool append_arg_number(win_T *wp, char *buf, int buflen, bool add_file) return false; } - char *p = buf + STRLEN(buf); // go to the end of the buffer + char *p = buf + strlen(buf); // go to the end of the buffer // Early out if the string is getting too long if (p - buf + 35 >= buflen) { @@ -3440,7 +3448,7 @@ void fname_expand(buf_T *buf, char **ffname, char **sfname) } *ffname = fix_fname((*ffname)); // expand to full path -#ifdef WIN32 +#ifdef MSWIN if (!buf->b_p_bin) { // If the file name is a shortcut file, use the file it links to. char *rfname = os_resolve_shortcut((const char *)(*ffname)); @@ -3693,7 +3701,7 @@ static int chk_modeline(linenr_T lnum, int flags) int retval = OK; prev = -1; - for (s = (char *)ml_get(lnum); *s != NUL; s++) { + for (s = ml_get(lnum); *s != NUL; s++) { if (prev == -1 || ascii_isspace(prev)) { if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) || STRNCMP(s, "vi:", (size_t)3) == 0) { @@ -3826,7 +3834,8 @@ bool bt_terminal(const buf_T *const buf) } /// @return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt" -/// buffer. This means the buffer name is not a file name. +/// buffer. This means the buffer name may not be a file name, +/// at least not for writing the buffer. bool bt_nofilename(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -3836,6 +3845,17 @@ bool bt_nofilename(const buf_T *const buf) || buf->b_p_bt[0] == 'p'); } +/// @return true if "buf" is a "nofile", "quickfix", "terminal" or "prompt" +/// buffer. This means the buffer is not to be read from a file. +static bool bt_nofileread(const buf_T *const buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') + || buf->b_p_bt[0] == 't' + || buf->b_p_bt[0] == 'q' + || buf->b_p_bt[0] == 'p'); +} + /// @return true if "buf" has 'buftype' set to "nofile". bool bt_nofile(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT @@ -4034,7 +4054,7 @@ void buf_signcols_add_check(buf_T *buf, sign_entry_T *added) buf->b_signcols.max++; } buf->b_signcols.size++; - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); return; } @@ -4055,7 +4075,7 @@ void buf_signcols_add_check(buf_T *buf, sign_entry_T *added) buf->b_signcols.size = linesum; buf->b_signcols.max = linesum; buf->b_signcols.sentinel = added->se_lnum; - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); } } @@ -4074,7 +4094,7 @@ int buf_signcols(buf_T *buf, int maximum) if (signcols != buf->b_signcols.size) { buf->b_signcols.size = signcols; buf->b_signcols.max = maximum; - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); } buf->b_signcols.valid = true; @@ -4139,7 +4159,7 @@ bool buf_contents_changed(buf_T *buf) if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) { differ = false; for (linenr_T lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) { - if (STRCMP(ml_get_buf(buf, lnum, false), ml_get(lnum)) != 0) { + if (strcmp(ml_get_buf(buf, lnum, false), ml_get(lnum)) != 0) { differ = true; break; } @@ -4183,14 +4203,19 @@ void wipe_buffer(buf_T *buf, bool aucmd) /// @param bufnr Buffer to switch to, or 0 to create a new buffer. /// /// @see curbufIsChanged() -void buf_open_scratch(handle_T bufnr, char *bufname) +/// +/// @return FAIL for failure, OK otherwise +int buf_open_scratch(handle_T bufnr, char *bufname) { - (void)do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL); + if (do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL) { + return FAIL; + } apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); (void)setfname(curbuf, bufname, NULL, true); apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); - set_option_value("bh", 0L, "hide", OPT_LOCAL); - set_option_value("bt", 0L, "nofile", OPT_LOCAL); - set_option_value("swf", 0L, NULL, OPT_LOCAL); + set_option_value_give_err("bh", 0L, "hide", OPT_LOCAL); + set_option_value_give_err("bt", 0L, "nofile", OPT_LOCAL); + set_option_value_give_err("swf", 0L, NULL, OPT_LOCAL); RESET_BINDING(curwin); + return OK; } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 6c8a3bfb31..829632358f 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -41,32 +41,30 @@ typedef struct { // for Map(K, V) #include "nvim/map.h" // for kvec -#include "nvim/lib/kvec.h" +#include "klib/kvec.h" // for marktree #include "nvim/marktree.h" #define GETFILE_SUCCESS(x) ((x) <= 0) #define MODIFIABLE(buf) (buf->b_p_ma) -/* - * Flags for w_valid. - * These are set when something in a window structure becomes invalid, except - * when the cursor is moved. Call check_cursor_moved() before testing one of - * the flags. - * These are reset when that thing has been updated and is valid again. - * - * Every function that invalidates one of these must call one of the - * invalidate_* functions. - * - * w_valid is supposed to be used only in screen.c. From other files, use the - * functions that set or reset the flags. - * - * VALID_BOTLINE VALID_BOTLINE_AP - * on on w_botline valid - * off on w_botline approximated - * off off w_botline not valid - * on off not possible - */ +// Flags for w_valid. +// These are set when something in a window structure becomes invalid, except +// when the cursor is moved. Call check_cursor_moved() before testing one of +// the flags. +// These are reset when that thing has been updated and is valid again. +// +// Every function that invalidates one of these must call one of the +// invalidate_* functions. +// +// w_valid is supposed to be used only in screen.c. From other files, use the +// functions that set or reset the flags. +// +// VALID_BOTLINE VALID_BOTLINE_AP +// on on w_botline valid +// off on w_botline approximated +// off off w_botline not valid +// on off not possible #define VALID_WROW 0x01 // w_wrow (window row) is valid #define VALID_WCOL 0x02 // w_wcol (window col) is valid #define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid @@ -112,31 +110,25 @@ typedef uint64_t disptick_T; // display tick type #include "nvim/sign_defs.h" #include "nvim/terminal.h" // for Terminal -/* - * The taggy struct is used to store the information about a :tag command. - */ +// The taggy struct is used to store the information about a :tag command. typedef struct taggy { - char_u *tagname; // tag name + char *tagname; // tag name fmark_T fmark; // cursor position BEFORE ":tag" int cur_match; // match number int cur_fnum; // buffer number used for cur_match - char_u *user_data; // used with tagfunc + char *user_data; // used with tagfunc } taggy_T; typedef struct buffblock buffblock_T; typedef struct buffheader buffheader_T; -/* - * structure used to store one block of the stuff/redo/recording buffers - */ +// structure used to store one block of the stuff/redo/recording buffers struct buffblock { buffblock_T *b_next; // pointer to next buffblock - char_u b_str[1]; // contents (actually longer) + char b_str[1]; // contents (actually longer) }; -/* - * header used for the stuff buffer and the redo buffer - */ +// header used for the stuff buffer and the redo buffer struct buffheader { buffblock_T bh_first; // first (dummy) block of list buffblock_T *bh_curr; // buffblock for appending @@ -149,49 +141,47 @@ typedef struct { buffheader_T sr_old_redobuff; } save_redo_T; -/* - * Structure that contains all options that are local to a window. - * Used twice in a window: for the current buffer and for all buffers. - * Also used in wininfo_T. - */ +// Structure that contains all options that are local to a window. +// Used twice in a window: for the current buffer and for all buffers. +// Also used in wininfo_T. typedef struct { int wo_arab; #define w_p_arab w_onebuf_opt.wo_arab // 'arabic' int wo_bri; #define w_p_bri w_onebuf_opt.wo_bri // 'breakindent' - char_u *wo_briopt; + char *wo_briopt; #define w_p_briopt w_onebuf_opt.wo_briopt // 'breakindentopt' int wo_diff; #define w_p_diff w_onebuf_opt.wo_diff // 'diff' - char_u *wo_fdc; + char *wo_fdc; #define w_p_fdc w_onebuf_opt.wo_fdc // 'foldcolumn' - char_u *wo_fdc_save; + char *wo_fdc_save; #define w_p_fdc_save w_onebuf_opt.wo_fdc_save // 'fdc' saved for diff mode int wo_fen; #define w_p_fen w_onebuf_opt.wo_fen // 'foldenable' int wo_fen_save; // 'foldenable' saved for diff mode #define w_p_fen_save w_onebuf_opt.wo_fen_save - char_u *wo_fdi; + char *wo_fdi; #define w_p_fdi w_onebuf_opt.wo_fdi // 'foldignore' long wo_fdl; #define w_p_fdl w_onebuf_opt.wo_fdl // 'foldlevel' long wo_fdl_save; // 'foldlevel' state saved for diff mode #define w_p_fdl_save w_onebuf_opt.wo_fdl_save - char_u *wo_fdm; + char *wo_fdm; #define w_p_fdm w_onebuf_opt.wo_fdm // 'foldmethod' - char_u *wo_fdm_save; + char *wo_fdm_save; #define w_p_fdm_save w_onebuf_opt.wo_fdm_save // 'fdm' saved for diff mode long wo_fml; #define w_p_fml w_onebuf_opt.wo_fml // 'foldminlines' long wo_fdn; #define w_p_fdn w_onebuf_opt.wo_fdn // 'foldnestmax' - char_u *wo_fde; + char *wo_fde; #define w_p_fde w_onebuf_opt.wo_fde // 'foldexpr' - char_u *wo_fdt; + char *wo_fdt; #define w_p_fdt w_onebuf_opt.wo_fdt // 'foldtext' - char_u *wo_fmr; + char *wo_fmr; #define w_p_fmr w_onebuf_opt.wo_fmr // 'foldmarker' int wo_lbr; #define w_p_lbr w_onebuf_opt.wo_lbr // 'linebreak' @@ -201,7 +191,7 @@ typedef struct { #define w_p_nu w_onebuf_opt.wo_nu // 'number' int wo_rnu; #define w_p_rnu w_onebuf_opt.wo_rnu // 'relativenumber' - char_u *wo_ve; + char *wo_ve; #define w_p_ve w_onebuf_opt.wo_ve // 'virtualedit' unsigned wo_ve_flags; #define w_ve_flags w_onebuf_opt.wo_ve_flags // flags for 'virtualedit' @@ -215,7 +205,7 @@ typedef struct { #define w_p_pvw w_onebuf_opt.wo_pvw // 'previewwindow' int wo_rl; #define w_p_rl w_onebuf_opt.wo_rl // 'rightleft' - char_u *wo_rlc; + char *wo_rlc; #define w_p_rlc w_onebuf_opt.wo_rlc // 'rightleftcmd' long wo_scr; #define w_p_scr w_onebuf_opt.wo_scr // 'scroll' @@ -225,13 +215,13 @@ typedef struct { #define w_p_cuc w_onebuf_opt.wo_cuc // 'cursorcolumn' int wo_cul; #define w_p_cul w_onebuf_opt.wo_cul // 'cursorline' - char_u *wo_culopt; + char *wo_culopt; #define w_p_culopt w_onebuf_opt.wo_culopt // 'cursorlineopt' - char_u *wo_cc; + char *wo_cc; #define w_p_cc w_onebuf_opt.wo_cc // 'colorcolumn' - char_u *wo_sbr; + char *wo_sbr; #define w_p_sbr w_onebuf_opt.wo_sbr // 'showbreak' - char_u *wo_stl; + char *wo_stl; #define w_p_stl w_onebuf_opt.wo_stl // 'statusline' char *wo_wbr; #define w_p_wbr w_onebuf_opt.wo_wbr // 'winbar' @@ -245,7 +235,7 @@ typedef struct { #define w_p_wrap w_onebuf_opt.wo_wrap // 'wrap' int wo_wrap_save; // 'wrap' state saved for diff mode #define w_p_wrap_save w_onebuf_opt.wo_wrap_save - char_u *wo_cocu; // 'concealcursor' + char *wo_cocu; // 'concealcursor' #define w_p_cocu w_onebuf_opt.wo_cocu long wo_cole; // 'conceallevel' #define w_p_cole w_onebuf_opt.wo_cole @@ -253,14 +243,14 @@ typedef struct { #define w_p_crb w_onebuf_opt.wo_crb // 'cursorbind' int wo_crb_save; // 'cursorbind' state saved for diff mode #define w_p_crb_save w_onebuf_opt.wo_crb_save - char_u *wo_scl; + char *wo_scl; #define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn' - char_u *wo_winhl; + char *wo_winhl; #define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight' - char_u *wo_fcs; -#define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars' - char_u *wo_lcs; + char *wo_lcs; #define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars' + char *wo_fcs; +#define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars' long wo_winbl; #define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend' @@ -268,16 +258,14 @@ typedef struct { #define w_p_script_ctx w_onebuf_opt.wo_script_ctx } winopt_T; -/* - * Window info stored with a buffer. - * - * Two types of info are kept for a buffer which are associated with a - * specific window: - * 1. Each window can have a different line number associated with a buffer. - * 2. The window-local options for a buffer work in a similar way. - * The window-info is kept in a list at b_wininfo. It is kept in - * most-recently-used order. - */ +// Window info stored with a buffer. +// +// Two types of info are kept for a buffer which are associated with a +// specific window: +// 1. Each window can have a different line number associated with a buffer. +// 2. The window-local options for a buffer work in a similar way. +// The window-info is kept in a list at b_wininfo. It is kept in +// most-recently-used order. struct wininfo_S { wininfo_T *wi_next; // next entry or NULL for last entry wininfo_T *wi_prev; // previous entry or NULL for first entry @@ -290,12 +278,10 @@ struct wininfo_S { int wi_changelistidx; // copy of w_changelistidx }; -/* - * Argument list: Array of file names. - * Used for the global argument list and the argument lists local to a window. - * - * TODO: move struct arglist to another header - */ +// Argument list: Array of file names. +// Used for the global argument list and the argument lists local to a window. +// +// TODO(neovim): move struct arglist to another header typedef struct arglist { garray_T al_ga; // growarray with the array of file names int al_refcount; // number of windows using this arglist @@ -308,8 +294,8 @@ typedef struct arglist { // // TODO(Felipe): move aentry_T to another header typedef struct argentry { - char_u *ae_fname; // file name as specified - int ae_fnum; // buffer number with expanded file name + char *ae_fname; // file name as specified + int ae_fnum; // buffer number with expanded file name } aentry_T; #define ALIST(win) (win)->w_alist @@ -321,12 +307,10 @@ typedef struct argentry { #define ARGCOUNT (ALIST(curwin)->al_ga.ga_len) #define WARGCOUNT(wp) (ALIST(wp)->al_ga.ga_len) -/* - * Used for the typeahead buffer: typebuf. - */ +// Used for the typeahead buffer: typebuf. typedef struct { - char_u *tb_buf; // buffer for typed characters - char_u *tb_noremap; // mapping flags for characters in tb_buf[] + uint8_t *tb_buf; // buffer for typed characters + uint8_t *tb_noremap; // mapping flags for characters in tb_buf[] int tb_buflen; // size of tb_buf[] int tb_off; // current position in tb_buf[] int tb_len; // number of valid bytes in tb_buf[] @@ -347,16 +331,14 @@ typedef struct { String save_inputbuf; } tasave_T; -/* - * Structure used for mappings and abbreviations. - */ +// Structure used for mappings and abbreviations. typedef struct mapblock mapblock_T; struct mapblock { - mapblock_T *m_next; // next mapblock in list - char_u *m_keys; // mapped from, lhs - char_u *m_str; // mapped to, rhs - char_u *m_orig_str; // rhs as entered by the user - LuaRef m_luaref; // lua function reference as rhs + mapblock_T *m_next; // next mapblock in list + uint8_t *m_keys; // mapped from, lhs + char *m_str; // mapped to, rhs + char *m_orig_str; // rhs as entered by the user + LuaRef m_luaref; // lua function reference as rhs int m_keylen; // strlen(m_keys) int m_mode; // valid mode int m_simplified; // m_keys was simplified, do no use this map @@ -366,8 +348,8 @@ struct mapblock { char m_nowait; // <nowait> used 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 + char *m_desc; // description of mapping + bool m_replace_keycodes; // replace keycodes in result of expression }; /// Used for highlighting in the status line. @@ -414,9 +396,7 @@ struct stl_item { typedef struct qf_info_S qf_info_T; -/* - * Used for :syntime: timing of executing a syntax pattern. - */ +// Used for :syntime: timing of executing a syntax pattern. typedef struct { proftime_T total; // total time used proftime_T slowest; // time of slowest call @@ -424,10 +404,8 @@ typedef struct { long match; // nr of times matched } syn_time_T; -/* - * These are items normally related to a buffer. But when using ":ownsyntax" - * a window may have its own instance. - */ +// These are items normally related to a buffer. But when using ":ownsyntax" +// a window may have its own instance. typedef struct { hashtab_T b_keywtab; // syntax keywords hash table hashtab_T b_keywtab_ic; // idem, ignore case @@ -440,14 +418,14 @@ typedef struct { garray_T b_syn_clusters; // table for syntax clusters int b_spell_cluster_id; // @Spell cluster ID or 0 int b_nospell_cluster_id; // @NoSpell cluster ID or 0 - int b_syn_containedin; // TRUE when there is an item with a + int b_syn_containedin; // true when there is an item with a // "containedin" argument int b_syn_sync_flags; // flags about how to sync int16_t b_syn_sync_id; // group to sync on 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 + char *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 @@ -476,17 +454,20 @@ typedef struct { disptick_T b_sst_lasttick; // last display tick // for spell checking - garray_T b_langp; // list of pointers to slang_T, see spell.c - bool b_spell_ismw[256]; // flags: is midword char - char_u *b_spell_ismw_mb; // multi-byte midword chars - char_u *b_p_spc; // 'spellcapcheck' + garray_T b_langp; // list of pointers to slang_T, see spell.c + bool b_spell_ismw[256]; // flags: is midword char + char *b_spell_ismw_mb; // multi-byte midword chars + char *b_p_spc; // 'spellcapcheck' regprog_T *b_cap_prog; // program for 'spellcapcheck' - char_u *b_p_spf; // 'spellfile' - char_u *b_p_spl; // 'spelllang' - char_u *b_p_spo; // 'spelloptions' - int b_cjk; // all CJK letters as OK - char_u b_syn_chartab[32]; // syntax iskeyword option - char_u *b_syn_isk; // iskeyword option + char *b_p_spf; // 'spellfile' + char *b_p_spl; // 'spelllang' + char *b_p_spo; // 'spelloptions' +#define SPO_CAMEL 0x1 +#define SPO_NPBUFFER 0x2 + unsigned b_p_spo_flags; // 'spelloptions' flags + int b_cjk; // all CJK letters as OK + uint8_t b_syn_chartab[32]; // syntax iskeyword option + char *b_syn_isk; // iskeyword option } synblock_T; /// Type used for changedtick_di member in buf_T @@ -514,13 +495,11 @@ EXTERN int curbuf_splice_pending INIT(= 0); // Maximum number of maphash blocks we will have #define MAX_MAPHASH 256 -/* - * buffer: structure that holds information about one file - * - * Several windows can share a single Buffer - * A buffer is unallocated if there is no memfile for it. - * A buffer is new if the associated file has never been loaded yet. - */ +// buffer: structure that holds information about one file +// +// Several windows can share a single Buffer +// A buffer is unallocated if there is no memfile for it. +// A buffer is new if the associated file has never been loaded yet. struct file_buffer { handle_T handle; // unique id for the buffer (buffer number) @@ -570,15 +549,13 @@ struct file_buffer { varnumber_T b_last_changedtick_pum; // b:changedtick when TextChangedP was // last triggered. - bool b_saving; /* Set to true if we are in the middle of - saving the buffer. */ + bool b_saving; // Set to true if we are in the middle of + // saving the buffer. - /* - * Changes to a buffer require updating of the display. To minimize the - * work, remember changes made and update everything at once. - */ - bool b_mod_set; /* true when there are changes since the last - time the display was updated */ + // Changes to a buffer require updating of the display. To minimize the + // work, remember changes made and update everything at once. + bool b_mod_set; // true when there are changes since the last + // time the display was updated linenr_T b_mod_top; // topmost lnum that was changed linenr_T b_mod_bot; // lnum below last changed line, AFTER the // change @@ -600,7 +577,7 @@ struct file_buffer { fmark_T b_namedm[NMARKS]; // current named marks (mark.c) - // These variables are set when VIsual_active becomes FALSE + // These variables are set when VIsual_active becomes false visualinfo_T b_visual; int b_visual_mode_eval; // b_visual.vi_mode for visualmode() @@ -609,17 +586,13 @@ struct file_buffer { fmark_T b_last_insert; // where Insert mode was left fmark_T b_last_change; // position of last change: '. mark - /* - * the changelist contains old change positions - */ + // the changelist contains old change positions fmark_T b_changelist[JUMPLISTSIZE]; int b_changelistlen; // number of active entries bool b_new_change; // set by u_savecommon() - /* - * Character table, only used in charset.c for 'iskeyword' - * bitset with 4*64=256 bits: 1 bit per character 0-255. - */ + // Character table, only used in charset.c for 'iskeyword' + // bitset with 4*64=256 bits: 1 bit per character 0-255. uint64_t b_chartab[4]; // Table used for mappings local to a buffer. @@ -629,18 +602,14 @@ struct file_buffer { mapblock_T *b_first_abbr; // User commands local to the buffer. garray_T b_ucmds; - /* - * start and end of an operator, also used for '[ and '] - */ + // start and end of an operator, also used for '[ and '] pos_T b_op_start; pos_T b_op_start_orig; // used for Insstart_orig pos_T b_op_end; bool b_marks_read; // Have we read ShaDa marks yet? - /* - * The following only used in undo.c. - */ + // The following only used in undo.c. u_header_T *b_u_oldhead; // pointer to oldest header u_header_T *b_u_newhead; // pointer to newest header; may not be valid // if b_u_curhead is not NULL @@ -649,14 +618,12 @@ struct file_buffer { bool b_u_synced; // entry lists are synced long b_u_seq_last; // last used undo sequence number long b_u_save_nr_last; // counter for last file write - long b_u_seq_cur; // hu_seq of header below which we are now + long b_u_seq_cur; // uh_seq of header below which we are now time_t b_u_time_cur; // uh_time of header below which we are now long b_u_save_nr_cur; // file write nr after which we are now - /* - * variables for "U" command in undo.c - */ - char_u *b_u_line_ptr; // saved line for "U" command + // variables for "U" command in undo.c + char *b_u_line_ptr; // saved line for "U" command linenr_T b_u_line_lnum; // line number of line in u_line colnr_T b_u_line_colnr; // optional column number @@ -675,83 +642,81 @@ struct file_buffer { #define KEYMAP_LOADED 2 // 'keymap' mappings have been loaded garray_T b_kmap_ga; // the keymap table - /* - * Options local to a buffer. - * They are here because their value depends on the type of file - * or contents of the file being edited. - */ + // Options local to a buffer. + // They are here because their value depends on the type of file + // or contents of the file being edited. bool b_p_initialized; // set when options initialized LastSet b_p_script_ctx[BV_COUNT]; // SCTXs for buffer-local options int b_p_ai; ///< 'autoindent' int b_p_ai_nopaste; ///< b_p_ai saved for paste mode - char_u *b_p_bkc; ///< 'backupco + char *b_p_bkc; ///< 'backupco unsigned int b_bkc_flags; ///< flags for 'backupco int b_p_ci; ///< 'copyindent' int b_p_bin; ///< 'binary' int b_p_bomb; ///< 'bomb' - char_u *b_p_bh; ///< 'bufhidden' - char_u *b_p_bt; ///< 'buftype' + char *b_p_bh; ///< 'bufhidden' + char *b_p_bt; ///< 'buftype' int b_has_qf_entry; ///< quickfix exists for buffer int b_p_bl; ///< 'buflisted' long b_p_channel; ///< 'channel' int b_p_cin; ///< 'cindent' - char_u *b_p_cino; ///< 'cinoptions' - char_u *b_p_cink; ///< 'cinkeys' - char_u *b_p_cinw; ///< 'cinwords' - char_u *b_p_cinsd; ///< 'cinscopedecls' - char_u *b_p_com; ///< 'comments' - char_u *b_p_cms; ///< 'commentstring' - char_u *b_p_cpt; ///< 'complete' + char *b_p_cino; ///< 'cinoptions' + char *b_p_cink; ///< 'cinkeys' + char *b_p_cinw; ///< 'cinwords' + char *b_p_cinsd; ///< 'cinscopedecls' + char *b_p_com; ///< 'comments' + char *b_p_cms; ///< 'commentstring' + char *b_p_cpt; ///< 'complete' #ifdef BACKSLASH_IN_FILENAME - char_u *b_p_csl; ///< 'completeslash' + char *b_p_csl; ///< 'completeslash' #endif - char_u *b_p_cfu; ///< 'completefunc' - char_u *b_p_ofu; ///< 'omnifunc' - char_u *b_p_tfu; ///< 'tagfunc' + char *b_p_cfu; ///< 'completefunc' + char *b_p_ofu; ///< 'omnifunc' + char *b_p_tfu; ///< 'tagfunc' int b_p_eol; ///< 'endofline' int b_p_fixeol; ///< 'fixendofline' int b_p_et; ///< 'expandtab' int b_p_et_nobin; ///< b_p_et saved for binary mode int b_p_et_nopaste; ///< b_p_et saved for paste mode - char_u *b_p_fenc; ///< 'fileencoding' - char_u *b_p_ff; ///< 'fileformat' - char_u *b_p_ft; ///< 'filetype' - char_u *b_p_fo; ///< 'formatoptions' - char_u *b_p_flp; ///< 'formatlistpat' + char *b_p_fenc; ///< 'fileencoding' + char *b_p_ff; ///< 'fileformat' + char *b_p_ft; ///< 'filetype' + char *b_p_fo; ///< 'formatoptions' + char *b_p_flp; ///< 'formatlistpat' int b_p_inf; ///< 'infercase' - char_u *b_p_isk; ///< 'iskeyword' - char_u *b_p_def; ///< 'define' local value - char_u *b_p_inc; ///< 'include' - char_u *b_p_inex; ///< 'includeexpr' + char *b_p_isk; ///< 'iskeyword' + char *b_p_def; ///< 'define' local value + char *b_p_inc; ///< 'include' + char *b_p_inex; ///< 'includeexpr' uint32_t b_p_inex_flags; ///< flags for 'includeexpr' - char_u *b_p_inde; ///< 'indentexpr' + char *b_p_inde; ///< 'indentexpr' uint32_t b_p_inde_flags; ///< flags for 'indentexpr' - char_u *b_p_indk; ///< 'indentkeys' - char_u *b_p_fp; ///< 'formatprg' - char_u *b_p_fex; ///< 'formatexpr' + char *b_p_indk; ///< 'indentkeys' + char *b_p_fp; ///< 'formatprg' + char *b_p_fex; ///< 'formatexpr' uint32_t b_p_fex_flags; ///< flags for 'formatexpr' - char_u *b_p_kp; ///< 'keywordprg' + char *b_p_kp; ///< 'keywordprg' int b_p_lisp; ///< 'lisp' - char_u *b_p_menc; ///< 'makeencoding' - char_u *b_p_mps; ///< 'matchpairs' + char *b_p_menc; ///< 'makeencoding' + char *b_p_mps; ///< 'matchpairs' int b_p_ml; ///< 'modeline' int b_p_ml_nobin; ///< b_p_ml saved for binary mode int b_p_ma; ///< 'modifiable' - char_u *b_p_nf; ///< 'nrformats' + char *b_p_nf; ///< 'nrformats' int b_p_pi; ///< 'preserveindent' - char_u *b_p_qe; ///< 'quoteescape' + char *b_p_qe; ///< 'quoteescape' int b_p_ro; ///< 'readonly' long b_p_sw; ///< 'shiftwidth' long b_p_scbk; ///< 'scrollback' int b_p_si; ///< 'smartindent' long b_p_sts; ///< 'softtabstop' long b_p_sts_nopaste; ///< b_p_sts saved for paste mode - char_u *b_p_sua; ///< 'suffixesadd' + char *b_p_sua; ///< 'suffixesadd' int b_p_swf; ///< 'swapfile' long b_p_smc; ///< 'synmaxcol' - char_u *b_p_syn; ///< 'syntax' + char *b_p_syn; ///< 'syntax' long b_p_ts; ///< 'tabstop' long b_p_tw; ///< 'textwidth' long b_p_tw_nobin; ///< b_p_tw saved for binary mode @@ -759,29 +724,29 @@ struct file_buffer { long b_p_wm; ///< 'wrapmargin' long b_p_wm_nobin; ///< b_p_wm saved for binary mode long b_p_wm_nopaste; ///< b_p_wm saved for paste mode - char_u *b_p_vsts; ///< 'varsofttabstop' - long *b_p_vsts_array; ///< 'varsofttabstop' in internal format - char_u *b_p_vsts_nopaste; ///< b_p_vsts saved for paste mode - char_u *b_p_vts; ///< 'vartabstop' - long *b_p_vts_array; ///< 'vartabstop' in internal format - char_u *b_p_keymap; ///< 'keymap' + char *b_p_vsts; ///< 'varsofttabstop' + long *b_p_vsts_array; ///< 'varsofttabstop' in internal format + char *b_p_vsts_nopaste; ///< b_p_vsts saved for paste mode + char *b_p_vts; ///< 'vartabstop' + long *b_p_vts_array; ///< 'vartabstop' in internal format + char *b_p_keymap; ///< 'keymap' // local values for options which are normally global - char_u *b_p_gp; ///< 'grepprg' local value - char_u *b_p_mp; ///< 'makeprg' local value - char_u *b_p_efm; ///< 'errorformat' local value - char_u *b_p_ep; ///< 'equalprg' local value - char_u *b_p_path; ///< 'path' local value + char *b_p_gp; ///< 'grepprg' local value + char *b_p_mp; ///< 'makeprg' local value + char *b_p_efm; ///< 'errorformat' local value + char *b_p_ep; ///< 'equalprg' local value + char *b_p_path; ///< 'path' local value int b_p_ar; ///< 'autoread' local value - char_u *b_p_tags; ///< 'tags' local value - char_u *b_p_tc; ///< 'tagcase' local value + char *b_p_tags; ///< 'tags' local value + char *b_p_tc; ///< 'tagcase' local value unsigned b_tc_flags; ///< flags for 'tagcase' - char_u *b_p_dict; ///< 'dictionary' local value - char_u *b_p_tsr; ///< 'thesaurus' local value - char_u *b_p_tsrfu; ///< 'thesaurusfunc' local value + char *b_p_dict; ///< 'dictionary' local value + char *b_p_tsr; ///< 'thesaurus' local value + char *b_p_tsrfu; ///< 'thesaurusfunc' local value long b_p_ul; ///< 'undolevels' local value int b_p_udf; ///< 'undofile' - char_u *b_p_lw; ///< 'lispwords' local value + char *b_p_lw; ///< 'lispwords' local value // end of buffer options @@ -824,8 +789,8 @@ struct file_buffer { int b_ind_cpp_extern_c; int b_ind_pragma; - linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary - * write should not have an end-of-line */ + linenr_T b_no_eol_lnum; // non-zero lnum when last line of next binary + // write should not have an end-of-line int b_start_eol; // last line had eol when it was read int b_start_ffc; // first char of 'ff' when edit started @@ -836,20 +801,18 @@ struct file_buffer { ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary. dict_T *b_vars; ///< b: scope dictionary. - /* When a buffer is created, it starts without a swap file. b_may_swap is - * then set to indicate that a swap file may be opened later. It is reset - * if a swap file could not be opened. - */ + // When a buffer is created, it starts without a swap file. b_may_swap is + // then set to indicate that a swap file may be opened later. It is reset + // if a swap file could not be opened. bool b_may_swap; - bool b_did_warn; /* Set to true if user has been warned on first - change of a read-only file */ - - /* Two special kinds of buffers: - * help buffer - used for help files, won't use a swap file. - * spell buffer - used for spell info, never displayed and doesn't have a - * file name. - */ - bool b_help; // TRUE for help file buffer (when set b_p_bt + bool b_did_warn; // Set to true if user has been warned on first + // change of a read-only file + + // Two special kinds of buffers: + // help buffer - used for help files, won't use a swap file. + // spell buffer - used for spell info, never displayed and doesn't have a + // file name. + bool b_help; // true for help file buffer (when set b_p_bt // is "help") bool b_spell; // True for a spell file buffer, most fields // are not used! Use the B_SPELL macro to @@ -908,25 +871,21 @@ struct file_buffer { int b_diff_failed; // internal diff failed for this buffer }; -/* - * Stuff for diff mode. - */ +// Stuff for diff mode. #define DB_COUNT 8 // up to four buffers can be diff'ed -/* - * Each diffblock defines where a block of lines starts in each of the buffers - * and how many lines it occupies in that buffer. When the lines are missing - * in the buffer the df_count[] is zero. This is all counted in - * buffer lines. - * There is always at least one unchanged line in between the diffs. - * Otherwise it would have been included in the diff above or below it. - * df_lnum[] + df_count[] is the lnum below the change. When in one buffer - * lines have been inserted, in the other buffer df_lnum[] is the line below - * the insertion and df_count[] is zero. When appending lines at the end of - * the buffer, df_lnum[] is one beyond the end! - * This is using a linked list, because the number of differences is expected - * to be reasonable small. The list is sorted on lnum. - */ +// Each diffblock defines where a block of lines starts in each of the buffers +// and how many lines it occupies in that buffer. When the lines are missing +// in the buffer the df_count[] is zero. This is all counted in +// buffer lines. +// There is always at least one unchanged line in between the diffs. +// Otherwise it would have been included in the diff above or below it. +// df_lnum[] + df_count[] is the lnum below the change. When in one buffer +// lines have been inserted, in the other buffer df_lnum[] is the line below +// the insertion and df_count[] is zero. When appending lines at the end of +// the buffer, df_lnum[] is one beyond the end! +// This is using a linked list, because the number of differences is expected +// to be reasonable small. The list is sorted on lnum. typedef struct diffblock_S diff_T; struct diffblock_S { diff_T *df_next; @@ -966,30 +925,26 @@ struct tabpage_S { char *tp_prevdir; ///< Previous directory. }; -/* - * Structure to cache info for displayed lines in w_lines[]. - * Each logical line has one entry. - * The entry tells how the logical line is currently displayed in the window. - * This is updated when displaying the window. - * When the display is changed (e.g., when clearing the screen) w_lines_valid - * is changed to exclude invalid entries. - * When making changes to the buffer, wl_valid is reset to indicate wl_size - * may not reflect what is actually in the buffer. When wl_valid is FALSE, - * the entries can only be used to count the number of displayed lines used. - * wl_lnum and wl_lastlnum are invalid too. - */ +// Structure to cache info for displayed lines in w_lines[]. +// Each logical line has one entry. +// The entry tells how the logical line is currently displayed in the window. +// This is updated when displaying the window. +// When the display is changed (e.g., when clearing the screen) w_lines_valid +// is changed to exclude invalid entries. +// When making changes to the buffer, wl_valid is reset to indicate wl_size +// may not reflect what is actually in the buffer. When wl_valid is false, +// the entries can only be used to count the number of displayed lines used. +// wl_lnum and wl_lastlnum are invalid too. typedef struct w_line { linenr_T wl_lnum; // buffer line number for logical line uint16_t wl_size; // height in screen lines - char wl_valid; // TRUE values are valid for text in buffer - char wl_folded; // TRUE when this is a range of folded lines + char wl_valid; // true values are valid for text in buffer + char wl_folded; // true when this is a range of folded lines linenr_T wl_lastlnum; // last buffer line number for logical line } wline_T; -/* - * Windows are kept in a tree of frames. Each frame has a column (FR_COL) - * or row (FR_ROW) layout or is a leaf, which has a window. - */ +// Windows are kept in a tree of frames. Each frame has a column (FR_COL) +// or row (FR_ROW) layout or is a leaf, which has a window. struct frame_S { char fr_layout; // FR_LEAF, FR_COL or FR_ROW int fr_width; @@ -1010,12 +965,10 @@ struct frame_S { #define FR_ROW 1 // frame with a row of windows #define FR_COL 2 // frame with a column of windows -/* - * Struct used for highlighting 'hlsearch' matches, matches defined by - * ":match" and matches defined by match functions. - * For 'hlsearch' there is one pattern for all windows. For ":match" and the - * match functions there is a different pattern for each window. - */ +// Struct used for highlighting 'hlsearch' matches, matches defined by +// ":match" and matches defined by match functions. +// For 'hlsearch' there is one pattern for all windows. For ":match" and the +// match functions there is a different pattern for each window. typedef struct { regmmatch_T rm; // points to the regexp program; contains last found // match (may continue in next line) @@ -1031,9 +984,6 @@ typedef struct { proftime_T tm; // for a time limit } match_T; -/// number of positions supported by matchaddpos() -#define MAXPOSMATCH 8 - /// Same as lpos_T, but with additional field len. typedef struct { linenr_T lnum; ///< line number @@ -1041,31 +991,28 @@ typedef struct { int len; ///< length: 0 - to the end of line } llpos_T; -/// posmatch_T provides an array for storing match items for matchaddpos() -/// function. -typedef struct posmatch posmatch_T; -struct posmatch { - llpos_T pos[MAXPOSMATCH]; ///< array of positions - int cur; ///< internal position counter - linenr_T toplnum; ///< top buffer line - linenr_T botlnum; ///< bottom buffer line -}; - -/* - * matchitem_T provides a linked list for storing match items for ":match" and - * the match functions. - */ +/// matchitem_T provides a linked list for storing match items for ":match", +/// matchadd() and matchaddpos(). typedef struct matchitem matchitem_T; struct matchitem { - matchitem_T *next; - int id; ///< match ID - int priority; ///< match priority - char *pattern; ///< pattern to highlight - regmmatch_T match; ///< regexp program for pattern - posmatch_T pos; ///< position matches - match_T hl; ///< struct for doing the actual highlighting - int hlg_id; ///< highlight group ID - int conceal_char; ///< cchar for Conceal highlighting + matchitem_T *mit_next; + int mit_id; ///< match ID + int mit_priority; ///< match priority + + // Either a pattern is defined (mit_pattern is not NUL) or a list of + // positions is given (mit_pos is not NULL and mit_pos_count > 0). + char *mit_pattern; ///< pattern to highlight + regmmatch_T mit_match; ///< regexp program for pattern + + llpos_T *mit_pos_array; ///< array of positions + int mit_pos_count; ///< nr of entries in mit_pos + int mit_pos_cur; ///< internal position counter + linenr_T mit_toplnum; ///< top buffer line + linenr_T mit_botlnum; ///< bottom buffer line + + match_T mit_hl; ///< struct for doing the actual highlighting + int mit_hlg_id; ///< highlight group ID + int mit_conceal_char; ///< cchar for Conceal highlighting }; typedef int FloatAnchor; @@ -1236,16 +1183,15 @@ struct window_S { int diff; int msgsep; int eob; + int lastline; } w_p_fcs_chars; - /* - * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for - * displaying the buffer. - */ - linenr_T w_topline; /* buffer line number of the line at the - top of the window */ - char w_topline_was_set; /* flag set to TRUE when topline is set, - e.g. by winrestview() */ + // "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for + // displaying the buffer. + linenr_T w_topline; // buffer line number of the line at the + // top of the window + char w_topline_was_set; // flag set to true when topline is set, + // e.g. by winrestview() int w_topfill; // number of filler lines above w_topline int w_old_topfill; // w_topfill at last redraw bool w_botfill; // true when filler lines are actually @@ -1257,9 +1203,10 @@ struct window_S { colnr_T w_skipcol; // starting column when a single line // doesn't fit in the window - // four fields that are only used when there is a WinScrolled autocommand + // five fields that are only used when there is a WinScrolled autocommand linenr_T w_last_topline; ///< last known value for w_topline colnr_T w_last_leftcol; ///< last known value for w_leftcol + colnr_T w_last_skipcol; ///< last known value for w_skipcol int w_last_width; ///< last known value for w_width int w_last_height; ///< last known value for w_height @@ -1270,6 +1217,8 @@ struct window_S { int w_winrow; // first row of window in screen int w_height; // number of rows in window, excluding // status/command line(s) + int w_prev_winrow; // previous winrow used for 'splitkeep' + int w_prev_height; // previous height used for 'splitkeep' int w_status_height; // number of status lines (0 or 1) int w_winbar_height; // number of window bars (0 or 1) int w_wincol; // Leftmost column of window in screen. @@ -1295,26 +1244,20 @@ struct window_S { int w_height_outer; int w_width_outer; - /* - * === start of cached values ==== - */ - /* - * Recomputing is minimized by storing the result of computations. - * Use functions in screen.c to check if they are valid and to update. - * w_valid is a bitfield of flags, which indicate if specific values are - * valid or need to be recomputed. - */ + // === start of cached values ==== + + // Recomputing is minimized by storing the result of computations. + // Use functions in screen.c to check if they are valid and to update. + // w_valid is a bitfield of flags, which indicate if specific values are + // valid or need to be recomputed. int w_valid; - pos_T w_valid_cursor; /* last known position of w_cursor, used - to adjust w_valid */ + pos_T w_valid_cursor; // last known position of w_cursor, used to adjust w_valid colnr_T w_valid_leftcol; // last known w_leftcol bool w_viewport_invalid; - /* - * w_cline_height is the number of physical lines taken by the buffer line - * that the cursor is on. We use this to avoid extra calls to plines_win(). - */ + // w_cline_height is the number of physical lines taken by the buffer line + // that the cursor is on. We use this to avoid extra calls to plines_win(). int w_cline_height; // current size of cursor line bool w_cline_folded; // cursor line is folded @@ -1327,11 +1270,9 @@ struct window_S { // more than one screen line or when // w_leftcol is non-zero - /* - * w_wrow and w_wcol specify the cursor position in the window. - * This is related to positions in the window, not in the display or - * buffer, thus w_wrow is relative to w_winrow. - */ + // w_wrow and w_wcol specify the cursor position in the window. + // This is related to positions in the window, not in the display or + // buffer, thus w_wrow is relative to w_winrow. int w_wrow, w_wcol; // cursor position in window linenr_T w_botline; // number of the line below the bottom of @@ -1340,16 +1281,14 @@ struct window_S { int w_filler_rows; // number of filler rows at the end of the // window - /* - * Info about the lines currently in the window is remembered to avoid - * recomputing it every time. The allocated size of w_lines[] is Rows. - * Only the w_lines_valid entries are actually valid. - * When the display is up-to-date w_lines[0].wl_lnum is equal to w_topline - * and w_lines[w_lines_valid - 1].wl_lnum is equal to w_botline. - * Between changing text and updating the display w_lines[] represents - * what is currently displayed. wl_valid is reset to indicated this. - * This is used for efficient redrawing. - */ + // Info about the lines currently in the window is remembered to avoid + // recomputing it every time. The allocated size of w_lines[] is Rows. + // Only the w_lines_valid entries are actually valid. + // When the display is up-to-date w_lines[0].wl_lnum is equal to w_topline + // and w_lines[w_lines_valid - 1].wl_lnum is equal to w_botline. + // Between changing text and updating the display w_lines[] represents + // what is currently displayed. wl_valid is reset to indicated this. + // This is used for efficient redrawing. int w_lines_valid; // number of valid entries wline_T *w_lines; @@ -1362,13 +1301,11 @@ struct window_S { // column being used int w_scwidth; // width of 'signcolumn' - /* - * === end of cached values === - */ + // === end of cached values === int w_redr_type; // type of redraw to be performed on win int w_upd_rows; // number of window lines to update when - // w_redr_type is REDRAW_TOP + // w_redr_type is UPD_REDRAW_TOP linenr_T w_redraw_top; // when != 0: first line needing redraw linenr_T w_redraw_bot; // when != 0: last line needing redraw bool w_redr_status; // if true statusline/winbar must be redrawn @@ -1380,7 +1317,7 @@ struct window_S { linenr_T w_ru_topline; // topline shown in ruler linenr_T w_ru_line_count; // line count used for ruler int w_ru_topfill; // topfill shown in ruler - char w_ru_empty; // TRUE if ruler shows 0-1 (empty line) + char w_ru_empty; // true if ruler shows 0-1 (empty line) int w_alt_fnum; // alternate file (for # and CTRL-^) @@ -1422,17 +1359,13 @@ struct window_S { ScopeDictDictItem w_winvar; ///< Variable for "w:" dictionary. dict_T *w_vars; ///< Dictionary with w: variables. - /* - * The w_prev_pcmark field is used to check whether we really did jump to - * a new line after setting the w_pcmark. If not, then we revert to - * using the previous w_pcmark. - */ + // The w_prev_pcmark field is used to check whether we really did jump to + // a new line after setting the w_pcmark. If not, then we revert to + // using the previous w_pcmark. pos_T w_pcmark; // previous context mark pos_T w_prev_pcmark; // previous w_pcmark - /* - * the jumplist contains old cursor positions - */ + // the jumplist contains old cursor positions xfmark_T w_jumplist[JUMPLISTSIZE]; int w_jumplistlen; // number of active entries int w_jumplistidx; // current position @@ -1442,12 +1375,10 @@ struct window_S { matchitem_T *w_match_head; // head of match list int w_next_match_id; // next match ID - /* - * the tagstack grows from 0 upwards: - * entry 0: older - * entry 1: newer - * entry 2: newest - */ + // the tagstack grows from 0 upwards: + // entry 0: older + // entry 1: newer + // entry 2: newest taggy_T w_tagstack[TAGSTACKSIZE]; // the tag stack int w_tagstackidx; // idx just below active entry int w_tagstacklen; // number of tags on stack @@ -1458,17 +1389,14 @@ struct window_S { bool w_floating; ///< whether the window is floating FloatConfig w_float_config; - /* - * w_fraction is the fractional row of the cursor within the window, from - * 0 at the top row to FRACTION_MULT at the last row. - * w_prev_fraction_row was the actual cursor row when w_fraction was last - * calculated. - */ + // w_fraction is the fractional row of the cursor within the window, from + // 0 at the top row to FRACTION_MULT at the last row. + // w_prev_fraction_row was the actual cursor row when w_fraction was last + // calculated. int w_fraction; int w_prev_fraction_row; - linenr_T w_nrwidth_line_count; /* line count when ml_nrwidth_width - * was computed. */ + linenr_T w_nrwidth_line_count; // line count when ml_nrwidth_width was computed. int w_nrwidth_width; // nr of chars to print line count. qf_info_T *w_llist; // Location list for this window @@ -1491,4 +1419,4 @@ struct window_S { #define CHANGEDTICK(buf) \ (=== Include buffer.h & use buf_(get|set|inc) _changedtick ===) -#endif // NVIM_BUFFER_DEFS_H +#endif // NVIM_BUFFER_DEFS_H diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 14973502ab..1b3c0bc28f 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -285,14 +285,13 @@ void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added, args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits); } textlock++; - Object res = nlua_call_ref(cb.on_lines, "lines", args, true, NULL); + Object res = nlua_call_ref(cb.on_lines, "lines", args, false, NULL); textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { buffer_update_callbacks_free(cb); keep = false; } - api_free_object(res); } if (keep) { kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i); @@ -335,7 +334,7 @@ void buf_updates_send_splice(buf_T *buf, int start_row, colnr_T start_col, bcoun ADD_C(args, INTEGER_OBJ(new_byte)); textlock++; - Object res = nlua_call_ref(cb.on_bytes, "bytes", args, true, NULL); + Object res = nlua_call_ref(cb.on_bytes, "bytes", args, false, NULL); textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { @@ -371,14 +370,13 @@ void buf_updates_changedtick(buf_T *buf) textlock++; Object res = nlua_call_ref(cb.on_changedtick, "changedtick", - args, true, NULL); + args, false, NULL); textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { buffer_update_callbacks_free(cb); keep = false; } - api_free_object(res); } if (keep) { kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i); diff --git a/src/nvim/change.c b/src/nvim/change.c index 5184dc0689..c9e57ab88f 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -26,6 +26,7 @@ #include "nvim/plines.h" #include "nvim/search.h" #include "nvim/state.h" +#include "nvim/textformat.h" #include "nvim/ui.h" #include "nvim/undo.h" @@ -96,8 +97,7 @@ void changed(void) // Create a swap file if that is wanted. // Don't do this for "nofile" and "nowrite" buffer types. - if (curbuf->b_may_swap - && !bt_dontwrite(curbuf)) { + if (curbuf->b_may_swap && !bt_dontwrite(curbuf)) { bool save_need_wait_return = need_wait_return; need_wait_return = false; @@ -223,8 +223,8 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_buffer == curbuf) { // Mark this window to be redrawn later. - if (wp->w_redr_type < VALID) { - wp->w_redr_type = VALID; + if (wp->w_redr_type < UPD_VALID) { + wp->w_redr_type = UPD_VALID; } // Check if a change in the buffer has invalidated the cached @@ -301,17 +301,17 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T // requires a redraw. if (wp->w_p_rnu && xtra != 0) { wp->w_last_cursor_lnum_rnu = 0; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } // Cursor line highlighting probably need to be updated with - // "VALID" if it's below the change. + // "UPD_VALID" if it's below the change. // If the cursor line is inside the change we need to redraw more. if (wp->w_p_cul) { if (xtra == 0) { - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } else if (lnum <= wp->w_last_cursorline) { - redraw_later(wp, SOME_VALID); + redraw_later(wp, UPD_SOME_VALID); } } } @@ -319,8 +319,8 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T // Call update_screen() later, which checks out what needs to be redrawn, // since it notices b_mod_set and then uses b_mod_*. - if (must_redraw < VALID) { - must_redraw = VALID; + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; } // when the cursor line is changed always trigger CursorMoved @@ -364,7 +364,7 @@ void changed_bytes(linenr_T lnum, colnr_T col) if (curwin->w_p_diff) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_diff && wp != curwin) { - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); linenr_T wlnum = diff_lnum_win(lnum, wp); if (wlnum > 0) { changedOneline(wp->w_buffer, wlnum); @@ -493,7 +493,7 @@ void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra, bo FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_diff && wp != curwin) { - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); wlnum = diff_lnum_win(lnum, wp); if (wlnum > 0) { changed_lines_buf(wp->w_buffer, wlnum, @@ -534,16 +534,67 @@ void unchanged(buf_T *buf, int ff, bool always_inc_changedtick) } } +/// Save the current values of 'fileformat' and 'fileencoding', so that we know +/// the file must be considered changed when the value is different. +void save_file_ff(buf_T *buf) +{ + buf->b_start_ffc = (unsigned char)(*buf->b_p_ff); + buf->b_start_eol = buf->b_p_eol; + buf->b_start_bomb = buf->b_p_bomb; + + // Only use free/alloc when necessary, they take time. + if (buf->b_start_fenc == NULL + || strcmp(buf->b_start_fenc, buf->b_p_fenc) != 0) { + xfree(buf->b_start_fenc); + buf->b_start_fenc = xstrdup(buf->b_p_fenc); + } +} + +/// Return true if 'fileformat' and/or 'fileencoding' has a different value +/// from when editing started (save_file_ff() called). +/// Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was +/// changed and 'binary' is not set. +/// Also when 'endofline' was changed and 'fixeol' is not set. +/// When "ignore_empty" is true don't consider a new, empty buffer to be +/// changed. +bool file_ff_differs(buf_T *buf, bool ignore_empty) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + // In a buffer that was never loaded the options are not valid. + if (buf->b_flags & BF_NEVERLOADED) { + return false; + } + if (ignore_empty + && (buf->b_flags & BF_NEW) + && buf->b_ml.ml_line_count == 1 + && *ml_get_buf(buf, (linenr_T)1, false) == NUL) { + return false; + } + if (buf->b_start_ffc != *buf->b_p_ff) { + return true; + } + if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) { + return true; + } + if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) { + return true; + } + if (buf->b_start_fenc == NULL) { + return *buf->b_p_fenc != NUL; + } + return strcmp(buf->b_start_fenc, buf->b_p_fenc) != 0; +} + /// Insert string "p" at the cursor position. Stops at a NUL byte. /// Handles Replace mode and multi-byte characters. -void ins_bytes(char_u *p) +void ins_bytes(char *p) { - ins_bytes_len(p, STRLEN(p)); + ins_bytes_len(p, strlen(p)); } /// Insert string "p" with length "len" at the cursor position. /// Handles Replace mode and multi-byte characters. -void ins_bytes_len(char_u *p, size_t len) +void ins_bytes_len(char *p, size_t len) { size_t n; for (size_t i = 0; i < len; i += n) { @@ -560,18 +611,18 @@ void ins_bytes_len(char_u *p, size_t len) /// convert bytes to a character. void ins_char(int c) { - char_u buf[MB_MAXBYTES + 1]; - size_t n = (size_t)utf_char2bytes(c, (char *)buf); + char buf[MB_MAXBYTES + 1]; + size_t n = (size_t)utf_char2bytes(c, buf); // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte. // Happens for CTRL-Vu9900. if (buf[0] == 0) { buf[0] = '\n'; } - ins_char_bytes((char_u *)buf, n); + ins_char_bytes(buf, n); } -void ins_char_bytes(char_u *buf, size_t charlen) +void ins_char_bytes(char *buf, size_t charlen) { // Break tabs if needed. if (virtual_active() && curwin->w_cursor.coladd > 0) { @@ -580,8 +631,8 @@ void ins_char_bytes(char_u *buf, size_t charlen) size_t col = (size_t)curwin->w_cursor.col; linenr_T lnum = curwin->w_cursor.lnum; - char_u *oldp = ml_get(lnum); - size_t linelen = STRLEN(oldp) + 1; // length of old line including NUL + char *oldp = ml_get(lnum); + size_t linelen = strlen(oldp) + 1; // length of old line including NUL // The lengths default to the values for when not replacing. size_t oldlen = 0; // nr of bytes inserted @@ -610,7 +661,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) if (vcol > new_vcol && oldp[col + oldlen] == TAB) { break; } - oldlen += (size_t)utfc_ptr2len((char *)oldp + col + oldlen); + oldlen += (size_t)utfc_ptr2len(oldp + col + oldlen); // Deleted a bit too much, insert spaces. if (vcol > new_vcol) { newlen += (size_t)(vcol - new_vcol); @@ -619,7 +670,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) curwin->w_p_list = old_list; } else if (oldp[col] != NUL) { // normal replace - oldlen = (size_t)utfc_ptr2len((char *)oldp + col); + oldlen = (size_t)utfc_ptr2len(oldp + col); } // Push the replaced bytes onto the replace stack, so that they can be @@ -632,7 +683,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) } } - char_u *newp = xmalloc(linelen + newlen - oldlen); + char *newp = xmalloc(linelen + newlen - oldlen); // Copy bytes before the cursor. if (col > 0) { @@ -640,7 +691,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) } // Copy bytes after the changed character(s). - char_u *p = newp + col; + char *p = newp + col; if (linelen > col + oldlen) { memmove(p + newlen, oldp + col + oldlen, (size_t)(linelen - col - oldlen)); @@ -655,7 +706,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) } // Replace the line in the buffer. - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); // mark the buffer as changed and prepare for displaying inserted_bytes(lnum, (colnr_T)col, (int)oldlen, (int)newlen); @@ -665,7 +716,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) if (p_sm && (State & MODE_INSERT) && msg_silent == 0 && !ins_compl_active()) { - showmatch(utf_ptr2char((char *)buf)); + showmatch(utf_ptr2char(buf)); } if (!p_ri || (State & REPLACE_FLAG)) { @@ -678,9 +729,9 @@ void ins_char_bytes(char_u *buf, size_t charlen) /// Insert a string at the cursor position. /// Note: Does NOT handle Replace mode. /// Caller must have prepared for undo. -void ins_str(char_u *s) +void ins_str(char *s) { - int newlen = (int)STRLEN(s); + int newlen = (int)strlen(s); linenr_T lnum = curwin->w_cursor.lnum; if (virtual_active() && curwin->w_cursor.coladd > 0) { @@ -688,10 +739,10 @@ void ins_str(char_u *s) } colnr_T col = curwin->w_cursor.col; - char_u *oldp = ml_get(lnum); - int oldlen = (int)STRLEN(oldp); + char *oldp = ml_get(lnum); + int oldlen = (int)strlen(oldp); - char_u *newp = (char_u *)xmalloc((size_t)oldlen + (size_t)newlen + 1); + char *newp = xmalloc((size_t)oldlen + (size_t)newlen + 1); if (col > 0) { memmove(newp, oldp, (size_t)col); } @@ -699,7 +750,7 @@ void ins_str(char_u *s) int bytes = oldlen - col + 1; assert(bytes >= 0); memmove(newp + col + newlen, oldp + col, (size_t)bytes); - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); inserted_bytes(lnum, col, 0, newlen); curwin->w_cursor.col += newlen; } @@ -723,9 +774,9 @@ int del_char(bool fixpos) int del_chars(long count, int fixpos) { int bytes = 0; - char_u *p = get_cursor_pos_ptr(); + char *p = get_cursor_pos_ptr(); for (long i = 0; i < count && *p != NUL; i++) { - int l = utfc_ptr2len((char *)p); + int l = utfc_ptr2len(p); bytes += l; p += l; } @@ -746,8 +797,8 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) linenr_T lnum = curwin->w_cursor.lnum; colnr_T col = curwin->w_cursor.col; bool fixpos = fixpos_arg; - char_u *oldp = ml_get(lnum); - colnr_T oldlen = (colnr_T)STRLEN(oldp); + char *oldp = ml_get(lnum); + colnr_T oldlen = (colnr_T)strlen(oldp); // Can't do anything when the cursor is on the NUL after the line. if (col >= oldlen) { @@ -766,7 +817,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // If 'delcombine' is set and deleting (less than) one character, only // delete the last combining character. if (p_deco && use_delcombine - && utfc_ptr2len((char *)oldp + col) >= count) { + && utfc_ptr2len(oldp + col) >= count) { int cc[MAX_MCO]; (void)utfc_ptr2char(oldp + col, cc); @@ -775,7 +826,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) int n = col; do { col = n; - count = utf_ptr2len((char *)oldp + n); + count = utf_ptr2len(oldp + n); n += count; } while (utf_composinglike(oldp + col, oldp + n)); fixpos = false; @@ -801,9 +852,9 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // If the old line has been allocated the deletion can be done in the // existing line. Otherwise a new line has to be allocated. bool was_alloced = ml_line_alloced(); // check if oldp was allocated - char_u *newp; + char *newp; if (was_alloced) { - ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen); + ml_add_deleted_len((char *)curbuf->b_ml.ml_line_ptr, oldlen); newp = oldp; // use same allocated memory } else { // need to allocate a new line newp = xmalloc((size_t)(oldlen + 1 - count)); @@ -811,7 +862,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) } memmove(newp + col, oldp + col + count, (size_t)movelen); if (!was_alloced) { - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); } // mark the buffer as changed and prepare for displaying @@ -823,10 +874,10 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) /// Copy the indent from ptr to the current line (and fill to size). /// Leaves the cursor on the first non-blank in the line. /// @return true if the line was changed. -int copy_indent(int size, char_u *src) +int copy_indent(int size, char *src) { - char_u *p = NULL; - char_u *line = NULL; + char *p = NULL; + char *line = NULL; int ind_len; int line_len = 0; int tab_pad; @@ -838,7 +889,7 @@ int copy_indent(int size, char_u *src) ind_len = 0; int ind_done = 0; int ind_col = 0; - char_u *s = src; + char *s = src; // Count/copy the usable portion of the source line. while (todo > 0 && ascii_iswhite(*s)) { @@ -911,7 +962,7 @@ int copy_indent(int size, char_u *src) if (p == NULL) { // Allocate memory for the result: the copied indent, new indent // and the rest of the line. - line_len = (int)STRLEN(get_cursor_line_ptr()) + 1; + line_len = (int)strlen(get_cursor_line_ptr()) + 1; assert(ind_len + line_len >= 0); size_t line_size; STRICT_ADD(ind_len, line_len, &line_size, size_t); @@ -924,7 +975,7 @@ int copy_indent(int size, char_u *src) memmove(p, get_cursor_line_ptr(), (size_t)line_len); // Replace the line - ml_replace(curwin->w_cursor.lnum, (char *)line, false); + ml_replace(curwin->w_cursor.lnum, line, false); // Put the cursor after the indent. curwin->w_cursor.col = ind_len; @@ -948,15 +999,15 @@ int copy_indent(int size, char_u *src) /// "second_line_indent": indent for after ^^D in Insert mode or if flag /// OPENLINE_COM_LIST /// "did_do_comment" is set to true when intentionally putting the comment -/// leader in fromt of the new line. +/// leader in front of the new line. /// /// @param dir FORWARD or BACKWARD /// /// @return true on success, false on failure int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) { - char_u *next_line = NULL; // copy of the next line - char_u *p_extra = NULL; // what goes to next line + char *next_line = NULL; // copy of the next line + char *p_extra = NULL; // what goes to next line colnr_T less_cols = 0; // less columns for mark in new line colnr_T less_cols_off = 0; // columns to skip for mark adjust pos_T old_cursor; // old cursor position @@ -969,9 +1020,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) int comment_start = 0; // start index of the 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 *allocated = NULL; // allocated memory char *p; - char_u saved_char = NUL; // init for GCC + char saved_char = NUL; // init for GCC pos_T *pos; bool do_si = may_do_si(); bool do_cindent; @@ -985,7 +1036,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) colnr_T mincol = curwin->w_cursor.col + 1; // make a copy of the current line so we can mess with it - char_u *saved_line = vim_strsave(get_cursor_line_ptr()); + char *saved_line = xstrdup(get_cursor_line_ptr()); if (State & VREPLACE_FLAG) { // With MODE_VREPLACE we make a copy of the next line, which we will be @@ -996,9 +1047,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // the line, replacing what was there before and pushing the right // stuff onto the replace stack. -- webb. if (curwin->w_cursor.lnum < orig_line_count) { - next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1)); + next_line = xstrdup(ml_get(curwin->w_cursor.lnum + 1)); } else { - next_line = vim_strsave((char_u *)""); + next_line = xstrdup(""); } // In MODE_VREPLACE state, a NL replaces the rest of the line, and @@ -1008,9 +1059,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 = (char *)saved_line + curwin->w_cursor.col; + p = saved_line + curwin->w_cursor.col; while (*p != NUL) { - p += replace_push_mb((char_u *)p); + p += replace_push_mb(p); } saved_line[curwin->w_cursor.col] = NUL; } @@ -1018,10 +1069,10 @@ 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 = skipwhite((char *)p_extra); + p = skipwhite(p_extra); first_char = (unsigned char)(*p); } - extra_len = (int)STRLEN(p_extra); + extra_len = (int)strlen(p_extra); saved_char = *p_extra; *p_extra = NUL; } @@ -1058,7 +1109,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) char *ptr; old_cursor = curwin->w_cursor; - ptr = (char *)saved_line; + ptr = saved_line; if (flags & OPENLINE_DO_COM) { lead_len = get_leader_len(ptr, NULL, false, true); } else { @@ -1068,7 +1119,7 @@ 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 = (char *)ml_get(--curwin->w_cursor.lnum); + ptr = ml_get(--curwin->w_cursor.lnum); } newindent = get_indent(); } @@ -1104,7 +1155,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } } else { // Not a comment line // Find last non-blank in line - p = ptr + STRLEN(ptr) - 1; + p = ptr + strlen(ptr) - 1; while (p > ptr && ascii_iswhite(*p)) { p--; } @@ -1130,7 +1181,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 = (char *)get_cursor_line_ptr(); + ptr = get_cursor_line_ptr(); } } // If last character is '{' do indent, without @@ -1142,7 +1193,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((char_u *)ptr)) { + && cin_is_cinword(ptr)) { did_si = true; } } @@ -1154,12 +1205,12 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) while ((ptr[0] == '#' || was_backslashed) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') { + if (*ptr && ptr[strlen(ptr) - 1] == '\\') { was_backslashed = true; } else { was_backslashed = false; } - ptr = (char *)ml_get(++curwin->w_cursor.lnum); + ptr = ml_get(++curwin->w_cursor.lnum); } if (was_backslashed) { newindent = 0; // Got to end of file @@ -1192,13 +1243,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, &lead_flags, dir == BACKWARD, true); + lead_len = get_leader_len(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, &lead_flags, false, true); + lead_len = get_leader_len(saved_line + comment_start, &lead_flags, false, true); if (lead_len != 0) { lead_len += comment_start; if (did_do_comment != NULL) { @@ -1213,13 +1264,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) if (lead_len > 0) { 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 lead_middle[COM_MAX_LEN]; // middle-comment string + char lead_end[COM_MAX_LEN]; // end-comment string + char *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 - char_u *p2; + char *p2; // If the comment leader has the start, middle or end flag, it may not // be used or may be replaced with the middle leader. @@ -1261,15 +1312,15 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) 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]; + end_comment_pending = (unsigned char)lead_end[n - 1]; } // If the end of the comment is in the same line, don't use // the comment leader. if (dir == FORWARD) { - for (p = (char *)saved_line + lead_len; *p; p++) { + for (p = saved_line + lead_len; *p; p++) { if (STRNCMP(p, lead_end, n) == 0) { - comment_end = (char_u *)p; + comment_end = p; lead_len = 0; break; } @@ -1280,7 +1331,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) if (lead_len > 0) { if (current_flag == COM_START) { lead_repl = (char *)lead_middle; - lead_repl_len = (int)STRLEN(lead_middle); + lead_repl_len = (int)strlen(lead_middle); } // If we have hit RETURN immediately after the start @@ -1302,17 +1353,17 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // Remember where the end is, might want to use it to find the // start (for C-comments). if (dir == FORWARD) { - comment_end = (char_u *)skipwhite((char *)saved_line); + comment_end = skipwhite(saved_line); lead_len = 0; break; } // Doing "O" on the end of a comment inserts the middle leader. // Find the string for the middle leader, searching backwards. - while (p > (char *)curbuf->b_p_com && *p != ',') { + while (p > curbuf->b_p_com && *p != ',') { p--; } - for (lead_repl = p; lead_repl > (char *)curbuf->b_p_com + for (lead_repl = p; lead_repl > curbuf->b_p_com && lead_repl[-1] != ':'; lead_repl--) {} lead_repl_len = (int)(p - lead_repl); @@ -1321,7 +1372,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 = (char_u *)p; *p2 && *p2 != ':'; p2++) { + for (p2 = p; *p2 && *p2 != ':'; p2++) { if (*p2 == COM_AUTO_END) { end_comment_pending = -1; // means we want to set it } @@ -1331,7 +1382,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) while (*p2 && *p2 != ',') { p2++; } - end_comment_pending = p2[-1]; + end_comment_pending = (unsigned char)p2[-1]; } break; } @@ -1357,7 +1408,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 = (char_u *)leader; // remember to free it later + allocated = leader; // remember to free it later STRLCPY(leader, saved_line, lead_len + 1); @@ -1391,7 +1442,7 @@ 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((char_u *)lead_repl, lead_repl_len); + int repl_size = vim_strnsize(lead_repl, lead_repl_len); int old_size = 0; char *endp = p; int l; @@ -1414,7 +1465,7 @@ 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((char_u *)leader, (char_u *)p); + int l = utf_head_off(leader, p); if (l > 1) { p -= l; @@ -1436,13 +1487,13 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // screen characters, not bytes. Move the part that is // not to be overwritten. { - int repl_size = vim_strnsize((char_u *)lead_repl, lead_repl_len); + int repl_size = vim_strnsize(lead_repl, lead_repl_len); int i; int l; for (i = 0; i < lead_len && p[i] != NUL; i += l) { l = utfc_ptr2len(p + i); - if (vim_strnsize((char_u *)p, i + l) > repl_size) { + if (vim_strnsize(p, i + l) > repl_size) { break; } } @@ -1485,7 +1536,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((char_u *)leader, + newindent = get_indent_str_vtab(leader, curbuf->b_p_ts, curbuf->b_p_vts_array, false); } @@ -1568,7 +1619,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) { while ((*p_extra == ' ' || *p_extra == '\t') - && !utf_iscomposing(utf_ptr2char((char *)p_extra + 1))) { + && !utf_iscomposing(utf_ptr2char(p_extra + 1))) { if (REPLACE_NORMAL(State)) { replace_push(*p_extra); } @@ -1582,7 +1633,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } if (p_extra == NULL) { - p_extra = (char_u *)""; // append empty line + p_extra = ""; // append empty line } // concatenate leader and p_extra, if there is a leader @@ -1590,7 +1641,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) if (flags & OPENLINE_COM_LIST && second_line_indent > 0) { int i; int padding = second_line_indent - - (newindent + (int)STRLEN(leader)); + - (newindent + (int)strlen(leader)); // Here whitespace is inserted after the comment char. // Below, set_indent(newindent, SIN_INSERT) will insert the @@ -1602,7 +1653,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } } STRCAT(leader, p_extra); - p_extra = (char_u *)leader; + p_extra = leader; did_ai = true; // So truncating blanks works with comments less_cols -= lead_len; } else { @@ -1615,7 +1666,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) curwin->w_cursor.lnum--; } if ((State & VREPLACE_FLAG) == 0 || old_cursor.lnum >= orig_line_count) { - if (ml_append(curwin->w_cursor.lnum, (char *)p_extra, (colnr_T)0, false) == FAIL) { + if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, false) == FAIL) { goto theend; } // Postpone calling changed_lines(), because it would mess up folding @@ -1637,7 +1688,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) (void)u_save_cursor(); // errors are ignored! vr_lines_changed++; } - ml_replace(curwin->w_cursor.lnum, (char *)p_extra, true); + ml_replace(curwin->w_cursor.lnum, p_extra, true); changed_bytes(curwin->w_cursor.lnum, 0); // TODO(vigoux): extmark_splice_cols here?? curwin->w_cursor.lnum--; @@ -1702,9 +1753,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) { truncate_spaces(saved_line); } - ml_replace(curwin->w_cursor.lnum, (char *)saved_line, false); + ml_replace(curwin->w_cursor.lnum, saved_line, false); - int new_len = (int)STRLEN(saved_line); + int new_len = (int)strlen(saved_line); // TODO(vigoux): maybe there is issues there with expandtabs ? int cols_spliced = 0; @@ -1744,7 +1795,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) if (did_append) { changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true); // bail out and just get the final length of the line we just manipulated - bcount_t extra = (bcount_t)STRLEN(ml_get(curwin->w_cursor.lnum)); + bcount_t extra = (bcount_t)strlen(ml_get(curwin->w_cursor.lnum)); extmark_splice(curbuf, (int)curwin->w_cursor.lnum - 1, 0, 0, 0, 0, 1, 0, 1 + extra, kExtmarkUndo); } @@ -1787,10 +1838,10 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // stuff onto the replace stack (via ins_char()). if (State & VREPLACE_FLAG) { // Put new line in p_extra - p_extra = vim_strsave(get_cursor_line_ptr()); + p_extra = xstrdup(get_cursor_line_ptr()); // Put back original line - ml_replace(curwin->w_cursor.lnum, (char *)next_line, false); + ml_replace(curwin->w_cursor.lnum, next_line, false); // Insert new stuff into line again curwin->w_cursor.col = 0; @@ -1814,16 +1865,16 @@ theend: /// If "fixpos" is true fix the cursor position when done. void truncate_line(int fixpos) { - char_u *newp; + char *newp; linenr_T lnum = curwin->w_cursor.lnum; colnr_T col = curwin->w_cursor.col; if (col == 0) { - newp = vim_strsave((char_u *)""); + newp = xstrdup(""); } else { - newp = vim_strnsave(ml_get(lnum), (size_t)col); + newp = xstrnsave(ml_get(lnum), (size_t)col); } - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); // mark the buffer as changed and prepare for displaying changed_bytes(lnum, curwin->w_cursor.col); @@ -1900,7 +1951,7 @@ int get_leader_len(char *line, char **flags, bool backward, bool include_space) while (line[i] != NUL) { // scan through the 'comments' option for a match int found_one = false; - for (list = (char *)curbuf->b_p_com; *list;) { + for (list = curbuf->b_p_com; *list;) { // Get one option part into part_buf[]. Advance "list" to next // one. Put "string" at start of string. if (!got_com && flags != NULL) { @@ -2033,11 +2084,11 @@ int get_last_leader_offset(char *line, char **flags) char part_buf[COM_MAX_LEN]; // buffer for one option part // Repeat to match several nested comment strings. - int i = (int)STRLEN(line); + int i = (int)strlen(line); while (--i >= lower_check_bound) { // scan through the 'comments' option for a match int found_one = false; - for (list = (char *)curbuf->b_p_com; *list;) { + for (list = curbuf->b_p_com; *list;) { char *flags_save = list; // Get one option part into part_buf[]. Advance list to next one. @@ -2120,9 +2171,9 @@ int get_last_leader_offset(char *line, char **flags) while (ascii_iswhite(*com_leader)) { com_leader++; } - len1 = (int)STRLEN(com_leader); + len1 = (int)strlen(com_leader); - for (list = (char *)curbuf->b_p_com; *list;) { + for (list = curbuf->b_p_com; *list;) { char *flags_save = list; (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ","); @@ -2134,7 +2185,7 @@ int get_last_leader_offset(char *line, char **flags) while (ascii_iswhite(*string)) { string++; } - len2 = (int)STRLEN(string); + len2 = (int)strlen(string); if (len2 == 0) { continue; } diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 5910053025..7c5bc1c410 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -14,7 +14,7 @@ #include "nvim/msgpack_rpc/server.h" #include "nvim/os/fs.h" #include "nvim/os/shell.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/os_win_console.h" # include "nvim/os/pty_conpty_win.h" #endif @@ -492,7 +492,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err int stdin_dup_fd = STDIN_FILENO; int stdout_dup_fd = STDOUT_FILENO; -#ifdef WIN32 +#ifdef MSWIN // Strangely, ConPTY doesn't work if stdin and stdout are pipes. So replace // stdin and stdout with CONIN$ and CONOUT$, respectively. if (embedded_mode && os_has_conpty_working()) { diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 6238d85b3a..f5db03b0b4 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -140,16 +140,16 @@ int buf_init_chartab(buf_T *buf, int global) const char_u *p; if (i == 0) { // first round: 'isident' - p = p_isi; + p = (char_u *)p_isi; } else if (i == 1) { // second round: 'isprint' - p = p_isp; + p = (char_u *)p_isp; } else if (i == 2) { // third round: 'isfname' - p = p_isf; + p = (char_u *)p_isf; } else { // i == 3 // fourth round: 'iskeyword' - p = buf->b_p_isk; + p = (char_u *)buf->b_p_isk; } while (*p) { @@ -246,7 +246,7 @@ int buf_init_chartab(buf_T *buf, int global) } c = *p; - p = skip_to_option_part(p); + p = (char_u *)skip_to_option_part((char *)p); if ((c == ',') && (*p == NUL)) { // Trailing comma is not allowed. @@ -268,7 +268,7 @@ int buf_init_chartab(buf_T *buf, int global) void trans_characters(char *buf, int bufsize) { char_u *trs; // translated character - int len = (int)STRLEN(buf); // length of string needing translation + int len = (int)strlen(buf); // length of string needing translation int room = bufsize - len; // room in buffer after string while (*buf != 0) { @@ -313,7 +313,7 @@ size_t transstr_len(const char *const s, bool untab) const size_t l = (size_t)utfc_ptr2len(p); if (l > 1) { int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]); + pcc[0] = utfc_ptr2char(p, &pcc[1]); if (vim_isprintc(pcc[0])) { len += l; @@ -359,7 +359,7 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len, bool break; // Exceeded `buf` size. } int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char((const char_u *)p, &pcc[1]); + pcc[0] = utfc_ptr2char(p, &pcc[1]); if (vim_isprintc(pcc[0])) { memmove(buf_p, p, l); @@ -650,7 +650,7 @@ static inline unsigned nr2hex(unsigned n) /// /// @param b /// -/// @reeturn Number of display cells. +/// @return Number of display cells. int byte2cells(int b) FUNC_ATTR_PURE { @@ -709,7 +709,7 @@ int ptr2cells(const char *p_in) /// @return number of character cells. int vim_strsize(char *s) { - return vim_strnsize((char_u *)s, MAXCOL); + return vim_strnsize(s, MAXCOL); } /// Return the number of character cells string "s[len]" will take on the @@ -721,13 +721,13 @@ int vim_strsize(char *s) /// @param len /// /// @return Number of character cells. -int vim_strnsize(char_u *s, int len) +int vim_strnsize(char *s, int len) { assert(s != NULL); int size = 0; while (*s != NUL && --len >= 0) { - int l = utfc_ptr2len((char *)s); - size += ptr2cells((char *)s); + int l = utfc_ptr2len(s); + size += ptr2cells(s); s += l; len -= l - 1; } @@ -789,7 +789,7 @@ bool vim_iswordc_buf(const int c, buf_T *const buf) bool vim_iswordp(const char_u *const p) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - return vim_iswordp_buf(p, curbuf); + return vim_iswordp_buf((char *)p, curbuf); } /// Just like vim_iswordc_buf() but uses a pointer to the (multi-byte) @@ -799,13 +799,13 @@ bool vim_iswordp(const char_u *const p) /// @param buf buffer whose keywords to use /// /// @return true if "p" points to a keyword character. -bool vim_iswordp_buf(const char_u *const p, buf_T *const buf) +bool vim_iswordp_buf(const char *const p, buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - int c = *p; + int c = (uint8_t)(*p); if (MB_BYTE2LEN(c) > 1) { - c = utf_ptr2char((char *)p); + c = utf_ptr2char(p); } return vim_iswordc_buf(c, buf); } @@ -829,8 +829,8 @@ bool vim_isfilec(int c) bool vim_isfilec_or_wc(int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - char_u buf[2]; - buf[0] = (char_u)c; + char buf[2]; + buf[0] = (char)c; buf[1] = NUL; return vim_isfilec(c) || c == ']' || path_has_wildcard(buf); } @@ -905,15 +905,15 @@ bool in_win_border(win_T *wp, colnr_T vcol) /// @param end void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) { - char_u *ptr; // points to current char - char_u *posptr; // points to char at pos->col + char *ptr; // points to current char + char *posptr; // points to char at pos->col int incr; int head; long *vts = wp->w_buffer->b_p_vts_array; int ts = (int)wp->w_buffer->b_p_ts; colnr_T vcol = 0; - char_u *line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); // start of the line + char *line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); // start of the line if (pos->col == MAXCOL) { // continue until the NUL @@ -930,17 +930,21 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en posptr -= utf_head_off(line, posptr); } + chartabsize_T cts; + init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); + // This function is used very often, do some speed optimizations. // When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set - // use a simple loop. + // and there are no virtual text use a simple loop. // Also use this when 'list' is set but tabs take their normal size. if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL)) && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL - && !wp->w_p_bri) { + && !wp->w_p_bri + && !cts.cts_has_virt_text) { for (;;) { head = 0; - int c = *ptr; + int c = (uint8_t)(*ptr); // make sure we don't go past the end of the line if (c == NUL) { @@ -956,7 +960,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en // For utf-8, if the byte is >= 0x80, need to look at // further bytes to find the cell width. if (c >= 0x80) { - incr = utf_ptr2cells((char *)ptr); + incr = utf_ptr2cells(ptr); } else { incr = g_chartab[c] & CT_CELL_MASK; } @@ -966,7 +970,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en // cells wide. if ((incr == 2) && wp->w_p_wrap - && (MB_BYTE2LEN(*ptr) > 1) + && (MB_BYTE2LEN((uint8_t)(*ptr)) > 1) && in_win_border(wp, vcol)) { incr++; head = 1; @@ -984,25 +988,29 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } else { for (;;) { // A tab gets expanded, depending on the current column + // Other things also take up space. head = 0; - incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head); + incr = win_lbr_chartabsize(&cts, &head); // make sure we don't go past the end of the line - if (*ptr == NUL) { + if (*cts.cts_ptr == NUL) { // NUL at end of line only takes one column incr = 1; break; } - if ((posptr != NULL) && (ptr >= posptr)) { + if ((posptr != NULL) && (cts.cts_ptr >= posptr)) { // character at pos->col break; } - vcol += incr; - MB_PTR_ADV(ptr); + cts.cts_vcol += incr; + MB_PTR_ADV(cts.cts_ptr); } + vcol = cts.cts_vcol; + ptr = cts.cts_ptr; } + clear_chartabsize_arg(&cts); if (start != NULL) { *start = vcol + head; @@ -1013,6 +1021,8 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } if (cursor != NULL) { + // cursor is after inserted text + vcol += cts.cts_cur_text_width; if ((*ptr == TAB) && (State & MODE_NORMAL) && !wp->w_p_list @@ -1066,10 +1076,10 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e colnr_T endadd = 0; // Cannot put the cursor on part of a wide character. - char_u *ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); + char *ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); - if (pos->col < (colnr_T)STRLEN(ptr)) { - int c = utf_ptr2char((char *)ptr + pos->col); + if (pos->col < (colnr_T)strlen(ptr)) { + int c = utf_ptr2char(ptr + pos->col); if ((c != TAB) && vim_isprintc(c)) { endadd = (colnr_T)(char2cells(c) - 1); if (coladd > endadd) { @@ -1147,7 +1157,7 @@ char *skipwhite(const char *const p) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - return (char *)skipwhite_len((char_u *)p, STRLEN(p)); + return skipwhite_len(p, strlen(p)); } /// Like `skipwhite`, but skip up to `len` characters. @@ -1158,14 +1168,14 @@ char *skipwhite(const char *const p) /// /// @return Pointer to character after the skipped whitespace, or the `len`-th /// character in the string. -char_u *skipwhite_len(const char_u *p, size_t len) +char *skipwhite_len(const char *p, size_t len) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { for (; len > 0 && ascii_iswhite(*p); len--) { p++; } - return (char_u *)p; + return (char *)p; } // getwhitecols: return the number of whitespace @@ -1175,10 +1185,10 @@ intptr_t getwhitecols_curline(void) return getwhitecols(get_cursor_line_ptr()); } -intptr_t getwhitecols(const char_u *p) +intptr_t getwhitecols(const char *p) FUNC_ATTR_PURE { - return (char_u *)skipwhite((char *)p) - p; + return skipwhite(p) - p; } /// Skip over digits @@ -1222,10 +1232,10 @@ const char *skipbin(const char *q) /// /// @return Pointer to the character after the skipped digits and hex /// characters. -char_u *skiphex(char_u *q) +char *skiphex(char *q) FUNC_ATTR_PURE { - char_u *p = q; + char *p = q; while (ascii_isxdigit(*p)) { // skip to next non-digit p++; @@ -1238,10 +1248,10 @@ char_u *skiphex(char_u *q) /// @param q /// /// @return Pointer to the digit or (NUL after the string). -char_u *skiptodigit(char_u *q) +char *skiptodigit(char *q) FUNC_ATTR_PURE { - char_u *p = q; + char *p = q; while (*p != NUL && !ascii_isdigit(*p)) { // skip to next digit p++; @@ -1272,10 +1282,10 @@ const char *skiptobin(const char *q) /// @param q /// /// @return Pointer to the hex character or (NUL after the string). -char_u *skiptohex(char_u *q) +char *skiptohex(char *q) FUNC_ATTR_PURE { - char_u *p = q; + char *p = q; while (*p != NUL && !ascii_isxdigit(*p)) { // skip to next digit p++; @@ -1288,13 +1298,13 @@ char_u *skiptohex(char_u *q) /// @param[in] p Text to skip over. /// /// @return Pointer to the next whitespace or NUL character. -char_u *skiptowhite(const char_u *p) +char *skiptowhite(const char *p) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { while (*p != ' ' && *p != '\t' && *p != NUL) { p++; } - return (char_u *)p; + return (char *)p; } /// skiptowhite_esc: Like skiptowhite(), but also skip escaped chars @@ -1319,16 +1329,16 @@ char *skiptowhite_esc(char *p) /// @param[in] p Text to skip over. /// /// @return Pointer to the next '\n' or NUL character. -char_u *skip_to_newline(const char_u *const p) +char *skip_to_newline(const char *const p) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - return (char_u *)xstrchrnul((const char *)p, NL); + return xstrchrnul(p, NL); } /// Gets a number from a string and skips over it, signalling overflow. /// -/// @param[out] pp A pointer to a pointer to char_u. +/// @param[out] pp A pointer to a pointer to char. /// It will be advanced past the read number. /// @param[out] nr Number read from the string. /// @@ -1345,7 +1355,7 @@ bool try_getdigits(char **pp, intmax_t *nr) /// Gets a number from a string and skips over it. /// -/// @param[out] pp Pointer to a pointer to char_u. +/// @param[out] pp Pointer to a pointer to char. /// It will be advanced past the read number. /// @param strict Abort on overflow. /// @param def Default value, if parsing fails or overflow occurs. @@ -1412,10 +1422,10 @@ int32_t getdigits_int32(char **pp, bool strict, long def) /// Check that "lbuf" is empty or only contains blanks. /// /// @param lbuf line buffer to check -bool vim_isblankline(char_u *lbuf) +bool vim_isblankline(char *lbuf) FUNC_ATTR_PURE { - char_u *p = (char_u *)skipwhite((char *)lbuf); + char *p = skipwhite(lbuf); return *p == NUL || *p == '\r' || *p == '\n'; } @@ -1453,14 +1463,14 @@ bool vim_isblankline(char_u *lbuf) /// @param strict If true, fail if the number has unexpected trailing /// alphanumeric chars: *len is set to 0 and nothing else is /// returned. -void vim_str2nr(const char_u *const start, int *const prep, int *const len, const int what, +void vim_str2nr(const char *const start, int *const prep, int *const len, const int what, varnumber_T *const nptr, uvarnumber_T *const unptr, const int maxlen, const bool strict) FUNC_ATTR_NONNULL_ARG(1) { - const char *ptr = (const char *)start; + const char *ptr = start; #define STRING_ENDED(ptr) \ - (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen)) + (!(maxlen == 0 || (int)((ptr) - start) < maxlen)) int pre = 0; // default is decimal const bool negative = (ptr[0] == '-'); uvarnumber_T un = 0; @@ -1512,7 +1522,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, cons } else if ((what & (STR2NR_HEX | STR2NR_OCT | STR2NR_OOCT | STR2NR_BIN)) && !STRING_ENDED(ptr + 1) && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { - pre = (char_u)ptr[1]; + pre = (uint8_t)ptr[1]; // Detect hexadecimal: 0x or 0X followed by hex digit. if ((what & STR2NR_HEX) && !STRING_ENDED(ptr + 2) @@ -1600,7 +1610,7 @@ vim_str2nr_hex: vim_str2nr_proceed: // Check for an alphanumeric character immediately following, that is // most likely a typo. - if (strict && ptr - (const char *)start != maxlen && ASCII_ISALNUM(*ptr)) { + if (strict && ptr - start != maxlen && ASCII_ISALNUM(*ptr)) { return; } @@ -1609,7 +1619,7 @@ vim_str2nr_proceed: } if (len != NULL) { - *len = (int)(ptr - (const char *)start); + *len = (int)(ptr - start); } if (nptr != NULL) { @@ -1654,8 +1664,9 @@ int hex2nr(int c) } /// Convert two hex characters to a byte. -/// Return -1 if one of the characters is not hex. -int hexhex2nr(char_u *p) +/// +/// @return -1 if one of the characters is not hex. +int hexhex2nr(const char *p) FUNC_ATTR_PURE { if (!ascii_isxdigit(p[0]) || !ascii_isxdigit(p[1])) { @@ -1677,12 +1688,12 @@ int hexhex2nr(char_u *p) /// characters. /// /// @param str file path string to check -bool rem_backslash(const char_u *str) +bool rem_backslash(const char *str) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { #ifdef BACKSLASH_IN_FILENAME return str[0] == '\\' - && str[1] < 0x80 + && (uint8_t)str[1] < 0x80 && (str[1] == ' ' || (str[1] != NUL && str[1] != '*' @@ -1697,7 +1708,7 @@ bool rem_backslash(const char_u *str) /// Halve the number of backslashes in a file name argument. /// /// @param p -void backslash_halve(char_u *p) +void backslash_halve(char *p) { for (; *p; p++) { if (rem_backslash(p)) { @@ -1711,11 +1722,11 @@ void backslash_halve(char_u *p) /// @param p /// /// @return String with the number of backslashes halved. -char_u *backslash_halve_save(const char_u *p) +char *backslash_halve_save(const char *p) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { // TODO(philix): simplify and improve backslash_halve_save algorithm - char_u *res = vim_strsave(p); + char *res = xstrdup(p); backslash_halve(res); return res; } diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index e82e98ba4e..a29d022606 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -23,6 +23,7 @@ #include "nvim/help.h" #include "nvim/highlight_group.h" #include "nvim/if_cscope.h" +#include "nvim/locale.h" #include "nvim/lua/executor.h" #include "nvim/mapping.h" #include "nvim/menu.h" @@ -65,8 +66,8 @@ static int compl_selected; static int sort_func_compare(const void *s1, const void *s2) { - char_u *p1 = *(char_u **)s1; - char_u *p2 = *(char_u **)s2; + char *p1 = *(char **)s1; + char *p2 = *(char **)s2; if (*p1 != '<' && *p2 == '<') { return -1; @@ -74,7 +75,7 @@ static int sort_func_compare(const void *s1, const void *s2) if (*p1 == '<' && *p2 != '<') { return 1; } - return STRCMP(p1, p2); + return strcmp(p1, p2); } static void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char **files, int options) @@ -176,29 +177,29 @@ int nextwild(expand_T *xp, int type, int options, bool escape) ui_flush(); } - i = (int)((char_u *)xp->xp_pattern - ccline->cmdbuff); + i = (int)(xp->xp_pattern - ccline->cmdbuff); assert(ccline->cmdpos >= i); xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i; if (type == WILD_NEXT || type == WILD_PREV) { // Get next/previous match for a previous expanded pattern. - p2 = ExpandOne(xp, NULL, NULL, 0, type); + p2 = (char_u *)ExpandOne(xp, NULL, NULL, 0, type); } else { // Translate string into pattern and expand it. - p1 = addstar((char_u *)xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + p1 = (char_u *)addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); const int use_options = (options | WILD_HOME_REPLACE | WILD_ADD_SLASH | WILD_SILENT | (escape ? WILD_ESCAPE : 0) | (p_wic ? WILD_ICASE : 0)); - p2 = ExpandOne(xp, p1, vim_strnsave(&ccline->cmdbuff[i], xp->xp_pattern_len), - use_options, type); + p2 = (char_u *)ExpandOne(xp, (char *)p1, xstrnsave(&ccline->cmdbuff[i], xp->xp_pattern_len), + use_options, type); xfree(p1); // xp->xp_pattern might have been modified by ExpandOne (for example, // in lua completion), so recompute the pattern index and length - i = (int)((char_u *)xp->xp_pattern - ccline->cmdbuff); + i = (int)(xp->xp_pattern - ccline->cmdbuff); xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i; // Longest match: make sure it is not shorter, happens with :help. @@ -219,7 +220,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape) difflen = (int)STRLEN(p2) - (int)(xp->xp_pattern_len); if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen) { realloc_cmdbuff(ccline->cmdlen + difflen + 4); - xp->xp_pattern = (char *)ccline->cmdbuff + i; + xp->xp_pattern = ccline->cmdbuff + i; } assert(ccline->cmdpos <= ccline->cmdlen); memmove(&ccline->cmdbuff[ccline->cmdpos + difflen], @@ -275,6 +276,150 @@ void cmdline_pum_cleanup(CmdlineInfo *cclp) wildmenu_cleanup(cclp); } +/// Get the next or prev cmdline completion match. The index of the match is set +/// in "p_findex" +static char *get_next_or_prev_match(int mode, expand_T *xp, int *p_findex, char *orig_save) +{ + if (xp->xp_numfiles <= 0) { + return NULL; + } + + int findex = *p_findex; + + if (mode == WILD_PREV) { + if (findex == -1) { + findex = xp->xp_numfiles; + } + findex--; + } else { // mode == WILD_NEXT + findex++; + } + + // When wrapping around, return the original string, set findex to -1. + if (findex < 0) { + if (orig_save == NULL) { + findex = xp->xp_numfiles - 1; + } else { + findex = -1; + } + } + if (findex >= xp->xp_numfiles) { + if (orig_save == NULL) { + findex = 0; + } else { + findex = -1; + } + } + if (compl_match_array) { + compl_selected = findex; + cmdline_pum_display(false); + } else if (p_wmnu) { + redraw_wildmenu(xp, xp->xp_numfiles, xp->xp_files, findex, cmd_showtail); + } + *p_findex = findex; + + return xstrdup(findex == -1 ? orig_save : xp->xp_files[findex]); +} + +/// Start the command-line expansion and get the matches. +static char *ExpandOne_start(int mode, expand_T *xp, char *str, int options) +{ + int non_suf_match; // number without matching suffix + char *ss = NULL; + + // Do the expansion. + if (ExpandFromContext(xp, (char_u *)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, + // causing the pattern to be added, which has illegal characters. + if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) { + semsg(_(e_nomatch2), str); + } +#endif + } else if (xp->xp_numfiles == 0) { + if (!(options & WILD_SILENT)) { + semsg(_(e_nomatch2), str); + } + } else { + // Escape the matches for use on the command line. + ExpandEscape(xp, (char_u *)str, xp->xp_numfiles, xp->xp_files, options); + + // Check for matching suffixes in file names. + if (mode != WILD_ALL && mode != WILD_ALL_KEEP + && mode != WILD_LONGEST) { + if (xp->xp_numfiles) { + non_suf_match = xp->xp_numfiles; + } else { + non_suf_match = 1; + } + if ((xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_DIRECTORIES) + && xp->xp_numfiles > 1) { + // More than one match; check suffix. + // The files will have been sorted on matching suffix in + // expand_wildcards, only need to check the first two. + non_suf_match = 0; + for (int i = 0; i < 2; i++) { + if (match_suffix(xp->xp_files[i])) { + non_suf_match++; + } + } + } + if (non_suf_match != 1) { + // Can we ever get here unless it's while expanding + // interactively? If not, we can get rid of this all + // together. Don't really want to wait for this message + // (and possibly have to hit return to continue!). + if (!(options & WILD_SILENT)) { + emsg(_(e_toomany)); + } else if (!(options & WILD_NO_BEEP)) { + beep_flush(); + } + } + if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) { + ss = xstrdup(xp->xp_files[0]); + } + } + } + + return ss; +} + +/// Return the longest common part in the list of cmdline completion matches. +static char *find_longest_match(expand_T *xp, int options) +{ + size_t len = 0; + + for (size_t mb_len; xp->xp_files[0][len]; len += mb_len) { + mb_len = (size_t)utfc_ptr2len(&xp->xp_files[0][len]); + int c0 = utf_ptr2char(&xp->xp_files[0][len]); + int i; + for (i = 1; i < xp->xp_numfiles; i++) { + int ci = utf_ptr2char(&xp->xp_files[i][len]); + + if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS)) { + if (mb_tolower(c0) != mb_tolower(ci)) { + break; + } + } else if (c0 != ci) { + break; + } + } + if (i < xp->xp_numfiles) { + if (!(options & WILD_NO_BEEP)) { + vim_beep(BO_WILD); + } + break; + } + } + + return xstrndup(xp->xp_files[0], len); +} + /// Do wildcard expansion on the string 'str'. /// Chars that should not be expanded must be preceded with a backslash. /// Return a pointer to allocated memory containing the new string. @@ -295,6 +440,10 @@ void cmdline_pum_cleanup(CmdlineInfo *cclp) /// mode = WILD_ALL: return all matches concatenated /// mode = WILD_LONGEST: return longest matched part /// mode = WILD_ALL_KEEP: get all matches, keep matches +/// mode = WILD_APPLY: apply the item selected in the cmdline completion +/// popup menu and close the menu. +/// mode = WILD_CANCEL: cancel and close the cmdline completion popup and +/// use the original text. /// /// options = WILD_LIST_NOTFOUND: list entries without a match /// options = WILD_HOME_REPLACE: do home_replace() for buffer names @@ -309,63 +458,25 @@ void cmdline_pum_cleanup(CmdlineInfo *cclp) /// The variables xp->xp_context and xp->xp_backslash must have been set! /// /// @param orig allocated copy of original of expanded string -char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode) +char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode) { - char_u *ss = NULL; + char *ss = NULL; static int findex; - static char_u *orig_save = NULL; // kept value of orig + static char *orig_save = NULL; // kept value of orig int orig_saved = false; int i; - int non_suf_match; // number without matching suffix // first handle the case of using an old match if (mode == WILD_NEXT || mode == WILD_PREV) { - if (xp->xp_numfiles > 0) { - if (mode == WILD_PREV) { - if (findex == -1) { - findex = xp->xp_numfiles; - } - findex--; - } else { // mode == WILD_NEXT - findex++; - } - - // When wrapping around, return the original string, set findex to - // -1. - if (findex < 0) { - if (orig_save == NULL) { - findex = xp->xp_numfiles - 1; - } else { - findex = -1; - } - } - if (findex >= xp->xp_numfiles) { - if (orig_save == NULL) { - findex = 0; - } else { - findex = -1; - } - } - if (compl_match_array) { - compl_selected = findex; - cmdline_pum_display(false); - } else if (p_wmnu) { - redraw_wildmenu(xp, xp->xp_numfiles, xp->xp_files, findex, cmd_showtail); - } - if (findex == -1) { - return vim_strsave(orig_save); - } - return vim_strsave((char_u *)xp->xp_files[findex]); - } else { - return NULL; - } + return get_next_or_prev_match(mode, xp, &findex, orig_save); } if (mode == WILD_CANCEL) { - ss = vim_strsave(orig_save ? orig_save : (char_u *)""); + ss = xstrdup(orig_save ? orig_save : ""); } else if (mode == WILD_APPLY) { - ss = vim_strsave(findex == -1 ? (orig_save ? orig_save : (char_u *)"") : - (char_u *)xp->xp_files[findex]); + ss = xstrdup(findex == -1 + ? (orig_save ? orig_save : "") + : xp->xp_files[findex]); } // free old names @@ -385,93 +496,12 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode orig_save = orig; orig_saved = true; - // Do the expansion. - 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, - // causing the pattern to be added, which has illegal characters. - if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) { - semsg(_(e_nomatch2), str); - } -#endif - } else if (xp->xp_numfiles == 0) { - if (!(options & WILD_SILENT)) { - semsg(_(e_nomatch2), str); - } - } else { - // Escape the matches for use on the command line. - ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options); - - // Check for matching suffixes in file names. - if (mode != WILD_ALL && mode != WILD_ALL_KEEP - && mode != WILD_LONGEST) { - if (xp->xp_numfiles) { - non_suf_match = xp->xp_numfiles; - } else { - non_suf_match = 1; - } - if ((xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_DIRECTORIES) - && xp->xp_numfiles > 1) { - // More than one match; check suffix. - // The files will have been sorted on matching suffix in - // expand_wildcards, only need to check the first two. - non_suf_match = 0; - for (i = 0; i < 2; i++) { - if (match_suffix((char_u *)xp->xp_files[i])) { - non_suf_match++; - } - } - } - if (non_suf_match != 1) { - // Can we ever get here unless it's while expanding - // interactively? If not, we can get rid of this all - // together. Don't really want to wait for this message - // (and possibly have to hit return to continue!). - if (!(options & WILD_SILENT)) { - emsg(_(e_toomany)); - } else if (!(options & WILD_NO_BEEP)) { - beep_flush(); - } - } - if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) { - ss = vim_strsave((char_u *)xp->xp_files[0]); - } - } - } + ss = ExpandOne_start(mode, xp, str, options); } // Find longest common part if (mode == WILD_LONGEST && xp->xp_numfiles > 0) { - size_t len = 0; - - for (size_t mb_len; xp->xp_files[0][len]; len += mb_len) { - mb_len = (size_t)utfc_ptr2len(&xp->xp_files[0][len]); - int c0 = utf_ptr2char(&xp->xp_files[0][len]); - for (i = 1; i < xp->xp_numfiles; i++) { - int ci = utf_ptr2char(&xp->xp_files[i][len]); - - if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES - || xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS)) { - if (mb_tolower(c0) != mb_tolower(ci)) { - break; - } - } else if (c0 != ci) { - break; - } - } - if (i < xp->xp_numfiles) { - if (!(options & WILD_NO_BEEP)) { - vim_beep(BO_WILD); - } - break; - } - } - - ss = (char_u *)xstrndup(xp->xp_files[0], len); + ss = find_longest_match(xp, options); findex = -1; // next p_wc gets first one } @@ -481,7 +511,7 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode if (mode == WILD_ALL && xp->xp_numfiles > 0 && !got_int) { size_t len = 0; for (i = 0; i < xp->xp_numfiles; i++) { - len += STRLEN(xp->xp_files[i]) + 1; + len += strlen(xp->xp_files[i]) + 1; } ss = xmalloc(len); *ss = NUL; @@ -544,7 +574,7 @@ int showmatches(expand_T *xp, int wildmenu) if (xp->xp_numfiles == -1) { set_expand_context(xp); - i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos, + i = expand_cmdline(xp, (char_u *)ccline->cmdbuff, ccline->cmdpos, &num_files, &files_found); showtail = expand_showtail(xp); if (i != EXPAND_OK) { @@ -573,7 +603,7 @@ int showmatches(expand_T *xp, int wildmenu) .pum_kind = NULL, }; } - char_u *endpos = (char_u *)(showtail ? sm_gettail(xp->xp_pattern, true) : xp->xp_pattern); + char *endpos = (showtail ? sm_gettail(xp->xp_pattern, true) : xp->xp_pattern); if (ui_has(kUICmdline)) { compl_startcol = (int)(endpos - ccline->cmdbuff); } else { @@ -641,12 +671,12 @@ 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((char_u *)files_found[k], HL_ATTR(HLF_D)); - p = (char_u *)files_found[k] + STRLEN(files_found[k]) + 1; + msg_outtrans_attr(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); - msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D)); + msg_outtrans_long_attr((char *)p + 2, HL_ATTR(HLF_D)); break; } for (j = maxlen - lastlen; --j >= 0;) { @@ -662,33 +692,32 @@ int showmatches(expand_T *xp, int wildmenu) // $HOME has been replaced with ~/. 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); + char_u *halved_slash = (char_u *)backslash_halve_save((char *)path); + j = os_isdir((char *)halved_slash); xfree(exp_path); if (halved_slash != path) { xfree(halved_slash); } } else { // Expansion was done here, file names are literal. - j = os_isdir((char_u *)files_found[k]); + j = os_isdir(files_found[k]); } if (showtail) { p = (char_u *)L_SHOWFILE(k); } else { home_replace(NULL, files_found[k], (char *)NameBuff, MAXPATHL, true); - p = NameBuff; + p = (char_u *)NameBuff; } } else { j = false; p = (char_u *)L_SHOWFILE(k); } - lastlen = msg_outtrans_attr(p, j ? attr : 0); + lastlen = msg_outtrans_attr((char *)p, j ? attr : 0); } if (msg_col > 0) { // when not wrapped around msg_clr_eos(); msg_putchar('\n'); } - ui_flush(); // show one line at a time if (got_int) { got_int = false; break; @@ -758,7 +787,7 @@ static bool expand_showtail(expand_T *xp) for (s = (char_u *)xp->xp_pattern; s < end; s++) { // Skip escaped wildcards. Only when the backslash is not a path // separator, on DOS the '*' "path\*\file" must not be skipped. - if (rem_backslash(s)) { + if (rem_backslash((char *)s)) { s++; } else if (vim_strchr("*?[", *s) != NULL) { return false; @@ -775,13 +804,13 @@ static bool expand_showtail(expand_T *xp) /// the name into allocated memory and prepend "^". /// /// @param context EXPAND_FILES etc. -char_u *addstar(char_u *fname, size_t len, int context) +char *addstar(char *fname, size_t len, int context) FUNC_ATTR_NONNULL_RET { - char_u *retval; + char *retval; size_t i, j; size_t new_len; - char_u *tail; + char *tail; int ends_in_star; if (context != EXPAND_FILES @@ -803,7 +832,7 @@ char_u *addstar(char_u *fname, size_t len, int context) || context == EXPAND_PACKADD || ((context == EXPAND_TAGS_LISTFILES || context == EXPAND_TAGS) && fname[0] == '/')) { - retval = vim_strnsave(fname, len); + retval = xstrnsave(fname, len); } else { new_len = len + 2; // +2 for '^' at start, NUL at end for (i = 0; i < len; i++) { @@ -873,7 +902,7 @@ char_u *addstar(char_u *fname, size_t len, int context) // $ could be anywhere in the tail. // ` could be anywhere in the file name. // When the name ends in '$' don't add a star, remove the '$'. - tail = (char_u *)path_tail((char *)retval); + tail = path_tail(retval); ends_in_star = (len > 0 && retval[len - 1] == '*'); #ifndef BACKSLASH_IN_FILENAME for (ssize_t k = (ssize_t)len - 2; k >= 0; k--) { @@ -885,8 +914,8 @@ char_u *addstar(char_u *fname, size_t len, int context) #endif if ((*retval != '~' || tail != retval) && !ends_in_star - && vim_strchr((char *)tail, '$') == NULL - && vim_strchr((char *)retval, '`') == NULL) { + && vim_strchr(tail, '$') == NULL + && vim_strchr(retval, '`') == NULL) { retval[len++] = '*'; } else if (len > 0 && retval[len - 1] == '$') { len--; @@ -948,68 +977,26 @@ void set_expand_context(expand_T *xp) xp->xp_context = EXPAND_NOTHING; return; } - set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, true); + set_cmd_context(xp, (char_u *)ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, true); } -/// This is all pretty much copied from do_one_cmd(), with all the extra stuff -/// we don't need/want deleted. Maybe this could be done better if we didn't -/// repeat all this stuff. The only problem is that they may not stay -/// perfectly compatible with each other, but then the command line syntax -/// probably won't change that much -- webb. +/// Sets the index of a built-in or user defined command "cmd" in eap->cmdidx. +/// For user defined commands, the completion context is set in "xp" and the +/// completion flags in "complp". /// -/// @param buff buffer for command string -static const char *set_one_cmd_context(expand_T *xp, const char *buff) +/// @return a pointer to the text after the command or NULL for failure. +static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, int *complp) { + const char *p = NULL; size_t len = 0; - exarg_T ea; - int context = EXPAND_NOTHING; - bool forceit = false; - bool usefilter = false; // Filter instead of file name. - - ExpandInit(xp); - xp->xp_pattern = (char *)buff; - xp->xp_line = (char *)buff; - xp->xp_context = EXPAND_COMMANDS; // Default until we get past command - ea.argt = 0; - - // 2. skip comment lines and leading space, colons or bars - const char *cmd; - for (cmd = buff; vim_strchr(" \t:|", *cmd) != NULL; cmd++) {} - xp->xp_pattern = (char *)cmd; - - if (*cmd == NUL) { - return NULL; - } - if (*cmd == '"') { // ignore comment lines - xp->xp_context = EXPAND_NOTHING; - return NULL; - } - - // 3. parse a range specifier of the form: addr [,addr] [;addr] .. - cmd = (const char *)skip_range(cmd, &xp->xp_context); - - // 4. parse command - xp->xp_pattern = (char *)cmd; - if (*cmd == NUL) { - return NULL; - } - if (*cmd == '"') { - xp->xp_context = EXPAND_NOTHING; - return NULL; - } - - if (*cmd == '|' || *cmd == '\n') { - return cmd + 1; // There's another command - } // Isolate the command and search for it in the command table. // Exceptions: // - the 'k' command can directly be followed by any character, but // do accept "keepmarks", "keepalt" and "keepjumps". // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' - const char *p; if (*cmd == 'k' && cmd[1] != 'e') { - ea.cmdidx = CMD_k; + eap->cmdidx = CMD_k; p = cmd + 1; } else { p = cmd; @@ -1040,7 +1027,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) return NULL; } - ea.cmdidx = excmd_get_cmdidx(cmd, len); + eap->cmdidx = excmd_get_cmdidx(cmd, len); if (cmd[0] >= 'A' && cmd[0] <= 'Z') { while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card @@ -1055,227 +1042,131 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) return NULL; } - if (ea.cmdidx == CMD_SIZE) { + if (eap->cmdidx == CMD_SIZE) { if (*cmd == 's' && vim_strchr("cgriI", cmd[1]) != NULL) { - ea.cmdidx = CMD_substitute; + eap->cmdidx = CMD_substitute; p = cmd + 1; } else if (cmd[0] >= 'A' && cmd[0] <= 'Z') { - ea.cmd = (char *)cmd; - p = (const char *)find_ucmd(&ea, (char *)p, NULL, xp, &context); + eap->cmd = (char *)cmd; + p = (const char *)find_ucmd(eap, (char *)p, NULL, xp, complp); if (p == NULL) { - ea.cmdidx = CMD_SIZE; // Ambiguous user command. + eap->cmdidx = CMD_SIZE; // Ambiguous user command. } } } - if (ea.cmdidx == CMD_SIZE) { + if (eap->cmdidx == CMD_SIZE) { // Not still touching the command and it was an illegal one xp->xp_context = EXPAND_UNSUCCESSFUL; return NULL; } - xp->xp_context = EXPAND_NOTHING; // Default now that we're past command - - if (*p == '!') { // forced commands - forceit = true; - p++; - } - - // 5. parse arguments - if (!IS_USER_CMDIDX(ea.cmdidx)) { - ea.argt = excmd_get_argt(ea.cmdidx); - } - - const char *arg = (const char *)skipwhite(p); + return p; +} - // Skip over ++argopt argument - if ((ea.argt & EX_ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) { - p = arg; - while (*p && !ascii_isspace(*p)) { - MB_PTR_ADV(p); - } - arg = (const char *)skipwhite(p); - } +/// Set the completion context for a command argument with wild card characters. +static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool usefilter, + expand_T *xp, int *complp) +{ + bool in_quote = false; + const char *bow = NULL; // Beginning of word. + size_t len = 0; - if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { - if (*arg == '>') { // Append. - if (*++arg == '>') { - arg++; + // Allow spaces within back-quotes to count as part of the argument + // being expanded. + xp->xp_pattern = skipwhite(arg); + const char *p = (const char *)xp->xp_pattern; + while (*p != NUL) { + int c = utf_ptr2char(p); + if (c == '\\' && p[1] != NUL) { + p++; + } else if (c == '`') { + if (!in_quote) { + xp->xp_pattern = (char *)p; + bow = p + 1; } - arg = (const char *)skipwhite(arg); - } else if (*arg == '!' && ea.cmdidx == CMD_write) { // :w !filter - arg++; - usefilter = true; - } - } - - if (ea.cmdidx == CMD_read) { - usefilter = forceit; // :r! filter if forced - if (*arg == '!') { // :r !filter - arg++; - usefilter = true; - } - } - - if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { - while (*arg == *cmd) { // allow any number of '>' or '<' - arg++; - } - arg = (const char *)skipwhite(arg); - } - - // Does command allow "+command"? - if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') { - // Check if we're in the +command - p = arg + 1; - arg = (const char *)skip_cmd_arg((char *)arg, false); - - // Still touching the command after '+'? - if (*arg == NUL) { - return p; - } - - // Skip space(s) after +command to get to the real argument. - arg = (const char *)skipwhite(arg); - } - - // Check for '|' to separate commands and '"' to start comments. - // Don't do this for ":read !cmd" and ":write !cmd". - if ((ea.argt & EX_TRLBAR) && !usefilter) { - p = arg; - // ":redir @" is not the start of a comment - if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') { - p += 2; - } - while (*p) { - if (*p == Ctrl_V) { - if (p[1] != NUL) { - p++; - } - } else if ((*p == '"' && !(ea.argt & EX_NOTRLCOM)) - || *p == '|' - || *p == '\n') { - if (*(p - 1) != '\\') { - if (*p == '|' || *p == '\n') { - return p + 1; - } - return NULL; // It's a comment + in_quote = !in_quote; + // An argument can contain just about everything, except + // characters that end the command and white space. + } else if (c == '|' || c == '\n' || c == '"' || ascii_iswhite(c)) { + len = 0; // avoid getting stuck when space is in 'isfname' + while (*p != NUL) { + c = utf_ptr2char(p); + if (c == '`' || vim_isfilec_or_wc(c)) { + break; } + len = (size_t)utfc_ptr2len(p); + MB_PTR_ADV(p); } - MB_PTR_ADV(p); - } - } - - if (!(ea.argt & EX_EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) { - // no arguments allowed but there is something - return NULL; - } - - // Find start of last argument (argument just before cursor): - p = buff; - xp->xp_pattern = (char *)p; - len = strlen(buff); - while (*p && p < buff + len) { - if (*p == ' ' || *p == TAB) { - // Argument starts after a space. - xp->xp_pattern = (char *)++p; - } else { - if (*p == '\\' && *(p + 1) != NUL) { - p++; // skip over escaped character + if (in_quote) { + bow = p; + } else { + xp->xp_pattern = (char *)p; } - MB_PTR_ADV(p); + p -= len; } + MB_PTR_ADV(p); } - if (ea.argt & EX_XFILE) { - int in_quote = false; - const char *bow = NULL; // Beginning of word. - - // Allow spaces within back-quotes to count as part of the argument - // being expanded. - xp->xp_pattern = skipwhite(arg); - p = (const char *)xp->xp_pattern; - while (*p != NUL) { - int c = utf_ptr2char(p); - if (c == '\\' && p[1] != NUL) { - p++; - } else if (c == '`') { - if (!in_quote) { - xp->xp_pattern = (char *)p; - bow = p + 1; - } - in_quote = !in_quote; - // An argument can contain just about everything, except - // characters that end the command and white space. - } else if (c == '|' || c == '\n' || c == '"' || ascii_iswhite(c)) { - len = 0; // avoid getting stuck when space is in 'isfname' - while (*p != NUL) { - c = utf_ptr2char(p); - if (c == '`' || vim_isfilec_or_wc(c)) { - break; - } - len = (size_t)utfc_ptr2len(p); - MB_PTR_ADV(p); - } - if (in_quote) { - bow = p; - } else { - xp->xp_pattern = (char *)p; - } - p -= len; - } - MB_PTR_ADV(p); - } - - // If we are still inside the quotes, and we passed a space, just - // expand from there. - if (bow != NULL && in_quote) { - xp->xp_pattern = (char *)bow; - } - xp->xp_context = EXPAND_FILES; + // If we are still inside the quotes, and we passed a space, just + // expand from there. + if (bow != NULL && in_quote) { + xp->xp_pattern = (char *)bow; + } + xp->xp_context = EXPAND_FILES; - // For a shell command more chars need to be escaped. - if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal) { + // For a shell command more chars need to be escaped. + if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal) { #ifndef BACKSLASH_IN_FILENAME - xp->xp_shell = true; + xp->xp_shell = true; #endif - // When still after the command name expand executables. - if (xp->xp_pattern == skipwhite(arg)) { - xp->xp_context = EXPAND_SHELLCMD; - } + // When still after the command name expand executables. + if (xp->xp_pattern == skipwhite(arg)) { + xp->xp_context = EXPAND_SHELLCMD; } + } - // Check for environment variable. - if (*xp->xp_pattern == '$') { - for (p = (const char *)xp->xp_pattern + 1; *p != NUL; p++) { - if (!vim_isIDc((uint8_t)(*p))) { - break; - } - } - if (*p == NUL) { - xp->xp_context = EXPAND_ENV_VARS; - xp->xp_pattern++; - // Avoid that the assignment uses EXPAND_FILES again. - if (context != EXPAND_USER_DEFINED && context != EXPAND_USER_LIST) { - context = EXPAND_ENV_VARS; - } + // Check for environment variable. + if (*xp->xp_pattern == '$') { + for (p = (const char *)xp->xp_pattern + 1; *p != NUL; p++) { + if (!vim_isIDc((uint8_t)(*p))) { + break; } } - // Check for user names. - if (*xp->xp_pattern == '~') { - for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {} - // Complete ~user only if it partially matches a user name. - // A full match ~user<Tab> will be replaced by user's home - // directory i.e. something like ~user<Tab> -> /home/user/ - if (*p == NUL && p > (const char *)xp->xp_pattern + 1 - && match_user((char_u *)xp->xp_pattern + 1) >= 1) { - xp->xp_context = EXPAND_USER; - xp->xp_pattern++; + if (*p == NUL) { + xp->xp_context = EXPAND_ENV_VARS; + xp->xp_pattern++; + // Avoid that the assignment uses EXPAND_FILES again. + if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST) { + *complp = EXPAND_ENV_VARS; } } } + // Check for user names. + if (*xp->xp_pattern == '~') { + for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {} + // Complete ~user only if it partially matches a user name. + // A full match ~user<Tab> will be replaced by user's home + // directory i.e. something like ~user<Tab> -> /home/user/ + if (*p == NUL && p > (const char *)xp->xp_pattern + 1 + && match_user(xp->xp_pattern + 1) >= 1) { + xp->xp_context = EXPAND_USER; + xp->xp_pattern++; + } + } +} - // 6. switch on command name - switch (ea.cmdidx) { +/// Set the completion context in "xp" for command "cmd" with index "cmdidx". +/// The argument to the command is "arg" and the argument flags is "argt". +/// For user-defined commands and for environment variables, "context" has the +/// completion type. +/// +/// @return a pointer to the next command, or NULL if there is no next command. +static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, const char *arg, + uint32_t argt, int context, expand_T *xp, bool forceit) +{ + const char *p; + + switch (cmdidx) { case CMD_find: case CMD_sfind: case CMD_tabfind: @@ -1313,6 +1204,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_folddoclosed: case CMD_folddoopen: case CMD_hide: + case CMD_horizontal: case CMD_keepalt: case CMD_keepjumps: case CMD_keepmarks: @@ -1348,14 +1240,13 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) if (*arg == NUL || !ends_excmd(*arg)) { // also complete "None" set_context_in_echohl_cmd(xp, arg); - arg = (const char *)skipwhite((char *)skiptowhite((const char_u *)arg)); + arg = (const char *)skipwhite(skiptowhite(arg)); if (*arg != NUL) { xp->xp_context = EXPAND_NOTHING; - arg = (const char *)skip_regexp((char_u *)arg + 1, (uint8_t)(*arg), - p_magic, NULL); + arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), p_magic, NULL); } } - return (const char *)find_nextcmd((char_u *)arg); + return (const char *)find_nextcmd(arg); // All completion for the +cmdline_compl feature goes here. @@ -1391,7 +1282,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) if (delim) { // Skip "from" part. arg++; - arg = (const char *)skip_regexp((char_u *)arg, delim, p_magic, NULL); + arg = (const char *)skip_regexp((char *)arg, delim, p_magic, NULL); } // Skip "to" part. while (arg[0] != NUL && (uint8_t)arg[0] != delim) { @@ -1498,7 +1389,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_lexpr: case CMD_laddexpr: case CMD_lgetexpr: - set_context_for_expression(xp, (char *)arg, ea.cmdidx); + set_context_for_expression(xp, (char *)arg, cmdidx); break; case CMD_unlet: @@ -1531,10 +1422,10 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_cscope: case CMD_lcscope: case CMD_scscope: - set_context_in_cscope_cmd(xp, arg, ea.cmdidx); + set_context_in_cscope_cmd(xp, arg, cmdidx); break; case CMD_sign: - set_context_in_sign_cmd(xp, (char_u *)arg); + set_context_in_sign_cmd(xp, (char *)arg); break; case CMD_bdelete: case CMD_bwipeout: @@ -1561,7 +1452,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_USER_BUF: if (context != EXPAND_NOTHING) { // EX_XFILE: file names are handled above. - if (!(ea.argt & EX_XFILE)) { + if (!(argt & EX_XFILE)) { if (context == EXPAND_MENUS) { return (const char *)set_context_in_menu_cmd(xp, cmd, (char *)arg, forceit); } else if (context == EXPAND_COMMANDS) { @@ -1607,7 +1498,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_xmap: case CMD_xnoremap: return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char_u *)arg, forceit, false, - false, ea.cmdidx); + false, cmdidx); case CMD_unmap: case CMD_nunmap: case CMD_vunmap: @@ -1618,7 +1509,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_sunmap: case CMD_xunmap: return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char_u *)arg, forceit, false, - true, ea.cmdidx); + true, cmdidx); case CMD_mapclear: case CMD_nmapclear: case CMD_vmapclear: @@ -1639,12 +1530,12 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) case CMD_iabbrev: case CMD_inoreabbrev: return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char_u *)arg, forceit, true, - false, ea.cmdidx); + false, cmdidx); case CMD_unabbreviate: case CMD_cunabbrev: case CMD_iunabbrev: return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char_u *)arg, forceit, true, - true, ea.cmdidx); + true, cmdidx); case CMD_menu: case CMD_noremenu: case CMD_unmenu: @@ -1702,7 +1593,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) #ifdef HAVE_WORKING_LIBINTL case CMD_language: - p = (const char *)skiptowhite((const char_u *)arg); + p = (const char *)skiptowhite(arg); if (*p == NUL) { xp->xp_context = EXPAND_LANGUAGE; xp->xp_pattern = (char *)arg; @@ -1763,6 +1654,182 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) return NULL; } +/// This is all pretty much copied from do_one_cmd(), with all the extra stuff +/// we don't need/want deleted. Maybe this could be done better if we didn't +/// repeat all this stuff. The only problem is that they may not stay +/// perfectly compatible with each other, but then the command line syntax +/// probably won't change that much -- webb. +/// +/// @param buff buffer for command string +static const char *set_one_cmd_context(expand_T *xp, const char *buff) +{ + size_t len = 0; + exarg_T ea; + int context = EXPAND_NOTHING; + bool forceit = false; + bool usefilter = false; // Filter instead of file name. + + ExpandInit(xp); + xp->xp_pattern = (char *)buff; + xp->xp_line = (char *)buff; + xp->xp_context = EXPAND_COMMANDS; // Default until we get past command + ea.argt = 0; + + // 1. skip comment lines and leading space, colons or bars + const char *cmd; + for (cmd = buff; vim_strchr(" \t:|", *cmd) != NULL; cmd++) {} + xp->xp_pattern = (char *)cmd; + + if (*cmd == NUL) { + return NULL; + } + if (*cmd == '"') { // ignore comment lines + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + + // 3. skip over a range specifier of the form: addr [,addr] [;addr] .. + cmd = (const char *)skip_range(cmd, &xp->xp_context); + xp->xp_pattern = (char *)cmd; + if (*cmd == NUL) { + return NULL; + } + if (*cmd == '"') { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + + if (*cmd == '|' || *cmd == '\n') { + return cmd + 1; // There's another command + } + + // Get the command index. + const char *p = set_cmd_index(cmd, &ea, xp, &context); + if (p == NULL) { + return NULL; + } + + xp->xp_context = EXPAND_NOTHING; // Default now that we're past command + + if (*p == '!') { // forced commands + forceit = true; + p++; + } + + // 6. parse arguments + if (!IS_USER_CMDIDX(ea.cmdidx)) { + ea.argt = excmd_get_argt(ea.cmdidx); + } + + const char *arg = (const char *)skipwhite(p); + + // Skip over ++argopt argument + if ((ea.argt & EX_ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) { + p = arg; + while (*p && !ascii_isspace(*p)) { + MB_PTR_ADV(p); + } + arg = (const char *)skipwhite(p); + } + + if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { + if (*arg == '>') { // append + if (*++arg == '>') { + arg++; + } + arg = (const char *)skipwhite(arg); + } else if (*arg == '!' && ea.cmdidx == CMD_write) { // :w !filter + arg++; + usefilter = true; + } + } + + if (ea.cmdidx == CMD_read) { + usefilter = forceit; // :r! filter if forced + if (*arg == '!') { // :r !filter + arg++; + usefilter = true; + } + } + + if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { + while (*arg == *cmd) { // allow any number of '>' or '<' + arg++; + } + arg = (const char *)skipwhite(arg); + } + + // Does command allow "+command"? + if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') { + // Check if we're in the +command + p = arg + 1; + arg = (const char *)skip_cmd_arg((char *)arg, false); + + // Still touching the command after '+'? + if (*arg == NUL) { + return p; + } + + // Skip space(s) after +command to get to the real argument. + arg = (const char *)skipwhite(arg); + } + + // Check for '|' to separate commands and '"' to start comments. + // Don't do this for ":read !cmd" and ":write !cmd". + if ((ea.argt & EX_TRLBAR) && !usefilter) { + p = arg; + // ":redir @" is not the start of a comment + if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') { + p += 2; + } + while (*p) { + if (*p == Ctrl_V) { + if (p[1] != NUL) { + p++; + } + } else if ((*p == '"' && !(ea.argt & EX_NOTRLCOM)) + || *p == '|' + || *p == '\n') { + if (*(p - 1) != '\\') { + if (*p == '|' || *p == '\n') { + return p + 1; + } + return NULL; // It's a comment + } + } + MB_PTR_ADV(p); + } + } + + if (!(ea.argt & EX_EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) { + // no arguments allowed but there is something + return NULL; + } + + // Find start of last argument (argument just before cursor): + p = buff; + xp->xp_pattern = (char *)p; + len = strlen(buff); + while (*p && p < buff + len) { + if (*p == ' ' || *p == TAB) { + // argument starts after a space + xp->xp_pattern = (char *)++p; + } else { + if (*p == '\\' && *(p + 1) != NUL) { + p++; // skip over escaped character + } + MB_PTR_ADV(p); + } + } + + if (ea.argt & EX_XFILE) { + set_context_for_wildcard_arg(&ea, arg, usefilter, xp, &context); + } + + // Switch on command name. + return set_context_by_cmdname(cmd, ea.cmdidx, arg, ea.argt, context, xp, forceit); +} + /// @param str start of command line /// @param len length of command line (excl. NUL) /// @param col position of cursor @@ -1785,7 +1852,7 @@ void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline set_context_for_expression(xp, (char *)str, CMD_SIZE); } else if (use_ccline && ccline->input_fn) { xp->xp_context = ccline->xp_context; - xp->xp_pattern = (char *)ccline->cmdbuff; + xp->xp_pattern = ccline->cmdbuff; xp->xp_arg = (char *)ccline->xp_arg; } else { while (nextcomm != NULL) { @@ -1832,7 +1899,7 @@ int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char *** // add star to file name, or convert to regexp if not exp. files. assert((str + col) - (char_u *)xp->xp_pattern >= 0); xp->xp_pattern_len = (size_t)((str + col) - (char_u *)xp->xp_pattern); - file_str = addstar((char_u *)xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + file_str = (char_u *)addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); if (p_wic) { options += WILD_ICASE; @@ -1848,6 +1915,66 @@ int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char *** return EXPAND_OK; } +/// Expand file or directory names. +static int expand_files_and_dirs(expand_T *xp, char *pat, char ***file, int *num_file, int flags, + int options) +{ + bool free_pat = false; + + // for ":set path=" and ":set tags=" halve backslashes for escaped space + if (xp->xp_backslash != XP_BS_NONE) { + free_pat = true; + pat = xstrdup(pat); + for (int i = 0; pat[i]; i++) { + if (pat[i] == '\\') { + if (xp->xp_backslash == XP_BS_THREE + && pat[i + 1] == '\\' + && pat[i + 2] == '\\' + && pat[i + 3] == ' ') { + STRMOVE(pat + i, pat + i + 3); + } + if (xp->xp_backslash == XP_BS_ONE + && pat[i + 1] == ' ') { + STRMOVE(pat + i, pat + i + 1); + } + } + } + } + + if (xp->xp_context == EXPAND_FILES) { + flags |= EW_FILE; + } else if (xp->xp_context == EXPAND_FILES_IN_PATH) { + flags |= (EW_FILE | EW_PATH); + } else { + flags = (flags | EW_DIR) & ~EW_FILE; + } + if (options & WILD_ICASE) { + flags |= EW_ICASE; + } + + // Expand wildcards, supporting %:h and the like. + int ret = expand_wildcards_eval(&pat, num_file, file, flags); + if (free_pat) { + xfree(pat); + } +#ifdef BACKSLASH_IN_FILENAME + if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) { + for (int j = 0; j < *num_file; j++) { + char *ptr = (*file)[j]; + while (*ptr != NUL) { + if (p_csl[0] == 's' && *ptr == '\\') { + *ptr = '/'; + } else if (p_csl[0] == 'b' && *ptr == '/') { + *ptr = '\\'; + } + ptr += utfc_ptr2len(ptr); + } + } + } +#endif + return ret; +} + /// Function given to ExpandGeneric() to obtain the possible arguments of the /// ":behave {mswin,xterm}" command. static char *get_behave_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) @@ -1905,6 +2032,67 @@ static char *get_healthcheck_names(expand_T *xp FUNC_ATTR_UNUSED, int idx) return NULL; } +/// Do the expansion based on xp->xp_context and "rmp". +static int ExpandOther(expand_T *xp, regmatch_T *rmp, int *num_file, char ***file) +{ + typedef CompleteListItemGetter ExpandFunc; + static struct expgen { + int context; + ExpandFunc func; + int ic; + int escaped; + } tab[] = { + { EXPAND_COMMANDS, get_command_name, false, true }, + { EXPAND_BEHAVE, get_behave_arg, true, true }, + { EXPAND_MAPCLEAR, get_mapclear_arg, true, true }, + { EXPAND_MESSAGES, get_messages_arg, true, true }, + { EXPAND_HISTORY, get_history_arg, true, true }, + { EXPAND_USER_COMMANDS, get_user_commands, false, true }, + { EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, false, true }, + { EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, false, true }, + { EXPAND_USER_NARGS, get_user_cmd_nargs, false, true }, + { EXPAND_USER_COMPLETE, get_user_cmd_complete, false, true }, + { EXPAND_USER_VARS, get_user_var_name, false, true }, + { EXPAND_FUNCTIONS, get_function_name, false, true }, + { EXPAND_USER_FUNC, get_user_func_name, false, true }, + { EXPAND_EXPRESSION, get_expr_name, false, true }, + { EXPAND_MENUS, get_menu_name, false, true }, + { EXPAND_MENUNAMES, get_menu_names, false, true }, + { EXPAND_SYNTAX, get_syntax_name, true, true }, + { EXPAND_SYNTIME, get_syntime_arg, true, true }, + { EXPAND_HIGHLIGHT, (ExpandFunc)get_highlight_name, true, false }, + { EXPAND_EVENTS, expand_get_event_name, true, false }, + { EXPAND_AUGROUP, expand_get_augroup_name, true, false }, + { EXPAND_CSCOPE, get_cscope_name, true, true }, + { EXPAND_SIGN, get_sign_name, true, true }, + { EXPAND_PROFILE, get_profile_name, true, true }, +#ifdef HAVE_WORKING_LIBINTL + { EXPAND_LANGUAGE, get_lang_arg, true, false }, + { EXPAND_LOCALES, get_locales, true, false }, +#endif + { EXPAND_ENV_VARS, get_env_name, true, true }, + { EXPAND_USER, get_users, true, false }, + { EXPAND_ARGLIST, get_arglist_name, true, false }, + { EXPAND_CHECKHEALTH, get_healthcheck_names, true, false }, + }; + int ret = FAIL; + + // Find a context in the table and call the ExpandGeneric() with the + // right function to do the expansion. + for (int i = 0; i < (int)ARRAY_SIZE(tab); i++) { + if (xp->xp_context == tab[i].context) { + if (tab[i].ic) { + rmp->rm_ic = true; + } + ExpandGeneric(xp, rmp, num_file, file, tab[i].func, tab[i].escaped); + ret = OK; + break; + } + } + + return ret; +} + /// Do the expansion based on xp->xp_context and "pat". /// /// @param options WILD_ flags @@ -1937,62 +2125,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***f if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES || xp->xp_context == EXPAND_FILES_IN_PATH) { - // Expand file or directory names. - bool free_pat = false; - int i; - - // for ":set path=" and ":set tags=" halve backslashes for escaped space - if (xp->xp_backslash != XP_BS_NONE) { - free_pat = true; - pat = vim_strsave(pat); - for (i = 0; pat[i]; i++) { - if (pat[i] == '\\') { - if (xp->xp_backslash == XP_BS_THREE - && pat[i + 1] == '\\' - && pat[i + 2] == '\\' - && pat[i + 3] == ' ') { - STRMOVE(pat + i, pat + i + 3); - } - if (xp->xp_backslash == XP_BS_ONE - && pat[i + 1] == ' ') { - STRMOVE(pat + i, pat + i + 1); - } - } - } - } - - if (xp->xp_context == EXPAND_FILES) { - flags |= EW_FILE; - } else if (xp->xp_context == EXPAND_FILES_IN_PATH) { - flags |= (EW_FILE | EW_PATH); - } else { - flags = (flags | EW_DIR) & ~EW_FILE; - } - if (options & WILD_ICASE) { - flags |= EW_ICASE; - } - - // Expand wildcards, supporting %:h and the like. - ret = expand_wildcards_eval(&pat, num_file, file, flags); - if (free_pat) { - xfree(pat); - } -#ifdef BACKSLASH_IN_FILENAME - if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) { - for (int i = 0; i < *num_file; i++) { - char_u *ptr = (*file)[i]; - while (*ptr != NUL) { - if (p_csl[0] == 's' && *ptr == '\\') { - *ptr = '/'; - } else if (p_csl[0] == 'b' && *ptr == '/') { - *ptr = '\\'; - } - ptr += utfc_ptr2len(ptr); - } - } - } -#endif - return ret; + return expand_files_and_dirs(xp, (char *)pat, file, num_file, flags, options); } *file = NULL; @@ -2010,7 +2143,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***f if (xp->xp_context == EXPAND_SHELLCMD) { *file = NULL; - expand_shellcmd(pat, num_file, file, flags); + expand_shellcmd((char *)pat, num_file, file, flags); return OK; } if (xp->xp_context == EXPAND_OLD_SETTING) { @@ -2029,19 +2162,19 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***f } 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((char *)pat, DIP_START + DIP_OPT + DIP_LUA, num_file, file, directories); } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = { "compiler", NULL }; - return ExpandRTDir(pat, DIP_LUA, num_file, file, directories); + return ExpandRTDir((char *)pat, DIP_LUA, num_file, file, directories); } if (xp->xp_context == EXPAND_OWNSYNTAX) { char *directories[] = { "syntax", NULL }; - return ExpandRTDir(pat, 0, num_file, file, directories); + return ExpandRTDir((char *)pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_FILETYPE) { char *directories[] = { "syntax", "indent", "ftplugin", NULL }; - return ExpandRTDir(pat, DIP_LUA, num_file, file, directories); + return ExpandRTDir((char *)pat, DIP_LUA, num_file, file, directories); } if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, num_file, file); @@ -2050,7 +2183,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***f return ExpandUserLua(xp, num_file, file); } if (xp->xp_context == EXPAND_PACKADD) { - return ExpandPackAddDir(pat, num_file, file); + return ExpandPackAddDir((char *)pat, num_file, file); } // When expanding a function name starting with s:, match the <SNR>nr_ @@ -2085,60 +2218,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char ***f } else if (xp->xp_context == EXPAND_USER_DEFINED) { ret = ExpandUserDefined(xp, ®match, num_file, file); } else { - typedef CompleteListItemGetter ExpandFunc; - static struct expgen { - int context; - ExpandFunc func; - int ic; - int escaped; - } tab[] = { - { EXPAND_COMMANDS, get_command_name, false, true }, - { EXPAND_BEHAVE, get_behave_arg, true, true }, - { EXPAND_MAPCLEAR, get_mapclear_arg, true, true }, - { EXPAND_MESSAGES, get_messages_arg, true, true }, - { EXPAND_HISTORY, get_history_arg, true, true }, - { EXPAND_USER_COMMANDS, get_user_commands, false, true }, - { EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, false, true }, - { EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, false, true }, - { EXPAND_USER_NARGS, get_user_cmd_nargs, false, true }, - { EXPAND_USER_COMPLETE, get_user_cmd_complete, false, true }, - { EXPAND_USER_VARS, get_user_var_name, false, true }, - { EXPAND_FUNCTIONS, get_function_name, false, true }, - { EXPAND_USER_FUNC, get_user_func_name, false, true }, - { EXPAND_EXPRESSION, get_expr_name, false, true }, - { EXPAND_MENUS, get_menu_name, false, true }, - { EXPAND_MENUNAMES, get_menu_names, false, true }, - { EXPAND_SYNTAX, get_syntax_name, true, true }, - { EXPAND_SYNTIME, get_syntime_arg, true, true }, - { EXPAND_HIGHLIGHT, (ExpandFunc)get_highlight_name, true, true }, - { EXPAND_EVENTS, expand_get_event_name, true, false }, - { EXPAND_AUGROUP, expand_get_augroup_name, true, false }, - { EXPAND_CSCOPE, get_cscope_name, true, true }, - { EXPAND_SIGN, get_sign_name, true, true }, - { EXPAND_PROFILE, get_profile_name, true, true }, -#ifdef HAVE_WORKING_LIBINTL - { EXPAND_LANGUAGE, get_lang_arg, true, false }, - { EXPAND_LOCALES, get_locales, true, false }, -#endif - { EXPAND_ENV_VARS, get_env_name, true, true }, - { EXPAND_USER, get_users, true, false }, - { EXPAND_ARGLIST, get_arglist_name, true, false }, - { EXPAND_CHECKHEALTH, get_healthcheck_names, true, false }, - }; - - // Find a context in the table and call the ExpandGeneric() with the - // right function to do the expansion. - ret = FAIL; - for (int i = 0; i < (int)ARRAY_SIZE(tab); i++) { - if (xp->xp_context == tab[i].context) { - if (tab[i].ic) { - regmatch.rm_ic = true; - } - ExpandGeneric(xp, ®match, num_file, file, tab[i].func, tab[i].escaped); - ret = OK; - break; - } - } + ret = ExpandOther(xp, ®match, num_file, file); } vim_regfree(regmatch.regprog); @@ -2159,18 +2239,18 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha { int i; size_t count = 0; - char_u *str; + char *str; // count the number of matching names for (i = 0;; i++) { - str = (char_u *)(*func)(xp, i); + str = (*func)(xp, i); if (str == NULL) { // end of list break; } if (*str == NUL) { // skip empty strings continue; } - if (vim_regexec(regmatch, (char *)str, (colnr_T)0)) { + if (vim_regexec(regmatch, str, (colnr_T)0)) { count++; } } @@ -2184,23 +2264,23 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha // copy the matching names into allocated memory count = 0; for (i = 0;; i++) { - str = (char_u *)(*func)(xp, i); + str = (*func)(xp, i); if (str == NULL) { // End of list. break; } if (*str == NUL) { // Skip empty strings. continue; } - if (vim_regexec(regmatch, (char *)str, (colnr_T)0)) { + if (vim_regexec(regmatch, str, (colnr_T)0)) { if (escaped) { - str = vim_strsave_escaped(str, (char_u *)" \t\\."); + str = (char *)vim_strsave_escaped((char_u *)str, (char_u *)" \t\\."); } else { - str = vim_strsave(str); + str = xstrdup(str); } - (*file)[count++] = (char *)str; + (*file)[count++] = str; if (func == get_menu_names) { // Test for separator added by get_menu_names(). - str += STRLEN(str) - 1; + str += strlen(str) - 1; if (*str == '\001') { *str = '.'; } @@ -2214,8 +2294,7 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha || xp->xp_context == EXPAND_FUNCTIONS || xp->xp_context == EXPAND_USER_FUNC) { // <SNR> functions should be sorted to the end. - qsort((void *)(*file), (size_t)(*num_file), sizeof(char_u *), - sort_func_compare); + qsort((void *)(*file), (size_t)(*num_file), sizeof(char *), sort_func_compare); } else { sort_strings(*file, *num_file); } @@ -2234,22 +2313,22 @@ 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 ***file, int flagsarg) +static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flagsarg) FUNC_ATTR_NONNULL_ALL { - char_u *pat; + char *pat; int i; - char_u *path = NULL; + char *path = NULL; garray_T ga; char *buf = xmalloc(MAXPATHL); size_t l; - char_u *s, *e; + char *s, *e; int flags = flagsarg; int ret; bool did_curdir = false; // for ":set path=" and ":set tags=" halve backslashes for escaped space - pat = vim_strsave(filepat); + pat = xstrdup(filepat); for (i = 0; pat[i]; i++) { if (pat[i] == '\\' && pat[i + 1] == ' ') { STRMOVE(pat + i, pat + i + 1); @@ -2261,14 +2340,14 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char ***file, int fl bool mustfree = false; // Track memory allocation for *path. if (pat[0] == '.' && (vim_ispathsep(pat[1]) || (pat[1] == '.' && vim_ispathsep(pat[2])))) { - path = (char_u *)"."; + path = "."; } else { // For an absolute name we don't use $PATH. - if (!path_is_absolute(pat)) { - path = (char_u *)vim_getenv("PATH"); + if (!path_is_absolute((char_u *)pat)) { + path = vim_getenv("PATH"); } if (path == NULL) { - path = (char_u *)""; + path = ""; } else { mustfree = true; } @@ -2281,9 +2360,9 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char ***file, int fl hashtab_T found_ht; hash_init(&found_ht); for (s = path;; s = e) { - e = (char_u *)vim_strchr((char *)s, ENV_SEPCHAR); + e = vim_strchr(s, ENV_SEPCHAR); if (e == NULL) { - e = s + STRLEN(s); + e = s + strlen(s); } if (*s == NUL) { @@ -2307,7 +2386,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char ***file, int fl } STRLCPY(buf, s, l + 1); add_pathsep(buf); - l = STRLEN(buf); + l = strlen(buf); STRLCPY(buf + l, pat, MAXPATHL - l); // Expand matches in one directory of $PATH. @@ -2359,9 +2438,9 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T FUNC_ATTR_NONNULL_ALL { CmdlineInfo *const ccline = get_cmdline_info(); - char_u keep = 0; + char keep = 0; typval_T args[4]; - char_u *pat = NULL; + char *pat = NULL; const sctx_T save_current_sctx = current_sctx; if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) { @@ -2375,12 +2454,12 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T ccline->cmdbuff[ccline->cmdlen] = 0; } - pat = vim_strnsave((char_u *)xp->xp_pattern, xp->xp_pattern_len); + pat = xstrnsave(xp->xp_pattern, xp->xp_pattern_len); args[0].v_type = VAR_STRING; args[1].v_type = VAR_STRING; args[2].v_type = VAR_NUMBER; args[3].v_type = VAR_UNKNOWN; - args[0].vval.v_string = (char *)pat; + args[0].vval.v_string = pat; args[1].vval.v_string = xp->xp_line; args[2].vval.v_number = xp->xp_col; @@ -2400,30 +2479,29 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T /// 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; + char *e; garray_T ga; - char_u *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp, num_file, - file); + char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp, num_file, + file); if (retstr == NULL) { return FAIL; } ga_init(&ga, (int)sizeof(char *), 3); - for (char_u *s = retstr; *s != NUL; s = e) { - e = (char_u *)vim_strchr((char *)s, '\n'); + for (char *s = retstr; *s != NUL; s = e) { + e = vim_strchr(s, '\n'); if (e == NULL) { - e = s + STRLEN(s); + e = s + strlen(s); } - const char_u keep = *e; + const char keep = *e; *e = NUL; - const bool skip = xp->xp_pattern[0] - && vim_regexec(regmatch, (char *)s, (colnr_T)0) == 0; + const bool skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0; *e = keep; if (!skip) { - GA_APPEND(char_u *, &ga, vim_strnsave(s, (size_t)(e - s))); + GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s))); } if (*e != NUL) { @@ -2494,7 +2572,7 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char ***file) /// Expand `file` for all comma-separated directories in `path`. /// Adds matches to `ga`. -void globpath(char *path, char_u *file, garray_T *ga, int expand_options) +void globpath(char *path, char *file, garray_T *ga, int expand_options) { expand_T xpc; ExpandInit(&xpc); @@ -2506,7 +2584,7 @@ void globpath(char *path, char_u *file, garray_T *ga, int expand_options) while (*path != NUL) { // Copy one item of the path to buf[] and concatenate the file name. copy_option_part(&path, (char *)buf, MAXPATHL, ","); - if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL) { + if (STRLEN(buf) + strlen(file) + 2 < MAXPATHL) { add_pathsep((char *)buf); STRCAT(buf, file); // NOLINT @@ -2584,7 +2662,7 @@ int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp) // cursor int found = false; - int j = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + int j = (int)(xp->xp_pattern - cclp->cmdbuff); int i = 0; while (--j > 0) { // check for start of menu name @@ -2639,7 +2717,7 @@ int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp) int found = false; int j = cclp->cmdpos; - int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + int i = (int)(xp->xp_pattern - cclp->cmdbuff); while (--j > i) { j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j); if (vim_ispathsep(cclp->cmdbuff[j])) { @@ -2660,7 +2738,7 @@ int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp) int found = false; int j = cclp->cmdpos - 1; - int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + int i = (int)(xp->xp_pattern - cclp->cmdbuff); while (--j > i) { j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j); if (vim_ispathsep(cclp->cmdbuff[j]) @@ -2732,7 +2810,7 @@ void wildmenu_cleanup(CmdlineInfo *cclp) p_ls = save_p_ls; p_wmh = save_p_wmh; last_status(false); - update_screen(VALID); // redraw the screen NOW + update_screen(); // redraw the screen NOW redrawcmd(); save_p_ls = -1; wild_menu_showing = 0; @@ -2751,7 +2829,7 @@ void wildmenu_cleanup(CmdlineInfo *cclp) } /// "getcompletion()" function -void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char_u *pat; expand_T xpc; @@ -2786,14 +2864,14 @@ 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 = (int)STRLEN(pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + xpc.xp_col = (int)strlen(pattern); goto theend; } ExpandInit(&xpc); xpc.xp_pattern = (char *)pattern; - xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); xpc.xp_context = cmdcomplete_str_to_type(type); if (xpc.xp_context == EXPAND_NOTHING) { semsg(_(e_invarg2), type); @@ -2802,22 +2880,22 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (xpc.xp_context == EXPAND_MENUS) { set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false); - xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); } if (xpc.xp_context == EXPAND_CSCOPE) { set_context_in_cscope_cmd(&xpc, (const char *)xpc.xp_pattern, CMD_cscope); - xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); } if (xpc.xp_context == EXPAND_SIGN) { - set_context_in_sign_cmd(&xpc, (char_u *)xpc.xp_pattern); - xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); + set_context_in_sign_cmd(&xpc, xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); } theend: - pat = addstar((char_u *)xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); - ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); + pat = (char_u *)addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); + ExpandOne(&xpc, (char *)pat, NULL, options, WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 13f97ba1e8..5a59f09113 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -90,14 +90,14 @@ static char *(history_names[]) = { /// arguments of the ":history command. char *get_history_arg(expand_T *xp, int idx) { - static char_u compl[2] = { NUL, NUL }; - char *short_names = ":=@>?/"; - int short_names_count = (int)STRLEN(short_names); - int history_name_count = ARRAY_SIZE(history_names) - 1; + const char *short_names = ":=@>?/"; + const int short_names_count = (int)strlen(short_names); + const int history_name_count = ARRAY_SIZE(history_names) - 1; if (idx < short_names_count) { - compl[0] = (char_u)short_names[idx]; - return (char *)compl; + xp->xp_buf[0] = short_names[idx]; + xp->xp_buf[1] = NUL; + return xp->xp_buf; } if (idx < short_names_count + history_name_count) { return history_names[idx - short_names_count]; @@ -186,7 +186,7 @@ static inline void clear_hist_entry(histentry_T *hisptr) /// If 'move_to_front' is true, matching entry is moved to end of history. /// /// @param move_to_front Move the entry to the front if it exists -static int in_history(int type, char_u *str, int move_to_front, int sep) +static int in_history(int type, char *str, int move_to_front, int sep) { int last_i = -1; @@ -201,8 +201,8 @@ static int in_history(int type, char_u *str, int move_to_front, int sep) // For search history, check that the separator character matches as // well. - char_u *p = history[type][i].hisstr; - if (STRCMP(str, p) == 0 + char *p = history[type][i].hisstr; + if (strcmp(str, p) == 0 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) { if (!move_to_front) { return true; @@ -276,7 +276,7 @@ static int last_maptick = -1; // last seen maptick /// @param histype may be one of the HIST_ values. /// @param in_map consider maptick when inside a mapping /// @param sep separator character used (search hist) -void add_to_history(int histype, char_u *new_entry, int in_map, int sep) +void add_to_history(int histype, char *new_entry, int in_map, int sep) { histentry_T *hisptr; @@ -312,11 +312,11 @@ void add_to_history(int histype, char_u *new_entry, int in_map, int sep) hist_free_entry(hisptr); // Store the separator after the NUL of the string. - size_t len = STRLEN(new_entry); - hisptr->hisstr = vim_strnsave(new_entry, len + 2); + size_t len = strlen(new_entry); + hisptr->hisstr = xstrnsave(new_entry, len + 2); hisptr->timestamp = os_time(); hisptr->additional_elements = NULL; - hisptr->hisstr[len + 1] = (char_u)sep; + hisptr->hisstr[len + 1] = (char)sep; hisptr->hisnum = ++hisnum[histype]; if (histype == HIST_SEARCH && in_map) { @@ -382,13 +382,13 @@ static int calc_hist_idx(int histype, int num) /// Get a history entry by its index. /// /// @param histype may be one of the HIST_ values. -static char_u *get_history_entry(int histype, int idx) +static char *get_history_entry(int histype, int idx) { idx = calc_hist_idx(histype, idx); if (idx >= 0) { return history[histype][idx].hisstr; } else { - return (char_u *)""; + return ""; } } @@ -438,7 +438,7 @@ static int del_history_entry(int histype, char_u *str) if (hisptr->hisstr == NULL) { break; } - if (vim_regexec(®match, (char *)hisptr->hisstr, (colnr_T)0)) { + if (vim_regexec(®match, hisptr->hisstr, (colnr_T)0)) { found = true; hist_free_entry(hisptr); } else { @@ -494,7 +494,7 @@ static int del_history_idx(int histype, int idx) } /// "histadd()" function -void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_histadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { HistoryType histype; @@ -509,7 +509,7 @@ void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) str = tv_get_string_buf(&argvars[1], buf); if (*str != NUL) { init_history(); - add_to_history(histype, (char_u *)str, false, NUL); + add_to_history(histype, (char *)str, false, NUL); rettv->vval.v_number = true; return; } @@ -517,7 +517,7 @@ void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "histdel()" function -void f_histdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_histdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int n; const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error @@ -540,7 +540,7 @@ void f_histdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "histget()" function -void f_histget(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_histget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { HistoryType type; int idx; @@ -556,13 +556,13 @@ void f_histget(typval_T *argvars, typval_T *rettv, FunPtr fptr) idx = (int)tv_get_number_chk(&argvars[1], NULL); } // -1 on type error - rettv->vval.v_string = (char *)vim_strsave(get_history_entry(type, idx)); + rettv->vval.v_string = xstrdup(get_history_entry(type, idx)); } rettv->v_type = VAR_STRING; } /// "histnr()" function -void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_histnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const histname = tv_get_string_chk(&argvars[0]); HistoryType i = histname == NULL @@ -643,14 +643,13 @@ void ex_history(exarg_T *eap) msg_putchar('\n'); snprintf((char *)IObuff, IOSIZE, "%c%6d ", i == idx ? '>' : ' ', hist[i].hisnum); - if (vim_strsize((char *)hist[i].hisstr) > Columns - 10) { - trunc_string((char *)hist[i].hisstr, (char *)IObuff + STRLEN(IObuff), - Columns - 10, IOSIZE - (int)STRLEN(IObuff)); + if (vim_strsize(hist[i].hisstr) > Columns - 10) { + trunc_string(hist[i].hisstr, (char *)IObuff + strlen(IObuff), + Columns - 10, IOSIZE - (int)strlen(IObuff)); } else { STRCAT(IObuff, hist[i].hisstr); } msg_outtrans((char *)IObuff); - ui_flush(); } if (i == idx) { break; diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h index 797b79a5f0..8b7bb7ac24 100644 --- a/src/nvim/cmdhist.h +++ b/src/nvim/cmdhist.h @@ -22,7 +22,7 @@ typedef enum { /// History entry definition typedef struct hist_entry { int hisnum; ///< Entry identifier number. - char_u *hisstr; ///< Actual entry, separator char after the NUL. + char *hisstr; ///< Actual entry, separator char after the NUL. Timestamp timestamp; ///< Time when entry was added. list_T *additional_elements; ///< Additional entries from ShaDa file. } histentry_T; diff --git a/src/nvim/context.c b/src/nvim/context.c index e3ae9355bf..34692cdf64 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -345,7 +345,7 @@ Dictionary ctx_to_dict(Context *ctx) PUT(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps))); PUT(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs))); PUT(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars))); - PUT(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs))); + PUT(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, NULL))); return rv; } @@ -381,7 +381,7 @@ int ctx_from_dict(Dictionary dict, Context *ctx) ctx->gvars = array_to_sbuf(item.value.data.array); } else if (strequal(item.key.data, "funcs")) { types |= kCtxFuncs; - ctx->funcs = copy_object(item.value).data.array; + ctx->funcs = copy_object(item.value, NULL).data.array; } } diff --git a/src/nvim/context.h b/src/nvim/context.h index c2deca12c9..ae77e66516 100644 --- a/src/nvim/context.h +++ b/src/nvim/context.h @@ -3,8 +3,8 @@ #include <msgpack.h> +#include "klib/kvec.h" #include "nvim/api/private/defs.h" -#include "nvim/lib/kvec.h" typedef struct { msgpack_sbuffer regs; ///< Registers. diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index d4670dedc7..6c0475822b 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -67,7 +67,7 @@ int coladvance_force(colnr_T wcol) /// Try to advance the Cursor to the specified screen column. /// If virtual editing: fine tune the cursor position. /// Note that all virtual positions off the end of a line should share -/// a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)), +/// a curwin->w_cursor.col value (n.b. this is equal to strlen(line)), /// beginning at coladd 0. /// /// @return OK if desired column is reached, FAIL if not @@ -101,7 +101,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a || (VIsual_active && *p_sel != 'o') || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL); - char_u *line = ml_get_buf(curbuf, pos->lnum, false); + char_u *line = (char_u *)ml_get_buf(curbuf, pos->lnum, false); if (wcol >= MAXCOL) { idx = (int)STRLEN(line) - 1 + one_more; @@ -137,14 +137,18 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } } - char_u *ptr = line; - while (col <= wcol && *ptr != NUL) { + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, (char *)line, (char *)line); + while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - csize = win_lbr_chartabsize(curwin, line, ptr, col, &head); - MB_PTR_ADV(ptr); - col += csize; + csize = win_lbr_chartabsize(&cts, &head); + MB_PTR_ADV(cts.cts_ptr); + cts.cts_vcol += csize; } - idx = (int)(ptr - line); + col = cts.cts_vcol; + idx = (int)(cts.cts_ptr - (char *)line); + clear_chartabsize_arg(&cts); + // Handle all the special cases. The virtual_active() check // is needed to ensure that a virtual position off the end of // a line has the correct indexing. The one_more comparison @@ -304,7 +308,7 @@ void check_pos(buf_T *buf, pos_T *pos) } if (pos->col > 0) { - char_u *line = ml_get_buf(buf, pos->lnum, false); + char_u *line = (char_u *)ml_get_buf(buf, pos->lnum, false); colnr_T len = (colnr_T)STRLEN(line); if (pos->col > len) { pos->col = len; @@ -342,7 +346,7 @@ void check_cursor_col_win(win_T *win) colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd; unsigned int cur_ve_flags = get_ve_flags(); - colnr_T len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, false)); + colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, win->w_cursor.lnum, false)); if (len == 0) { win->w_cursor.col = 0; } else if (win->w_cursor.col >= len) { @@ -408,7 +412,7 @@ void check_visual_pos(void) VIsual.col = 0; VIsual.coladd = 0; } else { - int len = (int)STRLEN(ml_get(VIsual.lnum)); + int len = (int)strlen(ml_get(VIsual.lnum)); if (VIsual.col > len) { VIsual.col = len; @@ -471,13 +475,13 @@ bool leftcol_changed(void) if (retval) { curwin->w_set_curswant = true; } - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); return retval; } int gchar_cursor(void) { - return utf_ptr2char((char *)get_cursor_pos_ptr()); + return utf_ptr2char(get_cursor_pos_ptr()); } /// Write a character at the current cursor position. @@ -485,18 +489,17 @@ int gchar_cursor(void) void pchar_cursor(char_u c) { *(ml_get_buf(curbuf, curwin->w_cursor.lnum, true) - + curwin->w_cursor.col) = c; + + curwin->w_cursor.col) = (char)c; } /// @return pointer to cursor line. -char_u *get_cursor_line_ptr(void) +char *get_cursor_line_ptr(void) { return ml_get_buf(curbuf, curwin->w_cursor.lnum, false); } /// @return pointer to cursor position. -char_u *get_cursor_pos_ptr(void) +char *get_cursor_pos_ptr(void) { - return ml_get_buf(curbuf, curwin->w_cursor.lnum, false) + - curwin->w_cursor.col; + return ml_get_buf(curbuf, curwin->w_cursor.lnum, false) + curwin->w_cursor.col; } diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index 9c33b1a806..6f4f17659a 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -120,7 +120,7 @@ char *parse_shape_opt(int what) } } // Repeat for all comma separated parts. - char *modep = (char *)p_guicursor; + char *modep = p_guicursor; while (modep != NULL && *modep != NUL) { colonp = vim_strchr(modep, ':'); commap = vim_strchr(modep, ','); @@ -220,7 +220,7 @@ char *parse_shape_opt(int what) endp = vim_strchr(p, '-'); if (commap == NULL) { // last part if (endp == NULL) { - endp = p + STRLEN(p); // find end of part + endp = p + strlen(p); // find end of part } } else if (endp > commap || endp == NULL) { endp = commap; diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index a061bd961b..3e0cf82740 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -33,7 +33,7 @@ static char *debug_newval = NULL; struct debuggy { int dbg_nr; ///< breakpoint number int dbg_type; ///< DBG_FUNC or DBG_FILE or DBG_EXPR - char_u *dbg_name; ///< function, expression or file name + char *dbg_name; ///< function, expression or file name regprog_T *dbg_prog; ///< regexp program linenr_T dbg_lnum; ///< line number in function or file int dbg_forceit; ///< ! used @@ -47,7 +47,7 @@ struct debuggy { /// Debug mode. Repeatedly get Ex commands, until told to continue normal /// execution. -void do_debug(char_u *cmd) +void do_debug(char *cmd) { int save_msg_scroll = msg_scroll; int save_State = State; @@ -60,7 +60,7 @@ void do_debug(char_u *cmd) bool typeahead_saved = false; int save_ignore_script = 0; int n; - char_u *cmdline = NULL; + char *cmdline = NULL; char *p; char *tail = NULL; static int last_cmd = 0; @@ -128,10 +128,15 @@ void do_debug(char_u *cmd) ignore_script = true; } + // don't debug any function call, e.g. from an expression mapping + n = debug_break_level; + debug_break_level = -1; + xfree(cmdline); - cmdline = (char_u *)getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL, - CALLBACK_NONE); + cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL, + CALLBACK_NONE); + debug_break_level = n; if (typeahead_saved) { restore_typeahead(&typeaheadbuf); ignore_script = save_ignore_script; @@ -144,7 +149,7 @@ void do_debug(char_u *cmd) // If this is a debug command, set "last_cmd". // If not, reset "last_cmd". // For a blank line use previous command. - p = skipwhite((char *)cmdline); + p = skipwhite(cmdline); if (*p != NUL) { switch (*p) { case 'c': @@ -246,7 +251,7 @@ void do_debug(char_u *cmd) do_showbacktrace(cmd); } else { p = skipwhite(p); - do_setdebugtracelevel((char_u *)p); + do_setdebugtracelevel(p); } continue; case CMD_UP: @@ -266,7 +271,7 @@ void do_debug(char_u *cmd) // don't debug this command n = debug_break_level; debug_break_level = -1; - (void)do_cmdline((char *)cmdline, getexline, NULL, DOCMD_VERBOSE|DOCMD_EXCRESET); + (void)do_cmdline(cmdline, getexline, NULL, DOCMD_VERBOSE|DOCMD_EXCRESET); debug_break_level = n; } lines_left = Rows - 1; @@ -275,7 +280,7 @@ void do_debug(char_u *cmd) RedrawingDisabled--; no_wait_return--; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); need_wait_return = false; msg_scroll = save_msg_scroll; lines_left = Rows - 1; @@ -306,9 +311,9 @@ static int get_maxbacktrace_level(char *sname) return maxbacktrace; } -static void do_setdebugtracelevel(char_u *arg) +static void do_setdebugtracelevel(char *arg) { - int level = atoi((char *)arg); + int level = atoi(arg); if (*arg == '+' || level < 0) { debug_backtrace_level += level; } else { @@ -335,7 +340,7 @@ static void do_checkbacktracelevel(void) } } -static void do_showbacktrace(char_u *cmd) +static void do_showbacktrace(char *cmd) { char *sname = estack_sfile(ESTACK_NONE); int max = get_maxbacktrace_level(sname); @@ -414,7 +419,7 @@ void dbg_check_breakpoint(exarg_T *eap) debug_breakpoint_name + (*p == NUL ? 0 : 3), (int64_t)debug_breakpoint_lnum); debug_breakpoint_name = NULL; - do_debug((char_u *)eap->cmd); + do_debug(eap->cmd); } else { debug_skipped = true; debug_skipped_name = debug_breakpoint_name; @@ -422,7 +427,7 @@ void dbg_check_breakpoint(exarg_T *eap) } } else if (ex_nesting_level <= debug_break_level) { if (!eap->skip) { - do_debug((char_u *)eap->cmd); + do_debug(eap->cmd); } else { debug_skipped = true; debug_skipped_name = NULL; @@ -470,7 +475,7 @@ static typval_T *eval_expr_no_emsg(struct debuggy *const bp) { // Disable error messages, a bad expression would make Vim unusable. emsg_off++; - typval_T *const tv = eval_expr((char *)bp->dbg_name); + typval_T *const tv = eval_expr(bp->dbg_name); emsg_off--; return tv; } @@ -482,9 +487,9 @@ static typval_T *eval_expr_no_emsg(struct debuggy *const bp) /// /// @param arg /// @param gap either &dbg_breakp or &prof_ga -static int dbg_parsearg(char_u *arg, garray_T *gap) +static int dbg_parsearg(char *arg, garray_T *gap) { - char *p = (char *)arg; + char *p = arg; char *q; bool here = false; @@ -531,11 +536,11 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) } if (bp->dbg_type == DBG_FUNC) { - bp->dbg_name = vim_strsave((char_u *)p); + bp->dbg_name = xstrdup(p); } else if (here) { - bp->dbg_name = vim_strsave((char_u *)curbuf->b_ffname); + bp->dbg_name = xstrdup(curbuf->b_ffname); } else if (bp->dbg_type == DBG_EXPR) { - bp->dbg_name = vim_strsave((char_u *)p); + bp->dbg_name = xstrdup(p); bp->dbg_val = eval_expr_no_emsg(bp); } else { // Expand the file name in the same way as do_source(). This means @@ -551,10 +556,10 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) return FAIL; } if (*p != '*') { - bp->dbg_name = (char_u *)fix_fname(p); + bp->dbg_name = fix_fname(p); xfree(p); } else { - bp->dbg_name = (char_u *)p; + bp->dbg_name = p; } } @@ -572,12 +577,12 @@ void ex_breakadd(exarg_T *eap) gap = &prof_ga; } - if (dbg_parsearg((char_u *)eap->arg, gap) == OK) { + if (dbg_parsearg(eap->arg, gap) == OK) { struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); bp->dbg_forceit = eap->forceit; if (bp->dbg_type != DBG_EXPR) { - char *pat = file_pat_to_reg_pat((char *)bp->dbg_name, NULL, NULL, false); + char *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); if (pat != NULL) { bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); xfree(pat); @@ -639,14 +644,14 @@ void ex_breakdel(exarg_T *eap) del_all = true; } else { // ":breakdel {func|file|expr} [lnum] {name}" - if (dbg_parsearg((char_u *)eap->arg, gap) == FAIL) { + if (dbg_parsearg(eap->arg, gap) == FAIL) { return; } bp = &DEBUGGY(gap, gap->ga_len); for (int i = 0; i < gap->ga_len; i++) { bpi = &DEBUGGY(gap, i); if (bp->dbg_type == bpi->dbg_type - && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 + && strcmp(bp->dbg_name, bpi->dbg_name) == 0 && (bp->dbg_lnum == bpi->dbg_lnum || (bp->dbg_lnum == 0 && (best_lnum == 0 @@ -697,7 +702,7 @@ void ex_breaklist(exarg_T *eap) for (int i = 0; i < dbg_breakp.ga_len; i++) { struct debuggy *bp = &BREAKP(i); if (bp->dbg_type == DBG_FILE) { - home_replace(NULL, (char *)bp->dbg_name, (char *)NameBuff, MAXPATHL, true); + home_replace(NULL, bp->dbg_name, (char *)NameBuff, MAXPATHL, true); } if (bp->dbg_type != DBG_EXPR) { smsg(_("%3d %s %s line %" PRId64), @@ -718,9 +723,9 @@ void ex_breaklist(exarg_T *eap) /// @param file true for a file, false for a function /// @param fname file or function name /// @param after after this line number -linenr_T dbg_find_breakpoint(bool file, char_u *fname, linenr_T after) +linenr_T dbg_find_breakpoint(bool file, char *fname, linenr_T after) { - return debuggy_find(file, fname, after, &dbg_breakp, NULL); + return debuggy_find(file, (char_u *)fname, after, &dbg_breakp, NULL); } /// @param file true for a file, false for a function @@ -728,9 +733,9 @@ linenr_T dbg_find_breakpoint(bool file, char_u *fname, linenr_T after) /// @param fp[out] forceit /// /// @returns true if profiling is on for a function or sourced file. -bool has_profiling(bool file, char_u *fname, bool *fp) +bool has_profiling(bool file, char *fname, bool *fp) { - return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) + return debuggy_find(file, (char_u *)fname, (linenr_T)0, &prof_ga, fp) != (linenr_T)0; } @@ -825,9 +830,9 @@ static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T } /// Called when a breakpoint was encountered. -void dbg_breakpoint(char_u *name, linenr_T lnum) +void dbg_breakpoint(char *name, linenr_T lnum) { // We need to check if this line is actually executed in do_one_cmd() - debug_breakpoint_name = name; + debug_breakpoint_name = (char_u *)name; debug_breakpoint_lnum = lnum; } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index a93fb599c4..5a1708a57c 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -69,18 +69,17 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor) { if (row2 >= row1) { - if (!decor || decor->hl_id || decor_has_sign(decor) || decor->conceal) { + if (!decor || decor->hl_id || decor_has_sign(decor) || decor->conceal || decor->spell) { redraw_buf_range_later(buf, row1 + 1, row2 + 1); } } if (decor && decor_virt_pos(*decor)) { - redraw_buf_line_later(buf, row1 + 1); + redraw_buf_line_later(buf, row1 + 1, false); } if (decor && kv_size(decor->virt_lines)) { - redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, - row1 + 1 + (decor->virt_lines_above?0:1))); + redraw_buf_line_later(buf, row1 + 1 + (decor->virt_lines_above?0:1), true); } } @@ -116,6 +115,11 @@ void decor_free(Decoration *decor) } } +void decor_state_free(DecorState *state) +{ + xfree(state->active.items); +} + void clear_virttext(VirtText *text) { for (size_t i = 0; i < kv_size(*text); i++) { @@ -306,6 +310,7 @@ next_mark: bool conceal = 0; int conceal_char = 0; int conceal_attr = 0; + bool spell = false; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange item = kv_A(state->active, i); @@ -339,6 +344,9 @@ next_mark: conceal_attr = item.attr_id; } } + if (active && item.decor.spell) { + spell = true; + } if ((item.start_row == state->row && item.start_col <= col) && decor_virt_pos(item.decor) && item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) { @@ -355,6 +363,7 @@ next_mark: state->conceal = conceal; state->conceal_char = conceal_char; state->conceal_attr = conceal_attr; + state->spell = spell; return attr; } @@ -394,7 +403,7 @@ void decor_redraw_signs(buf_T *buf, int row, int *num_signs, SignTextAttrs sattr } if (j < SIGN_SHOW_MAX) { sattrs[j] = (SignTextAttrs) { - .text = decor->sign_text, + .text = (char *)decor->sign_text, .hl_attr_id = decor->sign_hl_id == 0 ? 0 : syn_id2attr(decor->sign_hl_id), .priority = decor->priority }; @@ -547,7 +556,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) } int virt_lines = 0; - int row = (int)MAX(lnum - 2, 0); + int row = MAX(lnum - 2, 0); int end_row = (int)lnum; MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, row, 0, itr); @@ -558,7 +567,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) } else if (marktree_decor_level(mark) < kDecorLevelVirtLine) { goto next_mark; } - bool above = mark.pos.row > (int)(lnum - 2); + bool above = mark.pos.row > (lnum - 2); Decoration *decor = mark.decor_full; if (decor && decor->virt_lines_above == above) { virt_lines += (int)kv_size(decor->virt_lines); diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 8f28442d41..bdbfd72a81 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -46,6 +46,7 @@ struct Decoration { bool hl_eol; bool virt_lines_above; bool conceal; + bool spell; // TODO(bfredl): style, etc DecorPriority priority; int col; // fixed col value, like win_col @@ -61,8 +62,8 @@ struct Decoration { bool ui_watched; // watched for win_extmark }; #define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, \ - kHlModeUnknown, false, false, false, false, DECOR_PRIORITY_BASE, \ - 0, 0, NULL, 0, 0, 0, 0, 0, false } + kHlModeUnknown, false, false, false, false, false, \ + DECOR_PRIORITY_BASE, 0, 0, NULL, 0, 0, 0, 0, 0, false } typedef struct { int start_row; @@ -90,6 +91,8 @@ typedef struct { bool conceal; int conceal_char; int conceal_attr; + + bool spell; } DecorState; EXTERN DecorState decor_state INIT(= { 0 }); diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c index 14c1238fa4..48664421a3 100644 --- a/src/nvim/decoration_provider.c +++ b/src/nvim/decoration_provider.c @@ -1,6 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "klib/kvec.h" #include "nvim/api/extmark.h" #include "nvim/api/private/helpers.h" #include "nvim/buffer.h" @@ -14,7 +15,7 @@ static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE; #define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \ { ns_id, false, LUA_NOREF, LUA_NOREF, \ LUA_NOREF, LUA_NOREF, LUA_NOREF, \ - LUA_NOREF, -1, false } + LUA_NOREF, -1, false, false } static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args, bool default_true, char **perr) @@ -47,11 +48,33 @@ static bool decor_provider_invoke(NS ns_id, const char *name, LuaRef ref, Array return false; } +void decor_providers_invoke_spell(win_T *wp, int start_row, int start_col, int end_row, int end_col, + char **err) +{ + for (size_t i = 0; i < kv_size(decor_providers); i++) { + DecorProvider *p = &kv_A(decor_providers, i); + if (!p->active) { + continue; + } + + if (p->spell_nav != LUA_NOREF) { + MAXSIZE_TEMP_ARRAY(args, 6); + ADD_C(args, INTEGER_OBJ(wp->handle)); + ADD_C(args, INTEGER_OBJ(wp->w_buffer->handle)); + ADD_C(args, INTEGER_OBJ(start_row)); + ADD_C(args, INTEGER_OBJ(start_col)); + ADD_C(args, INTEGER_OBJ(end_row)); + ADD_C(args, INTEGER_OBJ(end_col)); + decor_provider_invoke(p->ns_id, "spell", p->spell_nav, args, true, err); + } + } +} + /// For each provider invoke the 'start' callback /// /// @param[out] providers Decoration providers /// @param[out] err Provider err -void decor_providers_start(DecorProviders *providers, int type, char **err) +void decor_providers_start(DecorProviders *providers, char **err) { kvi_init(*providers); @@ -65,7 +88,6 @@ void decor_providers_start(DecorProviders *providers, int type, char **err) if (p->redraw_start != LUA_NOREF) { 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; @@ -116,8 +138,8 @@ void decor_providers_invoke_win(win_T *wp, DecorProviders *providers, /// @param row Row to invoke line callback for /// @param[out] has_decor Set when at least one provider invokes a line callback /// @param[out] err Provider error -void providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *has_decor, - char **err) +void decor_providers_invoke_line(win_T *wp, DecorProviders *providers, int row, bool *has_decor, + char **err) { for (size_t k = 0; k < kv_size(*providers); k++) { DecorProvider *p = kv_A(*providers, k); @@ -215,6 +237,7 @@ void decor_provider_clear(DecorProvider *p) NLUA_CLEAR_REF(p->redraw_win); NLUA_CLEAR_REF(p->redraw_line); NLUA_CLEAR_REF(p->redraw_end); + NLUA_CLEAR_REF(p->spell_nav); p->active = false; } diff --git a/src/nvim/decoration_provider.h b/src/nvim/decoration_provider.h index dd1ed6c581..852b1583b9 100644 --- a/src/nvim/decoration_provider.h +++ b/src/nvim/decoration_provider.h @@ -12,6 +12,7 @@ typedef struct { LuaRef redraw_line; LuaRef redraw_end; LuaRef hl_def; + LuaRef spell_nav; int hl_valid; bool hl_cached; } DecorProvider; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 5485d528f7..9446d35630 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -120,7 +120,7 @@ void diff_buf_delete(buf_T *buf) // don't redraw right away, more might change or buffer state // is invalid right now need_diff_redraw = true; - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } } } @@ -573,9 +573,9 @@ static void diff_check_unchanged(tabpage_T *tp, diff_T *dp) if (dir == BACKWARD) { off_org = dp->df_count[i_org] - 1; } - char_u *line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org], - dp->df_lnum[i_org] + off_org, - false)); + char *line_org = xstrdup(ml_get_buf(tp->tp_diffbuf[i_org], + dp->df_lnum[i_org] + off_org, + false)); int i_new; for (i_new = i_org + 1; i_new < DB_COUNT; i_new++) { @@ -659,7 +659,7 @@ void diff_redraw(bool dofold) continue; } - redraw_later(wp, SOME_VALID); + redraw_later(wp, UPD_SOME_VALID); if (wp != curwin) { wp_other = wp; } @@ -729,7 +729,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) // xdiff requires one big block of memory with all the text. for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { - len += (long)STRLEN(ml_get_buf(buf, lnum, false)) + 1; + len += (long)strlen(ml_get_buf(buf, lnum, false)) + 1; } char_u *ptr = try_malloc((size_t)len); if (ptr == NULL) { @@ -750,7 +750,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) len = 0; for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { - for (char_u *s = ml_get_buf(buf, lnum, false); *s != NUL;) { + for (char_u *s = (char_u *)ml_get_buf(buf, lnum, false); *s != NUL;) { if (diff_flags & DIFF_ICASE) { int c; char cbuf[MB_MAXBYTES + 1]; @@ -797,8 +797,8 @@ static int diff_write(buf_T *buf, diffin_T *din) } // Always use 'fileformat' set to "unix". - char_u *save_ff = buf->b_p_ff; - buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); + char *save_ff = buf->b_p_ff; + buf->b_p_ff = xstrdup(FF_UNIX); const bool save_cmod_flags = cmdmod.cmod_flags; // Writing the buffer is an implementation detail of performing the diff, // so it shouldn't update the '[ and '] marks. @@ -824,9 +824,9 @@ static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap) ga_init(&dio->dio_diff.dout_ga, sizeof(char *), 1000); } else { // We need three temp file names. - dio->dio_orig.din_fname = vim_tempname(); - dio->dio_new.din_fname = vim_tempname(); - dio->dio_diff.dout_fname = vim_tempname(); + dio->dio_orig.din_fname = (char_u *)vim_tempname(); + dio->dio_new.din_fname = (char_u *)vim_tempname(); + dio->dio_diff.dout_fname = (char_u *)vim_tempname(); if (dio->dio_orig.din_fname == NULL || dio->dio_new.din_fname == NULL || dio->dio_diff.dout_fname == NULL) { @@ -1128,7 +1128,7 @@ static int diff_file(diffio_T *dio) return diff_file_internal(dio); } else { const size_t len = (strlen(tmp_orig) + strlen(tmp_new) + strlen(tmp_diff) - + STRLEN(p_srr) + 27); + + strlen(p_srr) + 27); char *const cmd = xmalloc(len); // We don't want $DIFF_OPTIONS to get in the way. @@ -1148,7 +1148,7 @@ static int diff_file(diffio_T *dio) (diff_flags & DIFF_IBLANK) ? "-B " : "", (diff_flags & DIFF_ICASE) ? "-i " : "", tmp_orig, tmp_new); - append_redir(cmd, len, (char *)p_srr, tmp_diff); + append_redir(cmd, len, p_srr, tmp_diff); block_autocmds(); // Avoid ShellCmdPost stuff (void)call_shell((char_u *)cmd, kShellOptFilter | kShellOptSilent | kShellOptDoOut, @@ -1178,9 +1178,9 @@ void ex_diffpatch(exarg_T *eap) // We need two temp file names. // Name of original temp file. - char_u *tmp_orig = vim_tempname(); + char_u *tmp_orig = (char_u *)vim_tempname(); // Name of patched temp file. - char_u *tmp_new = vim_tempname(); + char_u *tmp_new = (char_u *)vim_tempname(); if ((tmp_orig == NULL) || (tmp_new == NULL)) { goto theend; @@ -1267,7 +1267,7 @@ void ex_diffpatch(exarg_T *eap) emsg(_("E816: Cannot read patch output")); } else { if (curbuf->b_fname != NULL) { - newname = xstrnsave(curbuf->b_fname, STRLEN(curbuf->b_fname) + 4); + newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4); STRCAT(newname, ".new"); } @@ -1374,7 +1374,7 @@ static void set_diff_option(win_T *wp, int value) curwin = wp; curbuf = curwin->w_buffer; curbuf->b_ro_locked++; - set_option_value("diff", (long)value, NULL, OPT_LOCAL); + set_option_value_give_err("diff", (long)value, NULL, OPT_LOCAL); curbuf->b_ro_locked--; curwin = old_curwin; curbuf = curwin->w_buffer; @@ -1413,7 +1413,7 @@ void diff_win_options(win_T *wp, int addbuf) if (wp->w_p_diff_saved) { free_string_option(wp->w_p_fdm_save); } - wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm); + wp->w_p_fdm_save = xstrdup(wp->w_p_fdm); } set_string_option_direct_in_win(wp, "fdm", -1, "diff", OPT_LOCAL | OPT_FREE, 0); @@ -1424,12 +1424,12 @@ void diff_win_options(win_T *wp, int addbuf) if (wp->w_p_diff_saved) { free_string_option(wp->w_p_fdc_save); } - wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc); + wp->w_p_fdc_save = xstrdup(wp->w_p_fdc); } free_string_option(wp->w_p_fdc); - wp->w_p_fdc = (char_u *)xstrdup("2"); + wp->w_p_fdc = xstrdup("2"); assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9); - snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn); + snprintf(wp->w_p_fdc, strlen(wp->w_p_fdc) + 1, "%d", diff_foldcolumn); wp->w_p_fen = true; wp->w_p_fdl = 0; foldUpdateAll(wp); @@ -1448,7 +1448,7 @@ void diff_win_options(win_T *wp, int addbuf) if (addbuf) { diff_buf_add(wp->w_buffer); } - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } /// Set options not to show diffs. For the current window or all windows. @@ -1480,11 +1480,9 @@ void ex_diffoff(exarg_T *eap) } } free_string_option(wp->w_p_fdm); - wp->w_p_fdm = vim_strsave(*wp->w_p_fdm_save - ? wp->w_p_fdm_save - : (char_u *)"manual"); + wp->w_p_fdm = xstrdup(*wp->w_p_fdm_save ? wp->w_p_fdm_save : "manual"); free_string_option(wp->w_p_fdc); - wp->w_p_fdc = vim_strsave(wp->w_p_fdc_save); + wp->w_p_fdc = xstrdup(wp->w_p_fdc_save); if (wp->w_p_fdl == 0) { wp->w_p_fdl = wp->w_p_fdl_save; @@ -1541,8 +1539,8 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio) diff_T *dp = curtab->tp_first_diff; diff_T *dn, *dpl; diffout_T *dout = &dio->dio_diff; - char_u linebuf[LBUFLEN]; // only need to hold the diff line - char_u *line; + char linebuf[LBUFLEN]; // only need to hold the diff line + char *line; linenr_T off; int i; int notset = true; // block "*dp" not set yet @@ -1578,9 +1576,9 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio) if (line_idx >= dout->dout_ga.ga_len) { break; // did last line } - line = ((char_u **)dout->dout_ga.ga_data)[line_idx++]; + line = ((char **)dout->dout_ga.ga_data)[line_idx++]; } else { - if (vim_fgets(linebuf, LBUFLEN, fd)) { + if (vim_fgets((char_u *)linebuf, LBUFLEN, fd)) { break; // end of file } line = linebuf; @@ -1602,9 +1600,9 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio) } else if ((STRNCMP(line, "@@ ", 3) == 0)) { diffstyle = DIFF_UNIFIED; } else if ((STRNCMP(line, "--- ", 4) == 0) // -V501 - && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 + && (vim_fgets((char_u *)linebuf, LBUFLEN, fd) == 0) // -V501 && (STRNCMP(line, "+++ ", 4) == 0) - && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501 + && (vim_fgets((char_u *)linebuf, LBUFLEN, fd) == 0) // -V501 && (STRNCMP(line, "@@ ", 3) == 0)) { diffstyle = DIFF_UNIFIED; } else { @@ -1618,7 +1616,7 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio) if (!isdigit(*line)) { continue; // not the start of a diff block } - if (parse_diff_ed(line, hunk) == FAIL) { + if (parse_diff_ed((char_u *)line, hunk) == FAIL) { continue; } } else { @@ -1626,7 +1624,7 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio) if (STRNCMP(line, "@@ ", 3) != 0) { continue; // not the start of a diff block } - if (parse_diff_unified(line, hunk) == FAIL) { + if (parse_diff_unified((char_u *)line, hunk) == FAIL) { continue; } } @@ -1922,8 +1920,8 @@ static bool diff_equal_entry(diff_T *dp, int idx1, int idx2) } for (int i = 0; i < dp->df_count[idx1]; i++) { - char_u *line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1], - dp->df_lnum[idx1] + i, false)); + char *line = xstrdup(ml_get_buf(curtab->tp_diffbuf[idx1], + dp->df_lnum[idx1] + i, false)); int cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2], dp->df_lnum[idx2] + i, false)); @@ -1970,23 +1968,23 @@ static bool diff_equal_char(const char_u *const p1, const char_u *const p2, int /// @param s2 The second string /// /// @return on-zero if the two strings are different. -static int diff_cmp(char_u *s1, char_u *s2) +static int diff_cmp(char *s1, char *s2) { if ((diff_flags & DIFF_IBLANK) - && (*(char_u *)skipwhite((char *)s1) == NUL || *skipwhite((char *)s2) == NUL)) { + && (*(char_u *)skipwhite(s1) == NUL || *skipwhite(s2) == NUL)) { return 0; } if ((diff_flags & (DIFF_ICASE | ALL_WHITE_DIFF)) == 0) { - return STRCMP(s1, s2); + return strcmp(s1, s2); } if ((diff_flags & DIFF_ICASE) && !(diff_flags & ALL_WHITE_DIFF)) { return mb_stricmp((const char *)s1, (const char *)s2); } - char *p1 = (char *)s1; - char *p2 = (char *)s2; + char *p1 = s1; + char *p2 = s2; // Ignore white space changes and possibly ignore case. while (*p1 != NUL && *p2 != NUL) { @@ -2141,7 +2139,7 @@ int diffopt_changed(void) long diff_algorithm_new = 0; long diff_indent_heuristic = 0; - char *p = (char *)p_dip; + char *p = p_dip; while (*p != NUL) { if (STRNCMP(p, "filler", 6) == 0) { p += 6; @@ -2283,7 +2281,7 @@ bool diffopt_filler(void) bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - char_u *line_new; + char *line_new; int si_org; int si_new; int ei_org; @@ -2292,7 +2290,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) int l; // Make a copy of the line, the next ml_get() will invalidate it. - char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, false)); + char *line_org = xstrdup(ml_get_buf(wp->w_buffer, lnum, false)); int idx = diff_buf_idx(wp->w_buffer); if (idx == DB_COUNT) { @@ -2324,8 +2322,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) continue; } added = false; - line_new = ml_get_buf(curtab->tp_diffbuf[i], - dp->df_lnum[i] + off, false); + line_new = ml_get_buf(curtab->tp_diffbuf[i], dp->df_lnum[i] + off, false); // Search for start of difference si_org = si_new = 0; @@ -2337,10 +2334,10 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) || ((diff_flags & DIFF_IWHITEALL) && (ascii_iswhite(line_org[si_org]) || ascii_iswhite(line_new[si_new])))) { - si_org = (int)((char_u *)skipwhite((char *)line_org + si_org) - line_org); - si_new = (int)((char_u *)skipwhite((char *)line_new + si_new) - line_new); + si_org = (int)(skipwhite(line_org + si_org) - line_org); + si_new = (int)(skipwhite(line_new + si_new) - line_new); } else { - if (!diff_equal_char(line_org + si_org, line_new + si_new, &l)) { + if (!diff_equal_char((char_u *)line_org + si_org, (char_u *)line_new + si_new, &l)) { break; } si_org += l; @@ -2359,8 +2356,8 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) // Search for end of difference, if any. if ((line_org[si_org] != NUL) || (line_new[si_new] != NUL)) { - ei_org = (int)STRLEN(line_org); - ei_new = (int)STRLEN(line_new); + ei_org = (int)strlen(line_org); + ei_new = (int)strlen(line_new); while (ei_org >= *startp && ei_new >= si_new @@ -2380,11 +2377,11 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) ei_new--; } } else { - const char_u *p1 = line_org + ei_org; - const char_u *p2 = line_new + ei_new; + const char_u *p1 = (char_u *)line_org + ei_org; + const char_u *p2 = (char_u *)line_new + ei_new; - p1 -= utf_head_off(line_org, p1); - p2 -= utf_head_off(line_new, p2); + p1 -= utf_head_off(line_org, (char *)p1); + p2 -= utf_head_off(line_new, (char *)p2); if (!diff_equal_char(p1, p2, &l)) { break; @@ -2513,7 +2510,7 @@ void ex_diffgetput(exarg_T *eap) diff_T *dfree; int i; int added; - char_u *p; + char *p; aco_save_T aco; buf_T *buf; linenr_T start_skip; @@ -2567,18 +2564,18 @@ void ex_diffgetput(exarg_T *eap) } } else { // Buffer number or pattern given. Ignore trailing white space. - p = (char_u *)eap->arg + STRLEN(eap->arg); - while (p > (char_u *)eap->arg && ascii_iswhite(p[-1])) { + p = eap->arg + strlen(eap->arg); + while (p > eap->arg && ascii_iswhite(p[-1])) { p--; } - for (i = 0; ascii_isdigit(eap->arg[i]) && (char_u *)eap->arg + i < p; i++) {} + for (i = 0; ascii_isdigit(eap->arg[i]) && eap->arg + i < p; i++) {} - if ((char_u *)eap->arg + i == p) { + if (eap->arg + i == p) { // digits only i = (int)atol(eap->arg); } else { - i = buflist_findpat(eap->arg, (char *)p, false, true, false); + i = buflist_findpat(eap->arg, p, false, true, false); if (i < 0) { // error message already given @@ -2720,8 +2717,8 @@ void ex_diffgetput(exarg_T *eap) if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count) { break; } - p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from], nr, false)); - ml_append(lnum + i - 1, (char *)p, 0, false); + p = xstrdup(ml_get_buf(curtab->tp_diffbuf[idx_from], nr, false)); + ml_append(lnum + i - 1, p, 0, false); xfree(p); added++; if (buf_empty && (curbuf->b_ml.ml_line_count == 2)) { diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 0f511bd37c..1267d49ad1 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1578,7 +1578,7 @@ static int getexactdigraph(int char1, int char2, bool meta_char) if (retval == 0) { dp = digraphdefault; - for (int i = 0; dp->char1 != 0; i++) { + while (dp->char1 != 0) { if (((int)dp->char1 == char1) && ((int)dp->char2 == char2)) { retval = dp->result; break; @@ -1695,7 +1695,7 @@ static void digraph_header(const char *msg) if (msg_col > 0) { msg_putchar('\n'); } - msg_outtrans_attr((const char_u *)msg, HL_ATTR(HLF_CM)); + msg_outtrans_attr(msg, HL_ATTR(HLF_CM)); msg_putchar('\n'); } @@ -1707,7 +1707,7 @@ void listdigraphs(bool use_headers) const digr_T *dp = digraphdefault; - for (int i = 0; dp->char1 != NUL && !got_int; i++) { + while (dp->char1 != NUL && !got_int) { digr_T tmp; // May need to convert the result to 'encoding'. @@ -1759,7 +1759,7 @@ void digraph_getlist_common(bool list_all, typval_T *rettv) if (list_all) { dp = digraphdefault; - for (int i = 0; dp->char1 != NUL && !got_int; i++) { + while (dp->char1 != NUL && !got_int) { digr_T tmp; tmp.char1 = dp->char1; tmp.char2 = dp->char2; @@ -1856,7 +1856,7 @@ static void printdigraph(const digr_T *dp, result_T *previous) p += utf_char2bytes(dp->result, (char *)p); *p = NUL; - msg_outtrans_attr(buf, HL_ATTR(HLF_8)); + msg_outtrans_attr((char *)buf, HL_ATTR(HLF_8)); p = buf; if (char2cells(dp->result) == 1) { *p++ = ' '; @@ -1917,7 +1917,7 @@ static bool digraph_set_common(const typval_T *argchars, const typval_T *argdigr } /// "digraph_get()" function -void f_digraph_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_digraph_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; // Return empty string for failure @@ -1926,19 +1926,19 @@ void f_digraph_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (digraphs == NULL) { return; } - if (STRLEN(digraphs) != 2) { + if (strlen(digraphs) != 2) { semsg(_(e_digraph_must_be_just_two_characters_str), digraphs); return; } int code = digraph_get(digraphs[0], digraphs[1], false); - char_u buf[NUMBUFLEN]; - buf[utf_char2bytes(code, (char *)buf)] = NUL; - rettv->vval.v_string = (char *)vim_strsave(buf); + char buf[NUMBUFLEN]; + buf[utf_char2bytes(code, buf)] = NUL; + rettv->vval.v_string = xstrdup(buf); } /// "digraph_getlist()" function -void f_digraph_getlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_digraph_getlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool flag_list_all; @@ -1957,7 +1957,7 @@ void f_digraph_getlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "digraph_set()" function -void f_digraph_set(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_digraph_set(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_BOOL; rettv->vval.v_bool = kBoolVarFalse; @@ -1970,7 +1970,7 @@ void f_digraph_set(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "digraph_setlist()" function -void f_digraph_setlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_digraph_setlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_BOOL; rettv->vval.v_bool = kBoolVarFalse; @@ -2010,8 +2010,8 @@ void f_digraph_setlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// structure used for b_kmap_ga.ga_data typedef struct { - char_u *from; - char_u *to; + char *from; + char *to; } kmap_T; #define KMAP_MAXLEN 20 // maximum length of "from" or "to" @@ -2036,7 +2036,7 @@ char *keymap_init(void) // Source the keymap file. It will contain a ":loadkeymap" command // which will call ex_loadkeymap() below. - buflen = STRLEN(curbuf->b_p_keymap) + STRLEN(p_enc) + 14; + buflen = strlen(curbuf->b_p_keymap) + strlen(p_enc) + 14; buf = xmalloc(buflen); // try finding "keymap/'keymap'_'encoding'.vim" in 'runtimepath' @@ -2064,10 +2064,10 @@ char *keymap_init(void) /// @param eap void ex_loadkeymap(exarg_T *eap) { - char_u *s; + char *s; #define KMAP_LLEN 200 // max length of "to" and "from" together - char_u buf[KMAP_LLEN + 11]; + char buf[KMAP_LLEN + 11]; char *save_cpo = p_cpo; if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { @@ -2092,17 +2092,17 @@ void ex_loadkeymap(exarg_T *eap) break; } - char_u *p = (char_u *)skipwhite(line); + char *p = skipwhite(line); if ((*p != '"') && (*p != NUL)) { kmap_T *kp = GA_APPEND_VIA_PTR(kmap_T, &curbuf->b_kmap_ga); s = skiptowhite(p); - kp->from = vim_strnsave(p, (size_t)(s - p)); - p = (char_u *)skipwhite((char *)s); + kp->from = xstrnsave(p, (size_t)(s - p)); + p = skipwhite(s); s = skiptowhite(p); - kp->to = vim_strnsave(p, (size_t)(s - p)); + kp->to = xstrnsave(p, (size_t)(s - p)); - if ((STRLEN(kp->from) + STRLEN(kp->to) >= KMAP_LLEN) + if ((strlen(kp->from) + strlen(kp->to) >= KMAP_LLEN) || (*kp->from == NUL) || (*kp->to == NUL)) { if (*kp->to == NUL) { @@ -2118,10 +2118,10 @@ void ex_loadkeymap(exarg_T *eap) // setup ":lmap" to map the keys for (int i = 0; i < curbuf->b_kmap_ga.ga_len; i++) { - vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s", + vim_snprintf(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(MAPTYPE_MAP, buf, MODE_LANGMAP, false); + (void)do_map(MAPTYPE_MAP, (char_u *)buf, MODE_LANGMAP, false); } p_cpo = save_cpo; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 2b1b2607fb..10e1d95730 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -11,9 +11,11 @@ #include "nvim/arabic.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/cursor_shape.h" +#include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/drawline.h" #include "nvim/fold.h" @@ -116,7 +118,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b if (cells > maxcells) { return -1; } - u8c = utfc_ptr2char(p, u8cc); + u8c = utfc_ptr2char((char *)p, u8cc); if (*p == TAB) { cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells); for (int c = 0; c < cells; c++) { @@ -141,7 +143,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b nc = utf_ptr2char((char *)p + c_len); s->prev_c1 = u8cc[0]; } else { - pc = utfc_ptr2char(p + c_len, pcc); + pc = utfc_ptr2char((char *)p + c_len, pcc); nc = s->prev_c; pc1 = pcc[0]; } @@ -277,7 +279,7 @@ static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) } // Get information needed to display the sign in line 'lnum' in window 'wp'. -// If 'nrcol' is TRUE, the sign is going to be displayed in the number column. +// If 'nrcol' is true, the sign is going to be displayed in the number column. // Otherwise the sign is going to be displayed in the sign column. // // @param count max number of signs @@ -306,7 +308,7 @@ static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, SignText if (row == startrow + filler_lines && filler_todo <= 0) { SignTextAttrs *sattr = sign_get_attr(sign_idx, sattrs, wp->w_scwidth); if (sattr != NULL) { - *pp_extra = sattr->text; + *pp_extra = (char_u *)sattr->text; if (*pp_extra != NULL) { *c_extrap = NUL; *c_finalp = NUL; @@ -654,7 +656,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, has_decor = decor_redraw_line(buf, lnum - 1, &decor_state); - providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err); + decor_providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err); if (*provider_err) { provider_err_virt_text(lnum, *provider_err); @@ -687,7 +689,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Trick: skip a few chars for C/shell/Vim comments nextline[SPWORDLEN] = NUL; if (lnum < wp->w_buffer->b_ml.ml_line_count) { - line = ml_get_buf(wp->w_buffer, lnum + 1, false); + line = (char_u *)ml_get_buf(wp->w_buffer, lnum + 1, false); spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); } @@ -864,13 +866,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, line_attr_lowprio_save = line_attr_lowprio; } - line = end_fill ? (char_u *)"" : ml_get_buf(wp->w_buffer, lnum, false); + line = end_fill ? (char_u *)"" : (char_u *)ml_get_buf(wp->w_buffer, lnum, false); ptr = line; if (has_spell && !number_only) { // For checking first word with a capital skip white space. if (cap_col == 0) { - cap_col = (int)getwhitecols(line); + cap_col = (int)getwhitecols((char *)line); } // To be able to spell-check over line boundaries copy the end of the @@ -892,7 +894,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } else { // Long line, use only the last SPWORDLEN bytes. nextlinecol = (int)v - SPWORDLEN; - memmove(nextline, line + nextlinecol, SPWORDLEN); // -V512 + memmove(nextline, line + nextlinecol, SPWORDLEN); // -V1086 nextline_idx = SPWORDLEN + 1; } } @@ -940,12 +942,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (v > 0 && !number_only) { char_u *prev_ptr = ptr; - while (vcol < v && *ptr != NUL) { - c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); - vcol += c; - prev_ptr = ptr; - MB_PTR_ADV(ptr); + chartabsize_T cts; + int charsize; + + init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, (char *)line, (char *)ptr); + while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { + charsize = win_lbr_chartabsize(&cts, NULL); + cts.cts_vcol += charsize; + prev_ptr = (char_u *)cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); } + vcol = cts.cts_vcol; + ptr = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // When: // - 'cuc' is set, or @@ -963,11 +972,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Handle a character that's not completely on the screen: Put ptr at // that character but skip the first few screen characters. if (vcol > v) { - vcol -= c; + vcol -= charsize; ptr = prev_ptr; // 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) { + if (utf_ptr2cells((char *)ptr) >= charsize || *ptr == TAB) { n_skip = (int)(v - vcol); } } @@ -997,7 +1006,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, len = spell_move_to(wp, FORWARD, true, true, &spell_hlf); // spell_move_to() may call ml_get() and make "line" invalid - line = ml_get_buf(wp->w_buffer, lnum, false); + line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); ptr = line + linecol; if (len == 0 || (int)wp->w_cursor.col > ptr - line) { @@ -1164,7 +1173,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_rl) { // reverse line numbers // like rl_mirror(), but keep the space at the end char_u *p2 = (char_u *)skipwhite((char *)extra); - p2 = skiptowhite(p2) - 1; + p2 = (char_u *)skiptowhite((char *)p2) - 1; for (char_u *p1 = (char_u *)skipwhite((char *)extra); p1 < p2; p1++, p2--) { const char_u t = *p1; *p1 = *p2; @@ -1215,7 +1224,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, c_extra = ' '; c_final = NUL; n_extra = - get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, false)); + get_breakindent_win(wp, (char_u *)ml_get_buf(wp->w_buffer, lnum, false)); if (row == startrow) { n_extra -= win_col_off2(wp); if (n_extra < 0) { @@ -1247,7 +1256,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } char_attr = 0; } else if (filler_todo > 0) { - // draw "deleted" diff line(s) + // Draw "deleted" diff line(s) if (char2cells(wp->w_p_fcs_chars.diff) > 1) { c_extra = '-'; c_final = NUL; @@ -1342,7 +1351,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, linenr_T lnume = lnum + foldinfo.fi_lines - 1; memset(buf_fold, ' ', FOLD_TEXT_LEN); - p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); + p_extra = (char_u *)get_foldtext(wp, lnum, lnume, foldinfo, (char *)buf_fold); n_extra = (int)STRLEN(p_extra); if (p_extra != buf_fold) { @@ -1482,7 +1491,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (mb_l > n_extra) { mb_l = 1; } else if (mb_l > 1) { - mb_c = utfc_ptr2char(p_extra, u8cc); + mb_c = utfc_ptr2char((char *)p_extra, u8cc); mb_utf8 = true; c = 0xc0; } @@ -1533,7 +1542,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, mb_l = utfc_ptr2len((char *)ptr); mb_utf8 = false; if (mb_l > 1) { - mb_c = utfc_ptr2char(ptr, u8cc); + mb_c = utfc_ptr2char((char *)ptr, u8cc); // Overlong encoded ASCII or ASCII with composing char // is displayed normally, except a NUL. if (mb_c < 0x80) { @@ -1591,7 +1600,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, nc = utf_ptr2char((char *)ptr + mb_l); prev_c1 = u8cc[0]; } else { - pc = utfc_ptr2char(ptr + mb_l, pcc); + pc = utfc_ptr2char((char *)ptr + mb_l, pcc); nc = prev_c; pc1 = pcc[0]; } @@ -1639,7 +1648,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ptr++; if (extra_check) { - bool can_spell = true; + bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0; + bool can_spell = !no_plain_buffer; // Get syntax attribute, unless still at the start of the line // (double-wide char that doesn't fit). @@ -1666,7 +1676,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Need to get the line again, a multi-line regexp may // have made it invalid. - line = ml_get_buf(wp->w_buffer, lnum, false); + line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); ptr = line + v; if (!attr_pri) { @@ -1691,6 +1701,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char_attr = 0; } + if (has_decor && v > 0) { + bool selected = (area_active || (area_highlighting && noinvcur + && (colnr_T)vcol == wp->w_virtcol)); + int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, + selected, &decor_state); + if (extmark_attr != 0) { + if (!attr_pri) { + char_attr = hl_combine_attr(char_attr, extmark_attr); + } else { + char_attr = hl_combine_attr(extmark_attr, char_attr); + } + } + + decor_conceal = decor_state.conceal; + if (decor_conceal && decor_state.conceal_char) { + decor_conceal = 2; // really?? + } + + if (decor_state.spell) { + can_spell = true; + } + } + // Check spelling (unless at the end of the line). // Only do this when there is no syntax highlighting, the // @Spell cluster is not used or the current syntax item @@ -1699,9 +1732,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; if (!attr_pri) { - char_attr = syntax_attr; + char_attr = hl_combine_attr(char_attr, syntax_attr); } - if (c != 0 && (!has_syntax || can_spell)) { + if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) { char_u *prev_ptr; char_u *p; int len; @@ -1774,32 +1807,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char_attr = hl_combine_attr(term_attrs[vcol], char_attr); } - if (has_decor && v > 0) { - bool selected = (area_active || (area_highlighting && noinvcur - && (colnr_T)vcol == wp->w_virtcol)); - int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, - selected, &decor_state); - if (extmark_attr != 0) { - if (!attr_pri) { - char_attr = hl_combine_attr(char_attr, extmark_attr); - } else { - char_attr = hl_combine_attr(extmark_attr, char_attr); - } - } - - decor_conceal = decor_state.conceal; - if (decor_conceal && decor_state.conceal_char) { - decor_conceal = 2; // really?? - } - } - // Found last space before word: check for line break. if (wp->w_p_lbr && c0 == c && vim_isbreak(c) && !vim_isbreak((int)(*ptr))) { - int mb_off = utf_head_off(line, ptr - 1); + int mb_off = utf_head_off((char *)line, (char *)ptr - 1); char_u *p = ptr - (mb_off + 1); - // TODO(neovim): is passing p for start of the line OK? - n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1; + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, (char *)line, (char *)p); + n_extra = win_lbr_chartabsize(&cts, NULL) - 1; // We have just drawn the showbreak value, no need to add // space for it again. @@ -1825,6 +1841,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, c = ' '; } } + clear_chartabsize_arg(&cts); } in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' '); @@ -2082,7 +2099,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_cole > 0 && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp)) && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0 || decor_conceal > 0) - && !(lnum_in_visual_area && vim_strchr((char *)wp->w_p_cocu, 'v') == NULL)) { + && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { char_attr = conceal_attr; if (((prev_syntax_id != syntax_seqnr && (syntax_flags & HL_CONCEAL) != 0) || has_match_conc > 1 || decor_conceal > 1) @@ -2590,7 +2607,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, 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, - kHlModeReplace, grid->cols, offset); + kHlModeReplace, grid->cols, 0); } } else { draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row); @@ -2621,6 +2638,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // When the window is too narrow draw all "@" lines. if (draw_state != WL_LINE && filler_todo <= 0) { win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT); + set_empty_rows(wp, row); row = endrow; } diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index a451048275..2fbfd7080f 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -20,7 +20,7 @@ // // Commands that scroll a window change w_topline and must call // check_cursor() to move the cursor into the visible part of the window, and -// call redraw_later(wp, VALID) to have the window displayed by update_screen() +// call redraw_later(wp, UPD_VALID) to have the window displayed by update_screen() // later. // // Commands that change text in the buffer must call changed_bytes() or @@ -32,23 +32,23 @@ // // Commands that change how a window is displayed (e.g., setting 'list') or // invalidate the contents of a window in another way (e.g., change fold -// settings), must call redraw_later(wp, NOT_VALID) to have the whole window +// settings), must call redraw_later(wp, UPD_NOT_VALID) to have the whole window // redisplayed by update_screen() later. // // Commands that change how a buffer is displayed (e.g., setting 'tabstop') -// must call redraw_curbuf_later(NOT_VALID) to have all the windows for the +// must call redraw_curbuf_later(UPD_NOT_VALID) to have all the windows for the // buffer redisplayed by update_screen() later. // // Commands that change highlighting and possibly cause a scroll too must call -// redraw_later(wp, SOME_VALID) to update the whole window but still use +// redraw_later(wp, UPD_SOME_VALID) to update the whole window but still use // scrolling to avoid redrawing everything. But the length of displayed lines -// must not change, use NOT_VALID then. +// must not change, use UPD_NOT_VALID then. // -// Commands that move the window position must call redraw_later(wp, NOT_VALID). +// Commands that move the window position must call redraw_later(wp, UPD_NOT_VALID). // TODO(neovim): should minimize redrawing by scrolling when possible. // // Commands that change everything (e.g., resizing the screen) must call -// redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). +// redraw_all_later(UPD_NOT_VALID) or redraw_all_later(UPD_CLEAR). // // Things that are handled indirectly: // - When messages scroll the screen up, msg_scrolled will be set and @@ -97,7 +97,7 @@ typedef enum { static bool redraw_popupmenu = false; static bool msg_grid_invalid = false; -static bool resizing = false; +static bool resizing_autocmd = false; static char *provider_err = NULL; @@ -115,7 +115,7 @@ void conceal_check_cursor_line(void) } } -/// Resize the screen to Rows and Columns. +/// Resize default_grid to Rows and Columns. /// /// Allocate default_grid.chars[] and other grid arrays. /// @@ -125,19 +125,18 @@ void conceal_check_cursor_line(void) /// default_grid.Columns to access items in default_grid.chars[]. Use Rows /// and Columns for positioning text etc. where the final size of the screen is /// needed. -void screenalloc(void) +bool default_grid_alloc(void) { + static bool resizing = false; + // It's possible that we produce an out-of-memory message below, which // will cause this function to be called again. To break the loop, just // return here. if (resizing) { - return; + return false; } resizing = true; - int retry_count = 0; - -retry: // Allocation of the screen buffers is done only when the size changes and // when Rows and Columns have been set and we have started doing full // screen stuff. @@ -148,24 +147,9 @@ retry: || Columns == 0 || (!full_screen && default_grid.chars == NULL)) { resizing = false; - return; - } - - // Note that the window sizes are updated before reallocating the arrays, - // thus we must not redraw here! - RedrawingDisabled++; - - // win_new_screensize will recompute floats position, but tell the - // compositor to not redraw them yet - ui_comp_set_screen_valid(false); - if (msg_grid.chars) { - msg_grid_invalid = true; + return false; } - win_new_screensize(); // fit the windows in the new sized screen - - comp_col(); // recompute columns for shown command and ruler - // We're changing the size of the screen. // - Allocate new arrays for default_grid // - Move lines from the old arrays into the new arrays, clear extra @@ -193,26 +177,13 @@ retry: default_grid.col_offset = 0; default_grid.handle = DEFAULT_GRID_HANDLE; - must_redraw = CLEAR; // need to clear the screen later - - RedrawingDisabled--; - - // Do not apply autocommands more than 3 times to avoid an endless loop - // in case applying autocommands always changes Rows or Columns. - if (starting == 0 && ++retry_count <= 3) { - apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); - // In rare cases, autocommands may have altered Rows or Columns, - // jump back to check if we need to allocate the screen again. - goto retry; - } - resizing = false; + return true; } void screenclear(void) { check_for_delay(false); - screenalloc(); // allocate screen buffers if size changed int i; @@ -235,18 +206,18 @@ void screenclear(void) clear_cmdline = false; mode_displayed = false; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); redraw_cmdline = true; redraw_tabline = true; redraw_popupmenu = true; pum_invalidate(); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { - wp->w_redr_type = CLEAR; + wp->w_redr_type = UPD_CLEAR; } } - if (must_redraw == CLEAR) { - must_redraw = NOT_VALID; // no need to clear again + if (must_redraw == UPD_CLEAR) { + must_redraw = UPD_NOT_VALID; // no need to clear again } compute_cmdrow(); msg_row = cmdline_row; // put cursor on last line for messages @@ -281,13 +252,6 @@ void screen_resize(int width, int height) return; } - // curwin->w_buffer can be NULL when we are closing a window and the - // buffer has already been closed and removing a scrollbar causes a resize - // event. Don't resize then, it will happen after entering another buffer. - if (curwin->w_buffer == NULL) { - return; - } - resizing_screen = true; Rows = height; @@ -301,16 +265,54 @@ void screen_resize(int width, int height) width = Columns; p_lines = Rows; p_columns = Columns; - ui_call_grid_resize(1, width, height); - /// The window layout used to be adjusted here, but it now happens in - /// screenalloc() (also invoked from screenclear()). That is because the - /// recursize "resizing_screen" check above may skip this, but not screenalloc(). + // was invoked recursively from a VimResized autocmd, handled as a loop below + if (resizing_autocmd) { + return; + } + + int retry_count = 0; + resizing_autocmd = true; + + bool retry_resize = true; + while (retry_resize) { + retry_resize = default_grid_alloc(); + + // Do not apply autocommands more than 3 times to avoid an endless loop + // in case applying autocommands always changes Rows or Columns. + if (++retry_count > 3) { + break; + } + + if (retry_resize) { + // In rare cases, autocommands may have altered Rows or Columns, + // retry to check if we need to allocate the screen again. + apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); + } + } + + resizing_autocmd = false; - if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) { - screenclear(); + ui_call_grid_resize(1, width, height); + + // win_new_screensize will recompute floats position, but tell the + // compositor to not redraw them yet + ui_comp_set_screen_valid(false); + if (msg_grid.chars) { + msg_grid_invalid = true; } + // Note that the window sizes are updated before reallocating the arrays, + // thus we must not redraw here! + RedrawingDisabled++; + + win_new_screensize(); // fit the windows in the new sized screen + + comp_col(); // recompute columns for shown command and ruler + + RedrawingDisabled--; + redraw_all_later(UPD_CLEAR); + if (starting != NO_SCREEN) { maketitle(); @@ -320,14 +322,11 @@ void screen_resize(int width, int height) // We only redraw when it's needed: // - While at the more prompt or executing an external command, don't // redraw, but position the cursor. - // - While editing the command line, only redraw that. + // - While editing the command line, only redraw that. TODO: lies // - in Ex mode, don't redraw anything. // - Otherwise, redraw right now, and position the cursor. - // Always need to call update_screen() or screenalloc(), to make - // sure Rows/Columns and the size of the screen is correct! if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM || exmode_active) { - screenalloc(); if (msg_grid.chars) { msg_grid_validate(); } @@ -341,7 +340,7 @@ void screen_resize(int width, int height) } if (State & MODE_CMDLINE) { redraw_popupmenu = false; - update_screen(NOT_VALID); + update_screen(); redrawcmdline(); if (pum_drawn()) { cmdline_pum_display(false); @@ -350,12 +349,12 @@ void screen_resize(int width, int height) update_topline(curwin); if (pum_drawn()) { // TODO(bfredl): ins_compl_show_pum wants to redraw the screen first. - // For now make sure the nested update_screen(0) won't redraw the + // For now make sure the nested update_screen() won't redraw the // pum at the old position. Try to untangle this later. redraw_popupmenu = false; ins_compl_show_pum(); } - update_screen(NOT_VALID); + update_screen(); if (redrawing()) { setcursor(); } @@ -370,9 +369,7 @@ void screen_resize(int width, int height) /// /// Most code shouldn't call this directly, rather use redraw_later() and /// and redraw_all_later() to mark parts of the screen as needing a redraw. -/// -/// @param type set to a NOT_VALID to force redraw of entire screen -int update_screen(int type) +int update_screen(void) { static bool did_intro = false; bool is_stl_global = global_stl_height() > 0; @@ -380,7 +377,7 @@ int update_screen(int type) // Don't do anything if the screen structures are (not yet) valid. // A VimResized autocmd can invoke redrawing in the middle of a resize, // which would bypass the checks in screen_resize for popupmenu etc. - if (!default_grid.chars || resizing) { + if (resizing_autocmd || !default_grid.chars) { return FAIL; } @@ -389,37 +386,25 @@ int update_screen(int type) diff_redraw(true); } - if (must_redraw) { - if (type < must_redraw) { // use maximal type - type = must_redraw; - } - - // must_redraw is reset here, so that when we run into some weird - // reason to redraw while busy redrawing (e.g., asynchronous - // scrolling), or update_topline() in win_update() will cause a - // scroll, or a decoration provider requires a redraw, the screen - // will be redrawn later or in win_update(). - must_redraw = 0; - } - - // Need to update w_lines[]. - if (curwin->w_lines_valid == 0 && type < NOT_VALID) { - type = NOT_VALID; - } - // Postpone the redrawing when it's not needed and when being called // recursively. if (!redrawing() || updating_screen) { - must_redraw = type; - if (type > INVERTED_ALL) { - curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now - } return FAIL; } + + int type = must_redraw; + + // must_redraw is reset here, so that when we run into some weird + // reason to redraw while busy redrawing (e.g., asynchronous + // scrolling), or update_topline() in win_update() will cause a + // scroll, or a decoration provider requires a redraw, the screen + // will be redrawn later or in win_update(). + must_redraw = 0; + updating_screen = 1; - display_tick++; // let syntax code know we're in a next round of - // display updating + display_tick++; // let syntax code know we're in a next round of + // display updating // Tricky: vim code can reset msg_scrolled behind our back, so need // separate bookkeeping for now. @@ -428,7 +413,7 @@ int update_screen(int type) msg_scrolled_at_flush = 0; } - if (type >= CLEAR || !default_grid.valid) { + if (type >= UPD_CLEAR || !default_grid.valid) { ui_comp_set_screen_valid(false); } @@ -443,68 +428,47 @@ int update_screen(int type) msg_grid.cols, false); } } - if (msg_use_msgsep()) { - msg_grid.throttled = false; - // CLEAR is already handled - if (type == NOT_VALID && !ui_has(kUIMultigrid) && msg_scrolled) { - ui_comp_set_screen_valid(false); - for (int i = valid; i < Rows - p_ch; i++) { - grid_clear_line(&default_grid, default_grid.line_offset[i], - Columns, false); - } - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_floating) { - continue; - } - if (W_ENDROW(wp) > valid) { - wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID); - } - if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) { - wp->w_redr_status = true; - } - } - if (is_stl_global && Rows - p_ch - 1 > valid) { - curwin->w_redr_status = true; - } + msg_grid.throttled = false; + bool was_invalidated = false; + + // UPD_CLEAR is already handled + if (type == UPD_NOT_VALID && !ui_has(kUIMultigrid) && msg_scrolled) { + was_invalidated = ui_comp_set_screen_valid(false); + for (int i = valid; i < Rows - p_ch; i++) { + grid_clear_line(&default_grid, default_grid.line_offset[i], + Columns, 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; - } else if (type != CLEAR) { - check_for_delay(false); - grid_ins_lines(&default_grid, 0, msg_scrolled, Rows, 0, Columns); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { continue; } - if (wp->w_winrow < msg_scrolled) { - if (W_ENDROW(wp) > msg_scrolled - && wp->w_redr_type < REDRAW_TOP - && wp->w_lines_valid > 0 - && wp->w_topline == wp->w_lines[0].wl_lnum) { - wp->w_upd_rows = msg_scrolled - wp->w_winrow; - wp->w_redr_type = REDRAW_TOP; - } else { - wp->w_redr_type = NOT_VALID; - if (wp->w_winrow + wp->w_winbar_height <= msg_scrolled) { - wp->w_redr_status = true; - } - } + if (W_ENDROW(wp) > valid) { + // TODO(bfredl): too pessimistic. type could be UPD_NOT_VALID + // only because windows that are above the separator. + wp->w_redr_type = MAX(wp->w_redr_type, UPD_NOT_VALID); + } + if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) { + wp->w_redr_status = true; } } - if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) { + if (is_stl_global && Rows - p_ch - 1 > valid) { curwin->w_redr_status = true; } - redraw_cmdline = true; - redraw_tabline = true; + } + msg_grid_set_pos(Rows - (int)p_ch, false); + msg_grid_invalid = false; + if (was_invalidated) { + // screen was only invalid for the msgarea part. + // @TODO(bfredl): using the same "valid" flag + // for both messages and floats moving is bit of a mess. + ui_comp_set_screen_valid(true); } msg_scrolled = 0; msg_scrolled_at_flush = 0; need_wait_return = false; } - win_ui_flush(); + win_ui_flush(true); msg_ext_check_clear(); // reset cmdline_row now (may have been changed temporarily) @@ -517,10 +481,11 @@ int update_screen(int type) hl_changed = true; } - if (type == CLEAR) { // first clear screen - screenclear(); // will reset clear_cmdline + if (type == UPD_CLEAR) { // first clear screen + screenclear(); // will reset clear_cmdline + // and set UPD_NOT_VALID for each window cmdline_screen_cleared(); // clear external cmdline state - type = NOT_VALID; + type = UPD_NOT_VALID; // must_redraw may be set indirectly, avoid another redraw later must_redraw = 0; } else if (!default_grid.valid) { @@ -528,16 +493,15 @@ int update_screen(int type) default_grid.valid = true; } - // 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)) { + // might need to clear space on default_grid for the message area. + if (type == UPD_NOT_VALID && clear_cmdline && !ui_has(kUIMessages)) { grid_fill(&default_grid, Rows - (int)p_ch, Rows, 0, Columns, ' ', ' ', 0); } ui_comp_set_screen_valid(true); DecorProviders providers; - decor_providers_start(&providers, type, &provider_err); + decor_providers_start(&providers, &provider_err); // "start" callback could have changed highlights for global elements if (win_check_ns_hl(NULL)) { @@ -551,37 +515,20 @@ int update_screen(int type) // Force redraw when width of 'number' or 'relativenumber' column // changes. - if (curwin->w_redr_type < NOT_VALID + // TODO(bfredl): special casing curwin here is SÃ… JÄVLA BULL. + // Either this should be done for all windows or not at all. + if (curwin->w_redr_type < UPD_NOT_VALID && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu) ? number_width(curwin) : 0)) { - curwin->w_redr_type = NOT_VALID; - } - - // Only start redrawing if there is really something to do. - if (type == INVERTED) { - update_curswant(); - } - if (curwin->w_redr_type < type - && !((type == VALID - && curwin->w_lines[0].wl_valid - && curwin->w_topfill == curwin->w_old_topfill - && curwin->w_botfill == curwin->w_old_botfill - && curwin->w_topline == curwin->w_lines[0].wl_lnum) - || (type == INVERTED - && VIsual_active - && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum - && curwin->w_old_visual_mode == VIsual_mode - && (curwin->w_valid & VALID_VIRTCOL) - && curwin->w_old_curswant == curwin->w_curswant))) { - curwin->w_redr_type = type; + curwin->w_redr_type = UPD_NOT_VALID; } // Redraw the tab pages line if needed. - if (redraw_tabline || type >= NOT_VALID) { - update_window_hl(curwin, type >= NOT_VALID); + if (redraw_tabline || type >= UPD_NOT_VALID) { + update_window_hl(curwin, type >= UPD_NOT_VALID); FOR_ALL_TABS(tp) { if (tp != curtab) { - update_window_hl(tp->tp_curwin, type >= NOT_VALID); + update_window_hl(tp->tp_curwin, type >= UPD_NOT_VALID); } } draw_tabline(); @@ -590,7 +537,7 @@ int update_screen(int type) // Correct stored syntax highlighting info for changes in each displayed // buffer. Each buffer must only be done once. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - update_window_hl(wp, type >= NOT_VALID || hl_changed); + update_window_hl(wp, type >= UPD_NOT_VALID || hl_changed); buf_T *buf = wp->w_buffer; if (buf->b_mod_set) { @@ -612,9 +559,9 @@ int update_screen(int type) screen_search_hl.rm.regprog = NULL; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { + if (wp->w_redr_type == UPD_CLEAR && wp->w_floating && wp->w_grid_alloc.chars) { grid_invalidate(&wp->w_grid_alloc); - wp->w_redr_type = NOT_VALID; + wp->w_redr_type = UPD_NOT_VALID; } win_check_ns_hl(wp); @@ -622,7 +569,7 @@ int update_screen(int type) // reallocate grid if needed. win_grid_alloc(wp); - if (wp->w_redr_border || wp->w_redr_type >= NOT_VALID) { + if (wp->w_redr_border || wp->w_redr_type >= UPD_NOT_VALID) { win_redr_border(wp); } @@ -794,6 +741,8 @@ void show_cursor_info(bool always) if (!always && !redrawing()) { return; } + + win_check_ns_hl(curwin); if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && (curwin->w_status_height || global_stl_height())) { redraw_custom_statusline(curwin); @@ -810,6 +759,7 @@ void show_cursor_info(bool always) maketitle(); } + win_check_ns_hl(NULL); // Redraw the tab pages line if needed. if (redraw_tabline) { draw_tabline(); @@ -1005,20 +955,20 @@ static void draw_sep_connectors_win(win_T *wp) /// /// How the window is redrawn depends on wp->w_redr_type. Each type also /// implies the one below it. -/// NOT_VALID redraw the whole window -/// SOME_VALID redraw the whole window but do scroll when possible -/// REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID -/// INVERTED redraw the changed part of the Visual area -/// INVERTED_ALL redraw the whole Visual area -/// VALID 1. scroll up/down to adjust for a changed w_topline -/// 2. update lines at the top when scrolled down -/// 3. redraw changed text: -/// - if wp->w_buffer->b_mod_set set, update lines between -/// b_mod_top and b_mod_bot. -/// - if wp->w_redraw_top non-zero, redraw lines between -/// wp->w_redraw_top and wp->w_redr_bot. -/// - continue redrawing when syntax status is invalid. -/// 4. if scrolled up, update lines at the bottom. +/// UPD_NOT_VALID redraw the whole window +/// UPD_SOME_VALID redraw the whole window but do scroll when possible +/// UPD_REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like UPD_VALID +/// UPD_INVERTED redraw the changed part of the Visual area +/// UPD_INVERTED_ALL redraw the whole Visual area +/// UPD_VALID 1. scroll up/down to adjust for a changed w_topline +/// 2. update lines at the top when scrolled down +/// 3. redraw changed text: +/// - if wp->w_buffer->b_mod_set set, update lines between +/// b_mod_top and b_mod_bot. +/// - if wp->w_redraw_top non-zero, redraw lines between +/// wp->w_redraw_top and wp->w_redr_bot. +/// - continue redrawing when syntax status is invalid. +/// 4. if scrolled up, update lines at the bottom. /// This results in three areas that may need updating: /// top: from first row to top_end (when scrolled down) /// mid: from mid_start to mid_end (update inversion or changed text) @@ -1041,6 +991,9 @@ win_update_start: bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit bool top_to_mod = false; // redraw above mod_top + int bot_scroll_start = 999; // first line that needs to be redrawn due to + // scrolling. only used for EOB + int row; // current window row to display linenr_T lnum; // current buffer lnum to display int idx; // current index in w_lines[] @@ -1064,8 +1017,10 @@ win_update_start: type = wp->w_redr_type; - if (type >= NOT_VALID) { + if (type >= UPD_NOT_VALID) { + // TODO(bfredl): should only be implied for CLEAR, not NOT_VALID! wp->w_redr_status = true; + wp->w_lines_valid = 0; } @@ -1095,7 +1050,7 @@ win_update_start: // changes. i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0; if (wp->w_nrwidth != i) { - type = NOT_VALID; + type = UPD_NOT_VALID; wp->w_nrwidth = i; if (buf->terminal) { @@ -1107,7 +1062,7 @@ win_update_start: // When there are both inserted/deleted lines and specific lines to be // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw // everything (only happens when redrawing is off for while). - type = NOT_VALID; + type = UPD_NOT_VALID; } else { // Set mod_top to the first line that needs displaying because of // changes. Set mod_bot to the first line after the changes. @@ -1144,12 +1099,12 @@ win_update_start: } else { const matchitem_T *cur = wp->w_match_head; while (cur != NULL) { - if (cur->match.regprog != NULL - && re_multiline(cur->match.regprog)) { + if (cur->mit_match.regprog != NULL + && re_multiline(cur->mit_match.regprog)) { top_to_mod = true; break; } - cur = cur->next; + cur = cur->mit_next; } } } @@ -1216,12 +1171,13 @@ win_update_start: mod_bot = MAXLNUM; } } + wp->w_redraw_top = 0; // reset for next time wp->w_redraw_bot = 0; // When only displaying the lines at the top, set top_end. Used when // window has scrolled down for msg_scrolled. - if (type == REDRAW_TOP) { + if (type == UPD_REDRAW_TOP) { j = 0; for (i = 0; i < wp->w_lines_valid; i++) { j += wp->w_lines[i].wl_size; @@ -1232,10 +1188,10 @@ win_update_start: } if (top_end == 0) { // not found (cannot happen?): redraw everything - type = NOT_VALID; + type = UPD_NOT_VALID; } else { - // top area defined, the rest is VALID - type = VALID; + // top area defined, the rest is UPD_VALID + type = UPD_VALID; } } @@ -1245,8 +1201,8 @@ win_update_start: // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in // w_lines[] that needs updating. - if ((type == VALID || type == SOME_VALID - || type == INVERTED || type == INVERTED_ALL) + if ((type == UPD_VALID || type == UPD_SOME_VALID + || type == UPD_INVERTED || type == UPD_INVERTED_ALL) && !wp->w_botfill && !wp->w_old_botfill) { if (mod_top != 0 && wp->w_topline == mod_top @@ -1286,6 +1242,7 @@ win_update_start: // If not the last window, delete the lines at the bottom. // win_ins_lines may fail when the terminal can't do it. win_scroll_lines(wp, 0, i); + bot_scroll_start = 0; if (wp->w_lines_valid != 0) { // Need to update rows that are new, stop at the // first one that scrolled down. @@ -1346,6 +1303,7 @@ win_update_start: if (row > 0) { win_scroll_lines(wp, 0, -row); bot_start = wp->w_grid.rows - row; + bot_scroll_start = bot_start; } if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) { // Skip the lines (below the deleted lines) that are still @@ -1387,25 +1345,25 @@ win_update_start: mid_end = wp->w_grid.rows; } } else { - // Not VALID or INVERTED: redraw all lines. + // Not UPD_VALID or UPD_INVERTED: redraw all lines. mid_start = 0; mid_end = wp->w_grid.rows; } - if (type == SOME_VALID) { - // SOME_VALID: redraw all lines. + if (type == UPD_SOME_VALID) { + // UPD_SOME_VALID: redraw all lines. mid_start = 0; mid_end = wp->w_grid.rows; - type = NOT_VALID; + type = UPD_NOT_VALID; } // check if we are updating or removing the inverted part if ((VIsual_active && buf == curwin->w_buffer) - || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) { + || (wp->w_old_cursor_lnum != 0 && type != UPD_NOT_VALID)) { linenr_T from, to; if (VIsual_active) { - if (VIsual_mode != wp->w_old_visual_mode || type == INVERTED_ALL) { + if (VIsual_mode != wp->w_old_visual_mode || type == UPD_INVERTED_ALL) { // If the type of Visual selection changed, redraw the whole // selection. Also when the ownership of the X selection is // gained or lost. @@ -1491,7 +1449,7 @@ win_update_start: pos.lnum += cursor_above ? 1 : -1) { colnr_T t; - pos.col = (colnr_T)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; @@ -1723,6 +1681,7 @@ win_update_start: // need to redraw until the end of the window. // Inserting/deleting lines has no use. bot_start = 0; + bot_scroll_start = 0; } else { // Able to count old number of rows: Count new window // rows, and may insert/delete lines @@ -1753,6 +1712,7 @@ win_update_start: } else { win_scroll_lines(wp, row, xtra_rows); bot_start = wp->w_grid.rows + xtra_rows; + bot_scroll_start = bot_start; } } else if (xtra_rows > 0) { // May scroll text down. If there is not enough @@ -1762,6 +1722,7 @@ win_update_start: mod_bot = MAXLNUM; } else { win_scroll_lines(wp, row + old_rows, xtra_rows); + bot_scroll_start = 0; if (top_end > row + old_rows) { // Scrolled the part at the top that requires // updating down. @@ -1933,24 +1894,28 @@ win_update_start: wp->w_filler_rows = wp->w_grid.rows - srow; } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" int scr_row = wp->w_grid.rows - 1; + int symbol = wp->w_p_fcs_chars.lastline; + char fillbuf[12]; // 2 characters of 6 bytes + int charlen = utf_char2bytes(symbol, &fillbuf[0]); + utf_char2bytes(symbol, &fillbuf[charlen]); // Last line isn't finished: Display "@@@" in the last screen line. - grid_puts_len(&wp->w_grid, (char_u *)"@@", MIN(wp->w_grid.cols, 2), scr_row, 0, at_attr); - - grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols, - '@', ' ', at_attr); + grid_puts_len(&wp->w_grid, fillbuf, MIN(wp->w_grid.cols, 2) * charlen, scr_row, 0, at_attr); + grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.cols, symbol, ' ', at_attr); set_empty_rows(wp, srow); wp->w_botline = lnum; } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" int start_col = wp->w_grid.cols - 3; + int symbol = wp->w_p_fcs_chars.lastline; // Last line isn't finished: Display "@@@" at the end. grid_fill(&wp->w_grid, wp->w_grid.rows - 1, wp->w_grid.rows, - MAX(start_col, 0), wp->w_grid.cols, '@', '@', at_attr); + MAX(start_col, 0), wp->w_grid.cols, symbol, symbol, at_attr); set_empty_rows(wp, srow); wp->w_botline = lnum; } else { - win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.rows, HLF_AT); + win_draw_end(wp, wp->w_p_fcs_chars.lastline, ' ', true, srow, wp->w_grid.rows, HLF_AT); + set_empty_rows(wp, srow); wp->w_botline = lnum; } } else { @@ -1968,15 +1933,27 @@ win_update_start: wp->w_botline = lnum; } - // make sure the rest of the screen is blank - // write the 'eob' character to rows that aren't part of the file. - win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows, + // Make sure the rest of the screen is blank. + // write the "eob" character from 'fillchars' to rows that aren't part + // of the file. + // TODO(bfredl): just keep track of the valid EOB area from last redraw? + int lastline = bot_scroll_start; + if (mid_end >= row) { + lastline = MIN(lastline, mid_start); + } + // if (mod_bot > buf->b_ml.ml_line_count + 1) { + if (mod_bot > buf->b_ml.ml_line_count) { + lastline = 0; + } + + win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, MAX(lastline, row), wp->w_grid.rows, HLF_EOB); + set_empty_rows(wp, row); } kvi_destroy(line_providers); - if (wp->w_redr_type >= REDRAW_TOP) { + if (wp->w_redr_type >= UPD_REDRAW_TOP) { draw_vsep_win(wp); draw_hsep_win(wp); draw_sep_connectors_win(wp); @@ -2030,16 +2007,16 @@ win_update_start: } } -/// Redraw a window later, with update_screen(type). +/// Redraw a window later, with wp->w_redr_type >= type. /// /// Set must_redraw only if not already set to a higher value. -/// e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. +/// e.g. if must_redraw is UPD_CLEAR, type UPD_NOT_VALID will do nothing. void redraw_later(win_T *wp, int type) FUNC_ATTR_NONNULL_ALL { if (!exiting && wp->w_redr_type < type) { wp->w_redr_type = type; - if (type >= NOT_VALID) { + if (type >= UPD_NOT_VALID) { wp->w_lines_valid = 0; } if (must_redraw < type) { // must_redraw is the maximum of all windows @@ -2063,7 +2040,7 @@ void redraw_all_later(int type) void screen_invalidate_highlights(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); wp->w_grid_alloc.valid = false; } } @@ -2083,12 +2060,14 @@ void redraw_buf_later(buf_T *buf, int type) } } -void redraw_buf_line_later(buf_T *buf, linenr_T line) +void redraw_buf_line_later(buf_T *buf, linenr_T line, bool force) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf - && line >= wp->w_topline && line < wp->w_botline) { - redrawWinline(wp, line); + if (wp->w_buffer == buf) { + redrawWinline(wp, MIN(line, buf->b_ml.ml_line_count)); + if (force && line > buf->b_ml.ml_line_count) { + wp->w_redraw_bot = line; + } } } } @@ -2104,7 +2083,7 @@ void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lastline) { wp->w_redraw_bot = lastline; } - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2118,8 +2097,8 @@ void redraw_buf_status_later(buf_T *buf) || (wp == curwin && global_stl_height()) || wp->w_winbar_height)) { wp->w_redr_status = true; - if (must_redraw < VALID) { - must_redraw = VALID; + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; } } } @@ -2134,7 +2113,7 @@ void status_redraw_all(void) if ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin) || wp->w_winbar_height) { wp->w_redr_status = true; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2154,7 +2133,7 @@ void status_redraw_buf(buf_T *buf) if (wp->w_buffer == buf && ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin) || wp->w_winbar_height)) { wp->w_redr_status = true; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } } @@ -2164,10 +2143,13 @@ void redraw_statuslines(void) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_redr_status) { + win_check_ns_hl(wp); win_redr_winbar(wp); win_redr_status(wp); } } + + win_check_ns_hl(NULL); if (redraw_tabline) { draw_tabline(); } @@ -2210,6 +2192,6 @@ void redrawWinline(win_T *wp, linenr_T lnum) if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) { wp->w_redraw_bot = lnum; } - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } diff --git a/src/nvim/drawscreen.h b/src/nvim/drawscreen.h index 3eac1caaa1..ef99899581 100644 --- a/src/nvim/drawscreen.h +++ b/src/nvim/drawscreen.h @@ -6,13 +6,13 @@ /// flags for update_screen() /// The higher the value, the higher the priority enum { - VALID = 10, ///< buffer not changed, or changes marked with b_mod_* - INVERTED = 20, ///< redisplay inverted part that changed - INVERTED_ALL = 25, ///< redisplay whole inverted part - REDRAW_TOP = 30, ///< display first w_upd_rows screen lines - SOME_VALID = 35, ///< like NOT_VALID but may scroll - NOT_VALID = 40, ///< buffer needs complete redraw - CLEAR = 50, ///< screen messed up, clear it + UPD_VALID = 10, ///< buffer not changed, or changes marked with b_mod_* + UPD_INVERTED = 20, ///< redisplay inverted part that changed + UPD_INVERTED_ALL = 25, ///< redisplay whole inverted part + UPD_REDRAW_TOP = 30, ///< display first w_upd_rows screen lines + UPD_SOME_VALID = 35, ///< like UPD_NOT_VALID but may scroll + UPD_NOT_VALID = 40, ///< buffer needs complete redraw + UPD_CLEAR = 50, ///< screen messed up, clear it }; /// While redrawing the screen this flag is set. It means the screen size diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 6583ac8584..09f20baebf 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * edit.c: functions for Insert mode - */ +// edit.c: functions for Insert mode #include <assert.h> #include <inttypes.h> @@ -56,6 +54,8 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/terminal.h" +#include "nvim/textformat.h" +#include "nvim/textobject.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -92,6 +92,10 @@ typedef struct insert_state { #define BACKSPACE_WORD_NOT_SPACE 3 #define BACKSPACE_LINE 4 +/// Set when doing something for completion that may call edit() recursively, +/// which is not allowed. +static bool compl_busy = false; + 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 @@ -104,8 +108,6 @@ static int did_restart_edit; // "restart_edit" when calling edit() static bool can_cindent; // may do cindenting on this line -static int old_indent = 0; // for ^^D command in insert mode - static int revins_on; // reverse insert mode on static int revins_chars; // how much to skip after edit static int revins_legal; // was the last char 'legal'? @@ -115,8 +117,6 @@ static bool ins_need_undo; // call u_save() before inserting a // char. Set when edit() is called. // after that arrow_used is used. -static bool did_add_space = false; // auto_format() added an extra space - // under the cursor static TriState dont_sync_undo = kFalse; // CTRL-G U prevents syncing undo // for the next left/right cursor key @@ -188,7 +188,7 @@ static void insert_enter(InsertState *s) } } - Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr()); + Insstart_textlen = (colnr_T)linetabsize((char_u *)get_cursor_line_ptr()); Insstart_blank_vcol = MAXCOL; if (!did_ai) { @@ -272,7 +272,7 @@ static void insert_enter(InsertState *s) update_curswant(); if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) || curwin->w_curswant > curwin->w_virtcol) - && *(s->ptr = get_cursor_line_ptr() + curwin->w_cursor.col) != NUL) { + && *(s->ptr = (char_u *)get_cursor_line_ptr() + curwin->w_cursor.col) != NUL) { if (s->ptr[1] == NUL) { curwin->w_cursor.col++; } else { @@ -448,7 +448,7 @@ static int insert_check(VimState *state) && (curwin->w_cursor.lnum != curwin->w_topline || curwin->w_topfill > 0)) { if (curwin->w_topfill > 0) { - --curwin->w_topfill; + curwin->w_topfill--; } else if (hasFolding(curwin->w_topline, NULL, &s->old_topline)) { set_topline(curwin, s->old_topline + 1); } else { @@ -624,16 +624,17 @@ static int insert_execute(VimState *state, int key) } if (cindent_on() && ctrl_x_mode_none()) { + s->line_is_white = inindent(0); // 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 - // done before inserting the key. - s->line_is_white = inindent(0); - if (in_cinkeys(s->c, '!', s->line_is_white)) { - insert_do_cindent(s); + if (in_cinkeys(s->c, '!', s->line_is_white) + && stop_arrow() == OK) { + do_c_expr_indent(); return 1; // continue } + // A key name preceded by a star means that indenting has to be + // done before inserting the key. if (can_cindent && in_cinkeys(s->c, '*', s->line_is_white) && stop_arrow() == OK) { do_c_expr_indent(); @@ -1090,7 +1091,7 @@ check_pum: // but it is under other ^X modes if (*curbuf->b_p_cpt == NUL && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line()) - && !(compl_cont_status & CONT_LOCAL)) { + && !compl_status_local()) { goto normalchar; } @@ -1176,9 +1177,11 @@ normalchar: static void insert_do_complete(InsertState *s) { compl_busy = true; + disable_fold_update++; // don't redraw folds here if (ins_complete(s->c, true) == FAIL) { - compl_cont_status = 0; + compl_status_clear(); } + disable_fold_update--; compl_busy = false; can_si = may_do_si(); // allow smartindenting } @@ -1283,7 +1286,7 @@ void ins_redraw(bool ready) // a "(". The autocommand may also require a redraw, so it's done // again below, unfortunately. if (syntax_present(curwin) && must_redraw) { - update_screen(0); + update_screen(); } // Make sure curswant is correct, an autocommand may call // getcurpos() @@ -1345,7 +1348,7 @@ void ins_redraw(bool ready) pum_check_clear(); if (must_redraw) { - update_screen(0); + update_screen(); } else if (clear_cmdline || redraw_cmdline) { showmode(); // clear cmdline and show mode } @@ -1354,9 +1357,7 @@ void ins_redraw(bool ready) emsg_on_display = false; // may remove error message now } -/* - * Handle a CTRL-V or CTRL-Q typed in Insert mode. - */ +// Handle a CTRL-V or CTRL-Q typed in Insert mode. static void ins_ctrl_v(void) { int c; @@ -1386,10 +1387,8 @@ static void ins_ctrl_v(void) revins_legal++; } -/* - * Put a character directly onto the screen. It's not stored in a buffer. - * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. - */ +// Put a character directly onto the screen. It's not stored in a buffer. +// Used while handling CTRL-K, CTRL-V, etc. in Insert mode. static int pc_status; #define PC_STATUS_UNSET 0 // pc_bytes was not set #define PC_STATUS_RIGHT 1 // right half of double-wide char @@ -1440,21 +1439,21 @@ void edit_putchar(int c, bool highlight) } } -/// Return the effective prompt for the specified buffer. -char_u *buf_prompt_text(const buf_T *const buf) +/// @return the effective prompt for the specified buffer. +char *buf_prompt_text(const buf_T *const buf) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { if (buf->b_prompt_text == NULL) { - return (char_u *)"% "; + return "% "; } - return (char_u *)buf->b_prompt_text; + return buf->b_prompt_text; } // Return the effective prompt for the current buffer. char_u *prompt_text(void) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - return buf_prompt_text(curbuf); + return (char_u *)buf_prompt_text(curbuf); } // Prepare for prompt mode: Make sure the last line has the prompt text. @@ -1465,7 +1464,7 @@ static void init_prompt(int cmdchar_todo) char_u *text; curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - text = get_cursor_line_ptr(); + text = (char_u *)get_cursor_line_ptr(); if (STRNCMP(text, prompt, STRLEN(prompt)) != 0) { // prompt is missing, insert it or append a line with it if (*text == NUL) { @@ -1506,9 +1505,7 @@ bool prompt_curpos_editable(void) && curwin->w_cursor.col >= (int)STRLEN(prompt_text()); } -/* - * Undo the previous edit_putchar(). - */ +// Undo the previous edit_putchar(). void edit_unputchar(void) { if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) { @@ -1518,16 +1515,13 @@ void edit_unputchar(void) if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) { redrawWinline(curwin, curwin->w_cursor.lnum); } else { - grid_puts(&curwin->w_grid, pc_bytes, pc_row - msg_scrolled, pc_col, - pc_attr); + grid_puts(&curwin->w_grid, (char *)pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); } } } -/* - * Called when p_dollar is set: display a '$' at the end of the changed text - * Only works when cursor is in the line that changes. - */ +// Called when p_dollar is set: display a '$' at the end of the changed text +// Only works when cursor is in the line that changes. void display_dollar(colnr_T col) { colnr_T save_col; @@ -1540,8 +1534,8 @@ void display_dollar(colnr_T col) curwin->w_cursor.col = col; // If on the last byte of a multi-byte move to the first byte. - char_u *p = get_cursor_line_ptr(); - curwin->w_cursor.col -= utf_head_off(p, p + col); + char_u *p = (char_u *)get_cursor_line_ptr(); + curwin->w_cursor.col -= utf_head_off((char *)p, (char *)p + col); curs_columns(curwin, false); // Recompute w_wrow and w_wcol if (curwin->w_wcol < curwin->w_grid.cols) { edit_putchar('$', false); @@ -1550,11 +1544,9 @@ void display_dollar(colnr_T col) curwin->w_cursor.col = save_col; } -/* - * Call this function before moving the cursor from the normal insert position - * in insert mode. - */ -static void undisplay_dollar(void) +// Call this function before moving the cursor from the normal insert position +// in insert mode. +void undisplay_dollar(void) { if (dollar_vcol >= 0) { dollar_vcol = -1; @@ -1568,7 +1560,7 @@ static void undisplay_dollar(void) /// type == INDENT_DEC decrease indent (for CTRL-D) /// type == INDENT_SET set indent to "amount" /// -/// @param round if TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec). +/// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec). /// @param replaced replaced character, put on replace stack /// @param call_changed_bytes call changed_bytes() void change_indent(int type, int amount, int round, int replaced, int call_changed_bytes) @@ -1582,25 +1574,23 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang int start_col; colnr_T vc; colnr_T orig_col = 0; // init for GCC - char_u *new_line, *orig_line = NULL; // init for GCC + char *new_line, *orig_line = NULL; // init for GCC // MODE_VREPLACE state needs to know what the line was like before changing if (State & VREPLACE_FLAG) { - orig_line = vim_strsave(get_cursor_line_ptr()); // Deal with NULL below + orig_line = xstrdup(get_cursor_line_ptr()); // Deal with NULL below orig_col = curwin->w_cursor.col; } // for the following tricks we don't want list mode save_p_list = curwin->w_p_list; - curwin->w_p_list = FALSE; + curwin->w_p_list = false; vc = getvcol_nolist(&curwin->w_cursor); vcol = vc; - /* - * For Replace mode we need to fix the replace stack later, which is only - * possible when the cursor is in the indent. Remember the number of - * characters before the cursor if it's possible. - */ + // For Replace mode we need to fix the replace stack later, which is only + // possible when the cursor is in the indent. Remember the number of + // characters before the cursor if it's possible. start_col = curwin->w_cursor.col; // determine offset from first non-blank @@ -1610,10 +1600,8 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang insstart_less = curwin->w_cursor.col; - /* - * If the cursor is in the indent, compute how many screen columns the - * cursor is to the left of the first non-blank. - */ + // If the cursor is in the indent, compute how many screen columns the + // cursor is to the left of the first non-blank. if (new_cursor_col < 0) { vcol = get_indent() - vcol; } @@ -1622,9 +1610,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang start_col = -1; } - /* - * Set the new indent. The cursor will be put on the first non-blank. - */ + // Set the new indent. The cursor will be put on the first non-blank. if (type == INDENT_SET) { (void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0); } else { @@ -1639,20 +1625,16 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang } insstart_less -= curwin->w_cursor.col; - /* - * Try to put cursor on same character. - * If the cursor is at or after the first non-blank in the line, - * compute the cursor column relative to the column of the first - * non-blank character. - * If we are not in insert mode, leave the cursor on the first non-blank. - * If the cursor is before the first non-blank, position it relative - * to the first non-blank, counted in screen columns. - */ + // Try to put cursor on same character. + // If the cursor is at or after the first non-blank in the line, + // compute the cursor column relative to the column of the first + // non-blank character. + // If we are not in insert mode, leave the cursor on the first non-blank. + // If the cursor is before the first non-blank, position it relative + // to the first non-blank, counted in screen columns. if (new_cursor_col >= 0) { - /* - * When changing the indent while the cursor is touching it, reset - * Insstart_col to 0. - */ + // When changing the indent while the cursor is touching it, reset + // Insstart_col to 0. if (new_cursor_col == 0) { insstart_less = MAXCOL; } @@ -1660,47 +1642,43 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang } else if (!(State & MODE_INSERT)) { new_cursor_col = curwin->w_cursor.col; } else { - /* - * Compute the screen column where the cursor should be. - */ + // Compute the screen column where the cursor should be. vcol = get_indent() - vcol; curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol); - /* - * Advance the cursor until we reach the right screen column. - */ - vcol = last_vcol = 0; - new_cursor_col = -1; - ptr = get_cursor_line_ptr(); - while (vcol <= (int)curwin->w_virtcol) { - last_vcol = vcol; - if (new_cursor_col >= 0) { - new_cursor_col += utfc_ptr2len((char *)ptr + new_cursor_col); - } else { - new_cursor_col++; + // Advance the cursor until we reach the right screen column. + last_vcol = 0; + ptr = (char_u *)get_cursor_line_ptr(); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, 0, 0, (char *)ptr, (char *)ptr); + while (cts.cts_vcol <= (int)curwin->w_virtcol) { + last_vcol = cts.cts_vcol; + if (cts.cts_vcol > 0) { + MB_PTR_ADV(cts.cts_ptr); + } + if (*cts.cts_ptr == NUL) { + break; } - vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol); + cts.cts_vcol += lbr_chartabsize(&cts); } vcol = last_vcol; + new_cursor_col = (int)(cts.cts_ptr - cts.cts_line); + clear_chartabsize_arg(&cts); - /* - * May need to insert spaces to be able to position the cursor on - * the right screen column. - */ + // May need to insert spaces to be able to position the cursor on + // the right screen column. if (vcol != (int)curwin->w_virtcol) { curwin->w_cursor.col = (colnr_T)new_cursor_col; size_t i = (size_t)(curwin->w_virtcol - vcol); ptr = xmallocz(i); memset(ptr, ' ', i); new_cursor_col += (int)i; - ins_str(ptr); + ins_str((char *)ptr); xfree(ptr); } - /* - * When changing the indent while the cursor is in it, reset - * Insstart_col to 0. - */ + // When changing the indent while the cursor is in it, reset + // Insstart_col to 0. insstart_less = MAXCOL; } @@ -1711,12 +1689,10 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang } else { curwin->w_cursor.col = (colnr_T)new_cursor_col; } - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; changed_cline_bef_curs(); - /* - * May have to adjust the start of the insert. - */ + // May have to adjust the start of the insert. if (State & MODE_INSERT) { if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) { if ((int)Insstart.col <= insstart_less) { @@ -1757,14 +1733,14 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang // then put it back again the way we wanted it. if (State & VREPLACE_FLAG) { // Save new line - new_line = vim_strsave(get_cursor_line_ptr()); + new_line = xstrdup(get_cursor_line_ptr()); // We only put back the new line up to the cursor new_line[curwin->w_cursor.col] = NUL; int new_col = curwin->w_cursor.col; // Put back original line - ml_replace(curwin->w_cursor.lnum, (char *)orig_line, false); + ml_replace(curwin->w_cursor.lnum, orig_line, false); curwin->w_cursor.col = orig_col; curbuf_splice_pending++; @@ -1792,12 +1768,12 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang /// Truncate the space at the end of a line. This is to be used only in an /// insert mode. It handles fixing the replace stack for MODE_REPLACE and /// MODE_VREPLACE modes. -void truncate_spaces(char_u *line) +void truncate_spaces(char *line) { int i; // find start of trailing white space - for (i = (int)STRLEN(line) - 1; i >= 0 && ascii_iswhite(line[i]); i--) { + for (i = (int)strlen(line) - 1; i >= 0 && ascii_iswhite(line[i]); i--) { if (State & REPLACE_FLAG) { replace_join(0); // remove a NUL from the replace stack } @@ -1837,7 +1813,7 @@ static bool del_char_after_col(int limit_col) // composing character. mb_adjust_cursor(); while (curwin->w_cursor.col < (colnr_T)limit_col) { - int l = utf_ptr2len((char *)get_cursor_pos_ptr()); + int l = utf_ptr2len(get_cursor_pos_ptr()); if (l == 0) { // end of line break; @@ -1971,7 +1947,7 @@ static void insert_special(int c, int allow_modmask, int ctrlv) // inserted with ins_str(), so as not to replace characters in replace // mode. // Only use mod_mask for special keys, to avoid things like <S-Space>, - // unless 'allow_modmask' is TRUE. + // unless 'allow_modmask' is true. if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key. allow_modmask = true; } @@ -1984,7 +1960,7 @@ static void insert_special(int c, int allow_modmask, int ctrlv) return; } p[len - 1] = NUL; - ins_str(p); + ins_str((char *)p); AppendToRedobuffLit((char *)p, -1); ctrlv = false; } @@ -1994,20 +1970,15 @@ static void insert_special(int c, int allow_modmask, int ctrlv) } } -/* - * Special characters in this context are those that need processing other - * than the simple insertion that can be performed here. This includes ESC - * which terminates the insert, and CR/NL which need special processing to - * open up a new line. This routine tries to optimize insertions performed by - * the "redo", "undo" or "put" commands, so it needs to know when it should - * stop and defer processing to the "normal" mechanism. - * '0' and '^' are special, because they can be followed by CTRL-D. - */ +// Special characters in this context are those that need processing other +// than the simple insertion that can be performed here. This includes ESC +// which terminates the insert, and CR/NL which need special processing to +// open up a new line. This routine tries to optimize insertions performed by +// the "redo", "undo" or "put" commands, so it needs to know when it should +// stop and defer processing to the "normal" mechanism. +// '0' and '^' are special, because they can be followed by CTRL-D. #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') -#define WHITECHAR(cc) (ascii_iswhite(cc) \ - && !utf_iscomposing(utf_ptr2char((char *)get_cursor_pos_ptr() + 1))) - /// /// "flags": INSCHAR_FORMAT - force formatting /// INSCHAR_CTRLV - char typed just after CTRL-V @@ -2081,7 +2052,7 @@ void insertchar(int c, int flags, int second_indent) // Need to remove existing (middle) comment leader and insert end // comment leader. First, check what comment leader we can find. - char_u *line = get_cursor_line_ptr(); + char_u *line = (char_u *)get_cursor_line_ptr(); int i = get_leader_len((char *)line, &p, false, true); if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) { // Just checking // Skip middle-comment string @@ -2115,7 +2086,7 @@ void insertchar(int c, int flags, int second_indent) // Insert the end-comment string, except for the last // character, which will get inserted as normal later. - ins_bytes_len(lead_end, (size_t)(end_len - 1)); + ins_bytes_len((char *)lead_end, (size_t)(end_len - 1)); } } } @@ -2175,7 +2146,7 @@ void insertchar(int c, int flags, int second_indent) do_digraph(-1); // clear digraphs do_digraph(buf[i - 1]); // may be the start of a digraph buf[i] = NUL; - ins_str(buf); + ins_str((char *)buf); if (flags & INSCHAR_CTRLV) { redo_literal(*buf); i = 1; @@ -2193,7 +2164,7 @@ void insertchar(int c, int flags, int second_indent) utf_char2bytes(c, (char *)buf); buf[cc] = NUL; - ins_char_bytes((char_u *)buf, (size_t)cc); + ins_char_bytes(buf, (size_t)cc); AppendCharToRedobuff(c); } else { ins_char(c); @@ -2206,600 +2177,7 @@ void insertchar(int c, int flags, int second_indent) } } -/// Format text at the current insert position. -/// -/// If the INSCHAR_COM_LIST flag is present, then the value of second_indent -/// will be the comment leader length sent to open_line(). -/// -/// @param c character to be inserted (can be NUL) -static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c) -{ - int cc; - int save_char = NUL; - bool haveto_redraw = false; - const bool fo_ins_blank = has_format_option(FO_INS_BLANK); - const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK); - const bool fo_rigor_tw = has_format_option(FO_RIGOROUS_TW); - const bool fo_white_par = has_format_option(FO_WHITE_PAR); - bool first_line = true; - colnr_T leader_len; - bool no_leader = false; - int do_comments = (flags & INSCHAR_DO_COM); - int has_lbr = curwin->w_p_lbr; - - // make sure win_lbr_chartabsize() counts correctly - curwin->w_p_lbr = false; - - /* - * When 'ai' is off we don't want a space under the cursor to be - * deleted. Replace it with an 'x' temporarily. - */ - if (!curbuf->b_p_ai - && !(State & VREPLACE_FLAG)) { - cc = gchar_cursor(); - if (ascii_iswhite(cc)) { - save_char = cc; - pchar_cursor('x'); - } - } - - /* - * Repeat breaking lines, until the current line is not too long. - */ - while (!got_int) { - int startcol; // Cursor column at entry - int wantcol; // column at textwidth border - int foundcol; // column for start of spaces - int end_foundcol = 0; // column for start of word - colnr_T len; - colnr_T virtcol; - int orig_col = 0; - char_u *saved_text = NULL; - colnr_T col; - colnr_T end_col; - bool did_do_comment = false; - - virtcol = get_nolist_virtcol() - + char2cells(c != NUL ? c : gchar_cursor()); - if (virtcol <= (colnr_T)textwidth) { - break; - } - - if (no_leader) { - do_comments = false; - } else if (!(flags & INSCHAR_FORMAT) - && has_format_option(FO_WRAP_COMS)) { - do_comments = true; - } - - // Don't break until after the comment leader - if (do_comments) { - char_u *line = get_cursor_line_ptr(); - leader_len = get_leader_len((char *)line, NULL, false, true); - if (leader_len == 0 && curbuf->b_p_cin) { - // Check for a line comment after code. - int comment_start = check_linecomment(line); - if (comment_start != MAXCOL) { - leader_len = get_leader_len((char *)line + comment_start, NULL, false, true); - if (leader_len != 0) { - leader_len += comment_start; - } - } - } - } else { - leader_len = 0; - } - - // If the line doesn't start with a comment leader, then don't - // start one in a following broken line. Avoids that a %word - // moved to the start of the next line causes all following lines - // to start with %. - if (leader_len == 0) { - no_leader = true; - } - if (!(flags & INSCHAR_FORMAT) - && leader_len == 0 - && !has_format_option(FO_WRAP)) { - break; - } - if ((startcol = curwin->w_cursor.col) == 0) { - break; - } - - // find column of textwidth border - coladvance((colnr_T)textwidth); - wantcol = curwin->w_cursor.col; - - curwin->w_cursor.col = startcol; - foundcol = 0; - int skip_pos = 0; - - /* - * Find position to break at. - * Stop at first entered white when 'formatoptions' has 'v' - */ - while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) - || (flags & INSCHAR_FORMAT) - || curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) { - if (curwin->w_cursor.col == startcol && c != NUL) { - cc = c; - } else { - cc = gchar_cursor(); - } - if (WHITECHAR(cc)) { - // remember position of blank just before text - end_col = curwin->w_cursor.col; - - // find start of sequence of blanks - int wcc = 0; // counter for whitespace chars - while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) { - dec_cursor(); - cc = gchar_cursor(); - - // Increment count of how many whitespace chars in this - // group; we only need to know if it's more than one. - if (wcc < 2) { - wcc++; - } - } - if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) { - break; // only spaces in front of text - } - - // Don't break after a period when 'formatoptions' has 'p' and - // there are less than two spaces. - if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) { - continue; - } - - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) { - break; - } - - if (has_format_option(FO_ONE_LETTER)) { - // do not break after one-letter words - if (curwin->w_cursor.col == 0) { - break; // one-letter word at begin - } - // do not break "#a b" when 'tw' is 2 - if (curwin->w_cursor.col <= leader_len) { - break; - } - col = curwin->w_cursor.col; - dec_cursor(); - cc = gchar_cursor(); - - if (WHITECHAR(cc)) { - continue; // one-letter, continue - } - curwin->w_cursor.col = col; - } - - inc_cursor(); - - end_foundcol = end_col + 1; - foundcol = curwin->w_cursor.col; - if (curwin->w_cursor.col <= (colnr_T)wantcol) { - break; - } - } else if ((cc >= 0x100 || !utf_allow_break_before(cc)) && fo_multibyte) { - int ncc; - bool allow_break; - - // Break after or before a multi-byte character. - if (curwin->w_cursor.col != startcol) { - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) { - break; - } - col = curwin->w_cursor.col; - inc_cursor(); - ncc = gchar_cursor(); - allow_break = utf_allow_break(cc, ncc); - - // If we have already checked this position, skip! - if (curwin->w_cursor.col != skip_pos && allow_break) { - foundcol = curwin->w_cursor.col; - end_foundcol = foundcol; - if (curwin->w_cursor.col <= (colnr_T)wantcol) { - break; - } - } - curwin->w_cursor.col = col; - } - - if (curwin->w_cursor.col == 0) { - break; - } - - ncc = cc; - col = curwin->w_cursor.col; - - dec_cursor(); - cc = gchar_cursor(); - - if (WHITECHAR(cc)) { - continue; // break with space - } - // Don't break until after the comment leader. - if (curwin->w_cursor.col < leader_len) { - break; - } - - curwin->w_cursor.col = col; - skip_pos = curwin->w_cursor.col; - - allow_break = utf_allow_break(cc, ncc); - - // Must handle this to respect line break prohibition. - if (allow_break) { - foundcol = curwin->w_cursor.col; - end_foundcol = foundcol; - } - if (curwin->w_cursor.col <= (colnr_T)wantcol) { - const bool ncc_allow_break = utf_allow_break_before(ncc); - - if (allow_break) { - break; - } - if (!ncc_allow_break && !fo_rigor_tw) { - // Enable at most 1 punct hang outside of textwidth. - if (curwin->w_cursor.col == startcol) { - // We are inserting a non-breakable char, postpone - // line break check to next insert. - end_foundcol = foundcol = 0; - break; - } - - // Neither cc nor ncc is NUL if we are here, so - // it's safe to inc_cursor. - col = curwin->w_cursor.col; - - inc_cursor(); - cc = ncc; - ncc = gchar_cursor(); - // handle insert - ncc = (ncc != NUL) ? ncc : c; - - allow_break = utf_allow_break(cc, ncc); - - if (allow_break) { - // Break only when we are not at end of line. - end_foundcol = foundcol = ncc == NUL? 0 : curwin->w_cursor.col; - break; - } - curwin->w_cursor.col = col; - } - } - } - if (curwin->w_cursor.col == 0) { - break; - } - dec_cursor(); - } - - if (foundcol == 0) { // no spaces, cannot break line - curwin->w_cursor.col = startcol; - break; - } - - // Going to break the line, remove any "$" now. - undisplay_dollar(); - - // Offset between cursor position and line break is used by replace - // stack functions. MODE_VREPLACE does not use this, and backspaces - // over the text instead. - if (State & VREPLACE_FLAG) { - orig_col = startcol; // Will start backspacing from here - } else { - replace_offset = startcol - end_foundcol; - } - - /* - * adjust startcol for spaces that will be deleted and - * characters that will remain on top line - */ - curwin->w_cursor.col = foundcol; - while ((cc = gchar_cursor(), WHITECHAR(cc)) - && (!fo_white_par || curwin->w_cursor.col < startcol)) { - inc_cursor(); - } - startcol -= curwin->w_cursor.col; - if (startcol < 0) { - startcol = 0; - } - - if (State & VREPLACE_FLAG) { - // In MODE_VREPLACE state, we will backspace over the text to be - // wrapped, so save a copy now to put on the next line. - saved_text = vim_strsave(get_cursor_pos_ptr()); - curwin->w_cursor.col = orig_col; - saved_text[startcol] = NUL; - - // Backspace over characters that will move to the next line - if (!fo_white_par) { - backspace_until_column(foundcol); - } - } else { - // put cursor after pos. to break line - if (!fo_white_par) { - curwin->w_cursor.col = foundcol; - } - } - - /* - * Split the line just before the margin. - * Only insert/delete lines, but don't really redraw the window. - */ - open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX - + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) - + (do_comments ? OPENLINE_DO_COM : 0) - + OPENLINE_FORMAT - + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0), - ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent), - &did_do_comment); - if (!(flags & INSCHAR_COM_LIST)) { - old_indent = 0; - } - - // If a comment leader was inserted, may also do this on a following - // line. - if (did_do_comment) { - no_leader = false; - } - - replace_offset = 0; - if (first_line) { - if (!(flags & INSCHAR_COM_LIST)) { - // This section is for auto-wrap of numeric lists. When not - // in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST - // flag will be set and open_line() will handle it (as seen - // above). The code here (and in get_number_indent()) will - // recognize comments if needed... - if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) { - second_indent = get_number_indent(curwin->w_cursor.lnum - 1); - } - if (second_indent >= 0) { - if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, second_indent, false, NUL, true); - } else if (leader_len > 0 && second_indent - leader_len > 0) { - int padding = second_indent - leader_len; - - // We started at the first_line of a numbered list - // that has a comment. the open_line() function has - // inserted the proper comment leader and positioned - // the cursor at the end of the split line. Now we - // add the additional whitespace needed after the - // comment leader for the numbered list. - for (int i = 0; i < padding; i++) { - ins_str((char_u *)" "); - } - changed_bytes(curwin->w_cursor.lnum, leader_len); - } else { - (void)set_indent(second_indent, SIN_CHANGED); - } - } - } - first_line = false; - } - - if (State & VREPLACE_FLAG) { - // In MODE_VREPLACE state we have backspaced over the text to be - // moved, now we re-insert it into the new line. - ins_bytes(saved_text); - xfree(saved_text); - } else { - /* - * Check if cursor is not past the NUL off the line, cindent - * may have added or removed indent. - */ - curwin->w_cursor.col += startcol; - len = (colnr_T)STRLEN(get_cursor_line_ptr()); - if (curwin->w_cursor.col > len) { - curwin->w_cursor.col = len; - } - } - - haveto_redraw = true; - can_cindent = true; - // moved the cursor, don't autoindent or cindent now - did_ai = false; - did_si = false; - can_si = false; - can_si_back = false; - line_breakcheck(); - } - - if (save_char != NUL) { // put back space after cursor - pchar_cursor((char_u)save_char); - } - - curwin->w_p_lbr = has_lbr; - - if (!format_only && haveto_redraw) { - update_topline(curwin); - redraw_curbuf_later(VALID); - } -} - -/// Called after inserting or deleting text: When 'formatoptions' includes the -/// 'a' flag format from the current line until the end of the paragraph. -/// Keep the cursor at the same position relative to the text. -/// The caller must have saved the cursor line for undo, following ones will be -/// saved here. -/// -/// @param trailblank when true also format with trailing blank -/// @param prev_line may start in previous line -void auto_format(bool trailblank, bool prev_line) -{ - pos_T pos; - colnr_T len; - char_u *old; - char_u *new, *pnew; - int wasatend; - int cc; - - if (!has_format_option(FO_AUTO)) { - return; - } - - pos = curwin->w_cursor; - old = get_cursor_line_ptr(); - - // may remove added space - check_auto_format(false); - - // Don't format in Insert mode when the cursor is on a trailing blank, the - // user might insert normal text next. Also skip formatting when "1" is - // in 'formatoptions' and there is a single character before the cursor. - // Otherwise the line would be broken and when typing another non-white - // next they are not joined back together. - wasatend = (pos.col == (colnr_T)STRLEN(old)); - if (*old != NUL && !trailblank && wasatend) { - dec_cursor(); - cc = gchar_cursor(); - if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 - && has_format_option(FO_ONE_LETTER)) { - dec_cursor(); - } - cc = gchar_cursor(); - if (WHITECHAR(cc)) { - curwin->w_cursor = pos; - return; - } - curwin->w_cursor = pos; - } - - // With the 'c' flag in 'formatoptions' and 't' missing: only format - // comments. - if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) - && get_leader_len((char *)old, NULL, false, true) == 0) { - return; - } - - /* - * May start formatting in a previous line, so that after "x" a word is - * moved to the previous line if it fits there now. Only when this is not - * the start of a paragraph. - */ - if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) { - --curwin->w_cursor.lnum; - if (u_save_cursor() == FAIL) { - return; - } - } - - /* - * Do the formatting and restore the cursor position. "saved_cursor" will - * be adjusted for the text formatting. - */ - saved_cursor = pos; - format_lines((linenr_T) - 1, false); - curwin->w_cursor = saved_cursor; - saved_cursor.lnum = 0; - - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - // "cannot happen" - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); - } else { - check_cursor_col(); - } - - // Insert mode: If the cursor is now after the end of the line while it - // previously wasn't, the line was broken. Because of the rule above we - // need to add a space when 'w' is in 'formatoptions' to keep a paragraph - // formatted. - if (!wasatend && has_format_option(FO_WHITE_PAR)) { - new = get_cursor_line_ptr(); - len = (colnr_T)STRLEN(new); - if (curwin->w_cursor.col == len) { - pnew = vim_strnsave(new, (size_t)len + 2); - pnew[len] = ' '; - pnew[len + 1] = NUL; - ml_replace(curwin->w_cursor.lnum, (char *)pnew, false); - // remove the space later - did_add_space = true; - } else { - // may remove added space - check_auto_format(false); - } - } - - check_cursor(); -} - -/// When an extra space was added to continue a paragraph for auto-formatting, -/// delete it now. The space must be under the cursor, just after the insert -/// position. -/// -/// @param end_insert true when ending Insert mode -static void check_auto_format(bool end_insert) -{ - int c = ' '; - int cc; - - if (did_add_space) { - cc = gchar_cursor(); - if (!WHITECHAR(cc)) { - // Somehow the space was removed already. - did_add_space = false; - } else { - if (!end_insert) { - inc_cursor(); - c = gchar_cursor(); - dec_cursor(); - } - if (c != NUL) { - // The space is no longer at the end of the line, delete it. - del_char(false); - did_add_space = false; - } - } - } -} - -/// Find out textwidth to be used for formatting: -/// if 'textwidth' option is set, use it -/// else if 'wrapmargin' option is set, use curwin->w_width_inner-'wrapmargin' -/// if invalid value, use 0. -/// Set default to window width (maximum 79) for "gq" operator. -/// -/// @param ff force formatting (for "gq" command) -int comp_textwidth(bool ff) -{ - int textwidth = (int)curbuf->b_p_tw; - if (textwidth == 0 && curbuf->b_p_wm) { - // The width is the window width minus 'wrapmargin' minus all the - // things that add to the margin. - textwidth = curwin->w_width_inner - (int)curbuf->b_p_wm; - if (cmdwin_type != 0) { - textwidth -= 1; - } - textwidth -= win_fdccol_count(curwin); - textwidth -= win_signcol_count(curwin); - - if (curwin->w_p_nu || curwin->w_p_rnu) { - textwidth -= 8; - } - } - if (textwidth < 0) { - textwidth = 0; - } - if (ff && textwidth == 0) { - textwidth = curwin->w_width_inner - 1; - if (textwidth > 79) { - textwidth = 79; - } - } - return textwidth; -} - -/* - * Put a character in the redo buffer, for when just after a CTRL-V. - */ +// Put a character in the redo buffer, for when just after a CTRL-V. static void redo_literal(int c) { char buf[10]; @@ -2849,10 +2227,8 @@ static void start_arrow_common(pos_T *end_insert_pos, bool end_change) check_spell_redraw(); } -/* - * If we skipped highlighting word at cursor, do it now. - * It may be skipped again, thus reset spell_redraw_lnum first. - */ +// If we skipped highlighting word at cursor, do it now. +// It may be skipped again, thus reset spell_redraw_lnum first. static void check_spell_redraw(void) { if (spell_redraw_lnum != 0) { @@ -2863,11 +2239,9 @@ static void check_spell_redraw(void) } } -/* - * 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. - */ +// 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. int stop_arrow(void) { if (arrow_used) { @@ -2877,7 +2251,7 @@ int stop_arrow(void) // right, except when nothing was inserted yet. update_Insstart_orig = false; } - Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr()); + Insstart_textlen = (colnr_T)linetabsize((char_u *)get_cursor_line_ptr()); if (u_save_cursor() == OK) { arrow_used = false; @@ -2917,11 +2291,9 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) stop_redo_ins(); replace_flush(); // abandon replace stack - /* - * Save the inserted text for later redo with ^@ and CTRL-A. - * Don't do it when "restart_edit" was set and nothing was inserted, - * otherwise CTRL-O w and then <Left> will clear "last_insert". - */ + // Save the inserted text for later redo with ^@ and CTRL-A. + // Don't do it when "restart_edit" was set and nothing was inserted, + // otherwise CTRL-O w and then <Left> will clear "last_insert". ptr = get_inserted(); if (did_restart_edit == 0 || (ptr != NULL && (int)STRLEN(ptr) > new_insert_skip)) { @@ -2958,8 +2330,8 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) if (gchar_cursor() != NUL) { inc_cursor(); } - /* If the cursor is still at the same character, also keep - * the "coladd". */ + // If the cursor is still at the same character, also keep + // the "coladd". if (gchar_cursor() == NUL && curwin->w_cursor.lnum == tpos.lnum && curwin->w_cursor.col == tpos.col) { @@ -2986,7 +2358,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) check_cursor_col(); // make sure it is not past the line for (;;) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) { - --curwin->w_cursor.col; + curwin->w_cursor.col--; } cc = gchar_cursor(); if (!ascii_iswhite(cc)) { @@ -3003,7 +2375,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) tpos = curwin->w_cursor; tpos.col++; if (cc != NUL && gchar_pos(&tpos) == NUL) { - ++curwin->w_cursor.col; // put cursor back on the NUL + curwin->w_cursor.col++; // put cursor back on the NUL } } @@ -3028,10 +2400,8 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) } } -/* - * Set the last inserted text to a single character. - * Used for the replace command. - */ +// Set the last inserted text to a single character. +// Used for the replace command. void set_last_insert(int c) { char_u *s; @@ -3056,13 +2426,11 @@ void free_last_insert(void) } #endif -/* - * move cursor to start of line - * if flags & BL_WHITE move to first non-white - * if flags & BL_SOL move to first non-white if startofline is set, - * otherwise keep "curswant" column - * if flags & BL_FIX don't leave the cursor on a NUL. - */ +// move cursor to start of line +// if flags & BL_WHITE move to first non-white +// if flags & BL_SOL move to first non-white if startofline is set, +// otherwise keep "curswant" column +// if flags & BL_FIX don't leave the cursor on a NUL. void beginline(int flags) { if ((flags & BL_SOL) && !p_sol) { @@ -3074,22 +2442,20 @@ void beginline(int flags) if (flags & (BL_WHITE | BL_SOL)) { char_u *ptr; - for (ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr) - && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr) { - ++curwin->w_cursor.col; + for (ptr = (char_u *)get_cursor_line_ptr(); ascii_iswhite(*ptr) + && !((flags & BL_FIX) && ptr[1] == NUL); ptr++) { + curwin->w_cursor.col++; } } - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; } } -/* - * oneright oneleft cursor_down cursor_up - * - * Move one char {right,left,down,up}. - * Doesn't move onto the NUL past the end of the line, unless it is allowed. - * Return OK when successful, FAIL when we hit a line of file boundary. - */ +// oneright oneleft cursor_down cursor_up +// +// Move one char {right,left,down,up}. +// Doesn't move onto the NUL past the end of the line, unless it is allowed. +// Return OK when successful, FAIL when we hit a line of file boundary. int oneright(void) { @@ -3100,7 +2466,7 @@ int oneright(void) pos_T prevpos = curwin->w_cursor; // Adjust for multi-wide char (excluding TAB) - ptr = (char *)get_cursor_pos_ptr(); + ptr = get_cursor_pos_ptr(); coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) ? ptr2cells(ptr) : 1)); curwin->w_set_curswant = true; @@ -3109,7 +2475,7 @@ int oneright(void) || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL; } - ptr = (char *)get_cursor_pos_ptr(); + ptr = get_cursor_pos_ptr(); if (*ptr == NUL) { return FAIL; // already at the very end } @@ -3123,7 +2489,7 @@ int oneright(void) } curwin->w_cursor.col += l; - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; return OK; } @@ -3152,13 +2518,13 @@ int oneleft(void) if (curwin->w_cursor.coladd == 1) { // Adjust for multi-wide char (not a TAB) - char *ptr = (char *)get_cursor_pos_ptr(); + char *ptr = get_cursor_pos_ptr(); if (*ptr != TAB && vim_isprintc(utf_ptr2char(ptr)) && ptr2cells(ptr) > 1) { curwin->w_cursor.coladd = 0; } } - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; return OK; } @@ -3166,8 +2532,8 @@ int oneleft(void) return FAIL; } - curwin->w_set_curswant = TRUE; - --curwin->w_cursor.col; + curwin->w_set_curswant = true; + curwin->w_cursor.col--; // if the character on the left of the current cursor is a multi-byte // character, move to its first byte @@ -3175,98 +2541,112 @@ int oneleft(void) return OK; } -/// @oaram upd_topline When TRUE: update topline -int cursor_up(long n, int upd_topline) +/// Move the cursor up "n" lines in window "wp". +/// Takes care of closed folds. +/// Returns the new cursor line or zero for failure. +linenr_T cursor_up_inner(win_T *wp, long n) { - linenr_T lnum; + linenr_T lnum = wp->w_cursor.lnum; - if (n > 0) { - lnum = curwin->w_cursor.lnum; + // This fails if the cursor is already in the first line. + if (lnum <= 1) { + return 0; + } + if (n >= lnum) { + lnum = 1; + } else if (hasAnyFolding(wp)) { + // Count each sequence of folded lines as one logical line. - // This fails if the cursor is already in the first line. - if (lnum <= 1) { - return FAIL; - } - if (n >= lnum) { - lnum = 1; - } else if (hasAnyFolding(curwin)) { - /* - * Count each sequence of folded lines as one logical line. - */ - // go to the start of the current fold - (void)hasFolding(lnum, &lnum, NULL); - - while (n--) { - // move up one line - lnum--; - if (lnum <= 1) { - break; - } - // If we entered a fold, move to the beginning, unless in - // Insert mode or when 'foldopen' contains "all": it will open - // in a moment. - if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) { - (void)hasFolding(lnum, &lnum, NULL); - } + // go to the start of the current fold + (void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + + while (n--) { + // move up one line + lnum--; + if (lnum <= 1) { + break; } - if (lnum < 1) { - lnum = 1; + // If we entered a fold, move to the beginning, unless in + // Insert mode or when 'foldopen' contains "all": it will open + // in a moment. + if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) { + (void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); } - } else { - lnum -= (linenr_T)n; } - curwin->w_cursor.lnum = lnum; + if (lnum < 1) { + lnum = 1; + } + } else { + lnum -= (linenr_T)n; + } + + wp->w_cursor.lnum = lnum; + return lnum; +} + +/// @param upd_topline When true: update topline +int cursor_up(long n, int upd_topline) +{ + if (n > 0 && cursor_up_inner(curwin, n) == 0) { + return FAIL; } // try to advance to the column we want to be at coladvance(curwin->w_curswant); if (upd_topline) { - update_topline(curwin); // make sure curwin->w_topline is valid + update_topline(curwin); // make sure curwin->w_topline is valid } return OK; } -/// Cursor down a number of logical lines. -/// -/// @param upd_topline When TRUE: update topline -int cursor_down(long n, int upd_topline) +/// Move the cursor down "n" lines in window "wp". +/// Takes care of closed folds. +/// Returns the new cursor line or zero for failure. +linenr_T cursor_down_inner(win_T *wp, long n) { - linenr_T lnum; + linenr_T lnum = wp->w_cursor.lnum; + linenr_T line_count = wp->w_buffer->b_ml.ml_line_count; - if (n > 0) { - lnum = curwin->w_cursor.lnum; - // Move to last line of fold, will fail if it's the end-of-file. - (void)hasFolding(lnum, NULL, &lnum); - - // This fails if the cursor is already in the last line. - if (lnum >= curbuf->b_ml.ml_line_count) { - return FAIL; - } - if (lnum + n >= curbuf->b_ml.ml_line_count) { - lnum = curbuf->b_ml.ml_line_count; - } else if (hasAnyFolding(curwin)) { - linenr_T last; + // Move to last line of fold, will fail if it's the end-of-file. + (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + // This fails if the cursor is already in the last line. + if (lnum >= line_count) { + return FAIL; + } + if (lnum + n >= line_count) { + lnum = line_count; + } else if (hasAnyFolding(wp)) { + linenr_T last; - // count each sequence of folded lines as one logical line - while (n--) { - if (hasFolding(lnum, NULL, &last)) { - lnum = last + 1; - } else { - lnum++; - } - if (lnum >= curbuf->b_ml.ml_line_count) { - break; - } + // count each sequence of folded lines as one logical line + while (n--) { + if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) { + lnum = last + 1; + } else { + lnum++; } - if (lnum > curbuf->b_ml.ml_line_count) { - lnum = curbuf->b_ml.ml_line_count; + if (lnum >= line_count) { + break; } - } else { - lnum += (linenr_T)n; } - curwin->w_cursor.lnum = lnum; + if (lnum > line_count) { + lnum = line_count; + } + } else { + lnum += (linenr_T)n; + } + + wp->w_cursor.lnum = lnum; + return lnum; +} + +/// @param upd_topline When true: update topline +int cursor_down(long n, int upd_topline) +{ + if (n > 0 && cursor_down_inner(curwin, n) == 0) { + return FAIL; } // try to advance to the column we want to be at @@ -3288,12 +2668,12 @@ int cursor_down(long n, int upd_topline) /// @param no_esc Don't add an ESC at the end int stuff_inserted(int c, long count, int no_esc) { - char_u *esc_ptr; - char_u *ptr; - char_u *last_ptr; - char_u last = NUL; + char *esc_ptr; + char *ptr; + char *last_ptr; + char last = NUL; - ptr = get_last_insert(); + ptr = (char *)get_last_insert(); if (ptr == NULL) { emsg(_(e_noinstext)); return FAIL; @@ -3303,7 +2683,7 @@ int stuff_inserted(int c, long count, int no_esc) if (c != NUL) { stuffcharReadbuff(c); } - if ((esc_ptr = STRRCHR(ptr, ESC)) != NULL) { + if ((esc_ptr = strrchr(ptr, ESC)) != NULL) { // remove the ESC. *esc_ptr = NUL; } @@ -3311,7 +2691,7 @@ int stuff_inserted(int c, long count, int no_esc) // when the last char is either "0" or "^" it will be quoted if no ESC // comes after it OR if it will inserted more than once and "ptr" // starts with ^D. -- Acevedo - last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1; + last_ptr = (esc_ptr ? esc_ptr : ptr + strlen(ptr)) - 1; if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^') && (no_esc || (*ptr == Ctrl_D && count > 1))) { last = *last_ptr; @@ -3351,25 +2731,23 @@ char_u *get_last_insert(void) return last_insert + last_insert_skip; } -/* - * Get last inserted string, and remove trailing <Esc>. - * Returns pointer to allocated memory (must be freed) or NULL. - */ +// Get last inserted string, and remove trailing <Esc>. +// Returns pointer to allocated memory (must be freed) or NULL. char_u *get_last_insert_save(void) { - char_u *s; + char *s; int len; if (last_insert == NULL) { return NULL; } - s = vim_strsave(last_insert + last_insert_skip); + s = xstrdup((char *)last_insert + last_insert_skip); len = (int)STRLEN(s); if (len > 0 && s[len - 1] == ESC) { // remove trailing ESC s[len - 1] = NUL; } - return s; + return (char_u *)s; } /// Check the word in front of the cursor for an abbreviation. @@ -3389,24 +2767,22 @@ static bool echeck_abbr(int c) return false; } - return check_abbr(c, get_cursor_line_ptr(), curwin->w_cursor.col, + return check_abbr(c, (char_u *)get_cursor_line_ptr(), curwin->w_cursor.col, curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0); } -/* - * replace-stack functions - * - * When replacing characters, the replaced characters are remembered for each - * new character. This is used to re-insert the old text when backspacing. - * - * There is a NUL headed list of characters for each character that is - * currently in the file after the insertion point. When BS is used, one NUL - * headed list is put back for the deleted character. - * - * For a newline, there are two NUL headed lists. One contains the characters - * that the NL replaced. The extra one stores the characters after the cursor - * that were deleted (always white space). - */ +// replace-stack functions +// +// When replacing characters, the replaced characters are remembered for each +// new character. This is used to re-insert the old text when backspacing. +// +// There is a NUL headed list of characters for each character that is +// currently in the file after the insertion point. When BS is used, one NUL +// headed list is put back for the deleted character. +// +// For a newline, there are two NUL headed lists. One contains the characters +// that the NL replaced. The extra one stores the characters after the cursor +// that were deleted (always white space). static char_u *replace_stack = NULL; static ssize_t replace_stack_nr = 0; // next entry in replace stack @@ -3437,17 +2813,16 @@ void replace_push(int c) replace_stack_nr++; } -/* - * Push a character onto the replace stack. Handles a multi-byte character in - * reverse byte order, so that the first byte is popped off first. - * Return the number of bytes done (includes composing characters). - */ -int replace_push_mb(char_u *p) +/// Push a character onto the replace stack. Handles a multi-byte character in +/// reverse byte order, so that the first byte is popped off first. +/// +/// @return the number of bytes done (includes composing characters). +int replace_push_mb(char *p) { - int l = utfc_ptr2len((char *)p); + int l = utfc_ptr2len(p); int j; - for (j = l - 1; j >= 0; --j) { + for (j = l - 1; j >= 0; j--) { replace_push(p[j]); } return l; @@ -3492,10 +2867,8 @@ static void replace_pop_ins(void) State = oldState; } -/* - * Insert bytes popped from the replace stack. "cc" is the first byte. If it - * indicates a multi-byte char, pop the other bytes too. - */ +// Insert bytes popped from the replace stack. "cc" is the first byte. If it +// indicates a multi-byte char, pop the other bytes too. static void mb_replace_pop_ins(int cc) { int n; @@ -3508,7 +2881,7 @@ static void mb_replace_pop_ins(int cc) for (i = 1; i < n; i++) { buf[i] = (char_u)replace_pop(); } - ins_bytes_len(buf, (size_t)n); + ins_bytes_len((char *)buf, (size_t)n); } else { ins_char(cc); } @@ -3531,7 +2904,7 @@ static void mb_replace_pop_ins(int cc) buf[i] = (char_u)replace_pop(); } if (utf_iscomposing(utf_ptr2char((char *)buf))) { - ins_bytes_len(buf, (size_t)n); + ins_bytes_len((char *)buf, (size_t)n); } else { // Not a composing char, put it back. for (i = n - 1; i >= 0; i--) { @@ -3542,10 +2915,8 @@ static void mb_replace_pop_ins(int cc) } } -/* - * make the replace stack empty - * (called when exiting replace mode) - */ +// make the replace stack empty +// (called when exiting replace mode) static void replace_flush(void) { XFREE_CLEAR(replace_stack); @@ -3553,15 +2924,13 @@ static void replace_flush(void) replace_stack_nr = 0; } -/* - * Handle doing a BS for one character. - * cc < 0: replace stack empty, just move cursor - * cc == 0: character was inserted, delete it - * cc > 0: character was replaced, put cc (first byte of original char) back - * and check for more characters to be put back - * When "limit_col" is >= 0, don't delete before this column. Matters when - * using composing characters, use del_char_after_col() instead of del_char(). - */ +// Handle doing a BS for one character. +// cc < 0: replace stack empty, just move cursor +// cc == 0: character was inserted, delete it +// cc > 0: character was replaced, put cc (first byte of original char) back +// and check for more characters to be put back +// When "limit_col" is >= 0, don't delete before this column. Matters when +// using composing characters, use del_char_after_col() instead of del_char(). static void replace_do_bs(int limit_col) { int cc; @@ -3584,18 +2953,18 @@ static void replace_do_bs(int limit_col) } (void)del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { - orig_len = (int)STRLEN(get_cursor_pos_ptr()); + orig_len = (int)strlen(get_cursor_pos_ptr()); } replace_push(cc); replace_pop_ins(); if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the inserted characters - p = get_cursor_pos_ptr(); + p = (char_u *)get_cursor_pos_ptr(); ins_len = (int)STRLEN(p) - orig_len; vcol = start_vcol; for (i = 0; i < ins_len; i++) { - vcol += win_chartabsize(curwin, p + i, vcol); + vcol += win_chartabsize(curwin, (char *)p + i, vcol); i += utfc_ptr2len((char *)p) - 1; } vcol -= start_vcol; @@ -3624,12 +2993,10 @@ bool cindent_on(void) return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL); } -/* - * Re-indent the current line, based on the current contents of it and the - * surrounding lines. Fixing the cursor position seems really easy -- I'm very - * confused what all the part that handles Control-T is doing that I'm not. - * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent. - */ +// Re-indent the current line, based on the current contents of it and the +// surrounding lines. Fixing the cursor position seems really easy -- I'm very +// confused what all the part that handles Control-T is doing that I'm not. +// "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent. void fixthisline(IndentGetter get_the_indent) { int amount = get_the_indent(); @@ -3657,7 +3024,7 @@ void fix_indent(void) /// Check that "cinkeys" contains the key "keytyped", /// when == '*': Only if key is preceded with '*' (indent before insert) /// when == '!': Only if key is preceded with '!' (don't insert) -/// when == ' ': Only if key is not preceded with '*' (indent afterwards) +/// when == ' ': Only if key is not preceded with '*' or '!' (indent afterwards) /// /// "keytyped" can have a few special values: /// KEY_OPEN_FORW : @@ -3682,22 +3049,20 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) } if (*curbuf->b_p_inde != NUL) { - look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys' + look = (char_u *)curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys' } else { - look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys' + look = (char_u *)curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys' } while (*look) { - /* - * Find out if we want to try a match with this key, depending on - * 'when' and a '*' or '!' before the key. - */ + // Find out if we want to try a match with this key, depending on + // 'when' and a '*' or '!' before the key. switch (when) { case '*': try_match = (*look == '*'); break; case '!': try_match = (*look == '!'); break; default: - try_match = (*look != '*'); break; + try_match = (*look != '*') && (*look != '!'); break; } if (*look == '*' || *look == '!') { look++; @@ -3739,7 +3104,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) // cursor. } else if (*look == 'e') { if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) { - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); if ((char_u *)skipwhite((char *)p) == p + curwin->w_cursor.col - 4 && STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) { return true; @@ -3752,12 +3117,12 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) // class::method for C++). } else if (*look == ':') { if (try_match && keytyped == ':') { - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); if (cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel()) { return true; } // Need to get the line again after cin_islabel(). - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); if (curwin->w_cursor.col > 2 && p[curwin->w_cursor.col - 1] == ':' && p[curwin->w_cursor.col - 2] == ':') { @@ -3765,7 +3130,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) const bool i = cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel(); - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); p[curwin->w_cursor.col - 1] = ':'; if (i) { return true; @@ -3815,9 +3180,9 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) if (keytyped == KEY_COMPLETE) { char_u *n, *s; - /* Just completed a word, check if it starts with "look". - * search back for the start of a word. */ - line = get_cursor_line_ptr(); + // Just completed a word, check if it starts with "look". + // search back for the start of a word. + line = (char_u *)get_cursor_line_ptr(); for (s = line + curwin->w_cursor.col; s > line; s = n) { n = mb_prevptr(line, s); if (!vim_iswordp(n)) { @@ -3827,7 +3192,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX); if (s + (p - look) <= line + curwin->w_cursor.col && (icase - ? mb_strnicmp(s, look, (size_t)(p - look)) + ? mb_strnicmp((char *)s, (char *)look, (size_t)(p - look)) : STRNCMP(s, look, p - look)) == 0) { match = true; } @@ -3836,20 +3201,20 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) if (keytyped == (int)p[-1] || (icase && keytyped < 256 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) { - line = get_cursor_pos_ptr(); + line = (char_u *)get_cursor_pos_ptr(); assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX); if ((curwin->w_cursor.col == (colnr_T)(p - look) || !vim_iswordc(line[-(p - look) - 1])) && (icase - ? mb_strnicmp(line - (p - look), look, (size_t)(p - look)) + ? mb_strnicmp((char *)line - (p - look), (char *)look, (size_t)(p - look)) : STRNCMP(line - (p - look), look, p - look)) == 0) { match = true; } } } if (match && try_match_word && !try_match) { - /* "0=word": Check if there are only blanks before the - * word. */ + // "0=word": Check if there are only blanks before the + // word. if (getwhitecols_curline() != (int)(curwin->w_cursor.col - (p - look))) { match = false; @@ -3871,17 +3236,13 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) } } - /* - * Skip over ", ". - */ - look = skip_to_option_part(look); + // Skip over ", ". + look = (char_u *)skip_to_option_part((char *)look); } return false; } -/* - * Map Hebrew keyboard when in hkmap mode. - */ +// Map Hebrew keyboard when in hkmap mode. int hkmap(int c) FUNC_ATTR_PURE { @@ -3983,9 +3344,7 @@ static void ins_reg(void) int literally = 0; int vis_active = VIsual_active; - /* - * If we are going to wait for a character, show a '"'. - */ + // If we are going to wait for a character, show a '"'. pc_status = PC_STATUS_UNSET; if (redrawing() && !char_avail()) { // may need to redraw when no more chars available now @@ -4000,13 +3359,13 @@ static void ins_reg(void) no_mapping++; allow_keys++; regname = plain_vgetc(); - LANGMAP_ADJUST(regname, TRUE); + LANGMAP_ADJUST(regname, true); if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) { // Get a third key for literal register insertion literally = regname; add_to_showcmd_c(literally); regname = plain_vgetc(); - LANGMAP_ADJUST(regname, TRUE); + LANGMAP_ADJUST(regname, true); } no_mapping--; allow_keys--; @@ -4044,7 +3403,7 @@ static void ins_reg(void) need_redraw = true; // remove the '"' } else if (stop_insert_mode) { // When the '=' register was used and a function was invoked that - // did ":stopinsert" then stuff_empty() returns FALSE but we won't + // did ":stopinsert" then stuff_empty() returns false but we won't // insert anything, need to remove the '"' need_redraw = true; } @@ -4067,9 +3426,7 @@ static void ins_reg(void) } } -/* - * CTRL-G commands in Insert mode. - */ +// CTRL-G commands in Insert mode. static void ins_ctrl_g(void) { int c; @@ -4123,9 +3480,7 @@ static void ins_ctrl_g(void) } } -/* - * CTRL-^ in Insert mode. - */ +// CTRL-^ in Insert mode. static void ins_ctrl_hat(void) { if (map_to_exists_mode("", MODE_LANGMAP, false)) { @@ -4169,10 +3524,8 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) AppendToRedobuff(ESC_STR); } - /* - * Repeating insert may take a long time. Check for - * interrupt now and then. - */ + // Repeating insert may take a long time. Check for + // interrupt now and then. if (*count > 0) { line_breakcheck(); if (got_int) { @@ -4195,7 +3548,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) // Repeat the insert return false; } - stop_insert(&curwin->w_cursor, TRUE, nomove); + stop_insert(&curwin->w_cursor, true, nomove); undisplay_dollar(); } @@ -4215,10 +3568,8 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum, view); } - /* - * The cursor should end up on the last inserted character. - * Don't do it for CTRL-O, unless past the end of the line. - */ + // The cursor should end up on the last inserted character. + // Don't do it for CTRL-O, unless past the end of the line. if (!nomove && (curwin->w_cursor.col != 0 || curwin->w_cursor.coladd > 0) && (restart_edit == NUL || (gchar_cursor() == NUL && !VIsual_active)) @@ -4256,15 +3607,13 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) return true; } -/* - * Toggle language: hkmap and revins_on. - * Move to end of reverse inserted text. - */ +// Toggle language: hkmap and revins_on. +// Move to end of reverse inserted text. static void ins_ctrl_(void) { if (revins_on && revins_chars && revins_scol >= 0) { while (gchar_cursor() != NUL && revins_chars--) { - ++curwin->w_cursor.col; + curwin->w_cursor.col++; } } p_ri = !p_ri; @@ -4326,9 +3675,7 @@ static bool ins_start_select(int c) return false; } -/* - * <Insert> key in Insert mode: toggle insert/replace mode. - */ +// <Insert> key in Insert mode: toggle insert/replace mode. static void ins_insert(int replaceState) { set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" : @@ -4346,9 +3693,7 @@ static void ins_insert(int replaceState) ui_cursor_shape(); // may show different cursor shape } -/* - * Pressed CTRL-O in Insert mode. - */ +// Pressed CTRL-O in Insert mode. static void ins_ctrl_o(void) { if (State & VREPLACE_FLAG) { @@ -4365,13 +3710,11 @@ static void ins_ctrl_o(void) } } -/* - * If the cursor is on an indent, ^T/^D insert/delete one - * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". - * Always round the indent to 'shiftwidth', this is compatible - * with vi. But vi only supports ^T and ^D after an - * autoindent, we support it everywhere. - */ +// If the cursor is on an indent, ^T/^D insert/delete one +// shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". +// Always round the indent to 'shiftwidth', this is compatible +// with vi. But vi only supports ^T and ^D after an +// autoindent, we support it everywhere. static void ins_shift(int c, int lastc) { if (stop_arrow() == FAIL) { @@ -4379,9 +3722,7 @@ static void ins_shift(int c, int lastc) } AppendCharToRedobuff(c); - /* - * 0^D and ^^D: remove all indent. - */ + // 0^D and ^^D: remove all indent. if (c == Ctrl_D && (lastc == '0' || lastc == '^') && curwin->w_cursor.col > 0) { curwin->w_cursor.col--; @@ -4393,12 +3734,12 @@ static void ins_shift(int c, int lastc) if (lastc == '^') { old_indent = get_indent(); // remember curr. indent } - change_indent(INDENT_SET, 0, TRUE, 0, TRUE); + change_indent(INDENT_SET, 0, true, 0, true); } else { - change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); + change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, true, 0, true); } - if (did_ai && *skipwhite((char *)get_cursor_line_ptr()) != NUL) { + if (did_ai && *skipwhite(get_cursor_line_ptr()) != NUL) { did_ai = false; } did_si = false; @@ -4437,9 +3778,7 @@ static void ins_del(void) AppendCharToRedobuff(K_DEL); } -/* - * Delete one character for ins_bs(). - */ +// Delete one character for ins_bs(). static void ins_bs_one(colnr_T *vcolp) { dec_cursor(); @@ -4532,13 +3871,11 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) return false; } Insstart.lnum--; - Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum)); + Insstart.col = (colnr_T)strlen(ml_get(Insstart.lnum)); } - /* - * In replace mode: - * cc < 0: NL was inserted, delete it - * cc >= 0: NL was replaced, put original characters back - */ + // In replace mode: + // cc < 0: NL was inserted, delete it + // cc >= 0: NL was replaced, put original characters back cc = -1; if (State & REPLACE_FLAG) { cc = replace_pop(); // returns -1 if NL was inserted @@ -4558,7 +3895,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // again when auto-formatting. if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { - char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); + char_u *ptr = (char_u *)ml_get_buf(curbuf, curwin->w_cursor.lnum, true); int len; len = (int)STRLEN(ptr); @@ -4567,7 +3904,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) } } - do_join(2, FALSE, FALSE, FALSE, false); + do_join(2, false, false, false, false); if (temp == NUL && gchar_cursor() != NUL) { inc_cursor(); } @@ -4618,9 +3955,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) curwin->w_cursor.col = save_col; } - /* - * Handle deleting one 'shiftwidth' or 'softtabstop'. - */ + // Handle deleting one 'shiftwidth' or 'softtabstop'. if (mode == BACKSPACE_CHAR && ((p_sta && in_indent) || ((get_sts_value() != 0 @@ -4654,7 +3989,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // delete characters until we are at or before want_vcol while (vcol > want_vcol && curwin->w_cursor.col > 0 - && (cc = *(get_cursor_pos_ptr() - 1), ascii_iswhite(cc))) { + && (cc = (uint8_t)(*(get_cursor_pos_ptr() - 1)), ascii_iswhite(cc))) { ins_bs_one(&vcol); } @@ -4669,7 +4004,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (State & VREPLACE_FLAG) { ins_char(' '); } else { - ins_str((char_u *)" "); + ins_str(" "); if ((State & REPLACE_FLAG)) { replace_push(NUL); } @@ -4686,7 +4021,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Delete up to starting point, start of line or previous word. int prev_cclass = 0; - int cclass = mb_get_class(get_cursor_pos_ptr()); + int cclass = mb_get_class((char_u *)get_cursor_pos_ptr()); do { if (!revins_on) { // put cursor on char to be deleted dec_cursor(); @@ -4694,7 +4029,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) cc = gchar_cursor(); // look multi-byte character class prev_cclass = cclass; - cclass = mb_get_class(get_cursor_pos_ptr()); + cclass = mb_get_class((char_u *)get_cursor_pos_ptr()); if (mode == BACKSPACE_WORD && !ascii_isspace(cc)) { // start of word? mode = BACKSPACE_WORD_NOT_SPACE; temp = vim_iswordc(cc); @@ -4849,7 +4184,7 @@ static void ins_mousescroll(int dir) } } - curwin->w_redr_status = TRUE; + curwin->w_redr_status = true; curwin = old_curwin; curbuf = curwin->w_buffer; @@ -4880,7 +4215,7 @@ static void ins_left(void) revins_legal++; } revins_chars++; - } else if (vim_strchr((char *)p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) { + } else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) { // if 'whichwrap' set for cursor in insert mode may go to previous line. // always break undo when moving upwards/downwards, else undo may break start_arrow(&tpos); @@ -4966,14 +4301,14 @@ static void ins_right(void) if (virtual_active()) { oneright(); } else { - curwin->w_cursor.col += utfc_ptr2len((char *)get_cursor_pos_ptr()); + curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); } revins_legal++; if (revins_chars) { revins_chars--; } - } else if (vim_strchr((char *)p_ww, ']') != NULL + } else if (vim_strchr(p_ww, ']') != NULL && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { // if 'whichwrap' set for cursor in insert mode, may move the // cursor to the next line @@ -5017,13 +4352,13 @@ static void ins_up(bool startcol) undisplay_dollar(); tpos = curwin->w_cursor; - if (cursor_up(1L, TRUE) == OK) { + if (cursor_up(1L, true) == OK) { if (startcol) { coladvance(getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } start_arrow(&tpos); can_cindent = true; @@ -5065,13 +4400,13 @@ static void ins_down(bool startcol) undisplay_dollar(); tpos = curwin->w_cursor; - if (cursor_down(1L, TRUE) == OK) { + if (cursor_down(1L, true) == OK) { if (startcol) { coladvance(getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } start_arrow(&tpos); can_cindent = true; @@ -5175,21 +4510,19 @@ static bool ins_tab(void) if (State & VREPLACE_FLAG) { ins_char(' '); } else { - ins_str((char_u *)" "); + ins_str(" "); if (State & REPLACE_FLAG) { // no char replaced replace_push(NUL); } } } - /* - * When 'expandtab' not set: Replace spaces by TABs where possible. - */ + // When 'expandtab' not set: Replace spaces by TABs where possible. if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 || get_sts_value() > 0 || (p_sta && ind))) { char_u *ptr; - char_u *saved_line = NULL; // init for GCC + char *saved_line = NULL; // init for GCC pos_T pos; pos_T fpos; pos_T *cursor; @@ -5202,10 +4535,10 @@ static bool ins_tab(void) if (State & VREPLACE_FLAG) { pos = curwin->w_cursor; cursor = &pos; - saved_line = vim_strsave(get_cursor_line_ptr()); - ptr = saved_line + pos.col; + saved_line = xstrdup(get_cursor_line_ptr()); + ptr = (char_u *)saved_line + pos.col; } else { - ptr = get_cursor_pos_ptr(); + ptr = (char_u *)get_cursor_pos_ptr(); cursor = &curwin->w_cursor; } @@ -5233,11 +4566,15 @@ static bool ins_tab(void) getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); + char_u *tab = (char_u *)"\t"; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, 0, vcol, (char *)tab, (char *)tab); + // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' // and 'linebreak' adding extra virtual columns. while (ascii_iswhite(*ptr)) { - i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); - if (vcol + i > want_vcol) { + i = lbr_chartabsize(&cts); + if (cts.cts_vcol + i > want_vcol) { break; } if (*ptr != TAB) { @@ -5252,19 +4589,24 @@ static bool ins_tab(void) } fpos.col++; ptr++; - vcol += i; + cts.cts_vcol += i; } + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (change_col >= 0) { int repl_off = 0; - char_u *line = ptr; - // Skip over the spaces we need. - while (vcol < want_vcol && *ptr == ' ') { - vcol += lbr_chartabsize(line, ptr, vcol); - ptr++; + init_chartabsize_arg(&cts, curwin, 0, vcol, (char *)ptr, (char *)ptr); + while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ') { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; repl_off++; } + ptr = (char_u *)cts.cts_ptr; + vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + if (vcol > want_vcol) { // Must have a char with 'showbreak' just before it. ptr--; @@ -5326,11 +4668,9 @@ bool ins_eol(int c) } undisplay_dollar(); - /* - * Strange Vi behaviour: In Replace mode, typing a NL will not delete the - * character under the cursor. Only push a NUL on the replace stack, - * nothing to put back when the NL is deleted. - */ + // Strange Vi behaviour: In Replace mode, typing a NL will not delete the + // character under the cursor. Only push a NUL on the replace stack, + // nothing to put back when the NL is deleted. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { replace_push(NUL); @@ -5349,7 +4689,7 @@ bool ins_eol(int c) // NL in reverse insert will always start in the end of current line. if (revins_on) { - curwin->w_cursor.col += (colnr_T)STRLEN(get_cursor_pos_ptr()); + curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); } AppendToRedobuff(NL_STR); @@ -5364,11 +4704,9 @@ bool ins_eol(int c) return i; } -/* - * Handle digraph in insert mode. - * Returns character still to be inserted, or NUL when nothing remaining to be - * done. - */ +// Handle digraph in insert mode. +// Returns character still to be inserted, or NUL when nothing remaining to be +// done. static int ins_digraph(void) { int c; @@ -5400,7 +4738,7 @@ static int ins_digraph(void) if (IS_SPECIAL(c) || mod_mask) { // special key clear_showcmd(); - insert_special(c, TRUE, FALSE); + insert_special(c, true, false); return NUL; } if (c != ESC) { @@ -5437,14 +4775,11 @@ static int ins_digraph(void) return NUL; } -/* - * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. - * Returns the char to be inserted, or NUL if none found. - */ +// Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. +// Returns the char to be inserted, or NUL if none found. int ins_copychar(linenr_T lnum) { int c; - int temp; char_u *ptr, *prev_ptr; char_u *line; @@ -5454,17 +4789,23 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - temp = 0; - line = ptr = ml_get(lnum); - prev_ptr = ptr; + line = (char_u *)ml_get(lnum); + prev_ptr = line; validate_virtcol(); - while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) { - prev_ptr = ptr; - temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); + + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, lnum, 0, (char *)line, (char *)line); + while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) { + prev_ptr = (char_u *)cts.cts_ptr; + cts.cts_vcol += lbr_chartabsize_adv(&cts); } - if ((colnr_T)temp > curwin->w_virtcol) { + + if (cts.cts_vcol > curwin->w_virtcol) { ptr = prev_ptr; + } else { + ptr = (char_u *)cts.cts_ptr; } + clear_chartabsize_arg(&cts); c = utf_ptr2char((char *)ptr); if (c == NUL) { @@ -5473,9 +4814,7 @@ int ins_copychar(linenr_T lnum) return c; } -/* - * CTRL-Y or CTRL-E typed in Insert mode. - */ +// CTRL-Y or CTRL-E typed in Insert mode. static int ins_ctrl_ey(int tc) { int c = tc; @@ -5486,7 +4825,7 @@ static int ins_ctrl_ey(int tc) } else { scrollup_clamp(); } - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } else { c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); if (c != NUL) { @@ -5501,7 +4840,7 @@ static int ins_ctrl_ey(int tc) } tw_save = curbuf->b_p_tw; curbuf->b_p_tw = -1; - insert_special(c, TRUE, FALSE); + insert_special(c, true, false); curbuf->b_p_tw = tw_save; revins_chars++; revins_legal++; @@ -5512,10 +4851,8 @@ static int ins_ctrl_ey(int tc) return c; } -/* - * Try to do some very smart auto-indenting. - * Used when inserting a "normal" character. - */ +// Try to do some very smart auto-indenting. +// Used when inserting a "normal" character. static void ins_try_si(int c) { pos_T *pos, old_pos; @@ -5523,21 +4860,17 @@ static void ins_try_si(int c) int i; bool temp; - /* - * do some very smart indenting when entering '{' or '}' - */ + // do some very smart indenting when entering '{' or '}' if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) { // for '}' set indent equal to indent of line containing matching '{' if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) { old_pos = curwin->w_cursor; - /* - * If the matching '{' has a ')' immediately before it (ignoring - * white-space), then line up with the start of the line - * containing the matching '(' if there is one. This handles the - * case where an "if (..\n..) {" statement continues over multiple - * lines -- webb - */ - ptr = ml_get(pos->lnum); + // If the matching '{' has a ')' immediately before it (ignoring + // white-space), then line up with the start of the line + // containing the matching '(' if there is one. This handles the + // case where an "if (..\n..) {" statement continues over multiple + // lines -- webb + ptr = (char_u *)ml_get(pos->lnum); i = pos->col; if (i > 0) { // skip blanks before '{' while (--i > 0 && ascii_iswhite(ptr[i])) {} @@ -5550,7 +4883,7 @@ static void ins_try_si(int c) i = get_indent(); curwin->w_cursor = old_pos; if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, i, FALSE, NUL, TRUE); + change_indent(INDENT_SET, i, false, NUL, true); } else { (void)set_indent(i, SIN_CHANGED); } @@ -5562,7 +4895,7 @@ static void ins_try_si(int c) old_pos = curwin->w_cursor; i = get_indent(); while (curwin->w_cursor.lnum > 1) { - ptr = (char_u *)skipwhite((char *)ml_get(--(curwin->w_cursor.lnum))); + ptr = (char_u *)skipwhite(ml_get(--(curwin->w_cursor.lnum))); // ignore empty lines and lines starting with '#'. if (*ptr != '#' && *ptr != NUL) { @@ -5575,14 +4908,12 @@ static void ins_try_si(int c) curwin->w_cursor = old_pos; } if (temp) { - shift_line(TRUE, FALSE, 1, TRUE); + shift_line(true, false, 1, true); } } } - /* - * set indent of '#' always to 0 - */ + // set indent of '#' always to 0 if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) { // remember current indent for next line old_indent = get_indent(); @@ -5595,10 +4926,8 @@ static void ins_try_si(int c) } } -/* - * Get the value that w_virtcol would have when 'list' is off. - * Unless 'cpo' contains the 'L' flag. - */ +// Get the value that w_virtcol would have when 'list' is off. +// Unless 'cpo' contains the 'L' flag. colnr_T get_nolist_virtcol(void) { // check validity of cursor in current buffer @@ -5613,12 +4942,10 @@ colnr_T get_nolist_virtcol(void) return curwin->w_virtcol; } -/* - * Handle the InsertCharPre autocommand. - * "c" is the character that was typed. - * Return a pointer to allocated memory with the replacement string. - * Return NULL to continue inserting "c". - */ +// Handle the InsertCharPre autocommand. +// "c" is the character that was typed. +// Return a pointer to allocated memory with the replacement string. +// Return NULL to continue inserting "c". static char_u *do_insert_char_pre(int c) { char buf[MB_MAXBYTES + 1]; @@ -5634,13 +4961,13 @@ static char_u *do_insert_char_pre(int c) textlock++; set_vim_var_string(VV_CHAR, buf, -1); - char_u *res = NULL; + char *res = NULL; if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) { // Get the value of v:char. It may be empty or more than one // character. Only use it when changed, otherwise continue with the // original character to avoid breaking autoindent. - if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) { - res = vim_strsave((char_u *)get_vim_var_str(VV_CHAR)); + if (strcmp(buf, get_vim_var_str(VV_CHAR)) != 0) { + res = xstrdup(get_vim_var_str(VV_CHAR)); } } @@ -5650,14 +4977,19 @@ static char_u *do_insert_char_pre(int c) // Restore the State, it may have been changed. State = save_State; - return res; + return (char_u *)res; } -bool can_cindent_get(void) +bool get_can_cindent(void) { return can_cindent; } +void set_can_cindent(bool val) +{ + can_cindent = val; +} + /// Trigger "event" and take care of fixing undo. int ins_apply_autocmds(event_T event) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index cb46e26f82..ebc60ea5c7 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6,12 +6,6 @@ #include <math.h> #include <stdlib.h> -#include "auto/config.h" - -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif - #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -36,6 +30,7 @@ #include "nvim/ex_session.h" #include "nvim/getchar.h" #include "nvim/highlight_group.h" +#include "nvim/locale.h" #include "nvim/lua/executor.h" #include "nvim/mark.h" #include "nvim/memline.h" @@ -101,7 +96,7 @@ 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_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 @@ -363,7 +358,7 @@ void eval_init(void) for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { struct vimvar *p = &vimvars[i]; - assert(STRLEN(p->vv_name) <= VIMVAR_KEY_LEN); + 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; @@ -583,7 +578,7 @@ void var_redir_str(char *value, int value_len) int len; if (value_len == -1) { - len = (int)STRLEN(value); // Append the entire string + len = (int)strlen(value); // Append the entire string } else { len = value_len; // Append only "value_len" characters } @@ -631,7 +626,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to, 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)) { + if (eval_to_bool(p_ccv, &err, NULL, false)) { err = true; } set_vim_var_string(VV_CC_FROM, NULL, -1); @@ -651,7 +646,7 @@ int eval_printexpr(const char *const fname, const char *const args) 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)) { + if (eval_to_bool(p_pexpr, &err, NULL, false)) { err = true; } set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -671,7 +666,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char 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); + (void)eval_to_bool(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); @@ -691,11 +686,11 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch } /// Top level evaluation function, returning a boolean. -/// Sets "error" to TRUE if there was an error. +/// Sets "error" to true if there was an error. /// /// @param skip only parse, don't execute /// -/// @return TRUE or FALSE. +/// @return true or false. int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip) { typval_T tv; @@ -762,7 +757,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *r if (s == NULL || *s == NUL) { return FAIL; } - funcexe.evaluate = true; + funcexe.fe_evaluate = true; if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { return FAIL; } @@ -772,8 +767,8 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *r if (s == NULL || *s == NUL) { return FAIL; } - funcexe.evaluate = true; - funcexe.partial = partial; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { return FAIL; } @@ -895,7 +890,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert) /// Call eval_to_string() without using current local variables and using /// textlock. /// -/// @param use_sandbox when TRUE, use the sandbox. +/// @param use_sandbox when true, use the sandbox. char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox) { char *retval; @@ -1083,7 +1078,7 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett FUNC_ATTR_NONNULL_ALL { int ret; - int len = (int)STRLEN(func); + int len = (int)strlen(func); partial_T *pt = NULL; if (len >= 6 && !memcmp(func, "v:lua.", 6)) { @@ -1098,10 +1093,10 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett 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; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; + funcexe.fe_partial = pt; ret = call_func(func, len, rettv, argc, argv, &funcexe); fail: @@ -1672,7 +1667,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool // handle +=, -=, *=, /=, %= and .= di = NULL; - if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), + 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) @@ -1812,7 +1807,7 @@ notify: /// 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; +/// @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) @@ -1965,7 +1960,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) xp->xp_context = EXPAND_USER_VARS; if (strpbrk(arg, "\"'+-*/%.=!?~|&$([<>,#") == NULL) { // ":let var1 var2 ...": find last space. - for (p = arg + STRLEN(arg); p >= arg;) { + for (p = arg + strlen(arg); p >= arg;) { xp->xp_pattern = p; MB_PTR_BACK(arg, p); if (ascii_iswhite(*p)) { @@ -2047,7 +2042,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) || cmdidx == CMD_echomsg) && xp->xp_context == EXPAND_EXPRESSION) { for (;;) { - char *const n = (char *)skiptowhite((char_u *)arg); + char *const n = skiptowhite(arg); if (n == arg || ascii_iswhite_or_nul(*skipwhite(n))) { break; @@ -2082,7 +2077,7 @@ static size_t varnamebuflen = 0; char *cat_prefix_varname(int prefix, const char *name) FUNC_ATTR_NONNULL_ALL { - size_t len = STRLEN(name) + 3; + size_t len = strlen(name) + 3; if (len > varnamebuflen) { xfree(varnamebuf); @@ -2184,7 +2179,7 @@ char *get_user_var_name(expand_T *xp, int idx) /// Does not use 'cpo' and always uses 'magic'. /// -/// @return TRUE if "pat" matches "text". +/// @return true if "pat" matches "text". int pattern_match(char *pat, char *text, bool ic) { int matches = 0; @@ -2192,7 +2187,7 @@ int pattern_match(char *pat, char *text, bool ic) // avoid 'l' flag in 'cpoptions' char *save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { regmatch.rm_ic = ic; @@ -2232,11 +2227,11 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ // 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; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = evaluate; + funcexe.fe_partial = partial; + funcexe.fe_basetv = basetv; int ret = get_func_tv((char_u *)s, len, rettv, arg, &funcexe); xfree(s); @@ -2263,13 +2258,13 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ // TODO(ZyX-I): move to eval/expressions -/// The "evaluate" argument: When FALSE, the argument is only parsed but not +/// 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. +/// Put the result in "rettv" when returning OK and "evaluate" is true. /// Note: "rettv.v_lock" is not set. /// /// @return OK or FAIL. @@ -2297,7 +2292,7 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) ret = FAIL; } if (nextcmd != NULL) { - *nextcmd = (char *)check_nextcmd((char_u *)p); + *nextcmd = check_nextcmd(p); } return ret; @@ -2663,7 +2658,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) tv_clear(&var2); return FAIL; } - p = (char *)concat_str((const char_u *)s1, (const char_u *)s2); + p = concat_str(s1, s2); tv_clear(rettv); rettv->v_type = VAR_STRING; rettv->vval.v_string = p; @@ -3000,9 +2995,11 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) *arg = bp; } else { // decimal, hex or octal number - vim_str2nr((char_u *)(*arg), NULL, &len, STR2NR_ALL, &n, NULL, 0, true); + vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true); if (len == 0) { - semsg(_(e_invexpr2), *arg); + if (evaluate) { + semsg(_(e_invexpr2), *arg); + } ret = FAIL; break; } @@ -3214,12 +3211,12 @@ static int call_func_rettv(char **const arg, typval_T *const rettv, const bool e } 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; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = evaluate; + funcexe.fe_partial = pt; + funcexe.fe_selfdict = selfdict; + funcexe.fe_basetv = basetv; const int ret = get_func_tv((char_u *)funcname, is_lua ? (int)(*arg - funcname) : -1, rettv, arg, &funcexe); @@ -3662,7 +3659,6 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) int get_option_tv(const char **const arg, typval_T *const rettv, const bool evaluate) FUNC_ATTR_NONNULL_ARG(1) { - bool working = (**arg == '+'); // has("+option") int opt_flags; // Isolate the option name and find its value. @@ -3707,10 +3703,6 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval 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 @@ -3831,7 +3823,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) if (p[1] != '*') { flags |= FSK_SIMPLIFY; } - extra = trans_special((const char_u **)&p, STRLEN(p), (char_u *)name, flags, false, NULL); + 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) { @@ -3914,7 +3906,7 @@ char *partial_name(partial_T *pt) FUNC_ATTR_PURE { if (pt->pt_name != NULL) { - return (char *)pt->pt_name; + return pt->pt_name; } return (char *)pt->pt_func->uf_name; } @@ -3929,7 +3921,7 @@ static void partial_free(partial_T *pt) xfree(pt->pt_argv); tv_dict_unref(pt->pt_dict); if (pt->pt_name != NULL) { - func_unref(pt->pt_name); + func_unref((char_u *)pt->pt_name); xfree(pt->pt_name); } else { func_ptr_unref(pt->pt_func); @@ -4001,13 +3993,11 @@ failret: bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) { // empty and NULL function name considered the same - char_u *s1 = - (char_u *)(tv1->v_type == VAR_FUNC ? tv1->vval.v_string : partial_name(tv1->vval.v_partial)); + char *s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string : partial_name(tv1->vval.v_partial); if (s1 != NULL && *s1 == NUL) { s1 = NULL; } - char_u *s2 = - (char_u *)(tv2->v_type == VAR_FUNC ? tv2->vval.v_string : partial_name(tv2->vval.v_partial)); + char *s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string : partial_name(tv2->vval.v_partial); if (s2 != NULL && *s2 == NUL) { s2 = NULL; } @@ -4015,7 +4005,7 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) if (s1 != s2) { return false; } - } else if (STRCMP(s1, s2) != 0) { + } else if (strcmp(s1, s2) != 0) { return false; } @@ -4483,7 +4473,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack // 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); + abort = set_ref_in_func((char_u *)pt->pt_name, pt->pt_func, copyID); if (pt->pt_dict != NULL) { typval_T dtv; @@ -4587,21 +4577,20 @@ static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal) { typval_T tv; char *key = NULL; - char *start = skipwhite(*arg + 1); + char *curly_expr = skipwhite(*arg + 1); char buf[NUMBUFLEN]; - // First check if it's not a curly-braces thing: {expr}. + // First check if it's not a curly-braces expression: {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; - } + // "{}" is an empty Dictionary. + // "#{abc}" is never a curly-braces expression. + if (*curly_expr != '}' + && !literal + && eval1(&curly_expr, &tv, false) == OK + && *skipwhite(curly_expr) == '}') { + return NOTDONE; } dict_T *d = NULL; @@ -4851,7 +4840,7 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) break; } - vimvars[VV_KEY].vv_str = (char *)vim_strsave(di->di_key); + vimvars[VV_KEY].vv_str = xstrdup((char *)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) { @@ -4968,7 +4957,7 @@ theend: return retval; } -void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr fptr) +void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) { char *s; char *name; @@ -5025,7 +5014,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr // 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); + name = xmalloc(strlen(sid_buf) + strlen(s + off) + 1); STRCPY(name, sid_buf); STRCAT(name, s + off); } else { @@ -5118,7 +5107,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr func_ptr_ref(pt->pt_func); xfree(name); } else { - pt->pt_name = (char_u *)name; + pt->pt_name = name; func_ref((char_u *)name); } @@ -5228,12 +5217,12 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) 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("height"), wp->w_height_inner); 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("width"), wp->w_width_inner); 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)); @@ -5600,10 +5589,10 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T if (!append && lnum <= curbuf->b_ml.ml_line_count) { // Existing line, replace it. - int old_len = (int)STRLEN(ml_get(lnum)); + 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)); + inserted_bytes(lnum, 0, old_len, (int)strlen(line)); if (is_curbuf && lnum == curwin->w_cursor.lnum) { check_cursor_col(); } @@ -5844,7 +5833,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co switch (callback->type) { case kCallbackFuncref: name = callback->data.funcref; - int len = (int)STRLEN(name); + int len = (int)strlen(name); if (len >= 6 && !memcmp(name, "v:lua.", 6)) { name += 6; len = check_luafunc_name(name, false); @@ -5863,13 +5852,8 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co 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; - } + rv = nlua_call_ref(callback->data.luaref, NULL, args, false, NULL); + return (rv.type == kObjectTypeBoolean && rv.data.boolean == true); case kCallbackNone: return false; @@ -5880,10 +5864,10 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co } funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = true; - funcexe.partial = partial; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; return call_func(name, -1, rettv, argcount_in, argvars_in, &funcexe); } @@ -5990,7 +5974,7 @@ void timer_due_cb(TimeWatcher *tw, void *data) // Handle error message if (called_emsg > called_emsg_before && did_emsg) { timer->emsg_count++; - if (current_exception != NULL) { + if (did_throw) { discard_current_exception(); } } @@ -6218,7 +6202,7 @@ char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl) 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++) { + for (char *p = ml_get_buf(buf, lnum, false); *p != NUL; p++) { *len += 1; } *len += 1; @@ -6236,7 +6220,7 @@ char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl) 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++) { + for (char *p = ml_get_buf(buf, lnum, false); *p != NUL; p++) { *end++ = (*p == '\n') ? NUL : *p; } *end++ = '\n'; @@ -6285,7 +6269,7 @@ int buf_byteidx_to_charidx(buf_T *buf, linenr_T lnum, int byteidx) lnum = buf->b_ml.ml_line_count; } - char *str = (char *)ml_get_buf(buf, lnum, false); + char *str = ml_get_buf(buf, lnum, false); if (*str == NUL) { return 0; @@ -6323,7 +6307,7 @@ int buf_charidx_to_byteidx(buf_T *buf, linenr_T lnum, int charidx) lnum = buf->b_ml.ml_line_count; } - char *str = (char *)ml_get_buf(buf, lnum, false); + char *str = ml_get_buf(buf, lnum, false); // Convert the character offset to a byte offset char *t = str; @@ -6374,16 +6358,16 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret } int len; if (charcol) { - len = mb_charlen(ml_get(pos.lnum)); + len = mb_charlen((char_u *)ml_get(pos.lnum)); } else { - len = (int)STRLEN(ml_get(pos.lnum)); + len = (int)strlen(ml_get(pos.lnum)); } // We accept "$" for the column number: last column. listitem_T *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) { + && strcmp(TV_LIST_ITEM_TV(li)->vval.v_string, "$") == 0) { pos.col = len + 1; } @@ -6460,9 +6444,9 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret } else { pos.lnum = curwin->w_cursor.lnum; if (charcol) { - pos.col = (colnr_T)mb_charlen(get_cursor_line_ptr()); + pos.col = (colnr_T)mb_charlen((char_u *)get_cursor_line_ptr()); } else { - pos.col = (colnr_T)STRLEN(get_cursor_line_ptr()); + pos.col = (colnr_T)strlen(get_cursor_line_ptr()); } } return &pos; @@ -6470,11 +6454,14 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret 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. +/// Convert list in "arg" into position "posp" and optional file number "fnump". +/// When "fnump" is NULL there is no file number, only 3 items: [lnum, col, off] /// Note that the column is passed on as-is, the caller may want to decrement /// it to use 1 for the first column. /// +/// @param charcol if true, use the column as the character index instead of the +/// byte index. +/// /// @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) @@ -6514,13 +6501,16 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c return FAIL; } // If character position is specified, then convert to byte position + // If the line number is zero use the cursor line. 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; + n = buf_charidx_to_byteidx(buf, + posp->lnum == 0 ? curwin->w_cursor.lnum : posp->lnum, + (int)n) + 1; } posp->col = (colnr_T)n; @@ -6632,7 +6622,7 @@ int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbo } *alias = temp_string; *arg = (const char *)skipwhite(p); - return (int)STRLEN(temp_string); + return (int)strlen(temp_string); } len += get_id_len(arg); @@ -6758,7 +6748,7 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex char *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) + 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); @@ -6786,14 +6776,14 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex return retval; } -/// @return TRUE if character "c" can be used in a variable or function name. +/// @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 +/// @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) { @@ -6846,7 +6836,7 @@ void set_vim_var_char(int c) /// Set v:count to "count" and v:count1 to "count1". /// -/// @param set_prevcount if TRUE, first set v:prevcount from v:count. +/// @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) { @@ -7026,7 +7016,7 @@ char *set_cmdarg(exarg_T *eap, char *oldarg) len += 10; // " ++ff=unix" } if (eap->force_enc != 0) { - len += STRLEN(eap->cmd + eap->force_enc) + 7; + len += strlen(eap->cmd + eap->force_enc) + 7; } if (eap->bad_char != 0) { len += 7 + 4; // " ++bad=" + "keep" or "drop" @@ -7048,20 +7038,20 @@ char *set_cmdarg(exarg_T *eap, char *oldarg) } if (eap->force_ff != 0) { - snprintf(newval + STRLEN(newval), newval_len, " ++ff=%s", + 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", + 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"); + STRCPY(newval + strlen(newval), " ++bad=keep"); } else if (eap->bad_char == BAD_DROP) { - STRCPY(newval + STRLEN(newval), " ++bad=drop"); + STRCPY(newval + strlen(newval), " ++bad=drop"); } else if (eap->bad_char != 0) { - snprintf(newval + STRLEN(newval), newval_len, " ++bad=%c", + snprintf(newval + strlen(newval), newval_len, " ++bad=%c", eap->bad_char); } vimvars[VV_CMDARG].vv_str = newval; @@ -7405,7 +7395,7 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char 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); + char *sc_name = get_scriptname(last_set, &should_free); new_script_item(sc_name, ¤t_sctx.sc_sid); } } @@ -7532,9 +7522,9 @@ int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *c } 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)) + if ((to->vval.v_string = string_convert((vimconv_T *)conv, + from->vval.v_string, + NULL)) == NULL) { to->vval.v_string = xstrdup(from->vval.v_string); } @@ -7644,7 +7634,7 @@ void ex_echo(exarg_T *eap) tv_clear(&rettv); arg = skipwhite(arg); } - eap->nextcmd = (char *)check_nextcmd((char_u *)arg); + eap->nextcmd = check_nextcmd(arg); if (eap->skip) { emsg_skip--; @@ -7741,7 +7731,7 @@ void ex_execute(exarg_T *eap) emsg_skip--; } - eap->nextcmd = (char *)check_nextcmd((char_u *)arg); + eap->nextcmd = check_nextcmd(arg); } /// Skip over the name of an option: "&option", "&g:option" or "&l:option". @@ -7831,7 +7821,7 @@ bool script_autoload(const char *const name, const size_t name_len, const bool r // "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) { + if (strcmp(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) { break; } } @@ -7985,7 +7975,7 @@ 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); + char *p = get_scriptname(last_set, &should_free); verbose_enter(); msg_puts(_("\n\tLast set from ")); msg_puts(p); @@ -8082,9 +8072,9 @@ repeat: } // Append a path separator to a directory. - if (os_isdir((char_u *)(*fnamep))) { + if (os_isdir(*fnamep)) { // Make room for one or two extra characters. - *fnamep = xstrnsave(*fnamep, STRLEN(*fnamep) + 2); + *fnamep = xstrnsave(*fnamep, strlen(*fnamep) + 2); xfree(*bufp); // free any allocated file name *bufp = *fnamep; add_pathsep(*fnamep); @@ -8124,11 +8114,11 @@ repeat: home_replace(NULL, s, dirname, MAXPATHL, true); xfree(s); } - size_t namelen = STRLEN(dirname); + 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) { + if (path_fnamencmp(p, dirname, namelen) == 0) { p += namelen; if (vim_ispathsep(*p)) { while (*p && vim_ispathsep(*p)) { @@ -8148,6 +8138,7 @@ repeat: // Only replace it when it starts with '~' if (*dirname == '~') { s = xstrdup(dirname); + assert(s != NULL); // suppress clang "Argument with 'nonnull' attribute passed null" *fnamep = s; xfree(*bufp); *bufp = s; @@ -8159,14 +8150,14 @@ repeat: } char *tail = path_tail(*fnamep); - *fnamelen = STRLEN(*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)); + s = get_past_head(*fnamep); while (tail > s && after_pathsep(s, tail)) { MB_PTR_BACK(*fnamep, tail); } @@ -8276,7 +8267,7 @@ repeat: *usedlen = (size_t)(p + 1 - src); s = do_string_sub(str, pat, sub, NULL, flags); *fnamep = s; - *fnamelen = STRLEN(s); + *fnamelen = strlen(s); xfree(*bufp); *bufp = s; didit = true; @@ -8304,7 +8295,7 @@ repeat: } xfree(*bufp); *bufp = *fnamep = p; - *fnamelen = STRLEN(p); + *fnamelen = strlen(p); *usedlen += 2; } @@ -8325,7 +8316,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags // Make 'cpoptions' empty, so that the 'l' flag doesn't work here char *save_cpo = p_cpo; - p_cpo = (char *)empty_option; + p_cpo = empty_option; ga_init(&ga, 1, 200); @@ -8335,11 +8326,11 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { char *tail = str; - char *end = str + STRLEN(str); + char *end = str + strlen(str); while (vim_regexec_nl(®match, (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]) { + if (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); @@ -8347,7 +8338,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags tail += i; continue; } - zero_width = (char *)regmatch.startp[0]; + zero_width = regmatch.startp[0]; } // Get some space for a temporary buffer to do the substitution @@ -8360,14 +8351,14 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags (regmatch.endp[0] - regmatch.startp[0]))); // copy the text up to where the match is - int i = (int)(regmatch.startp[0] - (char_u *)tail); + int i = (int)(regmatch.startp[0] - tail); memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i); // add the substituted text (void)vim_regsub(®match, (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]; + tail = regmatch.endp[0]; if (*tail == NUL) { break; } @@ -8385,11 +8376,16 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data); ga_clear(&ga); - if ((char_u *)p_cpo == empty_option) { + if (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); + // If it's still empty it was changed and restored, need to restore in + // the complicated way. + if (*p_cpo == NUL) { + set_option_value_give_err("cpo", 0L, save_cpo, 0); + } + free_string_option(save_cpo); } return ret; @@ -8496,9 +8492,9 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments, boo tv_list_ref(arguments); funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = true; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; (void)call_func(func, name_len, &rettv, 2, argvars, &funcexe); tv_list_unref(arguments); @@ -8595,7 +8591,7 @@ void ex_checkhealth(exarg_T *eap) if (vimruntime_env == NULL) { emsg(_("E5009: $VIMRUNTIME is empty or unset")); } else { - bool rtp_ok = NULL != strstr((char *)p_rtp, vimruntime_env); + bool rtp_ok = NULL != strstr(p_rtp, vimruntime_env); if (rtp_ok) { semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env); } else { @@ -8605,7 +8601,7 @@ void ex_checkhealth(exarg_T *eap) return; } - size_t bufsize = STRLEN(eap->arg) + sizeof("call health#check('')"); + size_t bufsize = strlen(eap->arg) + sizeof("call health#check('')"); char *buf = xmalloc(bufsize); snprintf(buf, bufsize, "call health#check('%s')", eap->arg); @@ -8629,10 +8625,10 @@ void invoke_prompt_callback(void) if (curbuf->b_prompt_callback.type == kCallbackNone) { return; } - char *text = (char *)ml_get(lnum); + char *text = ml_get(lnum); char *prompt = (char *)prompt_text(); - if (STRLEN(text) >= STRLEN(prompt)) { - text += STRLEN(prompt); + if (strlen(text) >= strlen(prompt)) { + text += strlen(prompt); } argv[0].v_type = VAR_STRING; argv[0].vval.v_string = xstrdup(text); diff --git a/src/nvim/eval.h b/src/nvim/eval.h index b0cb5fd8c1..afebdf5acb 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -11,33 +11,31 @@ #define COPYID_INC 2 #define COPYID_MASK (~0x1) -/* - * Structure returned by get_lval() and used by set_var_lval(). - * For a plain name: - * "name" points to the variable name. - * "exp_name" is NULL. - * "tv" is NULL - * For a magic braces name: - * "name" points to the expanded variable name. - * "exp_name" is non-NULL, to be freed later. - * "tv" is NULL - * For an index in a list: - * "name" points to the (expanded) variable name. - * "exp_name" NULL or non-NULL, to be freed later. - * "tv" points to the (first) list item value - * "li" points to the (first) list item - * "range", "n1", "n2" and "empty2" indicate what items are used. - * For an existing Dict item: - * "name" points to the (expanded) variable name. - * "exp_name" NULL or non-NULL, to be freed later. - * "tv" points to the dict item value - * "newkey" is NULL - * For a non-existing Dict item: - * "name" points to the (expanded) variable name. - * "exp_name" NULL or non-NULL, to be freed later. - * "tv" points to the Dictionary typval_T - * "newkey" is the key for the new item. - */ +// Structure returned by get_lval() and used by set_var_lval(). +// For a plain name: +// "name" points to the variable name. +// "exp_name" is NULL. +// "tv" is NULL +// For a magic braces name: +// "name" points to the expanded variable name. +// "exp_name" is non-NULL, to be freed later. +// "tv" is NULL +// For an index in a list: +// "name" points to the (expanded) variable name. +// "exp_name" NULL or non-NULL, to be freed later. +// "tv" points to the (first) list item value +// "li" points to the (first) list item +// "range", "n1", "n2" and "empty2" indicate what items are used. +// For an existing Dict item: +// "name" points to the (expanded) variable name. +// "exp_name" NULL or non-NULL, to be freed later. +// "tv" points to the dict item value +// "newkey" is NULL +// For a non-existing Dict item: +// "name" points to the (expanded) variable name. +// "exp_name" NULL or non-NULL, to be freed later. +// "tv" points to the Dictionary typval_T +// "newkey" is the key for the new item. typedef struct lval_S { const char *ll_name; ///< Start of variable name (can be NULL). size_t ll_name_len; ///< Length of the .ll_name. diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index e4e9b34ec6..837fef23f4 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -23,7 +23,7 @@ end return { funcs={ abs={args=1, base=1}, - acos={args=1, base=1, func="float_op_wrapper", data="&acos"}, -- WJMc + acos={args=1, base=1, float_func="acos"}, -- WJMc add={args=2, base=1}, ['and']={args=2, base=1}, api_info={}, @@ -33,7 +33,7 @@ return { argidx={}, arglistid={args={0, 2}}, argv={args={0, 2}}, - asin={args=1, base=1, func="float_op_wrapper", data="&asin"}, -- WJMc + asin={args=1, base=1, float_func="asin"}, -- WJMc assert_beeps={args=1, base=1}, assert_equal={args={2, 3}, base=2}, assert_equalfile={args={2, 3}, base=1}, @@ -47,7 +47,7 @@ return { assert_notmatch={args={2, 3}, base=2}, assert_report={args=1, base=1}, assert_true={args={1, 2}, base=1}, - atan={args=1, base=1, func="float_op_wrapper", data="&atan"}, + atan={args=1, base=1, float_func="atan"}, atan2={args=2, base=1}, browse={args=4}, browsedir={args=2}, @@ -67,7 +67,7 @@ return { byteidx={args=2, base=1}, byteidxcomp={args=2, base=1}, call={args={2, 3}, base=1}, - ceil={args=1, base=1, func="float_op_wrapper", data="&ceil"}, + ceil={args=1, base=1, float_func="ceil"}, changenr={}, chanclose={args={1, 2}}, chansend={args=2}, @@ -85,8 +85,8 @@ return { complete_info={args={0, 1}, base=1}, confirm={args={1, 4}, base=1}, copy={args=1, base=1}, - cos={args=1, base=1, func="float_op_wrapper", data="&cos"}, - cosh={args=1, base=1, func="float_op_wrapper", data="&cosh"}, + cos={args=1, base=1, float_func="cos"}, + cosh={args=1, base=1, float_func="cosh"}, count={args={2, 4}, base=1}, cscope_connection={args={0, 3}}, ctxget={args={0, 1}}, @@ -117,7 +117,7 @@ return { execute={args={1, 2}, base=1}, exepath={args=1, base=1}, exists={args=1, base=1}, - exp={args=1, base=1, func="float_op_wrapper", data="&exp"}, + exp={args=1, base=1, float_func="exp"}, expand={args={1, 3}, base=1}, expandcmd={args=1, base=1}, extend={args={2, 3}, base=1}, @@ -130,7 +130,7 @@ return { findfile={args={1, 3}, base=1}, flatten={args={1, 2}, base=1}, float2nr={args=1, base=1}, - floor={args=1, base=1, func="float_op_wrapper", data="&floor"}, + floor={args=1, base=1, float_func="floor"}, fmod={args=2, base=1}, fnameescape={args=1, base=1}, fnamemodify={args=2, base=1}, @@ -236,6 +236,7 @@ return { json_decode={args=1, base=1}, json_encode={args=1, base=1}, keys={args=1, base=1}, + keytrans={args=1, base=1}, last_buffer_nr={}, -- obsolete len={args=1, base=1}, libcall={args=3, base=3}, @@ -245,8 +246,8 @@ return { lispindent={args=1, base=1}, list2str={args={1, 2}, base=1}, localtime={}, - log={args=1, base=1, func="float_op_wrapper", data="&log"}, - log10={args=1, base=1, func="float_op_wrapper", data="&log10"}, + log={args=1, base=1, float_func="log"}, + log10={args=1, base=1, float_func="log10"}, luaeval={args={1, 2}, base=1}, map={args=2, base=1}, maparg={args={1, 4}, base=1}, @@ -304,7 +305,7 @@ return { ['repeat']={args=2, base=1}, resolve={args=1, base=1}, reverse={args=1, base=1}, - round={args=1, base=1, func="float_op_wrapper", data="&round"}, + round={args=1, base=1, float_func="round"}, rpcnotify={args=varargs(2)}, rpcrequest={args=varargs(2)}, rpcstart={args={1, 2}}, @@ -332,6 +333,7 @@ return { setcharpos={args=2, base=2}, setcharsearch={args=1, base=1}, setcmdpos={args=1, base=1}, + setcmdline={args={1, 2}, base=1}, setcursorcharpos={args={1, 3}, base=1}, setenv={args=2, base=2}, setfperm={args=2, base=1}, @@ -358,8 +360,8 @@ return { sign_unplace={args={1, 2}, base=1}, sign_unplacelist={args=1, base=1}, simplify={args=1, base=1}, - sin={args=1, base=1, func="float_op_wrapper", data="&sin"}, - sinh={args=1, base=1, func="float_op_wrapper", data="&sinh"}, + sin={args=1, base=1, float_func="sin"}, + sinh={args=1, base=1, float_func="sinh"}, sockconnect={args={2,3}}, sort={args={1, 3}, base=1}, soundfold={args=1, base=1}, @@ -367,7 +369,7 @@ return { spellbadword={args={0, 1}, base=1}, spellsuggest={args={1, 3}, base=1}, split={args={1, 3}, base=1}, - sqrt={args=1, base=1, func="float_op_wrapper", data="&sqrt"}, + sqrt={args=1, base=1, float_func="sqrt"}, srand={args={0, 1}, base=1}, stdpath={args=1}, str2float={args=1, base=1}, @@ -402,8 +404,8 @@ return { tabpagewinnr={args={1, 2}, base=1}, tagfiles={}, taglist={args={1, 2}, base=1}, - tan={args=1, base=1, func="float_op_wrapper", data="&tan"}, - tanh={args=1, base=1, func="float_op_wrapper", data="&tanh"}, + tan={args=1, base=1, float_func="tan"}, + tanh={args=1, base=1, float_func="tanh"}, tempname={}, termopen={args={1, 2}}, test_garbagecollect_now={}, @@ -417,13 +419,14 @@ return { toupper={args=1, base=1}, tr={args=3, base=1}, trim={args={1, 3}, base=1}, - trunc={args=1, base=1, func="float_op_wrapper", data="&trunc"}, + trunc={args=1, base=1, float_func="trunc"}, type={args=1, base=1}, undofile={args=1, base=1}, undotree={}, uniq={args={1, 3}, base=1}, values={args=1, base=1}, virtcol={args=1, base=1}, + virtcol2col={args=3, base=1}, visualmode={args={0, 1}}, wait={args={2,3}}, wildmenumode={}, diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 7b975ce775..94ef419bed 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -4,6 +4,7 @@ #include <msgpack.h> #include <stddef.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/charset.h" // vim_str2nr #include "nvim/eval.h" @@ -11,7 +12,6 @@ #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/globals.h" -#include "nvim/lib/kvec.h" #include "nvim/macros.h" #include "nvim/message.h" #include "nvim/vim.h" // OK, FAIL @@ -430,7 +430,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, const char ubuf[] = { t[1], t[2], t[3], t[4] }; t += 4; uvarnumber_T ch; - vim_str2nr((char_u *)ubuf, NULL, NULL, + vim_str2nr(ubuf, NULL, NULL, STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true); if (ch == 0) { hasnul = true; @@ -600,7 +600,7 @@ parse_json_number_check: // Convert integer varnumber_T nr; int num_len; - vim_str2nr((char_u *)s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true); + vim_str2nr(s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true); if ((int)exp_num_len != num_len) { semsg(_("E685: internal error: while converting number \"%.*s\" " "to integer vim_str2nr consumed %i bytes in place of %zu"), diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index bb514fba47..27d35ea24f 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -13,6 +13,7 @@ #include <msgpack.h> #include <stddef.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" // vim_isprintc() @@ -21,7 +22,6 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_encode.h" #include "nvim/garray.h" -#include "nvim/lib/kvec.h" #include "nvim/macros.h" #include "nvim/math.h" #include "nvim/mbyte.h" @@ -219,7 +219,7 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, cha } len++; if (TV_LIST_ITEM_TV(li)->vval.v_string != NULL) { - len += STRLEN(TV_LIST_ITEM_TV(li)->vval.v_string); + len += strlen(TV_LIST_ITEM_TV(li)->vval.v_string); } }); if (len) { @@ -281,7 +281,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s state->offset = 0; state->li_length = (TV_LIST_ITEM_TV(state->li)->vval.v_string == NULL ? 0 - : STRLEN(TV_LIST_ITEM_TV(state->li)->vval.v_string)); + : strlen(TV_LIST_ITEM_TV(state->li)->vval.v_string)); } } *read_bytes = nbuf; diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index b461456a3a..0e0d0fe696 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -108,8 +108,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons const char *tvs = tv_get_string(tv1); char numbuf[NUMBUFLEN]; char *const s = - (char *)concat_str((const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2, - numbuf)); + concat_str(tvs, tv_get_string_buf(tv2, numbuf)); tv_clear(tv1); tv1->v_type = VAR_STRING; tv1->vval.v_string = s; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index daeb755deb..3fff0798c4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -195,15 +195,15 @@ int call_internal_func(const char_u *const fname, const int argcount, typval_T * { const EvalFuncDef *const fdef = find_internal_func((const char *)fname); if (fdef == NULL) { - return ERROR_UNKNOWN; + return FCERR_UNKNOWN; } else if (argcount < fdef->min_argc) { - return ERROR_TOOFEW; + return FCERR_TOOFEW; } else if (argcount > fdef->max_argc) { - return ERROR_TOOMANY; + return FCERR_TOOMANY; } argvars[argcount].v_type = VAR_UNKNOWN; fdef->func(argvars, rettv, fdef->data); - return ERROR_NONE; + return FCERR_NONE; } /// Invoke a method for base->method(). @@ -213,13 +213,13 @@ int call_internal_method(const char_u *const fname, const int argcount, typval_T { const EvalFuncDef *const fdef = find_internal_func((const char *)fname); if (fdef == NULL) { - return ERROR_UNKNOWN; + return FCERR_UNKNOWN; } else if (fdef->base_arg == BASE_NONE) { - return ERROR_NOTMETHOD; + return FCERR_NOTMETHOD; } else if (argcount + 1 < fdef->min_argc) { - return ERROR_TOOFEW; + return FCERR_TOOFEW; } else if (argcount + 1 > fdef->max_argc) { - return ERROR_TOOMANY; + return FCERR_TOOMANY; } typval_T argv[MAX_FUNC_ARGS + 1]; @@ -231,10 +231,10 @@ int call_internal_method(const char_u *const fname, const int argcount, typval_T argv[argcount + 1].v_type = VAR_UNKNOWN; fdef->func(argv, rettv, fdef->data); - return ERROR_NONE; + return FCERR_NONE; } -/// @return TRUE for a non-zero Number and a non-empty String. +/// @return true for a non-zero Number and a non-empty String. static int non_zero_arg(typval_T *argvars) { return ((argvars[0].v_type == VAR_NUMBER @@ -251,26 +251,25 @@ static int non_zero_arg(typval_T *argvars) /// Some versions of glibc on i386 have an optimization that makes it harder to /// call math functions indirectly from inside an inlined function, causing /// compile-time errors. Avoid `inline` in that case. #3072 -static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void float_op_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { float_T f; - float_T (*function)(float_T) = (float_T (*)(float_T)) fptr; rettv->v_type = VAR_FLOAT; if (tv_get_float_chk(argvars, &f)) { - rettv->vval.v_float = function(f); + rettv->vval.v_float = fptr.float_func(f); } else { rettv->vval.v_float = 0.0; } } -static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; } - ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr; + MsgpackRpcRequestHandler handler = *fptr.api_handler; Array args = ARRAY_DICT_INIT; @@ -279,7 +278,8 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) } Error err = ERROR_INIT; - Object result = fn(VIML_INTERNAL_CALL, args, &err); + Arena res_arena = ARENA_EMPTY; + Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err); if (ERROR_SET(&err)) { semsg_multiline((const char *)e_api_error, err.msg); @@ -292,15 +292,19 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) end: api_free_array(args); - api_free_object(result); + if (handler.arena_return) { + arena_mem_free(arena_finish(&res_arena)); + } else { + api_free_object(result); + } api_clear_error(&err); } /// "abs(expr)" function -static void f_abs(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_abs(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type == VAR_FLOAT) { - float_op_wrapper(argvars, rettv, (FunPtr)&fabs); + float_op_wrapper(argvars, rettv, (EvalFuncData){ .float_func = &fabs }); } else { bool error = false; @@ -316,7 +320,7 @@ static void f_abs(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "add(list, item)" function -static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = 1; // Default: failed. if (argvars[0].v_type == VAR_LIST) { @@ -344,22 +348,21 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "and(expr, expr)" function -static void f_and(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_and(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) & tv_get_number_chk(&argvars[1], NULL); } /// "api_info()" function -static void f_api_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { Dictionary metadata = api_metadata(); (void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL); - api_free_dictionary(metadata); } /// "append(lnum, string/list)" function -static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const linenr_T lnum = tv_get_lnum(&argvars[0]); @@ -367,7 +370,7 @@ static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "appendbufline(buf, lnum, string/list)" function -static void f_appendbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *const buf = tv_get_buf(&argvars[0], false); if (buf == NULL) { @@ -379,7 +382,7 @@ static void f_appendbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "atan2()" function -static void f_atan2(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_atan2(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { float_T fx; float_T fy; @@ -393,16 +396,16 @@ static void f_atan2(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "browse(save, title, initdir, default)" function -static void f_browse(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_browse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_string = NULL; rettv->v_type = VAR_STRING; } /// "browsedir(title, initdir)" function -static void f_browsedir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_browsedir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - f_browse(argvars, rettv, NULL); + f_browse(argvars, rettv, fptr); } /// Find a buffer by number or exact name. @@ -420,7 +423,7 @@ static buf_T *find_buffer(typval_T *avar) FOR_ALL_BUFFERS(bp) { if (bp->b_fname != NULL && (path_with_url(bp->b_fname) || bt_nofilename(bp)) - && STRCMP(bp->b_fname, avar->vval.v_string) == 0) { + && strcmp(bp->b_fname, avar->vval.v_string) == 0) { buf = bp; break; } @@ -431,7 +434,7 @@ static buf_T *find_buffer(typval_T *avar) } /// "bufadd(expr)" function -static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char_u *name = (char_u *)tv_get_string(&argvars[0]); @@ -439,13 +442,13 @@ static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "bufexists(expr)" function -static void f_bufexists(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); } /// "buflisted(expr)" function -static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_buflisted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *buf; @@ -454,7 +457,7 @@ static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "bufload(expr)" function -static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr) +static void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr) { buf_T *buf = get_buf_arg(&argvars[0]); @@ -469,7 +472,7 @@ static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr) } /// "bufloaded(expr)" function -static void f_bufloaded(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufloaded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *buf; @@ -478,7 +481,7 @@ static void f_bufloaded(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "bufname(expr)" function -static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const buf_T *buf; rettv->v_type = VAR_STRING; @@ -494,7 +497,7 @@ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "bufnr(expr)" function -static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const buf_T *buf; bool error = false; @@ -554,13 +557,13 @@ static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr) } /// "bufwinid(nr)" function -static void f_bufwinid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufwinid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_win_common(argvars, rettv, false); } /// "bufwinnr(nr)" function -static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_bufwinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_win_common(argvars, rettv, true); } @@ -588,7 +591,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only) int save_magic = p_magic; p_magic = true; char *save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; buf_T *buf = buflist_findnr(buflist_findpat((char *)name, (char *)name + STRLEN(name), true, false, curtab_only)); @@ -630,7 +633,7 @@ buf_T *get_buf_arg(typval_T *arg) } /// "byte2line(byte)" function -static void f_byte2line(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { long boff = tv_get_number(&argvars[0]) - 1; if (boff < 0) { @@ -665,19 +668,19 @@ static void byteidx(typval_T *argvars, typval_T *rettv, int comp) } /// "byteidx()" function -static void f_byteidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_byteidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { byteidx(argvars, rettv, false); } /// "byteidxcomp()" function -static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { byteidx(argvars, rettv, true); } /// "call(func, arglist [, dict])" function -static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[1].v_type != VAR_LIST) { emsg(_(e_listreq)); @@ -726,13 +729,13 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "changenr()" function -static void f_changenr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_changenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = curbuf->b_u_seq_cur; } /// "chanclose(id[, stream])" function -static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_chanclose(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -771,7 +774,7 @@ static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "chansend(id, data)" function -static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -812,7 +815,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "char2nr(string)" function -static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_char2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[1].v_type != VAR_UNKNOWN) { if (!tv_check_num(&argvars[1])) { @@ -837,7 +840,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) if (fp->col == MAXCOL) { // '> can be MAXCOL, get the length of the line then if (fp->lnum <= curbuf->b_ml.ml_line_count) { - col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; + col = (colnr_T)strlen(ml_get(fp->lnum)) + 1; } else { col = MAXCOL; } @@ -846,11 +849,12 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) // col(".") when the cursor is on the NUL at the end of the line // because of "coladd" can be seen as an extra column. if (virtual_active() && fp == &curwin->w_cursor) { - char_u *p = get_cursor_pos_ptr(); + char *p = get_cursor_pos_ptr(); if (curwin->w_cursor.coladd >= - (colnr_T)win_chartabsize(curwin, p, curwin->w_virtcol - curwin->w_cursor.coladd)) { + (colnr_T)win_chartabsize(curwin, p, + curwin->w_virtcol - curwin->w_cursor.coladd)) { int l; - if (*p != NUL && p[(l = utfc_ptr2len((char *)p))] == NUL) { + if (*p != NUL && p[(l = utfc_ptr2len(p))] == NUL) { col += l; } } @@ -861,20 +865,21 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) } /// "charcol()" function -static void f_charcol(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_col(argvars, rettv, true); } /// "charidx()" function -static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_NUMBER || (argvars[2].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_NUMBER)) { + && argvars[2].v_type != VAR_NUMBER + && argvars[2].v_type != VAR_BOOL)) { emsg(_(e_invarg)); return; } @@ -913,7 +918,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "chdir(dir)" function -static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -925,12 +930,12 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) } // Return the current directory - char_u *cwd = xmalloc(MAXPATHL); - if (os_dirname(cwd, MAXPATHL) != FAIL) { + char *cwd = xmalloc(MAXPATHL); + if (os_dirname((char_u *)cwd, MAXPATHL) != FAIL) { #ifdef BACKSLASH_IN_FILENAME slash_adjust(cwd); #endif - rettv->vval.v_string = (char *)vim_strsave(cwd); + rettv->vval.v_string = xstrdup(cwd); } xfree(cwd); @@ -948,7 +953,7 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "cindent(lnum)" function -static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { pos_T pos = curwin->w_cursor; linenr_T lnum = tv_get_lnum(argvars); @@ -976,13 +981,13 @@ win_T *get_optional_window(typval_T *argvars, int idx) } /// "col(string)" function -static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_col(argvars, rettv, false); } /// "confirm(message, buttons[, default [, type]])" function -static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_confirm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[NUMBUFLEN]; char buf2[NUMBUFLEN]; @@ -1029,19 +1034,19 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if (!error) { - rettv->vval.v_number = do_dialog(type, NULL, (char_u *)message, (char_u *)buttons, def, NULL, + rettv->vval.v_number = do_dialog(type, NULL, (char *)message, (char *)buttons, def, NULL, false); } } /// "copy()" function -static void f_copy(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_copy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { var_item_copy(NULL, &argvars[0], rettv, false, 0); } /// "count()" function -static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { long n = 0; int ic = 0; @@ -1060,7 +1065,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr) const size_t len = STRLEN(expr); while (*p != NUL) { - if (mb_strnicmp(p, expr, len) == 0) { + if (mb_strnicmp((char *)p, (char *)expr, len) == 0) { n++; p += len; } else { @@ -1130,7 +1135,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "cscope_connection([{num} , {dbpath} [, {prepend}]])" function /// /// Checks the existence of a cscope connection. -static void f_cscope_connection(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_cscope_connection(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int num = 0; const char *dbpath = NULL; @@ -1151,7 +1156,7 @@ static void f_cscope_connection(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "ctxget([{index}])" function -static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { size_t index = 0; if (argvars[0].v_type == VAR_NUMBER) { @@ -1175,7 +1180,7 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "ctxpop()" function -static void f_ctxpop(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_ctxpop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (!ctx_restore(NULL, kCtxAll)) { emsg(_("Context stack is empty")); @@ -1183,7 +1188,7 @@ static void f_ctxpop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "ctxpush([{types}])" function -static void f_ctxpush(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_ctxpush(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int types = kCtxAll; if (argvars[0].v_type == VAR_LIST) { @@ -1214,7 +1219,7 @@ static void f_ctxpush(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "ctxset({context}[, {index}])" function -static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_DICT) { semsg(_(e_invarg2), "expected dictionary as first argument"); @@ -1254,7 +1259,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "ctxsize()" function -static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_ctxsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = (varnumber_T)ctx_size(); @@ -1265,7 +1270,7 @@ static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// Otherwise use the column number as a byte offset. static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) { - long line, col; + long lnum, col; long coladd = 0; bool set_curswant = true; @@ -1279,7 +1284,7 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) return; } - line = pos.lnum; + lnum = pos.lnum; col = pos.col; coladd = pos.coladd; if (curswant >= 0) { @@ -1288,10 +1293,15 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) } } else if ((argvars[0].v_type == VAR_NUMBER || argvars[0].v_type == VAR_STRING) && (argvars[1].v_type == VAR_NUMBER || argvars[1].v_type == VAR_STRING)) { - line = tv_get_lnum(argvars); + lnum = tv_get_lnum(argvars); + if (lnum < 0) { + semsg(_(e_invarg2), tv_get_string(&argvars[0])); + } else if (lnum == 0) { + lnum = curwin->w_cursor.lnum; + } col = (long)tv_get_number_chk(&argvars[1], NULL); if (charcol) { - col = buf_charidx_to_byteidx(curbuf, (linenr_T)line, (int)col) + 1; + col = buf_charidx_to_byteidx(curbuf, (linenr_T)lnum, (int)col) + 1; } if (argvars[2].v_type != VAR_UNKNOWN) { coladd = (long)tv_get_number_chk(&argvars[2], NULL); @@ -1300,11 +1310,11 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) emsg(_(e_invarg)); return; } - if (line < 0 || col < 0 || coladd < 0) { + if (lnum < 0 || col < 0 || coladd < 0) { return; // type error; errmsg already given } - if (line > 0) { - curwin->w_cursor.lnum = (linenr_T)line; + if (lnum > 0) { + curwin->w_cursor.lnum = (linenr_T)lnum; } if (col > 0) { curwin->w_cursor.col = (colnr_T)col - 1; @@ -1326,20 +1336,20 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) /// Moves the cursor to the specified line and column. /// /// @return 0 when the position could be set, -1 otherwise. -static void f_cursor(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_cursor(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { set_cursorpos(argvars, rettv, false); } /// "debugbreak()" function -static void f_debugbreak(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_debugbreak(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = FAIL; int pid = (int)tv_get_number(&argvars[0]); if (pid == 0) { emsg(_(e_invarg)); } else { -#ifdef WIN32 +#ifdef MSWIN HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); if (hProcess != NULL) { @@ -1354,7 +1364,7 @@ static void f_debugbreak(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "deepcopy()" function -static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int noref = 0; @@ -1371,7 +1381,7 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "delete()" function -static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_delete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; if (check_secure()) { @@ -1407,7 +1417,7 @@ static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// dictwatcheradd(dict, key, funcref) function -static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; @@ -1445,7 +1455,7 @@ static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// dictwatcherdel(dict, key, funcref) function -static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; @@ -1480,7 +1490,7 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "deletebufline()" function -static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *const buf = tv_get_buf(&argvars[0], false); if (buf == NULL) { @@ -1556,19 +1566,19 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "did_filetype()" function -static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_did_filetype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = did_filetype; } /// "diff_filler()" function -static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_diff_filler(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = MAX(0, diff_check(curwin, tv_get_lnum(argvars))); } /// "diff_hlID()" function -static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum = tv_get_lnum(argvars); static linenr_T prev_lnum = 0; @@ -1618,7 +1628,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "empty({expr})" function -static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_empty(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool n = true; @@ -1668,7 +1678,7 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "environ()" function -static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_environ(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); @@ -1690,7 +1700,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) char c = env[i][len]; env[i][len] = NUL; -#ifdef WIN32 +#ifdef MSWIN // Upper-case all the keys for Windows so we can detect duplicates char *const key = strcase_save(str, true); #else @@ -1713,7 +1723,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "escape({string}, {chars})" function -static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_escape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[NUMBUFLEN]; @@ -1724,7 +1734,7 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getenv()" function -static void f_getenv(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char_u *p = (char_u *)vim_getenv(tv_get_string(&argvars[0])); @@ -1738,7 +1748,7 @@ static void f_getenv(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "eval()" function -static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *s = tv_get_string_chk(&argvars[0]); if (s != NULL) { @@ -1759,15 +1769,15 @@ static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "eventhandler()" function -static void f_eventhandler(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_eventhandler(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = vgetc_busy; } /// "executable()" function -static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_executable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (tv_check_for_string(&argvars[0]) == FAIL) { + if (tv_check_for_string_arg(argvars, 0) == FAIL) { return; } @@ -1794,7 +1804,7 @@ static char *get_list_line(int c, void *cookie, int indent, bool do_concat) return s == NULL ? NULL : xstrdup(s); } -static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int arg_off) +static void execute_common(typval_T *argvars, typval_T *rettv, int arg_off) { const int save_msg_silent = msg_silent; const int save_emsg_silent = emsg_silent; @@ -1873,13 +1883,13 @@ static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int } /// "execute(command)" function -static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - execute_common(argvars, rettv, fptr, 0); + execute_common(argvars, rettv, 0); } /// "win_execute(win_id, command)" function -static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // Return an empty string if something fails. rettv->v_type = VAR_STRING; @@ -1889,14 +1899,14 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) tabpage_T *tp; win_T *wp = win_id2wp_tp(id, &tp); if (wp != NULL && tp != NULL) { - WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, fptr, 1)); + WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1)); } } /// "exepath()" function -static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (tv_check_for_nonempty_string(&argvars[0]) == FAIL) { + if (tv_check_for_nonempty_string_arg(argvars, 0) == FAIL) { return; } @@ -1915,7 +1925,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "exists()" function -static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int n = false; @@ -1933,9 +1943,14 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr) xfree(exp); } } else if (*p == '&' || *p == '+') { // Option. - n = (get_option_tv(&p, NULL, true) == OK); - if (*skipwhite(p) != NUL) { - n = false; // Trailing garbage. + bool working = (*p == '+'); // whether option needs to be working + int opt_flags; + + if (find_option_end(&p, &opt_flags) != NULL) { + int opt_idx = findoption(p); + n = (opt_idx >= 0 && (!working || get_varp_scope(get_option(opt_idx), opt_flags) != NULL)); + } else { + n = false; } } else if (*p == '*') { // Internal or user defined function. n = function_exists(p + 1, false); @@ -1955,9 +1970,8 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "expand()" function -static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char *errormsg; int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; bool error = false; #ifdef BACKSLASH_IN_FILENAME @@ -1977,10 +1991,17 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *s = tv_get_string(&argvars[0]); if (*s == '%' || *s == '#' || *s == '<') { - emsg_off++; + if (p_verbose == 0) { + emsg_off++; + } size_t len; - char_u *result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL); - emsg_off--; + char *errormsg = NULL; + char_u *result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL, false); + if (p_verbose == 0) { + emsg_off--; + } else if (errormsg != NULL) { + emsg(errormsg); + } if (rettv->v_type == VAR_LIST) { tv_list_alloc_ret(rettv, (result != NULL)); if (result != NULL) { @@ -2005,10 +2026,9 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) options += WILD_ICASE; } if (rettv->v_type == VAR_STRING) { - rettv->vval.v_string = (char *)ExpandOne(&xpc, (char_u *)s, NULL, options, - WILD_ALL); + rettv->vval.v_string = ExpandOne(&xpc, (char *)s, NULL, options, WILD_ALL); } else { - ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL_KEEP); + ExpandOne(&xpc, (char *)s, NULL, options, WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { tv_list_append_string(rettv->vval.v_list, @@ -2026,7 +2046,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "menu_get(path [, modes])" function -static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenMayKnow); int modes = MENU_ALL_MODES; @@ -2039,7 +2059,7 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "expandcmd()" function /// Expand all the special characters in a command string. -static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char *errormsg = NULL; @@ -2063,7 +2083,7 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "flatten(list[, {maxdepth}])" function -static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool error = false; @@ -2098,7 +2118,7 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "extend(list, list [, idx])" function /// "extend(dict, dict [, action])" function -static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const arg_errmsg = N_("extend() argument"); @@ -2174,7 +2194,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "feedkeys()" function -static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // This is not allowed in the sandbox. If the commands would still be // executed in the sandbox it would be OK, but it probably happens later, @@ -2195,17 +2215,17 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "filereadable()" function -static void f_filereadable(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_filereadable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const p = tv_get_string(&argvars[0]); rettv->vval.v_number = - (*p && !os_isdir((const char_u *)p) && os_file_is_readable(p)); + (*p && !os_isdir(p) && os_file_is_readable(p)); } /// @return 0 for not writable /// 1 for writable file /// 2 for a dir which we have rights to write into. -static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *filename = tv_get_string(&argvars[0]); rettv->vval.v_number = os_file_is_writable(filename); @@ -2214,7 +2234,7 @@ static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) { char_u *fresult = NULL; - char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; + char_u *path = *curbuf->b_p_path == NUL ? p_path : (char_u *)curbuf->b_p_path; int count = 1; bool first = true; bool error = false; @@ -2255,7 +2275,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) find_what, (char_u *)curbuf->b_ffname, (find_what == FINDFILE_DIR ? (char_u *)"" - : curbuf->b_p_sua)); + : (char_u *)curbuf->b_p_sua)); first = false; if (fresult != NULL && rettv->v_type == VAR_LIST) { @@ -2270,25 +2290,25 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) } /// "filter()" function -static void f_filter(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_filter(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { filter_map(argvars, rettv, false); } /// "finddir({fname}[, {path}[, {count}]])" function -static void f_finddir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_finddir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { findfilendir(argvars, rettv, FINDFILE_DIR); } /// "findfile({fname}[, {path}[, {count}]])" function -static void f_findfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_findfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { findfilendir(argvars, rettv, FINDFILE_FILE); } /// "float2nr({float})" function -static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { float_T f; @@ -2304,7 +2324,7 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "fmod()" function -static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_fmod(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { float_T fx; float_T fy; @@ -2318,14 +2338,14 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "fnameescape({string})" function -static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_fnameescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_string = vim_strsave_fnameescape(tv_get_string(&argvars[0]), VSE_NONE); rettv->v_type = VAR_STRING; } /// "fnamemodify({fname}, {mods})" function -static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char_u *fbuf = NULL; size_t len = 0; @@ -2353,21 +2373,21 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "foreground()" function -static void f_foreground(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_foreground(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) {} -static void f_funcref(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_funcref(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - common_function(argvars, rettv, true, fptr); + common_function(argvars, rettv, true); } -static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_function(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - common_function(argvars, rettv, false, fptr); + common_function(argvars, rettv, false); } /// "garbagecollect()" function -static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_garbagecollect(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // This is postponed until we are back at the toplevel, because we may be // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". @@ -2379,7 +2399,7 @@ static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "get()" function -static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { typval_T *tv = NULL; bool what_is_dict = false; @@ -2426,7 +2446,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) pt = argvars[0].vval.v_partial; } else { CLEAR_FIELD(fref_pt); - fref_pt.pt_name = (char_u *)argvars[0].vval.v_string; + fref_pt.pt_name = argvars[0].vval.v_string; pt = &fref_pt; } @@ -2476,7 +2496,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getbufinfo()" function -static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *argbuf = NULL; bool filtered = false; @@ -2538,7 +2558,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// Get line or list of lines from buffer "buf" into "rettv". /// -/// @param retlist if TRUE, then the lines are returned as a Vim List. +/// @param retlist if true, then the lines are returned as a Vim List. /// /// @return range (from start to end) of lines in rettv from the specified /// buffer. @@ -2568,14 +2588,13 @@ static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retli } } else { rettv->v_type = VAR_STRING; - rettv->vval.v_string = - (char *)((start >= 1 && start <= buf->b_ml.ml_line_count) - ? vim_strsave(ml_get_buf(buf, start, false)) : NULL); + rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count) + ? xstrdup(ml_get_buf(buf, start, false)) : NULL); } } /// "getbufline()" function -static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *const buf = tv_get_buf_from_arg(&argvars[0]); @@ -2588,7 +2607,7 @@ static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getchangelist()" function -static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getchangelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, 2); @@ -2693,13 +2712,13 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos, bool } /// "getcharpos()" function -static void f_getcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getpos_both(argvars, rettv, false, true); } /// "getcharsearch()" function -static void f_getcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); @@ -2710,42 +2729,8 @@ static void f_getcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_dict_add_nr(dict, S_LEN("until"), last_csearch_until()); } -/// "getcmdcompltype()" function -static void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)get_cmdline_completion(); -} - -/// "getcmdline()" function -static void f_getcmdline(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)get_cmdline_str(); -} - -/// "getcmdpos()" function -static void f_getcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - rettv->vval.v_number = get_cmdline_pos() + 1; -} - -/// "getcmdscreenpos()" function -static void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - rettv->vval.v_number = get_cmdline_screen_pos() + 1; -} - -/// "getcmdtype()" function -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] = (char)get_cmdline_type(); -} - /// "getcmdwintype()" function -static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -2762,7 +2747,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// @pre An argument may not be -1 if preceding arguments are not all -1. /// /// @post The return value will be a string. -static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // Possible scope of working directory to return. CdScope scope = kCdScopeInvalid; @@ -2875,14 +2860,14 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getfontname()" function -static void f_getfontname(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getfontname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; } /// "getfperm({fname})" function -static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char *perm = NULL; char_u flags[] = "rwx"; @@ -2902,7 +2887,7 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getfsize({fname})" function -static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getfsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *fname = tv_get_string(&argvars[0]); @@ -2911,7 +2896,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) FileInfo file_info; if (os_fileinfo(fname, &file_info)) { uint64_t filesize = os_fileinfo_size(&file_info); - if (os_isdir((const char_u *)fname)) { + if (os_isdir(fname)) { rettv->vval.v_number = 0; } else { rettv->vval.v_number = (varnumber_T)filesize; @@ -2927,7 +2912,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getftime({fname})" function -static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *fname = tv_get_string(&argvars[0]); @@ -2940,9 +2925,9 @@ static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getftype({fname})" function -static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getftype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char_u *type = NULL; + char *type = NULL; char *t; const char *fname = tv_get_string(&argvars[0]); @@ -2968,13 +2953,13 @@ static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { t = "other"; } - type = vim_strsave((char_u *)t); + type = xstrdup(t); } - rettv->vval.v_string = (char *)type; + rettv->vval.v_string = type; } /// "getjumplist()" function -static void f_getjumplist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getjumplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenMayKnow); win_T *const wp = find_tabwin(&argvars[0], &argvars[1]); @@ -3005,7 +2990,7 @@ static void f_getjumplist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getline(lnum, [end])" function -static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T end; bool retlist; @@ -3023,7 +3008,7 @@ static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getmarklist()" function -static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getmarklist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -3041,7 +3026,7 @@ static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getmousepos()" function -static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getmousepos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int row = mouse_row; int col = mouse_col; @@ -3082,24 +3067,24 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getpid()" function -static void f_getpid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = os_get_pid(); } /// "getcurpos(string)" function -static void f_getcurpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcurpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getpos_both(argvars, rettv, true, false); } -static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getpos_both(argvars, rettv, true, true); } /// "getpos(string)" function -static void f_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getpos_both(argvars, rettv, false, false); } @@ -3125,7 +3110,7 @@ static int getreg_get_regname(typval_T *argvars) } /// "getreg()" function -static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getreg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int arg2 = false; bool return_list = false; @@ -3161,7 +3146,7 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getregtype()" function -static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getregtype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // on error return an empty string rettv->v_type = VAR_STRING; @@ -3181,7 +3166,7 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "gettabinfo()" function -static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_gettabinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tabpage_T *tparg = NULL; @@ -3213,7 +3198,7 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "gettagstack()" function -static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_gettagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = curwin; // default is current window @@ -3230,7 +3215,7 @@ static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getwininfo()" function -static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wparg = NULL; @@ -3275,7 +3260,7 @@ static void dummy_timer_close_cb(TimeWatcher *tw, void *data) } /// "wait(timeout, condition[, interval])" function -static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = -1; @@ -3329,7 +3314,7 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "win_screenpos()" function -static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, 2); const win_T *const wp = find_win_by_nr_or_id(&argvars[0]); @@ -3376,7 +3361,7 @@ static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags } /// "win_splitmove()" function -static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); win_T *targetwin = find_win_by_nr_or_id(&argvars[1]); @@ -3414,7 +3399,7 @@ static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getwinpos({timeout})" function -static void f_getwinpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getwinpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, 2); tv_list_append_number(rettv->vval.v_list, -1); @@ -3422,19 +3407,19 @@ static void f_getwinpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getwinposx()" function -static void f_getwinposx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getwinposx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; } /// "getwinposy()" function -static void f_getwinposy(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getwinposy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; } /// "glob()" function -static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int options = WILD_SILENT|WILD_USE_NL; expand_T xpc; @@ -3464,11 +3449,11 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr) options += WILD_ICASE; } if (rettv->v_type == VAR_STRING) { - rettv->vval.v_string = (char *)ExpandOne(&xpc, (char_u *) - tv_get_string(&argvars[0]), NULL, options, - WILD_ALL); + rettv->vval.v_string = ExpandOne(&xpc, (char *) + tv_get_string(&argvars[0]), NULL, options, + WILD_ALL); } else { - ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, + ExpandOne(&xpc, (char *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); for (int i = 0; i < xpc.xp_numfiles; i++) { @@ -3483,7 +3468,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "globpath()" function -static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath. bool error = false; @@ -3514,7 +3499,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (file != NULL && !error) { garray_T ga; ga_init(&ga, (int)sizeof(char_u *), 10); - globpath((char *)tv_get_string(&argvars[0]), (char_u *)file, &ga, flags); + globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags); if (rettv->v_type == VAR_STRING) { rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); @@ -3533,7 +3518,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "glob2regpat()" function -static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const pat = tv_get_string_chk(&argvars[0]); // NULL on type error @@ -3542,7 +3527,7 @@ static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "has()" function -static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { static const char *const has_list[] = { #if defined(BSD) && !defined(__APPLE__) @@ -3557,7 +3542,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) #ifdef UNIX "unix", #endif -#if defined(WIN32) +#if defined(MSWIN) "win32", #endif #ifdef _WIN64 @@ -3765,7 +3750,7 @@ static bool has_wsl(void) /// @pre An argument may not be -1 if preceding arguments are not all -1. /// /// @post The return value will be either the number `1` or `0`. -static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_haslocaldir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // Possible scope of working directory to return. CdScope scope = kCdScopeInvalid; @@ -3855,29 +3840,29 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "highlightID(name)" function -static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0])); } /// "highlight_exists()" function -static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_hlexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0])); } /// "hostname()" function -static void f_hostname(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_hostname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char hostname[256]; os_get_hostname(hostname, 256); rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)vim_strsave((char_u *)hostname); + rettv->vval.v_string = xstrdup(hostname); } /// iconv() function -static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_iconv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { vimconv_T vimconv; @@ -3886,17 +3871,19 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *const str = tv_get_string(&argvars[0]); char buf1[NUMBUFLEN]; - char_u *const from = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[1], buf1))); + char_u *const from = + (char_u *)enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[1], buf1))); char buf2[NUMBUFLEN]; - char_u *const to = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[2], buf2))); + char_u *const to = + (char_u *)enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[2], buf2))); vimconv.vc_type = CONV_NONE; - convert_setup(&vimconv, from, to); + convert_setup(&vimconv, (char *)from, (char *)to); // If the encodings are equal, no conversion needed. if (vimconv.vc_type == CONV_NONE) { rettv->vval.v_string = xstrdup(str); } else { - rettv->vval.v_string = (char *)string_convert(&vimconv, (char_u *)str, NULL); + rettv->vval.v_string = string_convert(&vimconv, (char *)str, NULL); } convert_setup(&vimconv, NULL, NULL); @@ -3905,7 +3892,7 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "indent()" function -static void f_indent(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const linenr_T lnum = tv_get_lnum(argvars); if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) { @@ -3916,7 +3903,7 @@ static void f_indent(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "index()" function -static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { long idx = 0; bool ic = false; @@ -3991,19 +3978,19 @@ static bool inputsecret_flag = false; /// "input()" function /// Also handles inputsecret() when inputsecret is set. -static void f_input(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_input(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_user_input(argvars, rettv, false, inputsecret_flag); } /// "inputdialog()" function -static void f_inputdialog(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_inputdialog(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_user_input(argvars, rettv, true, inputsecret_flag); } /// "inputlist()" function -static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_inputlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_LIST) { semsg(_(e_listarg), "inputlist()"); @@ -4034,7 +4021,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) static garray_T ga_userinput = { 0, 0, sizeof(tasave_T), 4, NULL }; /// "inputrestore()" function -static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_inputrestore(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (!GA_EMPTY(&ga_userinput)) { ga_userinput.ga_len--; @@ -4048,7 +4035,7 @@ static void f_inputrestore(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "inputsave()" function -static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_inputsave(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // Add an entry to the stack of typeahead storage. tasave_T *p = GA_APPEND_VIA_PTR(tasave_T, &ga_userinput); @@ -4056,17 +4043,17 @@ static void f_inputsave(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "inputsecret()" function -static void f_inputsecret(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_inputsecret(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { cmdline_star++; inputsecret_flag = true; - f_input(argvars, rettv, NULL); + f_input(argvars, rettv, fptr); cmdline_star--; inputsecret_flag = false; } /// "insert()" function -static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { list_T *l; bool error = false; @@ -4139,25 +4126,25 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "interrupt()" function static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, typval_T *rettv FUNC_ATTR_UNUSED, - FunPtr fptr FUNC_ATTR_UNUSED) + EvalFuncData fptr FUNC_ATTR_UNUSED) { got_int = true; } /// "invert(expr)" function -static void f_invert(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_invert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL); } /// "isdirectory()" function -static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_isdirectory(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - rettv->vval.v_number = os_isdir((const char_u *)tv_get_string(&argvars[0])); + rettv->vval.v_number = os_isdir(tv_get_string(&argvars[0])); } /// "islocked()" function -static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_islocked(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { lval_T lv; @@ -4199,7 +4186,7 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "isinf()" function -static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_isinf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type == VAR_FLOAT && xisinf(argvars[0].vval.v_float)) { @@ -4208,14 +4195,14 @@ static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "isnan()" function -static void f_isnan(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_isnan(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT && xisnan(argvars[0].vval.v_float); } /// "id()" function -static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_id(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { const int len = vim_vsnprintf_typval(NULL, 0, "%p", dummy_ap, argvars); @@ -4225,7 +4212,7 @@ static void f_id(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "jobpid(id)" function -static void f_jobpid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_jobpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -4249,7 +4236,7 @@ static void f_jobpid(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "jobresize(job, width, height)" function -static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -4281,7 +4268,7 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) } static const char *ignored_env_vars[] = { -#ifndef WIN32 +#ifndef MSWIN "COLUMNS", "LINES", "TERMCAP", @@ -4293,7 +4280,7 @@ static const char *ignored_env_vars[] = { /// According to comments in src/win/process.c of libuv, Windows has a few /// "essential" environment variables. static const char *required_env_vars[] = { -#ifdef WIN32 +#ifdef MSWIN "HOMEDRIVE", "HOMEPATH", "LOGONSERVER", @@ -4316,7 +4303,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en if (!clear_env) { typval_T temp_env = TV_INITIAL_VALUE; - f_environ(NULL, &temp_env, NULL); + f_environ(NULL, &temp_env, (EvalFuncData){ .nullptr = NULL }); tv_dict_extend(env, temp_env.vval.v_dict, "force"); tv_dict_free(temp_env.vval.v_dict); @@ -4332,7 +4319,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en tv_dict_item_remove(env, dv); } } -#ifndef WIN32 +#ifndef MSWIN // Set COLORTERM to "truecolor" if termguicolors is set and 256 // otherwise, but only if it was set in the parent terminal at all dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM")); @@ -4367,7 +4354,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en } if (job_env) { -#ifdef WIN32 +#ifdef MSWIN TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { // Always use upper-case keys for Windows so we detect duplicate keys char *const key = strcase_save((const char *)var->di_key, true); @@ -4405,7 +4392,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en } /// "jobstart()" function -static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -4467,7 +4454,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } -#ifdef WIN32 +#ifdef MSWIN if (pty && overlapped) { semsg(_(e_invarg2), "job cannot have both 'pty' and 'overlapped' options set"); @@ -4480,7 +4467,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (new_cwd && *new_cwd != NUL) { cwd = new_cwd; // The new cwd must be a directory. - if (!os_isdir((const char_u *)cwd)) { + if (!os_isdir(cwd)) { semsg(_(e_invarg2), "expected valid directory"); shell_free_argv(argv); return; @@ -4525,7 +4512,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "jobstop()" function -static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_jobstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -4558,7 +4545,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "jobwait(ids[, timeout])" function -static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -4657,7 +4644,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// json_decode() function -static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_json_decode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char numbuf[NUMBUFLEN]; const char *s = NULL; @@ -4691,14 +4678,28 @@ static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// json_encode() function -static void f_json_encode(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_json_encode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = encode_tv2json(&argvars[0], NULL); } +/// "keytrans()" function +static void f_keytrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + if (tv_check_for_string_arg(argvars, 0) == FAIL + || argvars[0].vval.v_string == NULL) { + return; + } + // Need to escape K_SPECIAL for mb_unescape(). + char *escaped = vim_strsave_escape_ks(argvars[0].vval.v_string); + rettv->vval.v_string = str2special_save(escaped, true, true); + xfree(escaped); +} + /// "last_buffer_nr()" function. -static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int n = 0; @@ -4712,7 +4713,7 @@ static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "len()" function -static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_len(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { switch (argvars[0].v_type) { case VAR_STRING: @@ -4783,19 +4784,19 @@ static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type) } /// "libcall()" function -static void f_libcall(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_libcall(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { libcall_common(argvars, rettv, VAR_STRING); } /// "libcallnr()" function -static void f_libcallnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_libcallnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { libcall_common(argvars, rettv, VAR_NUMBER); } /// "line(string, [winid])" function -static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum = 0; pos_T *fp = NULL; @@ -4826,7 +4827,7 @@ static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "line2byte(lnum)" function -static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_line2byte(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const linenr_T lnum = tv_get_lnum(argvars); if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) { @@ -4840,7 +4841,7 @@ static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "lispindent(lnum)" function -static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const pos_T pos = curwin->w_cursor; const linenr_T lnum = tv_get_lnum(argvars); @@ -4854,13 +4855,13 @@ static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "localtime()" function -static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_localtime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = (varnumber_T)time(NULL); } /// luaeval() function implementation -static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_luaeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { const char *const str = tv_get_string_chk(&argvars[0]); @@ -4872,7 +4873,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "map()" function -static void f_map(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_map(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { filter_map(argvars, rettv, true); } @@ -4894,7 +4895,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; rettv->vval.v_number = -1; switch (type) { @@ -5008,9 +5009,9 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, li = TV_LIST_ITEM_NEXT(l, li); idx++; } else { - startcol = (colnr_T)(regmatch.startp[0] - + utfc_ptr2len((char *)regmatch.startp[0]) - str); - if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) { + startcol = (colnr_T)((char_u *)regmatch.startp[0] + + utfc_ptr2len(regmatch.startp[0]) - str); + if (startcol > (colnr_T)len || str + startcol <= (char_u *)regmatch.startp[0]) { match = false; break; } @@ -5029,8 +5030,8 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]); TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz((const char *)regmatch.startp[0], rd); - TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(regmatch.startp[0] - expr); - TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(regmatch.endp[0] - expr); + TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)((char_u *)regmatch.startp[0] - expr); + TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(regmatch.endp[0] - (char *)expr); if (l != NULL) { TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx; } @@ -5065,10 +5066,10 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, } else { if (type == kSomeMatch) { rettv->vval.v_number = - (varnumber_T)(regmatch.startp[0] - str); + (varnumber_T)((char_u *)regmatch.startp[0] - str); } else { rettv->vval.v_number = - (varnumber_T)(regmatch.endp[0] - str); + (varnumber_T)(regmatch.endp[0] - (char *)str); } rettv->vval.v_number += (varnumber_T)(str - expr); } @@ -5090,31 +5091,31 @@ theend: } /// "match()" function -static void f_match(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_match(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { find_some_match(argvars, rettv, kSomeMatch); } /// "matchend()" function -static void f_matchend(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_matchend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { find_some_match(argvars, rettv, kSomeMatchEnd); } /// "matchlist()" function -static void f_matchlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_matchlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { find_some_match(argvars, rettv, kSomeMatchList); } /// "matchstr()" function -static void f_matchstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_matchstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { find_some_match(argvars, rettv, kSomeMatchStr); } /// "matchstrpos()" function -static void f_matchstrpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_matchstrpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { find_some_match(argvars, rettv, kSomeMatchStrPos); } @@ -5169,19 +5170,19 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool } /// "max()" function -static void f_max(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_max(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { max_min(argvars, rettv, true); } /// "min()" function -static void f_min(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_min(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { max_min(argvars, rettv, false); } /// "mkdir()" function -static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int prot = 0755; // -V536 @@ -5226,7 +5227,7 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "mode()" function -static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_mode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[MODE_MAX_LENGTH]; @@ -5243,7 +5244,7 @@ static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "msgpackdump()" function -static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { if (argvars[0].v_type != VAR_LIST) { @@ -5382,7 +5383,7 @@ static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret } /// "msgpackparse" function -static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_msgpackparse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) { @@ -5398,7 +5399,7 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "nextnonblank()" function -static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_nextnonblank(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum; @@ -5407,7 +5408,7 @@ static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr) lnum = 0; break; } - if (*skipwhite((char *)ml_get(lnum)) != NUL) { + if (*skipwhite(ml_get(lnum)) != NUL) { break; } } @@ -5415,7 +5416,7 @@ static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "nr2char()" function -static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_nr2char(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[1].v_type != VAR_UNKNOWN) { if (!tv_check_num(&argvars[1])) { @@ -5446,14 +5447,14 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "or(expr, expr)" function -static void f_or(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_or(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) | tv_get_number_chk(&argvars[1], NULL); } /// "pathshorten()" function -static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_pathshorten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int trim_len = 1; @@ -5465,17 +5466,17 @@ static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr) } rettv->v_type = VAR_STRING; - const char_u *p = (char_u *)tv_get_string_chk(&argvars[0]); + const char *p = tv_get_string_chk(&argvars[0]); if (p == NULL) { rettv->vval.v_string = NULL; } else { - rettv->vval.v_string = (char *)vim_strsave(p); + rettv->vval.v_string = xstrdup(p); shorten_dir_len((char_u *)rettv->vval.v_string, trim_len); } } /// "pow()" function -static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_pow(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { float_T fx; float_T fy; @@ -5489,13 +5490,13 @@ static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "prevnonblank()" function -static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prevnonblank(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum = tv_get_lnum(argvars); if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { lnum = 0; } else { - while (lnum >= 1 && *skipwhite((char *)ml_get(lnum)) == NUL) { + while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) { lnum--; } } @@ -5503,7 +5504,7 @@ static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "printf()" function -static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_printf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -5525,7 +5526,7 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "prompt_setcallback({buffer}, {callback})" function -static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { Callback prompt_callback = { .type = kCallbackNone }; @@ -5548,7 +5549,7 @@ static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr } /// "prompt_setinterrupt({buffer}, {callback})" function -static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { Callback interrupt_callback = { .type = kCallbackNone }; @@ -5571,7 +5572,7 @@ static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fpt } /// "prompt_getprompt({buffer})" function -static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { // return an empty string by default, e.g. it's not a prompt buffer @@ -5587,11 +5588,11 @@ static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - rettv->vval.v_string = (char *)vim_strsave(buf_prompt_text(buf)); + rettv->vval.v_string = xstrdup(buf_prompt_text(buf)); } /// "prompt_setprompt({buffer}, {text})" function -static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; @@ -5607,14 +5608,14 @@ static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "pum_getpos()" function -static void f_pum_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_pum_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); pum_set_event_info(rettv->vval.v_dict); } /// "pumvisible()" function -static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_pumvisible(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (pum_visible()) { rettv->vval.v_number = 1; @@ -5622,7 +5623,7 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "py3eval()" and "pyxeval()" functions (always python3) -static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_py3eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { script_host_eval("python3", argvars, rettv); } @@ -5694,7 +5695,7 @@ static inline uint32_t shuffle_xoshiro128starstar(uint32_t *const x, uint32_t *c } /// "rand()" function -static void f_rand(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { uint32_t result; @@ -5705,7 +5706,7 @@ static void f_rand(typval_T *argvars, typval_T *rettv, FunPtr fptr) // When no argument is given use the global seed list. if (!initialized) { // Initialize the global seed list. - uint32_t x; + uint32_t x = 0; init_srand(&x); gx = splitmix32(&x); @@ -5764,7 +5765,7 @@ theend: } /// "srand()" function -static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_srand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { uint32_t x = 0; @@ -5786,19 +5787,19 @@ static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "perleval()" function -static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_perleval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { script_host_eval("perl", argvars, rettv); } /// "rubyeval()" function -static void f_rubyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rubyeval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { script_host_eval("ruby", argvars, rettv); } /// "range()" function -static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_range(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { varnumber_T end; varnumber_T stride = 1; @@ -5868,7 +5869,7 @@ theend: } /// "readdir()" function -static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_readdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenUnknown); @@ -5886,14 +5887,14 @@ static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "readfile()" function -static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool binary = false; bool blob = false; FILE *fd; - char_u buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 + char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 int io_size = sizeof(buf); - char_u *prev = NULL; // previously read bytes, if any + char *prev = NULL; // previously read bytes, if any long prevlen = 0; // length of data in prev long prevsize = 0; // size of prev buffer long maxline = MAXLNUM; @@ -5913,7 +5914,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) // their own about CR-LF conversion. const char *const fname = tv_get_string(&argvars[0]); - if (os_isdir((const char_u *)fname)) { + if (os_isdir(fname)) { semsg(_(e_isadir2), fname); return; } @@ -5944,13 +5945,13 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) // - an incomplete line gets written // - a "binary" file gets an empty line at the end if it ends in a // newline. - char_u *p; // Position in buf. - char_u *start; // Start of current line. + char *p; // Position in buf. + char *start; // Start of current line. for (p = buf, start = buf; p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); p++) { if (*p == '\n' || readlen <= 0) { - char_u *s = NULL; + char *s = NULL; size_t len = (size_t)(p - start); // Finished a line. Remove CRs before NL. @@ -5967,7 +5968,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if (prevlen == 0) { assert(len < INT_MAX); - s = vim_strnsave(start, len); + s = xstrnsave(start, len); } else { // Change "prev" buffer to be the right size. This way // the bytes are only copied once, and very long lines are @@ -5982,7 +5983,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_list_append_owned_tv(l, (typval_T) { .v_type = VAR_STRING, .v_lock = VAR_UNLOCKED, - .vval.v_string = (char *)s, + .vval.v_string = s, }); start = p + 1; // Step over newline. @@ -6002,18 +6003,18 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) *p = '\n'; // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this // when finding the BF and check the previous two bytes. - } else if (*p == 0xbf && !binary) { + } else if ((uint8_t)(*p) == 0xbf && !binary) { // Find the two bytes before the 0xbf. If p is at buf, or buf + 1, // these may be in the "prev" string. - char_u back1 = p >= buf + 1 ? p[-1] + char back1 = p >= buf + 1 ? p[-1] : prevlen >= 1 ? prev[prevlen - 1] : NUL; - char_u back2 = p >= buf + 2 ? p[-2] + char back2 = p >= buf + 2 ? p[-2] : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] : prevlen >= - 2 ? prev[prevlen - 2] : NUL; + 2 ? prev[prevlen - 2] : NUL; - if (back2 == 0xef && back1 == 0xbb) { - char_u *dest = p - 2; + if ((uint8_t)back2 == 0xef && (uint8_t)back1 == 0xbb) { + char *dest = p - 2; // Usually a BOM is at the beginning of a file, and so at // the beginning of a line; then we can just step over it. @@ -6069,7 +6070,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getreginfo()" function -static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int regname = getreg_get_regname(argvars); if (regname == 0) { @@ -6119,18 +6120,18 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "reg_executing()" function -static void f_reg_executing(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reg_executing(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { return_register(reg_executing, rettv); } /// "reg_recording()" function -static void f_reg_recording(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reg_recording(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { return_register(reg_recording, rettv); } -static void f_reg_recorded(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reg_recorded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { return_register(reg_recorded, rettv); } @@ -6172,7 +6173,7 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL /// one argument it returns the time passed since the argument. /// With two arguments it returns the time passed between /// the two arguments. -static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reltime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { proftime_T res; proftime_T start; @@ -6214,7 +6215,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "reltimestr()" function -static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reltimestr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { proftime_T tm; @@ -6227,7 +6228,7 @@ 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) +static void f_remove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const arg_errmsg = N_("remove() argument"); @@ -6243,19 +6244,19 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "rename({from}, {to})" function -static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rename(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { rettv->vval.v_number = -1; } else { char buf[NUMBUFLEN]; - rettv->vval.v_number = vim_rename((const char_u *)tv_get_string(&argvars[0]), - (const char_u *)tv_get_string_buf(&argvars[1], buf)); + rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]), + tv_get_string_buf(&argvars[1], buf)); } } /// "repeat()" function -static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { varnumber_T n = tv_get_number(&argvars[1]); if (argvars[0].v_type == VAR_LIST) { @@ -6292,18 +6293,18 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "resolve()" function -static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; const char *fname = tv_get_string(&argvars[0]); -#ifdef WIN32 +#ifdef MSWIN char *v = os_resolve_shortcut(fname); if (v == NULL) { if (os_is_reparse_point_include(fname)) { v = os_realpath(fname, v); } } - rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v); + rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v); #else # ifdef HAVE_READLINK { @@ -6365,7 +6366,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (*q != NUL) { cpy = remain; remain = (remain - ? (char *)concat_str((char_u *)q - 1, (char_u *)remain) + ? concat_str(q - 1, remain) : xstrdup(q - 1)); xfree(cpy); q[-1] = NUL; @@ -6424,7 +6425,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) && (p[2] == NUL || vim_ispathsep(p[2])))))) { // Prepend "./". - cpy = (char *)concat_str((const char_u *)"./", (const char_u *)p); + cpy = concat_str("./", p); xfree(p); p = cpy; } else if (!is_relative_to_current) { @@ -6461,7 +6462,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "reverse({list})" function -static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type == VAR_BLOB) { blob_T *const b = argvars[0].vval.v_blob; @@ -6486,7 +6487,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "reduce(list, { accumulator, element -> value } [, initial])" function -static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reduce(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) { emsg(_(e_listblobreq)); @@ -6508,8 +6509,8 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr) } funcexe_T funcexe = FUNCEXE_INIT; - funcexe.evaluate = true; - funcexe.partial = partial; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; typval_T initial; typval_T argv[3]; @@ -6786,7 +6787,7 @@ theend: } /// "rpcnotify()" function -static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -6821,7 +6822,7 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "rpcrequest()" function -static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -6910,12 +6911,12 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) } end: - arena_mem_free(res_mem, NULL); + arena_mem_free(res_mem); api_clear_error(&err); } /// "rpcstart()" function (DEPRECATED) -static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -6982,7 +6983,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "rpcstop()" function -static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_rpcstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; @@ -7000,7 +7001,7 @@ 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 = (uint64_t)argvars[0].vval.v_number; if (find_job(id, false)) { - f_jobstop(argvars, rettv, NULL); + f_jobstop(argvars, rettv, fptr); } else { const char *error; rettv->vval.v_number = @@ -7012,7 +7013,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "screenattr()" function -static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screenattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; @@ -7030,7 +7031,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "screenchar()" function -static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; @@ -7048,7 +7049,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "screenchars()" function -static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1; int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1; @@ -7061,7 +7062,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] + (size_t)col], pcc); + int c = utfc_ptr2char((char *)grid->chars[grid->line_offset[row] + (size_t)col], pcc); int composing_len = 0; while (pcc[composing_len] != 0) { composing_len++; @@ -7076,45 +7077,19 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "screencol()" function /// /// First column is 1 to be consistent with virtcol(). -static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screencol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = ui_current_col() + 1; } -/// "screenpos({winid}, {lnum}, {col})" function -static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - tv_dict_alloc_ret(rettv); - dict_T *dict = rettv->vval.v_dict; - - win_T *wp = find_win_by_nr_or_id(&argvars[0]); - if (wp == NULL) { - return; - } - - pos_T pos = { - .lnum = (linenr_T)tv_get_number(&argvars[1]), - .col = (colnr_T)tv_get_number(&argvars[2]) - 1, - .coladd = 0 - }; - int row = 0; - int scol = 0, ccol = 0, ecol = 0; - textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol, false); - - tv_dict_add_nr(dict, S_LEN("row"), row); - tv_dict_add_nr(dict, S_LEN("col"), scol); - tv_dict_add_nr(dict, S_LEN("curscol"), ccol); - tv_dict_add_nr(dict, S_LEN("endcol"), ecol); -} - /// "screenrow()" function -static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screenrow(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = ui_current_row() + 1; } /// "screenstring()" function -static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_screenstring(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_string = NULL; rettv->v_type = VAR_STRING; @@ -7129,11 +7104,11 @@ 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] + (size_t)col]); + rettv->vval.v_string = xstrdup((char *)grid->chars[grid->line_offset[row] + (size_t)col]); } /// "search()" function -static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_search(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int flags = 0; @@ -7141,7 +7116,7 @@ static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "searchdecl()" function -static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_searchdecl(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int locally = 1; int thisblock = 0; @@ -7236,13 +7211,13 @@ theend: } /// "searchpair()" function -static void f_searchpair(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_searchpair(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = searchpair_cmn(argvars, NULL); } /// "searchpairpos()" function -static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_searchpairpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { pos_T match_pos; int lnum = 0; @@ -7284,7 +7259,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = (char *)empty_option; + p_cpo = empty_option; // Set the time limit, if there is one. proftime_T tm = profile_setlimit(time_limit); @@ -7410,18 +7385,23 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir xfree(pat2); xfree(pat3); - if ((char_u *)p_cpo == empty_option) { + if (p_cpo == empty_option) { p_cpo = save_cpo; } else { // Darn, evaluating the {skip} expression changed the value. - free_string_option((char_u *)save_cpo); + // If it's still empty it was changed and restored, need to restore in + // the complicated way. + if (*p_cpo == NUL) { + set_option_value_give_err("cpo", 0L, save_cpo, 0); + } + free_string_option(save_cpo); } return retval; } /// "searchpos()" function -static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_searchpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { pos_T match_pos; int flags = 0; @@ -7441,7 +7421,7 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "serverlist()" function -static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_serverlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { size_t n; char **addrs = server_address_list(&n); @@ -7455,7 +7435,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "serverstart()" function -static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_serverstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; // Address of the new server @@ -7500,7 +7480,7 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "serverstop()" function -static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; @@ -7520,7 +7500,7 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "setbufline()" function -static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum; buf_T *buf; @@ -7535,7 +7515,7 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// Set the cursor or mark position. -/// If 'charpos' is TRUE, then use the column number as a character offset. +/// If 'charpos' is true, then use the column number as a character offset. /// Otherwise use the column number as a byte offset. static void set_position(typval_T *argvars, typval_T *rettv, bool charpos) { @@ -7572,12 +7552,12 @@ static void set_position(typval_T *argvars, typval_T *rettv, bool charpos) } /// "setcharpos()" function -static void f_setcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { set_position(argvars, rettv, true); } -static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_DICT) { emsg(_(e_dictreq)); @@ -7589,7 +7569,7 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr) char_u *const csearch = (char_u *)tv_dict_get_string(d, "char", false); if (csearch != NULL) { int pcc[MAX_MCO]; - const int c = utfc_ptr2char(csearch, pcc); + const int c = utfc_ptr2char((char *)csearch, pcc); set_last_csearch(c, csearch, utfc_ptr2len((char *)csearch)); } @@ -7605,24 +7585,14 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } -/// "setcmdpos()" function -static void f_setcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) -{ - const int pos = (int)tv_get_number(&argvars[0]) - 1; - - if (pos >= 0) { - rettv->vval.v_number = set_cmdline_pos(pos); - } -} - /// "setcursorcharpos" function -static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { set_cursorpos(argvars, rettv, true); } /// "setenv()" function -static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char namebuf[NUMBUFLEN]; char valbuf[NUMBUFLEN]; @@ -7637,7 +7607,7 @@ static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "setfperm({fname}, {mode})" function -static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = 0; @@ -7668,14 +7638,14 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "setline()" function -static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { linenr_T lnum = tv_get_lnum(&argvars[0]); set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv); } /// "setpos()" function -static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { set_position(argvars, rettv, false); } @@ -7711,7 +7681,7 @@ static int get_yank_type(char **const pp, MotionType *const yank_type, long *con } /// "setreg()" function -static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_setreg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool append = false; @@ -7837,7 +7807,7 @@ free_lstval: if (strval == NULL) { return; } - write_reg_contents_ex(regname, (const char_u *)strval, (ssize_t)STRLEN(strval), + write_reg_contents_ex(regname, strval, (ssize_t)strlen(strval), append, yank_type, (colnr_T)block_len); } if (pointreg != 0) { @@ -7852,7 +7822,7 @@ free_lstval: } /// "settagstack()" function -static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_settagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { static char *e_invact2 = N_("E962: Invalid action: '%s'"); char action = 'r'; @@ -7903,7 +7873,7 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// f_sha256 - sha256({string}) function -static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_sha256(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *p = tv_get_string(&argvars[0]); const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0); @@ -7914,7 +7884,7 @@ static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "shellescape({string})" function -static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_shellescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const bool do_special = non_zero_arg(&argvars[1]); @@ -7925,7 +7895,7 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// shiftwidth() function -static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = 0; @@ -7941,7 +7911,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "simplify()" function -static void f_simplify(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_simplify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const p = tv_get_string(&argvars[0]); rettv->vval.v_string = xstrdup(p); @@ -7950,7 +7920,7 @@ static void f_simplify(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "sockconnect()" function -static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_sockconnect(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) { emsg(_(e_invarg)); @@ -8002,7 +7972,7 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "stdioopen()" function -static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_stdioopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_DICT) { emsg(_(e_invarg)); @@ -8036,7 +8006,7 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "reltimefloat()" function -static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_reltimefloat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FUNC_ATTR_NONNULL_ALL { proftime_T tm; @@ -8049,7 +8019,7 @@ static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "soundfold({word})" function -static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_soundfold(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; const char *const s = tv_get_string(&argvars[0]); @@ -8057,7 +8027,7 @@ static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "spellbadword()" function -static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const int wo_spell_save = curwin->w_p_spell; @@ -8079,7 +8049,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Find the start and length of the badly spelled word. len = spell_move_to(curwin, FORWARD, true, true, &attr); if (len != 0) { - word = (char *)get_cursor_pos_ptr(); + word = get_cursor_pos_ptr(); curwin->w_set_curswant = true; } } else if (*curbuf->b_s.b_p_spl != NUL) { @@ -8113,7 +8083,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "spellsuggest()" function -static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { garray_T ga = GA_EMPTY_INIT_VALUE; const int wo_spell_save = curwin->w_p_spell; @@ -8160,7 +8130,7 @@ f_spellsuggest_return: curwin->w_p_spell = wo_spell_save; } -static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { colnr_T col = 0; bool keepempty = false; @@ -8168,7 +8138,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Make 'cpoptions' empty, the 'l' flag should not be used here. char *save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; const char *str = tv_get_string(&argvars[0]); const char *pat = NULL; @@ -8222,11 +8192,11 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; } // Advance to just after the match. - if (regmatch.endp[0] > (char_u *)str) { + if (regmatch.endp[0] > str) { col = 0; } else { // Don't get stuck at the same match. - col = utfc_ptr2len((char *)regmatch.endp[0]); + col = utfc_ptr2len(regmatch.endp[0]); } str = (const char *)regmatch.endp[0]; } @@ -8239,7 +8209,7 @@ theend: } /// "stdpath(type)" function -static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_stdpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -8271,7 +8241,7 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "str2float()" function -static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_str2float(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char *p = skipwhite(tv_get_string(&argvars[0])); bool isneg = (*p == '-'); @@ -8287,7 +8257,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "str2list()" function -static void f_str2list(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_str2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenUnknown); const char_u *p = (const char_u *)tv_get_string(&argvars[0]); @@ -8298,7 +8268,7 @@ static void f_str2list(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "str2nr()" function -static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int base = 10; int what = 0; @@ -8331,7 +8301,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; } varnumber_T n; - vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false); + vim_str2nr((char *)p, NULL, NULL, what, &n, NULL, 0, false); // Text after the number is silently ignored. if (isneg) { rettv->vval.v_number = -n; @@ -8341,7 +8311,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strftime({format}[, {time}])" function -static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { time_t seconds; @@ -8361,13 +8331,12 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = xstrdup(_("(Invalid)")); } else { vimconv_T conv; - char_u *enc; conv.vc_type = CONV_NONE; - enc = enc_locale(); + char *enc = (char *)enc_locale(); convert_setup(&conv, p_enc, enc); if (conv.vc_type != CONV_NONE) { - p = (char *)string_convert(&conv, (char_u *)p, NULL); + p = string_convert(&conv, p, NULL); } char result_buf[256]; if (p != NULL) { @@ -8381,7 +8350,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) } convert_setup(&conv, enc, p_enc); if (conv.vc_type != CONV_NONE) { - rettv->vval.v_string = (char *)string_convert(&conv, (char_u *)result_buf, NULL); + rettv->vval.v_string = string_convert(&conv, result_buf, NULL); } else { rettv->vval.v_string = xstrdup(result_buf); } @@ -8393,7 +8362,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strgetchar()" function -static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strgetchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; @@ -8407,7 +8376,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - const size_t len = STRLEN(str); + const size_t len = strlen(str); size_t byteidx = 0; while (charidx >= 0 && byteidx < len) { @@ -8421,7 +8390,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "stridx()" function -static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_stridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; @@ -8453,20 +8422,20 @@ static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "string()" function -static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_string(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = encode_tv2string(&argvars[0], NULL); } /// "strlen()" function -static void f_strlen(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0])); } /// "strchars()" function -static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *s = tv_get_string(&argvars[0]); int skipcc = 0; @@ -8489,7 +8458,7 @@ static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strdisplaywidth()" function -static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const s = tv_get_string(&argvars[0]); int col = 0; @@ -8498,11 +8467,11 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) col = (int)tv_get_number(&argvars[1]); } - rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char_u *)s) - col); + rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char *)s) - col); } /// "strwidth()" function -static void f_strwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const s = tv_get_string(&argvars[0]); @@ -8510,10 +8479,10 @@ static void f_strwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strcharpart()" function -static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strcharpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const p = tv_get_string(&argvars[0]); - const size_t slen = STRLEN(p); + const size_t slen = strlen(p); int nbyte = 0; bool error = false; @@ -8564,7 +8533,7 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strpart()" function -static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strpart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool error = false; @@ -8610,7 +8579,7 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strptime({format}, {timestring})" function -static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char fmt_buf[NUMBUFLEN]; char str_buf[NUMBUFLEN]; @@ -8624,10 +8593,10 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr) vimconv_T conv = { .vc_type = CONV_NONE, }; - char_u *enc = enc_locale(); + char *enc = (char *)enc_locale(); convert_setup(&conv, p_enc, enc); if (conv.vc_type != CONV_NONE) { - fmt = (char *)string_convert(&conv, (char_u *)fmt, NULL); + fmt = string_convert(&conv, fmt, NULL); } if (fmt == NULL || os_strptime(str, fmt, &tmval) == NULL @@ -8642,7 +8611,7 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strridx()" function -static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strridx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[NUMBUFLEN]; const char *const needle = tv_get_string_chk(&argvars[1]); @@ -8653,7 +8622,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; // Type error; errmsg already given. } - const size_t haystack_len = STRLEN(haystack); + const size_t haystack_len = strlen(haystack); ptrdiff_t end_idx; if (argvars[2].v_type != VAR_UNKNOWN) { // Third argument: upper limit for index. @@ -8685,14 +8654,14 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "strtrans()" function -static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_strtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = transstr(tv_get_string(&argvars[0]), true); } /// "submatch()" function -static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_submatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { bool error = false; int no = (int)tv_get_number_chk(&argvars[0], &error); @@ -8715,7 +8684,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (retList == 0) { rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)reg_submatch(no); + rettv->vval.v_string = reg_submatch(no); } else { rettv->v_type = VAR_LIST; rettv->vval.v_list = reg_submatch_list(no); @@ -8723,7 +8692,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "substitute()" function -static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_substitute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char patbuf[NUMBUFLEN]; char subbuf[NUMBUFLEN]; @@ -8752,14 +8721,14 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "swapinfo(swap_filename)" function -static void f_swapinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_swapinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict); } /// "swapname(expr)" function -static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_swapname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; buf_T *buf = tv_get_buf(&argvars[0], false); @@ -8768,12 +8737,12 @@ static void f_swapname(typval_T *argvars, typval_T *rettv, FunPtr fptr) || buf->b_ml.ml_mfp->mf_fname == NULL) { rettv->vval.v_string = NULL; } else { - rettv->vval.v_string = (char *)vim_strsave(buf->b_ml.ml_mfp->mf_fname); + rettv->vval.v_string = xstrdup(buf->b_ml.ml_mfp->mf_fname); } } /// "synID(lnum, col, trans)" function -static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_synID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // -1 on type error (both) const linenr_T lnum = tv_get_lnum(argvars); @@ -8784,7 +8753,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr) int id = 0; if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && (size_t)col < STRLEN(ml_get(lnum))) { + && col >= 0 && (size_t)col < strlen(ml_get(lnum))) { id = syn_get_id(curwin, lnum, col, trans, NULL, false); } @@ -8792,7 +8761,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "synIDattr(id, what [, mode])" function -static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_synIDattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const int id = (int)tv_get_number(&argvars[0]); const char *const what = tv_get_string(&argvars[1]); @@ -8850,7 +8819,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } break; case 'u': - if (STRLEN(what) >= 9) { + if (strlen(what) >= 9) { if (TOLOWER_ASC(what[5]) == 'l') { // underline p = highlight_has_attr(id, HL_UNDERLINE, modec); @@ -8879,7 +8848,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) +static void f_synIDtrans(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int id = (int)tv_get_number(&argvars[0]); @@ -8893,7 +8862,7 @@ static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "synconcealed(lnum, col)" function -static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int syntax_flags = 0; int cchar; @@ -8909,7 +8878,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr) CLEAR_FIELD(str); if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 - && (size_t)col <= STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) { + && (size_t)col <= strlen(ml_get(lnum)) && curwin->w_p_cole > 0) { (void)syn_get_id(curwin, lnum, col, false, NULL, false); syntax_flags = get_syntax_info(&matchid); @@ -8935,7 +8904,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "synstack(lnum, col)" function -static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_set_ret(rettv, NULL); @@ -8946,7 +8915,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 - && (size_t)col <= STRLEN(ml_get(lnum))) { + && (size_t)col <= strlen(ml_get(lnum))) { tv_list_alloc_ret(rettv, kListLenMayKnow); (void)syn_get_id(curwin, lnum, col, false, NULL, true); @@ -8959,18 +8928,18 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// f_system - the VimL system() function -static void f_system(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_system(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_system_output_as_rettv(argvars, rettv, false); } -static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_systemlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_system_output_as_rettv(argvars, rettv, true); } /// "tabpagebuflist()" function -static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = NULL; @@ -8992,7 +8961,7 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "tabpagenr()" function -static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tabpagenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int nr = 1; @@ -9078,7 +9047,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar) } /// "tabpagewinnr()" function -static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int nr = 1; tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0])); @@ -9091,14 +9060,14 @@ static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "tagfiles()" function -static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tagfiles(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenUnknown); char *fname = xmalloc(MAXPATHL); bool first = true; tagname_T tn; - while (get_tagfname(&tn, first, (char_u *)fname) == OK) { + while (get_tagfname(&tn, first, fname) == OK) { tv_list_append_string(rettv->vval.v_list, fname, -1); first = false; } @@ -9108,7 +9077,7 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "taglist()" function -static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const tag_pattern = tv_get_string(&argvars[0]); @@ -9126,14 +9095,14 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "tempname()" function -static void f_tempname(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tempname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)vim_tempname(); + rettv->vval.v_string = vim_tempname(); } /// "termopen(cmd[, cwd])" function -static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure()) { return; @@ -9176,7 +9145,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (new_cwd && *new_cwd != NUL) { cwd = new_cwd; // The new cwd must be a directory. - if (!os_isdir((const char_u *)cwd)) { + if (!os_isdir(cwd)) { semsg(_(e_invarg2), "expected valid directory"); shell_free_argv(argv); return; @@ -9256,7 +9225,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "timer_info([timer])" function -static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_UNKNOWN) { if (argvars[0].v_type != VAR_NUMBER) { @@ -9274,7 +9243,7 @@ static void f_timer_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "timer_pause(timer, paused)" function -static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr) +static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr) { if (argvars[0].v_type != VAR_NUMBER) { emsg(_(e_number_exp)); @@ -9294,7 +9263,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr) } /// "timer_start(timeout, callback, opts)" function -static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int repeat = 1; @@ -9326,7 +9295,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "timer_stop(timerid)" function -static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_timer_stop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_NUMBER) { emsg(_(e_number_exp)); @@ -9341,27 +9310,27 @@ static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr) timer_stop(timer); } -static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr) +static void f_timer_stopall(typval_T *argvars, typval_T *unused, EvalFuncData fptr) { timer_stop_all(); } /// "tolower(string)" function -static void f_tolower(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tolower(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), false); } /// "toupper(string)" function -static void f_toupper(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_toupper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = strcase_save(tv_get_string(&argvars[0]), true); } /// "tr(string, fromstr, tostr)" function -static void f_tr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[NUMBUFLEN]; char buf2[NUMBUFLEN]; @@ -9440,14 +9409,14 @@ error: } /// "trim({expr})" function -static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf1[NUMBUFLEN]; char buf2[NUMBUFLEN]; - const char_u *head = (const char_u *)tv_get_string_buf_chk(&argvars[0], buf1); - const char_u *mask = NULL; - const char_u *prev; - const char_u *p; + const char *head = tv_get_string_buf_chk(&argvars[0], buf1); + const char *mask = NULL; + const char *prev; + const char *p; int dir = 0; rettv->v_type = VAR_STRING; @@ -9456,8 +9425,13 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } + if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_STRING) { + semsg(_(e_invarg2), tv_get_string(&argvars[1])); + return; + } + if (argvars[1].v_type == VAR_STRING) { - mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2); + mask = tv_get_string_buf_chk(&argvars[1], buf2); if (argvars[2].v_type != VAR_UNKNOWN) { bool error = false; // leading or trailing characters to trim @@ -9495,7 +9469,7 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - const char_u *tail = head + STRLEN(head); + const char *tail = head + strlen(head); if (dir == 0 || dir == 2) { // Trim trailing characters for (; tail > head; tail = prev) { @@ -9518,11 +9492,11 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } } - rettv->vval.v_string = (char *)vim_strnsave(head, (size_t)(tail - head)); + rettv->vval.v_string = xstrnsave(head, (size_t)(tail - head)); } /// "type(expr)" function -static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_type(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int n = -1; @@ -9554,7 +9528,7 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "undofile(name)" function -static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_undofile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; const char *const fname = tv_get_string(&argvars[0]); @@ -9573,7 +9547,7 @@ static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "undotree()" function -static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_undotree(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); @@ -9591,7 +9565,7 @@ static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "virtcol(string)" function -static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { colnr_T vcol = 0; int fnum = curbuf->b_fnum; @@ -9603,7 +9577,7 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (fp->col < 0) { fp->col = 0; } else { - const size_t len = STRLEN(ml_get(fp->lnum)); + const size_t len = strlen(ml_get(fp->lnum)); if (fp->col > (colnr_T)len) { fp->col = (colnr_T)len; } @@ -9616,14 +9590,14 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "visualmode()" function -static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_visualmode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char_u str[2]; + char str[2]; rettv->v_type = VAR_STRING; - str[0] = (char_u)curbuf->b_visual_mode_eval; + str[0] = (char)curbuf->b_visual_mode_eval; str[1] = NUL; - rettv->vval.v_string = (char *)vim_strsave(str); + rettv->vval.v_string = xstrdup(str); // A non-zero number or non-empty string argument: reset mode. if (non_zero_arg(&argvars[0])) { @@ -9632,7 +9606,7 @@ static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "wildmenumode()" function -static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_wildmenumode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (wild_menu_showing || ((State & MODE_CMDLINE) && cmdline_pum_active())) { rettv->vval.v_number = 1; @@ -9640,20 +9614,20 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "win_findbuf()" function -static void f_win_findbuf(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_findbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_list_alloc_ret(rettv, kListLenMayKnow); win_findbuf(argvars, rettv->vval.v_list); } /// "win_getid()" function -static void f_win_getid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = win_getid(argvars); } /// "win_gettype(nr)" function -static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = curwin; @@ -9662,7 +9636,7 @@ static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type != VAR_UNKNOWN) { wp = find_win_by_nr_or_id(&argvars[0]); if (wp == NULL) { - rettv->vval.v_string = (char *)vim_strsave((char_u *)"unknown"); + rettv->vval.v_string = xstrdup("unknown"); return; } } @@ -9680,25 +9654,37 @@ static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "win_gotoid()" function -static void f_win_gotoid(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - rettv->vval.v_number = win_gotoid(argvars); + int id = (int)tv_get_number(&argvars[0]); + + if (cmdwin_type != 0) { + emsg(_(e_cmdwin)); + return; + } + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->handle == id) { + goto_tabpage_win(tp, wp); + rettv->vval.v_number = 1; + return; + } + } } /// "win_id2tabwin()" function -static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_id2tabwin(argvars, rettv); } /// "win_id2win()" function -static void f_win_id2win(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_id2win(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = win_id2win(argvars); } /// "win_move_separator()" function -static void f_win_move_separator(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = false; @@ -9713,7 +9699,7 @@ static void f_win_move_separator(typval_T *argvars, typval_T *rettv, FunPtr fptr } /// "win_move_statusline()" function -static void f_win_move_statusline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_win_move_statusline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp; int offset; @@ -9731,7 +9717,7 @@ static void f_win_move_statusline(typval_T *argvars, typval_T *rettv, FunPtr fpt } /// "winbufnr(nr)" function -static void f_winbufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); if (wp == NULL) { @@ -9742,25 +9728,25 @@ static void f_winbufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "wincol()" function -static void f_wincol(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { validate_cursor(); rettv->vval.v_number = curwin->w_wcol + 1; } /// "winheight(nr)" function -static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winheight(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); if (wp == NULL) { rettv->vval.v_number = -1; } else { - rettv->vval.v_number = wp->w_height; + rettv->vval.v_number = wp->w_height_inner; } } /// "winlayout()" function -static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tabpage_T *tp; @@ -9779,20 +9765,20 @@ static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "winline()" function -static void f_winline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { validate_cursor(); rettv->vval.v_number = curwin->w_wrow + 1; } /// "winnr()" function -static void f_winnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = get_winnr(curtab, &argvars[0]); } /// "winrestcmd()" function -static void f_winrestcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char_u buf[50]; @@ -9819,7 +9805,7 @@ static void f_winrestcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "winrestview()" function -static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { dict_T *dict = argvars[0].vval.v_dict; @@ -9869,7 +9855,7 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "winsaveview()" function -static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winsaveview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); dict_T *dict = rettv->vval.v_dict; @@ -9887,32 +9873,32 @@ static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "winwidth(nr)" function -static void f_winwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_winwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); if (wp == NULL) { rettv->vval.v_number = -1; } else { - rettv->vval.v_number = wp->w_width; + rettv->vval.v_number = wp->w_width_inner; } } /// "windowsversion()" function -static void f_windowsversion(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_windowsversion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = xstrdup(windowsVersion); } /// "wordcount()" function -static void f_wordcount(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_wordcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); cursor_pos_info(rettv->vval.v_dict); } /// "writefile()" function -static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; @@ -9990,7 +9976,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "xor(expr, expr)" function -static void f_xor(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_xor(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL) ^ tv_get_number_chk(&argvars[1], NULL); diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h index 583ee0e75e..adff0b2441 100644 --- a/src/nvim/eval/funcs.h +++ b/src/nvim/eval/funcs.h @@ -1,11 +1,12 @@ #ifndef NVIM_EVAL_FUNCS_H #define NVIM_EVAL_FUNCS_H +#include "nvim/api/private/dispatch.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" /// Prototype of C function that implements VimL function -typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data); +typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, EvalFuncData data); /// Special flags for base_arg @see EvalFuncDef #define BASE_NONE 0 ///< Not a method (no base argument). @@ -13,13 +14,13 @@ typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data); /// Structure holding VimL function definition typedef struct { - char *name; ///< Name of the function. - uint8_t min_argc; ///< Minimal number of arguments. - uint8_t max_argc; ///< Maximal number of arguments. - uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST. - bool fast; ///< Can be run in |api-fast| events - VimLFunc func; ///< Function implementation. - FunPtr data; ///< Userdata for function implementation. + char *name; ///< Name of the function. + uint8_t min_argc; ///< Minimal number of arguments. + uint8_t max_argc; ///< Maximal number of arguments. + uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST. + bool fast; ///< Can be run in |api-fast| events + VimLFunc func; ///< Function implementation. + EvalFuncData data; ///< Userdata for function implementation. } EvalFuncDef; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 8822bb0491..a0b06aaaf4 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -40,6 +40,13 @@ # include "eval/typval.c.generated.h" #endif +static char e_string_required_for_argument_nr[] + = N_("E1174: String required for argument %d"); +static char e_non_empty_string_required_for_argument_nr[] + = N_("E1142: Non-empty string required for argument %d"); +static char e_number_required_for_argument_nr[] + = N_("E1210: Number required for argument %d"); + bool tv_in_free_unref_items = false; // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead @@ -831,7 +838,7 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep) } /// "join()" function -void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_join(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_LIST) { emsg(_(e_listreq)); @@ -855,7 +862,7 @@ void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "list2str()" function -void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_list2str(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { garray_T ga; @@ -1016,7 +1023,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) if (sortinfo->item_compare_lc) { res = strcoll(p1, p2); } else { - res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2); + res = sortinfo->item_compare_ic ? STRICMP(p1, p2): strcmp(p1, p2); } } else { double n1, n2; @@ -1079,9 +1086,9 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero) 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; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; + funcexe.fe_selfdict = sortinfo->item_compare_selfdict; res = call_func(func_name, -1, &rettv, 2, argv, &funcexe); tv_clear(&argv[0]); tv_clear(&argv[1]); @@ -1242,20 +1249,18 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) 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); } + if (info.item_compare_func_err) { // -V547 + emsg(_("E882: Uniq compare function failed")); + break; + } } } @@ -1267,13 +1272,13 @@ theend: } /// "sort"({list})" function -void f_sort(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sort(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { do_sort_uniq(argvars, rettv, true); } /// "uniq({list})" function -void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { do_sort_uniq(argvars, rettv, false); } @@ -1568,7 +1573,7 @@ bool tv_callback_equal(const Callback *cb1, const Callback *cb2) } switch (cb1->type) { case kCallbackFuncref: - return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0; + return strcmp(cb1->data.funcref, cb2->data.funcref) == 0; case kCallbackPartial: // FIXME: this is inconsistent with tv_equal but is needed for precision // maybe change dictwatcheradd to return a watcher id instead? @@ -1774,7 +1779,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T tv_dict_add(argv[2].vval.v_dict, v); } - if (oldtv) { + if (oldtv && oldtv->v_type != VAR_UNKNOWN) { dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old")); tv_copy(oldtv, &v->di_tv); tv_dict_add(argv[2].vval.v_dict, v); @@ -2533,7 +2538,7 @@ dict_T *tv_dict_copy(const vimconv_T *const conv, dict_T *const orig, const bool new_di = tv_dict_item_alloc((const char *)di->di_key); } else { size_t len = STRLEN(di->di_key); - char *const key = (char *)string_convert(conv, di->di_key, &len); + char *const key = (char *)string_convert(conv, (char *)di->di_key, &len); if (key == NULL) { new_di = tv_dict_item_alloc_len((const char *)di->di_key, len); } else { @@ -2777,7 +2782,7 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi switch (what) { case kDictListKeys: tv_item.v_type = VAR_STRING; - tv_item.vval.v_string = (char *)vim_strsave(di->di_key); + tv_item.vval.v_string = xstrdup((char *)di->di_key); break; case kDictListValues: tv_copy(&di->di_tv, &tv_item); @@ -2806,25 +2811,25 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi } /// "items(dict)" function -void f_items(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_list(argvars, rettv, 2); } /// "keys()" function -void f_keys(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_keys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_list(argvars, rettv, 0); } /// "values(dict)" function -void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_values(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_list(argvars, rettv, 1); } /// "has_key()" function -void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_has_key(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_DICT) { emsg(_(e_dictreq)); @@ -3717,8 +3722,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) case VAR_STRING: { varnumber_T n = 0; if (tv->vval.v_string != NULL) { - vim_str2nr((char_u *)tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0, - false); + vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0, false); } return n; } @@ -3746,9 +3750,11 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) linenr_T tv_get_lnum(const typval_T *const tv) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { + const int did_emsg_before = did_emsg; linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL); - if (lnum == 0) { // No valid number, try using same function as line() does. + if (lnum <= 0 && did_emsg_before == did_emsg && tv->v_type != VAR_NUMBER) { int fnum; + // No valid number, try using same function as line() does. pos_T *const fp = var2fpos(tv, true, &fnum, false); if (fp != NULL) { lnum = fp->lnum; @@ -3801,31 +3807,50 @@ float_T tv_get_float(const typval_T *const tv) return 0; } -// Give an error and return FAIL unless "tv" is a string. -int tv_check_for_string(const typval_T *const tv) +/// Give an error and return FAIL unless "args[idx]" is a string. +int tv_check_for_string_arg(const typval_T *const args, const int idx) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - if (tv->v_type != VAR_STRING) { - emsg(_(e_stringreq)); + if (args[idx].v_type != VAR_STRING) { + semsg(_(e_string_required_for_argument_nr), idx + 1); return FAIL; } return OK; } -// Give an error and return FAIL unless "tv" is a non-empty string. -int tv_check_for_nonempty_string(const typval_T *const tv) +/// Give an error and return FAIL unless "args[idx]" is a non-empty string. +int tv_check_for_nonempty_string_arg(const typval_T *const args, const int idx) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - if (tv_check_for_string(tv) == FAIL) { + if (tv_check_for_string_arg(args, idx) == FAIL) { return FAIL; } - if (tv->vval.v_string == NULL || *tv->vval.v_string == NUL) { - emsg(_(e_non_empty_string_required)); + if (args[idx].vval.v_string == NULL || *args[idx].vval.v_string == NUL) { + semsg(_(e_non_empty_string_required_for_argument_nr), idx + 1); return FAIL; } return OK; } +/// Give an error and return FAIL unless "args[idx]" is a number. +int tv_check_for_number_arg(const typval_T *const args, const int idx) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +{ + if (args[idx].v_type != VAR_NUMBER) { + semsg(_(e_number_required_for_argument_nr), idx + 1); + return FAIL; + } + return OK; +} + +/// Check for an optional number argument at "idx" +int tv_check_for_opt_number_arg(const typval_T *const args, const int idx) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +{ + return (args[idx].v_type == VAR_UNKNOWN + || tv_check_for_number_arg(args, idx) != FAIL) ? OK : FAIL; +} + /// Get the string value of a "stringish" VimL object. /// /// @param[in] tv Object to get value of. diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index c4bc9f603b..0a4adc1f53 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -2,418 +2,19 @@ #define NVIM_EVAL_TYPVAL_H #include <assert.h> -#include <inttypes.h> #include <stdbool.h> #include <stddef.h> #include <string.h> +#include "nvim/eval/typval_defs.h" #include "nvim/func_attr.h" -#include "nvim/garray.h" #include "nvim/gettext.h" -#include "nvim/hashtab.h" -#include "nvim/lib/queue.h" #include "nvim/macros.h" #include "nvim/mbyte_defs.h" #include "nvim/message.h" -#include "nvim/pos.h" // for linenr_T -#include "nvim/types.h" -#ifdef LOG_LIST_ACTIONS -# include "nvim/memory.h" -#endif - -/// Type used for VimL VAR_NUMBER values -typedef int64_t varnumber_T; -typedef uint64_t uvarnumber_T; - -/// Type used for VimL VAR_FLOAT values -typedef double float_T; - -/// Refcount for dict or list that should not be freed -enum { DO_NOT_FREE_CNT = (INT_MAX / 2), }; - -/// Additional values for tv_list_alloc() len argument -enum ListLenSpecials { - /// List length is not known in advance - /// - /// To be used when there is neither a way to know how many elements will be - /// needed nor are any educated guesses. - kListLenUnknown = -1, - /// List length *should* be known, but is actually not - /// - /// All occurrences of this value should be eventually removed. This is for - /// the case when the only reason why list length is not known is that it - /// would be hard to code without refactoring, but refactoring is needed. - kListLenShouldKnow = -2, - /// List length may be known in advance, but it requires too much effort - /// - /// To be used when it looks impractical to determine list length. - kListLenMayKnow = -3, -}; - -/// Maximal possible value of varnumber_T variable -#define VARNUMBER_MAX INT64_MAX -#define UVARNUMBER_MAX UINT64_MAX - -/// Minimal possible value of varnumber_T variable -#define VARNUMBER_MIN INT64_MIN - -/// %d printf format specifier for varnumber_T -#define PRIdVARNUMBER PRId64 - -typedef struct listvar_S list_T; -typedef struct dictvar_S dict_T; -typedef struct partial_S partial_T; -typedef struct blobvar_S blob_T; - -typedef struct ufunc ufunc_T; - -typedef enum { - kCallbackNone = 0, - kCallbackFuncref, - kCallbackPartial, - kCallbackLua, -} CallbackType; - -typedef struct { - union { - char *funcref; - partial_T *partial; - LuaRef luaref; - } data; - CallbackType type; -} Callback; - -#define CALLBACK_INIT { .type = kCallbackNone } -#define CALLBACK_NONE ((Callback)CALLBACK_INIT) - -/// Structure holding dictionary watcher -typedef struct dict_watcher { - Callback callback; - char *key_pattern; - size_t key_pattern_len; - QUEUE node; - bool busy; // prevent recursion if the dict is changed in the callback - bool needs_free; -} DictWatcher; - -/// Bool variable values -typedef enum { - kBoolVarFalse, ///< v:false - kBoolVarTrue, ///< v:true -} BoolVarValue; - -/// Special variable values -typedef enum { - kSpecialVarNull, ///< v:null -} SpecialVarValue; - -/// Variable lock status for typval_T.v_lock -typedef enum { - VAR_UNLOCKED = 0, ///< Not locked. - VAR_LOCKED = 1, ///< User lock, can be unlocked. - VAR_FIXED = 2, ///< Locked forever. -} VarLockStatus; - -/// VimL variable types, for use in typval_T.v_type -typedef enum { - VAR_UNKNOWN = 0, ///< Unknown (unspecified) value. - VAR_NUMBER, ///< Number, .v_number is used. - VAR_STRING, ///< String, .v_string is used. - VAR_FUNC, ///< Function reference, .v_string is used as function name. - VAR_LIST, ///< List, .v_list is used. - VAR_DICT, ///< Dictionary, .v_dict is used. - VAR_FLOAT, ///< Floating-point value, .v_float is used. - VAR_BOOL, ///< true, false - VAR_SPECIAL, ///< Special value (null), .v_special - ///< is used. - VAR_PARTIAL, ///< Partial, .v_partial is used. - VAR_BLOB, ///< Blob, .v_blob is used. -} VarType; - -/// Structure that holds an internal variable value -typedef struct { - VarType v_type; ///< Variable type. - VarLockStatus v_lock; ///< Variable lock status. - union typval_vval_union { - varnumber_T v_number; ///< Number, for VAR_NUMBER. - BoolVarValue v_bool; ///< Bool value, for VAR_BOOL - SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL. - float_T v_float; ///< Floating-point number, for VAR_FLOAT. - char *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL. - list_T *v_list; ///< List for VAR_LIST, can be NULL. - dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL. - partial_T *v_partial; ///< Closure: function with args. - blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL. - } vval; ///< Actual value. -} typval_T; - -/// Values for (struct dictvar_S).dv_scope -typedef enum { - VAR_NO_SCOPE = 0, ///< Not a scope dictionary. - VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …). - VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix - ///< (l:, g:). -} ScopeType; - -/// Structure to hold an item of a list -typedef struct listitem_S listitem_T; - -struct listitem_S { - listitem_T *li_next; ///< Next item in list. - listitem_T *li_prev; ///< Previous item in list. - typval_T li_tv; ///< Item value. -}; - -/// Structure used by those that are using an item in a list -typedef struct listwatch_S listwatch_T; - -struct listwatch_S { - listitem_T *lw_item; ///< Item being watched. - listwatch_T *lw_next; ///< Next watcher. -}; - -/// Structure to hold info about a list -/// Order of members is optimized to reduce padding. -struct listvar_S { - listitem_T *lv_first; ///< First item, NULL if none. - listitem_T *lv_last; ///< Last item, NULL if none. - listwatch_T *lv_watch; ///< First watcher, NULL if none. - listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx". - list_T *lv_copylist; ///< Copied list used by deepcopy(). - list_T *lv_used_next; ///< next list in used lists list. - list_T *lv_used_prev; ///< Previous list in used lists list. - int lv_refcount; ///< Reference count. - int lv_len; ///< Number of items. - int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx]. - int lv_copyID; ///< ID used by deepcopy(). - VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED. - - LuaRef lua_table_ref; -}; - -// Static list with 10 items. Use tv_list_init_static10() to initialize. -typedef struct { - list_T sl_list; // must be first - listitem_T sl_items[10]; -} staticList10_T; - -#define TV_LIST_STATIC10_INIT { \ - .sl_list = { \ - .lv_first = NULL, \ - .lv_last = NULL, \ - .lv_refcount = 0, \ - .lv_len = 0, \ - .lv_watch = NULL, \ - .lv_idx_item = NULL, \ - .lv_lock = VAR_FIXED, \ - .lv_used_next = NULL, \ - .lv_used_prev = NULL, \ - }, \ -} - -#define TV_DICTITEM_STRUCT(...) \ - struct { \ - typval_T di_tv; /* Structure that holds scope dictionary itself. */ \ - uint8_t di_flags; /* Flags. */ \ - char_u di_key[__VA_ARGS__]; /* Key value. */ \ - } - -/// Structure to hold a scope dictionary -/// -/// @warning Must be compatible with dictitem_T. -/// -/// For use in find_var_in_ht to pretend that it found dictionary item when it -/// finds scope dictionary. -typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem; - -/// Structure to hold an item of a Dictionary -/// -/// @warning Must be compatible with ScopeDictDictItem. -/// -/// Also used for a variable. -typedef TV_DICTITEM_STRUCT() dictitem_T; - -/// Flags for dictitem_T.di_flags -typedef enum { - DI_FLAGS_RO = 1, ///< Read-only value - DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox - DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d. - DI_FLAGS_LOCK = 8, ///< Locked value. - DI_FLAGS_ALLOC = 16, ///< Separately allocated. -} DictItemFlags; - -/// Structure representing a Dictionary -struct dictvar_S { - VarLockStatus dv_lock; ///< Whole dictionary lock status. - ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if - ///< dictionary represents a scope (i.e. g:, l: …). - int dv_refcount; ///< Reference count. - int dv_copyID; ///< ID used when recursivery traversing a value. - hashtab_T dv_hashtab; ///< Hashtab containing all items. - dict_T *dv_copydict; ///< Copied dict used by deepcopy(). - dict_T *dv_used_next; ///< Next dictionary in used dictionaries list. - dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list. - QUEUE watchers; ///< Dictionary key watchers set by user code. - - LuaRef lua_table_ref; -}; - -/// Structure to hold info about a Blob -struct blobvar_S { - garray_T bv_ga; ///< Growarray with the data. - int bv_refcount; ///< Reference count. - VarLockStatus bv_lock; ///< VAR_UNLOCKED, VAR_LOCKED, VAR_FIXED. -}; - -/// Type used for script ID -typedef int scid_T; -/// Format argument for scid_T -#define PRIdSCID "d" - -// SCript ConteXt (SCTX): identifies a script line. -// When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current -// line number. When executing a user function "sc_lnum" is the line where the -// function was defined, "sourcing_lnum" is the line number inside the -// function. When stored with a function, mapping, option, etc. "sc_lnum" is -// the line number in the script "sc_sid". -typedef struct { - scid_T sc_sid; // script ID - int sc_seq; // sourcing sequence number - linenr_T sc_lnum; // line number -} sctx_T; - -/// Maximum number of function arguments -#define MAX_FUNC_ARGS 20 -/// Short variable name length -#define VAR_SHORT_LEN 20 -/// Number of fixed variables used for arguments -#define FIXVAR_CNT 12 - -/// Callback interface for C function reference> -/// Used for managing functions that were registered with |register_cfunc| -typedef int (*cfunc_T)(int argcount, typval_T *argvars, typval_T *rettv, void *state); // NOLINT -/// Callback to clear cfunc_T and any associated state. -typedef void (*cfunc_free_T)(void *state); - -// Structure to hold info for a function that is currently being executed. -typedef struct funccall_S funccall_T; - -struct funccall_S { - ufunc_T *func; ///< Function being called. - int linenr; ///< Next line to be executed. - int returned; ///< ":return" used. - /// Fixed variables for arguments. - TV_DICTITEM_STRUCT(VAR_SHORT_LEN + 1) fixvar[FIXVAR_CNT]; - dict_T l_vars; ///< l: local function variables. - ScopeDictDictItem l_vars_var; ///< Variable for l: scope. - dict_T l_avars; ///< a: argument variables. - ScopeDictDictItem l_avars_var; ///< Variable for a: scope. - list_T l_varlist; ///< List for a:000. - listitem_T l_listitems[MAX_FUNC_ARGS]; ///< List items for a:000. - typval_T *rettv; ///< Return value. - linenr_T breakpoint; ///< Next line with breakpoint or zero. - int dbg_tick; ///< Debug_tick when breakpoint was set. - int level; ///< Top nesting level of executed function. - proftime_T prof_child; ///< Time spent in a child. - funccall_T *caller; ///< Calling function or NULL; or next funccal in - ///< list pointed to by previous_funccal. - int fc_refcount; ///< Number of user functions that reference this funccall. - int fc_copyID; ///< CopyID used for garbage collection. - garray_T fc_funcs; ///< List of ufunc_T* which keep a reference to "func". -}; - -/// Structure to hold info for a user function. -struct ufunc { - int uf_varargs; ///< variable nr of arguments - int uf_flags; - int uf_calls; ///< nr of active calls - bool uf_cleared; ///< func_clear() was already called - garray_T uf_args; ///< arguments - garray_T uf_def_args; ///< default argument expressions - garray_T uf_lines; ///< function lines - int uf_profiling; ///< true when func is being profiled - int uf_prof_initialized; - // Managing cfuncs - cfunc_T uf_cb; ///< C function extension callback - cfunc_free_T uf_cb_free; ///< C function extension free callback - void *uf_cb_state; ///< State of C function extension. - // Profiling the function as a whole. - int uf_tm_count; ///< nr of calls - proftime_T uf_tm_total; ///< time spent in function + children - proftime_T uf_tm_self; ///< time spent in function itself - proftime_T uf_tm_children; ///< time spent in children this call - // Profiling the function per line. - int *uf_tml_count; ///< nr of times line was executed - proftime_T *uf_tml_total; ///< time spent in a line + children - proftime_T *uf_tml_self; ///< time spent in a line itself - proftime_T uf_tml_start; ///< start time for current line - proftime_T uf_tml_children; ///< time spent in children for this line - proftime_T uf_tml_wait; ///< start wait time for current line - int uf_tml_idx; ///< index of line being timed; -1 if none - int uf_tml_execed; ///< line being timed was executed - sctx_T uf_script_ctx; ///< SCTX where function was defined, - ///< used for s: variables - int uf_refcount; ///< reference count, see func_name_refcount() - funccall_T *uf_scoped; ///< l: local variables for closure - char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with - ///< "<SNR>" as a string, otherwise NULL - char_u uf_name[]; ///< Name of function (actual size equals name); - ///< can start with <SNR>123_ - ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) -}; - -struct partial_S { - int pt_refcount; ///< Reference count. - char_u *pt_name; ///< Function name; when NULL use pt_func->name. - ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with - ///< pt_name. - bool pt_auto; ///< When true the partial was created by using dict.member - ///< in handle_subscript(). - int pt_argc; ///< Number of arguments. - typval_T *pt_argv; ///< Arguments in allocated array. - dict_T *pt_dict; ///< Dict for "self". -}; - -/// Structure used for explicit stack while garbage collecting hash tables -typedef struct ht_stack_S { - hashtab_T *ht; - struct ht_stack_S *prev; -} ht_stack_T; - -/// Structure used for explicit stack while garbage collecting lists -typedef struct list_stack_S { - list_T *list; - struct list_stack_S *prev; -} list_stack_T; - -/// Structure representing one list item, used for sort array. -typedef struct { - listitem_T *item; ///< Sorted list item. - int idx; ///< Sorted list item index. -} ListSortItem; - -typedef int (*ListSorter)(const void *, const void *); #ifdef LOG_LIST_ACTIONS - -/// List actions log entry -typedef struct { - uintptr_t l; ///< List log entry belongs to. - uintptr_t li1; ///< First list item log entry belongs to, if applicable. - uintptr_t li2; ///< Second list item log entry belongs to, if applicable. - int len; ///< List length when log entry was created. - const char *action; ///< Logged action. -} ListLogEntry; - -typedef struct list_log ListLog; - -/// List actions log -struct list_log { - ListLog *next; ///< Next chunk or NULL. - size_t capacity; ///< Number of entries in current chunk. - size_t size; ///< Current chunk size. - ListLogEntry entries[]; ///< Actual log entries. -}; +# include "nvim/memory.h" extern ListLog *list_log_first; ///< First list log chunk, NULL if missing extern ListLog *list_log_last; ///< Last list log chunk @@ -793,12 +394,6 @@ static inline void tv_init(typval_T *const tv) } } -#define TV_INITIAL_VALUE \ - ((typval_T) { \ - .v_type = VAR_UNKNOWN, \ - .v_lock = VAR_UNLOCKED, \ - }) - /// Empty string /// /// Needed for hack which allows not allocating empty string and still not @@ -897,9 +492,6 @@ static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret_f) REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; -// FIXME circular dependency, cannot import message.h. -bool semsg(const char *const fmt, ...); - /// Get the float value /// /// Raises an error if object is not number or floating-point. diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h new file mode 100644 index 0000000000..1c0a438751 --- /dev/null +++ b/src/nvim/eval/typval_defs.h @@ -0,0 +1,399 @@ +#ifndef NVIM_EVAL_TYPVAL_DEFS_H +#define NVIM_EVAL_TYPVAL_DEFS_H + +#include <inttypes.h> +#include <limits.h> + +#include "nvim/garray.h" +#include "nvim/hashtab.h" +#include "nvim/lib/queue.h" +#include "nvim/pos.h" +#include "nvim/types.h" + +/// Type used for VimL VAR_NUMBER values +typedef int64_t varnumber_T; +typedef uint64_t uvarnumber_T; + +/// Refcount for dict or list that should not be freed +enum { DO_NOT_FREE_CNT = (INT_MAX / 2), }; + +/// Additional values for tv_list_alloc() len argument +enum ListLenSpecials { + /// List length is not known in advance + /// + /// To be used when there is neither a way to know how many elements will be + /// needed nor are any educated guesses. + kListLenUnknown = -1, + /// List length *should* be known, but is actually not + /// + /// All occurrences of this value should be eventually removed. This is for + /// the case when the only reason why list length is not known is that it + /// would be hard to code without refactoring, but refactoring is needed. + kListLenShouldKnow = -2, + /// List length may be known in advance, but it requires too much effort + /// + /// To be used when it looks impractical to determine list length. + kListLenMayKnow = -3, +}; + +/// Maximal possible value of varnumber_T variable +#define VARNUMBER_MAX INT64_MAX +#define UVARNUMBER_MAX UINT64_MAX + +/// Minimal possible value of varnumber_T variable +#define VARNUMBER_MIN INT64_MIN + +/// %d printf format specifier for varnumber_T +#define PRIdVARNUMBER PRId64 + +typedef struct listvar_S list_T; +typedef struct dictvar_S dict_T; +typedef struct partial_S partial_T; +typedef struct blobvar_S blob_T; + +typedef struct ufunc ufunc_T; + +typedef enum { + kCallbackNone = 0, + kCallbackFuncref, + kCallbackPartial, + kCallbackLua, +} CallbackType; + +typedef struct { + union { + char *funcref; + partial_T *partial; + LuaRef luaref; + } data; + CallbackType type; +} Callback; + +#define CALLBACK_INIT { .type = kCallbackNone } +#define CALLBACK_NONE ((Callback)CALLBACK_INIT) + +/// Structure holding dictionary watcher +typedef struct dict_watcher { + Callback callback; + char *key_pattern; + size_t key_pattern_len; + QUEUE node; + bool busy; // prevent recursion if the dict is changed in the callback + bool needs_free; +} DictWatcher; + +/// Bool variable values +typedef enum { + kBoolVarFalse, ///< v:false + kBoolVarTrue, ///< v:true +} BoolVarValue; + +/// Special variable values +typedef enum { + kSpecialVarNull, ///< v:null +} SpecialVarValue; + +/// Variable lock status for typval_T.v_lock +typedef enum { + VAR_UNLOCKED = 0, ///< Not locked. + VAR_LOCKED = 1, ///< User lock, can be unlocked. + VAR_FIXED = 2, ///< Locked forever. +} VarLockStatus; + +/// VimL variable types, for use in typval_T.v_type +typedef enum { + VAR_UNKNOWN = 0, ///< Unknown (unspecified) value. + VAR_NUMBER, ///< Number, .v_number is used. + VAR_STRING, ///< String, .v_string is used. + VAR_FUNC, ///< Function reference, .v_string is used as function name. + VAR_LIST, ///< List, .v_list is used. + VAR_DICT, ///< Dictionary, .v_dict is used. + VAR_FLOAT, ///< Floating-point value, .v_float is used. + VAR_BOOL, ///< true, false + VAR_SPECIAL, ///< Special value (null), .v_special is used. + VAR_PARTIAL, ///< Partial, .v_partial is used. + VAR_BLOB, ///< Blob, .v_blob is used. +} VarType; + +/// Structure that holds an internal variable value +typedef struct { + VarType v_type; ///< Variable type. + VarLockStatus v_lock; ///< Variable lock status. + union typval_vval_union { + varnumber_T v_number; ///< Number, for VAR_NUMBER. + BoolVarValue v_bool; ///< Bool value, for VAR_BOOL + SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL. + float_T v_float; ///< Floating-point number, for VAR_FLOAT. + char *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL. + list_T *v_list; ///< List for VAR_LIST, can be NULL. + dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL. + partial_T *v_partial; ///< Closure: function with args. + blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL. + } vval; ///< Actual value. +} typval_T; + +#define TV_INITIAL_VALUE \ + ((typval_T) { \ + .v_type = VAR_UNKNOWN, \ + .v_lock = VAR_UNLOCKED, \ + }) + +/// Values for (struct dictvar_S).dv_scope +typedef enum { + VAR_NO_SCOPE = 0, ///< Not a scope dictionary. + VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …). + VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix + ///< (l:, g:). +} ScopeType; + +/// Structure to hold an item of a list +typedef struct listitem_S listitem_T; + +struct listitem_S { + listitem_T *li_next; ///< Next item in list. + listitem_T *li_prev; ///< Previous item in list. + typval_T li_tv; ///< Item value. +}; + +/// Structure used by those that are using an item in a list +typedef struct listwatch_S listwatch_T; + +struct listwatch_S { + listitem_T *lw_item; ///< Item being watched. + listwatch_T *lw_next; ///< Next watcher. +}; + +/// Structure to hold info about a list +/// Order of members is optimized to reduce padding. +struct listvar_S { + listitem_T *lv_first; ///< First item, NULL if none. + listitem_T *lv_last; ///< Last item, NULL if none. + listwatch_T *lv_watch; ///< First watcher, NULL if none. + listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx". + list_T *lv_copylist; ///< Copied list used by deepcopy(). + list_T *lv_used_next; ///< next list in used lists list. + list_T *lv_used_prev; ///< Previous list in used lists list. + int lv_refcount; ///< Reference count. + int lv_len; ///< Number of items. + int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx]. + int lv_copyID; ///< ID used by deepcopy(). + VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED. + + LuaRef lua_table_ref; +}; + +/// Static list with 10 items. Use tv_list_init_static10() to initialize. +typedef struct { + list_T sl_list; // must be first + listitem_T sl_items[10]; +} staticList10_T; + +#define TV_LIST_STATIC10_INIT { \ + .sl_list = { \ + .lv_first = NULL, \ + .lv_last = NULL, \ + .lv_refcount = 0, \ + .lv_len = 0, \ + .lv_watch = NULL, \ + .lv_idx_item = NULL, \ + .lv_lock = VAR_FIXED, \ + .lv_used_next = NULL, \ + .lv_used_prev = NULL, \ + }, \ +} + +#define TV_DICTITEM_STRUCT(...) \ + struct { \ + typval_T di_tv; /* Structure that holds scope dictionary itself. */ \ + uint8_t di_flags; /* Flags. */ \ + char_u di_key[__VA_ARGS__]; /* Key value. */ \ + } + +/// Structure to hold a scope dictionary +/// +/// @warning Must be compatible with dictitem_T. +/// +/// For use in find_var_in_ht to pretend that it found dictionary item when it +/// finds scope dictionary. +typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem; + +/// Structure to hold an item of a Dictionary +/// +/// @warning Must be compatible with ScopeDictDictItem. +/// +/// Also used for a variable. +typedef TV_DICTITEM_STRUCT() dictitem_T; + +/// Flags for dictitem_T.di_flags +typedef enum { + DI_FLAGS_RO = 1, ///< Read-only value + DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox + DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d. + DI_FLAGS_LOCK = 8, ///< Locked value. + DI_FLAGS_ALLOC = 16, ///< Separately allocated. +} DictItemFlags; + +/// Structure representing a Dictionary +struct dictvar_S { + VarLockStatus dv_lock; ///< Whole dictionary lock status. + ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if + ///< dictionary represents a scope (i.e. g:, l: …). + int dv_refcount; ///< Reference count. + int dv_copyID; ///< ID used when recursivery traversing a value. + hashtab_T dv_hashtab; ///< Hashtab containing all items. + dict_T *dv_copydict; ///< Copied dict used by deepcopy(). + dict_T *dv_used_next; ///< Next dictionary in used dictionaries list. + dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list. + QUEUE watchers; ///< Dictionary key watchers set by user code. + + LuaRef lua_table_ref; +}; + +/// Structure to hold info about a Blob +struct blobvar_S { + garray_T bv_ga; ///< Growarray with the data. + int bv_refcount; ///< Reference count. + VarLockStatus bv_lock; ///< VAR_UNLOCKED, VAR_LOCKED, VAR_FIXED. +}; + +/// Type used for script ID +typedef int scid_T; +/// Format argument for scid_T +#define PRIdSCID "d" + +/// SCript ConteXt (SCTX): identifies a script line. +/// When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current +/// line number. When executing a user function "sc_lnum" is the line where the +/// function was defined, "sourcing_lnum" is the line number inside the +/// function. When stored with a function, mapping, option, etc. "sc_lnum" is +/// the line number in the script "sc_sid". +typedef struct { + scid_T sc_sid; ///< script ID + int sc_seq; ///< sourcing sequence number + linenr_T sc_lnum; ///< line number +} sctx_T; + +/// Maximum number of function arguments +enum { MAX_FUNC_ARGS = 20, }; +/// Short variable name length +enum { VAR_SHORT_LEN = 20, }; +/// Number of fixed variables used for arguments +enum { FIXVAR_CNT = 12, }; + +/// Structure to hold info for a function that is currently being executed. +typedef struct funccall_S funccall_T; + +struct funccall_S { + ufunc_T *func; ///< Function being called. + int linenr; ///< Next line to be executed. + int returned; ///< ":return" used. + /// Fixed variables for arguments. + TV_DICTITEM_STRUCT(VAR_SHORT_LEN + 1) fixvar[FIXVAR_CNT]; + dict_T l_vars; ///< l: local function variables. + ScopeDictDictItem l_vars_var; ///< Variable for l: scope. + dict_T l_avars; ///< a: argument variables. + ScopeDictDictItem l_avars_var; ///< Variable for a: scope. + list_T l_varlist; ///< List for a:000. + listitem_T l_listitems[MAX_FUNC_ARGS]; ///< List items for a:000. + typval_T *rettv; ///< Return value. + linenr_T breakpoint; ///< Next line with breakpoint or zero. + int dbg_tick; ///< debug_tick when breakpoint was set. + int level; ///< Top nesting level of executed function. + proftime_T prof_child; ///< Time spent in a child. + funccall_T *caller; ///< Calling function or NULL; or next funccal in + ///< list pointed to by previous_funccal. + int fc_refcount; ///< Number of user functions that reference this funccall. + int fc_copyID; ///< CopyID used for garbage collection. + garray_T fc_funcs; ///< List of ufunc_T* which keep a reference to "func". +}; + +/// Structure to hold info for a user function. +struct ufunc { + int uf_varargs; ///< variable nr of arguments + int uf_flags; + int uf_calls; ///< nr of active calls + bool uf_cleared; ///< func_clear() was already called + garray_T uf_args; ///< arguments + garray_T uf_def_args; ///< default argument expressions + garray_T uf_lines; ///< function lines + int uf_profiling; ///< true when func is being profiled + int uf_prof_initialized; + LuaRef uf_luaref; ///< lua callback, used if (uf_flags & FC_LUAREF) + // Profiling the function as a whole. + int uf_tm_count; ///< nr of calls + proftime_T uf_tm_total; ///< time spent in function + children + proftime_T uf_tm_self; ///< time spent in function itself + proftime_T uf_tm_children; ///< time spent in children this call + // Profiling the function per line. + int *uf_tml_count; ///< nr of times line was executed + proftime_T *uf_tml_total; ///< time spent in a line + children + proftime_T *uf_tml_self; ///< time spent in a line itself + proftime_T uf_tml_start; ///< start time for current line + proftime_T uf_tml_children; ///< time spent in children for this line + proftime_T uf_tml_wait; ///< start wait time for current line + int uf_tml_idx; ///< index of line being timed; -1 if none + int uf_tml_execed; ///< line being timed was executed + sctx_T uf_script_ctx; ///< SCTX where function was defined, + ///< used for s: variables + int uf_refcount; ///< reference count, see func_name_refcount() + funccall_T *uf_scoped; ///< l: local variables for closure + char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with + ///< "<SNR>" as a string, otherwise NULL + char_u uf_name[]; ///< Name of function (actual size equals name); + ///< can start with <SNR>123_ + ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) +}; + +struct partial_S { + int pt_refcount; ///< Reference count. + char *pt_name; ///< Function name; when NULL use pt_func->name. + ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with pt_name. + bool pt_auto; ///< When true the partial was created by using dict.member + ///< in handle_subscript(). + int pt_argc; ///< Number of arguments. + typval_T *pt_argv; ///< Arguments in allocated array. + dict_T *pt_dict; ///< Dict for "self". +}; + +/// Structure used for explicit stack while garbage collecting hash tables +typedef struct ht_stack_S { + hashtab_T *ht; + struct ht_stack_S *prev; +} ht_stack_T; + +/// Structure used for explicit stack while garbage collecting lists +typedef struct list_stack_S { + list_T *list; + struct list_stack_S *prev; +} list_stack_T; + +/// Structure representing one list item, used for sort array. +typedef struct { + listitem_T *item; ///< Sorted list item. + int idx; ///< Sorted list item index. +} ListSortItem; + +typedef int (*ListSorter)(const void *, const void *); + +#ifdef LOG_LIST_ACTIONS +/// List actions log entry +typedef struct { + uintptr_t l; ///< List log entry belongs to. + uintptr_t li1; ///< First list item log entry belongs to, if applicable. + uintptr_t li2; ///< Second list item log entry belongs to, if applicable. + int len; ///< List length when log entry was created. + const char *action; ///< Logged action. +} ListLogEntry; + +typedef struct list_log ListLog; + +/// List actions log +struct list_log { + ListLog *next; ///< Next chunk or NULL. + size_t capacity; ///< Number of entries in current chunk. + size_t size; ///< Current chunk size. + ListLogEntry entries[]; ///< Actual log entries. +}; +#endif + +#endif // NVIM_EVAL_TYPVAL_DEFS_H diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 73b36b8611..ff4f92e40b 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -250,7 +250,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_encode.h" #include "nvim/func_attr.h" -#include "nvim/lib/kvec.h" +#include "klib/kvec.h" // -V::1063 diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index ed70ba87ec..33e19c531c 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -10,9 +10,9 @@ #include <stddef.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/eval/typval.h" #include "nvim/func_attr.h" -#include "nvim/lib/kvec.h" /// Type of the stack entry typedef enum { diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index c46cb6ba5d..b0a56c4440 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -28,20 +28,6 @@ #include "nvim/ui.h" #include "nvim/vim.h" -// flags used in uf_flags -#define FC_ABORT 0x01 // abort function on error -#define FC_RANGE 0x02 // function accepts range -#define FC_DICT 0x04 // Dict function, uses "self" -#define FC_CLOSURE 0x08 // closure, uses outer scope variables -#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 -#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 -#define FC_SANDBOX 0x40 // function defined in the sandbox -#define FC_DEAD 0x80 // function kept only for reference to dfunc -#define FC_EXPORT 0x100 // "export def Func()" -#define FC_NOARGS 0x200 // no a: variables in lambda -#define FC_VIM9 0x400 // defined in vim9 script file -#define FC_CFUNC 0x800 // C function extension - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/userfunc.c.generated.h" #endif @@ -125,7 +111,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int // Check for duplicate argument name. for (i = 0; i < newargs->ga_len; i++) { - if (STRCMP(((char **)(newargs->ga_data))[i], arg) == 0) { + if (strcmp(((char **)(newargs->ga_data))[i], arg) == 0) { semsg(_("E853: Duplicate argument name: %s"), arg); xfree(arg); goto err_ret; @@ -142,18 +128,18 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int any_default = true; p = skipwhite(p) + 1; p = skipwhite(p); - char_u *expr = (char_u *)p; + char *expr = p; if (eval1(&p, &rettv, false) != FAIL) { ga_grow(default_args, 1); // trim trailing whitespace - while (p > (char *)expr && ascii_iswhite(p[-1])) { + while (p > expr && ascii_iswhite(p[-1])) { p--; } c = (char_u)(*p); *p = NUL; - expr = vim_strsave(expr); - ((char **)(default_args->ga_data))[default_args->ga_len] = (char *)expr; + expr = xstrdup(expr); + ((char **)(default_args->ga_data))[default_args->ga_len] = expr; default_args->ga_len++; *p = (char)c; } else { @@ -378,7 +364,7 @@ char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp, *lenp = 0; return (char_u *)""; } - *lenp = (int)STRLEN(v->di_tv.vval.v_string); + *lenp = (int)strlen(v->di_tv.vval.v_string); return (char_u *)v->di_tv.vval.v_string; } @@ -409,7 +395,7 @@ void emsg_funcname(char *ermsg, const char_u *name) char_u *p; if (*name == K_SPECIAL) { - p = concat_str((char_u *)"<SNR>", name + 3); + p = (char_u *)concat_str("<SNR>", (char *)name + 3); } else { p = (char_u *)name; } @@ -439,12 +425,12 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex // Get the arguments. argp = *arg; while (argcount < MAX_FUNC_ARGS - - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) { + - (funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc)) { argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) { break; } - if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) { + if (eval1(&argp, &argvars[argcount], funcexe->fe_evaluate) == FAIL) { ret = FAIL; break; } @@ -525,39 +511,38 @@ static inline bool eval_fname_sid(const char *const name) /// /// @return transformed name: either `fname_buf` or a pointer to an allocated /// memory. -static char_u *fname_trans_sid(const char_u *const name, char_u *const fname_buf, - char_u **const tofree, int *const error) +static char *fname_trans_sid(const char *const name, char *const fname_buf, char **const tofree, + int *const error) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - char_u *fname; - const int llen = eval_fname_script((const char *)name); - if (llen > 0) { - fname_buf[0] = K_SPECIAL; - fname_buf[1] = KS_EXTRA; - fname_buf[2] = KE_SNR; - int i = 3; - if (eval_fname_sid((const char *)name)) { // "<SID>" or "s:" - if (current_sctx.sc_sid <= 0) { - *error = ERROR_SCRIPT; - } else { - snprintf((char *)fname_buf + i, (size_t)(FLEN_FIXED + 1 - i), "%" PRId64 "_", - (int64_t)current_sctx.sc_sid); - i = (int)STRLEN(fname_buf); - } - } - if ((size_t)i + STRLEN(name + llen) < FLEN_FIXED) { - STRCPY(fname_buf + i, name + llen); - fname = fname_buf; + const int llen = eval_fname_script(name); + if (llen == 0) { + return (char *)name; // no prefix + } + + fname_buf[0] = (char)K_SPECIAL; + fname_buf[1] = (char)KS_EXTRA; + fname_buf[2] = KE_SNR; + int i = 3; + if (eval_fname_sid(name)) { // "<SID>" or "s:" + if (current_sctx.sc_sid <= 0) { + *error = FCERR_SCRIPT; } else { - fname = xmalloc((size_t)i + STRLEN(name + llen) + 1); - *tofree = fname; - memmove(fname, fname_buf, (size_t)i); - STRCPY(fname + i, name + llen); + snprintf(fname_buf + i, (size_t)(FLEN_FIXED + 1 - i), "%" PRId64 "_", + (int64_t)current_sctx.sc_sid); + i = (int)strlen(fname_buf); } + } + char *fname; + if ((size_t)i + strlen(name + llen) < FLEN_FIXED) { + STRCPY(fname_buf + i, name + llen); + fname = fname_buf; } else { - fname = (char_u *)name; + fname = xmalloc((size_t)i + strlen(name + llen) + 1); + *tofree = fname; + memmove(fname, fname_buf, (size_t)i); + STRCPY(fname + i, name + llen); } - return fname; } @@ -758,9 +743,9 @@ static void func_clear_items(ufunc_T *fp) ga_clear_strings(&(fp->uf_lines)); XFREE_CLEAR(fp->uf_name_exp); - if (fp->uf_cb_free != NULL) { - fp->uf_cb_free(fp->uf_cb_state); - fp->uf_cb_free = NULL; + if (fp->uf_flags & FC_LUAREF) { + api_free_luaref(fp->uf_luaref); + fp->uf_luaref = LUA_NOREF; } XFREE_CLEAR(fp->uf_tml_count); @@ -852,7 +837,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett saveRedobuff(&save_redo); did_save_redo = true; } - ++fp->uf_calls; + fp->uf_calls++; // check for CTRL-C hit line_breakcheck(); // prepare the funccall_T structure @@ -863,7 +848,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett fc->rettv = rettv; fc->level = ex_nesting_level; // Check if this function has a breakpoint. - fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); + fc->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, (linenr_T)0); fc->dbg_tick = debug_tick; // Set up fields for closure. @@ -893,7 +878,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett v->di_tv.v_type = VAR_DICT; v->di_tv.v_lock = VAR_UNLOCKED; v->di_tv.vval.v_dict = selfdict; - ++selfdict->dv_refcount; + selfdict->dv_refcount++; } // Init a: variables, unless none found (in lambda). @@ -970,11 +955,11 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1); name = (char *)numbuf; } - if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) { + if (fixvar_idx < FIXVAR_CNT && strlen(name) <= VAR_SHORT_LEN) { v = (dictitem_T *)&fc->fixvar[fixvar_idx++]; v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; } else { - v = xmalloc(sizeof(dictitem_T) + STRLEN(name)); + v = xmalloc(sizeof(dictitem_T) + strlen(name)); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC; } STRCPY(v->di_key, name); @@ -1058,7 +1043,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett bool func_not_yet_profiling_but_should = do_profiling_yes - && !fp->uf_profiling && has_profiling(false, fp->uf_name, NULL); + && !fp->uf_profiling && has_profiling(false, (char *)fp->uf_name, NULL); if (func_not_yet_profiling_but_should) { started_profiling = true; @@ -1071,7 +1056,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett || (fc->caller != NULL && fc->caller->func->uf_profiling)); if (func_or_func_caller_profiling) { - ++fp->uf_tm_count; + fp->uf_tm_count++; call_start = profile_start(); fp->uf_tm_children = profile_zero(); } @@ -1083,7 +1068,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett const sctx_T save_current_sctx = current_sctx; current_sctx = fp->uf_script_ctx; save_did_emsg = did_emsg; - did_emsg = FALSE; + did_emsg = false; if (default_arg_err && (fp->uf_flags & FC_ABORT)) { did_emsg = true; @@ -1213,6 +1198,34 @@ static bool func_name_refcount(char_u *name) return isdigit(*name) || *name == '<'; } +/// Call a user function after checking the arguments. +static int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, + funcexe_T *funcexe, dict_T *selfdict) + FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5) +{ + if (fp->uf_flags & FC_LUAREF) { + return typval_exec_lua_callable(fp->uf_luaref, argcount, argvars, rettv); + } + + if ((fp->uf_flags & FC_RANGE) && funcexe->fe_doesrange != NULL) { + *funcexe->fe_doesrange = true; + } + int error; + if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) { + error = FCERR_TOOFEW; + } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) { + error = FCERR_TOOMANY; + } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { + error = FCERR_DICT; + } else { + // Call the user function. + call_user_func(fp, argcount, argvars, rettv, funcexe->fe_firstline, funcexe->fe_lastline, + (fp->uf_flags & FC_DICT) ? selfdict : NULL); + error = FCERR_NONE; + } + return error; +} + static funccal_entry_T *funccal_stack = NULL; /// Save the current function call pointer, and set it to NULL. @@ -1353,11 +1366,11 @@ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict }); funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = true; - funcexe.partial = partial; - funcexe.selfdict = selfdict; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; + funcexe.fe_selfdict = selfdict; r = call_func((char *)name, -1, rettv, argc, argv, &funcexe); func_call_skip_call: @@ -1375,27 +1388,27 @@ static void user_func_error(int error, const char_u *name) FUNC_ATTR_NONNULL_ALL { switch (error) { - case ERROR_UNKNOWN: + case FCERR_UNKNOWN: emsg_funcname(N_("E117: Unknown function: %s"), name); break; - case ERROR_NOTMETHOD: + case FCERR_NOTMETHOD: emsg_funcname(N_("E276: Cannot use function as a method: %s"), name); break; - case ERROR_DELETED: + case FCERR_DELETED: emsg_funcname(N_("E933: Function was deleted: %s"), name); break; - case ERROR_TOOMANY: + case FCERR_TOOMANY: emsg_funcname(_(e_toomanyarg), name); break; - case ERROR_TOOFEW: + case FCERR_TOOFEW: emsg_funcname(N_("E119: Not enough arguments for function: %s"), name); break; - case ERROR_SCRIPT: + case FCERR_SCRIPT: emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), name); break; - case ERROR_DICT: + case FCERR_DICT: emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name); break; @@ -1435,27 +1448,27 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6) { int ret = FAIL; - int error = ERROR_NONE; + int error = FCERR_NONE; ufunc_T *fp = NULL; - char_u fname_buf[FLEN_FIXED + 1]; - char_u *tofree = NULL; - char_u *fname = NULL; - char_u *name = NULL; + char fname_buf[FLEN_FIXED + 1]; + char *tofree = NULL; + char *fname = NULL; + char *name = NULL; int argcount = argcount_in; typval_T *argvars = argvars_in; - dict_T *selfdict = funcexe->selfdict; + dict_T *selfdict = funcexe->fe_selfdict; typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or - // "funcexe->basetv" is not NULL + // "funcexe->fe_basetv" is not NULL int argv_clear = 0; int argv_base = 0; - partial_T *partial = funcexe->partial; + partial_T *partial = funcexe->fe_partial; // Initialize rettv so that it is safe for caller to invoke clear_tv(rettv) // even when call_func() returns FAIL. rettv->v_type = VAR_UNKNOWN; if (len <= 0) { - len = (int)STRLEN(funcname); + len = (int)strlen(funcname); } if (partial != NULL) { fp = partial->pt_func; @@ -1463,12 +1476,12 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t if (fp == NULL) { // Make a copy of the name, if it comes from a funcref variable it could // be changed or deleted in the called function. - name = vim_strnsave((char_u *)funcname, (size_t)len); - fname = fname_trans_sid(name, fname_buf, &tofree, &error); + name = xstrnsave(funcname, (size_t)len); + fname = fname_trans_sid(name, (char *)fname_buf, &tofree, &error); } - if (funcexe->doesrange != NULL) { - *funcexe->doesrange = false; + if (funcexe->fe_doesrange != NULL) { + *funcexe->fe_doesrange = false; } if (partial != NULL) { @@ -1478,10 +1491,10 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto)) { selfdict = partial->pt_dict; } - if (error == ERROR_NONE && partial->pt_argc > 0) { + if (error == FCERR_NONE && partial->pt_argc > 0) { for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) { if (argv_clear + argcount_in >= MAX_FUNC_ARGS) { - error = ERROR_TOOMANY; + error = FCERR_TOOMANY; goto theend; } tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]); @@ -1494,8 +1507,8 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t } } - if (error == ERROR_NONE && funcexe->evaluate) { - char_u *rfname = fname; + if (error == FCERR_NONE && funcexe->fe_evaluate) { + char *rfname = fname; // Ignore "g:" before a function name. if (fp == NULL && fname[0] == 'g' && fname[1] == ':') { @@ -1504,12 +1517,12 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t rettv->v_type = VAR_NUMBER; // default rettv is number zero rettv->vval.v_number = 0; - error = ERROR_UNKNOWN; + error = FCERR_UNKNOWN; if (is_luafunc(partial)) { if (len > 0) { - error = ERROR_NONE; - argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base); + error = FCERR_NONE; + argv_add_base(funcexe->fe_basetv, &argvars, &argcount, argv, &argv_base); nlua_typval_call(funcname, (size_t)len, argvars, argcount, rettv); } else { // v:lua was called directly; show its name in the emsg @@ -1519,76 +1532,55 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t } else if (fp != NULL || !builtin_function((const char *)rfname, -1)) { // User defined function. if (fp == NULL) { - fp = find_func(rfname); + fp = find_func((char_u *)rfname); } // Trigger FuncUndefined event, may load the function. if (fp == NULL - && apply_autocmds(EVENT_FUNCUNDEFINED, (char *)rfname, (char *)rfname, true, NULL) + && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL) && !aborting()) { // executed an autocommand, search for the function again - fp = find_func(rfname); + fp = find_func((char_u *)rfname); } // Try loading a package. - if (fp == NULL && script_autoload((const char *)rfname, STRLEN(rfname), + if (fp == NULL && script_autoload((const char *)rfname, strlen(rfname), true) && !aborting()) { // Loaded a package, search for the function again. - fp = find_func(rfname); + fp = find_func((char_u *)rfname); } if (fp != NULL && (fp->uf_flags & FC_DELETED)) { - error = ERROR_DELETED; - } else if (fp != NULL && (fp->uf_flags & FC_CFUNC)) { - cfunc_T cb = fp->uf_cb; - error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state); + error = FCERR_DELETED; } else if (fp != NULL) { - if (funcexe->argv_func != NULL) { + if (funcexe->fe_argv_func != NULL) { // postponed filling in the arguments, do it now - argcount = funcexe->argv_func(argcount, argvars, argv_clear, - fp->uf_args.ga_len); + argcount = funcexe->fe_argv_func(argcount, argvars, argv_clear, fp); } - argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base); + argv_add_base(funcexe->fe_basetv, &argvars, &argcount, argv, &argv_base); - if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) { - *funcexe->doesrange = true; - } - if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) { - error = ERROR_TOOFEW; - } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) { - error = ERROR_TOOMANY; - } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { - error = ERROR_DICT; - } else { - // Call the user function. - call_user_func(fp, argcount, argvars, rettv, funcexe->firstline, - funcexe->lastline, - (fp->uf_flags & FC_DICT) ? selfdict : NULL); - error = ERROR_NONE; - } + error = call_user_func_check(fp, argcount, argvars, rettv, funcexe, selfdict); } - } else if (funcexe->basetv != NULL) { + } else if (funcexe->fe_basetv != NULL) { // expr->method(): Find the method name in the table, call its // implementation with the base as one of the arguments. - error = call_internal_method(fname, argcount, argvars, rettv, - funcexe->basetv); + error = call_internal_method((char_u *)fname, argcount, argvars, rettv, + funcexe->fe_basetv); } else { // Find the function name in the table, call its implementation. - error = call_internal_func(fname, argcount, argvars, rettv); - } - /* - * The function call (or "FuncUndefined" autocommand sequence) might - * have been aborted by an error, an interrupt, or an explicitly thrown - * exception that has not been caught so far. This situation can be - * tested for by calling aborting(). For an error in an internal - * function or for the "E132" error in call_user_func(), however, the - * throw point at which the "force_abort" flag (temporarily reset by - * emsg()) is normally updated has not been reached yet. We need to - * update that flag first to make aborting() reliable. - */ + error = call_internal_func((char_u *)fname, argcount, argvars, rettv); + } + // The function call (or "FuncUndefined" autocommand sequence) might + // have been aborted by an error, an interrupt, or an explicitly thrown + // exception that has not been caught so far. This situation can be + // tested for by calling aborting(). For an error in an internal + // function or for the "E132" error in call_user_func(), however, the + // throw point at which the "force_abort" flag (temporarily reset by + // emsg()) is normally updated has not been reached yet. We need to + // update that flag first to make aborting() reliable. update_force_abort(); } - if (error == ERROR_NONE) { + if (error == FCERR_NONE) { ret = OK; } @@ -1596,7 +1588,7 @@ theend: // Report an error unless the argument evaluation or function call has been // cancelled due to an aborting error, an interrupt, or an exception. if (!aborting()) { - user_func_error(error, (name != NULL) ? name : (char_u *)funcname); + user_func_error(error, (name != NULL) ? (char_u *)name : (char_u *)funcname); } // clear the copies made from the partial @@ -1682,7 +1674,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial) FUNC_ATTR_NONNULL_ARG(1) { - char_u *name = NULL; + char *name = NULL; const char_u *start; const char_u *end; int lead; @@ -1720,11 +1712,9 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa goto theend; } if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range))) { - /* - * Report an invalid expression in braces, unless the expression - * evaluation has been cancelled due to an aborting error, an - * interrupt, or an exception. - */ + // 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()) { if (end != NULL) { semsg(_(e_invarg2), start); @@ -1743,7 +1733,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa fdp->fd_di = lv.ll_di; } if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL) { - name = vim_strsave((char_u *)lv.ll_tv->vval.v_string); + name = xstrdup(lv.ll_tv->vval.v_string); *pp = (char *)end; } else if (lv.ll_tv->v_type == VAR_PARTIAL && lv.ll_tv->vval.v_partial != NULL) { @@ -1757,7 +1747,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa memcpy(name, end + 1, (size_t)len); *pp = (char *)end + 1 + len; } else { - name = vim_strsave((char_u *)partial_name(lv.ll_tv->vval.v_partial)); + name = xstrdup(partial_name(lv.ll_tv->vval.v_partial)); *pp = (char *)end; } if (partial != NULL) { @@ -1785,28 +1775,28 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa // Check if the name is a Funcref. If so, use the value. if (lv.ll_exp_name != NULL) { len = (int)strlen(lv.ll_exp_name); - name = deref_func_name(lv.ll_exp_name, &len, partial, - flags & TFN_NO_AUTOLOAD); + name = (char *)deref_func_name(lv.ll_exp_name, &len, partial, + flags & TFN_NO_AUTOLOAD); if ((const char *)name == lv.ll_exp_name) { name = NULL; } } else if (!(flags & TFN_NO_DEREF)) { len = (int)(end - (char_u *)(*pp)); - name = deref_func_name((const char *)(*pp), &len, partial, - flags & TFN_NO_AUTOLOAD); - if (name == (char_u *)(*pp)) { + name = (char *)deref_func_name((const char *)(*pp), &len, partial, + flags & TFN_NO_AUTOLOAD); + if (name == *pp) { name = NULL; } } if (name != NULL) { - name = vim_strsave(name); + name = xstrdup(name); *pp = (char *)end; if (STRNCMP(name, "<SNR>", 5) == 0) { // Change "<SNR>" to the byte sequence. - name[0] = K_SPECIAL; - name[1] = KS_EXTRA; + name[0] = (char)K_SPECIAL; + name[1] = (char)KS_EXTRA; name[2] = KE_SNR; - memmove(name + 3, name + 5, strlen((char *)name + 5) + 1); + memmove(name + 3, name + 5, strlen(name + 5) + 1); } goto theend; } @@ -1869,8 +1859,8 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa name = xmalloc((size_t)len + (size_t)lead + 1); if (!skip && lead > 0) { - name[0] = K_SPECIAL; - name[1] = KS_EXTRA; + name[0] = (char)K_SPECIAL; + name[1] = (char)KS_EXTRA; name[2] = KE_SNR; if (sid_buf_len > 0) { // If it's "<SID>" memcpy(name + 3, sid_buf, sid_buf_len); @@ -1882,21 +1872,23 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa theend: clear_lval(&lv); - return name; + return (char_u *)name; } +#define MAX_FUNC_NESTING 50 + /// ":function" void ex_function(exarg_T *eap) { - char_u *theline; - char_u *line_to_free = NULL; - char_u c; + char *theline; + char *line_to_free = NULL; + char c; int saved_did_emsg; bool saved_wait_return = need_wait_return; - char_u *name = NULL; - char_u *p; - char_u *arg; - char_u *line_arg = NULL; + char *name = NULL; + char *p; + char *arg; + char *line_arg = NULL; garray_T newargs; garray_T default_args; garray_T newlines; @@ -1916,22 +1908,20 @@ void ex_function(exarg_T *eap) linenr_T sourcing_lnum_off; linenr_T sourcing_lnum_top; bool is_heredoc = false; - char_u *skip_until = NULL; - char_u *heredoc_trimmed = NULL; + char *skip_until = NULL; + char *heredoc_trimmed = NULL; bool show_block = false; bool do_concat = true; - /* - * ":function" without argument: list functions. - */ + // ":function" without argument: list functions. if (ends_excmd(*eap->arg)) { if (!eap->skip) { todo = (int)func_hashtab.ht_used; - for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) { + for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; fp = HI2UF(hi); - if (message_filtered(fp->uf_name)) { + if (message_filtered((char *)fp->uf_name)) { continue; } if (!func_name_refcount(fp->uf_name)) { @@ -1940,15 +1930,13 @@ void ex_function(exarg_T *eap) } } } - eap->nextcmd = (char *)check_nextcmd((char_u *)eap->arg); + eap->nextcmd = check_nextcmd(eap->arg); return; } - /* - * ":function /pat": list functions matching pattern. - */ + // ":function /pat": list functions matching pattern. if (*eap->arg == '/') { - p = skip_regexp((char_u *)eap->arg + 1, '/', true, NULL); + p = skip_regexp(eap->arg + 1, '/', true, NULL); if (!eap->skip) { regmatch_T regmatch; @@ -1960,7 +1948,7 @@ void ex_function(exarg_T *eap) regmatch.rm_ic = p_ic; todo = (int)func_hashtab.ht_used; - for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) { + for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; fp = HI2UF(hi); @@ -1976,7 +1964,7 @@ void ex_function(exarg_T *eap) if (*p == '/') { p++; } - eap->nextcmd = (char *)check_nextcmd(p); + eap->nextcmd = check_nextcmd(p); return; } @@ -1994,15 +1982,20 @@ void ex_function(exarg_T *eap) // "fudi.fd_di" set, "fudi.fd_newkey" == NULL // s:func script-local function name // g:func global function name, same as "func" - p = (char_u *)eap->arg; - name = trans_function_name((char **)&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL); - paren = (vim_strchr((char *)p, '(') != NULL); + p = eap->arg; + if (strncmp(p, "<lambda>", 8) == 0) { + p += 8; + (void)getdigits(&p, false, 0); + name = xstrndup(eap->arg, (size_t)(p - eap->arg)); + CLEAR_FIELD(fudi); + } else { + name = (char *)trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL); + } + paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { - /* - * Return on an invalid expression in braces, unless the expression - * evaluation has been cancelled due to an aborting error, an - * interrupt, or an exception. - */ + // Return on an invalid expression in braces, unless the expression + // evaluation has been cancelled due to an aborting error, an + // interrupt, or an exception. if (!aborting()) { if (fudi.fd_newkey != NULL) { semsg(_(e_dictkey), fudi.fd_newkey); @@ -2010,14 +2003,14 @@ void ex_function(exarg_T *eap) xfree(fudi.fd_newkey); return; } else { - eap->skip = TRUE; + eap->skip = true; } } // An error in a function call during evaluation of an expression in magic // braces should not cause the function not to be defined. saved_did_emsg = did_emsg; - did_emsg = FALSE; + did_emsg = false; // // ":function func" with only function name: list function. @@ -2026,16 +2019,16 @@ void ex_function(exarg_T *eap) // - exclude line numbers from function body // if (!paren) { - if (!ends_excmd(*skipwhite((char *)p))) { + if (!ends_excmd(*skipwhite(p))) { semsg(_(e_trailing_arg), p); goto ret_free; } - eap->nextcmd = (char *)check_nextcmd(p); + eap->nextcmd = check_nextcmd(p); if (eap->nextcmd != NULL) { *p = NUL; } if (!eap->skip && !got_int) { - fp = find_func(name); + fp = find_func((char_u *)name); if (fp != NULL) { list_func_head(fp, !eap->forceit, eap->forceit); for (int j = 0; j < fp->uf_lines.ga_len && !got_int; j++) { @@ -2052,7 +2045,7 @@ void ex_function(exarg_T *eap) msg_putchar(' '); } } - msg_prt_line((char_u *)FUNCLINE(fp, j), false); + msg_prt_line(FUNCLINE(fp, j), false); ui_flush(); // show a line at a time os_breakcheck(); } @@ -2061,27 +2054,25 @@ void ex_function(exarg_T *eap) msg_puts(eap->forceit ? "endfunction" : " endfunction"); } } else { - emsg_funcname(N_("E123: Undefined function: %s"), name); + emsg_funcname(N_("E123: Undefined function: %s"), (char_u *)name); } } goto ret_free; } - /* - * ":function name(arg1, arg2)" Define function. - */ - p = (char_u *)skipwhite((char *)p); + // ":function name(arg1, arg2)" Define function. + p = skipwhite(p); if (*p != '(') { if (!eap->skip) { semsg(_("E124: Missing '(': %s"), eap->arg); goto ret_free; } // attempt to continue by skipping some text - if (vim_strchr((char *)p, '(') != NULL) { - p = (char_u *)vim_strchr((char *)p, '('); + if (vim_strchr(p, '(') != NULL) { + p = vim_strchr(p, '('); } } - p = (char_u *)skipwhite((char *)p + 1); + p = skipwhite(p + 1); ga_init(&newargs, (int)sizeof(char_u *), 3); ga_init(&newlines, (int)sizeof(char_u *), 3); @@ -2092,15 +2083,15 @@ void ex_function(exarg_T *eap) if (name != NULL) { arg = name; } else { - arg = fudi.fd_newkey; + arg = (char *)fudi.fd_newkey; } if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) { - int j = (*arg == K_SPECIAL) ? 3 : 0; + int j = ((uint8_t)(*arg) == K_SPECIAL) ? 3 : 0; while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j]) : eval_isnamec(arg[j]))) { j++; } if (arg[j] != NUL) { - emsg_funcname((char *)e_invarg2, arg); + emsg_funcname((char *)e_invarg2, (char_u *)arg); } } // Disallow using the g: dict. @@ -2109,7 +2100,7 @@ void ex_function(exarg_T *eap) } } - if (get_function_args((char **)&p, ')', &newargs, &varargs, + if (get_function_args(&p, ')', &newargs, &varargs, &default_args, eap->skip) == FAIL) { goto errret_2; } @@ -2121,7 +2112,7 @@ void ex_function(exarg_T *eap) // find extra arguments "range", "dict", "abort" and "closure" for (;;) { - p = (char_u *)skipwhite((char *)p); + p = skipwhite(p); if (STRNCMP(p, "range", 5) == 0) { flags |= FC_RANGE; p += 5; @@ -2135,9 +2126,8 @@ void ex_function(exarg_T *eap) flags |= FC_CLOSURE; p += 7; if (current_funccal == NULL) { - emsg_funcname(N_ - ("E932: Closure function should not be at top level: %s"), - name == NULL ? (char_u *)"" : name); + emsg_funcname(N_("E932: Closure function should not be at top level: %s"), + name == NULL ? (char_u *)"" : (char_u *)name); goto erret; } } else { @@ -2153,9 +2143,7 @@ void ex_function(exarg_T *eap) semsg(_(e_trailing_arg), p); } - /* - * Read the body of the function, until ":endfunction" is found. - */ + // Read the body of the function, until ":endfunction" is found. if (KeyTyped) { // Check if the function already exists, don't let the user type the // whole function before telling him it doesn't work! For a script we @@ -2163,8 +2151,8 @@ void ex_function(exarg_T *eap) if (!eap->skip && !eap->forceit) { if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) { emsg(_(e_funcdict)); - } else if (name != NULL && find_func(name) != NULL) { - emsg_funcname(e_funcexts, name); + } else if (name != NULL && find_func((char_u *)name) != NULL) { + emsg_funcname(e_funcexts, (char_u *)name); } } @@ -2193,9 +2181,9 @@ void ex_function(exarg_T *eap) if (line_arg != NULL) { // Use eap->arg, split up in parts by line breaks. theline = line_arg; - p = (char_u *)vim_strchr((char *)theline, '\n'); + p = vim_strchr(theline, '\n'); if (p == NULL) { - line_arg += STRLEN(line_arg); + line_arg += strlen(line_arg); } else { *p = NUL; line_arg = p + 1; @@ -2203,9 +2191,9 @@ void ex_function(exarg_T *eap) } else { xfree(line_to_free); if (eap->getline == NULL) { - theline = getcmdline(':', 0L, indent, do_concat); + theline = (char *)getcmdline(':', 0L, indent, do_concat); } else { - theline = (char_u *)eap->getline(':', eap->cookie, indent, do_concat); + theline = eap->getline(':', eap->cookie, indent, do_concat); } line_to_free = theline; } @@ -2235,18 +2223,18 @@ void ex_function(exarg_T *eap) // * ":python <<EOF" and "EOF" // * ":let {var-name} =<< [trim] {marker}" and "{marker}" if (heredoc_trimmed == NULL - || (is_heredoc && (char_u *)skipwhite((char *)theline) == theline) + || (is_heredoc && skipwhite(theline) == theline) || STRNCMP(theline, heredoc_trimmed, - STRLEN(heredoc_trimmed)) == 0) { + strlen(heredoc_trimmed)) == 0) { if (heredoc_trimmed == NULL) { p = theline; } else if (is_heredoc) { - p = (char_u *)skipwhite((char *)theline) == theline - ? theline : theline + STRLEN(heredoc_trimmed); + p = skipwhite(theline) == theline + ? theline : theline + strlen(heredoc_trimmed); } else { - p = theline + STRLEN(heredoc_trimmed); + p = theline + strlen(heredoc_trimmed); } - if (STRCMP(p, skip_until) == 0) { + if (strcmp(p, skip_until) == 0) { XFREE_CLEAR(skip_until); XFREE_CLEAR(heredoc_trimmed); do_concat = true; @@ -2258,27 +2246,26 @@ void ex_function(exarg_T *eap) for (p = theline; ascii_iswhite(*p) || *p == ':'; p++) {} // Check for "endfunction". - if (checkforcmd((char **)&p, "endfunction", 4) && nesting-- == 0) { + if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) { if (*p == '!') { p++; } - char_u *nextcmd = NULL; + char *nextcmd = NULL; if (*p == '|') { nextcmd = p + 1; - } else if (line_arg != NULL && *skipwhite((char *)line_arg) != NUL) { + } else if (line_arg != NULL && *skipwhite(line_arg) != NUL) { nextcmd = line_arg; } else if (*p != NUL && *p != '"' && p_verbose > 0) { - give_warning2((char_u *)_("W22: Text found after :endfunction: %s"), - p, true); + give_warning2(_("W22: Text found after :endfunction: %s"), p, true); } if (nextcmd != NULL) { // Another command follows. If the line came from "eap" we // can simply point into it, otherwise we need to change // "eap->cmdlinep". - eap->nextcmd = (char *)nextcmd; + eap->nextcmd = nextcmd; if (line_to_free != NULL) { xfree(*eap->cmdlinep); - *eap->cmdlinep = (char *)line_to_free; + *eap->cmdlinep = line_to_free; line_to_free = NULL; } } @@ -2297,20 +2284,24 @@ void ex_function(exarg_T *eap) } // Check for defining a function inside this function. - if (checkforcmd((char **)&p, "function", 2)) { + if (checkforcmd(&p, "function", 2)) { if (*p == '!') { - p = (char_u *)skipwhite((char *)p + 1); + p = skipwhite(p + 1); } p += eval_fname_script((const char *)p); - xfree(trans_function_name((char **)&p, true, 0, NULL, NULL)); - if (*skipwhite((char *)p) == '(') { - nesting++; - indent += 2; + xfree(trans_function_name(&p, true, 0, NULL, NULL)); + if (*skipwhite(p) == '(') { + if (nesting == MAX_FUNC_NESTING - 1) { + emsg(_("E1058: function nesting too deep")); + } else { + nesting++; + indent += 2; + } } } // Check for ":append", ":change", ":insert". - p = (char_u *)skip_range((char *)p, NULL); + p = skip_range(p, NULL); if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p')) || (p[0] == 'c' && (!ASCII_ISALPHA(p[1]) @@ -2322,11 +2313,11 @@ void ex_function(exarg_T *eap) && (!ASCII_ISALPHA(p[1]) || (p[1] == 'n' && (!ASCII_ISALPHA(p[2]) || (p[2] == 's')))))) { - skip_until = vim_strsave((char_u *)"."); + skip_until = xstrdup("."); } // heredoc: Check for ":python <<EOF", ":lua <<EOF", etc. - arg = (char_u *)skipwhite((char *)skiptowhite(p)); + arg = skipwhite(skiptowhite(p)); if (arg[0] == '<' && arg[1] == '<' && ((p[0] == 'p' && p[1] == 'y' && (!ASCII_ISALNUM(p[2]) || p[2] == 't' @@ -2343,22 +2334,22 @@ void ex_function(exarg_T *eap) || (p[0] == 'm' && p[1] == 'z' && (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) { // ":python <<" continues until a dot, like ":append" - p = (char_u *)skipwhite((char *)arg + 2); + p = skipwhite(arg + 2); if (*p == NUL) { - skip_until = vim_strsave((char_u *)"."); + skip_until = xstrdup("."); } else { - skip_until = vim_strsave(p); + skip_until = xstrdup(p); } } // Check for ":let v =<< [trim] EOF" // and ":let [a, b] =<< [trim] EOF" - arg = (char_u *)skipwhite((char *)skiptowhite(p)); + arg = skipwhite(skiptowhite(p)); if (*arg == '[') { - arg = (char_u *)vim_strchr((char *)arg, ']'); + arg = vim_strchr(arg, ']'); } if (arg != NULL) { - arg = (char_u *)skipwhite((char *)skiptowhite(arg)); + arg = skipwhite(skiptowhite(arg)); if (arg[0] == '=' && arg[1] == '<' && arg[2] == '<' @@ -2366,14 +2357,13 @@ void ex_function(exarg_T *eap) && p[1] == 'e' && (!ASCII_ISALNUM(p[2]) || (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) { - p = (char_u *)skipwhite((char *)arg + 3); + p = skipwhite(arg + 3); if (STRNCMP(p, "trim", 4) == 0) { // Ignore leading white space. - p = (char_u *)skipwhite((char *)p + 4); - heredoc_trimmed = - vim_strnsave(theline, (size_t)((char_u *)skipwhite((char *)theline) - theline)); + p = skipwhite(p + 4); + heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline)); } - skip_until = vim_strnsave(p, (size_t)(skiptowhite(p) - p)); + skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p)); do_concat = false; is_heredoc = true; } @@ -2386,8 +2376,8 @@ void ex_function(exarg_T *eap) // Copy the line to newly allocated memory. get_one_sourceline() // allocates 250 bytes per line, this saves 80% on average. The cost // is an extra alloc/free. - p = vim_strsave(theline); - ((char **)(newlines.ga_data))[newlines.ga_len++] = (char *)p; + p = xstrdup(theline); + ((char **)(newlines.ga_data))[newlines.ga_len++] = p; // Add NULL lines for continuation lines, so that the line count is // equal to the index in the growarray. @@ -2407,30 +2397,28 @@ void ex_function(exarg_T *eap) goto erret; } - /* - * If there are no errors, add the function - */ + // If there are no errors, add the function if (fudi.fd_dict == NULL) { - v = find_var((const char *)name, STRLEN(name), &ht, false); + v = find_var((const char *)name, strlen(name), &ht, false); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { emsg_funcname(N_("E707: Function name conflicts with variable: %s"), - name); + (char_u *)name); goto erret; } - fp = find_func(name); + fp = find_func((char_u *)name); if (fp != NULL) { // Function can be replaced with "function!" and when sourcing the // same script again, but only once. if (!eap->forceit && (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid || fp->uf_script_ctx.sc_seq == current_sctx.sc_seq)) { - emsg_funcname(e_funcexts, name); + emsg_funcname(e_funcexts, (char_u *)name); goto erret; } if (fp->uf_calls > 0) { emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"), - name); + (char_u *)name); goto erret; } if (fp->uf_refcount > 1) { @@ -2474,23 +2462,23 @@ void ex_function(exarg_T *eap) // Give the function a sequential number. Can only be used with a // Funcref! xfree(name); - sprintf(numbuf, "%d", ++func_nr); - name = vim_strsave((char_u *)numbuf); + sprintf(numbuf, "%d", ++func_nr); // NOLINT(runtime/printf) + name = xstrdup(numbuf); } if (fp == NULL) { - if (fudi.fd_dict == NULL && vim_strchr((char *)name, AUTOLOAD_CHAR) != NULL) { + if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) { int slen, plen; char_u *scriptname; // Check that the autoload name matches the script name. int j = FAIL; if (SOURCING_NAME != NULL) { - scriptname = (char_u *)autoload_name((const char *)name, STRLEN(name)); - p = (char_u *)vim_strchr((char *)scriptname, '/'); + scriptname = (char_u *)autoload_name((const char *)name, strlen(name)); + p = vim_strchr((char *)scriptname, '/'); plen = (int)STRLEN(p); slen = (int)STRLEN(SOURCING_NAME); - if (slen > plen && FNAMECMP(p, SOURCING_NAME + slen - plen) == 0) { + if (slen > plen && path_fnamecmp(p, SOURCING_NAME + slen - plen) == 0) { j = OK; } xfree(scriptname); @@ -2502,7 +2490,7 @@ void ex_function(exarg_T *eap) } } - fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); + fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1); if (fudi.fd_dict != NULL) { if (fudi.fd_di == NULL) { @@ -2518,16 +2506,16 @@ void ex_function(exarg_T *eap) tv_clear(&fudi.fd_di->di_tv); } fudi.fd_di->di_tv.v_type = VAR_FUNC; - fudi.fd_di->di_tv.vval.v_string = (char *)vim_strsave(name); + fudi.fd_di->di_tv.vval.v_string = xstrdup(name); // behave like "dict" was used flags |= FC_DICT; } // insert the new function in the function list - set_ufunc_name(fp, name); + set_ufunc_name(fp, (char_u *)name); if (overwrite) { - hi = hash_find(&func_hashtab, (char *)name); + hi = hash_find(&func_hashtab, name); hi->hi_key = UF2HIKEY(fp); } else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) { xfree(fp); @@ -2584,8 +2572,8 @@ int eval_fname_script(const char *const p) // Use mb_strnicmp() because in Turkish comparing the "I" may not work with // the standard library function. if (p[0] == '<' - && (mb_strnicmp((char_u *)p + 1, (char_u *)"SID>", 4) == 0 - || mb_strnicmp((char_u *)p + 1, (char_u *)"SNR>", 4) == 0)) { + && (mb_strnicmp(p + 1, "SID>", 4) == 0 + || mb_strnicmp(p + 1, "SNR>", 4) == 0)) { return 5; } if (p[0] == 's' && p[1] == ':') { @@ -2660,7 +2648,7 @@ char *get_user_func_name(expand_T *xp, int idx) return (char *)fp->uf_name; // Prevent overflow. } - cat_func_name(IObuff, fp); + cat_func_name((char_u *)IObuff, fp); if (xp->xp_context != EXPAND_USER_FUNC) { STRCAT(IObuff, "("); if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) { @@ -2694,7 +2682,7 @@ void ex_delfunction(exarg_T *eap) semsg(_(e_trailing_arg), p); return; } - eap->nextcmd = (char *)check_nextcmd(p); + eap->nextcmd = check_nextcmd((char *)p); if (eap->nextcmd != NULL) { *p = NUL; } @@ -2847,7 +2835,7 @@ void ex_return(exarg_T *eap) { char_u *arg = (char_u *)eap->arg; typval_T rettv; - int returning = FALSE; + int returning = false; if (current_funccal == NULL) { emsg(_("E133: :return not inside a function")); @@ -2883,7 +2871,7 @@ void ex_return(exarg_T *eap) if (returning) { eap->nextcmd = NULL; } else if (eap->nextcmd == NULL) { // no argument - eap->nextcmd = (char *)check_nextcmd(arg); + eap->nextcmd = check_nextcmd((char *)arg); } if (eap->skip) { @@ -2969,12 +2957,12 @@ void ex_call(exarg_T *eap) arg = startarg; funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = eap->line1; - funcexe.lastline = eap->line2; - funcexe.doesrange = &doesrange; - funcexe.evaluate = true; - funcexe.partial = partial; - funcexe.selfdict = fudi.fd_dict; + funcexe.fe_firstline = eap->line1; + funcexe.fe_lastline = eap->line2; + funcexe.fe_doesrange = &doesrange; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; + funcexe.fe_selfdict = fudi.fd_dict; if (get_func_tv(name, -1, &rettv, (char **)&arg, &funcexe) == FAIL) { failed = true; break; @@ -3004,7 +2992,7 @@ void ex_call(exarg_T *eap) // When inside :try we need to check for following "| catch" or "| endtry". // Not when there was an error, but do check if an exception was thrown. - if ((!aborting() || current_exception != NULL) && (!failed || eap->cstack->cs_trylevel > 0)) { + if ((!aborting() || did_throw) && (!failed || eap->cstack->cs_trylevel > 0)) { // Check for trailing illegal characters and a following command. if (!ends_excmd(*arg)) { if (!failed && !aborting()) { @@ -3012,7 +3000,7 @@ void ex_call(exarg_T *eap) semsg(_(e_trailing_arg), arg); } } else { - eap->nextcmd = (char *)check_nextcmd(arg); + eap->nextcmd = check_nextcmd((char *)arg); } } @@ -3029,8 +3017,8 @@ end: /// @param is_cmd set when called due to a ":return" command. /// @param rettv may point to a typval_T with the return rettv. /// -/// @return TRUE when the return can be carried out, -/// FALSE when the return gets pending. +/// @return true when the return can be carried out, +/// false when the return gets pending. int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) { int idx; @@ -3080,7 +3068,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) } report_make_pending(CSTP_RETURN, rettv); } else { - current_funccal->returned = TRUE; + current_funccal->returned = true; // If the return is carried out now, store the return value. For // a return immediately after reanimation, the value is already @@ -3099,25 +3087,25 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) /// Generate a return command for producing the value of "rettv". The result /// is an allocated string. Used by report_pending() for verbose messages. -char_u *get_return_cmd(void *rettv) +char *get_return_cmd(void *rettv) { - char_u *s = NULL; - char_u *tofree = NULL; + char *s = NULL; + char *tofree = NULL; if (rettv != NULL) { - tofree = s = (char_u *)encode_tv2echo((typval_T *)rettv, NULL); + tofree = s = encode_tv2echo((typval_T *)rettv, NULL); } if (s == NULL) { - s = (char_u *)""; + s = ""; } STRCPY(IObuff, ":return "); STRLCPY(IObuff + 8, s, IOSIZE - 8); - if (STRLEN(s) + 8 >= IOSIZE) { + if (strlen(s) + 8 >= IOSIZE) { STRCPY(IObuff + IOSIZE - 4, "..."); } xfree(tofree); - return vim_strsave(IObuff); + return xstrdup((char *)IObuff); } /// Get next function line. @@ -3128,12 +3116,12 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; - char_u *retval; + char *retval; garray_T *gap; // growarray with function lines // If breakpoints have been added/deleted need to check for it. if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -3153,7 +3141,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) if (fcp->linenr >= gap->ga_len) { retval = NULL; } else { - retval = (char_u *)xstrdup(((char **)(gap->ga_data))[fcp->linenr++]); + retval = xstrdup(((char **)(gap->ga_data))[fcp->linenr++]); SOURCING_LNUM = fcp->linenr; if (do_profiling == PROF_YES) { func_line_start(cookie); @@ -3163,16 +3151,16 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // Did we encounter a breakpoint? if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { - dbg_breakpoint(fp->uf_name, SOURCING_LNUM); + dbg_breakpoint((char *)fp->uf_name, SOURCING_LNUM); // Find next breakpoint. - fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } - return (char *)retval; + return retval; } -/// @return TRUE if the currently active function should be ended, because a +/// @return true if the currently active function should be ended, because a /// return was encountered or an error occurred. Used inside a ":while". int func_has_ended(void *cookie) { @@ -3184,7 +3172,7 @@ int func_has_ended(void *cookie) || fcp->returned; } -/// @return TRUE if cookie indicates a function which "abort"s on errors. +/// @return true if cookie indicates a function which "abort"s on errors. int func_has_abort(void *cookie) { return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT; @@ -3205,9 +3193,9 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) } else { fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING ? (char_u *)rettv->vval.v_string - : rettv->vval.v_partial->pt_name; + : (char_u *)rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. - fname = fname_trans_sid(fname, fname_buf, &tofree, &error); + fname = (char_u *)fname_trans_sid((char *)fname, (char *)fname_buf, (char **)&tofree, &error); fp = find_func(fname); xfree(tofree); } @@ -3221,7 +3209,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) pt->pt_auto = true; if (rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING) { // Just a function: Take over the function name and use selfdict. - pt->pt_name = (char_u *)rettv->vval.v_string; + pt->pt_name = rettv->vval.v_string; } else { partial_T *ret_pt = rettv->vval.v_partial; int i; @@ -3230,8 +3218,8 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) // args. Can't take over name or args, the partial might // be referenced elsewhere. if (ret_pt->pt_name != NULL) { - pt->pt_name = vim_strsave(ret_pt->pt_name); - func_ref(pt->pt_name); + pt->pt_name = xstrdup(ret_pt->pt_name); + func_ref((char_u *)pt->pt_name); } else { pt->pt_func = ret_pt->pt_func; func_ptr_ref(pt->pt_func); @@ -3275,7 +3263,7 @@ int func_level(void *cookie) return ((funccall_T *)cookie)->level; } -/// @return TRUE when a function was ended by a ":return" command. +/// @return true when a function was ended by a ":return" command. int current_func_returned(void) { return current_funccal->returned; @@ -3543,7 +3531,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) { ufunc_T *fp = fp_in; funccall_T *fc; - int error = ERROR_NONE; + int error = FCERR_NONE; char_u fname_buf[FLEN_FIXED + 1]; char_u *tofree = NULL; char_u *fname; @@ -3553,7 +3541,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) } if (fp_in == NULL) { - fname = fname_trans_sid(name, fname_buf, &tofree, &error); + fname = (char_u *)fname_trans_sid((char *)name, (char *)fname_buf, (char **)&tofree, &error); fp = find_func(fname); } if (fp != NULL) { @@ -3565,20 +3553,18 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) return abort; } -/// Registers a C extension user function. -char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state) +/// Registers a luaref as a lambda. +char_u *register_luafunc(LuaRef ref) { char_u *name = get_lambda_name(); ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); fp->uf_refcount = 1; fp->uf_varargs = true; - fp->uf_flags = FC_CFUNC; + fp->uf_flags = FC_LUAREF; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; - fp->uf_cb = cb; - fp->uf_cb_free = cb_free; - fp->uf_cb_state = state; + fp->uf_luaref = ref; STRCPY(fp->uf_name, name); hash_add(&func_hashtab, UF2HIKEY(fp)); diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h index 4b7007aae9..4098622a14 100644 --- a/src/nvim/eval/userfunc.h +++ b/src/nvim/eval/userfunc.h @@ -9,6 +9,20 @@ #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) #define HI2UF(hi) HIKEY2UF((hi)->hi_key) +// flags used in uf_flags +#define FC_ABORT 0x01 // abort function on error +#define FC_RANGE 0x02 // function accepts range +#define FC_DICT 0x04 // Dict function, uses "self" +#define FC_CLOSURE 0x08 // closure, uses outer scope variables +#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 +#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 +#define FC_SANDBOX 0x40 // function defined in the sandbox +#define FC_DEAD 0x80 // function kept only for reference to dfunc +#define FC_EXPORT 0x100 // "export def Func()" +#define FC_NOARGS 0x200 // no a: variables in lambda +#define FC_VIM9 0x400 // defined in vim9 script file +#define FC_LUAREF 0x800 // luaref callback + ///< Structure used by trans_function_name() typedef struct { dict_T *fd_dict; ///< Dictionary used. @@ -24,44 +38,43 @@ struct funccal_entry { /// errors for when calling a function typedef enum { - ERROR_UNKNOWN = 0, - ERROR_TOOMANY, - ERROR_TOOFEW, - ERROR_SCRIPT, - ERROR_DICT, - ERROR_NONE, - ERROR_OTHER, - ERROR_BOTH, - ERROR_DELETED, - ERROR_NOTMETHOD, + FCERR_UNKNOWN = 0, + FCERR_TOOMANY = 1, + FCERR_TOOFEW = 2, + FCERR_SCRIPT = 3, + FCERR_DICT = 4, + FCERR_NONE = 5, + FCERR_OTHER = 6, + FCERR_DELETED = 7, + FCERR_NOTMETHOD = 8, ///< function cannot be used as a method } FnameTransError; /// Used in funcexe_T. Returns the new argcount. -typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip, - int called_func_argcount); +typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int partial_argcount, + ufunc_T *called_func); /// Structure passed between functions dealing with function call execution. typedef struct { - ArgvFunc argv_func; ///< when not NULL, can be used to fill in arguments only - ///< when the invoked function uses them - linenr_T firstline; ///< first line of range - linenr_T lastline; ///< last line of range - bool *doesrange; ///< [out] if not NULL: function handled range - bool evaluate; ///< actually evaluate expressions - partial_T *partial; ///< for extra arguments - dict_T *selfdict; ///< Dictionary for "self" - typval_T *basetv; ///< base for base->method() + ArgvFunc fe_argv_func; ///< when not NULL, can be used to fill in arguments only + ///< when the invoked function uses them + linenr_T fe_firstline; ///< first line of range + linenr_T fe_lastline; ///< last line of range + bool *fe_doesrange; ///< [out] if not NULL: function handled range + bool fe_evaluate; ///< actually evaluate expressions + partial_T *fe_partial; ///< for extra arguments + dict_T *fe_selfdict; ///< Dictionary for "self" + typval_T *fe_basetv; ///< base for base->method() } funcexe_T; #define FUNCEXE_INIT (funcexe_T) { \ - .argv_func = NULL, \ - .firstline = 0, \ - .lastline = 0, \ - .doesrange = NULL, \ - .evaluate = false, \ - .partial = NULL, \ - .selfdict = NULL, \ - .basetv = NULL, \ + .fe_argv_func = NULL, \ + .fe_firstline = 0, \ + .fe_lastline = 0, \ + .fe_doesrange = NULL, \ + .fe_evaluate = false, \ + .fe_partial = NULL, \ + .fe_selfdict = NULL, \ + .fe_basetv = NULL, \ } #define FUNCARG(fp, j) ((char **)(fp->uf_args.ga_data))[j] diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index b38849730a..4d7214205d 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -81,7 +81,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd) // The marker is the next word. if (*cmd != NUL && *cmd != '"') { marker = skipwhite(cmd); - p = (char *)skiptowhite((char_u *)marker); + p = skiptowhite(marker); if (*skipwhite(p) != NUL && *skipwhite(p) != '"') { semsg(_(e_trailing_arg), p); return NULL; @@ -113,7 +113,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd) && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) { mi = marker_indent_len; } - if (STRCMP(marker, theline + mi) == 0) { + if (strcmp(marker, theline + mi) == 0) { xfree(theline); break; } @@ -207,7 +207,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const) list_func_vars(&first); list_vim_vars(&first); } - eap->nextcmd = (char *)check_nextcmd((char_u *)arg); + eap->nextcmd = check_nextcmd(arg); } else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') { // HERE document list_T *l = heredoc_get(eap, expr + 3); @@ -413,7 +413,7 @@ void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *firs // apply :filter /pat/ to variable name xstrlcpy(buf, prefix, IOSIZE); xstrlcat(buf, (char *)di->di_key, IOSIZE); - if (message_filtered((char_u *)buf)) { + if (message_filtered(buf)) { continue; } @@ -587,7 +587,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo char *s = vim_getenv(name); if (s != NULL) { - tofree = (char *)concat_str((const char_u *)s, (const char_u *)p); + tofree = concat_str(s, p); p = (const char *)tofree; xfree(s); } @@ -663,8 +663,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo } 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); + stringval = concat_str(stringval, s); xfree(oldstringval); s = stringval; } @@ -705,14 +704,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo if (p != NULL && op != NULL && *op == '.') { s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); if (s != NULL) { - ptofree = (char *)concat_str((char_u *)s, (const char_u *)p); + ptofree = concat_str(s, p); p = (const char *)ptofree; xfree(s); } } if (p != NULL) { - write_reg_contents(*arg == '@' ? '"' : *arg, - (const char_u *)p, (ssize_t)STRLEN(p), false); + write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false); arg_end = arg + 1; } xfree(ptofree); @@ -791,6 +789,7 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca semsg(_(e_invarg2), arg - 1); return; } + assert(*lv.ll_name == '$'); // suppress clang "Uninitialized argument value" if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) { error = true; } @@ -825,7 +824,7 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca arg = skipwhite(name_end); } while (!ends_excmd(*arg)); - eap->nextcmd = (char *)check_nextcmd((char_u *)arg); + eap->nextcmd = check_nextcmd(arg); } // TODO(ZyX-I): move to eval/ex_cmds @@ -1118,7 +1117,7 @@ void vars_clear(hashtab_T *ht) vars_clear_ext(ht, true); } -/// Like vars_clear(), but only free the value if "free_val" is 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; @@ -1300,7 +1299,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, 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); + redraw_all_later(UPD_SOME_VALID); } return; } else if (v->di_tv.v_type != tv->v_type) { @@ -1349,12 +1348,8 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const 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); - } + tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv); + tv_clear(&oldtv); } if (is_const) { @@ -1627,7 +1622,7 @@ static void set_option_from_tv(const char *varname, typval_T *varp) strval = tv_get_string_buf_chk(varp, nbuf); } if (!error && strval != NULL) { - set_option_value(varname, numval, strval, OPT_LOCAL); + set_option_value_give_err(varname, numval, strval, OPT_LOCAL); } } @@ -1702,7 +1697,7 @@ bool var_exists(const char *var) } /// "gettabvar()" function -void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_gettabvar(typval_T *argvars, typval_T *rettv, EvalFuncData 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)); @@ -1716,19 +1711,19 @@ void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "gettabwinvar()" function -void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_gettabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getwinvar(argvars, rettv, 1); } /// "getwinvar()" function -void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getwinvar(argvars, rettv, 0); } /// "getbufvar()" function -void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const varname = tv_get_string_chk(&argvars[1]); buf_T *const buf = tv_get_buf_from_arg(&argvars[0]); @@ -1737,7 +1732,7 @@ void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "settabvar()" function -void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = 0; @@ -1768,19 +1763,19 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "settabwinvar()" function -void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { setwinvar(argvars, rettv, 1); } /// "setwinvar()" function -void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { setwinvar(argvars, rettv, 0); } /// "setbufvar()" function -void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (check_secure() || !tv_check_str_or_nr(&argvars[0])) { @@ -1802,7 +1797,7 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) // reset notion of buffer aucmd_restbuf(&aco); } else { - const size_t varname_len = STRLEN(varname); + const size_t varname_len = strlen(varname); char *const bufvarname = xmalloc(varname_len + 3); buf_T *const save_curbuf = curbuf; curbuf = buf; diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 0251ea9957..f012bacdd9 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -25,7 +25,7 @@ int libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvopts.file = proc->argv[0]; uvproc->uvopts.args = proc->argv; uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE; -#ifdef WIN32 +#ifdef MSWIN // libuv collapses the argv to a CommandLineToArgvW()-style string. cmd.exe // expects a different syntax (must be prepared by the caller before now). if (os_shell_is_cmdexe(proc->argv[0])) { @@ -55,7 +55,7 @@ int libuv_process_spawn(LibuvProcess *uvproc) if (!proc->in.closed) { uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; -#ifdef WIN32 +#ifdef MSWIN uvproc->uvstdio[0].flags |= proc->overlapped ? UV_OVERLAPPED_PIPE : 0; #endif uvproc->uvstdio[0].data.stream = STRUCT_CAST(uv_stream_t, @@ -64,7 +64,7 @@ int libuv_process_spawn(LibuvProcess *uvproc) if (!proc->out.closed) { uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; -#ifdef WIN32 +#ifdef MSWIN // pipe must be readable for IOCP to work on Windows. uvproc->uvstdio[1].flags |= proc->overlapped ? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0; @@ -113,7 +113,7 @@ static void close_cb(uv_handle_t *handle) static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) { Process *proc = handle->data; -#if defined(WIN32) +#if defined(MSWIN) // Use stored/expected signal. term_signal = proc->exit_signal; #endif diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index 1b5cc23b09..3329cbd574 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -31,41 +31,57 @@ void loop_init(Loop *loop, void *data) loop->poll_timer.data = xmalloc(sizeof(bool)); // "timeout expired" flag } -/// Processes one `Loop.uv` event (at most). -/// Processes all `Loop.fast_events` events. -/// Does NOT process `Loop.events`, that is an application-specific decision. +/// Process `Loop.uv` events with a timeout. /// /// @param loop -/// @param ms 0: non-blocking poll. -/// >0: timeout after `ms`. -/// <0: wait forever. -/// @returns true if `ms` timeout was reached -bool loop_poll_events(Loop *loop, int ms) +/// @param ms 0: non-blocking poll. +/// > 0: timeout after `ms`. +/// < 0: wait forever. +/// @param once true: process at most one `Loop.uv` event. +/// false: process until `ms` timeout (only has effect if `ms` > 0). +/// @return true if `ms` > 0 and was reached +bool loop_uv_run(Loop *loop, int ms, bool once) { if (loop->recursive++) { abort(); // Should not re-enter uv_run } uv_run_mode mode = UV_RUN_ONCE; - bool timeout_expired = false; + bool *timeout_expired = loop->poll_timer.data; + *timeout_expired = false; if (ms > 0) { - *((bool *)loop->poll_timer.data) = false; // reset "timeout expired" flag - // Dummy timer to ensure UV_RUN_ONCE does not block indefinitely for I/O. + // This timer ensures UV_RUN_ONCE does not block indefinitely for I/O. uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms); } else if (ms == 0) { // For ms == 0, do a non-blocking event poll. mode = UV_RUN_NOWAIT; } - uv_run(&loop->uv, mode); + do { // -V1044 + uv_run(&loop->uv, mode); + } while (ms > 0 && !once && !*timeout_expired); // -V560 if (ms > 0) { - timeout_expired = *((bool *)loop->poll_timer.data); uv_timer_stop(&loop->poll_timer); } loop->recursive--; // Can re-enter uv_run now + return *timeout_expired; +} + +/// Processes one `Loop.uv` event (at most). +/// Processes all `Loop.fast_events` events. +/// Does NOT process `Loop.events`, that is an application-specific decision. +/// +/// @param loop +/// @param ms 0: non-blocking poll. +/// > 0: timeout after `ms`. +/// < 0: wait forever. +/// @return true if `ms` > 0 and was reached +bool loop_poll_events(Loop *loop, int ms) +{ + bool timeout_expired = loop_uv_run(loop, ms, true); multiqueue_process_events(loop->fast_events); return timeout_expired; } diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h index 65980c6c05..c0bcda40ce 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -4,8 +4,8 @@ #include <stdint.h> #include <uv.h> +#include "klib/klist.h" #include "nvim/event/multiqueue.h" -#include "nvim/lib/klist.h" #include "nvim/os/time.h" typedef void *WatcherPtr; diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 9496a568b9..9ca3dcc276 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -125,7 +125,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) // Libuv converts ENOENT to EACCES for Windows compatibility, but if // the parent directory does not exist, ENOENT would be more accurate. *path_tail(watcher->addr) = NUL; - if (!os_path_exists((char_u *)watcher->addr)) { + if (!os_path_exists(watcher->addr)) { result = UV_ENOENT; } } diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index b34fd73d52..bfb7a551b9 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -10,7 +10,7 @@ #include "nvim/log.h" #include "nvim/macros.h" #include "nvim/rbuffer.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/os_win_console.h" #endif @@ -60,7 +60,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) stream->uv.idle.data = stream; } else { assert(type == UV_NAMED_PIPE || type == UV_TTY); -#ifdef WIN32 +#ifdef MSWIN if (type == UV_TTY) { uv_tty_init(&loop->uv, &stream->uv.tty, fd, 0); uv_tty_set_mode(&stream->uv.tty, UV_TTY_MODE_RAW); @@ -75,7 +75,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) uv_pipe_init(&loop->uv, &stream->uv.pipe, 0); uv_pipe_open(&stream->uv.pipe, fd); stream->uvstream = STRUCT_CAST(uv_stream_t, &stream->uv.pipe); -#ifdef WIN32 +#ifdef MSWIN } #endif } @@ -109,7 +109,7 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) stream->close_cb = on_stream_close; stream->close_cb_data = data; -#ifdef WIN32 +#ifdef MSWIN if (UV_TTY == uv_guess_handle(stream->fd)) { // Undo UV_TTY_MODE_RAW from stream_init(). #10801 uv_tty_set_mode(&stream->uv.tty, UV_TTY_MODE_NORMAL); diff --git a/src/nvim/event/stream.h b/src/nvim/event/stream.h index 02e816b4be..b580d3c33d 100644 --- a/src/nvim/event/stream.h +++ b/src/nvim/event/stream.h @@ -35,7 +35,7 @@ struct stream { uv_pipe_t pipe; uv_tcp_t tcp; uv_idle_t idle; -#ifdef WIN32 +#ifdef MSWIN uv_tty_t tty; #endif } uv; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 06a372bb93..ea51cac163 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * ex_cmds.c: some functions for command line commands - */ +// ex_cmds.c: some functions for command line commands #include <assert.h> #include <float.h> @@ -249,11 +247,9 @@ void ex_align(exarg_T *eap) indent = width; } } else { - /* - * if 'textwidth' set, use it - * else if 'wrapmargin' set, use it - * if invalid value, use 80 - */ + // if 'textwidth' set, use it + // else if 'wrapmargin' set, use it + // if invalid value, use 80 if (width <= 0) { width = (int)curbuf->b_p_tw; } @@ -274,7 +270,7 @@ void ex_align(exarg_T *eap) if (eap->cmdidx == CMD_left) { // left align new_indent = indent; } else { - has_tab = FALSE; // avoid uninit warnings + has_tab = false; // avoid uninit warnings len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent(); @@ -287,18 +283,14 @@ void ex_align(exarg_T *eap) } else { new_indent = width - len; // right align - /* - * Make sure that embedded TABs don't make the text go too far - * to the right. - */ + // Make sure that embedded TABs don't make the text go too far + // to the right. if (has_tab) { while (new_indent > 0) { (void)set_indent(new_indent, 0); if (linelen(NULL) <= width) { - /* - * Now try to move the line as much as possible to - * the right. Stop when it moves too far. - */ + // Now try to move the line as much as possible to + // the right. Stop when it moves too far. do { (void)set_indent(++new_indent, 0); } while (linelen(NULL) <= width); @@ -330,7 +322,7 @@ static int linelen(int *has_tab) // Get the line. If it's empty bail out early (could be the empty string // for an unloaded buffer). - line = (char *)get_cursor_line_ptr(); + line = get_cursor_line_ptr(); if (*line == NUL) { return 0; } @@ -338,7 +330,7 @@ static int linelen(int *has_tab) first = skipwhite(line); // find the character after the last non-blank character - for (last = first + STRLEN(first); + for (last = first + strlen(first); last > first && ascii_iswhite(last[-1]); last--) {} char save = *last; *last = NUL; @@ -387,7 +379,7 @@ static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL if (sort_lc) { return strcoll((char *)s1, (char *)s2); } - return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2); + return sort_ic ? STRICMP(s1, s2) : strcmp(s1, s2); } static int sort_compare(const void *s1, const void *s2) @@ -404,7 +396,7 @@ static int sort_compare(const void *s1, const void *s2) } fast_breakcheck(); if (got_int) { - sort_abort = TRUE; + sort_abort = true; } // When sorting numbers "start_col_nr" is the number, not the column @@ -509,11 +501,11 @@ void ex_sort(exarg_T *eap) } else if (*p == '"') { // comment start break; - } else if (check_nextcmd((char_u *)p) != NULL) { - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + } else if (check_nextcmd(p) != NULL) { + eap->nextcmd = check_nextcmd(p); break; } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = (char *)skip_regexp((char_u *)p + 1, *p, true, NULL); + s = skip_regexp(p + 1, *p, true, NULL); if (*s != *p) { emsg(_(e_invalpat)); goto sortend; @@ -557,8 +549,8 @@ void ex_sort(exarg_T *eap) // matching and number conversion only has to be done once per line. // Also get the longest line length for allocating "sortbuf". for (lnum = eap->line1; lnum <= eap->line2; lnum++) { - s = (char *)ml_get(lnum); - len = (int)STRLEN(s); + s = ml_get(lnum); + len = (int)strlen(s); if (maxlen < len) { maxlen = len; } @@ -567,10 +559,10 @@ void ex_sort(exarg_T *eap) end_col = len; if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) { if (sort_rx) { - start_col = (colnr_T)(regmatch.startp[0] - (char_u *)s); - end_col = (colnr_T)(regmatch.endp[0] - (char_u *)s); + start_col = (colnr_T)(regmatch.startp[0] - s); + end_col = (colnr_T)(regmatch.endp[0] - s); } else { - start_col = (colnr_T)(regmatch.endp[0] - (char_u *)s); + start_col = (colnr_T)(regmatch.endp[0] - s); } } else if (regmatch.regprog != NULL) { end_col = 0; @@ -586,11 +578,11 @@ void ex_sort(exarg_T *eap) p = s + start_col; if (sort_nr) { if (sort_what & STR2NR_HEX) { - s = (char *)skiptohex((char_u *)p); + s = skiptohex(p); } else if (sort_what & STR2NR_BIN) { s = (char *)skiptobin(p); } else { - s = (char *)skiptodigit((char_u *)p); + s = skiptodigit(p); } if (s > p && s[-1] == '-') { s--; // include preceding negative sign @@ -601,7 +593,7 @@ void ex_sort(exarg_T *eap) nrs[lnum - eap->line1].st_u.num.value = 0; } else { nrs[lnum - eap->line1].st_u.num.is_number = true; - vim_str2nr((char_u *)s, NULL, NULL, sort_what, + vim_str2nr(s, NULL, NULL, sort_what, &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false); } } else { @@ -658,8 +650,8 @@ void ex_sort(exarg_T *eap) change_occurred = true; } - s = (char *)ml_get(get_lnum); - size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen + s = ml_get(get_lnum); + size_t bytelen = strlen(s) + 1; // include EOL in bytelen old_count += (bcount_t)bytelen; if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in @@ -678,7 +670,7 @@ void ex_sort(exarg_T *eap) // delete the original lines if appending worked if (i == count) { - for (i = 0; i < count; ++i) { + for (i = 0; i < count; i++) { ml_delete(eap->line1, false); } } else { @@ -743,7 +735,7 @@ void ex_retab(exarg_T *eap) curwin->w_p_list = 0; // don't want list mode here new_ts_str = eap->arg; - if (!tabstop_set((char_u *)eap->arg, &new_vts_array)) { + if (!tabstop_set(eap->arg, &new_vts_array)) { return; } while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') { @@ -760,7 +752,7 @@ void ex_retab(exarg_T *eap) new_ts_str = xstrnsave(new_ts_str, (size_t)(eap->arg - new_ts_str)); } for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) { - ptr = (char *)ml_get(lnum); + ptr = ml_get(lnum); col = 0; vcol = 0; did_undo = false; @@ -804,7 +796,7 @@ void ex_retab(exarg_T *eap) // len is actual number of white characters used len = num_spaces + num_tabs; - old_len = (long)STRLEN(ptr); + old_len = (long)strlen(ptr); const long new_len = old_len - col + start_col + len + 1; if (new_len <= 0 || new_len >= MAXCOL) { emsg(_(e_resulting_text_too_long)); @@ -841,7 +833,7 @@ void ex_retab(exarg_T *eap) if (ptr[col] == NUL) { break; } - vcol += win_chartabsize(curwin, (char_u *)ptr + col, (colnr_T)vcol); + vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); if (vcol >= MAXCOL) { emsg(_(e_resulting_text_too_long)); break; @@ -867,7 +859,7 @@ void ex_retab(exarg_T *eap) && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) { // not changed } else { - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); } if (first_line != 0) { changed_lines(first_line, 0, last_line + 1, 0L, true); @@ -933,15 +925,13 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) num_lines = line2 - line1 + 1; - /* - * First we copy the old text to its new location -- webb - * Also copy the flag that ":global" command uses. - */ + // First we copy the old text to its new location -- webb + // Also copy the flag that ":global" command uses. if (u_save(dest, dest + 1) == FAIL) { return FAIL; } for (extra = 0, l = line1; l <= line2; l++) { - str = (char *)vim_strsave(ml_get(l + extra)); + str = xstrdup(ml_get(l + extra)); ml_append(dest + l - line1, str, (colnr_T)0, false); xfree(str); if (dest < line1) { @@ -949,21 +939,19 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) } } - /* - * Now we must be careful adjusting our marks so that we don't overlap our - * mark_adjust() calls. - * - * We adjust the marks within the old text so that they refer to the - * last lines of the file (temporarily), because we know no other marks - * will be set there since these line numbers did not exist until we added - * our new lines. - * - * Then we adjust the marks on lines between the old and new text positions - * (either forwards or backwards). - * - * And Finally we adjust the marks we put at the end of the file back to - * their final destination at the new text position -- webb - */ + // Now we must be careful adjusting our marks so that we don't overlap our + // mark_adjust() calls. + // + // We adjust the marks within the old text so that they refer to the + // last lines of the file (temporarily), because we know no other marks + // will be set there since these line numbers did not exist until we added + // our new lines. + // + // Then we adjust the marks on lines between the old and new text positions + // (either forwards or backwards). + // + // And Finally we adjust the marks we put at the end of the file back to + // their final destination at the new text position -- webb last_line = curbuf->b_ml.ml_line_count; mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP); @@ -1011,9 +999,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) // send update regarding the new lines that were added buf_updates_send_changes(curbuf, dest + 1, num_lines, 0); - /* - * Now we delete the original text -- webb - */ + // Now we delete the original text -- webb if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) { return FAIL; } @@ -1030,9 +1016,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) dest + line_off, 0, dest_byte + byte_off, kExtmarkUndo); - /* - * Leave the cursor on the last of the moved lines. - */ + // Leave the cursor on the last of the moved lines. if (dest >= line1) { curwin->w_cursor.lnum = dest; } else { @@ -1069,26 +1053,24 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) curbuf->b_op_start.col = curbuf->b_op_end.col = 0; } - /* - * there are three situations: - * 1. destination is above line1 - * 2. destination is between line1 and line2 - * 3. destination is below line2 - * - * n = destination (when starting) - * curwin->w_cursor.lnum = destination (while copying) - * line1 = start of source (while copying) - * line2 = end of source (while copying) - */ + // there are three situations: + // 1. destination is above line1 + // 2. destination is between line1 and line2 + // 3. destination is below line2 + // + // n = destination (when starting) + // curwin->w_cursor.lnum = destination (while copying) + // line1 = start of source (while copying) + // line2 = end of source (while copying) if (u_save(n, n + 1) == FAIL) { return; } curwin->w_cursor.lnum = n; while (line1 <= line2) { - // need to use vim_strsave() because the line will be unlocked within + // need to use xstrdup() because the line will be unlocked within // ml_append() - p = (char *)vim_strsave(ml_get(line1)); + p = xstrdup(ml_get(line1)); ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, false); xfree(p); @@ -1103,7 +1085,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) if (curwin->w_cursor.lnum < line2) { line2++; } - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; } appended_lines_mark(n, count); @@ -1150,21 +1132,19 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } if (addr_count == 0) { // :! - msg_scroll = FALSE; // don't scroll here + msg_scroll = false; // don't scroll here autowrite_all(); msg_scroll = scroll_save; } - /* - * Try to find an embedded bang, like in :!<cmd> ! [args] - * (:!! is indicated by the 'forceit' variable) - */ + // Try to find an embedded bang, like in :!<cmd> ! [args] + // (:!! is indicated by the 'forceit' variable) bool ins_prevcmd = forceit; trailarg = arg; do { - len = STRLEN(trailarg) + 1; + len = strlen(trailarg) + 1; if (newcmd != NULL) { - len += STRLEN(newcmd); + len += strlen(newcmd); } if (ins_prevcmd) { if (prevcmd == NULL) { @@ -1172,7 +1152,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out xfree(newcmd); return; } - len += STRLEN(prevcmd); + len += strlen(prevcmd); } t = xmalloc(len); *t = NUL; @@ -1182,15 +1162,13 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out if (ins_prevcmd) { STRCAT(t, prevcmd); } - p = t + STRLEN(t); + p = t + strlen(t); STRCAT(t, trailarg); xfree(newcmd); newcmd = t; - /* - * Scan the rest of the argument for '!', which is replaced by the - * previous command. "\!" is replaced by "!" (this is vi compatible). - */ + // Scan the rest of the argument for '!', which is replaced by the + // previous command. "\!" is replaced by "!" (this is vi compatible). trailarg = NULL; while (*p) { if (*p == '!') { @@ -1221,11 +1199,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out AppendToRedobuff("\n"); bangredo = false; } - /* - * Add quotes around the command, for shells that need them. - */ + // Add quotes around the command, for shells that need them. if (*p_shq != NUL) { - newcmd = xmalloc(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1); + newcmd = xmalloc(strlen(prevcmd) + 2 * STRLEN(p_shq) + 1); STRCPY(newcmd, p_shq); STRCAT(newcmd, prevcmd); STRCAT(newcmd, p_shq); @@ -1298,18 +1274,16 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b changed_line_abv_curs(); invalidate_botline(); - /* - * When using temp files: - * 1. * Form temp file names - * 2. * Write the lines to a temp file - * 3. Run the filter command on the temp file - * 4. * Read the output of the command into the buffer - * 5. * Delete the original lines to be filtered - * 6. * Remove the temp files - * - * When writing the input with a pipe or when catching the output with a - * pipe only need to do 3. - */ + // When using temp files: + // 1. * Form temp file names + // 2. * Write the lines to a temp file + // 3. Run the filter command on the temp file + // 4. * Read the output of the command into the buffer + // 5. * Delete the original lines to be filtered + // 6. * Remove the temp files + // + // When writing the input with a pipe or when catching the output with a + // pipe only need to do 3. if (do_out) { shell_flags |= kShellOptDoOut; @@ -1331,23 +1305,22 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b curbuf->b_op_start.lnum = line1; curbuf->b_op_end.lnum = line2; curwin->w_cursor.lnum = line2; - } else if ((do_in && (itmp = (char *)vim_tempname()) == NULL) - || (do_out && (otmp = (char *)vim_tempname()) == NULL)) { + } else if ((do_in && (itmp = vim_tempname()) == NULL) + || (do_out && (otmp = vim_tempname()) == NULL)) { emsg(_(e_notmp)); goto filterend; } - /* - * The writing and reading of temp files will not be shown. - * Vi also doesn't do this and the messages are not very informative. - */ + // The writing and reading of temp files will not be shown. + // Vi also doesn't do this and the messages are not very informative. no_wait_return++; // don't call wait_return() while busy if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap, false, false, false, true) == FAIL) { msg_putchar('\n'); // Keep message from buf_write(). no_wait_return--; if (!aborting()) { - semsg(_("E482: Can't create file %s"), itmp); // Will call wait_return. + // will call wait_return() + semsg(_("E482: Can't create file %s"), itmp); } goto filterend; } @@ -1368,7 +1341,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b xfree(cmd_buf); goto error; } - redraw_curbuf_later(VALID); + redraw_curbuf_later(UPD_VALID); } read_linecount = curbuf->b_ml.ml_line_count; @@ -1376,14 +1349,14 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b call_shell((char_u *)cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL); xfree(cmd_buf); - did_check_timestamps = FALSE; - need_check_timestamps = TRUE; + did_check_timestamps = false; + need_check_timestamps = true; // When interrupting the shell command, it may still have produced some // useful output. Reset got_int here, so that readfile() won't cancel // reading. os_breakcheck(); - got_int = FALSE; + got_int = false; if (do_out) { if (otmp != NULL) { @@ -1427,10 +1400,8 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b } } - /* - * Put cursor on first filtered line for ":range!cmd". - * Adjust '[ and '] (set by buf_write()). - */ + // Put cursor on first filtered line for ":range!cmd". + // Adjust '[ and '] (set by buf_write()). curwin->w_cursor.lnum = line1; del_lines(linecount, true); curbuf->b_op_start.lnum -= linecount; // adjust '[ @@ -1439,9 +1410,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b // for next write foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum); } else { - /* - * Put cursor on last new line for ":r !cmd". - */ + // Put cursor on last new line for ":r !cmd". linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1; curwin->w_cursor.lnum = curbuf->b_op_end.lnum; } @@ -1503,10 +1472,8 @@ void do_shell(char *cmd, int flags) return; } - /* - * For autocommands we want to get the output on the current screen, to - * avoid having to type return below. - */ + // For autocommands we want to get the output on the current screen, to + // avoid having to type return below. msg_putchar('\r'); // put cursor at start of line msg_putchar('\n'); // may shift screen one line up @@ -1568,95 +1535,83 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) { bool is_fish_shell = #if defined(UNIX) - STRNCMP(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; + STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "fish", 4) == 0; #else false; #endif - bool is_pwsh = STRNCMP(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 - || STRNCMP(invocation_path_tail(p_sh, NULL), "powershell", 10) == 0; + bool is_pwsh = STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "pwsh", 4) == 0 + || STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "powershell", 10) == 0; - size_t len = STRLEN(cmd) + 1; // At least enough space for cmd + NULL. + size_t len = strlen(cmd) + 1; // At least enough space for cmd + NULL. - len += is_fish_shell ? sizeof("begin; " "; end") - 1 - : is_pwsh ? sizeof("Start-Process ") - : sizeof("(" ")") - 1; + len += is_fish_shell ? sizeof("begin; " "; end") - 1 + : !is_pwsh ? sizeof("(" ")") - 1 + : 0; if (itmp != NULL) { - len += is_pwsh ? STRLEN(itmp) + sizeof(" -RedirectStandardInput ") - : STRLEN(itmp) + sizeof(" { " " < " " } ") - 1; + len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + : strlen(itmp) + sizeof(" { " " < " " } ") - 1; } if (otmp != NULL) { - len += STRLEN(otmp) + STRLEN(p_srr) + 2; // two extra spaces (" "), + 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 (is_pwsh) { - xstrlcpy(buf, "Start-Process ", len); - if (cmd_args == NULL) { - xstrlcat(buf, cmd, len); + if (itmp != NULL) { + xstrlcpy(buf, "& { Get-Content ", len - 1); // FIXME: should we add "-Encoding utf8"? + xstrlcat(buf, (const char *)itmp, len - 1); + xstrlcat(buf, " | & ", len - 1); // FIXME: add `&` ourself or leave to user? + xstrlcat(buf, cmd, len - 1); + xstrlcat(buf, " }", len - 1); } 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); + xstrlcpy(buf, cmd, len - 1); } + } else { #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); + if (itmp != NULL || otmp != NULL) { + char *fmt = is_fish_shell ? "begin; %s; end" + : "(%s)"; + vim_snprintf(buf, len, fmt, cmd); } else { + xstrlcpy(buf, cmd, len); + } + + if (itmp != NULL) { xstrlcat(buf, " < ", len - 1); + xstrlcat(buf, (const char *)itmp, len - 1); } - xstrlcat(buf, itmp, len - 1); - } #else - 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 - // redirection would be inside the quotes. - if (*p_shq == NUL) { - char *const p = find_pipe(buf); - if (p != NULL) { - *p = NUL; + // For shells that don't understand braces around commands, at least allow + // the use of commands in a pipe. + xstrlcpy(buf, (char *)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 + // redirection would be inside the quotes. + if (*p_shq == NUL) { + char *const p = find_pipe(buf); + if (p != NULL) { + *p = NUL; + } } - } - if (is_pwsh) { - xstrlcat(buf, " -RedirectStandardInput ", len); - } else { xstrlcat(buf, " < ", len); - } - xstrlcat(buf, itmp, len); - if (*p_shq == NUL) { - const char *const p = find_pipe(cmd); - if (p != NULL) { - xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS - xstrlcat(buf, p, len - 1); + xstrlcat(buf, (const char *)itmp, len); + if (*p_shq == NUL) { + const char *const p = find_pipe((const char *)cmd); + if (p != NULL) { + xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS + xstrlcat(buf, p, len - 1); + } } } - } #endif + } if (otmp != NULL) { - append_redir(buf, len, (char *)p_srr, otmp); + append_redir(buf, len, p_srr, otmp); } return buf; } @@ -1714,7 +1669,7 @@ void print_line(linenr_T lnum, int use_number, int list) } msg_start(); - silent_mode = FALSE; + silent_mode = false; info_message = true; // use mch_msg(), not mch_errmsg() print_line_no_prefix(lnum, use_number, list); if (save_silent) { @@ -1739,13 +1694,11 @@ int rename_buffer(char *new_fname) if (aborting()) { // autocmds may abort script processing return FAIL; } - /* - * The name of the current buffer will be changed. - * A new (unlisted) buffer entry needs to be made to hold the old file - * name, which will become the alternate file name. - * But don't set the alternate file name if the buffer didn't have a - * name. - */ + // The name of the current buffer will be changed. + // A new (unlisted) buffer entry needs to be made to hold the old file + // name, which will become the alternate file name. + // But don't set the alternate file name if the buffer didn't have a + // name. fname = curbuf->b_ffname; sfname = curbuf->b_sfname; xfname = curbuf->b_fname; @@ -1822,7 +1775,7 @@ void ex_write(exarg_T *eap) } /// write current buffer to file 'eap->arg' -/// if 'eap->append' is TRUE, append to the file +/// if 'eap->append' is true, append to the file /// /// if *eap->arg == NUL write to current file /// @@ -1847,7 +1800,7 @@ int do_write(exarg_T *eap) emsg(_(e_argreq)); goto theend; } - other = FALSE; + other = false; } else { fname = ffname; free_fname = fix_fname(ffname); @@ -1859,9 +1812,7 @@ int do_write(exarg_T *eap) other = otherfile(ffname); } - /* - * If we have a new file, put its name in the list of alternate file names. - */ + // If we have a new file, put its name in the list of alternate file names. if (other) { if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL || eap->cmdidx == CMD_saveas) { @@ -1880,8 +1831,7 @@ int do_write(exarg_T *eap) // Writing to the current file is not allowed in readonly mode // and a file name is required. // "nofile" and "nowrite" buffers cannot be written implicitly either. - if (!other && (bt_dontwrite_msg(curbuf) - || check_fname() == FAIL + if (!other && (bt_dontwrite_msg(curbuf) || check_fname() == FAIL || check_readonly(&eap->forceit, curbuf))) { goto theend; } @@ -1897,10 +1847,10 @@ int do_write(exarg_T *eap) && !p_wa) { if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { if (vim_dialog_yesno(VIM_QUESTION, NULL, - (char_u *)_("Write partial file?"), 2) != VIM_YES) { + _("Write partial file?"), 2) != VIM_YES) { goto theend; } - eap->forceit = TRUE; + eap->forceit = true; } else { emsg(_("E140: Use ! to write partial buffer")); goto theend; @@ -1937,8 +1887,8 @@ int do_write(exarg_T *eap) apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, alt_buf); if (!alt_buf->b_p_bl) { - alt_buf->b_p_bl = TRUE; - apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, alt_buf); + alt_buf->b_p_bl = true; + apply_autocmds(EVENT_BUFADD, NULL, NULL, false, alt_buf); } if (curbuf != was_curbuf || aborting()) { // buffer changed, don't write the file @@ -1966,7 +1916,7 @@ int do_write(exarg_T *eap) // After ":saveas fname" reset 'readonly'. if (eap->cmdidx == CMD_saveas) { if (retval == OK) { - curbuf->b_p_ro = FALSE; + curbuf->b_p_ro = false; redraw_tabline = true; } } @@ -1996,17 +1946,22 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth { // Write to another file or b_flags set or not writing the whole file: // overwriting only allowed with '!' + // If "other" is false and bt_nofilename(buf) is true, this must be + // writing an "acwrite" buffer to the same file as its b_ffname, and + // buf_write() will only allow writing with BufWriteCmd autocommands, + // so there is no need for an overwrite check. if ((other - || (buf->b_flags & BF_NOTEDITED) - || ((buf->b_flags & BF_NEW) - && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) - || (buf->b_flags & BF_READERR)) + || (!bt_nofilename(buf) + && ((buf->b_flags & BF_NOTEDITED) + || ((buf->b_flags & BF_NEW) + && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) + || (buf->b_flags & BF_READERR)))) && !p_wa - && os_path_exists((char_u *)ffname)) { + && os_path_exists(ffname)) { if (!eap->forceit && !eap->append) { #ifdef UNIX // It is possible to open a directory on Unix. - if (os_isdir((char_u *)ffname)) { + if (os_isdir(ffname)) { semsg(_(e_isadir2), ffname); return FAIL; } @@ -2015,10 +1970,10 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth char buff[DIALOG_MSG_SIZE]; dialog_msg((char *)buff, _("Overwrite existing file \"%s\"?"), fname); - if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 2) != VIM_YES) { + if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) { return FAIL; } - eap->forceit = TRUE; + eap->forceit = true; } else { emsg(_(e_exists)); return FAIL; @@ -2041,24 +1996,24 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth STRCPY(dir, "."); } else { dir = xmalloc(MAXPATHL); - p = (char *)p_dir; + p = p_dir; copy_option_part(&p, dir, MAXPATHL, ","); } swapname = (char *)makeswapname((char_u *)fname, (char_u *)ffname, curbuf, (char_u *)dir); xfree(dir); - if (os_path_exists((char_u *)swapname)) { + if (os_path_exists(swapname)) { if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { char buff[DIALOG_MSG_SIZE]; dialog_msg((char *)buff, _("Swap file \"%s\" exists, overwrite anyway?"), swapname); - if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 2) + if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) { xfree(swapname); return FAIL; } - eap->forceit = TRUE; + eap->forceit = true; } else { semsg(_("E768: Swap file exists: %s (:silent! overrides)"), swapname); @@ -2108,13 +2063,11 @@ void do_wqall(exarg_T *eap) } else if (!bufIsChanged(buf) || bt_dontwrite(buf)) { continue; } - /* - * Check if there is a reason the buffer cannot be written: - * 1. if the 'write' option is set - * 2. if there is no file name (even after browsing) - * 3. if the 'readonly' is set (even after a dialog) - * 4. if overwriting is allowed (even after a dialog) - */ + // Check if there is a reason the buffer cannot be written: + // 1. if the 'write' option is set + // 2. if there is no file name (even after browsing) + // 3. if the 'readonly' is set (even after a dialog) + // 4. if overwriting is allowed (even after a dialog) if (not_writing()) { error++; break; @@ -2159,14 +2112,14 @@ bool not_writing(void) } /// Check if a buffer is read-only (either 'readonly' option is set or file is -/// read-only). Ask for overruling in a dialog. Return TRUE and give an error +/// read-only). Ask for overruling in a dialog. Return true and give an error /// message when the buffer is readonly. static int check_readonly(int *forceit, buf_T *buf) { // Handle a file being readonly when the 'readonly' option is set or when // the file exists and permissions are read-only. if (!*forceit && (buf->b_p_ro - || (os_path_exists((char_u *)buf->b_ffname) + || (os_path_exists(buf->b_ffname) && !os_file_is_writable(buf->b_ffname)))) { if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && buf->b_fname != NULL) { char buff[DIALOG_MSG_SIZE]; @@ -2182,12 +2135,12 @@ static int check_readonly(int *forceit, buf_T *buf) buf->b_fname); } - if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 2) == VIM_YES) { + if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES) { // Set forceit, to force the writing of a readonly file - *forceit = TRUE; - return FALSE; + *forceit = true; + return false; } else { - return TRUE; + return true; } } else if (buf->b_p_ro) { emsg(_(e_readonly)); @@ -2195,10 +2148,10 @@ static int check_readonly(int *forceit, buf_T *buf) semsg(_("E505: \"%s\" is read-only (add ! to override)"), buf->b_fname); } - return TRUE; + return true; } - return FALSE; + return false; } /// Try to abandon the current file and edit a new or existing file. @@ -2292,7 +2245,7 @@ theend: /// ECMD_LASTL: use last position in loaded file /// ECMD_LAST: use last position in all files /// ECMD_ONE: use first line -/// @param flags ECMD_HIDE: if TRUE don't free the current buffer +/// @param flags ECMD_HIDE: if true don't free the current buffer /// ECMD_SET_HELP: set b_help flag of (new) buffer before /// opening file /// ECMD_OLDBUF: use existing buffer if it exists @@ -2310,7 +2263,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum win_T *oldwin) { bool other_file; // true if editing another file - int oldbuf; // TRUE if using existing buffer + int oldbuf; // true if using existing buffer bool auto_buf = false; // true if autocommands brought us // into the buffer unexpectedly char *new_name = NULL; @@ -2386,7 +2339,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // If the file was changed we may not be allowed to abandon it: // - if we are going to re-edit the same file - // - or if we are the only window on this file and if ECMD_HIDE is FALSE + // - or if we are the only window on this file and if ECMD_HIDE is false if (((!other_file && !(flags & ECMD_OLDBUF)) || (curbuf->b_nwindows == 1 && !(flags & (ECMD_HIDE | ECMD_ADDBUF | ECMD_ALTBUF)))) @@ -2400,16 +2353,14 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum goto theend; } - /* - * End Visual mode before switching to another buffer, so the text can be - * copied into the GUI selection buffer. - */ + // End Visual mode before switching to another buffer, so the text can be + // copied into the GUI selection buffer. reset_VIsual(); if ((command != NULL || newlnum > (linenr_T)0) && *get_vim_var_str(VV_SWAPCOMMAND) == NUL) { // Set v:swapcommand for the SwapExists autocommands. - const size_t len = (command != NULL) ? STRLEN(command) + 3 : 30; + const size_t len = (command != NULL) ? strlen(command) + 3 : 30; char *const p = xmalloc(len); if (command != NULL) { vim_snprintf(p, len, ":%s\r", command); @@ -2421,10 +2372,8 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum xfree(p); } - /* - * If we are starting to edit another file, open a (new) buffer. - * Otherwise we re-use the current buffer. - */ + // If we are starting to edit another file, open a (new) buffer. + // Otherwise we re-use the current buffer. if (other_file) { const int prev_alt_fnum = curwin->w_alt_fnum; @@ -2502,12 +2451,10 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum solcol = pos->col; } - /* - * Make the (new) buffer the one used by the current window. - * If the old buffer becomes unused, free it if ECMD_HIDE is FALSE. - * If the current buffer was empty and has no file name, curbuf - * is returned by buflist_new(), nothing to do here. - */ + // Make the (new) buffer the one used by the current window. + // If the old buffer becomes unused, free it if ECMD_HIDE is false. + // If the current buffer was empty and has no file name, curbuf + // is returned by buflist_new(), nothing to do here. if (buf != curbuf) { const int save_cmdwin_type = cmdwin_type; @@ -2601,11 +2548,11 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum curwin->w_buffer = buf; curbuf = buf; - ++curbuf->b_nwindows; + curbuf->b_nwindows++; // Set 'fileformat', 'binary' and 'fenc' when forced. if (!oldbuf && eap != NULL) { - set_file_options(TRUE, eap); + set_file_options(true, eap); set_forced_fenc(eap); } } @@ -2641,7 +2588,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum } else if (!curbuf->b_help) { // Don't make a buffer listed if it's a help buffer. Useful when using // CTRL-O to go back to a help file. - set_buflisted(TRUE); + set_buflisted(true); } // If autocommands change buffers under our fingers, forget about @@ -2658,13 +2605,11 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // highlighting to work in the other file. did_filetype = false; - /* - * other_file oldbuf - * FALSE FALSE re-edit same file, buffer is re-used - * FALSE TRUE re-edit same file, nothing changes - * TRUE FALSE start editing new file, new buffer - * TRUE TRUE start editing in existing buffer (nothing to do) - */ + // other_file oldbuf + // false false re-edit same file, buffer is re-used + // false true re-edit same file, nothing changes + // true false start editing new file, new buffer + // true true start editing in existing buffer (nothing to do) if (!other_file && !oldbuf) { // re-use the buffer set_last_cursor(curwin); // may set b_last_cursor if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL) { @@ -2673,7 +2618,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum } buf = curbuf; if (buf->b_fname != NULL) { - new_name = (char *)vim_strsave((char_u *)buf->b_fname); + new_name = xstrdup(buf->b_fname); } else { new_name = NULL; } @@ -2723,9 +2668,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum curbuf->b_op_end.lnum = 0; } - /* - * If we get here we are sure to start editing - */ + // If we get here we are sure to start editing // Assume success now retval = OK; @@ -2736,17 +2679,13 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum curbuf->b_flags &= ~BF_NOTEDITED; } - /* - * Check if we are editing the w_arg_idx file in the argument list. - */ + // Check if we are editing the w_arg_idx file in the argument list. check_arg_idx(curwin); if (!auto_buf) { - /* - * Set cursor and init window before reading the file and executing - * autocommands. This allows for the autocommands to position the - * cursor. - */ + // Set cursor and init window before reading the file and executing + // autocommands. This allows for the autocommands to position the + // cursor. curwin_init(); // It's possible that all lines in the buffer changed. Need to update @@ -2760,19 +2699,15 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // Change directories when the 'acd' option is set. do_autochdir(); - /* - * Careful: open_buffer() and apply_autocmds() may change the current - * buffer and window. - */ + // Careful: open_buffer() and apply_autocmds() may change the current + // buffer and window. orig_pos = curwin->w_cursor; topline = curwin->w_topline; if (!oldbuf) { // need to read the file swap_exists_action = SEA_DIALOG; curbuf->b_flags |= BF_CHECK_RO; // set/reset 'ro' flag - /* - * Open the buffer and read the file. - */ + // Open the buffer and read the file. if (flags & ECMD_NOWINENTER) { readfile_flags |= READ_NOWINENTER; } @@ -2790,7 +2725,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // changed by the user. do_modelines(OPT_WINONLY); - apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, + apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, false, curbuf, &retval); if ((flags & ECMD_NOWINENTER) == 0) { apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, false, curbuf, @@ -2803,7 +2738,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // keep it. Also when it moves within a line. But not when it moves // to the first non-blank. if (!equalpos(curwin->w_cursor, orig_pos)) { - const char *text = (char *)get_cursor_line_ptr(); + const char *text = get_cursor_line_ptr(); if (curwin->w_cursor.lnum != orig_pos.lnum || curwin->w_cursor.col != (int)(skipwhite(text) - text)) { @@ -2848,7 +2783,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum curwin->w_cursor.col = solcol; check_cursor_col(); curwin->w_cursor.coladd = 0; - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; } else { beginline(BL_SOL | BL_FIX); } @@ -2863,10 +2798,8 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // Check if cursors in other windows on the same buffer are still valid check_lnums(false); - /* - * Did not read the file, need to show some info about the file. - * Do this after setting the cursor. - */ + // Did not read the file, need to show some info about the file. + // Do this after setting the cursor. if (oldbuf && !auto_buf) { int msg_scroll_save = msg_scroll; @@ -2874,7 +2807,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // Obey the 'O' flag in 'cpoptions': overwrite any previous file // message. if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) { - msg_scroll = FALSE; + msg_scroll = false; } if (!msg_scroll) { // wait a bit when overwriting an error msg check_for_delay(false); @@ -2910,7 +2843,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum update_topline(curwin); curwin->w_scbind_pos = curwin->w_topline; *so_ptr = n; - redraw_curbuf_later(NOT_VALID); // redraw this buffer later + redraw_curbuf_later(UPD_NOT_VALID); // redraw this buffer later } // Change directories when the 'acd' option is set. @@ -2996,7 +2929,7 @@ void ex_append(exarg_T *eap) } p = vim_strchr(eap->nextcmd, NL); if (p == NULL) { - p = eap->nextcmd + STRLEN(eap->nextcmd); + p = eap->nextcmd + strlen(eap->nextcmd); } theline = xstrnsave(eap->nextcmd, (size_t)(p - eap->nextcmd)); if (*p != NUL) { @@ -3018,7 +2951,7 @@ void ex_append(exarg_T *eap) // Look for the "." after automatic indent. vcol = 0; - for (p = theline; indent > vcol; ++p) { + for (p = theline; indent > vcol; p++) { if (*p == ' ') { vcol++; } else if (*p == TAB) { @@ -3098,7 +3031,7 @@ void ex_change(exarg_T *eap) append_indent = get_indent_lnum(eap->line1); } - for (lnum = eap->line2; lnum >= eap->line1; --lnum) { + for (lnum = eap->line2; lnum >= eap->line1; lnum--) { if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete break; } @@ -3313,7 +3246,7 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, char *sub, char *cmd, boo // TODO(vim): find a generic solution to make line-joining operations more // efficient, avoid allocating a string that grows in size. if (pat != NULL - && STRCMP(pat, "\\n") == 0 + && strcmp(pat, "\\n") == 0 && *sub == NUL && (*cmd == NUL || (cmd[1] == NUL && (*cmd == 'g' @@ -3346,10 +3279,10 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, char *sub, char *cmd, boo if (save) { if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { - save_re_pat(RE_SUBST, (char_u *)pat, p_magic); + save_re_pat(RE_SUBST, pat, p_magic); } // put pattern in history - add_to_history(HIST_SEARCH, (char_u *)pat, true, NUL); + add_to_history(HIST_SEARCH, pat, true, NUL); } return true; @@ -3384,7 +3317,7 @@ static char *sub_grow_buf(char **new_start, int needed_len) // Check if the temporary buffer is long enough to do the // substitution into. If not, make it larger (with a bit // extra to avoid too many calls to xmalloc()/free()). - size_t len = STRLEN(*new_start); + size_t len = strlen(*new_start); needed_len += (int)len; if (needed_len > new_start_len) { new_start_len = needed_len + 50; @@ -3547,17 +3480,15 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T which_pat = RE_LAST; // use last used regexp delimiter = (char_u)(*cmd++); // remember delimiter character pat = cmd; // remember start of search pat - cmd = (char *)skip_regexp((char_u *)cmd, delimiter, p_magic, &eap->arg); + cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg); if (cmd[0] == delimiter) { // end delimiter found *cmd++ = NUL; // replace it with a NUL has_second_delim = true; } } - /* - * Small incompatibility: vi sees '\n' as end of the command, but in - * Vim we want to use '\n' to find/substitute a NUL. - */ + // Small incompatibility: vi sees '\n' as end of the command, but in + // Vim we want to use '\n' to find/substitute a NUL. sub = cmd; // remember the start of the substitution while (cmd[0]) { @@ -3615,12 +3546,10 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T } } - /* - * check for trailing command or garbage - */ + // check for trailing command or garbage cmd = skipwhite(cmd); if (*cmd && *cmd != '"') { // if not end-of-line or comment - eap->nextcmd = (char *)check_nextcmd((char_u *)cmd); + eap->nextcmd = check_nextcmd(cmd); if (eap->nextcmd == NULL) { semsg(_(e_trailing_arg), cmd); return 0; @@ -3667,7 +3596,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T sub = xstrdup(sub); sub_copy = sub; } else { - char *newsub = (char *)regtilde((char_u *)sub, p_magic, cmdpreview); + char *newsub = regtilde(sub, p_magic, cmdpreview); if (newsub != sub) { // newsub was allocated, free it later. sub_copy = newsub; @@ -3675,13 +3604,6 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T } } - 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); - redraw_statuslines(); - } - // Check for a match on each line. // If preview: limit to max('cmdwinheight', viewport). linenr_T line2 = eap->line2; @@ -3706,50 +3628,48 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T bool skip_match = false; linenr_T sub_firstlnum; // nr of first sub line - /* - * The new text is build up step by step, to avoid too much - * copying. There are these pieces: - * sub_firstline The old text, unmodified. - * copycol Column in the old text where we started - * looking for a match; from here old text still - * needs to be copied to the new text. - * matchcol Column number of the old text where to look - * for the next match. It's just after the - * previous match or one further. - * prev_matchcol Column just after the previous match (if any). - * Mostly equal to matchcol, except for the first - * match and after skipping an empty match. - * regmatch.*pos Where the pattern matched in the old text. - * new_start The new text, all that has been produced so - * far. - * new_end The new text, where to append new text. - * - * lnum The line number where we found the start of - * the match. Can be below the line we searched - * when there is a \n before a \zs in the - * pattern. - * sub_firstlnum The line number in the buffer where to look - * for a match. Can be different from "lnum" - * when the pattern or substitute string contains - * line breaks. - * - * Special situations: - * - When the substitute string contains a line break, the part up - * to the line break is inserted in the text, but the copy of - * the original line is kept. "sub_firstlnum" is adjusted for - * the inserted lines. - * - When the matched pattern contains a line break, the old line - * is taken from the line at the end of the pattern. The lines - * in the match are deleted later, "sub_firstlnum" is adjusted - * accordingly. - * - * The new text is built up in new_start[]. It has some extra - * room to avoid using xmalloc()/free() too often. - * - * Make a copy of the old line, so it won't be taken away when - * updating the screen or handling a multi-line match. The "old_" - * pointers point into this copy. - */ + // The new text is build up step by step, to avoid too much + // copying. There are these pieces: + // sub_firstline The old text, unmodified. + // copycol Column in the old text where we started + // looking for a match; from here old text still + // needs to be copied to the new text. + // matchcol Column number of the old text where to look + // for the next match. It's just after the + // previous match or one further. + // prev_matchcol Column just after the previous match (if any). + // Mostly equal to matchcol, except for the first + // match and after skipping an empty match. + // regmatch.*pos Where the pattern matched in the old text. + // new_start The new text, all that has been produced so + // far. + // new_end The new text, where to append new text. + // + // lnum The line number where we found the start of + // the match. Can be below the line we searched + // when there is a \n before a \zs in the + // pattern. + // sub_firstlnum The line number in the buffer where to look + // for a match. Can be different from "lnum" + // when the pattern or substitute string contains + // line breaks. + // + // Special situations: + // - When the substitute string contains a line break, the part up + // to the line break is inserted in the text, but the copy of + // the original line is kept. "sub_firstlnum" is adjusted for + // the inserted lines. + // - When the matched pattern contains a line break, the old line + // is taken from the line at the end of the pattern. The lines + // in the match are deleted later, "sub_firstlnum" is adjusted + // accordingly. + // + // The new text is built up in new_start[]. It has some extra + // room to avoid using xmalloc()/free() too often. + // + // Make a copy of the old line, so it won't be taken away when + // updating the screen or handling a multi-line match. The "old_" + // pointers point into this copy. sub_firstlnum = lnum; copycol = 0; matchcol = 0; @@ -3760,14 +3680,12 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T got_match = true; } - /* - * Loop until nothing more to replace in this line. - * 1. Handle match with empty string. - * 2. If subflags.do_ask is set, ask for confirmation. - * 3. substitute the string. - * 4. if subflags.do_all is set, find next match - * 5. break if there isn't another match in this line - */ + // Loop until nothing more to replace in this line. + // 1. Handle match with empty string. + // 2. If subflags.do_ask is set, ask for confirmation. + // 3. substitute the string. + // 4. if subflags.do_all is set, find next match + // 5. break if there isn't another match in this line for (;;) { SubResult current_match = { .start = { 0, 0 }, @@ -3798,19 +3716,17 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T break; } if (sub_firstline == NULL) { - sub_firstline = (char *)vim_strsave(ml_get(sub_firstlnum)); + sub_firstline = xstrdup(ml_get(sub_firstlnum)); } // Save the line number of the last change for the final // cursor position (just like Vi). curwin->w_cursor.lnum = lnum; - do_again = FALSE; + do_again = false; - /* - * 1. Match empty string does not count, except for first - * match. This reproduces the strange vi behaviour. - * This also catches endless loops. - */ + // 1. Match empty string does not count, except for first + // match. This reproduces the strange vi behaviour. + // This also catches endless loops. if (matchcol == prev_matchcol && regmatch.endpos[0].lnum == 0 && matchcol == regmatch.endpos[0].col) { @@ -3842,7 +3758,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // we continue looking for a match on the next line. // Avoids that ":s/\nB\@=//gc" get stuck. if (nmatch > 1) { - matchcol = (colnr_T)STRLEN(sub_firstline); + matchcol = (colnr_T)strlen(sub_firstline); nmatch = 1; skip_match = true; } @@ -3875,9 +3791,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T no_u_sync++; } - /* - * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. - */ + // Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. while (subflags.do_ask) { if (exmode_active) { char *prompt; @@ -3939,14 +3853,13 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // really update the line, it would change // what matches. Temporarily replace the line // and change it back afterwards. - orig_line = (char *)vim_strsave(ml_get(lnum)); - char *new_line = (char *)concat_str((char_u *)new_start, - (char_u *)sub_firstline + copycol); + orig_line = xstrdup(ml_get(lnum)); + char *new_line = concat_str(new_start, sub_firstline + copycol); // Position the cursor relative to the end of the line, the // previous substitute may have inserted or deleted characters // before the cursor. - len_change = (int)STRLEN(new_line) - (int)STRLEN(orig_line); + len_change = (int)strlen(new_line) - (int)strlen(orig_line); curwin->w_cursor.col += len_change; ml_replace(lnum, new_line, false); } @@ -3955,13 +3868,18 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T - regmatch.startpos[0].lnum; search_match_endcol = regmatch.endpos[0].col + len_change; - highlight_match = TRUE; + if (search_match_lines == 0 && search_match_endcol == 0) { + // highlight at least one character for /^/ + search_match_endcol = 1; + } + highlight_match = true; update_topline(curwin); validate_cursor(); - update_screen(SOME_VALID); + redraw_later(curwin, UPD_SOME_VALID); + update_screen(); highlight_match = false; - redraw_later(curwin, SOME_VALID); + redraw_later(curwin, UPD_SOME_VALID); curwin->w_p_fen = save_p_fen; if (msg_row == Rows - 1) { @@ -3978,7 +3896,9 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T msg_no_more = false; msg_scroll = (int)i; show_cursor_info(true); - ui_cursor_goto(msg_row, msg_col); + if (!ui_has(kUIMessages)) { + ui_cursor_goto(msg_row, msg_col); + } RedrawingDisabled = temp; no_mapping++; // don't map this key @@ -4039,7 +3959,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // Avoids that ":%s/\nB\@=//gc" and ":%s/\n/,\r/gc" // get stuck when pressing 'n'. if (nmatch > 1) { - matchcol = (colnr_T)STRLEN(sub_firstline); + matchcol = (colnr_T)strlen(sub_firstline); skip_match = true; } goto skip; @@ -4068,7 +3988,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T if (nmatch > 1) { \ sub_firstlnum += (linenr_T)nmatch - 1; \ xfree(sub_firstline); \ - sub_firstline = (char *)vim_strsave(ml_get(sub_firstlnum)); \ + sub_firstline = xstrdup(ml_get(sub_firstlnum)); \ /* When going beyond the last line, stop substituting. */ \ if (sub_firstlnum <= line2) { \ do_again = true; \ @@ -4144,12 +4064,12 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T if (nmatch == 1) { p1 = sub_firstline; } else { - p1 = (char *)ml_get(sub_firstlnum + (linenr_T)nmatch - 1); + p1 = ml_get(sub_firstlnum + (linenr_T)nmatch - 1); nmatch_tl += nmatch - 1; } size_t copy_len = (size_t)(regmatch.startpos[0].col - copycol); new_end = sub_grow_buf(&new_start, - (colnr_T)STRLEN(p1) - regmatch.endpos[0].col + (colnr_T)strlen(p1) - regmatch.endpos[0].col + (colnr_T)copy_len + sublen + 1); // copy the text up to the part that matched @@ -4183,7 +4103,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T bcount_t replaced_bytes = 0; lpos_T start = regmatch.startpos[0], end = regmatch.endpos[0]; for (i = 0; i < nmatch - 1; i++) { - replaced_bytes += (bcount_t)STRLEN(ml_get((linenr_T)(lnum_start + i))) + 1; + replaced_bytes += (bcount_t)strlen(ml_get((linenr_T)(lnum_start + i))) + 1; } replaced_bytes += end.col - start.col; @@ -4226,7 +4146,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T p1 += utfc_ptr2len(p1) - 1; } } - colnr_T new_endcol = (colnr_T)STRLEN(new_start); + colnr_T new_endcol = (colnr_T)strlen(new_start); current_match.end.col = new_endcol; current_match.end.lnum = lnum; @@ -4262,15 +4182,13 @@ skip: && !re_multiline(regmatch.regprog))); nmatch = -1; - /* - * Replace the line in the buffer when needed. This is - * skipped when there are more matches. - * The check for nmatch_tl is needed for when multi-line - * matching must replace the lines before trying to do another - * match, otherwise "\@<=" won't work. - * When the match starts below where we start searching also - * need to replace the line first (using \zs after \n). - */ + // Replace the line in the buffer when needed. This is + // skipped when there are more matches. + // The check for nmatch_tl is needed for when multi-line + // matching must replace the lines before trying to do another + // match, otherwise "\@<=" won't work. + // When the match starts below where we start searching also + // need to replace the line first (using \zs after \n). if (lastone || nmatch_tl > 0 || (nmatch = vim_regexec_multi(®match, curwin, @@ -4278,16 +4196,14 @@ skip: matchcol, NULL, NULL)) == 0 || regmatch.startpos[0].lnum > 0) { if (new_start != NULL) { - /* - * Copy the rest of the line, that didn't match. - * "matchcol" has to be adjusted, we use the end of - * the line as reference, because the substitute may - * have changed the number of characters. Same for - * "prev_matchcol". - */ + // Copy the rest of the line, that didn't match. + // "matchcol" has to be adjusted, we use the end of + // the line as reference, because the substitute may + // have changed the number of characters. Same for + // "prev_matchcol". STRCAT(new_start, sub_firstline + copycol); - matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; - prev_matchcol = (colnr_T)STRLEN(sub_firstline) + matchcol = (colnr_T)strlen(sub_firstline) - matchcol; + prev_matchcol = (colnr_T)strlen(sub_firstline) - prev_matchcol; if (u_savesub(lnum) != OK) { @@ -4296,12 +4212,10 @@ skip: ml_replace(lnum, new_start, true); if (nmatch_tl > 0) { - /* - * Matched lines have now been substituted and are - * useless, delete them. The part after the match - * has been appended to new_start, we don't need - * it in the buffer. - */ + // Matched lines have now been substituted and are + // useless, delete them. The part after the match + // has been appended to new_start, we don't need + // it in the buffer. lnum++; if (u_savedel(lnum, nmatch_tl) != OK) { break; @@ -4334,8 +4248,8 @@ skip: xfree(sub_firstline); // free the temp buffer sub_firstline = new_start; new_start = NULL; - matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; - prev_matchcol = (colnr_T)STRLEN(sub_firstline) + matchcol = (colnr_T)strlen(sub_firstline) - matchcol; + prev_matchcol = (colnr_T)strlen(sub_firstline) - prev_matchcol; copycol = 0; } @@ -4344,9 +4258,7 @@ skip: sub_firstlnum, matchcol, NULL, NULL); } - /* - * 5. break if there isn't another match in this line - */ + // 5. break if there isn't another match in this line if (nmatch <= 0) { // If the match found didn't start where we were // searching, do the next search in the line where we @@ -4442,7 +4354,7 @@ skip: beginline(BL_WHITE | BL_FIX); } } - if (!cmdpreview && !do_sub_msg(subflags.do_count) && subflags.do_ask) { + if (!cmdpreview && !do_sub_msg(subflags.do_count) && subflags.do_ask && p_ch > 0) { msg(""); } } else { @@ -4457,7 +4369,9 @@ skip: emsg(_(e_interr)); } else if (got_match) { // did find something but nothing substituted - msg(""); + if (p_ch > 0) { + msg(""); + } } else if (subflags.do_error) { // nothing found semsg(_(e_patnotf2), get_search_pat()); @@ -4490,11 +4404,6 @@ skip: } } - if (cmdheight0) { - // Restore cmdheight - set_option_value("ch", 0L, NULL, 0); - } - kv_destroy(preview_lines.subresults); return retv; #undef ADJUST_SUB_FIRSTLNUM @@ -4509,12 +4418,10 @@ skip: /// @return true if a message was given. bool do_sub_msg(bool count_only) { - /* - * Only report substitutions when: - * - more than 'report' substitutions - * - command was typed by user, or number of changed lines > 'report' - * - giving messages is not disabled by 'lazyredraw' - */ + // Only report substitutions when: + // - more than 'report' substitutions + // - command was typed by user, or number of changed lines > 'report' + // - giving messages is not disabled by 'lazyredraw' if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1)) || count_only) && messaging()) { @@ -4605,11 +4512,9 @@ void ex_global(exarg_T *eap) cmd = eap->arg; which_pat = RE_LAST; // default: use last used regexp - /* - * undocumented vi feature: - * "\/" and "\?": use previous search pattern. - * "\&": use previous substitute pattern. - */ + // undocumented vi feature: + // "\/" and "\?": use previous search pattern. + // "\&": use previous substitute pattern. if (*cmd == '\\') { cmd++; if (vim_strchr("/?&", *cmd) == NULL) { @@ -4632,7 +4537,7 @@ void ex_global(exarg_T *eap) delim = *cmd; // get the delimiter cmd++; // skip delimiter if there is one pat = cmd; // remember start of pattern - cmd = (char *)skip_regexp((char_u *)cmd, delim, p_magic, &eap->arg); + cmd = skip_regexp(cmd, delim, p_magic, &eap->arg); if (cmd[0] == delim) { // end delimiter found *cmd++ = NUL; // replace it with a NUL } @@ -4748,9 +4653,7 @@ void free_old_sub(void) /// @return true when it was created. bool prepare_tagpreview(bool undo_sync) { - /* - * If there is already a preview window open, use that one. - */ + // If there is already a preview window open, use that one. if (!curwin->w_p_pvw) { bool found_win = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { @@ -4761,17 +4664,14 @@ bool prepare_tagpreview(bool undo_sync) } } if (!found_win) { - /* - * There is no preview window open yet. Create one. - */ + // There is no preview window open yet. Create one. if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) == FAIL) { return false; } - curwin->w_p_pvw = TRUE; - curwin->w_p_wfh = TRUE; - RESET_BINDING(curwin); /* don't take over 'scrollbind' - and 'cursorbind' */ + curwin->w_p_pvw = true; + curwin->w_p_wfh = true; + RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind' curwin->w_p_diff = false; // no 'diff' set_string_option_direct("fdc", -1, // no 'foldcolumn' "0", OPT_FREE, SID_NONE); @@ -4789,7 +4689,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i long cmdpreview_ns, handle_T cmdpreview_bufnr) FUNC_ATTR_NONNULL_ALL { - char *save_shm_p = (char *)vim_strsave(p_shm); + char *save_shm_p = xstrdup(p_shm); PreviewLines lines = *preview_lines; buf_T *orig_buf = curbuf; // We keep a special-purpose buffer around, but don't assume it exists. @@ -4867,7 +4767,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i if (next_linenr == orig_buf->b_ml.ml_line_count + 1) { line = ""; } else { - line = (char *)ml_get_buf(orig_buf, next_linenr, false); + line = ml_get_buf(orig_buf, next_linenr, false); line_size = strlen(line) + (size_t)col_width + 1; // Reallocate if line not long enough @@ -4940,7 +4840,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) if (s != NULL) { *s = p; } - p = (char *)skiptowhite((char_u *)p); + p = skiptowhite(p); if (s != NULL && *p != NUL) { *p++ = NUL; } @@ -4950,7 +4850,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) *s = p + 1; } c = (char_u)(*p); - p = (char *)skip_regexp((char_u *)p + 1, c, true, NULL); + p = skip_regexp(p + 1, c, true, NULL); if (*p != c) { return NULL; } @@ -4995,13 +4895,12 @@ void ex_oldfiles(exarg_T *eap) } nr++; const char *fname = tv_get_string(TV_LIST_ITEM_TV(li)); - if (!message_filtered((char_u *)fname)) { + if (!message_filtered((char *)fname)) { msg_outnum(nr); msg_puts(": "); msg_outtrans((char *)tv_get_string(TV_LIST_ITEM_TV(li))); msg_clr_eos(); msg_putchar('\n'); - ui_flush(); // output one line at a time os_breakcheck(); } }); diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 4bed1e94b9..04b8832428 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1141,6 +1141,12 @@ module.cmds = { func='ex_history', }, { + command='horizontal', + flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), + addr_type='ADDR_NONE', + func='ex_wrongmodifier', + }, + { command='insert', flags=bit.bor(BANG, RANGE, TRLBAR, CMDWIN, LOCK_OK, MODIFY), addr_type='ADDR_LINES', diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 54315a6417..1248251556 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -14,11 +14,6 @@ #include "nvim/arglist.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" -#include "nvim/globals.h" -#include "nvim/vim.h" -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" @@ -30,6 +25,7 @@ #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/fileio.h" +#include "nvim/globals.h" #include "nvim/mark.h" #include "nvim/mbyte.h" #include "nvim/memory.h" @@ -39,13 +35,13 @@ #include "nvim/ops.h" #include "nvim/option.h" #include "nvim/os/fs_defs.h" -#include "nvim/os/shell.h" #include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/quickfix.h" #include "nvim/runtime.h" #include "nvim/strings.h" #include "nvim/undo.h" +#include "nvim/vim.h" #include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -204,9 +200,9 @@ void dialog_changed(buf_T *buf, bool checkall) dialog_msg((char *)buff, _("Save changes to \"%s\"?"), buf->b_fname); if (checkall) { - ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, (char_u *)buff, 1); + ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); } else { - ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, (char_u *)buff, 1); + ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); } if (ret == VIM_YES) { @@ -256,7 +252,7 @@ bool dialog_close_terminal(buf_T *buf) dialog_msg(buff, _("Close \"%s\"?"), (buf->b_fname != NULL) ? buf->b_fname : "?"); - int ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, (char_u *)buff, 1); + int ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); return ret == VIM_YES; } @@ -368,7 +364,7 @@ bool check_changed_any(bool hidden, bool unload) exiting = false; // When ":confirm" used, don't give an error message. if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))) { - // There must be a wait_return for this message, do_buffer() + // There must be a wait_return() for this message, do_buffer() // may cause a redraw. But wait_return() is a no-op when vgetc() // is busy (Quit used from window menu), then make sure we don't // cause a scroll up. @@ -543,10 +539,10 @@ void ex_listdo(exarg_T *eap) if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) { // Clear 'shm' to avoid that the file message overwrites // any output from the command. - p_shm_save = (char *)vim_strsave(p_shm); - set_option_value("shm", 0L, "", 0); + p_shm_save = xstrdup(p_shm); + set_option_value_give_err("shm", 0L, "", 0); do_argfile(eap, i); - set_option_value("shm", 0L, p_shm_save, 0); + set_option_value_give_err("shm", 0L, p_shm_save, 0); xfree(p_shm_save); } if (curwin->w_arg_idx != i) { @@ -612,10 +608,10 @@ void ex_listdo(exarg_T *eap) // Go to the next buffer. Clear 'shm' to avoid that the file // message overwrites any output from the command. - p_shm_save = (char *)vim_strsave(p_shm); - set_option_value("shm", 0L, "", 0); + p_shm_save = xstrdup(p_shm); + set_option_value_give_err("shm", 0L, "", 0); goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); - set_option_value("shm", 0L, p_shm_save, 0); + set_option_value_give_err("shm", 0L, p_shm_save, 0); xfree(p_shm_save); // If autocommands took us elsewhere, quit here. @@ -635,10 +631,10 @@ void ex_listdo(exarg_T *eap) // Clear 'shm' to avoid that the file message overwrites // any output from the command. - p_shm_save = (char *)vim_strsave(p_shm); - set_option_value("shm", 0L, "", 0); + p_shm_save = xstrdup(p_shm); + set_option_value_give_err("shm", 0L, "", 0); ex_cnext(eap); - set_option_value("shm", 0L, p_shm_save, 0); + set_option_value_give_err("shm", 0L, p_shm_save, 0); xfree(p_shm_save); // If jumping to the next quickfix entry fails, quit here. @@ -680,11 +676,11 @@ void ex_listdo(exarg_T *eap) // buffer was opened while Syntax autocommands were disabled, // need to trigger them now. if (buf == curbuf) { - apply_autocmds(EVENT_SYNTAX, (char *)curbuf->b_p_syn, curbuf->b_fname, true, + apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, true, curbuf); } else { aucmd_prepbuf(&aco, buf); - apply_autocmds(EVENT_SYNTAX, (char *)buf->b_p_syn, buf->b_fname, true, buf); + apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, true, buf); aucmd_restbuf(&aco); } @@ -707,7 +703,7 @@ void ex_compiler(exarg_T *eap) do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')"); // NOLINT do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.lua')"); // NOLINT } else { - size_t bufsize = STRLEN(eap->arg) + 14; + size_t bufsize = strlen(eap->arg) + 14; buf = xmalloc(bufsize); if (eap->forceit) { // ":compiler! {name}" sets global options @@ -776,324 +772,6 @@ void ex_checktime(exarg_T *eap) no_check_timestamps = save_no_check_timestamps; } -#if defined(HAVE_LOCALE_H) -# define HAVE_GET_LOCALE_VAL - -static char *get_locale_val(int what) -{ - // Obtain the locale value from the libraries. - char *loc = setlocale(what, NULL); - - return loc; -} -#endif - -/// @return true when "lang" starts with a valid language name. -/// Rejects NULL, empty string, "C", "C.UTF-8" and others. -static bool is_valid_mess_lang(char *lang) -{ - return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]); -} - -/// Obtain the current messages language. Used to set the default for -/// 'helplang'. May return NULL or an empty string. -char *get_mess_lang(void) -{ - char *p; - -#ifdef HAVE_GET_LOCALE_VAL -# if defined(LC_MESSAGES) - p = get_locale_val(LC_MESSAGES); -# else - // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG - // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME - // and LC_MONETARY may be set differently for a Japanese working in the - // US. - p = get_locale_val(LC_COLLATE); -# endif -#else - p = os_getenv("LC_ALL"); - if (!is_valid_mess_lang(p)) { - p = os_getenv("LC_MESSAGES"); - if (!is_valid_mess_lang(p)) { - p = os_getenv("LANG"); - } - } -#endif - return is_valid_mess_lang(p) ? p : NULL; -} - -// Complicated #if; matches with where get_mess_env() is used below. -#ifdef HAVE_WORKING_LIBINTL -/// Get the language used for messages from the environment. -static char *get_mess_env(void) -{ - char *p; - - p = (char *)os_getenv("LC_ALL"); - if (p == NULL) { - p = (char *)os_getenv("LC_MESSAGES"); - if (p == NULL) { - p = (char *)os_getenv("LANG"); - if (p != NULL && ascii_isdigit(*p)) { - p = NULL; // ignore something like "1043" - } -# ifdef HAVE_GET_LOCALE_VAL - if (p == NULL) { - p = get_locale_val(LC_CTYPE); - } -# endif - } - } - return p; -} - -#endif - -/// Set the "v:lang" variable according to the current locale setting. -/// Also do "v:lc_time"and "v:ctype". -void set_lang_var(void) -{ - const char *loc; - -#ifdef HAVE_GET_LOCALE_VAL - loc = get_locale_val(LC_CTYPE); -#else - // setlocale() not supported: use the default value - loc = "C"; -#endif - set_vim_var_string(VV_CTYPE, loc, -1); - - // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall - // back to LC_CTYPE if it's empty. -#ifdef HAVE_WORKING_LIBINTL - loc = get_mess_env(); -#elif defined(LC_MESSAGES) - loc = get_locale_val(LC_MESSAGES); -#else - // In Windows LC_MESSAGES is not defined fallback to LC_CTYPE - loc = get_locale_val(LC_CTYPE); -#endif - set_vim_var_string(VV_LANG, loc, -1); - -#ifdef HAVE_GET_LOCALE_VAL - loc = get_locale_val(LC_TIME); -#endif - set_vim_var_string(VV_LC_TIME, loc, -1); - -#ifdef HAVE_GET_LOCALE_VAL - loc = get_locale_val(LC_COLLATE); -#else - // setlocale() not supported: use the default value - loc = "C"; -#endif - set_vim_var_string(VV_COLLATE, loc, -1); -} - -#ifdef HAVE_WORKING_LIBINTL - -/// ":language": Set the language (locale). -/// -/// @param eap -void ex_language(exarg_T *eap) -{ - char *loc; - char *p; - char *name; - int what = LC_ALL; - char *whatstr = ""; -# ifdef LC_MESSAGES -# define VIM_LC_MESSAGES LC_MESSAGES -# else -# define VIM_LC_MESSAGES 6789 -# endif - - name = eap->arg; - - // Check for "messages {name}", "ctype {name}" or "time {name}" argument. - // Allow abbreviation, but require at least 3 characters to avoid - // confusion with a two letter language name "me" or "ct". - p = (char *)skiptowhite((char_u *)eap->arg); - if ((*p == NUL || ascii_iswhite(*p)) && p - eap->arg >= 3) { - if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) { - what = VIM_LC_MESSAGES; - name = skipwhite(p); - whatstr = "messages "; - } else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) { - what = LC_CTYPE; - name = skipwhite(p); - whatstr = "ctype "; - } else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) { - what = LC_TIME; - name = skipwhite(p); - whatstr = "time "; - } else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0) { - what = LC_COLLATE; - name = skipwhite(p); - whatstr = "collate "; - } - } - - if (*name == NUL) { - if (what == VIM_LC_MESSAGES) { - p = get_mess_env(); - } else { - p = setlocale(what, NULL); - } - if (p == NULL || *p == NUL) { - p = "Unknown"; - } - smsg(_("Current %slanguage: \"%s\""), whatstr, p); - } else { -# ifndef LC_MESSAGES - if (what == VIM_LC_MESSAGES) { - loc = ""; - } else { -# endif - loc = setlocale(what, name); -# ifdef LC_NUMERIC - // Make sure strtod() uses a decimal point, not a comma. - setlocale(LC_NUMERIC, "C"); -# endif -# ifndef LC_MESSAGES - } -# endif - if (loc == NULL) { - semsg(_("E197: Cannot set language to \"%s\""), name); - } else { -# ifdef HAVE_NL_MSG_CAT_CNTR - // Need to do this for GNU gettext, otherwise cached translations - // will be used again. - extern int _nl_msg_cat_cntr; - - _nl_msg_cat_cntr++; -# endif - // Reset $LC_ALL, otherwise it would overrule everything. - os_setenv("LC_ALL", "", 1); - - if (what != LC_TIME && what != LC_COLLATE) { - // Tell gettext() what to translate to. It apparently doesn't - // use the currently effective locale. - if (what == LC_ALL) { - os_setenv("LANG", name, 1); - - // Clear $LANGUAGE because GNU gettext uses it. - os_setenv("LANGUAGE", "", 1); - } - if (what != LC_CTYPE) { - os_setenv("LC_MESSAGES", name, 1); - set_helplang_default(name); - } - } - - // Set v:lang, v:lc_time, v:collate and v:ctype to the final result. - set_lang_var(); - maketitle(); - } - } -} - -static char **locales = NULL; // Array of all available locales - -# ifndef WIN32 -static bool did_init_locales = false; - -/// @return an array of strings for all available locales + NULL for the -/// last element or, -/// NULL in case of error. -static char **find_locales(void) -{ - garray_T locales_ga; - char *loc; - char *saveptr = NULL; - - // Find all available locales by running command "locale -a". If this - // doesn't work we won't have completion. - char *locale_a = (char *)get_cmd_output((char_u *)"locale -a", NULL, - kShellOptSilent, NULL); - if (locale_a == NULL) { - return NULL; - } - ga_init(&locales_ga, sizeof(char_u *), 20); - - // Transform locale_a string where each locale is separated by "\n" - // into an array of locale strings. - loc = os_strtok(locale_a, "\n", &saveptr); - - while (loc != NULL) { - loc = xstrdup(loc); - GA_APPEND(char *, &locales_ga, loc); - loc = os_strtok(NULL, "\n", &saveptr); - } - xfree(locale_a); - // Guarantee that .ga_data is NULL terminated - ga_grow(&locales_ga, 1); - ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL; - return locales_ga.ga_data; -} -# endif - -/// Lazy initialization of all available locales. -static void init_locales(void) -{ -# ifndef WIN32 - if (!did_init_locales) { - did_init_locales = true; - locales = find_locales(); - } -# endif -} - -# if defined(EXITFREE) -void free_locales(void) -{ - int i; - if (locales != NULL) { - for (i = 0; locales[i] != NULL; i++) { - xfree(locales[i]); - } - XFREE_CLEAR(locales); - } -} - -# endif - -/// Function given to ExpandGeneric() to obtain the possible arguments of the -/// ":language" command. -char *get_lang_arg(expand_T *xp, int idx) -{ - if (idx == 0) { - return "messages"; - } - if (idx == 1) { - return "ctype"; - } - if (idx == 2) { - return "time"; - } - if (idx == 3) { - return "collate"; - } - - init_locales(); - if (locales == NULL) { - return NULL; - } - return locales[idx - 4]; -} - -/// Function given to ExpandGeneric() to obtain the available locales. -char *get_locales(expand_T *xp, int idx) -{ - init_locales(); - if (locales == NULL) { - return NULL; - } - return locales[idx]; -} - -#endif - static void script_host_execute(char *name, exarg_T *eap) { size_t len; diff --git a/src/nvim/ex_cmds2.h b/src/nvim/ex_cmds2.h index e454a30028..3a41e105f3 100644 --- a/src/nvim/ex_cmds2.h +++ b/src/nvim/ex_cmds2.h @@ -1,8 +1,6 @@ #ifndef NVIM_EX_CMDS2_H #define NVIM_EX_CMDS2_H -#include <stdbool.h> - #include "nvim/ex_cmds_defs.h" // diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index e80e47bcff..71956b2246 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -188,7 +188,7 @@ struct exarg { cmdidx_T cmdidx; ///< the index for the command uint32_t argt; ///< flags for the command int skip; ///< don't execute the command, only parse it - int forceit; ///< TRUE if ! present + int forceit; ///< true if ! present int addr_count; ///< the number of addresses given linenr_T line1; ///< the first line number linenr_T line2; ///< the second line number or count @@ -196,8 +196,8 @@ struct exarg { int flags; ///< extra flags after count: EXFLAG_ char *do_ecmd_cmd; ///< +command arg to be used in edited file linenr_T do_ecmd_lnum; ///< the line number in an edited file - int append; ///< TRUE with ":w >>file" command - int usefilter; ///< TRUE with ":w !command" and ":r!command" + int append; ///< true with ":w >>file" command + int usefilter; ///< true with ":w !command" and ":r!command" int amount; ///< number of '>' or '<' for shift command int regname; ///< register name (NUL if none) int force_bin; ///< 0, FORCE_BIN or FORCE_NOBIN @@ -230,13 +230,15 @@ struct expand { sctx_T xp_script_ctx; // SCTX for completion function int xp_backslash; // one of the XP_BS_ values #ifndef BACKSLASH_IN_FILENAME - int xp_shell; // TRUE for a shell command, more + int xp_shell; // true for a shell command, more // characters need to be escaped #endif int xp_numfiles; // number of files found by file name completion int xp_col; // cursor position in line char **xp_files; // list of files char *xp_line; // text being completed +#define EXPAND_BUF_LEN 256 + char xp_buf[EXPAND_BUF_LEN]; // buffer for returned match }; // values for xp_backslash diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7bf272fbba..5591b5f55d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -47,6 +47,7 @@ #include "nvim/if_cscope.h" #include "nvim/input.h" #include "nvim/keycodes.h" +#include "nvim/locale.h" #include "nvim/lua/executor.h" #include "nvim/main.h" #include "nvim/mapping.h" @@ -94,6 +95,12 @@ static char e_ambiguous_use_of_user_defined_command[] = N_("E464: Ambiguous use of user-defined command"); static char e_not_an_editor_command[] = N_("E492: Not an editor command"); +static char e_no_source_file_name_to_substitute_for_sfile[] + = N_("E498: no :source file name to substitute for \"<sfile>\""); +static char e_no_call_stack_to_substitute_for_stack[] + = N_("E489: no call stack to substitute for \"<stack>\""); +static char e_no_script_file_name_to_substitute_for_script[] + = N_("E1274: No script file name to substitute for \"<script>\""); static int quitmore = 0; static bool ex_pressedreturn = false; @@ -127,6 +134,7 @@ struct dbg_stuff { char *vv_throwpoint; int did_emsg; int got_int; + bool did_throw; int need_rethrow; int check_cstack; except_T *current_exception; @@ -158,6 +166,7 @@ static void save_dbg_stuff(struct dbg_stuff *dsp) // Necessary for debugging an inactive ":catch", ":finally", ":endtry". dsp->did_emsg = did_emsg; did_emsg = false; dsp->got_int = got_int; got_int = false; + dsp->did_throw = did_throw; did_throw = false; dsp->need_rethrow = need_rethrow; need_rethrow = false; dsp->check_cstack = check_cstack; check_cstack = false; dsp->current_exception = current_exception; current_exception = NULL; @@ -173,6 +182,7 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp) (void)v_throwpoint(dsp->vv_throwpoint); did_emsg = dsp->did_emsg; got_int = dsp->got_int; + did_throw = dsp->did_throw; need_rethrow = dsp->need_rethrow; check_cstack = dsp->check_cstack; current_exception = dsp->current_exception; @@ -243,8 +253,8 @@ void do_exmode(void) RedrawingDisabled--; no_wait_return--; - redraw_all_later(NOT_VALID); - update_screen(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); + update_screen(); need_wait_return = false; msg_scroll = save_msg_scroll; } @@ -390,7 +400,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) initial_trylevel = trylevel; - current_exception = NULL; + // "did_throw" will be set to true when an exception is being thrown. + did_throw = false; // "did_emsg" will be set to true when emsg() is used, in which case we // cancel the whole command line, and any if/endif or loop. // If force_abort is set, we cancel everything. @@ -455,7 +466,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (breakpoint != NULL && dbg_tick != NULL && *dbg_tick != debug_tick) { *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), - (char_u *)fname, SOURCING_LNUM); + fname, SOURCING_LNUM); *dbg_tick = debug_tick; } @@ -464,10 +475,10 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // Did we encounter a breakpoint? if (breakpoint != NULL && *breakpoint != 0 && *breakpoint <= SOURCING_LNUM) { - dbg_breakpoint((char_u *)fname, SOURCING_LNUM); + dbg_breakpoint(fname, SOURCING_LNUM); // Find next breakpoint. *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), - (char_u *)fname, SOURCING_LNUM); + fname, SOURCING_LNUM); *dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -509,7 +520,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2, true)) == NULL) { - // Don't call wait_return for aborted command line. The NULL + // Don't call wait_return() for aborted command line. The NULL // returned for the end of a sourced file or executed function // doesn't do this. if (KeyTyped && !(flags & DOCMD_REPEAT)) { @@ -524,7 +535,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (flags & DOCMD_KEEPLINE) { xfree(repeat_cmdline); if (count == 0) { - repeat_cmdline = vim_strsave((char_u *)next_cmdline); + repeat_cmdline = xstrdup(next_cmdline); } else { repeat_cmdline = NULL; } @@ -618,7 +629,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // not to use a cs_line[] from an entry that isn't a ":while" // or ":for": It would make "current_line" invalid and can // cause a crash. - if (!did_emsg && !got_int && !current_exception + if (!did_emsg && !got_int && !did_throw && cstack.cs_idx >= 0 && (cstack.cs_flags[cstack.cs_idx] & (CSF_WHILE | CSF_FOR)) @@ -631,9 +642,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // Check for the next breakpoint at or after the ":while" // or ":for". - if (breakpoint != NULL) { - *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), - (char_u *)fname, + if (breakpoint != NULL && lines_ga.ga_len > current_line) { + *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), fname, ((wcmd_T *)lines_ga.ga_data)[current_line].lnum - 1); *dbg_tick = debug_tick; } @@ -660,7 +670,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) current_line = 0; } - // A ":finally" makes did_emsg, got_int and current_exception pending for + // A ":finally" makes did_emsg, got_int and did_throw pending for // being restored at the ":endtry". Reset them here and set the // ACTIVE and FINALLY flags, so that the finally clause gets executed. // This includes the case where a missing ":endif", ":endwhile" or @@ -669,9 +679,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) cstack.cs_lflags &= ~CSL_HAD_FINA; report_make_pending((cstack.cs_pending[cstack.cs_idx] & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW)), - current_exception); - did_emsg = got_int = false; - current_exception = NULL; + did_throw ? current_exception : NULL); + did_emsg = got_int = did_throw = false; cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY; } @@ -684,7 +693,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // exception, cancel everything. If it is left normally, reset // force_abort to get the non-EH compatible abortion behavior for // the rest of the script. - if (trylevel == 0 && !did_emsg && !got_int && !current_exception) { + if (trylevel == 0 && !did_emsg && !got_int && !did_throw) { force_abort = false; } @@ -698,7 +707,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // - didn't get an error message or lines are not typed // - there is a command after '|', inside a :if, :while, :for or :try, or // looping for ":source" command or function call. - } while (!((got_int || (did_emsg && force_abort) || current_exception) + } while (!((got_int || (did_emsg && force_abort) || did_throw) && cstack.cs_trylevel == 0) && !(did_emsg // Keep going when inside try/catch, so that the error can be @@ -718,7 +727,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (cstack.cs_idx >= 0) { // If a sourced file or executed function ran to its end, report the // unclosed conditional. - if (!got_int && !current_exception + if (!got_int && !did_throw && ((getline_equal(fgetline, cookie, getsourceline) && !source_finished(fgetline, cookie)) || (getline_equal(fgetline, cookie, get_func_line) @@ -761,7 +770,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // conditional, discard the uncaught exception, disable the conversion // of interrupts or errors to exceptions, and ensure that no more // commands are executed. - if (current_exception) { + if (did_throw) { + assert(current_exception != NULL); char *p = NULL; msglist_T *messages = NULL; msglist_T *next; @@ -775,7 +785,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) vim_snprintf((char *)IObuff, IOSIZE, _("E605: Exception not caught: %s"), current_exception->value); - p = (char *)vim_strsave(IObuff); + p = xstrdup((char *)IObuff); break; case ET_ERROR: messages = current_exception->messages; @@ -823,14 +833,14 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // cstack belongs to the same function or, respectively, script file, it // will have to be checked for finally clauses to be executed due to the // ":return" or ":finish". This is done in do_one_cmd(). - if (current_exception) { + if (did_throw) { need_rethrow = true; } if ((getline_equal(fgetline, cookie, getsourceline) && ex_nesting_level > source_level(real_cookie)) || (getline_equal(fgetline, cookie, get_func_line) && ex_nesting_level > func_level(real_cookie) + 1)) { - if (!current_exception) { + if (!did_throw) { check_cstack = true; } } else { @@ -844,8 +854,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) || getline_equal(fgetline, cookie, get_func_line)) && ex_nesting_level + 1 <= debug_break_level) { do_debug(getline_equal(fgetline, cookie, getsourceline) - ? (char_u *)_("End of sourced file") - : (char_u *)_("End of function")); + ? _("End of sourced file") + : _("End of function")); } } @@ -881,7 +891,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) need_wait_return = false; msg_didany = false; // don't wait when restarting edit } else if (need_wait_return) { - // The msg_start() above clears msg_didout. The wait_return we do + // The msg_start() above clears msg_didout. The wait_return() we do // here should not overwrite the command that may be shown before // doing that. msg_didout |= msg_didout_before_start; @@ -1290,9 +1300,9 @@ static void parse_register(exarg_T *eap) // for '=' register: accept the rest of the line as an expression if (eap->arg[-1] == '=' && eap->arg[0] != NUL) { if (!eap->skip) { - set_expr_line(vim_strsave((char_u *)eap->arg)); + set_expr_line(xstrdup(eap->arg)); } - eap->arg += STRLEN(eap->arg); + eap->arg += strlen(eap->arg); } eap->arg = skipwhite(eap->arg); } @@ -1329,6 +1339,20 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate) || ascii_iswhite(*p))) { long n = getdigits_long(&eap->arg, false, -1); eap->arg = skipwhite(eap->arg); + + if (eap->args != NULL) { + assert(eap->argc > 0 && eap->arg >= eap->args[0]); + // If eap->arg is still pointing to the first argument, just make eap->args[0] point to the + // same location. This is needed for usecases like vim.cmd.sleep('10m'). If eap->arg is + // pointing outside the first argument, shift arguments by 1. + if (eap->arg < eap->args[0] + eap->arglens[0]) { + eap->arglens[0] -= (size_t)(eap->arg - eap->args[0]); + eap->args[0] = eap->arg; + } else { + shift_cmd_args(eap); + } + } + if (n <= 0 && (eap->argt & EX_ZEROR) == 0) { if (errormsg != NULL) { *errormsg = _(e_zerocount); @@ -1361,6 +1385,13 @@ bool is_cmd_ni(cmdidx_T cmdidx) bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg) { char *after_modifier = NULL; + bool retval = false; + // parsing the command modifiers may set ex_pressedreturn + const bool save_ex_pressedreturn = ex_pressedreturn; + // parsing the command range may require moving the cursor + const pos_T save_cursor = curwin->w_cursor; + // parsing the command range may set the last search pattern + save_last_search_pattern(); // Initialize cmdinfo CLEAR_POINTER(cmdinfo); @@ -1375,13 +1406,10 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er .cookie = NULL, }; - const bool save_ex_pressedreturn = ex_pressedreturn; // Parse command modifiers if (parse_command_modifiers(eap, errormsg, &cmdinfo->cmdmod, false) == FAIL) { - ex_pressedreturn = save_ex_pressedreturn; - goto err; + goto end; } - ex_pressedreturn = save_ex_pressedreturn; after_modifier = eap->cmd; // Save location after command modifiers @@ -1394,21 +1422,21 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er char *p = find_ex_command(eap, NULL); if (p == NULL) { *errormsg = _(e_ambiguous_use_of_user_defined_command); - goto err; + goto end; } // Set command address type and parse command range set_cmd_addr_type(eap, p); eap->cmd = cmd; - if (parse_cmd_address(eap, errormsg, false) == FAIL) { - goto err; + if (parse_cmd_address(eap, errormsg, true) == FAIL) { + goto end; } // Skip colon and whitespace eap->cmd = skip_colon_white(eap->cmd, true); // Fail if command is a comment or if command doesn't exist if (*eap->cmd == NUL || *eap->cmd == '"') { - goto err; + goto end; } // Fail if command is invalid if (eap->cmdidx == CMD_SIZE) { @@ -1417,7 +1445,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er char *cmdname = after_modifier ? after_modifier : cmdline; append_command(cmdname); *errormsg = (char *)IObuff; - goto err; + goto end; } // Correctly set 'forceit' for commands @@ -1456,12 +1484,12 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er // Fail if command doesn't support bang but is used with a bang if (!(eap->argt & EX_BANG) && eap->forceit) { *errormsg = _(e_nobang); - goto err; + goto end; } // Fail if command doesn't support a range but it is given a range if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) { *errormsg = _(e_norange); - goto err; + goto end; } // Set default range for command if required if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) { @@ -1471,7 +1499,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er // Parse register and count parse_register(eap); if (parse_count(eap, errormsg, false) == FAIL) { - goto err; + goto end; } // Remove leading whitespace and colon from next command @@ -1487,10 +1515,39 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er cmdinfo->magic.bar = true; } - return true; -err: - undo_cmdmod(&cmdinfo->cmdmod); - return false; + retval = true; +end: + if (!retval) { + undo_cmdmod(&cmdinfo->cmdmod); + } + ex_pressedreturn = save_ex_pressedreturn; + curwin->w_cursor = save_cursor; + restore_last_search_pattern(); + return retval; +} + +// Shift Ex-command arguments to the right. +static void shift_cmd_args(exarg_T *eap) +{ + assert(eap->args != NULL && eap->argc > 0); + + char **oldargs = eap->args; + size_t *oldarglens = eap->arglens; + + eap->argc--; + eap->args = eap->argc > 0 ? xcalloc(eap->argc, sizeof(char *)) : NULL; + eap->arglens = eap->argc > 0 ? xcalloc(eap->argc, sizeof(size_t)) : NULL; + + for (size_t i = 0; i < eap->argc; i++) { + eap->args[i] = oldargs[i + 1]; + eap->arglens[i] = oldarglens[i + 1]; + } + + // If there are no arguments, make eap->arg point to the end of string. + eap->arg = (eap->argc > 0 ? eap->args[0] : (oldargs[0] + oldarglens[0])); + + xfree(oldargs); + xfree(oldarglens); } static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) @@ -1517,7 +1574,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) || eap->cmdidx == CMD_bunload) { p = skiptowhite_esc(eap->arg); } else { - p = eap->arg + STRLEN(eap->arg); + p = eap->arg + strlen(eap->arg); while (p > eap->arg && ascii_iswhite(p[-1])) { p--; } @@ -1532,15 +1589,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) eap->args[0] + eap->arglens[0], (eap->argt & EX_BUFUNL) != 0, false, false); eap->addr_count = 1; - // Shift each argument by 1 - for (size_t i = 0; i < eap->argc - 1; i++) { - eap->args[i] = eap->args[i + 1]; - } - // Make the last argument point to the NUL terminator at the end of string - eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1]; - eap->argc -= 1; - - eap->arg = eap->args[0]; + shift_cmd_args(eap); } if (eap->line2 < 0) { // failed return FAIL; @@ -1639,6 +1688,11 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) (void)hasFolding(eap->line2, NULL, &eap->line2); } + // Use first argument as count when possible + if (parse_count(eap, &errormsg, true) == FAIL) { + goto end; + } + // Execute the command execute_cmd0(&retv, eap, &errormsg, preview); @@ -1660,7 +1714,7 @@ static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetlin && (!eap->skip || cstack->cs_idx == 0 || (cstack->cs_idx > 0 && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))) { - int skip = did_emsg || got_int || current_exception; + bool skip = did_emsg || got_int || did_throw; if (eap->cmdidx == CMD_catch) { skip = !skip && !(cstack->cs_idx >= 0 @@ -1738,6 +1792,7 @@ static bool skip_cmd(const exarg_T *eap) case CMD_filter: case CMD_help: case CMD_hide: + case CMD_horizontal: case CMD_ijump: case CMD_ilist: case CMD_isearch: @@ -1857,7 +1912,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter ea.skip = (did_emsg || got_int - || current_exception + || did_throw || (cstack->cs_idx >= 0 && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))); @@ -1910,7 +1965,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // If we got a line, but no command, then go to the line. // If we find a '|' or '\n' we set ea.nextcmd. if (*ea.cmd == NUL || *ea.cmd == '"' - || (ea.nextcmd = (char *)check_nextcmd((char_u *)ea.cmd)) != NULL) { + || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { // strange vi behaviour: // ":3" jumps to line 3 // ":3|..." prints line 3 @@ -2419,8 +2474,12 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool continue; } - // ":hide" and ":hide | cmd" are not modifiers case 'h': + if (checkforcmd(&eap->cmd, "horizontal", 3)) { + cmod->cmod_split |= WSP_HOR; + continue; + } + // ":hide" and ":hide | cmd" are not modifiers if (p != eap->cmd || !checkforcmd(&p, "hide", 3) || *p == NUL || ends_excmd(*p)) { break; @@ -2565,7 +2624,7 @@ static void apply_cmdmod(cmdmod_T *cmod) if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmod->cmod_save_ei == NULL) { // Set 'eventignore' to "all". // First save the existing option value for restoring it later. - cmod->cmod_save_ei = (char *)vim_strsave(p_ei); + cmod->cmod_save_ei = xstrdup(p_ei); set_string_option_direct("ei", -1, "all", OPT_FREE, SID_NONE); } } @@ -2587,7 +2646,7 @@ void undo_cmdmod(cmdmod_T *cmod) if (cmod->cmod_save_ei != NULL) { // Restore 'eventignore' to the value before ":noautocmd". set_string_option_direct("ei", -1, cmod->cmod_save_ei, OPT_FREE, SID_NONE); - free_string_option((char_u *)cmod->cmod_save_ei); + free_string_option(cmod->cmod_save_ei); cmod->cmod_save_ei = NULL; } @@ -2800,24 +2859,24 @@ bool checkforcmd(char **pp, char *cmd, int len) /// invisible otherwise. static void append_command(char *cmd) { - size_t len = STRLEN(IObuff); + size_t len = strlen(IObuff); char *s = cmd; char *d; if (len > IOSIZE - 100) { // Not enough space, truncate and put in "...". d = (char *)IObuff + IOSIZE - 100; - d -= utf_head_off(IObuff, (const char_u *)d); + d -= utf_head_off((char *)IObuff, d); STRCPY(d, "..."); } STRCAT(IObuff, ": "); d = (char *)IObuff + STRLEN(IObuff); - while (*s != NUL && (char_u *)d - IObuff + 5 < IOSIZE) { + while (*s != NUL && d - IObuff + 5 < IOSIZE) { if ((char_u)s[0] == 0xc2 && (char_u)s[1] == 0xa0) { s += 2; STRCPY(d, "<a0>"); d += 4; - } else if ((char_u *)d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { + } else if (d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { break; } else { mb_copy_char((const char **)&s, &d); @@ -3038,7 +3097,7 @@ int cmd_exists(const char *const name) } /// "fullcommand" function -void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char *name = argvars[0].vval.v_string; @@ -3062,17 +3121,16 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - rettv->vval.v_string = (char *)vim_strsave(IS_USER_CMDIDX(ea.cmdidx) - ? (char_u *)get_user_command_name(ea.useridx, - ea.cmdidx) - : (char_u *)cmdnames[ea.cmdidx].cmd_name); + rettv->vval.v_string = xstrdup(IS_USER_CMDIDX(ea.cmdidx) + ? get_user_command_name(ea.useridx, ea.cmdidx) + : cmdnames[ea.cmdidx].cmd_name); } cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len) { cmdidx_T idx; - for (idx = (cmdidx_T)0; (int)idx < (int)CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) { + for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) { if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) { break; } @@ -3294,7 +3352,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int goto error; } if (skip) { // skip "/pat/" - cmd = (char *)skip_regexp((char_u *)cmd, c, p_magic, NULL); + cmd = skip_regexp(cmd, c, p_magic, NULL); if (*cmd == c) { cmd++; } @@ -3570,6 +3628,9 @@ char *invalid_range(exarg_T *eap) assert(eap->line2 >= 0); // No error for value that is too big, will use the last entry. if (eap->line2 <= 0) { + if (eap->addr_count == 0) { + return _(e_no_errors); + } return _(e_invrange); } break; @@ -3631,8 +3692,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // Don't do it when ":vimgrep" is used for ":grep". if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake || isgrep) && !grep_internal(eap->cmdidx)) { - 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); + const char *program = isgrep ? (*curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) + : (*curbuf->b_p_mp == NUL ? (char *)p_mp : curbuf->b_p_mp); arg = skipwhite(arg); @@ -3640,13 +3701,13 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // 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); + new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2); STRCPY(new_cmdline, program); STRCAT(new_cmdline, " "); STRCAT(new_cmdline, arg); } - msg_make((char_u *)arg); + msg_make(arg); // 'eap->cmd' is not set here, because it is not used at CMD_make xfree(*cmdlinep); @@ -3668,7 +3729,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // Decide to expand wildcards *before* replacing '%', '#', etc. If // the file name contains a wildcard it should not cause expanding. // (it will be expanded anyway if there is a wildcard before replacing). - int has_wildcards = path_has_wildcard((char_u *)p); + int has_wildcards = path_has_wildcard(p); while (*p != NUL) { // Skip over `=expr`, wildcards in it are not expanded. if (p[0] == '`' && p[1] == '=') { @@ -3690,7 +3751,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) size_t srclen; int escaped; char *repl = (char *)eval_vars((char_u *)p, (char_u *)eap->arg, &srclen, &(eap->do_ecmd_lnum), - errormsgp, &escaped); + errormsgp, &escaped, true); if (*errormsgp != NULL) { // error detected return FAIL; } @@ -3772,14 +3833,14 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // if there are still wildcards present. if (vim_strchr(eap->arg, '$') != NULL || vim_strchr(eap->arg, '~') != NULL) { - expand_env_esc((char_u *)eap->arg, NameBuff, MAXPATHL, true, true, NULL); + expand_env_esc((char_u *)eap->arg, (char_u *)NameBuff, MAXPATHL, true, true, NULL); has_wildcards = path_has_wildcard(NameBuff); p = (char *)NameBuff; } else { p = NULL; } if (p != NULL) { - (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep); + (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); } } @@ -3788,7 +3849,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // done by ExpandOne() below. #ifdef UNIX if (!has_wildcards) { - backslash_halve((char_u *)eap->arg); + backslash_halve(eap->arg); } #else backslash_halve((char_u *)eap->arg); @@ -3803,11 +3864,11 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) if (p_wic) { options += WILD_ICASE; } - p = (char *)ExpandOne(&xpc, (char_u *)eap->arg, NULL, options, WILD_EXPAND_FREE); + p = ExpandOne(&xpc, eap->arg, NULL, options, WILD_EXPAND_FREE); if (p == NULL) { return FAIL; } - (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep); + (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); xfree(p); } } @@ -3825,10 +3886,10 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch // The new command line is build in new_cmdline[]. // First allocate it. // Careful: a "+cmd" argument may have been NUL terminated. - size_t len = STRLEN(repl); - size_t i = (size_t)(src - *cmdlinep) + STRLEN(src + srclen) + len + 3; + size_t len = strlen(repl); + size_t i = (size_t)(src - *cmdlinep) + strlen(src + srclen) + len + 3; if (eap->nextcmd != NULL) { - i += STRLEN(eap->nextcmd); // add space for next command + i += strlen(eap->nextcmd); // add space for next command } char *new_cmdline = xmalloc(i); size_t offset = (size_t)(src - *cmdlinep); @@ -3846,7 +3907,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch src = new_cmdline + i; // remember where to continue if (eap->nextcmd != NULL) { // append next command - i = STRLEN(new_cmdline) + 1; + i = strlen(new_cmdline) + 1; STRCPY(new_cmdline + i, eap->nextcmd); eap->nextcmd = new_cmdline + i; } @@ -3861,7 +3922,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch } else { // Otherwise, argument gets shifted alongside the replaced text. // The amount of the shift is equal to the difference of the old and new string length. - eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep) + (len - srclen); + eap->args[j] = new_cmdline + ((eap->args[j] - *cmdlinep) + (ptrdiff_t)(len - srclen)); } } @@ -3913,7 +3974,7 @@ void separate_nextcmd(exarg_T *eap) STRMOVE(p - 1, p); // remove the '\' p--; } else { - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); *p = NUL; break; } @@ -4042,7 +4103,7 @@ static int getargopt(exarg_T *eap) *arg = NUL; if (pp == &eap->force_ff) { - if (check_ff_value((char_u *)eap->cmd + eap->force_ff) == FAIL) { + if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) { return FAIL; } eap->force_ff = (char_u)eap->cmd[eap->force_ff]; @@ -4088,9 +4149,9 @@ static int get_tabpage_arg(exarg_T *eap) tab_number = (int)getdigits(&p, false, tab_number); if (relative == 0) { - if (STRCMP(p, "$") == 0) { + if (strcmp(p, "$") == 0) { tab_number = LAST_TAB_NR; - } else if (STRCMP(p, "#") == 0) { + } else if (strcmp(p, "#") == 0) { if (valid_tabpage(lastused_tabpage)) { tab_number = tabpage_index(lastused_tabpage); } else { @@ -4276,7 +4337,7 @@ int ends_excmd(int c) FUNC_ATTR_CONST /// @return the next command, after the first '|' or '\n' or, /// NULL if not found. -char_u *find_nextcmd(const char_u *p) +char *find_nextcmd(const char *p) { while (*p != '|' && *p != '\n') { if (*p == NUL) { @@ -4284,18 +4345,18 @@ char_u *find_nextcmd(const char_u *p) } p++; } - return (char_u *)p + 1; + return (char *)p + 1; } /// Check if *p is a separator between Ex commands, skipping over white space. /// /// @return NULL if it isn't, the following character if it is. -char_u *check_nextcmd(char_u *p) +char *check_nextcmd(char *p) { - char *s = skipwhite((char *)p); + char *s = skipwhite(p); if (*s == '|' || *s == '\n') { - return (char_u *)(s + 1); + return s + 1; } else { return NULL; } @@ -4322,7 +4383,7 @@ static int check_more(int message, bool forceit) vim_snprintf((char *)buff, DIALOG_MSG_SIZE, NGETTEXT("%d more file to edit. Quit anyway?", "%d more files to edit. Quit anyway?", (unsigned long)n), n); - if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 1) == VIM_YES) { + if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) { return OK; } return FAIL; @@ -4670,7 +4731,6 @@ void tabpage_close(int forceit) void tabpage_close_other(tabpage_T *tp, int forceit) { int done = 0; - int h = tabline_height(); char prev_idx[NUMBUFLEN]; // Limit to 1000 windows, autocommands may add a window while we close @@ -4686,11 +4746,6 @@ void tabpage_close_other(tabpage_T *tp, int forceit) break; } } - - redraw_tabline = true; - if (h != tabline_height()) { - win_new_screen_rows(); - } } /// ":only". @@ -4812,7 +4867,6 @@ static void ex_print(exarg_T *eap) if (++eap->line1 > eap->line2) { break; } - ui_flush(); // show one line at a time } setpcmark(); // put cursor at last line @@ -4888,7 +4942,7 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { - fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg), + fname = (char *)find_file_in_path((char_u *)eap->arg, strlen(eap->arg), FNAME_MESS, true, (char_u *)curbuf->b_ffname); if (fname == NULL) { goto theend; @@ -5013,8 +5067,7 @@ static void ex_tabs(exarg_T *eap) msg_putchar('\n'); vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++); - msg_outtrans_attr(IObuff, HL_ATTR(HLF_T)); - ui_flush(); // output one line at a time + msg_outtrans_attr((char *)IObuff, HL_ATTR(HLF_T)); os_breakcheck(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -5033,7 +5086,6 @@ static void ex_tabs(exarg_T *eap) home_replace(wp->w_buffer, wp->w_buffer->b_fname, (char *)IObuff, IOSIZE, true); } msg_outtrans((char *)IObuff); - ui_flush(); // output one line at a time os_breakcheck(); } } @@ -5044,7 +5096,7 @@ static void ex_tabs(exarg_T *eap) static void ex_mode(exarg_T *eap) { if (*eap->arg == NUL) { - must_redraw = CLEAR; + must_redraw = UPD_CLEAR; ex_redraw(eap); } else { emsg(_(e_screenmode)); @@ -5083,7 +5135,7 @@ static void ex_resize(exarg_T *eap) /// ":find [+command] <file>" command. static void ex_find(exarg_T *eap) { - char *fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg), + char *fname = (char *)find_file_in_path((char_u *)eap->arg, strlen(eap->arg), FNAME_MESS, true, (char_u *)curbuf->b_ffname); if (eap->addr_count > 0) { // Repeat finding the file "count" times. This matters when it @@ -5136,7 +5188,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) no_wait_return = 0; need_wait_return = false; msg_scroll = 0; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); pending_exmode_active = true; normal_enter(false, true); @@ -5251,7 +5303,7 @@ static void ex_swapname(exarg_T *eap) if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) { msg(_("No swap file")); } else { - msg((char *)curbuf->b_ml.ml_mfp->mf_fname); + msg(curbuf->b_ml.ml_mfp->mf_fname); } } @@ -5298,7 +5350,7 @@ static void ex_syncbind(exarg_T *eap) scrolldown(-y, true); } curwin->w_scbind_pos = topline; - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); cursor_correct(); curwin->w_redr_status = true; } @@ -5366,7 +5418,7 @@ static void ex_read(exarg_T *eap) deleted_lines_mark(lnum, 1L); } } - redraw_curbuf_later(VALID); + redraw_curbuf_later(UPD_VALID); } } } @@ -5457,7 +5509,7 @@ bool changedir_func(char *new_dir, CdScope scope) char *pdir = NULL; // ":cd -": Change to previous directory - if (STRCMP(new_dir, "-") == 0) { + if (strcmp(new_dir, "-") == 0) { pdir = get_prevdir(scope); if (pdir == NULL) { emsg(_("E186: No previous directory")); @@ -5466,8 +5518,8 @@ bool changedir_func(char *new_dir, CdScope scope) new_dir = pdir; } - if (os_dirname(NameBuff, MAXPATHL) == OK) { - pdir = (char *)vim_strsave(NameBuff); + if (os_dirname((char_u *)NameBuff, MAXPATHL) == OK) { + pdir = xstrdup(NameBuff); } else { pdir = NULL; } @@ -5480,7 +5532,7 @@ bool changedir_func(char *new_dir, CdScope scope) if (*new_dir == NUL && p_cdh) { #endif // Use NameBuff for home directory name. - expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); + expand_env("$HOME", NameBuff, MAXPATHL); new_dir = (char *)NameBuff; } @@ -5521,27 +5573,26 @@ void ex_cd(exarg_T *eap) // for non-UNIX ":cd" means: print current directory unless 'cdhome' is set if (*new_dir == NUL && !p_cdh) { ex_pwd(NULL); - } else + return; + } #endif - { - CdScope scope = kCdScopeGlobal; - switch (eap->cmdidx) { - case CMD_tcd: - case CMD_tchdir: - scope = kCdScopeTabpage; - break; - case CMD_lcd: - case CMD_lchdir: - scope = kCdScopeWindow; - break; - default: - break; - } - if (changedir_func(new_dir, scope)) { - // Echo the new current directory if the command was typed. - if (KeyTyped || p_verbose >= 5) { - ex_pwd(eap); - } + CdScope scope = kCdScopeGlobal; + switch (eap->cmdidx) { + case CMD_tcd: + case CMD_tchdir: + scope = kCdScopeTabpage; + break; + case CMD_lcd: + case CMD_lchdir: + scope = kCdScopeWindow; + break; + default: + break; + } + if (changedir_func(new_dir, scope)) { + // Echo the new current directory if the command was typed. + if (KeyTyped || p_verbose >= 5) { + ex_pwd(eap); } } } @@ -5549,7 +5600,7 @@ void ex_cd(exarg_T *eap) /// ":pwd". static void ex_pwd(exarg_T *eap) { - if (os_dirname(NameBuff, MAXPATHL) == OK) { + if (os_dirname((char_u *)NameBuff, MAXPATHL) == OK) { #ifdef BACKSLASH_IN_FILENAME slash_adjust(NameBuff); #endif @@ -5653,7 +5704,7 @@ static void ex_wincmd(exarg_T *eap) p = eap->arg + 1; } - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); p = skipwhite(p); if (*p != NUL && *p != '"' && eap->nextcmd == NULL) { emsg(_(e_invarg)); @@ -5851,7 +5902,7 @@ static void ex_undo(exarg_T *eap) { if (eap->addr_count != 1) { if (eap->forceit) { - u_undo_and_forget(1); // :undo! + u_undo_and_forget(1, true); // :undo! } else { u_undo(1); // :undo } @@ -5878,7 +5929,7 @@ static void ex_undo(exarg_T *eap) emsg(_(e_undobang_cannot_redo_or_move_branch)); return; } - u_undo_and_forget(count); + u_undo_and_forget(count, true); } else { // :undo 123 undo_time(step, false, false, true); } @@ -5985,7 +6036,7 @@ static void ex_redir(exarg_T *eap) // Make register empty when not using @A-@Z and the // command is valid. if (*arg == NUL && !isupper(redir_reg)) { - write_reg_contents(redir_reg, (char_u *)"", 0, false); + write_reg_contents(redir_reg, "", 0, false); } } } @@ -6037,11 +6088,12 @@ static void ex_redraw(exarg_T *eap) validate_cursor(); update_topline(curwin); if (eap->forceit) { - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); redraw_cmdline = true; + } else if (VIsual_active) { + redraw_curbuf_later(UPD_INVERTED); } - update_screen(eap->forceit ? NOT_VALID - : VIsual_active ? INVERTED : 0); + update_screen(); if (need_maketitle) { maketitle(); } @@ -6067,14 +6119,22 @@ static void ex_redrawstatus(exarg_T *eap) int r = RedrawingDisabled; int p = p_lz; - RedrawingDisabled = 0; - p_lz = false; if (eap->forceit) { status_redraw_all(); } else { status_redraw_curbuf(); } - update_screen(VIsual_active ? INVERTED : 0); + + RedrawingDisabled = 0; + p_lz = false; + if (State & MODE_CMDLINE) { + redraw_statuslines(); + } else { + if (VIsual_active) { + redraw_curbuf_later(UPD_INVERTED); + } + update_screen(); + } RedrawingDisabled = r; p_lz = p; ui_flush(); @@ -6135,12 +6195,12 @@ FILE *open_exfile(char_u *fname, int forceit, char *mode) { #ifdef UNIX // with Unix it is possible to open a directory - if (os_isdir(fname)) { + if (os_isdir((char *)fname)) { semsg(_(e_isadir2), fname); return NULL; } #endif - if (!forceit && *mode != 'a' && os_path_exists(fname)) { + if (!forceit && *mode != 'a' && os_path_exists((char *)fname)) { semsg(_("E189: \"%s\" exists (add ! to override)"), fname); return NULL; } @@ -6270,7 +6330,7 @@ static void ex_normal(exarg_T *eap) } } if (len > 0) { - arg = xmalloc(STRLEN(eap->arg) + (size_t)len + 1); + arg = xmalloc(strlen(eap->arg) + (size_t)len + 1); len = 0; for (p = eap->arg; *p != NUL; p++) { arg[len++] = *p; @@ -6435,7 +6495,7 @@ static void ex_findpat(exarg_T *eap) if (*eap->arg == '/') { // Match regexp, not just whole words whole = false; eap->arg++; - char *p = (char *)skip_regexp((char_u *)eap->arg, '/', p_magic, NULL); + char *p = skip_regexp(eap->arg, '/', p_magic, NULL); if (*p) { *p++ = NUL; p = skipwhite(p); @@ -6444,12 +6504,12 @@ static void ex_findpat(exarg_T *eap) if (!ends_excmd(*p)) { eap->errmsg = ex_errmsg(e_trailing_arg, p); } else { - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); } } } if (!eap->skip) { - find_pattern_in_path((char_u *)eap->arg, 0, STRLEN(eap->arg), whole, !eap->forceit, + find_pattern_in_path((char_u *)eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, n, action, eap->line1, eap->line2); } @@ -6477,7 +6537,7 @@ static void ex_pedit(exarg_T *eap) if (curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were validate_cursor(); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } g_do_tagpreview = 0; @@ -6541,7 +6601,7 @@ static void ex_tag_cmd(exarg_T *eap, char *name) cmd = DT_LTAG; } - do_tag((char_u *)eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, + do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit, true); } @@ -6555,6 +6615,7 @@ enum { SPEC_SFILE, SPEC_SLNUM, SPEC_STACK, + SPEC_SCRIPT, SPEC_AFILE, SPEC_ABUF, SPEC_AMATCH, @@ -6579,6 +6640,7 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) [SPEC_SFILE] = "<sfile>", // ":so" file name [SPEC_SLNUM] = "<slnum>", // ":so" file line number [SPEC_STACK] = "<stack>", // call stack + [SPEC_SCRIPT] = "<script>", // script file name [SPEC_AFILE] = "<afile>", // autocommand file name [SPEC_ABUF] = "<abuf>", // autocommand buffer number [SPEC_AMATCH] = "<amatch>", // autocommand match name @@ -6588,7 +6650,7 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) }; for (size_t i = 0; i < ARRAY_SIZE(spec_str); i++) { - size_t len = STRLEN(spec_str[i]); + size_t len = strlen(spec_str[i]); if (STRNCMP(src, spec_str[i], len) == 0) { *usedlen = len; assert(i <= SSIZE_MAX); @@ -6600,34 +6662,36 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) /// Evaluate cmdline variables. /// -/// change '%' to curbuf->b_ffname -/// '#' to curwin->w_alt_fnum -/// '<cword>' to word under the cursor -/// '<cWORD>' to WORD under the cursor -/// '<cexpr>' to C-expression under the cursor -/// '<cfile>' to path name under the cursor -/// '<sfile>' to sourced file name -/// '<stack>' to call stack -/// '<slnum>' to sourced file line number -/// '<afile>' to file name for autocommand -/// '<abuf>' to buffer number for autocommand -/// '<amatch>' to matching name for autocommand +/// change "%" to curbuf->b_ffname +/// "#" to curwin->w_alt_fnum +/// "<cword>" to word under the cursor +/// "<cWORD>" to WORD under the cursor +/// "<cexpr>" to C-expression under the cursor +/// "<cfile>" to path name under the cursor +/// "<sfile>" to sourced file name +/// "<stack>" to call stack +/// "<script>" to current script name +/// "<slnum>" to sourced file line number +/// "<afile>" to file name for autocommand +/// "<abuf>" to buffer number for autocommand +/// "<amatch>" to matching name for autocommand /// /// When an error is detected, "errormsg" is set to a non-NULL pointer (may be /// "" for error without a message) and NULL is returned. /// -/// @param src pointer into commandline -/// @param srcstart beginning of valid memory for src -/// @param usedlen characters after src that are used -/// @param lnump line number for :e command, or NULL -/// @param errormsg pointer to error message -/// @param escaped return value has escaped white space (can be NULL) +/// @param src pointer into commandline +/// @param srcstart beginning of valid memory for src +/// @param usedlen characters after src that are used +/// @param lnump line number for :e command, or NULL +/// @param errormsg pointer to error message +/// @param escaped return value has escaped white space (can be NULL) +/// @param empty_is_error empty result is considered an error /// /// @return an allocated string if a valid match was found. /// Returns NULL if no match was found. "usedlen" then still contains the /// number of characters to skip. char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg, - int *escaped) + int *escaped, bool empty_is_error) { char *result; char *resultbuf = NULL; @@ -6686,7 +6750,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum valid = 0; // Must have ":p:h" to be valid } else { result = curbuf->b_fname; - tilde_file = STRCMP(result, "~") == 0; + tilde_file = strcmp(result, "~") == 0; } break; @@ -6740,7 +6804,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum valid = 0; // Must have ":p:h" to be valid } else { result = buf->b_fname; - tilde_file = STRCMP(result, "~") == 0; + tilde_file = strcmp(result, "~") == 0; } } break; @@ -6792,12 +6856,25 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum break; case SPEC_SFILE: // file name for ":so" command + result = estack_sfile(ESTACK_SFILE); + if (result == NULL) { + *errormsg = _(e_no_source_file_name_to_substitute_for_sfile); + return NULL; + } + resultbuf = result; // remember allocated string + break; case SPEC_STACK: // call stack - result = estack_sfile(spec_idx == SPEC_SFILE ? ESTACK_SFILE : ESTACK_STACK); + result = estack_sfile(ESTACK_STACK); if (result == NULL) { - *errormsg = spec_idx == SPEC_SFILE - ? _("E498: no :source file name to substitute for \"<sfile>\"") - : _("E489: no call stack to substitute for \"<stack>\""); + *errormsg = _(e_no_call_stack_to_substitute_for_stack); + return NULL; + } + resultbuf = result; // remember allocated string + break; + case SPEC_SCRIPT: // script file name + result = estack_sfile(ESTACK_SCRIPT); + if (result == NULL) { + *errormsg = _(e_no_script_file_name_to_substitute_for_script); return NULL; } resultbuf = result; // remember allocated string @@ -6840,12 +6917,12 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum } // Length of new string. - resultlen = STRLEN(result); + resultlen = strlen(result); // Remove the file name extension. if (src[*usedlen] == '<') { (*usedlen)++; char *s; - if ((s = (char *)STRRCHR(result, '.')) != NULL + if ((s = strrchr(result, '.')) != NULL && s >= path_tail(result)) { resultlen = (size_t)(s - result); } @@ -6860,11 +6937,13 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum } if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH) { - if (valid != VALID_HEAD + VALID_PATH) { - // xgettext:no-c-format - *errormsg = _("E499: Empty file name for '%' or '#', only works with \":p:h\""); - } else { - *errormsg = _("E500: Evaluates to an empty string"); + if (empty_is_error) { + if (valid != VALID_HEAD + VALID_PATH) { + // xgettext:no-c-format + *errormsg = _("E499: Empty file name for '%' or '#', only works with \":p:h\""); + } else { + *errormsg = _("E500: Evaluates to an empty string"); + } } result = NULL; } else { @@ -6888,7 +6967,8 @@ char *expand_sfile(char *arg) // replace "<sfile>" with the sourced file name, and do ":" stuff size_t srclen; char *errormsg; - char *repl = (char *)eval_vars((char_u *)p, (char_u *)result, &srclen, NULL, &errormsg, NULL); + char *repl = (char *)eval_vars((char_u *)p, (char_u *)result, &srclen, NULL, &errormsg, NULL, + true); if (errormsg != NULL) { if (*errormsg) { emsg(errormsg); @@ -6900,11 +6980,11 @@ char *expand_sfile(char *arg) p += srclen; continue; } - size_t len = STRLEN(result) - srclen + STRLEN(repl) + 1; + size_t len = strlen(result) - srclen + strlen(repl) + 1; char *newres = xmalloc(len); memmove(newres, result, (size_t)(p - result)); STRCPY(newres + (p - result), repl); - len = STRLEN(newres); + len = strlen(newres); STRCAT(newres, p + srclen); xfree(repl); xfree(result); @@ -6919,16 +6999,16 @@ char *expand_sfile(char *arg) /// ":rshada" and ":wshada". static void ex_shada(exarg_T *eap) { - char *save_shada = (char *)p_shada; + char *save_shada = p_shada; if (*p_shada == NUL) { - p_shada = (char_u *)"'100"; + p_shada = "'100"; } if (eap->cmdidx == CMD_rviminfo || eap->cmdidx == CMD_rshada) { (void)shada_read_everything(eap->arg, eap->forceit, false); } else { shada_write_file(eap->arg, eap->forceit); } - p_shada = (char_u *)save_shada; + p_shada = save_shada; } /// Make a dialog message in "buff[DIALOG_MSG_SIZE]". @@ -6944,16 +7024,16 @@ void dialog_msg(char *buff, char *format, char *fname) /// ":behave {mswin,xterm}" static void ex_behave(exarg_T *eap) { - if (STRCMP(eap->arg, "mswin") == 0) { - set_option_value("selection", 0L, "exclusive", 0); - set_option_value("selectmode", 0L, "mouse,key", 0); - set_option_value("mousemodel", 0L, "popup", 0); - set_option_value("keymodel", 0L, "startsel,stopsel", 0); - } else if (STRCMP(eap->arg, "xterm") == 0) { - set_option_value("selection", 0L, "inclusive", 0); - set_option_value("selectmode", 0L, "", 0); - set_option_value("mousemodel", 0L, "extend", 0); - set_option_value("keymodel", 0L, "", 0); + if (strcmp(eap->arg, "mswin") == 0) { + set_option_value_give_err("selection", 0L, "exclusive", 0); + set_option_value_give_err("selectmode", 0L, "mouse,key", 0); + set_option_value_give_err("mousemodel", 0L, "popup", 0); + set_option_value_give_err("keymodel", 0L, "startsel,stopsel", 0); + } else if (strcmp(eap->arg, "xterm") == 0) { + set_option_value_give_err("selection", 0L, "inclusive", 0); + set_option_value_give_err("selectmode", 0L, "", 0); + set_option_value_give_err("mousemodel", 0L, "extend", 0); + set_option_value_give_err("keymodel", 0L, "", 0); } else { semsg(_(e_invarg2), eap->arg); } @@ -6999,7 +7079,7 @@ static void ex_filetype(exarg_T *eap) } break; } - if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) { + if (strcmp(arg, "on") == 0 || strcmp(arg, "detect") == 0) { if (*arg == 'o' || !filetype_detect) { source_runtime(FILETYPE_FILE, DIP_ALL); filetype_detect = kTrue; @@ -7016,7 +7096,7 @@ static void ex_filetype(exarg_T *eap) (void)do_doautocmd("filetypedetect BufRead", true, NULL); do_modelines(0); } - } else if (STRCMP(arg, "off") == 0) { + } else if (strcmp(arg, "off") == 0) { if (plugin || indent) { if (plugin) { source_runtime(FTPLUGOF_FILE, DIP_ALL); @@ -7073,7 +7153,7 @@ static void ex_setfiletype(exarg_T *eap) arg += 9; } - set_option_value("filetype", 0L, arg, OPT_LOCAL); + set_option_value_give_err("filetype", 0L, arg, OPT_LOCAL); if (arg != eap->arg) { did_filetype = false; } @@ -7099,7 +7179,7 @@ void set_no_hlsearch(bool flag) static void ex_nohlsearch(exarg_T *eap) { set_no_hlsearch(true); - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } static void ex_fold(exarg_T *eap) diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 69d509abb7..c2648b9bfc 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -45,20 +45,19 @@ // there or even outside the try conditional. Try conditionals may be nested. // Configuration whether an exception is thrown on error or interrupt. When -// the preprocessor macros below evaluate to FALSE, an error (did_emsg) or +// the preprocessor macros below evaluate to false, an error (did_emsg) or // interrupt (got_int) under an active try conditional terminates the script // after the non-active finally clauses of all active try conditionals have been // executed. Otherwise, errors and/or interrupts are converted into catchable -// exceptions, which terminate the script only if not caught. For user -// exceptions, only current_exception is set. (Note: got_int can be set -// asynchronously afterwards by a SIGINT, so current_exception && got_int is not +// exceptions (did_throw additionally set), which terminate the script only if +// not caught. For user exceptions, only did_throw is set. (Note: got_int can +// be set asynchronously afterwards by a SIGINT, so did_throw && got_int is not // a reliant test that the exception currently being thrown is an interrupt // exception. Similarly, did_emsg can be set afterwards on an error in an -// (unskipped) conditional command inside an inactive conditional, so -// current_exception && did_emsg is not a reliant test that the exception -// currently being thrown is an error exception.) - The macros can be defined -// as expressions checking for a variable that is allowed to be changed during -// execution of a script. +// (unskipped) conditional command inside an inactive conditional, so did_throw +// && did_emsg is not a reliant test that the exception currently being thrown +// is an error exception.) - The macros can be defined as expressions checking +// for a variable that is allowed to be changed during execution of a script. // Values used for the Vim release. #define THROW_ON_ERROR true @@ -71,7 +70,7 @@ #define CHECK_SKIP \ (did_emsg \ || got_int \ - || current_exception \ + || did_throw \ || (cstack->cs_idx > 0 \ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE))) @@ -80,16 +79,14 @@ static void discard_pending_return(typval_T *p) tv_free(p); } -/* - * When several errors appear in a row, setting "force_abort" is delayed until - * the failing command returned. "cause_abort" is set to TRUE meanwhile, in - * order to indicate that situation. This is useful when "force_abort" was set - * during execution of a function call from an expression: the aborting of the - * expression evaluation is done without producing any error messages, but all - * error messages on parsing errors during the expression evaluation are given - * (even if a try conditional is active). - */ -static int cause_abort = FALSE; +// When several errors appear in a row, setting "force_abort" is delayed until +// the failing command returned. "cause_abort" is set to true meanwhile, in +// order to indicate that situation. This is useful when "force_abort" was set +// during execution of a function call from an expression: the aborting of the +// expression evaluation is done without producing any error messages, but all +// error messages on parsing errors during the expression evaluation are given +// (even if a try conditional is active). +static int cause_abort = false; /// @return true when immediately aborting on error, or when an interrupt /// occurred or an exception was thrown but not caught. @@ -104,7 +101,7 @@ static int cause_abort = FALSE; /// value. "got_int" is also set by calling interrupt(). int aborting(void) { - return (did_emsg && force_abort) || got_int || current_exception; + return (did_emsg && force_abort) || got_int || did_throw; } /// The value of "force_abort" is temporarily reset by the first emsg() call @@ -114,11 +111,11 @@ int aborting(void) void update_force_abort(void) { if (cause_abort) { - force_abort = TRUE; + force_abort = true; } } -/// @return TRUE if a command with a subcommand resulting in "retcode" should +/// @return true if a command with a subcommand resulting in "retcode" should /// abort the script processing. Can be used to suppress an autocommand after /// execution of a failing subcommand as long as the error message has not been /// displayed and actually caused the abortion. @@ -127,7 +124,7 @@ int should_abort(int retcode) return (retcode == FAIL && trylevel != 0 && !emsg_silent) || aborting(); } -/// @return TRUE if a function with the "abort" flag should not be considered +/// @return true if a function with the "abort" flag should not be considered /// ended on an error. This means that parsing commands is continued in order /// to find finally clauses to be executed, and that some errors in skipped /// commands are still reported. @@ -154,70 +151,58 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore) msglist_T *elem; msglist_T **plist; - /* - * Do nothing when displaying the interrupt message or reporting an - * uncaught exception (which has already been discarded then) at the top - * level. Also when no exception can be thrown. The message will be - * displayed by emsg(). - */ + // Do nothing when displaying the interrupt message or reporting an + // uncaught exception (which has already been discarded then) at the top + // level. Also when no exception can be thrown. The message will be + // displayed by emsg(). if (suppress_errthrow) { return false; } - /* - * If emsg() has not been called previously, temporarily reset - * "force_abort" until the throw point for error messages has been - * reached. This ensures that aborting() returns the same value for all - * errors that appear in the same command. This means particularly that - * for parsing errors during expression evaluation emsg() will be called - * multiply, even when the expression is evaluated from a finally clause - * that was activated due to an aborting error, interrupt, or exception. - */ + // If emsg() has not been called previously, temporarily reset + // "force_abort" until the throw point for error messages has been + // reached. This ensures that aborting() returns the same value for all + // errors that appear in the same command. This means particularly that + // for parsing errors during expression evaluation emsg() will be called + // multiply, even when the expression is evaluated from a finally clause + // that was activated due to an aborting error, interrupt, or exception. if (!did_emsg) { cause_abort = force_abort; - force_abort = FALSE; - } - - /* - * If no try conditional is active and no exception is being thrown and - * there has not been an error in a try conditional or a throw so far, do - * nothing (for compatibility of non-EH scripts). The message will then - * be displayed by emsg(). When ":silent!" was used and we are not - * currently throwing an exception, do nothing. The message text will - * then be stored to v:errmsg by emsg() without displaying it. - */ - if (((trylevel == 0 && !cause_abort) || emsg_silent) && !current_exception) { + force_abort = false; + } + + // If no try conditional is active and no exception is being thrown and + // there has not been an error in a try conditional or a throw so far, do + // nothing (for compatibility of non-EH scripts). The message will then + // be displayed by emsg(). When ":silent!" was used and we are not + // currently throwing an exception, do nothing. The message text will + // then be stored to v:errmsg by emsg() without displaying it. + if (((trylevel == 0 && !cause_abort) || emsg_silent) && !did_throw) { return false; } - /* - * Ignore an interrupt message when inside a try conditional or when an - * exception is being thrown or when an error in a try conditional or - * throw has been detected previously. This is important in order that an - * interrupt exception is catchable by the innermost try conditional and - * not replaced by an interrupt message error exception. - */ + // Ignore an interrupt message when inside a try conditional or when an + // exception is being thrown or when an error in a try conditional or + // throw has been detected previously. This is important in order that an + // interrupt exception is catchable by the innermost try conditional and + // not replaced by an interrupt message error exception. if (mesg == _(e_interr)) { *ignore = true; return true; } - /* - * Ensure that all commands in nested function calls and sourced files - * are aborted immediately. - */ - cause_abort = TRUE; - - /* - * When an exception is being thrown, some commands (like conditionals) are - * not skipped. Errors in those commands may affect what of the subsequent - * commands are regarded part of catch and finally clauses. Catching the - * exception would then cause execution of commands not intended by the - * user, who wouldn't even get aware of the problem. Therefore, discard the - * exception currently being thrown to prevent it from being caught. Just - * execute finally clauses and terminate. - */ - if (current_exception) { + // Ensure that all commands in nested function calls and sourced files + // are aborted immediately. + cause_abort = true; + + // When an exception is being thrown, some commands (like conditionals) are + // not skipped. Errors in those commands may affect what of the subsequent + // commands are regarded part of catch and finally clauses. Catching the + // exception would then cause execution of commands not intended by the + // user, who wouldn't even get aware of the problem. Therefore, discard the + // exception currently being thrown to prevent it from being caught. Just + // execute finally clauses and terminate. + if (did_throw) { // When discarding an interrupt exception, reset got_int to prevent the // same interrupt being converted to an exception again and discarding // the error exception we are about to throw here. @@ -229,25 +214,21 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore) #ifdef THROW_TEST if (!THROW_ON_ERROR) { - /* - * Print error message immediately without searching for a matching - * catch clause; just finally clauses are executed before the script - * is terminated. - */ + // Print error message immediately without searching for a matching + // catch clause; just finally clauses are executed before the script + // is terminated. return false; } else // NOLINT(readability/braces) #endif { - /* - * Prepare the throw of an error exception, so that everything will - * be aborted (except for executing finally clauses), until the error - * exception is caught; if still uncaught at the top level, the error - * message will be displayed and the script processing terminated - * then. - This function has no access to the conditional stack. - * Thus, the actual throw is made after the failing command has - * returned. - Throw only the first of several errors in a row, except - * a severe error is following. - */ + // Prepare the throw of an error exception, so that everything will + // be aborted (except for executing finally clauses), until the error + // exception is caught; if still uncaught at the top level, the error + // message will be displayed and the script processing terminated + // then. - This function has no access to the conditional stack. + // Thus, the actual throw is made after the failing command has + // returned. - Throw only the first of several errors in a row, except + // a severe error is following. if (msg_list != NULL) { plist = msg_list; while (*plist != NULL) { @@ -313,13 +294,11 @@ void free_global_msglist(void) /// has returned (see do_one_cmd()). void do_errthrow(cstack_T *cstack, char *cmdname) { - /* - * Ensure that all commands in nested function calls and sourced files - * are aborted immediately. - */ + // Ensure that all commands in nested function calls and sourced files + // are aborted immediately. if (cause_abort) { - cause_abort = FALSE; - force_abort = TRUE; + cause_abort = false; + force_abort = true; } // If no exception is to be thrown or the conversion should be done after @@ -334,7 +313,7 @@ void do_errthrow(cstack_T *cstack, char *cmdname) if (cstack != NULL) { do_throw(cstack); } else { - need_rethrow = TRUE; + need_rethrow = true; } } *msg_list = NULL; @@ -343,13 +322,13 @@ void do_errthrow(cstack_T *cstack, char *cmdname) /// do_intthrow(): Replace the current exception by an interrupt or interrupt /// exception if appropriate. /// -/// @return TRUE if the current exception is discarded or, -/// FALSE otherwise. +/// @return true if the current exception is discarded or, +/// false otherwise. int do_intthrow(cstack_T *cstack) { // If no interrupt occurred or no try conditional is active and no exception // is being thrown, do nothing (for compatibility of non-EH scripts). - if (!got_int || (trylevel == 0 && !current_exception)) { + if (!got_int || (trylevel == 0 && !did_throw)) { return false; } @@ -358,7 +337,7 @@ int do_intthrow(cstack_T *cstack) // The interrupt aborts everything except for executing finally clauses. // Discard any user or error or interrupt exception currently being // thrown. - if (current_exception) { + if (did_throw) { discard_current_exception(); } } else { @@ -369,7 +348,7 @@ int do_intthrow(cstack_T *cstack) // will be terminated then. - If an interrupt exception is already // being thrown, do nothing. - if (current_exception) { + if (did_throw) { if (current_exception->type == ET_INTERRUPT) { return false; } @@ -397,13 +376,13 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int * *should_free = true; mesg = ((msglist_T *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { - size_t cmdlen = STRLEN(cmdname); - ret = xstrnsave("Vim(", 4 + cmdlen + 2 + STRLEN(mesg)); + size_t cmdlen = strlen(cmdname); + ret = xstrnsave("Vim(", 4 + cmdlen + 2 + strlen(mesg)); STRCPY(&ret[4], cmdname); STRCPY(&ret[4 + cmdlen], "):"); val = ret + 4 + cmdlen + 2; } else { - ret = xstrnsave("Vim:", 4 + STRLEN(mesg)); + ret = xstrnsave("Vim:", 4 + strlen(mesg)); val = ret + 4; } @@ -431,7 +410,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int * STRCAT(val, p); p[-2] = NUL; - snprintf(val + STRLEN(p), strlen(" (%s)"), " (%s)", &mesg[1]); + snprintf(val + strlen(p), strlen(" (%s)"), " (%s)", &mesg[1]); p[-2] = '"'; } break; @@ -456,11 +435,9 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) except_T *excp; int should_free; - /* - * Disallow faking Interrupt or error exceptions as user exceptions. They - * would be treated differently from real interrupt or error exceptions - * when no active try block is found, see do_cmdline(). - */ + // Disallow faking Interrupt or error exceptions as user exceptions. They + // would be treated differently from real interrupt or error exceptions + // when no active try block is found, see do_cmdline(). if (type == ET_USER) { if (STRNCMP((char_u *)value, "Vim", 3) == 0 && (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' @@ -501,13 +478,13 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) int save_msg_silent = msg_silent; if (debug_break_level > 0) { - msg_silent = FALSE; // display messages + msg_silent = false; // display messages } else { verbose_enter(); } no_wait_return++; if (debug_break_level > 0 || *p_vfile == NUL) { - msg_scroll = TRUE; // always scroll up, don't overwrite + msg_scroll = true; // always scroll up, don't overwrite } smsg(_("Exception thrown: %s"), excp->value); msg_puts("\n"); // don't overwrite this either @@ -552,15 +529,15 @@ static void discard_exception(except_T *excp, bool was_finished) if (p_verbose >= 13 || debug_break_level > 0) { int save_msg_silent = msg_silent; - saved_IObuff = (char *)vim_strsave(IObuff); + saved_IObuff = xstrdup((char *)IObuff); if (debug_break_level > 0) { - msg_silent = FALSE; // display messages + msg_silent = false; // display messages } else { verbose_enter(); } no_wait_return++; if (debug_break_level > 0 || *p_vfile == NUL) { - msg_scroll = TRUE; // always scroll up, don't overwrite + msg_scroll = true; // always scroll up, don't overwrite } smsg(was_finished ? _("Exception finished: %s") : _("Exception discarded: %s"), @@ -596,6 +573,7 @@ void discard_current_exception(void) } // Note: all globals manipulated here should be saved/restored in // try_enter/try_leave. + did_throw = false; need_rethrow = false; } @@ -622,13 +600,13 @@ static void catch_exception(except_T *excp) int save_msg_silent = msg_silent; if (debug_break_level > 0) { - msg_silent = FALSE; // display messages + msg_silent = false; // display messages } else { verbose_enter(); } no_wait_return++; if (debug_break_level > 0 || *p_vfile == NUL) { - msg_scroll = TRUE; // always scroll up, don't overwrite + msg_scroll = true; // always scroll up, don't overwrite } smsg(_("Exception caught: %s"), excp->value); msg_puts("\n"); // don't overwrite this either @@ -678,9 +656,7 @@ static void finish_exception(except_T *excp) discard_exception(excp, true); } -/* - * Flags specifying the message displayed by report_pending. - */ +// Flags specifying the message displayed by report_pending. #define RP_MAKE 0 #define RP_RESUME 1 #define RP_DISCARD 2 @@ -726,14 +702,14 @@ static void report_pending(int action, int pending, void *value) break; case CSTP_RETURN: // ":return" command producing value, allocated - s = (char *)get_return_cmd(value); + s = get_return_cmd(value); break; default: if (pending & CSTP_THROW) { vim_snprintf((char *)IObuff, IOSIZE, mesg, _("Exception")); - mesg = (char *)concat_str(IObuff, (char_u *)": %s"); + mesg = concat_str((char *)IObuff, ": %s"); s = ((except_T *)value)->value; } else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT)) { s = _("Error and interrupt"); @@ -746,7 +722,7 @@ static void report_pending(int action, int pending, void *value) save_msg_silent = msg_silent; if (debug_break_level > 0) { - msg_silent = FALSE; // display messages + msg_silent = false; // display messages } no_wait_return++; msg_scroll = true; // always scroll up, don't overwrite @@ -830,7 +806,7 @@ void ex_if(exarg_T *eap) if (cstack->cs_idx == CSTACK_LEN - 1) { eap->errmsg = _("E579: :if nesting too deep"); } else { - ++cstack->cs_idx; + cstack->cs_idx++; cstack->cs_flags[cstack->cs_idx] = 0; skip = CHECK_SKIP; @@ -870,7 +846,7 @@ void ex_endif(exarg_T *eap) (void)do_intthrow(eap->cstack); } - --eap->cstack->cs_idx; + eap->cstack->cs_idx--; } } @@ -958,14 +934,12 @@ void ex_while(exarg_T *eap) if (cstack->cs_idx == CSTACK_LEN - 1) { eap->errmsg = _("E585: :while/:for nesting too deep"); } else { - /* - * The loop flag is set when we have jumped back from the matching - * ":endwhile" or ":endfor". When not set, need to initialise this - * cstack entry. - */ + // The loop flag is set when we have jumped back from the matching + // ":endwhile" or ":endfor". When not set, need to initialise this + // cstack entry. if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0) { - ++cstack->cs_idx; - ++cstack->cs_looplevel; + cstack->cs_idx++; + cstack->cs_looplevel++; cstack->cs_line[cstack->cs_idx] = -1; } cstack->cs_flags[cstack->cs_idx] = @@ -973,21 +947,17 @@ void ex_while(exarg_T *eap) skip = CHECK_SKIP; if (eap->cmdidx == CMD_while) { - /* - * ":while bool-expr" - */ + // ":while bool-expr" result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); } else { void *fi; - /* - * ":for var in list-expr" - */ + // ":for var in list-expr" if ((cstack->cs_lflags & CSL_HAD_LOOP) != 0) { // Jumping here from a ":continue" or ":endfor": use the // previously evaluated list. fi = cstack->cs_forinfo[cstack->cs_idx]; - error = FALSE; + error = false; } else { // Evaluate the argument and get the info in a structure. fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip); @@ -998,7 +968,7 @@ void ex_while(exarg_T *eap) if (!error && fi != NULL && !skip) { result = next_for_item(fi, eap->arg); } else { - result = FALSE; + result = false; } if (!result) { @@ -1007,11 +977,9 @@ void ex_while(exarg_T *eap) } } - /* - * If this cstack entry was just initialised and is active, set the - * loop flag, so do_cmdline() will set the line number in cs_line[]. - * If executing the command a second time, clear the loop flag. - */ + // If this cstack entry was just initialised and is active, set the + // loop flag, so do_cmdline() will set the line number in cs_line[]. + // If executing the command a second time, clear the loop flag. if (!skip && !error && result) { cstack->cs_flags[cstack->cs_idx] |= (CSF_ACTIVE | CSF_TRUE); cstack->cs_lflags ^= CSL_HAD_LOOP; @@ -1046,10 +1014,8 @@ void ex_continue(exarg_T *eap) if (cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)) { rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel); - /* - * Set CSL_HAD_CONT, so do_cmdline() will jump back to the - * matching ":while". - */ + // Set CSL_HAD_CONT, so do_cmdline() will jump back to the + // matching ":while". cstack->cs_lflags |= CSL_HAD_CONT; // let do_cmdline() handle it } else { // If a try conditional not in its finally clause is reached first, @@ -1118,7 +1084,7 @@ void ex_endwhile(exarg_T *eap) eap->errmsg = _(e_endtry); } // Try to find the matching ":while" and report what's missing. - for (idx = cstack->cs_idx; idx > 0; --idx) { + for (idx = cstack->cs_idx; idx > 0; idx--) { fl = cstack->cs_flags[idx]; if ((fl & CSF_TRY) && !(fl & CSF_FINALLY)) { // Give up at a try conditional not in its finally clause. @@ -1131,7 +1097,7 @@ void ex_endwhile(exarg_T *eap) } } // Cleanup and rewind all contained (and unclosed) conditionals. - (void)cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE); + (void)cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, false); rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel); } else if (cstack->cs_flags[cstack->cs_idx] & CSF_TRUE && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE) @@ -1147,10 +1113,8 @@ void ex_endwhile(exarg_T *eap) (void)do_intthrow(cstack); } - /* - * Set loop flag, so do_cmdline() will jump back to the matching - * ":while" or ":for". - */ + // Set loop flag, so do_cmdline() will jump back to the matching + // ":while" or ":for". cstack->cs_lflags |= CSL_HAD_ENDLOOP; } } @@ -1186,7 +1150,7 @@ void ex_throw(exarg_T *eap) void do_throw(cstack_T *cstack) { int idx; - int inactivate_try = FALSE; + int inactivate_try = false; // // Cleanup and deactivate up to the next surrounding try conditional that @@ -1199,31 +1163,29 @@ void do_throw(cstack_T *cstack) // #ifndef THROW_ON_ERROR_TRUE if (did_emsg && !THROW_ON_ERROR) { - inactivate_try = TRUE; - did_emsg = FALSE; + inactivate_try = true; + did_emsg = false; } #endif #ifndef THROW_ON_INTERRUPT_TRUE if (got_int && !THROW_ON_INTERRUPT) { - inactivate_try = TRUE; - got_int = FALSE; + inactivate_try = true; + got_int = false; } #endif idx = cleanup_conditionals(cstack, 0, inactivate_try); if (idx >= 0) { - /* - * If this try conditional is active and we are before its first - * ":catch", set THROWN so that the ":catch" commands will check - * whether the exception matches. When the exception came from any of - * the catch clauses, it will be made pending at the ":finally" (if - * present) and rethrown at the ":endtry". This will also happen if - * the try conditional is inactive. This is the case when we are - * throwing an exception due to an error or interrupt on the way from - * a preceding ":continue", ":break", ":return", ":finish", error or - * interrupt (not converted to an exception) to the finally clause or - * from a preceding throw of a user or error or interrupt exception to - * the matching catch clause or the finally clause. - */ + // If this try conditional is active and we are before its first + // ":catch", set THROWN so that the ":catch" commands will check + // whether the exception matches. When the exception came from any of + // the catch clauses, it will be made pending at the ":finally" (if + // present) and rethrown at the ":endtry". This will also happen if + // the try conditional is inactive. This is the case when we are + // throwing an exception due to an error or interrupt on the way from + // a preceding ":continue", ":break", ":return", ":finish", error or + // interrupt (not converted to an exception) to the finally clause or + // from a preceding throw of a user or error or interrupt exception to + // the matching catch clause or the finally clause. if (!(cstack->cs_flags[idx] & CSF_CAUGHT)) { if (cstack->cs_flags[idx] & CSF_ACTIVE) { cstack->cs_flags[idx] |= CSF_THROWN; @@ -1237,6 +1199,8 @@ void do_throw(cstack_T *cstack) cstack->cs_flags[idx] &= ~CSF_ACTIVE; cstack->cs_exception[idx] = current_exception; } + + did_throw = true; } /// Handle ":try" @@ -1248,8 +1212,8 @@ void ex_try(exarg_T *eap) if (cstack->cs_idx == CSTACK_LEN - 1) { eap->errmsg = _("E601: :try nesting too deep"); } else { - ++cstack->cs_idx; - ++cstack->cs_trylevel; + cstack->cs_idx++; + cstack->cs_trylevel++; cstack->cs_flags[cstack->cs_idx] = CSF_TRY; cstack->cs_pending[cstack->cs_idx] = CSTP_NONE; @@ -1261,22 +1225,20 @@ void ex_try(exarg_T *eap) // that the finally clause needs to be executed. cstack->cs_flags[cstack->cs_idx] |= CSF_ACTIVE | CSF_TRUE; - /* - * ":silent!", even when used in a try conditional, disables - * displaying of error messages and conversion of errors to - * exceptions. When the silent commands again open a try - * conditional, save "emsg_silent" and reset it so that errors are - * again converted to exceptions. The value is restored when that - * try conditional is left. If it is left normally, the commands - * following the ":endtry" are again silent. If it is left by - * a ":continue", ":break", ":return", or ":finish", the commands - * executed next are again silent. If it is left due to an - * aborting error, an interrupt, or an exception, restoring - * "emsg_silent" does not matter since we are already in the - * aborting state and/or the exception has already been thrown. - * The effect is then just freeing the memory that was allocated - * to save the value. - */ + // ":silent!", even when used in a try conditional, disables + // displaying of error messages and conversion of errors to + // exceptions. When the silent commands again open a try + // conditional, save "emsg_silent" and reset it so that errors are + // again converted to exceptions. The value is restored when that + // try conditional is left. If it is left normally, the commands + // following the ":endtry" are again silent. If it is left by + // a ":continue", ":break", ":return", or ":finish", the commands + // executed next are again silent. If it is left due to an + // aborting error, an interrupt, or an exception, restoring + // "emsg_silent" does not matter since we are already in the + // aborting state and/or the exception has already been thrown. + // The effect is then just freeing the memory that was allocated + // to save the value. if (emsg_silent) { eslist_T *elem = xmalloc(sizeof(*elem)); elem->saved_emsg_silent = emsg_silent; @@ -1314,7 +1276,7 @@ void ex_catch(exarg_T *eap) eap->errmsg = get_end_emsg(cstack); skip = true; } - for (idx = cstack->cs_idx; idx > 0; --idx) { + for (idx = cstack->cs_idx; idx > 0; idx--) { if (cstack->cs_flags[idx] & CSF_TRY) { break; } @@ -1333,27 +1295,23 @@ void ex_catch(exarg_T *eap) if (ends_excmd(*eap->arg)) { // no argument, catch all errors pat = ".*"; end = NULL; - eap->nextcmd = (char *)find_nextcmd((char_u *)eap->arg); + eap->nextcmd = find_nextcmd(eap->arg); } else { pat = eap->arg + 1; - end = (char *)skip_regexp((char_u *)pat, *eap->arg, true, NULL); + end = skip_regexp(pat, *eap->arg, true, NULL); } if (!give_up) { - /* - * Don't do something when no exception has been thrown or when the - * corresponding try block never got active (because of an inactive - * surrounding conditional or after an error or interrupt or throw). - */ - if (!current_exception || !(cstack->cs_flags[idx] & CSF_TRUE)) { + // Don't do something when no exception has been thrown or when the + // corresponding try block never got active (because of an inactive + // surrounding conditional or after an error or interrupt or throw). + if (!did_throw || !(cstack->cs_flags[idx] & CSF_TRUE)) { skip = true; } - /* - * Check for a match only if an exception is thrown but not caught by - * a previous ":catch". An exception that has replaced a discarded - * exception is not checked (THROWN is not set then). - */ + // Check for a match only if an exception is thrown but not caught by + // a previous ":catch". An exception that has replaced a discarded + // exception is not checked (THROWN is not set then). if (!skip && (cstack->cs_flags[idx] & CSF_THROWN) && !(cstack->cs_flags[idx] & CSF_CAUGHT)) { if (end != NULL && *end != NUL && !ends_excmd(*skipwhite(end + 1))) { @@ -1376,7 +1334,7 @@ void ex_catch(exarg_T *eap) *end = NUL; } save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; // Disable error messages, it will make current exception // invalid emsg_off++; @@ -1406,10 +1364,10 @@ void ex_catch(exarg_T *eap) } if (caught) { - // Make this ":catch" clause active and reset did_emsg and got_int. - // Put the exception on the caught stack. + // Make this ":catch" clause active and reset did_emsg, got_int, + // and did_throw. Put the exception on the caught stack. cstack->cs_flags[idx] |= CSF_ACTIVE | CSF_CAUGHT; - did_emsg = got_int = false; + did_emsg = got_int = did_throw = false; catch_exception((except_T *)cstack->cs_exception[idx]); // It's mandatory that the current exception is stored in the cstack // so that it can be discarded at the next ":catch", ":finally", or @@ -1419,27 +1377,21 @@ void ex_catch(exarg_T *eap) if (cstack->cs_exception[cstack->cs_idx] != current_exception) { internal_error("ex_catch()"); } - // Discarding current_exceptions happens based on what is stored in - // cstack->cs_exception, *all* calls to discard_current_exception() are - // (and must be) guarded by current_exception check. - current_exception = NULL; } else { - /* - * If there is a preceding catch clause and it caught the exception, - * finish the exception now. This happens also after errors except - * when this ":catch" was after the ":finally" or not within - * a ":try". Make the try conditional inactive so that the - * following catch clauses are skipped. On an error or interrupt - * after the preceding try block or catch clause was left by - * a ":continue", ":break", ":return", or ":finish", discard the - * pending action. - */ - cleanup_conditionals(cstack, CSF_TRY, TRUE); + // If there is a preceding catch clause and it caught the exception, + // finish the exception now. This happens also after errors except + // when this ":catch" was after the ":finally" or not within + // a ":try". Make the try conditional inactive so that the + // following catch clauses are skipped. On an error or interrupt + // after the preceding try block or catch clause was left by + // a ":continue", ":break", ":return", or ":finish", discard the + // pending action. + cleanup_conditionals(cstack, CSF_TRY, true); } } if (end != NULL) { - eap->nextcmd = (char *)find_nextcmd((char_u *)end); + eap->nextcmd = find_nextcmd(end); } } @@ -1447,7 +1399,7 @@ void ex_catch(exarg_T *eap) void ex_finally(exarg_T *eap) { int idx; - int skip = FALSE; + int skip = false; int pending = CSTP_NONE; cstack_T *const cstack = eap->cstack; @@ -1456,7 +1408,7 @@ void ex_finally(exarg_T *eap) } else { if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) { eap->errmsg = get_end_emsg(cstack); - for (idx = cstack->cs_idx - 1; idx > 0; --idx) { + for (idx = cstack->cs_idx - 1; idx > 0; idx--) { if (cstack->cs_flags[idx] & CSF_TRY) { break; } @@ -1477,14 +1429,12 @@ void ex_finally(exarg_T *eap) rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR, &cstack->cs_looplevel); - /* - * Don't do something when the corresponding try block never got active - * (because of an inactive surrounding conditional or after an error or - * interrupt or throw) or for a ":finally" without ":try" or a multiple - * ":finally". After every other error (did_emsg or the conditional - * errors detected above) or after an interrupt (got_int) or an - * exception (current_exception), the finally clause must be executed. - */ + // Don't do something when the corresponding try block never got active + // (because of an inactive surrounding conditional or after an error or + // interrupt or throw) or for a ":finally" without ":try" or a multiple + // ":finally". After every other error (did_emsg or the conditional + // errors detected above) or after an interrupt (got_int) or an + // exception (did_throw), the finally clause must be executed. skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); if (!skip) { @@ -1499,32 +1449,28 @@ void ex_finally(exarg_T *eap) (void)do_intthrow(cstack); } - /* - * If there is a preceding catch clause and it caught the exception, - * finish the exception now. This happens also after errors except - * when this is a multiple ":finally" or one not within a ":try". - * After an error or interrupt, this also discards a pending - * ":continue", ":break", ":finish", or ":return" from the preceding - * try block or catch clause. - */ - cleanup_conditionals(cstack, CSF_TRY, FALSE); - - /* - * Make did_emsg, got_int, current_exception pending. If set, they - * overrule a pending ":continue", ":break", ":return", or ":finish". - * Then we have particularly to discard a pending return value (as done - * by the call to cleanup_conditionals() above when did_emsg or - * got_int is set). The pending values are restored by the - * ":endtry", except if there is a new error, interrupt, exception, - * ":continue", ":break", ":return", or ":finish" in the following - * finally clause. A missing ":endwhile", ":endfor" or ":endif" - * detected here is treated as if did_emsg and current_exception had - * already been set, respectively in case that the error is not - * converted to an exception, current_exception had already been unset. - * We must not set did_emsg here since that would suppress the - * error message. - */ - if (pending == CSTP_ERROR || did_emsg || got_int || current_exception) { + // If there is a preceding catch clause and it caught the exception, + // finish the exception now. This happens also after errors except + // when this is a multiple ":finally" or one not within a ":try". + // After an error or interrupt, this also discards a pending + // ":continue", ":break", ":finish", or ":return" from the preceding + // try block or catch clause. + cleanup_conditionals(cstack, CSF_TRY, false); + + // Make did_emsg, got_int, did_throw pending. If set, they overrule + // a pending ":continue", ":break", ":return", or ":finish". Then + // we have particularly to discard a pending return value (as done + // by the call to cleanup_conditionals() above when did_emsg or + // got_int is set). The pending values are restored by the + // ":endtry", except if there is a new error, interrupt, exception, + // ":continue", ":break", ":return", or ":finish" in the following + // finally clause. A missing ":endwhile", ":endfor" or ":endif" + // detected here is treated as if did_emsg and did_throw had + // already been set, respectively in case that the error is not + // converted to an exception, did_throw had already been unset. + // We must not set did_emsg here since that would suppress the + // error message. + if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) { if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) { report_discard_pending(CSTP_RETURN, cstack->cs_rettv[cstack->cs_idx]); @@ -1533,7 +1479,7 @@ void ex_finally(exarg_T *eap) if (pending == CSTP_ERROR && !did_emsg) { pending |= (THROW_ON_ERROR ? CSTP_THROW : 0); } else { - pending |= (current_exception ? CSTP_THROW : 0); + pending |= (did_throw ? CSTP_THROW : 0); } pending |= did_emsg ? CSTP_ERROR : 0; pending |= got_int ? CSTP_INTERRUPT : 0; @@ -1547,19 +1493,16 @@ void ex_finally(exarg_T *eap) // exception. When emsg() is called for a missing ":endif" or // a missing ":endwhile"/":endfor" detected here, the // exception will be discarded. - if (current_exception - && cstack->cs_exception[cstack->cs_idx] != current_exception) { + if (did_throw && cstack->cs_exception[cstack->cs_idx] != current_exception) { internal_error("ex_finally()"); } } - /* - * Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg, - * got_int, and current_exception and make the finally clause active. - * This will happen after emsg() has been called for a missing - * ":endif" or a missing ":endwhile"/":endfor" detected here, so - * that the following finally clause will be executed even then. - */ + // Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg, + // got_int, and did_throw and make the finally clause active. + // This will happen after emsg() has been called for a missing + // ":endif" or a missing ":endwhile"/":endfor" detected here, so + // that the following finally clause will be executed even then. cstack->cs_lflags |= CSL_HAD_FINA; } } @@ -1587,8 +1530,7 @@ void ex_endtry(exarg_T *eap) // made inactive by a ":continue", ":break", ":return", or ":finish" in // the finally clause. The latter case need not be tested since then // anything pending has already been discarded. - bool skip = did_emsg || got_int || current_exception - || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); + bool skip = did_emsg || got_int || did_throw || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) { eap->errmsg = get_end_emsg(cstack); @@ -1602,14 +1544,12 @@ void ex_endtry(exarg_T *eap) &cstack->cs_looplevel); skip = true; - /* - * If an exception is being thrown, discard it to prevent it from - * being rethrown at the end of this function. It would be - * discarded by the error message, anyway. Resets current_exception. - * This does not affect the script termination due to the error - * since "trylevel" is decremented after emsg() has been called. - */ - if (current_exception) { + // If an exception is being thrown, discard it to prevent it from + // being rethrown at the end of this function. It would be + // discarded by the error message, anyway. Resets did_throw. + // This does not affect the script termination due to the error + // since "trylevel" is decremented after emsg() has been called. + if (did_throw) { discard_current_exception(); } @@ -1618,13 +1558,11 @@ void ex_endtry(exarg_T *eap) } else { idx = cstack->cs_idx; - /* - * If we stopped with the exception currently being thrown at this - * try conditional since we didn't know that it doesn't have - * a finally clause, we need to rethrow it after closing the try - * conditional. - */ - if (current_exception + // If we stopped with the exception currently being thrown at this + // try conditional since we didn't know that it doesn't have + // a finally clause, we need to rethrow it after closing the try + // conditional. + if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE) && !(cstack->cs_flags[idx] & CSF_FINALLY)) { rethrow = true; @@ -1648,21 +1586,19 @@ void ex_endtry(exarg_T *eap) if (got_int) { skip = true; (void)do_intthrow(cstack); - // The do_intthrow() call may have reset current_exception or + // The do_intthrow() call may have reset did_throw or // cstack->cs_pending[idx]. rethrow = false; - if (current_exception && !(cstack->cs_flags[idx] & CSF_FINALLY)) { + if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY)) { rethrow = true; } } } - /* - * If a ":return" is pending, we need to resume it after closing the - * try conditional; remember the return value. If there was a finally - * clause making an exception pending, we need to rethrow it. Make it - * the exception currently being thrown. - */ + // If a ":return" is pending, we need to resume it after closing the + // try conditional; remember the return value. If there was a finally + // clause making an exception pending, we need to rethrow it. Make it + // the exception currently being thrown. if (!skip) { pending = cstack->cs_pending[idx]; cstack->cs_pending[idx] = CSTP_NONE; @@ -1673,17 +1609,15 @@ void ex_endtry(exarg_T *eap) } } - /* - * Discard anything pending on an error, interrupt, or throw in the - * finally clause. If there was no ":finally", discard a pending - * ":continue", ":break", ":return", or ":finish" if an error or - * interrupt occurred afterwards, but before the ":endtry" was reached. - * If an exception was caught by the last of the catch clauses and there - * was no finally clause, finish the exception now. This happens also - * after errors except when this ":endtry" is not within a ":try". - * Restore "emsg_silent" if it has been reset by this try conditional. - */ - (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE); + // Discard anything pending on an error, interrupt, or throw in the + // finally clause. If there was no ":finally", discard a pending + // ":continue", ":break", ":return", or ":finish" if an error or + // interrupt occurred afterwards, but before the ":endtry" was reached. + // If an exception was caught by the last of the catch clauses and there + // was no finally clause, finish the exception now. This happens also + // after errors except when this ":endtry" is not within a ":try". + // Restore "emsg_silent" if it has been reset by this try conditional. + (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, true); if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) { cstack->cs_idx--; @@ -1712,16 +1646,16 @@ void ex_endtry(exarg_T *eap) ex_break(eap); break; case CSTP_RETURN: - do_return(eap, FALSE, FALSE, rettv); + do_return(eap, false, false, rettv); break; case CSTP_FINISH: - do_finish(eap, FALSE); + do_finish(eap, false); break; // When the finally clause was entered due to an error, // interrupt or throw (as opposed to a ":continue", ":break", // ":return", or ":finish"), restore the pending values of - // did_emsg, got_int, and current_exception. This is skipped, if there + // did_emsg, got_int, and did_throw. This is skipped, if there // was a new error, interrupt, throw, ":continue", ":break", // ":return", or ":finish". in the finally clause. default: @@ -1745,18 +1679,16 @@ void ex_endtry(exarg_T *eap) } } -/* - * enter_cleanup() and leave_cleanup() - * - * Functions to be called before/after invoking a sequence of autocommands for - * cleanup for a failed command. (Failure means here that a call to emsg() - * has been made, an interrupt occurred, or there is an uncaught exception - * from a previous autocommand execution of the same command.) - * - * Call enter_cleanup() with a pointer to a cleanup_T and pass the same - * pointer to leave_cleanup(). The cleanup_T structure stores the pending - * error/interrupt/exception state. - */ +// enter_cleanup() and leave_cleanup() +// +// Functions to be called before/after invoking a sequence of autocommands for +// cleanup for a failed command. (Failure means here that a call to emsg() +// has been made, an interrupt occurred, or there is an uncaught exception +// from a previous autocommand execution of the same command.) +// +// Call enter_cleanup() with a pointer to a cleanup_T and pass the same +// pointer to leave_cleanup(). The cleanup_T structure stores the pending +// error/interrupt/exception state. /// This function works a bit like ex_finally() except that there was not /// actually an extra try block around the part that failed and an error or @@ -1768,35 +1700,32 @@ void enter_cleanup(cleanup_T *csp) { int pending = CSTP_NONE; - /* - * Postpone did_emsg, got_int, current_exception. The pending values will be - * restored by leave_cleanup() except if there was an aborting error, - * interrupt, or uncaught exception after this function ends. - */ - if (did_emsg || got_int || current_exception || need_rethrow) { + // Postpone did_emsg, got_int, did_throw. The pending values will be + // restored by leave_cleanup() except if there was an aborting error, + // interrupt, or uncaught exception after this function ends. + if (did_emsg || got_int || did_throw || need_rethrow) { csp->pending = (did_emsg ? CSTP_ERROR : 0) | (got_int ? CSTP_INTERRUPT : 0) - | (current_exception ? CSTP_THROW : 0) + | (did_throw ? CSTP_THROW : 0) | (need_rethrow ? CSTP_THROW : 0); - // If we are currently throwing an exception, save it as well. On an error - // not yet converted to an exception, update "force_abort" and reset - // "cause_abort" (as do_errthrow() would do). This is needed for the - // do_cmdline() call that is going to be made for autocommand execution. We - // need not save *msg_list because there is an extra instance for every call - // of do_cmdline(), anyway. - if (current_exception || need_rethrow) { + // If we are currently throwing an exception (did_throw), save it as + // well. On an error not yet converted to an exception, update + // "force_abort" and reset "cause_abort" (as do_errthrow() would do). + // This is needed for the do_cmdline() call that is going to be made + // for autocommand execution. We need not save *msg_list because + // there is an extra instance for every call of do_cmdline(), anyway. + if (did_throw || need_rethrow) { csp->exception = current_exception; current_exception = NULL; } else { csp->exception = NULL; if (did_emsg) { force_abort |= cause_abort; - cause_abort = FALSE; + cause_abort = false; } } - did_emsg = got_int = need_rethrow = false; - current_exception = NULL; + did_emsg = got_int = did_throw = need_rethrow = false; // Report if required by the 'verbose' option or when debugging. report_make_pending(pending, csp->exception); @@ -1844,18 +1773,14 @@ void leave_cleanup(cleanup_T *csp) if (msg_list != NULL) { free_global_msglist(); } - } - /* - * If there was no new error, interrupt, or throw between the calls - * to enter_cleanup() and leave_cleanup(), restore the pending - * error/interrupt/exception state. - */ - else { - /* - * If there was an exception being thrown when enter_cleanup() was - * called, we need to rethrow it. Make it the exception currently - * being thrown. - */ + } else { + // If there was no new error, interrupt, or throw between the calls + // to enter_cleanup() and leave_cleanup(), restore the pending + // error/interrupt/exception state. + + // If there was an exception being thrown when enter_cleanup() was + // called, we need to rethrow it. Make it the exception currently + // being thrown. if (pending & CSTP_THROW) { current_exception = csp->exception; } else if (pending & CSTP_ERROR) { @@ -1863,10 +1788,10 @@ void leave_cleanup(cleanup_T *csp) // enter_cleanup() was called, let "cause_abort" take the part of // "force_abort" (as done by cause_errthrow()). cause_abort = force_abort; - force_abort = FALSE; + force_abort = false; } - // Restore the pending values of did_emsg, got_int, and current_exception. + // Restore the pending values of did_emsg, got_int, and did_throw. if (pending & CSTP_ERROR) { did_emsg = true; } @@ -1874,7 +1799,7 @@ void leave_cleanup(cleanup_T *csp) got_int = true; } if (pending & CSTP_THROW) { - need_rethrow = true; // current_exception will be set by do_one_cmd() + need_rethrow = true; // did_throw will be set by do_one_cmd() } // Report if required by the 'verbose' option or when debugging. @@ -1895,7 +1820,7 @@ void leave_cleanup(cleanup_T *csp) /// inactive itself (a try conditional not in its finally /// clause possibly find before is always made inactive). /// -/// If "inclusive" is TRUE and "searched_cond" is CSF_TRY|CSF_SILENT, the saved +/// If "inclusive" is true and "searched_cond" is CSF_TRY|CSF_SILENT, the saved /// former value of "emsg_silent", if reset when the try conditional finally /// reached was entered, is restored (used by ex_endtry()). This is normally /// done only when such a try conditional is left. @@ -1904,16 +1829,14 @@ void leave_cleanup(cleanup_T *csp) int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive) { int idx; - int stop = FALSE; + int stop = false; - for (idx = cstack->cs_idx; idx >= 0; --idx) { + for (idx = cstack->cs_idx; idx >= 0; idx--) { if (cstack->cs_flags[idx] & CSF_TRY) { - /* - * Discard anything pending in a finally clause and continue the - * search. There may also be a pending ":continue", ":break", - * ":return", or ":finish" before the finally clause. We must not - * discard it, unless an error or interrupt occurred afterwards. - */ + // Discard anything pending in a finally clause and continue the + // search. There may also be a pending ":continue", ":break", + // ":return", or ":finish" before the finally clause. We must not + // discard it, unless an error or interrupt occurred afterwards. if (did_emsg || got_int || (cstack->cs_flags[idx] & CSF_FINALLY)) { switch (cstack->cs_pending[idx]) { case CSTP_NONE: @@ -1949,11 +1872,9 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive) } } - /* - * Stop at a try conditional not in its finally clause. If this try - * conditional is in an active catch clause, finish the caught - * exception. - */ + // Stop at a try conditional not in its finally clause. If this try + // conditional is in an active catch clause, finish the caught + // exception. if (!(cstack->cs_flags[idx] & CSF_FINALLY)) { if ((cstack->cs_flags[idx] & CSF_ACTIVE) && (cstack->cs_flags[idx] & CSF_CAUGHT) && !(cstack->cs_flags[idx] & CSF_FINISHED)) { @@ -1968,31 +1889,29 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive) if (searched_cond == 0 && !inclusive) { break; } - stop = TRUE; + stop = true; } } } // Stop on the searched conditional type (even when the surrounding // conditional is not active or something has been made pending). - // If "inclusive" is TRUE and "searched_cond" is CSF_TRY|CSF_SILENT, + // If "inclusive" is true and "searched_cond" is CSF_TRY|CSF_SILENT, // check first whether "emsg_silent" needs to be restored. if (cstack->cs_flags[idx] & searched_cond) { if (!inclusive) { break; } - stop = TRUE; + stop = true; } cstack->cs_flags[idx] &= ~CSF_ACTIVE; if (stop && searched_cond != (CSF_TRY | CSF_SILENT)) { break; } - /* - * When leaving a try conditional that reset "emsg_silent" on its - * entry after saving the original value, restore that value here and - * free the memory used to store it. - */ + // When leaving a try conditional that reset "emsg_silent" on its + // entry after saving the original value, restore that value here and + // free the memory used to store it. if ((cstack->cs_flags[idx] & CSF_TRY) && (cstack->cs_flags[idx] & CSF_SILENT)) { eslist_T *elem; @@ -2036,7 +1955,7 @@ void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_lev if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) { free_for_info(cstack->cs_forinfo[cstack->cs_idx]); } - --cstack->cs_idx; + cstack->cs_idx--; } } @@ -2046,7 +1965,7 @@ void ex_endfunction(exarg_T *eap) emsg(_("E193: :endfunction not inside a function")); } -/// @return TRUE if the string "p" looks like a ":while" or ":for" command. +/// @return true if the string "p" looks like a ":while" or ":for" command. int has_loop_cmd(char *p) { int len; @@ -2064,7 +1983,7 @@ int has_loop_cmd(char *p) } if ((p[0] == 'w' && p[1] == 'h') || (p[0] == 'f' && p[1] == 'o' && p[2] == 'r')) { - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a0bcccb5be..031226c5a1 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * ex_getln.c: Functions for entering and editing an Ex command line. - */ +// ex_getln.c: Functions for entering and editing an Ex command line. #include <assert.h> #include <inttypes.h> @@ -11,6 +9,7 @@ #include <stdlib.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/api/extmark.h" #include "nvim/api/vim.h" #include "nvim/arabic.h" @@ -42,7 +41,6 @@ #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/keycodes.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/mapping.h" @@ -105,9 +103,9 @@ typedef struct command_line_state { long count; int indent; int c; - int gotesc; // TRUE when <ESC> just typed - int do_abbr; // when TRUE check for abbr. - char_u *lookfor; // string to match + int gotesc; // true when <ESC> just typed + int do_abbr; // when true check for abbr. + char *lookfor; // string to match int hiscnt; // current history line in use int save_hiscnt; // history line before attempting // to jump to next match @@ -118,7 +116,7 @@ typedef struct command_line_state { int res; int save_msg_scroll; int save_State; // remember State when called - char_u *save_p_icm; + char *save_p_icm; int some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are // preceded with a mouse down event @@ -138,6 +136,7 @@ typedef struct cmdpreview_win_info { typedef struct cmdpreview_buf_info { buf_T *buf; + bool save_b_u_synced; time_t save_b_u_time_cur; long save_b_u_seq_cur; u_header_T *save_b_u_newhead; @@ -170,6 +169,8 @@ static Array cmdline_block = ARRAY_DICT_INIT; /// user interrupting highlight function to not interrupt command-line. static bool getln_interrupted_highlight = false; +static int cedit_key = -1; ///< key value of 'cedit' option + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_getln.c.generated.h" #endif @@ -253,7 +254,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s exarg_T ea = { .line1 = 1, .line2 = 1, - .cmd = (char *)ccline.cmdbuff, + .cmd = ccline.cmdbuff, .addr_type = ADDR_LINES, }; @@ -313,7 +314,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s p = skipwhite(p); delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++; *search_delim = delim; - end = (char *)skip_regexp((char_u *)p, delim, p_magic, NULL); + end = skip_regexp(p, delim, p_magic, NULL); use_last_pat = end == p && *end == delim; if (end == p && !use_last_pat) { @@ -326,7 +327,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s int empty; *end = NUL; - empty = empty_pattern((char_u *)p); + empty = empty_pattern(p); *end = c; if (empty) { goto theend; @@ -334,7 +335,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s } // found a non-empty pattern or // - *skiplen = (int)((char_u *)p - ccline.cmdbuff); + *skiplen = (int)(p - ccline.cmdbuff); *patlen = (int)(end - p); // parse the address range @@ -407,7 +408,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat int found; // do_search() result // Use the previous pattern for ":s//". - next_char = ccline.cmdbuff[skiplen + patlen]; + next_char = (char_u)ccline.cmdbuff[skiplen + patlen]; use_last_pat = patlen == 0 && skiplen > 0 && ccline.cmdbuff[skiplen - 1] == next_char; @@ -415,7 +416,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat if (patlen == 0 && !use_last_pat) { found = 0; set_no_hlsearch(true); // turn off previous highlight - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } else { int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK; ui_busy_start(); @@ -434,9 +435,9 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat .sa_tm = &tm, }; found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, - ccline.cmdbuff + skiplen, count, + (char_u *)ccline.cmdbuff + skiplen, count, search_flags, &sia); - ccline.cmdbuff[skiplen + patlen] = next_char; + ccline.cmdbuff[skiplen + patlen] = (char)next_char; emsg_off--; if (curwin->w_cursor.lnum < search_first_line || curwin->w_cursor.lnum > search_last_line) { @@ -485,13 +486,13 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat // Disable 'hlsearch' highlighting if the pattern matches // everything. Avoids a flash when typing "foo\|". if (!use_last_pat) { - next_char = ccline.cmdbuff[skiplen + patlen]; + next_char = (char_u)ccline.cmdbuff[skiplen + patlen]; ccline.cmdbuff[skiplen + patlen] = NUL; if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) { - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); set_no_hlsearch(true); } - ccline.cmdbuff[skiplen + patlen] = next_char; + ccline.cmdbuff[skiplen + patlen] = (char)next_char; } validate_cursor(); @@ -500,7 +501,8 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat curwin->w_redr_status = true; } - update_screen(SOME_VALID); + redraw_later(curwin, UPD_SOME_VALID); + update_screen(); highlight_match = false; restore_last_search_pattern(); @@ -546,7 +548,7 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s) // command line has no uppercase characters, convert // the character to lowercase if (p_ic && p_scs - && !pat_has_uppercase(ccline.cmdbuff + skiplen)) { + && !pat_has_uppercase((char_u *)ccline.cmdbuff + skiplen)) { *c = mb_tolower(*c); } if (*c == search_delim @@ -585,9 +587,9 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool p_magic = s->magic_save; validate_cursor(); // needed for TAB - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); if (call_update_screen) { - update_screen(SOME_VALID); + update_screen(); } } } @@ -599,24 +601,6 @@ 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) { - const bool cmdheight0 = !ui_has_messages(); - - if (cmdheight0) { - 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 static int cmdline_level = 0; cmdline_level++; @@ -632,7 +616,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init .ignore_drag_release = true, }; CommandLineState *s = &state; - s->save_p_icm = vim_strsave(p_icm); + s->save_p_icm = xstrdup(p_icm); init_incsearch_state(&s->is_state); CmdlineInfo save_ccline; bool did_save_ccline = false; @@ -722,7 +706,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init if (ccline.input_fn) { s->xpc.xp_context = ccline.xp_context; - s->xpc.xp_pattern = (char *)ccline.cmdbuff; + s->xpc.xp_pattern = ccline.cmdbuff; s->xpc.xp_arg = (char *)ccline.xp_arg; } @@ -791,11 +775,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init // Redraw the statusline in case it uses the current mode using the mode() // function. - if (!cmd_silent && msg_scrolled == 0) { + if (!cmd_silent) { bool found_one = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (*p_stl != NUL || *wp->w_p_stl != NUL) { + if (*p_stl != NUL || *wp->w_p_stl != NUL || *p_wbr != NUL || *wp->w_p_wbr != NUL) { wp->w_redr_status = true; found_one = true; } @@ -852,7 +836,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init s->histype == HIST_SEARCH ? s->firstc : NUL); if (s->firstc == ':') { xfree(new_last_cmdline); - new_last_cmdline = vim_strsave(ccline.cmdbuff); + new_last_cmdline = xstrdup(ccline.cmdbuff); } } @@ -865,12 +849,18 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init // If the line is too long, clear it, so ruler and shown command do // not get printed in the middle of it. msg_check(); + if (p_ch == 0 && !ui_has(kUIMessages)) { + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; + } + } msg_scroll = s->save_msg_scroll; redir_off = false; if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); - msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg); + semsg(e_autocmd_err, err.msg); + did_emsg = false; api_clear_error(&err); } @@ -879,11 +869,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init need_wait_return = false; } - set_string_option_direct("icm", -1, (char *)s->save_p_icm, OPT_FREE, SID_NONE); + set_string_option_direct("icm", -1, s->save_p_icm, OPT_FREE, SID_NONE); State = s->save_State; if (cmdpreview != save_cmdpreview) { cmdpreview = save_cmdpreview; // restore preview state - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } may_trigger_modechanged(); setmouse(); @@ -895,7 +885,7 @@ theend: xfree(ccline.last_colors.cmdbuff); kv_destroy(ccline.last_colors.colors); - char_u *p = ccline.cmdbuff; + char_u *p = (char_u *)ccline.cmdbuff; if (ui_has(kUICmdline)) { ui_call_cmdline_hide(ccline.level); @@ -910,17 +900,6 @@ theend: ccline.cmdbuff = NULL; } - 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; } @@ -1087,7 +1066,7 @@ static int command_line_execute(VimState *state, int key) s->c = get_expr_register(); if (s->c == '=') { textlock++; - p = get_expr_line(); + p = (char_u *)get_expr_line(); textlock--; if (p != NULL) { @@ -1260,7 +1239,7 @@ static int command_line_execute(VimState *state, int key) } if (s->wim_index < 3) { - ++s->wim_index; + s->wim_index++; } if (s->c == ESC) { @@ -1277,8 +1256,11 @@ static int command_line_execute(VimState *state, int key) // <S-Tab> goes to last match, in a clumsy way if (s->c == K_S_TAB && KeyTyped) { if (nextwild(&s->xpc, WILD_EXPAND_KEEP, 0, s->firstc != '@') == OK) { - // Trigger the popup menu when wildoptions=pum - showmatches(&s->xpc, p_wmnu && ((wim_flags[s->wim_index] & WIM_LIST) == 0)); + if (s->xpc.xp_numfiles > 1 + && ((!s->did_wild_list && (wim_flags[s->wim_index] & WIM_LIST)) || p_wmnu)) { + // Trigger the popup menu when wildoptions=pum + showmatches(&s->xpc, p_wmnu && ((wim_flags[s->wim_index] & WIM_LIST) == 0)); + } nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@'); nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@'); return command_line_changed(s); @@ -1334,7 +1316,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ skiplen = 0; patlen = (int)STRLEN(pat); } else { - pat = ccline.cmdbuff + skiplen; + pat = (char_u *)ccline.cmdbuff + skiplen; } if (next_match) { @@ -1395,7 +1377,8 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ validate_cursor(); highlight_match = true; save_viewstate(curwin, &s->old_viewstate); - update_screen(NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); + update_screen(); highlight_match = false; redrawcmdline(); curwin->w_cursor = s->match_end; @@ -1408,7 +1391,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ static void command_line_next_histidx(CommandLineState *s, bool next_match) { - int j = (int)STRLEN(s->lookfor); + int j = (int)strlen(s->lookfor); for (;;) { // one step backwards if (!next_match) { @@ -1474,28 +1457,28 @@ static int command_line_handle_key(CommandLineState *s) // delete current character is the same as backspace on next // character, except at end of line if (s->c == K_DEL && ccline.cmdpos != ccline.cmdlen) { - ++ccline.cmdpos; + ccline.cmdpos++; } if (s->c == K_DEL) { - ccline.cmdpos += mb_off_next(ccline.cmdbuff, - ccline.cmdbuff + ccline.cmdpos); + ccline.cmdpos += mb_off_next((char_u *)ccline.cmdbuff, + (char_u *)ccline.cmdbuff + ccline.cmdpos); } if (ccline.cmdpos > 0) { char_u *p; int j = ccline.cmdpos; - p = mb_prevptr(ccline.cmdbuff, ccline.cmdbuff + j); + p = mb_prevptr((char_u *)ccline.cmdbuff, (char_u *)ccline.cmdbuff + j); if (s->c == Ctrl_W) { - while (p > ccline.cmdbuff && ascii_isspace(*p)) { - p = mb_prevptr(ccline.cmdbuff, p); + while (p > (char_u *)ccline.cmdbuff && ascii_isspace(*p)) { + p = mb_prevptr((char_u *)ccline.cmdbuff, p); } int i = mb_get_class(p); - while (p > ccline.cmdbuff && mb_get_class(p) == i) { - p = mb_prevptr(ccline.cmdbuff, p); + while (p > (char_u *)ccline.cmdbuff && mb_get_class(p) == i) { + p = mb_prevptr((char_u *)ccline.cmdbuff, p); } if (mb_get_class(p) != i) { @@ -1503,7 +1486,7 @@ static int command_line_handle_key(CommandLineState *s) } } - ccline.cmdpos = (int)(p - ccline.cmdbuff); + ccline.cmdpos = (int)(p - (char_u *)ccline.cmdbuff); ccline.cmdlen -= j - ccline.cmdpos; int i = ccline.cmdpos; @@ -1683,7 +1666,7 @@ static int command_line_handle_key(CommandLineState *s) } ccline.cmdspos += cells; - ccline.cmdpos += utfc_ptr2len((char *)ccline.cmdbuff + ccline.cmdpos); + ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos); } while ((s->c == K_S_RIGHT || s->c == K_C_RIGHT || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))) && ccline.cmdbuff[ccline.cmdpos] != ' '); @@ -1756,7 +1739,7 @@ static int command_line_handle_key(CommandLineState *s) // Count ">" for double-wide char that doesn't fit. correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos); - ccline.cmdpos += utfc_ptr2len((char *)ccline.cmdbuff + ccline.cmdpos) - 1; + ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1; ccline.cmdspos += cells; } return command_line_not_changed(s); @@ -1798,13 +1781,17 @@ static int command_line_handle_key(CommandLineState *s) return command_line_not_changed(s); case Ctrl_A: // all matches - if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) { - break; - } if (cmdline_pum_active()) { + // As Ctrl-A completes all the matches, close the popup + // menu (if present) cmdline_pum_cleanup(&ccline); - s->xpc.xp_context = EXPAND_NOTHING; } + + if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) { + break; + } + s->xpc.xp_context = EXPAND_NOTHING; + s->did_wild_list = false; return command_line_changed(s); case Ctrl_L: @@ -1846,7 +1833,7 @@ static int command_line_handle_key(CommandLineState *s) // save current command string so it can be restored later if (s->lookfor == NULL) { - s->lookfor = vim_strsave(ccline.cmdbuff); + s->lookfor = xstrdup(ccline.cmdbuff); s->lookfor[ccline.cmdpos] = NUL; } @@ -1863,13 +1850,13 @@ static int command_line_handle_key(CommandLineState *s) XFREE_CLEAR(ccline.cmdbuff); s->xpc.xp_context = EXPAND_NOTHING; if (s->hiscnt == get_hislen()) { - p = s->lookfor; // back to the old one + p = (char_u *)s->lookfor; // back to the old one } else { - p = get_histentry(s->histype)[s->hiscnt].hisstr; + p = (char_u *)get_histentry(s->histype)[s->hiscnt].hisstr; } if (s->histype == HIST_SEARCH - && p != s->lookfor + && p != (char_u *)s->lookfor && (old_firstc = p[STRLEN(p) + 1]) != s->firstc) { // Correct for the separator character used when // adding the history entry vs the one used now. @@ -1883,7 +1870,7 @@ static int command_line_handle_key(CommandLineState *s) if (p[j] == old_firstc && (j == 0 || p[j - 1] != '\\')) { if (i > 0) { - ccline.cmdbuff[len] = (char_u)s->firstc; + ccline.cmdbuff[len] = (char)s->firstc; } } else { // Escape new sep, unless it is already @@ -1897,7 +1884,7 @@ static int command_line_handle_key(CommandLineState *s) } if (i > 0) { - ccline.cmdbuff[len] = p[j]; + ccline.cmdbuff[len] = (char)p[j]; } } len++; @@ -1913,7 +1900,7 @@ static int command_line_handle_key(CommandLineState *s) STRCPY(ccline.cmdbuff, p); } - ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); + ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff); redrawcmd(); return command_line_changed(s); } @@ -1998,7 +1985,7 @@ static int command_line_handle_key(CommandLineState *s) } else { int j = utf_char2bytes(s->c, (char *)IObuff); IObuff[j] = NUL; // exclude composing chars - put_on_cmdline(IObuff, j, true); + put_on_cmdline((char_u *)IObuff, j, true); } return command_line_changed(s); } @@ -2018,9 +2005,9 @@ static int command_line_not_changed(CommandLineState *s) /// Guess that the pattern matches everything. Only finds specific cases, such /// as a trailing \|, which can happen while typing a pattern. -static int empty_pattern(char_u *p) +static int empty_pattern(char *p) { - size_t n = STRLEN(p); + size_t n = strlen(p); // remove trailing \v and the like while (n >= 2 && p[n - 2] == '\\' @@ -2147,6 +2134,7 @@ static void cmdpreview_prepare(CpInfo *cpinfo) CpBufInfo cp_bufinfo; cp_bufinfo.buf = buf; + cp_bufinfo.save_b_u_synced = buf->b_u_synced; cp_bufinfo.save_b_u_time_cur = buf->b_u_time_cur; cp_bufinfo.save_b_u_seq_cur = buf->b_u_seq_cur; cp_bufinfo.save_b_u_newhead = buf->b_u_newhead; @@ -2184,6 +2172,8 @@ static void cmdpreview_prepare(CpInfo *cpinfo) cmdmod.cmod_split = 0; // Disable :leftabove/botright modifiers cmdmod.cmod_tab = 0; // Disable :tab modifier cmdmod.cmod_flags |= CMOD_NOSWAPFILE; // Disable swap for preview buffer + + u_sync(true); } // Restore the state of buffers and windows before command preview. @@ -2206,7 +2196,7 @@ static void cmdpreview_restore_state(CpInfo *cpinfo) aco_save_T aco; aucmd_prepbuf(&aco, buf); // Undo invisibly. This also moves the cursor! - if (!u_undo_and_forget(count)) { + if (!u_undo_and_forget(count, false)) { abort(); } aucmd_restbuf(&aco); @@ -2216,6 +2206,11 @@ static void cmdpreview_restore_state(CpInfo *cpinfo) buf->b_u_newhead = cp_bufinfo.save_b_u_newhead; buf->b_u_time_cur = cp_bufinfo.save_b_u_time_cur; } + + if (buf->b_u_curhead == NULL) { + buf->b_u_synced = cp_bufinfo.save_b_u_synced; + } + if (cp_bufinfo.save_changedtick != buf_get_changedtick(buf)) { buf_set_changedtick(buf, cp_bufinfo.save_changedtick); } @@ -2272,7 +2267,7 @@ static bool cmdpreview_may_show(CommandLineState *s) CmdParseInfo cmdinfo; // Copy the command line so we can modify it. int cmdpreview_type = 0; - char *cmdline = xstrdup((char *)ccline.cmdbuff); + char *cmdline = xstrdup(ccline.cmdbuff); char *errormsg = NULL; emsg_off++; // Block errors when parsing the command line, and don't update v:errmsg if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) { @@ -2343,7 +2338,7 @@ static bool cmdpreview_may_show(CommandLineState *s) if (cmdpreview_type != 0) { int save_rd = RedrawingDisabled; RedrawingDisabled = 0; - update_screen(SOME_VALID); + update_screen(); RedrawingDisabled = save_rd; } @@ -2364,9 +2359,9 @@ end: return cmdpreview_type != 0; } -static int command_line_changed(CommandLineState *s) +/// Trigger CmdlineChanged autocommands. +static void do_autocmd_cmdlinechanged(int firstc) { - // Trigger CmdlineChanged autocommands. if (has_event(EVENT_CMDLINECHANGED)) { TryState tstate; Error err = ERROR_INIT; @@ -2374,7 +2369,7 @@ static int command_line_changed(CommandLineState *s) dict_T *dict = get_v_event(&save_v_event); char firstcbuf[2]; - firstcbuf[0] = (char)(s->firstc > 0 ? s->firstc : '-'); + firstcbuf[0] = (char)firstc; firstcbuf[1] = 0; // set v:event to a dictionary with information about the commandline @@ -2394,7 +2389,14 @@ static int command_line_changed(CommandLineState *s) redrawcmd(); } } +} +static int command_line_changed(CommandLineState *s) +{ + // Trigger CmdlineChanged autocommands. + do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-'); + + const bool prev_cmdpreview = cmdpreview; if (s->firstc == ':' && current_sctx.sc_sid == 0 // only if interactive && *p_icm != NUL // 'inccommand' is set @@ -2403,10 +2405,13 @@ static int command_line_changed(CommandLineState *s) && !vpeekc_any() && cmdpreview_may_show(s)) { // 'inccommand' preview has been shown. - } else if (cmdpreview) { - cmdpreview = false; - update_screen(SOME_VALID); // Clear 'inccommand' preview. } else { + cmdpreview = false; + if (prev_cmdpreview) { + // TODO(bfredl): add an immediate redraw flag for cmdline mode which will trigger + // at next wait-for-input + update_screen(); // Clear 'inccommand' preview. + } if (s->xpc.xp_context == EXPAND_NOTHING && (KeyTyped || vpeekc() == NUL)) { may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state); } @@ -2526,6 +2531,58 @@ char_u *get_cmdprompt(void) return ccline.cmdprompt; } +/// Read the 'wildmode' option, fill wim_flags[]. +int check_opt_wim(void) +{ + char_u new_wim_flags[4]; + int i; + int idx = 0; + + for (i = 0; i < 4; i++) { + new_wim_flags[i] = 0; + } + + for (char *p = p_wim; *p; p++) { + for (i = 0; ASCII_ISALPHA(p[i]); i++) {} + if (p[i] != NUL && p[i] != ',' && p[i] != ':') { + return FAIL; + } + if (i == 7 && STRNCMP(p, "longest", 7) == 0) { + new_wim_flags[idx] |= WIM_LONGEST; + } else if (i == 4 && STRNCMP(p, "full", 4) == 0) { + new_wim_flags[idx] |= WIM_FULL; + } else if (i == 4 && STRNCMP(p, "list", 4) == 0) { + new_wim_flags[idx] |= WIM_LIST; + } else if (i == 8 && STRNCMP(p, "lastused", 8) == 0) { + new_wim_flags[idx] |= WIM_BUFLASTUSED; + } else { + return FAIL; + } + p += i; + if (*p == NUL) { + break; + } + if (*p == ',') { + if (idx == 3) { + return FAIL; + } + idx++; + } + } + + // fill remaining entries with last flag + while (idx < 3) { + new_wim_flags[idx + 1] = new_wim_flags[idx]; + idx++; + } + + // only when there are no errors, wim_flags[] is changed + for (i = 0; i < 4; i++) { + wim_flags[i] = new_wim_flags[i]; + } + return OK; +} + /// Return true when the text must not be changed and we can't switch to /// another window or buffer. True when editing the command line etc. bool text_locked(void) @@ -2536,10 +2593,8 @@ bool text_locked(void) return textlock != 0; } -/* - * Give an error message for a command that isn't allowed while the cmdline - * window is open or editing the cmdline in another way. - */ +// Give an error message for a command that isn't allowed while the cmdline +// window is open or editing the cmdline in another way. void text_locked_msg(void) { emsg(_(get_text_locked_msg())); @@ -2592,7 +2647,7 @@ static int cmdline_charsize(int idx) if (cmdline_star > 0) { // showing '*', always 1 position return 1; } - return ptr2cells((char *)ccline.cmdbuff + idx); + return ptr2cells(ccline.cmdbuff + idx); } /// Compute the offset of the cursor on the command line for the prompt and @@ -2618,7 +2673,7 @@ int cmd_screencol(int bytepos) } for (int i = 0; i < ccline.cmdlen && i < bytepos; - i += utfc_ptr2len((char *)ccline.cmdbuff + i)) { + i += utfc_ptr2len(ccline.cmdbuff + i)) { int c = cmdline_charsize(i); // Count ">" for double-wide multi-byte char that doesn't fit. correct_screencol(i, c, &col); @@ -2637,8 +2692,8 @@ int cmd_screencol(int bytepos) /// character that doesn't fit, so that a ">" must be displayed. static void correct_screencol(int idx, int cells, int *col) { - if (utfc_ptr2len((char *)ccline.cmdbuff + idx) > 1 - && utf_ptr2cells((char *)ccline.cmdbuff + idx) > 1 + if (utfc_ptr2len(ccline.cmdbuff + idx) > 1 + && utf_ptr2cells(ccline.cmdbuff + idx) > 1 && (*col) % Columns + cells > Columns) { (*col)++; } @@ -2671,15 +2726,11 @@ bool cmdline_at_end(void) return (ccline.cmdpos >= ccline.cmdlen); } -/* - * Allocate a new command line buffer. - * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. - */ +// Allocate a new command line buffer. +// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. static void alloc_cmdbuff(int len) { - /* - * give some extra space to avoid having to allocate all the time - */ + // give some extra space to avoid having to allocate all the time if (len < 80) { len = 100; } else { @@ -2697,7 +2748,7 @@ void realloc_cmdbuff(int len) return; // no need to resize } - char_u *p = ccline.cmdbuff; + char_u *p = (char_u *)ccline.cmdbuff; alloc_cmdbuff(len); // will get some more // There isn't always a NUL after the command, but it may need to be // there, thus copy up to the NUL and add a NUL. @@ -2714,7 +2765,7 @@ void realloc_cmdbuff(int len) // If xp_pattern points inside the old cmdbuff it needs to be adjusted // to point into the newly allocated memory. if (i >= 0 && i <= ccline.cmdlen) { - ccline.xpc->xp_pattern = (char *)ccline.cmdbuff + i; + ccline.xpc->xp_pattern = ccline.cmdbuff + i; } } } @@ -2744,7 +2795,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, ParserLine parser_lines[] = { { .data = (const char *)colored_ccline->cmdbuff, - .size = STRLEN(colored_ccline->cmdbuff), + .size = strlen(colored_ccline->cmdbuff), .allocated = false, }, { NULL, 0, false }, @@ -2822,7 +2873,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) // Check whether result of the previous call is still valid. if (ccline_colors->prompt_id == colored_ccline->prompt_id && ccline_colors->cmdbuff != NULL - && STRCMP(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { + && strcmp(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) { return ret; } @@ -2837,7 +2888,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) bool arg_allocated = false; typval_T arg = { .v_type = VAR_STRING, - .vval.v_string = (char *)colored_ccline->cmdbuff, + .vval.v_string = colored_ccline->cmdbuff, }; typval_T tv = { .v_type = VAR_UNKNOWN }; @@ -3021,10 +3072,8 @@ color_cmdline_error: #undef PRINT_ERRMSG } -/* - * Draw part of the cmdline at the current cursor position. But draw stars - * when cmdline_star is TRUE. - */ +// Draw part of the cmdline at the current cursor position. But draw stars +// when cmdline_star is true. static void draw_cmdline(int start, int len) { if (!color_cmdline(&ccline)) { @@ -3040,16 +3089,16 @@ static void draw_cmdline(int start, int len) if (cmdline_star > 0) { for (int i = 0; i < len; i++) { msg_putchar('*'); - i += utfc_ptr2len((char *)ccline.cmdbuff + start + i) - 1; + i += utfc_ptr2len(ccline.cmdbuff + start + i) - 1; } } else if (p_arshape && !p_tbidi && len > 0) { bool do_arabicshape = false; int mb_l; for (int i = start; i < start + len; i += mb_l) { - char_u *p = ccline.cmdbuff + i; + char_u *p = (char_u *)ccline.cmdbuff + i; int u8cc[MAX_MCO]; int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len(p, start + len - i); + mb_l = utfc_ptr2len_len((char *)p, start + len - i); if (ARABIC_CHAR(u8c)) { do_arabicshape = true; break; @@ -3073,7 +3122,7 @@ static void draw_cmdline(int start, int len) } int newlen = 0; - if (utf_iscomposing(utf_ptr2char((char *)ccline.cmdbuff + start))) { + if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start))) { // Prepend a space to draw the leading composing char on. arshape_buf[0] = ' '; newlen = 1; @@ -3082,10 +3131,10 @@ static void draw_cmdline(int start, int len) int prev_c = 0; int prev_c1 = 0; for (int i = start; i < start + len; i += mb_l) { - char_u *p = ccline.cmdbuff + i; + char_u *p = (char_u *)ccline.cmdbuff + i; int u8cc[MAX_MCO]; int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len(p, start + len - i); + mb_l = utfc_ptr2len_len((char *)p, start + len - i); if (ARABIC_CHAR(u8c)) { int pc; int pc1 = 0; @@ -3131,7 +3180,7 @@ static void draw_cmdline(int start, int len) } } - msg_outtrans_len((char_u *)arshape_buf, newlen); + msg_outtrans_len(arshape_buf, newlen); } else { draw_cmdline_no_arabicshape: if (kv_size(ccline.last_colors.colors)) { @@ -3154,12 +3203,11 @@ draw_cmdline_no_arabicshape: static void ui_ext_cmdline_show(CmdlineInfo *line) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array content; if (cmdline_star) { content = arena_array(&arena, 1); size_t len = 0; - for (char_u *p = ccline.cmdbuff; *p; MB_PTR_ADV(p)) { + for (char_u *p = (char_u *)ccline.cmdbuff; *p; MB_PTR_ADV(p)) { len++; } char *buf = arena_alloc(&arena, len, false); @@ -3199,7 +3247,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) line->special_shift, line->level); } - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } void ui_ext_cmdline_block_append(size_t indent, const char *line) @@ -3276,11 +3324,9 @@ void cmdline_ui_flush(void) } } -/* - * Put a character on the command line. Shifts the following text to the - * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. - * "c" must be printable (fit in one display cell)! - */ +// Put a character on the command line. Shifts the following text to the +// right when "shift" is true. Used for CTRL-V, CTRL-K, etc. +// "c" must be printable (fit in one display cell)! void putcmdline(char c, int shift) { if (cmd_silent) { @@ -3304,7 +3350,7 @@ void putcmdline(char c, int shift) ui_cursor_shape(); } -/// Undo a putcmdline(c, FALSE). +/// Undo a putcmdline(c, false). void unputcmdline(void) { if (cmd_silent) { @@ -3314,7 +3360,7 @@ void unputcmdline(void) if (ccline.cmdlen == ccline.cmdpos && !ui_has(kUICmdline)) { msg_putchar(' '); } else { - draw_cmdline(ccline.cmdpos, utfc_ptr2len((char *)ccline.cmdbuff + ccline.cmdpos)); + draw_cmdline(ccline.cmdpos, utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos)); } msg_no_more = false; cursorcmd(); @@ -3322,14 +3368,12 @@ void unputcmdline(void) ui_cursor_shape(); } -/* - * Put the given string, of the given length, onto the command line. - * If len is -1, then STRLEN() is used to calculate the length. - * If 'redraw' is TRUE then the new part of the command line, and the remaining - * part will be redrawn, otherwise it will not. If this function is called - * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be - * called afterwards. - */ +// Put the given string, of the given length, onto the command line. +// If len is -1, then strlen() is used to calculate the length. +// If 'redraw' is true then the new part of the command line, and the remaining +// part will be redrawn, otherwise it will not. If this function is called +// twice in a row, then 'redraw' should be false and redrawcmd() should be +// called afterwards. void put_on_cmdline(char_u *str, int len, int redraw) { int i; @@ -3356,7 +3400,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) // Count nr of bytes in cmdline that are overwritten by these // characters. for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0; - i += utfc_ptr2len((char *)ccline.cmdbuff + i)) { + i += utfc_ptr2len(ccline.cmdbuff + i)) { m--; } if (i < ccline.cmdlen) { @@ -3374,17 +3418,17 @@ void put_on_cmdline(char_u *str, int len, int redraw) // When the inserted text starts with a composing character, // backup to the character before it. There could be two of them. i = 0; - c = utf_ptr2char((char *)ccline.cmdbuff + ccline.cmdpos); + c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); while (ccline.cmdpos > 0 && utf_iscomposing(c)) { i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1; ccline.cmdpos -= i; len += i; - c = utf_ptr2char((char *)ccline.cmdbuff + ccline.cmdpos); + c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); } if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c)) { // Check the previous character for Arabic combining pair. i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1; - if (arabic_combine(utf_ptr2char((char *)ccline.cmdbuff + ccline.cmdpos - i), c)) { + if (arabic_combine(utf_ptr2char(ccline.cmdbuff + ccline.cmdpos - i), c)) { ccline.cmdpos -= i; len += i; } else { @@ -3393,7 +3437,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) } if (i != 0) { // Also backup the cursor position. - i = ptr2cells((char *)ccline.cmdbuff + ccline.cmdpos); + i = ptr2cells(ccline.cmdbuff + ccline.cmdpos); ccline.cmdspos -= i; msg_col -= i; if (msg_col < 0) { @@ -3404,7 +3448,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) } if (redraw && !cmd_silent) { - msg_no_more = TRUE; + msg_no_more = true; i = cmdline_row; cursorcmd(); draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); @@ -3412,7 +3456,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) if (cmdline_row != i || ccline.overstrike) { msg_clr_eos(); } - msg_no_more = FALSE; + msg_no_more = false; } if (KeyTyped) { m = Columns * Rows; @@ -3432,7 +3476,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) if (ccline.cmdspos + c < m) { ccline.cmdspos += c; } - c = utfc_ptr2len((char *)ccline.cmdbuff + ccline.cmdpos) - 1; + c = utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1; if (c > len - i - 1) { c = len - i - 1; } @@ -3514,14 +3558,14 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) int len; // Locate start of last word in the cmd buffer. - for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff;) { - len = utf_head_off(ccline.cmdbuff, w - 1) + 1; + for (w = (char_u *)ccline.cmdbuff + ccline.cmdpos; w > (char_u *)ccline.cmdbuff;) { + len = utf_head_off(ccline.cmdbuff, (char *)w - 1) + 1; if (!vim_iswordc(utf_ptr2char((char *)w - len))) { break; } w -= len; } - len = (int)((ccline.cmdbuff + ccline.cmdpos) - w); + len = (int)(((char_u *)ccline.cmdbuff + ccline.cmdpos) - w); if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0) { p += len; } @@ -3537,18 +3581,16 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) return cmdline_paste_reg(regname, literally, remcr); } -/* - * Put a string on the command line. - * When "literally" is TRUE, insert literally. - * When "literally" is FALSE, insert as typed, but don't leave the command - * line. - */ +// Put a string on the command line. +// When "literally" is true, insert literally. +// When "literally" is false, insert as typed, but don't leave the command +// line. void cmdline_paste_str(char_u *s, int literally) { int c, cv; if (literally) { - put_on_cmdline(s, -1, TRUE); + put_on_cmdline(s, -1, true); } else { while (*s != NUL) { cv = *s; @@ -3609,9 +3651,7 @@ static void redrawcmdprompt(void) } } -/* - * Redraw what is currently on the command line. - */ +// Redraw what is currently on the command line. void redrawcmd(void) { if (cmd_silent) { @@ -3637,7 +3677,7 @@ void redrawcmd(void) redrawcmdprompt(); // Don't use more prompt, truncate the cmdline if it doesn't fit. - msg_no_more = TRUE; + msg_no_more = true; draw_cmdline(0, ccline.cmdlen); msg_clr_eos(); msg_no_more = false; @@ -3648,11 +3688,9 @@ void redrawcmd(void) putcmdline(ccline.special_char, ccline.special_shift); } - /* - * An emsg() before may have set msg_scroll. This is used in normal mode, - * in cmdline mode we can reset them now. - */ - msg_scroll = FALSE; // next message overwrites cmdline + // An emsg() before may have set msg_scroll. This is used in normal mode, + // in cmdline mode we can reset them now. + msg_scroll = false; // next message overwrites cmdline // Typing ':' at the more prompt may set skip_redraw. We don't want this // in cmdline mode. @@ -3670,6 +3708,9 @@ void compute_cmdrow(void) cmdline_row = wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height + global_stl_height(); } + if (cmdline_row == Rows) { + cmdline_row--; + } lines_left = cmdline_row; } @@ -3728,12 +3769,10 @@ void gotocmdline(bool clr) cmd_cursor_goto(cmdline_row, 0); } -/* - * Check the word in front of the cursor for an abbreviation. - * Called when the non-id character "c" has been entered. - * When an abbreviation is recognized it is removed from the text with - * backspaces and the replacement string is inserted, followed by "c". - */ +// Check the word in front of the cursor for an abbreviation. +// Called when the non-id character "c" has been entered. +// When an abbreviation is recognized it is removed from the text with +// backspaces and the replacement string is inserted, followed by "c". static int ccheck_abbr(int c) { int spos = 0; @@ -3757,7 +3796,7 @@ static int ccheck_abbr(int c) spos = 0; } - return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos); + return check_abbr(c, (char_u *)ccline.cmdbuff, ccline.cmdpos, spos); } /// Escape special characters in "fname", depending on "what": @@ -3819,7 +3858,7 @@ 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. void escape_fname(char **pp) { - char_u *p = xmalloc(STRLEN(*pp) + 2); + char_u *p = xmalloc(strlen(*pp) + 2); p[0] = '\\'; STRCPY(p + 1, *pp); xfree(*pp); @@ -3867,8 +3906,42 @@ static CmdlineInfo *get_ccline_ptr(void) } } +/// Get the current command-line type. +/// Returns ':' or '/' or '?' or '@' or '>' or '-' +/// Only works when the command line is being edited. +/// Returns NUL when something is wrong. +static int get_cmdline_type(void) +{ + CmdlineInfo *p = get_ccline_ptr(); + + if (p == NULL) { + return NUL; + } + if (p->cmdfirstc == NUL) { + return (p->input_fn) ? '@' : '-'; + } + return p->cmdfirstc; +} + +/// Get the current command line in allocated memory. +/// Only works when the command line is being edited. +/// +/// @return NULL when something is wrong. +static char *get_cmdline_str(void) +{ + if (cmdline_star > 0) { + return NULL; + } + CmdlineInfo *p = get_ccline_ptr(); + + if (p == NULL) { + return NULL; + } + return xstrnsave(p->cmdbuff, (size_t)p->cmdlen); +} + /// Get the current command-line completion type. -char_u *get_cmdline_completion(void) +static char *get_cmdline_completion(void) { if (cmdline_star > 0) { return NULL; @@ -3879,64 +3952,79 @@ char_u *get_cmdline_completion(void) set_expand_context(p->xpc); char *cmd_compl = get_user_cmd_complete(p->xpc, p->xpc->xp_context); if (cmd_compl != NULL) { - return vim_strsave((char_u *)cmd_compl); + return xstrdup(cmd_compl); } } return NULL; } -/* - * Get the current command line in allocated memory. - * Only works when the command line is being edited. - * Returns NULL when something is wrong. - */ -char_u *get_cmdline_str(void) +/// "getcmdcompltype()" function +void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (cmdline_star > 0) { - return NULL; - } - CmdlineInfo *p = get_ccline_ptr(); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = get_cmdline_completion(); +} - if (p == NULL) { - return NULL; - } - return vim_strnsave(p->cmdbuff, (size_t)p->cmdlen); +/// "getcmdline()" function +void f_getcmdline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = get_cmdline_str(); } -/* - * Get the current command line position, counted in bytes. - * Zero is the first position. - * Only works when the command line is being edited. - * Returns -1 when something is wrong. - */ -int get_cmdline_pos(void) +/// "getcmdpos()" function +void f_getcmdpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { CmdlineInfo *p = get_ccline_ptr(); + rettv->vval.v_number = p != NULL ? p->cmdpos + 1 : 0; +} - if (p == NULL) { - return -1; - } - return p->cmdpos; +/// "getcmdscreenpos()" function +void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + CmdlineInfo *p = get_ccline_ptr(); + rettv->vval.v_number = p != NULL ? p->cmdspos + 1 : 0; } -/// Get the command line cursor screen position. -int get_cmdline_screen_pos(void) +/// "getcmdtype()" function +void f_getcmdtype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = xmallocz(1); + rettv->vval.v_string[0] = (char)get_cmdline_type(); +} + +/// Set the command line str to "str". +/// @return 1 when failed, 0 when OK. +static int set_cmdline_str(const char *str, int pos) { CmdlineInfo *p = get_ccline_ptr(); if (p == NULL) { - return -1; + return 1; } - return p->cmdspos; + + int len = (int)strlen(str); + realloc_cmdbuff(len + 1); + p->cmdlen = len; + STRCPY(p->cmdbuff, str); + + p->cmdpos = pos < 0 || pos > p->cmdlen ? p->cmdlen : pos; + new_cmdpos = p->cmdpos; + + redrawcmd(); + + // Trigger CmdlineChanged autocommands. + do_autocmd_cmdlinechanged(get_cmdline_type()); + + return 0; } -/* - * Set the command line byte position to "pos". Zero is the first position. - * Only works when the command line is being edited. - * Returns 1 when failed, 0 when OK. - */ -int set_cmdline_pos(int pos) +/// Set the command line byte position to "pos". Zero is the first position. +/// Only works when the command line is being edited. +/// @return 1 when failed, 0 when OK. +static int set_cmdline_pos(int pos) { CmdlineInfo *p = get_ccline_ptr(); @@ -3954,23 +4042,39 @@ int set_cmdline_pos(int pos) return 0; } -/* - * Get the current command-line type. - * Returns ':' or '/' or '?' or '@' or '>' or '-' - * Only works when the command line is being edited. - * Returns NUL when something is wrong. - */ -int get_cmdline_type(void) +/// "setcmdline()" function +void f_setcmdline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - CmdlineInfo *p = get_ccline_ptr(); + if (tv_check_for_string_arg(argvars, 0) == FAIL + || tv_check_for_opt_number_arg(argvars, 1) == FAIL) { + return; + } - if (p == NULL) { - return NUL; + int pos = -1; + if (argvars[1].v_type != VAR_UNKNOWN) { + bool error = false; + + pos = (int)tv_get_number_chk(&argvars[1], &error) - 1; + if (error) { + return; + } + if (pos < 0) { + emsg(_(e_positive)); + return; + } } - if (p->cmdfirstc == NUL) { - return (p->input_fn) ? '@' : '-'; + + rettv->vval.v_number = set_cmdline_str(argvars[0].vval.v_string, pos); +} + +/// "setcmdpos()" function +void f_setcmdpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const int pos = (int)tv_get_number(&argvars[0]) - 1; + + if (pos >= 0) { + rettv->vval.v_number = set_cmdline_pos(pos); } - return p->cmdfirstc; } /// Return the first character of the current command line. @@ -3995,7 +4099,7 @@ int get_list_range(char **str, int *num1, int *num2) *str = skipwhite((*str)); if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range - vim_str2nr((char_u *)(*str), NULL, &len, 0, &num, NULL, 0, false); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); *str += len; *num1 = (int)num; first = true; @@ -4003,7 +4107,7 @@ int get_list_range(char **str, int *num1, int *num2) *str = skipwhite((*str)); if (**str == ',') { // parse "to" part of range *str = skipwhite((*str) + 1); - vim_str2nr((char_u *)(*str), NULL, &len, 0, &num, NULL, 0, false); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); if (len > 0) { *num2 = (int)num; *str = skipwhite((*str) + len); @@ -4021,6 +4125,24 @@ void cmdline_init(void) CLEAR_FIELD(ccline); } +/// Check value of 'cedit' and set cedit_key. +/// Returns NULL if value is OK, error message otherwise. +char *check_cedit(void) +{ + int n; + + if (*p_cedit == NUL) { + cedit_key = -1; + } else { + n = string_to_key((char_u *)p_cedit); + if (vim_isprintc(n)) { + return e_invarg; + } + cedit_key = n; + } + return NULL; +} + /// Open a window on the current command line and history. Allow editing in /// the window. Returns when the window is closed. /// Returns: @@ -4068,17 +4190,27 @@ static int open_cmdwin(void) ga_clear(&winsizes); return K_IGNORE; } + // Don't let quitting the More prompt make this fail. + got_int = false; + + // Set "cmdwin_type" before any autocommands may mess things up. cmdwin_type = get_cmdline_type(); cmdwin_level = ccline.level; // Create empty command-line buffer. - buf_open_scratch(0, _("[Command Line]")); + if (buf_open_scratch(0, _("[Command Line]")) == FAIL) { + // Some autocommand messed it up? + win_close(curwin, true, false); + ga_clear(&winsizes); + cmdwin_type = 0; + return Ctrl_C; + } // Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer. - set_option_value("bh", 0L, "wipe", OPT_LOCAL); - curwin->w_p_rl = cmdmsg_rl; - cmdmsg_rl = false; + set_option_value_give_err("bh", 0L, "wipe", OPT_LOCAL); curbuf->b_p_ma = true; curwin->w_p_fen = false; + curwin->w_p_rl = cmdmsg_rl; + cmdmsg_rl = false; // Don't allow switching to another buffer. curbuf->b_ro_locked++; @@ -4092,7 +4224,7 @@ static int open_cmdwin(void) add_map("<Tab>", "<C-X><C-V>", MODE_INSERT, true); add_map("<Tab>", "a<C-X><C-V>", MODE_NORMAL, true); } - set_option_value("ft", 0L, "vim", OPT_LOCAL); + set_option_value_give_err("ft", 0L, "vim", OPT_LOCAL); } curbuf->b_ro_locked--; @@ -4111,7 +4243,7 @@ static int open_cmdwin(void) i = 0; } if (get_histentry(histtype)[i].hisstr != NULL) { - ml_append(lnum++, (char *)get_histentry(histtype)[i].hisstr, (colnr_T)0, false); + ml_append(lnum++, get_histentry(histtype)[i].hisstr, (colnr_T)0, false); } } while (i != *get_hisidx(histtype)); } @@ -4119,7 +4251,7 @@ static int open_cmdwin(void) // Replace the empty last line with the current command-line and put the // cursor there. - ml_replace(curbuf->b_ml.ml_line_count, (char *)ccline.cmdbuff, true); + ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, true); curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; curwin->w_cursor.col = ccline.cmdpos; changed_line_abv_curs(); @@ -4128,7 +4260,7 @@ static int open_cmdwin(void) ccline.redraw_state = kCmdRedrawNone; ui_call_cmdline_hide(ccline.level); } - redraw_later(curwin, SOME_VALID); + redraw_later(curwin, UPD_SOME_VALID); // No Ex mode here! exmode_active = false; @@ -4151,9 +4283,7 @@ static int open_cmdwin(void) RedrawingDisabled = 0; int save_count = save_batch_count(); - /* - * Call the main loop until <CR> or CTRL-C is typed. - */ + // Call the main loop until <CR> or CTRL-C is typed. normal_enter(true, false); RedrawingDisabled = i; @@ -4189,7 +4319,7 @@ static int open_cmdwin(void) if (histtype == HIST_CMD) { // Execute the command directly. - ccline.cmdbuff = (char_u *)xstrdup(p); + ccline.cmdbuff = xstrdup(p); cmdwin_result = CAR; } else { // First need to cancel what we were doing. @@ -4203,16 +4333,16 @@ static int open_cmdwin(void) // and don't modify the cmd window. ccline.cmdbuff = NULL; } else { - ccline.cmdbuff = vim_strsave(get_cursor_line_ptr()); + ccline.cmdbuff = xstrdup(get_cursor_line_ptr()); } if (ccline.cmdbuff == NULL) { - ccline.cmdbuff = vim_strsave((char_u *)""); + ccline.cmdbuff = xstrdup(""); ccline.cmdlen = 0; ccline.cmdbufflen = 1; ccline.cmdpos = 0; cmdwin_result = Ctrl_C; } else { - ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); + ccline.cmdlen = (int)strlen(ccline.cmdbuff); ccline.cmdbufflen = ccline.cmdlen + 1; ccline.cmdpos = curwin->w_cursor.col; if (ccline.cmdpos > ccline.cmdlen) { @@ -4229,6 +4359,7 @@ static int open_cmdwin(void) // First go back to the original window. wp = curwin; set_bufref(&bufref, curbuf); + skip_win_fix_cursor = true; win_goto(old_curwin); // win_goto() may trigger an autocommand that already closes the @@ -4245,6 +4376,7 @@ static int open_cmdwin(void) // Restore window sizes. win_size_restore(&winsizes); + skip_win_fix_cursor = false; } ga_clear(&winsizes); @@ -4285,7 +4417,7 @@ char *script_get(exarg_T *const eap, size_t *const lenp) const char *const cmd = (const char *)eap->arg; if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) { - *lenp = STRLEN(eap->arg); + *lenp = strlen(eap->arg); return eap->skip ? NULL : xmemdupz(eap->arg, *lenp); } diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h index 5e3ad20a31..919a6c8f11 100644 --- a/src/nvim/ex_getln.h +++ b/src/nvim/ex_getln.h @@ -41,7 +41,7 @@ typedef enum { /// structure. typedef struct cmdline_info CmdlineInfo; struct cmdline_info { - char_u *cmdbuff; ///< pointer to command line buffer + char *cmdbuff; ///< pointer to command line buffer int cmdbufflen; ///< length of cmdbuff int cmdlen; ///< number of chars in command line int cmdpos; ///< current cursor position diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 9495ae1c4b..e907c45e79 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -359,7 +359,7 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr // Then ":help" will re-use both the buffer and the window and set // the options, even when "options" is not in 'sessionoptions'. if (0 < wp->w_tagstackidx && wp->w_tagstackidx <= wp->w_tagstacklen) { - curtag = (char *)wp->w_tagstack[wp->w_tagstackidx - 1].tagname; + curtag = wp->w_tagstack[wp->w_tagstackidx - 1].tagname; } if (put_line(fd, "enew | setl bt=help") == FAIL @@ -956,7 +956,7 @@ void ex_mkrc(exarg_T *eap) } // When using 'viewdir' may have to create the directory. - if (using_vdir && !os_isdir(p_vdir)) { + if (using_vdir && !os_isdir((char *)p_vdir)) { vim_mkdir_emsg((const char *)p_vdir, 0755); } diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 1639f72990..176ad0d5c8 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -30,6 +30,7 @@ #include <assert.h> +#include "klib/kbtree.h" #include "nvim/api/extmark.h" #include "nvim/buffer.h" #include "nvim/buffer_updates.h" @@ -37,7 +38,6 @@ #include "nvim/decoration.h" #include "nvim/extmark.h" #include "nvim/globals.h" -#include "nvim/lib/kbtree.h" #include "nvim/map.h" #include "nvim/memline.h" #include "nvim/pos.h" @@ -70,7 +70,8 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col || kv_size(decor->virt_lines) || decor->conceal || decor_has_sign(decor) - || decor->ui_watched) { + || decor->ui_watched + || decor->spell) { decor_full = true; decor = xmemdup(decor, sizeof *decor); } @@ -510,11 +511,11 @@ void extmark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount, bcount_t old_byte = 0, new_byte = 0; int old_row, new_row; if (amount == MAXLNUM) { - old_row = (int)(line2 - line1 + 1); + old_row = line2 - line1 + 1; // TODO(bfredl): ej kasta? old_byte = (bcount_t)buf->deleted_bytes2; - new_row = (int)(amount_after + old_row); + new_row = amount_after + old_row; } else { // A region is either deleted (amount == MAXLNUM) or // added (line2 == MAXLNUM). The only other case is :move diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h index 5570b5c71e..9ef4ec23e5 100644 --- a/src/nvim/extmark_defs.h +++ b/src/nvim/extmark_defs.h @@ -1,7 +1,7 @@ #ifndef NVIM_EXTMARK_DEFS_H #define NVIM_EXTMARK_DEFS_H -#include "nvim/lib/kvec.h" +#include "klib/kvec.h" #include "nvim/types.h" typedef struct { diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 2d09e7aa71..d9adf84acc 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -69,17 +69,14 @@ #include "nvim/vim.h" #include "nvim/window.h" -static char_u *ff_expand_buffer = NULL; // used for expanding filenames +static char *ff_expand_buffer = NULL; // used for expanding filenames -/* - * type for the directory search stack - */ +// type for the directory search stack typedef struct ff_stack { struct ff_stack *ffs_prev; - /* the fix part (no wildcards) and the part containing the wildcards - * of the search path - */ + // the fix part (no wildcards) and the part containing the wildcards + // of the search path char_u *ffs_fix_path; char_u *ffs_wc_path; @@ -89,98 +86,87 @@ typedef struct ff_stack { int ffs_filearray_size; 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 - * 1: this directory was partly searched in an earlier step - */ + // to store status of partly handled directories + // 0: we work on this directory for the first time + // 1: this directory was partly searched in an earlier step int ffs_stage; - /* How deep are we in the directory tree? - * Counts backward from value of level parameter to vim_findfile_init - */ + // How deep are we in the directory tree? + // Counts backward from value of level parameter to vim_findfile_init int ffs_level; // Did we already expand '**' to an empty string? int ffs_star_star_empty; } ff_stack_T; -/* - * type for already visited directories or files. - */ +// type for already visited directories or files. typedef struct ff_visited { struct ff_visited *ffv_next; - /* Visited directories are different if the wildcard string are - * different. So we have to save it. - */ - char_u *ffv_wc_path; + // Visited directories are different if the wildcard string are + // different. So we have to save it. + char *ffv_wc_path; + // use FileID for comparison (needed because of links), else use filename. bool file_id_valid; FileID file_id; - /* The memory for this struct is allocated according to the length of - * ffv_fname. - */ - char_u ffv_fname[1]; // actually longer + // The memory for this struct is allocated according to the length of + // ffv_fname. + char ffv_fname[1]; // actually longer } ff_visited_T; -/* - * We might have to manage several visited lists during a search. - * This is especially needed for the tags option. If tags is set to: - * "./++/tags,./++/TAGS,++/tags" (replace + with *) - * So we have to do 3 searches: - * 1) search from the current files directory downward for the file "tags" - * 2) search from the current files directory downward for the file "TAGS" - * 3) search from Vims current directory downwards for the file "tags" - * As you can see, the first and the third search are for the same file, so for - * the third search we can use the visited list of the first search. For the - * second search we must start from an empty visited list. - * The struct ff_visited_list_hdr is used to manage a linked list of already - * visited lists. - */ +// We might have to manage several visited lists during a search. +// This is especially needed for the tags option. If tags is set to: +// "./++/tags,./++/TAGS,++/tags" (replace + with *) +// So we have to do 3 searches: +// 1) search from the current files directory downward for the file "tags" +// 2) search from the current files directory downward for the file "TAGS" +// 3) search from Vims current directory downwards for the file "tags" +// As you can see, the first and the third search are for the same file, so for +// the third search we can use the visited list of the first search. For the +// second search we must start from an empty visited list. +// The struct ff_visited_list_hdr is used to manage a linked list of already +// visited lists. typedef struct ff_visited_list_hdr { struct ff_visited_list_hdr *ffvl_next; // the filename the attached visited list is for - char_u *ffvl_filename; + char *ffvl_filename; ff_visited_T *ffvl_visited_list; } ff_visited_list_hdr_T; -/* - * '**' can be expanded to several directory levels. - * Set the default maximum depth. - */ +// '**' can be expanded to several directory levels. +// Set the default maximum depth. #define FF_MAX_STAR_STAR_EXPAND ((char_u)30) -/* - * The search context: - * ffsc_stack_ptr: the stack for the dirs to search - * ffsc_visited_list: the currently active visited list - * ffsc_dir_visited_list: the currently active visited list for search dirs - * ffsc_visited_lists_list: the list of all visited lists - * ffsc_dir_visited_lists_list: the list of all visited lists for search dirs - * ffsc_file_to_search: the file to search for - * ffsc_start_dir: the starting directory, if search path was relative - * ffsc_fix_path: the fix part of the given path (without wildcards) - * Needed for upward search. - * ffsc_wc_path: the part of the given path containing wildcards - * ffsc_level: how many levels of dirs to search downwards - * ffsc_stopdirs_v: array of stop directories for upward search - * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE - * ffsc_tagfile: searching for tags file, don't use 'suffixesadd' - */ +// The search context: +// ffsc_stack_ptr: the stack for the dirs to search +// ffsc_visited_list: the currently active visited list +// ffsc_dir_visited_list: the currently active visited list for search dirs +// ffsc_visited_lists_list: the list of all visited lists +// ffsc_dir_visited_lists_list: the list of all visited lists for search dirs +// ffsc_file_to_search: the file to search for +// ffsc_start_dir: the starting directory, if search path was relative +// ffsc_fix_path: the fix part of the given path (without wildcards) +// Needed for upward search. +// ffsc_wc_path: the part of the given path containing wildcards +// ffsc_level: how many levels of dirs to search downwards +// ffsc_stopdirs_v: array of stop directories for upward search +// ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE +// ffsc_tagfile: searching for tags file, don't use 'suffixesadd' typedef struct ff_search_ctx_T { ff_stack_T *ffsc_stack_ptr; ff_visited_list_hdr_T *ffsc_visited_list; ff_visited_list_hdr_T *ffsc_dir_visited_list; ff_visited_list_hdr_T *ffsc_visited_lists_list; ff_visited_list_hdr_T *ffsc_dir_visited_lists_list; - char_u *ffsc_file_to_search; - char_u *ffsc_start_dir; - char_u *ffsc_fix_path; - char_u *ffsc_wc_path; + char *ffsc_file_to_search; + char *ffsc_start_dir; + char *ffsc_fix_path; + char *ffsc_wc_path; int ffsc_level; - char_u **ffsc_stopdirs_v; + char **ffsc_stopdirs_v; int ffsc_find_what; int ffsc_tagfile; } ff_search_ctx_T; @@ -221,8 +207,8 @@ static char_u e_pathtoolong[] = N_("E854: path too long for completion"); /// /// Upward search is only done on the starting dir. /// -/// If 'free_visited' is TRUE the list of already visited files/directories is -/// cleared. Set this to FALSE if you just want to search from another +/// If 'free_visited' is true the list of already visited files/directories is +/// cleared. Set this to false if you just want to search from another /// directory, but want to be sure that no directory from a previous search is /// searched again. This is useful if you search for a file at different places. /// The list of visited files/dirs can also be cleared with the function @@ -246,17 +232,15 @@ static char_u e_pathtoolong[] = N_("E854: path too long for completion"); /// /// @param tagfile expanding names of tags files /// @param rel_fname file name to use for "." -void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int level, - int free_visited, int find_what, void *search_ctx_arg, int tagfile, - char_u *rel_fname) +void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, int free_visited, + int find_what, void *search_ctx_arg, int tagfile, char *rel_fname) { - char_u *wc_part; + char *wc_part; ff_stack_T *sptr; ff_search_ctx_T *search_ctx; - /* If a search context is given by the caller, reuse it, else allocate a - * new one. - */ + // If a search context is given by the caller, reuse it, else allocate a + // new one. if (search_ctx_arg != NULL) { search_ctx = search_ctx_arg; } else { @@ -269,12 +253,12 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le ff_clear(search_ctx); // clear visited list if wanted - if (free_visited == TRUE) { + if (free_visited == true) { vim_findfile_free_visited(search_ctx); } else { - /* Reuse old visited lists. Get the visited list for the given - * filename. If no list for the current filename exists, creates a new - * one. */ + // Reuse old visited lists. Get the visited list for the given + // filename. If no list for the current filename exists, creates a new + // one. search_ctx->ffsc_visited_list = ff_get_visited_list(filename, &search_ctx->ffsc_visited_lists_list); if (search_ctx->ffsc_visited_list == NULL) { @@ -291,25 +275,25 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le ff_expand_buffer = xmalloc(MAXPATHL); } - /* Store information on starting dir now if path is relative. - * If path is absolute, we do that later. */ + // Store information on starting dir now if path is relative. + // If path is absolute, we do that later. if (path[0] == '.' && (vim_ispathsep(path[1]) || path[1] == NUL) && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL) && rel_fname != NULL) { - size_t len = (size_t)((char_u *)path_tail((char *)rel_fname) - rel_fname); + size_t len = (size_t)(path_tail(rel_fname) - rel_fname); - if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) { + if (!vim_isAbsName((char_u *)rel_fname) && len + 1 < MAXPATHL) { // Make the start dir an absolute path name. STRLCPY(ff_expand_buffer, rel_fname, len + 1); - search_ctx->ffsc_start_dir = (char_u *)FullName_save((char *)ff_expand_buffer, FALSE); + search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, false); } else { - search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len); + search_ctx->ffsc_start_dir = xstrnsave(rel_fname, len); } if (*++path != NUL) { path++; } - } else if (*path == NUL || !vim_isAbsName(path)) { + } else if (*path == NUL || !vim_isAbsName((char_u *)path)) { #ifdef BACKSLASH_IN_FILENAME // "c:dir" needs "c:" to be expanded, otherwise use current dir if (*path != NUL && path[1] == ':') { @@ -326,15 +310,15 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le path += 2; } else #endif - if (os_dirname(ff_expand_buffer, MAXPATHL) == FAIL) { + if (os_dirname((char_u *)ff_expand_buffer, MAXPATHL) == FAIL) { goto error_return; } - search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer); + search_ctx->ffsc_start_dir = xstrdup(ff_expand_buffer); #ifdef BACKSLASH_IN_FILENAME - /* A path that starts with "/dir" is relative to the drive, not to the - * directory (but not for "//machine/dir"). Only use the drive name. */ + // A path that starts with "/dir" is relative to the drive, not to the + // directory (but not for "//machine/dir"). Only use the drive name. if ((*path == '/' || *path == '\\') && path[1] != path[0] && search_ctx->ffsc_start_dir[1] == ':') { @@ -343,17 +327,15 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le #endif } - /* - * If stopdirs are given, split them into an array of pointers. - * If this fails (mem allocation), there is no upward search at all or a - * stop directory is not recognized -> continue silently. - * If stopdirs just contains a ";" or is empty, - * search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This - * is handled as unlimited upward search. See function - * ff_path_in_stoplist() for details. - */ + // If stopdirs are given, split them into an array of pointers. + // If this fails (mem allocation), there is no upward search at all or a + // stop directory is not recognized -> continue silently. + // If stopdirs just contains a ";" or is empty, + // search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This + // is handled as unlimited upward search. See function + // ff_path_in_stoplist() for details. if (stopdirs != NULL) { - char_u *walker = stopdirs; + char *walker = stopdirs; while (*walker == ';') { walker++; @@ -363,25 +345,21 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le search_ctx->ffsc_stopdirs_v = xmalloc(sizeof(char_u *)); do { - char_u *helper; + char *helper; void *ptr; helper = walker; ptr = xrealloc(search_ctx->ffsc_stopdirs_v, (dircount + 1) * sizeof(char_u *)); search_ctx->ffsc_stopdirs_v = ptr; - walker = (char_u *)vim_strchr((char *)walker, ';'); + walker = vim_strchr(walker, ';'); if (walker) { assert(walker - helper >= 0); - search_ctx->ffsc_stopdirs_v[dircount - 1] = - vim_strnsave(helper, (size_t)(walker - helper)); + search_ctx->ffsc_stopdirs_v[dircount - 1] = xstrnsave(helper, (size_t)(walker - helper)); walker++; } else { - /* this might be "", which means ascent till top - * of directory tree. - */ - search_ctx->ffsc_stopdirs_v[dircount - 1] = - vim_strsave(helper); + // this might be "", which means ascent till top of directory tree. + search_ctx->ffsc_stopdirs_v[dircount - 1] = xstrdup(helper); } dircount++; @@ -391,11 +369,10 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le search_ctx->ffsc_level = level; - /* split into: - * -fix path - * -wildcard_stuff (might be NULL) - */ - wc_part = (char_u *)vim_strchr((char *)path, '*'); + // split into: + // -fix path + // -wildcard_stuff (might be NULL) + wc_part = vim_strchr(path, '*'); if (wc_part != NULL) { int64_t llevel; int len; @@ -403,17 +380,15 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le // save the fix part of the path assert(wc_part - path >= 0); - search_ctx->ffsc_fix_path = vim_strnsave(path, (size_t)(wc_part - path)); - - /* - * copy wc_path and add restricts to the '**' wildcard. - * The octet after a '**' is used as a (binary) counter. - * So '**3' is transposed to '**^C' ('^C' is ASCII value 3) - * or '**76' is transposed to '**N'( 'N' is ASCII value 76). - * If no restrict is given after '**' the default is used. - * Due to this technique the path looks awful if you print it as a - * string. - */ + search_ctx->ffsc_fix_path = xstrnsave(path, (size_t)(wc_part - path)); + + // copy wc_path and add restricts to the '**' wildcard. + // The octet after a '**' is used as a (binary) counter. + // So '**3' is transposed to '**^C' ('^C' is ASCII value 3) + // or '**76' is transposed to '**N'( 'N' is ASCII value 76). + // If no restrict is given after '**' the default is used. + // Due to this technique the path looks awful if you print it as a + // string. len = 0; while (*wc_part != NUL) { if (len + 5 >= MAXPATHL) { @@ -424,16 +399,16 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le ff_expand_buffer[len++] = *wc_part++; ff_expand_buffer[len++] = *wc_part++; - llevel = strtol((char *)wc_part, &errpt, 10); - if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255) { - ff_expand_buffer[len++] = (char_u)llevel; - } else if ((char_u *)errpt != wc_part && llevel == 0) { + llevel = strtol(wc_part, &errpt, 10); + if (errpt != wc_part && llevel > 0 && llevel < 255) { + ff_expand_buffer[len++] = (char)llevel; + } else if (errpt != wc_part && llevel == 0) { // restrict is 0 -> remove already added '**' len -= 2; } else { ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND; } - wc_part = (char_u *)errpt; + wc_part = errpt; if (*wc_part != NUL && !vim_ispathsep(*wc_part)) { semsg(_( "E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), @@ -445,40 +420,39 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le } } ff_expand_buffer[len] = NUL; - search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer); + search_ctx->ffsc_wc_path = xstrdup(ff_expand_buffer); } else { - search_ctx->ffsc_fix_path = vim_strsave(path); + search_ctx->ffsc_fix_path = xstrdup(path); } if (search_ctx->ffsc_start_dir == NULL) { - /* store the fix part as startdir. - * This is needed if the parameter path is fully qualified. - */ - search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path); + // store the fix part as startdir. + // This is needed if the parameter path is fully qualified. + search_ctx->ffsc_start_dir = xstrdup(search_ctx->ffsc_fix_path); search_ctx->ffsc_fix_path[0] = NUL; } // create an absolute path - if (STRLEN(search_ctx->ffsc_start_dir) - + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL) { + if (strlen(search_ctx->ffsc_start_dir) + + strlen(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL) { emsg(_(e_pathtoolong)); goto error_return; } STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir); - add_pathsep((char *)ff_expand_buffer); + add_pathsep(ff_expand_buffer); { - size_t eb_len = STRLEN(ff_expand_buffer); - char_u *buf = xmalloc(eb_len + STRLEN(search_ctx->ffsc_fix_path) + 1); + size_t eb_len = strlen(ff_expand_buffer); + char_u *buf = xmalloc(eb_len + strlen(search_ctx->ffsc_fix_path) + 1); STRCPY(buf, ff_expand_buffer); STRCPY(buf + eb_len, search_ctx->ffsc_fix_path); - if (os_isdir(buf)) { + if (os_isdir((char *)buf)) { STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path); - add_pathsep((char *)ff_expand_buffer); + add_pathsep(ff_expand_buffer); } else { - char_u *p = (char_u *)path_tail((char *)search_ctx->ffsc_fix_path); - char_u *wc_path = NULL; - char_u *temp = NULL; + char *p = path_tail(search_ctx->ffsc_fix_path); + char *wc_path = NULL; + char *temp = NULL; int len = 0; if (p > search_ctx->ffsc_fix_path) { @@ -489,16 +463,16 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le xfree(buf); goto error_return; } - STRLCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, eb_len + (size_t)len + 1); - add_pathsep((char *)ff_expand_buffer); + xstrlcat(ff_expand_buffer, search_ctx->ffsc_fix_path, eb_len + (size_t)len + 1); + add_pathsep(ff_expand_buffer); } else { - len = (int)STRLEN(search_ctx->ffsc_fix_path); + len = (int)strlen(search_ctx->ffsc_fix_path); } if (search_ctx->ffsc_wc_path != NULL) { - wc_path = vim_strsave(search_ctx->ffsc_wc_path); - temp = xmalloc(STRLEN(search_ctx->ffsc_wc_path) - + STRLEN(search_ctx->ffsc_fix_path + len) + wc_path = xstrdup(search_ctx->ffsc_wc_path); + temp = xmalloc(strlen(search_ctx->ffsc_wc_path) + + strlen(search_ctx->ffsc_fix_path + len) + 1); STRCPY(temp, search_ctx->ffsc_fix_path + len); STRCAT(temp, search_ctx->ffsc_wc_path); @@ -510,20 +484,16 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le xfree(buf); } - sptr = ff_create_stack_element(ff_expand_buffer, - search_ctx->ffsc_wc_path, - level, 0); + sptr = ff_create_stack_element(ff_expand_buffer, search_ctx->ffsc_wc_path, level, 0); ff_push(search_ctx, sptr); - search_ctx->ffsc_file_to_search = vim_strsave(filename); + search_ctx->ffsc_file_to_search = xstrdup(filename); return search_ctx; error_return: - /* - * We clear the search context now! - * Even when the caller gave us a (perhaps valid) context we free it here, - * as we might have already destroyed it. - */ + // We clear the search context now! + // Even when the caller gave us a (perhaps valid) context we free it here, + // as we might have already destroyed it. vim_findfile_cleanup(search_ctx); return NULL; } @@ -535,8 +505,8 @@ char_u *vim_findfile_stopdir(char_u *buf) while (*r_ptr != NUL && *r_ptr != ';') { if (r_ptr[0] == '\\' && r_ptr[1] == ';') { - /* Overwrite the escape char, - * use STRLEN(r_ptr) to move the trailing '\0'. */ + // Overwrite the escape char, + // use STRLEN(r_ptr) to move the trailing '\0'. STRMOVE(r_ptr, r_ptr + 1); r_ptr++; } @@ -593,16 +563,13 @@ char_u *vim_findfile(void *search_ctx_arg) search_ctx = (ff_search_ctx_T *)search_ctx_arg; - /* - * filepath is used as buffer for various actions and as the storage to - * return a found filename. - */ + // filepath is used as buffer for various actions and as the storage to + // return a found filename. file_path = xmalloc(MAXPATHL); // store the end of the start dir -- needed for upward search if (search_ctx->ffsc_start_dir != NULL) { - path_end = &search_ctx->ffsc_start_dir[ - STRLEN(search_ctx->ffsc_start_dir)]; + path_end = (char_u *)&search_ctx->ffsc_start_dir[strlen(search_ctx->ffsc_start_dir)]; } // upward search loop @@ -621,31 +588,26 @@ char_u *vim_findfile(void *search_ctx_arg) break; } - /* - * TODO: decide if we leave this test in - * - * GOOD: don't search a directory(-tree) twice. - * BAD: - check linked list for every new directory entered. - * - check for double files also done below - * - * Here we check if we already searched this directory. - * We already searched a directory if: - * 1) The directory is the same. - * 2) We would use the same wildcard string. - * - * Good if you have links on same directory via several ways - * or you have selfreferences in directories (e.g. SuSE Linux 6.3: - * /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop) - * - * This check is only needed for directories we work on for the - * first time (hence stackp->ff_filearray == NULL) - */ + // TODO(vim): decide if we leave this test in + // + // GOOD: don't search a directory(-tree) twice. + // BAD: - check linked list for every new directory entered. + // - check for double files also done below + // + // Here we check if we already searched this directory. + // We already searched a directory if: + // 1) The directory is the same. + // 2) We would use the same wildcard string. + // + // Good if you have links on same directory via several ways + // or you have selfreferences in directories (e.g. SuSE Linux 6.3: + // /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop) + // + // This check is only needed for directories we work on for the + // first time (hence stackp->ff_filearray == NULL) if (stackp->ffs_filearray == NULL - && ff_check_visited(&search_ctx->ffsc_dir_visited_list - ->ffvl_visited_list, - stackp->ffs_fix_path, - stackp->ffs_wc_path - ) == FAIL) { + && ff_check_visited(&search_ctx->ffsc_dir_visited_list->ffvl_visited_list, + (char *)stackp->ffs_fix_path, (char *)stackp->ffs_wc_path) == FAIL) { #ifdef FF_VERBOSE if (p_verbose >= 5) { verbose_enter_scroll(); @@ -676,25 +638,21 @@ char_u *vim_findfile(void *search_ctx_arg) file_path[0] = NUL; - /* - * If no filearray till now expand wildcards - * The function expand_wildcards() can handle an array of paths - * and all possible expands are returned in one array. We use this - * to handle the expansion of '**' into an empty string. - */ + // If no filearray till now expand wildcards + // The function expand_wildcards() can handle an array of paths + // and all possible expands are returned in one array. We use this + // to handle the expansion of '**' into an empty string. if (stackp->ffs_filearray == NULL) { char *dirptrs[2]; - /* we use filepath to build the path expand_wildcards() should - * expand. - */ + // we use filepath to build the path expand_wildcards() should expand. dirptrs[0] = (char *)file_path; dirptrs[1] = NULL; // if we have a start dir copy it in if (!vim_isAbsName(stackp->ffs_fix_path) && search_ctx->ffsc_start_dir) { - if (STRLEN(search_ctx->ffsc_start_dir) + 1 >= MAXPATHL) { + if (strlen(search_ctx->ffsc_start_dir) + 1 >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } @@ -747,13 +705,11 @@ char_u *vim_findfile(void *search_ctx_arg) } } - /* - * Here we copy until the next path separator or the end of - * the path. If we stop at a path separator, there is - * still something else left. This is handled below by - * pushing every directory returned from expand_wildcards() - * on the stack again for further search. - */ + // Here we copy until the next path separator or the end of + // the path. If we stop at a path separator, there is + // still something else left. This is handled below by + // pushing every directory returned from expand_wildcards() + // on the stack again for further search. while (*rest_of_wildcards && !vim_ispathsep(*rest_of_wildcards)) { if (len + 1 >= MAXPATHL) { @@ -769,18 +725,16 @@ char_u *vim_findfile(void *search_ctx_arg) } } - /* - * Expand wildcards like "*" and "$VAR". - * If the path is a URL don't try this. - */ + // Expand wildcards like "*" and "$VAR". + // If the path is a URL don't try this. if (path_with_url(dirptrs[0])) { stackp->ffs_filearray = xmalloc(sizeof(char *)); stackp->ffs_filearray[0] = xstrdup(dirptrs[0]); stackp->ffs_filearray_size = 1; } else { - /* Add EW_NOTWILD because the expanded path may contain - * wildcard characters that are to be taken literally. - * This is a bit of a hack. */ + // Add EW_NOTWILD because the expanded path may contain + // wildcard characters that are to be taken literally. + // This is a bit of a hack. expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs, &stackp->ffs_filearray_size, &stackp->ffs_filearray, @@ -790,25 +744,22 @@ char_u *vim_findfile(void *search_ctx_arg) stackp->ffs_filearray_cur = 0; stackp->ffs_stage = 0; } else { - rest_of_wildcards = &stackp->ffs_wc_path[ - STRLEN(stackp->ffs_wc_path)]; + rest_of_wildcards = &stackp->ffs_wc_path[STRLEN(stackp->ffs_wc_path)]; } if (stackp->ffs_stage == 0) { // this is the first time we work on this directory if (*rest_of_wildcards == NUL) { - /* - * We don't have further wildcards to expand, so we have to - * check for the final file now. - */ + // 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(stackp->ffs_filearray[i]) - && !os_isdir((char_u *)stackp->ffs_filearray[i])) { + && !os_isdir(stackp->ffs_filearray[i])) { continue; // not a directory } // prepare the filename to be checked for existence below - if (STRLEN(stackp->ffs_filearray[i]) + 1 - + STRLEN(search_ctx->ffsc_file_to_search) >= MAXPATHL) { + if (strlen(stackp->ffs_filearray[i]) + 1 + + strlen(search_ctx->ffsc_file_to_search) >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } @@ -819,37 +770,29 @@ char_u *vim_findfile(void *search_ctx_arg) } STRCAT(file_path, search_ctx->ffsc_file_to_search); - /* - * Try without extra suffix and then with suffixes - * from 'suffixesadd'. - */ + // Try without extra suffix and then with suffixes + // from 'suffixesadd'. len = STRLEN(file_path); if (search_ctx->ffsc_tagfile) { suf = ""; } else { - suf = (char *)curbuf->b_p_sua; + suf = curbuf->b_p_sua; } for (;;) { // if file exists and we didn't already find it if ((path_with_url((char *)file_path) - || (os_path_exists(file_path) - && (search_ctx->ffsc_find_what - == FINDFILE_BOTH - || ((search_ctx->ffsc_find_what - == FINDFILE_DIR) - == os_isdir(file_path))))) + || (os_path_exists((char *)file_path) + && (search_ctx->ffsc_find_what == FINDFILE_BOTH + || ((search_ctx->ffsc_find_what == FINDFILE_DIR) + == os_isdir((char *)file_path))))) #ifndef FF_VERBOSE && (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list, - file_path, - (char_u *)"" - ) == OK) + (char *)file_path, "") == OK) #endif ) { #ifdef FF_VERBOSE if (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list, - file_path, - (char_u *)"" - ) == FAIL) { + file_path, (char_u *)"") == FAIL) { if (p_verbose >= 5) { verbose_enter_scroll(); smsg("Already: %s", file_path); @@ -868,10 +811,9 @@ char_u *vim_findfile(void *search_ctx_arg) if (!path_with_url((char *)file_path)) { simplify_filename(file_path); } - if (os_dirname(ff_expand_buffer, MAXPATHL) + if (os_dirname((char_u *)ff_expand_buffer, MAXPATHL) == OK) { - p = path_shorten_fname(file_path, - ff_expand_buffer); + p = (char_u *)path_shorten_fname((char *)file_path, ff_expand_buffer); if (p != NULL) { STRMOVE(file_path, p); } @@ -898,12 +840,12 @@ 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((char_u *)stackp->ffs_filearray[i])) { + if (!os_isdir(stackp->ffs_filearray[i])) { continue; // not a directory } ff_push(search_ctx, - ff_create_stack_element((char_u *)stackp->ffs_filearray[i], - rest_of_wildcards, + ff_create_stack_element(stackp->ffs_filearray[i], + (char *)rest_of_wildcards, stackp->ffs_level - 1, 0)); } } @@ -911,23 +853,21 @@ char_u *vim_findfile(void *search_ctx_arg) stackp->ffs_stage = 1; } - /* - * if wildcards contains '**' we have to descent till we reach the - * leaves of the directory tree. - */ + // if wildcards contains '**' we have to descent till we reach the + // leaves of the directory tree. if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0) { for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) { - if (FNAMECMP(stackp->ffs_filearray[i], - stackp->ffs_fix_path) == 0) { + if (path_fnamecmp(stackp->ffs_filearray[i], + (char *)stackp->ffs_fix_path) == 0) { continue; // don't repush same directory } - if (!os_isdir((char_u *)stackp->ffs_filearray[i])) { + if (!os_isdir(stackp->ffs_filearray[i])) { continue; // not a directory } ff_push(search_ctx, - ff_create_stack_element((char_u *)stackp->ffs_filearray[i], - stackp->ffs_wc_path, stackp->ffs_level - 1, 1)); + ff_create_stack_element(stackp->ffs_filearray[i], + (char *)stackp->ffs_wc_path, stackp->ffs_level - 1, 1)); } } @@ -935,27 +875,24 @@ char_u *vim_findfile(void *search_ctx_arg) ff_free_stack_element(stackp); } - /* If we reached this, we didn't find anything downwards. - * Let's check if we should do an upward search. - */ + // If we reached this, we didn't find anything downwards. + // Let's check if we should do an upward search. if (search_ctx->ffsc_start_dir && search_ctx->ffsc_stopdirs_v != NULL && !got_int) { ff_stack_T *sptr; // is the last starting directory in the stop list? if (ff_path_in_stoplist(search_ctx->ffsc_start_dir, - (int)(path_end - search_ctx->ffsc_start_dir), - search_ctx->ffsc_stopdirs_v) == TRUE) { + (int)(path_end - (char_u *)search_ctx->ffsc_start_dir), + search_ctx->ffsc_stopdirs_v) == true) { break; } // cut of last dir - while (path_end > search_ctx->ffsc_start_dir - && vim_ispathsep(*path_end)) { + while (path_end > (char_u *)search_ctx->ffsc_start_dir && vim_ispathsep(*path_end)) { path_end--; } - while (path_end > search_ctx->ffsc_start_dir - && !vim_ispathsep(path_end[-1])) { + while (path_end > (char_u *)search_ctx->ffsc_start_dir && !vim_ispathsep(path_end[-1])) { path_end--; } *path_end = 0; @@ -965,8 +902,8 @@ char_u *vim_findfile(void *search_ctx_arg) break; } - if (STRLEN(search_ctx->ffsc_start_dir) + 1 - + STRLEN(search_ctx->ffsc_fix_path) >= MAXPATHL) { + if (strlen(search_ctx->ffsc_start_dir) + 1 + + strlen(search_ctx->ffsc_fix_path) >= MAXPATHL) { goto fail; } STRCPY(file_path, search_ctx->ffsc_start_dir); @@ -976,7 +913,7 @@ char_u *vim_findfile(void *search_ctx_arg) STRCAT(file_path, search_ctx->ffsc_fix_path); // create a new stack entry - sptr = ff_create_stack_element(file_path, + sptr = ff_create_stack_element((char *)file_path, search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0); ff_push(search_ctx, sptr); } else { @@ -1034,7 +971,7 @@ static void ff_free_visited_list(ff_visited_T *vl) /// @return the already visited list for the given filename. If none is found it /// allocates a new one. -static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, +static ff_visited_list_hdr_T *ff_get_visited_list(char *filename, ff_visited_list_hdr_T **list_headp) { ff_visited_list_hdr_T *retptr = NULL; @@ -1043,7 +980,7 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, if (*list_headp != NULL) { retptr = *list_headp; while (retptr != NULL) { - if (FNAMECMP(filename, retptr->ffvl_filename) == 0) { + if (path_fnamecmp(filename, retptr->ffvl_filename) == 0) { #ifdef FF_VERBOSE if (p_verbose >= 5) { verbose_enter_scroll(); @@ -1067,13 +1004,11 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, } #endif - /* - * if we reach this we didn't find a list and we have to allocate new list - */ + // if we reach this we didn't find a list and we have to allocate new list retptr = xmalloc(sizeof(*retptr)); retptr->ffvl_visited_list = NULL; - retptr->ffvl_filename = vim_strsave(filename); + retptr->ffvl_filename = xstrdup(filename); retptr->ffvl_next = *list_headp; *list_headp = retptr; @@ -1124,7 +1059,7 @@ static bool ff_wc_equal(char_u *s1, char_u *s2) /// /// @return FAIL if the given file/dir is already in the list or, /// OK if it is newly added -static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path) +static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_path) { ff_visited_T *vp; bool url = false; @@ -1132,33 +1067,31 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * FileID file_id; // For a URL we only compare the name, otherwise we compare the // device/inode. - if (path_with_url((char *)fname)) { + if (path_with_url(fname)) { STRLCPY(ff_expand_buffer, fname, MAXPATHL); url = true; } else { ff_expand_buffer[0] = NUL; - if (!os_fileid((char *)fname, &file_id)) { + if (!os_fileid(fname, &file_id)) { return FAIL; } } // check against list of already visited files for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) { - if ((url && FNAMECMP(vp->ffv_fname, ff_expand_buffer) == 0) + if ((url && path_fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0) || (!url && vp->file_id_valid && os_fileid_equal(&(vp->file_id), &file_id))) { // are the wildcard parts equal - if (ff_wc_equal(vp->ffv_wc_path, wc_path)) { + if (ff_wc_equal((char_u *)vp->ffv_wc_path, (char_u *)wc_path)) { // already visited return FAIL; } } } - /* - * New file/dir. Add it to the list of visited files/dirs. - */ - vp = xmalloc(sizeof(ff_visited_T) + STRLEN(ff_expand_buffer)); + // New file/dir. Add it to the list of visited files/dirs. + vp = xmalloc(sizeof(ff_visited_T) + strlen(ff_expand_buffer)); if (!url) { vp->file_id_valid = true; @@ -1170,7 +1103,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * } if (wc_path != NULL) { - vp->ffv_wc_path = vim_strsave(wc_path); + vp->ffv_wc_path = xstrdup(wc_path); } else { vp->ffv_wc_path = NULL; } @@ -1182,7 +1115,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * } /// create stack element from given path pieces -static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, int level, +static ff_stack_T *ff_create_stack_element(char *fix_part, char *wc_part, int level, int star_star_empty) { ff_stack_T *new = xmalloc(sizeof(ff_stack_T)); @@ -1197,14 +1130,14 @@ static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, in // the following saves NULL pointer checks in vim_findfile if (fix_part == NULL) { - fix_part = (char_u *)""; + fix_part = ""; } - new->ffs_fix_path = vim_strsave(fix_part); + new->ffs_fix_path = (char_u *)xstrdup(fix_part); if (wc_part == NULL) { - wc_part = (char_u *)""; + wc_part = ""; } - new->ffs_wc_path = vim_strsave(wc_part); + new->ffs_wc_path = (char_u *)xstrdup(wc_part); return new; } @@ -1212,8 +1145,8 @@ static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, in /// Push a dir on the directory stack. static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr) { - /* check for NULL pointer, not to return an error to the user, but - * to prevent a crash */ + // check for NULL pointer, not to return an error to the user, but + // to prevent a crash if (stack_ptr != NULL) { stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr; search_ctx->ffsc_stack_ptr = stack_ptr; @@ -1289,8 +1222,8 @@ static void ff_clear(ff_search_ctx_T *search_ctx) /// check if the given path is in the stopdirs /// -/// @return TRUE if yes else FALSE -static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v) +/// @return true if yes else false +static int ff_path_in_stoplist(char *path, int path_len, char **stopdirs_v) { int i = 0; @@ -1301,32 +1234,31 @@ static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v) // if no path consider it as match if (path_len == 0) { - return TRUE; + return true; } for (i = 0; stopdirs_v[i] != NULL; i++) { if ((int)STRLEN(stopdirs_v[i]) > path_len) { - /* match for parent directory. So '/home' also matches - * '/home/rks'. Check for PATHSEP in stopdirs_v[i], else - * '/home/r' would also match '/home/rks' - */ - if (FNAMENCMP(stopdirs_v[i], path, path_len) == 0 + // match for parent directory. So '/home' also matches + // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else + // '/home/r' would also match '/home/rks' + if (path_fnamencmp(stopdirs_v[i], path, (size_t)path_len) == 0 && vim_ispathsep(stopdirs_v[i][path_len])) { - return TRUE; + return true; } } else { - if (FNAMECMP(stopdirs_v[i], path) == 0) { + if (path_fnamecmp(stopdirs_v[i], path) == 0) { return true; } } } - return FALSE; + return false; } /// Find the file name "ptr[len]" in the path. Also finds directory names. /// -/// On the first call set the parameter 'first' to TRUE to initialize -/// the search. For repeating calls to FALSE. +/// On the first call set the parameter 'first' to true to initialize +/// the search. For repeating calls to false. /// /// Repeating calls will return other files called 'ptr[len]' from the path. /// @@ -1355,11 +1287,11 @@ char_u *find_file_in_path(char_u *ptr, size_t len, int options, int first, char_ return find_file_in_path_option(ptr, len, options, first, (*curbuf->b_p_path == NUL ? p_path - : curbuf->b_p_path), - FINDFILE_BOTH, rel_fname, curbuf->b_p_sua); + : (char_u *)curbuf->b_p_path), + FINDFILE_BOTH, rel_fname, (char_u *)curbuf->b_p_sua); } -static char_u *ff_file_to_find = NULL; +static char *ff_file_to_find = NULL; static void *fdip_search_ctx = NULL; #if defined(EXITFREE) @@ -1387,7 +1319,7 @@ void free_findfile(void) /// @return an allocated string for the file name. NULL for error. char_u *find_directory_in_path(char_u *ptr, size_t len, int options, char_u *rel_fname) { - return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath, + return find_file_in_path_option(ptr, len, options, true, p_cdpath, FINDFILE_DIR, rel_fname, (char_u *)""); } @@ -1405,7 +1337,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first static char *dir; static int did_findfile_init = false; char_u save_char; - char_u *file_name = NULL; + char *file_name = NULL; char *buf = NULL; int rel_to_curdir; @@ -1422,14 +1354,14 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first // copy file name into NameBuff, expanding environment variables save_char = ptr[len]; ptr[len] = NUL; - expand_env_esc(ptr, NameBuff, MAXPATHL, false, true, NULL); + expand_env_esc(ptr, (char_u *)NameBuff, MAXPATHL, false, true, NULL); ptr[len] = save_char; xfree(ff_file_to_find); - ff_file_to_find = vim_strsave(NameBuff); + ff_file_to_find = xstrdup(NameBuff); if (options & FNAME_UNESC) { // Change all "\ " to " ". - for (ptr = ff_file_to_find; *ptr != NUL; ++ptr) { + for (ptr = (char_u *)ff_file_to_find; *ptr != NUL; ptr++) { if (ptr[0] == '\\' && ptr[1] == ' ') { memmove(ptr, ptr + 1, STRLEN(ptr)); } @@ -1443,31 +1375,29 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first || (ff_file_to_find[1] == '.' && (ff_file_to_find[2] == NUL || vim_ispathsep(ff_file_to_find[2]))))); - if (vim_isAbsName(ff_file_to_find) + if (vim_isAbsName((char_u *)ff_file_to_find) // "..", "../path", "." and "./path": don't use the path_option || rel_to_curdir -#if defined(WIN32) +#if defined(MSWIN) // handle "\tmp" as absolute path || vim_ispathsep(ff_file_to_find[0]) // handle "c:name" as absolute path || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':') #endif ) { - /* - * Absolute path, no need to use "path_option". - * If this is not a first call, return NULL. We already returned a - * filename on the first call. - */ - if (first == TRUE) { - if (path_with_url((char *)ff_file_to_find)) { - file_name = vim_strsave(ff_file_to_find); + // Absolute path, no need to use "path_option". + // If this is not a first call, return NULL. We already returned a + // filename on the first call. + if (first == true) { + if (path_with_url(ff_file_to_find)) { + file_name = xstrdup(ff_file_to_find); goto theend; } - /* When FNAME_REL flag given first use the directory of the file. - * Otherwise or when this fails use the current directory. */ - for (int run = 1; run <= 2; ++run) { - size_t l = STRLEN(ff_file_to_find); + // When FNAME_REL flag given first use the directory of the file. + // Otherwise or when this fails use the current directory. + for (int run = 1; run <= 2; run++) { + size_t l = strlen(ff_file_to_find); if (run == 1 && rel_to_curdir && (options & FNAME_REL) @@ -1475,14 +1405,13 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first && STRLEN(rel_fname) + l < MAXPATHL) { STRCPY(NameBuff, rel_fname); STRCPY(path_tail((char *)NameBuff), ff_file_to_find); - l = STRLEN(NameBuff); + l = strlen(NameBuff); } else { STRCPY(NameBuff, ff_file_to_find); run = 2; } - /* When the file doesn't exist, try adding parts of - * 'suffixesadd'. */ + // When the file doesn't exist, try adding parts of 'suffixesadd'. buf = (char *)suffixes; for (;;) { if ( @@ -1490,7 +1419,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first && (find_what == FINDFILE_BOTH || ((find_what == FINDFILE_DIR) == os_isdir(NameBuff))))) { - file_name = vim_strsave(NameBuff); + file_name = xstrdup(NameBuff); goto theend; } if (*buf == NUL) { @@ -1502,12 +1431,10 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first } } } else { - /* - * Loop over all paths in the 'path' or 'cdpath' option. - * When "first" is set, first setup to the start of the option. - * Otherwise continue to find the next match. - */ - if (first == TRUE) { + // Loop over all paths in the 'path' or 'cdpath' option. + // When "first" is set, first setup to the start of the option. + // Otherwise continue to find the next match. + if (first == true) { // vim_findfile_free_visited can handle a possible NULL pointer vim_findfile_free_visited(fdip_search_ctx); dir = (char *)path_option; @@ -1516,18 +1443,17 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first for (;;) { if (did_findfile_init) { - file_name = vim_findfile(fdip_search_ctx); + file_name = (char *)vim_findfile(fdip_search_ctx); if (file_name != NULL) { break; } - did_findfile_init = FALSE; + did_findfile_init = false; } else { char_u *r_ptr; if (dir == NULL || *dir == NUL) { - /* We searched all paths of the option, now we can - * free the search context. */ + // We searched all paths of the option, now we can free the search context. vim_findfile_cleanup(fdip_search_ctx); fdip_search_ctx = NULL; break; @@ -1541,18 +1467,18 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first // get the stopdir string r_ptr = vim_findfile_stopdir((char_u *)buf); - fdip_search_ctx = vim_findfile_init((char_u *)buf, ff_file_to_find, - r_ptr, 100, false, find_what, - fdip_search_ctx, false, rel_fname); + fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find, + (char *)r_ptr, 100, false, find_what, + fdip_search_ctx, false, (char *)rel_fname); if (fdip_search_ctx != NULL) { - did_findfile_init = TRUE; + did_findfile_init = true; } xfree(buf); } } } if (file_name == NULL && (options & FNAME_MESS)) { - if (first == TRUE) { + if (first == true) { if (find_what == FINDFILE_DIR) { semsg(_("E344: Can't find directory \"%s\" in cdpath"), ff_file_to_find); @@ -1572,7 +1498,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first } theend: - return file_name; + return (char_u *)file_name; } void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre) @@ -1654,7 +1580,7 @@ int vim_chdirfile(char *fname, CdCause cause) STRLCPY(dir, fname, MAXPATHL); *path_tail_with_sep(dir) = NUL; - if (os_dirname(NameBuff, sizeof(NameBuff)) != OK) { + if (os_dirname((char_u *)NameBuff, sizeof(NameBuff)) != OK) { NameBuff[0] = NUL; } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 5dfcbb0668..30898981de 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -82,17 +82,15 @@ #define FIO_UCSBOM 0x4000 // check for BOM at start of file #define FIO_ALL (-1) // allow all formats -/* When converting, a read() or write() may leave some bytes to be converted - * for the next call. The value is guessed... */ +// When converting, a read() or write() may leave some bytes to be converted +// for the next call. The value is guessed... #define CONV_RESTLEN 30 -/* We have to guess how much a sequence of bytes may expand when converting - * with iconv() to be able to allocate a buffer. */ +// We have to guess how much a sequence of bytes may expand when converting +// with iconv() to be able to allocate a buffer. #define ICONV_MULT 8 -/* - * Structure to pass arguments from buf_write() to buf_write_bytes(). - */ +// Structure to pass arguments from buf_write() to buf_write_bytes(). struct bw_info { int bw_fd; // file descriptor char_u *bw_buf; // buffer with data to be written @@ -118,8 +116,10 @@ struct bw_info { #endif static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); +static char e_no_matching_autocommands_for_buftype_str_buffer[] + = N_("E676: No matching autocommands for buftype=%s buffer"); -void filemess(buf_T *buf, char_u *name, char_u *s, int attr) +void filemess(buf_T *buf, char *name, char *s, int attr) { int msg_scroll_save; @@ -128,13 +128,13 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) } add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)name); // Avoid an over-long translation to cause trouble. - STRLCAT(IObuff, s, IOSIZE); + xstrlcat(IObuff, s, IOSIZE); // For the first message may have to start a new line. // For further ones overwrite the previous one, reset msg_scroll before // calling filemess(). msg_scroll_save = msg_scroll; if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) { - msg_scroll = FALSE; + msg_scroll = false; } if (!msg_scroll) { // wait a bit when overwriting an error msg check_for_delay(false); @@ -143,7 +143,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) msg_scroll = msg_scroll_save; msg_scrolled_ign = true; // may truncate the message to avoid a hit-return prompt - msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr); + msg_outtrans_attr(msg_may_trunc(false, (char *)IObuff), attr); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; @@ -167,6 +167,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) /// READ_STDIN read from stdin instead of a file /// READ_BUFFER read from curbuf instead of a file (converting after reading /// stdin) +/// READ_NOFILE do not read a file, only trigger BufReadCmd /// READ_DUMMY read into a dummy buffer (to check if file contents changed) /// READ_KEEP_UNDO don't clear undo info or read it from a file /// READ_FIFO read from fifo/socket instead of a file @@ -256,12 +257,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read - /* - * If there is no file name yet, use the one for the read file. - * BF_NOTEDITED is set to reflect this. - * Don't do this for a read from a filter. - * Only do this when 'cpoptions' contains the 'f' flag. - */ + // If there is no file name yet, use the one for the read file. + // BF_NOTEDITED is set to reflect this. + // Don't do this for a read from a filter. + // Only do this when 'cpoptions' contains the 'f' flag. if (curbuf->b_ffname == NULL && !filtering && fname != NULL @@ -334,20 +333,26 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } curbuf->b_op_start = orig_start; + + if (flags & READ_NOFILE) { + // Return NOTDONE instead of FAIL so that BufEnter can be triggered + // and other operations don't fail. + return NOTDONE; + } } if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) { - msg_scroll = FALSE; // overwrite previous file message + msg_scroll = false; // overwrite previous file message } else { - msg_scroll = TRUE; // don't overwrite previous file message + msg_scroll = true; // don't overwrite previous file message } // If the name is too long we might crash further on, quit here. if (fname != NULL && *fname != NUL) { - size_t namelen = STRLEN(fname); + size_t namelen = strlen(fname); // If the name is too long we might crash further on, quit here. if (namelen >= MAXPATHL) { - filemess(curbuf, (char_u *)fname, (char_u *)_("Illegal file name"), 0); + filemess(curbuf, fname, _("Illegal file name"), 0); msg_end(); msg_scroll = msg_save; return FAIL; @@ -358,7 +363,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // swap file may destroy it! Reported on MS-DOS and Win 95. if (after_pathsep(fname, fname + namelen)) { if (!silent) { - filemess(curbuf, (char_u *)fname, (char_u *)_(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory), 0); } msg_end(); msg_scroll = msg_save; @@ -380,10 +385,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, ) { if (S_ISDIR(perm)) { if (!silent) { - filemess(curbuf, (char_u *)fname, (char_u *)_(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory), 0); } } else { - filemess(curbuf, (char_u *)fname, (char_u *)_("is not a file"), 0); + filemess(curbuf, fname, _("is not a file"), 0); } msg_end(); msg_scroll = msg_save; @@ -394,15 +399,13 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // Set default or forced 'fileformat' and 'binary'. set_file_options(set_options, eap); - /* - * When opening a new file we take the readonly flag from the file. - * Default is r/w, can be set to r/o below. - * Don't reset it when in readonly mode - * Only set/reset b_p_ro when BF_CHECK_RO is set. - */ + // When opening a new file we take the readonly flag from the file. + // Default is r/w, can be set to r/o below. + // Don't reset it when in readonly mode + // Only set/reset b_p_ro when BF_CHECK_RO is set. check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO)); if (check_readonly && !readonlymode) { - curbuf->b_p_ro = FALSE; + curbuf->b_p_ro = false; } if (newfile && !read_stdin && !read_buffer && !read_fifo) { @@ -412,17 +415,15 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_mtime_read = curbuf->b_mtime; curbuf->b_mtime_read_ns = curbuf->b_mtime_ns; #ifdef UNIX - /* - * Use the protection bits of the original file for the swap file. - * This makes it possible for others to read the name of the - * edited file from the swapfile, but only if they can read the - * edited file. - * Remove the "write" and "execute" bits for group and others - * (they must not write the swapfile). - * Add the "read" and "write" bits for the user, otherwise we may - * not be able to write to the file ourselves. - * Setting the bits is done below, after creating the swap file. - */ + // Use the protection bits of the original file for the swap file. + // This makes it possible for others to read the name of the + // edited file from the swapfile, but only if they can read the + // edited file. + // Remove the "write" and "execute" bits for group and others + // (they must not write the swapfile). + // Add the "read" and "write" bits for the user, otherwise we may + // not be able to write to the file ourselves. + // Setting the bits is done below, after creating the swap file. swap_mode = ((int)file_info.stat.st_mode & 0644) | 0600; #endif } else { @@ -476,9 +477,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } if (!silent) { if (dir_of_file_exists((char_u *)fname)) { - filemess(curbuf, (char_u *)sfname, (char_u *)new_file_message(), 0); + filemess(curbuf, sfname, new_file_message(), 0); } else { - filemess(curbuf, (char_u *)sfname, (char_u *)_("[New DIRECTORY]"), 0); + filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); } } // Even though this is a new file, it might have been @@ -498,38 +499,36 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } return OK; // a new file is not an error } else { - filemess(curbuf, (char_u *)sfname, (char_u *)((fd == UV_EFBIG) ? _("[File too big]") : + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : #if defined(UNIX) && defined(EOVERFLOW) - // libuv only returns -errno - // in Unix and in Windows - // open() does not set - // EOVERFLOW - (fd == -EOVERFLOW) ? _("[File too big]") : + // libuv only returns -errno + // in Unix and in Windows + // open() does not set + // EOVERFLOW + (fd == -EOVERFLOW) ? _("[File too big]") : #endif - _("[Permission Denied]")), 0); + _("[Permission Denied]")), 0); curbuf->b_p_ro = true; // must use "w!" now } return FAIL; } - /* - * Only set the 'ro' flag for readonly files the first time they are - * loaded. Help files always get readonly mode - */ + // Only set the 'ro' flag for readonly files the first time they are + // loaded. Help files always get readonly mode if ((check_readonly && file_readonly) || curbuf->b_help) { - curbuf->b_p_ro = TRUE; + curbuf->b_p_ro = true; } if (set_options) { // Don't change 'eol' if reading from buffer as it will already be // correctly set when reading stdin. if (!read_buffer) { - curbuf->b_p_eol = TRUE; - curbuf->b_start_eol = TRUE; + curbuf->b_p_eol = true; + curbuf->b_start_eol = true; } - curbuf->b_p_bomb = FALSE; - curbuf->b_start_bomb = FALSE; + curbuf->b_p_bomb = false; + curbuf->b_start_bomb = false; } // Create a swap file now, so that other Vims are warned that we are @@ -583,7 +582,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, return FAIL; } - ++no_wait_return; // don't wait for return yet + no_wait_return++; // don't wait for return yet // Set '[ mark to the line above where the lines go (line 1 if zero). orig_start = curbuf->b_op_start; @@ -635,16 +634,14 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (aborting()) { // autocmds may abort script processing no_wait_return--; msg_scroll = msg_save; - curbuf->b_p_ro = TRUE; // must use "w!" now + curbuf->b_p_ro = true; // must use "w!" now return FAIL; } - /* - * Don't allow the autocommands to change the current buffer. - * Try to re-open the file. - * - * Don't allow the autocommands to change the buffer name either - * (cd for example) if it invalidates fname or sfname. - */ + // Don't allow the autocommands to change the current buffer. + // Try to re-open the file. + // + // Don't allow the autocommands to change the buffer name either + // (cd for example) if it invalidates fname or sfname. if (!read_stdin && (curbuf != old_curbuf || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) || (using_b_fname && (old_b_fname != curbuf->b_fname)) @@ -656,7 +653,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } else { emsg(_("E201: *ReadPre autocommands must not change current buffer")); } - curbuf->b_p_ro = TRUE; // must use "w!" now + curbuf->b_p_ro = true; // must use "w!" now return FAIL; } } @@ -666,16 +663,14 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!recoverymode && !filtering && !(flags & READ_DUMMY) && !silent) { if (!read_stdin && !read_buffer) { - filemess(curbuf, (char_u *)sfname, (char_u *)"", 0); + filemess(curbuf, sfname, "", 0); } } - msg_scroll = FALSE; // overwrite the file message + msg_scroll = false; // overwrite the file message - /* - * Set linecnt now, before the "retry" caused by a wrong guess for - * fileformat, and after the autocommands, which may change them. - */ + // Set linecnt now, before the "retry" caused by a wrong guess for + // fileformat, and after the autocommands, which may change them. linecnt = curbuf->b_ml.ml_line_count; // "++bad=" argument. @@ -688,11 +683,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_bad_char = 0; } - /* - * Decide which 'encoding' to use or use first. - */ + // Decide which 'encoding' to use or use first. if (eap != NULL && eap->force_enc != 0) { - fenc = (char *)enc_canonize((char_u *)eap->cmd + eap->force_enc); + fenc = enc_canonize(eap->cmd + eap->force_enc); fenc_alloced = true; keep_dest_enc = true; } else if (curbuf->b_p_bin) { @@ -708,32 +701,30 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, fenc_alloced = false; } else if (*p_fencs == NUL) { - fenc = (char *)curbuf->b_p_fenc; // use format from buffer + fenc = curbuf->b_p_fenc; // use format from buffer fenc_alloced = false; } else { - fenc_next = (char *)p_fencs; // try items in 'fileencodings' - fenc = (char *)next_fenc(&fenc_next, &fenc_alloced); - } - - /* - * Jump back here to retry reading the file in different ways. - * Reasons to retry: - * - encoding conversion failed: try another one from "fenc_next" - * - BOM detected and fenc was set, need to setup conversion - * - "fileformat" check failed: try another - * - * Variables set for special retry actions: - * "file_rewind" Rewind the file to start reading it again. - * "advance_fenc" Advance "fenc" using "fenc_next". - * "skip_read" Re-use already read bytes (BOM detected). - * "did_iconv" iconv() conversion failed, try 'charconvert'. - * "keep_fileformat" Don't reset "fileformat". - * - * Other status indicators: - * "tmpname" When != NULL did conversion with 'charconvert'. - * Output file has to be deleted afterwards. - * "iconv_fd" When != -1 did conversion with iconv(). - */ + fenc_next = p_fencs; // try items in 'fileencodings' + fenc = next_fenc(&fenc_next, &fenc_alloced); + } + + // Jump back here to retry reading the file in different ways. + // Reasons to retry: + // - encoding conversion failed: try another one from "fenc_next" + // - BOM detected and fenc was set, need to setup conversion + // - "fileformat" check failed: try another + // + // Variables set for special retry actions: + // "file_rewind" Rewind the file to start reading it again. + // "advance_fenc" Advance "fenc" using "fenc_next". + // "skip_read" Re-use already read bytes (BOM detected). + // "did_iconv" iconv() conversion failed, try 'charconvert'. + // "keep_fileformat" Don't reset "fileformat". + // + // Other status indicators: + // "tmpname" When != NULL did conversion with 'charconvert'. + // Output file has to be deleted afterwards. + // "iconv_fd" When != -1 did conversion with iconv(). retry: if (file_rewind) { @@ -751,22 +742,20 @@ retry: } file_rewind = false; if (set_options) { - curbuf->b_p_bomb = FALSE; - curbuf->b_start_bomb = FALSE; + curbuf->b_p_bomb = false; + curbuf->b_start_bomb = false; } conv_error = 0; } - /* - * When retrying with another "fenc" and the first time "fileformat" - * will be reset. - */ + // When retrying with another "fenc" and the first time "fileformat" + // will be reset. if (keep_fileformat) { keep_fileformat = false; } else { if (eap != NULL && eap->force_ff != 0) { fileformat = get_fileformat_force(curbuf, eap); - try_unix = try_dos = try_mac = FALSE; + try_unix = try_dos = try_mac = false; } else if (curbuf->b_p_bin) { fileformat = EOL_UNIX; // binary: use Unix format } else if (*p_ffs == @@ -786,9 +775,7 @@ retry: #endif if (advance_fenc) { - /* - * Try the next entry in 'fileencodings'. - */ + // Try the next entry in 'fileencodings'. advance_fenc = false; if (eap != NULL && eap->force_enc != 0) { @@ -806,7 +793,7 @@ retry: xfree(fenc); } if (fenc_next != NULL) { - fenc = (char *)next_fenc(&fenc_next, &fenc_alloced); + fenc = next_fenc(&fenc_next, &fenc_alloced); } else { fenc = ""; fenc_alloced = false; @@ -818,16 +805,14 @@ retry: } } - /* - * Conversion may be required when the encoding of the file is different - * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. - */ + // Conversion may be required when the encoding of the file is different + // from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. fio_flags = 0; - converted = need_conversion((char_u *)fenc); + converted = need_conversion(fenc); if (converted) { // "ucs-bom" means we need to check the first bytes of the file // for a BOM. - if (STRCMP(fenc, ENC_UCSBOM) == 0) { + if (strcmp(fenc, ENC_UCSBOM) == 0) { fio_flags = FIO_UCSBOM; } else { // Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be @@ -848,10 +833,8 @@ retry: } #endif - /* - * Use the 'charconvert' expression when conversion is required - * and we can't do it internally or with iconv(). - */ + // Use the 'charconvert' expression when conversion is required + // and we can't do it internally or with iconv(). if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL && !read_fifo #ifdef HAVE_ICONV @@ -892,7 +875,7 @@ retry: } // Set "can_retry" when it's possible to rewind the file and try with - // another "fenc" value. It's FALSE when no other "fenc" to try, reading + // another "fenc" value. It's false when no other "fenc" to try, reading // stdin or fixed at a specific encoding. can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc && !read_fifo); @@ -915,12 +898,10 @@ retry: } while (!error && !got_int) { - /* - * We allocate as much space for the file as we can get, plus - * space for the old line plus room for one terminating NUL. - * The amount is limited by the fact that read() only can read - * up to max_unsigned characters (and other things). - */ + // We allocate as much space for the file as we can get, plus + // space for the old line plus room for one terminating NUL. + // The amount is limited by the fact that read() only can read + // up to max_unsigned characters (and other things). { if (!skip_read) { // Use buffer >= 64K. Add linerest to double the size if the @@ -992,10 +973,8 @@ retry: } if (read_buffer) { - /* - * Read bytes from curbuf. Used for converting text read - * from stdin. - */ + // Read bytes from curbuf. Used for converting text read + // from stdin. if (read_buf_lnum > from) { size = 0; } else { @@ -1004,14 +983,14 @@ retry: tlen = 0; for (;;) { - p = ml_get(read_buf_lnum) + read_buf_col; + p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; n = (int)STRLEN(p); if ((int)tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done // below. n = (int)(size - tlen); - for (ni = 0; ni < n; ++ni) { + for (ni = 0; ni < n; ni++) { if (p[ni] == NL) { ptr[tlen++] = NUL; } else { @@ -1045,9 +1024,7 @@ retry: } } } else { - /* - * Read bytes from the file. - */ + // Read bytes from the file. size = read_eintr(fd, ptr, (size_t)size); } @@ -1055,10 +1032,8 @@ retry: if (size < 0) { // read error error = true; } else if (conv_restlen > 0) { - /* - * Reached end-of-file but some trailing bytes could - * not be converted. Truncated file? - */ + // Reached end-of-file but some trailing bytes could + // not be converted. Truncated file? // When we did a conversion report an error. if (fio_flags != 0 @@ -1111,12 +1086,10 @@ retry: skip_read = false; - /* - * At start of file: Check for BOM. - * Also check for a BOM for other Unicode encodings, but not after - * converting with 'charconvert' or when a BOM has already been - * found. - */ + // At start of file: Check for BOM. + // Also check for a BOM for other Unicode encodings, but not after + // converting with 'charconvert' or when a BOM has already been + // found. if ((filesize == 0) && (fio_flags == FIO_UCSBOM || (!curbuf->b_p_bomb @@ -1138,8 +1111,8 @@ retry: size -= blen; memmove(ptr, ptr + blen, (size_t)size); if (set_options) { - curbuf->b_p_bomb = TRUE; - curbuf->b_start_bomb = TRUE; + curbuf->b_p_bomb = true; + curbuf->b_start_bomb = true; } } @@ -1165,9 +1138,7 @@ retry: ptr -= conv_restlen; size += conv_restlen; conv_restlen = 0; - /* - * Break here for a read error or end-of-file. - */ + // Break here for a read error or end-of-file. if (size <= 0) { break; } @@ -1181,11 +1152,9 @@ retry: char *top = ptr; size_t to_size = (size_t)(real_size - size); - /* - * If there is conversion error or not enough room try using - * another conversion. Except for when there is no - * alternative (help files). - */ + // If there is conversion error or not enough room try using + // another conversion. Except for when there is no + // alternative (help files). while ((iconv(iconv_fd, (void *)&fromp, &from_size, &top, &to_size) == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) @@ -1364,7 +1333,7 @@ retry: if (*--p < 0x80) { u8c = *p; } else { - len = utf_head_off((char_u *)ptr, p); + len = utf_head_off(ptr, (char *)p); p -= len; u8c = (unsigned)utf_ptr2char((char *)p); if (len == 0) { @@ -1486,9 +1455,7 @@ rewind_retry: // count the number of characters (after conversion!) filesize += size; - /* - * when reading the first part of a file: guess EOL type - */ + // when reading the first part of a file: guess EOL type if (fileformat == EOL_UNKNOWN) { // First try finding a NL, for Dos and Unix if (try_dos || try_unix) { @@ -1553,10 +1520,8 @@ rewind_retry: } } - /* - * This loop is executed once for every character read. - * Keep it fast! - */ + // This loop is executed once for every character read. + // Keep it fast! if (fileformat == EOL_MAC) { ptr--; while (++ptr, --size >= 0) { @@ -1658,11 +1623,9 @@ failed: error = false; } - /* - * If we get EOF in the middle of a line, note the fact and - * complete the line ourselves. - * In Dos format ignore a trailing CTRL-Z, unless 'binary' set. - */ + // If we get EOF in the middle of a line, note the fact and + // complete the line ourselves. + // In Dos format ignore a trailing CTRL-Z, unless 'binary' set. if (!error && !got_int && linerest != 0 @@ -1672,7 +1635,7 @@ failed: && ptr == line_start + 1)) { // remember for when writing if (set_options) { - curbuf->b_p_eol = FALSE; + curbuf->b_p_eol = false; } *ptr = NUL; len = (colnr_T)(ptr - line_start + 1); @@ -1712,7 +1675,7 @@ failed: if (read_stdin) { close(fd); if (stdin_fd < 0) { -#ifndef WIN32 +#ifndef MSWIN // On Unix, use stderr for stdin, makes shell commands work. vim_ignored = dup(2); #else @@ -1720,7 +1683,7 @@ failed: HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, (HANDLE)NULL); - vim_ignored = _open_osfhandle(conin, _O_RDONLY); + vim_ignored = _open_osfhandle((intptr_t)conin, _O_RDONLY); #endif } } @@ -1729,11 +1692,9 @@ failed: os_remove(tmpname); // delete converted file xfree(tmpname); } - --no_wait_return; // may wait for return now + no_wait_return--; // may wait for return now - /* - * In recovery mode everything but autocommands is skipped. - */ + // In recovery mode everything but autocommands is skipped. if (!recoverymode) { // need to delete the last line, which comes from the empty buffer if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { @@ -1749,7 +1710,7 @@ failed: linecnt = 0; } if (newfile || read_buffer) { - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); // After reading the text into the buffer the diff info needs to // be updated. diff_invalidate(curbuf); @@ -1760,20 +1721,11 @@ failed: appended_lines_mark(from, linecnt); } - /* - * If we were reading from the same terminal as where messages go, - * the screen will have been messed up. - * Switch on raw mode now and clear the screen. - */ - if (read_stdin) { - screenclear(); - } - if (got_int) { if (!(flags & READ_DUMMY)) { - filemess(curbuf, (char_u *)sfname, (char_u *)_(e_interr), 0); + filemess(curbuf, sfname, _(e_interr), 0); if (newfile) { - curbuf->b_p_ro = TRUE; // must use "w!" now + curbuf->b_p_ro = true; // must use "w!" now } } msg_scroll = msg_save; @@ -1788,30 +1740,30 @@ failed: #ifdef UNIX if (S_ISFIFO(perm)) { // fifo STRCAT(IObuff, _("[fifo]")); - c = TRUE; + c = true; } if (S_ISSOCK(perm)) { // or socket STRCAT(IObuff, _("[socket]")); - c = TRUE; + c = true; } # ifdef OPEN_CHR_FILES if (S_ISCHR(perm)) { // or character special STRCAT(IObuff, _("[character special]")); - c = TRUE; + c = true; } # endif #endif if (curbuf->b_p_ro) { STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")); - c = TRUE; + c = true; } if (read_no_eol_lnum) { msg_add_eol(); - c = TRUE; + c = true; } if (ff_error == EOL_DOS) { STRCAT(IObuff, _("[CR missing]")); - c = TRUE; + c = true; } if (split) { STRCAT(IObuff, _("[long lines split]")); @@ -1819,25 +1771,25 @@ failed: } if (notconverted) { STRCAT(IObuff, _("[NOT converted]")); - c = TRUE; + c = true; } else if (converted) { STRCAT(IObuff, _("[converted]")); - c = TRUE; + c = true; } if (conv_error != 0) { - sprintf((char *)IObuff + STRLEN(IObuff), - _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error); - c = TRUE; + snprintf(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), + _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error); + c = true; } else if (illegal_byte > 0) { - sprintf((char *)IObuff + STRLEN(IObuff), - _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); - c = TRUE; + snprintf(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), + _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); + c = true; } else if (error) { STRCAT(IObuff, _("[READ ERRORS]")); - c = TRUE; + c = true; } if (msg_add_fileformat(fileformat)) { - c = TRUE; + c = true; } msg_add_lines(c, (long)linecnt, filesize); @@ -1865,17 +1817,14 @@ failed: // with errors writing the file requires ":w!" if (newfile && (error || conv_error != 0 - || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP) - )) { - curbuf->b_p_ro = TRUE; + || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP))) { + curbuf->b_p_ro = true; } u_clearline(); // cannot use "U" command after adding lines - /* - * In Ex mode: cursor at last new line. - * Otherwise: cursor at first new line. - */ + // In Ex mode: cursor at last new line. + // Otherwise: cursor at first new line. if (exmode_active) { curwin->w_cursor.lnum = from + linecnt; } else { @@ -1894,17 +1843,13 @@ failed: } msg_scroll = msg_save; - /* - * Get the marks before executing autocommands, so they can be used there. - */ + // Get the marks before executing autocommands, so they can be used there. check_marks_read(); - /* - * We remember if the last line of the read didn't have - * an eol even when 'binary' is off, to support turning 'fixeol' off, - * or writing the read again with 'binary' on. The latter is required - * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. - */ + // We remember if the last line of the read didn't have + // an eol even when 'binary' is off, to support turning 'fixeol' off, + // or writing the read again with 'binary' on. The latter is required + // for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. curbuf->b_no_eol_lnum = read_no_eol_lnum; // When reloading a buffer put the cursor at the first line that is @@ -1913,9 +1858,7 @@ failed: u_find_first_changed(); } - /* - * When opening a new file locate undo info and read it. - */ + // When opening a new file locate undo info and read it. if (read_undo_file) { char_u hash[UNDO_HASH_SIZE]; @@ -1933,11 +1876,9 @@ failed: save_file_ff(curbuf); } - /* - * The output from the autocommands should not overwrite anything and - * should not be overwritten: Set msg_scroll, restore its value if no - * output was done. - */ + // The output from the autocommands should not overwrite anything and + // should not be overwritten: Set msg_scroll, restore its value if no + // output was done. msg_scroll = true; if (filtering) { apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname, @@ -1948,7 +1889,7 @@ failed: if (!au_did_filetype && *curbuf->b_p_ft != NUL) { // EVENT_FILETYPE was not triggered but the buffer already has a // filetype. Trigger EVENT_FILETYPE using the existing filetype. - apply_autocmds(EVENT_FILETYPE, (char *)curbuf->b_p_ft, curbuf->b_fname, true, curbuf); + apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, true, curbuf); } } else { apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname, @@ -1999,7 +1940,7 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp) linenr_T lnum; lnum = curbuf->b_ml.ml_line_count - linecnt + 1; - for (s = p; s < endp; ++s) { + for (s = p; s < endp; s++) { if (*s == '\n') { lnum++; } @@ -2012,17 +1953,17 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp) void prep_exarg(exarg_T *eap, const buf_T *buf) FUNC_ATTR_NONNULL_ALL { - const size_t cmd_len = 15 + STRLEN(buf->b_p_fenc); + const size_t cmd_len = 15 + strlen(buf->b_p_fenc); eap->cmd = xmalloc(cmd_len); snprintf(eap->cmd, cmd_len, "e ++enc=%s", buf->b_p_fenc); eap->force_enc = 8; eap->bad_char = buf->b_bad_char; - eap->force_ff = *buf->b_p_ff; + eap->force_ff = (unsigned char)(*buf->b_p_ff); eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN; - eap->read_edit = FALSE; - eap->forceit = FALSE; + eap->read_edit = false; + eap->forceit = false; } /// Set default or forced 'fileformat' and 'binary'. @@ -2050,8 +1991,8 @@ void set_file_options(int set_options, exarg_T *eap) void set_forced_fenc(exarg_T *eap) { if (eap->force_enc != 0) { - char_u *fenc = enc_canonize((char_u *)eap->cmd + eap->force_enc); - set_string_option_direct("fenc", -1, (char *)fenc, OPT_FREE|OPT_LOCAL, 0); + char *fenc = enc_canonize(eap->cmd + eap->force_enc); + set_string_option_direct("fenc", -1, fenc, OPT_FREE|OPT_LOCAL, 0); xfree(fenc); } } @@ -2062,24 +2003,24 @@ 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 **pp, bool *alloced) +static char *next_fenc(char **pp, bool *alloced) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char_u *p; - char_u *r; + char *p; + char *r; *alloced = false; if (**pp == NUL) { *pp = NULL; - return (char_u *)""; + return ""; } - p = (char_u *)vim_strchr((*pp), ','); + p = vim_strchr((*pp), ','); if (p == NULL) { - r = enc_canonize((char_u *)(*pp)); - *pp += STRLEN(*pp); + r = enc_canonize(*pp); + *pp += strlen(*pp); } else { - r = vim_strnsave((char_u *)(*pp), (size_t)(p - (char_u *)(*pp))); - *pp = (char *)p + 1; + r = xstrnsave(*pp, (size_t)(p - *pp)); + *pp = p + 1; p = enc_canonize(r); xfree(r); r = p; @@ -2103,7 +2044,7 @@ static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) char_u *tmpname; char *errmsg = NULL; - tmpname = vim_tempname(); + tmpname = (char_u *)vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { @@ -2145,8 +2086,8 @@ static void check_marks_read(void) shada_read_marks(); } - /* Always set b_marks_read; needed when 'shada' is changed to include - * the ' parameter after opening a buffer. */ + // Always set b_marks_read; needed when 'shada' is changed to include + // the ' parameter after opening a buffer. curbuf->b_marks_read = true; } @@ -2161,9 +2102,9 @@ char *new_file_message(void) /// /// If "forceit" is true, we don't care for errors when attempting backups. /// In case of an error everything possible is done to restore the original -/// file. But when "forceit" is TRUE, we risk losing it. +/// file. But when "forceit" is true, we risk losing it. /// -/// When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and +/// When "reset_changed" is true and "append" == false and "start" == 1 and /// "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. /// /// This function must NOT use NameBuff (because it's called by autowrite()). @@ -2204,9 +2145,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int bufsize; long perm; // file permissions int retval = OK; - int newfile = false; // TRUE if file doesn't exist yet + int newfile = false; // true if file doesn't exist yet int msg_save = msg_scroll; - int overwriting; // TRUE if writing over original + int overwriting; // true if writing over original int no_eol = false; // no end-of-line written int device = false; // writing to a device int prev_got_int = got_int; @@ -2215,7 +2156,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; #if defined(UNIX) - int made_writable = FALSE; // 'w' bit has been set + int made_writable = false; // 'w' bit has been set #endif // writing everything int whole = (start == 1 && end == buf->b_ml.ml_line_count); @@ -2231,10 +2172,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int wb_flags = 0; #endif #ifdef HAVE_ACL - vim_acl_T acl = NULL; /* ACL copied from original file to - backup or new file */ + vim_acl_T acl = NULL; // ACL copied from original file to + // backup or new file #endif - int write_undo_file = FALSE; + int write_undo_file = false; context_sha256_T sha_ctx; unsigned int bkc = get_bkc_value(buf); const pos_T orig_start = buf->b_op_start; @@ -2244,46 +2185,42 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en return FAIL; } if (buf->b_ml.ml_mfp == NULL) { - /* This can happen during startup when there is a stray "w" in the - * vimrc file. */ + // This can happen during startup when there is a stray "w" in the + // vimrc file. emsg(_(e_emptybuf)); return FAIL; } - /* - * Disallow writing from .exrc and .vimrc in current directory for - * security reasons. - */ + // Disallow writing from .exrc and .vimrc in current directory for + // security reasons. if (check_secure()) { return FAIL; } // Avoid a crash for a long name. - if (STRLEN(fname) >= MAXPATHL) { + if (strlen(fname) >= MAXPATHL) { emsg(_(e_longname)); return FAIL; } // must init bw_conv_buf and bw_iconv_fd before jumping to "fail" write_info.bw_conv_buf = NULL; - write_info.bw_conv_error = FALSE; + write_info.bw_conv_error = false; write_info.bw_conv_error_lnum = 0; write_info.bw_restlen = 0; #ifdef HAVE_ICONV write_info.bw_iconv_fd = (iconv_t)-1; #endif - /* After writing a file changedtick changes but we don't want to display - * the line. */ + // After writing a file changedtick changes but we don't want to display + // the line. ex_no_reprint = true; - /* - * If there is no file name yet, use the one for the written file. - * BF_NOTEDITED is set to reflect this (in case the write fails). - * Don't do this when the write is for a filter command. - * Don't do this when appending. - * Only do this when 'cpoptions' contains the 'F' flag. - */ + // If there is no file name yet, use the one for the written file. + // BF_NOTEDITED is set to reflect this (in case the write fails). + // Don't do this when the write is for a filter command. + // Don't do this when appending. + // Only do this when 'cpoptions' contains the 'F' flag. if (buf->b_ffname == NULL && reset_changed && whole @@ -2311,17 +2248,15 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en fname = sfname; #endif - if (buf->b_ffname != NULL && FNAMECMP(ffname, buf->b_ffname) == 0) { + if (buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0) { overwriting = true; } else { - overwriting = FALSE; + overwriting = false; } - ++no_wait_return; // don't wait for return yet + no_wait_return++; // don't wait for return yet - /* - * Set '[ and '] marks to the lines to be written. - */ + // Set '[ and '] marks to the lines to be written. buf->b_op_start.lnum = start; buf->b_op_start.col = 0; buf->b_op_end.lnum = end; @@ -2329,20 +2264,18 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en { aco_save_T aco; - int buf_ffname = FALSE; - int buf_sfname = FALSE; - int buf_fname_f = FALSE; - int buf_fname_s = FALSE; - int did_cmd = FALSE; - int nofile_err = FALSE; + int buf_ffname = false; + int buf_sfname = false; + int buf_fname_f = false; + int buf_fname_s = false; + int did_cmd = false; + int nofile_err = false; int empty_memline = (buf->b_ml.ml_mfp == NULL); bufref_T bufref; - /* - * Apply PRE autocommands. - * Set curbuf to the buffer to be written. - * Careful: The autocommands may call buf_write() recursively! - */ + // Apply PRE autocommands. + // Set curbuf to the buffer to be written. + // Careful: The autocommands may call buf_write() recursively! if (ffname == buf->b_ffname) { buf_ffname = true; } @@ -2380,9 +2313,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en sfname, sfname, false, curbuf, eap); if (did_cmd) { if (was_changed && !curbufIsChanged()) { - /* Written everything correctly and BufWriteCmd has reset - * 'modified': Correct the undo information so that an - * undo now sets 'modified'. */ + // Written everything correctly and BufWriteCmd has reset + // 'modified': Correct the undo information so that an + // undo now sets 'modified'. u_unchanged(curbuf); u_update_save_nr(curbuf); } @@ -2428,19 +2361,19 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en no_wait_return--; msg_scroll = msg_save; if (nofile_err) { - emsg(_("E676: No matching autocommands for acwrite buffer")); + semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); } if (nofile_err || aborting()) { - /* An aborting error, interrupt or exception in the - * autocommands. */ + // An aborting error, interrupt or exception in the + // autocommands. return FAIL; } if (did_cmd) { if (buf == NULL) { - /* The buffer was deleted. We assume it was written - * (can't retry anyway). */ + // The buffer was deleted. We assume it was written + // (can't retry anyway). return OK; } if (overwriting) { @@ -2465,12 +2398,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en return FAIL; } - /* - * The autocommands may have changed the number of lines in the file. - * When writing the whole file, adjust the end. - * When writing part of the file, assume that the autocommands only - * changed the number of lines that are to be written (tricky!). - */ + // The autocommands may have changed the number of lines in the file. + // When writing the whole file, adjust the end. + // When writing part of the file, assume that the autocommands only + // changed the number of lines that are to be written (tricky!). if (buf->b_ml.ml_line_count != old_line_count) { if (whole) { // write all end = buf->b_ml.ml_line_count; @@ -2487,10 +2418,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - /* - * The autocommands may have changed the name of the buffer, which may - * be kept in fname, ffname and sfname. - */ + // The autocommands may have changed the name of the buffer, which may + // be kept in fname, ffname and sfname. if (buf_ffname) { ffname = buf->b_ffname; } @@ -2512,20 +2441,20 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } if (shortmess(SHM_OVER) && !exiting) { - msg_scroll = FALSE; // overwrite previous file message + msg_scroll = false; // overwrite previous file message } else { - msg_scroll = TRUE; // don't overwrite previous file message + msg_scroll = true; // don't overwrite previous file message } if (!filtering) { filemess(buf, #ifndef UNIX (char_u *)sfname, #else - (char_u *)fname, + fname, #endif - (char_u *)"", 0); // show that we are busy + "", 0); // show that we are busy } - msg_scroll = FALSE; // always overwrite the file message now + msg_scroll = false; // always overwrite the file message now buffer = verbose_try_malloc(BUFSIZE); // can't allocate big buffer, use small one (to be able to write when out of @@ -2537,9 +2466,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bufsize = BUFSIZE; } - /* - * Get information about original file (if there is one). - */ + // Get information about original file (if there is one). FileInfo file_info_old; #if defined(UNIX) perm = -1; @@ -2556,10 +2483,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; } - /* It's a device of some kind (or a fifo) which we can write to - * but for which we can't make a backup. */ - device = TRUE; - newfile = TRUE; + // It's a device of some kind (or a fifo) which we can write to + // but for which we can't make a backup. + device = true; + newfile = true; perm = -1; } } @@ -2571,8 +2498,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } if (c == NODE_WRITABLE) { - device = TRUE; - newfile = TRUE; + device = true; + newfile = true; perm = -1; } else { perm = os_getperm((const char *)fname); @@ -2589,10 +2516,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // !UNIX if (!device && !newfile) { - /* - * Check if the file is really writable (when renaming the file to - * make a backup we won't discover it later). - */ + // Check if the file is really writable (when renaming the file to + // make a backup we won't discover it later). file_readonly = !os_file_is_writable(fname); if (!forceit && file_readonly) { @@ -2604,10 +2529,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } - /* - * Check if the timestamp hasn't changed since reading the file. - */ - if (overwriting) { + // If 'forceit' is false, check if the timestamp hasn't changed since reading the file. + if (overwriting && !forceit) { retval = check_mtime(buf, &file_info_old); if (retval == FAIL) { goto fail; @@ -2616,71 +2539,59 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } #ifdef HAVE_ACL - /* - * For systems that support ACL: get the ACL from the original file. - */ + // For systems that support ACL: get the ACL from the original file. if (!newfile) { acl = mch_get_acl((char_u *)fname); } #endif - /* - * If 'backupskip' is not empty, don't make a backup for some files. - */ + // If 'backupskip' is not empty, don't make a backup for some files. dobackup = (p_wb || p_bk || *p_pm != NUL); if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, (char_u *)sfname, (char_u *)ffname)) { dobackup = false; } - /* - * Save the value of got_int and reset it. We don't want a previous - * interruption cancel writing, only hitting CTRL-C while writing should - * abort it. - */ + // Save the value of got_int and reset it. We don't want a previous + // interruption cancel writing, only hitting CTRL-C while writing should + // abort it. prev_got_int = got_int; - got_int = FALSE; + got_int = false; // Mark the buffer as 'being saved' to prevent changed buffer warnings buf->b_saving = true; - /* - * If we are not appending or filtering, the file exists, and the - * 'writebackup', 'backup' or 'patchmode' option is set, need a backup. - * When 'patchmode' is set also make a backup when appending. - * - * Do not make any backup, if 'writebackup' and 'backup' are both switched - * off. This helps when editing large files on almost-full disks. - */ + // If we are not appending or filtering, the file exists, and the + // 'writebackup', 'backup' or 'patchmode' option is set, need a backup. + // When 'patchmode' is set also make a backup when appending. + // + // Do not make any backup, if 'writebackup' and 'backup' are both switched + // off. This helps when editing large files on almost-full disks. if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { FileInfo file_info; const bool no_prepend_dot = false; if ((bkc & BKC_YES) || append) { // "yes" - backup_copy = TRUE; + backup_copy = true; } else if ((bkc & BKC_AUTO)) { // "auto" int i; - /* - * Don't rename the file when: - * - it's a hard link - * - it's a symbolic link - * - we don't have write permission in the directory - */ + // Don't rename the file when: + // - it's a hard link + // - it's a symbolic link + // - we don't have write permission in the directory if (os_fileinfo_hardlinks(&file_info_old) > 1 || !os_fileinfo_link(fname, &file_info) || !os_fileinfo_id_equal(&file_info, &file_info_old)) { - backup_copy = TRUE; + backup_copy = true; } else { - /* - * Check if we can create a file and set the owner/group to - * the ones from the original file. - * First find a file name that doesn't exist yet (use some - * arbitrary numbers). - */ + // Check if we can create a file and set the owner/group to + // the ones from the original file. + // First find a file name that doesn't exist yet (use some + // arbitrary numbers). STRCPY(IObuff, fname); for (i = 4913;; i += 123) { char *tail = path_tail((char *)IObuff); - size_t size = (size_t)((char_u *)tail - IObuff); + size_t size = (size_t)(tail - IObuff); snprintf(tail, IOSIZE - size, "%d", i); if (!os_fileinfo_link((char *)IObuff, &file_info)) { break; @@ -2689,7 +2600,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en fd = os_open((char *)IObuff, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, (int)perm); if (fd < 0) { // can't write in directory - backup_copy = TRUE; + backup_copy = true; } else { #ifdef UNIX os_fchown(fd, (uv_uid_t)file_info_old.stat.st_uid, (uv_gid_t)file_info_old.stat.st_gid); @@ -2697,20 +2608,18 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en || file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_gid != file_info_old.stat.st_gid || (long)file_info.stat.st_mode != perm) { - backup_copy = TRUE; + backup_copy = true; } #endif - /* Close the file before removing it, on MS-Windows we - * can't delete an open file. */ + // Close the file before removing it, on MS-Windows we + // can't delete an open file. close(fd); os_remove((char *)IObuff); } } } - /* - * Break symlinks and/or hardlinks if we've been asked to. - */ + // Break symlinks and/or hardlinks if we've been asked to. if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) { #ifdef UNIX bool file_info_link_ok = os_fileinfo_link(fname, &file_info); @@ -2719,7 +2628,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if ((bkc & BKC_BREAKSYMLINK) && file_info_link_ok && !os_fileinfo_id_equal(&file_info, &file_info_old)) { - backup_copy = FALSE; + backup_copy = false; } // Hardlinks. @@ -2727,7 +2636,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en && os_fileinfo_hardlinks(&file_info_old) > 1 && (!file_info_link_ok || os_fileinfo_id_equal(&file_info, &file_info_old))) { - backup_copy = FALSE; + backup_copy = false; } #endif } @@ -2736,7 +2645,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (*p_bex == NUL) { backup_ext = ".bak"; } else { - backup_ext = (char *)p_bex; + backup_ext = p_bex; } if (backup_copy) { @@ -2746,30 +2655,26 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en char *rootname; char *p; - /* - * Try to make the backup in each directory in the 'bdir' option. - * - * Unix semantics has it, that we may have a writable file, - * that cannot be recreated with a simple open(..., O_CREAT, ) e.g: - * - the directory is not writable, - * - the file may be a symbolic link, - * - the file may belong to another user/group, etc. - * - * For these reasons, the existing writable file must be truncated - * and reused. Creation of a backup COPY will be attempted. - */ - dirp = (char *)p_bdir; + // Try to make the backup in each directory in the 'bdir' option. + // + // Unix semantics has it, that we may have a writable file, + // that cannot be recreated with a simple open(..., O_CREAT, ) e.g: + // - the directory is not writable, + // - the file may be a symbolic link, + // - the file may belong to another user/group, etc. + // + // For these reasons, the existing writable file must be truncated + // and reused. Creation of a backup COPY will be attempted. + dirp = p_bdir; while (*dirp) { - /* - * Isolate one directory name, using an entry in 'bdir'. - */ + // Isolate one directory name, using an entry in 'bdir'. size_t dir_len = copy_option_part(&dirp, (char *)IObuff, IOSIZE, ","); p = (char *)IObuff + dir_len; bool trailing_pathseps = after_pathsep((char *)IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; } - if (*dirp == NUL && !os_isdir(IObuff)) { + if (*dirp == NUL && !os_isdir((char *)IObuff)) { int ret; char *failed_dir; if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) { @@ -2787,9 +2692,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - rootname = (char *)get_file_in_dir((char_u *)fname, IObuff); + rootname = get_file_in_dir(fname, (char *)IObuff); if (rootname == NULL) { - some_error = TRUE; // out of memory + some_error = true; // out of memory goto nobackup; } @@ -2804,13 +2709,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (backup == NULL) { xfree(rootname); - some_error = TRUE; // out of memory + some_error = true; // out of memory goto nobackup; } - /* - * Check if backup file already exists. - */ + // Check if backup file already exists. if (os_fileinfo(backup, &file_info_new)) { if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { // @@ -2825,7 +2728,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // delete an existing one, and try to use another name instead. // Change one character, just before the extension. // - wp = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); + wp = backup + strlen(backup) - 1 - strlen(backup_ext); if (wp < backup) { // empty file name ??? wp = backup; } @@ -2842,9 +2745,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } xfree(rootname); - /* - * Try to create the backup file - */ + // Try to create the backup file if (backup != NULL) { // remove old backup, if present os_remove(backup); @@ -2889,7 +2790,7 @@ nobackup: if (backup == NULL && errmsg == NULL) { SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)")); } - // Ignore errors when forceit is TRUE. + // Ignore errors when forceit is true. if ((some_error || errmsg != NULL) && !forceit) { retval = FAIL; goto fail; @@ -2900,37 +2801,29 @@ nobackup: char *p; char *rootname; - /* - * Make a backup by renaming the original file. - */ - /* - * If 'cpoptions' includes the "W" flag, we don't want to - * overwrite a read-only file. But rename may be possible - * anyway, thus we need an extra check here. - */ + // Make a backup by renaming the original file. + + // If 'cpoptions' includes the "W" flag, we don't want to + // overwrite a read-only file. But rename may be possible + // anyway, thus we need an extra check here. if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { SET_ERRMSG_NUM("E504", _(err_readonly)); goto fail; } - /* - * - * Form the backup file name - change path/fo.o.h to - * path/fo.o.h.bak Try all directories in 'backupdir', first one - * that works is used. - */ - dirp = (char *)p_bdir; + // Form the backup file name - change path/fo.o.h to + // path/fo.o.h.bak Try all directories in 'backupdir', first one + // that works is used. + dirp = p_bdir; while (*dirp) { - /* - * Isolate one directory name and make the backup file name. - */ + // Isolate one directory name and make the backup file name. size_t dir_len = copy_option_part(&dirp, (char *)IObuff, IOSIZE, ","); p = (char *)IObuff + dir_len; bool trailing_pathseps = after_pathsep((char *)IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; } - if (*dirp == NUL && !os_isdir(IObuff)) { + if (*dirp == NUL && !os_isdir((char *)IObuff)) { int ret; char *failed_dir; if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) { @@ -2949,7 +2842,7 @@ nobackup: } if (backup == NULL) { - rootname = (char *)get_file_in_dir((char_u *)fname, IObuff); + rootname = get_file_in_dir(fname, (char *)IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -2959,18 +2852,16 @@ nobackup: } if (backup != NULL) { - /* - * If we are not going to keep the backup file, don't - * delete an existing one, try to use another name. - * Change one character, just before the extension. - */ - if (!p_bk && os_path_exists((char_u *)backup)) { - p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); + // If we are not going to keep the backup file, don't + // delete an existing one, try to use another name. + // Change one character, just before the extension. + if (!p_bk && os_path_exists(backup)) { + p = backup + strlen(backup) - 1 - strlen(backup_ext); if (p < backup) { // empty file name ??? p = backup; } *p = 'z'; - while (*p > 'a' && os_path_exists((char_u *)backup)) { + while (*p > 'a' && os_path_exists(backup)) { (*p)--; } // They all exist??? Must be something wrong! @@ -2988,7 +2879,7 @@ nobackup: // If the renaming of the original file to the backup file // works, quit here. /// - if (vim_rename((char_u *)fname, (char_u *)backup) == 0) { + if (vim_rename(fname, backup) == 0) { break; } @@ -3049,14 +2940,14 @@ nobackup: // Check for forced 'fileencoding' from "++opt=val" argument. if (eap != NULL && eap->force_enc != 0) { fenc = eap->cmd + eap->force_enc; - fenc = (char *)enc_canonize((char_u *)fenc); + fenc = enc_canonize(fenc); fenc_tofree = fenc; } else { - fenc = (char *)buf->b_p_fenc; + fenc = buf->b_p_fenc; } // Check if the file needs to be converted. - converted = need_conversion((char_u *)fenc); + converted = need_conversion(fenc); // Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). @@ -3089,23 +2980,26 @@ nobackup: if (!write_info.bw_conv_buf) { end = 0; } - write_info.bw_first = TRUE; - } else + write_info.bw_first = true; + } else { #endif - /* - * When the file needs to be converted with 'charconvert' after - * writing, write to a temp file instead and let the conversion - * overwrite the original file. - */ + // When the file needs to be converted with 'charconvert' after + // writing, write to a temp file instead and let the conversion + // overwrite the original file. if (*p_ccv != NUL) { - wfname = (char *)vim_tempname(); + wfname = vim_tempname(); if (wfname == NULL) { // Can't write without a tempfile! SET_ERRMSG(_("E214: Can't find temp file for writing")); goto restore_backup; } } } + +#ifdef HAVE_ICONV +} +#endif + if (converted && wb_flags == 0 #ifdef HAVE_ICONV && write_info.bw_iconv_fd == (iconv_t)-1 @@ -3115,7 +3009,7 @@ nobackup: SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)")); goto restore_backup; } - notconverted = TRUE; + notconverted = true; } // If conversion is taking place, we may first pretend to write and check @@ -3137,12 +3031,12 @@ nobackup: } else { // Open the file "wfname" for writing. // We may try to open the file twice: If we can't write to the file - // and forceit is TRUE we delete the existing file and try to + // and forceit is true we delete the existing file and try to // create a new one. If this still fails we may have lost the // original file! (this may happen when the user reached his // quotum for number of files). // Appending will fail if the file does not exist and forceit is - // FALSE. + // false. while ((fd = os_open(wfname, O_WRONLY | (append ? @@ -3200,21 +3094,21 @@ restore_backup: // This may not work if the vim_rename() fails. // In that case we leave the copy around. // If file does not exist, put the copy in its place - if (!os_path_exists((char_u *)fname)) { - vim_rename((char_u *)backup, (char_u *)fname); + if (!os_path_exists(fname)) { + vim_rename(backup, fname); } // if original file does exist throw away the copy - if (os_path_exists((char_u *)fname)) { + if (os_path_exists(fname)) { os_remove(backup); } } else { // try to put the original file back - vim_rename((char_u *)backup, (char_u *)fname); + vim_rename(backup, fname); } } // if original file no longer exists give an extra warning - if (!newfile && !os_path_exists((char_u *)fname)) { + if (!newfile && !os_path_exists(fname)) { end = 0; } } @@ -3271,9 +3165,9 @@ restore_backup: for (lnum = start; lnum <= end; lnum++) { // The next while loop is done once for each character written. // Keep it fast! - ptr = (char *)ml_get_buf(buf, lnum, false) - 1; + ptr = ml_get_buf(buf, lnum, false) - 1; if (write_undo_file) { - sha256_update(&sha_ctx, (char_u *)ptr + 1, (uint32_t)(STRLEN(ptr + 1) + 1)); + sha256_update(&sha_ctx, (char_u *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); } while ((c = *++ptr) != NUL) { if (c == NL) { @@ -3366,7 +3260,7 @@ restore_backup: // been written to disk and we don't lose it. // For a device do try the fsync() but don't complain if it does not work // (could be a pipe). - // If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. + // If the 'fsync' option is false, don't fsync(). Useful for laptops. int error; if (p_fs && (error = os_fsync(fd)) != 0 && !device // fsync not supported on this storage. @@ -3476,7 +3370,7 @@ restore_backup: end = 1; // success } } else { - if (vim_rename((char_u *)backup, (char_u *)fname) == 0) { + if (vim_rename(backup, fname) == 0) { end = 1; } } @@ -3485,7 +3379,7 @@ restore_backup: } lnum -= start; // compute number of written lines - --no_wait_return; // may wait for return now + no_wait_return--; // may wait for return now #if !defined(UNIX) fname = sfname; // use shortname now, for the messages @@ -3495,32 +3389,32 @@ restore_backup: c = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); - c = TRUE; + c = true; if (write_info.bw_conv_error_lnum != 0) { vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %" PRId64 ";"), (int64_t)write_info.bw_conv_error_lnum); } } else if (notconverted) { STRCAT(IObuff, _("[NOT converted]")); - c = TRUE; + c = true; } else if (converted) { STRCAT(IObuff, _("[converted]")); - c = TRUE; + c = true; } if (device) { STRCAT(IObuff, _("[Device]")); - c = TRUE; + c = true; } else if (newfile) { STRCAT(IObuff, new_file_message()); c = true; } if (no_eol) { msg_add_eol(); - c = TRUE; + c = true; } // may add [unix/dos/mac] if (msg_add_fileformat(fileformat)) { - c = TRUE; + c = true; } msg_add_lines(c, (long)lnum, nchars); // add line/char count if (!shortmess(SHM_WRITE)) { @@ -3534,8 +3428,8 @@ restore_backup: set_keep_msg(msg_trunc_attr((char *)IObuff, false, 0), 0); } - /* When written everything correctly: reset 'modified'. Unless not - * writing to the original file and '+' is not in 'cpoptions'. */ + // When written everything correctly: reset 'modified'. Unless not + // writing to the original file and '+' is not in 'cpoptions'. if (reset_changed && whole && !append && !write_info.bw_conv_error && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { @@ -3550,10 +3444,8 @@ restore_backup: u_update_save_nr(buf); } - /* - * If written to the current file, update the timestamp of the swap file - * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. - */ + // If written to the current file, update the timestamp of the swap file + // and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. if (overwriting) { ml_timestamp(buf); if (append) { @@ -3563,22 +3455,18 @@ restore_backup: } } - /* - * If we kept a backup until now, and we are in patch mode, then we make - * the backup file our 'original' file. - */ + // If we kept a backup until now, and we are in patch mode, then we make + // the backup file our 'original' file. if (*p_pm && dobackup) { - char *const org = modname(fname, (char *)p_pm, false); + char *const org = modname(fname, p_pm, false); if (backup != NULL) { - /* - * If the original file does not exist yet - * the current backup file becomes the original file - */ + // If the original file does not exist yet + // the current backup file becomes the original file if (org == NULL) { emsg(_("E205: Patchmode: can't save original file")); - } else if (!os_path_exists((char_u *)org)) { - vim_rename((char_u *)backup, (char_u *)org); + } else if (!os_path_exists(org)) { + vim_rename(backup, org); XFREE_CLEAR(backup); // don't delete the file #ifdef UNIX os_file_settime(org, @@ -3586,12 +3474,9 @@ restore_backup: (double)file_info_old.stat.st_mtim.tv_sec); #endif } - } - /* - * If there is no backup file, remember that a (new) file was - * created. - */ - else { + } else { + // If there is no backup file, remember that a (new) file was + // created. int empty_fd; if (org == NULL @@ -3609,9 +3494,7 @@ restore_backup: } } - /* - * Remove the backup unless 'backup' option is set - */ + // Remove the backup unless 'backup' option is set if (!p_bk && backup != NULL && !write_info.bw_conv_error && os_remove(backup) != 0) { @@ -3620,11 +3503,9 @@ restore_backup: goto nofail; - /* - * Finish up. We get here either after failure or success. - */ + // Finish up. We get here either after failure or success. fail: - --no_wait_return; // may wait for return now + no_wait_return--; // may wait for return now nofail: // Done saving, we accept changed buffer warnings again @@ -3687,10 +3568,8 @@ nofail: } msg_scroll = msg_save; - /* - * When writing the whole file and 'undofile' is set, also write the undo - * file. - */ + // When writing the whole file and 'undofile' is set, also write the undo + // file. if (retval == OK && write_undo_file) { char hash[UNDO_HASH_SIZE]; @@ -3703,31 +3582,29 @@ nofail: curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read - /* - * Apply POST autocommands. - * Careful: The autocommands may call buf_write() recursively! - */ + // Apply POST autocommands. + // Careful: The autocommands may call buf_write() recursively! aucmd_prepbuf(&aco, buf); if (append) { apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, - FALSE, curbuf, eap); + false, curbuf, eap); } else if (filtering) { apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, - FALSE, curbuf, eap); + false, curbuf, eap); } else if (reset_changed && whole) { apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, - FALSE, curbuf, eap); + false, curbuf, eap); } else { apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, - FALSE, curbuf, eap); + false, curbuf, eap); } // restore curwin/curbuf and a few other things aucmd_restbuf(&aco); if (aborting()) { // autocmds may abort script processing - retval = FALSE; + retval = false; } } @@ -3834,20 +3711,20 @@ void msg_add_lines(int insert_space, long lnum, off_T nchars) { char_u *p; - p = IObuff + STRLEN(IObuff); + p = (char_u *)IObuff + STRLEN(IObuff); if (insert_space) { *p++ = ' '; } if (shortmess(SHM_LINES)) { - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), "%" PRId64 "L, %" PRId64 "B", + vim_snprintf((char *)p, (size_t)(IOSIZE - (p - (char_u *)IObuff)), "%" PRId64 "L, %" PRId64 "B", (int64_t)lnum, (int64_t)nchars); } else { - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), + vim_snprintf((char *)p, (size_t)(IOSIZE - (p - (char_u *)IObuff)), NGETTEXT("%" PRId64 " line, ", "%" PRId64 " lines, ", lnum), (int64_t)lnum); p += STRLEN(p); - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), + vim_snprintf((char *)p, (size_t)(IOSIZE - (p - (char_u *)IObuff)), NGETTEXT("%" PRId64 " byte", "%" PRId64 " bytes", nchars), (int64_t)nchars); } @@ -3907,18 +3784,14 @@ static int buf_write_bytes(struct bw_info *ip) int flags = ip->bw_flags; // extra flags #endif - /* - * Skip conversion when writing the BOM. - */ + // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { char_u *p; unsigned c; int n; if (flags & FIO_UTF8) { - /* - * Convert latin1 in the buffer to UTF-8 in the file. - */ + // Convert latin1 in the buffer to UTF-8 in the file. p = ip->bw_conv_buf; // translate to buffer for (wlen = 0; wlen < len; wlen++) { p += utf_char2bytes(buf[wlen], (char *)p); @@ -3926,10 +3799,8 @@ static int buf_write_bytes(struct bw_info *ip) buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { - /* - * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or - * Latin1 chars in the file. - */ + // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or + // Latin1 chars in the file. if (flags & FIO_LATIN1) { p = buf; // translate in-place (can only get shorter) } else { @@ -3939,9 +3810,9 @@ static int buf_write_bytes(struct bw_info *ip) if (wlen == 0 && ip->bw_restlen != 0) { int l; - /* Use remainder of previous call. Append the start of - * buf[] to get a full sequence. Might still be too - * short! */ + // Use remainder of previous call. Append the start of + // buf[] to get a full sequence. Might still be too + // short! l = CONV_RESTLEN - ip->bw_restlen; if (l > len) { l = len; @@ -3949,9 +3820,9 @@ static int buf_write_bytes(struct bw_info *ip) memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); if (n > ip->bw_restlen + len) { - /* We have an incomplete byte sequence at the end to - * be written. We can't convert it without the - * remaining bytes. Keep them for the next call. */ + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. if (ip->bw_restlen + len > CONV_RESTLEN) { return FAIL; } @@ -3975,9 +3846,9 @@ static int buf_write_bytes(struct bw_info *ip) } else { n = utf_ptr2len_len(buf + wlen, len - wlen); if (n > len - wlen) { - /* We have an incomplete byte sequence at the end to - * be written. We can't convert it without the - * remaining bytes. Keep them for the next call. */ + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. if (len - wlen > CONV_RESTLEN) { return FAIL; } @@ -3994,11 +3865,11 @@ static int buf_write_bytes(struct bw_info *ip) } if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { - ip->bw_conv_error = TRUE; + ip->bw_conv_error = true; ip->bw_conv_error_lnum = ip->bw_start_lnum; } if (c == NL) { - ++ip->bw_start_lnum; + ip->bw_start_lnum++; } } if (flags & FIO_LATIN1) { @@ -4020,9 +3891,9 @@ static int buf_write_bytes(struct bw_info *ip) if (ip->bw_restlen > 0) { char *fp; - /* Need to concatenate the remainder of the previous call and - * the bytes of the current call. Use the end of the - * conversion buffer for this. */ + // Need to concatenate the remainder of the previous call and + // the bytes of the current call. Use the end of the + // conversion buffer for this. fromlen = (size_t)len + (size_t)ip->bw_restlen; fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); @@ -4042,23 +3913,20 @@ static int buf_write_bytes(struct bw_info *ip) // output the initial shift state sequence (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen); - /* There is a bug in iconv() on Linux (which appears to be - * wide-spread) which sets "to" to NULL and messes up "tolen". - */ + // There is a bug in iconv() on Linux (which appears to be + // wide-spread) which sets "to" to NULL and messes up "tolen". if (to == NULL) { to = (char *)ip->bw_conv_buf; tolen = save_len; } - ip->bw_first = FALSE; + ip->bw_first = false; } - /* - * If iconv() has an error or there is not enough room, fail. - */ + // If iconv() has an error or there is not enough room, fail. if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen) == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) || fromlen > CONV_RESTLEN) { - ip->bw_conv_error = TRUE; + ip->bw_conv_error = true; return FAIL; } @@ -4110,8 +3978,8 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL } else if (flags & (FIO_UCS2 | FIO_UTF16)) { if (c >= 0x10000) { if (flags & FIO_UTF16) { - /* Make two words, ten bits of the character in each. First - * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */ + // Make two words, ten bits of the character in each. First + // word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff c -= 0x10000; if (c >= 0x100000) { error = true; @@ -4155,21 +4023,21 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL /// @param fenc file encoding to check /// /// @return true if conversion is required -static bool need_conversion(const char_u *fenc) +static bool need_conversion(const char *fenc) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { int same_encoding; int enc_flags; int fenc_flags; - if (*fenc == NUL || STRCMP(p_enc, fenc) == 0) { - same_encoding = TRUE; + if (*fenc == NUL || strcmp(p_enc, fenc) == 0) { + same_encoding = true; fenc_flags = 0; } else { // Ignore difference between "ansi" and "latin1", "ucs-4" and // "ucs-4be", etc. - enc_flags = get_fio_flags(p_enc); - fenc_flags = get_fio_flags(fenc); + enc_flags = get_fio_flags((char_u *)p_enc); + fenc_flags = get_fio_flags((char_u *)fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } if (same_encoding) { @@ -4192,7 +4060,7 @@ static int get_fio_flags(const char_u *name) int prop; if (*name == NUL) { - name = p_enc; + name = (char_u *)p_enc; } prop = enc_canon_props(name); if (prop & ENC_UNICODE) { @@ -4296,10 +4164,10 @@ static int make_bom(char_u *buf, char_u *name) /// Shorten filename of a buffer. /// -/// @param force when TRUE: Use full path from now on for files currently being +/// @param force when true: Use full path from now on for files currently being /// edited, both for file name and swap file name. Try to shorten the file /// names a bit, if safe to do so. -/// when FALSE: Only try to shorten absolute file names. +/// when false: Only try to shorten absolute file names. /// /// For buffers that have buftype "nofile" or "scratch": never change the file /// name. @@ -4316,7 +4184,7 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = (char *)path_shorten_fname((char_u *)buf->b_ffname, dirname); + p = path_shorten_fname(buf->b_ffname, (char *)dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4386,7 +4254,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) } add_pathsep(retval); fnamelen = strlen(retval); - prepend_dot = FALSE; // nothing to prepend a dot to + prepend_dot = false; // nothing to prepend a dot to } else { fnamelen = strlen(fname); retval = xmalloc(fnamelen + extlen + 3); @@ -4608,7 +4476,7 @@ int put_time(FILE *fd, time_t time_) /// function will (attempts to?) copy the file across if rename fails -- webb /// /// @return -1 for failure, 0 for success -int vim_rename(const char_u *from, const char_u *to) +int vim_rename(const char *from, const char *to) FUNC_ATTR_NONNULL_ALL { int fd_in; @@ -4622,13 +4490,11 @@ int vim_rename(const char_u *from, const char_u *to) #endif bool use_tmp_file = false; - /* - * When the names are identical, there is nothing to do. When they refer - * to the same file (ignoring case and slash/backslash differences) but - * the file name differs we need to go through a temp file. - */ - if (FNAMECMP(from, to) == 0) { - if (p_fic && (STRCMP(path_tail((char *)from), path_tail((char *)to)) + // When the names are identical, there is nothing to do. When they refer + // to the same file (ignoring case and slash/backslash differences) but + // the file name differs we need to go through a temp file. + if (path_fnamecmp(from, to) == 0) { + if (p_fic && (strcmp(path_tail((char *)from), path_tail((char *)to)) != 0)) { use_tmp_file = true; } else { @@ -4654,11 +4520,9 @@ int vim_rename(const char_u *from, const char_u *to) if (use_tmp_file) { char_u tempname[MAXPATHL + 1]; - /* - * Find a name that doesn't exist and is in the same directory. - * Rename "from" to "tempname" and then rename "tempname" to "to". - */ - if (STRLEN(from) >= MAXPATHL - 5) { + // Find a name that doesn't exist and is in the same directory. + // Rename "from" to "tempname" and then rename "tempname" to "to". + if (strlen(from) >= MAXPATHL - 5) { return -1; } STRCPY(tempname, from); @@ -4666,14 +4530,14 @@ int vim_rename(const char_u *from, const char_u *to) char *tail = path_tail((char *)tempname); snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - (char *)tempname - 1)), "%d", n); - if (!os_path_exists(tempname)) { - if (os_rename(from, tempname) == OK) { - if (os_rename(tempname, to) == OK) { + if (!os_path_exists((char *)tempname)) { + if (os_rename((char_u *)from, tempname) == OK) { + if (os_rename(tempname, (char_u *)to) == OK) { return 0; } // Strange, the second step failed. Try moving the // file back and return failure. - (void)os_rename(tempname, from); + (void)os_rename(tempname, (char_u *)from); return -1; } // If it fails for one temp name it will most likely fail @@ -4684,28 +4548,22 @@ int vim_rename(const char_u *from, const char_u *to) return -1; } - /* - * Delete the "to" file, this is required on some systems to make the - * os_rename() work, on other systems it makes sure that we don't have - * two files when the os_rename() fails. - */ + // Delete the "to" file, this is required on some systems to make the + // os_rename() work, on other systems it makes sure that we don't have + // two files when the os_rename() fails. os_remove((char *)to); - /* - * First try a normal rename, return if it works. - */ - if (os_rename(from, to) == OK) { + // First try a normal rename, return if it works. + if (os_rename((char_u *)from, (char_u *)to) == OK) { return 0; } - /* - * Rename() failed, try copying the file. - */ - perm = os_getperm((const char *)from); + // Rename() failed, try copying the file. + perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. - acl = mch_get_acl(from); + acl = mch_get_acl((char_u *)from); #endif fd_in = os_open((char *)from, O_RDONLY, 0); if (fd_in < 0) { @@ -4758,7 +4616,7 @@ int vim_rename(const char_u *from, const char_u *to) os_setperm((const char *)to, perm); #endif #ifdef HAVE_ACL - mch_set_acl(to, acl); + mch_set_acl((char_u *)to, acl); mch_free_acl(acl); #endif if (errmsg != NULL) { @@ -4769,7 +4627,7 @@ int vim_rename(const char_u *from, const char_u *to) return 0; } -static int already_warned = FALSE; +static int already_warned = false; /// Check if any not hidden buffer has been changed. /// Postpone the check if there are characters in the stuff buffer, a global @@ -4778,7 +4636,7 @@ static int already_warned = FALSE; /// /// @param focus called for GUI focus event /// -/// @return TRUE if some message was written (screen should be redrawn and cursor positioned). +/// @return true if some message was written (screen should be redrawn and cursor positioned). int check_timestamps(int focus) { int didit = 0; @@ -4786,15 +4644,15 @@ int check_timestamps(int focus) // Don't check timestamps while system() or another low-level function may // cause us to lose and gain focus. if (no_check_timestamps > 0) { - return FALSE; + return false; } // Avoid doing a check twice. The OK/Reload dialog can cause a focus // event and we would keep on checking if the file is steadily growing. // Do check again after typing something. if (focus && did_check_timestamps) { - need_check_timestamps = TRUE; - return FALSE; + need_check_timestamps = true; + return false; } if (!stuff_empty() || global_busy || !typebuf_typed() @@ -4841,13 +4699,13 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) buf_T *tbuf = curbuf; int retval = OK; linenr_T lnum; - char_u *p; + char *p; // Copy the lines in "frombuf" to "tobuf". curbuf = tobuf; for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { - p = vim_strsave(ml_get_buf(frombuf, lnum, false)); - if (ml_append(lnum - 1, (char *)p, 0, false) == FAIL) { + p = xstrdup(ml_get_buf(frombuf, lnum, false)); + if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; break; @@ -4882,7 +4740,7 @@ int buf_check_timestamp(buf_T *buf) FUNC_ATTR_NONNULL_ALL { int retval = 0; - char_u *path; + char *path; char *mesg = NULL; char *mesg2 = ""; bool helpmesg = false; @@ -4897,7 +4755,7 @@ int buf_check_timestamp(buf_T *buf) uint64_t orig_size = buf->b_orig_size; int orig_mode = buf->b_orig_mode; static bool busy = false; - char_u *s; + char *s; char *reason; bufref_T bufref; @@ -4937,7 +4795,7 @@ int buf_check_timestamp(buf_T *buf) buf_store_file_info(buf, &file_info); } - if (os_isdir((char_u *)buf->b_fname)) { + if (os_isdir(buf->b_fname)) { // Don't do anything for a directory. Might contain the file explorer. } else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar) && !bufIsChanged(buf) && file_info_ok) { @@ -4972,12 +4830,12 @@ int buf_check_timestamp(buf_T *buf) if (!bufref_valid(&bufref)) { emsg(_("E246: FileChangedShell autocommand deleted buffer")); } - s = (char_u *)get_vim_var_str(VV_FCS_CHOICE); - if (STRCMP(s, "reload") == 0 && *reason != 'd') { + s = get_vim_var_str(VV_FCS_CHOICE); + if (strcmp(s, "reload") == 0 && *reason != 'd') { reload = RELOAD_NORMAL; - } else if (STRCMP(s, "edit") == 0) { + } else if (strcmp(s, "edit") == 0) { reload = RELOAD_DETECT; - } else if (STRCMP(s, "ask") == 0) { + } else if (strcmp(s, "ask") == 0) { n = false; } else { return 2; @@ -5017,7 +4875,7 @@ int buf_check_timestamp(buf_T *buf) } } } else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W) - && os_path_exists((char_u *)buf->b_ffname)) { + && os_path_exists(buf->b_ffname)) { retval = 1; mesg = _("W13: Warning: File \"%s\" has been created after editing started"); buf->b_flags |= BF_NEW_W; @@ -5025,11 +4883,11 @@ int buf_check_timestamp(buf_T *buf) } if (mesg != NULL) { - path = (char_u *)home_replace_save(buf, buf->b_fname); + path = home_replace_save(buf, buf->b_fname); if (!helpmesg) { mesg2 = ""; } - const size_t tbuf_len = STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2; + const size_t tbuf_len = strlen(path) + strlen(mesg) + strlen(mesg2) + 2; char *const tbuf = xmalloc(tbuf_len); snprintf(tbuf, tbuf_len, mesg, path); // Set warningmsg here, before the unimportant and output-specific @@ -5040,8 +4898,8 @@ int buf_check_timestamp(buf_T *buf) xstrlcat(tbuf, "\n", tbuf_len - 1); xstrlcat(tbuf, mesg2, tbuf_len - 1); } - switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf, - (char_u *)_("&OK\n&Load File\nLoad File &and Options"), + switch (do_dialog(VIM_WARNING, _("Warning"), tbuf, + _("&OK\n&Load File\nLoad File &and Options"), 1, NULL, true)) { case 2: reload = RELOAD_NORMAL; @@ -5075,7 +4933,7 @@ int buf_check_timestamp(buf_T *buf) redraw_cmdline = false; } } - already_warned = TRUE; + already_warned = true; } xfree(path); @@ -5306,8 +5164,8 @@ static void vim_mktempdir(void) mode_t umask_save = umask(0077); for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); i++) { // Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999". - expand_env((char_u *)temp_dirs[i], (char_u *)tmp, TEMP_FILE_PATH_MAXLEN - 64); - if (!os_isdir((char_u *)tmp)) { + expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64); + if (!os_isdir(tmp)) { continue; } @@ -5317,7 +5175,7 @@ static void vim_mktempdir(void) xstrlcat(tmp, user, sizeof(tmp)); (void)os_mkdir(tmp, 0700); // Always create, to avoid a race. bool owned = os_file_owned(tmp); - bool isdir = os_isdir((char_u *)tmp); + bool isdir = os_isdir(tmp); #ifdef UNIX int perm = os_getperm(tmp); // XDG_RUNTIME_DIR must be owned by the user, mode 0700. bool valid = isdir && owned && 0700 == (perm & 0777); @@ -5495,7 +5353,7 @@ static bool vim_settempdir(char *tempdir) /// /// @return pointer to the temp file name or NULL if Nvim can't create /// temporary directory for its own temporary files. -char_u *vim_tempname(void) +char *vim_tempname(void) { // Temp filename counter. static uint64_t temp_count; @@ -5507,10 +5365,10 @@ char_u *vim_tempname(void) // There is no need to check if the file exists, because we own the directory // and nobody else creates a file in it. - char_u template[TEMP_FILE_PATH_MAXLEN]; - snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, + char template[TEMP_FILE_PATH_MAXLEN]; + snprintf(template, TEMP_FILE_PATH_MAXLEN, "%s%" PRIu64, tempdir, temp_count++); - return vim_strsave(template); + return xstrdup(template); } /// Tries matching a filename with a "pattern" ("prog" is NULL), or use the @@ -5542,12 +5400,10 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, } } - /* - * Try for a match with the pattern with: - * 1. the full file name, when the pattern has a '/'. - * 2. the short file name, when the pattern has a '/'. - * 3. the tail of the file name, when the pattern has no '/'. - */ + // Try for a match with the pattern with: + // 1. the full file name, when the pattern has a '/'. + // 2. the short file name, when the pattern has a '/'. + // 3. the tail of the file name, when the pattern has no '/'. if (regmatch.regprog != NULL && ((allow_dirs && (vim_regexec(®match, fname, (colnr_T)0) @@ -5606,8 +5462,8 @@ bool match_file_list(char_u *list, char_u *sfname, char_u *ffname) /// Convert the given pattern "pat" which has shell style wildcards in it, into /// a regular expression, and return the result in allocated memory. If there -/// is a directory path separator to be matched, then TRUE is put in -/// allow_dirs, otherwise FALSE is put there -- webb. +/// is a directory path separator to be matched, then true is put in +/// allow_dirs, otherwise false is put there -- webb. /// Handle backslashes before special characters, like "\*" and "\ ". /// /// @param pat_end first char after pattern or NULL @@ -5625,10 +5481,10 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs bool add_dollar = true; if (allow_dirs != NULL) { - *allow_dirs = FALSE; + *allow_dirs = false; } if (pat_end == NULL) { - pat_end = pat + STRLEN(pat); + pat_end = pat + strlen(pat); } if (pat_end == pat) { @@ -5711,7 +5567,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs reg_pat[i++] = '/'; reg_pat[i++] = ']'; if (allow_dirs != NULL) { - *allow_dirs = TRUE; + *allow_dirs = true; } break; } @@ -5745,7 +5601,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs && (!no_bslash || *p != '\\') #endif ) { - *allow_dirs = TRUE; + *allow_dirs = true; } reg_pat[i++] = '\\'; reg_pat[i++] = *p; @@ -5758,7 +5614,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs reg_pat[i++] = '/'; reg_pat[i++] = ']'; if (allow_dirs != NULL) { - *allow_dirs = TRUE; + *allow_dirs = true; } break; #endif diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h index 650977deac..ae3c51f1bc 100644 --- a/src/nvim/fileio.h +++ b/src/nvim/fileio.h @@ -15,6 +15,7 @@ #define READ_KEEP_UNDO 0x20 // keep undo info #define READ_FIFO 0x40 // read from fifo or socket #define READ_NOWINENTER 0x80 // do not trigger BufWinEnter +#define READ_NOFILE 0x100 // do not read a file, do trigger BufReadCmd #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 8ce24fd378..1872558669 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -111,7 +111,7 @@ static int prev_lnum_lvl = -1; #define DONE_FOLD 2 // did find a fold static size_t foldstartmarkerlen; -static char_u *foldendmarker; +static char *foldendmarker; static size_t foldendmarkerlen; // Exported folding functions. {{{1 @@ -394,7 +394,7 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, int ha } // Force a redraw to remove the Visual highlighting. if (had_visual) { - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } } @@ -721,7 +721,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const emsg(_(e_nofold)); // Force a redraw to remove the Visual highlighting. if (had_visual) { - redraw_buf_later(wp->w_buffer, INVERTED); + redraw_buf_later(wp->w_buffer, UPD_INVERTED); } } else { // Deleting markers may make cursor column invalid @@ -757,7 +757,7 @@ void clearFolding(win_T *win) /// The changes in lines from top to bot (inclusive). void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) { - if (disable_fold_update || compl_busy || State & MODE_INSERT) { + if (disable_fold_update || State & MODE_INSERT) { return; } @@ -819,7 +819,7 @@ void foldUpdateAfterInsert(void) void foldUpdateAll(win_T *win) { win->w_foldinvalid = true; - redraw_later(win, NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } // foldMoveTo() {{{2 @@ -982,7 +982,7 @@ void foldAdjustVisual(void) } pos_T *start, *end; - char_u *ptr; + char *ptr; if (ltoreq(VIsual, curwin->w_cursor)) { start = &VIsual; @@ -996,7 +996,7 @@ void foldAdjustVisual(void) } if (hasFolding(end->lnum, NULL, &end->lnum)) { ptr = ml_get(end->lnum); - end->col = (colnr_T)STRLEN(ptr); + end->col = (colnr_T)strlen(ptr); if (end->col > 0 && *p_sel == 'o') { end->col--; } @@ -1573,23 +1573,23 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end) // foldAddMarker() {{{2 /// Add "marker[markerlen]" in 'commentstring' to position `pos`. -static void foldAddMarker(buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen) +static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t markerlen) { - char_u *cms = buf->b_p_cms; - char_u *newline; - char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s"); + char *cms = buf->b_p_cms; + char *newline; + char *p = strstr(buf->b_p_cms, "%s"); bool line_is_comment = false; linenr_T lnum = pos.lnum; // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end - char_u *line = ml_get_buf(buf, lnum, false); + char *line = ml_get_buf(buf, lnum, false); size_t line_len = STRLEN(line); size_t added = 0; if (u_save(lnum - 1, lnum + 1) == OK) { // Check if the line ends with an unclosed comment skip_comment(line, false, false, &line_is_comment); - newline = xmalloc(line_len + markerlen + STRLEN(cms) + 1); + newline = xmalloc(line_len + markerlen + strlen(cms) + 1); STRCPY(newline, line); // Append the marker to the end of the line if (p == NULL || line_is_comment) { @@ -1599,7 +1599,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char_u *marker, size_t ma STRCPY(newline + line_len, cms); memcpy(newline + line_len + (p - cms), marker, markerlen); STRCPY(newline + line_len + (p - cms) + markerlen, p + 2); - added = markerlen + STRLEN(cms) - 2; + added = markerlen + strlen(cms) - 2; } ml_replace_buf(buf, lnum, newline, false); if (added) { @@ -1632,16 +1632,16 @@ static void deleteFoldMarkers(win_T *wp, fold_T *fp, int recursive, linenr_T lnu /// Delete 'commentstring' if it matches. /// If the marker is not found, there is no error message. Could be a missing /// close-marker. -static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen) +static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t markerlen) { // end marker may be missing and fold extends below the last line if (lnum > buf->b_ml.ml_line_count) { return; } - char_u *cms = buf->b_p_cms; - char_u *line = ml_get_buf(buf, lnum, false); - for (char_u *p = line; *p != NUL; p++) { + char *cms = buf->b_p_cms; + char *line = ml_get_buf(buf, lnum, false); + for (char *p = line; *p != NUL; p++) { if (STRNCMP(p, marker, markerlen) != 0) { continue; } @@ -1652,17 +1652,17 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t mark } if (*cms != NUL) { // Also delete 'commentstring' if it matches. - char_u *cms2 = (char_u *)strstr((char *)cms, "%s"); + char *cms2 = strstr(cms, "%s"); if (p - line >= cms2 - cms && STRNCMP(p - (cms2 - cms), cms, cms2 - cms) == 0 - && STRNCMP(p + len, cms2 + 2, STRLEN(cms2 + 2)) == 0) { + && STRNCMP(p + len, cms2 + 2, strlen(cms2 + 2)) == 0) { p -= cms2 - cms; - len += STRLEN(cms) - 2; + len += strlen(cms) - 2; } } if (u_save(lnum - 1, lnum + 1) == OK) { // Make new line: text-before-marker + text-after-marker - char_u *newline = xmalloc(STRLEN(line) - len + 1); + char *newline = xmalloc(strlen(line) - len + 1); assert(p >= line); memcpy(newline, line, (size_t)(p - line)); STRCPY(newline + (p - line), p + len); @@ -1683,10 +1683,10 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t mark /// @return the text for a closed fold /// /// Otherwise the result is in allocated memory. -char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo, char_u *buf) +char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo, char *buf) FUNC_ATTR_NONNULL_ARG(1) { - char_u *text = NULL; + char *text = NULL; // an error occurred when evaluating 'fdt' setting static bool got_fdt_error = false; int save_did_emsg = did_emsg; @@ -1728,9 +1728,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin curbuf = wp->w_buffer; emsg_silent++; // handle exceptions, but don't display errors - text = - (char_u *)eval_to_string_safe((char *)wp->w_p_fdt, NULL, - was_set_insecurely(wp, "foldtext", OPT_LOCAL)); + text = eval_to_string_safe(wp->w_p_fdt, NULL, was_set_insecurely(wp, "foldtext", OPT_LOCAL)); emsg_silent--; if (text == NULL || did_emsg) { @@ -1751,23 +1749,23 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin if (text != NULL) { // Replace unprintable characters, if there are any. But // replace a TAB with a space. - char_u *p; + char *p; for (p = text; *p != NUL; p++) { - int len = utfc_ptr2len((char *)p); + int len = utfc_ptr2len(p); if (len > 1) { - if (!vim_isprintc(utf_ptr2char((char *)p))) { + if (!vim_isprintc(utf_ptr2char(p))) { break; } p += len - 1; } else if (*p == TAB) { *p = ' '; - } else if (ptr2cells((char *)p) > 1) { + } else if (ptr2cells(p) > 1) { break; } } if (*p != NUL) { - p = (char_u *)transstr((const char *)text, true); + p = transstr((const char *)text, true); xfree(text); text = p; } @@ -1776,7 +1774,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin if (text == NULL) { unsigned long count = (unsigned long)(lnume - lnum + 1); - vim_snprintf((char *)buf, FOLD_TEXT_LEN, + vim_snprintf(buf, FOLD_TEXT_LEN, NGETTEXT("+--%3ld line folded", "+--%3ld lines folded ", count), count); @@ -1787,17 +1785,17 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin // foldtext_cleanup() {{{2 /// Remove 'foldmarker' and 'commentstring' from "str" (in-place). -static void foldtext_cleanup(char_u *str) +static void foldtext_cleanup(char *str) { // Ignore leading and trailing white space in 'commentstring'. - char_u *cms_start = (char_u *)skipwhite((char *)curbuf->b_p_cms); - size_t cms_slen = STRLEN(cms_start); + char *cms_start = skipwhite(curbuf->b_p_cms); + size_t cms_slen = strlen(cms_start); while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1])) { cms_slen--; } // locate "%s" in 'commentstring', use the part before and after it. - char_u *cms_end = (char_u *)strstr((char *)cms_start, "%s"); + char *cms_end = strstr(cms_start, "%s"); size_t cms_elen = 0; if (cms_end != NULL) { cms_elen = cms_slen - (size_t)(cms_end - cms_start); @@ -1809,7 +1807,7 @@ static void foldtext_cleanup(char_u *str) } // skip "%s" and white space after it - char_u *s = (char_u *)skipwhite((char *)cms_end + 2); + char *s = skipwhite(cms_end + 2); cms_elen -= (size_t)(s - cms_end); cms_end = s; } @@ -1818,7 +1816,7 @@ static void foldtext_cleanup(char_u *str) bool did1 = false; bool did2 = false; - for (char_u *s = str; *s != NUL;) { + for (char *s = str; *s != NUL;) { size_t len = 0; if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0) { len = foldstartmarkerlen; @@ -1832,7 +1830,7 @@ static void foldtext_cleanup(char_u *str) // May remove 'commentstring' start. Useful when it's a double // quote and we already removed a double quote. - char_u *p; + char *p; for (p = s; p > str && ascii_iswhite(p[-1]); p--) {} if (p >= str + cms_slen && STRNCMP(p - cms_slen, cms_start, cms_slen) == 0) { @@ -2850,11 +2848,11 @@ static void foldlevelIndent(fline_T *flp) linenr_T lnum = flp->lnum + flp->off; buf_T *buf = flp->wp->w_buffer; - char_u *s = (char_u *)skipwhite((char *)ml_get_buf(buf, lnum, false)); + char *s = skipwhite(ml_get_buf(buf, lnum, false)); // empty line or lines starting with a character in 'foldignore': level // depends on surrounding lines - if (*s == NUL || vim_strchr((char *)flp->wp->w_p_fdi, *s) != NULL) { + if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, *s) != NULL) { // first and last line can't be undefined, use level 0 if (lnum == 1 || lnum == buf->b_ml.ml_line_count) { flp->lvl = 0; @@ -2907,7 +2905,7 @@ static void foldlevelExpr(fline_T *flp) const bool save_keytyped = KeyTyped; int c; - const int n = eval_foldexpr((char *)flp->wp->w_p_fde, &c); + const int n = eval_foldexpr(flp->wp->w_p_fde, &c); KeyTyped = save_keytyped; switch (c) { @@ -2985,9 +2983,9 @@ static void foldlevelExpr(fline_T *flp) /// Relies on the option value to have been checked for correctness already. static void parseMarker(win_T *wp) { - foldendmarker = (char_u *)vim_strchr((char *)wp->w_p_fmr, ','); + foldendmarker = vim_strchr(wp->w_p_fmr, ','); foldstartmarkerlen = (size_t)(foldendmarker++ - wp->w_p_fmr); - foldendmarkerlen = STRLEN(foldendmarker); + foldendmarkerlen = strlen(foldendmarker); } // foldlevelMarker() {{{2 @@ -3003,23 +3001,23 @@ static void foldlevelMarker(fline_T *flp) int start_lvl = flp->lvl; // cache a few values for speed - char_u *startmarker = flp->wp->w_p_fmr; - int cstart = *startmarker; + char *startmarker = flp->wp->w_p_fmr; + char cstart = *startmarker; startmarker++; - int cend = *foldendmarker; + char cend = *foldendmarker; // Default: no start found, next level is same as current level flp->start = 0; flp->lvl_next = flp->lvl; - char_u *s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, false); + char *s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, false); while (*s) { if (*s == cstart && STRNCMP(s + 1, startmarker, foldstartmarkerlen - 1) == 0) { // found startmarker: set flp->lvl s += foldstartmarkerlen; if (ascii_isdigit(*s)) { - int n = atoi((char *)s); + int n = atoi(s); if (n > 0) { flp->lvl = n; flp->lvl_next = n; @@ -3034,12 +3032,12 @@ static void foldlevelMarker(fline_T *flp) flp->lvl_next++; flp->start++; } - } else if (*s == cend && STRNCMP(s + 1, foldendmarker + 1, - foldendmarkerlen - 1) == 0) { + } else if (*s == cend + && STRNCMP(s + 1, foldendmarker + 1, foldendmarkerlen - 1) == 0) { // found endmarker: set flp->lvl_next s += foldendmarkerlen; if (ascii_isdigit(*s)) { - int n = atoi((char *)s); + int n = atoi(s); if (n > 0) { flp->lvl = n; flp->lvl_next = n - 1; @@ -3212,19 +3210,19 @@ static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end) } /// "foldclosed()" function -void f_foldclosed(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_foldclosed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { foldclosed_both(argvars, rettv, false); } /// "foldclosedend()" function -void f_foldclosedend(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_foldclosedend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { foldclosed_both(argvars, rettv, true); } /// "foldlevel()" function -void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_foldlevel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const linenr_T lnum = tv_get_lnum(argvars); if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) { @@ -3233,14 +3231,14 @@ void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "foldtext()" function -void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; linenr_T foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART); linenr_T foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND); - char_u *dashes = (char_u *)get_vim_var_str(VV_FOLDDASHES); + char *dashes = get_vim_var_str(VV_FOLDDASHES); if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count) { // Find first non-empty line in the fold. linenr_T lnum; @@ -3251,12 +3249,12 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) } // Find interesting text in this line. - char_u *s = (char_u *)skipwhite((char *)ml_get(lnum)); + char_u *s = (char_u *)skipwhite(ml_get(lnum)); // skip C comment-start if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) { s = (char_u *)skipwhite((char *)s + 2); if (*skipwhite((char *)s) == NUL && lnum + 1 < foldend) { - s = (char_u *)skipwhite((char *)ml_get(lnum + 1)); + s = (char_u *)skipwhite(ml_get(lnum + 1)); if (*s == '*') { s = (char_u *)skipwhite((char *)s + 1); } @@ -3264,24 +3262,24 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) } int count = foldend - foldstart + 1; char *txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count); - size_t len = STRLEN(txt) - + STRLEN(dashes) // for %s + size_t len = strlen(txt) + + strlen(dashes) // for %s + 20 // for %3ld + STRLEN(s); // concatenated - char_u *r = xmalloc(len); - snprintf((char *)r, len, txt, dashes, count); - len = STRLEN(r); + char *r = xmalloc(len); + snprintf(r, len, txt, dashes, count); + len = strlen(r); STRCAT(r, s); // remove 'foldmarker' and 'commentstring' foldtext_cleanup(r + len); - rettv->vval.v_string = (char *)r; + rettv->vval.v_string = r; } } /// "foldtextresult(lnum)" function -void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char_u buf[FOLD_TEXT_LEN]; + char buf[FOLD_TEXT_LEN]; static bool entered = false; rettv->v_type = VAR_STRING; @@ -3298,11 +3296,11 @@ void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr) foldinfo_T info = fold_info(curwin, lnum); if (info.fi_lines > 0) { - char_u *text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf); + char *text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf); if (text == buf) { - text = vim_strsave(text); + text = xstrdup(text); } - rettv->vval.v_string = (char *)text; + rettv->vval.v_string = text; } entered = false; diff --git a/src/nvim/fold.h b/src/nvim/fold.h index f34e6d43c3..395cd8e30a 100644 --- a/src/nvim/fold.h +++ b/src/nvim/fold.h @@ -8,10 +8,8 @@ #include "nvim/pos.h" #include "nvim/types.h" -/* - * Info used to pass info about a fold from the fold-detection code to the - * code that displays the foldcolumn. - */ +// Info used to pass info about a fold from the fold-detection code to the +// code that displays the foldcolumn. typedef struct foldinfo { linenr_T fi_lnum; // line number where fold starts int fi_level; // level of the fold; when this is zero the diff --git a/src/nvim/garray.c b/src/nvim/garray.c index 7a3c14b1bb..6c63ce5a7c 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -123,7 +123,7 @@ void ga_remove_duplicate_strings(garray_T *gap) // loop over the growing array in reverse for (int i = gap->ga_len - 1; i > 0; i--) { - if (FNAMECMP(fnames[i - 1], fnames[i]) == 0) { + if (path_fnamecmp(fnames[i - 1], fnames[i]) == 0) { xfree(fnames[i]); // close the gap (move all strings one slot lower) @@ -131,7 +131,7 @@ void ga_remove_duplicate_strings(garray_T *gap) fnames[j - 1] = fnames[j]; } - --gap->ga_len; + gap->ga_len--; } } } @@ -198,7 +198,7 @@ void ga_concat(garray_T *gap, const char *restrict s) return; } - ga_concat_len(gap, s, STRLEN(s)); + ga_concat_len(gap, s, strlen(s)); } /// Concatenate a string to a growarray which contains characters diff --git a/src/nvim/garray.h b/src/nvim/garray.h index 56bd5c9130..0281678925 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -4,7 +4,7 @@ #include <stddef.h> // for size_t #include "nvim/log.h" -#include "nvim/types.h" // for char_u +#include "nvim/types.h" /// Structure used for growing arrays. /// This is used to store information that only grows, is deleted all at diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua index 70a7be86b5..d872ffd6a9 100644 --- a/src/nvim/generators/c_grammar.lua +++ b/src/nvim/generators/c_grammar.lua @@ -26,6 +26,7 @@ local c_id = ( local c_void = P('void') local c_param_type = ( ((P('Error') * fill * P('*') * fill) * Cc('error')) + + ((P('Arena') * fill * P('*') * fill) * Cc('arena')) + C((P('const ') ^ -1) * (c_id) * (ws ^ 1) * P('*')) + (C(c_id) * (ws ^ 1)) ) diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index b167767f7a..67b8f5f0f5 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -17,6 +17,7 @@ local nvimdir = arg[1] package.path = nvimdir .. '/?.lua;' .. package.path _G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')() +_G.vim.inspect = loadfile(nvimdir..'/../../runtime/lua/vim/inspect.lua')() local hashy = require'generators.hashy' @@ -72,6 +73,11 @@ for i = 6, #arg do -- for specifying errors fn.parameters[#fn.parameters] = nil end + if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'arena' then + -- return value is allocated in an arena + fn.arena_return = true + fn.parameters[#fn.parameters] = nil + end end end input:close() @@ -210,7 +216,7 @@ for i = 1, #functions do if fn.impl_name == nil and fn.remote then local args = {} - output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Error *error)') + output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Arena* arena, Error *error)') output:write('\n{') output:write('\n#if MIN_LOG_LEVEL <= LOGLVL_DBG') output:write('\n logmsg(LOGLVL_DBG, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke ' @@ -319,6 +325,10 @@ for i = 1, #functions do output:write(call_args) end + if fn.arena_return then + output:write(', arena') + end + if fn.can_fail then -- if the function can fail, also pass a pointer to the local error object if #args > 0 then @@ -355,11 +365,12 @@ local hashorder, hashfun = hashy.hashy_hash("msgpack_rpc_get_handler_for", vim.t return "method_handlers["..idx.."].name" end) -output:write("static const MsgpackRpcRequestHandler method_handlers[] = {\n") -for _, name in ipairs(hashorder) do +output:write("const MsgpackRpcRequestHandler method_handlers[] = {\n") +for n, name in ipairs(hashorder) do local fn = remote_fns[name] + fn.handler_id = n-1 output:write(' { .name = "'..name..'", .fn = handle_'.. (fn.impl_name or fn.name).. - ', .fast = '..tostring(fn.fast)..'},\n') + ', .fast = '..tostring(fn.fast)..', .arena_return = '..tostring(not not fn.arena_return)..'},\n') end output:write("};\n\n") output:write(hashfun) @@ -400,6 +411,8 @@ output:write([[ #include "nvim/api/private/helpers.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" +#include "nvim/memory.h" + ]]) include_headers(output, headers) output:write('\n') @@ -477,6 +490,13 @@ local function process_function(fn) if fn.receives_channel_id then cparams = 'LUA_INTERNAL_CALL, ' .. cparams end + if fn.arena_return then + cparams = cparams .. '&arena, ' + write_shifted_output(output, [[ + Arena arena = ARENA_EMPTY; + ]]) + end + if fn.can_fail then cparams = cparams .. '&err' else @@ -511,15 +531,21 @@ local function process_function(fn) else return_type = fn.return_type end + local free_retval + if fn.arena_return then + free_retval = "arena_mem_free(arena_finish(&arena));" + else + free_retval = "api_free_"..return_type:lower().."(ret);" + end write_shifted_output(output, string.format([[ const %s ret = %s(%s); nlua_push_%s(lstate, ret, true); - api_free_%s(ret); + %s %s %s return 1; - ]], fn.return_type, fn.name, cparams, return_type, return_type:lower(), - free_at_exit_code, err_throw_code)) + ]], fn.return_type, fn.name, cparams, return_type, + free_retval, free_at_exit_code, err_throw_code)) else write_shifted_output(output, string.format([[ %s(%s); diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 93bbaab74c..ea66be7ee8 100755 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -75,6 +75,8 @@ local function call_ui_event_method(output, ev) hlattrs_args_count = hlattrs_args_count + 1 elseif kind == 'Object' then output:write('args.items['..(j-1)..'];\n') + elseif kind == 'Window' then + output:write('(Window)args.items['..(j-1)..'].data.integer;\n') else output:write('args.items['..(j-1)..'].data.'..string.lower(kind)..';\n') end @@ -125,7 +127,7 @@ for i = 1, #events do local param = ev.parameters[j] local copy = 'copy_'..param[2] if param[1] == 'String' then - send = send..' String copy_'..param[2]..' = copy_string('..param[2]..');\n' + send = send..' String copy_'..param[2]..' = copy_string('..param[2]..', NULL);\n' argv = argv..', '..copy..'.data, INT2PTR('..copy..'.size)' recv = (recv..' String '..param[2].. ' = (String){.data = argv['..argc..'],'.. @@ -134,7 +136,7 @@ for i = 1, #events do recv_cleanup = recv_cleanup..' api_free_string('..param[2]..');\n' argc = argc+2 elseif param[1] == 'Array' then - send = send..' Array '..copy..' = copy_array('..param[2]..');\n' + send = send..' Array '..copy..' = copy_array('..param[2]..', NULL);\n' argv = argv..', '..copy..'.items, INT2PTR('..copy..'.size)' recv = (recv..' Array '..param[2].. ' = (Array){.items = argv['..argc..'],'.. @@ -144,7 +146,7 @@ for i = 1, #events do argc = argc+2 elseif param[1] == 'Object' then send = send..' Object *'..copy..' = xmalloc(sizeof(Object));\n' - send = send..' *'..copy..' = copy_object('..param[2]..');\n' + send = send..' *'..copy..' = copy_object('..param[2]..', NULL);\n' argv = argv..', '..copy recv = recv..' Object '..param[2]..' = *(Object *)argv['..argc..'];\n' recv_argv = recv_argv..', '..param[2] diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua index c7d5a1a191..bf1adaeee3 100755 --- a/src/nvim/generators/gen_declarations.lua +++ b/src/nvim/generators/gen_declarations.lua @@ -218,7 +218,7 @@ local footer = [[ local non_static = header .. [[ #ifndef DLLEXPORT -# ifdef WIN32 +# ifdef MSWIN # define DLLEXPORT __declspec(dllexport) # else # define DLLEXPORT diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index c72249161b..8e6d1f2634 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -28,13 +28,20 @@ local hashy = require'generators.hashy' local hashpipe = io.open(funcsfname, 'wb') local funcs = require('eval').funcs +for _, func in pairs(funcs) do + if func.float_func then + func.func = "float_op_wrapper" + func.data = "{ .float_func = &"..func.float_func.." }" + end +end + local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all")) for _,fun in ipairs(metadata) do if fun.eval then funcs[fun.name] = { args=#fun.parameters, func='api_wrapper', - data='&handle_'..fun.name, + data='{ .api_handler = &method_handlers['..fun.handler_id..'] }' } end end @@ -60,12 +67,12 @@ for _, name in ipairs(neworder) do end local base = def.base or "BASE_NONE" local func = def.func or ('f_' .. name) - local data = def.data or "NULL" + local data = def.data or "{ .nullptr = NULL }" local fast = def.fast and 'true' or 'false' - hashpipe:write((' { "%s", %s, %s, %s, %s, &%s, (FunPtr)%s },\n') + hashpipe:write((' { "%s", %s, %s, %s, %s, &%s, %s },\n') :format(name, args[1], args[2], base, fast, func, data)) end -hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, NULL },\n') +hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, { .nullptr = NULL } },\n') hashpipe:write("};\n\n") hashpipe:write(hashfun) hashpipe:close() diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 0454c54faf..6dba6552b3 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -34,7 +34,6 @@ local redraw_flags={ current_window_only='P_RWINONLY', current_buffer='P_RBUF', all_windows='P_RALL', - everything='P_RCLR', curswant='P_CURSWANT', ui_option='P_UI_OPTION', } @@ -115,7 +114,7 @@ local value_dumpers = { } local get_value = function(v) - return '(char_u *) ' .. value_dumpers[type(v)](v) + return '(char *) ' .. value_dumpers[type(v)](v) end local get_defaults = function(d,n) diff --git a/src/nvim/generators/gen_unicode_tables.lua b/src/nvim/generators/gen_unicode_tables.lua index 36553f4649..9ad99c8029 100644 --- a/src/nvim/generators/gen_unicode_tables.lua +++ b/src/nvim/generators/gen_unicode_tables.lua @@ -153,7 +153,8 @@ local build_combining_table = function(ut_fp, dataprops) local start = -1 local end_ = -1 for _, p in ipairs(dataprops) do - if (({Mn=true, Mc=true, Me=true})[p[3]]) then + -- The 'Mc' property was removed, it does take up space. + if (({Mn=true, Me=true})[p[3]]) then local n = tonumber(p[1], 16) if start >= 0 and end_ + 1 == n then -- Continue with the same range. diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 0f55158733..4135065787 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -81,33 +81,29 @@ static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 }; static int typeahead_char = 0; // typeahead char that's not flushed -/* - * when block_redo is TRUE redo buffer will not be changed - * used by edit() to repeat insertions and 'V' command for redoing - */ -static int block_redo = FALSE; +// when block_redo is true redo buffer will not be changed +// used by edit() to repeat insertions and 'V' command for redoing +static int block_redo = false; static int KeyNoremap = 0; // remapping flags -/* - * Variables used by vgetorpeek() and flush_buffers() - * - * typebuf.tb_buf[] contains all characters that are not consumed yet. - * typebuf.tb_buf[typebuf.tb_off] is the first valid character. - * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char. - * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL. - * The head of the buffer may contain the result of mappings, abbreviations - * and @a commands. The length of this part is typebuf.tb_maplen. - * typebuf.tb_silent is the part where <silent> applies. - * After the head are characters that come from the terminal. - * typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that - * should not be considered for abbreviations. - * Some parts of typebuf.tb_buf may not be mapped. These parts are remembered - * in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and - * contains RM_NONE for the characters that are not to be remapped. - * typebuf.tb_noremap[typebuf.tb_off] is the first valid flag. - * (typebuf has been put in globals.h, because check_termcode() needs it). - */ +// Variables used by vgetorpeek() and flush_buffers() +// +// typebuf.tb_buf[] contains all characters that are not consumed yet. +// typebuf.tb_buf[typebuf.tb_off] is the first valid character. +// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char. +// typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL. +// The head of the buffer may contain the result of mappings, abbreviations +// and @a commands. The length of this part is typebuf.tb_maplen. +// typebuf.tb_silent is the part where <silent> applies. +// After the head are characters that come from the terminal. +// typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that +// should not be considered for abbreviations. +// Some parts of typebuf.tb_buf may not be mapped. These parts are remembered +// in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and +// contains RM_NONE for the characters that are not to be remapped. +// typebuf.tb_noremap[typebuf.tb_off] is the first valid flag. +// (typebuf has been put in globals.h, because check_termcode() needs it). #define RM_YES 0 // tb_noremap: remap #define RM_NONE 1 // tb_noremap: don't remap #define RM_SCRIPT 2 // tb_noremap: remap local script mappings @@ -126,9 +122,7 @@ static size_t last_recorded_len = 0; // number of last recorded chars # include "getchar.c.generated.h" #endif -/* - * Free and clear a buffer. - */ +// Free and clear a buffer. void free_buff(buffheader_T *buf) { buffblock_T *p, *np; @@ -154,7 +148,7 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero) // compute the total length of the string for (const buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) { - count += STRLEN(bp->b_str); + count += strlen(bp->b_str); } if (count || dozero) { @@ -162,7 +156,7 @@ static char_u *get_buffcont(buffheader_T *buffer, int dozero) p2 = p; for (const buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) { - for (const char_u *str = bp->b_str; *str;) { + for (const char_u *str = (char_u *)bp->b_str; *str;) { *p2++ = *str++; } } @@ -179,23 +173,19 @@ char_u *get_recorded(void) char_u *p; size_t len; - p = get_buffcont(&recordbuff, TRUE); + p = get_buffcont(&recordbuff, true); free_buff(&recordbuff); - /* - * Remove the characters that were added the last time, these must be the - * (possibly mapped) characters that stopped the recording. - */ + // Remove the characters that were added the last time, these must be the + // (possibly mapped) characters that stopped the recording. len = STRLEN(p); if (len >= last_recorded_len) { len -= last_recorded_len; p[len] = NUL; } - /* - * When stopping recording from Insert mode with CTRL-O q, also remove the - * CTRL-O. - */ + // When stopping recording from Insert mode with CTRL-O q, also remove the + // CTRL-O. if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O) { p[len - 1] = NUL; } @@ -207,7 +197,7 @@ char_u *get_recorded(void) /// K_SPECIAL in the returned string is escaped. char_u *get_inserted(void) { - return get_buffcont(&redobuff, FALSE); + return get_buffcont(&redobuff, false); } /// Add string after the current block of the given buffer @@ -235,13 +225,13 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } else if (buf->bh_index != 0) { memmove(buf->bh_first.b_next->b_str, buf->bh_first.b_next->b_str + buf->bh_index, - STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); + strlen(buf->bh_first.b_next->b_str + buf->bh_index) + 1); } buf->bh_index = 0; size_t len; if (buf->bh_space >= (size_t)slen) { - len = STRLEN(buf->bh_curr->b_str); + len = strlen(buf->bh_curr->b_str); STRLCPY(buf->bh_curr->b_str + len, s, slen + 1); buf->bh_space -= (size_t)slen; } else { @@ -269,7 +259,7 @@ static void delete_buff_tail(buffheader_T *buf, int slen) if (buf->bh_curr == NULL) { return; // nothing to delete } - len = (int)STRLEN(buf->bh_curr->b_str); + len = (int)strlen(buf->bh_curr->b_str); if (len >= slen) { buf->bh_curr->b_str[len - slen] = NUL; buf->bh_space += (size_t)slen; @@ -319,7 +309,7 @@ static void add_char_buff(buffheader_T *buf, int c) /// Get one byte from the read buffers. Use readbuf1 one first, use readbuf2 /// if that one is empty. -/// If advance == TRUE go to the next char. +/// If advance == true go to the next char. /// No translation is done K_SPECIAL is escaped. static int read_readbuffers(int advance) { @@ -341,7 +331,7 @@ static int read_readbuf(buffheader_T *buf, int advance) } buffblock_T *const curr = buf->bh_first.b_next; - c = curr->b_str[buf->bh_index]; + c = (char_u)curr->b_str[buf->bh_index]; if (advance) { if (curr->b_str[++buf->bh_index] == NUL) { @@ -353,9 +343,7 @@ static int read_readbuf(buffheader_T *buf, int advance) return c; } -/* - * Prepare the read buffers for reading (if they contain something). - */ +// Prepare the read buffers for reading (if they contain something). static void start_stuff(void) { if (readbuf1.bh_first.b_next != NULL) { @@ -368,38 +356,30 @@ static void start_stuff(void) } } -/* - * Return TRUE if the stuff buffer is empty. - */ +/// Return true if the stuff buffer is empty. int stuff_empty(void) FUNC_ATTR_PURE { return (readbuf1.bh_first.b_next == NULL && readbuf2.bh_first.b_next == NULL); } -/* - * Return TRUE if readbuf1 is empty. There may still be redo characters in - * redbuf2. - */ +/// Return true if readbuf1 is empty. There may still be redo characters in +/// redbuf2. int readbuf1_empty(void) FUNC_ATTR_PURE { return (readbuf1.bh_first.b_next == NULL); } -/* - * Set a typeahead character that won't be flushed. - */ +// Set a typeahead character that won't be flushed. void typeahead_noflush(int c) { typeahead_char = c; } -/* - * Remove the contents of the stuff buffer and the mapped characters in the - * typeahead buffer (used in case of an error). If "flush_typeahead" is true, - * flush all typeahead characters (used when interrupted by a CTRL-C). - */ +// Remove the contents of the stuff buffer and the mapped characters in the +// typeahead buffer (used in case of an error). If "flush_typeahead" is true, +// flush all typeahead characters (used when interrupted by a CTRL-C). void flush_buffers(flush_buffers_T flush_typeahead) { init_typebuf(); @@ -443,10 +423,8 @@ void beep_flush(void) } } -/* - * The previous contents of the redo buffer is kept in old_redobuffer. - * This is used for the CTRL-O <.> command in insert mode. - */ +// The previous contents of the redo buffer is kept in old_redobuffer. +// This is used for the CTRL-O <.> command in insert mode. void ResetRedobuff(void) { if (!block_redo) { @@ -456,10 +434,8 @@ void ResetRedobuff(void) } } -/* - * Discard the contents of the redo buffer and restore the previous redo - * buffer. - */ +// Discard the contents of the redo buffer and restore the previous redo +// buffer. void CancelRedo(void) { if (!block_redo) { @@ -565,9 +541,7 @@ void AppendCharToRedobuff(int c) } } -/* - * Append a number to the redo buffer. - */ +// Append a number to the redo buffer. void AppendNumberToRedobuff(long n) { if (!block_redo) { @@ -621,14 +595,40 @@ void stuffcharReadbuff(int c) add_char_buff(&readbuf1, c); } -/* - * Append a number to the stuff buffer. - */ +// Append a number to the stuff buffer. void stuffnumReadbuff(long n) { add_num_buff(&readbuf1, n); } +/// Stuff a string into the typeahead buffer, such that edit() will insert it +/// literally ("literally" true) or interpret is as typed characters. +void stuffescaped(const char *arg, bool literally) +{ + while (*arg != NUL) { + // Stuff a sequence of normal ASCII characters, that's fast. Also + // stuff K_SPECIAL to get the effect of a special key when "literally" + // is true. + const char *const start = arg; + while ((*arg >= ' ' && *arg < DEL) || ((uint8_t)(*arg) == K_SPECIAL + && !literally)) { + arg++; + } + if (arg > start) { + stuffReadbuffLen(start, (arg - start)); + } + + // stuff a single special character + if (*arg != NUL) { + const int c = mb_cptr2char_adv((const char_u **)&arg); + if (literally && ((c < ' ' && c != TAB) || c == DEL)) { + stuffcharReadbuff(Ctrl_V); + } + stuffcharReadbuff(c); + } + } +} + /// Read a character from the redo buffer. Translates K_SPECIAL and /// multibyte characters. /// The redo buffer is left as it is. @@ -649,7 +649,7 @@ static int read_redo(bool init, bool old_redo) if (bp == NULL) { return FAIL; } - p = bp->b_str; + p = (char_u *)bp->b_str; return OK; } if ((c = *p) == NUL) { @@ -670,7 +670,7 @@ static int read_redo(bool init, bool old_redo) } if (*++p == NUL && bp->b_next != NULL) { bp = bp->b_next; - p = bp->b_str; + p = (char_u *)bp->b_str; } buf[i] = (char_u)c; if (i == n - 1) { // last byte of a character @@ -761,11 +761,9 @@ int start_redo(long count, bool old_redo) return OK; } -/* - * Repeat the last insert (R, o, O, a, A, i or I command) by stuffing - * the redo buffer into readbuf2. - * return FAIL for failure, OK otherwise - */ +// Repeat the last insert (R, o, O, a, A, i or I command) by stuffing +// the redo buffer into readbuf2. +// return FAIL for failure, OK otherwise int start_redo_ins(void) { int c; @@ -793,14 +791,12 @@ int start_redo_ins(void) void stop_redo_ins(void) { - block_redo = FALSE; + block_redo = false; } -/* - * Initialize typebuf.tb_buf to point to typebuf_init. - * alloc() cannot be used here: In out-of-memory situations it would - * be impossible to type anything. - */ +// Initialize typebuf.tb_buf to point to typebuf_init. +// alloc() cannot be used here: In out-of-memory situations it would +// be impossible to type anything. static void init_typebuf(void) { if (typebuf.tb_buf == NULL) { @@ -849,7 +845,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) typebuf.tb_change_cnt = 1; } - addlen = (int)STRLEN(str); + addlen = (int)strlen(str); if (offset == 0 && addlen <= typebuf.tb_off) { // Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off] @@ -917,14 +913,12 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) val = RM_NONE; } - /* - * Adjust typebuf.tb_noremap[] for the new characters: - * If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are - * (sometimes) not remappable - * If noremap == REMAP_YES: all the new characters are mappable - * If noremap > 0: "noremap" characters are not remappable, the rest - * mappable - */ + // Adjust typebuf.tb_noremap[] for the new characters: + // If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are + // (sometimes) not remappable + // If noremap == REMAP_YES: all the new characters are mappable + // If noremap > 0: "noremap" characters are not remappable, the rest + // mappable if (noremap == REMAP_SKIP) { nrm = 1; } else if (noremap < 0) { @@ -932,9 +926,9 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) } else { nrm = noremap; } - for (i = 0; i < addlen; ++i) { + for (i = 0; i < addlen; i++) { typebuf.tb_noremap[typebuf.tb_off + i + offset] = - (char_u)((--nrm >= 0) ? val : RM_YES); + (uint8_t)((--nrm >= 0) ? val : RM_YES); } // tb_maplen and tb_silent only remember the length of mapped and/or @@ -970,7 +964,7 @@ int ins_char_typebuf(int c, int modifiers) return (int)len; } -/// Return TRUE if the typeahead buffer was changed (while waiting for a +/// Return true if the typeahead buffer was changed (while waiting for a /// character to arrive). Happens when a message was received from a client or /// from feedkeys(). /// But check in a more generic way to avoid trouble: When "typebuf.tb_buf" @@ -986,28 +980,22 @@ bool typebuf_changed(int tb_change_cnt) || typebuf_was_filled); } -/* - * Return TRUE if there are no characters in the typeahead buffer that have - * not been typed (result from a mapping or come from ":normal"). - */ +/// Return true if there are no characters in the typeahead buffer that have +/// not been typed (result from a mapping or come from ":normal"). int typebuf_typed(void) FUNC_ATTR_PURE { return typebuf.tb_maplen == 0; } -/* - * Return the number of characters that are mapped (or not typed). - */ +// Return the number of characters that are mapped (or not typed). int typebuf_maplen(void) FUNC_ATTR_PURE { return typebuf.tb_maplen; } -/* - * remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset] - */ +// remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset] void del_typebuf(int len, int offset) { int i; @@ -1018,21 +1006,14 @@ void del_typebuf(int len, int offset) typebuf.tb_len -= len; - /* - * Easy case: Just increase typebuf.tb_off. - */ + // Easy case: Just increase typebuf.tb_off. if (offset == 0 && typebuf.tb_buflen - (typebuf.tb_off + len) >= 3 * MAXMAPLEN + 3) { typebuf.tb_off += len; - } - /* - * Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[] - */ - else { + } else { + // Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[] i = typebuf.tb_off + offset; - /* - * Leave some extra room at the end to avoid reallocation. - */ + // Leave some extra room at the end to avoid reallocation. if (typebuf.tb_off > MAXMAPLEN) { memmove(typebuf.tb_buf + MAXMAPLEN, typebuf.tb_buf + typebuf.tb_off, (size_t)offset); @@ -1081,10 +1062,8 @@ void del_typebuf(int len, int offset) } } -/* - * Write typed characters to script file. - * If recording is on put the character in the recordbuffer. - */ +// Write typed characters to script file. +// If recording is on put the character in the recordbuffer. static void gotchars(const char_u *chars, size_t len) FUNC_ATTR_NONNULL_ALL { @@ -1141,14 +1120,12 @@ void ungetchars(int len) } } -/* - * Sync undo. Called when typed characters are obtained from the typeahead - * buffer, or when a menu is used. - * Do not sync: - * - In Insert mode, unless cursor key has been used. - * - While reading a script file. - * - When no_u_sync is non-zero. - */ +// Sync undo. Called when typed characters are obtained from the typeahead +// buffer, or when a menu is used. +// Do not sync: +// - In Insert mode, unless cursor key has been used. +// - While reading a script file. +// - When no_u_sync is non-zero. void may_sync_undo(void) { if ((!(State & (MODE_INSERT | MODE_CMDLINE)) || arrow_used) @@ -1157,9 +1134,7 @@ void may_sync_undo(void) } } -/* - * Make "typebuf" empty and allocate new buffers. - */ +// Make "typebuf" empty and allocate new buffers. void alloc_typebuf(void) { typebuf.tb_buf = xmalloc(TYPELEN_INIT); @@ -1175,9 +1150,7 @@ void alloc_typebuf(void) } } -/* - * Free the buffers of "typebuf". - */ +// Free the buffers of "typebuf". void free_typebuf(void) { if (typebuf.tb_buf == typebuf_init) { @@ -1192,10 +1165,8 @@ void free_typebuf(void) } } -/* - * When doing ":so! file", the current typeahead needs to be saved, and - * restored when "file" has been read completely. - */ +// When doing ":so! file", the current typeahead needs to be saved, and +// restored when "file" has been read completely. static typebuf_T saved_typebuf[NSCRIPT]; void save_typebuf(void) @@ -1219,9 +1190,7 @@ static bool can_get_old_char(void) return old_char != -1 && (old_KeyStuffed || stuff_empty()); } -/* - * Save all three kinds of typeahead, so that the user must type at a prompt. - */ +// Save all three kinds of typeahead, so that the user must type at a prompt. void save_typeahead(tasave_T *tp) { tp->save_typebuf = typebuf; @@ -1237,10 +1206,8 @@ void save_typeahead(tasave_T *tp) readbuf2.bh_first.b_next = NULL; } -/* - * Restore the typeahead to what it was before calling save_typeahead(). - * The allocated memory is freed, can only be called once! - */ +// Restore the typeahead to what it was before calling save_typeahead(). +// The allocated memory is freed, can only be called once! void restore_typeahead(tasave_T *tp) { if (tp->typebuf_valid) { @@ -1260,7 +1227,7 @@ void restore_typeahead(tasave_T *tp) /// Open a new script file for the ":source!" command. /// /// @param directly when true execute directly -void openscript(char_u *name, bool directly) +void openscript(char *name, bool directly) { if (curscript + 1 == NSCRIPT) { emsg(_(e_nesting)); @@ -1294,12 +1261,10 @@ void openscript(char_u *name, bool directly) } save_typebuf(); - /* - * Execute the commands from the file right now when using ":source!" - * after ":global" or ":argdo" or in a loop. Also when another command - * follows. This means the display won't be updated. Don't do this - * always, "make test" would fail. - */ + // Execute the commands from the file right now when using ":source!" + // after ":global" or ":argdo" or in a loop. Also when another command + // follows. This means the display won't be updated. Don't do this + // always, "make test" would fail. if (directly) { oparg_T oa; int oldcurscript; @@ -1328,9 +1293,7 @@ void openscript(char_u *name, bool directly) } } -/* - * Close the currently active input script. - */ +// Close the currently active input script. static void closescript(void) { free_typebuf(); @@ -1353,9 +1316,7 @@ void close_all_scripts(void) #endif -/* - * Return TRUE when reading keys from a script file. - */ +/// Return true when reading keys from a script file. int using_script(void) FUNC_ATTR_PURE { @@ -1434,10 +1395,8 @@ int vgetc(void) garbage_collect(false); } - /* - * If a character was put back with vungetc, it was already processed. - * Return it directly. - */ + // If a character was put back with vungetc, it was already processed. + // Return it directly. if (can_get_old_char()) { c = old_char; old_char = -1; @@ -1610,11 +1569,9 @@ int vgetc(void) last_vgetc_recorded_len = last_recorded_len; } - /* - * In the main loop "may_garbage_collect" can be set to do garbage - * collection in the first next vgetc(). It's disabled after that to - * avoid internally used Lists and Dicts to be freed. - */ + // In the main loop "may_garbage_collect" can be set to do garbage + // collection in the first next vgetc(). It's disabled after that to + // avoid internally used Lists and Dicts to be freed. may_garbage_collect = false; // Execute Lua on_key callbacks. @@ -1623,10 +1580,8 @@ int vgetc(void) return c; } -/* - * Like vgetc(), but never return a NUL when called recursively, get a key - * directly from the user (ignoring typeahead). - */ +// Like vgetc(), but never return a NUL when called recursively, get a key +// directly from the user (ignoring typeahead). int safe_vgetc(void) { int c; @@ -1638,10 +1593,8 @@ int safe_vgetc(void) return c; } -/* - * Like safe_vgetc(), but loop to handle K_IGNORE. - * Also ignore scrollbar events. - */ +// Like safe_vgetc(), but loop to handle K_IGNORE. +// Also ignore scrollbar events. int plain_vgetc(void) { int c; @@ -1654,12 +1607,10 @@ int plain_vgetc(void) return c; } -/* - * Check if a character is available, such that vgetc() will not block. - * If the next character is a special character or multi-byte, the returned - * character is not valid!. - * Returns NUL if no character is available. - */ +// Check if a character is available, such that vgetc() will not block. +// If the next character is a special character or multi-byte, the returned +// character is not valid!. +// Returns NUL if no character is available. int vpeekc(void) { if (can_get_old_char()) { @@ -1668,11 +1619,9 @@ int vpeekc(void) return vgetorpeek(false); } -/* - * Check if any character is available, also half an escape sequence. - * Trick: when no typeahead found, but there is something in the typeahead - * buffer, it must be an ESC that is recognized as the start of a key code. - */ +// Check if any character is available, also half an escape sequence. +// Trick: when no typeahead found, but there is something in the typeahead +// buffer, it must be an ESC that is recognized as the start of a key code. int vpeekc_any(void) { int c; @@ -1684,10 +1633,8 @@ int vpeekc_any(void) return c; } -/* - * Call vpeekc() without causing anything to be mapped. - * Return TRUE if a character is available, FALSE otherwise. - */ +// Call vpeekc() without causing anything to be mapped. +// Return true if a character is available, false otherwise. int char_avail(void) { int retval; @@ -1708,9 +1655,10 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) no_mapping++; allow_keys++; for (;;) { - // Position the cursor. Needed after a message that ends in a space, - // or if event processing caused a redraw. - ui_cursor_goto(msg_row, msg_col); + if (msg_col > 0) { + // Position the cursor. Needed after a message that ends in a space. + ui_cursor_goto(msg_row, msg_col); + } if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. @@ -1718,7 +1666,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) if (!char_avail()) { // flush output before waiting ui_flush(); - (void)os_inchar(NULL, 0, -1, 0, main_loop.events); + (void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); if (!multiqueue_empty(main_loop.events)) { state_handle_k_event(); continue; @@ -1748,11 +1696,6 @@ 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); @@ -1760,26 +1703,26 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = n; if (n != 0 && (IS_SPECIAL(n) || mod_mask != 0)) { - char_u temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 + char temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 int i = 0; // Turn a special key into three bytes, plus modifier. if (mod_mask != 0) { - temp[i++] = K_SPECIAL; - temp[i++] = KS_MODIFIER; - temp[i++] = (char_u)mod_mask; + temp[i++] = (char)K_SPECIAL; + temp[i++] = (char)KS_MODIFIER; + temp[i++] = (char)mod_mask; } if (IS_SPECIAL(n)) { - temp[i++] = K_SPECIAL; - temp[i++] = (char_u)K_SECOND(n); - temp[i++] = K_THIRD(n); + temp[i++] = (char)K_SPECIAL; + temp[i++] = (char)K_SECOND(n); + temp[i++] = (char)K_THIRD(n); } else { - i += utf_char2bytes((int)n, (char *)temp + i); + i += utf_char2bytes((int)n, temp + i); } assert(i < 10); temp[i++] = NUL; rettv->v_type = VAR_STRING; - rettv->vval.v_string = (char *)vim_strsave(temp); + rettv->vval.v_string = xstrdup(temp); if (is_mouse_key((int)n)) { int row = mouse_row; @@ -1810,13 +1753,13 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) } /// "getchar()" function -void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getchar_common(argvars, rettv); } /// "getcharstr()" function -void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getcharstr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { getchar_common(argvars, rettv); @@ -1836,7 +1779,7 @@ void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getcharmod()" function -void f_getcharmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getcharmod(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = mod_mask; } @@ -1881,7 +1824,7 @@ static bool at_ins_compl_key(void) c = p[3] & 0x1f; } return (ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c)) - || ((compl_cont_status & CONT_LOCAL) && (c == Ctrl_N || c == Ctrl_P)); + || (compl_status_local() && (c == Ctrl_N || c == Ctrl_P)); } /// Check if typebuf.tb_buf[] contains a modifier plus key that can be changed @@ -2047,12 +1990,11 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // - Partly match: mlen == typebuf.tb_len keylen = mp->m_keylen; if (mlen == keylen || (mlen == typebuf.tb_len && typebuf.tb_len < keylen)) { - char_u *s; int n; // If only script-local mappings are allowed, check if the // mapping starts with K_SNR. - s = typebuf.tb_noremap + typebuf.tb_off; + uint8_t *s = typebuf.tb_noremap + typebuf.tb_off; if (*s == RM_SCRIPT && (mp->m_keys[0] != K_SPECIAL || mp->m_keys[1] != KS_EXTRA @@ -2103,7 +2045,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // Check for match with 'pastetoggle' if (*p_pt != NUL && mp == NULL && (State & (MODE_INSERT | MODE_NORMAL))) { - bool match = typebuf_match_len(p_pt, &mlen); + bool match = typebuf_match_len((char_u *)p_pt, &mlen); if (match) { // write chars to script file(s) if (mlen > typebuf.tb_maplen) { @@ -2112,7 +2054,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } del_typebuf(mlen, 0); // remove the chars - set_option_value("paste", !p_paste, NULL, 0); + set_option_value_give_err("paste", !p_paste, NULL, 0); if (!(State & MODE_INSERT)) { msg_col = 0; msg_row = Rows - 1; @@ -2162,7 +2104,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } else { keylen = 0; } - if (keylen == 0) { // no simplication has been done + if (keylen == 0) { // no simplification has been done // If there was no mapping at all use the character from the // typeahead buffer right here. if (mp == NULL) { @@ -2188,7 +2130,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // complete match if (keylen >= 0 && keylen <= typebuf.tb_len) { - char_u *map_str = NULL; + char *map_str = NULL; // Write chars to script file(s). // Note: :lmap mappings are written *after* being applied. #5658 @@ -2228,8 +2170,8 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) char save_m_expr = mp->m_expr; int save_m_noremap = mp->m_noremap; char save_m_silent = mp->m_silent; - char_u *save_m_keys = NULL; // only saved when needed - char_u *save_m_str = NULL; // only saved when needed + char *save_m_keys = NULL; // only saved when needed + char *save_m_str = NULL; // only saved when needed LuaRef save_m_luaref = mp->m_luaref; // Handle ":map <expr>": evaluate the {rhs} as an @@ -2246,9 +2188,9 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) vgetc_busy = 0; may_garbage_collect = false; - save_m_keys = vim_strsave(mp->m_keys); + save_m_keys = xstrdup((char *)mp->m_keys); if (save_m_luaref == LUA_NOREF) { - save_m_str = vim_strsave(mp->m_str); + save_m_str = xstrdup(mp->m_str); } map_str = eval_map_expr(mp, NUL); @@ -2260,13 +2202,13 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // If an error was displayed and the expression returns an empty // string, generate a <Nop> to allow for a redraw. if (prev_did_emsg != did_emsg && (map_str == NULL || *map_str == NUL)) { - char_u buf[4]; + char buf[4]; xfree(map_str); - buf[0] = K_SPECIAL; - buf[1] = KS_EXTRA; + buf[0] = (char)K_SPECIAL; + buf[1] = (char)KS_EXTRA; buf[2] = KE_IGNORE; buf[3] = NUL; - map_str = vim_strsave(buf); + map_str = xstrdup(buf); if (State & MODE_CMDLINE) { // redraw the command below the error msg_didout = true; @@ -2295,18 +2237,18 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) // If this is a LANGMAP mapping, then we didn't record the keys // at the start of the function and have to record them now. if (keylen > typebuf.tb_maplen && (mp->m_mode & MODE_LANGMAP) != 0) { - gotchars(map_str, STRLEN(map_str)); + gotchars((char_u *)map_str, STRLEN(map_str)); } if (save_m_noremap != REMAP_YES) { noremap = save_m_noremap; - } else if (STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys, + } else if (STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : (char *)mp->m_keys, (size_t)keylen) != 0) { noremap = REMAP_YES; } else { noremap = REMAP_SKIP; } - i = ins_typebuf((char *)map_str, noremap, 0, true, cmd_silent || save_m_silent); + i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent); if (save_m_expr) { xfree(map_str); } @@ -2364,8 +2306,8 @@ void check_end_reg_executing(bool advance) /// /// if "advance" is true (vgetc()): /// Really get the character. -/// KeyTyped is set to TRUE in the case the user typed the key. -/// KeyStuffed is TRUE if the character comes from the stuff buffer. +/// KeyTyped is set to true in the case the user typed the key. +/// KeyStuffed is true if the character comes from the stuff buffer. /// if "advance" is false (vpeekc()): /// Just look whether there is a character available. /// Return NUL if not. @@ -2452,7 +2394,7 @@ static int vgetorpeek(bool advance) // flush all input c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L); - // If inchar() returns TRUE (script file was active) or we + // If inchar() returns true (script file was active) or we // are inside a mapping, get out of Insert mode. // Otherwise we behave like having gotten a CTRL-C. // As a result typing CTRL-C in insert mode will @@ -2501,7 +2443,7 @@ static int vgetorpeek(bool advance) // write char to script file(s) gotchars(typebuf.tb_buf + typebuf.tb_off, 1); } - KeyNoremap = typebuf.tb_noremap[typebuf.tb_off]; + KeyNoremap = (unsigned char)typebuf.tb_noremap[typebuf.tb_off]; del_typebuf(1, 0); } break; // got character, break the for loop @@ -2530,7 +2472,7 @@ static int vgetorpeek(bool advance) && (State & MODE_INSERT) && (p_timeout || (keylen == KEYLEN_PART_KEY && p_ttimeout)) && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25L)) == 0) { - colnr_T col = 0, vcol; + colnr_T col = 0; char_u *ptr; if (mode_displayed) { @@ -2548,22 +2490,27 @@ static int vgetorpeek(bool advance) // We are expecting to truncate the trailing // white-space, so find the last non-white // character -- webb - col = vcol = curwin->w_wcol = 0; - ptr = get_cursor_line_ptr(); - while (col < curwin->w_cursor.col) { - if (!ascii_iswhite(ptr[col])) { - curwin->w_wcol = vcol; + curwin->w_wcol = 0; + ptr = (char_u *)get_cursor_line_ptr(); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, + curwin->w_cursor.lnum, 0, (char *)ptr, (char *)ptr); + while ((char_u *)cts.cts_ptr < ptr + curwin->w_cursor.col) { + if (!ascii_iswhite(*cts.cts_ptr)) { + curwin->w_wcol = cts.cts_vcol; } - vcol += lbr_chartabsize(ptr, ptr + col, vcol); - col += utfc_ptr2len((char *)ptr + col); + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr += utfc_ptr2len(cts.cts_ptr); } + clear_chartabsize_arg(&cts); + curwin->w_wrow = curwin->w_cline_row + curwin->w_wcol / curwin->w_width_inner; curwin->w_wcol %= curwin->w_width_inner; curwin->w_wcol += curwin_col_off(); col = 0; // no correction needed } else { - --curwin->w_wcol; + curwin->w_wcol--; col = curwin->w_cursor.col - 1; } } else if (curwin->w_p_wrap && curwin->w_wrow) { @@ -2574,8 +2521,8 @@ static int vgetorpeek(bool advance) if (col > 0 && curwin->w_wcol > 0) { // Correct when the cursor is on the right halve // of a double-wide character. - ptr = get_cursor_line_ptr(); - col -= utf_head_off(ptr, ptr + col); + ptr = (char_u *)get_cursor_line_ptr(); + col -= utf_head_off((char *)ptr, (char *)ptr + col); if (utf_ptr2cells((char *)ptr + col) > 1) { curwin->w_wcol--; } @@ -2654,7 +2601,7 @@ static int vgetorpeek(bool advance) // input buffer (e.g., termresponse). if (((State & MODE_INSERT) != 0 || p_lz) && (State & MODE_CMDLINE) == 0 && advance && must_redraw != 0 && !need_wait_return) { - update_screen(0); + update_screen(); setcursor(); // put cursor back where it belongs } @@ -2829,11 +2776,9 @@ int inchar(char_u *buf, int maxlen, long wait_time) ui_flush(); } - /* - * Don't reset these when at the hit-return prompt, otherwise an endless - * recursive loop may result (write error in swapfile, hit-return, timeout - * on char wait, flush swapfile, write error....). - */ + // Don't reset these when at the hit-return prompt, otherwise an endless + // recursive loop may result (write error in swapfile, hit-return, timeout + // on char wait, flush swapfile, write error....). if (State != MODE_HITRETURN) { did_outofmem_msg = false; // display out of memory message (again) did_swapwrite_msg = false; // display swap file write error again @@ -2866,7 +2811,7 @@ int inchar(char_u *buf, int maxlen, long wait_time) if (read_size <= 0) { // Did not get a character from script. // If we got an interrupt, skip all previously typed characters and - // return TRUE if quit reading script file. + // return true if quit reading script file. // Stop reading typeahead when a single CTRL-C was read, // fill_input_buf() returns this when not able to read from stdin. // Don't use buf[] here, closescript() may have freed typebuf.tb_buf[] @@ -2929,7 +2874,7 @@ int fix_input_buffer(char_u *buf, int len) // Two characters are special: NUL and K_SPECIAL. // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER // Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER - for (i = len; --i >= 0; ++p) { + for (i = len; --i >= 0; p++) { if (p[0] == NUL || (p[0] == K_SPECIAL && (i < 2 || p[1] != KS_EXTRA))) { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 231220c319..209caca880 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -23,7 +23,7 @@ #define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8 // takes 6 bytes for one cell) -#ifdef WIN32 +#ifdef MSWIN # define _PATHSEPSTR "\\" #else # define _PATHSEPSTR "/" @@ -159,31 +159,10 @@ EXTERN colnr_T dollar_vcol INIT(= -1); // Variables for Insert mode completion. -// Length in bytes of the text being completed (this is deleted to be replaced -// by the match.) -EXTERN int compl_length INIT(= 0); - -// 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); - -// List of flags for method of completion. -EXTERN int compl_cont_status INIT(= 0); -#define CONT_ADDING 1 // "normal" or "adding" expansion -#define CONT_INTRPT (2 + 4) // a ^X interrupted the current expansion - // it's set only iff N_ADDS is set -#define CONT_N_ADDS 4 // next ^X<> will add-new or expand-current -#define CONT_S_IPOS 8 // next ^X<> will set initial_pos? - // if so, word-wise-expansion will set SOL -#define CONT_SOL 16 // pattern includes start of line, just for - // word-wise expansion, not set for ^X^L -#define CONT_LOCAL 32 // for ctrl_x_mode 0, ^X^P/^X^N do a local - // expansion, (eg use complete=.) - -EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode -EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode -EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode -EXTERN hlf_T edit_submode_highl; // highl. method for extra info +EXTERN char *edit_submode INIT(= NULL); // msg for CTRL-X submode +EXTERN char *edit_submode_pre INIT(= NULL); // prepended to edit_submode +EXTERN char *edit_submode_extra INIT(= NULL); // appended to edit_submode +EXTERN hlf_T edit_submode_highl; // highl. method for extra info // state for putting characters in the message area EXTERN int cmdmsg_rl INIT(= false); // cmdline is drawn right to left @@ -198,7 +177,7 @@ EXTERN bool msg_scrolled_ign INIT(= false); // is reset before the screen is redrawn, so we need to keep track of this. EXTERN bool msg_did_scroll INIT(= false); -EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw +EXTERN char *keep_msg INIT(= NULL); // msg to be shown after redraw EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg EXTERN bool need_fileinfo INIT(= false); // do fileinfo() after redraw EXTERN int msg_scroll INIT(= false); // msg_start() will scroll @@ -220,7 +199,7 @@ EXTERN dict_T vimvardict; // Dictionary with v: variables EXTERN dict_T globvardict; // Dictionary with g: variables /// g: value #define globvarht globvardict.dv_hashtab -EXTERN bool did_emsg; // set by emsg() when the message +EXTERN int did_emsg; // set by emsg() when the message // is displayed or thrown EXTERN bool called_vim_beep; // set if vim_beep() is called EXTERN bool did_emsg_syntax; // did_emsg set because of a @@ -262,9 +241,13 @@ EXTERN int do_profiling INIT(= PROF_NONE); ///< PROF_ values /// Exception currently being thrown. Used to pass an exception to a different /// cstack. Also used for discarding an exception before it is caught or made -/// pending. +/// pending. Only valid when did_throw is true. EXTERN except_T *current_exception; +/// An exception is being thrown. Reset when the exception is caught or as +/// long as it is pending in a finally clause. +EXTERN bool did_throw INIT(= false); + /// Set when a throw that cannot be handled in do_cmdline() must be propagated /// to the cstack of the previously called do_cmdline(). EXTERN bool need_rethrow INIT(= false); @@ -580,6 +563,8 @@ EXTERN bool can_si INIT(= false); // one indent will be removed. EXTERN bool can_si_back INIT(= false); +EXTERN int old_indent INIT(= 0); ///< for ^^D command in insert mode + // w_cursor before formatting text. EXTERN pos_T saved_cursor INIT(= { 0, 0, 0 }); @@ -614,7 +599,7 @@ EXTERN int inhibit_delete_count INIT(= 0); #define DBCS_DEBUG (-1) /// Encoding used when 'fencs' is set to "default" -EXTERN char_u *fenc_default INIT(= NULL); +EXTERN char *fenc_default INIT(= NULL); /// "State" is the main state of Vim. /// There are other variables that modify the state: @@ -685,8 +670,8 @@ EXTERN bool cmd_silent INIT(= false); // don't echo the command line EXTERN int swap_exists_action INIT(= SEA_NONE); ///< For dialog when swap file already exists. EXTERN bool swap_exists_did_quit INIT(= false); ///< Selected "quit" at the dialog. -EXTERN char_u IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc. -EXTERN char_u NameBuff[MAXPATHL]; ///< Buffer for expanding file names +EXTERN char IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc. +EXTERN char NameBuff[MAXPATHL]; ///< Buffer for expanding file names EXTERN char msg_buf[MSG_BUF_LEN]; ///< Small buffer for messages EXTERN char os_buf[ ///< Buffer for the os/ layer #if MAXPATHL > IOSIZE @@ -750,9 +735,9 @@ EXTERN bool need_start_insertmode INIT(= false); ///< start insert mode soon // including the terminating NUL EXTERN char last_mode[MODE_MAX_LENGTH] INIT(= "n"); -EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":) -EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "." -EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline +EXTERN char *last_cmdline INIT(= NULL); // last command line (for ":) +EXTERN char *repeat_cmdline INIT(= NULL); // command line for "." +EXTERN char *new_last_cmdline INIT(= NULL); // new value for last_cmdline EXTERN char *autocmd_fname INIT(= NULL); // fname for <afile> on cmdline EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline EXTERN char *autocmd_match INIT(= NULL); // name for <amatch> on cmdline @@ -776,7 +761,7 @@ EXTERN int keep_help_flag INIT(= false); // doing :ta from help file // When a string option is NULL (which only happens in out-of-memory // situations), it is set to empty_option, to avoid having to check for NULL // everywhere. -EXTERN char_u *empty_option INIT(= (char_u *)""); +EXTERN char *empty_option INIT(= ""); EXTERN bool redir_off INIT(= false); // no redirection for a moment EXTERN FILE *redir_fd INIT(= NULL); // message redirection file @@ -816,7 +801,6 @@ EXTERN char *last_chdir_reason INIT(= NULL); EXTERN bool km_stopsel INIT(= false); EXTERN bool km_startsel INIT(= false); -EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0 EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level @@ -940,7 +924,7 @@ EXTERN char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); EXTERN char e_positive[] INIT(= N_("E487: Argument must be positive")); EXTERN char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); -EXTERN char e_quickfix[] INIT(= N_("E42: No Errors")); +EXTERN char e_no_errors[] INIT(= N_("E42: No Errors")); 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")); @@ -1021,6 +1005,8 @@ EXTERN char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too lon EXTERN char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); +EXTERN char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); + EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); EXTERN char e_undobang_cannot_redo_or_move_branch[] @@ -1085,7 +1071,11 @@ 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); +///< Skip win_fix_cursor() call for 'splitkeep' when cmdwin is closed. +EXTERN bool skip_win_fix_cursor INIT(= false); +///< Skip win_fix_scroll() call for 'splitkeep' when closing tab page. +EXTERN bool skip_win_fix_scroll INIT(= false); +///< Skip update_topline() call while executing win_fix_scroll(). +EXTERN bool skip_update_topline INIT(= false); #endif // NVIM_GLOBALS_H diff --git a/src/nvim/grid.c b/src/nvim/grid.c index f95ef3e705..2b73ff895d 100644 --- a/src/nvim/grid.c +++ b/src/nvim/grid.c @@ -46,14 +46,14 @@ void grid_adjust(ScreenGrid **grid, int *row_off, int *col_off) } /// Put a unicode char, and up to MAX_MCO composing chars, in a screen cell. -int schar_from_cc(char_u *p, int c, int u8cc[MAX_MCO]) +int schar_from_cc(char *p, int c, int u8cc[MAX_MCO]) { - int len = utf_char2bytes(c, (char *)p); + int len = utf_char2bytes(c, p); for (int i = 0; i < MAX_MCO; i++) { if (u8cc[i] == 0) { break; } - len += utf_char2bytes(u8cc[i], (char *)p + len); + len += utf_char2bytes(u8cc[i], p + len); } p[len] = 0; return len; @@ -125,7 +125,7 @@ void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr) char buf[MB_MAXBYTES + 1]; buf[utf_char2bytes(c, buf)] = NUL; - grid_puts(grid, (char_u *)buf, row, col, attr); + grid_puts(grid, buf, row, col, attr); } /// get a single character directly from grid.chars into "bytes[]". @@ -140,7 +140,7 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp if (grid->chars != NULL && row < grid->rows && col < grid->cols) { off = grid->line_offset[row] + (size_t)col; *attrp = grid->attrs[off]; - schar_copy(bytes, grid->chars[off]); + schar_copy((char *)bytes, grid->chars[off]); } } @@ -148,7 +148,7 @@ void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp /// attributes 'attr', and update chars[] and attrs[]. /// Note: only outputs within one row, message is truncated at grid boundary! /// Note: if grid, row and/or col is invalid, nothing is done. -void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr) +void grid_puts(ScreenGrid *grid, char *text, int row, int col, int attr) { grid_puts_len(grid, text, -1, row, col, attr); } @@ -171,11 +171,11 @@ void grid_puts_line_start(ScreenGrid *grid, int row) put_dirty_grid = grid; } -void grid_put_schar(ScreenGrid *grid, int row, int col, char_u *schar, int attr) +void grid_put_schar(ScreenGrid *grid, int row, int col, char *schar, int attr) { assert(put_dirty_row == row); size_t off = grid->line_offset[row] + (size_t)col; - if (grid->attrs[off] != attr || schar_cmp(grid->chars[off], schar)) { + if (grid->attrs[off] != attr || schar_cmp(grid->chars[off], schar) || rdb_flags & RDB_NODELTA) { schar_copy(grid->chars[off], schar); grid->attrs[off] = attr; @@ -187,10 +187,10 @@ void grid_put_schar(ScreenGrid *grid, int row, int col, char_u *schar, int attr) /// like grid_puts(), but output "text[len]". When "len" is -1 output up to /// a NUL. -void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col, int attr) +void grid_puts_len(ScreenGrid *grid, char *text, int textlen, int row, int col, int attr) { size_t off; - char_u *ptr = text; + char *ptr = text; int len = textlen; int c; size_t max_off; @@ -237,13 +237,13 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col while (col < grid->cols && (len < 0 || (int)(ptr - text) < len) && *ptr != NUL) { - c = *ptr; + c = (unsigned char)(*ptr); // check if this is the first byte of a multibyte mbyte_blen = len > 0 ? utfc_ptr2len_len(ptr, (int)((text + len) - ptr)) - : utfc_ptr2len((char *)ptr); + : utfc_ptr2len(ptr); u8c = len >= 0 - ? utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr)) + ? utfc_ptr2char_len((char_u *)ptr, u8cc, (int)((text + len) - ptr)) : utfc_ptr2char(ptr, u8cc); mbyte_cells = utf_char2cells(u8c); if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) { @@ -254,7 +254,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col nc1 = NUL; } else { nc = len >= 0 - ? utfc_ptr2char_len(ptr + mbyte_blen, pcc, (int)((text + len) - ptr - mbyte_blen)) + ? utfc_ptr2char_len((char_u *)ptr + mbyte_blen, pcc, + (int)((text + len) - ptr - mbyte_blen)) : utfc_ptr2char(ptr + mbyte_blen, pcc); nc1 = pcc[0]; } @@ -279,7 +280,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col need_redraw = schar_cmp(grid->chars[off], buf) || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) || grid->attrs[off] != attr - || exmode_active; + || exmode_active + || rdb_flags & RDB_NODELTA; if (need_redraw) { // When at the end of the text and overwriting a two-cell @@ -320,7 +322,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col ptr += mbyte_blen; if (clear_next_cell) { // This only happens at the end, display one space next. - ptr = (char_u *)" "; + ptr = " "; len = -1; } } @@ -393,11 +395,11 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int // double wide-char clear out the right half. Only needed in a // terminal. if (start_col > 0 && grid_fix_col(grid, start_col, row) != start_col) { - grid_puts_len(grid, (char_u *)" ", 1, row, start_col - 1, 0); + grid_puts_len(grid, " ", 1, row, start_col - 1, 0); } if (end_col < grid->cols && grid_fix_col(grid, end_col, row) != end_col) { - grid_puts_len(grid, (char_u *)" ", 1, row, end_col, 0); + grid_puts_len(grid, " ", 1, row, end_col, 0); } // if grid was resized (in ext_multigrid mode), the UI has no redraw updates @@ -411,8 +413,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int size_t lineoff = grid->line_offset[row]; for (col = start_col; col < end_col; col++) { size_t off = lineoff + (size_t)col; - if (schar_cmp(grid->chars[off], sc) - || grid->attrs[off] != attr) { + if (schar_cmp(grid->chars[off], sc) || grid->attrs[off] != attr || rdb_flags & RDB_NODELTA) { schar_copy(grid->chars[off], sc); grid->attrs[off] = attr; if (dirty_first == INT_MAX) { @@ -475,9 +476,9 @@ static int grid_char_needs_redraw(ScreenGrid *grid, size_t off_from, size_t off_ /// "endcol" gives the columns where valid characters are. /// "clear_width" is the width of the window. It's > 0 if the rest of the line /// needs to be cleared, negative otherwise. -/// "rlflag" is TRUE in a rightleft window: -/// When TRUE and "clear_width" > 0, clear columns 0 to "endcol" -/// When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" +/// "rlflag" is true in a rightleft window: +/// When true and "clear_width" > 0, clear columns 0 to "endcol" +/// When false and "clear_width" > 0, clear columns "endcol" to "clear_width" /// If "wrap" is true, then hint to the UI that "row" contains a line /// which has wrapped into the next row. void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int clear_width, @@ -604,7 +605,8 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle while (col < clear_width) { if (grid->chars[off_to][0] != ' ' || grid->chars[off_to][1] != NUL - || grid->attrs[off_to] != bg_attr) { + || grid->attrs[off_to] != bg_attr + || rdb_flags & RDB_NODELTA) { grid->chars[off_to][0] = ' '; grid->chars[off_to][1] = NUL; grid->attrs[off_to] = bg_attr; diff --git a/src/nvim/grid.h b/src/nvim/grid.h index 6a93bf3d90..0e79183c14 100644 --- a/src/nvim/grid.h +++ b/src/nvim/grid.h @@ -29,30 +29,30 @@ EXTERN sattr_T *linebuf_attr INIT(= NULL); // screen grid. /// Put a ASCII character in a screen cell. -static inline void schar_from_ascii(char_u *p, const char c) +static inline void schar_from_ascii(char *p, const char c) { - p[0] = (char_u)c; + p[0] = c; p[1] = 0; } /// Put a unicode character in a screen cell. -static inline int schar_from_char(char_u *p, int c) +static inline int schar_from_char(char *p, int c) { - int len = utf_char2bytes(c, (char *)p); + int len = utf_char2bytes(c, p); p[len] = NUL; return len; } /// compare the contents of two screen cells. -static inline int schar_cmp(char_u *sc1, char_u *sc2) +static inline int schar_cmp(char *sc1, char *sc2) { - return strncmp((char *)sc1, (char *)sc2, sizeof(schar_T)); + return strncmp(sc1, sc2, sizeof(schar_T)); } /// copy the contents of screen cell `sc2` into cell `sc1` -static inline void schar_copy(char_u *sc1, char_u *sc2) +static inline void schar_copy(char *sc1, char *sc2) { - xstrlcpy((char *)sc1, (char *)sc2, sizeof(schar_T)); + xstrlcpy(sc1, sc2, sizeof(schar_T)); } #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index 9252b8a371..57b3817bc6 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -10,7 +10,7 @@ #define MAX_MCO 6 // fixed value for 'maxcombine' // The characters and attributes drawn on grids. -typedef char_u schar_T[(MAX_MCO + 1) * 4 + 1]; +typedef char schar_T[(MAX_MCO + 1) * 4 + 1]; typedef int sattr_T; enum { diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index e8410d1ee7..c46f95b64f 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -1,19 +1,13 @@ // 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 -/* - * hardcopy.c: printing to paper - */ +// hardcopy.c: printing to paper #include <assert.h> #include <inttypes.h> #include <string.h> #include "nvim/ascii.h" -#include "nvim/vim.h" -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/eval.h" @@ -38,85 +32,81 @@ #include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/version.h" +#include "nvim/vim.h" -/* - * To implement printing on a platform, the following functions must be - * defined: - * - * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) - * Called once. Code should display printer dialogue (if appropriate) and - * determine printer font and margin settings. Reset has_color if the printer - * doesn't support colors at all. - * Returns FAIL to abort. - * - * int mch_print_begin(prt_settings_T *settings) - * Called to start the print job. - * Return FALSE to abort. - * - * int mch_print_begin_page(char_u *msg) - * Called at the start of each page. - * "msg" indicates the progress of the print job, can be NULL. - * Return FALSE to abort. - * - * int mch_print_end_page() - * Called at the end of each page. - * Return FALSE to abort. - * - * int mch_print_blank_page() - * Called to generate a blank page for collated, duplex, multiple copy - * document. Return FALSE to abort. - * - * void mch_print_end(prt_settings_T *psettings) - * Called at normal end of print job. - * - * void mch_print_cleanup() - * Called if print job ends normally or is abandoned. Free any memory, close - * devices and handles. Also called when mch_print_begin() fails, but not - * when mch_print_init() fails. - * - * void mch_print_set_font(int Bold, int Italic, int Underline); - * Called whenever the font style changes. - * - * void mch_print_set_bg(uint32_t bgcol); - * Called to set the background color for the following text. Parameter is an - * RGB value. - * - * void mch_print_set_fg(uint32_t fgcol); - * Called to set the foreground color for the following text. Parameter is an - * RGB value. - * - * mch_print_start_line(int margin, int page_line) - * Sets the current position at the start of line "page_line". - * If margin is TRUE start in the left margin (for header and line number). - * - * int mch_print_text_out(char_u *p, size_t len); - * Output one character of text p[len] at the current position. - * Return TRUE if there is no room for another character in the same line. - * - * Note that the generic code has no idea of margins. The machine code should - * simply make the page look smaller! The header and the line numbers are - * printed in the margin. - */ - -static option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS] - = - { - { "top", TRUE, 0, NULL, 0, FALSE }, - { "bottom", TRUE, 0, NULL, 0, FALSE }, - { "left", TRUE, 0, NULL, 0, FALSE }, - { "right", TRUE, 0, NULL, 0, FALSE }, - { "header", TRUE, 0, NULL, 0, FALSE }, - { "syntax", FALSE, 0, NULL, 0, FALSE }, - { "number", FALSE, 0, NULL, 0, FALSE }, - { "wrap", FALSE, 0, NULL, 0, FALSE }, - { "duplex", FALSE, 0, NULL, 0, FALSE }, - { "portrait", FALSE, 0, NULL, 0, FALSE }, - { "paper", FALSE, 0, NULL, 0, FALSE }, - { "collate", FALSE, 0, NULL, 0, FALSE }, - { "jobsplit", FALSE, 0, NULL, 0, FALSE }, - { "formfeed", FALSE, 0, NULL, 0, FALSE }, - } -; +// To implement printing on a platform, the following functions must be +// defined: +// +// int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) +// Called once. Code should display printer dialogue (if appropriate) and +// determine printer font and margin settings. Reset has_color if the printer +// doesn't support colors at all. +// Returns FAIL to abort. +// +// int mch_print_begin(prt_settings_T *settings) +// Called to start the print job. +// Return false to abort. +// +// int mch_print_begin_page(char_u *msg) +// Called at the start of each page. +// "msg" indicates the progress of the print job, can be NULL. +// Return false to abort. +// +// int mch_print_end_page() +// Called at the end of each page. +// Return false to abort. +// +// int mch_print_blank_page() +// Called to generate a blank page for collated, duplex, multiple copy +// document. Return false to abort. +// +// void mch_print_end(prt_settings_T *psettings) +// Called at normal end of print job. +// +// void mch_print_cleanup() +// Called if print job ends normally or is abandoned. Free any memory, close +// devices and handles. Also called when mch_print_begin() fails, but not +// when mch_print_init() fails. +// +// void mch_print_set_font(int Bold, int Italic, int Underline); +// Called whenever the font style changes. +// +// void mch_print_set_bg(uint32_t bgcol); +// Called to set the background color for the following text. Parameter is an +// RGB value. +// +// void mch_print_set_fg(uint32_t fgcol); +// Called to set the foreground color for the following text. Parameter is an +// RGB value. +// +// mch_print_start_line(int margin, int page_line) +// Sets the current position at the start of line "page_line". +// If margin is true start in the left margin (for header and line number). +// +// int mch_print_text_out(char_u *p, size_t len); +// Output one character of text p[len] at the current position. +// Return true if there is no room for another character in the same line. +// +// Note that the generic code has no idea of margins. The machine code should +// simply make the page look smaller! The header and the line numbers are +// printed in the margin. + +static option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS] = { + { "top", true, 0, NULL, 0, false }, + { "bottom", true, 0, NULL, 0, false }, + { "left", true, 0, NULL, 0, false }, + { "right", true, 0, NULL, 0, false }, + { "header", true, 0, NULL, 0, false }, + { "syntax", false, 0, NULL, 0, false }, + { "number", false, 0, NULL, 0, false }, + { "wrap", false, 0, NULL, 0, false }, + { "duplex", false, 0, NULL, 0, false }, + { "portrait", false, 0, NULL, 0, false }, + { "paper", false, 0, NULL, 0, false }, + { "collate", false, 0, NULL, 0, false }, + { "jobsplit", false, 0, NULL, 0, false }, + { "formfeed", false, 0, NULL, 0, false }, +}; static const uint32_t cterm_color_8[8] = { 0x000000, 0xff0000, 0x00ff00, 0xffff00, @@ -152,17 +142,15 @@ static int page_count; static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] = { - { "c", FALSE, 0, NULL, 0, FALSE }, - { "a", FALSE, 0, NULL, 0, FALSE }, - { "r", FALSE, 0, NULL, 0, FALSE }, - { "b", FALSE, 0, NULL, 0, FALSE }, - { "i", FALSE, 0, NULL, 0, FALSE }, - { "o", FALSE, 0, NULL, 0, FALSE }, + { "c", false, 0, NULL, 0, false }, + { "a", false, 0, NULL, 0, false }, + { "r", false, 0, NULL, 0, false }, + { "b", false, 0, NULL, 0, false }, + { "i", false, 0, NULL, 0, false }, + { "o", false, 0, NULL, 0, false }, }; -/* - * These values determine the print position on a page. - */ +// These values determine the print position on a page. typedef struct { int lead_spaces; // remaining spaces for a TAB int print_pos; // virtual column for computing TABs @@ -188,8 +176,8 @@ struct prt_ps_font_S { char *(ps_fontname[4]); }; -/* Structures to map user named encoding and mapping to PS equivalents for - * building CID font name */ +// Structures to map user named encoding and mapping to PS equivalents for +// building CID font name struct prt_ps_encoding_S { char *encoding; char *cmap_encoding; @@ -247,8 +235,8 @@ struct prt_dsc_line_S { int len; }; -/* Static buffer to read initial comments in a resource file, some can have a - * couple of KB of comments! */ +// Static buffer to read initial comments in a resource file, some can have a +// couple of KB of comments! #define PRT_FILE_BUFFER_LEN (2048) struct prt_resfile_buffer_S { char_u buffer[PRT_FILE_BUFFER_LEN]; @@ -261,33 +249,27 @@ struct prt_resfile_buffer_S { # include "hardcopy.c.generated.h" #endif -/* - * Parse 'printoptions' and set the flags in "printer_opts". - * Returns an error message or NULL; - */ +// Parse 'printoptions' and set the flags in "printer_opts". +// Returns an error message or NULL; char *parse_printoptions(void) { - return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS); + return parse_list_options((char_u *)p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS); } -/* - * Parse 'printoptions' and set the flags in "printer_opts". - * Returns an error message or NULL; - */ +// Parse 'printoptions' and set the flags in "printer_opts". +// Returns an error message or NULL; char *parse_printmbfont(void) { - return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS); + return parse_list_options((char_u *)p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS); } -/* - * Parse a list of options in the form - * option:value,option:value,option:value - * - * "value" can start with a number which is parsed out, e.g. margin:12mm - * - * Returns an error message for an illegal option, NULL otherwise. - * Only used for the printer at the moment... - */ +// Parse a list of options in the form +// option:value,option:value,option:value +// +// "value" can start with a number which is parsed out, e.g. margin:12mm +// +// Returns an error message for an illegal option, NULL otherwise. +// Only used for the printer at the moment... static char *parse_list_options(char_u *option_str, option_table_T *table, size_t table_size) { option_table_T *old_opts; @@ -307,9 +289,7 @@ static char *parse_list_options(char_u *option_str, option_table_T *table, size_ table[idx].present = false; } - /* - * Repeat for all comma separated parts. - */ + // Repeat for all comma separated parts. stringp = option_str; while (*stringp) { colonp = (char_u *)vim_strchr((char *)stringp, ':'); @@ -324,7 +304,7 @@ static char *parse_list_options(char_u *option_str, option_table_T *table, size_ len = (int)(colonp - stringp); - for (idx = 0; idx < table_size; ++idx) { + for (idx = 0; idx < table_size; idx++) { if (STRNICMP(stringp, table[idx].name, len) == 0) { break; } @@ -367,10 +347,8 @@ static char *parse_list_options(char_u *option_str, option_table_T *table, size_ return ret; } -/* - * If using a dark background, the colors will probably be too bright to show - * up well on white paper, so reduce their brightness. - */ +// If using a dark background, the colors will probably be too bright to show +// up well on white paper, so reduce their brightness. static uint32_t darken_rgb(uint32_t rgb) { return ((rgb >> 17) << 16) @@ -495,9 +473,7 @@ static void prt_line_number(prt_settings_T *const psettings, const int page_line } } -/* - * Get the currently effective header height. - */ +// Get the currently effective header height. int prt_header_height(void) { if (printer_opts[OPT_PRINT_HEADERHEIGHT].present) { @@ -506,19 +482,15 @@ int prt_header_height(void) return 2; } -/* - * Return TRUE if using a line number for printing. - */ +// Return true if using a line number for printing. int prt_use_number(void) { return printer_opts[OPT_PRINT_NUMBER].present && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y'; } -/* - * Return the unit used in a margin item in 'printoptions'. - * Returns PRT_UNIT_NONE if not recognized. - */ +// Return the unit used in a margin item in 'printoptions'. +// Returns PRT_UNIT_NONE if not recognized. int prt_get_unit(int idx) { int u = PRT_UNIT_NONE; @@ -526,7 +498,7 @@ int prt_get_unit(int idx) static char *(units[4]) = PRT_UNIT_NAMES; if (printer_opts[idx].present) { - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; i++) { if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0) { u = i; break; @@ -552,14 +524,12 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const if (*p_header != NUL) { linenr_T tmp_lnum, tmp_topline, tmp_botline; - int use_sandbox = FALSE; - - /* - * Need to (temporarily) set current line number and first/last line - * number on the 'window'. Since we don't know how long the page is, - * set the first and current line number to the top line, and guess - * that the page length is 64. - */ + int use_sandbox = false; + + // Need to (temporarily) set current line number and first/last line + // number on the 'window'. Since we don't know how long the page is, + // set the first and current line number to the top line, and guess + // that the page length is 64. tmp_lnum = curwin->w_cursor.lnum; tmp_topline = curwin->w_topline; tmp_botline = curwin->w_botline; @@ -614,14 +584,12 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const } } -/* - * Display a print status message. - */ +// Display a print status message. static void prt_message(char_u *s) { // TODO(bfredl): delete this grid_fill(&default_grid, Rows - 1, Rows, 0, Columns, ' ', ' ', 0); - grid_puts(&default_grid, s, Rows - 1, 0, HL_ATTR(HLF_R)); + grid_puts(&default_grid, (char *)s, Rows - 1, 0, HL_ATTR(HLF_R)); ui_flush(); } @@ -652,13 +620,11 @@ void ex_hardcopy(exarg_T *eap) settings.arguments = (char_u *)eap->arg; } - /* - * Initialise for printing. Ask the user for settings, unless forceit is - * set. - * The mch_print_init() code should set up margins if applicable. (It may - * not be a real printer - for example the engine might generate HTML or - * PS.) - */ + // Initialise for printing. Ask the user for settings, unless forceit is + // set. + // The mch_print_init() code should set up margins if applicable. (It may + // not be a real printer - for example the engine might generate HTML or + // PS.) if (mch_print_init(&settings, curbuf->b_fname == NULL ? (char_u *)buf_spname(curbuf) : curbuf->b_sfname == NULL ? (char_u *)curbuf->b_fname : (char_u *)curbuf->b_sfname, @@ -669,7 +635,7 @@ void ex_hardcopy(exarg_T *eap) settings.modec = 'c'; if (!syntax_present(curwin)) { - settings.do_syntax = FALSE; + settings.do_syntax = false; } else if (printer_opts[OPT_PRINT_SYNTAX].present && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a') { settings.do_syntax = @@ -695,11 +661,9 @@ void ex_hardcopy(exarg_T *eap) prt_get_attr(id, &settings.number, settings.modec); } - /* - * Estimate the total lines to be printed - */ + // Estimate the total lines to be printed for (lnum = eap->line1; lnum <= eap->line2; lnum++) { - bytes_to_print += STRLEN(skipwhite((char *)ml_get(lnum))); + bytes_to_print += strlen(skipwhite(ml_get(lnum))); } if (bytes_to_print == 0) { msg(_("No text to be printed")); @@ -725,9 +689,7 @@ void ex_hardcopy(exarg_T *eap) goto print_fail_no_begin; } - /* - * Loop over collated copies: 1 2 3, 1 2 3, ... - */ + // Loop over collated copies: 1 2 3, 1 2 3, ... page_count = 0; for (collated_copies = 0; collated_copies < settings.n_collated_copies; @@ -748,27 +710,19 @@ void ex_hardcopy(exarg_T *eap) } } - /* - * Loop over all pages in the print job: 1 2 3 ... - */ - for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count) { - /* - * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ... - * For duplex: 12 12 12 34 34 34, ... - */ + // Loop over all pages in the print job: 1 2 3 ... + for (page_count = 0; prtpos.file_line <= eap->line2; page_count++) { + // Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ... + // For duplex: 12 12 12 34 34 34, ... for (uncollated_copies = 0; uncollated_copies < settings.n_uncollated_copies; uncollated_copies++) { // Set the print position to the start of this page. prtpos = page_prtpos; - /* - * Do front and rear side of a page. - */ - for (side = 0; side <= settings.duplex; ++side) { - /* - * Print one page. - */ + // Do front and rear side of a page. + for (side = 0; side <= settings.duplex; side++) { + // Print one page. // Check for interrupt character every page. os_breakcheck(); @@ -780,21 +734,19 @@ void ex_hardcopy(exarg_T *eap) sprintf((char *)IObuff, _("Printing page %d (%zu%%)"), page_count + 1 + side, prtpos.bytes_printed * 100 / bytes_to_print); - if (!mch_print_begin_page(IObuff)) { + if (!mch_print_begin_page((char_u *)IObuff)) { goto print_fail; } if (settings.n_collated_copies > 1) { - sprintf((char *)IObuff + STRLEN(IObuff), - _(" Copy %d of %d"), - collated_copies + 1, - settings.n_collated_copies); + snprintf(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), + _(" Copy %d of %d"), + collated_copies + 1, + settings.n_collated_copies); } - prt_message(IObuff); + prt_message((char_u *)IObuff); - /* - * Output header if required - */ + // Output header if required if (prt_header_height() > 0) { prt_header(&settings, page_count + 1 + side, prtpos.file_line); @@ -807,7 +759,7 @@ void ex_hardcopy(exarg_T *eap) if (prtpos.column == 0) { // finished a file line prtpos.bytes_printed += - STRLEN(skipwhite((char *)ml_get(prtpos.file_line))); + strlen(skipwhite(ml_get(prtpos.file_line))); if (++prtpos.file_line > eap->line2) { break; // reached the end } @@ -826,10 +778,8 @@ void ex_hardcopy(exarg_T *eap) } } - /* - * Extra blank page for duplexing with odd number of pages and - * more copies to come. - */ + // Extra blank page for duplexing with odd number of pages and + // more copies to come. if (prtpos.file_line > eap->line2 && settings.duplex && side == 0 && uncollated_copies + 1 < settings.n_uncollated_copies) { @@ -848,13 +798,13 @@ void ex_hardcopy(exarg_T *eap) vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"), settings.jobname); - prt_message(IObuff); + prt_message((char_u *)IObuff); } print_fail: if (got_int || settings.user_abort) { - sprintf((char *)IObuff, "%s", _("Printing aborted")); - prt_message(IObuff); + snprintf(IObuff, IOSIZE, "%s", _("Printing aborted")); + prt_message((char_u *)IObuff); } mch_print_end(&settings); @@ -862,15 +812,13 @@ print_fail_no_begin: mch_print_cleanup(); } -/* - * Print one page line. - * Return the next column to print, or zero if the line is finished. - */ +// Print one page line. +// Return the next column to print, or zero if the line is finished. static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos) { colnr_T col; char_u *line; - int need_break = FALSE; + int need_break = false; int outputlen; int tab_spaces; int print_pos; @@ -883,7 +831,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T if (!ppos->ff && prt_use_number()) { prt_line_number(psettings, page_line, ppos->file_line); } - ppos->ff = FALSE; + ppos->ff = false; } else { // left over from wrap halfway through a tab print_pos = ppos->print_pos; @@ -891,11 +839,9 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T } mch_print_start_line(false, page_line); - line = ml_get(ppos->file_line); + line = (char_u *)ml_get(ppos->file_line); - /* - * Loop over the columns until the end of the file line or right margin. - */ + // Loop over the columns until the end of the file line or right margin. for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen) { if ((outputlen = utfc_ptr2len((char *)line + col)) < 1) { outputlen = 1; @@ -909,7 +855,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T id = 0; } // Get the line again, a multi-line regexp may invalidate it. - line = ml_get(ppos->file_line); + line = (char_u *)ml_get(ppos->file_line); if (id != current_syn_id) { current_syn_id = id; @@ -920,9 +866,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T } } - /* - * Appropriately expand any tabs to spaces. - */ + // Appropriately expand any tabs to spaces. if (line[col] == TAB || tab_spaces != 0) { if (tab_spaces == 0) { tab_spaces = tabstop_padding(print_pos, @@ -946,7 +890,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T && printer_opts[OPT_PRINT_FORMFEED].present && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0]) == 'y') { - ppos->ff = TRUE; + ppos->ff = true; need_break = 1; } else { need_break = mch_print_text_out(line + col, (size_t)outputlen); @@ -957,10 +901,8 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T ppos->lead_spaces = tab_spaces; ppos->print_pos = print_pos; - /* - * Start next line of file if we clip lines, or have reached end of the - * line, unless we are doing a formfeed. - */ + // Start next line of file if we clip lines, or have reached end of the + // line, unless we are doing a formfeed. if (!ppos->ff && (line[col] == NUL || (printer_opts[OPT_PRINT_WRAP].present @@ -971,34 +913,32 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T return col; } -/* - * PS printer stuff. - * - * Sources of information to help maintain the PS printing code: - * - * 1. PostScript Language Reference, 3rd Edition, - * Addison-Wesley, 1999, ISBN 0-201-37922-8 - * 2. PostScript Language Program Design, - * Addison-Wesley, 1988, ISBN 0-201-14396-8 - * 3. PostScript Tutorial and Cookbook, - * Addison Wesley, 1985, ISBN 0-201-10179-3 - * 4. PostScript Language Document Structuring Conventions Specification, - * version 3.0, - * Adobe Technote 5001, 25th September 1992 - * 5. PostScript Printer Description File Format Specification, Version 4.3, - * Adobe technote 5003, 9th February 1996 - * 6. Adobe Font Metrics File Format Specification, Version 4.1, - * Adobe Technote 5007, 7th October 1998 - * 7. Adobe CMap and CIDFont Files Specification, Version 1.0, - * Adobe Technote 5014, 8th October 1996 - * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts, - * Adoboe Technote 5094, 8th September, 2001 - * 9. CJKV Information Processing, 2nd Edition, - * O'Reilly, 2002, ISBN 1-56592-224-7 - * - * Some of these documents can be found in PDF form on Adobe's web site - - * http://www.adobe.com - */ +// PS printer stuff. +// +// Sources of information to help maintain the PS printing code: +// +// 1. PostScript Language Reference, 3rd Edition, +// Addison-Wesley, 1999, ISBN 0-201-37922-8 +// 2. PostScript Language Program Design, +// Addison-Wesley, 1988, ISBN 0-201-14396-8 +// 3. PostScript Tutorial and Cookbook, +// Addison Wesley, 1985, ISBN 0-201-10179-3 +// 4. PostScript Language Document Structuring Conventions Specification, +// version 3.0, +// Adobe Technote 5001, 25th September 1992 +// 5. PostScript Printer Description File Format Specification, Version 4.3, +// Adobe technote 5003, 9th February 1996 +// 6. Adobe Font Metrics File Format Specification, Version 4.1, +// Adobe Technote 5007, 7th October 1998 +// 7. Adobe CMap and CIDFont Files Specification, Version 1.0, +// Adobe Technote 5014, 8th October 1996 +// 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts, +// Adoboe Technote 5094, 8th September, 2001 +// 9. CJKV Information Processing, 2nd Edition, +// O'Reilly, 2002, ISBN 1-56592-224-7 +// +// Some of these documents can be found in PDF form on Adobe's web site - +// http://www.adobe.com #define PRT_PS_DEFAULT_DPI (72) // Default user space resolution #define PRT_PS_DEFAULT_FONTSIZE (10) @@ -1222,16 +1162,15 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] = } }; -/* The PS prolog file version number has to match - if the prolog file is - * updated, increment the number in the file and here. Version checking was - * added as of VIM 6.2. - * The CID prolog file version number behaves as per PS prolog. - * Table of VIM and prolog versions: - * - * VIM Prolog CIDProlog - * 6.2 1.3 - * 7.0 1.4 1.0 - */ +// The PS prolog file version number has to match - if the prolog file is +// updated, increment the number in the file and here. Version checking was +// added as of VIM 6.2. +// The CID prolog file version number behaves as per PS prolog. +// Table of VIM and prolog versions: +// +// VIM Prolog CIDProlog +// 6.2 1.3 +// 7.0 1.4 1.0 #define PRT_PROLOG_VERSION ((char_u *)"1.4") #define PRT_CID_PROLOG_VERSION ((char_u *)"1.0") @@ -1242,8 +1181,8 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] = #define PRT_RESOURCE_ENCODING "Encoding" #define PRT_RESOURCE_CMAP "CMap" -/* Data for table based DSC comment recognition, easy to extend if VIM needs to - * read more comments. */ +// Data for table based DSC comment recognition, easy to extend if VIM needs to +// read more comments. #define PRT_DSC_MISC_TYPE (-1) #define PRT_DSC_TITLE_TYPE (1) #define PRT_DSC_VERSION_TYPE (2) @@ -1263,17 +1202,13 @@ static struct prt_dsc_comment_S prt_dsc_table[] = PRT_DSC_ENDCOMMENTS_TYPE } }; -/* - * Variables for the output PostScript file. - */ +// Variables for the output PostScript file. static FILE *prt_ps_fd; static bool prt_file_error; static char_u *prt_ps_file_name = NULL; -/* - * Various offsets and dimensions in default PostScript user space (points). - * Used for text positioning calculations - */ +// Various offsets and dimensions in default PostScript user space (points). +// Used for text positioning calculations static double prt_page_width; static double prt_page_height; static double prt_left_margin; @@ -1288,10 +1223,8 @@ static double prt_bgcol_offset; static double prt_pos_x_moveto = 0.0; static double prt_pos_y_moveto = 0.0; -/* - * Various control variables used to decide when and how to change the - * PostScript graphics state. - */ +// Various control variables used to decide when and how to change the +// PostScript graphics state. static bool prt_need_moveto; static bool prt_do_moveto; static bool prt_need_font; @@ -1310,9 +1243,7 @@ static double prt_text_run; static int prt_page_num; static int prt_bufsiz; -/* - * Variables controlling physical printing. - */ +// Variables controlling physical printing. static int prt_media; static int prt_portrait; static int prt_num_copies; @@ -1320,9 +1251,7 @@ static int prt_duplex; static int prt_tumble; static int prt_collate; -/* - * Buffers used when generating PostScript output - */ +// Buffers used when generating PostScript output static char prt_line_buffer[257]; static garray_T prt_ps_buffer = GA_EMPTY_INIT_VALUE; @@ -1349,7 +1278,7 @@ static void prt_write_file_raw_len(char_u *buffer, size_t bytes) static void prt_write_file(char *buffer) { - prt_write_file_len((char_u *)buffer, STRLEN(buffer)); + prt_write_file_len((char_u *)buffer, strlen(buffer)); } static void prt_write_file_len(char_u *buffer, size_t bytes) @@ -1357,36 +1286,28 @@ static void prt_write_file_len(char_u *buffer, size_t bytes) prt_write_file_raw_len(buffer, bytes); } -/* - * Write a string. - */ +// Write a string. static void prt_write_string(char *s) { vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%s", s); prt_write_file(prt_line_buffer); } -/* - * Write an int and a space. - */ +// Write an int and a space. static void prt_write_int(int i) { snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%d ", i); prt_write_file(prt_line_buffer); } -/* - * Write a boolean and a space. - */ +// Write a boolean and a space. static void prt_write_boolean(int b) { snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%s ", (b ? "T" : "F")); prt_write_file(prt_line_buffer); } -/* - * Write PostScript to re-encode and define the font. - */ +// Write PostScript to re-encode and define the font. static void prt_def_font(char *new_name, char *encoding, int height, char *font) { vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), @@ -1402,9 +1323,7 @@ static void prt_def_font(char *new_name, char *encoding, int height, char *font) prt_write_file(prt_line_buffer); } -/* - * Write a line to define the CID font. - */ +// Write a line to define the CID font. static void prt_def_cidfont(char *new_name, int height, char *cidfont) { vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), @@ -1415,9 +1334,7 @@ static void prt_def_cidfont(char *new_name, int height, char *cidfont) prt_write_file(prt_line_buffer); } -/* - * Write a line to define a duplicate of a CID font - */ +// Write a line to define a duplicate of a CID font static void prt_dup_cidfont(char *original_name, char *new_name) { vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), @@ -1425,11 +1342,9 @@ static void prt_dup_cidfont(char *original_name, char *new_name) prt_write_file(prt_line_buffer); } -/* - * Convert a real value into an integer and fractional part as integers, with - * the fractional part being in the range [0,10^precision). The fractional part - * is also rounded based on the precision + 1'th fractional digit. - */ +// Convert a real value into an integer and fractional part as integers, with +// the fractional part being in the range [0,10^precision). The fractional part +// is also rounded based on the precision + 1'th fractional digit. static void prt_real_bits(double real, int precision, int *pinteger, int *pfraction) { int integer = (int)real; @@ -1445,11 +1360,9 @@ static void prt_real_bits(double real, int precision, int *pinteger, int *pfract *pfraction = (int)(fraction + 0.5); } -/* - * Write a real and a space. Save bytes if real value has no fractional part! - * We use prt_real_bits() as %f in sprintf uses the locale setting to decide - * what decimal point character to use, but PS always requires a '.'. - */ +// Write a real and a space. Save bytes if real value has no fractional part! +// We use prt_real_bits() as %f in sprintf uses the locale setting to decide +// what decimal point character to use, but PS always requires a '.'. static void prt_write_real(double val, int prec) { int integer; @@ -1475,9 +1388,7 @@ static void prt_write_real(double val, int prec) prt_write_file(prt_line_buffer); } -/* - * Write a line to define a numeric variable. - */ +// Write a line to define a numeric variable. static void prt_def_var(char *name, double value, int prec) { vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), @@ -1564,7 +1475,7 @@ static void prt_resource_name(char *filename, void *cookie) { char_u *resource_filename = cookie; - if (STRLEN(filename) >= MAXPATHL) { + if (strlen(filename) >= MAXPATHL) { *resource_filename = NUL; } else { STRCPY(resource_filename, filename); @@ -1582,8 +1493,8 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource) // Look for named resource file in runtimepath STRCPY(buffer, "print"); add_pathsep(buffer); - STRLCAT(buffer, name, MAXPATHL); - STRLCAT(buffer, ".ps", MAXPATHL); + xstrlcat(buffer, name, MAXPATHL); + xstrlcat(buffer, ".ps", MAXPATHL); resource->filename[0] = NUL; retval = (do_in_runtimepath(buffer, 0, prt_resource_name, resource->filename) && resource->filename[0] != NUL); @@ -1661,8 +1572,9 @@ static int prt_resfile_skip_ws(int offset) return -1; } -/* prt_next_dsc() - returns detail on next DSC comment line found. Returns true - * if a DSC comment is found, else false */ +/// Returns detail on next DSC comment line found. +/// +/// @return true if a DSC comment is found, else false static bool prt_next_dsc(struct prt_dsc_line_S *p_dsc_line) FUNC_ATTR_NONNULL_ALL { @@ -1741,14 +1653,14 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource) int offset = 0; if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER, - (int)STRLEN(PRT_RESOURCE_HEADER)) != 0) { + (int)strlen(PRT_RESOURCE_HEADER)) != 0) { semsg(_("E618: file \"%s\" is not a PostScript resource file"), resource->filename); return false; } // Skip over any version numbers and following ws - offset += (int)STRLEN(PRT_RESOURCE_HEADER); + offset += (int)strlen(PRT_RESOURCE_HEADER); offset = prt_resfile_skip_nonws(offset); if (offset == -1) { return false; @@ -1758,22 +1670,22 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource) return false; } if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE, - (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0) { + (int)strlen(PRT_RESOURCE_RESOURCE)) != 0) { semsg(_("E619: file \"%s\" is not a supported PostScript resource file"), resource->filename); return false; } - offset += (int)STRLEN(PRT_RESOURCE_RESOURCE); + offset += (int)strlen(PRT_RESOURCE_RESOURCE); // Decide type of resource in the file if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET, - (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0) { + (int)strlen(PRT_RESOURCE_PROCSET)) == 0) { resource->type = PRT_RESOURCE_TYPE_PROCSET; } else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING, - (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0) { + (int)strlen(PRT_RESOURCE_ENCODING)) == 0) { resource->type = PRT_RESOURCE_TYPE_ENCODING; } else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP, - (int)STRLEN(PRT_RESOURCE_CMAP)) == 0) { + (int)strlen(PRT_RESOURCE_CMAP)) == 0) { resource->type = PRT_RESOURCE_TYPE_CMAP; } else { semsg(_("E619: file \"%s\" is not a supported PostScript resource file"), @@ -1988,7 +1900,7 @@ void mch_print_cleanup(void) if (prt_do_conv) { convert_setup(&prt_conv, NULL, NULL); - prt_do_conv = FALSE; + prt_do_conv = false; } if (prt_ps_fd != NULL) { fclose(prt_ps_fd); @@ -2032,9 +1944,7 @@ static double to_device_units(int idx, double physsize, int def_number) return ret; } -/* - * Calculate margins for given width and height from printoptions settings. - */ +// Calculate margins for given width and height from printoptions settings. static void prt_page_margins(double width, double height, double *left, double *right, double *top, double *bottom) { @@ -2074,18 +1984,14 @@ static void prt_build_cid_fontname(int font, char_u *name, int name_len) prt_ps_mb_font.ps_fontname[font] = fontname; } -/* - * Get number of lines of text that fit on a page (excluding the header). - */ +// Get number of lines of text that fit on a page (excluding the header). static int prt_get_lpp(void) { int lpp; - /* - * Calculate offset to lower left corner of background rect based on actual - * font height (based on its bounding box) and the line height, handling the - * case where the font height can exceed the line height. - */ + // Calculate offset to lower left corner of background rect based on actual + // font height (based on its bounding box) and the line height, handling the + // case where the font height can exceed the line height. prt_bgcol_offset = PRT_PS_FONT_TO_USER(prt_line_height, prt_ps_font->bbox_min_y); if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0) { @@ -2115,16 +2021,16 @@ static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap, *pp_mbenc = NULL; // Look for recognised encoding - enc_len = (int)STRLEN(p_encoding); + enc_len = (int)strlen(p_encoding); p_mbenc = p_cmap->encodings; for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++) { if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0) { *pp_mbenc = p_mbenc; - return TRUE; + return true; } p_mbenc++; } - return FALSE; + return false; } static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, @@ -2138,16 +2044,16 @@ static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, if (*p_charset == NUL) { p_charset = p_cmap->defcs; } - char_len = (int)STRLEN(p_charset); + char_len = (int)strlen(p_charset); p_mbchar = p_cmap->charsets; for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++) { if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0) { *pp_mbchar = p_mbchar; - return TRUE; + return true; } p_mbchar++; } - return FALSE; + return false; } int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) @@ -2159,17 +2065,14 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) char_u *p; int props; int cmap = 0; - char_u *p_encoding; struct prt_ps_encoding_S *p_mbenc; struct prt_ps_encoding_S *p_mbenc_first; struct prt_ps_charset_S *p_mbchar = NULL; - /* - * Set up font and encoding. - */ - p_encoding = enc_skip(p_penc); + // Set up font and encoding. + char_u *p_encoding = (char_u *)enc_skip(p_penc); if (*p_encoding == NUL) { - p_encoding = enc_skip(p_enc); + p_encoding = (char_u *)enc_skip(p_enc); } // Look for a multi-byte font that matches the encoding and character set. @@ -2188,7 +2091,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) p_mbenc_first = p_mbenc; effective_cmap = cmap; } - if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar)) { + if (prt_match_charset(p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar)) { break; } } @@ -2232,8 +2135,8 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) } // CMap name ends with (optional) encoding name and -H for horizontal - if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap) - + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap)) { + if (p_mbenc->cmap_encoding != NULL && strlen(prt_cmap) + + strlen(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap)) { STRCAT(prt_cmap, p_mbenc->cmap_encoding); STRCAT(prt_cmap, "-"); } @@ -2281,13 +2184,11 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) prt_ps_font = &prt_ps_mb_font; } else { - prt_use_courier = FALSE; + prt_use_courier = false; prt_ps_font = &prt_ps_courier_font; } - /* - * Find the size of the paper and set the margins. - */ + // Find the size of the paper and set the margins. prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y'); @@ -2298,8 +2199,8 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) paper_name = "A4"; paper_strlen = 2; } - for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i) { - if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen + for (i = 0; i < (int)PRT_MEDIASIZE_LEN; i++) { + if (strlen(prt_mediasize[i].name) == (unsigned)paper_strlen && STRNICMP(prt_mediasize[i].name, paper_name, paper_strlen) == 0) { break; @@ -2310,13 +2211,11 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) } prt_media = i; - /* - * Set PS pagesize based on media dimensions and print orientation. - * Note: Media and page sizes have defined meanings in PostScript and should - * be kept distinct. Media is the paper (or transparency, or ...) that is - * printed on, whereas the page size is the area that the PostScript - * interpreter renders into. - */ + // Set PS pagesize based on media dimensions and print orientation. + // Note: Media and page sizes have defined meanings in PostScript and should + // be kept distinct. Media is the paper (or transparency, or ...) that is + // printed on, whereas the page size is the area that the PostScript + // interpreter renders into. if (prt_portrait) { prt_page_width = prt_mediasize[i].width; prt_page_height = prt_mediasize[i].height; @@ -2335,21 +2234,17 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) prt_top_margin = top; prt_bottom_margin = bottom; - /* - * Set up the font size. - */ + // Set up the font size. fontsize = PRT_PS_DEFAULT_FONTSIZE; - for (p = p_pfn; (p = (char_u *)vim_strchr((char *)p, ':')) != NULL; p++) { + for (p = (char_u *)p_pfn; (p = (char_u *)vim_strchr((char *)p, ':')) != NULL; p++) { if (p[1] == 'h' && ascii_isdigit(p[2])) { fontsize = atoi((char *)p + 2); } } prt_font_metrics(fontsize); - /* - * Return the number of characters per line, and lines per page for the - * generic print code. - */ + // Return the number of characters per line, and lines per page for the + // generic print code. psettings->chars_per_line = prt_get_cpl(); psettings->lines_per_page = prt_get_lpp(); @@ -2358,12 +2253,10 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) return FAIL; } - /* - * Sort out the number of copies to be printed. PS by default will do - * uncollated copies for you, so once we know how many uncollated copies are - * wanted cache it away and lie to the generic code that we only want one - * uncollated copy. - */ + // Sort out the number of copies to be printed. PS by default will do + // uncollated copies for you, so once we know how many uncollated copies are + // wanted cache it away and lie to the generic code that we only want one + // uncollated copy. psettings->n_collated_copies = 1; psettings->n_uncollated_copies = 1; prt_num_copies = 1; @@ -2379,20 +2272,18 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) psettings->jobname = jobname; - /* - * Set up printer duplex and tumble based on Duplex option setting - default - * is long sided duplex printing (i.e. no tumble). - */ - prt_duplex = TRUE; - prt_tumble = FALSE; + // Set up printer duplex and tumble based on Duplex option setting - default + // is long sided duplex printing (i.e. no tumble). + prt_duplex = true; + prt_tumble = false; psettings->duplex = 1; if (printer_opts[OPT_PRINT_DUPLEX].present) { if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0) { - prt_duplex = FALSE; + prt_duplex = false; psettings->duplex = 0; } else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5) == 0) { - prt_tumble = TRUE; + prt_tumble = true; } } @@ -2401,7 +2292,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) // If the user didn't specify a file name, use a temp file. if (psettings->outfile == NULL) { - prt_ps_file_name = vim_tempname(); + prt_ps_file_name = (char_u *)vim_tempname(); if (prt_ps_file_name == NULL) { emsg(_(e_notmp)); return FAIL; @@ -2506,9 +2397,7 @@ bool mch_print_begin(prt_settings_T *psettings) struct prt_ps_resource_S res_cidfont; struct prt_ps_resource_S res_cmap; - /* - * PS DSC Header comments - no PS code! - */ + // PS DSC Header comments - no PS code! prt_dsc_start(); prt_dsc_textline("Title", (char *)psettings->jobname); if (os_get_username(buffer, 256) == FAIL) { @@ -2603,13 +2492,13 @@ bool mch_print_begin(prt_settings_T *psettings) // that cannot be found then default to "latin1". // Note: VIM specific encoding header is always skipped. if (!prt_out_mbyte) { - p_encoding = (char *)enc_skip(p_penc); + p_encoding = enc_skip(p_penc); if (*p_encoding == NUL || !prt_find_resource(p_encoding, &res_encoding)) { // 'printencoding' not set or not supported - find alternate int props; - p_encoding = (char *)enc_skip(p_enc); + p_encoding = enc_skip(p_enc); props = enc_canon_props((char_u *)p_encoding); if (!(props & ENC_8BIT) || !prt_find_resource(p_encoding, &res_encoding)) { @@ -2629,9 +2518,9 @@ bool mch_print_begin(prt_settings_T *psettings) // For the moment there are no checks on encoding resource files to // perform } else { - p_encoding = (char *)enc_skip(p_penc); + p_encoding = enc_skip(p_penc); if (*p_encoding == NUL) { - p_encoding = (char *)enc_skip(p_enc); + p_encoding = enc_skip(p_enc); } if (prt_use_courier) { // Include ASCII range encoding vector @@ -2649,9 +2538,9 @@ bool mch_print_begin(prt_settings_T *psettings) } prt_conv.vc_type = CONV_NONE; - if (!(enc_canon_props(p_enc) & enc_canon_props((char_u *)p_encoding) & ENC_8BIT)) { + if (!(enc_canon_props((char_u *)p_enc) & enc_canon_props((char_u *)p_encoding) & ENC_8BIT)) { // Set up encoding conversion if required - if (convert_setup(&prt_conv, p_enc, (char_u *)p_encoding) == FAIL) { + if (convert_setup(&prt_conv, p_enc, p_encoding) == FAIL) { semsg(_("E620: Unable to convert to print encoding \"%s\""), p_encoding); return false; @@ -2700,9 +2589,7 @@ bool mch_print_begin(prt_settings_T *psettings) prt_num_copies); prt_dsc_noarg("EndComments"); - /* - * PS Document page defaults - */ + // PS Document page defaults prt_dsc_noarg("BeginDefaults"); // List font resources most likely common to all pages @@ -2722,9 +2609,7 @@ bool mch_print_begin(prt_settings_T *psettings) prt_dsc_noarg("EndDefaults"); - /* - * PS Document prolog inclusion - all required procsets. - */ + // PS Document prolog inclusion - all required procsets. prt_dsc_noarg("BeginProlog"); // Add required procsets - NOTE: order is important! @@ -2751,9 +2636,7 @@ bool mch_print_begin(prt_settings_T *psettings) prt_dsc_noarg("EndProlog"); - /* - * PS Document setup - must appear after the prolog - */ + // PS Document setup - must appear after the prolog prt_dsc_noarg("BeginSetup"); // Device setup - page size and number of uncollated copies @@ -2862,9 +2745,7 @@ void mch_print_end(prt_settings_T *psettings) { prt_dsc_noarg("Trailer"); - /* - * Output any info we don't know in toto until we finish - */ + // Output any info we don't know in toto until we finish prt_dsc_ints("Pages", 1, &prt_page_num); prt_dsc_noarg("EOF"); @@ -2945,7 +2826,7 @@ int mch_print_begin_page(char_u *str) int mch_print_blank_page(void) { - return mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE; + return mch_print_begin_page(NULL) ? (mch_print_end_page()) : false; } static double prt_pos_x = 0; @@ -3077,7 +2958,8 @@ int mch_print_text_out(char_u *const textp, size_t len) if (prt_do_conv) { // Convert from multi-byte to 8-bit encoding - tofree = p = string_convert(&prt_conv, p, &len); + p = (char_u *)string_convert(&prt_conv, (char *)p, &len); + tofree = p; if (p == NULL) { p = (char_u *)""; len = 0; diff --git a/src/nvim/hardcopy.h b/src/nvim/hardcopy.h index 9ef4eb0074..ce562cd3e6 100644 --- a/src/nvim/hardcopy.h +++ b/src/nvim/hardcopy.h @@ -8,9 +8,7 @@ #include "nvim/globals.h" // for TriState #include "nvim/types.h" // for char_u -/* - * Structure to hold printing color and font attributes. - */ +// Structure to hold printing color and font attributes. typedef struct { uint32_t fg_color; uint32_t bg_color; @@ -23,9 +21,7 @@ typedef struct { int underdashed; } prt_text_attr_T; -/* - * Structure passed back to the generic printer code. - */ +// Structure passed back to the generic printer code. typedef struct { int n_collated_copies; int n_uncollated_copies; @@ -42,9 +38,7 @@ typedef struct { char_u *arguments; } prt_settings_T; -/* - * Generic option table item, only used for printer at the moment. - */ +// Generic option table item, only used for printer at the moment. typedef struct { const char *name; int hasnum; diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c index 951e72ea52..1ebac603c2 100644 --- a/src/nvim/hashtab.c +++ b/src/nvim/hashtab.c @@ -67,7 +67,7 @@ void hash_clear(hashtab_T *ht) void hash_clear_all(hashtab_T *ht, unsigned int off) { size_t todo = ht->ht_used; - for (hashitem_T *hi = ht->ht_array; todo > 0; ++hi) { + for (hashitem_T *hi = ht->ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { xfree(hi->hi_key - off); todo--; @@ -87,7 +87,7 @@ void hash_clear_all(hashtab_T *ht, unsigned int off) /// is changed in any way. hashitem_T *hash_find(const hashtab_T *const ht, const char *const key) { - return hash_lookup(ht, key, STRLEN(key), hash_hash((char_u *)key)); + return hash_lookup(ht, key, strlen(key), hash_hash((char_u *)key)); } /// Like hash_find, but key is not NUL-terminated @@ -194,7 +194,7 @@ void hash_debug_results(void) #endif // ifdef HT_DEBUG } -/// Add item for key "key" to hashtable "ht". +/// Add (empty) item for key `key` to hashtable `ht`. /// /// @param key Pointer to the key for the new item. The key has to be contained /// in the new item (@see hashitem_T). Must not be NULL. @@ -265,7 +265,7 @@ void hash_unlock(hashtab_T *ht) hash_may_resize(ht, 0); } -/// Resize hastable (new size can be given or automatically computed). +/// Resize hashtable (new size can be given or automatically computed). /// /// @param minitems Minimum number of items the new table should hold. /// If zero, new size will depend on currently used items: @@ -356,7 +356,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems) hash_T newmask = newsize - 1; size_t todo = ht->ht_used; - for (hashitem_T *olditem = oldarray; todo > 0; ++olditem) { + for (hashitem_T *olditem = oldarray; todo > 0; olditem++) { if (HASHITEM_EMPTY(olditem)) { continue; } diff --git a/src/nvim/help.c b/src/nvim/help.c index 442f2e0b7b..7c61a56785 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -75,7 +75,7 @@ void ex_help(exarg_T *eap) } // remove trailing blanks - p = arg + STRLEN(arg) - 1; + p = arg + strlen(arg) - 1; while (p > arg && ascii_iswhite(*p) && p[-1] != '\\') { *p-- = NUL; } @@ -95,7 +95,7 @@ void ex_help(exarg_T *eap) if (n != FAIL && lang != NULL) { // Find first item with the requested language. for (i = 0; i < num_matches; i++) { - len = (int)STRLEN(matches[i]); + len = (int)strlen(matches[i]); if (len > 3 && matches[i][len - 3] == '@' && STRICMP(matches[i] + len - 2, lang) == 0) { break; @@ -137,7 +137,7 @@ void ex_help(exarg_T *eap) } else { // There is no help window yet. // Try to open the file specified by the "helpfile" option. - if ((helpfd = os_fopen((char *)p_hf, READBIN)) == NULL) { + if ((helpfd = os_fopen(p_hf, READBIN)) == NULL) { smsg(_("Sorry, help file \"%s\" not found"), p_hf); goto erret; } @@ -149,7 +149,7 @@ void ex_help(exarg_T *eap) n = WSP_HELP; if (cmdmod.cmod_split == 0 && curwin->w_width != Columns && curwin->w_width < 80) { - n |= WSP_TOP; + n |= p_sb ? WSP_BOT : WSP_TOP; } if (win_split(0, n) == FAIL) { goto erret; @@ -180,7 +180,7 @@ void ex_help(exarg_T *eap) // It is needed for do_tag top open folds under the cursor. KeyTyped = old_KeyTyped; - do_tag((char_u *)tag, DT_HELP, 1, false, true); + do_tag(tag, DT_HELP, 1, false, true); // Delete the empty buffer if we're not using it. Careful: autocommands // may have jumped to another window, check that the buffer is not in a @@ -219,7 +219,7 @@ void ex_helpclose(exarg_T *eap) /// @return NULL if not found. char *check_help_lang(char *arg) { - int len = (int)STRLEN(arg); + int len = (int)strlen(arg); if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2]) && ASCII_ISALPHA(arg[len - 1])) { @@ -278,7 +278,7 @@ int help_heuristic(char *matched_string, int offset, int wrong_case) if (matched_string[0] == '+' && matched_string[1] != NUL) { offset += 100; } - return 100 * num_letters + (int)STRLEN(matched_string) + offset; + return 100 * num_letters + (int)strlen(matched_string) + offset; } /// Compare functions for qsort() below, that checks the help heuristics number @@ -367,7 +367,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // the table, it is taken literally (but ~ is escaped). Otherwise '?' // is recognized as a wildcard. for (i = (int)ARRAY_SIZE(expr_table); --i >= 0;) { - if (STRCMP(arg + 5, expr_table[i]) == 0) { + if (strcmp(arg + 5, expr_table[i]) == 0) { for (int si = 0, di = 0;; si++) { if (arg[si] == '~') { d[di++] = '\\'; @@ -384,7 +384,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // Recognize a few exceptions to the rule. Some strings that contain // '*'are changed to "star", otherwise '*' is recognized as a wildcard. for (i = 0; except_tbl[i][0] != NULL; i++) { - if (STRCMP(arg, except_tbl[i][0]) == 0) { + if (strcmp(arg, except_tbl[i][0]) == 0) { STRCPY(d, except_tbl[i][1]); break; } @@ -428,7 +428,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // completion. // Insert a backslash before '~', '$' and '.' to avoid their // special meaning. - if ((char_u *)d - IObuff > IOSIZE - 10) { // getting too long!? + if (d - IObuff > IOSIZE - 10) { // getting too long!? break; } switch (*s) { @@ -459,7 +459,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1]) || vim_strchr("?@[\\]^", s[1]) != NULL))) { - if ((char_u *)d > IObuff && d[-1] != '_' && d[-1] != '\\') { + if (d > IObuff && d[-1] != '_' && d[-1] != '\\') { *d++ = '_'; // prepend a '_' to make x_CTRL-x } STRCPY(d, "CTRL-"); @@ -513,18 +513,18 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep *d = NUL; if (*IObuff == '`') { - if ((char_u *)d > IObuff + 2 && d[-1] == '`') { + if (d > IObuff + 2 && d[-1] == '`') { // remove the backticks from `command` - memmove(IObuff, IObuff + 1, STRLEN(IObuff)); + memmove(IObuff, IObuff + 1, strlen(IObuff)); d[-2] = NUL; - } else if ((char_u *)d > IObuff + 3 && d[-2] == '`' && d[-1] == ',') { + } else if (d > IObuff + 3 && d[-2] == '`' && d[-1] == ',') { // remove the backticks and comma from `command`, - memmove(IObuff, IObuff + 1, STRLEN(IObuff)); + memmove(IObuff, IObuff + 1, strlen(IObuff)); d[-3] = NUL; - } else if ((char_u *)d > IObuff + 4 && d[-3] == '`' + } else if (d > IObuff + 4 && d[-3] == '`' && d[-2] == '\\' && d[-1] == '.') { // remove the backticks and dot from `command`\. - memmove(IObuff, IObuff + 1, STRLEN(IObuff)); + memmove(IObuff, IObuff + 1, strlen(IObuff)); d[-4] = NUL; } } @@ -537,7 +537,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, matches, flags, MAXCOL, NULL) == OK + if (find_tags((char *)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. @@ -556,8 +556,8 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep /// tag matches it. Otherwise remove "@en" if "en" is the only language. void cleanup_help_tags(int num_file, char **file) { - char_u buf[4]; - char_u *p = buf; + char buf[4]; + char_u *p = (char_u *)buf; if (p_hlg[0] != NUL && (p_hlg[0] != 'e' || p_hlg[1] != 'n')) { *p++ = '@'; @@ -567,17 +567,17 @@ void cleanup_help_tags(int num_file, char **file) *p = NUL; for (int i = 0; i < num_file; i++) { - int len = (int)STRLEN(file[i]) - 3; + int len = (int)strlen(file[i]) - 3; if (len <= 0) { continue; } - if (STRCMP(file[i] + len, "@en") == 0) { + if (strcmp(file[i] + len, "@en") == 0) { // Sorting on priority means the same item in another language may // be anywhere. Search all items for a match up to the "@en". int j; for (j = 0; j < num_file; j++) { if (j != i - && (int)STRLEN(file[j]) == len + 3 + && (int)strlen(file[j]) == len + 3 && STRNCMP(file[i], file[j], len + 1) == 0) { break; } @@ -591,11 +591,11 @@ void cleanup_help_tags(int num_file, char **file) if (*buf != NUL) { for (int i = 0; i < num_file; i++) { - int len = (int)STRLEN(file[i]) - 3; + int len = (int)strlen(file[i]) - 3; if (len <= 0) { continue; } - if (STRCMP(file[i] + len, buf) == 0) { + if (strcmp(file[i] + len, buf) == 0) { // remove the default language file[i][len] = NUL; } @@ -615,7 +615,7 @@ void prepare_help_buffer(void) // latin1 word characters (for translated help files). // Only set it when needed, buf_init_chartab() is some work. char *p = "!-~,^*,^|,^\",192-255"; - if (STRCMP(curbuf->b_p_isk, p) != 0) { + if (strcmp(curbuf->b_p_isk, p) != 0) { set_string_option_direct("isk", -1, p, OPT_FREE|OPT_LOCAL, 0); check_buf_options(curbuf); (void)buf_init_chartab(curbuf, false); @@ -650,21 +650,21 @@ void fix_help_buffer(void) bool in_example = false; // Set filetype to "help". - if (STRCMP(curbuf->b_p_ft, "help") != 0) { + if (strcmp(curbuf->b_p_ft, "help") != 0) { curbuf->b_ro_locked++; - set_option_value("ft", 0L, "help", OPT_LOCAL); + set_option_value_give_err("ft", 0L, "help", OPT_LOCAL); curbuf->b_ro_locked--; } if (!syntax_present(curwin)) { for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) { - line = (char *)ml_get_buf(curbuf, lnum, false); + line = ml_get_buf(curbuf, lnum, false); const size_t len = STRLEN(line); if (in_example && len > 0 && !ascii_iswhite(line[0])) { // End of example: non-white or '<' in first column. if (line[0] == '<') { // blank-out a '<' in the first column - line = (char *)ml_get_buf(curbuf, lnum, true); + line = ml_get_buf(curbuf, lnum, true); line[0] = ' '; } in_example = false; @@ -672,12 +672,12 @@ void fix_help_buffer(void) if (!in_example && len > 0) { if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' ')) { // blank-out a '>' in the last column (start of example) - line = (char *)ml_get_buf(curbuf, lnum, true); + line = ml_get_buf(curbuf, lnum, true); line[len - 1] = ' '; in_example = true; } else if (line[len - 1] == '~') { // blank-out a '~' at the end of line (header marker) - line = (char *)ml_get_buf(curbuf, lnum, true); + line = ml_get_buf(curbuf, lnum, true); line[len - 1] = ' '; } } @@ -687,21 +687,21 @@ void fix_help_buffer(void) // In the "help.txt" and "help.abx" file, add the locally added help // files. This uses the very first line in the help file. char *const fname = path_tail(curbuf->b_fname); - if (FNAMECMP(fname, "help.txt") == 0 - || (FNAMENCMP(fname, "help.", 5) == 0 + if (path_fnamecmp(fname, "help.txt") == 0 + || (path_fnamencmp(fname, "help.", 5) == 0 && ASCII_ISALPHA(fname[5]) && ASCII_ISALPHA(fname[6]) && TOLOWER_ASC(fname[7]) == 'x' && fname[8] == NUL)) { for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; lnum++) { - line = (char *)ml_get_buf(curbuf, lnum, false); + line = ml_get_buf(curbuf, lnum, false); if (strstr(line, "*local-additions*") == NULL) { continue; } // Go through all directories in 'runtimepath', skipping // $VIMRUNTIME. - char *p = (char *)p_rtp; + char *p = p_rtp; while (*p != NUL) { copy_option_part(&p, (char *)NameBuff, MAXPATHL, ","); char *const rt = vim_getenv("VIMRUNTIME"); @@ -715,8 +715,8 @@ void fix_help_buffer(void) // Find all "doc/ *.txt" files in this directory. if (!add_pathsep((char *)NameBuff) - || STRLCAT(NameBuff, "doc/*.??[tx]", // NOLINT - sizeof(NameBuff)) >= MAXPATHL) { + || xstrlcat(NameBuff, "doc/*.??[tx]", // NOLINT + sizeof(NameBuff)) >= MAXPATHL) { emsg(_(e_fnametoolong)); continue; } @@ -741,23 +741,23 @@ void fix_help_buffer(void) const char *const f2 = fnames[i2]; const char *const t1 = path_tail(f1); const char *const t2 = path_tail(f2); - const char *const e1 = (char *)STRRCHR(t1, '.'); - const char *const e2 = (char *)STRRCHR(t2, '.'); + const char *const e1 = strrchr(t1, '.'); + const char *const e2 = strrchr(t2, '.'); if (e1 == NULL || e2 == NULL) { continue; } - if (FNAMECMP(e1, ".txt") != 0 - && FNAMECMP(e1, fname + 4) != 0) { + if (path_fnamecmp(e1, ".txt") != 0 + && path_fnamecmp(e1, fname + 4) != 0) { // Not .txt and not .abx, remove it. XFREE_CLEAR(fnames[i1]); continue; } if (e1 - f1 != e2 - f2 - || FNAMENCMP(f1, f2, e1 - f1) != 0) { + || path_fnamencmp(f1, f2, (size_t)(e1 - f1)) != 0) { continue; } - if (FNAMECMP(e1, ".txt") == 0 - && FNAMECMP(e2, fname + 4) == 0) { + if (path_fnamecmp(e1, ".txt") == 0 + && path_fnamecmp(e2, fname + 4) == 0) { // use .abx instead of .txt XFREE_CLEAR(fnames[i1]); } @@ -772,7 +772,7 @@ void fix_help_buffer(void) if (fd == NULL) { continue; } - vim_fgets(IObuff, IOSIZE, fd); + vim_fgets((char_u *)IObuff, IOSIZE, fd); if (IObuff[0] == '*' && (s = vim_strchr((char *)IObuff + 1, '*')) != NULL) { @@ -803,7 +803,7 @@ void fix_help_buffer(void) // 'encoding' may be required. vc.vc_type = CONV_NONE; convert_setup(&vc, - (char_u *)(this_utf == kTrue ? "utf-8" : "latin1"), + (this_utf == kTrue ? "utf-8" : "latin1"), p_enc); if (vc.vc_type == CONV_NONE) { // No conversion needed. @@ -811,7 +811,7 @@ void fix_help_buffer(void) } else { // Do the conversion. If it fails // use the unconverted text. - cp = (char *)string_convert(&vc, IObuff, NULL); + cp = string_convert(&vc, (char *)IObuff, NULL); if (cp == NULL) { cp = (char *)IObuff; } @@ -819,7 +819,7 @@ void fix_help_buffer(void) convert_setup(&vc, NULL, NULL); ml_append(lnum, cp, (colnr_T)0, false); - if ((char_u *)cp != IObuff) { + if (cp != IObuff) { xfree(cp); } lnum++; @@ -871,8 +871,8 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // Find all *.txt files. size_t dirlen = STRLCPY(NameBuff, dir, sizeof(NameBuff)); if (dirlen >= MAXPATHL - || STRLCAT(NameBuff, "/**/*", sizeof(NameBuff)) >= MAXPATHL // NOLINT - || STRLCAT(NameBuff, ext, sizeof(NameBuff)) >= MAXPATHL) { + || xstrlcat(NameBuff, "/**/*", sizeof(NameBuff)) >= MAXPATHL // NOLINT + || xstrlcat(NameBuff, ext, sizeof(NameBuff)) >= MAXPATHL) { emsg(_(e_fnametoolong)); return; } @@ -896,7 +896,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // Do this before scanning through all the files. memcpy(NameBuff, dir, dirlen + 1); if (!add_pathsep((char *)NameBuff) - || STRLCAT(NameBuff, tagfname, sizeof(NameBuff)) >= MAXPATHL) { + || xstrlcat(NameBuff, tagfname, sizeof(NameBuff)) >= MAXPATHL) { emsg(_(e_fnametoolong)); return; } @@ -915,7 +915,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool ga_init(&ga, (int)sizeof(char_u *), 100); if (add_help_tags || path_full_compare("$VIMRUNTIME/doc", dir, false, true) == kEqualFiles) { - size_t s_len = 18 + STRLEN(tagfname); + size_t s_len = 18 + strlen(tagfname); s = xmalloc(s_len); snprintf(s, s_len, "help-tags\t%s\t1\n", tagfname); GA_APPEND(char *, &ga, s); @@ -931,7 +931,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool const char *const fname = files[fi] + dirlen + 1; bool firstline = true; - while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) { + while (!vim_fgets((char_u *)IObuff, IOSIZE, fd) && !got_int) { if (firstline) { // Detect utf-8 file by a non-ASCII char in the first line. TriState this_utf8 = kNone; @@ -974,12 +974,12 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // characters, there is white space before it and is // followed by a white character or end-of-line. if (s == p2 - && ((char_u *)p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') + && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') && (vim_strchr(" \t\n\r", s[1]) != NULL || s[1] == '\0')) { *p2 = '\0'; p1++; - size_t s_len= (size_t)(p2 - p1) + STRLEN(fname) + 2; + size_t s_len= (size_t)(p2 - p1) + strlen(fname) + 2; s = xmalloc(s_len); GA_APPEND(char *, &ga, s); snprintf(s, s_len, "%s\t%s", p1, fname); @@ -1067,7 +1067,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr) // Get a list of all files in the help directory and in subdirectories. STRLCPY(NameBuff, dirname, sizeof(NameBuff)); if (!add_pathsep((char *)NameBuff) - || STRLCAT(NameBuff, "**", sizeof(NameBuff)) >= MAXPATHL) { + || xstrlcat(NameBuff, "**", sizeof(NameBuff)) >= MAXPATHL) { emsg(_(e_fnametoolong)); return; } @@ -1087,7 +1087,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr) int j; ga_init(&ga, 1, 10); for (int i = 0; i < filecount; i++) { - len = (int)STRLEN(files[i]); + len = (int)strlen(files[i]); if (len <= 4) { continue; } @@ -1162,14 +1162,13 @@ void ex_helptags(exarg_T *eap) eap->arg = skipwhite(eap->arg + 3); } - if (STRCMP(eap->arg, "ALL") == 0) { + if (strcmp(eap->arg, "ALL") == 0) { do_in_path(p_rtp, "doc", DIP_ALL + DIP_DIR, helptags_cb, &add_help_tags); } else { ExpandInit(&xpc); xpc.xp_context = EXPAND_DIRECTORIES; - dirname = (char *)ExpandOne(&xpc, (char_u *)eap->arg, NULL, - WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); - if (dirname == NULL || !os_isdir((char_u *)dirname)) { + dirname = ExpandOne(&xpc, eap->arg, NULL, WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); + if (dirname == NULL || !os_isdir(dirname)) { semsg(_("E150: Not a directory: %s"), eap->arg); } else { do_helptags(dirname, add_help_tags, false); diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index d6a18fcf8e..d507f07bca 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -223,7 +223,7 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault) } } - it.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs); + it.attr_id = fallback ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs); it.version = p->hl_valid - tmp; it.is_default = attrs.rgb_ae_attr & HL_DEFAULT; it.link_global = attrs.rgb_ae_attr & HL_GLOBAL; @@ -406,8 +406,8 @@ void update_ns_hl(int ns_id) } int *hl_attrs = **alloc; - for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) { - int id = syn_check_group(hlf_names[hlf], STRLEN(hlf_names[hlf])); + for (int hlf = 0; hlf < HLF_COUNT; hlf++) { + int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); bool optional = (hlf == HLF_INACTIVE || hlf == HLF_NFLOAT); hl_attrs[hlf] = hl_get_ui_attr(ns_id, hlf, id, optional); } @@ -729,7 +729,7 @@ static int hl_cterm2rgb_color(int nr) 0x08, 0x12, 0x1C, 0x26, 0x30, 0x3A, 0x44, 0x4E, 0x58, 0x62, 0x6C, 0x76, 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE }; - static char_u ansi_table[16][4] = { + static uint8_t ansi_table[16][4] = { // R G B idx { 0, 0, 0, 1 }, // black { 224, 0, 0, 2 }, // dark red @@ -788,7 +788,7 @@ HlAttrs syn_attr2entry(int attr) } /// Gets highlight description for id `attr_id` as a map. -Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err) +Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *err) { Dictionary dic = ARRAY_DICT_INIT; @@ -801,25 +801,21 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err) "Invalid attribute id: %" PRId64, attr_id); return dic; } - - return hlattrs2dict(NULL, syn_attr2entry((int)attr_id), rgb); + Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE); + hlattrs2dict(&retval, syn_attr2entry((int)attr_id), rgb); + return retval; } /// 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/out] hl Dictionary with pre-allocated space for HLATTRS_DICT_SIZE elements /// @param[in] aep data to convert /// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' -Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb) +void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb) { + assert(dict->capacity >= HLATTRS_DICT_SIZE); // at most 16 items + Dictionary hl = *dict; 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_C(hl, "bold", BOOLEAN_OBJ(true)); @@ -899,14 +895,7 @@ Dictionary hlattrs2dict(Dictionary *hl_alloc, HlAttrs ae, bool use_rgb) PUT_C(hl, "blend", INTEGER_OBJ(ae.hl_blend)); } - if (hl_alloc) { - *hl_alloc = hl; - return hl; - } else { - Dictionary allocated = copy_dictionary(hl); - kv_destroy(hl); - return allocated; - } + *dict = hl; } HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err) @@ -1086,6 +1075,7 @@ int object_to_color(Object val, char *key, bool rgb, Error *err) Array hl_inspect(int attr) { + // TODO(bfredl): use arena allocation Array ret = ARRAY_DICT_INIT; if (hlstate_active) { hl_inspect_impl(&ret, attr); diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h index 50299bb91c..e85e3859e2 100644 --- a/src/nvim/highlight.h +++ b/src/nvim/highlight.h @@ -19,6 +19,8 @@ static inline int win_hl_attr(win_T *wp, int hlf) return ((wp->w_ns_hl_attr && ns_hl_fast < 0) ? wp->w_ns_hl_attr : hl_attr_active)[hlf]; } +#define HLATTRS_DICT_SIZE 16 + #define HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp) \ do { \ bool dark_ = (*p_bg == 'd'); \ diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 77424de3b8..3508560e20 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -79,6 +79,8 @@ typedef struct { int sg_rgb_sp_idx; ///< RGB special color index int sg_blend; ///< blend level (0-100 inclusive), -1 if unset + + int sg_parent; ///< parent of @nested.group } HlGroup; enum { @@ -183,6 +185,53 @@ static const char *highlight_init_both[] = { "default link DiagnosticSignWarn DiagnosticWarn", "default link DiagnosticSignInfo DiagnosticInfo", "default link DiagnosticSignHint DiagnosticHint", + + "default link @text.underline Underlined", + "default link @todo Todo", + "default link @debug Debug", + + // Miscs + "default link @comment Comment", + "default link @punctuation Delimiter", + + // Constants + "default link @constant Constant", + "default link @constant.builtin Special", + "default link @constant.macro Define", + "default link @define Define", + "default link @macro Macro", + "default link @string String", + "default link @string.escape SpecialChar", + "default link @character Character", + "default link @character.special SpecialChar", + "default link @number Number", + "default link @boolean Boolean", + "default link @float Float", + + // Functions + "default link @function Function", + "default link @function.builtin Special", + "default link @function.macro Macro", + "default link @parameter Identifier", + "default link @method Function", + "default link @field Identifier", + "default link @property Identifier", + "default link @constructor Special", + + // Keywords + "default link @conditional Conditional", + "default link @repeat Repeat", + "default link @label Label", + "default link @operator Operator", + "default link @keyword Keyword", + "default link @exception Exception", + + "default link @type Type", + "default link @type.definition Typedef", + "default link @storageclass StorageClass", + "default link @structure Structure", + "default link @include Include", + "default link @preproc PreProc", NULL }; @@ -504,12 +553,12 @@ void init_highlight(bool both, bool reset) // Try finding the color scheme file. Used when a color file was loaded // and 'background' or 't_Co' is changed. - char_u *p = get_var_value("g:colors_name"); + char *p = (char *)get_var_value("g:colors_name"); if (p != NULL) { // Value of g:colors_name could be freed in load_colors() and make // p invalid, so copy it. - char_u *copy_p = vim_strsave(p); - bool okay = load_colors(copy_p); + char *copy_p = xstrdup(p); + bool okay = load_colors((char_u *)copy_p); xfree(copy_p); if (okay) { return; @@ -582,7 +631,9 @@ int load_colors(char_u *name) retval = source_runtime((char *)buf, DIP_START + DIP_OPT); } xfree(buf); - apply_autocmds(EVENT_COLORSCHEME, (char *)name, curbuf->b_fname, false, curbuf); + if (retval == OK) { + apply_autocmds(EVENT_COLORSCHEME, (char *)name, curbuf->b_fname, false, curbuf); + } recursive = false; @@ -640,7 +691,7 @@ static int color_numbers_8[28] = { 0, 4, 2, 6, // Lookup the "cterm" value to be used for color with index "idx" in // color_names[]. -// "boldp" will be set to TRUE or FALSE for a foreground color when using 8 +// "boldp" will be set to kTrue or kFalse for a foreground color when using 8 // colors, otherwise it will be unchanged. int lookup_color(const int idx, const bool foreground, TriState *const boldp) { @@ -740,7 +791,7 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) g->sg_attr = hl_get_syn_attr(0, id, attrs); // 'Normal' is special - if (STRCMP(g->sg_name_u, "NORMAL") == 0) { + if (strcmp(g->sg_name_u, "NORMAL") == 0) { cterm_normal_fg_color = g->sg_cterm_fg; cterm_normal_bg_color = g->sg_cterm_bg; normal_fg = g->sg_rgb_fg; @@ -756,7 +807,7 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) update: if (!updating_screen) { - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } need_highlight_changed = true; } @@ -802,14 +853,14 @@ void do_highlight(const char *line, const bool forceit, const bool init) } // Isolate the name. - name_end = (const char *)skiptowhite((const char_u *)line); + name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); // Check for "default" argument. if (strncmp(line, "default", (size_t)(name_end - line)) == 0) { dodefault = true; line = linep; - name_end = (const char *)skiptowhite((const char_u *)line); + name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); } @@ -841,9 +892,9 @@ void do_highlight(const char *line, const bool forceit, const bool init) int to_id; HlGroup *hlgroup = NULL; - from_end = (const char *)skiptowhite((const char_u *)from_start); + from_end = (const char *)skiptowhite(from_start); to_start = (const char *)skipwhite(from_end); - to_end = (const char *)skiptowhite((const char_u *)to_start); + to_end = (const char *)skiptowhite(to_start); if (ends_excmd((uint8_t)(*from_start)) || ends_excmd((uint8_t)(*to_start))) { @@ -893,7 +944,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) hlgroup->sg_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hlgroup->sg_script_ctx); hlgroup->sg_cleared = false; - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); // Only call highlight changed() once after multiple changes need_highlight_changed = true; @@ -916,10 +967,10 @@ void do_highlight(const char *line, const bool forceit, const bool init) } init_highlight(true, true); highlight_changed(); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); return; } - name_end = (const char *)skiptowhite((const char_u *)line); + name_end = (const char *)skiptowhite(line); linep = (const char *)skipwhite(name_end); } @@ -937,7 +988,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) // Make a copy so we can check if any attribute actually changed item_before = hl_table[idx]; - is_normal_group = (STRCMP(hl_table[idx].sg_name_u, "NORMAL") == 0); + is_normal_group = (strcmp(hl_table[idx].sg_name_u, "NORMAL") == 0); // Clear the highlighting for ":hi clear {group}" and ":hi clear". if (doclear || (forceit && init)) { @@ -1004,7 +1055,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } } else { arg_start = linep; - linep = (const char *)skiptowhite((const char_u *)linep); + linep = (const char *)skiptowhite(linep); } if (linep == arg_start) { semsg(_("E417: missing argument: %s"), key_start); @@ -1033,7 +1084,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) int i; while (arg[off] != NUL) { for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) { - len = (int)STRLEN(hl_name_table[i]); + len = (int)strlen(hl_name_table[i]); if (STRNICMP(arg + off, hl_name_table[i], len) == 0) { attr |= hl_attr_table[i]; off += len; @@ -1068,9 +1119,9 @@ void do_highlight(const char *line, const bool forceit, const bool init) hl_table[idx].sg_gui = attr; } } - } else if (STRCMP(key, "FONT") == 0) { + } else if (strcmp(key, "FONT") == 0) { // in non-GUI fonts are simply ignored - } else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) { + } else if (strcmp(key, "CTERMFG") == 0 || strcmp(key, "CTERMBG") == 0) { if (!init || !(hl_table[idx].sg_set & SG_CTERM)) { if (!init) { hl_table[idx].sg_set |= SG_CTERM; @@ -1156,7 +1207,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) if (dark != -1 && dark != (*p_bg == 'd') && !option_was_set("bg")) { - set_option_value("bg", 0L, (dark ? "dark" : "light"), 0); + set_option_value_give_err("bg", 0L, (dark ? "dark" : "light"), 0); reset_option_was_set("bg"); } } @@ -1188,7 +1239,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) if (is_normal_group) { normal_fg = hl_table[idx].sg_rgb_fg; } - } else if (STRCMP(key, "GUIBG") == 0) { + } else if (strcmp(key, "GUIBG") == 0) { int *indexp = &hl_table[idx].sg_rgb_bg_idx; if (!init || !(hl_table[idx].sg_set & SG_GUI)) { @@ -1199,7 +1250,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) RgbValue old_color = hl_table[idx].sg_rgb_bg; int old_idx = hl_table[idx].sg_rgb_bg_idx; - if (STRCMP(arg, "NONE") != 0) { + if (strcmp(arg, "NONE") != 0) { hl_table[idx].sg_rgb_bg = name_to_color(arg, indexp); } else { hl_table[idx].sg_rgb_bg = -1; @@ -1270,12 +1321,12 @@ void do_highlight(const char *line, const bool forceit, const bool init) // changed ui_refresh(); } else { - // TUI and newer UIs will repaint the screen themselves. NOT_VALID + // TUI and newer UIs will repaint the screen themselves. UPD_NOT_VALID // redraw below will still handle usages of guibg=fg etc. ui_default_colors_set(); } did_highlight_changed = true; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } else { set_hl_attr(idx); } @@ -1292,7 +1343,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) // redrawing. This may happen when evaluating 'statusline' changes the // StatusLine group. if (!updating_screen) { - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } need_highlight_changed = true; } @@ -1303,7 +1354,7 @@ void free_highlight(void) { ga_clear(&highlight_ga); map_destroy(cstr_t, int)(&highlight_unames); - arena_mem_free(arena_finish(&highlight_arena), NULL); + arena_mem_free(arena_finish(&highlight_arena)); } #endif @@ -1321,7 +1372,7 @@ void restore_cterm_colors(void) /// @param check_link if true also check for an existing link. /// -/// @return TRUE if highlight group "idx" has any settings. +/// @return true if highlight group "idx" has any settings. static int hl_has_settings(int idx, bool check_link) { return hl_table[idx].sg_cleared == 0 @@ -1371,7 +1422,12 @@ static void highlight_list_one(const int id) const HlGroup *sgp = &hl_table[id - 1]; // index is ID minus one bool didh = false; - if (message_filtered(sgp->sg_name)) { + if (message_filtered((char *)sgp->sg_name)) { + return; + } + + // don't list specialized groups if a parent is used instead + if (sgp->sg_parent && sgp->sg_cleared) { return; } @@ -1411,19 +1467,21 @@ static void highlight_list_one(const int id) } } -Dictionary get_global_hl_defs(void) +Dictionary get_global_hl_defs(Arena *arena) { - Dictionary rv = ARRAY_DICT_INIT; - for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) { + Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len); + for (int i = 1; i <= highlight_ga.ga_len; i++) { Dictionary attrs = ARRAY_DICT_INIT; HlGroup *h = &hl_table[i - 1]; if (h->sg_attr > 0) { - attrs = hlattrs2dict(NULL, syn_attr2entry(h->sg_attr), true); + attrs = arena_dict(arena, HLATTRS_DICT_SIZE); + hlattrs2dict(&attrs, 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))); + attrs = arena_dict(arena, 1); + char *link = (char *)hl_table[h->sg_link - 1].sg_name; + PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link))); } - PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs)); + PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs)); } return rv; @@ -1461,7 +1519,7 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg } } - (void)syn_list_header(didh, vim_strsize((char *)ts) + (int)STRLEN(name) + 1, id, false); + (void)syn_list_header(didh, vim_strsize((char *)ts) + (int)strlen(name) + 1, id, false); didh = true; if (!got_int) { if (*name != NUL) { @@ -1661,7 +1719,12 @@ static void set_hl_attr(int idx) int syn_name2id(const char *name) FUNC_ATTR_NONNULL_ALL { - return syn_name2id_len(name, STRLEN(name)); + if (name[0] == '@') { + // if we look up @aaa.bbb, we have to consider @aaa as well + return syn_check_group(name, strlen(name)); + } else { + return syn_name2id_len(name, strlen(name)); + } } /// Lookup a highlight group name and return its ID. @@ -1701,7 +1764,7 @@ int syn_name2attr(const char_u *name) return 0; } -/// Return TRUE if highlight group "name" exists. +/// Return true if highlight group "name" exists. int highlight_exists(const char *name) { return syn_name2id(name) > 0; @@ -1750,11 +1813,19 @@ static int syn_add_group(const char *name, size_t len) if (!vim_isprintc(c)) { emsg(_("E669: Unprintable character in group name")); return 0; - } else if (!ASCII_ISALNUM(c) && c != '_') { - // This is an error, but since there previously was no check only give a warning. + } else if (!ASCII_ISALNUM(c) && c != '_' && c != '.' && c != '@') { + // '.' and '@' are allowed characters for use with treesitter capture names. msg_source(HL_ATTR(HLF_W)); - msg(_("W18: Invalid character in group name")); - break; + emsg(_(e_highlight_group_name_invalid_char)); + return 0; + } + } + + int scoped_parent = 0; + if (len > 1 && name[0] == '@') { + char *delim = xmemrchr(name, '.', len); + if (delim) { + scoped_parent = syn_check_group(name, (size_t)(delim - name)); } } @@ -1783,6 +1854,9 @@ static int syn_add_group(const char *name, size_t len) hlgp->sg_rgb_sp_idx = kColorIdxNone; hlgp->sg_blend = -1; hlgp->sg_name_u = arena_memdupz(&highlight_arena, name, len); + hlgp->sg_parent = scoped_parent; + // will get set to false by caller if settings are added + hlgp->sg_cleared = true; vim_strup((char_u *)hlgp->sg_name_u); int id = highlight_ga.ga_len; // ID is index plus one @@ -1844,10 +1918,13 @@ int syn_ns_get_final_id(int *ns_id, int hl_id) continue; } - if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) { + if (sgp->sg_link > 0 && sgp->sg_link <= highlight_ga.ga_len) { + hl_id = sgp->sg_link; + } else if (sgp->sg_cleared && sgp->sg_parent > 0) { + hl_id = sgp->sg_parent; + } else { break; } - hl_id = sgp->sg_link; } return hl_id; @@ -1930,7 +2007,7 @@ void highlight_changed(void) /// Translate builtin highlight groups into attributes for quick lookup. for (int hlf = 0; hlf < HLF_COUNT; hlf++) { - id = syn_check_group(hlf_names[hlf], STRLEN(hlf_names[hlf])); + id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); if (id == 0) { abort(); } @@ -1957,7 +2034,7 @@ void highlight_changed(void) } } - // sentinel value. used when no hightlight namespace is active + // sentinel value. used when no highlight namespace is active highlight_attr[HLF_COUNT] = 0; // @@ -2000,13 +2077,13 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg) // (part of) subcommand already typed if (*arg != NUL) { - const char *p = (const char *)skiptowhite((const char_u *)arg); + const char *p = (const char *)skiptowhite(arg); if (*p != NUL) { // Past "default" or group name. include_default = 0; if (strncmp("default", arg, (unsigned)(p - arg)) == 0) { arg = (const char *)skipwhite(p); xp->xp_pattern = (char *)arg; - p = (const char *)skiptowhite((const char_u *)arg); + p = (const char *)skiptowhite(arg); } if (*p != NUL) { // past group name include_link = 0; @@ -2016,10 +2093,10 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg) if (strncmp("link", arg, (unsigned)(p - arg)) == 0 || strncmp("clear", arg, (unsigned)(p - arg)) == 0) { xp->xp_pattern = skipwhite(p); - p = (const char *)skiptowhite((char_u *)xp->xp_pattern); + p = (const char *)skiptowhite(xp->xp_pattern); if (*p != NUL) { // Past first group name. xp->xp_pattern = skipwhite(p); - p = (const char *)skiptowhite((char_u *)xp->xp_pattern); + p = (const char *)skiptowhite(xp->xp_pattern); } } if (*p != NUL) { // Past group name(s). diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 689d1fce0d..bc31d702f4 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -1,13 +1,11 @@ // 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 -/* - * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com> - * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> - * - * The basic idea/structure of cscope for Vim was borrowed from Nvi. There - * might be a few lines of code that look similar to what Nvi has. - */ +// CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com> +// Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> +// +// The basic idea/structure of cscope for Vim was borrowed from Nvi. There +// might be a few lines of code that look similar to what Nvi has. #include <assert.h> #include <errno.h> @@ -78,10 +76,8 @@ static enum { EXP_CSCOPE_KILL, // expand ":cscope kill" arguments } expand_what; -/* - * Function given to ExpandGeneric() to obtain the cscope command - * expansion. - */ +// Function given to ExpandGeneric() to obtain the cscope command +// expansion. char *get_cscope_name(expand_T *xp, int idx) { int current_idx; @@ -140,9 +136,7 @@ char *get_cscope_name(expand_T *xp, int idx) } } -/* - * Handle command line completion for :cscope command. - */ +// Handle command line completion for :cscope command. void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) { // Default: expand subcommands. @@ -153,10 +147,10 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) // (part of) subcommand already typed if (*arg != NUL) { - const char *p = (const char *)skiptowhite((const char_u *)arg); + const char *p = (const char *)skiptowhite(arg); if (*p != NUL) { // Past first word. xp->xp_pattern = skipwhite(p); - if (*skiptowhite((char_u *)xp->xp_pattern) != NUL) { + if (*skiptowhite(xp->xp_pattern) != NUL) { xp->xp_context = EXPAND_NOTHING; } else if (STRNICMP(arg, "add", p - arg) == 0) { xp->xp_context = EXPAND_FILES; @@ -203,19 +197,19 @@ static void do_cscope_general(exarg_T *eap, int make_split) /// Implementation of ":cscope" and ":lcscope" void ex_cscope(exarg_T *eap) { - do_cscope_general(eap, FALSE); + do_cscope_general(eap, false); } /// Implementation of ":scscope". Same as ex_cscope(), but splits window, too. void ex_scscope(exarg_T *eap) { - do_cscope_general(eap, TRUE); + do_cscope_general(eap, true); } /// Implementation of ":cstag" void ex_cstag(exarg_T *eap) { - int ret = FALSE; + int ret = false; if (*eap->arg == NUL) { (void)emsg(_("E562: Usage: cstag <ident>")); @@ -234,16 +228,16 @@ void ex_cstag(exarg_T *eap) } if (cs_check_for_tags()) { - ret = do_tag((char_u *)eap->arg, DT_JUMP, 0, eap->forceit, false); + ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, false); } } } else if (cs_check_for_tags()) { - ret = do_tag((char_u *)eap->arg, DT_JUMP, 0, eap->forceit, false); + ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, false); } break; case 1: if (cs_check_for_tags()) { - ret = do_tag((char_u *)eap->arg, DT_JUMP, 0, eap->forceit, false); + ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, false); if (ret == false) { if (msg_col) { msg_putchar('\n'); @@ -278,7 +272,7 @@ void ex_cstag(exarg_T *eap) /// This simulates a vim_fgets(), but for cscope, returns the next line /// from the cscope output. should only be called from find_tags() /// -/// @return true if eof, FALSE otherwise +/// @return true if eof, false otherwise bool cs_fgets(char_u *buf, int size) FUNC_ATTR_NONNULL_ALL { @@ -304,33 +298,31 @@ void cs_print_tags(void) cs_manage_matches(NULL, NULL, 0, Print); } -/* - * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function - * - * Checks for the existence of a |cscope| connection. If no - * parameters are specified, then the function returns: - * - * 0, if cscope was not available (not compiled in), or if there - * are no cscope connections; or - * 1, if there is at least one cscope connection. - * - * If parameters are specified, then the value of {num} - * determines how existence of a cscope connection is checked: - * - * {num} Description of existence check - * ----- ------------------------------ - * 0 Same as no parameters (e.g., "cscope_connection()"). - * 1 Ignore {prepend}, and use partial string matches for - * {dbpath}. - * 2 Ignore {prepend}, and use exact string matches for - * {dbpath}. - * 3 Use {prepend}, use partial string matches for both - * {dbpath} and {prepend}. - * 4 Use {prepend}, use exact string matches for both - * {dbpath} and {prepend}. - * - * Note: All string comparisons are case sensitive! - */ +// "cscope_connection([{num} , {dbpath} [, {prepend}]])" function +// +// Checks for the existence of a |cscope| connection. If no +// parameters are specified, then the function returns: +// +// 0, if cscope was not available (not compiled in), or if there +// are no cscope connections; or +// 1, if there is at least one cscope connection. +// +// If parameters are specified, then the value of {num} +// determines how existence of a cscope connection is checked: +// +// {num} Description of existence check +// ----- ------------------------------ +// 0 Same as no parameters (e.g., "cscope_connection()"). +// 1 Ignore {prepend}, and use partial string matches for +// {dbpath}. +// 2 Ignore {prepend}, and use exact string matches for +// {dbpath}. +// 3 Use {prepend}, use partial string matches for both +// {dbpath} and {prepend}. +// 4 Use {prepend}, use exact string matches for both +// {dbpath} and {prepend}. +// +// Note: All string comparisons are case sensitive! bool cs_connection(int num, char_u *dbpath, char_u *ppath) { if (num < 0 || num > 4 || (num > 0 && !dbpath)) { @@ -379,9 +371,8 @@ bool cs_connection(int num, char_u *dbpath, char_u *ppath) return false; } // cs_connection -/* - * PRIVATE functions - ****************************************************************************/ +// PRIVATE functions +// ************************************************************************** /// Add cscope database or a directory name (to look for cscope.out) /// to the cscope connection list. @@ -423,8 +414,8 @@ static int cs_add_common(char *arg1, char *arg2, char *flags) // get the filename (arg1), expand it, and try to stat it fname = xmalloc(MAXPATHL + 1); - expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL); - size_t len = STRLEN(fname); + expand_env(arg1, fname, MAXPATHL); + size_t len = strlen(fname); fbuf = fname; (void)modify_fname(":p", false, &usedlen, &fname, &fbuf, &len); if (fname == NULL) { @@ -445,8 +436,8 @@ staterr: // get the prepend path (arg2), expand it, and see if it exists if (arg2 != NULL) { ppath = xmalloc(MAXPATHL + 1); - expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL); - if (!os_path_exists((char_u *)ppath)) { + expand_env(arg2, ppath, MAXPATHL); + if (!os_path_exists(ppath)) { goto staterr; } } @@ -658,7 +649,7 @@ static char *cs_create_cmd(char *csoption, char *pattern) return NULL; } - // Skip white space before the patter, except for text and pattern search, + // Skip white space before the pattern, except for text and pattern search, // they may want to use the leading white space. pat = pattern; if (search != 4 && search != 6) { @@ -684,10 +675,8 @@ static int cs_create_connection(size_t i) char *prog, *cmd, *ppath = NULL; #if defined(UNIX) - /* - * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from - * from_cs[0] and writes to to_cs[1]. - */ + // Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from + // from_cs[0] and writes to to_cs[1]. to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1; if (pipe(to_cs) < 0 || pipe(from_cs) < 0) { (void)emsg(_("E566: Could not create cscope pipes")); @@ -757,14 +746,14 @@ err_closing: #endif // expand the cscope exec for env var's prog = xmalloc(MAXPATHL + 1); - expand_env(p_csprg, (char_u *)prog, MAXPATHL); + expand_env(p_csprg, prog, MAXPATHL); // alloc space to hold the cscope command size_t len = strlen(prog) + strlen(csinfo[i].fname) + 32; if (csinfo[i].ppath) { // expand the prepend path for env var's ppath = xmalloc(MAXPATHL + 1); - expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL); + expand_env(csinfo[i].ppath, ppath, MAXPATHL); len += strlen(ppath); } @@ -779,7 +768,7 @@ err_closing: #if defined(UNIX) (void)snprintf(cmd, len, "exec %s -dl -f %s", prog, csinfo[i].fname); #else - // WIN32 + // MS-Windows (void)snprintf(cmd, len, "%s -dl -f %s", prog, csinfo[i].fname); #endif if (csinfo[i].ppath != NULL) { @@ -831,7 +820,7 @@ err_closing: } #else - // WIN32 + // MS-Windows // Create a new process to run cscope and use pipes to talk with it GetStartupInfo(&si); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; @@ -839,7 +828,7 @@ err_closing: si.hStdOutput = stdout_wr; si.hStdError = stdout_wr; si.hStdInput = stdin_rd; - created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, + created = CreateProcess(NULL, cmd, NULL, NULL, true, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); xfree(prog); xfree(cmd); @@ -875,7 +864,7 @@ err_closing: /// Query cscope using command line interface. Parse the output and use tselect /// to allow choices. Like Nvi, creates a pipe to send to/from query/cscope. /// -/// @return TRUE if we jump to a tag or abort, FALSE if not. +/// @return true if we jump to a tag or abort, false if not. static int cs_find(exarg_T *eap) { char *opt, *pat; @@ -896,11 +885,9 @@ static int cs_find(exarg_T *eap) return false; } - /* - * Let's replace the NULs written by strtok() with spaces - we need the - * spaces to correctly display the quickfix/location list window's title. - */ - for (int i = 0; i < eap_arg_len; ++i) { + // Let's replace the NULs written by strtok() with spaces - we need the + // spaces to correctly display the quickfix/location list window's title. + for (int i = 0; i < eap_arg_len; i++) { if (NUL == eap->arg[i]) { eap->arg[i] = ' '; } @@ -953,7 +940,7 @@ static bool cs_find_common(char *opt, char *pat, int forceit, int verbose, bool cmdletter = opt[0]; } - qfpos = vim_strchr((char *)p_csqf, cmdletter); + qfpos = vim_strchr(p_csqf, cmdletter); if (qfpos != NULL) { qfpos++; // next symbol must be + or - @@ -1016,7 +1003,7 @@ static bool cs_find_common(char *opt, char *pat, int forceit, int verbose, bool if (qfpos != NULL && *qfpos != '0') { // Fill error list. FILE *f; - char_u *tmp = vim_tempname(); + char_u *tmp = (char_u *)vim_tempname(); qf_info_T *qi = NULL; win_T *wp = NULL; @@ -1041,10 +1028,8 @@ static bool cs_find_common(char *opt, char *pat, int forceit, int verbose, bool apply_autocmds(EVENT_QUICKFIXCMDPOST, "cscope", curbuf->b_fname, true, curbuf); if (use_ll) { - /* - * In the location list window, use the displayed location - * list. Otherwise, use the location list for the window. - */ + // In the location list window, use the displayed location + // list. Otherwise, use the location list for the window. qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) ? wp->w_llist_ref : wp->w_llist; } @@ -1068,7 +1053,7 @@ static bool cs_find_common(char *opt, char *pat, int forceit, int verbose, bool (void)cs_manage_matches(matches, contexts, matched, Store); - return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose); + return do_tag(pat, DT_CSCOPE, 0, forceit, verbose); } } @@ -1106,7 +1091,7 @@ static int cs_help(exarg_T *eap) cmdp++; } - wait_return(TRUE); + wait_return(true); return CSCOPE_SUCCESS; } @@ -1195,7 +1180,7 @@ static cscmd_T *cs_lookup_cmd(exarg_T *eap) } // Store length of eap->arg before it gets modified by strtok(). - eap_arg_len = (int)STRLEN(eap->arg); + eap_arg_len = (int)strlen(eap->arg); if ((stok = strtok(eap->arg, (const char *)" ")) == NULL) { // NOLINT(runtime/threadsafe_fn) return NULL; @@ -1280,7 +1265,7 @@ static void cs_kill_execute(size_t i, char *cname) (void)smsg_attr(HL_ATTR(HLF_R) | MSG_HIST, _("cscope connection %s closed"), cname); } - cs_release_csp(i, TRUE); + cs_release_csp(i, true); } /// Convert the cscope output into a ctags style entry (as might be found @@ -1431,11 +1416,9 @@ retry: } *p = '\0'; - /* - * cscope output is in the following format: - * - * <filename> <context> <line number> <pattern> - */ + // cscope output is in the following format: + // + // <filename> <context> <line number> <pattern> char *saveptr = NULL; if ((name = os_strtok(buf, (const char *)" ", &saveptr)) == NULL) { return NULL; @@ -1651,7 +1634,7 @@ static void cs_print_tags_priv(char **matches, char **cntxts, } (void)snprintf(buf, bufsize, csfmt_str, i + 1, lno); msg_puts_attr(buf, HL_ATTR(HLF_CM)); - msg_outtrans_long_attr((char_u *)cs_pathcomponents(fname), HL_ATTR(HLF_CM)); + msg_outtrans_long_attr(cs_pathcomponents(fname), HL_ATTR(HLF_CM)); // compute the required space for the context char *context = cntxts[i] ? cntxts[i] : globalcntx; @@ -1673,11 +1656,11 @@ static void cs_print_tags_priv(char **matches, char **cntxts, msg_putchar('\n'); } msg_advance(12); - msg_outtrans_long_attr((char_u *)buf, 0); + msg_outtrans_long_attr(buf, 0); msg_putchar('\n'); if (extra != NULL) { msg_advance(13); - msg_outtrans_long_attr((char_u *)extra, 0); + msg_outtrans_long_attr(extra, 0); } // restore matches[i] @@ -1786,9 +1769,7 @@ static int cs_read_prompt(size_t i) } #if defined(UNIX) && defined(SIGALRM) -/* - * Used to catch and ignore SIGALRM below. - */ +// Used to catch and ignore SIGALRM below. static void sig_handler(int s) { // do nothing @@ -1838,7 +1819,7 @@ static void cs_release_csp(size_t i, bool freefnpp) // Can't use sigaction(), loop for two seconds. First yield the CPU // to give cscope a chance to exit quickly. sleep(0); - for (waited = 0; waited < 40; ++waited) { + for (waited = 0; waited < 40; waited++) { pid = waitpid(csinfo[i].pid, &pstat, WNOHANG); waitpid_errno = errno; if (pid != 0) { @@ -1847,25 +1828,21 @@ static void cs_release_csp(size_t i, bool freefnpp) os_delay(50L, false); // sleep 50 ms } # endif - /* - * If the cscope process is still running: kill it. - * Safety check: If the PID would be zero here, the entire X session - * would be killed. -1 and 1 are dangerous as well. - */ + // If the cscope process is still running: kill it. + // Safety check: If the PID would be zero here, the entire X session + // would be killed. -1 and 1 are dangerous as well. if (pid < 0 && csinfo[i].pid > 1) { # ifdef ECHILD bool alive = true; if (waitpid_errno == ECHILD) { - /* - * When using 'vim -g', vim is forked and cscope process is - * no longer a child process but a sibling. So waitpid() - * fails with errno being ECHILD (No child processes). - * Don't send SIGKILL to cscope immediately but wait - * (polling) for it to exit normally as result of sending - * the "q" command, hence giving it a chance to clean up - * its temporary files. - */ + // When using 'vim -g', vim is forked and cscope process is + // no longer a child process but a sibling. So waitpid() + // fails with errno being ECHILD (No child processes). + // Don't send SIGKILL to cscope immediately but wait + // (polling) for it to exit normally as result of sending + // the "q" command, hence giving it a chance to clean up + // its temporary files. int waited; sleep(0); @@ -1932,7 +1909,7 @@ static int cs_reset(exarg_T *eap) pplist[i] = csinfo[i].ppath; fllist[i] = csinfo[i].flags; if (csinfo[i].fname != NULL) { - cs_release_csp(i, FALSE); + cs_release_csp(i, false); } } @@ -1974,11 +1951,9 @@ static char *cs_resolve_file(size_t i, char *name) char *fullname; char_u *csdir = NULL; - /* - * Ppath is freed when we destroy the cscope connection. - * Fullname is freed after cs_make_vim_style_matches, after it's been - * copied into the tag buffer used by Vim. - */ + // Ppath is freed when we destroy the cscope connection. + // Fullname is freed after cs_make_vim_style_matches, after it's been + // copied into the tag buffer used by Vim. size_t len = strlen(name) + 2; if (csinfo[i].ppath != NULL) { len += strlen(csinfo[i].ppath); @@ -2035,7 +2010,7 @@ static int cs_show(exarg_T *eap) } } - wait_return(TRUE); + wait_return(false); return CSCOPE_SUCCESS; } diff --git a/src/nvim/indent.c b/src/nvim/indent.c index f18a6d7b32..0f7a5a8e44 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -25,6 +25,7 @@ #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/strings.h" +#include "nvim/textformat.h" #include "nvim/undo.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -33,12 +34,13 @@ /// Set the integer values corresponding to the string setting of 'vartabstop'. /// "array" will be set, caller must free it if needed. -/// Return false for an error. -bool tabstop_set(char_u *var, long **array) +/// +/// @return false for an error. +bool tabstop_set(char *var, long **array) { long valcount = 1; int t; - char_u *cp; + char *cp; if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) { *array = NULL; @@ -49,8 +51,8 @@ bool tabstop_set(char_u *var, long **array) if (cp == var || cp[-1] == ',') { char *end; - if (strtol((char *)cp, &end, 10) <= 0) { - if (cp != (char_u *)end) { + if (strtol(cp, &end, 10) <= 0) { + if (cp != end) { emsg(_(e_positive)); } else { semsg(_(e_invarg2), cp); @@ -75,7 +77,7 @@ bool tabstop_set(char_u *var, long **array) t = 1; for (cp = var; *cp != NUL;) { - int n = atoi((char *)cp); + int n = atoi(cp); // Catch negative values, overflow and ridiculous big values. if (n <= 0 || n > TABSTOP_MAX) { @@ -398,7 +400,7 @@ int get_indent_str(const char_u *ptr, int ts, bool list) /// Count the size (in window cells) of the indent in line "ptr", using /// variable tabstops. /// if "list" is true, count only screen size for tabs. -int get_indent_str_vtab(const char_u *ptr, long ts, long *vts, bool list) +int get_indent_str_vtab(const char *ptr, long ts, long *vts, bool list) { int count = 0; @@ -452,7 +454,7 @@ int set_indent(int size, int flags) // characters needed for the indent. todo = size; ind_len = 0; - p = oldline = get_cursor_line_ptr(); + p = oldline = (char_u *)get_cursor_line_ptr(); // Calculate the buffer size for the new indent, and check to see if it // isn't already set. @@ -708,16 +710,16 @@ int get_number_indent(linenr_T lnum) // In format_lines() (i.e. not insert mode), fo+=q is needed too... if ((State & MODE_INSERT) || has_format_option(FO_Q_COMS)) { - lead_len = get_leader_len((char *)ml_get(lnum), NULL, false, true); + lead_len = get_leader_len(ml_get(lnum), NULL, false, true); } - regmatch.regprog = vim_regcomp((char *)curbuf->b_p_flp, RE_MAGIC); + regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC); if (regmatch.regprog != NULL) { regmatch.rm_ic = false; // vim_regexec() expects a pointer to a line. This lets us // start matching for the flp beyond any comment leader... - if (vim_regexec(®match, (char *)ml_get(lnum) + lead_len, (colnr_T)0)) { + if (vim_regexec(®match, ml_get(lnum) + lead_len, (colnr_T)0)) { pos.lnum = lnum; pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum)); pos.coladd = 0; @@ -732,6 +734,47 @@ int get_number_indent(linenr_T lnum) return (int)col; } +/// This is called when 'breakindentopt' is changed and when a window is +/// initialized +bool briopt_check(win_T *wp) +{ + int bri_shift = 0; + int bri_min = 20; + bool bri_sbr = false; + int bri_list = 0; + + char *p = 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(&p, true, 0); + } else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) { + p += 4; + bri_min = getdigits_int(&p, true, 0); + } else if (STRNCMP(p, "sbr", 3) == 0) { + p += 3; + bri_sbr = true; + } else if (STRNCMP(p, "list:", 5) == 0) { + p += 5; + bri_list = (int)getdigits(&p, false, 0); + } + if (*p != ',' && *p != NUL) { + return false; + } + if (*p == ',') { + p++; + } + } + + wp->w_briopt_shift = bri_shift; + wp->w_briopt_min = bri_min; + wp->w_briopt_sbr = bri_sbr; + wp->w_briopt_list = bri_list; + + return true; +} + // Return appropriate space number for breakindent, taking influencing // parameters into account. Window must be specified, since it is not // necessarily always the current one. @@ -757,7 +800,7 @@ int get_breakindent_win(win_T *wp, char_u *line) prev_ts = wp->w_buffer->b_p_ts; prev_tick = buf_get_changedtick(wp->w_buffer); prev_vts = wp->w_buffer->b_p_vts_array; - prev_indent = get_indent_str_vtab(line, + prev_indent = get_indent_str_vtab((char *)line, wp->w_buffer->b_p_ts, wp->w_buffer->b_p_vts_array, wp->w_p_list); @@ -770,7 +813,7 @@ int get_breakindent_win(win_T *wp, char_u *line) // add additional indent for numbered lists if (wp->w_briopt_list != 0) { regmatch_T regmatch = { - .regprog = vim_regcomp((char *)curbuf->b_p_flp, + .regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT), }; @@ -814,7 +857,7 @@ int inindent(int extra) char_u *ptr; colnr_T col; - for (col = 0, ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) { + for (col = 0, ptr = (char_u *)get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) { ptr++; } @@ -831,7 +874,7 @@ bool may_do_si(void) return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste; } -// Get indent level from 'indentexpr'. +/// Get indent level from 'indentexpr'. int get_expr_indent(void) { int indent = -1; @@ -855,8 +898,8 @@ int get_expr_indent(void) // Need to make a copy, the 'indentexpr' option could be changed while // evaluating it. - char_u *inde_copy = vim_strsave(curbuf->b_p_inde); - indent = (int)eval_to_number((char *)inde_copy); + char *inde_copy = xstrdup(curbuf->b_p_inde); + indent = (int)eval_to_number(inde_copy); xfree(inde_copy); if (use_sandbox) { @@ -936,7 +979,7 @@ int get_lisp_indent(void) continue; } - for (that = get_cursor_line_ptr(); *that != NUL; that++) { + for (that = (char_u *)get_cursor_line_ptr(); *that != NUL; that++) { if (*that == ';') { while (*(that + 1) != NUL) { that++; @@ -986,19 +1029,21 @@ int get_lisp_indent(void) curwin->w_cursor.col = pos->col; col = pos->col; - that = get_cursor_line_ptr(); + that = (char_u *)get_cursor_line_ptr(); if (vi_lisp && (get_indent() == 0)) { amount = 2; } else { char_u *line = that; - - amount = 0; - - while (*that && col) { - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, (char *)line, (char *)line); + while (*cts.cts_ptr != NUL && col > 0) { + cts.cts_vcol += lbr_chartabsize_adv(&cts); col--; } + amount = cts.cts_vcol; + that = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // Some keywords require "body" indenting rules (the // non-standard-lisp ones are Scheme special forms): @@ -1014,10 +1059,15 @@ int get_lisp_indent(void) } firsttry = amount; - while (ascii_iswhite(*that)) { - amount += lbr_chartabsize(line, that, (colnr_T)amount); - that++; + init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line), + amount, (char *)line, (char *)that); + while (ascii_iswhite(*cts.cts_ptr)) { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; } + that = (char_u *)cts.cts_ptr; + amount = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (*that && (*that != ';')) { // Not a comment line. @@ -1030,33 +1080,38 @@ int get_lisp_indent(void) parencount = 0; quotecount = 0; + init_chartabsize_arg(&cts, curwin, + (colnr_T)(that - line), amount, (char *)line, (char *)that); if (vi_lisp || ((*that != '"') && (*that != '\'') && (*that != '#') && ((*that < '0') || (*that > '9')))) { - while (*that - && (!ascii_iswhite(*that) || quotecount || parencount) - && (!((*that == '(' || *that == '[') + while (*cts.cts_ptr + && (!ascii_iswhite(*cts.cts_ptr) || quotecount || parencount) + && (!((*cts.cts_ptr == '(' || *cts.cts_ptr == '[') && !quotecount && !parencount && vi_lisp))) { - if (*that == '"') { + if (*cts.cts_ptr == '"') { quotecount = !quotecount; } - if (((*that == '(') || (*that == '[')) && !quotecount) { + if (((*cts.cts_ptr == '(') || (*cts.cts_ptr == '[')) && !quotecount) { parencount++; } - if (((*that == ')') || (*that == ']')) && !quotecount) { + if (((*cts.cts_ptr == ')') || (*cts.cts_ptr == ']')) && !quotecount) { parencount--; } - if ((*that == '\\') && (*(that + 1) != NUL)) { - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + if ((*cts.cts_ptr == '\\') && (*(cts.cts_ptr + 1) != NUL)) { + cts.cts_vcol += lbr_chartabsize_adv(&cts); } - amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); + cts.cts_vcol += lbr_chartabsize_adv(&cts); } } - while (ascii_iswhite(*that)) { - amount += lbr_chartabsize(line, that, (colnr_T)amount); - that++; + while (ascii_iswhite(*cts.cts_ptr)) { + cts.cts_vcol += lbr_chartabsize(&cts); + cts.cts_ptr++; } + that = (char_u *)cts.cts_ptr; + amount = cts.cts_vcol; + clear_chartabsize_arg(&cts); if (!*that || (*that == ';')) { amount = firsttry; @@ -1077,7 +1132,7 @@ static int lisp_match(char_u *p) { char_u buf[LSIZE]; int len; - char *word = (char *)(*curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords); + char *word = (char *)(*curbuf->b_p_lw != NUL ? (char_u *)curbuf->b_p_lw : p_lispwords); while (*word != NUL) { (void)copy_option_part(&word, (char *)buf, LSIZE, ","); diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 34a3de4f78..5eed2601d5 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -27,11 +27,9 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "indent_c.c.generated.h" #endif -/* - * Find the start of a comment, not knowing if we are in a comment right now. - * Search starts at w_cursor.lnum and goes backwards. - * Return NULL when not inside a comment. - */ +// Find the start of a comment, not knowing if we are in a comment right now. +// Search starts at w_cursor.lnum and goes backwards. +// Return NULL when not inside a comment. static pos_T *ind_find_start_comment(void) // XXX { return find_start_comment(curbuf->b_ind_maxcomment); @@ -48,11 +46,9 @@ pos_T *find_start_comment(int ind_maxcomment) // XXX break; } - /* - * Check if the comment start we found is inside a string. - * If it is then restrict the search to below this line and try again. - */ - if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) { + // Check if the comment start we found is inside a string. + // If it is then restrict the search to below this line and try again. + if (!is_pos_in_string((char_u *)ml_get(pos->lnum), pos->col)) { break; } cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; @@ -97,11 +93,9 @@ static pos_T *ind_find_start_CORS(linenr_T *is_raw) return comment_pos; } -/* - * Find the start of a raw string, not knowing if we are in one right now. - * Search starts at w_cursor.lnum and goes backwards. - * Return NULL when not inside a raw string. - */ +// Find the start of a raw string, not knowing if we are in one right now. +// Search starts at w_cursor.lnum and goes backwards. +// Return NULL when not inside a raw string. static pos_T *find_start_rawstring(int ind_maxcomment) // XXX { pos_T *pos; @@ -115,7 +109,7 @@ static pos_T *find_start_rawstring(int ind_maxcomment) // XXX // Check if the raw string start we found is inside a string. // If it is then restrict the search to below this line and try again. - if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) { + if (!is_pos_in_string((char_u *)ml_get(pos->lnum), pos->col)) { break; } cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1; @@ -127,17 +121,13 @@ static pos_T *find_start_rawstring(int ind_maxcomment) // XXX return pos; } -/* - * Skip to the end of a "string" and a 'c' character. - * If there is no string or character, return argument unmodified. - */ +// Skip to the end of a "string" and a 'c' character. +// If there is no string or character, return argument unmodified. static const char_u *skip_string(const char_u *p) { int i; - /* - * We loop, because strings may be concatenated: "date""time". - */ + // We loop, because strings may be concatenated: "date""time". for (;; p++) { if (p[0] == '\'') { // 'c' or '\n' or '\000' if (p[1] == NUL) { // ' at end of line @@ -204,26 +194,21 @@ int is_pos_in_string(const char_u *line, colnr_T col) return !((colnr_T)(p - line) <= col); } -/* - * Functions for C-indenting. - * Most of this originally comes from Eric Fischer. - */ -/* - * Below "XXX" means that this function may unlock the current line. - */ - -/* - * Return true if the string "line" starts with a word from 'cinwords'. - */ -bool cin_is_cinword(const char_u *line) +// Functions for C-indenting. +// Most of this originally comes from Eric Fischer. + +// Below "XXX" means that this function may unlock the current line. + +/// @return true if the string "line" starts with a word from 'cinwords'. +bool cin_is_cinword(const char *line) { bool retval = false; - size_t cinw_len = STRLEN(curbuf->b_p_cinw) + 1; + size_t cinw_len = strlen(curbuf->b_p_cinw) + 1; char_u *cinw_buf = xmalloc(cinw_len); - line = (char_u *)skipwhite((char *)line); + line = skipwhite((char *)line); - for (char *cinw = (char *)curbuf->b_p_cinw; *cinw;) { + for (char *cinw = curbuf->b_p_cinw; *cinw;) { size_t len = copy_option_part(&cinw, (char *)cinw_buf, cinw_len, ","); if (STRNCMP(line, cinw_buf, len) == 0 && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1]))) { @@ -237,10 +222,8 @@ bool cin_is_cinword(const char_u *line) return retval; } -/* - * Skip over white space and C comments within the line. - * Also skip over Perl/shell comments if desired. - */ +// Skip over white space and C comments within the line. +// Also skip over Perl/shell comments if desired. static const char_u *cin_skipcomment(const char_u *s) { while (*s) { @@ -248,8 +231,8 @@ static const char_u *cin_skipcomment(const char_u *s) s = (char_u *)skipwhite((char *)s); - /* Perl/shell # comment comment continues until eol. Require a space - * before # to avoid recognizing $#array. */ + // Perl/shell # comment comment continues until eol. Require a space + // before # to avoid recognizing $#array. if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#') { s += STRLEN(s); break; @@ -275,18 +258,14 @@ static const char_u *cin_skipcomment(const char_u *s) return s; } -/* - * Return TRUE if there is no code at *s. White space and comments are - * not considered code. - */ +/// Return true if there is no code at *s. White space and comments are +/// not considered code. static int cin_nocode(const char_u *s) { return *cin_skipcomment(s) == NUL; } -/* - * Check previous lines for a "//" line comment, skipping over blank lines. - */ +// Check previous lines for a "//" line comment, skipping over blank lines. static pos_T *find_line_comment(void) // XXX { static pos_T pos; @@ -295,7 +274,7 @@ static pos_T *find_line_comment(void) // XXX pos = curwin->w_cursor; while (--pos.lnum > 0) { - line = ml_get(pos.lnum); + line = (char_u *)ml_get(pos.lnum); p = (char_u *)skipwhite((char *)line); if (cin_islinecomment(p)) { pos.col = (int)(p - line); @@ -359,7 +338,7 @@ static bool cin_islabel_skip(const char_u **s) // Note: curwin->w_cursor must be where we are looking for the label. bool cin_islabel(void) // XXX { - const char_u *s = cin_skipcomment(get_cursor_line_ptr()); + const char_u *s = cin_skipcomment((char_u *)get_cursor_line_ptr()); // Exclude "default" from labels, since it should be indented // like a switch label. Same for C++ scope declarations. @@ -373,28 +352,24 @@ bool cin_islabel(void) // XXX return false; } - /* - * Only accept a label if the previous line is terminated or is a case - * label. - */ + // Only accept a label if the previous line is terminated or is a case + // label. pos_T cursor_save; pos_T *trypos; const char_u *line; cursor_save = curwin->w_cursor; while (curwin->w_cursor.lnum > 1) { - --curwin->w_cursor.lnum; + curwin->w_cursor.lnum--; - /* - * If we're in a comment or raw string now, skip to the start of - * it. - */ + // If we're in a comment or raw string now, skip to the start of + // it. curwin->w_cursor.col = 0; if ((trypos = ind_find_start_CORS(NULL)) != NULL) { // XXX curwin->w_cursor = *trypos; } - line = get_cursor_line_ptr(); + line = (char_u *)get_cursor_line_ptr(); if (cin_ispreproc(line)) { // ignore #defines, #if, etc. continue; } @@ -403,7 +378,7 @@ bool cin_islabel(void) // XXX } curwin->w_cursor = cursor_save; - if (cin_isterminated(line, TRUE, FALSE) + if (cin_isterminated(line, true, false) || cin_isscopedecl(line) || cin_iscase(line, true) || (cin_islabel_skip(&line) && cin_nocode(line))) { @@ -415,17 +390,15 @@ bool cin_islabel(void) // XXX return true; // label at start of file??? } -/* - * Recognize structure initialization and enumerations: - * "[typedef] [static|public|protected|private] enum" - * "[typedef] [static|public|protected|private] = {" - */ +// Recognize structure initialization and enumerations: +// "[typedef] [static|public|protected|private] enum" +// "[typedef] [static|public|protected|private] = {" static int cin_isinit(void) { const char_u *s; static char *skip[] = { "static", "public", "protected", "private" }; - s = cin_skipcomment(get_cursor_line_ptr()); + s = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (cin_starts_with(s, "typedef")) { s = cin_skipcomment(s + 7); @@ -434,7 +407,7 @@ static int cin_isinit(void) for (;;) { int i, l; - for (i = 0; i < (int)ARRAY_SIZE(skip); ++i) { + for (i = 0; i < (int)ARRAY_SIZE(skip); i++) { l = (int)strlen(skip[i]); if (cin_starts_with(s, skip[i])) { s = cin_skipcomment(s + l); @@ -455,7 +428,7 @@ static int cin_isinit(void) return true; } - return FALSE; + return false; } /// Recognize a switch label: "case .*:" or "default:". @@ -465,7 +438,7 @@ bool cin_iscase(const char_u *s, bool strict) { s = cin_skipcomment(s); if (cin_starts_with(s, "case")) { - for (s += 4; *s; ++s) { + for (s += 4; *s; s++) { s = cin_skipcomment(s); if (*s == NUL) { break; @@ -499,9 +472,7 @@ bool cin_iscase(const char_u *s, bool strict) return false; } -/* - * Recognize a "default" switch label. - */ +// Recognize a "default" switch label. static int cin_isdefault(const char_u *s) { return STRNCMP(s, "default", 7) == 0 @@ -514,12 +485,12 @@ bool cin_isscopedecl(const char_u *p) { const char_u *s = cin_skipcomment(p); - const size_t cinsd_len = STRLEN(curbuf->b_p_cinsd) + 1; + const size_t cinsd_len = strlen(curbuf->b_p_cinsd) + 1; char_u *cinsd_buf = xmalloc(cinsd_len); bool found = false; - for (char *cinsd = (char *)curbuf->b_p_cinsd; *cinsd;) { + for (char *cinsd = curbuf->b_p_cinsd; *cinsd;) { const size_t len = copy_option_part(&cinsd, (char *)cinsd_buf, cinsd_len, ","); if (STRNCMP(s, cinsd_buf, len) == 0) { const char_u *skip = cin_skipcomment(s + len); @@ -580,15 +551,13 @@ static bool cin_is_cpp_namespace(const char_u *s) return false; } -/* - * Return a pointer to the first non-empty non-comment character after a ':'. - * Return NULL if not found. - * case 234: a = b; - * ^ - */ +// Return a pointer to the first non-empty non-comment character after a ':'. +// Return NULL if not found. +// case 234: a = b; +// ^ static const char_u *after_label(const char_u *l) { - for (; *l; ++l) { + for (; *l; l++) { if (*l == ':') { if (l[1] == ':') { // skip over "::" for C++ l++; @@ -609,10 +578,8 @@ static const char_u *after_label(const char_u *l) return l; } -/* - * Get indent of line "lnum", skipping a label. - * Return 0 if there is nothing after the label. - */ +// Get indent of line "lnum", skipping a label. +// Return 0 if there is nothing after the label. static int get_indent_nolabel(linenr_T lnum) // XXX { const char_u *l; @@ -620,7 +587,7 @@ static int get_indent_nolabel(linenr_T lnum) // XXX colnr_T col; const char_u *p; - l = ml_get(lnum); + l = (char_u *)ml_get(lnum); p = after_label(l); if (p == NULL) { return 0; @@ -632,12 +599,10 @@ static int get_indent_nolabel(linenr_T lnum) // XXX return (int)col; } -/* - * Find indent for line "lnum", ignoring any case or jump label. - * Also return a pointer to the text (after the label) in "pp". - * label: if (asdf && asdfasdf) - * ^ - */ +// Find indent for line "lnum", ignoring any case or jump label. +// Also return a pointer to the text (after the label) in "pp". +// label: if (asdf && asdfasdf) +// ^ static int skip_label(linenr_T lnum, const char_u **pp) { const char_u *l; @@ -646,17 +611,17 @@ static int skip_label(linenr_T lnum, const char_u **pp) cursor_save = curwin->w_cursor; curwin->w_cursor.lnum = lnum; - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); // XXX if (cin_iscase(l, false) || cin_isscopedecl(l) || cin_islabel()) { amount = get_indent_nolabel(lnum); - l = after_label(get_cursor_line_ptr()); + l = after_label((char_u *)get_cursor_line_ptr()); if (l == NULL) { // just in case - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); } } else { amount = get_indent(); - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); } *pp = l; @@ -664,13 +629,11 @@ static int skip_label(linenr_T lnum, const char_u **pp) return amount; } -/* - * Return the indent of the first variable name after a type in a declaration. - * int a, indent of "a" - * static struct foo b, indent of "b" - * enum bla c, indent of "c" - * Returns zero when it doesn't look like a declaration. - */ +// Return the indent of the first variable name after a type in a declaration. +// int a, indent of "a" +// static struct foo b, indent of "b" +// enum bla c, indent of "c" +// Returns zero when it doesn't look like a declaration. static int cin_first_id_amount(void) { char_u *line, *p, *s; @@ -678,12 +641,12 @@ static int cin_first_id_amount(void) pos_T fp; colnr_T col; - line = get_cursor_line_ptr(); + line = (char_u *)get_cursor_line_ptr(); p = (char_u *)skipwhite((char *)line); - len = (int)(skiptowhite(p) - p); + len = (int)((char_u *)skiptowhite((char *)p) - p); if (len == 6 && STRNCMP(p, "static", 6) == 0) { p = (char_u *)skipwhite((char *)p + 6); - len = (int)(skiptowhite(p) - p); + len = (int)((char_u *)skiptowhite((char *)p) - p); } if (len == 6 && STRNCMP(p, "struct", 6) == 0) { p = (char_u *)skipwhite((char *)p + 6); @@ -711,15 +674,13 @@ static int cin_first_id_amount(void) return (int)col; } -/* - * Return the indent of the first non-blank after an equal sign. - * char *foo = "here"; - * Return zero if no (useful) equal sign found. - * Return -1 if the line above "lnum" ends in a backslash. - * foo = "asdf\ - * asdf\ - * here"; - */ +// Return the indent of the first non-blank after an equal sign. +// char *foo = "here"; +// Return zero if no (useful) equal sign found. +// Return -1 if the line above "lnum" ends in a backslash. +// foo = "asdf{backslash} +// asdf{backslash} +// here"; static int cin_get_equal_amount(linenr_T lnum) { const char_u *line; @@ -728,13 +689,14 @@ static int cin_get_equal_amount(linenr_T lnum) pos_T fp; if (lnum > 1) { - line = ml_get(lnum - 1); + line = (char_u *)ml_get(lnum - 1); if (*line != NUL && line[STRLEN(line) - 1] == '\\') { return -1; } } - line = s = ml_get(lnum); + s = (char_u *)ml_get(lnum); + line = s; while (*s != NUL && vim_strchr("=;{}\"'", *s) == NULL) { if (cin_iscomment(s)) { // ignore comments s = cin_skipcomment(s); @@ -761,18 +723,16 @@ static int cin_get_equal_amount(linenr_T lnum) return (int)col; } -/* - * Recognize a preprocessor statement: Any line that starts with '#'. - */ +// Recognize a preprocessor statement: Any line that starts with '#'. static int cin_ispreproc(const char_u *s) { if (*skipwhite((char *)s) == '#') { return true; } - return FALSE; + return false; } -/// Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a +/// Return true if line "*pp" at "*lnump" is a preprocessor statement or a /// continuation line of a preprocessor statement. Decrease "*lnump" to the /// start and return the line in "*pp". /// Put the amount of indent in "*amount". @@ -789,21 +749,21 @@ static int cin_ispreproc_cont(const char_u **pp, linenr_T *lnump, int *amount) for (;;) { if (cin_ispreproc(line)) { - retval = TRUE; + retval = true; *lnump = lnum; break; } if (lnum == 1) { break; } - line = ml_get(--lnum); + line = (char_u *)ml_get(--lnum); if (*line == NUL || line[STRLEN(line) - 1] != '\\') { break; } } if (lnum != *lnump) { - *pp = ml_get(*lnump); + *pp = (char_u *)ml_get(*lnump); } if (retval) { *amount = candidate_amount; @@ -811,17 +771,13 @@ static int cin_ispreproc_cont(const char_u **pp, linenr_T *lnump, int *amount) return retval; } -/* - * Recognize the start of a C or C++ comment. - */ +// Recognize the start of a C or C++ comment. static int cin_iscomment(const char_u *p) { return p[0] == '/' && (p[1] == '*' || p[1] == '/'); } -/* - * Recognize the start of a "//" comment. - */ +// Recognize the start of a "//" comment. static int cin_islinecomment(const char_u *p) { return p[0] == '/' && p[1] == '/'; @@ -842,7 +798,7 @@ static char_u cin_isterminated(const char_u *s, int incl_open, int incl_comma) { char_u found_start = 0; unsigned n_open = 0; - int is_else = FALSE; + int is_else = false; s = cin_skipcomment(s); @@ -899,7 +855,7 @@ static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_l int just_started = true; if (sp == NULL) { - s = ml_get(lnum); + s = (char_u *)ml_get(lnum); } else { s = *sp; } @@ -912,7 +868,7 @@ static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_l curwin->w_cursor.lnum = save_lnum; return false; } - s = ml_get(lnum); + s = (char_u *)ml_get(lnum); } curwin->w_cursor.lnum = save_lnum; @@ -951,7 +907,7 @@ static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_l // #if defined(x) && {backslash} // defined(y) lnum = first_lnum - 1; - s = ml_get(lnum); + s = (char_u *)ml_get(lnum); if (*s == NUL || s[STRLEN(s) - 1] != '\\') { retval = true; } @@ -960,15 +916,15 @@ static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_l if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s)) { int comma = (*s == ','); - /* ',' at the end: continue looking in the next line. - * At the end: check for ',' in the next line, for this style: - * func(arg1 - * , arg2) */ + // ',' at the end: continue looking in the next line. + // At the end: check for ',' in the next line, for this style: + // func(arg1 + // , arg2) for (;;) { if (lnum >= curbuf->b_ml.ml_line_count) { break; } - s = ml_get(++lnum); + s = (char_u *)ml_get(++lnum); if (!cin_ispreproc(s)) { break; } @@ -993,7 +949,7 @@ static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_l done: if (lnum != first_lnum && sp != NULL) { - *sp = ml_get(first_lnum); + *sp = (char_u *)ml_get(first_lnum); } return retval; @@ -1017,11 +973,9 @@ static int cin_isdo(const char_u *p) return STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]); } -/* - * Check if this is a "while" that should have a matching "do". - * We only accept a "while (condition) ;", with only white space between the - * ')' and ';'. The condition may be spread over several lines. - */ +// Check if this is a "while" that should have a matching "do". +// We only accept a "while (condition) ;", with only white space between the +// ')' and ';'. The condition may be spread over several lines. static int cin_iswhileofdo(const char_u *p, linenr_T lnum) // XXX { pos_T cursor_save; @@ -1036,7 +990,7 @@ static int cin_iswhileofdo(const char_u *p, linenr_T lnum) // XXX cursor_save = curwin->w_cursor; curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = 0; - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); while (*p && *p != 'w') { // skip any '}', until the 'w' of the "while" p++; curwin->w_cursor.col++; @@ -1050,12 +1004,10 @@ static int cin_iswhileofdo(const char_u *p, linenr_T lnum) // XXX return retval; } -/* - * Check whether in "p" there is an "if", "for" or "while" before "*poffset". - * Return 0 if there is none. - * Otherwise return !0 and update "*poffset" to point to the place where the - * string was found. - */ +// Check whether in "p" there is an "if", "for" or "while" before "*poffset". +// Return 0 if there is none. +// Otherwise return !0 and update "*poffset" to point to the place where the +// string was found. static int cin_is_if_for_while_before_offset(const char_u *line, int *poffset) { int offset = *poffset; @@ -1095,14 +1047,12 @@ probablyFound: return 0; } -/* - * Return TRUE if we are at the end of a do-while. - * do - * nothing; - * while (foo - * && bar); <-- here - * Adjust the cursor to the line with "while". - */ +/// Return true if we are at the end of a do-while. +/// do +/// nothing; +/// while (foo +/// && bar); <-- here +/// Adjust the cursor to the line with "while". static int cin_iswhileofdo_end(int terminated) { const char_u *line; @@ -1115,30 +1065,30 @@ static int cin_iswhileofdo_end(int terminated) return false; } - p = line = get_cursor_line_ptr(); + p = line = (char_u *)get_cursor_line_ptr(); while (*p != NUL) { p = cin_skipcomment(p); if (*p == ')') { s = (char_u *)skipwhite((char *)p + 1); if (*s == ';' && cin_nocode(s + 1)) { - /* Found ");" at end of the line, now check there is "while" - * before the matching '('. XXX */ + // Found ");" at end of the line, now check there is "while" + // before the matching '('. XXX i = (int)(p - line); curwin->w_cursor.col = i; trypos = find_match_paren(curbuf->b_ind_maxparen); if (trypos != NULL) { - s = cin_skipcomment(ml_get(trypos->lnum)); + s = cin_skipcomment((char_u *)ml_get(trypos->lnum)); if (*s == '}') { // accept "} while (cond);" s = cin_skipcomment(s + 1); } if (cin_starts_with(s, "while")) { curwin->w_cursor.lnum = trypos->lnum; - return TRUE; + return true; } } // Searching may have made "line" invalid, get it again. - line = get_cursor_line_ptr(); + line = (char_u *)get_cursor_line_ptr(); p = line + i; } } @@ -1146,7 +1096,7 @@ static int cin_iswhileofdo_end(int terminated) p++; } } - return FALSE; + return false; } static int cin_isbreak(const char_u *p) @@ -1154,26 +1104,24 @@ static int cin_isbreak(const char_u *p) return STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]); } -/* - * Find the position of a C++ base-class declaration or - * constructor-initialization. eg: - * - * class MyClass : - * baseClass <-- here - * class MyClass : public baseClass, - * anotherBaseClass <-- here (should probably lineup ??) - * MyClass::MyClass(...) : - * baseClass(...) <-- here (constructor-initialization) - * - * This is a lot of guessing. Watch out for "cond ? func() : foo". - */ +// Find the position of a C++ base-class declaration or +// constructor-initialization. eg: +// +// class MyClass : +// baseClass <-- here +// class MyClass : public baseClass, +// anotherBaseClass <-- here (should probably lineup ??) +// MyClass::MyClass(...) : +// baseClass(...) <-- here (constructor-initialization) +// +// This is a lot of guessing. Watch out for "cond ? func() : foo". static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) { lpos_T *pos = &cached->lpos; // find position const char_u *s; int class_or_struct, lookfor_ctor_init, cpp_base_class; linenr_T lnum = curwin->w_cursor.lnum; - const char_u *line = get_cursor_line_ptr(); + const char_u *line = (char_u *)get_cursor_line_ptr(); if (pos->lnum <= lnum) { return cached->found; // Use the cached result @@ -1190,23 +1138,22 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) return false; } - cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; - - /* Search for a line starting with '#', empty, ending in ';' or containing - * '{' or '}' and start below it. This handles the following situations: - * a = cond ? - * func() : - * asdf; - * func::foo() - * : something - * {} - * Foo::Foo (int one, int two) - * : something(4), - * somethingelse(3) - * {} - */ + cpp_base_class = lookfor_ctor_init = class_or_struct = false; + + // Search for a line starting with '#', empty, ending in ';' or containing + // '{' or '}' and start below it. This handles the following situations: + // a = cond ? + // func() : + // asdf; + // func::foo() + // : something + // {} + // Foo::Foo (int one, int two) + // : something(4), + // somethingelse(3) + // {} while (lnum > 1) { - line = ml_get(lnum - 1); + line = (char_u *)ml_get(lnum - 1); s = (char_u *)skipwhite((char *)line); if (*s == '#' || *s == NUL) { break; @@ -1228,7 +1175,7 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) } pos->lnum = lnum; - line = ml_get(lnum); + line = (char_u *)ml_get(lnum); s = line; for (;;) { if (*s == NUL) { @@ -1236,7 +1183,7 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) break; } // Continue in the cursor line. - line = ml_get(++lnum); + line = (char_u *)ml_get(++lnum); s = line; } if (s == line) { @@ -1254,13 +1201,13 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) s = skip_string(s) + 1; } else if (s[0] == ':') { if (s[1] == ':') { - /* skip double colon. It can't be a constructor - * initialization any more */ - lookfor_ctor_init = FALSE; + // skip double colon. It can't be a constructor + // initialization any more + lookfor_ctor_init = false; s = cin_skipcomment(s + 2); } else if (lookfor_ctor_init || class_or_struct) { - /* we have something found, that looks like the start of - * cpp-base-class-declaration or constructor-initialization */ + // we have something found, that looks like the start of + // cpp-base-class-declaration or constructor-initialization cpp_base_class = true; lookfor_ctor_init = class_or_struct = false; pos->col = 0; @@ -1270,8 +1217,8 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) } } else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5])) || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6]))) { - class_or_struct = TRUE; - lookfor_ctor_init = FALSE; + class_or_struct = true; + lookfor_ctor_init = false; if (*s == 'c') { s = cin_skipcomment(s + 5); @@ -1280,12 +1227,12 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) } } else { if (s[0] == '{' || s[0] == '}' || s[0] == ';') { - cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; + cpp_base_class = lookfor_ctor_init = class_or_struct = false; } else if (s[0] == ')') { - /* Constructor-initialization is assumed if we come across - * something like "):" */ - class_or_struct = FALSE; - lookfor_ctor_init = TRUE; + // Constructor-initialization is assumed if we come across + // something like "):" + class_or_struct = false; + lookfor_ctor_init = true; } else if (s[0] == '?') { // Avoid seeing '() :' after '?' as constructor init. return false; @@ -1327,11 +1274,11 @@ static int get_baseclass_amount(int col) if (col == 0) { amount = get_indent(); - if (find_last_paren(get_cursor_line_ptr(), '(', ')') + if (find_last_paren((char_u *)get_cursor_line_ptr(), '(', ')') && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) { amount = get_indent_lnum(trypos->lnum); // XXX } - if (!cin_ends_in(get_cursor_line_ptr(), (char_u *)",", NULL)) { + if (!cin_ends_in((char_u *)get_cursor_line_ptr(), (char_u *)",", NULL)) { amount += curbuf->b_ind_cpp_baseclass; } } else { @@ -1345,11 +1292,9 @@ static int get_baseclass_amount(int col) return amount; } -/* - * Return TRUE if string "s" ends with the string "find", possibly followed by - * white space and comments. Skip strings and comments. - * Ignore "ignore" after "find" if it's not NULL. - */ +/// Return true if string "s" ends with the string "find", possibly followed by +/// white space and comments. Skip strings and comments. +/// Ignore "ignore" after "find" if it's not NULL. static int cin_ends_in(const char_u *s, const char_u *find, const char_u *ignore) { const char_u *p = s; @@ -1371,15 +1316,13 @@ static int cin_ends_in(const char_u *s, const char_u *find, const char_u *ignore p++; } } - return FALSE; + return false; } -/* - * Return TRUE when "s" starts with "word" and then a non-ID character. - */ +/// Return true when "s" starts with "word" and then a non-ID character. static int cin_starts_with(const char_u *s, const char *word) { - int l = (int)STRLEN(word); + int l = (int)strlen(word); return STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l]); } @@ -1420,17 +1363,16 @@ static int cin_is_cpp_extern_c(const char_u *s) return false; } -/* - * Skip strings, chars and comments until at or past "trypos". - * Return the column found. - */ +// Skip strings, chars and comments until at or past "trypos". +// Return the column found. static int cin_skip2pos(pos_T *trypos) { const char_u *line; const char_u *p; const char_u *new_p; - p = line = ml_get(trypos->lnum); + line = (char_u *)ml_get(trypos->lnum); + p = line; while (*p && (colnr_T)(p - line) < trypos->col) { if (cin_iscomment(p)) { p = cin_skipcomment(p); @@ -1446,11 +1388,10 @@ static int cin_skip2pos(pos_T *trypos) return (int)(p - line); } -/* - * Find the '{' at the start of the block we are in. - * Return NULL if no match found. - * Ignore a '{' that is in a comment, makes indenting the next three lines - * work. */ +// Find the '{' at the start of the block we are in. +// Return NULL if no match found. +// Ignore a '{' that is in a comment, makes indenting the next three lines +// work. // foo() // { // } @@ -1550,12 +1491,10 @@ static pos_T *find_match_paren_after_brace(int ind_maxparen) return trypos; } -/* - * Return ind_maxparen corrected for the difference in line number between the - * cursor position and "startpos". This makes sure that searching for a - * matching paren above the cursor line doesn't find a match because of - * looking a few lines further. - */ +// Return ind_maxparen corrected for the difference in line number between the +// cursor position and "startpos". This makes sure that searching for a +// matching paren above the cursor line doesn't find a match because of +// looking a few lines further. static int corr_ind_maxparen(pos_T *startpos) { long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; @@ -1566,14 +1505,12 @@ static int corr_ind_maxparen(pos_T *startpos) return curbuf->b_ind_maxparen; } -/* - * Set w_cursor.col to the column number of the last unmatched ')' or '{' in - * line "l". "l" must point to the start of the line. - */ +// Set w_cursor.col to the column number of the last unmatched ')' or '{' in +// line "l". "l" must point to the start of the line. static int find_last_paren(const char_u *l, int start, int end) { int i; - int retval = FALSE; + int retval = false; int open_count = 0; curwin->w_cursor.col = 0; // default is start of line @@ -1588,17 +1525,15 @@ static int find_last_paren(const char_u *l, int start, int end) open_count--; } else { curwin->w_cursor.col = i; - retval = TRUE; + retval = true; } } } return retval; } -/* - * Parse 'cinoptions' and set the values in "curbuf". - * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. - */ +// Parse 'cinoptions' and set the values in "curbuf". +// Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. void parse_cino(buf_T *buf) { char *p; @@ -1607,39 +1542,37 @@ void parse_cino(buf_T *buf) int fraction = 0; int sw = get_sw_value(buf); - /* - * Set the default values. - */ - /* Spaces from a block's opening brace the prevailing indent for that - * block should be. */ + // Set the default values. + // Spaces from a block's opening brace the prevailing indent for that + // block should be. buf->b_ind_level = sw; - /* Spaces from the edge of the line an open brace that's at the end of a - * line is imagined to be. */ + // Spaces from the edge of the line an open brace that's at the end of a + // line is imagined to be. buf->b_ind_open_imag = 0; - /* Spaces from the prevailing indent for a line that is not preceded by - * an opening brace. */ + // Spaces from the prevailing indent for a line that is not preceded by + // an opening brace. buf->b_ind_no_brace = 0; // Column where the first { of a function should be located }. buf->b_ind_first_open = 0; - /* Spaces from the prevailing indent a leftmost open brace should be - * located. */ + // Spaces from the prevailing indent a leftmost open brace should be + // located. buf->b_ind_open_extra = 0; - /* Spaces from the matching open brace (real location for one at the left - * edge; imaginary location from one that ends a line) the matching close - * brace should be located. */ + // Spaces from the matching open brace (real location for one at the left + // edge; imaginary location from one that ends a line) the matching close + // brace should be located. buf->b_ind_close_extra = 0; - /* Spaces from the edge of the line an open brace sitting in the leftmost - * column is imagined to be. */ + // Spaces from the edge of the line an open brace sitting in the leftmost + // column is imagined to be. buf->b_ind_open_left_imag = 0; - /* Spaces jump labels should be shifted to the left if N is non-negative, - * otherwise the jump label will be put to column 1. */ + // Spaces jump labels should be shifted to the left if N is non-negative, + // otherwise the jump label will be put to column 1. buf->b_ind_jump_label = -1; // Spaces from the switch() indent a "case xx" label should be located. @@ -1651,8 +1584,8 @@ void parse_cino(buf_T *buf) // Lineup break at end of case in switch() with case label. buf->b_ind_case_break = 0; - /* Spaces from the class declaration indent a scope declaration label - * should be located. */ + // Spaces from the class declaration indent a scope declaration label + // should be located. buf->b_ind_scopedecl = sw; // Spaces from the scope declaration label code should be located. @@ -1664,32 +1597,32 @@ void parse_cino(buf_T *buf) // Amount a function type spec should be indented. buf->b_ind_func_type = sw; - /* Amount a cpp base class declaration or constructor initialization - * should be indented. */ + // Amount a cpp base class declaration or constructor initialization + // should be indented. buf->b_ind_cpp_baseclass = sw; - /* additional spaces beyond the prevailing indent a continuation line - * should be located. */ + // additional spaces beyond the prevailing indent a continuation line + // should be located. buf->b_ind_continuation = sw; // Spaces from the indent of the line with an unclosed parentheses. buf->b_ind_unclosed = sw * 2; - /* Spaces from the indent of the line with an unclosed parentheses, which - * itself is also unclosed. */ + // Spaces from the indent of the line with an unclosed parentheses, which + // itself is also unclosed. buf->b_ind_unclosed2 = sw; // Suppress ignoring spaces from the indent of a line starting with an // unclosed parenthesis. buf->b_ind_unclosed_noignore = 0; - /* If the opening paren is the last nonwhite character on the line, and - * b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer - * context (for very long lines). */ + // If the opening paren is the last nonwhite character on the line, and + // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer + // context (for very long lines). buf->b_ind_unclosed_wrapped = 0; - /* Suppress ignoring white space when lining up with the character after - * an unclosed parentheses. */ + // Suppress ignoring white space when lining up with the character after + // an unclosed parentheses. buf->b_ind_unclosed_whiteok = 0; // Indent a closing parenthesis under the line start of the matching @@ -1705,8 +1638,8 @@ void parse_cino(buf_T *buf) // Spaces from the comment opener when there is nothing after it. buf->b_ind_in_comment = 3; - /* Boolean: if non-zero, use b_ind_in_comment even if there is something - * after the comment opener. */ + // Boolean: if non-zero, use b_ind_in_comment even if there is something + // after the comment opener. buf->b_ind_in_comment2 = 0; // Max lines to search for an open paren. @@ -1727,8 +1660,8 @@ void parse_cino(buf_T *buf) // Handle C++ namespace. buf->b_ind_cpp_namespace = 0; - /* Handle continuation lines containing conditions of if(), for() and - * while(). */ + // Handle continuation lines containing conditions of if(), for() and + // while(). buf->b_ind_if_for_while = 0; // indentation for # comments @@ -1740,7 +1673,7 @@ void parse_cino(buf_T *buf) // Handle C #pragma directives buf->b_ind_pragma = 0; - for (p = (char *)buf->b_p_cino; *p;) { + for (p = buf->b_p_cino; *p;) { l = p++; if (*p == '-') { p++; @@ -1774,8 +1707,8 @@ void parse_cino(buf_T *buf) n = -n; } - /* When adding an entry here, also update the default 'cinoptions' in - * doc/indent.txt, and add explanation for it! */ + // When adding an entry here, also update the default 'cinoptions' in + // doc/indent.txt, and add explanation for it! switch (*l) { case '>': buf->b_ind_level = n; @@ -1895,10 +1828,8 @@ void parse_cino(buf_T *buf) } } -/* - * Return the desired indent for C code. - * Return -1 if the indent should be left alone (inside a raw string). - */ +// Return the desired indent for C code. +// Return -1 if the indent should be left alone (inside a raw string). int get_c_indent(void) { pos_T cur_curpos; @@ -1907,7 +1838,7 @@ int get_c_indent(void) int cur_amount = MAXCOL; colnr_T col; char_u *theline; - char_u *linecopy; + char *linecopy; pos_T *trypos; pos_T *comment_pos; pos_T *tryposBrace = NULL; @@ -1959,25 +1890,23 @@ int get_c_indent(void) return 0; } - /* Get a copy of the current contents of the line. - * This is required, because only the most recent line obtained with - * ml_get is valid! */ - linecopy = vim_strsave(ml_get(cur_curpos.lnum)); + // Get a copy of the current contents of the line. + // This is required, because only the most recent line obtained with + // ml_get is valid! + linecopy = xstrdup(ml_get(cur_curpos.lnum)); - /* - * In insert mode and the cursor is on a ')' truncate the line at the - * cursor position. We don't want to line up with the matching '(' when - * inserting new stuff. - * For unknown reasons the cursor might be past the end of the line, thus - * check for that. - */ + // In insert mode and the cursor is on a ')' truncate the line at the + // cursor position. We don't want to line up with the matching '(' when + // inserting new stuff. + // For unknown reasons the cursor might be past the end of the line, thus + // check for that. if ((State & MODE_INSERT) - && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy) + && curwin->w_cursor.col < (colnr_T)strlen(linecopy) && linecopy[curwin->w_cursor.col] == ')') { linecopy[curwin->w_cursor.col] = NUL; } - theline = (char_u *)skipwhite((char *)linecopy); + theline = (char_u *)skipwhite(linecopy); // move the cursor to the start of the line @@ -1985,10 +1914,8 @@ int get_c_indent(void) original_line_islabel = cin_islabel(); // XXX - /* - * If we are inside a raw string don't change the indent. - * Ignore a raw string inside a comment. - */ + // If we are inside a raw string don't change the indent. + // Ignore a raw string inside a comment. comment_pos = ind_find_start_comment(); if (comment_pos != NULL) { // findmatchlimit() static pos is overwritten, make a copy @@ -2018,10 +1945,8 @@ int get_c_indent(void) amount = 0; goto theend; } - /* - * If we're inside a "//" comment and there is a "//" comment in a - * previous line, lineup with that one. - */ + // If we're inside a "//" comment and there is a "//" comment in a + // previous line, lineup with that one. if (cin_islinecomment(theline)) { pos_T linecomment_pos; @@ -2042,10 +1967,8 @@ int get_c_indent(void) goto theend; } } - /* - * If we're inside a comment and not looking at the start of the - * comment, try using the 'comments' option. - */ + // If we're inside a comment and not looking at the start of the + // comment, try using the 'comments' option. if (!cin_iscomment(theline) && comment_pos != NULL) { // XXX int lead_start_len = 2; int lead_middle_len = 1; @@ -2055,7 +1978,7 @@ int get_c_indent(void) char *p; int start_align = 0; int start_off = 0; - int done = FALSE; + int done = false; // find how indented the line beginning the comment is getvcol(curwin, comment_pos, &col, NULL, NULL); @@ -2063,7 +1986,7 @@ int get_c_indent(void) *lead_start = NUL; *lead_middle = NUL; - p = (char *)curbuf->b_p_com; + p = curbuf->b_p_com; while (*p != NUL) { int align = 0; int off = 0; @@ -2087,24 +2010,24 @@ int get_c_indent(void) (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); if (what == COM_START) { STRCPY(lead_start, lead_end); - lead_start_len = (int)STRLEN(lead_start); + lead_start_len = (int)strlen(lead_start); start_off = off; start_align = align; } else if (what == COM_MIDDLE) { STRCPY(lead_middle, lead_end); - lead_middle_len = (int)STRLEN(lead_middle); + lead_middle_len = (int)strlen(lead_middle); } else if (what == COM_END) { - /* If our line starts with the middle comment string, line it - * up with the comment opener per the 'comments' option. */ + // If our line starts with the middle comment string, line it + // up with the comment opener per the 'comments' option. if (STRNCMP(theline, lead_middle, lead_middle_len) == 0 - && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0) { - done = TRUE; + && STRNCMP(theline, lead_end, strlen(lead_end)) != 0) { + done = true; if (curwin->w_cursor.lnum > 1) { - /* If the start comment string matches in the previous - * line, use the indent of that line plus offset. If - * the middle comment string matches in the previous - * line, use the indent of that line. XXX */ - look = (char_u *)skipwhite((char *)ml_get(curwin->w_cursor.lnum - 1)); + // If the start comment string matches in the previous + // line, use the indent of that line plus offset. If + // the middle comment string matches in the previous + // line, use the indent of that line. XXX + look = (char_u *)skipwhite(ml_get(curwin->w_cursor.lnum - 1)); if (STRNCMP(look, lead_start, lead_start_len) == 0) { amount = get_indent_lnum(curwin->w_cursor.lnum - 1); } else if (STRNCMP(look, lead_middle, lead_middle_len) == 0) { @@ -2125,10 +2048,10 @@ int get_c_indent(void) break; } - /* If our line starts with the end comment string, line it up - * with the middle comment */ + // If our line starts with the end comment string, line it up + // with the middle comment if (STRNCMP(theline, lead_middle, lead_middle_len) != 0 - && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) { + && STRNCMP(theline, lead_end, strlen(lead_end)) == 0) { amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX if (off != 0) { @@ -2142,10 +2065,9 @@ int get_c_indent(void) } } - /* If our line starts with an asterisk, line up with the - * asterisk in the comment opener; otherwise, line up - * with the first character of the comment text. - */ + // If our line starts with an asterisk, line up with the + // asterisk in the comment opener; otherwise, line up + // with the first character of the comment text. if (done) { // skip } else if (theline[0] == '*') { @@ -2166,7 +2088,7 @@ int get_c_indent(void) } if (amount == -1) { // use the comment opener if (!curbuf->b_ind_in_comment2) { - start = ml_get(comment_pos->lnum); + start = (char_u *)ml_get(comment_pos->lnum); look = start + comment_pos->col + 2; // skip / and * if (*look != NUL) { // if something after it comment_pos->col = (colnr_T)((char_u *)skipwhite((char *)look) - start); @@ -2195,8 +2117,8 @@ int get_c_indent(void) || (tryposBrace = find_start_brace()) != NULL || trypos != NULL) { if (trypos != NULL && tryposBrace != NULL) { - /* Both an unmatched '(' and '{' is found. Use the one which is - * closer to the current cursor position, set the other to NULL. */ + // Both an unmatched '(' and '{' is found. Use the one which is + // closer to the current cursor position, set the other to NULL. if (trypos->lnum != tryposBrace->lnum ? trypos->lnum < tryposBrace->lnum : trypos->col < tryposBrace->col) { @@ -2208,17 +2130,15 @@ int get_c_indent(void) if (trypos != NULL) { our_paren_pos = *trypos; - /* - * If the matching paren is more than one line away, use the indent of - * a previous non-empty line that matches the same paren. - */ + // If the matching paren is more than one line away, use the indent of + // a previous non-empty line that matches the same paren. if (theline[0] == ')' && curbuf->b_ind_paren_prev) { // Line up with the start of the matching paren line. amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX } else { amount = -1; for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; lnum--) { - l = (char_u *)skipwhite((char *)ml_get(lnum)); + l = (char_u *)skipwhite(ml_get(lnum)); if (cin_nocode(l)) { // skip comment lines continue; } @@ -2251,18 +2171,16 @@ int get_c_indent(void) } } - /* - * Line up with line where the matching paren is. XXX - * If the line starts with a '(' or the indent for unclosed - * parentheses is zero, line up with the unclosed parentheses. - */ + // Line up with line where the matching paren is. XXX + // If the line starts with a '(' or the indent for unclosed + // parentheses is zero, line up with the unclosed parentheses. if (amount == -1) { int ignore_paren_col = 0; int is_if_for_while = 0; if (curbuf->b_ind_if_for_while) { - /* Look for the outermost opening parenthesis on this line - * and check whether it belongs to an "if", "for" or "while". */ + // Look for the outermost opening parenthesis on this line + // and check whether it belongs to an "if", "for" or "while". pos_T cursor_save = curwin->w_cursor; pos_T outermost; @@ -2279,7 +2197,7 @@ int get_c_indent(void) curwin->w_cursor = cursor_save; - line = ml_get(outermost.lnum); + line = (char_u *)ml_get(outermost.lnum); is_if_for_while = cin_is_if_for_while_before_offset(line, &outermost.col); @@ -2292,10 +2210,10 @@ int get_c_indent(void) char_u *line; int look_col; - /* Ignore a '(' in front of the line that has a match before - * our matching '('. */ + // Ignore a '(' in front of the line that has a match before + // our matching '('. curwin->w_cursor.lnum = our_paren_pos.lnum; - line = get_cursor_line_ptr(); + line = (char_u *)get_cursor_line_ptr(); look_col = (int)(look - line); curwin->w_cursor.col = look_col + 1; if ((trypos = findmatchlimit(NULL, ')', 0, @@ -2307,30 +2225,28 @@ int get_c_indent(void) } curwin->w_cursor.lnum = save_lnum; - look = ml_get(our_paren_pos.lnum) + look_col; + look = (char_u *)ml_get(our_paren_pos.lnum) + look_col; } if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0 && is_if_for_while == 0) || (!curbuf->b_ind_unclosed_noignore && *look == '(' && ignore_paren_col == 0)) { - /* - * If we're looking at a close paren, line up right there; - * otherwise, line up with the next (non-white) character. - * When b_ind_unclosed_wrapped is set and the matching paren is - * the last nonwhite character of the line, use either the - * indent of the current line or the indentation of the next - * outer paren and add b_ind_unclosed_wrapped (for very long - * lines). - */ + // If we're looking at a close paren, line up right there; + // otherwise, line up with the next (non-white) character. + // When b_ind_unclosed_wrapped is set and the matching paren is + // the last nonwhite character of the line, use either the + // indent of the current line or the indentation of the next + // outer paren and add b_ind_unclosed_wrapped (for very long + // lines). if (theline[0] != ')') { cur_amount = MAXCOL; - l = ml_get(our_paren_pos.lnum); + l = (char_u *)ml_get(our_paren_pos.lnum); if (curbuf->b_ind_unclosed_wrapped && cin_ends_in(l, (char_u *)"(", NULL)) { - /* look for opening unmatched paren, indent one level - * for each additional level */ + // look for opening unmatched paren, indent one level + // for each additional level n = 1; - for (col = 0; col < our_paren_pos.col; ++col) { + for (col = 0; col < our_paren_pos.col; col++) { switch (l[col]) { case '(': case '{': @@ -2363,10 +2279,8 @@ int get_c_indent(void) } } - /* - * Find how indented the paren is, or the character after it - * if we did the above "if". - */ + // Find how indented the paren is, or the character after it + // if we did the above "if". if (our_paren_pos.col > 0) { getvcol(curwin, &our_paren_pos, &col, NULL, NULL); if (cur_amount > (int)col) { @@ -2384,11 +2298,11 @@ int get_c_indent(void) amount = cur_amount; } } else { - /* Add b_ind_unclosed2 for each '(' before our matching one, - * but ignore (void) before the line (ignore_paren_col). */ + // Add b_ind_unclosed2 for each '(' before our matching one, + // but ignore (void) before the line (ignore_paren_col). col = our_paren_pos.col; while ((int)our_paren_pos.col > ignore_paren_col) { - --our_paren_pos.col; + our_paren_pos.col--; switch (*ml_get_pos(&our_paren_pos)) { case '(': amount += curbuf->b_ind_unclosed2; @@ -2401,8 +2315,8 @@ int get_c_indent(void) } } - /* Use b_ind_unclosed once, when the first '(' is not inside - * braces */ + // Use b_ind_unclosed once, when the first '(' is not inside + // braces if (col == MAXCOL) { amount += curbuf->b_ind_unclosed; } else { @@ -2418,14 +2332,12 @@ int get_c_indent(void) } } } - /* - * For a line starting with ')' use the minimum of the two - * positions, to avoid giving it more indent than the previous - * lines: - * func_long_name( if (x - * arg && yy - * ) ^ not here ) ^ not here - */ + // For a line starting with ')' use the minimum of the two + // positions, to avoid giving it more indent than the previous + // lines: + // func_long_name( if (x + // arg && yy + // ) ^ not here ) ^ not here if (cur_amount < amount) { amount = cur_amount; } @@ -2445,14 +2357,12 @@ int get_c_indent(void) tryposBrace = &tryposCopy; trypos = tryposBrace; ourscope = trypos->lnum; - start = ml_get(ourscope); - - /* - * Now figure out how indented the line is in general. - * If the brace was at the start of the line, we use that; - * otherwise, check out the indentation of the line as - * a whole and then add the "imaginary indent" to that. - */ + start = (char_u *)ml_get(ourscope); + + // Now figure out how indented the line is in general. + // If the brace was at the start of the line, we use that; + // otherwise, check out the indentation of the line as + // a whole and then add the "imaginary indent" to that. look = (char_u *)skipwhite((char *)start); if (*look == '{') { getvcol(curwin, trypos, &col, NULL, NULL); @@ -2480,7 +2390,7 @@ int get_c_indent(void) // ldfd) { // } if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label) - && cin_iscase((char_u *)skipwhite((char *)get_cursor_line_ptr()), false)) { + && cin_iscase((char_u *)skipwhite(get_cursor_line_ptr()), false)) { amount = get_indent(); } else if (curbuf->b_ind_js) { amount = get_indent_lnum(lnum); @@ -2498,18 +2408,14 @@ int get_c_indent(void) // we want to be. Otherwise, add the amount of room // that an indent is supposed to be. if (theline[0] == '}') { - /* - * they may want closing braces to line up with something - * other than the open brace. indulge them, if so. - */ + // they may want closing braces to line up with something + // other than the open brace. indulge them, if so. amount += curbuf->b_ind_close_extra; } else { - /* - * If we're looking at an "else", try to find an "if" - * to match it with. - * If we're looking at a "while", try to find a "do" - * to match it with. - */ + // If we're looking at an "else", try to find an "if" + // to match it with. + // If we're looking at a "while", try to find a "do" + // to match it with. lookfor = LOOKFOR_INITIAL; if (cin_iselse(theline)) { lookfor = LOOKFOR_IF; @@ -2524,18 +2430,14 @@ int get_c_indent(void) } } - /* - * We get here if we are not on an "while-of-do" or "else" (or - * failed to find a matching "if"). - * Search backwards for something to line up with. - * First set amount for when we don't find anything. - */ + // We get here if we are not on an "while-of-do" or "else" (or + // failed to find a matching "if"). + // Search backwards for something to line up with. + // First set amount for when we don't find anything. - /* - * if the '{' is _really_ at the left margin, use the imaginary - * location of a left-margin brace. Otherwise, correct the - * location for b_ind_open_extra. - */ + // if the '{' is _really_ at the left margin, use the imaginary + // location of a left-margin brace. Otherwise, correct the + // location for b_ind_open_extra. if (start_brace == BRACE_IN_COL0) { // '{' is in column 0 amount = curbuf->b_ind_open_left_imag; @@ -2547,7 +2449,7 @@ int get_c_indent(void) if (start_brace == BRACE_AT_END) { // '{' is at end of line amount += curbuf->b_ind_open_imag; - l = (char_u *)skipwhite((char *)get_cursor_line_ptr()); + l = (char_u *)skipwhite(get_cursor_line_ptr()); if (cin_is_cpp_namespace(l)) { amount += curbuf->b_ind_cpp_namespace; } else if (cin_is_cpp_extern_c(l)) { @@ -2562,7 +2464,7 @@ int get_c_indent(void) } } - lookfor_break = FALSE; + lookfor_break = false; if (cin_iscase(theline, false)) { // it's a switch() label lookfor = LOOKFOR_CASE; // find a previous switch() label @@ -2594,10 +2496,8 @@ int get_c_indent(void) curwin->w_cursor.lnum--; curwin->w_cursor.col = 0; - /* - * If we went all the way back to the start of our scope, line - * up with it. - */ + // If we went all the way back to the start of our scope, line + // up with it. if (curwin->w_cursor.lnum <= ourscope) { // We reached end of scope: // If looking for a enum or structure initialization @@ -2611,9 +2511,9 @@ int get_c_indent(void) if (curwin->w_cursor.lnum == 0 || curwin->w_cursor.lnum < ourscope - curbuf->b_ind_maxparen) { - /* nothing found (abuse curbuf->b_ind_maxparen as - * limit) assume terminated line (i.e. a variable - * initialization) */ + // nothing found (abuse curbuf->b_ind_maxparen as + // limit) assume terminated line (i.e. a variable + // initialization) if (cont_amount > 0) { amount = cont_amount; } else if (!curbuf->b_ind_js) { @@ -2622,12 +2522,10 @@ int get_c_indent(void) break; } - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); - /* - * If we're in a comment or raw string now, skip to - * the start of it. - */ + // If we're in a comment or raw string now, skip to + // the start of it. trypos = ind_find_start_CORS(NULL); if (trypos != NULL) { curwin->w_cursor.lnum = trypos->lnum + 1; @@ -2646,29 +2544,25 @@ int get_c_indent(void) continue; } - terminated = cin_isterminated(l, FALSE, TRUE); + terminated = cin_isterminated(l, false, true); - /* - * If we are at top level and the line looks like a - * function declaration, we are done - * (it's a variable declaration). - */ + // If we are at top level and the line looks like a + // function declaration, we are done + // (it's a variable declaration). if (start_brace != BRACE_IN_COL0 || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) { - /* if the line is terminated with another ',' - * it is a continued variable initialization. - * don't add extra indent. - * TODO: does not work, if a function - * declaration is split over multiple lines: - * cin_isfuncdecl returns FALSE then. - */ + // if the line is terminated with another ',' + // it is a continued variable initialization. + // don't add extra indent. + // TODO(vim): does not work, if a function + // declaration is split over multiple lines: + // cin_isfuncdecl returns false then. if (terminated == ',') { break; } - /* if it is an enum declaration or an assignment, - * we are done. - */ + // if it is an enum declaration or an assignment, + // we are done. if (terminated != ';' && cin_isinit()) { break; } @@ -2700,11 +2594,10 @@ int get_c_indent(void) } } - /* it's a variable declaration, add indentation - * like in - * int a, - * b; - */ + // it's a variable declaration, add indentation + // like in + // int a, + // b; if (cont_amount > 0) { amount = cont_amount; } else { @@ -2728,10 +2621,8 @@ int get_c_indent(void) } if (lookfor_cpp_namespace) { - /* - * Looking for C++ namespace, need to look further - * back. - */ + // Looking for C++ namespace, need to look further + // back. if (curwin->w_cursor.lnum == ourscope) { continue; } @@ -2742,10 +2633,10 @@ int get_c_indent(void) break; } - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); - /* If we're in a comment or raw string now, skip - * to the start of it. */ + // If we're in a comment or raw string now, skip + // to the start of it. trypos = ind_find_start_CORS(NULL); if (trypos != NULL) { curwin->w_cursor.lnum = trypos->lnum + 1; @@ -2785,22 +2676,20 @@ int get_c_indent(void) continue; } - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); - /* - * If this is a switch() label, may line up relative to that. - * If this is a C++ scope declaration, do the same. - */ + // If this is a switch() label, may line up relative to that. + // If this is a C++ scope declaration, do the same. bool iscase = cin_iscase(l, false); if (iscase || cin_isscopedecl(l)) { - /* we are only looking for cpp base class - * declaration/initialization any longer */ + // we are only looking for cpp base class + // declaration/initialization any longer if (lookfor == LOOKFOR_CPP_BASECLASS) { break; } - /* When looking for a "do" we are not interested in - * labels. */ + // When looking for a "do" we are not interested in + // labels. if (whilelevel > 0) { continue; } @@ -2861,8 +2750,8 @@ int get_c_indent(void) // -> y = y + 1; if (n) { amount = n; - l = after_label(get_cursor_line_ptr()); - if (l != NULL && cin_is_cinword(l)) { + l = after_label((char_u *)get_cursor_line_ptr()); + if (l != NULL && cin_is_cinword((char *)l)) { if (theline[0] == '{') { amount += curbuf->b_ind_open_extra; } else { @@ -2873,14 +2762,12 @@ int get_c_indent(void) break; } - /* - * Try to get the indent of a statement before the switch - * label. If nothing is found, line up relative to the - * switch label. - * break; <- may line up with this line - * case xx: - * -> y = 1; - */ + // Try to get the indent of a statement before the switch + // label. If nothing is found, line up relative to the + // switch label. + // break; <- may line up with this line + // case xx: + // -> y = 1; scope_amount = get_indent() + (iscase // XXX ? curbuf->b_ind_case_code : curbuf->b_ind_scopedecl_code); @@ -2889,10 +2776,8 @@ int get_c_indent(void) continue; } - /* - * Looking for a switch() label or C++ scope declaration, - * ignore other lines, skip {}-blocks. - */ + // Looking for a switch() label or C++ scope declaration, + // ignore other lines, skip {}-blocks. if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL) { if (find_last_paren(l, '{', '}') && (trypos = find_start_brace()) != NULL) { @@ -2902,23 +2787,19 @@ int get_c_indent(void) continue; } - /* - * Ignore jump labels with nothing after them. - */ + // Ignore jump labels with nothing after them. if (!curbuf->b_ind_js && cin_islabel()) { - l = after_label(get_cursor_line_ptr()); + l = after_label((char_u *)get_cursor_line_ptr()); if (l == NULL || cin_nocode(l)) { continue; } } - /* - * Ignore #defines, #if, etc. - * Ignore comment and empty lines. - * (need to get the line again, cin_islabel() may have - * unlocked it) - */ - l = get_cursor_line_ptr(); + // Ignore #defines, #if, etc. + // Ignore comment and empty lines. + // (need to get the line again, cin_islabel() may have + // unlocked it) + l = (char_u *)get_cursor_line_ptr(); if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount) || cin_nocode(l)) { continue; @@ -2930,7 +2811,7 @@ int get_c_indent(void) n = 0; if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) { n = cin_is_cpp_baseclass(&cache_cpp_baseclass); - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); } if (n) { if (lookfor == LOOKFOR_UNTERM) { @@ -2950,9 +2831,8 @@ int get_c_indent(void) } break; } else if (lookfor == LOOKFOR_CPP_BASECLASS) { - /* only look, whether there is a cpp base class - * declaration or initialization before the opening brace. - */ + // only look, whether there is a cpp base class + // declaration or initialization before the opening brace. if (cin_isterminated(l, true, false)) { break; } else { @@ -2960,18 +2840,16 @@ int get_c_indent(void) } } - /* - * What happens next depends on the line being terminated. - * If terminated with a ',' only consider it terminating if - * there is another unterminated statement behind, eg: - * 123, - * sizeof - * here - * Otherwise check whether it is an enumeration or structure - * initialisation (not indented) or a variable declaration - * (indented). - */ - terminated = cin_isterminated(l, FALSE, TRUE); + // What happens next depends on the line being terminated. + // If terminated with a ',' only consider it terminating if + // there is another unterminated statement behind, eg: + // 123, + // sizeof + // here + // Otherwise check whether it is an enumeration or structure + // initialisation (not indented) or a variable declaration + // (indented). + terminated = cin_isterminated(l, false, true); if (js_cur_has_key) { js_cur_has_key = false; // only check the first line @@ -3040,14 +2918,12 @@ int get_c_indent(void) } if (trypos != NULL) { - /* - * Check if we are on a case label now. This is - * handled above. - * case xx: if ( asdf && - * asdf) - */ + // Check if we are on a case label now. This is + // handled above. + // case xx: if ( asdf && + // asdf) curwin->w_cursor = *trypos; - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); if (cin_iscase(l, false) || cin_isscopedecl(l)) { curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; @@ -3055,16 +2931,14 @@ int get_c_indent(void) } } - /* - * Skip over continuation lines to find the one to get the - * indent from - * char *usethis = "bla\ - * bla", - * here; - */ + // Skip over continuation lines to find the one to get the + // indent from + // char *usethis = "bla{backslash} + // bla", + // here; if (terminated == ',') { while (curwin->w_cursor.lnum > 1) { - l = ml_get(curwin->w_cursor.lnum - 1); + l = (char_u *)ml_get(curwin->w_cursor.lnum - 1); if (*l == NUL || l[STRLEN(l) - 1] != '\\') { break; } @@ -3073,50 +2947,42 @@ int get_c_indent(void) } } - /* - * Get indent and pointer to text for current line, - * ignoring any jump label. XXX - */ + // Get indent and pointer to text for current line, + // ignoring any jump label. XXX if (curbuf->b_ind_js) { cur_amount = get_indent(); } else { cur_amount = skip_label(curwin->w_cursor.lnum, &l); } - /* - * If this is just above the line we are indenting, and it - * starts with a '{', line it up with this line. - * while (not) - * -> { - * } - */ + // If this is just above the line we are indenting, and it + // starts with a '{', line it up with this line. + // while (not) + // -> { + // } if (terminated != ',' && lookfor != LOOKFOR_TERM && theline[0] == '{') { amount = cur_amount; - /* - * Only add b_ind_open_extra when the current line - * doesn't start with a '{', which must have a match - * in the same line (scope is the same). Probably: - * { 1, 2 }, - * -> { 3, 4 } - */ + // Only add b_ind_open_extra when the current line + // doesn't start with a '{', which must have a match + // in the same line (scope is the same). Probably: + // { 1, 2 }, + // -> { 3, 4 } if (*skipwhite((char *)l) != '{') { amount += curbuf->b_ind_open_extra; } if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js) { - /* have to look back, whether it is a cpp base - * class declaration or initialization */ + // have to look back, whether it is a cpp base + // class declaration or initialization lookfor = LOOKFOR_CPP_BASECLASS; continue; } break; } - /* - * Check if we are after an "if", "while", etc. - * Also allow " } else". - */ - if (cin_is_cinword(l) || cin_iselse((char_u *)skipwhite((char *)l))) { + // Check if we are after an "if", "while", etc. + // Also allow " } else". + if (cin_is_cinword((char *)l) || cin_iselse((char_u *)skipwhite((char *)l))) { // Found an unterminated line after an if (), line up // with the last one. // if (cond) @@ -3132,19 +2998,17 @@ int get_c_indent(void) break; } - /* - * If this is just above the line we are indenting, we - * are finished. - * while (not) - * -> here; - * Otherwise this indent can be used when the line - * before this is terminated. - * yyy; - * if (stat) - * while (not) - * xxx; - * -> here; - */ + // If this is just above the line we are indenting, we + // are finished. + // while (not) + // -> here; + // Otherwise this indent can be used when the line + // before this is terminated. + // yyy; + // if (stat) + // while (not) + // xxx; + // -> here; amount = cur_amount; if (theline[0] == '{') { amount += curbuf->b_ind_open_extra; @@ -3155,14 +3019,12 @@ int get_c_indent(void) break; } - /* - * Special trick: when expecting the while () after a - * do, line up with the while() - * do - * x = 1; - * -> here - */ - l = (char_u *)skipwhite((char *)get_cursor_line_ptr()); + // Special trick: when expecting the while () after a + // do, line up with the while() + // do + // x = 1; + // -> here + l = (char_u *)skipwhite(get_cursor_line_ptr()); if (cin_isdo(l)) { if (whilelevel == 0) { break; @@ -3170,19 +3032,17 @@ int get_c_indent(void) whilelevel--; } - /* - * When searching for a terminated line, don't use the - * one between the "if" and the matching "else". - * Need to use the scope of this "else". XXX - * If whilelevel != 0 continue looking for a "do {". - */ + // When searching for a terminated line, don't use the + // one between the "if" and the matching "else". + // Need to use the scope of this "else". XXX + // If whilelevel != 0 continue looking for a "do {". if (cin_iselse(l) && whilelevel == 0) { - /* If we're looking at "} else", let's make sure we - * find the opening brace of the enclosing scope, - * not the one from "if () {". */ + // If we're looking at "} else", let's make sure we + // find the opening brace of the enclosing scope, + // not the one from "if () {". if (*l == '}') { curwin->w_cursor.col = - (colnr_T)(l - get_cursor_line_ptr()) + 1; + (colnr_T)(l - (char_u *)get_cursor_line_ptr()) + 1; } if ((trypos = find_start_brace()) == NULL @@ -3191,21 +3051,17 @@ int get_c_indent(void) break; } } - } - /* - * If we're below an unterminated line that is not an - * "if" or something, we may line up with this line or - * add something for a continuation line, depending on - * the line before this one. - */ - else { - /* - * Found two unterminated lines on a row, line up with - * the last one. - * c = 99 + - * 100 + - * -> here; - */ + } else { + // If we're below an unterminated line that is not an + // "if" or something, we may line up with this line or + // add something for a continuation line, depending on + // the line before this one. + + // Found two unterminated lines on a row, line up with + // the last one. + // c = 99 + + // 100 + + // -> here; if (lookfor == LOOKFOR_UNTERM) { // When line ends in a comma add extra indent if (terminated == ',') { @@ -3215,11 +3071,11 @@ int get_c_indent(void) } if (lookfor == LOOKFOR_ENUM_OR_INIT) { - /* Found two lines ending in ',', lineup with the - * lowest one, but check for cpp base class - * declaration/initialization, if it is an - * opening brace or we are looking just for - * enumerations/initializations. */ + // Found two lines ending in ',', lineup with the + // lowest one, but check for cpp base class + // declaration/initialization, if it is an + // opening brace or we are looking just for + // enumerations/initializations. if (terminated == ',') { if (curbuf->b_ind_cpp_baseclass == 0) { break; @@ -3239,7 +3095,7 @@ int get_c_indent(void) // line up with this line, remember its indent // 100 + // NOLINT(whitespace/tab) // -> here; // NOLINT(whitespace/tab) - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); amount = cur_amount; n = (int)STRLEN(l); @@ -3304,19 +3160,14 @@ int get_c_indent(void) } } } - } - /* - * Check if we are after a while (cond); - * If so: Ignore until the matching "do". - */ - else if (cin_iswhileofdo_end(terminated)) { // XXX - /* - * Found an unterminated line after a while ();, line up - * with the last one. - * while (cond); - * 100 + <- line up with this one - * -> here; - */ + // Check if we are after a while (cond); + // If so: Ignore until the matching "do". + } else if (cin_iswhileofdo_end(terminated)) { // XXX + // Found an unterminated line after a while ();, line up + // with the last one. + // while (cond); + // 100 + <- line up with this one + // -> here; if (lookfor == LOOKFOR_UNTERM || lookfor == LOOKFOR_ENUM_OR_INIT) { if (cont_amount > 0) { @@ -3335,30 +3186,24 @@ int get_c_indent(void) } } whilelevel++; - } - /* - * We are after a "normal" statement. - * If we had another statement we can stop now and use the - * indent of that other statement. - * Otherwise the indent of the current statement may be used, - * search backwards for the next "normal" statement. - */ - else { - /* - * Skip single break line, if before a switch label. It - * may be lined up with the case label. - */ + } else { + // We are after a "normal" statement. + // If we had another statement we can stop now and use the + // indent of that other statement. + // Otherwise the indent of the current statement may be used, + // search backwards for the next "normal" statement. + + // Skip single break line, if before a switch label. It + // may be lined up with the case label. if (lookfor == LOOKFOR_NOBREAK - && cin_isbreak((char_u *)skipwhite((char *)get_cursor_line_ptr()))) { + && cin_isbreak((char_u *)skipwhite(get_cursor_line_ptr()))) { lookfor = LOOKFOR_ANY; continue; } - /* - * Handle "do {" line. - */ + // Handle "do {" line. if (whilelevel > 0) { - l = cin_skipcomment(get_cursor_line_ptr()); + l = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (cin_isdo(l)) { amount = get_indent(); // XXX whilelevel--; @@ -3366,17 +3211,15 @@ int get_c_indent(void) } } - /* - * Found a terminated line above an unterminated line. Add - * the amount for a continuation line. - * x = 1; - * y = foo + - * -> here; - * or - * int x = 1; - * int foo, - * -> here; - */ + // Found a terminated line above an unterminated line. Add + // the amount for a continuation line. + // x = 1; + // y = foo + + // -> here; + // or + // int x = 1; + // int foo, + // -> here; if (lookfor == LOOKFOR_UNTERM || lookfor == LOOKFOR_ENUM_OR_INIT) { if (cont_amount > 0) { @@ -3387,36 +3230,30 @@ int get_c_indent(void) break; } - /* - * Found a terminated line above a terminated line or "if" - * etc. line. Use the amount of the line below us. - * x = 1; x = 1; - * if (asdf) y = 2; - * while (asdf) ->here; - * here; - * ->foo; - */ + // Found a terminated line above a terminated line or "if" + // etc. line. Use the amount of the line below us. + // x = 1; x = 1; + // if (asdf) y = 2; + // while (asdf) ->here; + // here; + // ->foo; if (lookfor == LOOKFOR_TERM) { if (!lookfor_break && whilelevel == 0) { break; } - } - /* - * First line above the one we're indenting is terminated. - * To know what needs to be done look further backward for - * a terminated line. - */ - else { - /* - * position the cursor over the rightmost paren, so - * that matching it will take us back to the start of - * the line. Helps for: - * func(asdr, - * asdfasdf); - * here; - */ + } else { + // First line above the one we're indenting is terminated. + // To know what needs to be done look further backward for + // a terminated line. + + // position the cursor over the rightmost paren, so + // that matching it will take us back to the start of + // the line. Helps for: + // func(asdr, + // asdfasdf); + // here; term_again: - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); if (find_last_paren(l, '(', ')') && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) { // Check if we are on a case label now. This is @@ -3424,7 +3261,7 @@ term_again: // case xx: if ( asdf && // asdf) curwin->w_cursor = *trypos; - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); if (cin_iscase(l, false) || cin_isscopedecl(l)) { curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; @@ -3432,21 +3269,18 @@ term_again: } } - /* When aligning with the case statement, don't align - * with a statement after it. - * case 1: { <-- don't use this { position - * stat; - * } - * case 2: - * stat; - * } - */ + // When aligning with the case statement, don't align + // with a statement after it. + // case 1: { <-- don't use this { position + // stat; + // } + // case 2: + // stat; + // } iscase = curbuf->b_ind_keep_case_label && cin_iscase(l, false); - /* - * Get indent and pointer to text for current line, - * ignoring any jump label. - */ + // Get indent and pointer to text for current line, + // ignoring any jump label. amount = skip_label(curwin->w_cursor.lnum, &l); if (theline[0] == '{') { @@ -3459,14 +3293,12 @@ term_again: } lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM; - /* - * When a terminated line starts with "else" skip to - * the matching "if": - * else 3; - * indent this; - * Need to use the scope of this "else". XXX - * If whilelevel != 0 continue looking for a "do {". - */ + // When a terminated line starts with "else" skip to + // the matching "if": + // else 3; + // indent this; + // Need to use the scope of this "else". XXX + // If whilelevel != 0 continue looking for a "do {". if (lookfor == LOOKFOR_TERM && *l != '}' && cin_iselse(l) @@ -3479,17 +3311,15 @@ term_again: continue; } - /* - * If we're at the end of a block, skip to the start of - * that block. - */ - l = get_cursor_line_ptr(); + // If we're at the end of a block, skip to the start of + // that block. + l = (char_u *)get_cursor_line_ptr(); if (find_last_paren(l, '{', '}') // XXX && (trypos = find_start_brace()) != NULL) { curwin->w_cursor = *trypos; // if not "else {" check for terminated again // but skip block for "} else {" - l = cin_skipcomment(get_cursor_line_ptr()); + l = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (*l == '}' || !cin_iselse(l)) { goto term_again; } @@ -3529,13 +3359,11 @@ term_again: amount = curbuf->b_ind_first_open; goto theend; } - /* - * If the NEXT line is a function declaration, the current - * line needs to be indented as a function type spec. - * Don't do this if the current line looks like a comment or if the - * current line is terminated, ie. ends in ';', or if the current line - * contains { or }: "void f() {\n if (1)" - */ + // If the NEXT line is a function declaration, the current + // line needs to be indented as a function type spec. + // Don't do this if the current line looks like a comment or if the + // current line is terminated, ie. ends in ';', or if the current line + // contains { or }: "void f() {\n if (1)" if (cur_curpos.lnum < curbuf->b_ml.ml_line_count && !cin_nocode(theline) && vim_strchr((char *)theline, '{') == NULL @@ -3555,7 +3383,7 @@ term_again: curwin->w_cursor.lnum--; curwin->w_cursor.col = 0; - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); // If we're in a comment or raw string now, skip to the start // of it. @@ -3571,7 +3399,7 @@ term_again: n = 0; if (curbuf->b_ind_cpp_baseclass != 0) { n = cin_is_cpp_baseclass(&cache_cpp_baseclass); - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); } if (n) { // XXX @@ -3590,18 +3418,16 @@ term_again: continue; } - /* - * If the previous line ends in ',', use one level of - * indentation: - * int foo, - * bar; - * do this before checking for '}' in case of eg. - * enum foobar - * { - * ... - * } foo, - * bar; - */ + // If the previous line ends in ',', use one level of + // indentation: + // int foo, + // bar; + // do this before checking for '}' in case of eg. + // enum foobar + // { + // ... + // } foo, + // bar; if (cin_ends_in(l, (char_u *)",", NULL) || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) { // take us back to opening paren @@ -3610,14 +3436,13 @@ term_again: curwin->w_cursor = *trypos; } - /* For a line ending in ',' that is a continuation line go - * back to the first line with a backslash: - * char *foo = "bla\ - * bla", - * here; - */ + // For a line ending in ',' that is a continuation line go + // back to the first line with a backslash: + // char *foo = "bla{backslash} + // bla", + // here; while (n == 0 && curwin->w_cursor.lnum > 1) { - l = ml_get(curwin->w_cursor.lnum - 1); + l = (char_u *)ml_get(curwin->w_cursor.lnum - 1); if (*l == NUL || l[STRLEN(l) - 1] != '\\') { break; } @@ -3636,19 +3461,15 @@ term_again: break; } - /* - * If the line looks like a function declaration, and we're - * not in a comment, put it the left margin. - */ + // If the line looks like a function declaration, and we're + // not in a comment, put it the left margin. if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) { // XXX break; } - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); - /* - * Finding the closing '}' of a previous function. Put - * current line at the left margin. For when 'cino' has "fs". - */ + // Finding the closing '}' of a previous function. Put + // current line at the left margin. For when 'cino' has "fs". if (*skipwhite((char *)l) == '}') { break; } @@ -3671,16 +3492,14 @@ term_again: break; } - /* - * Find a line only has a semicolon that belongs to a previous - * line ending in '}', e.g. before an #endif. Don't increase - * indent then. - */ + // Find a line only has a semicolon that belongs to a previous + // line ending in '}', e.g. before an #endif. Don't increase + // indent then. if (*(look = (char_u *)skipwhite((char *)l)) == ';' && cin_nocode(look + 1)) { pos_T curpos_save = curwin->w_cursor; while (curwin->w_cursor.lnum > 1) { - look = ml_get(--curwin->w_cursor.lnum); + look = (char_u *)ml_get(--curwin->w_cursor.lnum); if (!(cin_nocode(look) || cin_ispreproc_cont(&look, &curwin->w_cursor.lnum, &amount))) { break; @@ -3694,39 +3513,33 @@ term_again: curwin->w_cursor = curpos_save; } - /* - * If the PREVIOUS line is a function declaration, the current - * line (and the ones that follow) needs to be indented as - * parameters. - */ + // If the PREVIOUS line is a function declaration, the current + // line (and the ones that follow) needs to be indented as + // parameters. if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) { amount = curbuf->b_ind_param; break; } - /* - * If the previous line ends in ';' and the line before the - * previous line ends in ',' or '\', ident to column zero: - * int foo, - * bar; - * indent_to_0 here; - */ + // If the previous line ends in ';' and the line before the + // previous line ends in ',' or '\', ident to column zero: + // int foo, + // bar; + // indent_to_0 here; if (cin_ends_in(l, (char_u *)";", NULL)) { - l = ml_get(curwin->w_cursor.lnum - 1); + l = (char_u *)ml_get(curwin->w_cursor.lnum - 1); if (cin_ends_in(l, (char_u *)",", NULL) || (*l != NUL && l[STRLEN(l) - 1] == '\\')) { break; } - l = get_cursor_line_ptr(); + l = (char_u *)get_cursor_line_ptr(); } - /* - * Doesn't look like anything interesting -- so just - * use the indent of this line. - * - * Position the cursor over the rightmost paren, so that - * matching it will take us back to the start of the line. - */ + // Doesn't look like anything interesting -- so just + // use the indent of this line. + // + // Position the cursor over the rightmost paren, so that + // matching it will take us back to the start of the line. (void)find_last_paren(l, '(', ')'); if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) { @@ -3747,7 +3560,7 @@ term_again: // char *foo = "asdf{backslash} // here"; if (cur_curpos.lnum > 1) { - l = ml_get(cur_curpos.lnum - 1); + l = (char_u *)ml_get(cur_curpos.lnum - 1); if (*l != NUL && l[STRLEN(l) - 1] == '\\') { cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1); if (cur_amount > 0) { @@ -3794,7 +3607,7 @@ static int find_match(int lookfor, linenr_T ourscope) curwin->w_cursor.lnum--; curwin->w_cursor.col = 0; - look = cin_skipcomment(get_cursor_line_ptr()); + look = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (!cin_iselse(look) && !cin_isif(look) && !cin_isdo(look) // XXX @@ -3802,39 +3615,31 @@ static int find_match(int lookfor, linenr_T ourscope) continue; } - /* - * if we've gone outside the braces entirely, - * we must be out of scope... - */ + // if we've gone outside the braces entirely, + // we must be out of scope... theirscope = find_start_brace(); // XXX if (theirscope == NULL) { break; } - /* - * and if the brace enclosing this is further - * back than the one enclosing the else, we're - * out of luck too. - */ + // and if the brace enclosing this is further + // back than the one enclosing the else, we're + // out of luck too. if (theirscope->lnum < ourscope) { break; } - /* - * and if they're enclosed in a *deeper* brace, - * then we can ignore it because it's in a - * different scope... - */ + // and if they're enclosed in a *deeper* brace, + // then we can ignore it because it's in a + // different scope... if (theirscope->lnum > ourscope) { continue; } - /* - * if it was an "else" (that's not an "else if") - * then we need to go back to another if, so - * increment elselevel - */ - look = cin_skipcomment(get_cursor_line_ptr()); + // if it was an "else" (that's not an "else if") + // then we need to go back to another if, so + // increment elselevel + look = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (cin_iselse(look)) { mightbeif = cin_skipcomment(look + 4); if (!cin_isif(mightbeif)) { @@ -3843,23 +3648,19 @@ static int find_match(int lookfor, linenr_T ourscope) continue; } - /* - * if it was a "while" then we need to go back to - * another "do", so increment whilelevel. XXX - */ + // if it was a "while" then we need to go back to + // another "do", so increment whilelevel. XXX if (cin_iswhileofdo(look, curwin->w_cursor.lnum)) { whilelevel++; continue; } // If it's an "if" decrement elselevel - look = cin_skipcomment(get_cursor_line_ptr()); + look = cin_skipcomment((char_u *)get_cursor_line_ptr()); if (cin_isif(look)) { - elselevel--; - /* - * When looking for an "if" ignore "while"s that - * get in the way. - */ + elselevel--; // NOLINT(readability/braces) + // When looking for an "if" ignore "while"s that + // get in the way. if (elselevel == 0 && lookfor == LOOKFOR_IF) { whilelevel = 0; } @@ -3870,11 +3671,9 @@ static int find_match(int lookfor, linenr_T ourscope) whilelevel--; } - /* - * if we've used up all the elses, then - * this must be the if that we want! - * match the indent level of that if. - */ + // if we've used up all the elses, then + // this must be the if that we want! + // match the indent level of that if. if (elselevel <= 0 && whilelevel <= 0) { return OK; } @@ -3882,9 +3681,7 @@ static int find_match(int lookfor, linenr_T ourscope) return FAIL; } -/* - * Do C or expression indenting on the current line. - */ +// Do C or expression indenting on the current line. void do_c_expr_indent(void) { if (*curbuf->b_p_inde != NUL) { diff --git a/src/nvim/input.c b/src/nvim/input.c index 37c2903cfd..681d9d5f9c 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -46,7 +46,7 @@ int ask_yesno(const char *const str, const bool direct) int r = ' '; while (r != 'y' && r != 'n') { - // Same highlighting as for wait_return. + // same highlighting as for wait_return() smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str); if (direct) { r = get_keystroke(NULL); @@ -83,7 +83,6 @@ int get_keystroke(MultiQueue *events) int len = 0; int n; int save_mapped_ctrl_c = mapped_ctrl_c; - int waited = 0; mapped_ctrl_c = 0; // mappings are not used here for (;;) { @@ -110,10 +109,8 @@ int get_keystroke(MultiQueue *events) // Replace zero and K_SPECIAL by a special key code. n = fix_input_buffer(buf + len, n); len += n; - waited = 0; - } else if (len > 0) { - waited++; // keep track of the waiting time } + if (n > 0) { // found a termcode: adjust length len = n; } diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 938189f343..da1063f699 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -43,6 +43,7 @@ #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/tag.h" +#include "nvim/textformat.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -131,15 +132,30 @@ 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 + char *cp_str; ///< matched text + char *(cp_text[CPT_COUNT]); ///< text for the menu typval_T cp_user_data; - char_u *cp_fname; ///< file containing the match, allocated when + char *cp_fname; ///< file containing the match, allocated when ///< cp_flags has CP_FREE_FNAME int cp_flags; ///< CP_ values int cp_number; ///< sequence number }; +/// state information used for getting the next set of insert completion +/// matches. +typedef struct { + char *e_cpt; ///< current entry in 'complete' + buf_T *ins_buf; ///< buffer being scanned + pos_T *cur_match_pos; ///< current match position + pos_T prev_match_pos; ///< previous match position + bool set_match_pos; ///< save first_match_pos/last_match_pos + pos_T first_match_pos; ///< first match position + pos_T last_match_pos; ///< last match position + bool found_all; ///< found all matches of a certain type. + char_u *dict; ///< dictionary file to search + int dict_f; ///< "dict" is an exact file name or not +} ins_compl_next_state_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "insexpand.c.generated.h" #endif @@ -162,6 +178,7 @@ static char e_compldel[] = N_("E840: Completion function deleted text"); // "compl_curr_match" points to the currently selected entry. // "compl_shown_match" is different from compl_curr_match during // ins_compl_get_exp(). +// "compl_old_match" points to previous "compl_curr_match". static compl_T *compl_first_match = NULL; static compl_T *compl_curr_match = NULL; @@ -174,7 +191,7 @@ 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 char *compl_leader = NULL; static bool compl_get_longest = false; ///< put longest common string in compl_leader @@ -182,6 +199,8 @@ static bool compl_no_insert = false; ///< false: select & insert ///< true: noinsert static bool compl_no_select = false; ///< false: select & insert ///< true: noselect +static bool compl_longest = false; ///< false: insert full match + ///< true: insert longest prefix /// Selected one of the matches. When false the match was edited or using the /// longest common string. @@ -203,19 +222,36 @@ 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 int compl_matches = 0; ///< number of completion matches 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; +/// Length in bytes of the text being completed (this is deleted to be replaced +/// by the match.) +static int compl_length = 0; 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 +static char *compl_orig_text = NULL; ///< text as it was before ///< completion started static int compl_cont_mode = 0; static expand_T compl_xp; +// List of flags for method of completion. +static int compl_cont_status = 0; + +#define CONT_ADDING 1 ///< "normal" or "adding" expansion +#define CONT_INTRPT (2 + 4) ///< a ^X interrupted the current expansion + ///< it's set only iff N_ADDS is set +#define CONT_N_ADDS 4 ///< next ^X<> will add-new or expand-current +#define CONT_S_IPOS 8 ///< next ^X<> will set initial_pos? + ///< if so, word-wise-expansion will set SOL +#define CONT_SOL 16 ///< pattern includes start of line, just for + ///< word-wise expansion, not set for ^X^L +#define CONT_LOCAL 32 ///< for ctrl_x_mode 0, ^X^P/^X^N do a local + ///< expansion, (eg use complete=.) + static bool compl_opt_refresh_always = false; static size_t spell_bad_len = 0; // length of located bad word @@ -234,7 +270,7 @@ void ins_ctrl_x(void) } // 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 = _(CTRL_X_MSG(ctrl_x_mode)); edit_submode_pre = NULL; showmode(); } else { @@ -359,9 +395,52 @@ bool ctrl_x_mode_not_defined_yet(void) return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET; } -/// Check that the "dict" or "tsr" option can be used. +/// @return true if currently in "normal" or "adding" insert completion matches state +bool compl_status_adding(void) +{ + return compl_cont_status & CONT_ADDING; +} + +/// @return true if the completion pattern includes start of line, just for +/// word-wise expansion. +bool compl_status_sol(void) +{ + return compl_cont_status & CONT_SOL; +} + +/// @return true if ^X^P/^X^N will do a local completion (i.e. use complete=.) +bool compl_status_local(void) +{ + return compl_cont_status & CONT_LOCAL; +} + +/// Clear the completion status flags +void compl_status_clear(void) +{ + compl_cont_status = 0; +} + +// @return true if completion is using the forward direction matches +static bool compl_dir_forward(void) +{ + return compl_direction == FORWARD; +} + +/// @return true if currently showing forward completion matches +static bool compl_shows_dir_forward(void) +{ + return compl_shows_dir == FORWARD; +} + +/// @return true if currently showing backward completion matches +static bool compl_shows_dir_backward(void) +{ + return compl_shows_dir == BACKWARD; +} + +/// Check that the 'dictionary' or 'thesaurus' option can be used. /// -/// @param dict_opt check "dict" when true, "tsr" when false. +/// @param dict_opt check 'dictionary' when true, 'thesaurus' when false. bool check_compl_option(bool dict_opt) { if (dict_opt @@ -445,6 +524,18 @@ bool vim_is_ctrl_x_key(int c) return false; } +/// @return true if "match" is the original text when the completion began. +static bool match_at_original_text(const compl_T *const match) +{ + return match->cp_flags & CP_ORIGINAL_TEXT; +} + +/// @return true if "match" is the first match in the completion list. +static bool is_first_match(const compl_T *const match) +{ + return match == compl_first_match; +} + /// 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. @@ -479,6 +570,106 @@ bool ins_compl_accept_char(int c) return vim_iswordc(c); } +/// Get the completed text by inferring the case of the originally typed text. +/// If the result is in allocated memory "tofree" is set to it. +static char_u *ins_compl_infercase_gettext(char_u *str, int char_len, int compl_char_len, + int min_len, char **tofree) +{ + bool has_lower = false; + bool was_letter = false; + + // Allocate wide character array for the completion and fill it. + int *const wca = xmalloc((size_t)char_len * sizeof(*wca)); + { + const char_u *p = str; + for (int i = 0; i < char_len; i++) { + wca[i] = mb_ptr2char_adv(&p); + } + } + + // Rule 1: Were any chars converted to lower? + { + const char_u *p = (char_u *)compl_orig_text; + for (int i = 0; i < min_len; i++) { + const int c = mb_ptr2char_adv(&p); + if (mb_islower(c)) { + has_lower = true; + if (mb_isupper(wca[i])) { + // Rule 1 is satisfied. + for (i = compl_char_len; i < char_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 = (char_u *)compl_orig_text; + for (int i = 0; i < min_len; i++) { + const int c = mb_ptr2char_adv(&p); + if (was_letter && mb_isupper(c) && mb_islower(wca[i])) { + // Rule 2 is satisfied. + for (i = compl_char_len; i < char_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 = (char_u *)compl_orig_text; + for (int i = 0; i < min_len; i++) { + const int 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. + garray_T gap; + char *p = (char *)IObuff; + int i = 0; + ga_init(&gap, 1, 500); + while (i < char_len) { + if (gap.ga_data != NULL) { + ga_grow(&gap, 10); + assert(gap.ga_data != NULL); // suppress clang "Dereference of NULL pointer" + p = (char *)gap.ga_data + gap.ga_len; + gap.ga_len += utf_char2bytes(wca[i++], p); + } else if ((p - (char *)IObuff) + 6 >= IOSIZE) { + // Multi-byte characters can occupy up to five bytes more than + // ASCII characters, and we also need one byte for NUL, so when + // getting to six bytes from the edge of IObuff switch to using a + // growarray. Add the character in the next round. + ga_grow(&gap, IOSIZE); + *p = NUL; + STRCPY(gap.ga_data, IObuff); + gap.ga_len = (int)strlen(IObuff); + } else { + p += utf_char2bytes(wca[i++], p); + } + } + xfree(wca); + + if (gap.ga_data != NULL) { + *tofree = gap.ga_data; + return gap.ga_data; + } + + *p = NUL; + return (char_u *)IObuff; +} + /// 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 @@ -490,13 +681,10 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, 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 char_len; // count multi-byte characters + int compl_char_len; int flags = 0; + char *tofree = NULL; if (p_ic && curbuf->b_p_inf && len > 0) { // Infer case of completed part. @@ -504,101 +692,28 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, // Find actual length of completion. { const char_u *p = str; - actual_len = 0; + char_len = 0; while (*p != NUL) { MB_PTR_ADV(p); - actual_len++; + char_len++; } } // Find actual length of original text. { - const char_u *p = compl_orig_text; - actual_compl_length = 0; + const char_u *p = (char_u *)compl_orig_text; + compl_char_len = 0; while (*p != NUL) { MB_PTR_ADV(p); - actual_compl_length++; + compl_char_len++; } } - // "actual_len" may be smaller than "actual_compl_length" when using + // "char_len" may be smaller than "compl_char_len" 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]); - } - } - } + int min_len = char_len < compl_char_len ? char_len : compl_char_len; - // 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; + str = ins_compl_infercase_gettext(str, char_len, compl_char_len, min_len, &tofree); } if (cont_s_ipos) { flags |= CP_CONT_S_IPOS; @@ -607,29 +722,37 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, flags |= CP_ICASE; } - return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false); + int res = ins_compl_add((char *)str, len, (char *)fname, NULL, false, NULL, dir, flags, false); + xfree(tofree); + return res; } /// 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] str text of the match to add +/// @param[in] len length of "str". If -1, then the length of "str" is computed. +/// @param[in] fname file name to associate with this match. May be NULL. +/// @param[in] cptext list of strings to use with this match (for abbr, menu, info +/// and kind). 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. +/// @param[in] user_data user supplied data (any vim type) for this match +/// @param[in] cdir match direction. If 0, use "compl_direction". +/// @param[in] flags_arg match flags (cp_flags) +/// @param[in] adup accept this match even if it is already present. +/// +/// If "cdir" is FORWARD, then the match is added after the current match. +/// Otherwise, it is added before the current match. /// /// @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) +static int ins_compl_add(char *const str, int len, char *const fname, char *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; @@ -654,21 +777,21 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, return FAIL; } if (len < 0) { - len = (int)STRLEN(str); + 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) + if (!match_at_original_text(match) && STRNCMP(match->cp_str, str, len) == 0 - && match->cp_str[len] == NUL) { + && ((int)strlen(match->cp_str) <= len || match->cp_str[len] == NUL)) { FREE_CPTEXT(cptext, cptext_allocated); return NOTDONE; } match = match->cp_next; - } while (match != NULL && match != compl_first_match); + } while (match != NULL && !is_first_match(match)); } // Remove any popup menu before changing the list of matches. @@ -681,7 +804,7 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, if (flags & CP_ORIGINAL_TEXT) { match->cp_number = 0; } - match->cp_str = vim_strnsave(str, (size_t)len); + match->cp_str = xstrnsave(str, (size_t)len); // match-fname is: // - compl_curr_match->cp_fname if it is a string equal to fname. @@ -690,10 +813,10 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, if (fname != NULL && compl_curr_match != NULL && compl_curr_match->cp_fname != NULL - && STRCMP(fname, compl_curr_match->cp_fname) == 0) { + && 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); + match->cp_fname = xstrdup(fname); flags |= CP_FREE_FNAME; } else { match->cp_fname = NULL; @@ -708,9 +831,7 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, continue; } if (*cptext[i] != NUL) { - match->cp_text[i] = (cptext_allocated - ? cptext[i] - : (char_u *)xstrdup((char *)cptext[i])); + match->cp_text[i] = (cptext_allocated ? cptext[i] : xstrdup(cptext[i])); } else if (cptext_allocated) { xfree(cptext[i]); } @@ -721,7 +842,8 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname, match->cp_user_data = *user_data; } - // Link the new match structure in the list of matches. + // Link the new match structure after (FORWARD) or before (BACKWARD) the + // current match in the list of matches . if (compl_first_match == NULL) { match->cp_next = match->cp_prev = NULL; } else if (dir == FORWARD) { @@ -776,7 +898,8 @@ static void ins_compl_longest_match(compl_T *match) if (compl_leader == NULL) { // First match, use it as a whole. - compl_leader = vim_strsave(match->cp_str); + compl_leader = xstrdup(match->cp_str); + had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(); ins_bytes(compl_leader + get_compl_len()); @@ -788,40 +911,42 @@ static void ins_compl_longest_match(compl_T *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); + return; + } - // When the match isn't there (to avoid matching itself) remove it - // again after redrawing. - if (!had_match) { - ins_compl_delete(); - } + // Reduce the text if this match differs from compl_leader. + p = (char_u *)compl_leader; + s = (char_u *)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); + } - compl_used_match = false; + 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. @@ -832,7 +957,7 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase) 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, + 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. @@ -846,20 +971,21 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase) /// 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) { + return 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; + // Find the end of the list. + compl_T *match = compl_first_match; + int count = 0; + // there's always an entry for the compl_orig_text, it doesn't count. + while (match->cp_next != NULL && !is_first_match(match->cp_next)) { + match = match->cp_next; + count++; } + match->cp_next = compl_first_match; + compl_first_match->cp_prev = match; + return count; } @@ -873,7 +999,7 @@ bool ins_compl_has_shown_match(void) 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; + && (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col; } /// Set variables that store noselect and noinsert behavior from the @@ -882,12 +1008,16 @@ void completeopt_was_set(void) { compl_no_insert = false; compl_no_select = false; - if (strstr((char *)p_cot, "noselect") != NULL) { + compl_longest = false; + if (strstr(p_cot, "noselect") != NULL) { compl_no_select = true; } - if (strstr((char *)p_cot, "noinsert") != NULL) { + if (strstr(p_cot, "noinsert") != NULL) { compl_no_insert = true; } + if (strstr(p_cot, "longest") != NULL) { + compl_longest = true; + } } /// "compl_match_array" points the currently displayed list of entries in the @@ -898,10 +1028,12 @@ 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); + if (compl_match_array == NULL) { + return; } + + pum_undisplay(false); + XFREE_CLEAR(compl_match_array); } /// Check if the popup menu should be displayed. @@ -909,7 +1041,7 @@ 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; + return vim_strchr(p_cot, 'm') != NULL; } /// Check that there are two or more matches to be shown in the popup menu. @@ -919,17 +1051,16 @@ static bool pum_enough_matches(void) { // 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; + compl_T *compl = compl_first_match; int i = 0; do { - if (comp == NULL - || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) { + if (compl == NULL || (!match_at_original_text(compl) && ++i == 2)) { break; } - comp = comp->cp_next; - } while (comp != compl_first_match); + compl = compl->cp_next; + } while (!is_first_match(compl)); - if (strstr((char *)p_cot, "menuone") != NULL) { + if (strstr(p_cot, "menuone") != NULL) { return i >= 1; } return i >= 2; @@ -953,6 +1084,8 @@ static dict_T *ins_compl_dict_alloc(compl_T *match) return dict; } +/// Trigger the CompleteChanged autocmd event. Invoked each time the Insert mode +/// completion menu is changed. static void trigger_complete_changed_event(int cur) { static bool recursive = false; @@ -981,141 +1114,151 @@ static void trigger_complete_changed_event(int cur) 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) +/// Build a popup menu to show the completion matches. +/// +/// @return the popup menu entry that should be selected, +/// -1 if nothing should be selected. +static int ins_compl_build_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; + // Need to build the popup menu list. + compl_match_arraysize = 0; + compl_T *compl = compl_first_match; - if (!pum_wanted() || !pum_enough_matches()) { - return; + // 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); } - // 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); + const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 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; + do { + if (!match_at_original_text(compl) + && (compl_leader == NULL + || ins_compl_equal(compl, (char_u *)compl_leader, (size_t)lead_len))) { + compl_match_arraysize++; } + compl = compl->cp_next; + } while (compl != NULL && !is_first_match(compl)); - 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; - } + if (compl_match_arraysize == 0) { + return -1; + } - 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; - } + assert(compl_match_arraysize >= 0); + compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T)); - 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]; + // If the current match is the original text don't find the first + // match after it, don't highlight anything. + bool shown_match_ok = match_at_original_text(compl_shown_match); + + compl_T *shown_compl = NULL; + bool did_find_shown_match = false; + int cur = -1; + int i = 0; + compl = compl_first_match; + do { + if (!match_at_original_text(compl) + && (compl_leader == NULL + || ins_compl_equal(compl, (char_u *)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 { - compl_match_array[i++].pum_extra = compl->cp_fname; + // Remember this displayed match for when the + // shown match is just below it. + shown_compl = compl; } + cur = i; } - if (compl == compl_shown_match) { - did_find_shown_match = true; + if (compl->cp_text[CPT_ABBR] != NULL) { + compl_match_array[i].pum_text = (char_u *)compl->cp_text[CPT_ABBR]; + } else { + compl_match_array[i].pum_text = (char_u *)compl->cp_str; + } + compl_match_array[i].pum_kind = (char_u *)compl->cp_text[CPT_KIND]; + compl_match_array[i].pum_info = (char_u *)compl->cp_text[CPT_INFO]; + if (compl->cp_text[CPT_MENU] != NULL) { + compl_match_array[i++].pum_extra = (char_u *)compl->cp_text[CPT_MENU]; + } else { + compl_match_array[i++].pum_extra = (char_u *)compl->cp_fname; + } + } - // 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 (compl == compl_shown_match) { + did_find_shown_match = 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; - } + // When the original text is the shown match don't set + // compl_shown_match. + if (match_at_original_text(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; + 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 && !is_first_match(compl)); + + if (!shown_match_ok) { // no displayed match at all + cur = -1; + } + + return cur; +} + +/// 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) +{ + 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(); + + int cur = -1; + bool array_changed = false; + + if (compl_match_array == NULL) { + array_changed = true; + // Need to build the popup menu list. + cur = ins_compl_build_pum(); } 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]) { + for (int i = 0; i < compl_match_arraysize; i++) { + if (compl_match_array[i].pum_text == (char_u *)compl_shown_match->cp_str + || compl_match_array[i].pum_text == (char_u *)compl_shown_match->cp_text[CPT_ABBR]) { cur = i; break; } } } + if (compl_match_array == NULL) { + return; + } + // 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; + const colnr_T 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); @@ -1129,8 +1272,8 @@ void ins_compl_show_pum(void) #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. +/// Add any identifiers that match the given pattern "pat" 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 @@ -1195,7 +1338,7 @@ static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, i // 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) { + if (!thesaurus && strcmp(buf, "spell") == 0) { count = -1; } else if (vim_strchr(buf, '`') != NULL || expand_wildcards(1, &buf, &count, &files, @@ -1212,7 +1355,7 @@ static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, i } else { ptr = pat; } - spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0); + spell_dump_compl((char *)ptr, regmatch.rm_ic, &dir, 0); } else if (count > 0) { // avoid warning for using "files" uninit ins_compl_files(count, files, thesaurus, flags, ®match, (char_u *)buf, &dir); @@ -1231,6 +1374,54 @@ theend: xfree(buf); } +/// Add all the words in the line "*buf_arg" from the thesaurus file "fname" +/// skipping the word at 'skip_word'. +/// +/// @return OK on success. +static int thesaurus_add_words_in_line(char *fname, char_u **buf_arg, int dir, char_u *skip_word) +{ + int status = OK; + + // Add the other matches on the line + char_u *ptr = *buf_arg; + 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; + } + char_u *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((const char *)ptr); + + if (l < 2 && !vim_iswordc(*ptr)) { + break; + } + ptr += l; + } + + // Add the word. Skip the regexp match. + if (wstart != skip_word) { + status = ins_compl_add_infercase(wstart, (int)(ptr - wstart), p_ic, + (char_u *)fname, dir, false); + if (status == FAIL) { + break; + } + } + } + + *buf_arg = ptr; + return status; +} + +/// Process "count" dictionary/thesaurus "files" and add the text matching +/// "regmatch". 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) @@ -1255,52 +1446,23 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r // Read dictionary file line by line. // Check each line for a match. - while (!got_int && !compl_interrupted - && !vim_fgets(buf, LSIZE, fp)) { + 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]; + ptr = (char_u *)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]), + add_r = ins_compl_add_infercase((char_u *)regmatch->startp[0], + (int)(ptr - (char_u *)regmatch->startp[0]), p_ic, (char_u *)files[i], *dir, false); if (thesaurus) { - char_u *wstart; - - // Add the other matches on the line + // For a thesaurus, add all the words in 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); - } - } + add_r = thesaurus_add_words_in_line(files[i], &ptr, *dir, + (char_u *)regmatch->startp[0]); } if (add_r == OK) { // if dir was BACKWARD then honor it just once @@ -1391,12 +1553,13 @@ static void ins_compl_free(void) } tv_clear(&match->cp_user_data); xfree(match); - } while (compl_curr_match != NULL && compl_curr_match != compl_first_match); + } while (compl_curr_match != NULL && !is_first_match(compl_curr_match)); compl_first_match = compl_curr_match = NULL; compl_shown_match = NULL; compl_old_match = NULL; } +/// Reset/clear the completion state. void ins_compl_clear(void) { compl_cont_status = 0; @@ -1450,14 +1613,20 @@ colnr_T ins_compl_col(void) return compl_col; } +/// Return the length in bytes of the text being completed +int ins_compl_len(void) +{ + return compl_length; +} + /// 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; + char *line = get_cursor_line_ptr(); + char *p = line + curwin->w_cursor.col; MB_PTR_BACK(line, p); ptrdiff_t p_off = p - line; @@ -1479,18 +1648,18 @@ int ins_compl_bs(void) ins_compl_restart(); } - // ins_compl_restart() calls update_screen(0) which may invalidate the pointer + // ins_compl_restart() calls update_screen() 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)); + compl_leader = xstrnsave(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; } @@ -1567,7 +1736,7 @@ void ins_compl_addleader(int c) utf_char2bytes(c, (char *)buf); buf[cc] = NUL; - ins_char_bytes((char_u *)buf, (size_t)cc); + ins_char_bytes(buf, (size_t)cc); } else { ins_char(c); } @@ -1578,8 +1747,8 @@ void ins_compl_addleader(int c) } xfree(compl_leader); - compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, - (size_t)(curwin->w_cursor.col - compl_col)); + compl_leader = xstrnsave(get_cursor_line_ptr() + compl_col, + (size_t)(curwin->w_cursor.col - compl_col)); ins_compl_new_leader(); } @@ -1590,7 +1759,7 @@ 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); + update_screen(); // TODO(bfredl): no. ins_compl_free(); compl_started = false; compl_matches = 0; @@ -1599,19 +1768,19 @@ static void ins_compl_restart(void) } /// Set the first match, the original text. -static void ins_compl_set_original_text(char_u *str) +static void ins_compl_set_original_text(char *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 + // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly + // be at the last item for backward completion + if (match_at_original_text(compl_first_match)) { // safety check xfree(compl_first_match->cp_str); - compl_first_match->cp_str = vim_strsave(str); + compl_first_match->cp_str = xstrdup(str); } else if (compl_first_match->cp_prev != NULL - && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) { + && match_at_original_text(compl_first_match->cp_prev)) { xfree(compl_first_match->cp_prev->cp_str); - compl_first_match->cp_prev->cp_str = vim_strsave(str); + compl_first_match->cp_prev->cp_str = xstrdup(str); } } @@ -1624,24 +1793,24 @@ void ins_compl_addfrommatch(void) int c; compl_T *cp; assert(compl_shown_match != NULL); - p = compl_shown_match->cp_str; + p = (char_u *)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; + if (!match_at_original_text(compl_shown_match)) { + return; + } + + p = NULL; + for (cp = compl_shown_match->cp_next; cp != NULL + && !is_first_match(cp); cp = cp->cp_next) { + if (compl_leader == NULL + || ins_compl_equal(cp, (char_u *)compl_leader, STRLEN(compl_leader))) { + p = (char_u *)cp->cp_str; + break; } - } else { + } + if (p == NULL || (int)STRLEN(p) <= len) { return; } } @@ -1650,6 +1819,249 @@ void ins_compl_addfrommatch(void) ins_compl_addleader(c); } +/// Set the CTRL-X completion mode based on the key "c" typed after a CTRL-X. +/// Uses the global variables: ctrl_x_mode, edit_submode, edit_submode_pre, +/// compl_cont_mode and compl_cont_status. +/// +/// @return true when the character is not to be inserted. +static bool set_ctrl_x_mode(const int c) +{ + bool retval = false; + + switch (c) { + case Ctrl_E: + case Ctrl_Y: + // scroll the window one line up or down + ctrl_x_mode = CTRL_X_SCROLL; + if (!(State & REPLACE_FLAG)) { + edit_submode = _(" (insert) Scroll (^E/^Y)"); + } else { + edit_submode = _(" (replace) Scroll (^E/^Y)"); + } + edit_submode_pre = NULL; + showmode(); + break; + case Ctrl_L: + // complete whole line + ctrl_x_mode = CTRL_X_WHOLE_LINE; + break; + case Ctrl_F: + // complete filenames + ctrl_x_mode = CTRL_X_FILES; + break; + case Ctrl_K: + // complete words from a dictionary + ctrl_x_mode = CTRL_X_DICTIONARY; + break; + case Ctrl_R: + // Register insertion without exiting CTRL-X mode + // Simply allow ^R to happen without affecting ^X mode + break; + case Ctrl_T: + // complete words from a thesaurus + ctrl_x_mode = CTRL_X_THESAURUS; + break; + case Ctrl_U: + // user defined completion + ctrl_x_mode = CTRL_X_FUNCTION; + break; + case Ctrl_O: + // omni completion + ctrl_x_mode = CTRL_X_OMNI; + break; + case 's': + case Ctrl_S: + // complete spelling suggestions + ctrl_x_mode = CTRL_X_SPELL; + emsg_off++; // Avoid getting the E756 error twice. + spell_back_to_badword(); + emsg_off--; + break; + case Ctrl_RSB: + // complete tag names + ctrl_x_mode = CTRL_X_TAGS; + break; + case Ctrl_I: + case K_S_TAB: + // complete keywords from included files + ctrl_x_mode = CTRL_X_PATH_PATTERNS; + break; + case Ctrl_D: + // complete definitions from included files + ctrl_x_mode = CTRL_X_PATH_DEFINES; + break; + case Ctrl_V: + case Ctrl_Q: + // complete vim commands + ctrl_x_mode = CTRL_X_CMDLINE; + break; + case Ctrl_Z: + // stop completion + 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; + } + + return retval; +} + +/// Stop insert completion mode +static bool ins_compl_stop(const int c, const int prev_mode, bool retval) +{ + // 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. + char_u *ptr; + if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) { + ptr = (char_u *)compl_curr_match->cp_str; + } else { + ptr = NULL; + } + ins_compl_fixRedoBufForLeader(ptr); + } + + bool want_cindent = (get_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 { + const int prev_col = curwin->w_cursor.col; + + // put the cursor on the last char, for 'tw' formatting + if (prev_col > 0) { + dec_cursor(); + } + + // only format when something was inserted + 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(); + char_u *p = NULL; + if (compl_leader != NULL) { + p = (char_u *)compl_leader; + } else if (compl_first_match != NULL) { + p = (char_u *)compl_orig_text; + } + if (p != NULL) { + const int compl_len = get_compl_len(); + const int len = (int)STRLEN(p); + if (len > compl_len) { + ins_bytes_len((char *)p + compl_len, (size_t)(len - 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(); + } + + if (c == Ctrl_C && cmdwin_type != 0) { + // Avoid the popup menu remains displayed when leaving the + // command line window. + update_screen(); + } + + // 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); + + return retval; +} + /// Prepare for Insert mode completion, or stop it. /// Called just after typing a character in Insert mode. /// @@ -1658,7 +2070,6 @@ void ins_compl_addfrommatch(void) /// @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; @@ -1698,111 +2109,14 @@ bool ins_compl_prep(int c) // 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_get_longest = compl_longest; 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; - } + retval = set_ctrl_x_mode(c); } 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)) { @@ -1827,107 +2141,7 @@ bool ins_compl_prep(int c) && 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); + retval = ins_compl_stop(c, prev_mode, retval); } } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) { // Trigger the CompleteDone event to give scripts a chance to act @@ -1958,16 +2172,16 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg) if (ptr == NULL) { if (compl_leader != NULL) { - ptr = compl_leader; + ptr = (char_u *)compl_leader; } else { return; // nothing to do } } if (compl_orig_text != NULL) { - p = compl_orig_text; + p = (char_u *)compl_orig_text; for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {} if (len > 0) { - len -= utf_head_off(p, p + len); + len -= utf_head_off((char *)p, (char *)p + len); } for (p += len; *p != NUL; MB_PTR_ADV(p)) { AppendCharToRedobuff(K_BS); @@ -2010,16 +2224,16 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag) return buf; } -/// Get the user-defined completion function name for completion 'type' +/// 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; + return (char_u *)curbuf->b_p_cfu; case CTRL_X_OMNI: - return curbuf->b_p_ofu; + return (char_u *)curbuf->b_p_ofu; case CTRL_X_THESAURUS: - return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu; + return *curbuf->b_p_tsrfu == NUL ? (char_u *)p_tsrfu : (char_u *)curbuf->b_p_tsrfu; default: return (char_u *)""; } @@ -2147,10 +2361,15 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) for (size_t i = 0; i < CPT_COUNT; i++) { xfree(cptext[i]); } + tv_clear(&user_data); return FAIL; } - return ins_compl_add((char_u *)word, -1, NULL, - (char_u **)cptext, true, &user_data, dir, flags, dup); + int status = ins_compl_add((char *)word, -1, NULL, cptext, true, + &user_data, dir, flags, dup); + if (status != OK) { + tv_clear(&user_data); + } + return status; } /// Add completions from a list. @@ -2207,6 +2426,7 @@ static void set_completion(colnr_T startcol, list_T *list) } ins_compl_clear(); ins_compl_free(); + compl_get_longest = compl_longest; compl_direction = FORWARD; if (startcol > curwin->w_cursor.col) { @@ -2215,8 +2435,8 @@ static void set_completion(colnr_T startcol, list_T *list) 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); + compl_orig_text = xstrnsave(get_cursor_line_ptr() + compl_col, + (size_t)compl_length); if (p_ic) { flags |= CP_ICASE; } @@ -2236,9 +2456,10 @@ static void set_completion(colnr_T startcol, list_T *list) int save_w_leftcol = curwin->w_leftcol; compl_curr_match = compl_first_match; - if (compl_no_insert || compl_no_select) { + bool no_select = compl_no_select || compl_longest; + if (compl_no_insert || no_select) { ins_complete(K_DOWN, false); - if (compl_no_select) { + if (no_select) { ins_complete(K_UP, false); } } else { @@ -2256,7 +2477,7 @@ static void set_completion(colnr_T startcol, list_T *list) } /// "complete()" function -void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_complete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if ((State & MODE_INSERT) == 0) { emsg(_("E785: complete() can only be used in Insert mode")); @@ -2280,13 +2501,13 @@ void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "complete_add()" function -void f_complete_add(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_complete_add(typval_T *argvars, typval_T *rettv, EvalFuncData 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) +void f_complete_check(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int saved = RedrawingDisabled; @@ -2305,18 +2526,19 @@ static char_u *ins_compl_mode(void) return (char_u *)""; } +/// Assign the sequence number to all the completion matches which don't have +/// one assigned yet. static void ins_compl_update_sequence_numbers(void) { int number = 0; compl_T *match; - if (compl_direction == FORWARD) { + if (compl_dir_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) { + match != NULL && !is_first_match(match); match = match->cp_prev) { if (match->cp_number != -1) { number = match->cp_number; break; @@ -2336,8 +2558,7 @@ static void ins_compl_update_sequence_numbers(void) // 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) { + match != NULL && !is_first_match(match); match = match->cp_next) { if (match->cp_number != -1) { number = match->cp_number; break; @@ -2375,15 +2596,15 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) ; item = TV_LIST_ITEM_NEXT(what_list, item)) { const char *what = tv_get_string(TV_LIST_ITEM_TV(item)); - if (STRCMP(what, "mode") == 0) { + if (strcmp(what, "mode") == 0) { what_flag |= CI_WHAT_MODE; - } else if (STRCMP(what, "pum_visible") == 0) { + } else if (strcmp(what, "pum_visible") == 0) { what_flag |= CI_WHAT_PUM_VISIBLE; - } else if (STRCMP(what, "items") == 0) { + } else if (strcmp(what, "items") == 0) { what_flag |= CI_WHAT_ITEMS; - } else if (STRCMP(what, "selected") == 0) { + } else if (strcmp(what, "selected") == 0) { what_flag |= CI_WHAT_SELECTED; - } else if (STRCMP(what, "inserted") == 0) { + } else if (strcmp(what, "inserted") == 0) { what_flag |= CI_WHAT_INSERTED; } } @@ -2406,7 +2627,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) if (ret == OK && compl_first_match != NULL) { compl_T *match = compl_first_match; do { - if (!(match->cp_flags & CP_ORIGINAL_TEXT)) { + if (!match_at_original_text(match)) { dict_T *di = tv_dict_alloc(); tv_list_append_dict(li, di); @@ -2422,7 +2643,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) } } match = match->cp_next; - } while (match != NULL && match != compl_first_match); + } while (match != NULL && !is_first_match(match)); } } @@ -2441,7 +2662,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) } /// "complete_info()" function -void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_complete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); @@ -2464,6 +2685,481 @@ static bool thesaurus_func_complete(int type) && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL); } +/// Return value of process_next_cpt_value() +enum { + INS_COMPL_CPT_OK = 1, + INS_COMPL_CPT_CONT, + INS_COMPL_CPT_END, +}; + +/// Process the next 'complete' option value in st->e_cpt. +/// +/// If successful, the arguments are set as below: +/// st->cpt - pointer to the next option value in "st->cpt" +/// compl_type_arg - type of insert mode completion to use +/// st->found_all - all matches of this type are found +/// st->ins_buf - search for completions in this buffer +/// st->first_match_pos - position of the first completion match +/// st->last_match_pos - position of the last completion match +/// st->set_match_pos - true if the first match position should be saved to +/// avoid loops after the search wraps around. +/// st->dict - name of the dictionary or thesaurus file to search +/// st->dict_f - flag specifying whether "dict" is an exact file name or not +/// +/// @return INS_COMPL_CPT_OK if the next value is processed successfully. +/// INS_COMPL_CPT_CONT to skip the current completion source matching +/// the "st->e_cpt" option value and process the next matching source. +/// INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed. +static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_arg, + pos_T *start_match_pos) +{ + int compl_type = -1; + int status = INS_COMPL_CPT_OK; + + st->found_all = false; + + while (*st->e_cpt == ',' || *st->e_cpt == ' ') { + st->e_cpt++; + } + + if (*st->e_cpt == '.' && !curbuf->b_scanned) { + st->ins_buf = curbuf; + st->first_match_pos = *start_match_pos; + // Move the cursor back one character so that ^N can match the + // word immediately after the cursor. + if (ctrl_x_mode_normal() && dec(&st->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. + st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count; + st->first_match_pos.col = (colnr_T)strlen(ml_get(st->first_match_pos.lnum)); + } + st->last_match_pos = st->first_match_pos; + compl_type = 0; + + // Remember the first match so that the loop stops when we + // wrap and come back there a second time. + st->set_match_pos = true; + } else if (vim_strchr("buwU", *st->e_cpt) != NULL + && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf) { + // Scan a buffer, but not the current one. + if (st->ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer + compl_started = true; + st->first_match_pos.col = st->last_match_pos.col = 0; + st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count + 1; + st->last_match_pos.lnum = 0; + compl_type = 0; + } else { // unloaded buffer, scan like dictionary + st->found_all = true; + if (st->ins_buf->b_fname == NULL) { + status = INS_COMPL_CPT_CONT; + goto done; + } + compl_type = CTRL_X_DICTIONARY; + st->dict = (char_u *)st->ins_buf->b_fname; + st->dict_f = DICT_EXACT; + } + msg_hist_off = true; // reset in msg_trunc_attr() + vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"), + st->ins_buf->b_fname == NULL + ? buf_spname(st->ins_buf) + : st->ins_buf->b_sfname == NULL + ? st->ins_buf->b_fname + : st->ins_buf->b_sfname); + (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R)); + } else if (*st->e_cpt == NUL) { + status = INS_COMPL_CPT_END; + } else { + if (ctrl_x_mode_line_or_eval()) { + compl_type = -1; + } else if (*st->e_cpt == 'k' || *st->e_cpt == 's') { + if (*st->e_cpt == 'k') { + compl_type = CTRL_X_DICTIONARY; + } else { + compl_type = CTRL_X_THESAURUS; + } + if (*++st->e_cpt != ',' && *st->e_cpt != NUL) { + st->dict = (char_u *)st->e_cpt; + st->dict_f = DICT_FIRST; + } + } else if (*st->e_cpt == 'i') { + compl_type = CTRL_X_PATH_PATTERNS; + } else if (*st->e_cpt == 'd') { + compl_type = CTRL_X_PATH_DEFINES; + } else if (*st->e_cpt == ']' || *st->e_cpt == 't') { + msg_hist_off = true; // reset in msg_trunc_attr() + compl_type = CTRL_X_TAGS; + vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags.")); + (void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R)); + } else { + compl_type = -1; + } + + // in any case e_cpt is advanced to the next entry + (void)copy_option_part(&st->e_cpt, (char *)IObuff, IOSIZE, ","); + + st->found_all = true; + if (compl_type == -1) { + status = INS_COMPL_CPT_CONT; + } + } + +done: + *compl_type_arg = compl_type; + return status; +} + +/// Get the next set of identifiers or defines matching "compl_pattern" in +/// included files. +static void get_next_include_file_completion(int compl_type) +{ + find_pattern_in_path((char_u *)compl_pattern, compl_direction, + strlen(compl_pattern), false, false, + ((compl_type == CTRL_X_PATH_DEFINES + && !(compl_cont_status & CONT_SOL)) + ? FIND_DEFINE : FIND_ANY), + 1L, ACTION_EXPAND, 1, MAXLNUM); +} + +/// Get the next set of words matching "compl_pattern" in dictionary or +/// thesaurus files. +static void get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f) +{ + if (thesaurus_func_complete(compl_type)) { + expand_by_function(compl_type, (char_u *)compl_pattern); + } else { + ins_compl_dictionaries(dict != NULL ? dict + : (compl_type == CTRL_X_THESAURUS + ? (*curbuf->b_p_tsr == NUL ? p_tsr : (char_u *)curbuf->b_p_tsr) + : (*curbuf->b_p_dict == + NUL ? (char_u *)p_dict : (char_u *)curbuf->b_p_dict)), + (char_u *)compl_pattern, + dict != NULL ? dict_f : 0, + compl_type == CTRL_X_THESAURUS); + } +} + +/// Get the next set of tag names matching "compl_pattern". +static void get_next_tag_completion(void) +{ + // set p_ic according to p_ic, p_scs and pat for find_tags(). + const int 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; + char **matches; + int num_matches; + if (find_tags(compl_pattern, &num_matches, &matches, + TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP + | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0), + TAG_MANY, 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; +} + +/// Get the next set of filename matching "compl_pattern". +static void get_next_filename_completion(void) +{ + char **matches; + int num_matches; + if (expand_wildcards(1, &compl_pattern, &num_matches, &matches, + EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) { + return; + } + + // 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); +} + +/// Get the next set of command-line completions matching "compl_pattern". +static void get_next_cmdline_completion(void) +{ + char **matches; + int num_matches; + 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); + } +} + +/// Get the next set of spell suggestions matching "compl_pattern". +static void get_next_spell_completion(linenr_T lnum) +{ + char **matches; + int num_matches = expand_spelling(lnum, (char_u *)compl_pattern, &matches); + if (num_matches > 0) { + ins_compl_add_matches(num_matches, matches, p_ic); + } else { + xfree(matches); + } +} + +/// Return the next word or line from buffer "ins_buf" at position +/// "cur_match_pos" for completion. The length of the match is set in "len". +/// @param ins_buf buffer being scanned +/// @param cur_match_pos current match position +/// @param match_len +/// @param cont_s_ipos next ^X<> will set initial_pos +static char_u *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len, + bool *cont_s_ipos) +{ + *match_len = 0; + char_u *ptr = (char_u *)ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col; + int len; + if (ctrl_x_mode_line_or_eval()) { + if (compl_status_adding()) { + if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) { + return NULL; + } + ptr = (char_u *)ml_get_buf(ins_buf, cur_match_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_status_adding() && compl_length <= (int)STRLEN(tmp_ptr)) { + tmp_ptr += compl_length; + // Skip if already inside a word. + if (vim_iswordp(tmp_ptr)) { + return NULL; + } + // 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_status_adding() && len == compl_length) { + if (cur_match_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 = (char_u *)ml_get_buf(ins_buf, cur_match_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 = (char_u *)IObuff; + } + if (len == compl_length) { + return NULL; + } + } + } + + *match_len = len; + return ptr; +} + +/// Get the next set of words matching "compl_pattern" for default completion(s) +/// (normal ^P/^N and ^X^L). +/// Search for "compl_pattern" in the buffer "st->ins_buf" starting from the +/// position "st->start_pos" in the "compl_direction" direction. If +/// "st->set_match_pos" is true, then set the "st->first_match_pos" and +/// "st->last_match_pos". +/// +/// @return OK if a new next match is found, otherwise FAIL. +static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos) +{ + // If 'infercase' is set, don't use 'smartcase' here + const int save_p_scs = p_scs; + assert(st->ins_buf); + if (st->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 + const int save_p_ws = p_ws; + if (st->ins_buf != curbuf) { + p_ws = false; + } else if (*st->e_cpt == '.') { + p_ws = true; + } + bool looped_around = false; + int found_new_match = FAIL; + 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(st->ins_buf, st->cur_match_pos, + compl_direction, (char_u *)compl_pattern); + } else { + found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, + NULL, compl_direction, (char_u *)compl_pattern, 1L, + SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); + } + msg_silent--; + if (!compl_started || st->set_match_pos) { + // set "compl_started" even on fail + compl_started = true; + st->first_match_pos = *st->cur_match_pos; + st->last_match_pos = *st->cur_match_pos; + st->set_match_pos = false; + } else if (st->first_match_pos.lnum == st->last_match_pos.lnum + && st->first_match_pos.col == st->last_match_pos.col) { + found_new_match = FAIL; + } else if (compl_dir_forward() + && (st->prev_match_pos.lnum > st->cur_match_pos->lnum + || (st->prev_match_pos.lnum == st->cur_match_pos->lnum + && st->prev_match_pos.col >= st->cur_match_pos->col))) { + if (looped_around) { + found_new_match = FAIL; + } else { + looped_around = true; + } + } else if (!compl_dir_forward() + && (st->prev_match_pos.lnum < st->cur_match_pos->lnum + || (st->prev_match_pos.lnum == st->cur_match_pos->lnum + && st->prev_match_pos.col <= st->cur_match_pos->col))) { + if (looped_around) { + found_new_match = FAIL; + } else { + looped_around = true; + } + } + st->prev_match_pos = *st->cur_match_pos; + if (found_new_match == FAIL) { + break; + } + + // when ADDING, the text before the cursor matches, skip it + if (compl_status_adding() && st->ins_buf == curbuf + && start_pos->lnum == st->cur_match_pos->lnum + && start_pos->col == st->cur_match_pos->col) { + continue; + } + int len; + char_u *ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos, + &len, &cont_s_ipos); + if (ptr == NULL) { + continue; + } + if (ins_compl_add_infercase(ptr, len, p_ic, + st->ins_buf == curbuf ? NULL : (char_u *)st->ins_buf->b_sfname, + 0, cont_s_ipos) != NOTDONE) { + found_new_match = OK; + break; + } + } + p_scs = save_p_scs; + p_ws = save_p_ws; + + return found_new_match; +} + +/// get the next set of completion matches for "type". +/// @return true if a new match is found, otherwise false. +static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini) +{ + int found_new_match = FAIL; + + switch (type) { + case -1: + break; + case CTRL_X_PATH_PATTERNS: + case CTRL_X_PATH_DEFINES: + get_next_include_file_completion(type); + break; + + case CTRL_X_DICTIONARY: + case CTRL_X_THESAURUS: + get_next_dict_tsr_completion(type, st->dict, st->dict_f); + st->dict = NULL; + break; + + case CTRL_X_TAGS: + get_next_tag_completion(); + break; + + case CTRL_X_FILES: + get_next_filename_completion(); + break; + + case CTRL_X_CMDLINE: + case CTRL_X_CMDLINE_CTRL_X: + get_next_cmdline_completion(); + break; + + case CTRL_X_FUNCTION: + case CTRL_X_OMNI: + expand_by_function(type, (char_u *)compl_pattern); + break; + + case CTRL_X_SPELL: + get_next_spell_completion(st->first_match_pos.lnum); + break; + + default: // normal ^P/^N and ^X^L + found_new_match = get_next_default_completion(st, ini); + if (found_new_match == FAIL && st->ins_buf == curbuf) { + st->found_all = true; + } + } + + // 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; + } + + return found_new_match; +} + /// Get the next expansion(s), using "compl_pattern". /// The search starts at position "ini" in curbuf and in the direction /// compl_direction. @@ -2473,28 +3169,10 @@ static bool thesaurus_func_complete(int type) /// 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 *e_cpt = ""; // 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; + static ins_compl_next_state_T st; 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); @@ -2502,111 +3180,34 @@ static int ins_compl_get_exp(pos_T *ini) FOR_ALL_BUFFERS(buf) { buf->b_scanned = false; } - found_all = false; - ins_buf = curbuf; - e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : (char *)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. + st.found_all = false; + st.ins_buf = curbuf; + st.e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt; + st.last_match_pos = st.first_match_pos = *ini; + } else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) { + st.ins_buf = curbuf; // In case the buffer was wiped out. } - assert(ins_buf != NULL); + assert(st.ins_buf != NULL); compl_old_match = compl_curr_match; // remember the last current match - pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos; + st.cur_match_pos = (compl_dir_forward() ? &st.last_match_pos : &st.first_match_pos); // For ^N/^P loop over all the flags/windows/buffers in 'complete' for (;;) { found_new_match = FAIL; - set_match_pos = false; + st.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) { + && (!compl_started || st.found_all)) { + int status = process_next_cpt_value(&st, &type, ini); + if (status == INS_COMPL_CPT_END) { 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 = (char_u *)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(&e_cpt, (char *)IObuff, IOSIZE, ","); - - found_all = true; - if (type == -1) { - continue; - } + } + if (status == INS_COMPL_CPT_CONT) { + continue; } } @@ -2616,271 +3217,12 @@ static int ins_compl_get_exp(pos_T *ini) 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; - } + // get the next set of completion matches + found_new_match = get_next_completion_match(type, &st, ini); // 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()) + if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval()) || found_new_match != FAIL) { if (got_int) { break; @@ -2890,8 +3232,7 @@ static int ins_compl_get_exp(pos_T *ini) ins_compl_check_keys(0, false); } - if ((ctrl_x_mode_not_default() - && !ctrl_x_mode_line_or_eval()) + if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval()) || compl_interrupted) { break; } @@ -2899,8 +3240,8 @@ static int ins_compl_get_exp(pos_T *ini) } 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; + assert(st.ins_buf); + st.ins_buf->b_scanned = true; } compl_started = false; @@ -2908,16 +3249,14 @@ static int ins_compl_get_exp(pos_T *ini) } compl_started = true; - if ((ctrl_x_mode_normal() - || ctrl_x_mode_line_or_eval()) - && *e_cpt == NUL) { // Got to end of 'complete' + if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval()) + && *st.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())) { + || (ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval())) { i = ins_compl_make_cyclic(); } @@ -2925,7 +3264,7 @@ static int ins_compl_get_exp(pos_T *ini) // 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_curr_match = compl_dir_forward() ? compl_old_match->cp_next : compl_old_match->cp_prev; if (compl_curr_match == NULL) { @@ -2937,6 +3276,31 @@ static int ins_compl_get_exp(pos_T *ini) return i; } +/// Update "compl_shown_match" to the actually shown match, it may differ when +/// "compl_leader" is used to omit some of the matches. +static void ins_compl_update_shown_match(void) +{ + while (!ins_compl_equal(compl_shown_match, + (char_u *)compl_leader, STRLEN(compl_leader)) + && compl_shown_match->cp_next != NULL + && !is_first_match(compl_shown_match->cp_next)) { + 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, (char_u *)compl_leader, STRLEN(compl_leader)) + && (compl_shown_match->cp_next == NULL + || is_first_match(compl_shown_match->cp_next))) { + while (!ins_compl_equal(compl_shown_match, (char_u *)compl_leader, STRLEN(compl_leader)) + && compl_shown_match->cp_prev != NULL + && !is_first_match(compl_shown_match->cp_prev)) { + compl_shown_match = compl_shown_match->cp_prev; + } + } +} + /// Delete the old text being completed. void ins_compl_delete(void) { @@ -2944,7 +3308,7 @@ void ins_compl_delete(void) // 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); + col = compl_col + (compl_status_adding() ? compl_length : 0); if ((int)curwin->w_cursor.col > col) { if (stop_arrow() == FAIL) { return; @@ -2964,7 +3328,7 @@ void ins_compl_delete(void) 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); + compl_used_match = !match_at_original_text(compl_shown_match); dict_T *dict = ins_compl_dict_alloc(compl_shown_match); set_vim_var_dict(VV_COMPLETED_ITEM, dict); @@ -2973,97 +3337,69 @@ void ins_compl_insert(bool in_compl_func) } } -/// 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) +/// show the file name for the completion match (if any). Truncate the file +/// name to avoid a wait for return. +static void ins_compl_show_filename(void) { - 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; + char *const lead = _("match in file"); + int space = sc_col - vim_strsize(lead) - 2; + if (space <= 0) { + return; } - 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; - } + // 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". + char *s; + char *e; + for (s = e = 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, + s > compl_shown_match->cp_fname ? "<" : "", s); + msg((char *)IObuff); + msg_hist_off = false; + redraw_cmdline = false; // don't overwrite! +} - 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; - } +/// Find the next set of matches for completion. Repeat the completion "todo" +/// times. The number of matches found is returned in 'num_matches'. +/// +/// @param allow_get_expansion If true, then ins_compl_get_exp() may be called to +/// get more completions. +/// If false, then do nothing when there are no more +/// completions in the given direction. +/// @param todo repeat completion this many times +/// @param advance If true, then completion will move to the first match. +/// Otherwise, the original text will be shown. +/// +/// @return OK on success and -1 if the number of matches are unknown. +static int find_next_completion_match(bool allow_get_expansion, int todo, bool advance, + int *num_matches) +{ + bool found_end = false; + compl_T *found_compl = NULL; - // 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) { + 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 + && (is_first_match(compl_shown_match->cp_next) + || is_first_match(compl_shown_match))); + } else if (compl_shows_dir_backward() && compl_shown_match->cp_prev != NULL) { - found_end = (compl_shown_match == compl_first_match); + found_end = is_first_match(compl_shown_match); compl_shown_match = compl_shown_match->cp_prev; - found_end |= (compl_shown_match == compl_first_match); + found_end |= is_first_match(compl_shown_match); } else { if (!allow_get_expansion) { if (advance) { - if (compl_shows_dir == BACKWARD) { + if (compl_shows_dir_backward()) { compl_pending -= todo + 1; } else { compl_pending += todo + 1; @@ -3073,7 +3409,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match } if (!compl_no_select && advance) { - if (compl_shows_dir == BACKWARD) { + if (compl_shows_dir_backward()) { compl_pending--; } else { compl_pending++; @@ -3081,7 +3417,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match } // Find matches. - num_matches = ins_compl_get_exp(&compl_startpos); + *num_matches = ins_compl_get_exp(&compl_startpos); // handle any pending completions while (compl_pending != 0 && compl_direction == compl_shows_dir @@ -3099,10 +3435,10 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match } found_end = false; } - if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0 + if (!match_at_original_text(compl_shown_match) && compl_leader != NULL && !ins_compl_equal(compl_shown_match, - compl_leader, STRLEN(compl_leader))) { + (char_u *)compl_leader, STRLEN(compl_leader))) { todo++; } else { // Remember a matching item. @@ -3119,6 +3455,68 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match } } + return OK; +} + +/// 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; + 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 && !match_at_original_text(compl_shown_match)) { + // Update "compl_shown_match" to the actually shown match + ins_compl_update_shown_match(); + } + + 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. + if (find_next_completion_match(allow_get_expansion, todo, advance, + &num_matches) == -1) { + return -1; + } + // Insert the text of the new completion, or the compl_leader. if (compl_no_insert && !started) { ins_bytes(compl_orig_text + get_compl_len()); @@ -3135,7 +3533,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match if (!allow_get_expansion) { // redraw to show the user what was inserted - update_screen(0); + update_screen(); // TODO(bfredl): no! // display the updated popup menu ins_compl_show_pum(); @@ -3154,31 +3552,8 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match } // 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! - } + ins_compl_show_filename(); } return num_matches; @@ -3328,46 +3703,46 @@ static bool ins_compl_use_match(int c) /// 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) +static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) { if ((compl_cont_status & CONT_SOL) || ctrl_x_mode_path_defines()) { - if (!(compl_cont_status & CONT_ADDING)) { + if (!compl_status_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); + compl_pattern = (char *)str_foldcase((char_u *)line + compl_col, compl_length, NULL, 0); } else { - compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length); + compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); } - } else if (compl_cont_status & CONT_ADDING) { + } else if (compl_status_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))))) { + compl_pattern = xmalloc(quote_meta(NULL, (char_u *)line + compl_col, compl_length) + 2); + if (!vim_iswordp((char_u *)line + compl_col) + || (compl_col > 0 + && (vim_iswordp(mb_prevptr((char_u *)line, (char_u *)line + compl_col))))) { prefix = (char_u *)""; } STRCPY(compl_pattern, prefix); (void)quote_meta((char_u *)compl_pattern + STRLEN(prefix), - line + compl_col, compl_length); + (char_u *)line + compl_col, compl_length); } else if (--startcol < 0 - || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { + || !vim_iswordp(mb_prevptr((char_u *)line, (char_u *)line + startcol + 1))) { // Match any word of at least two chars - compl_pattern = (char *)vim_strsave((char_u *)"\\<\\k\\k"); + compl_pattern = xstrdup("\\<\\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); + int base_class = mb_get_class((char_u *)line + startcol); while (--startcol >= 0) { int head_off = utf_head_off(line, line + startcol); - if (base_class != mb_get_class(line + startcol - head_off)) { + if (base_class != mb_get_class((char_u *)line + startcol - head_off)) { break; } startcol -= head_off; @@ -3380,13 +3755,13 @@ static int get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) // xmalloc(7) is enough -- Acevedo compl_pattern = xmalloc(7); STRCPY(compl_pattern, "\\<"); - (void)quote_meta((char_u *)compl_pattern + 2, line + compl_col, 1); + (void)quote_meta((char_u *)compl_pattern + 2, (char_u *)line + compl_col, 1); STRCAT(compl_pattern, "\\k"); } else { - compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, + compl_pattern = xmalloc(quote_meta(NULL, (char_u *)line + compl_col, compl_length) + 2); STRCPY(compl_pattern, "\\<"); - (void)quote_meta((char_u *)compl_pattern + 2, line + compl_col, compl_length); + (void)quote_meta((char_u *)compl_pattern + 2, (char_u *)line + compl_col, compl_length); } } @@ -3396,7 +3771,7 @@ static int get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) /// 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) +static int get_wholeline_compl_info(char *line, colnr_T curs_col) { compl_col = (colnr_T)getwhitecols(line); compl_length = (int)curs_col - (int)compl_col; @@ -3404,9 +3779,9 @@ static int get_wholeline_compl_info(char_u *line, colnr_T curs_col) compl_length = 0; } if (p_ic) { - compl_pattern = (char *)str_foldcase(line + compl_col, compl_length, NULL, 0); + compl_pattern = (char *)str_foldcase((char_u *)line + compl_col, compl_length, NULL, 0); } else { - compl_pattern = (char *)vim_strnsave(line + compl_col, (size_t)compl_length); + compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); } return OK; @@ -3433,17 +3808,17 @@ static int get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col) compl_col += startcol; compl_length = (int)curs_col - startcol; - compl_pattern = (char *)addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES); + compl_pattern = addstar((char *)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) +static int get_cmdline_compl_info(char *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); + compl_pattern = xstrnsave(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 @@ -3510,7 +3885,7 @@ static int get_userdefined_compl_info(colnr_T curs_col) return FAIL; } - // Reset extended parameters of completion, when start new + // Reset extended parameters of completion, when starting new // completion. compl_opt_refresh_always = false; @@ -3524,9 +3899,9 @@ static int get_userdefined_compl_info(colnr_T 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); + char *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); + compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); return OK; } @@ -3550,36 +3925,44 @@ static int get_spell_compl_info(int startcol, colnr_T curs_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); + char *line = ml_get(curwin->w_cursor.lnum); + compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); return OK; } /// Get the completion pattern, column and length. +/// +/// @param startcol start column number of the completion pattern/text +/// @param cur_col current cursor column +/// +/// On return, "line_invalid" is set to true, if the current line may have +/// become invalid and needs to be fetched again. +/// +/// @return OK on success. 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); + return get_normal_compl_info((char *)line, startcol, curs_col); } else if (ctrl_x_mode_line_or_eval()) { - return get_wholeline_compl_info(line, curs_col); + return get_wholeline_compl_info((char *)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); + return get_cmdline_compl_info((char *)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 + *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 + *line_invalid = true; // "line" may have become invalid } else { internal_error("ins_complete()"); return FAIL; @@ -3588,232 +3971,191 @@ static int compl_get_info(char_u *line, int startcol, colnr_T curs_col, bool *li 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) +/// Continue an interrupted completion mode search in "line". +/// +/// 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. +static void ins_compl_continue_search(char_u *line) { - 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; + // 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((char *)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; } - - 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 + 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 { + 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; + } +} - 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); - } +/// start insert mode completion +static int ins_compl_start(void) +{ + const bool save_did_ai = did_ai; - 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; + // First time we hit ^N or ^P (in a row, I mean) - 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; - } + did_ai = false; + did_si = false; + can_si = false; + can_si_back = false; + if (stop_arrow() == FAIL) { + return FAIL; + } - 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)); - } + char *line = ml_get(curwin->w_cursor.lnum); + colnr_T curs_col = curwin->w_cursor.col; + compl_pending = 0; - // If any of the original typed text has been changed we need to fix - // the redo buffer. - ins_compl_fixRedoBufForLeader(NULL); + if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT + && compl_cont_mode == ctrl_x_mode) { + // this same ctrl-x_mode was interrupted previously. Continue the + // completion. + ins_compl_continue_search((char_u *)line); + } else { + compl_cont_status &= CONT_LOCAL; + } - // 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; + int startcol = 0; // column where searched text starts + if (!compl_status_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; + } - // 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) { + // Work out completion pattern and original text -- webb + bool line_invalid = false; + if (compl_get_info((char_u *)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); + } - compl_shown_match = compl_curr_match; - compl_shows_dir = compl_direction; + if (compl_status_adding()) { + edit_submode_pre = _(" Adding"); + if (ctrl_x_mode_line_or_eval()) { + // Insert a new line, keep indentation but ignore 'comments'. + char *old = curbuf->b_p_com; - // 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); + curbuf->b_p_com = ""; + 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 (n > 1) { // all matches have been found - compl_matches = n; + if (compl_cont_status & CONT_LOCAL) { + edit_submode = _(ctrl_x_msgs[CTRL_X_LOCAL_MSG]); + } else { + edit_submode = _(CTRL_X_MSG(ctrl_x_mode)); } - 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; + // 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 = xstrnsave(line + compl_col, (size_t)compl_length); + int flags = CP_ORIGINAL_TEXT; + 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 = _("-- Searching..."); + edit_submode_highl = HLF_COUNT; + showmode(); + edit_submode_extra = NULL; + ui_flush(); + + return OK; +} +/// display the completion status message +static void ins_compl_show_statusmsg(void) +{ // 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); + if (is_first_match(compl_first_match->cp_next)) { + edit_submode_extra = compl_status_adding() && compl_length > 1 ? _(e_hitend) : _(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"); + if (match_at_original_text(compl_curr_match)) { + edit_submode_extra = _("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_extra = _("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_extra = _("The only match"); edit_submode_highl = HLF_COUNT; compl_curr_match->cp_number = 1; } else { @@ -3838,7 +4180,7 @@ int ins_complete(int c, bool enable_pum) _("match %d"), compl_curr_match->cp_number); } - edit_submode_extra = match_ref; + edit_submode_extra = (char *)match_ref; edit_submode_highl = HLF_R; if (dollar_vcol >= 0) { curs_columns(curwin, false); @@ -3862,6 +4204,72 @@ int ins_complete(int c, bool enable_pum) msg_clr_cmdline(); // necessary for "noshowmode" } } +} + +/// 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) +{ + int n; + int save_w_wrow; + int save_w_leftcol; + int insert_match; + + compl_direction = ins_compl_key2dir(c); + insert_match = ins_compl_use_match(c); + + if (!compl_started) { + if (ins_compl_start() == FAIL) { + return FAIL; + } + } 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 (is_first_match(compl_first_match->cp_next)) { + // 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_status_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; + } + + ins_compl_show_statusmsg(); // Show the popup menu, unless we got interrupted. if (enable_pum && !compl_interrupted) { @@ -3873,6 +4281,7 @@ int ins_complete(int c, bool enable_pum) return OK; } +/// Remove (if needed) and show the popup menu static void show_pum(int prev_w_wrow, int prev_w_leftcol) { // RedrawingDisabled may be set when invoked through complete(). diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index 5a5257efb2..61dc2ac035 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -57,15 +57,15 @@ static char_u modifier_keys_table[] = MOD_MASK_SHIFT, '*', '4', 'k', 'D', // delete char MOD_MASK_SHIFT, '*', '5', 'k', 'L', // delete line MOD_MASK_SHIFT, '*', '7', '@', '7', // end - MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', // end + MOD_MASK_CTRL, KS_EXTRA, KE_C_END, '@', '7', // end MOD_MASK_SHIFT, '*', '9', '@', '9', // exit MOD_MASK_SHIFT, '*', '0', '@', '0', // find MOD_MASK_SHIFT, '#', '1', '%', '1', // help MOD_MASK_SHIFT, '#', '2', 'k', 'h', // home - MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', // home + MOD_MASK_CTRL, KS_EXTRA, KE_C_HOME, 'k', 'h', // home MOD_MASK_SHIFT, '#', '3', 'k', 'I', // insert MOD_MASK_SHIFT, '#', '4', 'k', 'l', // left arrow - MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', // left arrow + MOD_MASK_CTRL, KS_EXTRA, KE_C_LEFT, 'k', 'l', // left arrow MOD_MASK_SHIFT, '%', 'a', '%', '3', // message MOD_MASK_SHIFT, '%', 'b', '%', '4', // move MOD_MASK_SHIFT, '%', 'c', '%', '5', // next @@ -75,63 +75,63 @@ static char_u modifier_keys_table[] = MOD_MASK_SHIFT, '%', 'g', '%', '0', // redo MOD_MASK_SHIFT, '%', 'h', '&', '3', // replace MOD_MASK_SHIFT, '%', 'i', 'k', 'r', // right arr. - MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', // right arr. + MOD_MASK_CTRL, KS_EXTRA, KE_C_RIGHT, 'k', 'r', // right arr. MOD_MASK_SHIFT, '%', 'j', '&', '5', // resume MOD_MASK_SHIFT, '!', '1', '&', '6', // save MOD_MASK_SHIFT, '!', '2', '&', '7', // suspend MOD_MASK_SHIFT, '!', '3', '&', '8', // undo - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', // up arrow - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', // down arrow + MOD_MASK_SHIFT, KS_EXTRA, KE_S_UP, 'k', 'u', // up arrow + MOD_MASK_SHIFT, KS_EXTRA, KE_S_DOWN, 'k', 'd', // down arrow // vt100 F1 - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1, - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2, - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3, - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4, - - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', // F1 - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', // F10 - - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A', - - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K', - - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q', - MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_XF1, KS_EXTRA, KE_XF1, + MOD_MASK_SHIFT, KS_EXTRA, KE_S_XF2, KS_EXTRA, KE_XF2, + MOD_MASK_SHIFT, KS_EXTRA, KE_S_XF3, KS_EXTRA, KE_XF3, + MOD_MASK_SHIFT, KS_EXTRA, KE_S_XF4, KS_EXTRA, KE_XF4, + + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F1, 'k', '1', // F1 + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F2, 'k', '2', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F3, 'k', '3', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F4, 'k', '4', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F5, 'k', '5', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F6, 'k', '6', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F7, 'k', '7', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F8, 'k', '8', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F9, 'k', '9', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F10, 'k', ';', // F10 + + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F11, 'F', '1', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F12, 'F', '2', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F13, 'F', '3', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F14, 'F', '4', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F15, 'F', '5', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F16, 'F', '6', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F17, 'F', '7', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F18, 'F', '8', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F19, 'F', '9', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F20, 'F', 'A', + + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F21, 'F', 'B', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F22, 'F', 'C', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F23, 'F', 'D', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F24, 'F', 'E', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F25, 'F', 'F', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F26, 'F', 'G', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F27, 'F', 'H', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F28, 'F', 'I', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F29, 'F', 'J', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F30, 'F', 'K', + + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F31, 'F', 'L', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F32, 'F', 'M', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F33, 'F', 'N', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F34, 'F', 'O', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F35, 'F', 'P', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F36, 'F', 'Q', + MOD_MASK_SHIFT, KS_EXTRA, KE_S_F37, 'F', 'R', // TAB pseudo code - MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB, + MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, KE_TAB, NUL }; @@ -349,26 +349,26 @@ static struct mousetable { bool is_drag; // Is it a mouse drag event? } mouse_table[] = { - { (int)KE_LEFTMOUSE, MOUSE_LEFT, true, false }, - { (int)KE_LEFTDRAG, MOUSE_LEFT, false, true }, - { (int)KE_LEFTRELEASE, MOUSE_LEFT, false, false }, - { (int)KE_MIDDLEMOUSE, MOUSE_MIDDLE, true, false }, - { (int)KE_MIDDLEDRAG, MOUSE_MIDDLE, false, true }, - { (int)KE_MIDDLERELEASE, MOUSE_MIDDLE, false, false }, - { (int)KE_RIGHTMOUSE, MOUSE_RIGHT, true, false }, - { (int)KE_RIGHTDRAG, MOUSE_RIGHT, false, true }, - { (int)KE_RIGHTRELEASE, MOUSE_RIGHT, false, false }, - { (int)KE_X1MOUSE, MOUSE_X1, true, false }, - { (int)KE_X1DRAG, MOUSE_X1, false, true }, - { (int)KE_X1RELEASE, MOUSE_X1, false, false }, - { (int)KE_X2MOUSE, MOUSE_X2, true, false }, - { (int)KE_X2DRAG, MOUSE_X2, false, true }, - { (int)KE_X2RELEASE, MOUSE_X2, false, false }, + { KE_LEFTMOUSE, MOUSE_LEFT, true, false }, + { KE_LEFTDRAG, MOUSE_LEFT, false, true }, + { KE_LEFTRELEASE, MOUSE_LEFT, false, false }, + { KE_MIDDLEMOUSE, MOUSE_MIDDLE, true, false }, + { KE_MIDDLEDRAG, MOUSE_MIDDLE, false, true }, + { KE_MIDDLERELEASE, MOUSE_MIDDLE, false, false }, + { KE_RIGHTMOUSE, MOUSE_RIGHT, true, false }, + { KE_RIGHTDRAG, MOUSE_RIGHT, false, true }, + { KE_RIGHTRELEASE, MOUSE_RIGHT, false, false }, + { KE_X1MOUSE, MOUSE_X1, true, false }, + { KE_X1DRAG, MOUSE_X1, false, true }, + { KE_X1RELEASE, MOUSE_X1, false, false }, + { KE_X2MOUSE, MOUSE_X2, true, false }, + { KE_X2DRAG, MOUSE_X2, false, true }, + { KE_X2RELEASE, MOUSE_X2, false, false }, // DRAG without CLICK - { (int)KE_MOUSEMOVE, MOUSE_RELEASE, false, true }, + { KE_MOUSEMOVE, MOUSE_RELEASE, false, true }, // RELEASE without CLICK - { (int)KE_IGNORE, MOUSE_RELEASE, false, false }, - { 0, 0, 0, 0 }, + { KE_IGNORE, MOUSE_RELEASE, false, false }, + { 0, 0, 0, 0 }, }; /// Return the modifier mask bit (#MOD_MASK_*) corresponding to mod name @@ -539,7 +539,7 @@ char_u *get_special_key_name(int c, int modifiers) } } } else { // use name of special key - size_t len = STRLEN(key_names_table[table_idx].name); + size_t len = strlen(key_names_table[table_idx].name); if ((int)len + idx + 2 <= MAX_KEY_NAME_LEN) { STRCPY(string + idx, key_names_table[table_idx].name); @@ -650,7 +650,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const if (*bp == '-') { last_dash = bp; if (bp + 1 <= end) { - l = utfc_ptr2len_len(bp + 1, (int)(end - bp) + 1); + l = utfc_ptr2len_len((char *)bp + 1, (int)(end - bp) + 1); // Anything accepted, like <C-?>. // <C-"> or <M-"> are not special in strings as " is // the string delimiter. With a backslash it works: <M-\"> @@ -665,7 +665,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { bp += 3; // skip t_xx, xx may be '-' or '>' } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { - vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); + vim_str2nr((char *)bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); if (l == 0) { emsg(_(e_invarg)); return 0; @@ -695,7 +695,7 @@ int find_special_key(const char_u **const srcp, const size_t src_len, int *const if (STRNICMP(last_dash + 1, "char-", 5) == 0 && ascii_isdigit(last_dash[6])) { // <Char-123> or <Char-033> or <Char-0x33> - vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true); + vim_str2nr((char *)last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true); if (l == 0) { emsg(_(e_invarg)); return 0; @@ -861,10 +861,9 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) /// @param[in] from What characters to replace. /// @param[in] from_len Length of the "from" argument. /// @param[out] bufp Location where results were saved in case of success (allocated). -/// if *bufp is non-NULL, it will be used directly. it is -/// assumed to be 128 bytes long (enough for transcoding LHS -/// of mapping) -/// Will be set to NULL in case of failure. +/// If `*bufp` is non-NULL, it will be used directly, +/// and is assumed to be 128 bytes long (enough for transcoding LHS of mapping), +/// and will be set to NULL in case of failure. /// @param[in] flags REPTERM_FROM_PART see above /// REPTERM_DO_LT also translate <lt> /// REPTERM_NO_SPECIAL do not accept <key> notation @@ -872,7 +871,7 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) /// @param[out] did_simplify set when some <C-H> code was simplied, unless it is NULL. /// @param[in] cpo_flags Relevant flags derived from p_cpo, see CPO_TO_CPO_FLAGS. /// -/// @return Pointer to an allocated memory, which is also saved to "bufp". +/// @return The same as what `*bufp` is set to. char *replace_termcodes(const char *const from, const size_t from_len, char **const bufp, const int flags, bool *const did_simplify, const int cpo_flags) FUNC_ATTR_NONNULL_ARG(1, 3) @@ -926,8 +925,8 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co } else { src += 5; result[dlen++] = K_SPECIAL; - result[dlen++] = (int)KS_EXTRA; - result[dlen++] = (int)KE_SNR; + result[dlen++] = KS_EXTRA; + result[dlen++] = KE_SNR; snprintf((char *)result + dlen, buf_len - dlen, "%" PRId64, (int64_t)current_sctx.sc_sid); dlen += STRLEN(result + dlen); @@ -993,7 +992,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co } // skip multibyte char correctly - for (i = utfc_ptr2len_len(src, (int)(end - src) + 1); i > 0; i--) { + for (i = utfc_ptr2len_len((char *)src, (int)(end - src) + 1); i > 0; i--) { // If the character is K_SPECIAL, replace it with K_SPECIAL // KS_SPECIAL KE_FILLER. if (*src == K_SPECIAL) { @@ -1050,7 +1049,7 @@ char *vim_strsave_escape_ks(char *p) // Need a buffer to hold up to three times as much. Four in case of an // illegal utf-8 byte: // 0xc0 -> 0xc3 - 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER - char_u *res = xmalloc(STRLEN(p) * 4 + 1); + char_u *res = xmalloc(strlen(p) * 4 + 1); char_u *d = res; for (char_u *s = (char_u *)p; *s != NUL;) { if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) { diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h deleted file mode 100644 index 99f79952d7..0000000000 --- a/src/nvim/lib/kbtree.h +++ /dev/null @@ -1,477 +0,0 @@ -/*- - * Copyright 1997-1999, 2001, John-Mark Gurney. - * 2008-2009, Attractive Chaos <attractor@live.co.uk> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -// Gotchas -// ------- -// -// if you delete from a kbtree while iterating over it you must use -// kb_del_itr and not kb_del otherwise the iterator might point to freed memory. - -#ifndef NVIM_LIB_KBTREE_H -#define NVIM_LIB_KBTREE_H - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "nvim/memory.h" - -#define KB_MAX_DEPTH 64 - -#define __KB_KEY(type, x) (x->key) -#define __KB_PTR(btr, x) (x->ptr) - -#define __KB_TREE_T(name, key_t, T) \ - typedef struct kbnode_##name##_s kbnode_##name##_t; \ - struct kbnode_##name##_s { \ - int32_t n; \ - bool is_internal; \ - key_t key[2*T - 1]; \ - kbnode_##name##_t *ptr[]; \ - }; \ - typedef struct { \ - kbnode_##name##_t *root; \ - int n_keys, n_nodes; \ - } kbtree_##name##_t; \ - typedef struct { \ - kbnode_##name##_t *x; \ - int i; \ - } kbpos_##name##_t; \ - typedef struct { \ - kbpos_##name##_t stack[KB_MAX_DEPTH], *p; \ - } kbitr_##name##_t; \ - - -#define __kb_destroy(kbnode_t, b) do { \ - int i; \ - unsigned int max = 8; \ - kbnode_t *x, **top, **stack = 0; \ - if (b->root) { \ - top = stack = (kbnode_t **)xcalloc(max, sizeof(kbnode_t *)); \ - *top++ = (b)->root; \ - while (top != stack) { \ - x = *--top; \ - if (x->is_internal == 0) { XFREE_CLEAR(x); continue; } \ - for (i = 0; i <= x->n; ++i) \ - if (__KB_PTR(b, x)[i]) { \ - if (top - stack == (int)max) { \ - max <<= 1; \ - stack = (kbnode_t **)xrealloc(stack, max * sizeof(kbnode_t *)); \ - top = stack + (max>>1); \ - } \ - *top++ = __KB_PTR(b, x)[i]; \ - } \ - XFREE_CLEAR(x); \ - } \ - } \ - XFREE_CLEAR(stack); \ -} while (0) - -#define __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \ - static inline int __kb_getp_aux_##name(const kbnode_t * __restrict x, key_t * __restrict k, \ - int *r) \ - { \ - int tr, *rr, begin = 0, end = x->n; \ - if (x->n == 0) return -1; \ - rr = r? r : &tr; \ - while (begin < end) { \ - int mid = (begin + end) >> 1; \ - if (__cmp(__KB_KEY(key_t, x)[mid], *k) < 0) begin = mid + 1; \ - else end = mid; \ - } \ - if (begin == x->n) { *rr = 1; return x->n - 1; } \ - if ((*rr = __cmp(*k, __KB_KEY(key_t, x)[begin])) < 0) --begin; \ - return begin; \ - } - -#define __KB_GET(name, key_t, kbnode_t) \ - static key_t *kb_getp_##name(kbtree_##name##_t *b, key_t * __restrict k) \ - { \ - if (!b->root) { \ - return 0; \ - } \ - int i, r = 0; \ - kbnode_t *x = b->root; \ - while (x) { \ - i = __kb_getp_aux_##name(x, k, &r); \ - if (i >= 0 && r == 0) return &__KB_KEY(key_t, x)[i]; \ - if (x->is_internal == 0) return 0; \ - x = __KB_PTR(b, x)[i + 1]; \ - } \ - return 0; \ - } \ - static inline key_t *kb_get_##name(kbtree_##name##_t *b, key_t k) \ - { \ - return kb_getp_##name(b, &k); \ - } - -#define __KB_INTERVAL(name, key_t, kbnode_t) \ - static inline void kb_intervalp_##name(kbtree_##name##_t *b, key_t * __restrict k, key_t **lower, \ - key_t **upper) \ - { \ - if (!b->root) { \ - return; \ - } \ - int i, r = 0; \ - kbnode_t *x = b->root; \ - *lower = *upper = 0; \ - while (x) { \ - i = __kb_getp_aux_##name(x, k, &r); \ - if (i >= 0 && r == 0) { \ - *lower = *upper = &__KB_KEY(key_t, x)[i]; \ - return; \ - } \ - if (i >= 0) *lower = &__KB_KEY(key_t, x)[i]; \ - if (i < x->n - 1) *upper = &__KB_KEY(key_t, x)[i + 1]; \ - if (x->is_internal == 0) return; \ - x = __KB_PTR(b, x)[i + 1]; \ - } \ - } \ - static inline void kb_interval_##name(kbtree_##name##_t *b, key_t k, key_t **lower, key_t **upper) \ - { \ - kb_intervalp_##name(b, &k, lower, upper); \ - } - -#define __KB_PUT(name, key_t, kbnode_t, __cmp, T, ILEN) \ - /* x must be an internal node */ \ - static inline void __kb_split_##name(kbtree_##name##_t *b, kbnode_t *x, int i, kbnode_t *y) \ - { \ - kbnode_t *z; \ - z = (kbnode_t *)xcalloc(1, y->is_internal? ILEN : sizeof(kbnode_##name##_t)); \ - ++b->n_nodes; \ - z->is_internal = y->is_internal; \ - z->n = T - 1; \ - memcpy(__KB_KEY(key_t, z), &__KB_KEY(key_t, y)[T], sizeof(key_t) * (T - 1)); \ - if (y->is_internal) memcpy(__KB_PTR(b, z), &__KB_PTR(b, y)[T], sizeof(void *) * T); \ - y->n = T - 1; \ - memmove(&__KB_PTR(b, x)[i + 2], &__KB_PTR(b, \ - x)[i + 1], sizeof(void *) * (unsigned int)(x->n - i)); \ - __KB_PTR(b, x)[i + 1] = z; \ - memmove(&__KB_KEY(key_t, x)[i + 1], &__KB_KEY(key_t, x)[i], \ - sizeof(key_t) * (unsigned int)(x->n - i)); \ - __KB_KEY(key_t, x)[i] = __KB_KEY(key_t, y)[T - 1]; \ - ++x->n; \ - } \ - static inline key_t *__kb_putp_aux_##name(kbtree_##name##_t *b, kbnode_t *x, key_t * __restrict k) \ - { \ - int i = x->n - 1; \ - key_t *ret; \ - if (x->is_internal == 0) { \ - i = __kb_getp_aux_##name(x, k, 0); \ - if (i != x->n - 1) \ - memmove(&__KB_KEY(key_t, x)[i + 2], &__KB_KEY(key_t, \ - x)[i + 1], \ - (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ - ret = &__KB_KEY(key_t, x)[i + 1]; \ - *ret = *k; \ - ++x->n; \ - } else { \ - i = __kb_getp_aux_##name(x, k, 0) + 1; \ - if (__KB_PTR(b, x)[i]->n == 2 * T - 1) { \ - __kb_split_##name(b, x, i, __KB_PTR(b, x)[i]); \ - if (__cmp(*k, __KB_KEY(key_t, x)[i]) > 0) ++i; \ - } \ - ret = __kb_putp_aux_##name(b, __KB_PTR(b, x)[i], k); \ - } \ - return ret; \ - } \ - static inline key_t *kb_putp_##name(kbtree_##name##_t *b, key_t * __restrict k) \ - { \ - if (!b->root) { \ - b->root = (kbnode_t *)xcalloc(1, ILEN); \ - ++b->n_nodes; \ - } \ - kbnode_t *r, *s; \ - ++b->n_keys; \ - r = b->root; \ - if (r->n == 2 * T - 1) { \ - ++b->n_nodes; \ - s = (kbnode_t *)xcalloc(1, ILEN); \ - b->root = s; s->is_internal = 1; s->n = 0; \ - __KB_PTR(b, s)[0] = r; \ - __kb_split_##name(b, s, 0, r); \ - r = s; \ - } \ - return __kb_putp_aux_##name(b, r, k); \ - } \ - static inline void kb_put_##name(kbtree_##name##_t *b, key_t k) \ - { \ - kb_putp_##name(b, &k); \ - } - -#define __KB_DEL(name, key_t, kbnode_t, T) \ - static inline key_t __kb_delp_aux_##name(kbtree_##name##_t *b, kbnode_t *x, key_t * __restrict k, \ - int s) \ - { \ - int yn, zn, i, r = 0; \ - kbnode_t *xp, *y, *z; \ - key_t kp; \ - if (x == 0) return *k; \ - if (s) { /* s can only be 0, 1 or 2 */ \ - r = x->is_internal == 0? 0 : s == 1? 1 : -1; \ - i = s == 1? x->n - 1 : -1; \ - } else i = __kb_getp_aux_##name(x, k, &r); \ - if (x->is_internal == 0) { \ - if (s == 2) ++i; \ - kp = __KB_KEY(key_t, x)[i]; \ - memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, \ - x)[i + 1], \ - (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ - --x->n; \ - return kp; \ - } \ - if (r == 0) { \ - if ((yn = __KB_PTR(b, x)[i]->n) >= T) { \ - xp = __KB_PTR(b, x)[i]; \ - kp = __KB_KEY(key_t, x)[i]; \ - __KB_KEY(key_t, x)[i] = __kb_delp_aux_##name(b, xp, 0, 1); \ - return kp; \ - } else if ((zn = __KB_PTR(b, x)[i + 1]->n) >= T) { \ - xp = __KB_PTR(b, x)[i + 1]; \ - kp = __KB_KEY(key_t, x)[i]; \ - __KB_KEY(key_t, x)[i] = __kb_delp_aux_##name(b, xp, 0, 2); \ - return kp; \ - } else if (yn == T - 1 && zn == T - 1) { \ - y = __KB_PTR(b, x)[i]; z = __KB_PTR(b, x)[i + 1]; \ - __KB_KEY(key_t, y)[y->n++] = *k; \ - memmove(&__KB_KEY(key_t, y)[y->n], __KB_KEY(key_t, z), (unsigned int)z->n * sizeof(key_t)); \ - if (y->is_internal) memmove(&__KB_PTR(b, y)[y->n], __KB_PTR(b, \ - z), \ - (unsigned int)(z->n + 1) * sizeof(void *)); \ - y->n += z->n; \ - memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, \ - x)[i + 1], \ - (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ - memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, \ - x)[i + 2], \ - (unsigned int)(x->n - i - 1) * sizeof(void *)); \ - --x->n; \ - XFREE_CLEAR(z); \ - return __kb_delp_aux_##name(b, y, k, s); \ - } \ - } \ - ++i; \ - if ((xp = __KB_PTR(b, x)[i])->n == T - 1) { \ - if (i > 0 && (y = __KB_PTR(b, x)[i - 1])->n >= T) { \ - memmove(&__KB_KEY(key_t, xp)[1], __KB_KEY(key_t, xp), (unsigned int)xp->n * sizeof(key_t)); \ - if (xp->is_internal) memmove(&__KB_PTR(b, xp)[1], __KB_PTR(b, \ - xp), \ - (unsigned int)(xp->n + 1) * sizeof(void *)); \ - __KB_KEY(key_t, xp)[0] = __KB_KEY(key_t, x)[i - 1]; \ - __KB_KEY(key_t, x)[i - 1] = __KB_KEY(key_t, y)[y->n - 1]; \ - if (xp->is_internal) __KB_PTR(b, xp)[0] = __KB_PTR(b, y)[y->n]; \ - --y->n; ++xp->n; \ - } else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n >= T) { \ - __KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \ - __KB_KEY(key_t, x)[i] = __KB_KEY(key_t, y)[0]; \ - if (xp->is_internal) __KB_PTR(b, xp)[xp->n] = __KB_PTR(b, y)[0]; \ - --y->n; \ - memmove(__KB_KEY(key_t, y), &__KB_KEY(key_t, y)[1], (unsigned int)y->n * sizeof(key_t)); \ - if (y->is_internal) memmove(__KB_PTR(b, y), &__KB_PTR(b, \ - y)[1], \ - (unsigned int)(y->n + 1) * sizeof(void *)); \ - } else if (i > 0 && (y = __KB_PTR(b, x)[i - 1])->n == T - 1) { \ - __KB_KEY(key_t, y)[y->n++] = __KB_KEY(key_t, x)[i - 1]; \ - memmove(&__KB_KEY(key_t, y)[y->n], __KB_KEY(key_t, xp), \ - (unsigned int)xp->n * sizeof(key_t)); \ - if (y->is_internal) memmove(&__KB_PTR(b, y)[y->n], __KB_PTR(b, \ - xp), \ - (unsigned int)(xp->n + 1) * sizeof(void *)); \ - y->n += xp->n; \ - memmove(&__KB_KEY(key_t, x)[i - 1], &__KB_KEY(key_t, \ - x)[i], \ - (unsigned int)(x->n - i) * sizeof(key_t)); \ - memmove(&__KB_PTR(b, x)[i], &__KB_PTR(b, \ - x)[i + 1], (unsigned int)(x->n - i) * sizeof(void *)); \ - --x->n; \ - XFREE_CLEAR(xp); \ - xp = y; \ - } else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n == T - 1) { \ - __KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \ - memmove(&__KB_KEY(key_t, xp)[xp->n], __KB_KEY(key_t, y), \ - (unsigned int)y->n * sizeof(key_t)); \ - if (xp->is_internal) memmove(&__KB_PTR(b, xp)[xp->n], __KB_PTR(b, y), \ - (unsigned int)(y->n + 1) * sizeof(void *)); \ - xp->n += y->n; \ - memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, \ - x)[i + 1], \ - (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ - memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, \ - x)[i + 2], \ - (unsigned int)(x->n - i - 1) * sizeof(void *)); \ - --x->n; \ - XFREE_CLEAR(y); \ - } \ - } \ - return __kb_delp_aux_##name(b, xp, k, s); \ - } \ - static inline key_t kb_delp_##name(kbtree_##name##_t *b, key_t * __restrict k) \ - { \ - kbnode_t *x; \ - key_t ret; \ - ret = __kb_delp_aux_##name(b, b->root, k, 0); \ - --b->n_keys; \ - if (b->root->n == 0 && b->root->is_internal) { \ - --b->n_nodes; \ - x = b->root; \ - b->root = __KB_PTR(b, x)[0]; \ - XFREE_CLEAR(x); \ - } \ - return ret; \ - } \ - static inline key_t kb_del_##name(kbtree_##name##_t *b, key_t k) \ - { \ - return kb_delp_##name(b, &k); \ - } - -#define __KB_ITR(name, key_t, kbnode_t) \ - static inline void kb_itr_first_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \ - { \ - itr->p = NULL; \ - if (b->n_keys == 0) return; \ - itr->p = itr->stack; \ - itr->p->x = b->root; itr->p->i = 0; \ - while (itr->p->x->is_internal && __KB_PTR(b, itr->p->x)[0] != 0) { \ - kbnode_t *x = itr->p->x; \ - ++itr->p; \ - itr->p->x = __KB_PTR(b, x)[0]; itr->p->i = 0; \ - } \ - } \ - static inline int kb_itr_next_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \ - { \ - if (itr->p == NULL) return 0; \ - for (;;) { \ - ++itr->p->i; \ - assert(itr->p->i <= 21); \ - while (itr->p->x && itr->p->i <= itr->p->x->n) { \ - itr->p[1].i = 0; \ - itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[itr->p->i] : 0; \ - ++itr->p; \ - } \ - if (itr->p == itr->stack) { \ - itr->p = NULL; \ - return 0; \ - } \ - --itr->p; \ - if (itr->p->x && itr->p->i < itr->p->x->n) return 1; \ - } \ - } \ - static inline int kb_itr_prev_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \ - { \ - if (itr->p == NULL) return 0; \ - for (;;) { \ - while (itr->p->x && itr->p->i >= 0) { \ - itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[itr->p->i] : 0; \ - itr->p[1].i = itr->p[1].x ? itr->p[1].x->n : -1; \ - ++itr->p; \ - } \ - if (itr->p == itr->stack) { \ - itr->p = NULL; \ - return 0; \ - } \ - --itr->p; \ - --itr->p->i; \ - if (itr->p->x && itr->p->i >= 0) return 1; \ - } \ - } \ - static inline int kb_itr_getp_##name(kbtree_##name##_t *b, key_t * __restrict k, \ - kbitr_##name##_t *itr) \ - { \ - if (b->n_keys == 0) { \ - itr->p = NULL; \ - return 0; \ - } \ - int i, r = 0; \ - itr->p = itr->stack; \ - itr->p->x = b->root; \ - while (itr->p->x) { \ - i = __kb_getp_aux_##name(itr->p->x, k, &r); \ - itr->p->i = i; \ - if (i >= 0 && r == 0) return 1; \ - ++itr->p->i; \ - assert(itr->p->i <= 21); \ - itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[i + 1] : 0; \ - ++itr->p; \ - } \ - itr->p->i = 0; \ - return 0; \ - } \ - static inline int kb_itr_get_##name(kbtree_##name##_t *b, key_t k, kbitr_##name##_t *itr) \ - { \ - return kb_itr_getp_##name(b, &k, itr); \ - } \ - static inline void kb_del_itr_##name(kbtree_##name##_t *b, kbitr_##name##_t *itr) \ - { \ - key_t k = kb_itr_key(itr); \ - kb_delp_##name(b, &k); \ - kb_itr_getp_##name(b, &k, itr); \ - } - -#define KBTREE_INIT(name, key_t, __cmp, T) \ - KBTREE_INIT_IMPL(name, key_t, kbnode_##name##_t, __cmp, T, \ - (sizeof(kbnode_##name##_t) + (2*T)*sizeof(void *))) - -#define KBTREE_INIT_IMPL(name, key_t, kbnode_t, __cmp, T, ILEN) \ - __KB_TREE_T(name, key_t, T) \ - __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \ - __KB_GET(name, key_t, kbnode_t) \ - __KB_INTERVAL(name, key_t, kbnode_t) \ - __KB_PUT(name, key_t, kbnode_t, __cmp, T, ILEN) \ - __KB_DEL(name, key_t, kbnode_t, T) \ - __KB_ITR(name, key_t, kbnode_t) - -#define KB_DEFAULT_SIZE 512 - -#define kbtree_t(name) kbtree_##name##_t -#define kbitr_t(name) kbitr_##name##_t -#define kb_init(b) ((b)->n_keys = (b)->n_nodes = 0, (b)->root = 0) -#define kb_destroy(name, b) __kb_destroy(kbnode_##name##_t, b) -#define kb_get(name, b, k) kb_get_##name(b, k) -#define kb_put(name, b, k) kb_put_##name(b, k) -#define kb_del(name, b, k) kb_del_##name(b, k) -#define kb_interval(name, b, k, l, u) kb_interval_##name(b, k, l, u) -#define kb_getp(name, b, k) kb_getp_##name(b, k) -#define kb_putp(name, b, k) kb_putp_##name(b, k) -#define kb_delp(name, b, k) kb_delp_##name(b, k) -#define kb_intervalp(name, b, k, l, u) kb_intervalp_##name(b, k, l, u) - -#define kb_itr_first(name, b, i) kb_itr_first_##name(b, i) -#define kb_itr_get(name, b, k, i) kb_itr_get_##name(b, k, i) -#define kb_itr_getp(name, b, k, i) kb_itr_getp_##name(b, k, i) -#define kb_itr_next(name, b, i) kb_itr_next_##name(b, i) -#define kb_itr_prev(name, b, i) kb_itr_prev_##name(b, i) -#define kb_del_itr(name, b, i) kb_del_itr_##name(b, i) -#define kb_itr_key(itr) __KB_KEY(dummy, (itr)->p->x)[(itr)->p->i] -#define kb_itr_valid(itr) ((itr)->p >= (itr)->stack) - -#define kb_size(b) ((b)->n_keys) - -#define kb_generic_cmp(a, b) (((b) < (a)) - ((a) < (b))) -#define kb_str_cmp(a, b) strcmp(a, b) - -#endif // NVIM_LIB_KBTREE_H diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h deleted file mode 100644 index 57a41f9c13..0000000000 --- a/src/nvim/lib/khash.h +++ /dev/null @@ -1,730 +0,0 @@ -/* The MIT License - - Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/* - Example: - - #include "nvim/khash.h" - KHASH_MAP_INIT_INT(32, char) - int main() { - int ret, is_missing; - khiter_t k; - khash_t(32) *h = kh_init(32); - k = kh_put(32, h, 5, &ret); - kh_value(h, k) = 10; - k = kh_get(32, h, 10); - is_missing = (k == kh_end(h)); - k = kh_get(32, h, 5); - kh_del(32, h, k); - for (k = kh_begin(h); k != kh_end(h); ++k) - if (kh_exist(h, k)) kh_value(h, k) = 1; - kh_destroy(32, h); - return 0; - } - */ - -/* - 2013-05-02 (0.2.8): - - * Use quadratic probing. When the capacity is power of 2, stepping function - i*(i+1)/2 guarantees to traverse each bucket. It is better than double - hashing on cache performance and is more robust than linear probing. - - In theory, double hashing should be more robust than quadratic probing. - However, my implementation is probably not for large hash tables, because - the second hash function is closely tied to the first hash function, - which reduce the effectiveness of double hashing. - - Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php - - 2011-12-29 (0.2.7): - - * Minor code clean up; no actual effect. - - 2011-09-16 (0.2.6): - - * The capacity is a power of 2. This seems to dramatically improve the - speed for simple keys. Thank Zilong Tan for the suggestion. Reference: - - - http://code.google.com/p/ulib/ - - http://nothings.org/computer/judy/ - - * Allow to optionally use linear probing which usually has better - performance for random input. Double hashing is still the default as it - is more robust to certain non-random input. - - * Added Wang's integer hash function (not used by default). This hash - function is more robust to certain non-random input. - - 2011-02-14 (0.2.5): - - * Allow to declare global functions. - - 2009-09-26 (0.2.4): - - * Improve portability - - 2008-09-19 (0.2.3): - - * Corrected the example - * Improved interfaces - - 2008-09-11 (0.2.2): - - * Improved speed a little in kh_put() - - 2008-09-10 (0.2.1): - - * Added kh_clear() - * Fixed a compiling error - - 2008-09-02 (0.2.0): - - * Changed to token concatenation which increases flexibility. - - 2008-08-31 (0.1.2): - - * Fixed a bug in kh_get(), which has not been tested previously. - - 2008-08-31 (0.1.1): - - * Added destructor - */ - -#ifndef NVIM_LIB_KHASH_H -#define NVIM_LIB_KHASH_H - -/*! - @header - - Generic hash table library. - */ - -#define AC_VERSION_KHASH_H "0.2.8" - -#include <limits.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "nvim/func_attr.h" -#include "nvim/memory.h" - -// compiler specific configuration - -#if UINT_MAX == 0xffffffffu -typedef unsigned int khint32_t; -#elif ULONG_MAX == 0xffffffffu -typedef unsigned long khint32_t; -#endif - -#if ULONG_MAX == ULLONG_MAX -typedef unsigned long khint64_t; -#else -typedef unsigned long long khint64_t; -#endif - -#ifdef _MSC_VER -# define kh_inline __inline -#else -# define kh_inline inline -#endif - -typedef khint32_t khint_t; -typedef khint_t khiter_t; - -#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) -#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) -#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) -#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(khint_t)(1ul<<((i&0xfU)<<1))) -#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(khint_t)(2ul<<((i&0xfU)<<1))) -#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(khint_t)(3ul<<((i&0xfU)<<1))) -#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=(khint_t)1ul<<((i&0xfU)<<1)) - -#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) - -#ifndef kroundup32 -# define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, \ - ++(x)) -#endif - -#ifndef kcalloc -# define kcalloc(N, Z) xcalloc(N, Z) -#endif -#ifndef kmalloc -# define kmalloc(Z) xmalloc(Z) -#endif -#ifndef krealloc -# define krealloc(P, Z) xrealloc(P, Z) -#endif -#ifndef kfree -# define kfree(P) XFREE_CLEAR(P) -#endif - -#define __ac_HASH_UPPER 0.77 - -#define __KHASH_TYPE(name, khkey_t, khval_t) \ - typedef struct { \ - khint_t n_buckets, size, n_occupied, upper_bound; \ - khint32_t *flags; \ - khkey_t *keys; \ - khval_t *vals; \ - } kh_##name##_t; - -#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ - extern kh_##name##_t *kh_init_##name(void); \ - extern void kh_dealloc_##name(kh_##name##_t *h); \ - extern void kh_destroy_##name(kh_##name##_t *h); \ - extern void kh_clear_##name(kh_##name##_t *h); \ - extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ - extern void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ - extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ - extern void kh_del_##name(kh_##name##_t *h, khint_t x); - -#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, \ - __hash_equal) \ - SCOPE kh_##name##_t *kh_init_##name(void) \ - REAL_FATTR_UNUSED; \ - SCOPE kh_##name##_t *kh_init_##name(void) { \ - return (kh_##name##_t *)kcalloc(1, sizeof(kh_##name##_t)); \ - } \ - SCOPE void kh_dealloc_##name(kh_##name##_t *h) \ - REAL_FATTR_UNUSED; \ - SCOPE void kh_dealloc_##name(kh_##name##_t *h) \ - { \ - kfree(h->keys); \ - kfree(h->flags); \ - kfree(h->vals); \ - } \ - SCOPE void kh_destroy_##name(kh_##name##_t *h) \ - REAL_FATTR_UNUSED; \ - SCOPE void kh_destroy_##name(kh_##name##_t *h) \ - { \ - if (h) { \ - kh_dealloc_##name(h); \ - kfree(h); \ - } \ - } \ - SCOPE void kh_clear_##name(kh_##name##_t *h) \ - REAL_FATTR_UNUSED; \ - SCOPE void kh_clear_##name(kh_##name##_t *h) \ - { \ - if (h && h->flags) { \ - memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ - h->size = h->n_occupied = 0; \ - } \ - } \ - SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ - REAL_FATTR_UNUSED; \ - SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ - { \ - if (h->n_buckets) { \ - khint_t k, i, last, mask, step = 0; \ - mask = h->n_buckets - 1; \ - k = __hash_func(key); i = k & mask; \ - last = i; \ - while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || \ - !__hash_equal(h->keys[i], key))) { \ - i = (i + (++step)) & mask; \ - if (i == last) { \ - return h->n_buckets; \ - } \ - } \ - return __ac_iseither(h->flags, i) ? h->n_buckets : i; \ - } else { \ - return 0; \ - } \ - } \ - SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ - REAL_FATTR_UNUSED; \ - SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ - { /* This function uses 0.25*n_buckets bytes of working space instead of */ \ - /* [sizeof(key_t+val_t)+.25]*n_buckets. */ \ - khint32_t *new_flags = 0; \ - khint_t j = 1; \ - { \ - kroundup32(new_n_buckets); \ - if (new_n_buckets < 4) { \ - new_n_buckets = 4; \ - } \ - /* requested size is too small */ \ - if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) { \ - j = 0; \ - } else { /* hash table size to be changed (shrink or expand); rehash */ \ - new_flags = (khint32_t *)kmalloc(__ac_fsize(new_n_buckets) \ - * sizeof(khint32_t)); \ - memset(new_flags, 0xaa, \ - __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ - if (h->n_buckets < new_n_buckets) { /* expand */ \ - khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ - h->keys = new_keys; \ - if (kh_is_map) { \ - khval_t *new_vals = \ - (khval_t *)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ - h->vals = new_vals; \ - } \ - } /* otherwise shrink */ \ - } \ - } \ - if (j) { /* rehashing is needed */ \ - for (j = 0; j != h->n_buckets; ++j) { \ - if (__ac_iseither(h->flags, j) == 0) { \ - khkey_t key = h->keys[j]; \ - khval_t val; \ - khint_t new_mask; \ - new_mask = new_n_buckets - 1; \ - if (kh_is_map) { \ - val = h->vals[j]; \ - } \ - __ac_set_isdel_true(h->flags, j); \ - /* kick-out process; sort of like in Cuckoo hashing */ \ - while (1) { \ - khint_t k, i, step = 0; \ - k = __hash_func(key); \ - i = k & new_mask; \ - while (!__ac_isempty(new_flags, i)) { \ - i = (i + (++step)) & new_mask; \ - } \ - __ac_set_isempty_false(new_flags, i); \ - /* kick out the existing element */ \ - if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { \ - { \ - khkey_t tmp = h->keys[i]; \ - h->keys[i] = key; \ - key = tmp; \ - } \ - if (kh_is_map) { \ - khval_t tmp = h->vals[i]; \ - h->vals[i] = val; \ - val = tmp; \ - } \ - /* mark it as deleted in the old hash table */ \ - __ac_set_isdel_true(h->flags, i); \ - } else { /* write the element and jump out of the loop */ \ - h->keys[i] = key; \ - if (kh_is_map) { \ - h->vals[i] = val; \ - } \ - break; \ - } \ - } \ - } \ - } \ - if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ - h->keys = (khkey_t *)krealloc((void *)h->keys, \ - new_n_buckets * sizeof(khkey_t)); \ - if (kh_is_map) { \ - h->vals = (khval_t *)krealloc((void *)h->vals, \ - new_n_buckets * sizeof(khval_t)); \ - } \ - } \ - kfree(h->flags); /* free the working space */ \ - h->flags = new_flags; \ - h->n_buckets = new_n_buckets; \ - h->n_occupied = h->size; \ - h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ - } \ - } \ - SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ - REAL_FATTR_UNUSED; \ - SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ - { \ - khint_t x; \ - if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ - if (h->n_buckets > (h->size << 1)) { \ - kh_resize_##name(h, h->n_buckets - 1); /* clear "deleted" elements */ \ - } else { \ - kh_resize_##name(h, h->n_buckets + 1); /* expand the hash table */ \ - } \ - } /* TODO: implement automatically shrinking; */ \ - /* resize() already support shrinking */ \ - { \ - khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \ - x = site = h->n_buckets; \ - k = __hash_func(key); \ - i = k & mask; \ - if (__ac_isempty(h->flags, i)) { \ - x = i; /* for speed up */ \ - } else { \ - last = i; \ - while (!__ac_isempty(h->flags, i) \ - && (__ac_isdel(h->flags, i) \ - || !__hash_equal(h->keys[i], key))) { \ - if (__ac_isdel(h->flags, i)) { \ - site = i; \ - } \ - i = (i + (++step)) & mask; \ - if (i == last) { \ - x = site; \ - break; \ - } \ - } \ - if (x == h->n_buckets) { \ - if (__ac_isempty(h->flags, i) && site != h->n_buckets) { \ - x = site; \ - } else { \ - x = i; \ - } \ - } \ - } \ - } \ - if (__ac_isempty(h->flags, x)) { /* not present at all */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - h->size++; \ - h->n_occupied++; \ - *ret = 1; \ - } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ - h->keys[x] = key; \ - __ac_set_isboth_false(h->flags, x); \ - h->size++; \ - *ret = 2; \ - } else { \ - *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ - } \ - return x; \ - } \ - SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ - REAL_FATTR_UNUSED; \ - SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ - { \ - if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ - __ac_set_isdel_true(h->flags, x); \ - --h->size; \ - } \ - } - -#define KHASH_DECLARE(name, khkey_t, khval_t) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_PROTOTYPES(name, khkey_t, khval_t) - -#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - __KHASH_TYPE(name, khkey_t, khval_t) \ - __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) - -#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) - -// --- BEGIN OF HASH FUNCTIONS --- - -/*! @function - @abstract Integer hash function - @param key The integer [khint32_t] - @return The hash value [khint_t] - */ -#define kh_int_hash_func(key) (khint32_t)(key) -/*! @function - @abstract Integer comparison function - */ -#define kh_int_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract 64-bit integer hash function - @param key The integer [khint64_t] - @return The hash value [khint_t] - */ -#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) -/*! @function - @abstract 64-bit integer comparison function - */ -#define kh_int64_hash_equal(a, b) ((a) == (b)) -/*! @function - @abstract const char* hash function - @param s Pointer to a null terminated string - @return The hash value - */ -static kh_inline khint_t __ac_X31_hash_string(const char *s) -{ - khint_t h = (khint_t)*s; - if (h) { - for (++s; *s; ++s) { h = (h << 5) - h + (uint8_t)*s; } - } - return h; -} -/*! @function - @abstract Another interface to const char* hash function - @param key Pointer to a null terminated string [const char*] - @return The hash value [khint_t] - */ -#define kh_str_hash_func(key) __ac_X31_hash_string(key) -/*! @function - @abstract Const char* comparison function - */ -#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) - -static kh_inline khint_t __ac_Wang_hash(khint_t key) -{ - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - return key; -} -#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key) - -// --- END OF HASH FUNCTIONS --- - -// Other convenient macros... - -/*! - @abstract Type of the hash table. - @param name Name of the hash table [symbol] - */ -#define khash_t(name) kh_##name##_t - -/*! @function - @abstract Initiate a hash table. - @param name Name of the hash table [symbol] - @return Pointer to the hash table [khash_t(name)*] - */ -#define kh_init(name) kh_init_##name() - -/*! @function - @abstract Destroy a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_destroy(name, h) kh_destroy_##name(h) - -/*! @function - @abstract Free memory referenced directly inside a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_dealloc(name, h) kh_dealloc_##name(h) - -/*! @function - @abstract Reset a hash table without deallocating memory. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - */ -#define kh_clear(name, h) kh_clear_##name(h) - -/*! @function - @abstract Resize a hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param s New size [khint_t] - */ -#define kh_resize(name, h, s) kh_resize_##name(h, s) - -/*! @function - @abstract Insert a key to the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @param r Extra return code: -1 if the operation failed; - 0 if the key is present in the hash table; - 1 if the bucket is empty (never used); 2 if the element in - the bucket has been deleted [int*] - @return Iterator to the inserted element [khint_t] - */ -#define kh_put(name, h, k, r) kh_put_##name(h, k, r) - -/*! @function - @abstract Retrieve a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Key [type of keys] - @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t] - */ -#define kh_get(name, h, k) kh_get_##name(h, k) - -/*! @function - @abstract Remove a key from the hash table. - @param name Name of the hash table [symbol] - @param h Pointer to the hash table [khash_t(name)*] - @param k Iterator to the element to be deleted [khint_t] - */ -#define kh_del(name, h, k) kh_del_##name(h, k) - -/*! @function - @abstract Test whether a bucket contains data. - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return 1 if containing data; 0 otherwise [int] - */ -#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) - -/*! @function - @abstract Get key given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Key [type of keys] - */ -#define kh_key(h, x) ((h)->keys[x]) - -/*! @function - @abstract Get value given an iterator - @param h Pointer to the hash table [khash_t(name)*] - @param x Iterator to the bucket [khint_t] - @return Value [type of values] - @discussion For hash sets, calling this results in segfault. - */ -#define kh_val(h, x) ((h)->vals[x]) - -/*! @function - @abstract Alias of kh_val() - */ -#define kh_value(h, x) ((h)->vals[x]) - -/*! @function - @abstract Get the start iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The start iterator [khint_t] - */ -#define kh_begin(h) (khint_t)(0) - -/*! @function - @abstract Get the end iterator - @param h Pointer to the hash table [khash_t(name)*] - @return The end iterator [khint_t] - */ -#define kh_end(h) ((h)->n_buckets) - -/*! @function - @abstract Get the number of elements in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of elements in the hash table [khint_t] - */ -#define kh_size(h) ((h)->size) - -/*! @function - @abstract Get the number of buckets in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @return Number of buckets in the hash table [khint_t] - */ -#define kh_n_buckets(h) ((h)->n_buckets) - -/*! @function - @abstract Iterate over the entries in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param kvar Variable to which key will be assigned - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h, __i)) continue; \ - (kvar) = kh_key(h, __i); \ - (vvar) = kh_val(h, __i); \ - code; \ - } } - -/*! @function - @abstract Iterate over the values in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param vvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach_value(h, vvar, code) { khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ - if (!kh_exist(h, __i)) continue; \ - (vvar) = kh_val(h, __i); \ - code; \ - } } - -/*! @function - @abstract Iterate over the keys in the hash table - @param h Pointer to the hash table [khash_t(name)*] - @param kvar Variable to which value will be assigned - @param code Block of code to execute - */ -#define kh_foreach_key(h, kvar, code) \ - { \ - khint_t __i; \ - for (__i = kh_begin(h); __i != kh_end(h); __i++) { \ - if (!kh_exist(h, __i)) { \ - continue; \ - } \ - (kvar) = kh_key(h, __i); \ - code; \ - } \ - } - -// More convenient interfaces - -/*! @function - @abstract Instantiate a hash set containing integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT(name) \ - KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT(name, khval_t) \ - KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing 64-bit integer keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_INT64(name) \ - KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing 64-bit integer keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_INT64(name, khval_t) \ - KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) - -typedef const char *kh_cstr_t; -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - */ -#define KHASH_SET_INIT_STR(name) \ - KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) - -/*! @function - @abstract Instantiate a hash map containing const char* keys - @param name Name of the hash table [symbol] - @param khval_t Type of values [type] - */ -#define KHASH_MAP_INIT_STR(name, khval_t) \ - KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) - -/*! @function - @abstract Return a literal for an empty hash table. - @param name Name of the hash table [symbol] - */ -#define KHASH_EMPTY_TABLE(name) \ - ((kh_##name##_t) { \ - .n_buckets = 0, \ - .size = 0, \ - .n_occupied = 0, \ - .upper_bound = 0, \ - .flags = NULL, \ - .keys = NULL, \ - .vals = NULL, \ - }) -#endif // NVIM_LIB_KHASH_H diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h deleted file mode 100644 index a9abbc6dc2..0000000000 --- a/src/nvim/lib/klist.h +++ /dev/null @@ -1,144 +0,0 @@ -/* The MIT License - - Copyright (c) 2008-2009, by Attractive Chaos <attractor@live.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -#ifndef _AC_KLIST_H -#define _AC_KLIST_H - -#include <assert.h> -#include <stdlib.h> - -#include "nvim/func_attr.h" -#include "nvim/memory.h" - -#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \ - typedef struct { \ - size_t cnt, n, max; \ - kmptype_t **buf; \ - } kmp_##name##_t; \ - static inline kmp_##name##_t *kmp_init_##name(void) { \ - return xcalloc(1, sizeof(kmp_##name##_t)); \ - } \ - static inline void kmp_destroy_##name(kmp_##name##_t *mp) \ - REAL_FATTR_UNUSED; \ - static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \ - size_t k; \ - for (k = 0; k < mp->n; k++) { \ - kmpfree_f(mp->buf[k]); XFREE_CLEAR(mp->buf[k]); \ - } \ - XFREE_CLEAR(mp->buf); XFREE_CLEAR(mp); \ - } \ - static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \ - mp->cnt++; \ - if (mp->n == 0) { \ - return xcalloc(1, sizeof(kmptype_t)); \ - } \ - return mp->buf[--mp->n]; \ - } \ - static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \ - mp->cnt--; \ - if (mp->n == mp->max) { \ - mp->max = mp->max ? (mp->max << 1) : 16; \ - mp->buf = xrealloc(mp->buf, sizeof(kmptype_t *) * mp->max); \ - } \ - mp->buf[mp->n++] = p; \ - } - -#define kmempool_t(name) kmp_##name##_t -#define kmp_init(name) kmp_init_##name() -#define kmp_destroy(name, mp) kmp_destroy_##name(mp) -#define kmp_alloc(name, mp) kmp_alloc_##name(mp) -#define kmp_free(name, mp, p) kmp_free_##name(mp, p) - -#define KLIST_INIT(name, kltype_t, kmpfree_t) \ - struct __kl1_##name { \ - kltype_t data; \ - struct __kl1_##name *next; \ - }; \ - typedef struct __kl1_##name kl1_##name; \ - KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \ - typedef struct { \ - kl1_##name *head, *tail; \ - kmp_##name##_t *mp; \ - size_t size; \ - } kl_##name##_t; \ - static inline kl_##name##_t *kl_init_##name(void) { \ - kl_##name##_t *kl = xcalloc(1, sizeof(kl_##name##_t)); \ - kl->mp = kmp_init(name); \ - kl->head = kl->tail = kmp_alloc(name, kl->mp); \ - kl->head->next = 0; \ - return kl; \ - } \ - static inline void kl_destroy_##name(kl_##name##_t *kl) \ - REAL_FATTR_UNUSED; \ - static inline void kl_destroy_##name(kl_##name##_t *kl) { \ - kl1_##name *p; \ - for (p = kl->head; p != kl->tail; p = p->next) { \ - kmp_free(name, kl->mp, p); \ - } \ - kmp_free(name, kl->mp, p); \ - kmp_destroy(name, kl->mp); \ - XFREE_CLEAR(kl); \ - } \ - static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ - kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ - q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \ - kl->size++; \ - q->data = d; \ - } \ - static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \ - kl1_##name **n) { \ - assert((*n)->next); \ - kl1_##name *p; \ - kl->size--; \ - p = *n; \ - *n = (*n)->next; \ - if (p == kl->head) { \ - kl->head = *n; \ - } \ - kltype_t d = p->data; \ - kmp_free(name, kl->mp, p); \ - return d; \ - } - -#define kliter_t(name) kl1_##name -#define klist_t(name) kl_##name##_t -#define kl_val(iter) ((iter)->data) -#define kl_next(iter) ((iter)->next) -#define kl_begin(kl) ((kl)->head) -#define kl_end(kl) ((kl)->tail) - -#define kl_init(name) kl_init_##name() -#define kl_destroy(name, kl) kl_destroy_##name(kl) -#define kl_push(name, kl, d) kl_push_##name(kl, d) -#define kl_shift_at(name, kl, node) kl_shift_at_##name(kl, node) -#define kl_shift(name, kl) kl_shift_at(name, kl, &kl->head) -#define kl_empty(kl) ((kl)->size == 0) -// Iteration macros. It's ok to modify the list while iterating as long as a -// `break` statement is executed before the next iteration. -#define kl_iter(name, kl, p) kl_iter_at(name, kl, p, NULL) -#define kl_iter_at(name, kl, p, h) \ - for (kl1_##name **p = h ? h : &kl->head; *p != kl->tail; p = &(*p)->next) - -#endif diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h deleted file mode 100644 index b5b3adf7d2..0000000000 --- a/src/nvim/lib/kvec.h +++ /dev/null @@ -1,236 +0,0 @@ -// The MIT License -// -// Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk> -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -// An example: -// -// #include "kvec.h" -// int main() { -// kvec_t(int) array = KV_INITIAL_VALUE; -// kv_push(array, 10); // append -// kv_a(array, 20) = 5; // dynamic -// kv_A(array, 20) = 4; // static -// kv_destroy(array); -// return 0; -// } - -#ifndef NVIM_LIB_KVEC_H -#define NVIM_LIB_KVEC_H - -#include <stdlib.h> -#include <string.h> - -#include "nvim/memory.h" -#include "nvim/os/os_defs.h" - -#define kv_roundup32(x) \ - ((--(x)), \ - ((x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16), \ - (++(x))) - -#define KV_INITIAL_VALUE { .size = 0, .capacity = 0, .items = NULL } - -#define kvec_t(type) \ - struct { \ - size_t size; \ - size_t capacity; \ - type *items; \ - } - -#define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0) -#define kv_destroy(v) \ - do { \ - xfree((v).items); \ - kv_init(v); \ - } while (0) -#define kv_A(v, i) ((v).items[(i)]) -#define kv_pop(v) ((v).items[--(v).size]) -#define kv_size(v) ((v).size) -#define kv_max(v) ((v).capacity) -#define kv_Z(v, i) kv_A(v, kv_size(v) - (i) - 1) -#define kv_last(v) kv_Z(v, 0) - -/// Drop last n items from kvec without resizing -/// -/// Previously spelled as `(void)kv_pop(v)`, repeated n times. -/// -/// @param[out] v Kvec to drop items from. -/// @param[in] n Number of elements to drop. -#define kv_drop(v, n) ((v).size -= (n)) - -#define kv_resize(v, s) \ - ((v).capacity = (s), \ - (v).items = xrealloc((v).items, sizeof((v).items[0]) * (v).capacity)) - -#define kv_resize_full(v) \ - kv_resize(v, (v).capacity ? (v).capacity << 1 : 8) - -#define kv_copy(v1, v0) \ - do { \ - if ((v1).capacity < (v0).size) { \ - kv_resize(v1, (v0).size); \ - } \ - (v1).size = (v0).size; \ - memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \ - } while (0) - -/// fit at least "len" more items -#define kv_ensure_space(v, len) \ - do { \ - if ((v).capacity < (v).size + len) { \ - (v).capacity = (v).size + len; \ - kv_roundup32((v).capacity); \ - kv_resize((v), (v).capacity); \ - } \ - } while (0) - -#define kv_concat_len(v, data, len) \ - do { \ - kv_ensure_space(v, len); \ - memcpy((v).items + (v).size, data, sizeof((v).items[0]) * len); \ - (v).size = (v).size + len; \ - } while (0) - -#define kv_concat(v, str) kv_concat_len(v, str, STRLEN(str)) -#define kv_splice(v1, v0) kv_concat_len(v1, (v0).items, (v0).size) - -#define kv_pushp(v) \ - ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \ - ((v).items + ((v).size++))) - -#define kv_push(v, x) \ - (*kv_pushp(v) = (x)) - -#define kv_pushp_c(v) ((v).items + ((v).size++)) -#define kv_push_c(v, x) (*kv_pushp_c(v) = (x)) - -#define kv_a(v, i) \ - (*(((v).capacity <= (size_t)(i) \ - ? ((v).capacity = (v).size = (i) + 1, \ - kv_roundup32((v).capacity), \ - kv_resize((v), (v).capacity), 0UL) \ - : ((v).size <= (size_t)(i) \ - ? (v).size = (i) + 1 \ - : 0UL)), \ - &(v).items[(i)])) - -#define kv_printf(v, ...) kv_do_printf(&(v), __VA_ARGS__) - -/// Type of a vector with a few first members allocated on stack -/// -/// Is compatible with #kv_A, #kv_pop, #kv_size, #kv_max, #kv_last. -/// Is not compatible with #kv_resize, #kv_resize_full, #kv_copy, #kv_push, -/// #kv_pushp, #kv_a, #kv_destroy. -/// -/// @param[in] type Type of vector elements. -/// @param[in] init_size Number of the elements in the initial array. -#define kvec_withinit_t(type, INIT_SIZE) \ - struct { \ - size_t size; \ - size_t capacity; \ - type *items; \ - type init_array[INIT_SIZE]; \ - } - -/// Initialize vector with preallocated array -/// -/// @param[out] v Vector to initialize. -#define kvi_init(v) \ - ((v).capacity = ARRAY_SIZE((v).init_array), \ - (v).size = 0, \ - (v).items = (v).init_array) - -/// Move data to a new destination and free source -static inline void *_memcpy_free(void *const restrict dest, void *const restrict src, - const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE -{ - memcpy(dest, src, size); - XFREE_CLEAR(src); - return dest; -} - -// -V:kvi_push:512 - -/// Resize vector with preallocated array -/// -/// @note May not resize to an array smaller then init_array: if requested, -/// init_array will be used. -/// -/// @param[out] v Vector to resize. -/// @param[in] s New size. -#define kvi_resize(v, s) \ - ((v).capacity = ((s) > ARRAY_SIZE((v).init_array) \ - ? (s) \ - : ARRAY_SIZE((v).init_array)), \ - (v).items = ((v).capacity == ARRAY_SIZE((v).init_array) \ - ? ((v).items == (v).init_array \ - ? (v).items \ - : _memcpy_free((v).init_array, (v).items, \ - (v).size * sizeof((v).items[0]))) \ - : ((v).items == (v).init_array \ - ? memcpy(xmalloc((v).capacity * sizeof((v).items[0])), \ - (v).items, \ - (v).size * sizeof((v).items[0])) \ - : xrealloc((v).items, \ - (v).capacity * sizeof((v).items[0]))))) - -/// Resize vector with preallocated array when it is full -/// -/// @param[out] v Vector to resize. -#define kvi_resize_full(v) \ - /* ARRAY_SIZE((v).init_array) is the minimal capacity of this vector. */ \ - /* Thus when vector is full capacity may not be zero and it is safe */ \ - /* not to bother with checking whether (v).capacity is 0. But now */ \ - /* capacity is not guaranteed to have size that is a power of 2, it is */ \ - /* hard to fix this here and is not very necessary if users will use */ \ - /* 2^x initial array size. */ \ - kvi_resize(v, (v).capacity << 1) - -/// Get location where to store new element to a vector with preallocated array -/// -/// @param[in,out] v Vector to push to. -/// -/// @return Pointer to the place where new value should be stored. -#define kvi_pushp(v) \ - ((((v).size == (v).capacity) ? (kvi_resize_full(v), 0) : 0), \ - ((v).items + ((v).size++))) - -/// Push value to a vector with preallocated array -/// -/// @param[out] v Vector to push to. -/// @param[in] x Value to push. -#define kvi_push(v, x) \ - (*kvi_pushp(v) = (x)) - -/// Free array of elements of a vector with preallocated array if needed -/// -/// @param[out] v Vector to free. -#define kvi_destroy(v) \ - do { \ - if ((v).items != (v).init_array) { \ - XFREE_CLEAR((v).items); \ - } \ - } while (0) - -#endif // NVIM_LIB_KVEC_H diff --git a/src/nvim/locale.c b/src/nvim/locale.c new file mode 100644 index 0000000000..c472d9ba66 --- /dev/null +++ b/src/nvim/locale.c @@ -0,0 +1,369 @@ +// 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 + +// locale.c: functions for language/locale configuration + +#include "auto/config.h" + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#include "nvim/ascii.h" +#include "nvim/buffer.h" +#include "nvim/charset.h" +#include "nvim/eval.h" +#include "nvim/garray.h" +#include "nvim/locale.h" +#include "nvim/memory.h" +#include "nvim/message.h" +#include "nvim/option.h" +#include "nvim/os/os.h" +#include "nvim/os/shell.h" +#include "nvim/path.h" +#include "nvim/profile.h" +#include "nvim/types.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "locale.c.generated.h" +#endif + +#if defined(HAVE_LOCALE_H) +# define HAVE_GET_LOCALE_VAL + +static char *get_locale_val(int what) +{ + // Obtain the locale value from the libraries. + char *loc = setlocale(what, NULL); + + return loc; +} +#endif + +/// @return true when "lang" starts with a valid language name. +/// Rejects NULL, empty string, "C", "C.UTF-8" and others. +static bool is_valid_mess_lang(char *lang) +{ + return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]); +} + +/// Obtain the current messages language. Used to set the default for +/// 'helplang'. May return NULL or an empty string. +char *get_mess_lang(void) +{ + char *p; + +#ifdef HAVE_GET_LOCALE_VAL +# if defined(LC_MESSAGES) + p = get_locale_val(LC_MESSAGES); +# else + // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG + // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME + // and LC_MONETARY may be set differently for a Japanese working in the + // US. + p = get_locale_val(LC_COLLATE); +# endif +#else + p = os_getenv("LC_ALL"); + if (!is_valid_mess_lang(p)) { + p = os_getenv("LC_MESSAGES"); + if (!is_valid_mess_lang(p)) { + p = os_getenv("LANG"); + } + } +#endif + return is_valid_mess_lang(p) ? p : NULL; +} + +// Complicated #if; matches with where get_mess_env() is used below. +#ifdef HAVE_WORKING_LIBINTL +/// Get the language used for messages from the environment. +static char *get_mess_env(void) +{ + char *p; + + p = (char *)os_getenv("LC_ALL"); + if (p == NULL) { + p = (char *)os_getenv("LC_MESSAGES"); + if (p == NULL) { + p = (char *)os_getenv("LANG"); + if (p != NULL && ascii_isdigit(*p)) { + p = NULL; // ignore something like "1043" + } +# ifdef HAVE_GET_LOCALE_VAL + if (p == NULL) { + p = get_locale_val(LC_CTYPE); + } +# endif + } + } + return p; +} +#endif + +/// Set the "v:lang" variable according to the current locale setting. +/// Also do "v:lc_time"and "v:ctype". +void set_lang_var(void) +{ + const char *loc; + +#ifdef HAVE_GET_LOCALE_VAL + loc = get_locale_val(LC_CTYPE); +#else + // setlocale() not supported: use the default value + loc = "C"; +#endif + set_vim_var_string(VV_CTYPE, loc, -1); + + // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall + // back to LC_CTYPE if it's empty. +#ifdef HAVE_WORKING_LIBINTL + loc = get_mess_env(); +#elif defined(LC_MESSAGES) + loc = get_locale_val(LC_MESSAGES); +#else + // In Windows LC_MESSAGES is not defined fallback to LC_CTYPE + loc = get_locale_val(LC_CTYPE); +#endif + set_vim_var_string(VV_LANG, loc, -1); + +#ifdef HAVE_GET_LOCALE_VAL + loc = get_locale_val(LC_TIME); +#endif + set_vim_var_string(VV_LC_TIME, loc, -1); + +#ifdef HAVE_GET_LOCALE_VAL + loc = get_locale_val(LC_COLLATE); +#else + // setlocale() not supported: use the default value + loc = "C"; +#endif + set_vim_var_string(VV_COLLATE, loc, -1); +} + +#if defined(HAVE_LOCALE_H) +/// Setup to use the current locale (for ctype() and many other things). +void init_locale(void) +{ + setlocale(LC_ALL, ""); + +# ifdef LC_NUMERIC + // Make sure strtod() uses a decimal point, not a comma. + setlocale(LC_NUMERIC, "C"); +# endif + + char localepath[MAXPATHL] = { 0 }; + snprintf(localepath, sizeof(localepath), "%s", get_vim_var_str(VV_PROGPATH)); + char *tail = path_tail_with_sep(localepath); + *tail = NUL; + tail = path_tail(localepath); + xstrlcpy(tail, "share/locale", + sizeof(localepath) - (size_t)(tail - localepath)); + bindtextdomain(PROJECT_NAME, localepath); + textdomain(PROJECT_NAME); + TIME_MSG("locale set"); +} +#endif + +#ifdef HAVE_WORKING_LIBINTL + +/// ":language": Set the language (locale). +/// +/// @param eap +void ex_language(exarg_T *eap) +{ + char *loc; + char *p; + char *name; + int what = LC_ALL; + char *whatstr = ""; +# ifdef LC_MESSAGES +# define VIM_LC_MESSAGES LC_MESSAGES +# else +# define VIM_LC_MESSAGES 6789 +# endif + + name = eap->arg; + + // Check for "messages {name}", "ctype {name}" or "time {name}" argument. + // Allow abbreviation, but require at least 3 characters to avoid + // confusion with a two letter language name "me" or "ct". + p = skiptowhite(eap->arg); + if ((*p == NUL || ascii_iswhite(*p)) && p - eap->arg >= 3) { + if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) { + what = VIM_LC_MESSAGES; + name = skipwhite(p); + whatstr = "messages "; + } else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) { + what = LC_CTYPE; + name = skipwhite(p); + whatstr = "ctype "; + } else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) { + what = LC_TIME; + name = skipwhite(p); + whatstr = "time "; + } else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0) { + what = LC_COLLATE; + name = skipwhite(p); + whatstr = "collate "; + } + } + + if (*name == NUL) { + if (what == VIM_LC_MESSAGES) { + p = get_mess_env(); + } else { + p = setlocale(what, NULL); + } + if (p == NULL || *p == NUL) { + p = "Unknown"; + } + smsg(_("Current %slanguage: \"%s\""), whatstr, p); + } else { +# ifndef LC_MESSAGES + if (what == VIM_LC_MESSAGES) { + loc = ""; + } else { +# endif + loc = setlocale(what, name); +# ifdef LC_NUMERIC + // Make sure strtod() uses a decimal point, not a comma. + setlocale(LC_NUMERIC, "C"); +# endif +# ifndef LC_MESSAGES + } +# endif + if (loc == NULL) { + semsg(_("E197: Cannot set language to \"%s\""), name); + } else { +# ifdef HAVE_NL_MSG_CAT_CNTR + // Need to do this for GNU gettext, otherwise cached translations + // will be used again. + extern int _nl_msg_cat_cntr; + + _nl_msg_cat_cntr++; +# endif + // Reset $LC_ALL, otherwise it would overrule everything. + os_setenv("LC_ALL", "", 1); + + if (what != LC_TIME && what != LC_COLLATE) { + // Tell gettext() what to translate to. It apparently doesn't + // use the currently effective locale. + if (what == LC_ALL) { + os_setenv("LANG", name, 1); + + // Clear $LANGUAGE because GNU gettext uses it. + os_setenv("LANGUAGE", "", 1); + } + if (what != LC_CTYPE) { + os_setenv("LC_MESSAGES", name, 1); + set_helplang_default(name); + } + } + + // Set v:lang, v:lc_time, v:collate and v:ctype to the final result. + set_lang_var(); + maketitle(); + } + } +} + +static char **locales = NULL; // Array of all available locales + +# ifndef MSWIN +static bool did_init_locales = false; + +/// @return an array of strings for all available locales + NULL for the +/// last element or, +/// NULL in case of error. +static char **find_locales(void) +{ + garray_T locales_ga; + char *loc; + char *saveptr = NULL; + + // Find all available locales by running command "locale -a". If this + // doesn't work we won't have completion. + char *locale_a = (char *)get_cmd_output((char_u *)"locale -a", NULL, + kShellOptSilent, NULL); + if (locale_a == NULL) { + return NULL; + } + ga_init(&locales_ga, sizeof(char_u *), 20); + + // Transform locale_a string where each locale is separated by "\n" + // into an array of locale strings. + loc = os_strtok(locale_a, "\n", &saveptr); + + while (loc != NULL) { + loc = xstrdup(loc); + GA_APPEND(char *, &locales_ga, loc); + loc = os_strtok(NULL, "\n", &saveptr); + } + xfree(locale_a); + // Guarantee that .ga_data is NULL terminated + ga_grow(&locales_ga, 1); + ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL; + return locales_ga.ga_data; +} +# endif + +/// Lazy initialization of all available locales. +static void init_locales(void) +{ +# ifndef MSWIN + if (!did_init_locales) { + did_init_locales = true; + locales = find_locales(); + } +# endif +} + +# if defined(EXITFREE) +void free_locales(void) +{ + int i; + if (locales != NULL) { + for (i = 0; locales[i] != NULL; i++) { + xfree(locales[i]); + } + XFREE_CLEAR(locales); + } +} +# endif + +/// Function given to ExpandGeneric() to obtain the possible arguments of the +/// ":language" command. +char *get_lang_arg(expand_T *xp, int idx) +{ + if (idx == 0) { + return "messages"; + } + if (idx == 1) { + return "ctype"; + } + if (idx == 2) { + return "time"; + } + if (idx == 3) { + return "collate"; + } + + init_locales(); + if (locales == NULL) { + return NULL; + } + return locales[idx - 4]; +} + +/// Function given to ExpandGeneric() to obtain the available locales. +char *get_locales(expand_T *xp, int idx) +{ + init_locales(); + if (locales == NULL) { + return NULL; + } + return locales[idx]; +} + +#endif diff --git a/src/nvim/locale.h b/src/nvim/locale.h new file mode 100644 index 0000000000..39735d371f --- /dev/null +++ b/src/nvim/locale.h @@ -0,0 +1,10 @@ +#ifndef NVIM_LOCALE_H +#define NVIM_LOCALE_H + +#include "nvim/ex_cmds_defs.h" +#include "nvim/types.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "locale.h.generated.h" +#endif +#endif // NVIM_LOCALE_H diff --git a/src/nvim/log.c b/src/nvim/log.c index 99b17a612b..9bdf327430 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -60,16 +60,16 @@ static bool log_try_create(char *fname) static void log_path_init(void) { size_t size = sizeof(log_file_path); - expand_env((char_u *)"$" ENV_LOGFILE, (char_u *)log_file_path, (int)size - 1); + expand_env("$" ENV_LOGFILE, log_file_path, (int)size - 1); if (strequal("$" ENV_LOGFILE, log_file_path) || log_file_path[0] == '\0' - || os_isdir((char_u *)log_file_path) + || os_isdir(log_file_path) || !log_try_create(log_file_path)) { // Make $XDG_STATE_HOME if it does not exist. char *loghome = get_xdg_home(kXDGStateHome); char *failed_dir = NULL; bool log_dir_failure = false; - if (!os_isdir((char_u *)loghome)) { + if (!os_isdir(loghome)) { log_dir_failure = (os_mkdir_recurse(loghome, 0700, &failed_dir) != 0); } XFREE_CLEAR(loghome); diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 49d49f76b9..bdb0719809 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -15,12 +15,12 @@ #include "nvim/memory.h" // FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is // redefined +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/eval/decode.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/globals.h" -#include "nvim/lib/kvec.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/macros.h" @@ -385,15 +385,12 @@ nlua_pop_typval_table_processing_end: break; } case LUA_TFUNCTION: { - LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = nlua_ref_global(lstate, -1); + LuaRef func = nlua_ref_global(lstate, -1); - char_u *name = register_cfunc(&nlua_CFunction_func_call, - &nlua_CFunction_func_free, - state); + char *name = (char *)register_luafunc(func); cur.tv->v_type = VAR_FUNC; - cur.tv->vval.v_string = (char *)vim_strsave(name); + cur.tv->vval.v_string = xstrdup(name); break; } case LUA_TUSERDATA: { @@ -476,8 +473,8 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ ufunc_T *fp = find_func(fun); \ - if (fp != NULL && fp->uf_cb == nlua_CFunction_func_call) { \ - nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \ + if (fp != NULL && fp->uf_flags & FC_LUAREF) { \ + nlua_pushref(lstate, fp->uf_luaref); \ } else { \ TYPVAL_ENCODE_CONV_NIL(tv); \ } \ diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h index f6a85900ba..ddc0acfbfa 100644 --- a/src/nvim/lua/converter.h +++ b/src/nvim/lua/converter.h @@ -9,14 +9,6 @@ #include "nvim/eval/typval.h" #include "nvim/func_attr.h" -typedef struct { - LuaRef func_ref; -} LuaCallable; - -typedef struct { - LuaCallable lua_callable; -} LuaCFunctionState; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/converter.h.generated.h" #endif diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d1d1480696..f3821f149a 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -7,6 +7,7 @@ #include <tree_sitter/api.h> #include "luv/luv.h" +#include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" @@ -40,6 +41,9 @@ #include "nvim/os/os.h" #include "nvim/profile.h" #include "nvim/runtime.h" +#include "nvim/screen.h" +#include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/usercmd.h" #include "nvim/version.h" @@ -244,7 +248,7 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres mch_errmsg(e_outofmem); mch_errmsg("\n"); lua_close(lstate); -#ifdef WIN32 +#ifdef MSWIN ExitThread(0); #else pthread_exit(0); @@ -589,6 +593,71 @@ static bool nlua_init_packages(lua_State *lstate) return true; } +/// "vim.ui_attach(ns_id, {ext_foo=true}, cb)" function +static int nlua_ui_attach(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1); + + if (!ns_initialized(ns_id)) { + return luaL_error(lstate, "invalid ns_id"); + } + if (!lua_istable(lstate, 2)) { + return luaL_error(lstate, "ext_widgets must be a table"); + } + if (!lua_isfunction(lstate, 3)) { + return luaL_error(lstate, "callback must be a Lua function"); + } + + bool ext_widgets[kUIGlobalCount] = { false }; + bool tbl_has_true_val = false; + + lua_pushvalue(lstate, 2); + lua_pushnil(lstate); + while (lua_next(lstate, -2)) { + // [dict, key, val] + size_t len; + const char *s = lua_tolstring(lstate, -2, &len); + bool val = lua_toboolean(lstate, -1); + + for (size_t i = 0; i < kUIGlobalCount; i++) { + if (strequal(s, ui_ext_names[i])) { + if (val) { + tbl_has_true_val = true; + } + ext_widgets[i] = val; + goto ok; + } + } + + return luaL_error(lstate, "Unexpected key: %s", s); +ok: + lua_pop(lstate, 1); + } + + if (!tbl_has_true_val) { + return luaL_error(lstate, "ext_widgets table must contain at least one 'true' value"); + } + + LuaRef ui_event_cb = nlua_ref_global(lstate, 3); + ui_comp_add_cb(ns_id, ui_event_cb, ext_widgets); + return 0; +} + +/// "vim.ui_detach(ns_id)" function +static int nlua_ui_detach(lua_State *lstate) + FUNC_ATTR_NONNULL_ALL +{ + uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1); + + if (!ns_initialized(ns_id)) { + return luaL_error(lstate, "invalid ns_id"); + } + + ui_comp_remove_cb(ns_id); + return 0; +} + /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -604,7 +673,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setfield(lstate, -2, "debug"); lua_pop(lstate, 1); -#ifdef WIN32 +#ifdef MSWIN // os.getenv lua_getglobal(lstate, "os"); lua_pushcfunction(lstate, &nlua_getenv); @@ -649,6 +718,14 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_wait); lua_setfield(lstate, -2, "wait"); + // ui_attach + lua_pushcfunction(lstate, &nlua_ui_attach); + lua_setfield(lstate, -2, "ui_attach"); + + // ui_detach + lua_pushcfunction(lstate, &nlua_ui_detach); + lua_setfield(lstate, -2, "ui_detach"); + nlua_common_vim_init(lstate, false); // patch require() (only for --startuptime) @@ -967,12 +1044,12 @@ static int nlua_debug(lua_State *lstate) if (input.v_type != VAR_STRING || input.vval.v_string == NULL || *input.vval.v_string == NUL - || STRCMP(input.vval.v_string, "cont") == 0) { + || strcmp(input.vval.v_string, "cont") == 0) { tv_clear(&input); return 0; } if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string, - STRLEN(input.vval.v_string), "=(debug command)")) { + strlen(input.vval.v_string), "=(debug command)")) { nlua_error(lstate, _("E5115: Error while loading debug string: %.*s")); } else if (nlua_pcall(lstate, 0, 0)) { nlua_error(lstate, _("E5116: Error while calling debug string: %.*s")); @@ -990,7 +1067,7 @@ int nlua_in_fast_event(lua_State *lstate) static bool viml_func_is_fast(const char *name) { - const EvalFuncDef *const fdef = find_internal_func((const char *)name); + const EvalFuncDef *const fdef = find_internal_func(name); if (fdef) { return fdef->fast; } @@ -1027,15 +1104,15 @@ int nlua_call(lua_State *lstate) // TODO(bfredl): this should be simplified in error handling refactor force_abort = false; suppress_errthrow = false; - current_exception = NULL; + did_throw = false; did_emsg = false; try_start(); typval_T rettv; funcexe_T funcexe = FUNCEXE_INIT; - funcexe.firstline = curwin->w_cursor.lnum; - funcexe.lastline = curwin->w_cursor.lnum; - funcexe.evaluate = true; + funcexe.fe_firstline = curwin->w_cursor.lnum; + funcexe.fe_lastline = curwin->w_cursor.lnum; + funcexe.fe_evaluate = true; // call_func() retval is deceptive, ignore it. Instead we set `msg_list` // (TRY_WRAP) to capture abort-causing non-exception errors. (void)call_func((char *)name, (int)name_len, &rettv, nargs, vim_args, &funcexe); @@ -1093,7 +1170,7 @@ static int nlua_rpc(lua_State *lstate, bool request) Object result = rpc_send_call(chan_id, name, args, &res_mem, &err); if (!ERROR_SET(&err)) { nlua_push_Object(lstate, result, false); - arena_mem_free(res_mem, NULL); + arena_mem_free(res_mem); } } else { if (!rpc_send_event(chan_id, name, args)) { @@ -1124,7 +1201,7 @@ static int nlua_empty_dict_tostring(lua_State *lstate) return 1; } -#ifdef WIN32 +#ifdef MSWIN /// os.getenv: override os.getenv to maintain coherency. #9681 /// /// uv_os_setenv uses SetEnvironmentVariableW which does not update _environ. @@ -1348,23 +1425,22 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) /// @param[in] argcount Count of typval arguments /// @param[in] argvars Typval Arguments /// @param[out] rettv The return value from the called function. -int typval_exec_lua_callable(lua_State *lstate, LuaCallable lua_cb, int argcount, typval_T *argvars, - typval_T *rettv) +int typval_exec_lua_callable(LuaRef lua_cb, int argcount, typval_T *argvars, typval_T *rettv) { - LuaRef cb = lua_cb.func_ref; + lua_State *lstate = global_lstate; - nlua_pushref(lstate, cb); + nlua_pushref(lstate, lua_cb); PUSH_ALL_TYPVALS(lstate, argvars, argcount, false); if (nlua_pcall(lstate, argcount, 1)) { nlua_print(lstate); - return ERROR_OTHER; + return FCERR_OTHER; } nlua_pop_typval(lstate, rettv); - return ERROR_NONE; + return FCERR_NONE; } /// Execute Lua string @@ -1422,9 +1498,10 @@ bool nlua_ref_is_function(LuaRef ref) /// @param name if non-NULL, sent to callback as first arg /// if NULL, only args are used /// @param retval if true, convert return value to Object -/// if false, discard return value +/// if false, only check if return value is truthy /// @param err Error details, if any (if NULL, errors are echoed) -/// @return Return value of function, if retval was set. Otherwise NIL. +/// @return Return value of function, if retval was set. Otherwise +/// BOOLEAN_OBJ(true) or NIL. Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err) { lua_State *const lstate = global_lstate; @@ -1438,7 +1515,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro nlua_push_Object(lstate, args.items[i], false); } - if (nlua_pcall(lstate, nargs, retval ? 1 : 0)) { + if (nlua_pcall(lstate, nargs, 1)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; @@ -1458,7 +1535,10 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro } return nlua_pop_Object(lstate, false, err); } else { - return NIL; + bool value = lua_toboolean(lstate, -1); + lua_pop(lstate, 1); + + return value ? BOOLEAN_OBJ(true) : NIL; } } @@ -1561,7 +1641,7 @@ void ex_luado(exarg_T *const eap) break; } if (lua_isstring(lstate, -1)) { - size_t old_line_len = STRLEN(old_line); + size_t old_line_len = strlen(old_line); size_t new_line_len; const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); @@ -1578,7 +1658,7 @@ void ex_luado(exarg_T *const eap) } lua_pop(lstate, 1); check_cursor(); - update_screen(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); } /// Run lua file @@ -1662,6 +1742,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_has_language); lua_setfield(lstate, -2, "_ts_has_language"); + lua_pushcfunction(lstate, tslua_remove_lang); + lua_setfield(lstate, -2, "_ts_remove_language"); + lua_pushcfunction(lstate, tslua_inspect_lang); lua_setfield(lstate, -2, "_ts_inspect_language"); @@ -1749,26 +1832,6 @@ static int nlua_is_thread(lua_State *lstate) return 1; } -// Required functions for lua c functions as VimL callbacks - -int nlua_CFunction_func_call(int argcount, typval_T *argvars, typval_T *rettv, void *state) -{ - lua_State *const lstate = global_lstate; - LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - - return typval_exec_lua_callable(lstate, funcstate->lua_callable, - argcount, argvars, rettv); -} - -void nlua_CFunction_func_free(void *state) -{ - lua_State *const lstate = global_lstate; - LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - - nlua_unref_global(lstate, funcstate->lua_callable.func_ref); - xfree(funcstate); -} - bool nlua_is_table_from_lua(typval_T *const arg) { if (arg->v_type == VAR_DICT) { @@ -1814,11 +1877,9 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) } lua_pop(lstate, 2); // [table] - LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = nlua_ref_global(lstate, -1); + LuaRef func = nlua_ref_global(lstate, -1); - char_u *name = register_cfunc(&nlua_CFunction_func_call, - &nlua_CFunction_func_free, state); + char_u *name = register_luafunc(func); lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); @@ -1940,7 +2001,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) // Split args by unescaped whitespace |<f-args>| (nargs dependent) if (cmd->uc_argt & EX_NOSPC) { - if ((cmd->uc_argt & EX_NEEDARG) || STRLEN(eap->arg)) { + if ((cmd->uc_argt & EX_NEEDARG) || strlen(eap->arg)) { // For commands where nargs is 1 or "?" and argument is passed, fargs = { args } lua_rawseti(lstate, -2, 1); } else { @@ -1950,7 +2011,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) } else if (eap->args == NULL) { // For commands with more than one possible argument, split if argument list isn't available. lua_pop(lstate, 1); // Pop the reference of opts.args - size_t length = STRLEN(eap->arg); + size_t length = strlen(eap->arg); size_t end = 0; size_t len = 0; int i = 1; @@ -1975,7 +2036,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) } lua_setfield(lstate, -2, "fargs"); - lua_pushstring(lstate, (const char *)&eap->regname); + char reg[2] = { (char)eap->regname, NUL }; + lua_pushstring(lstate, reg); lua_setfield(lstate, -2, "reg"); lua_pushinteger(lstate, eap->addr_count); @@ -1998,7 +2060,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_newtable(lstate); // smods table - lua_pushinteger(lstate, cmdmod.cmod_tab); + lua_pushinteger(lstate, cmdmod.cmod_tab - 1); lua_setfield(lstate, -2, "tab"); lua_pushinteger(lstate, cmdmod.cmod_verbose - 1); @@ -2019,6 +2081,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) lua_pushboolean(lstate, cmdmod.cmod_split & WSP_VERT); lua_setfield(lstate, -2, "vertical"); + lua_pushboolean(lstate, cmdmod.cmod_split & WSP_HOR); + lua_setfield(lstate, -2, "horizontal"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT); lua_setfield(lstate, -2, "silent"); lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT); diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 5a82ae30b5..2f46f6ff65 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -60,8 +60,8 @@ static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) *prog = rm.regprog; if (match) { - lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - str)); - lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - str)); + lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - (char *)str)); + lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - (char *)str)); return 2; } return 0; @@ -111,7 +111,7 @@ static int regex_match_line(lua_State *lstate) return luaL_error(lstate, "invalid row"); } - char_u *line = ml_get_buf(buf, rownr + 1, false); + char_u *line = (char_u *)ml_get_buf(buf, rownr + 1, false); size_t len = STRLEN(line); if (start < 0 || (size_t)start > len) { @@ -304,8 +304,10 @@ int nlua_regex(lua_State *lstate) nlua_push_errstr(lstate, "couldn't parse regex: %s", err.msg); api_clear_error(&err); return lua_error(lstate); + } else if (prog == NULL) { + nlua_push_errstr(lstate, "couldn't parse regex"); + return lua_error(lstate); } - assert(prog); regprog_T **p = lua_newuserdata(lstate, sizeof(regprog_T *)); *p = prog; @@ -369,12 +371,19 @@ int nlua_setvar(lua_State *lstate) return 0; } + bool watched = tv_dict_is_watched(dict); + if (del) { // Delete the key if (di == NULL) { // Doesn't exist, nothing to do return 0; } else { + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv); + } + // Delete the entry tv_dict_item_remove(dict, di); } @@ -388,17 +397,29 @@ int nlua_setvar(lua_State *lstate) return luaL_error(lstate, "Couldn't convert lua value"); } + typval_T oldtv = TV_INITIAL_VALUE; + if (di == NULL) { // Need to create an entry di = tv_dict_item_alloc_len(key.data, key.size); tv_dict_add(dict, di); } else { + if (watched) { + tv_copy(&di->di_tv, &oldtv); + } // Clear the old value tv_clear(&di->di_tv); } // Update the value tv_copy(&tv, &di->di_tv); + + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, &tv, &oldtv); + tv_clear(&oldtv); + } + // Clear the temporary variable tv_clear(&tv); } @@ -474,6 +495,52 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } +#if defined(HAVE_ICONV) + +/// Convert string from one encoding to another +static int nlua_iconv(lua_State *lstate) +{ + int narg = lua_gettop(lstate); + + if (narg < 3) { + return luaL_error(lstate, "Expected at least 3 arguments"); + } + + for (int i = 1; i <= 3; i++) { + if (lua_type(lstate, i) != LUA_TSTRING) { + return luaL_argerror(lstate, i, "expected string"); + } + } + + size_t str_len = 0; + const char *str = lua_tolstring(lstate, 1, &str_len); + + char_u *from = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL))); + char_u *to = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL))); + + vimconv_T vimconv; + vimconv.vc_type = CONV_NONE; + convert_setup_ext(&vimconv, (char *)from, false, (char *)to, false); + + char_u *ret = (char_u *)string_convert(&vimconv, (char *)str, &str_len); + + convert_setup(&vimconv, NULL, NULL); + + xfree(from); + xfree(to); + + if (ret == NULL) { + lua_pushnil(lstate); + } else { + lua_pushlstring(lstate, (char *)ret, str_len); + xfree(ret); + } + + return 1; +} + +#endif + void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { @@ -519,6 +586,13 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) // vim.spell luaopen_spell(lstate); lua_setfield(lstate, -2, "spell"); + +#if defined(HAVE_ICONV) + // vim.iconv + // depends on p_ambw, p_emoji + lua_pushcfunction(lstate, &nlua_iconv); + lua_setfield(lstate, -2, "iconv"); +#endif } // vim.mpack diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index f0d847e352..79b11eca4a 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -14,11 +14,14 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <uv.h> +#include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/buffer.h" -#include "nvim/lib/kvec.h" +#include "nvim/log.h" #include "nvim/lua/treesitter.h" +#include "nvim/map.h" #include "nvim/memline.h" #include "tree_sitter/api.h" @@ -85,6 +88,10 @@ static struct luaL_Reg node_meta[] = { { "prev_sibling", node_prev_sibling }, { "next_named_sibling", node_next_named_sibling }, { "prev_named_sibling", node_prev_named_sibling }, + { "named_children", node_named_children }, + { "root", node_root }, + { "byte_length", node_byte_length }, + { NULL, NULL } }; @@ -145,18 +152,27 @@ int tslua_has_language(lua_State *L) return 1; } +// Creates the language into the internal language map. +// +// Returns true if the language is correctly loaded in the language map int tslua_add_language(lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *lang_name = luaL_checkstring(L, 2); + const char *symbol_name = lang_name; + + if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) { + symbol_name = luaL_checkstring(L, 3); + } if (pmap_has(cstr_t)(&langs, lang_name)) { - return 0; + lua_pushboolean(L, true); + return 1; } #define BUFSIZE 128 char symbol_buf[BUFSIZE]; - snprintf(symbol_buf, BUFSIZE, "tree_sitter_%s", lang_name); + snprintf(symbol_buf, BUFSIZE, "tree_sitter_%s", symbol_name); #undef BUFSIZE uv_lib_t lib; @@ -179,6 +195,7 @@ int tslua_add_language(lua_State *L) TSLanguage *lang = lang_parser(); if (lang == NULL) { + uv_dlclose(&lib); return luaL_error(L, "Failed to load parser %s: internal error", path); } @@ -198,6 +215,19 @@ int tslua_add_language(lua_State *L) return 1; } +int tslua_remove_lang(lua_State *L) +{ + const char *lang_name = luaL_checkstring(L, 1); + bool present = pmap_has(cstr_t)(&langs, lang_name); + if (present) { + char *key = (char *)pmap_key(cstr_t)(&langs, lang_name); + pmap_del(cstr_t)(&langs, lang_name); + xfree(key); + } + lua_pushboolean(L, present); + return 1; +} + int tslua_inspect_lang(lua_State *L) { const char *lang_name = luaL_checkstring(L, 1); @@ -302,7 +332,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position *bytes_read = 0; return ""; } - char *line = (char *)ml_get_buf(bp, (linenr_T)position.row + 1, false); + char *line = ml_get_buf(bp, (linenr_T)position.row + 1, false); size_t len = STRLEN(line); if (position.column > len) { *bytes_read = 0; @@ -593,7 +623,7 @@ void push_tree(lua_State *L, TSTree *tree, bool do_copy) lua_setfenv(L, -2); // [udata] } -static TSTree **tree_check(lua_State *L, uint16_t index) +static TSTree **tree_check(lua_State *L, int index) { TSTree **ud = luaL_checkudata(L, index, TS_META_TREE); return ud; @@ -804,7 +834,7 @@ static int node_field(lua_State *L) do { const char *current_field = ts_tree_cursor_current_field_name(&cursor); - if (current_field != NULL && !STRCMP(field_name, current_field)) { + 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, (int)++curr_index); } @@ -1036,6 +1066,57 @@ static int node_prev_named_sibling(lua_State *L) return 1; } +static int node_named_children(lua_State *L) +{ + TSNode source; + if (!node_check(L, 1, &source)) { + return 0; + } + TSTreeCursor cursor = ts_tree_cursor_new(source); + + lua_newtable(L); + int curr_index = 0; + + if (ts_tree_cursor_goto_first_child(&cursor)) { + do { + TSNode node = ts_tree_cursor_current_node(&cursor); + if (ts_node_is_named(node)) { + push_node(L, node, 1); + lua_rawseti(L, -2, ++curr_index); + } + } while (ts_tree_cursor_goto_next_sibling(&cursor)); + } + + ts_tree_cursor_delete(&cursor); + return 1; +} + +static int node_root(lua_State *L) +{ + TSNode node; + if (!node_check(L, 1, &node)) { + return 0; + } + + TSNode root = ts_tree_root_node(node.tree); + push_node(L, root, 1); + return 1; +} + +static int node_byte_length(lua_State *L) +{ + TSNode node; + if (!node_check(L, 1, &node)) { + return 0; + } + + uint32_t start_byte = ts_node_start_byte(node); + uint32_t end_byte = ts_node_end_byte(node); + + lua_pushnumber(L, end_byte - start_byte); + return 1; +} + /// assumes the match table being on top of the stack static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx) { @@ -1195,8 +1276,8 @@ int tslua_parse_query(lua_State *L) 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", - query_err_string(error_type), (int)error_offset); + return luaL_error(L, "query: %s at position %d for language %s", + query_err_string(error_type), (int)error_offset, lang_name); } TSQuery **ud = lua_newuserdata(L, sizeof(TSQuery *)); // [udata] @@ -1288,7 +1369,7 @@ static int query_inspect(lua_State *L) lua_rawseti(L, -2, nextitem++); // [retval, patterns, pat, pred] } // last predicate should have ended with TypeDone - lua_pop(L, 1); // [retval, patters, pat] + lua_pop(L, 1); // [retval, patterns, pat] lua_rawseti(L, -2, (int)i + 1); // [retval, patterns] } lua_setfield(L, -2, "patterns"); // [retval] diff --git a/src/nvim/macros.h b/src/nvim/macros.h index a896a406d1..9b7562e86f 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -31,7 +31,7 @@ /// @return `s, sizeof(s) - 1` #define S_LEN(s) (s), (sizeof(s) - 1) -/// LINEEMPTY() - return TRUE if the line is empty +/// LINEEMPTY() - return true if the line is empty #define LINEEMPTY(p) (*ml_get(p) == NUL) // toupper() and tolower() that use the current locale. @@ -54,7 +54,7 @@ #define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || ascii_isdigit(c)) // Returns empty string if it is NULL. -#define EMPTY_IF_NULL(x) (char *)((x) ? (x) : (char_u *)"") +#define EMPTY_IF_NULL(x) ((x) ? (x) : "") /// Adjust chars in a language according to 'langmap' option. /// NOTE that there is no noticeable overhead if 'langmap' is not set. @@ -86,7 +86,7 @@ // mch_open_rw(): invoke os_open() with third argument for user R/W. #if defined(UNIX) // open in rw------- mode # define MCH_OPEN_RW(n, f) os_open((n), (f), (mode_t)0600) -#elif defined(WIN32) +#elif defined(MSWIN) # define MCH_OPEN_RW(n, f) os_open((n), (f), S_IREAD | S_IWRITE) #else # define MCH_OPEN_RW(n, f) os_open((n), (f), 0) @@ -104,7 +104,7 @@ // MB_PTR_BACK(): backup a pointer to the previous character, taking care of // multi-byte characters if needed. Only use with "p" > "s" ! #define MB_PTR_BACK(s, p) \ - (p -= utf_head_off((char_u *)(s), (char_u *)(p) - 1) + 1) + (p -= utf_head_off((char *)(s), (char *)(p) - 1) + 1) // MB_CHAR2BYTES(): convert character to bytes and advance pointer to bytes #define MB_CHAR2BYTES(c, b) ((b) += utf_char2bytes((c), ((char *)b))) @@ -178,14 +178,14 @@ // Type of uv_buf_t.len is platform-dependent. // Related: https://github.com/libuv/libuv/pull/1236 -#if defined(WIN32) +#if defined(MSWIN) # define UV_BUF_LEN(x) (ULONG)(x) #else # define UV_BUF_LEN(x) (x) #endif // Type of read()/write() `count` param is platform-dependent. -#if defined(WIN32) +#if defined(MSWIN) # define IO_COUNT(x) (unsigned)(x) #else # define IO_COUNT(x) (x) diff --git a/src/nvim/main.c b/src/nvim/main.c index d06b475934..5687e0a6a9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -25,23 +25,19 @@ #include "nvim/ex_getln.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/garray.h" +#include "nvim/grid.h" #include "nvim/hashtab.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/iconv.h" #include "nvim/if_cscope.h" #include "nvim/insexpand.h" +#include "nvim/locale.h" +#include "nvim/log.h" #include "nvim/lua/executor.h" #include "nvim/main.h" #include "nvim/mapping.h" -#include "nvim/ui_client.h" -#include "nvim/vim.h" -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif -#include "nvim/garray.h" -#include "nvim/grid.h" -#include "nvim/log.h" #include "nvim/mark.h" #include "nvim/mbyte.h" #include "nvim/memline.h" @@ -70,10 +66,12 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" +#include "nvim/ui_client.h" #include "nvim/ui_compositor.h" #include "nvim/version.h" +#include "nvim/vim.h" #include "nvim/window.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/os_win_console.h" #endif #include "nvim/api/private/defs.h" @@ -86,7 +84,7 @@ #include "nvim/msgpack_rpc/helpers.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/signal.h" -#ifndef WIN32 +#ifndef MSWIN # include "nvim/os/pty_process_unix.h" #endif #include "nvim/api/extmark.h" @@ -170,7 +168,7 @@ void early_init(mparm_T *paramp) runtime_init(); highlight_init(); -#ifdef WIN32 +#ifdef MSWIN OSVERSIONINFO ovi; ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionEx(&ovi); @@ -187,11 +185,11 @@ void early_init(mparm_T *paramp) init_locale(); #endif - // Allocate the first window and buffer. - // Can't do anything without it, exit when it fails. - if (!win_alloc_first()) { - os_exit(0); - } + // tabpage local options (p_ch) must be set before allocating first tabpage. + set_init_tablocal(); + + // Allocate the first tabpage, window and buffer. + win_alloc_first(); TIME_MSG("init first window"); alist_init(&global_alist); // Init the argument list to empty. @@ -212,13 +210,13 @@ void early_init(mparm_T *paramp) #ifdef MAKE_LIB int nvim_main(int argc, char **argv); // silence -Wmissing-prototypes int nvim_main(int argc, char **argv) -#elif defined(WIN32) +#elif defined(MSWIN) int wmain(int argc, wchar_t **argv_w) // multibyte args on Windows. #7060 #else int main(int argc, char **argv) #endif { -#if defined(WIN32) && !defined(MAKE_LIB) +#if defined(MSWIN) && !defined(MAKE_LIB) char **argv = xmalloc((size_t)argc * sizeof(char *)); for (int i = 0; i < argc; i++) { char *buf = NULL; @@ -316,7 +314,7 @@ int main(int argc, char **argv) assert(p_ch >= 0 && Rows >= p_ch && Rows - p_ch <= INT_MAX); cmdline_row = (int)(Rows - p_ch); msg_row = cmdline_row; - screenalloc(); // allocate screen buffers + default_grid_alloc(); // allocate screen buffers set_init_2(headless_mode); TIME_MSG("inits 2"); @@ -348,13 +346,15 @@ int main(int argc, char **argv) ui_builtin_start(); } TIME_MSG("done waiting for UI"); - - // prepare screen now, so external UIs can display messages - starting = NO_BUFFERS; - screenclear(); - TIME_MSG("init screen for UI"); + firstwin->w_prev_height = firstwin->w_height; // may have changed } + // prepare screen now + starting = NO_BUFFERS; + screenclear(); + win_new_screensize(); + TIME_MSG("clear screen"); + if (ui_client_channel_id) { ui_client_init(ui_client_channel_id); ui_client_execute(ui_client_channel_id); @@ -363,8 +363,8 @@ int main(int argc, char **argv) // Default mappings (incl. menus) Error err = ERROR_INIT; - Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim._init_default_mappings()"), - (Array)ARRAY_DICT_INIT, &err); + Object o = NLUA_EXEC_STATIC("return vim._init_default_mappings()", + (Array)ARRAY_DICT_INIT, &err); assert(!ERROR_SET(&err)); api_clear_error(&err); assert(o.type == kObjectTypeNil); @@ -434,10 +434,8 @@ int main(int argc, char **argv) p_ut = 1; } - // // Read in registers, history etc, from the ShaDa file. // This is where v:oldfiles gets filled. - // if (*p_shada != NUL) { shada_read_everything(NULL, false, true); TIME_MSG("reading ShaDa"); @@ -476,14 +474,7 @@ int main(int argc, char **argv) setmouse(); // may start using the mouse - if (exmode_active || use_remote_ui || use_builtin_ui) { - // Don't clear the screen when starting in Ex mode, or when a UI might have - // displayed messages. - redraw_later(curwin, VALID); - } else { - screenclear(); // clear screen - TIME_MSG("clearing screen"); - } + redraw_later(curwin, UPD_VALID); no_wait_return = true; @@ -508,7 +499,7 @@ int main(int argc, char **argv) // When started with "-q errorfile" jump to first error now. if (params.edit_type == EDIT_QF) { - qf_jump(NULL, 0, 0, FALSE); + qf_jump(NULL, 0, 0, false); TIME_MSG("jump to first error"); } @@ -520,7 +511,7 @@ int main(int argc, char **argv) if (params.diff_mode) { // set options in each window for "nvim -d". FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - diff_win_options(wp, TRUE); + diff_win_options(wp, true); } } @@ -539,7 +530,7 @@ int main(int argc, char **argv) starting = 0; RedrawingDisabled = 0; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); no_wait_return = false; // 'autochdir' has been postponed. @@ -584,7 +575,7 @@ int main(int argc, char **argv) // Main loop: never returns. normal_enter(false, false); -#if defined(WIN32) && !defined(MAKE_LIB) +#if defined(MSWIN) && !defined(MAKE_LIB) xfree(argv); #endif return 0; @@ -713,8 +704,8 @@ void getout(int exitval) if (did_emsg) { // give the user a chance to read the (error) message - no_wait_return = FALSE; - wait_return(FALSE); + no_wait_return = false; + wait_return(false); } // Position the cursor again, the autocommands may have moved it @@ -801,30 +792,6 @@ static int get_number_arg(const char *p, int *idx, int def) return def; } -#if defined(HAVE_LOCALE_H) -/// Setup to use the current locale (for ctype() and many other things). -static void init_locale(void) -{ - setlocale(LC_ALL, ""); - -# ifdef LC_NUMERIC - // Make sure strtod() uses a decimal point, not a comma. - setlocale(LC_NUMERIC, "C"); -# endif - - char localepath[MAXPATHL] = { 0 }; - snprintf(localepath, sizeof(localepath), "%s", get_vim_var_str(VV_PROGPATH)); - char *tail = path_tail_with_sep(localepath); - *tail = NUL; - tail = path_tail(localepath); - xstrlcpy(tail, "share/locale", - sizeof(localepath) - (size_t)(tail - localepath)); - bindtextdomain(PROJECT_NAME, localepath); - textdomain(PROJECT_NAME); - TIME_MSG("locale set"); -} -#endif - static uint64_t server_connect(char *server_addr, const char **errmsg) { if (server_addr == NULL) { @@ -1052,7 +1019,7 @@ static void command_line_scan(mparm_T *parmp) } else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) { parmp->use_vimrc = "NONE"; parmp->clean = true; - set_option_value("shadafile", 0L, "NONE", 0); + set_option_value_give_err("shadafile", 0L, "NONE", 0); } else if (STRNICMP(argv[0] + argv_idx, "luamod-dev", 9) == 0) { nlua_disable_preload = true; } else { @@ -1066,7 +1033,7 @@ static void command_line_scan(mparm_T *parmp) } break; case 'A': // "-A" start in Arabic mode. - set_option_value("arabic", 1L, NULL, 0); + set_option_value_give_err("arabic", 1L, NULL, 0); break; case 'b': // "-b" binary mode. // Needs to be effective before expanding file names, because @@ -1097,10 +1064,10 @@ static void command_line_scan(mparm_T *parmp) os_exit(0); case 'H': // "-H" start in Hebrew mode: rl + hkmap set. p_hkmap = true; - set_option_value("rl", 1L, NULL, 0); + set_option_value_give_err("rl", 1L, NULL, 0); break; case 'l': // "-l" lisp mode, 'lisp' and 'showmatch' on. - set_option_value("lisp", 1L, NULL, 0); + set_option_value_give_err("lisp", 1L, NULL, 0); p_sm = true; break; case 'M': // "-M" no changes or writing of files @@ -1181,15 +1148,15 @@ static void command_line_scan(mparm_T *parmp) // default is 10: a little bit verbose p_verbose = get_number_arg(argv[0], &argv_idx, 10); if (argv[0][argv_idx] != NUL) { - set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0); - argv_idx = (int)STRLEN(argv[0]); + set_option_value_give_err("verbosefile", 0L, argv[0] + argv_idx, 0); + argv_idx = (int)strlen(argv[0]); } break; case 'w': // "-w{number}" set window height // "-w {scriptout}" write to script if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) { n = get_number_arg(argv[0], &argv_idx, 10); - set_option_value("window", n, NULL, 0); + set_option_value_give_err("window", n, NULL, 0); break; } want_argument = true; @@ -1252,7 +1219,7 @@ static void command_line_scan(mparm_T *parmp) a = argv[0]; } - size_t s_size = STRLEN(a) + 9; + size_t s_size = strlen(a) + 9; char *s = xmalloc(s_size); snprintf(s, s_size, "so %s", a); parmp->cmds_tofree[parmp->n_commands] = true; @@ -1284,7 +1251,7 @@ static void command_line_scan(mparm_T *parmp) break; case 'i': // "-i {shada}" use for shada - set_option_value("shadafile", 0L, argv[0], 0); + set_option_value_give_err("shadafile", 0L, argv[0], 0); break; case 's': { // "-s {scriptin}" read from script file @@ -1299,7 +1266,7 @@ scripterror: int error; if (strequal(argv[0], "-")) { const int stdin_dup_fd = os_dup(STDIN_FILENO); -#ifdef WIN32 +#ifdef MSWIN // Replace the original stdin with the console input handle. os_replace_stdin_to_conin(); #endif @@ -1334,7 +1301,7 @@ scripterror: if (ascii_isdigit(*((char_u *)argv[0]))) { argv_idx = 0; n = get_number_arg(argv[0], &argv_idx, 10); - set_option_value("window", n, NULL, 0); + set_option_value_give_err("window", n, NULL, 0); argv_idx = -1; break; } @@ -1368,8 +1335,8 @@ scripterror: ga_grow(&global_alist.al_ga, 1); char *p = xstrdup(argv[0]); - if (parmp->diff_mode && os_isdir((char_u *)p) && GARGCOUNT > 0 - && !os_isdir((char_u *)alist_name(&GARGLIST[0]))) { + if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 + && !os_isdir(alist_name(&GARGLIST[0]))) { char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true); xfree(p); p = r; @@ -1401,7 +1368,7 @@ scripterror: // If there is a "+123" or "-c" command, set v:swapcommand to the first one. if (parmp->n_commands > 0) { - const size_t swcmd_len = STRLEN(parmp->commands[0]) + 3; + const size_t swcmd_len = strlen(parmp->commands[0]) + 3; char *const swcmd = xmalloc(swcmd_len); snprintf(swcmd, swcmd_len, ":%s\r", parmp->commands[0]); set_vim_var_string(VV_SWAPCOMMAND, swcmd, -1); @@ -1416,10 +1383,9 @@ scripterror: TIME_MSG("parsing arguments"); } -/* - * Many variables are in "params" so that we can pass them to invoked - * functions without a lot of arguments. "argc" and "argv" are also - * copied, so that they can be changed. */ +// Many variables are in "params" so that we can pass them to invoked +// functions without a lot of arguments. "argc" and "argv" are also +// copied, so that they can be changed. static void init_params(mparm_T *paramp, int argc, char **argv) { CLEAR_POINTER(paramp); @@ -1453,7 +1419,7 @@ static void check_and_set_isatty(mparm_T *paramp) stdout_isatty = paramp->output_isatty = os_isatty(STDOUT_FILENO); paramp->err_isatty = os_isatty(STDERR_FILENO); -#ifndef WIN32 +#ifndef MSWIN int tty_fd = paramp->input_isatty ? STDIN_FILENO : (paramp->output_isatty @@ -1478,7 +1444,7 @@ static void init_path(const char *exename) set_vim_var_string(VV_PROGPATH, exepath, -1); set_vim_var_string(VV_PROGNAME, path_tail(exename), -1); -#ifdef WIN32 +#ifdef MSWIN // Append the process start directory to $PATH, so that ":!foo" finds tools // shipped with Windows package. This also mimics SearchPath(). os_setenv_append_path(exepath); @@ -1491,9 +1457,7 @@ static char_u *get_fname(mparm_T *parmp, char_u *cwd) return (char_u *)alist_name(&GARGLIST[0]); } -/* - * Decide about window layout for diff mode after reading vimrc. - */ +// Decide about window layout for diff mode after reading vimrc. static void set_window_layout(mparm_T *paramp) { if (paramp->diff_mode && paramp->window_layout == 0) { @@ -1505,10 +1469,8 @@ static void set_window_layout(mparm_T *paramp) } } -/* - * "-q errorfile": Load the error file now. - * If the error file can't be read, exit before doing anything else. - */ +// "-q errorfile": Load the error file now. +// If the error file can't be read, exit before doing anything else. static void handle_quickfix(mparm_T *paramp) { if (paramp->edit_type == EDIT_QF) { @@ -1516,7 +1478,7 @@ static void handle_quickfix(mparm_T *paramp) set_string_option_direct("ef", -1, paramp->use_ef, OPT_FREE, SID_CARG); } vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef); - if (qf_init(NULL, (char *)p_ef, p_efm, true, (char *)IObuff, (char *)p_menc) < 0) { + if (qf_init(NULL, (char *)p_ef, p_efm, true, (char *)IObuff, p_menc) < 0) { msg_putchar('\n'); os_exit(3); } @@ -1524,10 +1486,8 @@ static void handle_quickfix(mparm_T *paramp) } } -/* - * Need to jump to the tag before executing the '-c command'. - * Makes "vim -c '/return' -t main" work. - */ +// Need to jump to the tag before executing the '-c command'. +// Makes "vim -c '/return' -t main" work. static void handle_tag(char_u *tagname) { if (tagname != NULL) { @@ -1566,18 +1526,14 @@ static void read_stdin(void) check_swap_exists_action(); } -/* - * Create the requested number of windows and edit buffers in them. - * Also does recovery if "recoverymode" set. - */ +// Create the requested number of windows and edit buffers in them. +// Also does recovery if "recoverymode" set. static void create_windows(mparm_T *parmp) { int dorewind; int done = 0; - /* - * Create the number of windows that was requested. - */ + // Create the number of windows that was requested. if (parmp->window_count == -1) { // was not set parmp->window_count = 1; } @@ -1638,7 +1594,7 @@ static void create_windows(mparm_T *parmp) } curwin = curwin->w_next; } - dorewind = FALSE; + dorewind = false; curbuf = curwin->w_buffer; if (curbuf->b_ml.ml_mfp == NULL) { // Set 'foldlevel' to 'foldlevelstart' if it's not negative.. @@ -1647,15 +1603,15 @@ static void create_windows(mparm_T *parmp) } // When getting the ATTENTION prompt here, use a dialog. swap_exists_action = SEA_DIALOG; - set_buflisted(TRUE); + set_buflisted(true); // create memfile, read file - (void)open_buffer(FALSE, NULL, 0); + (void)open_buffer(false, NULL, 0); if (swap_exists_action == SEA_QUIT) { if (got_int || only_one_window()) { // abort selected or quit and only one window - did_emsg = FALSE; // avoid hit-enter prompt + did_emsg = false; // avoid hit-enter prompt getout(1); } // We can't close the window, it would disturb what @@ -1667,7 +1623,7 @@ static void create_windows(mparm_T *parmp) } else { handle_swap_exists(NULL); } - dorewind = TRUE; // start again + dorewind = true; // start again } os_breakcheck(); if (got_int) { @@ -1696,9 +1652,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) win_T *win; char *p_shm_save = NULL; - /* - * Don't execute Win/Buf Enter/Leave autocommands here - */ + // Don't execute Win/Buf Enter/Leave autocommands here autocmd_no_enter++; autocmd_no_leave++; @@ -1709,7 +1663,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) } arg_idx = 1; - for (i = 1; i < parmp->window_count; ++i) { + for (i = 1; i < parmp->window_count; i++) { if (cwd != NULL) { os_chdir((char *)cwd); } @@ -1733,9 +1687,9 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) if (i == 1) { char buf[100]; - p_shm_save = xstrdup((char *)p_shm); + p_shm_save = xstrdup(p_shm); snprintf(buf, sizeof(buf), "F%s", p_shm); - set_option_value("shm", 0L, buf, 0); + set_option_value_give_err("shm", 0L, buf, 0); } } else { if (curwin->w_next == NULL) { // just checking @@ -1760,7 +1714,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) // abort or quit selected if (got_int || only_one_window()) { // abort selected and only one window - did_emsg = FALSE; // avoid hit-enter prompt + did_emsg = false; // avoid hit-enter prompt getout(1); } win_close(curwin, true, false); @@ -1779,7 +1733,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) } if (p_shm_save != NULL) { - set_option_value("shm", 0L, p_shm_save, 0); + set_option_value_give_err("shm", 0L, p_shm_save, 0); xfree(p_shm_save); } @@ -1807,9 +1761,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) } } -/* - * Execute the commands from --cmd arguments "cmds[cnt]". - */ +// Execute the commands from --cmd arguments "cmds[cnt]". static void exe_pre_commands(mparm_T *parmp) { char **cmds = parmp->pre_commands; @@ -1829,19 +1781,15 @@ static void exe_pre_commands(mparm_T *parmp) } } -/* - * Execute "+", "-c" and "-S" arguments. - */ +// Execute "+", "-c" and "-S" arguments. static void exe_commands(mparm_T *parmp) { int i; - /* - * We start commands on line 0, make "vim +/pat file" match a - * pattern on line 1. But don't move the cursor when an autocommand - * with g`" was used. - */ - msg_scroll = TRUE; + // We start commands on line 0, make "vim +/pat file" match a + // pattern on line 1. But don't move the cursor when an autocommand + // with g`" was used. + msg_scroll = true; if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1) { curwin->w_cursor.lnum = 0; } @@ -1861,12 +1809,12 @@ static void exe_commands(mparm_T *parmp) } if (!exmode_active) { - msg_scroll = FALSE; + msg_scroll = false; } // When started with "-q errorfile" jump to first error again. if (parmp->edit_type == EDIT_QF) { - qf_jump(NULL, 0, 0, FALSE); + qf_jump(NULL, 0, 0, false); } TIME_MSG("executing command arguments"); } @@ -1940,9 +1888,9 @@ static bool do_user_initialization(void) char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim"); // init.lua - if (os_path_exists(init_lua_path) + if (os_path_exists((char *)init_lua_path) && do_source((char *)init_lua_path, true, DOSO_VIMRC)) { - if (os_path_exists(user_vimrc)) { + if (os_path_exists((char *)user_vimrc)) { semsg(_("E5422: Conflicting configs: \"%s\" \"%s\""), init_lua_path, user_vimrc); } @@ -2153,6 +2101,7 @@ static void usage(void) mch_msg(_(" -V[N][file] Verbose [level][file]\n")); mch_msg("\n"); mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n")); + mch_msg(_(" --clean \"Factory defaults\" (skip user config and plugins, shada)\n")); mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n")); mch_msg(_(" --headless Don't start a user interface\n")); mch_msg(_(" --listen <address> Serve RPC API from this address\n")); @@ -2163,11 +2112,9 @@ static void usage(void) mch_msg(_("\nSee \":help startup-options\" for all options.\n")); } -/* - * Check the result of the ATTENTION dialog: - * When "Quit" selected, exit Vim. - * When "Recover" selected, recover the file. - */ +// Check the result of the ATTENTION dialog: +// When "Quit" selected, exit Vim. +// When "Recover" selected, recover the file. static void check_swap_exists_action(void) { if (swap_exists_action == SEA_QUIT) { diff --git a/src/nvim/map.c b/src/nvim/map.c index d3058a5d52..24478c6091 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -14,7 +14,7 @@ #include <stdlib.h> #include <string.h> -#include "nvim/lib/khash.h" +#include "klib/khash.h" #include "nvim/map.h" #include "nvim/map_defs.h" #include "nvim/memory.h" @@ -168,6 +168,7 @@ MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER) MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) +MAP_IMPL(uint32_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER) MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER) diff --git a/src/nvim/map.h b/src/nvim/map.h index 845daac3f7..f5f30f5a85 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -39,6 +39,7 @@ MAP_DECLS(int, cstr_t) MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(cstr_t, int) MAP_DECLS(ptr_t, ptr_t) +MAP_DECLS(uint32_t, ptr_t) MAP_DECLS(uint64_t, ptr_t) MAP_DECLS(uint64_t, ssize_t) MAP_DECLS(uint64_t, uint64_t) diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h index 7b4596ce2e..61afedbe50 100644 --- a/src/nvim/map_defs.h +++ b/src/nvim/map_defs.h @@ -1,7 +1,7 @@ #ifndef NVIM_MAP_DEFS_H #define NVIM_MAP_DEFS_H -#include "nvim/lib/khash.h" +#include "klib/khash.h" typedef const char *cstr_t; typedef void *ptr_t; diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 64a798a27b..001bbf7e48 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -150,8 +150,8 @@ static void showmap(mapblock_T *mp, bool local) { size_t len = 1; - if (message_filtered(mp->m_keys) && message_filtered(mp->m_str) - && (mp->m_desc == NULL || message_filtered((char_u *)mp->m_desc))) { + if (message_filtered((char *)mp->m_keys) && message_filtered(mp->m_str) + && (mp->m_desc == NULL || message_filtered(mp->m_desc))) { return; } @@ -174,7 +174,7 @@ static void showmap(mapblock_T *mp, bool local) } // Display the LHS. Get length of what we write. - len = (size_t)msg_outtrans_special(mp->m_keys, true, 0); + len = (size_t)msg_outtrans_special((char *)mp->m_keys, true, 0); do { msg_putchar(' '); // padd with blanks len++; @@ -214,7 +214,6 @@ static void showmap(mapblock_T *mp, bool local) last_set_msg(mp->m_script_ctx); } msg_clr_eos(); - ui_flush(); // show one line at a time } /// Replace termcodes in the given LHS and RHS and store the results into the @@ -263,7 +262,7 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs if (replaced == NULL) { return false; } - mapargs->lhs_len = STRLEN(replaced); + mapargs->lhs_len = strlen(replaced); STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs)); if (did_simplify) { replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, flags | REPTERM_NO_SIMPLIFY, @@ -271,32 +270,40 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs if (replaced == NULL) { return false; } - mapargs->alt_lhs_len = STRLEN(replaced); + mapargs->alt_lhs_len = strlen(replaced); STRLCPY(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs)); } else { mapargs->alt_lhs_len = 0; } + set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, cpo_flags, mapargs); + + return true; +} + +/// @see set_maparg_lhs_rhs +static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len, + const LuaRef rhs_lua, const int cpo_flags, MapArguments *const mapargs) +{ mapargs->rhs_lua = rhs_lua; if (rhs_lua == LUA_NOREF) { mapargs->orig_rhs_len = orig_rhs_len; mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u)); STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1); - if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing - mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char + mapargs->rhs = xcalloc(1, sizeof(char_u)); // single NUL-char mapargs->rhs_len = 0; mapargs->rhs_is_noop = true; } else { char *rhs_buf = NULL; - replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL, - cpo_flags); - mapargs->rhs_len = STRLEN(replaced); - // XXX: replace_termcodes may produce an empty string even if orig_rhs is non-empty + char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, REPTERM_DO_LT, NULL, + cpo_flags); + mapargs->rhs_len = strlen(replaced); + // NB: replace_termcodes may produce an empty string even if orig_rhs is non-empty // (e.g. a single ^V, see :h map-empty-rhs) mapargs->rhs_is_noop = orig_rhs_len != 0 && mapargs->rhs_len == 0; - mapargs->rhs = (char_u *)replaced; + mapargs->rhs = replaced; } } else { char tmp_buf[64]; @@ -306,9 +313,8 @@ static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs // stores <lua>ref_no<cr> in map_str mapargs->rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "%c%c%c%d\r", K_SPECIAL, (char_u)KS_EXTRA, KE_LUA, rhs_lua); - mapargs->rhs = vim_strsave((char_u *)tmp_buf); + mapargs->rhs = xstrdup(tmp_buf); } - return true; } /// Parse a string of |:map-arguments| into a @ref MapArguments struct. @@ -433,7 +439,7 @@ static int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *ma /// 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, +static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char *keys, MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid, linenr_T lnum, bool simplified) { @@ -448,9 +454,9 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, } } - mp->m_keys = vim_strsave(keys); + mp->m_keys = (uint8_t *)xstrdup(keys); mp->m_str = args->rhs; - mp->m_orig_str = args->orig_rhs; + mp->m_orig_str = (char *)args->orig_rhs; mp->m_luaref = args->rhs_lua; if (!simplified) { args->rhs = NULL; @@ -703,8 +709,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, } } else { // do we have a match? if (round) { // second round: Try unmap "rhs" string - n = (int)STRLEN(mp->m_str); - p = mp->m_str; + n = (int)strlen(mp->m_str); + p = (char_u *)mp->m_str; } else { n = mp->m_keylen; p = mp->m_keys; @@ -762,7 +768,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, XFREE_CLEAR(mp->m_orig_str); } mp->m_str = args->rhs; - mp->m_orig_str = args->orig_rhs; + mp->m_orig_str = (char *)args->orig_rhs; mp->m_luaref = args->rhs_lua; if (!keyround1_simplified) { args->rhs = NULL; @@ -840,7 +846,7 @@ 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. - map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev, + map_add(buf, map_table, abbr_table, (char *)lhs, args, noremap, mode, is_abbrev, -1, // sid 0, // lnum keyround1_simplified); @@ -884,7 +890,7 @@ theend: /// /// @param maptype MAPTYPE_MAP for |:map| /// MAPTYPE_UNMAP for |:unmap| -/// MAPTYPE_NOREMAP for |noremap|. +/// 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. @@ -965,12 +971,12 @@ static int get_map_mode(char **cmdp, bool forceit) /// Clear all mappings (":mapclear") or abbreviations (":abclear"). /// "abbr" should be false for mappings, true for abbreviations. /// This function used to be called map_clear(). -static void do_mapclear(char *cmdp, char_u *arg, int forceit, int abbr) +static void do_mapclear(char *cmdp, char *arg, int forceit, int abbr) { int mode; int local; - local = (STRCMP(arg, "<buffer>") == 0); + local = (strcmp(arg, "<buffer>") == 0); if (!local && *arg != NUL) { emsg(_(e_invarg)); return; @@ -1113,7 +1119,7 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr) mp = maphash[hash]; } for (; mp; mp = mp->m_next) { - if ((mp->m_mode & mode) && strstr((char *)mp->m_str, rhs) != NULL) { + if ((mp->m_mode & mode) && strstr(mp->m_str, rhs) != NULL) { return true; } } @@ -1259,7 +1265,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) int hash; int count; int round; - char_u *p; + char *p; int i; *num_file = 0; // return values in case of FAIL @@ -1272,28 +1278,28 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) for (i = 0; i < 7; i++) { if (i == 0) { - p = (char_u *)"<silent>"; + p = "<silent>"; } else if (i == 1) { - p = (char_u *)"<unique>"; + p = "<unique>"; } else if (i == 2) { - p = (char_u *)"<script>"; + p = "<script>"; } else if (i == 3) { - p = (char_u *)"<expr>"; + p = "<expr>"; } else if (i == 4 && !expand_buffer) { - p = (char_u *)"<buffer>"; + p = "<buffer>"; } else if (i == 5) { - p = (char_u *)"<nowait>"; + p = "<nowait>"; } else if (i == 6) { - p = (char_u *)"<special>"; + p = "<special>"; } else { continue; } - if (vim_regexec(regmatch, (char *)p, (colnr_T)0)) { + if (vim_regexec(regmatch, p, (colnr_T)0)) { if (round == 1) { count++; } else { - (*file)[count++] = (char *)vim_strsave(p); + (*file)[count++] = xstrdup(p); } } } @@ -1311,12 +1317,12 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) } for (; mp; mp = mp->m_next) { if (mp->m_mode & expand_mapmodes) { - p = translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS); - if (p != NULL && vim_regexec(regmatch, (char *)p, (colnr_T)0)) { + p = (char *)translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS); + if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) { if (round == 1) { count++; } else { - (*file)[count++] = (char *)p; + (*file)[count++] = p; p = NULL; } } @@ -1344,7 +1350,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) char **ptr3 = ptr1 + count; while (ptr2 < ptr3) { - if (STRCMP(*ptr1, *ptr2)) { + if (strcmp(*ptr1, *ptr2)) { *++ptr1 = *ptr2++; } else { xfree(*ptr2++); @@ -1441,20 +1447,20 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol) mp->m_next == NULL ? (mp = mp2, mp2 = NULL) : (mp = mp->m_next)) { int qlen = mp->m_keylen; - char_u *q = mp->m_keys; + char *q = (char *)mp->m_keys; int match; if (strchr((const char *)mp->m_keys, K_SPECIAL) != NULL) { // Might have K_SPECIAL escaped mp->m_keys. - q = vim_strsave(mp->m_keys); - vim_unescape_ks(q); + q = xstrdup((char *)mp->m_keys); + vim_unescape_ks((char_u *)q); qlen = (int)STRLEN(q); } // find entries with right mode and keys match = (mp->m_mode & State) && qlen == len && !STRNCMP(q, ptr, (size_t)len); - if (q != mp->m_keys) { + if (q != (char *)mp->m_keys) { xfree(q); } if (match) { @@ -1504,9 +1510,9 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol) (void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent); } if (mp->m_expr) { - s = eval_map_expr(mp, c); + s = (char_u *)eval_map_expr(mp, c); } else { - s = mp->m_str; + s = (char_u *)mp->m_str; } if (s != NULL) { // insert the to string @@ -1534,16 +1540,16 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol) /// special characters. /// /// @param c NUL or typed character for abbreviation -char_u *eval_map_expr(mapblock_T *mp, int c) +char *eval_map_expr(mapblock_T *mp, int c) { - char_u *p = NULL; - char_u *expr = NULL; + char *p = NULL; + char *expr = NULL; // Remove escaping of K_SPECIAL, because "str" is in a format to be used as // typeahead. if (mp->m_luaref == LUA_NOREF) { - expr = vim_strsave(mp->m_str); - vim_unescape_ks(expr); + expr = xstrdup(mp->m_str); + vim_unescape_ks((char_u *)expr); } // Forbid changing text or using ":normal" to avoid most of the bad side @@ -1559,7 +1565,7 @@ char_u *eval_map_expr(mapblock_T *mp, int c) Array args = ARRAY_DICT_INIT; Object ret = nlua_call_ref(mp->m_luaref, NULL, args, true, &err); if (ret.type == kObjectTypeString) { - p = (char_u *)xstrndup(ret.data.string.data, ret.data.string.size); + p = xstrndup(ret.data.string.data, ret.data.string.size); } api_free_object(ret); if (err.type != kErrorTypeNone) { @@ -1567,7 +1573,7 @@ char_u *eval_map_expr(mapblock_T *mp, int c) api_clear_error(&err); } } else { - p = (char_u *)eval_to_string((char *)expr, NULL, false); + p = eval_to_string(expr, NULL, false); xfree(expr); } textlock--; @@ -1580,13 +1586,13 @@ char_u *eval_map_expr(mapblock_T *mp, int c) return NULL; } - char_u *res = NULL; + char *res = NULL; if (mp->m_replace_keycodes) { - replace_termcodes((char *)p, STRLEN(p), (char **)&res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); + replace_termcodes(p, STRLEN(p), &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); + res = vim_strsave_escape_ks(p); } xfree(p); @@ -1639,7 +1645,7 @@ int makemap(FILE *fd, buf_T *buf) if (mp->m_luaref != LUA_NOREF) { continue; } - for (p = mp->m_str; *p != NUL; p++) { + for (p = (char_u *)mp->m_str; *p != NUL; p++) { if (p[0] == K_SPECIAL && p[1] == KS_EXTRA && p[2] == KE_SNR) { break; @@ -1785,7 +1791,7 @@ int makemap(FILE *fd, buf_T *buf) if (putc(' ', fd) < 0 || put_escstr(fd, mp->m_keys, 0) == FAIL || putc(' ', fd) < 0 - || put_escstr(fd, mp->m_str, 1) == FAIL + || put_escstr(fd, (char_u *)mp->m_str, 1) == FAIL || put_eol(fd) < 0) { return FAIL; } @@ -1956,7 +1962,7 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb *local_ptr = local; } *rhs_lua = mp->m_luaref; - return mp->m_luaref == LUA_NOREF ? mp->m_str : NULL; + return mp->m_luaref == LUA_NOREF ? (char_u *)mp->m_str : NULL; } } } @@ -1967,7 +1973,7 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb } /// "hasmapto()" function -void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *mode; const char *const name = tv_get_string(&argvars[0]); @@ -1989,18 +1995,19 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } -/// Fill a dictionary with all applicable maparg() like dictionaries +/// Fill a Dictionary with all applicable maparg() like dictionaries /// -/// @param dict The dictionary to be filled /// @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, - const char *lhsrawalt, long buffer_value, bool compatible) - FUNC_ATTR_NONNULL_ARG(1, 2) +/// +/// @return A Dictionary. +static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, + const long buffer_value, const bool compatible) + FUNC_ATTR_NONNULL_ARG(1) { - char *const lhs = str2special_save((const char *)mp->m_keys, - compatible, !compatible); + Dictionary dict = ARRAY_DICT_INIT; + char *const lhs = str2special_save((const char *)mp->m_keys, compatible, !compatible); char *const mapmode = map_mode_to_chars(mp->m_mode); varnumber_T noremap_value; @@ -2015,37 +2022,35 @@ static void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, } if (mp->m_luaref != LUA_NOREF) { - tv_dict_add_nr(dict, S_LEN("callback"), mp->m_luaref); + PUT(dict, "callback", LUAREF_OBJ(api_new_luaref(mp->m_luaref))); } else { - if (compatible) { - tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str); - } else { - tv_dict_add_allocated_str(dict, S_LEN("rhs"), - str2special_save((const char *)mp->m_str, false, - true)); - } + PUT(dict, "rhs", STRING_OBJ(compatible + ? cstr_to_string(mp->m_orig_str) + : cstr_as_string(str2special_save(mp->m_str, false, true)))); } if (mp->m_desc != NULL) { - tv_dict_add_allocated_str(dict, S_LEN("desc"), xstrdup(mp->m_desc)); + PUT(dict, "desc", STRING_OBJ(cstr_to_string(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); + PUT(dict, "lhs", STRING_OBJ(cstr_as_string(lhs))); + PUT(dict, "lhsraw", STRING_OBJ(cstr_to_string((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); - tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0); - tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ctx.sc_sid); - 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); + PUT(dict, "lhsrawalt", STRING_OBJ(cstr_to_string(lhsrawalt))); + } + PUT(dict, "noremap", INTEGER_OBJ(noremap_value)); + PUT(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0)); + PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0)); + PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0)); + PUT(dict, "sid", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_sid)); + PUT(dict, "lnum", INTEGER_OBJ((varnumber_T)mp->m_script_ctx.sc_lnum)); + PUT(dict, "buffer", INTEGER_OBJ((varnumber_T)buffer_value)); + PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0)); if (mp->m_replace_keycodes) { - tv_dict_add_nr(dict, S_LEN("replace_keycodes"), 1); + PUT(dict, "replace_keycodes", INTEGER_OBJ(1)); } - tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode); + PUT(dict, "mode", STRING_OBJ(cstr_as_string(mapmode))); + + return dict; } static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) @@ -2086,7 +2091,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) 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); mapblock_T *mp = NULL; int buffer_local; @@ -2096,7 +2101,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) // When the lhs is being simplified the not-simplified keys are // preferred for printing, like in do_map(). (void)replace_termcodes(keys, - STRLEN(keys), + strlen(keys), &alt_keys_buf, flags | REPTERM_NO_SIMPLIFY, NULL, CPO_TO_CPO_FLAGS); rhs = check_map((char_u *)alt_keys_buf, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua); @@ -2114,11 +2119,16 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) rettv->vval.v_string = nlua_funcref_str(mp->m_luaref); } } else { - tv_dict_alloc_ret(rettv); + // Return a dictionary. if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) { - // Return a dictionary. - mapblock_fill_dict(rettv->vval.v_dict, mp, did_simplify ? (char *)keys_simplified : NULL, - buffer_local, true); + Dictionary dict = mapblock_fill_dict(mp, + did_simplify ? (char *)keys_simplified : NULL, + buffer_local, true); + (void)object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL); + api_free_dictionary(dict); + } else { + // Return an empty dictionary. + tv_dict_alloc_ret(rettv); } } @@ -2127,7 +2137,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) } /// "mapset()" function -void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char buf[NUMBUFLEN]; const char *which = tv_get_string_buf_chk(&argvars[0], buf); @@ -2147,29 +2157,36 @@ void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr) 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) { + char *orig_rhs = tv_dict_get_string(d, "rhs", false); + LuaRef rhs_lua = LUA_NOREF; + dictitem_T *callback_di = tv_dict_find(d, S_LEN("callback")); + if (callback_di != NULL) { + Object callback_obj = vim_to_object(&callback_di->di_tv); + if (callback_obj.type == kObjectTypeLuaRef && callback_obj.data.luaref != LUA_NOREF) { + rhs_lua = callback_obj.data.luaref; + orig_rhs = ""; + callback_obj.data.luaref = LUA_NOREF; + } + api_free_object(callback_obj); + } + if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) { emsg(_("E460: entries missing in mapset() dict argument")); + api_free_luaref(rhs_lua); 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; + int noremap = tv_dict_get_number(d, "noremap") != 0 ? 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), + MapArguments args = { .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), }; + set_maparg_rhs(orig_rhs, strlen(orig_rhs), rhs_lua, CPO_TO_CPO_FLAGS, &args); 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; @@ -2180,28 +2197,28 @@ void f_mapset(typval_T *argvars, typval_T *rettv, FunPtr fptr) // 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); + set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, 0, &unmap_args); unmap_args.buffer = buffer; - buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, false, curbuf); + buf_do_map(MAPTYPE_UNMAP, &unmap_args, mode, is_abbr, 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, + map_add(curbuf, map_table, abbr_table, lhsrawalt, &args, noremap, mode, is_abbr, sid, lnum, true); } - map_add(curbuf, map_table, abbr_table, (char_u *)lhsraw, &args, noremap, mode, is_abbr, + map_add(curbuf, map_table, abbr_table, lhsraw, &args, noremap, mode, is_abbr, sid, lnum, false); } /// "maparg()" function -void f_maparg(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_maparg(argvars, rettv, true); } /// "mapcheck()" function -void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_mapcheck(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_maparg(argvars, rettv, false); } @@ -2322,7 +2339,7 @@ void langmap_set(void) ga_clear(&langmap_mapga); // clear the previous map first langmap_init(); // back to one-to-one map - for (p = p_langmap; p[0] != NUL;) { + for (p = (char_u *)p_langmap; p[0] != NUL;) { for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';'; MB_PTR_ADV(p2)) { if (p2[0] == '\\' && p2[1] != NUL) { @@ -2440,13 +2457,13 @@ void ex_unmap(exarg_T *eap) /// ":mapclear" and friends. void ex_mapclear(exarg_T *eap) { - do_mapclear(eap->cmd, (char_u *)eap->arg, eap->forceit, false); + do_mapclear(eap->cmd, eap->arg, eap->forceit, false); } /// ":abclear" and friends. void ex_abclear(exarg_T *eap) { - do_mapclear(eap->cmd, (char_u *)eap->arg, true, true); + do_mapclear(eap->cmd, eap->arg, true, true); } /// Set, tweak, or remove a mapping in a mode. Acts as the implementation for @@ -2599,12 +2616,10 @@ 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. /// @returns Array of maparg()-like dictionaries describing mappings -ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua) +ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf) { Array mappings = ARRAY_DICT_INIT; - dict_T *const dict = tv_dict_alloc(); // Convert the string mode to the integer mode // that is stored within each mapblock @@ -2623,25 +2638,11 @@ 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, NULL, buffer_value, false); - Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT, - .vval.v_dict = dict } }); - if (from_lua) { - Dictionary d = api_dict.data.dictionary; - for (size_t j = 0; j < d.size; j++) { - if (strequal("callback", d.items[j].key.data)) { - d.items[j].value.type = kObjectTypeLuaRef; - d.items[j].value.data.luaref = api_new_luaref((LuaRef)d.items[j].value.data.integer); - break; - } - } - } - ADD(mappings, api_dict); - tv_dict_clear(dict); + ADD(mappings, + DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, false))); } } } - tv_dict_free(dict); return mappings; } diff --git a/src/nvim/mapping.h b/src/nvim/mapping.h index 7c48c3bce2..156187b5d8 100644 --- a/src/nvim/mapping.h +++ b/src/nvim/mapping.h @@ -9,7 +9,7 @@ /// All possible |:map-arguments| usable in a |:map| command. /// /// The <special> argument has no effect on mappings and is excluded from this -/// struct declaration. |noremap| is included, since it behaves like a map +/// struct declaration. |:noremap| is included, since it behaves like a map /// argument when used in a mapping. /// /// @see mapblock_T @@ -35,7 +35,7 @@ struct map_arguments { char_u alt_lhs[MAXMAPLEN + 1]; size_t alt_lhs_len; - char_u *rhs; /// The {rhs} of the mapping. + char *rhs; /// The {rhs} of the mapping. size_t rhs_len; LuaRef rhs_lua; /// lua function as {rhs} bool rhs_is_noop; /// True when the {rhs} should be <Nop>. diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 593275d489..f41793c8a6 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * mark.c: functions for setting marks and jumping to them - */ +// mark.c: functions for setting marks and jumping to them #include <assert.h> #include <inttypes.h> @@ -33,23 +31,19 @@ #include "nvim/os/time.h" #include "nvim/path.h" #include "nvim/quickfix.h" -#include "nvim/search.h" #include "nvim/sign.h" #include "nvim/strings.h" +#include "nvim/textobject.h" #include "nvim/ui.h" #include "nvim/vim.h" -/* - * This file contains routines to maintain and manipulate marks. - */ +// This file contains routines to maintain and manipulate marks. -/* - * If a named file mark's lnum is non-zero, it is valid. - * If a named file mark's fnum is non-zero, it is for an existing buffer, - * otherwise it is from .shada and namedfm[n].fname is the file name. - * There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing - * shada). - */ +// If a named file mark's lnum is non-zero, it is valid. +// If a named file mark's fnum is non-zero, it is for an existing buffer, +// otherwise it is from .shada and namedfm[n].fname is the file name. +// There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing +// shada). /// Global marks (marks with file number or name) static xfmark_T namedfm[NGLOBALMARKS]; @@ -57,10 +51,9 @@ static xfmark_T namedfm[NGLOBALMARKS]; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mark.c.generated.h" #endif -/* - * Set named mark "c" at current cursor position. - * Returns OK on success, FAIL if bad name given. - */ + +// Set named mark "c" at current cursor position. +// Returns OK on success, FAIL if bad name given. int setmark(int c) { fmarkv_T view = mark_view_make(curwin->w_topline, curwin->w_cursor); @@ -88,11 +81,9 @@ void clear_fmark(fmark_T *fm) CLEAR_POINTER(fm); } -/* - * Set named mark "c" to position "pos". - * When "c" is upper case use file "fnum". - * Returns OK on success, FAIL if bad name given. - */ +// Set named mark "c" to position "pos". +// When "c" is upper case use file "fnum". +// Returns OK on success, FAIL if bad name given. int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt) { int i; @@ -166,10 +157,8 @@ int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt) return FAIL; } -/* - * Set the previous context mark to the current position and add it to the - * jump list. - */ +// Set the previous context mark to the current position and add it to the +// jump list. void setpcmark(void) { xfmark_T *fm; @@ -210,12 +199,10 @@ void setpcmark(void) SET_XFMARK(fm, curwin->w_pcmark, curbuf->b_fnum, view, NULL); } -/* - * To change context, call setpcmark(), then move the current position to - * where ever, then call checkpcmark(). This ensures that the previous - * context will only be changed if the cursor moved to a different line. - * If pcmark was deleted (with "dG") the previous mark is restored. - */ +// To change context, call setpcmark(), then move the current position to +// where ever, then call checkpcmark(). This ensures that the previous +// context will only be changed if the cursor moved to a different line. +// If pcmark was deleted (with "dG") the previous mark is restored. void checkpcmark(void) { if (curwin->w_prev_pcmark.lnum != 0 @@ -653,48 +640,39 @@ fmark_T *getnextmark(pos_T *startpos, int dir, int begin_line) return result; } -/* - * For an xtended filemark: set the fnum from the fname. - * This is used for marks obtained from the .shada file. It's postponed - * until the mark is used to avoid a long startup delay. - */ +// For an xtended filemark: set the fnum from the fname. +// This is used for marks obtained from the .shada file. It's postponed +// until the mark is used to avoid a long startup delay. static void fname2fnum(xfmark_T *fm) { - char_u *p; - if (fm->fname != NULL) { - /* - * First expand "~/" in the file name to the home directory. - * Don't expand the whole name, it may contain other '~' chars. - */ - if (fm->fname[0] == '~' && (fm->fname[1] == '/' + // First expand "~/" in the file name to the home directory. + // Don't expand the whole name, it may contain other '~' chars. #ifdef BACKSLASH_IN_FILENAME - || fm->fname[1] == '\\' + if (fm->fname[0] == '~' && (fm->fname[1] == '/' || fm->fname[1] == '\\')) { +#else + if (fm->fname[0] == '~' && (fm->fname[1] == '/')) { #endif - )) { - int len; - expand_env((char_u *)"~/", NameBuff, MAXPATHL); - len = (int)STRLEN(NameBuff); + expand_env("~/", NameBuff, MAXPATHL); + int len = (int)strlen(NameBuff); STRLCPY(NameBuff + len, fm->fname + 2, MAXPATHL - len); } else { STRLCPY(NameBuff, fm->fname, MAXPATHL); } // Try to shorten the file name. - os_dirname(IObuff, IOSIZE); - p = path_shorten_fname(NameBuff, IObuff); + os_dirname((char_u *)IObuff, IOSIZE); + char *p = path_shorten_fname(NameBuff, IObuff); // buflist_new() will call fmarks_check_names() - (void)buflist_new((char *)NameBuff, (char *)p, (linenr_T)1, 0); + (void)buflist_new(NameBuff, p, (linenr_T)1, 0); } } -/* - * Check all file marks for a name that matches the file name in buf. - * May replace the name with an fnum. - * Used for marks that come from the .shada file. - */ +// Check all file marks for a name that matches the file name in buf. +// May replace the name with an fnum. +// Used for marks that come from the .shada file. void fmarks_check_names(buf_T *buf) { char_u *name = (char_u *)buf->b_ffname; @@ -704,22 +682,22 @@ void fmarks_check_names(buf_T *buf) return; } - for (i = 0; i < NGLOBALMARKS; ++i) { - fmarks_check_one(&namedfm[i], name, buf); + for (i = 0; i < NGLOBALMARKS; i++) { + fmarks_check_one(&namedfm[i], (char *)name, buf); } FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - for (i = 0; i < wp->w_jumplistlen; ++i) { - fmarks_check_one(&wp->w_jumplist[i], name, buf); + for (i = 0; i < wp->w_jumplistlen; i++) { + fmarks_check_one(&wp->w_jumplist[i], (char *)name, buf); } } } -static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf) +static void fmarks_check_one(xfmark_T *fm, char *name, buf_T *buf) { if (fm->fmark.fnum == 0 && fm->fname != NULL - && FNAMECMP(name, fm->fname) == 0) { + && path_fnamecmp(name, fm->fname) == 0) { fm->fmark.fnum = buf->b_fnum; XFREE_CLEAR(fm->fname); } @@ -792,39 +770,35 @@ void clrallmarks(buf_T *const buf) buf->b_changelistlen = 0; } -/* - * Get name of file from a filemark. - * When it's in the current buffer, return the text at the mark. - * Returns an allocated string. - */ +// Get name of file from a filemark. +// When it's in the current buffer, return the text at the mark. +// Returns an allocated string. char_u *fm_getname(fmark_T *fmark, int lead_len) { if (fmark->fnum == curbuf->b_fnum) { // current buffer - return mark_line(&(fmark->mark), lead_len); + return (char_u *)mark_line(&(fmark->mark), lead_len); } return (char_u *)buflist_nr2name(fmark->fnum, false, true); } -/* - * Return the line at mark "mp". Truncate to fit in window. - * The returned string has been allocated. - */ -static char_u *mark_line(pos_T *mp, int lead_len) +/// Return the line at mark "mp". Truncate to fit in window. +/// The returned string has been allocated. +static char *mark_line(pos_T *mp, int lead_len) { - char_u *s, *p; + char *s, *p; int len; if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count) { - return vim_strsave((char_u *)"-invalid-"); + return xstrdup("-invalid-"); } assert(Columns >= 0); // Allow for up to 5 bytes per character. - s = vim_strnsave((char_u *)skipwhite((char *)ml_get(mp->lnum)), (size_t)Columns * 5); + s = xstrnsave(skipwhite(ml_get(mp->lnum)), (size_t)Columns * 5); // Truncate the line to fit it in the window len = 0; for (p = s; *p != NUL; MB_PTR_ADV(p)) { - len += ptr2cells((char *)p); + len += ptr2cells(p); if (len >= Columns - lead_len) { break; } @@ -833,9 +807,7 @@ static char_u *mark_line(pos_T *mp, int lead_len) return s; } -/* - * print the marks - */ +// print the marks void ex_marks(exarg_T *eap) { char_u *arg = (char_u *)eap->arg; @@ -848,10 +820,10 @@ void ex_marks(exarg_T *eap) } show_one_mark('\'', arg, &curwin->w_pcmark, NULL, true); - for (i = 0; i < NMARKS; ++i) { + for (i = 0; i < NMARKS; i++) { show_one_mark(i + 'a', arg, &curbuf->b_namedm[i].mark, NULL, true); } - for (i = 0; i < NGLOBALMARKS; ++i) { + for (i = 0; i < NGLOBALMARKS; i++) { if (namedfm[i].fmark.fnum != 0) { name = fm_getname(&namedfm[i].fmark, 15); } else { @@ -908,10 +880,10 @@ static void show_one_mark(int c, char_u *arg, pos_T *p, char_u *name_arg, int cu && p->lnum != 0) { // don't output anything if 'q' typed at --more-- prompt if (name == NULL && current) { - name = mark_line(p, 15); + name = (char_u *)mark_line(p, 15); mustfree = true; } - if (!message_filtered(name)) { + if (!message_filtered((char *)name)) { if (!did_title) { // Highlight title msg_puts_title(_("\nmark line col file/text")); @@ -922,10 +894,9 @@ static void show_one_mark(int c, char_u *arg, pos_T *p, char_u *name_arg, int cu snprintf((char *)IObuff, IOSIZE, " %c %6" PRIdLINENR " %4d ", c, p->lnum, p->col); msg_outtrans((char *)IObuff); if (name != NULL) { - msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0); + msg_outtrans_attr((char *)name, current ? HL_ATTR(HLF_D) : 0); } } - ui_flush(); // show one line at a time } if (mustfree) { xfree(name); @@ -933,9 +904,7 @@ static void show_one_mark(int c, char_u *arg, pos_T *p, char_u *name_arg, int cu } } -/* - * ":delmarks[!] [marks]" - */ +// ":delmarks[!] [marks]" void ex_delmarks(exarg_T *eap) { char_u *p; @@ -963,8 +932,8 @@ void ex_delmarks(exarg_T *eap) from = *p; to = p[2]; if (!(lower ? ASCII_ISLOWER(p[2]) - : (digit ? ascii_isdigit(p[2]) - : ASCII_ISUPPER(p[2]))) + : (digit ? ascii_isdigit(p[2]) + : ASCII_ISUPPER(p[2]))) || to < from) { semsg(_(e_invarg2), p); return; @@ -975,7 +944,7 @@ void ex_delmarks(exarg_T *eap) from = to = *p; } - for (i = from; i <= to; ++i) { + for (i = from; i <= to; i++) { if (lower) { curbuf->b_namedm[i - 'a'].mark.lnum = 0; } else { @@ -1016,25 +985,23 @@ void ex_delmarks(exarg_T *eap) } } -/* - * print the jumplist - */ +// print the jumplist void ex_jumps(exarg_T *eap) { int i; - char_u *name; + char *name; cleanup_jumplist(curwin, true); // Highlight title msg_puts_title(_("\n jump line col file/text")); - for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i) { + for (i = 0; i < curwin->w_jumplistlen && !got_int; i++) { if (curwin->w_jumplist[i].fmark.mark.lnum != 0) { - name = fm_getname(&curwin->w_jumplist[i].fmark, 16); + name = (char *)fm_getname(&curwin->w_jumplist[i].fmark, 16); // Make sure to output the current indicator, even when on an wiped // out buffer. ":filter" may still skip it. if (name == NULL && i == curwin->w_jumplistidx) { - name = vim_strsave((char_u *)"-invalid-"); + name = xstrdup("-invalid-"); } // apply :filter /pat/ or file name not available if (name == NULL || message_filtered(name)) { @@ -1058,7 +1025,6 @@ void ex_jumps(exarg_T *eap) xfree(name); os_breakcheck(); } - ui_flush(); } if (curwin->w_jumplistidx == curwin->w_jumplistlen) { msg_puts("\n>"); @@ -1072,9 +1038,7 @@ void ex_clearjumps(exarg_T *eap) curwin->w_jumplistidx = 0; } -/* - * print the changelist - */ +// print the changelist void ex_changes(exarg_T *eap) { int i; @@ -1083,25 +1047,23 @@ void ex_changes(exarg_T *eap) // Highlight title msg_puts_title(_("\nchange line col text")); - for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i) { + for (i = 0; i < curbuf->b_changelistlen && !got_int; i++) { if (curbuf->b_changelist[i].mark.lnum != 0) { msg_putchar('\n'); if (got_int) { break; } - sprintf((char *)IObuff, "%c %3d %5ld %4d ", - i == curwin->w_changelistidx ? '>' : ' ', - i > curwin->w_changelistidx ? i - curwin->w_changelistidx - : curwin->w_changelistidx - i, - (long)curbuf->b_changelist[i].mark.lnum, - curbuf->b_changelist[i].mark.col); + snprintf(IObuff, IOSIZE, "%c %3d %5ld %4d ", + i == curwin->w_changelistidx ? '>' : ' ', + i > curwin->w_changelistidx ? i - curwin->w_changelistidx : curwin->w_changelistidx - i, + (long)curbuf->b_changelist[i].mark.lnum, + curbuf->b_changelist[i].mark.col); msg_outtrans((char *)IObuff); - name = mark_line(&curbuf->b_changelist[i].mark, 17); - msg_outtrans_attr(name, HL_ATTR(HLF_D)); + name = (char_u *)mark_line(&curbuf->b_changelist[i].mark, 17); + msg_outtrans_attr((char *)name, HL_ATTR(HLF_D)); xfree(name); os_breakcheck(); } - ui_flush(); } if (curwin->w_changelistidx == curbuf->b_changelistlen) { msg_puts("\n>"); @@ -1111,43 +1073,41 @@ void ex_changes(exarg_T *eap) #define ONE_ADJUST(add) \ { \ lp = add; \ - if (*lp >= line1 && *lp <= line2) \ - { \ - if (amount == MAXLNUM) \ - *lp = 0; \ - else \ - *lp += amount; \ + if (*lp >= line1 && *lp <= line2) { \ + if (amount == MAXLNUM) { \ + *lp = 0; \ + } else { \ + *lp += amount; \ + } \ + } else if (amount_after && *lp > line2) { \ + *lp += amount_after; \ } \ - else if (amount_after && *lp > line2) \ - *lp += amount_after; \ } // don't delete the line, just put at first deleted line #define ONE_ADJUST_NODEL(add) \ { \ lp = add; \ - if (*lp >= line1 && *lp <= line2) \ - { \ - if (amount == MAXLNUM) \ - *lp = line1; \ - else \ - *lp += amount; \ + if (*lp >= line1 && *lp <= line2) { \ + if (amount == MAXLNUM) { \ + *lp = line1; \ + } else { \ + *lp += amount; \ + } \ + } else if (amount_after && *lp > line2) { \ + *lp += amount_after; \ } \ - else if (amount_after && *lp > line2) \ - *lp += amount_after; \ - } - -/* - * Adjust marks between line1 and line2 (inclusive) to move 'amount' lines. - * Must be called before changed_*(), appended_lines() or deleted_lines(). - * May be called before or after changing the text. - * When deleting lines line1 to line2, use an 'amount' of MAXLNUM: The marks - * within this range are made invalid. - * If 'amount_after' is non-zero adjust marks after line2. - * Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2); - * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0); - * or: mark_adjust(56, 55, MAXLNUM, 2); - */ + } + +// Adjust marks between line1 and line2 (inclusive) to move 'amount' lines. +// Must be called before changed_*(), appended_lines() or deleted_lines(). +// May be called before or after changing the text. +// When deleting lines line1 to line2, use an 'amount' of MAXLNUM: The marks +// within this range are made invalid. +// If 'amount_after' is non-zero adjust marks after line2. +// Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2); +// Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0); +// or: mark_adjust(56, 55, MAXLNUM, 2); void mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after, ExtmarkOp op) { @@ -1242,9 +1202,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount ONE_ADJUST_NODEL(&(saved_cursor.lnum)); } - /* - * Adjust items in all windows related to the current buffer. - */ + // Adjust items in all windows related to the current buffer. FOR_ALL_TAB_WINDOWS(tab, win) { if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // Marks in the jumplist. When deleting lines, this may create @@ -1320,8 +1278,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount #define COL_ADJUST(pp) \ { \ posp = pp; \ - if (posp->lnum == lnum && posp->col >= mincol) \ - { \ + if (posp->lnum == lnum && posp->col >= mincol) { \ posp->lnum += lnum_amount; \ assert(col_amount > INT_MIN && col_amount <= INT_MAX); \ if (col_amount < 0 && posp->col <= (colnr_T) - col_amount) { \ @@ -1386,12 +1343,10 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c // saved cursor for formatting COL_ADJUST(&saved_cursor); - /* - * Adjust items in all windows related to the current buffer. - */ + // Adjust items in all windows related to the current buffer. FOR_ALL_WINDOWS_IN_TAB(win, curtab) { // marks in the jumplist - for (i = 0; i < win->w_jumplistlen; ++i) { + for (i = 0; i < win->w_jumplistlen; i++) { if (win->w_jumplist[i].fmark.fnum == fnum) { COL_ADJUST(&(win->w_jumplist[i].fmark.mark)); } @@ -1486,14 +1441,12 @@ void cleanup_jumplist(win_T *wp, bool checktail) } } -/* - * Copy the jumplist from window "from" to window "to". - */ +// Copy the jumplist from window "from" to window "to". void copy_jumplist(win_T *from, win_T *to) { int i; - for (i = 0; i < from->w_jumplistlen; ++i) { + for (i = 0; i < from->w_jumplistlen; i++) { to->w_jumplist[i] = from->w_jumplist[i]; if (from->w_jumplist[i].fname != NULL) { to->w_jumplist[i].fname = xstrdup(from->w_jumplist[i].fname); @@ -1521,10 +1474,8 @@ const void *mark_jumplist_iter(const void *const iter, const win_T *const win, x *fm = (xfmark_T)INIT_XFMARK; return NULL; } - const xfmark_T *const iter_mark = - (iter == NULL - ? &(win->w_jumplist[0]) - : (const xfmark_T *const)iter); + const xfmark_T *const iter_mark = iter == NULL ? &(win->w_jumplist[0]) + : (const xfmark_T *const)iter; *fm = *iter_mark; if (iter_mark == &(win->w_jumplist[win->w_jumplistlen - 1])) { return NULL; @@ -1560,9 +1511,9 @@ const void *mark_global_iter(const void *const iter, char *const name, xfmark_T return NULL; } size_t iter_off = (size_t)(iter_mark - &(namedfm[0])); - *name = (char)(iter_off < NMARKS - ? 'A' + (char)iter_off - : '0' + (char)(iter_off - NMARKS)); + *name = (char)(iter_off < NMARKS ? + 'A' + (char)iter_off : + '0' + (char)(iter_off - NMARKS)); *fm = *iter_mark; while ((size_t)(++iter_mark - &(namedfm[0])) < ARRAY_SIZE(namedfm)) { if (iter_mark->fmark.mark.lnum) { @@ -1624,16 +1575,11 @@ const void *mark_buffer_iter(const void *const iter, const buf_T *const buf, cha FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT { *name = NUL; - char mark_name = (char)(iter == NULL - ? NUL - : (iter == &(buf->b_last_cursor) - ? '"' - : (iter == &(buf->b_last_insert) - ? '^' - : (iter == &(buf->b_last_change) - ? '.' - : 'a' + (char)((const fmark_T *)iter - - &(buf->b_namedm[0])))))); + char mark_name = (char)(iter == NULL ? NUL : + iter == &(buf->b_last_cursor) ? '"' : + iter == &(buf->b_last_insert) ? '^' : + iter == &(buf->b_last_change) ? '.' : + 'a' + (char)((const fmark_T *)iter - &(buf->b_namedm[0]))); const fmark_T *iter_mark = next_buffer_mark(buf, &mark_name); while (iter_mark != NULL && iter_mark->mark.lnum == 0) { iter_mark = next_buffer_mark(buf, &mark_name); @@ -1710,14 +1656,12 @@ bool mark_set_local(const char name, buf_T *const buf, const fmark_T fm, const b return true; } -/* - * Free items in the jumplist of window "wp". - */ +// Free items in the jumplist of window "wp". void free_jumplist(win_T *wp) { int i; - for (i = 0; i < wp->w_jumplistlen; ++i) { + for (i = 0; i < wp->w_jumplistlen; i++) { free_xfmark(wp->w_jumplist[i]); } wp->w_jumplistlen = 0; @@ -1754,11 +1698,11 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) FUNC_ATTR_NONNULL_ALL { if (lp->col > 0 || lp->coladd > 1) { - const char_u *const p = ml_get_buf(buf, lp->lnum, false); + const char_u *const p = (char_u *)ml_get_buf(buf, lp->lnum, false); if (*p == NUL || (int)STRLEN(p) < lp->col) { lp->col = 0; } else { - lp->col -= utf_head_off(p, p + lp->col); + lp->col -= utf_head_off((char *)p, (char *)p + lp->col); } // Reset "coladd" when the cursor would be on the right half of a // double-wide character. diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h index a78056c5f9..f9df0028db 100644 --- a/src/nvim/mark_defs.h +++ b/src/nvim/mark_defs.h @@ -5,10 +5,8 @@ #include "nvim/os/time.h" #include "nvim/pos.h" -/* - * marks: positions in a file - * (a normal mark is a lnum/col pair, the same as a file position) - */ +// marks: positions in a file +// (a normal mark is a lnum/col pair, the same as a file position) /// Flags for outcomes when moving to a mark. typedef enum { @@ -88,4 +86,4 @@ typedef struct xfilemark { #define INIT_XFMARK { INIT_FMARK, NULL } -#endif // NVIM_MARK_DEFS_H +#endif // NVIM_MARK_DEFS_H diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 03340a99d6..ad1680322c 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -49,8 +49,8 @@ #include <assert.h> +#include "klib/kvec.h" #include "nvim/garray.h" -#include "nvim/lib/kvec.h" #include "nvim/marktree.h" #define T MT_BRANCH_FACTOR diff --git a/src/nvim/match.c b/src/nvim/match.c index 1c34c9f004..b422dc0ba8 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -29,13 +29,13 @@ static char *e_invalwindow = N_("E957: Invalid window number"); #define SEARCH_HL_PRIORITY 0 -/// Add match to the match list of window 'wp'. The pattern 'pat' will be -/// highlighted with the group 'grp' with priority 'prio'. -/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1). +/// Add match to the match list of window "wp". +/// If "pat" is not NULL the pattern will be highlighted with the group "grp" +/// with priority "prio". +/// If "pos_list" is not NULL the list of posisions defines the highlights. +/// Optionally, a desired ID "id" can be specified (greater than or equal to 1). +/// If no particular ID is desired, -1 must be specified for "id". /// -/// @param[in] id a desired ID 'id' can be specified -/// (greater than or equal to 1). -1 must be specified if no -/// particular ID is desired /// @param[in] conceal_char pointer to conceal replacement char /// @return ID of added match, -1 on failure. static int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id, @@ -47,7 +47,7 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in matchitem_T *m; int hlg_id; regprog_T *regprog = NULL; - int rtype = SOME_VALID; + int rtype = UPD_SOME_VALID; if (*grp == NUL || (pat != NULL && *pat == NUL)) { return -1; @@ -58,16 +58,26 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in (int64_t)id); return -1; } - if (id != -1) { - cur = wp->w_match_head; - while (cur != NULL) { - if (cur->id == id) { + if (id == -1) { + // use the next available match ID + id = wp->w_next_match_id++; + } else { + // check the given ID is not already in use + for (cur = wp->w_match_head; cur != NULL; cur = cur->mit_next) { + if (cur->mit_id == id) { semsg(_("E801: ID already taken: %" PRId64), (int64_t)id); return -1; } - cur = cur->next; + } + + // Make sure the next match ID is always higher than the highest + // manually selected ID. Add some extra in case a few more IDs are + // added soon. + if (wp->w_next_match_id < id + 100) { + wp->w_next_match_id = id + 100; } } + if ((hlg_id = syn_check_group(grp, strlen(grp))) == 0) { return -1; } @@ -76,30 +86,22 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in return -1; } - // Find available match ID. - while (id == -1) { - cur = wp->w_match_head; - while (cur != NULL && cur->id != wp->w_next_match_id) { - cur = cur->next; - } - if (cur == NULL) { - id = wp->w_next_match_id; - } - wp->w_next_match_id++; - } - // Build new match. m = xcalloc(1, sizeof(matchitem_T)); - m->id = id; - m->priority = prio; - m->pattern = pat == NULL ? NULL: xstrdup(pat); - m->hlg_id = hlg_id; - m->match.regprog = regprog; - m->match.rmm_ic = false; - m->match.rmm_maxcol = 0; - m->conceal_char = 0; + if (pos_list != NULL) { + m->mit_pos_array = xcalloc((size_t)tv_list_len(pos_list), sizeof(llpos_T)); + m->mit_pos_count = tv_list_len(pos_list); + } + m->mit_id = id; + m->mit_priority = prio; + m->mit_pattern = pat == NULL ? NULL: xstrdup(pat); + m->mit_hlg_id = hlg_id; + m->mit_match.regprog = regprog; + m->mit_match.rmm_ic = false; + m->mit_match.rmm_maxcol = 0; + m->mit_conceal_char = 0; if (conceal_char != NULL) { - m->conceal_char = utf_ptr2char(conceal_char); + m->mit_conceal_char = utf_ptr2char(conceal_char); } // Set up position matches @@ -129,7 +131,7 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in if (lnum <= 0) { continue; } - m->pos.pos[i].lnum = lnum; + m->mit_pos_array[i].lnum = lnum; subli = TV_LIST_ITEM_NEXT(subl, subli); if (subli != NULL) { col = (colnr_T)tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error); @@ -150,15 +152,15 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in } } } - m->pos.pos[i].col = col; - m->pos.pos[i].len = len; + m->mit_pos_array[i].col = col; + m->mit_pos_array[i].len = len; } else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) { if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) { continue; } - m->pos.pos[i].lnum = (linenr_T)TV_LIST_ITEM_TV(li)->vval.v_number; - m->pos.pos[i].col = 0; - m->pos.pos[i].len = 0; + m->mit_pos_array[i].lnum = (linenr_T)TV_LIST_ITEM_TV(li)->vval.v_number; + m->mit_pos_array[i].col = 0; + m->mit_pos_array[i].len = 0; } else { semsg(_("E5031: List or number required at position %d"), (int)tv_list_idx_of_item(pos_list, li)); @@ -171,9 +173,6 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in botlnum = lnum + 1; } i++; - if (i >= MAXPOSMATCH) { - break; - } }); // Calculate top and bottom lines for redrawing area @@ -191,9 +190,9 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in wp->w_buffer->b_mod_bot = botlnum; wp->w_buffer->b_mod_xlines = 0; } - m->pos.toplnum = toplnum; - m->pos.botlnum = botlnum; - rtype = VALID; + m->mit_toplnum = toplnum; + m->mit_botlnum = botlnum; + rtype = UPD_VALID; } } @@ -201,21 +200,23 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in // the match priorities. cur = wp->w_match_head; prev = cur; - while (cur != NULL && prio >= cur->priority) { + while (cur != NULL && prio >= cur->mit_priority) { prev = cur; - cur = cur->next; + cur = cur->mit_next; } if (cur == prev) { wp->w_match_head = m; } else { - prev->next = m; + prev->mit_next = m; } - m->next = cur; + m->mit_next = cur; redraw_later(wp, rtype); return id; fail: + xfree(m->mit_pattern); + xfree(m->mit_pos_array); xfree(m); return -1; } @@ -227,19 +228,18 @@ static int match_delete(win_T *wp, int id, bool perr) { matchitem_T *cur = wp->w_match_head; matchitem_T *prev = cur; - int rtype = SOME_VALID; + int rtype = UPD_SOME_VALID; if (id < 1) { if (perr) { - semsg(_("E802: Invalid ID: %" PRId64 - " (must be greater than or equal to 1)"), + semsg(_("E802: Invalid ID: %" PRId64 " (must be greater than or equal to 1)"), (int64_t)id); } return -1; } - while (cur != NULL && cur->id != id) { + while (cur != NULL && cur->mit_id != id) { prev = cur; - cur = cur->next; + cur = cur->mit_next; } if (cur == NULL) { if (perr) { @@ -248,28 +248,29 @@ static int match_delete(win_T *wp, int id, bool perr) return -1; } if (cur == prev) { - wp->w_match_head = cur->next; + wp->w_match_head = cur->mit_next; } else { - prev->next = cur->next; + prev->mit_next = cur->mit_next; } - vim_regfree(cur->match.regprog); - xfree(cur->pattern); - if (cur->pos.toplnum != 0) { + vim_regfree(cur->mit_match.regprog); + xfree(cur->mit_pattern); + if (cur->mit_toplnum != 0) { if (wp->w_buffer->b_mod_set) { - if (wp->w_buffer->b_mod_top > cur->pos.toplnum) { - wp->w_buffer->b_mod_top = cur->pos.toplnum; + if (wp->w_buffer->b_mod_top > cur->mit_toplnum) { + wp->w_buffer->b_mod_top = cur->mit_toplnum; } - if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) { - wp->w_buffer->b_mod_bot = cur->pos.botlnum; + if (wp->w_buffer->b_mod_bot < cur->mit_botlnum) { + wp->w_buffer->b_mod_bot = cur->mit_botlnum; } } else { wp->w_buffer->b_mod_set = true; - wp->w_buffer->b_mod_top = cur->pos.toplnum; - wp->w_buffer->b_mod_bot = cur->pos.botlnum; + wp->w_buffer->b_mod_top = cur->mit_toplnum; + wp->w_buffer->b_mod_bot = cur->mit_botlnum; wp->w_buffer->b_mod_xlines = 0; } - rtype = VALID; + rtype = UPD_VALID; } + xfree(cur->mit_pos_array); xfree(cur); redraw_later(wp, rtype); return 0; @@ -281,23 +282,24 @@ void clear_matches(win_T *wp) matchitem_T *m; while (wp->w_match_head != NULL) { - m = wp->w_match_head->next; - vim_regfree(wp->w_match_head->match.regprog); - xfree(wp->w_match_head->pattern); + m = wp->w_match_head->mit_next; + vim_regfree(wp->w_match_head->mit_match.regprog); + xfree(wp->w_match_head->mit_pattern); + xfree(wp->w_match_head->mit_pos_array); xfree(wp->w_match_head); wp->w_match_head = m; } - redraw_later(wp, SOME_VALID); + redraw_later(wp, UPD_SOME_VALID); } /// Get match from ID 'id' in window 'wp'. /// Return NULL if match not found. -matchitem_T *get_match(win_T *wp, int id) +static matchitem_T *get_match(win_T *wp, int id) { matchitem_T *cur = wp->w_match_head; - while (cur != NULL && cur->id != id) { - cur = cur->next; + while (cur != NULL && cur->mit_id != id) { + cur = cur->mit_next; } return cur; } @@ -310,18 +312,18 @@ void init_search_hl(win_T *wp, match_T *search_hl) // match matchitem_T *cur = wp->w_match_head; while (cur != NULL) { - cur->hl.rm = cur->match; - if (cur->hlg_id == 0) { - cur->hl.attr = 0; + cur->mit_hl.rm = cur->mit_match; + if (cur->mit_hlg_id == 0) { + cur->mit_hl.attr = 0; } else { - cur->hl.attr = syn_id2attr(cur->hlg_id); + cur->mit_hl.attr = syn_id2attr(cur->mit_hlg_id); } - cur->hl.buf = wp->w_buffer; - cur->hl.lnum = 0; - cur->hl.first_lnum = 0; + cur->mit_hl.buf = wp->w_buffer; + cur->mit_hl.lnum = 0; + cur->mit_hl.first_lnum = 0; // Set the time limit to 'redrawtime'. - cur->hl.tm = profile_setlimit(p_rdt); - cur = cur->next; + cur->mit_hl.tm = profile_setlimit(p_rdt); + cur = cur->mit_next; } search_hl->buf = wp->w_buffer; search_hl->lnum = 0; @@ -332,19 +334,19 @@ void init_search_hl(win_T *wp, match_T *search_hl) } /// @param shl points to a match. Fill on match. -/// @param posmatch match positions +/// @param posmatch match item with positions /// @param mincol minimal column for a match /// /// @return one on match, otherwise return zero. -static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, colnr_T mincol) +static int next_search_hl_pos(match_T *shl, linenr_T lnum, matchitem_T *match, colnr_T mincol) FUNC_ATTR_NONNULL_ALL { int i; int found = -1; shl->lnum = 0; - for (i = posmatch->cur; i < MAXPOSMATCH; i++) { - llpos_T *pos = &posmatch->pos[i]; + for (i = match->mit_pos_cur; i < match->mit_pos_count; i++) { + llpos_T *pos = &match->mit_pos_array[i]; if (pos->lnum == 0) { break; @@ -354,25 +356,24 @@ static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, } if (pos->lnum == lnum) { if (found >= 0) { - // if this match comes before the one at "found" then swap - // them - if (pos->col < posmatch->pos[found].col) { + // if this match comes before the one at "found" then swap them + if (pos->col < match->mit_pos_array[found].col) { llpos_T tmp = *pos; - *pos = posmatch->pos[found]; - posmatch->pos[found] = tmp; + *pos = match->mit_pos_array[found]; + match->mit_pos_array[found] = tmp; } } else { found = i; } } } - posmatch->cur = 0; + match->mit_pos_cur = 0; if (found >= 0) { - colnr_T start = posmatch->pos[found].col == 0 - ? 0: posmatch->pos[found].col - 1; - colnr_T end = posmatch->pos[found].col == 0 - ? MAXCOL : start + posmatch->pos[found].len; + colnr_T start = match->mit_pos_array[found].col == 0 + ? 0: match->mit_pos_array[found].col - 1; + colnr_T end = match->mit_pos_array[found].col == 0 + ? MAXCOL : start + match->mit_pos_array[found].len; shl->lnum = lnum; shl->rm.startpos[0].lnum = 0; @@ -381,7 +382,7 @@ static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, shl->rm.endpos[0].col = end; shl->is_addpos = true; shl->has_cursor = false; - posmatch->cur = found + 1; + match->mit_pos_cur = found + 1; return 1; } return 0; @@ -446,7 +447,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_ char_u *ml; matchcol = shl->rm.startpos[0].col; - ml = ml_get_buf(shl->buf, lnum, false) + matchcol; + ml = (char_u *)ml_get_buf(shl->buf, lnum, false) + matchcol; if (*ml == NUL) { matchcol++; shl->lnum = 0; @@ -460,18 +461,17 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_ shl->lnum = lnum; if (shl->rm.regprog != NULL) { // Remember whether shl->rm is using a copy of the regprog in - // cur->match. - bool regprog_is_copy = (shl != search_hl - && cur != NULL - && shl == &cur->hl - && cur->match.regprog == cur->hl.rm.regprog); + // cur->mit_match. + bool regprog_is_copy = (shl != search_hl && cur != NULL + && shl == &cur->mit_hl + && cur->mit_match.regprog == cur->mit_hl.rm.regprog); int timed_out = false; nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol, &(shl->tm), &timed_out); // Copy the regprog, in case it got freed and recompiled. if (regprog_is_copy) { - cur->match.regprog = cur->hl.rm.regprog; + cur->mit_match.regprog = cur->mit_hl.rm.regprog; } if (called_emsg > called_emsg_before || got_int || timed_out) { // Error while handling regexp: stop using this regexp. @@ -486,7 +486,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_ break; } } else if (cur != NULL) { - nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); + nmatched = next_search_hl_pos(shl, lnum, cur, matchcol); } if (nmatched == 0) { shl->lnum = 0; // no match found @@ -521,7 +521,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) shl = search_hl; shl_flag = true; } else { - shl = &cur->hl; // -V595 + shl = &cur->mit_hl; // -V595 } if (shl->rm.regprog != NULL && shl->lnum == 0 @@ -536,7 +536,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) } } if (cur != NULL) { - cur->pos.cur = 0; + cur->mit_pos_cur = 0; } bool pos_inprogress = true; // mark that a position match search is // in progress @@ -545,7 +545,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) || (cur != NULL && pos_inprogress))) { next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n, shl == search_hl ? NULL : cur); - pos_inprogress = !(cur == NULL || cur->pos.cur == 0); + pos_inprogress = !(cur == NULL || cur->mit_pos_cur == 0); if (shl->lnum != 0) { shl->first_lnum = shl->lnum + shl->rm.endpos[0].lnum @@ -558,7 +558,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) } } if (shl != search_hl && cur != NULL) { - cur = cur->next; + cur = cur->mit_next; } } } @@ -598,7 +598,7 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l shl = search_hl; shl_flag = true; } else { - shl = &cur->hl; // -V595 + shl = &cur->mit_hl; // -V595 } shl->startcol = MAXCOL; shl->endcol = MAXCOL; @@ -606,14 +606,14 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l shl->is_addpos = false; shl->has_cursor = false; if (cur != NULL) { - cur->pos.cur = 0; + cur->mit_pos_cur = 0; } next_search_hl(wp, search_hl, shl, lnum, mincol, shl == search_hl ? NULL : cur); // Need to get the line again, a multi-line regexp may have made it // invalid. - *line = ml_get_buf(wp->w_buffer, lnum, false); + *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); if (shl->lnum != 0 && shl->lnum <= lnum) { if (shl->lnum == lnum) { @@ -649,7 +649,7 @@ bool prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **l area_highlighting = true; } if (shl != search_hl && cur != NULL) { - cur = cur->next; + cur = cur->mit_next; } } return area_highlighting; @@ -674,14 +674,14 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match // Do this for 'search_hl' and the match list (ordered by priority). while (cur != NULL || !shl_flag) { if (!shl_flag - && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { + && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) { shl = search_hl; shl_flag = true; } else { - shl = &cur->hl; + shl = &cur->mit_hl; } if (cur != NULL) { - cur->pos.cur = 0; + cur->mit_pos_cur = 0; } bool pos_inprogress = true; // mark that a position match search is // in progress @@ -706,9 +706,9 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match // the match. if (cur != NULL && shl != search_hl - && syn_name2id("Conceal") == cur->hlg_id) { + && syn_name2id("Conceal") == cur->mit_hlg_id) { *has_match_conc = col == shl->startcol ? 2 : 1; - *match_conc = cur->conceal_char; + *match_conc = cur->mit_conceal_char; } else { *has_match_conc = 0; } @@ -717,11 +717,11 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match next_search_hl(wp, search_hl, shl, lnum, col, shl == search_hl ? NULL : cur); - pos_inprogress = !(cur == NULL || cur->pos.cur == 0); + pos_inprogress = !(cur == NULL || cur->mit_pos_cur == 0); // Need to get the line again, a multi-line regexp // may have made it invalid. - *line = ml_get_buf(wp->w_buffer, lnum, false); + *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); if (shl->lnum == lnum) { shl->startcol = shl->rm.startpos[0].col; @@ -738,7 +738,13 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match if (shl->startcol == shl->endcol) { // highlight empty match, try again after it - shl->endcol += utfc_ptr2len((char *)(*line) + shl->endcol); + char *p = (char *)(*line) + shl->endcol; + + if (*p == NUL) { + shl->endcol++; + } else { + shl->endcol += utfc_ptr2len(p); + } } // Loop to check if the match starts at the @@ -749,30 +755,30 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match break; } if (shl != search_hl && cur != NULL) { - cur = cur->next; + cur = cur->mit_next; } } - // Use attributes from match with highest priority among - // 'search_hl' and the match list. + // Use attributes from match with highest priority among 'search_hl' and + // the match list. *search_attr_from_match = false; search_attr = search_hl->attr_cur; cur = wp->w_match_head; shl_flag = false; while (cur != NULL || !shl_flag) { if (!shl_flag - && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { + && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) { shl = search_hl; shl_flag = true; } else { - shl = &cur->hl; + shl = &cur->mit_hl; } if (shl->attr_cur != 0) { search_attr = shl->attr_cur; *search_attr_from_match = shl != search_hl; } if (shl != search_hl && cur != NULL) { - cur = cur->next; + cur = cur->mit_next; } } // Only highlight one character after the last column. @@ -792,15 +798,22 @@ bool get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol) prevcol++; } - if (!search_hl->is_addpos && prevcol == search_hl->startcol) { + // Highlight a character after the end of the line if the match started + // at the end of the line or when the match continues in the next line + // (match includes the line break). + if (!search_hl->is_addpos && (prevcol == (long)search_hl->startcol + || (prevcol > (long)search_hl->startcol + && search_hl->endcol == MAXCOL))) { return true; } else { cur = wp->w_match_head; while (cur != NULL) { - if (!cur->hl.is_addpos && prevcol == cur->hl.startcol) { + if (!cur->mit_hl.is_addpos && (prevcol == (long)cur->mit_hl.startcol + || (prevcol > (long)cur->mit_hl.startcol + && cur->mit_hl.endcol == MAXCOL))) { return true; } - cur = cur->next; + cur = cur->mit_next; } } return false; @@ -815,21 +828,20 @@ void get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr bool shl_flag = false; // flag to indicate whether search_hl // has been processed or not - *char_attr = search_hl->attr; while (cur != NULL || !shl_flag) { if (!shl_flag - && (cur == NULL || cur->priority > SEARCH_HL_PRIORITY)) { + && (cur == NULL || cur->mit_priority > SEARCH_HL_PRIORITY)) { shl = search_hl; shl_flag = true; } else { - shl = &cur->hl; + shl = &cur->mit_hl; } if (col - 1 == (long)shl->startcol && (shl == search_hl || !shl->is_addpos)) { *char_attr = shl->attr; } if (shl != search_hl && cur != NULL) { - cur = cur->next; + cur = cur->mit_next; } } } @@ -859,7 +871,7 @@ static int matchadd_dict_arg(typval_T *tv, const char **conceal_char, win_T **wi } /// "clearmatches()" function -void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_clearmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *win = get_optional_window(argvars, 0); @@ -869,7 +881,7 @@ void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "getmatches()" function -void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { matchitem_T *cur; int i; @@ -883,13 +895,13 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) cur = win->w_match_head; while (cur != NULL) { dict_T *dict = tv_dict_alloc(); - if (cur->match.regprog == NULL) { + if (cur->mit_match.regprog == NULL) { // match added with matchaddpos() - for (i = 0; i < MAXPOSMATCH; i++) { + for (i = 0; i < cur->mit_pos_count; i++) { llpos_T *llpos; char buf[30]; // use 30 to avoid compiler warning - llpos = &cur->pos.pos[i]; + llpos = &cur->mit_pos_array[i]; if (llpos->lnum == 0) { break; } @@ -904,27 +916,27 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_dict_add_list(dict, buf, (size_t)len, l); } } else { - tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cur->pattern); + tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cur->mit_pattern); } tv_dict_add_str(dict, S_LEN("group"), - (const char *)syn_id2name(cur->hlg_id)); - tv_dict_add_nr(dict, S_LEN("priority"), (varnumber_T)cur->priority); - tv_dict_add_nr(dict, S_LEN("id"), (varnumber_T)cur->id); + (const char *)syn_id2name(cur->mit_hlg_id)); + tv_dict_add_nr(dict, S_LEN("priority"), (varnumber_T)cur->mit_priority); + tv_dict_add_nr(dict, S_LEN("id"), (varnumber_T)cur->mit_id); - if (cur->conceal_char) { + if (cur->mit_conceal_char) { char buf[MB_MAXBYTES + 1]; - buf[utf_char2bytes(cur->conceal_char, buf)] = NUL; + buf[utf_char2bytes(cur->mit_conceal_char, buf)] = NUL; tv_dict_add_str(dict, S_LEN("conceal"), buf); } tv_list_append_dict(rettv->vval.v_list, dict); - cur = cur->next; + cur = cur->mit_next; } } /// "setmatches()" function -void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { dict_T *d; list_T *s = NULL; @@ -1027,7 +1039,7 @@ void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "matchadd()" function -void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matchadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { char grpbuf[NUMBUFLEN]; char patbuf[NUMBUFLEN]; @@ -1069,7 +1081,7 @@ void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "matchaddpo()" function -void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matchaddpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; @@ -1120,7 +1132,7 @@ void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "matcharg()" function -void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matcharg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const int id = (int)tv_get_number(&argvars[0]); @@ -1133,8 +1145,8 @@ void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (m != NULL) { tv_list_append_string(rettv->vval.v_list, - (const char *)syn_id2name(m->hlg_id), -1); - tv_list_append_string(rettv->vval.v_list, (const char *)m->pattern, -1); + (const char *)syn_id2name(m->mit_hlg_id), -1); + tv_list_append_string(rettv->vval.v_list, (const char *)m->mit_pattern, -1); } else { tv_list_append_string(rettv->vval.v_list, NULL, 0); tv_list_append_string(rettv->vval.v_list, NULL, 0); @@ -1143,7 +1155,7 @@ void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "matchdelete()" function -void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matchdelete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *win = get_optional_window(argvars, 1); if (win == NULL) { @@ -1159,9 +1171,9 @@ void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// skipping commands to find the next command. void ex_match(exarg_T *eap) { - char_u *p; - char_u *g = NULL; - char_u *end; + char *p; + char *g = NULL; + char *end; int c; int id; @@ -1178,16 +1190,16 @@ void ex_match(exarg_T *eap) } if (ends_excmd(*eap->arg)) { - end = (char_u *)eap->arg; + end = eap->arg; } else if ((STRNICMP(eap->arg, "none", 4) == 0 && (ascii_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) { - end = (char_u *)eap->arg + 4; + end = eap->arg + 4; } else { - p = skiptowhite((char_u *)eap->arg); + p = skiptowhite(eap->arg); if (!eap->skip) { - g = vim_strnsave((char_u *)eap->arg, (size_t)(p - (char_u *)eap->arg)); + g = xstrnsave(eap->arg, (size_t)(p - eap->arg)); } - p = (char_u *)skipwhite((char *)p); + p = skipwhite(p); if (*p == NUL) { // There must be two arguments. xfree(g); @@ -1196,7 +1208,7 @@ void ex_match(exarg_T *eap) } end = skip_regexp(p + 1, *p, true, NULL); if (!eap->skip) { - if (*end != NUL && !ends_excmd(*skipwhite((char *)end + 1))) { + if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) { xfree(g); eap->errmsg = ex_errmsg(e_trailing_arg, (const char *)end); return; @@ -1207,13 +1219,13 @@ void ex_match(exarg_T *eap) return; } - c = *end; + c = (uint8_t)(*end); *end = NUL; match_add(curwin, (const char *)g, (const char *)p + 1, 10, id, NULL, NULL); xfree(g); - *end = (char_u)c; + *end = (char)c; } } - eap->nextcmd = (char *)find_nextcmd(end); + eap->nextcmd = find_nextcmd(end); } diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index af9e214d92..33d652a51f 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -132,10 +132,8 @@ const uint8_t utf8len_tab_zero[] = { 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // F? }; -/* - * Canonical encoding names and their properties. - * "iso-8859-n" is handled by enc_canonize() directly. - */ +// Canonical encoding names and their properties. +// "iso-8859-n" is handled by enc_canonize() directly. static struct { const char *name; int prop; int codepage; } enc_canon_table[] = @@ -269,9 +267,7 @@ enc_canon_table[] = #define IDX_COUNT 59 }; -/* - * Aliases for encoding names. - */ +// Aliases for encoding names. static struct { const char *name; int canon; } enc_alias_table[] = @@ -342,29 +338,25 @@ enc_alias_table[] = { NULL, 0 } }; -/* - * Find encoding "name" in the list of canonical encoding names. - * Returns -1 if not found. - */ -static int enc_canon_search(const char_u *name) +/// Find encoding "name" in the list of canonical encoding names. +/// Returns -1 if not found. +static int enc_canon_search(const char *name) FUNC_ATTR_PURE { for (int i = 0; i < IDX_COUNT; i++) { - if (STRCMP(name, enc_canon_table[i].name) == 0) { + if (strcmp(name, enc_canon_table[i].name) == 0) { return i; } } return -1; } -/* - * Find canonical encoding "name" in the list and return its properties. - * Returns 0 if not found. - */ +// Find canonical encoding "name" in the list and return its properties. +// Returns 0 if not found. int enc_canon_props(const char_u *name) FUNC_ATTR_PURE { - int i = enc_canon_search(name); + int i = enc_canon_search((char *)name); if (i >= 0) { return enc_canon_table[i].prop; } else if (STRNCMP(name, "2byte-", 6) == 0) { @@ -375,13 +367,11 @@ int enc_canon_props(const char_u *name) return 0; } -/* - * Return the size of the BOM for the current buffer: - * 0 - no BOM - * 2 - UCS-2 or UTF-16 BOM - * 4 - UCS-4 BOM - * 3 - UTF-8 BOM - */ +// Return the size of the BOM for the current buffer: +// 0 - no BOM +// 2 - UCS-2 or UTF-16 BOM +// 4 - UCS-4 BOM +// 3 - UTF-8 BOM int bomb_size(void) FUNC_ATTR_PURE { @@ -389,7 +379,7 @@ int bomb_size(void) if (curbuf->b_p_bomb && !curbuf->b_p_bin) { if (*curbuf->b_p_fenc == NUL - || STRCMP(curbuf->b_p_fenc, "utf-8") == 0) { + || strcmp(curbuf->b_p_fenc, "utf-8") == 0) { n = 3; } else if (STRNCMP(curbuf->b_p_fenc, "ucs-2", 5) == 0 || STRNCMP(curbuf->b_p_fenc, "utf-16", 6) == 0) { @@ -401,9 +391,7 @@ int bomb_size(void) return n; } -/* - * Remove all BOM from "s" by moving remaining text. - */ +// Remove all BOM from "s" by moving remaining text. void remove_bom(char_u *s) { char *p = (char *)s; @@ -417,13 +405,11 @@ void remove_bom(char_u *s) } } -/* - * Get class of pointer: - * 0 for blank or NUL - * 1 for punctuation - * 2 for an (ASCII) word character - * >2 for other word characters - */ +// Get class of pointer: +// 0 for blank or NUL +// 1 for punctuation +// 2 for an (ASCII) word character +// >2 for other word characters int mb_get_class(const char_u *p) FUNC_ATTR_PURE { @@ -445,9 +431,7 @@ int mb_get_class_tab(const char_u *p, const uint64_t *const chartab) return utf_class_tab(utf_ptr2char((char *)p), chartab); } -/* - * Return true if "c" is in "table". - */ +// Return true if "c" is in "table". static bool intable(const struct interval *table, size_t n_items, int c) FUNC_ATTR_PURE { @@ -587,7 +571,7 @@ 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, (int)size + (int)(p - (char_u *)str))) { + p += utfc_ptr2len_len((char *)p, (int)size + (int)(p - (char_u *)str))) { clen += (size_t)utf_ptr2cells((char *)p); } @@ -646,22 +630,20 @@ int utf_ptr2char(const char *const p_in) return p[0]; } -/* - * Convert a UTF-8 byte sequence to a wide character. - * String is assumed to be terminated by NUL or after "n" bytes, whichever - * comes first. - * The function is safe in the sense that it never accesses memory beyond the - * first "n" bytes of "s". - * - * On success, returns decoded codepoint, advances "s" to the beginning of - * next character and decreases "n" accordingly. - * - * If end of string was reached, returns 0 and, if "n" > 0, advances "s" past - * NUL byte. - * - * If byte sequence is illegal or incomplete, returns -1 and does not advance - * "s". - */ +// Convert a UTF-8 byte sequence to a wide character. +// String is assumed to be terminated by NUL or after "n" bytes, whichever +// comes first. +// The function is safe in the sense that it never accesses memory beyond the +// first "n" bytes of "s". +// +// On success, returns decoded codepoint, advances "s" to the beginning of +// next character and decreases "n" accordingly. +// +// If end of string was reached, returns 0 and, if "n" > 0, advances "s" past +// NUL byte. +// +// If byte sequence is illegal or incomplete, returns -1 and does not advance +// "s". static int utf_safe_read_char_adv(const char_u **s, size_t *n) { int c; @@ -701,10 +683,8 @@ static int utf_safe_read_char_adv(const char_u **s, size_t *n) return -1; } -/* - * Get character at **pp and advance *pp to the next character. - * Note: composing characters are skipped! - */ +// Get character at **pp and advance *pp to the next character. +// Note: composing characters are skipped! int mb_ptr2char_adv(const char_u **const pp) { int c; @@ -714,10 +694,8 @@ int mb_ptr2char_adv(const char_u **const pp) return c; } -/* - * Get character at **pp and advance *pp to the next character. - * Note: composing characters are returned as separate characters. - */ +// Get character at **pp and advance *pp to the next character. +// Note: composing characters are returned as separate characters. int mb_cptr2char_adv(const char_u **pp) { int c; @@ -727,12 +705,10 @@ int mb_cptr2char_adv(const char_u **pp) return c; } -/* - * Check if the character pointed to by "p2" is a composing character when it - * comes after "p1". For Arabic sometimes "ab" is replaced with "c", which - * behaves like a composing character. - */ -bool utf_composinglike(const char_u *p1, const char_u *p2) +/// Check if the character pointed to by "p2" is a composing character when it +/// comes after "p1". For Arabic sometimes "ab" is replaced with "c", which +/// behaves like a composing character. +bool utf_composinglike(const char *p1, const char *p2) { int c2; @@ -754,21 +730,19 @@ bool utf_composinglike(const char_u *p1, const char_u *p2) /// space at least for #MAX_MCO + 1 elements. /// /// @return leading character. -int utfc_ptr2char(const char_u *p, int *pcc) +int utfc_ptr2char(const char *p_in, int *pcc) { - int len; - int c; - int cc; + uint8_t *p = (uint8_t *)p_in; int i = 0; - c = utf_ptr2char((char *)p); - len = utf_ptr2len((char *)p); + int c = utf_ptr2char((char *)p); + int len = utf_ptr2len((char *)p); // Only accept a composing char when the first char isn't illegal. if ((len > 1 || *p < 0x80) && p[len] >= 0x80 - && utf_composinglike(p, p + len)) { - cc = utf_ptr2char((char *)p + len); + && utf_composinglike((char *)p, (char *)p + len)) { + int cc = utf_ptr2char((char *)p + len); for (;;) { pcc[i++] = cc; if (i == MAX_MCO) { @@ -788,12 +762,10 @@ int utfc_ptr2char(const char_u *p, int *pcc) return c; } -/* - * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO - * composing characters. Use no more than p[maxlen]. - * - * @param [out] pcc: composing chars, last one is 0 - */ +// Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO +// composing characters. Use no more than p[maxlen]. +// +// @param [out] pcc: composing chars, last one is 0 int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen) { assert(maxlen > 0); @@ -811,7 +783,7 @@ int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen) int len_cc = utf_ptr2len_len(p + len, maxlen - len); safe = len_cc > 1 && len_cc <= maxlen - len; if (!safe || (pcc[i] = utf_ptr2char((char *)p + len)) < 0x80 - || !(i == 0 ? utf_composinglike(p, p + len) : utf_iscomposing(pcc[i]))) { + || !(i == 0 ? utf_composinglike((char *)p, (char *)p + len) : utf_iscomposing(pcc[i]))) { break; } len += len_cc; @@ -849,24 +821,20 @@ int utf_ptr2len(const char *const p_in) return len; } -/* - * Return length of UTF-8 character, obtained from the first byte. - * "b" must be between 0 and 255! - * Returns 1 for an invalid first byte value. - */ +// Return length of UTF-8 character, obtained from the first byte. +// "b" must be between 0 and 255! +// Returns 1 for an invalid first byte value. int utf_byte2len(int b) { return utf8len_tab[b]; } -/* - * Get the length of UTF-8 byte sequence "p[size]". Does not include any - * following composing characters. - * Returns 1 for "". - * Returns 1 for an illegal byte sequence (also in incomplete byte seq.). - * Returns number > "size" for an incomplete byte sequence. - * Never returns zero. - */ +// Get the length of UTF-8 byte sequence "p[size]". Does not include any +// following composing characters. +// Returns 1 for "". +// Returns 1 for an illegal byte sequence (also in incomplete byte seq.). +// Returns number > "size" for an incomplete byte sequence. +// Never returns zero. int utf_ptr2len_len(const char_u *p, int size) { int len; @@ -882,7 +850,7 @@ int utf_ptr2len_len(const char_u *p, int size) } else { m = len; } - for (i = 1; i < m; ++i) { + for (i = 1; i < m; i++) { if ((p[i] & 0xc0) != 0x80) { return 1; } @@ -918,7 +886,7 @@ int utfc_ptr2len(const char *const p_in) // skip all of them (otherwise the cursor would get stuck). int prevlen = 0; for (;;) { - if (p[len] < 0x80 || !utf_composinglike(p + prevlen, p + len)) { + if (p[len] < 0x80 || !utf_composinglike((char *)p + prevlen, (char *)p + len)) { return len; } @@ -928,13 +896,11 @@ int utfc_ptr2len(const char *const p_in) } } -/* - * Return the number of bytes the UTF-8 encoding of the character at "p[size]" - * takes. This includes following composing characters. - * Returns 0 for an empty string. - * Returns 1 for an illegal char or an incomplete byte sequence. - */ -int utfc_ptr2len_len(const char_u *p, int size) +/// Return the number of bytes the UTF-8 encoding of the character at "p[size]" +/// takes. This includes following composing characters. +/// Returns 0 for an empty string. +/// Returns 1 for an illegal char or an incomplete byte sequence. +int utfc_ptr2len_len(const char *p, int size) { int len; int prevlen; @@ -942,35 +908,31 @@ int utfc_ptr2len_len(const char_u *p, int size) if (size < 1 || *p == NUL) { return 0; } - if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) { // be quick for ASCII + if ((uint8_t)p[0] < 0x80 && (size == 1 || (uint8_t)p[1] < 0x80)) { // be quick for ASCII return 1; } // Skip over first UTF-8 char, stopping at a NUL byte. - len = utf_ptr2len_len(p, size); + len = utf_ptr2len_len((char_u *)p, size); // Check for illegal byte and incomplete byte sequence. - if ((len == 1 && p[0] >= 0x80) || len > size) { + if ((len == 1 && (uint8_t)p[0] >= 0x80) || len > size) { return 1; } - /* - * Check for composing characters. We can handle only the first six, but - * skip all of them (otherwise the cursor would get stuck). - */ + // Check for composing characters. We can handle only the first six, but + // skip all of them (otherwise the cursor would get stuck). prevlen = 0; while (len < size) { int len_next_char; - if (p[len] < 0x80) { + if ((uint8_t)p[len] < 0x80) { break; } - /* - * Next character length should not go beyond size to ensure that - * utf_composinglike(...) does not read beyond size. - */ - len_next_char = utf_ptr2len_len(p + len, size - len); + // Next character length should not go beyond size to ensure that + // utf_composinglike(...) does not read beyond size. + len_next_char = utf_ptr2len_len((char_u *)p + len, size - len); if (len_next_char > size - len) { break; } @@ -1048,20 +1010,16 @@ int utf_char2bytes(const int c, char *const buf) } } -/* - * Return true if "c" is a composing UTF-8 character. This means it will be - * drawn on top of the preceding character. - * Based on code from Markus Kuhn. - */ +// Return true if "c" is a composing UTF-8 character. This means it will be +// drawn on top of the preceding character. +// Based on code from Markus Kuhn. bool utf_iscomposing(int c) { return intable(combining, ARRAY_SIZE(combining), c); } -/* - * Return true for characters that can be displayed in a normal way. - * Only for characters of 0x100 and above! - */ +// Return true for characters that can be displayed in a normal way. +// Only for characters of 0x100 and above! bool utf_printable(int c) { // Sorted list of non-overlapping intervals. @@ -1076,12 +1034,10 @@ bool utf_printable(int c) return !intable(nonprint, ARRAY_SIZE(nonprint), c); } -/* - * Get class of a Unicode character. - * 0: white space - * 1: punctuation - * 2 or bigger: some class of word character. - */ +// Get class of a Unicode character. +// 0: white space +// 1: punctuation +// 2 or bigger: some class of word character. int utf_class(const int c) { return utf_class_tab(c, curbuf->b_chartab); @@ -1210,11 +1166,9 @@ bool utf_ambiguous_width(int c) || intable(emoji_all, ARRAY_SIZE(emoji_all), c)); } -/* - * Generic conversion function for case operations. - * Return the converted equivalent of "a", which is a UCS-4 character. Use - * the given conversion "table". Uses binary search on "table". - */ +// Generic conversion function for case operations. +// Return the converted equivalent of "a", which is a UCS-4 character. Use +// the given conversion "table". Uses binary search on "table". static int utf_convert(int a, const convertStruct *const table, size_t n_items) { size_t start, mid, end; // indices into table @@ -1240,10 +1194,8 @@ static int utf_convert(int a, const convertStruct *const table, size_t n_items) } } -/* - * Return the folded-case equivalent of "a", which is a UCS-4 character. Uses - * simple case folding. - */ +// Return the folded-case equivalent of "a", which is a UCS-4 character. Uses +// simple case folding. int utf_fold(int a) { if (a < 0x80) { @@ -1398,7 +1350,7 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2 return n1 == 0 ? -1 : 1; } -#ifdef WIN32 +#ifdef MSWIN # ifndef CP_UTF8 # define CP_UTF8 65001 // magic number from winnls.h # endif @@ -1505,7 +1457,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) { + for (size_t i = 0; i < len; i += clen) { 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 @@ -1527,7 +1479,7 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us if (index == 0) { return 0; } - for (i = 0; i < len && s[i] != NUL; i += clen) { + for (i = 0; i < len; i += clen) { 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 @@ -1543,17 +1495,16 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us return -1; } -/* - * Version of strnicmp() that handles multi-byte characters. - * Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can - * probably use strnicmp(), because there are no ASCII characters in the - * second byte. - * Returns zero if s1 and s2 are equal (ignoring case), the difference between - * two characters otherwise. - */ -int mb_strnicmp(const char_u *s1, const char_u *s2, const size_t nn) +/// Version of strnicmp() that handles multi-byte characters. +/// Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can +/// probably use strnicmp(), because there are no ASCII characters in the +/// second byte. +/// +/// @return zero if s1 and s2 are equal (ignoring case), the difference between +/// two characters otherwise. +int mb_strnicmp(const char *s1, const char *s2, const size_t nn) { - return utf_strnicmp(s1, s2, nn, nn); + return utf_strnicmp((char_u *)s1, (char_u *)s2, nn, nn); } /// Compare strings case-insensitively @@ -1570,13 +1521,11 @@ int mb_strnicmp(const char_u *s1, const char_u *s2, const size_t nn) /// @return 0 if strings are equal, <0 if s1 < s2, >0 if s1 > s2. int mb_stricmp(const char *s1, const char *s2) { - return mb_strnicmp((const char_u *)s1, (const char_u *)s2, MAXCOL); + return mb_strnicmp(s1, s2, MAXCOL); } -/* - * "g8": show bytes of the UTF-8 char under the cursor. Doesn't matter what - * 'encoding' has been set to. - */ +// "g8": show bytes of the UTF-8 char under the cursor. Doesn't matter what +// 'encoding' has been set to. void show_utf8(void) { int len; @@ -1587,7 +1536,7 @@ void show_utf8(void) // Get the byte length of the char under the cursor, including composing // characters. - line = get_cursor_pos_ptr(); + line = (char_u *)get_cursor_pos_ptr(); len = utfc_ptr2len((char *)line); if (len == 0) { msg("NUL"); @@ -1595,7 +1544,7 @@ void show_utf8(void) } clen = 0; - for (i = 0; i < len; ++i) { + for (i = 0; i < len; i++) { if (clen == 0) { // start of (composing) character, get its length if (i > 0) { @@ -1607,7 +1556,7 @@ void show_utf8(void) sprintf((char *)IObuff + rlen, "%02x ", (line[i] == NL) ? NUL : line[i]); // NUL is stored as NL clen--; - rlen += (int)STRLEN(IObuff + rlen); + rlen += (int)strlen(IObuff + rlen); if (rlen > IOSIZE - 20) { break; } @@ -1620,22 +1569,25 @@ void show_utf8(void) /// "base" must be the start of the string, which must be NUL terminated. /// If "p" points to the NUL at the end of the string return 0. /// Returns 0 when already at the first byte of a character. -int utf_head_off(const char_u *base, const char_u *p) +int utf_head_off(const char *base_in, const char *p_in) { int c; int len; - if (*p < 0x80) { // be quick for ASCII + if ((uint8_t)(*p_in) < 0x80) { // be quick for ASCII return 0; } + const uint8_t *base = (uint8_t *)base_in; + const uint8_t *p = (uint8_t *)p_in; + // Skip backwards over trailing bytes: 10xx.xxxx // Skip backwards again if on a composing char. - const char_u *q; - for (q = p;; --q) { + const uint8_t *q; + for (q = p;; q--) { // Move s to the last byte of this char. - const char_u *s; - for (s = q; (s[1] & 0xc0) == 0x80; ++s) {} + const uint8_t *s; + for (s = q; (s[1] & 0xc0) == 0x80; s++) {} // Move q to the first byte of this char. while (q > base && (*q & 0xc0) == 0x80) { @@ -1659,7 +1611,7 @@ int utf_head_off(const char_u *base, const char_u *p) if (arabic_maycombine(c)) { // Advance to get a sneak-peak at the next char - const char_u *j = q; + const uint8_t *j = q; j--; // Move j to the first byte of this char. while (j > base && (*j & 0xc0) == 0x80) { @@ -1920,9 +1872,7 @@ int utf_cp_head_off(const char_u *base, const char_u *p) return i; } -/* - * Find the next illegal byte sequence. - */ +// Find the next illegal byte sequence. void utf_find_illegal(void) { pos_T pos = curwin->w_cursor; @@ -1932,7 +1882,7 @@ void utf_find_illegal(void) char_u *tofree = NULL; vimconv.vc_type = CONV_NONE; - if (enc_canon_props(curbuf->b_p_fenc) & ENC_8BIT) { + if (enc_canon_props((char_u *)curbuf->b_p_fenc) & ENC_8BIT) { // 'encoding' is "utf-8" but we are editing a 8-bit encoded file, // possibly a utf-8 file with illegal bytes. Setup for conversion // from utf-8 to 'fileencoding'. @@ -1941,10 +1891,10 @@ void utf_find_illegal(void) curwin->w_cursor.coladd = 0; for (;;) { - p = get_cursor_pos_ptr(); + p = (char_u *)get_cursor_pos_ptr(); if (vimconv.vc_type != CONV_NONE) { xfree(tofree); - tofree = string_convert(&vimconv, p, NULL); + tofree = (char_u *)string_convert(&vimconv, (char *)p, NULL); if (tofree == NULL) { break; } @@ -1958,12 +1908,12 @@ void utf_find_illegal(void) if (*p >= 0x80 && (len == 1 || utf_char2len(utf_ptr2char((char *)p)) != len)) { if (vimconv.vc_type == CONV_NONE) { - curwin->w_cursor.col += (colnr_T)(p - get_cursor_pos_ptr()); + curwin->w_cursor.col += (colnr_T)(p - (char_u *)get_cursor_pos_ptr()); } else { int l; len = (int)(p - tofree); - for (p = get_cursor_pos_ptr(); *p != NUL && len-- > 0; p += l) { + for (p = (char_u *)get_cursor_pos_ptr(); *p != NUL && len-- > 0; p += l) { l = utf_ptr2len((char *)p); curwin->w_cursor.col += l; } @@ -1975,7 +1925,7 @@ void utf_find_illegal(void) if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) { break; } - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; } @@ -1989,8 +1939,7 @@ theend: } /// @return true if string "s" is a valid utf-8 string. -/// When "end" is NULL stop at the first NUL. -/// When "end" is positive stop there. +/// When "end" is NULL stop at the first NUL. Otherwise stop at "end". bool utf_valid_string(const char_u *s, const char_u *end) { const char_u *p = s; @@ -2013,10 +1962,8 @@ bool utf_valid_string(const char_u *s, const char_u *end) return true; } -/* - * If the cursor moves on an trail byte, set the cursor on the lead byte. - * Thus it moves left if necessary. - */ +// If the cursor moves on an trail byte, set the cursor on the lead byte. +// Thus it moves left if necessary. void mb_adjust_cursor(void) { mark_mb_adjustpos(curbuf, &curwin->w_cursor); @@ -2033,7 +1980,7 @@ void mb_check_adjust_col(void *win_) // Column 0 is always valid. if (oldcol != 0) { - char *p = (char *)ml_get_buf(win->w_buffer, win->w_cursor.lnum, false); + char *p = ml_get_buf(win->w_buffer, win->w_cursor.lnum, false); colnr_T len = (colnr_T)STRLEN(p); // Empty line or invalid column? @@ -2045,7 +1992,7 @@ void mb_check_adjust_col(void *win_) win->w_cursor.col = len - 1; } // Move the cursor to the head byte. - win->w_cursor.col -= utf_head_off((char_u *)p, (char_u *)p + win->w_cursor.col); + win->w_cursor.col -= utf_head_off(p, p + win->w_cursor.col); } // Reset `coladd` when the cursor would be on the right half of a @@ -2147,10 +2094,8 @@ const char *mb_unescape(const char **const pp) return NULL; } -/* - * Skip the Vim specific head of a 'encoding' name. - */ -char_u *enc_skip(char_u *p) +/// Skip the Vim specific head of a 'encoding' name. +char *enc_skip(char *p) { if (STRNCMP(p, "2byte-", 6) == 0) { return p + 6; @@ -2161,31 +2106,29 @@ char_u *enc_skip(char_u *p) return p; } -/* - * Find the canonical name for encoding "enc". - * When the name isn't recognized, returns "enc" itself, but with all lower - * case characters and '_' replaced with '-'. - * Returns an allocated string. - */ -char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET +/// Find the canonical name for encoding "enc". +/// When the name isn't recognized, returns "enc" itself, but with all lower +/// case characters and '_' replaced with '-'. +/// +/// @return an allocated string. +char *enc_canonize(char *enc) + FUNC_ATTR_NONNULL_RET { - char_u *p, *s; - int i; - - if (STRCMP(enc, "default") == 0) { + char *p, *s; + if (strcmp(enc, "default") == 0) { // Use the default encoding as found by set_init_1(). - return vim_strsave(fenc_default); + return xstrdup(fenc_default); } // copy "enc" to allocated memory, with room for two '-' - char_u *r = xmalloc(STRLEN(enc) + 3); + char *r = xmalloc(STRLEN(enc) + 3); // Make it all lower case and replace '_' with '-'. p = r; - for (s = enc; *s != NUL; ++s) { + for (s = enc; *s != NUL; s++) { if (*s == '_') { *p++ = '-'; } else { - *p++ = (char_u)TOLOWER_ASC(*s); + *p++ = (char)TOLOWER_ASC(*s); } } *p = NUL; @@ -2215,6 +2158,7 @@ char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET STRMOVE(p + 5, p + 6); } + int i; if (enc_canon_search(p) >= 0) { // canonical name can be used unmodified if (p != r) { @@ -2223,19 +2167,19 @@ char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET } else if ((i = enc_alias_search(p)) >= 0) { // alias recognized, get canonical name xfree(r); - r = vim_strsave((char_u *)enc_canon_table[i].name); + r = xstrdup(enc_canon_table[i].name); } return r; } /// Search for an encoding alias of "name". /// Returns -1 when not found. -static int enc_alias_search(const char_u *name) +static int enc_alias_search(const char *name) { int i; - for (i = 0; enc_alias_table[i].name != NULL; ++i) { - if (STRCMP(name, enc_alias_table[i].name) == 0) { + for (i = 0; enc_alias_table[i].name != NULL; i++) { + if (strcmp(name, enc_alias_table[i].name) == 0) { return enc_alias_table[i].canon; } } @@ -2246,10 +2190,8 @@ static int enc_alias_search(const char_u *name) # include <langinfo.h> #endif -/* - * Get the canonicalized encoding of the current locale. - * Returns an allocated string when successful, NULL when not. - */ +// Get the canonicalized encoding of the current locale. +// Returns an allocated string when successful, NULL when not. char_u *enc_locale(void) { int i; @@ -2310,17 +2252,15 @@ enc_locale_copy_enc: buf[i] = NUL; } - return enc_canonize((char_u *)buf); + return (char_u *)enc_canonize(buf); } #if defined(HAVE_ICONV) -/* - * Call iconv_open() with a check if iconv() works properly (there are broken - * versions). - * Returns (void *)-1 if failed. - * (should return iconv_t, but that causes problems with prototypes). - */ +// Call iconv_open() with a check if iconv() works properly (there are broken +// versions). +// Returns (void *)-1 if failed. +// (should return iconv_t, but that causes problems with prototypes). void *my_iconv_open(char_u *to, char_u *from) { iconv_t fd; @@ -2333,16 +2273,14 @@ void *my_iconv_open(char_u *to, char_u *from) if (iconv_working == kBroken) { return (void *)-1; // detected a broken iconv() previously } - fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from)); + fd = iconv_open(enc_skip((char *)to), enc_skip((char *)from)); if (fd != (iconv_t)-1 && iconv_working == kUnknown) { - /* - * Do a dummy iconv() call to check if it actually works. There is a - * version of iconv() on Linux that is broken. We can't ignore it, - * because it's wide-spread. The symptoms are that after outputting - * the initial shift state the "to" pointer is NULL and conversion - * stops for no apparent reason after about 8160 characters. - */ + // Do a dummy iconv() call to check if it actually works. There is a + // version of iconv() on Linux that is broken. We can't ignore it, + // because it's wide-spread. The symptoms are that after outputting + // the initial shift state the "to" pointer is NULL and conversion + // stops for no apparent reason after about 8160 characters. p = (char *)tobuf; tolen = ICONV_TESTLEN; (void)iconv(fd, NULL, NULL, &p, &tolen); @@ -2358,13 +2296,11 @@ void *my_iconv_open(char_u *to, char_u *from) return (void *)fd; } -/* - * Convert the string "str[slen]" with iconv(). - * If "unconvlenp" is not NULL handle the string ending in an incomplete - * sequence and set "*unconvlenp" to the length of it. - * Returns the converted string in allocated memory. NULL for an error. - * If resultlenp is not NULL, sets it to the result length in bytes. - */ +// Convert the string "str[slen]" with iconv(). +// If "unconvlenp" is not NULL handle the string ending in an incomplete +// sequence and set "*unconvlenp" to the length of it. +// Returns the converted string in allocated memory. NULL for an error. +// If resultlenp is not NULL, sets it to the result length in bytes. static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen, size_t *unconvlenp, size_t *resultlenp) { @@ -2424,7 +2360,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen if (utf_ptr2cells(from) > 1) { *to++ = '?'; } - l = utfc_ptr2len_len((const char_u *)from, (int)fromlen); + l = utfc_ptr2len_len(from, (int)fromlen); from += l; fromlen -= (size_t)l; } else if (ICONV_ERRNO != ICONV_E2BIG) { @@ -2444,23 +2380,22 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen #endif // HAVE_ICONV -/* - * Setup "vcp" for conversion from "from" to "to". - * The names must have been made canonical with enc_canonize(). - * vcp->vc_type must have been initialized to CONV_NONE. - * Note: cannot be used for conversion from/to ucs-2 and ucs-4 (will use utf-8 - * instead). - * Afterwards invoke with "from" and "to" equal to NULL to cleanup. - * Return FAIL when conversion is not supported, OK otherwise. - */ -int convert_setup(vimconv_T *vcp, char_u *from, char_u *to) +/// Setup "vcp" for conversion from "from" to "to". +/// The names must have been made canonical with enc_canonize(). +/// vcp->vc_type must have been initialized to CONV_NONE. +/// Note: cannot be used for conversion from/to ucs-2 and ucs-4 (will use utf-8 +/// instead). +/// Afterwards invoke with "from" and "to" equal to NULL to cleanup. +/// +/// @return FAIL when conversion is not supported, OK otherwise. +int convert_setup(vimconv_T *vcp, char *from, char *to) { return convert_setup_ext(vcp, from, true, to, true); } /// As convert_setup(), but only when from_unicode_is_utf8 is true will all /// "from" unicode charsets be considered utf-8. Same for "to". -int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, char_u *to, +int convert_setup_ext(vimconv_T *vcp, char *from, bool from_unicode_is_utf8, char *to, bool to_unicode_is_utf8) { int from_prop; @@ -2478,12 +2413,12 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c // No conversion when one of the names is empty or they are equal. if (from == NULL || *from == NUL || to == NULL || *to == NUL - || STRCMP(from, to) == 0) { + || strcmp(from, to) == 0) { return OK; } - from_prop = enc_canon_props(from); - to_prop = enc_canon_props(to); + from_prop = enc_canon_props((char_u *)from); + to_prop = enc_canon_props((char_u *)to); if (from_unicode_is_utf8) { from_is_utf8 = from_prop & ENC_UNICODE; } else { @@ -2513,8 +2448,8 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c #ifdef HAVE_ICONV else { // NOLINT(readability/braces) // Use iconv() for conversion. - vcp->vc_fd = (iconv_t)my_iconv_open(to_is_utf8 ? (char_u *)"utf-8" : to, - from_is_utf8 ? (char_u *)"utf-8" : from); + vcp->vc_fd = (iconv_t)my_iconv_open(to_is_utf8 ? (char_u *)"utf-8" : (char_u *)to, + from_is_utf8 ? (char_u *)"utf-8" : (char_u *)from); if (vcp->vc_fd != (iconv_t)-1) { vcp->vc_type = CONV_ICONV; vcp->vc_factor = 4; // could be longer too... @@ -2528,23 +2463,19 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c return OK; } -/* - * Convert text "ptr[*lenp]" according to "vcp". - * Returns the result in allocated memory and sets "*lenp". - * When "lenp" is NULL, use NUL terminated strings. - * Illegal chars are often changed to "?", unless vcp->vc_fail is set. - * When something goes wrong, NULL is returned and "*lenp" is unchanged. - */ -char_u *string_convert(const vimconv_T *const vcp, char_u *ptr, size_t *lenp) +/// Convert text "ptr[*lenp]" according to "vcp". +/// Returns the result in allocated memory and sets "*lenp". +/// When "lenp" is NULL, use NUL terminated strings. +/// Illegal chars are often changed to "?", unless vcp->vc_fail is set. +/// When something goes wrong, NULL is returned and "*lenp" is unchanged. +char *string_convert(const vimconv_T *const vcp, char *ptr, size_t *lenp) { - return string_convert_ext(vcp, ptr, lenp, NULL); + return (char *)string_convert_ext(vcp, (char_u *)ptr, lenp, NULL); } -/* - * Like string_convert(), but when "unconvlenp" is not NULL and there are is - * an incomplete sequence at the end it is not converted and "*unconvlenp" is - * set to the number of remaining bytes. - */ +// Like string_convert(), but when "unconvlenp" is not NULL and there are is +// an incomplete sequence at the end it is not converted and "*unconvlenp" is +// set to the number of remaining bytes. char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp, size_t *unconvlenp) { @@ -2560,14 +2491,14 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp len = *lenp; } if (len == 0) { - return vim_strsave((char_u *)""); + return (char_u *)xstrdup(""); } switch (vcp->vc_type) { case CONV_TO_UTF8: // latin1 to utf-8 conversion retval = xmalloc(len * 2 + 1); d = retval; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; i++) { c = ptr[i]; if (c < 0x80) { *d++ = (char_u)c; @@ -2585,7 +2516,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp case CONV_9_TO_UTF8: // latin9 to utf-8 conversion retval = xmalloc(len * 3 + 1); d = retval; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; i++) { c = ptr[i]; switch (c) { case 0xa4: @@ -2748,7 +2679,7 @@ static int tv_nr_compare(const void *a1, const void *a2) } /// "setcellwidths()" function -void f_setcellwidths(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) { emsg(_(e_listreq)); @@ -2857,12 +2788,12 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, FunPtr fptr) } xfree(cw_table_save); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } -void f_charclass(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_charclass(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (tv_check_for_string(&argvars[0]) == FAIL + if (tv_check_for_string_arg(argvars, 0) == FAIL || argvars[0].vval.v_string == NULL) { return; } diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h index 2a9afcbd03..b499f33cc6 100644 --- a/src/nvim/mbyte.h +++ b/src/nvim/mbyte.h @@ -11,12 +11,10 @@ #include "nvim/os/os_defs.h" // For indirect #include "nvim/types.h" // for char_u -/* - * Return byte length of character that starts with byte "b". - * Returns 1 for a single-byte character. - * MB_BYTE2LEN_CHECK() can be used to count a special key as one byte. - * Don't call MB_BYTE2LEN(b) with b < 0 or b > 255! - */ +// Return byte length of character that starts with byte "b". +// Returns 1 for a single-byte character. +// MB_BYTE2LEN_CHECK() can be used to count a special key as one byte. +// Don't call MB_BYTE2LEN(b) with b < 0 or b > 255! #define MB_BYTE2LEN(b) utf8len_tab[b] #define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : utf8len_tab[b]) diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 216ee26620..bb9be0766e 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -77,7 +77,7 @@ /// /// @return - The open memory file, on success. /// - NULL, on failure (e.g. file does not exist). -memfile_T *mf_open(char_u *fname, int flags) +memfile_T *mf_open(char *fname, int flags) { memfile_T *mfp = xmalloc(sizeof(memfile_T)); @@ -148,7 +148,7 @@ memfile_T *mf_open(char_u *fname, int flags) /// /// @return OK On success. /// FAIL If file could not be opened. -int mf_open_file(memfile_T *mfp, char_u *fname) +int mf_open_file(memfile_T *mfp, char *fname) { if (mf_do_open(mfp, fname, O_RDWR | O_CREAT | O_EXCL)) { mfp->mf_dirty = true; @@ -170,7 +170,7 @@ void mf_close(memfile_T *mfp, bool del_file) emsg(_(e_swapclose)); } if (del_file && mfp->mf_fname != NULL) { - os_remove((char *)mfp->mf_fname); + os_remove(mfp->mf_fname); } // free entries in used list @@ -210,7 +210,7 @@ void mf_close_file(buf_T *buf, bool getlines) mfp->mf_fd = -1; if (mfp->mf_fname != NULL) { - os_remove((char *)mfp->mf_fname); // delete the swap file + os_remove(mfp->mf_fname); // delete the swap file mf_free_fnames(mfp); } } @@ -749,10 +749,10 @@ void mf_free_fnames(memfile_T *mfp) /// /// Only called when creating or renaming the swapfile. Either way it's a new /// name so we must work out the full path name. -void mf_set_fnames(memfile_T *mfp, char_u *fname) +void mf_set_fnames(memfile_T *mfp, char *fname) { mfp->mf_fname = fname; - mfp->mf_ffname = (char_u *)FullName_save((char *)mfp->mf_fname, false); + mfp->mf_ffname = (char_u *)FullName_save(mfp->mf_fname, false); } /// Make name of memfile's swapfile a full path. @@ -762,7 +762,7 @@ void mf_fullname(memfile_T *mfp) { if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL) { xfree(mfp->mf_fname); - mfp->mf_fname = mfp->mf_ffname; + mfp->mf_fname = (char *)mfp->mf_ffname; mfp->mf_ffname = NULL; } } @@ -779,7 +779,7 @@ bool mf_need_trans(memfile_T *mfp) /// /// @param flags Flags for open(). /// @return A bool indicating success of the `open` call. -static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags) +static bool mf_do_open(memfile_T *mfp, char *fname, int flags) { // fname cannot be NameBuff, because it must have been allocated. mf_set_fnames(mfp, fname); @@ -789,7 +789,7 @@ static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags) /// exist yet. If there is a symbolic link, this is most likely an attack. FileInfo file_info; if ((flags & O_CREAT) - && os_fileinfo_link((char *)mfp->mf_fname, &file_info)) { + && os_fileinfo_link(mfp->mf_fname, &file_info)) { mfp->mf_fd = -1; emsg(_("E300: Swap file already exists (symlink attack?)")); } else { diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h index 537d3e5f65..d1e8fd0fb4 100644 --- a/src/nvim/memfile_defs.h +++ b/src/nvim/memfile_defs.h @@ -88,7 +88,7 @@ typedef struct mf_blocknr_trans_item { /// A memory file. typedef struct memfile { - char_u *mf_fname; /// name of the file + char *mf_fname; /// name of the file char_u *mf_ffname; /// idem, full path int mf_fd; /// file descriptor bhdr_T *mf_free_first; /// first block header in free list diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 23bc5d59c8..56342942db 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -5,36 +5,34 @@ // #define CHECK(c, s) do { if (c) emsg(s); } while (0) #define CHECK(c, s) do {} while (0) -/* - * memline.c: Contains the functions for appending, deleting and changing the - * text lines. The memfile functions are used to store the information in - * blocks of memory, backed up by a file. The structure of the information is - * a tree. The root of the tree is a pointer block. The leaves of the tree - * are data blocks. In between may be several layers of pointer blocks, - * forming branches. - * - * Three types of blocks are used: - * - Block nr 0 contains information for recovery - * - Pointer blocks contain list of pointers to other blocks. - * - Data blocks contain the actual text. - * - * Block nr 0 contains the block0 structure (see below). - * - * Block nr 1 is the first pointer block. It is the root of the tree. - * Other pointer blocks are branches. - * - * If a line is too big to fit in a single page, the block containing that - * line is made big enough to hold the line. It may span several pages. - * Otherwise all blocks are one page. - * - * A data block that was filled when starting to edit a file and was not - * changed since then, can have a negative block number. This means that it - * has not yet been assigned a place in the file. When recovering, the lines - * in this data block can be read from the original file. When the block is - * changed (lines appended/deleted/changed) or when it is flushed it gets a - * positive number. Use mf_trans_del() to get the new number, before calling - * mf_get(). - */ +// memline.c: Contains the functions for appending, deleting and changing the +// text lines. The memfile functions are used to store the information in +// blocks of memory, backed up by a file. The structure of the information is +// a tree. The root of the tree is a pointer block. The leaves of the tree +// are data blocks. In between may be several layers of pointer blocks, +// forming branches. +// +// Three types of blocks are used: +// - Block nr 0 contains information for recovery +// - Pointer blocks contain list of pointers to other blocks. +// - Data blocks contain the actual text. +// +// Block nr 0 contains the block0 structure (see below). +// +// Block nr 1 is the first pointer block. It is the root of the tree. +// Other pointer blocks are branches. +// +// If a line is too big to fit in a single page, the block containing that +// line is made big enough to hold the line. It may span several pages. +// Otherwise all blocks are one page. +// +// A data block that was filled when starting to edit a file and was not +// changed since then, can have a negative block number. This means that it +// has not yet been assigned a place in the file. When recovering, the lines +// in this data block can be read from the original file. When the block is +// changed (lines appended/deleted/changed) or when it is flushed it gets a +// positive number. Use mf_trans_del() to get the new number, before calling +// mf_get(). #include <assert.h> #include <errno.h> @@ -90,9 +88,7 @@ typedef struct pointer_entry PTR_EN; // block/line-count pair #define BLOCK0_ID0 'b' // block 0 id 0 #define BLOCK0_ID1 '0' // block 0 id 1 -/* - * pointer to a block, used in a pointer block - */ +// pointer to a block, used in a pointer block struct pointer_entry { blocknr_T pe_bnum; // block number linenr_T pe_line_count; // number of lines in this branch @@ -100,9 +96,7 @@ struct pointer_entry { int pe_page_count; // number of pages in block pe_bnum }; -/* - * A pointer block contains a list of branches in the tree. - */ +// A pointer block contains a list of branches in the tree. struct pointer_block { uint16_t pb_id; // ID for pointer block: PTR_ID uint16_t pb_count; // number of pointers in this block @@ -111,13 +105,11 @@ struct pointer_block { // followed by empty space until end of page }; -/* - * A data block is a leaf in the tree. - * - * The text of the lines is at the end of the block. The text of the first line - * in the block is put at the end, the text of the second line in front of it, - * etc. Thus the order of the lines is the opposite of the line number. - */ +// A data block is a leaf in the tree. +// +// The text of the lines is at the end of the block. The text of the first line +// in the block is put at the end, the text of the second line in front of it, +// etc. Thus the order of the lines is the opposite of the line number. struct data_block { uint16_t db_id; // ID for data block: DATA_ID unsigned db_free; // free space available @@ -130,14 +122,12 @@ struct data_block { // end of page }; -/* - * The low bits of db_index hold the actual index. The topmost bit is - * used for the global command to be able to mark a line. - * This method is not clean, but otherwise there would be at least one extra - * byte used for each line. - * The mark has to be in this place to keep it with the correct line when other - * lines are inserted or deleted. - */ +// The low bits of db_index hold the actual index. The topmost bit is +// used for the global command to be able to mark a line. +// This method is not clean, but otherwise there would be at least one extra +// byte used for each line. +// The mark has to be in this place to keep it with the correct line when other +// lines are inserted or deleted. #define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1)) #define DB_INDEX_MASK (~DB_MARKED) @@ -149,28 +139,24 @@ struct data_block { #define B0_FNAME_SIZE_CRYPT 890 // 10 bytes used for other things #define B0_UNAME_SIZE 40 #define B0_HNAME_SIZE 40 -/* - * Restrict the numbers to 32 bits, otherwise most compilers will complain. - * This won't detect a 64 bit machine that only swaps a byte in the top 32 - * bits, but that is crazy anyway. - */ +// Restrict the numbers to 32 bits, otherwise most compilers will complain. +// This won't detect a 64 bit machine that only swaps a byte in the top 32 +// bits, but that is crazy anyway. #define B0_MAGIC_LONG 0x30313233L #define B0_MAGIC_INT 0x20212223L #define B0_MAGIC_SHORT 0x10111213L #define B0_MAGIC_CHAR 0x55 -/* - * Block zero holds all info about the swap file. - * - * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing - * swap files unusable! - * - * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!! - * - * This block is built up of single bytes, to make it portable across - * different machines. b0_magic_* is used to check the byte order and size of - * variables, because the rest of the swap file is not portable. - */ +// Block zero holds all info about the swap file. +// +// NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing +// swap files unusable! +// +// If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!! +// +// This block is built up of single bytes, to make it portable across +// different machines. b0_magic_* is used to check the byte order and size of +// variables, because the rest of the swap file is not portable. struct block0 { char_u b0_id[2]; ///< ID for block 0: BLOCK0_ID0 and BLOCK0_ID1. char_u b0_version[10]; // Vim version string @@ -187,18 +173,14 @@ struct block0 { char_u b0_magic_char; // check for last char }; -/* - * Note: b0_dirty and b0_flags are put at the end of the file name. For very - * long file names in older versions of Vim they are invalid. - * The 'fileencoding' comes before b0_flags, with a NUL in front. But only - * when there is room, for very long file names it's omitted. - */ +// Note: b0_dirty and b0_flags are put at the end of the file name. For very +// long file names in older versions of Vim they are invalid. +// The 'fileencoding' comes before b0_flags, with a NUL in front. But only +// when there is room, for very long file names it's omitted. #define B0_DIRTY 0x55 #define b0_dirty b0_fname[B0_FNAME_SIZE_ORG - 1] -/* - * The b0_flags field is new in Vim 7.0. - */ +// The b0_flags field is new in Vim 7.0. #define b0_flags b0_fname[B0_FNAME_SIZE_ORG - 2] // The lowest two bits contain the fileformat. Zero means it's not set @@ -216,17 +198,13 @@ struct block0 { #define STACK_INCR 5 // nr of entries added to ml_stack at a time -/* - * The line number where the first mark may be is remembered. - * If it is 0 there are no marks at all. - * (always used for the current buffer only, no buffer change possible while - * executing a global command). - */ +// The line number where the first mark may be is remembered. +// If it is 0 there are no marks at all. +// (always used for the current buffer only, no buffer change possible while +// executing a global command). static linenr_T lowest_marked = 0; -/* - * arguments for ml_find_line() - */ +// arguments for ml_find_line() #define ML_DELETE 0x11 // delete line #define ML_INSERT 0x12 // insert line #define ML_FIND 0x13 // just find the line @@ -249,13 +227,8 @@ typedef enum { int ml_open(buf_T *buf) { bhdr_T *hp = NULL; - ZERO_BL *b0p; - PTR_BL *pp; - DATA_BL *dp; - /* - * init fields in memline struct - */ + // init fields in memline struct buf->b_ml.ml_stack_size = 0; // no stack yet buf->b_ml.ml_stack = NULL; // no stack yet buf->b_ml.ml_stack_top = 0; // nothing in the stack @@ -269,9 +242,7 @@ int ml_open(buf_T *buf) buf->b_p_swf = false; } - /* - * When 'updatecount' is non-zero swap file may be opened later. - */ + // When 'updatecount' is non-zero swap file may be opened later. if (!buf->terminal && p_uc && buf->b_p_swf) { buf->b_may_swap = true; } else { @@ -289,15 +260,13 @@ int ml_open(buf_T *buf) buf->b_ml.ml_line_count = 1; curwin->w_nrwidth_line_count = 0; - /* - * fill block0 struct and write page 0 - */ + // fill block0 struct and write page 0 hp = mf_new(mfp, false, 1); if (hp->bh_bnum != 0) { iemsg(_("E298: Didn't get block nr 0?")); goto error; } - b0p = hp->bh_data; + ZERO_BL *b0p = hp->bh_data; b0p->b0_id[0] = BLOCK0_ID0; b0p->b0_id[1] = BLOCK0_ID1; @@ -319,21 +288,17 @@ int ml_open(buf_T *buf) long_to_char(os_get_pid(), b0p->b0_pid); } - /* - * Always sync block number 0 to disk, so we can check the file name in - * the swap file in findswapname(). Don't do this for a help files or - * a spell buffer though. - * Only works when there's a swapfile, otherwise it's done when the file - * is created. - */ + // Always sync block number 0 to disk, so we can check the file name in + // the swap file in findswapname(). Don't do this for a help files or + // a spell buffer though. + // Only works when there's a swapfile, otherwise it's done when the file + // is created. mf_put(mfp, hp, true, false); if (!buf->b_help && !B_SPELL(buf)) { (void)mf_sync(mfp, 0); } - /* - * Fill in root pointer block and write page 1. - */ + // Fill in root pointer block and write page 1. if ((hp = ml_new_ptr(mfp)) == NULL) { goto error; } @@ -341,7 +306,7 @@ int ml_open(buf_T *buf) iemsg(_("E298: Didn't get block nr 1?")); goto error; } - pp = hp->bh_data; + PTR_BL *pp = hp->bh_data; pp->pb_count = 1; pp->pb_pointer[0].pe_bnum = 2; pp->pb_pointer[0].pe_page_count = 1; @@ -349,16 +314,14 @@ int ml_open(buf_T *buf) pp->pb_pointer[0].pe_line_count = 1; // line count after insertion mf_put(mfp, hp, true, false); - /* - * Allocate first data block and create an empty line 1. - */ + // Allocate first data block and create an empty line 1. hp = ml_new_data(mfp, false, 1); if (hp->bh_bnum != 2) { iemsg(_("E298: Didn't get block nr 2?")); goto error; } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; dp->db_index[0] = --dp->db_txt_start; // at end of block dp->db_free -= 1 + (unsigned)INDEX_SIZE; dp->db_line_count = 1; @@ -382,16 +345,11 @@ error: void ml_setname(buf_T *buf) { bool success = false; - memfile_T *mfp; - char_u *fname; - char *dirp; - mfp = buf->b_ml.ml_mfp; + memfile_T *mfp = buf->b_ml.ml_mfp; if (mfp->mf_fd < 0) { // there is no swap file yet - /* - * When 'updatecount' is 0 and 'noswapfile' there is no swap file. - * For help files we will make a swap file now. - */ + // When 'updatecount' is 0 and 'noswapfile' there is no swap file. + // For help files we will make a swap file now. if (p_uc != 0 && (cmdmod.cmod_flags & CMOD_NOSWAPFILE) == 0) { ml_open_file(buf); // create a swap file } @@ -399,13 +357,13 @@ void ml_setname(buf_T *buf) } // Try all directories in the 'directory' option. - dirp = (char *)p_dir; + char *dirp = p_dir; bool found_existing_dir = false; for (;;) { if (*dirp == NUL) { // tried all directories, fail break; } - fname = (char_u *)findswapname(buf, &dirp, (char *)mfp->mf_fname, &found_existing_dir); + char *fname = findswapname(buf, &dirp, mfp->mf_fname, &found_existing_dir); // alloc's fname if (dirp == NULL) { // out of memory break; @@ -415,7 +373,7 @@ void ml_setname(buf_T *buf) } // if the file name is the same we don't have to do anything - if (FNAMECMP(fname, mfp->mf_fname) == 0) { + if (path_fnamecmp(fname, mfp->mf_fname) == 0) { xfree(fname); success = true; break; @@ -438,7 +396,7 @@ void ml_setname(buf_T *buf) } if (mfp->mf_fd == -1) { // need to (re)open the swap file - mfp->mf_fd = os_open((char *)mfp->mf_fname, O_RDWR, 0); + mfp->mf_fd = os_open(mfp->mf_fname, O_RDWR, 0); if (mfp->mf_fd < 0) { // could not (re)open the swap file, what can we do???? emsg(_("E301: Oops, lost the swap file!!!")); @@ -468,11 +426,7 @@ void ml_open_files(void) /// and the memfile will be in memory only (no recovery possible). void ml_open_file(buf_T *buf) { - memfile_T *mfp; - char_u *fname; - char *dirp; - - mfp = buf->b_ml.ml_mfp; + memfile_T *mfp = buf->b_ml.ml_mfp; if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || (cmdmod.cmod_flags & CMOD_NOSWAPFILE) || buf->terminal) { @@ -481,16 +435,16 @@ void ml_open_file(buf_T *buf) // For a spell buffer use a temp file name. if (buf->b_spell) { - fname = vim_tempname(); + char *fname = vim_tempname(); if (fname != NULL) { - (void)mf_open_file(mfp, fname); // consumes fname! + (void)mf_open_file(mfp, (char *)fname); // consumes fname! } buf->b_may_swap = false; return; } // Try all directories in 'directory' option. - dirp = (char *)p_dir; + char *dirp = p_dir; bool found_existing_dir = false; for (;;) { if (*dirp == NUL) { @@ -499,7 +453,7 @@ void ml_open_file(buf_T *buf) // There is a small chance that between choosing the swap file name // and creating it, another Vim creates the file. In that case the // creation will fail and we will use another directory. - fname = (char_u *)findswapname(buf, &dirp, NULL, &found_existing_dir); + char *fname = findswapname(buf, &dirp, NULL, &found_existing_dir); if (dirp == NULL) { break; // out of memory } @@ -523,7 +477,7 @@ void ml_open_file(buf_T *buf) } if (*p_dir != NUL && mfp->mf_fname == NULL) { - need_wait_return = true; // call wait_return later + need_wait_return = true; // call wait_return() later no_wait_return++; (void)semsg(_("E303: Unable to open swap file for \"%s\", recovery impossible"), buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname); @@ -552,7 +506,7 @@ void check_need_swap(bool newfile) /// Close memline for buffer 'buf'. /// -/// @param del_file if TRUE, delete the swap file +/// @param del_file if true, delete the swap file void ml_close(buf_T *buf, int del_file) { if (buf->b_ml.ml_mfp == NULL) { // not open @@ -590,7 +544,7 @@ void ml_close_notmod(void) { FOR_ALL_BUFFERS(buf) { if (!bufIsChanged(buf)) { - ml_close(buf, TRUE); // close all not-modified buffers + ml_close(buf, true); // close all not-modified buffers } } } @@ -616,21 +570,19 @@ static bool ml_check_b0_strings(ZERO_BL *b0p) return (memchr(b0p->b0_version, NUL, 10) && memchr(b0p->b0_uname, NUL, B0_UNAME_SIZE) && memchr(b0p->b0_hname, NUL, B0_HNAME_SIZE) - && memchr(b0p->b0_fname, NUL, B0_FNAME_SIZE_CRYPT)); // -V512 + && memchr(b0p->b0_fname, NUL, B0_FNAME_SIZE_CRYPT)); // -V1086 } /// Update the timestamp or the B0_SAME_DIR flag of the .swp file. static void ml_upd_block0(buf_T *buf, upd_block0_T what) { - memfile_T *mfp; bhdr_T *hp; - ZERO_BL *b0p; - mfp = buf->b_ml.ml_mfp; + memfile_T *mfp = buf->b_ml.ml_mfp; if (mfp == NULL || (hp = mf_get(mfp, 0, 1)) == NULL) { return; } - b0p = hp->bh_data; + ZERO_BL *b0p = hp->bh_data; if (ml_check_b0_id(b0p) == FAIL) { iemsg(_("E304: ml_upd_block0(): Didn't get block 0??")); } else { @@ -653,19 +605,17 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf) } else { char uname[B0_UNAME_SIZE]; - /* - * For a file under the home directory of the current user, we try to - * replace the home directory path with "~user". This helps when - * editing the same file on different machines over a network. - * First replace home dir path with "~/" with home_replace(). - * Then insert the user name to get "~user/". - */ + // For a file under the home directory of the current user, we try to + // replace the home directory path with "~user". This helps when + // editing the same file on different machines over a network. + // First replace home dir path with "~/" with home_replace(). + // Then insert the user name to get "~user/". home_replace(NULL, buf->b_ffname, (char *)b0p->b0_fname, B0_FNAME_SIZE_CRYPT, true); if (b0p->b0_fname[0] == '~') { // If there is no user name or it is too long, don't use "~/" int retval = os_get_username(uname, B0_UNAME_SIZE); - size_t ulen = STRLEN(uname); + size_t ulen = strlen(uname); size_t flen = STRLEN(b0p->b0_fname); if (retval == FAIL || ulen + flen > B0_FNAME_SIZE_CRYPT - 1) { STRLCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT); @@ -703,7 +653,7 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf) /// not set. 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)) { + if (same_directory((char_u *)buf->b_ml.ml_mfp->mf_fname, (char_u *)buf->b_ffname)) { b0p->b0_flags |= B0_SAME_DIR; } else { b0p->b0_flags &= (uint8_t) ~B0_SAME_DIR; @@ -713,15 +663,14 @@ static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf) /// When there is room, add the 'fileencoding' to block zero. static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf) { - int n; - int size = B0_FNAME_SIZE_NOCRYPT; + const int size = B0_FNAME_SIZE_NOCRYPT; - n = (int)STRLEN(buf->b_p_fenc); + int n = (int)strlen(buf->b_p_fenc); if ((int)STRLEN(b0p->b0_fname) + n + 1 > size) { b0p->b0_flags &= (uint8_t) ~B0_HAS_FENC; } else { memmove((char *)b0p->b0_fname + size - n, - (char *)buf->b_p_fenc, (size_t)n); + buf->b_p_fenc, (size_t)n); *(b0p->b0_fname + size - n - 1) = NUL; b0p->b0_flags |= B0_HAS_FENC; } @@ -735,75 +684,60 @@ void ml_recover(bool checkext) { buf_T *buf = NULL; memfile_T *mfp = NULL; - char_u *fname; - char_u *fname_used = NULL; + char *fname_used = NULL; bhdr_T *hp = NULL; ZERO_BL *b0p; int b0_ff; - char_u *b0_fenc = NULL; + char *b0_fenc = NULL; PTR_BL *pp; DATA_BL *dp; infoptr_T *ip; - blocknr_T bnum; - int len; bool directly; - linenr_T lnum; - char_u *p; - int i; - long error; - bool cannot_open; - linenr_T line_count; - bool has_error; - int idx; - int top; - int txt_start; - off_T size; - int called_from_main; + char *p; bool serious_error = true; - long mtime; - int attr; int orig_file_status = NOTDONE; - recoverymode = TRUE; - called_from_main = (curbuf->b_ml.ml_mfp == NULL); - attr = HL_ATTR(HLF_E); + recoverymode = true; + int called_from_main = (curbuf->b_ml.ml_mfp == NULL); + int attr = HL_ATTR(HLF_E); // If the file name ends in ".s[a-w][a-z]" we assume this is the swap file. // Otherwise a search is done to find the swap file(s). - fname = (char_u *)curbuf->b_fname; + char *fname = curbuf->b_fname; if (fname == NULL) { // When there is no file name - fname = (char_u *)""; + fname = ""; } - len = (int)STRLEN(fname); + int len = (int)strlen(fname); if (checkext && len >= 4 && STRNICMP(fname + len - 4, ".s", 2) == 0 && vim_strchr("abcdefghijklmnopqrstuvw", TOLOWER_ASC(fname[len - 2])) != NULL && ASCII_ISALPHA(fname[len - 1])) { directly = true; - fname_used = vim_strsave(fname); // make a copy for mf_open() + fname_used = xstrdup(fname); // make a copy for mf_open() } else { directly = false; // count the number of matching swap files - len = recover_names(fname, FALSE, 0, NULL); + len = recover_names((char_u *)fname, false, 0, NULL); if (len == 0) { // no swap files found semsg(_("E305: No swap file found for %s"), fname); goto theend; } + int i; if (len == 1) { // one swap file found, use it i = 1; } else { // several swap files found, choose // list the names of the swap files - (void)recover_names(fname, TRUE, 0, NULL); + (void)recover_names((char_u *)fname, true, 0, NULL); msg_putchar('\n'); msg_puts(_("Enter number of swap file to use (0 to quit): ")); - i = get_number(FALSE, NULL); + i = get_number(false, NULL); if (i < 1 || i > len) { goto theend; } } // get the swap file name that will be used - (void)recover_names(fname, FALSE, i, &fname_used); + (void)recover_names((char_u *)fname, false, i, &fname_used); } if (fname_used == NULL) { goto theend; // user chose invalid number. @@ -813,15 +747,11 @@ void ml_recover(bool checkext) getout(1); } - /* - * Allocate a buffer structure for the swap file that is used for recovery. - * Only the memline in it is really used. - */ + // Allocate a buffer structure for the swap file that is used for recovery. + // Only the memline in it is really used. buf = xmalloc(sizeof(buf_T)); - /* - * init fields in memline struct - */ + // init fields in memline struct buf->b_ml.ml_stack_size = 0; // no stack yet buf->b_ml.ml_stack = NULL; // no stack yet buf->b_ml.ml_stack_top = 0; // nothing in the stack @@ -830,11 +760,9 @@ void ml_recover(bool checkext) buf->b_ml.ml_locked = NULL; // no locked block buf->b_ml.ml_flags = 0; - /* - * open the memfile from the old swap file - */ - p = vim_strsave(fname_used); // save "fname_used" for the message: - // mf_open() will consume "fname_used"! + // open the memfile from the old swap file + p = xstrdup(fname_used); // save "fname_used" for the message: + // mf_open() will consume "fname_used"! mfp = mf_open(fname_used, O_RDONLY); fname_used = p; if (mfp == NULL || mfp->mf_fd < 0) { @@ -843,17 +771,13 @@ void ml_recover(bool checkext) } buf->b_ml.ml_mfp = mfp; - /* - * The page size set in mf_open() might be different from the page size - * used in the swap file, we must get it from block 0. But to read block - * 0 we need a page size. Use the minimal size for block 0 here, it will - * be set to the real value below. - */ + // The page size set in mf_open() might be different from the page size + // used in the swap file, we must get it from block 0. But to read block + // 0 we need a page size. Use the minimal size for block 0 here, it will + // be set to the real value below. mfp->mf_page_size = MIN_SWAP_PAGE_SIZE; - /* - * try to read block 0 - */ + // try to read block 0 if ((hp = mf_get(mfp, 0, 1)) == NULL) { msg_start(); msg_puts_attr(_("Unable to read block 0 from "), attr | MSG_HIST); @@ -891,10 +815,8 @@ void ml_recover(bool checkext) goto theend; } - /* - * If we guessed the wrong page size, we have to recalculate the - * highest block number in the file. - */ + // If we guessed the wrong page size, we have to recalculate the + // highest block number in the file. if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size)) { unsigned previous_page_size = mfp->mf_page_size; @@ -907,6 +829,7 @@ void ml_recover(bool checkext) msg_end(); goto theend; } + off_T size; if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0) { mfp->mf_blocknr_max = 0; // no file or empty file } else { @@ -922,17 +845,15 @@ void ml_recover(bool checkext) b0p = hp->bh_data; } - /* - * If .swp file name given directly, use name from swap file for buffer. - */ + // If .swp file name given directly, use name from swap file for buffer. if (directly) { - expand_env(b0p->b0_fname, NameBuff, MAXPATHL); + expand_env((char *)b0p->b0_fname, NameBuff, MAXPATHL); if (setfname(curbuf, (char *)NameBuff, NULL, true) == FAIL) { goto theend; } } - home_replace(NULL, (char *)mfp->mf_fname, (char *)NameBuff, MAXPATHL, true); + home_replace(NULL, mfp->mf_fname, (char *)NameBuff, MAXPATHL, true); smsg(_("Using swap file \"%s\""), NameBuff); if (buf_spname(curbuf) != NULL) { @@ -943,15 +864,13 @@ void ml_recover(bool checkext) smsg(_("Original file \"%s\""), NameBuff); msg_putchar('\n'); - /* - * check date of swap file and original file - */ + // check date of swap file and original file FileInfo org_file_info; FileInfo swp_file_info; - mtime = char_to_long(b0p->b0_mtime); + long mtime = char_to_long(b0p->b0_mtime); if (curbuf->b_ffname != NULL && os_fileinfo(curbuf->b_ffname, &org_file_info) - && ((os_fileinfo((char *)mfp->mf_fname, &swp_file_info) + && ((os_fileinfo(mfp->mf_fname, &swp_file_info) && org_file_info.stat.st_mtim.tv_sec > swp_file_info.stat.st_mtim.tv_sec) || org_file_info.stat.st_mtim.tv_sec != mtime)) { @@ -964,25 +883,21 @@ void ml_recover(bool checkext) if (b0p->b0_flags & B0_HAS_FENC) { 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, (size_t)(b0p->b0_fname + fnsize - p)); + for (p = (char *)b0p->b0_fname + fnsize; (char_u *)p > b0p->b0_fname && p[-1] != NUL; p--) {} + b0_fenc = xstrnsave(p, (size_t)(b0p->b0_fname + fnsize - (char_u *)p)); } mf_put(mfp, hp, false, false); // release block 0 hp = NULL; - /* - * Now that we are sure that the file is going to be recovered, clear the - * contents of the current buffer. - */ + // Now that we are sure that the file is going to be recovered, clear the + // contents of the current buffer. while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) { ml_delete((linenr_T)1, false); } - /* - * Try reading the original file to obtain the values of 'fileformat', - * 'fileencoding', etc. Ignore errors. The text itself is not used. - */ + // Try reading the original file to obtain the values of 'fileformat', + // 'fileencoding', etc. Ignore errors. The text itself is not used. if (curbuf->b_ffname != NULL) { orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW, false); @@ -993,35 +908,29 @@ void ml_recover(bool checkext) set_fileformat(b0_ff - 1, OPT_LOCAL); } if (b0_fenc != NULL) { - set_option_value("fenc", 0L, (char *)b0_fenc, OPT_LOCAL); + set_option_value_give_err("fenc", 0L, b0_fenc, OPT_LOCAL); xfree(b0_fenc); } unchanged(curbuf, true, true); - bnum = 1; // start with block 1 + blocknr_T 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 - error = 0; + linenr_T lnum = 0; // append after line 0 in curbuf + linenr_T line_count = 0; + int idx = 0; // start with first index in block 1 + long error = 0; buf->b_ml.ml_stack_top = 0; // -V1048 buf->b_ml.ml_stack = NULL; buf->b_ml.ml_stack_size = 0; // -V1048 - if (curbuf->b_ffname == NULL) { - cannot_open = true; - } else { - cannot_open = false; - } + bool cannot_open = (curbuf->b_ffname == NULL); serious_error = false; for (; !got_int; line_breakcheck()) { if (hp != NULL) { mf_put(mfp, hp, false, false); // release previous block } - /* - * get block - */ + // get block if ((hp = mf_get(mfp, bnum, page_count)) == NULL) { if (bnum == 1) { semsg(_("E309: Unable to read block 1 from %s"), mfp->mf_fname); @@ -1035,7 +944,7 @@ void ml_recover(bool checkext) if (pp->pb_id == PTR_ID) { // it is a pointer block // check line count when using pointer block first time if (idx == 0 && line_count != 0) { - for (i = 0; i < (int)pp->pb_count; ++i) { + for (int i = 0; i < (int)pp->pb_count; i++) { line_count -= pp->pb_pointer[i].pe_line_count; } if (line_count != 0) { @@ -1051,11 +960,9 @@ void ml_recover(bool checkext) error++; } else if (idx < (int)pp->pb_count) { // go a block deeper if (pp->pb_pointer[idx].pe_bnum < 0) { - /* - * Data block with negative block number. - * Try to read lines from the original file. - * This is slow, but it works. - */ + // Data block with negative block number. + // Try to read lines from the original file. + // This is slow, but it works. if (!cannot_open) { line_count = pp->pb_pointer[idx].pe_line_count; if (readfile(curbuf->b_ffname, NULL, lnum, @@ -1071,14 +978,12 @@ void ml_recover(bool checkext) ml_append(lnum++, _("???LINES MISSING"), (colnr_T)0, true); } - ++idx; // get same block again for next index + idx++; // get same block again for next index continue; } - /* - * going one block deeper in the tree - */ - top = ml_add_stack(buf); // new entry in stack + // going one block deeper in the tree + int top = ml_add_stack(buf); // new entry in stack ip = &(buf->b_ml.ml_stack[top]); ip->ip_bnum = bnum; ip->ip_index = idx; @@ -1103,7 +1008,7 @@ void ml_recover(bool checkext) } else { // it is a data block // Append all the lines in this block - has_error = false; + bool has_error = false; // check length of block // if wrong, use length in pointer block if (page_count * mfp->mf_page_size != dp->db_txt_end) { @@ -1118,10 +1023,8 @@ void ml_recover(bool checkext) // make sure there is a NUL at the end of the block *((char_u *)dp + dp->db_txt_end - 1) = NUL; - /* - * check number of lines in block - * if wrong, use count in data block - */ + // check number of lines in block + // if wrong, use count in data block if (line_count != dp->db_line_count) { ml_append(lnum++, _("??? from here until ???END lines" @@ -1131,16 +1034,16 @@ void ml_recover(bool checkext) has_error = true; } - for (i = 0; i < dp->db_line_count; ++i) { - txt_start = (dp->db_index[i] & DB_INDEX_MASK); + for (int i = 0; i < dp->db_line_count; i++) { + int txt_start = (dp->db_index[i] & DB_INDEX_MASK); if (txt_start <= (int)HEADER_SIZE || txt_start >= (int)dp->db_txt_end) { - p = (char_u *)"???"; + p = "???"; error++; } else { - p = (char_u *)dp + txt_start; + p = (char *)dp + txt_start; } - ml_append(lnum++, (char *)p, (colnr_T)0, true); + ml_append(lnum++, p, (colnr_T)0, true); } if (has_error) { ml_append(lnum++, _("???END"), (colnr_T)0, true); @@ -1153,22 +1056,18 @@ void ml_recover(bool checkext) break; } - /* - * go one block up in the tree - */ + // go one block up in the tree ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]); bnum = ip->ip_bnum; idx = ip->ip_index + 1; // go to next index page_count = 1; } - /* - * Compare the buffer contents with the original file. When they differ - * set the 'modified' flag. - * Lines 1 - lnum are the new contents. - * Lines lnum + 1 to ml_line_count are the original contents. - * Line ml_line_count + 1 in the dummy empty line. - */ + // Compare the buffer contents with the original file. When they differ + // set the 'modified' flag. + // Lines 1 - lnum are the new contents. + // Lines lnum + 1 to ml_line_count are the original contents. + // Line ml_line_count + 1 in the dummy empty line. if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1) { // Recovering an empty file results in two lines and the first line is // empty. Don't set the modified flag then. @@ -1177,10 +1076,10 @@ void ml_recover(bool checkext) buf_inc_changedtick(curbuf); } } else { - for (idx = 1; idx <= lnum; ++idx) { + for (idx = 1; idx <= lnum; idx++) { // Need to copy one line, fetching the other one may flush it. - p = vim_strsave(ml_get(idx)); - i = STRCMP(p, ml_get(idx + lnum)); + p = xstrdup(ml_get(idx)); + int i = strcmp(p, ml_get(idx + lnum)); xfree(p); if (i != 0) { changed_internal(); @@ -1190,10 +1089,8 @@ void ml_recover(bool checkext) } } - /* - * Delete the lines from the original file and the dummy line from the - * empty buffer. These will now be after the last line in the buffer. - */ + // Delete the lines from the original file and the dummy line from the + // empty buffer. These will now be after the last line in the buffer. while (curbuf->b_ml.ml_line_count > lnum && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { ml_delete(curbuf->b_ml.ml_line_count, false); @@ -1201,7 +1098,7 @@ void ml_recover(bool checkext) curbuf->b_flags |= BF_RECOVERED; check_cursor(); - recoverymode = FALSE; + recoverymode = false; if (got_int) { emsg(_("E311: Recovery Interrupted")); } else if (error) { @@ -1222,23 +1119,23 @@ void ml_recover(bool checkext) msg_puts(_("\nYou may want to delete the .swp file now.\n\n")); cmdline_row = msg_row; } - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); theend: xfree(fname_used); - recoverymode = FALSE; + recoverymode = false; if (mfp != NULL) { if (hp != NULL) { mf_put(mfp, hp, false, false); } mf_close(mfp, false); // will also xfree(mfp->mf_fname) } - if (buf != NULL) { //may be NULL if swap file not found. + if (buf != NULL) { // may be NULL if swap file not found. xfree(buf->b_ml.ml_stack); xfree(buf); } if (serious_error && called_from_main) { - ml_close(curbuf, TRUE); + ml_close(curbuf, true); } else { apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, false, curbuf); apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, false, curbuf); @@ -1255,20 +1152,17 @@ theend: /// - find the name of the n'th swap file when recovering /// /// @param fname base for swap file name -/// @param list when TRUE, list the swap file names +/// @param list when true, list the swap file names /// @param nr when non-zero, return nr'th swap file name /// @param fname_out result when "nr" > 0 -int recover_names(char_u *fname, int list, int nr, char_u **fname_out) +int recover_names(char_u *fname, int list, int nr, char **fname_out) { int num_names; char *(names[6]); char_u *tail; - char_u *p; - int num_files; + char *p; int file_count = 0; char **files; - char *dirp; - char_u *dir_name; char_u *fname_res = NULL; #ifdef HAVE_READLINK char_u fname_buf[MAXPATHL]; @@ -1278,7 +1172,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) #ifdef HAVE_READLINK // Expand symlink in the file name, because the swap file is created // with the actual file instead of with the symlink. - if (resolve_symlink(fname, fname_buf) == OK) { + if (resolve_symlink((char *)fname, (char *)fname_buf) == OK) { fname_res = fname_buf; } else #endif @@ -1293,8 +1187,8 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) // Do the loop for every directory in 'directory'. // First allocate some memory to put the directory name in. - dir_name = xmalloc(STRLEN(p_dir) + 1); - dirp = (char *)p_dir; + char *dir_name = xmalloc(strlen(p_dir) + 1); + char *dirp = p_dir; while (*dirp) { // Isolate a directory name from *dirp and put it in dir_name (we know // it is large enough, so use 31000 for length). @@ -1310,7 +1204,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) names[2] = xstrdup(".sw?"); num_names = 3; } else { - num_names = recov_file_names(names, fname_res, TRUE); + num_names = recov_file_names(names, (char *)fname_res, true); } } else { // check directory dir_name if (fname == NULL) { @@ -1333,11 +1227,12 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) tail = (char_u *)path_tail((char *)fname_res); tail = (char_u *)concat_fnames((char *)dir_name, (char *)tail, true); } - num_names = recov_file_names(names, tail, FALSE); + num_names = recov_file_names(names, (char *)tail, false); xfree(tail); } } + int num_files; if (num_names == 0) { num_files = 0; } else if (expand_wildcards(num_names, names, &num_files, &files, @@ -1345,15 +1240,13 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) num_files = 0; } - /* - * When no swap file found, wildcard expansion might have failed (e.g. - * not able to execute the shell). - * Try finding a swap file by simply adding ".swp" to the file name. - */ + // When no swap file found, wildcard expansion might have failed (e.g. + // not able to execute the shell). + // Try finding a swap file by simply adding ".swp" to the file name. if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) { char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", true); if (swapname != NULL) { - if (os_path_exists(swapname)) { + if (os_path_exists((char *)swapname)) { files = xmalloc(sizeof(char_u *)); files[0] = (char *)swapname; swapname = NULL; @@ -1363,9 +1256,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) } } - /* - * remove swapfile name of the current buffer, it must be ignored - */ + // remove swapfile name of the current buffer, it must be ignored if (curbuf->b_ml.ml_mfp != NULL && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL) { for (int i = 0; i < num_files; i++) { @@ -1379,7 +1270,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) if (--num_files == 0) { xfree(files); } else { - for (; i < num_files; ++i) { + for (; i < num_files; i++) { files[i] = files[i + 1]; } } @@ -1389,7 +1280,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((char_u *)files[nr - 1 + num_files - file_count]); + *fname_out = xstrdup(files[nr - 1 + num_files - file_count]); dirp = ""; // stop searching } } else if (list) { @@ -1401,12 +1292,12 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) } } else { msg_puts(_(" In directory ")); - msg_home_replace(dir_name); + msg_home_replace((char *)dir_name); msg_puts(":\n"); } if (num_files) { - for (int i = 0; i < num_files; ++i) { + for (int i = 0; i < num_files; i++) { // print the swap file name msg_outnum((long)++file_count); msg_puts(". "); @@ -1422,7 +1313,7 @@ int recover_names(char_u *fname, int list, int nr, char_u **fname_out) file_count += num_files; } - for (int i = 0; i < num_names; ++i) { + for (int i = 0; i < num_names; i++) { xfree(names[i]); } if (num_files > 0) { @@ -1447,7 +1338,7 @@ char *make_percent_swname(const char *dir, const char *name) *d = '%'; } } - d = concat_fnames(dir, s, TRUE); + d = concat_fnames(dir, s, true); xfree(s); xfree(f); } @@ -1516,17 +1407,18 @@ static time_t swapfile_info(char_u *fname) msg_puts(_(" owned by: ")); msg_outtrans(uname); msg_puts(_(" dated: ")); - } else -#endif + } else { + msg_puts(_(" dated: ")); + } +#else msg_puts(_(" dated: ")); +#endif x = file_info.stat.st_mtim.tv_sec; char ctime_buf[50]; msg_puts(os_ctime_r(&x, ctime_buf, sizeof(ctime_buf))); } - /* - * print the original file name - */ + // print the original file name fd = os_open((char *)fname, O_RDONLY, 0); if (fd >= 0) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { @@ -1591,10 +1483,9 @@ static time_t swapfile_info(char_u *fname) static bool swapfile_unchanged(char *fname) { struct block0 b0; - int ret = true; // Swap file must exist. - if (!os_path_exists((char_u *)fname)) { + if (!os_path_exists(fname)) { return false; } @@ -1608,6 +1499,8 @@ static bool swapfile_unchanged(char *fname) return false; } + bool ret = true; + // the ID and magic number must be correct if (ml_check_b0_id(&b0) == FAIL || b0_magic_wrong(&b0)) { ret = false; @@ -1631,7 +1524,7 @@ static bool swapfile_unchanged(char *fname) return ret; } -static int recov_file_names(char **names, char_u *path, int prepend_dot) +static int recov_file_names(char **names, char *path, int prepend_dot) FUNC_ATTR_NONNULL_ALL { int num_names = 0; @@ -1639,7 +1532,7 @@ static int recov_file_names(char **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] = modname((char *)path, ".sw?", true); + names[num_names] = modname(path, ".sw?", true); if (names[num_names] == NULL) { return num_names; } @@ -1647,14 +1540,14 @@ static int recov_file_names(char **names, char_u *path, int prepend_dot) } // Form the normal swap file name pattern by appending ".sw?". - names[num_names] = concat_fnames((char *)path, ".sw?", false); + names[num_names] = concat_fnames(path, ".sw?", false); if (num_names >= 1) { // check if we have the same name twice - char_u *p = (char_u *)names[num_names - 1]; + char *p = 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 } - if (STRCMP(p, names[num_names]) != 0) { + if (strcmp(p, names[num_names]) != 0) { num_names++; } else { xfree(names[num_names]); @@ -1668,8 +1561,8 @@ static int recov_file_names(char **names, char_u *path, int prepend_dot) /// sync all memlines /// -/// @param check_file if TRUE, check if original file exists and was not changed. -/// @param check_char if TRUE, stop syncing when character becomes available, but +/// @param check_file if true, check if original file exists and was not changed. +/// @param check_char if true, stop syncing when character becomes available, but /// /// always sync at least one block. void ml_sync_all(int check_file, int check_char, bool do_fsync) @@ -1683,10 +1576,8 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync) (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp) && buf->b_ffname != NULL) { - /* - * If the original file does not exist anymore or has been changed - * call ml_preserve() to get rid of all negative numbered blocks. - */ + // If the original file does not exist anymore or has been changed + // call ml_preserve() to get rid of all negative numbered blocks. FileInfo file_info; if (!os_fileinfo(buf->b_ffname, &file_info) || file_info.stat.st_mtim.tv_sec != buf->b_mtime_read @@ -1714,13 +1605,10 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync) /// Used for the :preserve command and when the original file has been /// changed or deleted. /// -/// @param message if TRUE, the success of preserving is reported. +/// @param message if true, the success of preserving is reported. void ml_preserve(buf_T *buf, int message, bool do_fsync) { - bhdr_T *hp; - linenr_T lnum; memfile_T *mfp = buf->b_ml.ml_mfp; - int status; int got_int_save = got_int; if (mfp == NULL || mfp->mf_fname == NULL) { @@ -1736,27 +1624,25 @@ void ml_preserve(buf_T *buf, int message, bool do_fsync) ml_flush_line(buf); // flush buffered line (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block - status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0)); + int status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0)); // stack is invalid after mf_sync(.., MFS_ALL) buf->b_ml.ml_stack_top = 0; - /* - * Some of the data blocks may have been changed from negative to - * positive block number. In that case the pointer blocks need to be - * updated. - * - * We don't know in which pointer block the references are, so we visit - * all data blocks until there are no more translations to be done (or - * we hit the end of the file, which can only happen in case a write fails, - * e.g. when file system if full). - * ml_find_line() does the work by translating the negative block numbers - * when getting the first line of each data block. - */ + // Some of the data blocks may have been changed from negative to + // positive block number. In that case the pointer blocks need to be + // updated. + // + // We don't know in which pointer block the references are, so we visit + // all data blocks until there are no more translations to be done (or + // we hit the end of the file, which can only happen in case a write fails, + // e.g. when file system if full). + // ml_find_line() does the work by translating the negative block numbers + // when getting the first line of each data block. if (mf_need_trans(mfp) && !got_int) { - lnum = 1; + linenr_T lnum = 1; while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count) { - hp = ml_find_line(buf, lnum, ML_FIND); + bhdr_T *hp = ml_find_line(buf, lnum, ML_FIND); if (hp == NULL) { status = FAIL; goto theend; @@ -1783,19 +1669,17 @@ theend: } } -/* - * NOTE: The pointer returned by the ml_get_*() functions only remains valid - * until the next call! - * line1 = ml_get(1); - * line2 = ml_get(2); // line1 is now invalid! - * Make a copy of the line if necessary. - */ +// NOTE: The pointer returned by the ml_get_*() functions only remains valid +// until the next call! +// line1 = ml_get(1); +// line2 = ml_get(2); // line1 is now invalid! +// Make a copy of the line if necessary. /// @return a pointer to a (read-only copy of a) line. /// /// On failure an error message is given and IObuff is returned (to avoid /// having to check for error everywhere). -char_u *ml_get(linenr_T lnum) +char *ml_get(linenr_T lnum) { return ml_get_buf(curbuf, lnum, false); } @@ -1804,7 +1688,7 @@ char_u *ml_get(linenr_T lnum) char_u *ml_get_pos(const pos_T *pos) FUNC_ATTR_NONNULL_ALL { - return ml_get_buf(curbuf, pos->lnum, false) + pos->col; + return (char_u *)ml_get_buf(curbuf, pos->lnum, false) + pos->col; } /// @return codepoint at pos. pos must be either valid or have col set to MAXCOL! @@ -1821,14 +1705,11 @@ int gchar_pos(pos_T *pos) /// @param will_change true mark the buffer dirty (chars in the line will be changed) /// /// @return a pointer to a line in a specific buffer -char_u *ml_get_buf(buf_T *buf, linenr_T lnum, bool will_change) +char *ml_get_buf(buf_T *buf, linenr_T lnum, bool will_change) FUNC_ATTR_NONNULL_ALL { - bhdr_T *hp; - DATA_BL *dp; - char_u *ptr; static int recursive = 0; - static char_u questions[4]; + static char questions[4]; if (lnum > buf->b_ml.ml_line_count) { // invalid line number if (recursive == 0) { @@ -1850,23 +1731,20 @@ errorret: } if (buf->b_ml.ml_mfp == NULL) { // there are no lines - return (char_u *)""; + return ""; } - /* - * See if it is the same line as requested last time. - * Otherwise may need to flush last used line. - * Don't use the last used line when 'swapfile' is reset, need to load all - * blocks. - */ + // See if it is the same line as requested last time. + // Otherwise may need to flush last used line. + // Don't use the last used line when 'swapfile' is reset, need to load all + // blocks. if (buf->b_ml.ml_line_lnum != lnum) { ml_flush_line(buf); - /* - * Find the data block containing the line. - * This also fills the stack with the blocks from the root to the data - * block and releases any locked block. - */ + // Find the data block containing the line. + // This also fills the stack with the blocks from the root to the data + // block and releases any locked block. + bhdr_T *hp; if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL) { if (recursive == 0) { // Avoid giving this message for a recursive call, may happen @@ -1881,11 +1759,10 @@ errorret: goto errorret; } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; - ptr = (char_u *)dp + - ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK); - buf->b_ml.ml_line_ptr = ptr; + char *ptr = (char *)dp + (dp->db_index[lnum - buf->b_ml.ml_locked_low] & DB_INDEX_MASK); + buf->b_ml.ml_line_ptr = (char_u *)ptr; buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags &= ~ML_LINE_DIRTY; } @@ -1894,7 +1771,7 @@ errorret: ml_add_deleted_len_buf(buf, buf->b_ml.ml_line_ptr, -1); } - return buf->b_ml.ml_line_ptr; + return (char *)buf->b_ml.ml_line_ptr; } /// Check if a line that was just obtained by a call to ml_get @@ -1908,7 +1785,7 @@ int ml_line_alloced(void) /// "line" does not need to be allocated, but can't be another line in a /// buffer, unlocking may make it invalid. /// -/// newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum +/// newfile: true when starting to edit a new file, meaning that pe_old_lnum /// will be set for recovery /// Check: The caller of this function should probably also call /// appended_lines(). @@ -1922,7 +1799,7 @@ int ml_line_alloced(void) int ml_append(linenr_T lnum, char *line, colnr_T len, bool newfile) { // When starting up, we might still need to create the memfile - if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) { + if (curbuf->b_ml.ml_mfp == NULL && open_buffer(false, NULL, 0) == FAIL) { return FAIL; } @@ -1949,7 +1826,7 @@ int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool new if (buf->b_ml.ml_line_lnum != 0) { ml_flush_line(buf); } - return ml_append_int(buf, lnum, line, len, newfile, FALSE); + return ml_append_int(buf, lnum, line, len, newfile, false); } /// @param lnum append after this line (can be 0) @@ -1960,17 +1837,6 @@ int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool new static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool newfile, int mark) { - int i; - int line_count; // number of indexes in current block - int offset; - int from, to; - int page_count; - int db_idx; // index for lnum in data block - bhdr_T *hp; - DATA_BL *dp; - PTR_BL *pp; - infoptr_T *ip; - // lnum out of range if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL) { return FAIL; @@ -1988,11 +1854,10 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b memfile_T *mfp = buf->b_ml.ml_mfp; int page_size = (int)mfp->mf_page_size; - /* - * find the data block containing the previous line - * This also fills the stack with the blocks from the root to the data block - * This also releases any locked block. - */ + // find the data block containing the previous line + // This also fills the stack with the blocks from the root to the data block + // This also releases any locked block. + bhdr_T *hp; if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum, ML_INSERT)) == NULL) { return FAIL; @@ -2000,32 +1865,29 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b buf->b_ml.ml_flags &= ~ML_EMPTY; + int db_idx; // index for lnum in data block if (lnum == 0) { // got line one instead, correct db_idx db_idx = -1; // careful, it is negative! } else { db_idx = lnum - buf->b_ml.ml_locked_low; } - // get line count before the insertion - line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low; + // get line count (number of indexes in current block) before the insertion + int line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low; - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; - /* - * If - * - there is not enough room in the current block - * - appending to the last line in the block - * - not appending to the last line in the file - * insert in front of the next block. - */ + // If + // - there is not enough room in the current block + // - appending to the last line in the block + // - not appending to the last line in the file + // insert in front of the next block. if ((int)dp->db_free < space_needed && db_idx == line_count - 1 && lnum < buf->b_ml.ml_line_count) { - /* - * Now that the line is not going to be inserted in the block that we - * expected, the line count has to be adjusted in the pointer blocks - * by using ml_locked_lineadd. - */ - --(buf->b_ml.ml_locked_lineadd); - --(buf->b_ml.ml_locked_high); + // Now that the line is not going to be inserted in the block that we + // expected, the line count has to be adjusted in the pointer blocks + // by using ml_locked_lineadd. + (buf->b_ml.ml_locked_lineadd)--; + (buf->b_ml.ml_locked_high)--; if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL) { return FAIL; } @@ -2038,25 +1900,20 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b dp = hp->bh_data; } - ++buf->b_ml.ml_line_count; + buf->b_ml.ml_line_count++; if ((int)dp->db_free >= space_needed) { // enough room in data block - /* - * Insert new line in existing data block, or in data block allocated above. - */ + // Insert new line in existing data block, or in data block allocated above. 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 - * adjust the indexes of the lines that follow - */ + // move the text of the lines that follow to the front + // adjust the indexes of the lines that follow if (line_count > db_idx + 1) { // if there are following lines - /* - * Offset is the start of the previous line. - * This will become the character just after the new line. - */ + // Offset is the start of the previous line. + // This will become the character just after the new line. + int offset; if (db_idx < 0) { offset = (int)dp->db_txt_end; } else { @@ -2065,7 +1922,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b memmove((char *)dp + dp->db_txt_start, (char *)dp + dp->db_txt_start + len, (size_t)offset - (dp->db_txt_start + (size_t)len)); - for (i = line_count - 1; i > db_idx; i--) { + for (int 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] = (unsigned)(offset - len); @@ -2073,31 +1930,25 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b dp->db_index[db_idx + 1] = dp->db_txt_start; } - /* - * copy the text into the block - */ + // copy the text into the block memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len); if (mark) { dp->db_index[db_idx + 1] |= DB_MARKED; } - /* - * Mark the block dirty. - */ + // Mark the block dirty. buf->b_ml.ml_flags |= ML_LOCKED_DIRTY; if (!newfile) { buf->b_ml.ml_flags |= ML_LOCKED_POS; } } else { // not enough space in data block - /* - * If there is not enough room we have to create a new data block and copy some - * lines into it. - * Then we have to insert an entry in the pointer block. - * If this pointer block also is full, we go up another block, and so on, up - * to the root if necessary. - * The line counts in the pointer blocks have already been adjusted by - * ml_find_line(). - */ + // If there is not enough room we have to create a new data block and copy some + // lines into it. + // Then we have to insert an entry in the pointer block. + // If this pointer block also is full, we go up another block, and so on, up + // to the root if necessary. + // The line counts in the pointer blocks have already been adjusted by + // ml_find_line(). int line_count_left, line_count_right; int page_count_left, page_count_right; bhdr_T *hp_left; @@ -2115,14 +1966,12 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b int pb_idx; PTR_BL *pp_new; - /* - * We are going to allocate a new data block. Depending on the - * situation it will be put to the left or right of the existing - * block. If possible we put the new line in the left block and move - * the lines after it to the right block. Otherwise the new line is - * also put in the right block. This method is more efficient when - * inserting a lot of lines at one place. - */ + // We are going to allocate a new data block. Depending on the + // situation it will be put to the left or right of the existing + // block. If possible we put the new line in the left block and move + // the lines after it to the right block. Otherwise the new line is + // also put in the right block. This method is more efficient when + // inserting a lot of lines at one place. if (db_idx < 0) { // left block is new, right block is existing lines_moved = 0; in_left = true; @@ -2146,7 +1995,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b } } - page_count = ((space_needed + (int)HEADER_SIZE) + page_size - 1) / page_size; + int 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; @@ -2166,9 +2015,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b 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. - */ + // May move the new line into the right/new block. if (!in_left) { dp_right->db_txt_start -= (unsigned)len; dp_right->db_free -= (unsigned)len + (unsigned)INDEX_SIZE; @@ -2181,25 +2028,19 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b line, (size_t)len); line_count_right++; } - /* - * may move lines from the left/old block to the right/new one. - */ + // may move lines from the left/old block to the right/new one. if (lines_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 = (int)(dp_right->db_txt_start - dp_left->db_txt_start); + int 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; + // update indexes in the new block + for (int to = line_count_right, from = db_idx + 1; from < line_count_left; from++, to++) { dp_right->db_index[to] = dp->db_index[from] + (unsigned)offset; } @@ -2207,9 +2048,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b line_count_left -= lines_moved; } - /* - * May move the new line into the left (old or new) block. - */ + // May move the new line into the left (old or new) block. if (in_left) { dp_left->db_txt_start -= (unsigned)len; dp_left->db_free -= (unsigned)len + (unsigned)INDEX_SIZE; @@ -2236,12 +2075,10 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b dp_left->db_line_count = line_count_left; dp_right->db_line_count = line_count_right; - /* - * release the two data blocks - * The new one (hp_new) already has a correct blocknumber. - * The old one (hp, in ml_locked) gets a positive blocknumber if - * we changed it and we are not editing a new file. - */ + // release the two data blocks + // The new one (hp_new) already has a correct blocknumber. + // The old one (hp, in ml_locked) gets a positive blocknumber if + // we changed it and we are not editing a new file. if (lines_moved || in_left) { buf->b_ml.ml_flags |= ML_LOCKED_DIRTY; } @@ -2250,35 +2087,28 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b } mf_put(mfp, hp_new, true, false); - /* - * flush the old data block - * set ml_locked_lineadd to 0, because the updating of the - * pointer blocks is done below - */ + // flush the old data block + // set ml_locked_lineadd to 0, because the updating of the + // pointer blocks is done below lineadd = buf->b_ml.ml_locked_lineadd; buf->b_ml.ml_locked_lineadd = 0; (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush data block - /* - * update pointer blocks for the new data block - */ - for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; - --stack_idx) { - ip = &(buf->b_ml.ml_stack[stack_idx]); + // update pointer blocks for the new data block + for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; stack_idx--) { + infoptr_T *ip = &(buf->b_ml.ml_stack[stack_idx]); pb_idx = ip->ip_index; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) { return FAIL; } - pp = hp->bh_data; // must be pointer block + PTR_BL *pp = hp->bh_data; // must be pointer block if (pp->pb_id != PTR_ID) { iemsg(_("E317: pointer block id wrong 3")); mf_put(mfp, hp, false, false); return FAIL; } - /* - * TODO: If the pointer block is full and we are adding at the end - * try to insert in front of the next block - */ + // TODO(vim): If the pointer block is full and we are adding at the end + // try to insert in front of the next block // block not full, add one entry if (pp->pb_count < pp->pb_count_max) { if (pb_idx + 1 < (int)pp->pb_count) { @@ -2286,7 +2116,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b &pp->pb_pointer[pb_idx + 1], (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN)); } - ++pp->pb_count; + pp->pb_count++; pp->pb_pointer[pb_idx].pe_line_count = line_count_left; pp->pb_pointer[pb_idx].pe_bnum = bnum_left; pp->pb_pointer[pb_idx].pe_page_count = page_count_left; @@ -2314,9 +2144,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b ++(buf->b_ml.ml_stack_top); } - /* - * We are finished, break the loop here. - */ + // We are finished, break the loop here. break; } // pointer block full @@ -2386,11 +2214,11 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b // recompute line counts line_count_right = 0; - for (i = 0; i < (int)pp_new->pb_count; i++) { + for (int i = 0; i < (int)pp_new->pb_count; i++) { line_count_right += pp_new->pb_pointer[i].pe_line_count; } line_count_left = 0; - for (i = 0; i < (int)pp->pb_count; i++) { + for (int i = 0; i < (int)pp->pb_count; i++) { line_count_left += pp->pb_pointer[i].pe_line_count; } @@ -2402,9 +2230,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b mf_put(mfp, hp_new, true, false); } - /* - * Safety check: fallen out of for loop? - */ + // Safety check: fallen out of for loop? if (stack_idx < 0) { iemsg(_("E318: Updated too many blocks?")); buf->b_ml.ml_stack_top = 0; // invalidate stack @@ -2416,9 +2242,9 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b return OK; } -void ml_add_deleted_len(char_u *ptr, ssize_t len) +void ml_add_deleted_len(char *ptr, ssize_t len) { - ml_add_deleted_len_buf(curbuf, ptr, len); + ml_add_deleted_len_buf(curbuf, (char_u *)ptr, len); } void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len) @@ -2426,8 +2252,9 @@ void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len) if (inhibit_delete_count) { return; } - if (len == -1) { - len = (ssize_t)STRLEN(ptr); + ssize_t maxlen = (ssize_t)STRLEN(ptr); + if (len == -1 || len > maxlen) { + len = maxlen; } curbuf->deleted_bytes += (size_t)len + 1; curbuf->deleted_bytes2 += (size_t)len + 1; @@ -2441,7 +2268,7 @@ void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len) int ml_replace(linenr_T lnum, char *line, bool copy) { - return ml_replace_buf(curbuf, lnum, (char_u *)line, copy); + return ml_replace_buf(curbuf, lnum, line, copy); } /// Replace line "lnum", with buffering, in current buffer. @@ -2453,10 +2280,10 @@ int ml_replace(linenr_T lnum, char *line, bool copy) /// Do not use it after calling ml_replace(). /// /// Check: The caller of this function should probably also call -/// changed_lines(), unless update_screen(NOT_VALID) is used. +/// changed_lines(), unless update_screen(UPD_NOT_VALID) is used. /// /// @return FAIL for failure, OK otherwise -int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy) +int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy) { if (line == NULL) { // just checking... return FAIL; @@ -2470,7 +2297,7 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy) bool readlen = true; if (copy) { - line = vim_strsave(line); + line = xstrdup(line); } if (buf->b_ml.ml_line_lnum != lnum) { // other line buffered ml_flush_line(buf); // flush it @@ -2482,10 +2309,10 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy) } if (readlen && kv_size(buf->update_callbacks)) { - ml_add_deleted_len_buf(buf, ml_get_buf(buf, lnum, false), -1); + ml_add_deleted_len_buf(buf, (char_u *)ml_get_buf(buf, lnum, false), -1); } - buf->b_ml.ml_line_ptr = line; + buf->b_ml.ml_line_ptr = (char_u *)line; buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; @@ -2508,18 +2335,6 @@ int ml_delete(linenr_T lnum, bool message) static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) { - bhdr_T *hp; - memfile_T *mfp; - DATA_BL *dp; - PTR_BL *pp; - infoptr_T *ip; - int count; // number of entries in block - int idx; - int stack_idx; - int line_start; - long line_size; - int i; - if (lnum < 1 || lnum > buf->b_ml.ml_line_count) { return FAIL; } @@ -2528,42 +2343,40 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) lowest_marked--; } - /* - * If the file becomes empty the last line is replaced by an empty line. - */ + // If the file becomes empty the last line is replaced by an empty line. if (buf->b_ml.ml_line_count == 1) { // file becomes empty if (message) { set_keep_msg(_(no_lines_msg), 0); } - i = ml_replace((linenr_T)1, "", true); + int i = ml_replace((linenr_T)1, "", true); buf->b_ml.ml_flags |= ML_EMPTY; return i; } - /* - * find the data block containing the line - * This also fills the stack with the blocks from the root to the data block - * This also releases any locked block. - */ - mfp = buf->b_ml.ml_mfp; + // find the data block containing the line + // This also fills the stack with the blocks from the root to the data block + // This also releases any locked block. + memfile_T *mfp = buf->b_ml.ml_mfp; if (mfp == NULL) { return FAIL; } + bhdr_T *hp; if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL) { return FAIL; } - dp = hp->bh_data; - // compute line count before the delete - count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 2; - idx = lnum - buf->b_ml.ml_locked_low; + DATA_BL *dp = hp->bh_data; + // compute line count (number of entries in block) before the delete + int count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 2; + int idx = lnum - buf->b_ml.ml_locked_low; - --buf->b_ml.ml_line_count; + buf->b_ml.ml_line_count--; - line_start = ((dp->db_index[idx]) & DB_INDEX_MASK); + int line_start = ((dp->db_index[idx]) & DB_INDEX_MASK); + long line_size; if (idx == 0) { // first line in block, text at the end line_size = dp->db_txt_end - (unsigned)line_start; } else { @@ -2575,27 +2388,24 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) assert(line_size >= 1); ml_add_deleted_len_buf(buf, (char_u *)dp + line_start, line_size - 1); - /* - * special case: If there is only one line in the data block it becomes empty. - * Then we have to remove the entry, pointing to this data block, from the - * pointer block. If this pointer block also becomes empty, we go up another - * block, and so on, up to the root if necessary. - * The line counts in the pointer blocks have already been adjusted by - * ml_find_line(). - */ + // special case: If there is only one line in the data block it becomes empty. + // Then we have to remove the entry, pointing to this data block, from the + // pointer block. If this pointer block also becomes empty, we go up another + // block, and so on, up to the root if necessary. + // The line counts in the pointer blocks have already been adjusted by + // ml_find_line(). if (count == 1) { mf_free(mfp, hp); // free the data block buf->b_ml.ml_locked = NULL; - for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; - --stack_idx) { + for (int stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; stack_idx--) { buf->b_ml.ml_stack_top = 0; // stack is invalid when failing - ip = &(buf->b_ml.ml_stack[stack_idx]); + infoptr_T *ip = &(buf->b_ml.ml_stack[stack_idx]); idx = ip->ip_index; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) { return FAIL; } - pp = hp->bh_data; // must be pointer block + PTR_BL *pp = hp->bh_data; // must be pointer block if (pp->pb_id != PTR_ID) { iemsg(_("E317: pointer block id wrong 4")); mf_put(mfp, hp, false, false); @@ -2632,7 +2442,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) // delete the index by moving the next indexes backwards // Adjust the indexes for the text movement. - for (i = idx; i < count - 1; i++) { + for (int i = idx; i < count - 1; i++) { dp->db_index[i] = dp->db_index[i + 1] + (unsigned)line_size; } @@ -2640,9 +2450,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) 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) - */ + // mark the block dirty and make sure it is in the file (for recovery) buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS); } @@ -2653,8 +2461,6 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) /// set the B_MARKED flag for line 'lnum' void ml_setmarked(linenr_T lnum) { - bhdr_T *hp; - DATA_BL *dp; // invalid line number if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count || curbuf->b_ml.ml_mfp == NULL) { @@ -2664,15 +2470,14 @@ void ml_setmarked(linenr_T lnum) lowest_marked = lnum; } - /* - * find the data block containing the line - * This also fills the stack with the blocks from the root to the data block - * This also releases any locked block. - */ + // find the data block containing the line + // This also fills the stack with the blocks from the root to the data block + // This also releases any locked block. + bhdr_T *hp; if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) { return; // give error message? } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED; curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY; } @@ -2680,32 +2485,24 @@ void ml_setmarked(linenr_T lnum) /// find the first line with its B_MARKED flag set linenr_T ml_firstmarked(void) { - bhdr_T *hp; - DATA_BL *dp; - linenr_T lnum; - int i; - if (curbuf->b_ml.ml_mfp == NULL) { return (linenr_T)0; } - /* - * The search starts with lowest_marked line. This is the last line where - * a mark was found, adjusted by inserting/deleting lines. - */ - for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { - /* - * Find the data block containing the line. - * This also fills the stack with the blocks from the root to the data - * block This also releases any locked block. - */ + // The search starts with lowest_marked line. This is the last line where + // a mark was found, adjusted by inserting/deleting lines. + for (linenr_T lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { + // Find the data block containing the line. + // This also fills the stack with the blocks from the root to the data + // block This also releases any locked block. + bhdr_T *hp; if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) { return (linenr_T)0; // give error message? } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; - for (i = lnum - curbuf->b_ml.ml_locked_low; - lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum) { + for (int i = lnum - curbuf->b_ml.ml_locked_low; + lnum <= curbuf->b_ml.ml_locked_high; i++, lnum++) { if ((dp->db_index[i]) & DB_MARKED) { (dp->db_index[i]) &= DB_INDEX_MASK; curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY; @@ -2721,31 +2518,23 @@ linenr_T ml_firstmarked(void) /// clear all DB_MARKED flags void ml_clearmarked(void) { - bhdr_T *hp; - DATA_BL *dp; - linenr_T lnum; - int i; - if (curbuf->b_ml.ml_mfp == NULL) { // nothing to do return; } - /* - * The search starts with line lowest_marked. - */ - for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { - /* - * Find the data block containing the line. - * This also fills the stack with the blocks from the root to the data - * block and releases any locked block. - */ + // The search starts with line lowest_marked. + for (linenr_T lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) { + // Find the data block containing the line. + // This also fills the stack with the blocks from the root to the data + // block and releases any locked block. + bhdr_T *hp; if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) { return; // give error message? } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; - for (i = lnum - curbuf->b_ml.ml_locked_low; - lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum) { + for (int i = lnum - curbuf->b_ml.ml_locked_low; + lnum <= curbuf->b_ml.ml_locked_high; i++, lnum++) { if ((dp->db_index[i]) & DB_MARKED) { (dp->db_index[i]) &= DB_INDEX_MASK; curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY; @@ -2770,18 +2559,6 @@ size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits) /// flush ml_line if necessary static void ml_flush_line(buf_T *buf) { - bhdr_T *hp; - DATA_BL *dp; - linenr_T lnum; - char_u *new_line; - char_u *old_line; - colnr_T new_len; - int old_len; - int extra; - int idx; - int start; - int count; - int i; static bool entered = false; if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL) { @@ -2796,31 +2573,30 @@ static void ml_flush_line(buf_T *buf) buf->flush_count++; - lnum = buf->b_ml.ml_line_lnum; - new_line = buf->b_ml.ml_line_ptr; + linenr_T lnum = buf->b_ml.ml_line_lnum; + char_u *new_line = buf->b_ml.ml_line_ptr; - hp = ml_find_line(buf, lnum, ML_FIND); + bhdr_T *hp = ml_find_line(buf, lnum, ML_FIND); if (hp == NULL) { siemsg(_("E320: Cannot find line %" PRId64), (int64_t)lnum); } else { - dp = hp->bh_data; - idx = lnum - buf->b_ml.ml_locked_low; - start = ((dp->db_index[idx]) & DB_INDEX_MASK); - old_line = (char_u *)dp + start; + DATA_BL *dp = hp->bh_data; + int idx = lnum - buf->b_ml.ml_locked_low; + int start = ((dp->db_index[idx]) & DB_INDEX_MASK); + char_u *old_line = (char_u *)dp + start; + int old_len; if (idx == 0) { // line is last in block old_len = (int)dp->db_txt_end - start; } else { // text of previous line follows 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 + colnr_T new_len = (colnr_T)STRLEN(new_line) + 1; + int extra = new_len - old_len; // negative if lines gets smaller - /* - * if new line fits in data block, replace directly - */ + // if new line fits in data block, replace directly if ((int)dp->db_free >= extra) { // if the length changes and there are following lines - count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; + int count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; if (extra != 0 && idx < count - 1) { // move text of following lines memmove((char *)dp + dp->db_txt_start - extra, @@ -2828,7 +2604,7 @@ static void ml_flush_line(buf_T *buf) (size_t)(start - (int)dp->db_txt_start)); // adjust pointers of this and following lines - for (i = idx + 1; i < count; i++) { + for (int i = idx + 1; i < count; i++) { dp->db_index[i] -= (unsigned)extra; } } @@ -2905,28 +2681,17 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp) /// @return NULL for failure, pointer to block header otherwise static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) { - DATA_BL *dp; PTR_BL *pp; - infoptr_T *ip; bhdr_T *hp; - memfile_T *mfp; - linenr_T t; - blocknr_T bnum, bnum2; - int dirty; - linenr_T low, high; int top; - int page_count; - int idx; - mfp = buf->b_ml.ml_mfp; + memfile_T *mfp = buf->b_ml.ml_mfp; - /* - * If there is a locked block check if the wanted line is in it. - * If not, flush and release the locked block. - * Don't do this for ML_INSERT_SAME, because the stack need to be updated. - * Don't do this for ML_FLUSH, because we want to flush the locked block. - * Don't do this when 'swapfile' is reset, we want to load all the blocks. - */ + // If there is a locked block check if the wanted line is in it. + // If not, flush and release the locked block. + // Don't do this for ML_INSERT_SAME, because the stack need to be updated. + // Don't do this for ML_FLUSH, because we want to flush the locked block. + // Don't do this when 'swapfile' is reset, we want to load all the blocks. if (buf->b_ml.ml_locked) { if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum @@ -2946,10 +2711,8 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) buf->b_ml.ml_flags & ML_LOCKED_POS); buf->b_ml.ml_locked = NULL; - /* - * If lines have been added or deleted in the locked block, need to - * update the line count in pointer blocks. - */ + // If lines have been added or deleted in the locked block, need to + // update the line count in pointer blocks. if (buf->b_ml.ml_locked_lineadd != 0) { ml_lineadd(buf, buf->b_ml.ml_locked_lineadd); } @@ -2959,14 +2722,15 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) return NULL; } - bnum = 1; // start at the root of the tree - page_count = 1; - low = 1; - high = buf->b_ml.ml_line_count; + blocknr_T bnum = 1; // start at the root of the tree + blocknr_T bnum2; + int page_count = 1; + linenr_T low = 1; + linenr_T high = buf->b_ml.ml_line_count; if (action == ML_FIND) { // first try stack entries - for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top) { - ip = &(buf->b_ml.ml_stack[top]); + for (top = buf->b_ml.ml_stack_top - 1; top >= 0; top--) { + infoptr_T *ip = &(buf->b_ml.ml_stack[top]); if (ip->ip_low <= lnum && ip->ip_high >= lnum) { bnum = ip->ip_bnum; low = ip->ip_low; @@ -2981,24 +2745,20 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) } else { // ML_DELETE or ML_INSERT buf->b_ml.ml_stack_top = 0; // start at the root } - /* - * search downwards in the tree until a data block is found - */ + // search downwards in the tree until a data block is found for (;;) { if ((hp = mf_get(mfp, bnum, (unsigned)page_count)) == NULL) { goto error_noblock; } - /* - * update high for insert/delete - */ + // update high for insert/delete if (action == ML_INSERT) { high++; } else if (action == ML_DELETE) { high--; } - dp = hp->bh_data; + DATA_BL *dp = hp->bh_data; if (dp->db_id == DATA_ID) { // data block buf->b_ml.ml_locked = hp; buf->b_ml.ml_locked_low = low; @@ -3015,15 +2775,16 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) } top = ml_add_stack(buf); // add new entry to stack - ip = &(buf->b_ml.ml_stack[top]); + infoptr_T *ip = &(buf->b_ml.ml_stack[top]); ip->ip_bnum = bnum; ip->ip_low = low; ip->ip_high = high; ip->ip_index = -1; // index not known yet - dirty = FALSE; - for (idx = 0; idx < (int)pp->pb_count; ++idx) { - t = pp->pb_pointer[idx].pe_line_count; + bool dirty = false; + int idx; + for (idx = 0; idx < (int)pp->pb_count; idx++) { + linenr_T t = pp->pb_pointer[idx].pe_line_count; CHECK(t == 0, _("pe_line_count is zero")); if ((low += t) > lnum) { ip->ip_index = idx; @@ -3032,15 +2793,13 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) high = low - 1; low -= t; - /* - * a negative block number may have been changed - */ + // a negative block number may have been changed if (bnum < 0) { bnum2 = mf_trans_del(mfp, bnum); if (bnum != bnum2) { bnum = bnum2; pp->pb_pointer[idx].pe_bnum = bnum; - dirty = TRUE; + dirty = true; } } @@ -3058,10 +2817,10 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) } if (action == ML_DELETE) { pp->pb_pointer[idx].pe_line_count--; - dirty = TRUE; + dirty = true; } else if (action == ML_INSERT) { pp->pb_pointer[idx].pe_line_count++; - dirty = TRUE; + dirty = true; } mf_put(mfp, hp, dirty, false); } @@ -3069,11 +2828,9 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) error_block: mf_put(mfp, hp, false, false); error_noblock: - /* - * If action is ML_DELETE or ML_INSERT we have to correct the tree for - * the incremented/decremented line counts, because there won't be a line - * inserted/deleted after all. - */ + // If action is ML_DELETE or ML_INSERT we have to correct the tree for + // the incremented/decremented line counts, because there won't be a line + // inserted/deleted after all. if (action == ML_DELETE) { ml_lineadd(buf, 1); } else if (action == ML_INSERT) { @@ -3113,18 +2870,15 @@ static int ml_add_stack(buf_T *buf) /// Count is the number of lines added, negative if lines have been deleted. static void ml_lineadd(buf_T *buf, int count) { - int idx; - infoptr_T *ip; - PTR_BL *pp; memfile_T *mfp = buf->b_ml.ml_mfp; - bhdr_T *hp; - for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx) { - ip = &(buf->b_ml.ml_stack[idx]); + for (int idx = buf->b_ml.ml_stack_top - 1; idx >= 0; idx--) { + infoptr_T *ip = &(buf->b_ml.ml_stack[idx]); + bhdr_T *hp; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) { break; } - pp = hp->bh_data; // must be pointer block + PTR_BL *pp = hp->bh_data; // must be pointer block if (pp->pb_id != PTR_ID) { mf_put(mfp, hp, false, false); iemsg(_("E317: pointer block id wrong 2")); @@ -3144,10 +2898,9 @@ static void ml_lineadd(buf_T *buf, int count) /// /// @return OK if it worked and the resolved link in "buf[MAXPATHL]", /// FAIL otherwise -int resolve_symlink(const char_u *fname, char_u *buf) +int resolve_symlink(const char *fname, char *buf) { - char_u tmp[MAXPATHL]; - int ret; + char tmp[MAXPATHL]; int depth = 0; if (fname == NULL) { @@ -3164,7 +2917,7 @@ int resolve_symlink(const char_u *fname, char_u *buf) return FAIL; } - ret = (int)readlink((char *)tmp, (char *)buf, MAXPATHL - 1); + int ret = (int)readlink(tmp, buf, MAXPATHL - 1); if (ret <= 0) { if (errno == EINVAL || errno == ENOENT) { // Found non-symlink or not existing file, stop here. @@ -3187,23 +2940,21 @@ int resolve_symlink(const char_u *fname, char_u *buf) // If it's relative, build a new path based on the directory // portion of the filename (if any) and the path the symlink // points to. - if (path_is_absolute(buf)) { + if (path_is_absolute((char_u *)buf)) { STRCPY(tmp, buf); } else { - char_u *tail = (char_u *)path_tail((char *)tmp); - if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL) { + char_u *tail = (char_u *)path_tail(tmp); + if (STRLEN(tail) + strlen(buf) >= MAXPATHL) { return FAIL; } STRCPY(tail, buf); } } - /* - * Try to resolve the full name of the file so that the swapfile name will - * be consistent even when opening a relative symlink from different - * working directories. - */ - return vim_FullName((char *)tmp, (char *)buf, MAXPATHL, TRUE); + // Try to resolve the full name of the file so that the swapfile name will + // be consistent even when opening a relative symlink from different + // working directories. + return vim_FullName(tmp, buf, MAXPATHL, true); } #endif @@ -3212,24 +2963,23 @@ int resolve_symlink(const char_u *fname, char_u *buf) /// @return pointer to allocated memory or NULL. char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name) { - char_u *r, *s; char_u *fname_res = fname; #ifdef HAVE_READLINK char_u fname_buf[MAXPATHL]; // Expand symlink in the file name, so that we put the swap file with the // actual file instead of with the symlink. - if (resolve_symlink(fname, fname_buf) == OK) { + if (resolve_symlink((char *)fname, (char *)fname_buf) == OK) { fname_res = fname_buf; } #endif int len = (int)STRLEN(dir_name); - s = dir_name + len; + char_u *s = dir_name + len; if (after_pathsep((char *)dir_name, (char *)s) && len > 1 && s[-1] == s[-2]) { // Ends with '//', Use Full path - r = NULL; + char_u *r = NULL; s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname_res); if (s != NULL) { r = (char_u *)modname((char *)s, ".swp", false); @@ -3239,13 +2989,13 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name } // Prepend a '.' to the swap file name for the current directory. - r = (char_u *)modname((char *)fname_res, ".swp", - dir_name[0] == '.' && dir_name[1] == NUL); + char_u *r = (char_u *)modname((char *)fname_res, ".swp", + dir_name[0] == '.' && dir_name[1] == NUL); if (r == NULL) { // out of memory return NULL; } - s = get_file_in_dir(r, dir_name); + s = (char_u *)get_file_in_dir((char *)r, (char *)dir_name); xfree(r); return s; } @@ -3262,30 +3012,27 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name /// The return value is an allocated string and can be NULL. /// /// @param dname don't use "dirname", it is a global for Alpha -char_u *get_file_in_dir(char_u *fname, char_u *dname) +char *get_file_in_dir(char *fname, char *dname) { - char_u *t; - char_u *tail; - char_u *retval; - int save_char; + char *retval; - tail = (char_u *)path_tail((char *)fname); + char *tail = path_tail(fname); if (dname[0] == '.' && dname[1] == NUL) { - retval = vim_strsave(fname); + retval = xstrdup(fname); } else if (dname[0] == '.' && vim_ispathsep(dname[1])) { if (tail == fname) { // no path before file name - retval = (char_u *)concat_fnames((char *)dname + 2, (char *)tail, TRUE); + retval = concat_fnames(dname + 2, tail, true); } else { - save_char = *tail; + char save_char = *tail; *tail = NUL; - 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); + char *t = concat_fnames(fname, dname + 2, true); + *tail = save_char; + retval = concat_fnames(t, tail, true); xfree(t); } } else { - retval = (char_u *)concat_fnames((char *)dname, (char *)tail, TRUE); + retval = concat_fnames(dname, tail, true); } return retval; @@ -3302,7 +3049,7 @@ static void attention_message(buf_T *buf, char_u *fname) no_wait_return++; (void)emsg(_("E325: ATTENTION")); msg_puts(_("\nFound a swap file by the name \"")); - msg_home_replace(fname); + msg_home_replace((char *)fname); msg_puts("\"\n"); const time_t swap_mtime = swapfile_info(fname); msg_puts(_("While opening file \"")); @@ -3404,24 +3151,18 @@ static int do_swapexists(buf_T *buf, char_u *fname) static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_existing_dir) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4) { - char *fname; size_t n; - char *dir_name; char *buf_fname = buf->b_fname; - /* - * Isolate a directory name from *dirp and put it in dir_name. - * First allocate some memory to put the directory name in. - */ + // Isolate a directory name from *dirp and put it in dir_name. + // First allocate some memory to put the directory name in. const size_t dir_len = strlen(*dirp) + 1; - dir_name = xmalloc(dir_len); + char *dir_name = xmalloc(dir_len); (void)copy_option_part(dirp, dir_name, dir_len, ","); - /* - * we try different names until we find one that does not exist yet - */ - fname = (char *)makeswapname((char_u *)buf_fname, (char_u *)buf->b_ffname, buf, - (char_u *)dir_name); + // we try different names until we find one that does not exist yet + char *fname = (char *)makeswapname((char_u *)buf_fname, (char_u *)buf->b_ffname, buf, + (char_u *)dir_name); for (;;) { if (fname == NULL) { // must be out of memory @@ -3441,7 +3182,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ } // A file name equal to old_fname is OK to use. - if (old_fname != NULL && FNAMECMP(fname, old_fname) == 0) { + if (old_fname != NULL && path_fnamecmp(fname, old_fname) == 0) { break; } @@ -3455,7 +3196,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ && !buf->b_help && !(buf->b_flags & BF_DUMMY)) { int fd; struct block0 b0; - int differ = FALSE; + int differ = false; // Try to read block 0 from the swap file to get the original // file name (and inode number). @@ -3466,25 +3207,25 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ // buffer don't compare the directory names, they can // have a different mountpoint. if (b0.b0_flags & B0_SAME_DIR) { - if (FNAMECMP(path_tail((char *)buf->b_ffname), - path_tail((char *)b0.b0_fname)) != 0 + if (path_fnamecmp(path_tail(buf->b_ffname), + path_tail((char *)b0.b0_fname)) != 0 || !same_directory((char_u *)fname, (char_u *)buf->b_ffname)) { // Symlinks may point to the same file even // when the name differs, need to check the // inode too. - expand_env(b0.b0_fname, NameBuff, MAXPATHL); - if (fnamecmp_ino((char_u *)buf->b_ffname, NameBuff, + expand_env((char *)b0.b0_fname, NameBuff, MAXPATHL); + if (fnamecmp_ino(buf->b_ffname, NameBuff, char_to_long(b0.b0_ino))) { - differ = TRUE; + differ = true; } } } else { // The name in the swap file may be // "~user/path/file". Expand it first. - expand_env(b0.b0_fname, NameBuff, MAXPATHL); - if (fnamecmp_ino((char_u *)buf->b_ffname, NameBuff, + expand_env((char *)b0.b0_fname, NameBuff, MAXPATHL); + if (fnamecmp_ino(buf->b_ffname, NameBuff, char_to_long(b0.b0_ino))) { - differ = TRUE; + differ = true; } } } @@ -3494,14 +3235,14 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ // give the ATTENTION message when there is an old swap file // for the current file, and the buffer was not recovered. if (differ == false && !(curbuf->b_flags & BF_RECOVERED) - && vim_strchr((char *)p_shm, SHM_ATTENTION) == NULL) { + && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { int choice = 0; process_still_running = false; // It's safe to delete the swap file if all these are true: // - the edited file exists // - the swap file has no changes and looks OK - if (os_path_exists((char_u *)buf->b_fname) && swapfile_unchanged(fname)) { + if (os_path_exists(buf->b_fname) && swapfile_unchanged(fname)) { choice = 4; if (p_verbose > 0) { verb_msg(_("Found a swap file that is not useful, deleting it")); @@ -3543,13 +3284,13 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ memcpy(name, sw_msg_1, sw_msg_1_len + 1); home_replace(NULL, fname, &name[sw_msg_1_len], fname_len, true); xstrlcat(name, sw_msg_2, name_len); - choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), - (char_u *)name, + choice = do_dialog(VIM_WARNING, _("VIM - ATTENTION"), + name, process_still_running - ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover" - "\n&Quit\n&Abort") : - (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover" - "\n&Delete it\n&Quit\n&Abort"), + ? _("&Open Read-Only\n&Edit anyway\n&Recover" + "\n&Quit\n&Abort") : + _("&Open Read-Only\n&Edit anyway\n&Recover" + "\n&Delete it\n&Quit\n&Abort"), 1, NULL, false); if (process_still_running && choice >= 4) { @@ -3564,7 +3305,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ if (choice > 0) { switch (choice) { case 1: - buf->b_p_ro = TRUE; + buf->b_p_ro = true; break; case 2: break; @@ -3579,12 +3320,12 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ break; case 6: swap_exists_action = SEA_QUIT; - got_int = TRUE; + got_int = true; break; } // If the file was deleted this fname can be used. - if (!os_path_exists((char_u *)fname)) { + if (!os_path_exists(fname)) { break; } } else { @@ -3598,25 +3339,23 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ } } - /* - * Change the ".swp" extension to find another file that can be used. - * First decrement the last char: ".swo", ".swn", etc. - * If that still isn't enough decrement the last but one char: ".svz" - * Can happen when editing many "No Name" buffers. - */ + // Change the ".swp" extension to find another file that can be used. + // First decrement the last char: ".swo", ".swn", etc. + // If that still isn't enough decrement the last but one char: ".svz" + // Can happen when editing many "No Name" buffers. if (fname[n - 1] == 'a') { // ".s?a" if (fname[n - 2] == 'a') { // ".saa": tried enough, give up emsg(_("E326: Too many swap files found")); XFREE_CLEAR(fname); break; } - --fname[n - 2]; // ".svz", ".suz", etc. + fname[n - 2]--; // ".svz", ".suz", etc. fname[n - 1] = 'z' + 1; } - --fname[n - 1]; // ".swo", ".swn", etc. + fname[n - 1]--; // ".swo", ".swn", etc. } - if (os_isdir((char_u *)dir_name)) { + if (os_isdir(dir_name)) { *found_existing_dir = true; } else if (!*found_existing_dir && **dirp == NUL) { int ret; @@ -3667,18 +3406,18 @@ static int b0_magic_wrong(ZERO_BL *b0p) /// /// current file doesn't exist, file for swap file exist, file name(s) not /// available -> probably different -/// == 0 != 0 FAIL X TRUE -/// == 0 != 0 X FAIL TRUE +/// == 0 != 0 FAIL X true +/// == 0 != 0 X FAIL true /// /// current file exists, inode for swap unknown, file name(s) not /// available -> probably different -/// != 0 == 0 FAIL X TRUE -/// != 0 == 0 X FAIL TRUE +/// != 0 == 0 FAIL X true +/// != 0 == 0 X FAIL true /// /// current file doesn't exist, inode for swap unknown, one file name not /// available -> probably different -/// == 0 == 0 FAIL OK TRUE -/// == 0 == 0 OK FAIL TRUE +/// == 0 == 0 FAIL OK true +/// == 0 == 0 OK FAIL true /// /// current file doesn't exist, inode for swap unknown, both file names not /// available -> compare file names @@ -3689,26 +3428,24 @@ static int b0_magic_wrong(ZERO_BL *b0p) /// /// @param fname_c current file name /// @param fname_s file name from swap file -static bool fnamecmp_ino(char_u *fname_c, char_u *fname_s, long ino_block0) +static bool fnamecmp_ino(char *fname_c, char *fname_s, long ino_block0) { uint64_t ino_c = 0; // ino of current file uint64_t ino_s; // ino of file from swap file - char_u buf_c[MAXPATHL]; // full path of fname_c - char_u buf_s[MAXPATHL]; // full path of fname_s + char buf_c[MAXPATHL]; // full path of fname_c + char buf_s[MAXPATHL]; // full path of fname_s int retval_c; // flag: buf_c valid int retval_s; // flag: buf_s valid FileInfo file_info; - if (os_fileinfo((char *)fname_c, &file_info)) { + if (os_fileinfo(fname_c, &file_info)) { ino_c = os_fileinfo_inode(&file_info); } - /* - * First we try to get the inode from the file name, because the inode in - * the swap file may be outdated. If that fails (e.g. this path is not - * valid on this machine), use the inode from block 0. - */ - if (os_fileinfo((char *)fname_s, &file_info)) { + // First we try to get the inode from the file name, because the inode in + // the swap file may be outdated. If that fails (e.g. this path is not + // valid on this machine), use the inode from block 0. + if (os_fileinfo(fname_s, &file_info)) { ino_s = os_fileinfo_inode(&file_info); } else { ino_s = (uint64_t)ino_block0; @@ -3718,23 +3455,19 @@ static bool fnamecmp_ino(char_u *fname_c, char_u *fname_s, long ino_block0) return ino_c != ino_s; } - /* - * One of the inode numbers is unknown, try a forced vim_FullName() and - * compare the file names. - */ - retval_c = vim_FullName((char *)fname_c, (char *)buf_c, MAXPATHL, TRUE); - retval_s = vim_FullName((char *)fname_s, (char *)buf_s, MAXPATHL, TRUE); + // One of the inode numbers is unknown, try a forced vim_FullName() and + // compare the file names. + retval_c = vim_FullName(fname_c, (char *)buf_c, MAXPATHL, true); + retval_s = vim_FullName(fname_s, (char *)buf_s, MAXPATHL, true); if (retval_c == OK && retval_s == OK) { - return STRCMP(buf_c, buf_s) != 0; + return strcmp(buf_c, buf_s) != 0; } - /* - * Can't compare inodes or file names, guess that the files are different, - * unless both appear not to exist at all, then compare with the file name - * in the swap file. - */ + // Can't compare inodes or file names, guess that the files are different, + // unless both appear not to exist at all, then compare with the file name + // in the swap file. if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL) { - return STRCMP(fname_c, fname_s) != 0; + return strcmp(fname_c, fname_s) != 0; } return true; } @@ -3829,9 +3562,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) } if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1) { - /* - * First line in empty buffer from ml_flush_line() -- reset - */ + // First line in empty buffer from ml_flush_line() -- reset buf->b_ml.ml_usedchunks = 1; buf->b_ml.ml_chunksize[0].mlcs_numlines = 1; buf->b_ml.ml_chunksize[0].mlcs_totalsize = @@ -3839,10 +3570,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) return; } - /* - * Find chunk that our line belongs to, curline will be at start of the - * chunk. - */ + // Find chunk that our line belongs to, curline will be at start of the + // chunk. if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1 || updtype != ML_CHNK_ADDLINE) { for (curline = 1, curix = 0; @@ -3930,10 +3659,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) curchnk->mlcs_numlines = 0; curchnk->mlcs_totalsize = 0; } else { - /* - * Line is just prior to last, move count for last - * This is the common case when loading a new file - */ + // Line is just prior to last, move count for last + // This is the common case when loading a new file hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND); if (hp == NULL) { buf->b_ml.ml_usedchunks = -1; @@ -4046,10 +3773,8 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) if (lnum == 0 && offset <= 0) { return 1; // Not a "find offset" and offset 0 _must_ be in line 1 } - /* - * Find the last chunk before the one containing our line. Last chunk is - * special because it will never qualify - */ + // Find the last chunk before the one containing our line. Last chunk is + // special because it will never qualify curline = 1; curix = 0; size = 0; @@ -4163,7 +3888,7 @@ void goto_byte(long cnt) curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = (colnr_T)boff; curwin->w_cursor.coladd = 0; - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; } check_cursor(); @@ -4214,8 +3939,8 @@ int dec(pos_T *lp) lp->coladd = 0; if (lp->col == MAXCOL) { // past end of line - char_u *p = ml_get(lp->lnum); - lp->col = (colnr_T)STRLEN(p); + char *p = ml_get(lp->lnum); + lp->col = (colnr_T)strlen(p); lp->col -= utf_head_off(p, p + lp->col); return 0; } @@ -4223,15 +3948,15 @@ int dec(pos_T *lp) if (lp->col > 0) { // still within line lp->col--; - char_u *p = ml_get(lp->lnum); + char *p = ml_get(lp->lnum); lp->col -= utf_head_off(p, p + lp->col); return 0; } if (lp->lnum > 1) { // there is a prior line lp->lnum--; - char_u *p = ml_get(lp->lnum); - lp->col = (colnr_T)STRLEN(p); + char *p = ml_get(lp->lnum); + lp->col = (colnr_T)strlen(p); lp->col -= utf_head_off(p, p + lp->col); return 1; } diff --git a/src/nvim/memline_defs.h b/src/nvim/memline_defs.h index 922a2c98d1..552ec1e3a9 100644 --- a/src/nvim/memline_defs.h +++ b/src/nvim/memline_defs.h @@ -69,4 +69,4 @@ typedef struct memline { int ml_usedchunks; } memline_T; -#endif // NVIM_MEMLINE_DEFS_H +#endif // NVIM_MEMLINE_DEFS_H diff --git a/src/nvim/memory.c b/src/nvim/memory.c index fb36d4ccf4..61c43d8f99 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -23,6 +23,7 @@ #include "nvim/message.h" #include "nvim/sign.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/vim.h" #ifdef UNIT_TESTING @@ -60,6 +61,8 @@ void try_to_free_memory(void) // Try to save all buffers and release as many blocks as possible mf_release_all(); + arena_free_reuse_blks(); + trying_to_free = false; } @@ -499,22 +502,22 @@ bool striequal(const char *a, const char *b) return (a == NULL && b == NULL) || (a && b && STRICMP(a, b) == 0); } -/* - * Avoid repeating the error message many times (they take 1 second each). - * Did_outofmem_msg is reset when a character is read. - */ +// Avoid repeating the error message many times (they take 1 second each). +// Did_outofmem_msg is reset when a character is read. void do_outofmem_msg(size_t size) { - if (!did_outofmem_msg) { - // Don't hide this message - emsg_silent = 0; + if (did_outofmem_msg) { + return; + } - /* Must come first to avoid coming back here when printing the error - * message fails, e.g. when setting v:errmsg. */ - did_outofmem_msg = true; + // Don't hide this message + emsg_silent = 0; - semsg(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), (uint64_t)size); - } + // Must come first to avoid coming back here when printing the error + // message fails, e.g. when setting v:errmsg. + did_outofmem_msg = true; + + semsg(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), (uint64_t)size); } /// Writes time_t to "buf[8]". @@ -528,21 +531,19 @@ void time_to_bytes(time_t time_, uint8_t buf[8]) } #define ARENA_BLOCK_SIZE 4096 +#define REUSE_MAX 4 + +static struct consumed_blk *arena_reuse_blk; +static size_t arena_reuse_blk_count = 0; -void arena_start(Arena *arena, ArenaMem *reuse_blk) +static void arena_free_reuse_blks(void) { - if (reuse_blk && *reuse_blk) { - arena->cur_blk = (char *)(*reuse_blk); - *reuse_blk = NULL; - } else { - arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE); + while (arena_reuse_blk_count > 0) { + struct consumed_blk *blk = arena_reuse_blk; + arena_reuse_blk = arena_reuse_blk->prev; + xfree(blk); + arena_reuse_blk_count--; } - arena->pos = 0; - arena->size = ARENA_BLOCK_SIZE; - // address is the same as as (struct consumed_blk *)arena->cur_blk - struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); - assert((char *)blk == (char *)arena->cur_blk); - blk->prev = NULL; } /// Finnish the allocations in an arena. @@ -558,17 +559,45 @@ ArenaMem arena_finish(Arena *arena) return res; } +void alloc_block(Arena *arena) +{ + struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk; + if (arena_reuse_blk_count > 0) { + arena->cur_blk = (char *)arena_reuse_blk; + arena_reuse_blk = arena_reuse_blk->prev; + arena_reuse_blk_count--; + } else { + arena_alloc_count++; + arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE); + } + arena->pos = 0; + arena->size = ARENA_BLOCK_SIZE; + struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); + blk->prev = prev_blk; +} + +/// @param arena if NULL, do a global allocation. caller must then free the value! +/// @param size if zero, will still return a non-null pointer, but not a unique one void *arena_alloc(Arena *arena, size_t size, bool align) { + if (!arena) { + return xmalloc(size); + } if (align) { arena->pos = (arena->pos + (ARENA_ALIGN - 1)) & ~(ARENA_ALIGN - 1); } - if (arena->pos + size > arena->size) { - if (size > (arena->size - sizeof(struct consumed_blk)) >> 1) { + if (arena->pos + size > arena->size || !arena->cur_blk) { + if (size > (ARENA_BLOCK_SIZE - sizeof(struct consumed_blk)) >> 1) { // if allocation is too big, allocate a large block with the requested // size, but still with block pointer head. We do this even for // arena->size / 2, as there likely is space left for the next // small allocation in the current block. + if (!arena->cur_blk) { + // to simplify free-list management, arena->cur_blk must + // always be a normal, ARENA_BLOCK_SIZE sized, block + alloc_block(arena); + } + arena_alloc_count++; char *alloc = xmalloc(size + sizeof(struct consumed_blk)); struct consumed_blk *cur_blk = (struct consumed_blk *)arena->cur_blk; struct consumed_blk *fix_blk = (struct consumed_blk *)alloc; @@ -576,12 +605,7 @@ void *arena_alloc(Arena *arena, size_t size, bool align) cur_blk->prev = fix_blk; return (alloc + sizeof(struct consumed_blk)); } else { - struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk; - arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE); - arena->pos = 0; - arena->size = ARENA_BLOCK_SIZE; - struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); - blk->prev = prev_blk; + alloc_block(arena); } } @@ -590,15 +614,17 @@ void *arena_alloc(Arena *arena, size_t size, bool align) return mem; } -void arena_mem_free(ArenaMem mem, ArenaMem *reuse_blk) +void arena_mem_free(ArenaMem mem) { struct consumed_blk *b = mem; // peel of the first block, as it is guaranteed to be ARENA_BLOCK_SIZE, // not a custom fix_blk - if (reuse_blk && *reuse_blk == NULL && b != NULL) { - *reuse_blk = b; + if (arena_reuse_blk_count < REUSE_MAX && b != NULL) { + struct consumed_blk *reuse_blk = b; b = b->prev; - (*reuse_blk)->prev = NULL; + reuse_blk->prev = arena_reuse_blk; + arena_reuse_blk = reuse_blk; + arena_reuse_blk_count++; } while (b) { @@ -649,13 +675,11 @@ char *arena_memdupz(Arena *arena, const char *buf, size_t size) # include "nvim/tag.h" # include "nvim/window.h" -/* - * Free everything that we allocated. - * Can be used to detect memory leaks, e.g., with ccmalloc. - * NOTE: This is tricky! Things are freed that functions depend on. Don't be - * surprised if Vim crashes... - * Some things can't be freed, esp. things local to a library function. - */ +// Free everything that we allocated. +// Can be used to detect memory leaks, e.g., with ccmalloc. +// NOTE: This is tricky! Things are freed that functions depend on. Don't be +// surprised if Vim crashes... +// Some things can't be freed, esp. things local to a library function. void free_all_mem(void) { buf_T *buf, *nextbuf; @@ -797,8 +821,12 @@ void free_all_mem(void) decor_free_all_mem(); - nlua_free_all_mem(); ui_free_all_mem(); + ui_comp_free_all_mem(); + nlua_free_all_mem(); + + // should be last, in case earlier free functions deallocates arenas + arena_free_reuse_blks(); } #endif diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 63d607c2ce..f407192331 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -6,6 +6,8 @@ #include <stdint.h> // for uint8_t #include <time.h> // for time_t +#include "nvim/macros.h" + /// `malloc()` function signature typedef void *(*MemMalloc)(size_t); @@ -37,6 +39,8 @@ extern MemRealloc mem_realloc; extern bool entered_free_all_mem; #endif +EXTERN size_t arena_alloc_count INIT(=0); + typedef struct consumed_blk { struct consumed_blk *prev; } *ArenaMem; @@ -48,7 +52,7 @@ typedef struct { size_t pos, size; } Arena; -// inits an empty arena. use arena_start() to actually allocate space! +// inits an empty arena. #define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 } #define kv_fixsize_arena(a, v, s) \ diff --git a/src/nvim/menu.c b/src/nvim/menu.c index c3cf4457fc..57116170aa 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1,10 +1,8 @@ // 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 -/* - * Code for menus. Used for the GUI and 'wildmenu'. - * GUI/Motif support by Robert Webb - */ +// Code for menus. Used for the GUI and 'wildmenu'. +// GUI/Motif support by Robert Webb #include <assert.h> #include <inttypes.h> @@ -141,9 +139,7 @@ void ex_menu(exarg_T *eap) } pri_tab[MENUDEPTH] = -1; // mark end of the table - /* - * Check for "disable" or "enable" argument. - */ + // Check for "disable" or "enable" argument. if (STRNCMP(arg, "enable", 6) == 0 && ascii_iswhite(arg[6])) { enable = kTrue; arg = skipwhite(arg + 6); @@ -152,9 +148,7 @@ void ex_menu(exarg_T *eap) arg = skipwhite(arg + 7); } - /* - * If there is no argument, display all menus. - */ + // If there is no argument, display all menus. if (*arg == NUL) { show_menus(arg, modes); return; @@ -168,9 +162,7 @@ void ex_menu(exarg_T *eap) map_to = menu_translate_tab_and_shift(arg); - /* - * If there is only a menu name, display menus with that name. - */ + // If there is only a menu name, display menus with that name. if (*map_to == NUL && !unmenu && enable == kNone) { show_menus(menu_path, modes); goto theend; @@ -185,7 +177,7 @@ void ex_menu(exarg_T *eap) // Change sensitivity of the menu. // For the PopUp menu, remove a menu for each mode separately. // Careful: menu_enable_recurse() changes menu_path. - if (STRCMP(menu_path, "*") == 0) { // meaning: do all menus + if (strcmp(menu_path, "*") == 0) { // meaning: do all menus menu_path = ""; } @@ -200,16 +192,12 @@ void ex_menu(exarg_T *eap) } menu_enable_recurse(*root_menu_ptr, menu_path, modes, enable); } else if (unmenu) { - /* - * Delete menu(s). - */ - if (STRCMP(menu_path, "*") == 0) { // meaning: remove all menus + // Delete menu(s). + if (strcmp(menu_path, "*") == 0) { // meaning: remove all menus menu_path = ""; } - /* - * For the PopUp menu, remove a menu for each mode separately. - */ + // For the PopUp menu, remove a menu for each mode separately. if (menu_is_popup(menu_path)) { for (i = 0; i < MENU_INDEX_TIP; i++) { if (modes & (1 << i)) { @@ -223,10 +211,8 @@ void ex_menu(exarg_T *eap) // Careful: remove_menu() changes menu_path remove_menu(root_menu_ptr, menu_path, modes, false); } else { - /* - * Add menu(s). - * Replace special key codes. - */ + // Add menu(s). + // Replace special key codes. if (STRICMP(map_to, "<nop>") == 0) { // "<Nop>" means nothing map_to = ""; map_buf = NULL; @@ -234,7 +220,7 @@ void ex_menu(exarg_T *eap) map_buf = NULL; // Menu tips are plain text. } else { map_buf = NULL; - map_to = replace_termcodes(map_to, STRLEN(map_to), &map_buf, + map_to = replace_termcodes(map_to, strlen(map_to), &map_buf, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); } menuarg.modes = modes; @@ -242,9 +228,7 @@ void ex_menu(exarg_T *eap) menuarg.silent[0] = silent; add_menu_path(menu_path, &menuarg, pri_tab, map_to); - /* - * For the PopUp menu, add a menu for each mode separately. - */ + // For the PopUp menu, add a menu for each mode separately. if (menu_is_popup(menu_path)) { for (i = 0; i < MENU_INDEX_TIP; i++) { if (modes & (1 << i)) { @@ -302,7 +286,7 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const // Get name of this element in the menu hierarchy, and the simplified // name (without mnemonic and accelerator text). next_name = menu_name_skip(name); - map_to = menutrans_lookup(name, (int)STRLEN(name)); + map_to = menutrans_lookup(name, (int)strlen(name)); if (map_to != NULL) { en_name = name; name = map_to; @@ -384,11 +368,9 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const } else { old_modes = menu->modes; - /* - * If this menu option was previously only available in other - * modes, then make sure it's available for this one now - * Also enable a menu when it's created or changed. - */ + // If this menu option was previously only available in other + // modes, then make sure it's available for this one now + // Also enable a menu when it's created or changed. { menu->modes |= modes; menu->enabled |= modes; @@ -405,10 +387,8 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const } xfree(path_name); - /* - * Only add system menu items which have not been defined yet. - * First check if this was an ":amenu". - */ + // Only add system menu items which have not been defined yet. + // First check if this was an ":amenu". amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) == (MENU_NORMAL_MODE | MENU_INSERT_MODE)); if (sys_menu) { @@ -419,7 +399,7 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const p = (call_data == NULL) ? NULL : xstrdup(call_data); // loop over all modes, may add more than one - for (i = 0; i < MENU_MODES; ++i) { + for (i = 0; i < MENU_MODES; i++) { if (modes & (1 << i)) { // free any old menu free_menu_string(menu, i); @@ -444,7 +424,7 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const } if (c != 0) { - menu->strings[i] = xmalloc(STRLEN(call_data) + 5); + menu->strings[i] = xmalloc(strlen(call_data) + 5); menu->strings[i][0] = c; if (d == 0) { STRCPY(menu->strings[i] + 1, call_data); @@ -453,7 +433,7 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const STRCPY(menu->strings[i] + 2, call_data); } if (c == Ctrl_C) { - int len = (int)STRLEN(menu->strings[i]); + int len = (int)strlen(menu->strings[i]); menu->strings[i][len] = Ctrl_BSL; menu->strings[i][len + 1] = Ctrl_G; @@ -491,10 +471,8 @@ erret: return FAIL; } -/* - * Set the (sub)menu with the given name to enabled or disabled. - * Called recursively. - */ +// Set the (sub)menu with the given name to enabled or disabled. +// Called recursively. static int menu_enable_recurse(vimmenu_T *menu, char *name, int modes, int enable) { char *p; @@ -522,11 +500,9 @@ static int menu_enable_recurse(vimmenu_T *menu, char *name, int modes, int enabl menu->enabled &= ~modes; } - /* - * When name is empty, we are doing all menu items for the given - * modes, so keep looping, otherwise we are just doing the named - * menu item (which has been found) so break here. - */ + // When name is empty, we are doing all menu items for the given + // modes, so keep looping, otherwise we are just doing the named + // menu item (which has been found) so break here. if (*name != NUL && *name != '*') { break; } @@ -577,11 +553,9 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent) return FAIL; } - /* - * When name is empty, we are removing all menu items for the given - * modes, so keep looping, otherwise we are just removing the named - * menu item (which has been found) so break here. - */ + // When name is empty, we are removing all menu items for the given + // modes, so keep looping, otherwise we are just removing the named + // menu item (which has been found) so break here. if (*name != NUL) { break; } @@ -628,9 +602,7 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent) return OK; } -/* - * Free the given menu structure and remove it from the linked list. - */ +// Free the given menu structure and remove it from the linked list. static void free_menu(vimmenu_T **menup) { int i; @@ -652,9 +624,7 @@ static void free_menu(vimmenu_T **menup) xfree(menu); } -/* - * Free the menu->string with the given index. - */ +// Free the menu->string with the given index. static void free_menu_string(vimmenu_T *menu, int idx) { int count = 0; @@ -715,8 +685,7 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) if ((menu->modes & modes & (1 << bit)) != 0) { dict_T *impl = tv_dict_alloc(); tv_dict_add_allocated_str(impl, S_LEN("rhs"), - str2special_save(menu->strings[bit], - false, false)); + str2special_save(menu->strings[bit], false, false)); tv_dict_add_nr(impl, S_LEN("silent"), menu->silent[bit]); tv_dict_add_nr(impl, S_LEN("enabled"), (menu->enabled & (1 << bit)) ? 1 : 0); @@ -853,7 +822,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) msg_puts(" "); } // Same highlighting as for directories!? - msg_outtrans_attr((char_u *)menu->name, HL_ATTR(HLF_D)); + msg_outtrans_attr(menu->name, HL_ATTR(HLF_D)); } if (menu != NULL && menu->children == NULL) { @@ -888,7 +857,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) if (*menu->strings[bit] == NUL) { msg_puts_attr("<Nop>", HL_ATTR(HLF_8)); } else { - msg_outtrans_special((char_u *)menu->strings[bit], false, 0); + msg_outtrans_special(menu->strings[bit], false, 0); } } } @@ -909,16 +878,12 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) } } -/* - * Used when expanding menu names. - */ +// Used when expanding menu names. static vimmenu_T *expand_menu = NULL; static int expand_modes = 0x0; -static int expand_emenu; // TRUE for ":emenu" command +static int expand_emenu; // true for ":emenu" command -/* - * Work out what to complete when doing command line completion of menu names. - */ +// Work out what to complete when doing command line completion of menu names. char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool forceit) FUNC_ATTR_NONNULL_ALL { @@ -933,7 +898,7 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for xp->xp_context = EXPAND_UNSUCCESSFUL; // Check for priority numbers, enable and disable - for (p = arg; *p; ++p) { + for (p = arg; *p; p++) { if (!ascii_isdigit(*p) && *p != '.') { break; } @@ -957,7 +922,7 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for arg = after_dot = p; - for (; *p && !ascii_iswhite(*p); ++p) { + for (; *p && !ascii_iswhite(*p); p++) { if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL) { p++; } else if (*p == '.') { @@ -994,10 +959,8 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for // Found menu if ((*p != NUL && menu->children == NULL) || ((menu->modes & expand_modes) == 0x0)) { - /* - * Menu path continues, but we have reached a leaf. - * Or menu exists only in another mode. - */ + // Menu path continues, but we have reached a leaf. + // Or menu exists only in another mode. xfree(path_name); return NULL; } @@ -1024,10 +987,8 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for return NULL; } -/* - * Function given to ExpandGeneric() to obtain the list of (sub)menus (not - * entries). - */ +// Function given to ExpandGeneric() to obtain the list of (sub)menus (not +// entries). char *get_menu_name(expand_T *xp, int idx) { static vimmenu_T *menu = NULL; @@ -1056,7 +1017,7 @@ char *get_menu_name(expand_T *xp, int idx) } else { str = menu->dname; if (menu->en_dname == NULL) { - should_advance = TRUE; + should_advance = true; } } } else { @@ -1073,10 +1034,8 @@ char *get_menu_name(expand_T *xp, int idx) return str; } -/* - * Function given to ExpandGeneric() to obtain the list of menus and menu - * entries. - */ +// Function given to ExpandGeneric() to obtain the list of menus and menu +// entries. char *get_menu_names(expand_T *xp, int idx) { static vimmenu_T *menu = NULL; @@ -1094,7 +1053,7 @@ char *get_menu_names(expand_T *xp, int idx) while (menu != NULL && (menu_is_hidden(menu->dname) || (expand_emenu && menu_is_separator(menu->dname)) - || menu->dname[STRLEN(menu->dname) - 1] == '.')) { + || menu->dname[strlen(menu->dname) - 1] == '.')) { menu = menu->next; } @@ -1163,10 +1122,8 @@ char *menu_name_skip(char *const name) return p; } -/* - * Return TRUE when "name" matches with menu "menu". The name is compared in - * two ways: raw menu name and menu name without '&'. ignore part after a TAB. - */ +/// Return true when "name" matches with menu "menu". The name is compared in +/// two ways: raw menu name and menu name without '&'. ignore part after a TAB. static bool menu_name_equal(const char *const name, const vimmenu_T *const menu) { if (menu->en_name != NULL @@ -1181,7 +1138,7 @@ static bool menu_namecmp(const char *const name, const char *const mname) { int i; - for (i = 0; name[i] != NUL && name[i] != TAB; ++i) { + for (i = 0; name[i] != NUL && name[i] != TAB; i++) { if (name[i] != mname[i]) { break; } @@ -1314,13 +1271,11 @@ static char *get_menu_mode_str(int modes) return ""; } -/* - * Modify a menu name starting with "PopUp" to include the mode character. - * Returns the name in allocated memory. - */ +// Modify a menu name starting with "PopUp" to include the mode character. +// Returns the name in allocated memory. static char *popup_mode_name(char *name, int idx) { - size_t len = STRLEN(name); + size_t len = strlen(name); assert(len >= 4); char *mode_chars = menu_mode_chars[idx]; @@ -1405,13 +1360,11 @@ bool menu_is_toolbar(const char *const name) return STRNCMP(name, "ToolBar", 7) == 0; } -/* - * Return TRUE if the name is a menu separator identifier: Starts and ends - * with '-' - */ +/// Return true if the name is a menu separator identifier: Starts and ends +/// with '-' int menu_is_separator(char *name) { - return name[0] == '-' && name[STRLEN(name) - 1] == '-'; + return name[0] == '-' && name[strlen(name) - 1] == '-'; } /// True if a popup menu or starts with \ref MNU_HIDDEN_CHAR @@ -1734,9 +1687,7 @@ theend: return menu; } -/* - * Translation of menu names. Just a simple lookup table. - */ +// Translation of menu names. Just a simple lookup table. typedef struct { char *from; // English name @@ -1752,11 +1703,9 @@ static garray_T menutrans_ga = GA_EMPTY_INIT_VALUE; xfree(_mt->from_noamp); \ xfree(_mt->to) -/* - * ":menutrans". - * This function is also defined without the +multi_lang feature, in which - * case the commands are ignored. - */ +// ":menutrans". +// This function is also defined without the +multi_lang feature, in which +// case the commands are ignored. void ex_menutranslate(exarg_T *eap) { char *arg = eap->arg; @@ -1766,9 +1715,7 @@ void ex_menutranslate(exarg_T *eap) ga_init(&menutrans_ga, (int)sizeof(menutrans_T), 5); } - /* - * ":menutrans clear": clear all translations. - */ + // ":menutrans clear": clear all translations. if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) { GA_DEEP_CLEAR(&menutrans_ga, menutrans_T, FREE_MENUTRANS); @@ -1800,9 +1747,7 @@ void ex_menutranslate(exarg_T *eap) } } -/* - * Find the character just after one part of a menu name. - */ +// Find the character just after one part of a menu name. static char *menu_skip_part(char *p) { while (*p != NUL && *p != '.' && !ascii_iswhite(*p)) { @@ -1814,10 +1759,8 @@ static char *menu_skip_part(char *p) return p; } -/* - * Lookup part of a menu name in the translations. - * Return a pointer to the translation or NULL if not found. - */ +// Lookup part of a menu name in the translations. +// Return a pointer to the translation or NULL if not found. static char *menutrans_lookup(char *name, int len) { menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data; @@ -1845,9 +1788,7 @@ static char *menutrans_lookup(char *name, int len) return NULL; } -/* - * Unescape the name in the translate dictionary table. - */ +// Unescape the name in the translate dictionary table. static void menu_unescape_name(char *name) { char *p; @@ -1859,10 +1800,8 @@ static void menu_unescape_name(char *name) } } -/* - * Isolate the menu name. - * Skip the menu name, and translate <Tab> into a real TAB. - */ +// Isolate the menu name. +// Skip the menu name, and translate <Tab> into a real TAB. static char *menu_translate_tab_and_shift(char *arg_start) { char *arg = arg_start; @@ -1945,7 +1884,7 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m /// "menu_info()" function /// Return information about a menu (including all the child menus) -void f_menu_info(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_menu_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { tv_dict_alloc_ret(rettv); dict_T *const retdict = rettv->vval.v_dict; diff --git a/src/nvim/message.c b/src/nvim/message.c index 684cf7207c..a90e675423 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * message.c: functions for displaying messages on the command line - */ +// message.c: functions for displaying messages on the command line #include <assert.h> #include <inttypes.h> @@ -48,75 +46,71 @@ #include "nvim/ui_compositor.h" #include "nvim/vim.h" -/* - * To be able to scroll back at the "more" and "hit-enter" prompts we need to - * store the displayed text and remember where screen lines start. - */ +// To be able to scroll back at the "more" and "hit-enter" prompts we need to +// store the displayed text and remember where screen lines start. typedef struct msgchunk_S msgchunk_T; struct msgchunk_S { msgchunk_T *sb_next; msgchunk_T *sb_prev; - char sb_eol; // TRUE when line ends after this text + char sb_eol; // true when line ends after this text int sb_msg_col; // column in which text starts int sb_attr; // text attributes - char_u sb_text[1]; // text to be displayed, actually longer + char sb_text[1]; // text to be displayed, actually longer }; // Magic chars used in confirm dialog strings #define DLG_BUTTON_SEP '\n' #define DLG_HOTKEY_CHAR '&' -static int confirm_msg_used = FALSE; // displaying confirm_msg +static int confirm_msg_used = false; // displaying confirm_msg #ifdef INCLUDE_GENERATED_DECLARATIONS # include "message.c.generated.h" #endif -static char_u *confirm_msg = NULL; // ":confirm" message -static char_u *confirm_msg_tail; // tail of confirm_msg +static char *confirm_msg = NULL; // ":confirm" message +static char *confirm_msg_tail; // tail of confirm_msg MessageHistoryEntry *first_msg_hist = NULL; MessageHistoryEntry *last_msg_hist = NULL; static int msg_hist_len = 0; static FILE *verbose_fd = NULL; -static int verbose_did_open = FALSE; +static int verbose_did_open = false; bool keep_msg_more = false; // keep_msg was set by msgmore() -/* - * When writing messages to the screen, there are many different situations. - * A number of variables is used to remember the current state: - * msg_didany true when messages were written since the last time the - * user reacted to a prompt. - * Reset: After hitting a key for the hit-return prompt, - * hitting <CR> for the command line or input(). - * Set: When any message is written to the screen. - * msg_didout true when something was written to the current line. - * Reset: When advancing to the next line, when the current - * text can be overwritten. - * Set: When any message is written to the screen. - * msg_nowait No extra delay for the last drawn message. - * Used in normal_cmd() before the mode message is drawn. - * emsg_on_display There was an error message recently. Indicates that there - * should be a delay before redrawing. - * msg_scroll The next message should not overwrite the current one. - * msg_scrolled How many lines the screen has been scrolled (because of - * messages). Used in update_screen() to scroll the screen - * back. Incremented each time the screen scrolls a line. - * msg_scrolled_ign TRUE when msg_scrolled is non-zero and msg_puts_attr() - * writes something without scrolling should not make - * need_wait_return to be set. This is a hack to make ":ts" - * work without an extra prompt. - * lines_left Number of lines available for messages before the - * more-prompt is to be given. -1 when not set. - * need_wait_return true when the hit-return prompt is needed. - * Reset: After giving the hit-return prompt, when the user - * has answered some other prompt. - * Set: When the ruler or typeahead display is overwritten, - * scrolling the screen for some message. - * keep_msg Message to be displayed after redrawing the screen, in - * main_loop(). - * This is an allocated string or NULL when not used. - */ +// When writing messages to the screen, there are many different situations. +// A number of variables is used to remember the current state: +// msg_didany true when messages were written since the last time the +// user reacted to a prompt. +// Reset: After hitting a key for the hit-return prompt, +// hitting <CR> for the command line or input(). +// Set: When any message is written to the screen. +// msg_didout true when something was written to the current line. +// Reset: When advancing to the next line, when the current +// text can be overwritten. +// Set: When any message is written to the screen. +// msg_nowait No extra delay for the last drawn message. +// Used in normal_cmd() before the mode message is drawn. +// emsg_on_display There was an error message recently. Indicates that there +// should be a delay before redrawing. +// msg_scroll The next message should not overwrite the current one. +// msg_scrolled How many lines the screen has been scrolled (because of +// messages). Used in update_screen() to scroll the screen +// back. Incremented each time the screen scrolls a line. +// msg_scrolled_ign true when msg_scrolled is non-zero and msg_puts_attr() +// writes something without scrolling should not make +// need_wait_return to be set. This is a hack to make ":ts" +// work without an extra prompt. +// lines_left Number of lines available for messages before the +// more-prompt is to be given. -1 when not set. +// need_wait_return true when the hit-return prompt is needed. +// Reset: After giving the hit-return prompt, when the user +// has answered some other prompt. +// Set: When the ruler or typeahead display is overwritten, +// scrolling the screen for some message. +// keep_msg Message to be displayed after redrawing the screen, in +// main_loop(). +// This is an allocated string or NULL when not used. // Extended msg state, currently used for external UIs with ext_messages static const char *msg_ext_kind = NULL; @@ -159,8 +153,7 @@ void msg_grid_set_pos(int row, bool scrolled) bool msg_use_grid(void) { - return default_grid.chars && msg_use_msgsep() - && !ui_has(kUIMessages); + return default_grid.chars && !ui_has(kUIMessages); } void msg_grid_validate(void) @@ -178,19 +171,17 @@ void msg_grid_validate(void) xfree(msg_grid.dirty_col); msg_grid.dirty_col = xcalloc((size_t)Rows, sizeof(*msg_grid.dirty_col)); - // Tricky: allow resize while pager is active - int pos = msg_scrolled ? msg_grid_pos : max_rows; + // Tricky: allow resize while pager or ex mode is active + int pos = MAX(max_rows - msg_scrolled, 0); + msg_grid.throttled = false; // don't throttle in 'cmdheight' area + msg_grid_set_pos(pos, msg_scrolled); ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols, false, true); ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows); - msg_grid.throttled = false; // don't throttle in 'cmdheight' area msg_scrolled_at_flush = msg_scrolled; msg_grid.focusable = false; msg_grid_adj.target = &msg_grid; - if (!msg_scrolled) { - msg_grid_set_pos(max_rows, false); - } } else if (!should_alloc && msg_grid.chars) { ui_comp_remove_grid(&msg_grid); grid_free(&msg_grid); @@ -215,7 +206,7 @@ void msg_grid_validate(void) /// Displays the string 's' on the status line /// When terminal not initialized (yet) mch_errmsg(..) is used. /// -/// @return TRUE if wait_return not called +/// @return true if wait_return() not called int msg(char *s) { return msg_attr_keep(s, 0, false, false); @@ -251,7 +242,7 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea if (next_spec != NULL) { // Printing all char that are before the char found by strpbrk - msg_outtrans_len_attr((const char_u *)s, (int)(next_spec - s), attr); + msg_outtrans_len_attr(s, (int)(next_spec - s), attr); if (*next_spec != TAB && *need_clear) { msg_clr_eos(); @@ -265,7 +256,7 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea // Print the rest of the message. We know there is no special // character because strpbrk returned NULL if (*s != NUL) { - msg_outtrans_attr((char_u *)s, attr); + msg_outtrans_attr(s, attr); } } @@ -275,12 +266,12 @@ void msg_multiattr(HlMessage hl_msg, const char *kind, bool history) msg_start(); msg_clr_eos(); bool need_clear = false; + msg_ext_set_kind(kind); for (uint32_t i = 0; i < kv_size(hl_msg); i++) { HlMessageChunk chunk = kv_A(hl_msg, i); msg_multiline_attr((const char *)chunk.text.data, chunk.attr, true, &need_clear); } - msg_ext_set_kind(kind); if (history && kv_size(hl_msg)) { add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg); } @@ -294,7 +285,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) { static int entered = 0; int retval; - char_u *buf = NULL; + char *buf = NULL; if (keep && multiline) { // Not implemented. 'multiline' is only used by nvim-added messages, @@ -305,7 +296,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) // Skip messages not match ":filter pattern". // Don't filter when there is an error. - if (!emsg_on_display && message_filtered((char_u *)s)) { + if (!emsg_on_display && message_filtered((char *)s)) { return true; } @@ -313,38 +304,36 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) set_vim_var_string(VV_STATUSMSG, s, -1); } - /* - * It is possible that displaying a messages causes a problem (e.g., - * when redrawing the window), which causes another message, etc.. To - * break this loop, limit the recursiveness to 3 levels. - */ + // It is possible that displaying a messages causes a problem (e.g., + // when redrawing the window), which causes another message, etc.. To + // break this loop, limit the recursiveness to 3 levels. if (entered >= 3) { - return TRUE; + return true; } entered++; // Add message to history (unless it's a repeated kept message or a // truncated message) - if ((const char_u *)s != keep_msg + if (s != keep_msg || (*s != '<' && last_msg_hist != NULL && last_msg_hist->msg != NULL - && STRCMP(s, last_msg_hist->msg))) { + && strcmp(s, last_msg_hist->msg))) { add_msg_hist(s, -1, attr, multiline); } // Truncate the message if needed. msg_start(); - buf = msg_strtrunc((char_u *)s, FALSE); + buf = msg_strtrunc((char *)s, false); if (buf != NULL) { - s = (const char *)buf; + s = buf; } bool need_clear = true; if (multiline) { msg_multiline_attr(s, attr, false, &need_clear); } else { - msg_outtrans_attr((char_u *)s, attr); + msg_outtrans_attr(s, attr); } if (need_clear) { msg_clr_eos(); @@ -367,9 +356,9 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) /// @return an allocated string or NULL when no truncating is done. /// /// @param force always truncate -char_u *msg_strtrunc(char_u *s, int force) +char *msg_strtrunc(char *s, int force) { - char_u *buf = NULL; + char *buf = NULL; int len; int room; @@ -377,7 +366,7 @@ char_u *msg_strtrunc(char_u *s, int force) if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL) && !exmode_active && msg_silent == 0 && !ui_has(kUIMessages)) || force) { - len = vim_strsize((char *)s); + len = vim_strsize(s); if (msg_scrolled != 0) { // Use all the columns. room = (Rows - msg_row) * Columns - 1; @@ -390,7 +379,7 @@ char_u *msg_strtrunc(char_u *s, int force) // composing chars) len = (room + 2) * 18; buf = xmalloc((size_t)len); - trunc_string((char *)s, (char *)buf, room, len); + trunc_string(s, buf, room, len); } } return buf; @@ -420,7 +409,7 @@ void trunc_string(char *s, char *buf, int room_in, int buflen) half = room / 2; // First part: Start of the string. - for (e = 0; len < half && e < buflen; ++e) { + for (e = 0; len < half && e < buflen; e++) { if (s[e] == NUL) { // text fits without truncating! buf[e] = NUL; @@ -441,10 +430,10 @@ void trunc_string(char *s, char *buf, int room_in, int buflen) } // Last part: End of the string. - half = i = (int)STRLEN(s); + half = i = (int)strlen(s); for (;;) { do { - half = half - utf_head_off((char_u *)s, (char_u *)s + half - 1) - 1; + half = half - utf_head_off(s, s + half - 1) - 1; } while (half > 0 && utf_iscomposing(utf_ptr2char(s + half))); n = ptr2cells(s + half); if (len + n > room || half == 0) { @@ -457,7 +446,7 @@ void trunc_string(char *s, char *buf, int room_in, int buflen) if (i <= e + 3) { // text fits without truncating if (s != buf) { - len = (int)STRLEN(s); + len = (int)strlen(s); if (len >= buflen) { len = buflen - 1; } @@ -471,7 +460,7 @@ void trunc_string(char *s, char *buf, int room_in, int buflen) } else if (e + 3 < buflen) { // set the middle and copy the last part memmove(buf + e, "...", (size_t)3); - len = (int)STRLEN(s + i) + 1; + len = (int)strlen(s + i) + 1; if (len >= buflen - e - 3) { len = buflen - e - 3 - 1; } @@ -483,10 +472,8 @@ void trunc_string(char *s, char *buf, int room_in, int buflen) } } -/* - * Note: Caller of smsg() and smsg_attr() must check the resulting string is - * shorter than IOSIZE!!! - */ +// Note: Caller of smsg() and smsg_attr() must check the resulting string is +// shorter than IOSIZE!!! int smsg(const char *s, ...) FUNC_ATTR_PRINTF(1, 2) @@ -522,10 +509,8 @@ int smsg_attr_keep(int attr, const char *s, ...) return msg_attr_keep((const char *)IObuff, attr, true, false); } -/* - * Remember the last sourcing name/lnum used in an error message, so that it - * isn't printed each time when it didn't change. - */ +// Remember the last sourcing name/lnum used in an error message, so that it +// isn't printed each time when it didn't change. static int last_sourcing_lnum = 0; static char *last_sourcing_name = NULL; @@ -565,7 +550,7 @@ static char *get_emsg_source(void) } const char *const p = _("Error detected while processing %s:"); - const size_t buf_len = STRLEN(sname) + strlen(p) + 1; + const size_t buf_len = strlen(sname) + strlen(p) + 1; char *const buf = xmalloc(buf_len); snprintf(buf, buf_len, p, sname); xfree(tofree); @@ -608,10 +593,10 @@ void msg_source(int attr) } recursive = true; - msg_scroll = true; // this will take more than one line no_wait_return++; char *p = get_emsg_source(); if (p != NULL) { + msg_scroll = true; // this will take more than one line msg_attr(p, attr); xfree(p); } @@ -634,18 +619,18 @@ void msg_source(int attr) recursive = false; } -/// @return TRUE if not giving error messages right now: +/// @return true if not giving error messages right now: /// If "emsg_off" is set: no error messages at the moment. /// If "msg" is in 'debug': do error message but without side effects. /// If "emsg_skip" is set: never do error messages. int emsg_not_now(void) { - if ((emsg_off > 0 && vim_strchr((char *)p_debug, 'm') == NULL - && vim_strchr((char *)p_debug, 't') == NULL) + if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL + && vim_strchr(p_debug, 't') == NULL) || emsg_skip > 0) { - return TRUE; + return true; } - return FALSE; + return false; } static bool emsg_multiline(const char *s, bool multiline) @@ -665,7 +650,7 @@ static bool emsg_multiline(const char *s, bool multiline) bool severe = emsg_severe; emsg_severe = false; - if (!emsg_off || vim_strchr((char *)p_debug, 't') != NULL) { + if (!emsg_off || vim_strchr(p_debug, 't') != NULL) { // Cause a throw of an error exception if appropriate. Don't display // the error message in this case. (If no matching catch clause will // be found, the message will be displayed later on.) "ignore" is set @@ -673,7 +658,7 @@ static bool emsg_multiline(const char *s, bool multiline) // interrupt message). if (cause_errthrow(s, severe, &ignore)) { if (!ignore) { - did_emsg = true; + did_emsg++; } return true; } @@ -681,10 +666,8 @@ static bool emsg_multiline(const char *s, bool multiline) // set "v:errmsg", also when using ":silent! cmd" set_vim_var_string(VV_ERRMSG, s, -1); - /* - * When using ":silent! cmd" ignore error messages. - * But do write it to the redirection file. - */ + // When using ":silent! cmd" ignore error messages. + // But do write it to the redirection file. if (emsg_silent != 0) { if (!emsg_noredir) { msg_start(); @@ -738,14 +721,14 @@ static bool emsg_multiline(const char *s, bool multiline) } else { flush_buffers(FLUSH_MINIMAL); // flush internal buffers } - did_emsg = true; // flag for DoOneCmd() + did_emsg++; // flag for DoOneCmd() } emsg_on_display = true; // remember there is an error message attr = HL_ATTR(HLF_E); // set highlight mode for error messages if (msg_scrolled != 0) { need_wait_return = true; // needed in case emsg() is called after - } // wait_return has reset need_wait_return + } // wait_return() has reset need_wait_return // and a redraw is expected because // msg_scrolled is non-zero if (msg_ext_kind == NULL) { @@ -753,7 +736,7 @@ static bool emsg_multiline(const char *s, bool multiline) } // Display name and line number for the source of the error. - // Sets "msg_scroll". + msg_scroll = true; msg_source(attr); // Display the error message itself. @@ -766,7 +749,7 @@ static bool emsg_multiline(const char *s, bool multiline) /// Rings the bell, if appropriate, and calls message() to do the real work /// When terminal not initialized (yet) mch_errmsg(..) is used. /// -/// @return true if wait_return not called +/// @return true if wait_return() not called bool emsg(const char *s) { return emsg_multiline(s, false); @@ -900,7 +883,7 @@ char *msg_trunc_attr(char *s, bool force, int attr) // Add message to history before truncating. add_msg_hist(s, -1, attr, false); - char *ts = (char *)msg_may_trunc(force, (char_u *)s); + char *ts = msg_may_trunc(force, s); msg_hist_off = true; n = msg_attr(ts, attr); @@ -917,14 +900,14 @@ char *msg_trunc_attr(char *s, bool force, int attr) /// @return a pointer to where the truncated message starts. /// /// @note: May change the message by replacing a character with '<'. -char_u *msg_may_trunc(bool force, char_u *s) +char *msg_may_trunc(bool force, char *s) { int room; room = (Rows - cmdline_row - 1) * Columns + sc_col - 1; if ((force || (shortmess(SHM_TRUNC) && !exmode_active)) - && (int)STRLEN(s) - room > 0 && p_ch > 0) { - int size = vim_strsize((char *)s); + && (int)STRLEN(s) - room > 0) { + int size = vim_strsize(s); // There may be room anyway when there are multibyte chars. if (size <= room) { @@ -932,8 +915,8 @@ char_u *msg_may_trunc(bool force, char_u *s) } int n; for (n = 0; size >= room;) { - size -= utf_ptr2cells((char *)s + n); - n += utfc_ptr2len((char *)s + n); + size -= utf_ptr2cells(s + n); + n += utfc_ptr2len(s + n); } n--; s += n; @@ -950,15 +933,6 @@ void hl_msg_free(HlMessage hl_msg) kv_destroy(hl_msg); } -#define LINE_BUFFER_SIZE 4096 - -void add_hl_msg_hist(HlMessage hl_msg) -{ - if (kv_size(hl_msg)) { - add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg); - } -} - /// @param[in] len Length of s or -1. static void add_msg_hist(const char *s, int len, int attr, bool multiline) { @@ -982,7 +956,7 @@ static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multil struct msg_hist *p = xmalloc(sizeof(struct msg_hist)); if (s) { if (len < 0) { - len = (int)STRLEN(s); + len = (int)strlen(s); } // remove leading and trailing newlines while (len > 0 && *s == '\n') { @@ -992,7 +966,7 @@ static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multil while (len > 0 && s[len - 1] == '\n') { len--; } - p->msg = (char_u *)xmemdupz(s, (size_t)len); + p->msg = xmemdupz(s, (size_t)len); } else { p->msg = NULL; } @@ -1042,7 +1016,7 @@ void ex_messages(void *const eap_p) struct msg_hist *p; int c = 0; - if (STRCMP(eap->arg, "clear") == 0) { + if (strcmp(eap->arg, "clear") == 0) { int keep = eap->addr_count == 0 ? 0 : eap->line2; while (msg_hist_len > keep) { @@ -1086,7 +1060,7 @@ void ex_messages(void *const eap_p) HlMessageChunk chunk = kv_A(p->multiattr, i); Array content_entry = ARRAY_DICT_INIT; ADD(content_entry, INTEGER_OBJ(chunk.attr)); - ADD(content_entry, STRING_OBJ(copy_string(chunk.text))); + ADD(content_entry, STRING_OBJ(copy_string(chunk.text, NULL))); ADD(content, ARRAY_OBJ(content_entry)); } } else if (p->msg && p->msg[0]) { @@ -1109,7 +1083,7 @@ void ex_messages(void *const eap_p) if (kv_size(p->multiattr)) { msg_multiattr(p->multiattr, p->kind, false); } else if (p->msg != NULL) { - msg_attr_keep((char *)p->msg, p->attr, false, p->multiline); + msg_attr_keep(p->msg, p->attr, false, p->multiline); } } msg_hist_off = false; @@ -1131,7 +1105,7 @@ void msg_end_prompt(void) /// Wait for the user to hit a key (normally Enter) /// -/// @param redraw if true, redraw the entire screen NOT_VALID +/// @param redraw if true, redraw the entire screen UPD_NOT_VALID /// if false, do a normal redraw /// if -1, don't redraw at all void wait_return(int redraw) @@ -1143,7 +1117,7 @@ void wait_return(int redraw) FILE *save_scriptout; if (redraw == true) { - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } // If using ":silent cmd", don't wait for a return. Also don't set @@ -1156,12 +1130,10 @@ void wait_return(int redraw) return; } - /* - * When inside vgetc(), we can't wait for a typed character at all. - * With the global command (and some others) we only need one return at - * the end. Adjust cmdline_row to avoid the next message overwriting the - * last one. - */ + // When inside vgetc(), we can't wait for a typed character at all. + // With the global command (and some others) we only need one return at + // the end. Adjust cmdline_row to avoid the next message overwriting the + // last one. if (vgetc_busy > 0) { return; } @@ -1177,17 +1149,13 @@ void wait_return(int redraw) oldState = State; if (quit_more) { c = CAR; // just pretend CR was hit - quit_more = FALSE; - got_int = FALSE; + quit_more = false; + got_int = false; } else if (exmode_active) { msg_puts(" "); // make sure the cursor is on the right line c = CAR; // no need for a return in ex mode - got_int = FALSE; + got_int = false; } else { - // Make sure the hit-return prompt is on screen when 'guioptions' was - // just changed. - screenalloc(); - State = MODE_HITRETURN; setmouse(); cmdline_row = msg_row; @@ -1226,12 +1194,10 @@ void wait_return(int redraw) reg_recording = save_reg_recording; scriptout = save_scriptout; - /* - * Allow scrolling back in the messages. - * Also accept scroll-down commands when messages fill the screen, - * to avoid that typing one 'j' too many makes the messages - * disappear. - */ + // Allow scrolling back in the messages. + // Also accept scroll-down commands when messages fill the screen, + // to avoid that typing one 'j' too many makes the messages + // disappear. if (p_more) { if (c == 'b' || c == 'k' || c == 'u' || c == 'g' || c == K_UP || c == K_PAGEUP) { @@ -1247,8 +1213,8 @@ void wait_return(int redraw) } if (quit_more) { c = CAR; // just pretend CR was hit - quit_more = FALSE; - got_int = FALSE; + quit_more = false; + got_int = false; } else if (c != K_IGNORE) { c = K_IGNORE; hit_return_msg(); @@ -1268,9 +1234,7 @@ void wait_return(int redraw) || c == K_MOUSEDOWN || c == K_MOUSEUP || c == K_MOUSEMOVE); os_breakcheck(); - /* - * Avoid that the mouse-up event causes visual mode to start. - */ + // Avoid that the mouse-up event causes visual mode to start. if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE || c == K_X1MOUSE || c == K_X2MOUSE) { (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0); @@ -1307,7 +1271,7 @@ void wait_return(int redraw) emsg_on_display = false; // can delete error message now lines_left = -1; // reset lines_left at next msg_start() reset_last_sourcing(); - if (keep_msg != NULL && vim_strsize((char *)keep_msg) >= + if (keep_msg != NULL && vim_strsize(keep_msg) >= (Rows - cmdline_row - 1) * Columns + sc_col) { XFREE_CLEAR(keep_msg); // don't redisplay message, it's too long } @@ -1316,7 +1280,7 @@ void wait_return(int redraw) ui_refresh(); } else if (!skip_redraw) { if (redraw == true || (msg_scrolled != 0 && redraw != -1)) { - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } if (ui_has(kUIMessages)) { msg_ext_clear(true); @@ -1350,7 +1314,7 @@ void set_keep_msg(char *s, int attr) { xfree(keep_msg); if (s != NULL && msg_silent == 0) { - keep_msg = vim_strsave((char_u *)s); + keep_msg = xstrdup(s); } else { keep_msg = NULL; } @@ -1421,22 +1385,25 @@ void msg_start(void) need_fileinfo = false; } - const bool no_msg_area = !ui_has_messages(); - - if (need_clr_eos || (no_msg_area && redrawing_cmdline)) { + if (need_clr_eos || (p_ch == 0 && redrawing_cmdline)) { // Halfway an ":echo" command and getting an (error) message: clear // any text from the command. need_clr_eos = false; msg_clr_eos(); } + // if cmdheight=0, we need to scroll in the first line of msg_grid upon the screen + if (p_ch == 0 && !ui_has(kUIMessages) && !msg_scrolled) { + msg_grid_validate(); + msg_scroll_up(false, true); + msg_scrolled++; + cmdline_row = Rows - 1; + } + if (!msg_scroll && full_screen) { // overwrite last message msg_row = cmdline_row; msg_col = cmdmsg_rl ? Columns - 1 : 0; - if (no_msg_area && get_cmdprompt() == NULL) { - msg_row -= 1; - } - } else if (msg_didout || no_msg_area) { // start message on next line + } else if (msg_didout || (p_ch == 0 && !ui_has(kUIMessages))) { // start message on next line msg_putchar('\n'); did_return = true; cmdline_row = msg_row; @@ -1497,20 +1464,20 @@ void msg_outnum(long n) msg_puts(buf); } -void msg_home_replace(char_u *fname) +void msg_home_replace(char *fname) { msg_home_replace_attr(fname, 0); } -void msg_home_replace_hl(char_u *fname) +void msg_home_replace_hl(char *fname) { msg_home_replace_attr(fname, HL_ATTR(HLF_D)); } -static void msg_home_replace_attr(char_u *fname, int attr) +static void msg_home_replace_attr(char *fname, int attr) { - char *name = home_replace_save(NULL, (char *)fname); - msg_outtrans_attr((char_u *)name, attr); + char *name = home_replace_save(NULL, fname); + msg_outtrans_attr(name, attr); xfree(name); } @@ -1521,15 +1488,15 @@ static void msg_home_replace_attr(char_u *fname, int attr) /// @return the number of characters it takes on the screen. int msg_outtrans(char *str) { - return msg_outtrans_attr((char_u *)str, 0); + return msg_outtrans_attr(str, 0); } -int msg_outtrans_attr(const char_u *str, int attr) +int msg_outtrans_attr(const char *str, int attr) { - return msg_outtrans_len_attr(str, (int)STRLEN(str), attr); + return msg_outtrans_len_attr(str, (int)strlen(str), attr); } -int msg_outtrans_len(const char_u *str, int len) +int msg_outtrans_len(const char *str, int len) { return msg_outtrans_len_attr(str, len, 0); } @@ -1538,11 +1505,11 @@ int msg_outtrans_len(const char_u *str, int len) /// Handles multi-byte characters. /// /// @return pointer to the next character. -char_u *msg_outtrans_one(char_u *p, int attr) +char *msg_outtrans_one(char *p, int attr) { int l; - if ((l = utfc_ptr2len((char *)p)) > 1) { + if ((l = utfc_ptr2len(p)) > 1) { msg_outtrans_len_attr(p, l, attr); return p + l; } @@ -1550,12 +1517,12 @@ char_u *msg_outtrans_one(char_u *p, int attr) return p + 1; } -int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr) +int msg_outtrans_len_attr(const char *msgstr, int len, int attr) { int retval = 0; - const char *str = (const char *)msgstr; - const char *plain_start = (const char *)msgstr; - char_u *s; + const char *str = msgstr; + const char *plain_start = msgstr; + char *s; int mb_l; int c; int save_got_int = got_int; @@ -1575,13 +1542,11 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr) msg_puts_attr(" ", attr); } - /* - * Go over the string. Special characters are translated and printed. - * Normal characters are printed several at a time. - */ + // Go over the string. Special characters are translated and printed. + // Normal characters are printed several at a time. while (--len >= 0 && !got_int) { // Don't include composing chars after the end. - mb_l = utfc_ptr2len_len((char_u *)str, len + 1); + mb_l = utfc_ptr2len_len(str, len + 1); if (mb_l > 1) { c = utf_ptr2char(str); if (vim_isprintc(c)) { @@ -1601,7 +1566,7 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr) len -= mb_l - 1; str += mb_l; } else { - s = transchar_byte((uint8_t)(*str)); + s = (char *)transchar_byte((uint8_t)(*str)); if (s[1] != NUL) { // Unprintable char: print the printable chars so far and the // translation of the unprintable char. @@ -1610,7 +1575,7 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr) } plain_start = str + 1; msg_puts_attr((const char *)s, attr == 0 ? HL_ATTR(HLF_8) : attr); - retval += (int)STRLEN(s); + retval += (int)strlen(s); } else { retval++; } @@ -1628,12 +1593,13 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr) return retval; } -void msg_make(char_u *arg) +void msg_make(char *arg) { int i; - static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB"; + static char *str = "eeffoc"; + static char *rs = "Plon#dqg#vxjduB"; - arg = (char_u *)skipwhite((char *)arg); + arg = skipwhite(arg); for (i = 5; *arg && i >= 0; i--) { if (*arg++ != str[i]) { break; @@ -1641,7 +1607,7 @@ void msg_make(char_u *arg) } if (i < 0) { msg_putchar('\n'); - for (i = 0; rs[i]; ++i) { + for (i = 0; rs[i]; i++) { msg_putchar(rs[i] - 3); } } @@ -1653,7 +1619,7 @@ void msg_make(char_u *arg) /// If K_SPECIAL is encountered, then it is taken in conjunction with the /// following character and shown as <F1>, <S-Up> etc. Any other character /// which is not printable shown in <> form. -/// If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. +/// If 'from' is true (lhs of a mapping), a space is shown as <Space>. /// If a character is displayed in one of these special ways, is also /// highlighted (its highlight name is '8' in the p_hl variable). /// Otherwise characters are not highlighted. @@ -1662,12 +1628,12 @@ void msg_make(char_u *arg) /// /// @param from true for LHS of a mapping /// @param maxlen screen columns, 0 for unlimited -int msg_outtrans_special(const char_u *strstart, bool from, int maxlen) +int msg_outtrans_special(const char *strstart, bool from, int maxlen) { if (strstart == NULL) { return 0; // Do nothing. } - const char_u *str = strstart; + const char *str = strstart; int retval = 0; int attr = HL_ATTR(HLF_8); @@ -1678,7 +1644,7 @@ int msg_outtrans_special(const char_u *strstart, bool from, int maxlen) text = "<Space>"; str++; } else { - text = str2special((const char **)&str, from, false); + text = str2special(&str, from, false); } if (text[0] != NUL && text[1] == NUL) { // single-byte character or illegal byte @@ -1702,8 +1668,8 @@ int msg_outtrans_special(const char_u *strstart, bool from, int maxlen) /// Used for lhs or rhs of mappings. /// /// @param[in] str String to convert. -/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used fo -/// lhs, but not rhs. +/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used for +/// lhs of mapping and keytrans(), but not rhs. /// @param[in] replace_lt Convert `<` into `<lt>`. /// /// @return [allocated] Converted string. @@ -1725,8 +1691,8 @@ char *str2special_save(const char *const str, const bool replace_spaces, const b /// Convert character, replacing key with printable representation. /// /// @param[in,out] sp String to convert. Is advanced to the next key code. -/// @param[in] replace_spaces Convert spaces into <Space>, normally used for -/// lhs, but not rhs. +/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used for +/// lhs of mapping and keytrans(), but not rhs. /// @param[in] replace_lt Convert `<` into `<lt>`. /// /// @return Converted key code, in a static buffer. Buffer is always one and the @@ -1817,20 +1783,20 @@ void str2specialbuf(const char *sp, char *buf, size_t len) } /// print line for :print or :list command -void msg_prt_line(char_u *s, int list) +void msg_prt_line(char *s, int list) { int c; int col = 0; int n_extra = 0; int c_extra = 0; int c_final = 0; - char_u *p_extra = NULL; // init to make SASC shut up + char *p_extra = NULL; // init to make SASC shut up int n; int attr = 0; - char_u *lead = NULL; + char *lead = NULL; bool in_multispace = false; int multispace_pos = 0; - char_u *trail = NULL; + char *trail = NULL; int l; if (curwin->w_p_list) { @@ -1840,7 +1806,7 @@ void msg_prt_line(char_u *s, int list) if (list) { // find start of trailing whitespace if (curwin->w_p_lcs_chars.trail) { - trail = s + STRLEN(s); + trail = s + strlen(s); while (trail > s && ascii_iswhite(trail[-1])) { trail--; } @@ -1872,16 +1838,16 @@ void msg_prt_line(char_u *s, int list) c = c_extra; } else { assert(p_extra != NULL); - c = *p_extra++; + c = (unsigned char)(*p_extra++); } - } else if ((l = utfc_ptr2len((char *)s)) > 1) { - col += utf_ptr2cells((char *)s); + } else if ((l = utfc_ptr2len(s)) > 1) { + col += utf_ptr2cells(s); char buf[MB_MAXBYTES + 1]; if (l >= MB_MAXBYTES) { xstrlcpy(buf, "?", sizeof(buf)); } else if (curwin->w_p_lcs_chars.nbsp != NUL && list - && (utf_ptr2char((char *)s) == 160 - || utf_ptr2char((char *)s) == 0x202f)) { + && (utf_ptr2char(s) == 160 + || utf_ptr2char(s) == 0x202f)) { int len = utf_char2bytes(curwin->w_p_lcs_chars.nbsp, buf); buf[len] = NUL; } else { @@ -1893,7 +1859,7 @@ void msg_prt_line(char_u *s, int list) continue; } else { attr = 0; - c = *s++; + c = (unsigned char)(*s++); in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' '); if (!in_multispace) { multispace_pos = 0; @@ -1919,7 +1885,7 @@ void msg_prt_line(char_u *s, int list) c = curwin->w_p_lcs_chars.nbsp; attr = HL_ATTR(HLF_0); } else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) { - p_extra = (char_u *)""; + p_extra = ""; c_extra = NUL; c_final = NUL; n_extra = 1; @@ -1928,10 +1894,10 @@ void msg_prt_line(char_u *s, int list) s--; } else if (c != NUL && (n = byte2cells(c)) > 1) { n_extra = n - 1; - p_extra = transchar_byte(c); + p_extra = (char *)transchar_byte(c); c_extra = NUL; c_final = NUL; - c = *p_extra++; + c = (unsigned char)(*p_extra++); // Use special coloring to be able to distinguish <hex> from // the same in plain text. attr = HL_ATTR(HLF_0); @@ -1976,13 +1942,13 @@ void msg_prt_line(char_u *s, int list) /// Use grid_puts() to output one multi-byte character. /// /// @return the pointer "s" advanced to the next character. -static char_u *screen_puts_mbyte(char_u *s, int l, int attr) +static char *screen_puts_mbyte(char *s, int l, int attr) { int cw; attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr); msg_didout = true; // remember that line is not empty - cw = utf_ptr2cells((char *)s); + cw = utf_ptr2cells(s); if (cw > 1 && (cmdmsg_rl ? msg_col <= 1 : msg_col == Columns - 1)) { // Doesn't fit, print a highlighted '>' to fill it up. @@ -2022,12 +1988,12 @@ void msg_puts_title(const char *s) /// Show a message in such a way that it always fits in the line. Cut out a /// part in the middle and replace it with "..." when necessary. /// Does not handle multi-byte characters! -void msg_outtrans_long_attr(char_u *longstr, int attr) +void msg_outtrans_long_attr(char *longstr, int attr) { - msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr); + msg_outtrans_long_len_attr(longstr, (int)strlen(longstr), attr); } -void msg_outtrans_long_len_attr(char_u *longstr, int len, int attr) +void msg_outtrans_long_len_attr(char *longstr, int len, int attr) { int slen = len; int room; @@ -2083,7 +2049,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr) overflow = true; } } else { - overflow = msg_scrolled != 0; + overflow = msg_scrolled > (p_ch == 0 ? 1 : 0); } if (overflow && !msg_scrolled_ign && strcmp(str, "\r") != 0) { @@ -2104,7 +2070,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr) } } if (!msg_use_printf() || (headless_mode && default_grid.chars)) { - msg_puts_display((const char_u *)str, (int)len, attr, false); + msg_puts_display(str, (int)len, attr, false); } need_fileinfo = false; @@ -2147,10 +2113,10 @@ static void msg_ext_emit_chunk(void) /// The display part of msg_puts_attr_len(). /// May be called recursively to display scroll-back text. -static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurse) +static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) { - const char_u *s = str; - const char_u *t_s = str; // String from "t_s" to "s" is still todo. + const char *s = str; + const char *t_s = str; // String from "t_s" to "s" is still todo. int t_col = 0; // Screen cells todo, 0 when "t_s" not used. int l; int cw; @@ -2185,12 +2151,12 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs && (*s == '\n' || (cmdmsg_rl ? (msg_col <= 1 || (*s == TAB && msg_col <= 7) - || (utf_ptr2cells((char *)s) > 1 + || (utf_ptr2cells(s) > 1 && msg_col <= 2)) : ((*s != '\r' && msg_col + t_col >= Columns - 1) || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7)) - || (utf_ptr2cells((char *)s) > 1 + || (utf_ptr2cells(s) > 1 && msg_col + t_col >= Columns - 2))))) { // The screen is scrolled up when at the last row (some terminals // scroll automatically, some don't. To avoid problems we scroll @@ -2206,8 +2172,8 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs } // Scroll the screen up one line. - bool has_last_char = (*s >= ' ' && !cmdmsg_rl); - msg_scroll_up(!has_last_char); + bool has_last_char = ((uint8_t)(*s) >= ' ' && !cmdmsg_rl); + msg_scroll_up(!has_last_char, false); msg_row = Rows - 2; if (msg_col >= Columns) { // can happen after screen resize @@ -2220,9 +2186,9 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs // Avoid including composing chars after the end. l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); } else { - l = utfc_ptr2len((char *)s); + l = utfc_ptr2len(s); } - s = screen_puts_mbyte((char_u *)s, l, attr); + s = screen_puts_mbyte((char *)s, l, attr); did_last_char = true; } else { did_last_char = false; @@ -2243,16 +2209,14 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs } inc_msg_scrolled(); - need_wait_return = true; // may need wait_return in main() + need_wait_return = true; // may need wait_return() in main() redraw_cmdline = true; if (cmdline_row > 0 && !exmode_active) { cmdline_row--; } - /* - * If screen is completely filled and 'more' is set then wait - * for a character. - */ + // If screen is completely filled and 'more' is set then wait + // for a character. if (lines_left > 0) { lines_left--; } @@ -2275,7 +2239,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs wrap = *s == '\n' || msg_col + t_col >= Columns - || (utf_ptr2cells((char *)s) > 1 + || (utf_ptr2cells(s) > 1 && msg_col + t_col >= Columns - 1) ; if (t_col > 0 && (wrap || *s == '\r' || *s == '\b' @@ -2311,20 +2275,20 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs } while (msg_col & 7); } else if (*s == BELL) { // beep (from ":sh") vim_beep(BO_SH); - } else if (*s >= 0x20) { // printable char - cw = utf_ptr2cells((char *)s); + } else if ((uint8_t)(*s) >= 0x20) { // printable char + cw = utf_ptr2cells(s); if (maxlen >= 0) { // avoid including composing chars after the end l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); } else { - l = utfc_ptr2len((char *)s); + l = utfc_ptr2len(s); } // When drawing from right to left or when a double-wide character // doesn't fit, draw a single character here. Otherwise collect // characters and draw them all at once later. if (cmdmsg_rl || (cw > 1 && msg_col + t_col >= Columns - 1)) { if (l > 1) { - s = screen_puts_mbyte((char_u *)s, l, attr) - 1; + s = screen_puts_mbyte((char *)s, l, attr) - 1; } else { msg_screen_putchar(*s, attr); } @@ -2344,7 +2308,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs if (t_col > 0) { t_puts(&t_col, t_s, s, attr); } - if (p_more && !recurse) { + if (p_more && !recurse && !(s == sb_str + 1 && *sb_str == '\n')) { store_sb_text((char **)&sb_str, (char *)s, attr, &sb_col, false); } @@ -2353,27 +2317,20 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs /// @return true when ":filter pattern" was used and "msg" does not match /// "pattern". -bool message_filtered(char_u *msg) +bool message_filtered(char *msg) { if (cmdmod.cmod_filter_regmatch.regprog == NULL) { return false; } - bool match = vim_regexec(&cmdmod.cmod_filter_regmatch, (char *)msg, (colnr_T)0); + bool match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, (colnr_T)0); return cmdmod.cmod_filter_force ? match : !match; } /// including horizontal separator int msg_scrollsize(void) { - return msg_scrolled + (int)p_ch + 1; -} - -bool msg_use_msgsep(void) -{ - // the full-screen scroll behavior doesn't really make sense with - // 'ext_multigrid' - return ((dy_flags & DY_MSGSEP) || ui_has(kUIMultigrid)); + return msg_scrolled + (int)p_ch + ((p_ch > 0 || msg_scrolled > 1) ? 1 : 0); } bool msg_do_throttle(void) @@ -2382,27 +2339,28 @@ bool msg_do_throttle(void) } /// Scroll the screen up one line for displaying the next message line. -void msg_scroll_up(bool may_throttle) +void msg_scroll_up(bool may_throttle, bool zerocmd) { if (may_throttle && msg_do_throttle()) { msg_grid.throttled = true; } msg_did_scroll = true; - if (msg_use_msgsep()) { - if (msg_grid_pos > 0) { - msg_grid_set_pos(msg_grid_pos - 1, true); - } else { - grid_del_lines(&msg_grid, 0, 1, msg_grid.rows, 0, msg_grid.cols); - memmove(msg_grid.dirty_col, msg_grid.dirty_col + 1, - (size_t)(msg_grid.rows - 1) * sizeof(*msg_grid.dirty_col)); - msg_grid.dirty_col[msg_grid.rows - 1] = 0; + if (msg_grid_pos > 0) { + msg_grid_set_pos(msg_grid_pos - 1, !zerocmd); + + // When displaying the first line with cmdheight=0, we need to draw over + // the existing last line of the screen. + if (zerocmd && msg_grid.chars) { + grid_clear_line(&msg_grid, msg_grid.line_offset[0], msg_grid.cols, false); } } else { - grid_del_lines(&msg_grid_adj, 0, 1, Rows, 0, Columns); + grid_del_lines(&msg_grid, 0, 1, msg_grid.rows, 0, msg_grid.cols); + memmove(msg_grid.dirty_col, msg_grid.dirty_col + 1, + (size_t)(msg_grid.rows - 1) * sizeof(*msg_grid.dirty_col)); + msg_grid.dirty_col[msg_grid.rows - 1] = 0; } - grid_fill(&msg_grid_adj, Rows - 1, Rows, 0, Columns, ' ', ' ', - HL_ATTR(HLF_MSG)); + grid_fill(&msg_grid_adj, Rows - 1, Rows, 0, Columns, ' ', ' ', HL_ATTR(HLF_MSG)); } /// Send throttled message output to UI clients @@ -2464,21 +2422,17 @@ void msg_reset_scroll(void) } // TODO(bfredl): some duplicate logic with update_screen(). Later on // we should properly disentangle message clear with full screen redraw. - if (msg_use_grid()) { - msg_grid.throttled = false; - // TODO(bfredl): risk for extra flicker i e with - // "nvim -o has_swap also_has_swap" - msg_grid_set_pos(Rows - (int)p_ch, false); - clear_cmdline = true; - if (msg_grid.chars) { - // non-displayed part of msg_grid is considered invalid. - for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) { - grid_clear_line(&msg_grid, msg_grid.line_offset[i], - msg_grid.cols, false); - } + msg_grid.throttled = false; + // TODO(bfredl): risk for extra flicker i e with + // "nvim -o has_swap also_has_swap" + msg_grid_set_pos(Rows - (int)p_ch, false); + clear_cmdline = true; + if (msg_grid.chars) { + // non-displayed part of msg_grid is considered invalid. + for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) { + grid_clear_line(&msg_grid, msg_grid.line_offset[i], + msg_grid.cols, false); } - } else { - redraw_all_later(NOT_VALID); } msg_scrolled = 0; msg_scrolled_at_flush = 0; @@ -2506,8 +2460,8 @@ static void inc_msg_scrolled(void) xfree(tofree); } msg_scrolled++; - if (must_redraw < VALID) { - must_redraw = VALID; + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; } } @@ -2557,7 +2511,7 @@ static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int fin } mp->sb_next = NULL; } else if (finish && last_msgchunk != NULL) { - last_msgchunk->sb_eol = TRUE; + last_msgchunk->sb_eol = true; } *sb_str = s; @@ -2614,7 +2568,7 @@ void sb_text_end_cmdline(void) } /// Clear any text remembered for scrolling back. -/// When "all" is FALSE keep the last line. +/// When "all" is false keep the last line. /// Called when redrawing the screen. void clear_sb_text(int all) { @@ -2649,7 +2603,7 @@ void show_sb_text(void) vim_beep(BO_MESS); } else { do_more_prompt('G'); - wait_return(FALSE); + wait_return(false); } } @@ -2668,7 +2622,7 @@ static msgchunk_T *msg_sb_start(msgchunk_T *mps) void msg_sb_eol(void) { if (last_msgchunk != NULL) { - last_msgchunk->sb_eol = TRUE; + last_msgchunk->sb_eol = true; } } @@ -2678,7 +2632,7 @@ void msg_sb_eol(void) static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) { msgchunk_T *mp = smp; - char_u *p; + char *p; for (;;) { msg_row = row; @@ -2687,7 +2641,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) if (*p == '\n') { // don't display the line break p++; } - msg_puts_display(p, -1, mp->sb_attr, TRUE); + msg_puts_display(p, -1, mp->sb_attr, true); if (mp->sb_eol || mp->sb_next == NULL) { break; } @@ -2698,18 +2652,17 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) } /// Output any postponed text for msg_puts_attr_len(). -static void t_puts(int *t_col, const char_u *t_s, const char_u *s, int attr) +static void t_puts(int *t_col, const char *t_s, const char *s, int attr) { attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr); // Output postponed text. msg_didout = true; // Remember that line is not empty. - grid_puts_len(&msg_grid_adj, (char_u *)t_s, (int)(s - t_s), msg_row, msg_col, - attr); + grid_puts_len(&msg_grid_adj, (char *)t_s, (int)(s - t_s), msg_row, msg_col, attr); msg_col += *t_col; *t_col = 0; // If the string starts with a composing character don't increment the // column position for it. - if (utf_iscomposing(utf_ptr2char((char *)t_s))) { + if (utf_iscomposing(utf_ptr2char(t_s))) { msg_col--; } if (msg_col >= Columns) { @@ -2718,7 +2671,7 @@ static void t_puts(int *t_col, const char_u *t_s, const char_u *s, int attr) } } -/// @return TRUE when messages should be printed to stdout/stderr: +/// @return true when messages should be printed to stdout/stderr: /// - "batch mode" ("silent mode", -es/-Es) /// - no UI and not embedded int msg_use_printf(void) @@ -2786,14 +2739,14 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) /// When at hit-enter prompt "typed_char" is the already typed character, /// otherwise it's NUL. /// -/// @return TRUE when jumping ahead to "confirm_msg_tail". +/// @return true when jumping ahead to "confirm_msg_tail". static int do_more_prompt(int typed_char) { static bool entered = false; int used_typed_char = typed_char; int oldState = State; int c; - int retval = FALSE; + int retval = false; int toscroll; bool to_redraw = false; msgchunk_T *mp_last = NULL; @@ -2817,7 +2770,7 @@ static int do_more_prompt(int typed_char) // "g<": Find first line on the last page. mp_last = msg_sb_start(last_msgchunk); for (i = 0; i < Rows - 2 && mp_last != NULL - && mp_last->sb_prev != NULL; ++i) { + && mp_last->sb_prev != NULL; i++) { mp_last = msg_sb_start(mp_last->sb_prev); } } @@ -2825,12 +2778,10 @@ static int do_more_prompt(int typed_char) State = MODE_ASKMORE; setmouse(); if (typed_char == NUL) { - msg_moremsg(FALSE); + msg_moremsg(false); } for (;;) { - /* - * Get a typed character directly from the user. - */ + // Get a typed character directly from the user. if (used_typed_char != NUL) { c = used_typed_char; // was typed at hit-enter prompt used_typed_char = NUL; @@ -2898,10 +2849,10 @@ static int do_more_prompt(int typed_char) case ESC: if (confirm_msg_used) { // Jump to the choices of the dialog. - retval = TRUE; + retval = true; } else { - got_int = TRUE; - quit_more = TRUE; + got_int = true; + quit_more = true; } // When there is some more output (wrapping line) display that // without another prompt. @@ -2917,7 +2868,7 @@ static int do_more_prompt(int typed_char) break; default: // no valid response - msg_moremsg(TRUE); + msg_moremsg(true); continue; } @@ -2936,8 +2887,7 @@ static int do_more_prompt(int typed_char) } // go to start of line at top of the screen - for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; - ++i) { + for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; i++) { mp = msg_sb_start(mp->sb_prev); } @@ -2977,6 +2927,11 @@ static int do_more_prompt(int typed_char) } } else { // First display any text that we scrolled back. + // if p_ch=0 we need to allocate a line for "press enter" messages! + if (cmdline_row >= Rows && !ui_has(kUIMessages)) { + msg_scroll_up(true, false); + msg_scrolled++; + } while (toscroll > 0 && mp_last != NULL) { if (msg_do_throttle() && !msg_grid.throttled) { // Tricky: we redraw at one line higher than usual. Therefore @@ -2985,7 +2940,7 @@ static int do_more_prompt(int typed_char) msg_grid_scroll_discount++; } // scroll up, display line at bottom - msg_scroll_up(true); + msg_scroll_up(true, false); inc_msg_scrolled(); grid_fill(&msg_grid_adj, Rows - 2, Rows - 1, 0, Columns, ' ', ' ', HL_ATTR(HLF_MSG)); @@ -3029,7 +2984,7 @@ static int do_more_prompt(int typed_char) return retval; } -#if defined(WIN32) +#if defined(MSWIN) void mch_errmsg(char *str) { assert(str != NULL); @@ -3056,7 +3011,7 @@ void mch_msg(char *str) xfree(utf16str); } } -#endif // WIN32 +#endif // MSWIN /// Put a character on the screen at the current message position and advance /// to the next position. Only for printable ASCII! @@ -3081,14 +3036,13 @@ static void msg_screen_putchar(int c, int attr) void msg_moremsg(int full) { int attr; - char_u *s = (char_u *)_("-- More --"); + char *s = _("-- More --"); attr = hl_combine_attr(HL_ATTR(HLF_MSG), HL_ATTR(HLF_M)); grid_puts(&msg_grid_adj, s, Rows - 1, 0, attr); if (full) { - grid_puts(&msg_grid_adj, (char_u *) - _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "), - Rows - 1, vim_strsize((char *)s), attr); + grid_puts(&msg_grid_adj, _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "), + Rows - 1, vim_strsize(s), attr); } } @@ -3122,7 +3076,7 @@ void repeat_message(void) /// Skip this when ":silent" was used, no need to clear for redirection. void msg_clr_eos(void) { - if (msg_silent == 0 && p_ch > 0) { + if (msg_silent == 0) { msg_clr_eos_force(); } } @@ -3144,12 +3098,10 @@ void msg_clr_eos_force(void) msg_row = msg_grid_pos; } - 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, - ' ', ' ', HL_ATTR(HLF_MSG)); - } + 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, + ' ', ' ', HL_ATTR(HLF_MSG)); redraw_cmdline = true; // overwritten the command line if (msg_row < Rows - 1 || msg_col == (cmdmsg_rl ? Columns : 0)) { @@ -3167,17 +3119,15 @@ void msg_clr_cmdline(void) } /// end putting a message on the screen -/// call wait_return if the message does not fit in the available space +/// call wait_return() if the message does not fit in the available space /// -/// @return TRUE if wait_return not called. +/// @return true if wait_return() not called. int msg_end(void) { - /* - * If the string is larger than the window, - * or the ruler option is set and we run into it, - * we have to redraw the window. - * Do not do this if we are abandoning the file or editing the command line. - */ + // If the string is larger than the window, + // or the ruler option is set and we run into it, + // we have to redraw the window. + // Do not do this if we are abandoning the file or editing the command line. if (!exiting && need_wait_return && !(State & MODE_CMDLINE)) { wait_return(false); return false; @@ -3245,8 +3195,8 @@ void msg_ext_clear_later(void) { if (msg_ext_is_visible()) { msg_ext_need_clear = true; - if (must_redraw < VALID) { - must_redraw = VALID; + if (must_redraw < UPD_VALID) { + must_redraw = UPD_VALID; } } } @@ -3283,7 +3233,7 @@ void msg_check(void) /// @param maxlen if -1, write the whole string, otherwise up to "maxlen" bytes. static void redir_write(const char *const str, const ptrdiff_t maxlen) { - const char_u *s = (char_u *)str; + const char *s = str; static int cur_col = 0; if (maxlen == 0) { @@ -3308,7 +3258,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen) ga_concat_len(capture_ga, " ", 1); } if (redir_reg) { - write_reg_contents(redir_reg, (char_u *)" ", 1, true); + write_reg_contents(redir_reg, " ", 1, true); } else if (redir_vname) { var_redir_str(" ", -1); } else if (redir_fd != NULL) { @@ -3321,7 +3271,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen) } } - size_t len = maxlen == -1 ? STRLEN(s) : (size_t)maxlen; + size_t len = maxlen == -1 ? strlen(s) : (size_t)maxlen; if (capture_ga) { ga_concat_len(capture_ga, str, len); } @@ -3334,7 +3284,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen) // Write and adjust the current column. while (*s != NUL - && (maxlen < 0 || (int)(s - (const char_u *)str) < maxlen)) { + && (maxlen < 0 || (int)(s - str) < maxlen)) { if (!redir_reg && !redir_vname && !capture_ga) { if (redir_fd != NULL) { putc(*s, redir_fd); @@ -3392,7 +3342,7 @@ void verbose_enter_scroll(void) msg_silent++; } else { // always scroll up, don't overwrite - msg_scroll = TRUE; + msg_scroll = true; } } @@ -3415,7 +3365,7 @@ void verbose_stop(void) fclose(verbose_fd); verbose_fd = NULL; } - verbose_did_open = FALSE; + verbose_did_open = false; } /// Open the file 'verbosefile'. @@ -3425,9 +3375,9 @@ int verbose_open(void) { if (verbose_fd == NULL && !verbose_did_open) { // Only give the error message once. - verbose_did_open = TRUE; + verbose_did_open = true; - verbose_fd = os_fopen((char *)p_vfile, "a"); + verbose_fd = os_fopen(p_vfile, "a"); if (verbose_fd == NULL) { semsg(_(e_notopen), p_vfile); return FAIL; @@ -3471,9 +3421,9 @@ void give_warning(char *message, bool hl) no_wait_return--; } -void give_warning2(char_u *const message, char_u *const a1, bool hl) +void give_warning2(char *const message, char *const a1, bool hl) { - vim_snprintf((char *)IObuff, IOSIZE, (char *)message, a1); + vim_snprintf((char *)IObuff, IOSIZE, message, a1); give_warning((char *)IObuff, hl); } @@ -3524,13 +3474,13 @@ void msg_advance(int col) /// different letter. /// /// @param textfiel IObuff for inputdialog(), NULL otherwise -/// @param ex_cmd when TRUE pressing : accepts default and starts Ex command +/// @param ex_cmd when true pressing : accepts default and starts Ex command /// @returns 0 if cancelled, otherwise the nth button (1-indexed). -int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, - char_u *textfield, int ex_cmd) +int do_dialog(int type, char *title, char *message, char *buttons, int dfltbutton, char *textfield, + int ex_cmd) { int retval = 0; - char_u *hotkeys; + char *hotkeys; int c; int i; @@ -3547,10 +3497,8 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl State = MODE_CONFIRM; setmouse(); - /* - * Since we wait for a keypress, don't make the - * user press RETURN as well afterwards. - */ + // Since we wait for a keypress, don't make the + // user press RETURN as well afterwards. no_wait_return++; hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); @@ -3580,10 +3528,10 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl c = mb_tolower(c); retval = 1; for (i = 0; hotkeys[i]; i++) { - if (utf_ptr2char((char *)hotkeys + i) == c) { + if (utf_ptr2char(hotkeys + i) == c) { break; } - i += utfc_ptr2len((char *)hotkeys + i) - 1; + i += utfc_ptr2len(hotkeys + i) - 1; retval++; } if (hotkeys[i]) { @@ -3610,14 +3558,14 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl /// characters. Return the length of the character in bytes. /// /// @param lowercase make character lower case -static int copy_char(const char_u *from, char_u *to, bool lowercase) +static int copy_char(const char *from, char *to, bool lowercase) FUNC_ATTR_NONNULL_ALL { if (lowercase) { - int c = mb_tolower(utf_ptr2char((char *)from)); - return utf_char2bytes(c, (char *)to); + int c = mb_tolower(utf_ptr2char(from)); + return utf_char2bytes(c, to); } - int len = utfc_ptr2len((char *)from); + int len = utfc_ptr2len(from); memmove(to, from, (size_t)len); return len; } @@ -3637,7 +3585,7 @@ static int copy_char(const char_u *from, char_u *to, bool lowercase) /// corresponding button has a hotkey /// /// @return Pointer to memory allocated for storing hotkeys -static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool has_hotkey[]) +static char *console_dialog_alloc(const char *message, char *buttons, bool has_hotkey[]) { int lenhotkey = HOTK_LEN; // count first button has_hotkey[0] = false; @@ -3645,7 +3593,7 @@ static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool // Compute the size of memory to allocate. int len = 0; int idx = 0; - char_u *r = buttons; + char *r = buttons; while (*r) { if (*r == DLG_BUTTON_SEP) { len += 3; // '\n' -> ', '; 'x' -> '(x)' @@ -3665,9 +3613,9 @@ static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool MB_PTR_ADV(r); } - len += (int)(STRLEN(message) + len += (int)(strlen(message) + 2 // for the NL's - + STRLEN(buttons) + + strlen(buttons) + 3); // for the ": " and NUL lenhotkey++; // for the NUL @@ -3691,11 +3639,11 @@ static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool /// The hotkeys can be multi-byte characters, but without combining chars. /// /// @return an allocated string with hotkeys. -static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton) +static char *msg_show_console_dialog(char *message, char *buttons, int dfltbutton) FUNC_ATTR_NONNULL_RET { bool has_hotkey[HAS_HOTKEY_LEN] = { false }; - char_u *hotk = console_dialog_alloc(message, buttons, has_hotkey); + char *hotk = console_dialog_alloc(message, buttons, has_hotkey); copy_hotkeys_and_msg(message, buttons, dfltbutton, has_hotkey, hotk); @@ -3711,13 +3659,13 @@ static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfl /// @param has_hotkey An element in this array is true if corresponding button /// has a hotkey /// @param[out] hotkeys_ptr Pointer to the memory location where hotkeys will be copied -static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons, int default_button_idx, - const bool has_hotkey[], char_u *hotkeys_ptr) +static void copy_hotkeys_and_msg(const char *message, char *buttons, int default_button_idx, + const bool has_hotkey[], char *hotkeys_ptr) { *confirm_msg = '\n'; STRCPY(confirm_msg + 1, message); - char_u *msgp = confirm_msg + 1 + STRLEN(message); + char *msgp = confirm_msg + 1 + strlen(message); // Define first default hotkey. Keep the hotkey string NUL // terminated to avoid reading past the end. @@ -3734,14 +3682,14 @@ static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons, int def } int idx = 0; - char_u *r = buttons; + char *r = buttons; while (*r) { if (*r == DLG_BUTTON_SEP) { *msgp++ = ','; *msgp++ = ' '; // '\n' -> ', ' // Advance to next hotkey and set default hotkey - hotkeys_ptr += STRLEN(hotkeys_ptr); + hotkeys_ptr += strlen(hotkeys_ptr); hotkeys_ptr[copy_char(r + 1, hotkeys_ptr, true)] = NUL; if (default_button_idx) { @@ -3790,28 +3738,28 @@ void display_confirm_msg(void) confirm_msg_used++; if (confirm_msg != NULL) { msg_ext_set_kind("confirm"); - msg_puts_attr((const char *)confirm_msg, HL_ATTR(HLF_M)); + msg_puts_attr(confirm_msg, HL_ATTR(HLF_M)); } confirm_msg_used--; } -int vim_dialog_yesno(int type, char_u *title, char_u *message, int dflt) +int vim_dialog_yesno(int type, char *title, char *message, int dflt) { if (do_dialog(type, - title == NULL ? (char_u *)_("Question") : title, + title == NULL ? _("Question") : title, message, - (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1) { + _("&Yes\n&No"), dflt, NULL, false) == 1) { return VIM_YES; } return VIM_NO; } -int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt) +int vim_dialog_yesnocancel(int type, char *title, char *message, int dflt) { switch (do_dialog(type, - title == NULL ? (char_u *)_("Question") : title, + title == NULL ? _("Question") : title, message, - (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) { + _("&Yes\n&No\n&Cancel"), dflt, NULL, false)) { case 1: return VIM_YES; case 2: @@ -3820,13 +3768,13 @@ int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt) return VIM_CANCEL; } -int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message, int dflt) +int vim_dialog_yesnoallcancel(int type, char *title, char *message, int dflt) { switch (do_dialog(type, - title == NULL ? (char_u *)"Question" : title, + title == NULL ? "Question" : title, message, - (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"), - dflt, NULL, FALSE)) { + _("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"), + dflt, NULL, false)) { case 1: return VIM_YES; case 2: diff --git a/src/nvim/message.h b/src/nvim/message.h index 2de2890213..31cd54f18c 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -5,15 +5,13 @@ #include <stdbool.h> #include <stddef.h> +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/grid_defs.h" -#include "nvim/lib/kvec.h" #include "nvim/macros.h" #include "nvim/types.h" -/* - * Types of dialogs passed to do_dialog(). - */ +// Types of dialogs passed to do_dialog(). #define VIM_GENERIC 0 #define VIM_ERROR 1 #define VIM_WARNING 2 @@ -21,9 +19,7 @@ #define VIM_QUESTION 4 #define VIM_LAST_TYPE 4 // sentinel value -/* - * Return values for functions like vim_dialogyesno() - */ +// Return values for functions like vim_dialogyesno() #define VIM_YES 2 #define VIM_NO 3 #define VIM_CANCEL 4 @@ -40,7 +36,7 @@ typedef kvec_t(HlMessageChunk) HlMessage; /// Message history for `:messages` typedef struct msg_hist { struct msg_hist *next; ///< Next message. - char_u *msg; ///< Message text. + char *msg; ///< Message text. const char *kind; ///< Message kind (for msg_ext) int attr; ///< Message highlighting. bool multiline; ///< Multiline message. diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index a8d0b3b584..7b267d6ce4 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -179,7 +179,7 @@ retnomove: } if (flags & MOUSE_MAY_STOP_VIS) { end_visual_mode(); - redraw_curbuf_later(INVERTED); // delete the inversion + redraw_curbuf_later(UPD_INVERTED); // delete the inversion } return IN_BUFFER; } @@ -279,7 +279,7 @@ retnomove: : col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1)) && (flags & MOUSE_MAY_STOP_VIS)))) { end_visual_mode(); - redraw_curbuf_later(INVERTED); // delete the inversion + redraw_curbuf_later(UPD_INVERTED); // delete the inversion } if (cmdwin_type != 0 && wp != curwin) { // A click outside the command-line window: Use modeless @@ -345,7 +345,7 @@ retnomove: // before moving the cursor for a left click, stop Visual mode if (flags & MOUSE_MAY_STOP_VIS) { end_visual_mode(); - redraw_curbuf_later(INVERTED); // delete the inversion + redraw_curbuf_later(UPD_INVERTED); // delete the inversion } if (grid == 0) { @@ -374,14 +374,14 @@ retnomove: if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { curwin->w_topfill++; } else { - --curwin->w_topline; + curwin->w_topline--; curwin->w_topfill = 0; } } check_topfill(curwin, false); curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); row = 0; } else if (row >= curwin->w_height_inner) { count = 0; @@ -410,7 +410,7 @@ retnomove: } } check_topfill(curwin, false); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); row = curwin->w_height_inner - 1; @@ -631,14 +631,16 @@ colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { // try to advance to the specified column - char_u *ptr = ml_get_buf(wp->w_buffer, lnum, false); - char_u *const line = ptr; - colnr_T count = 0; - while (count < vcol && *ptr != NUL) { - count += win_lbr_chartabsize(wp, line, ptr, count, NULL); - MB_PTR_ADV(ptr); - } - return (colnr_T)(ptr - line); + char_u *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); + chartabsize_T cts; + init_chartabsize_arg(&cts, wp, lnum, 0, (char *)line, (char *)line); + while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL) { + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + MB_PTR_ADV(cts.cts_ptr); + } + clear_chartabsize_arg(&cts); + + return (colnr_T)((char_u *)cts.cts_ptr - line); } /// Set UI mouse depending on current mode and 'mouse'. @@ -664,10 +666,10 @@ void set_mouse_topline(win_T *wp) static colnr_T scroll_line_len(linenr_T lnum) { colnr_T col = 0; - char_u *line = ml_get(lnum); + char_u *line = (char_u *)ml_get(lnum); if (*line != NUL) { for (;;) { - int numchar = win_chartabsize(curwin, line, col); + int numchar = win_chartabsize(curwin, (char *)line, col); MB_PTR_ADV(line); if (*line == NUL) { // don't count the last character break; @@ -702,8 +704,8 @@ static linenr_T find_longest_lnum(void) max = len; ret = lnum; } else if (len == (colnr_T)max - && abs((int)(lnum - curwin->w_cursor.lnum)) - < abs((int)(ret - curwin->w_cursor.lnum))) { + && abs(lnum - curwin->w_cursor.lnum) + < abs(ret - curwin->w_cursor.lnum)) { ret = lnum; } } @@ -769,7 +771,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // highlighting the second byte, not the ninth. linenr_T lnum = wp->w_cursor.lnum; - char_u *line = ml_get(lnum); + char_u *line = (char_u *)ml_get(lnum); char_u *ptr = line; char_u *ptr_end; char_u *ptr_row_offset = line; // Where we begin adjusting `ptr_end` @@ -790,7 +792,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // checked for concealed characters. vcol = 0; while (vcol < offset && *ptr != NUL) { - vcol += win_chartabsize(curwin, ptr, vcol); + vcol += win_chartabsize(curwin, (char *)ptr, vcol); ptr += utfc_ptr2len((char *)ptr); } @@ -801,7 +803,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; ptr_end = ptr_row_offset; while (vcol < col && *ptr_end != NUL) { - vcol += win_chartabsize(curwin, ptr_end, vcol); + vcol += win_chartabsize(curwin, (char *)ptr_end, vcol); ptr_end += utfc_ptr2len((char *)ptr_end); } @@ -816,7 +818,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) #define DECR() nudge--; ptr_end -= utfc_ptr2len((char *)ptr_end) while (ptr < ptr_end && *ptr != NUL) { - cwidth = win_chartabsize(curwin, ptr, vcol); + cwidth = win_chartabsize(curwin, (char *)ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. diff --git a/src/nvim/mouse.h b/src/nvim/mouse.h index 08261e4a30..21ff56bbbc 100644 --- a/src/nvim/mouse.h +++ b/src/nvim/mouse.h @@ -36,7 +36,7 @@ #define MOUSE_X2 0x400 // Mouse-button X2 // Direction for nv_mousescroll() and ins_mousescroll() -#define MSCR_DOWN 0 // DOWN must be FALSE +#define MSCR_DOWN 0 // DOWN must be false #define MSCR_UP 1 #define MSCR_LEFT (-1) #define MSCR_RIGHT (-2) diff --git a/src/nvim/move.c b/src/nvim/move.c index 1ed7acd012..9b7755a828 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -1,16 +1,14 @@ // 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 -/* - * move.c: Functions for moving the cursor and scrolling text. - * - * There are two ways to move the cursor: - * 1. Move the cursor directly, the text is scrolled to keep the cursor in the - * window. - * 2. Scroll the text, the cursor is moved into the text visible in the - * window. - * The 'scrolloff' option makes this a bit complicated. - */ +// move.c: Functions for moving the cursor and scrolling text. +// +// There are two ways to move the cursor: +// 1. Move the cursor directly, the text is scrolled to keep the cursor in the +// window. +// 2. Scroll the text, the cursor is moved into the text visible in the +// window. +// The 'scrolloff' option makes this a bit complicated. #include <assert.h> #include <inttypes.h> @@ -23,12 +21,15 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/eval.h" +#include "nvim/eval/typval.h" #include "nvim/fold.h" #include "nvim/getchar.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/mbyte.h" #include "nvim/memline.h" +#include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/option.h" #include "nvim/plines.h" @@ -47,19 +48,15 @@ typedef struct { # include "move.c.generated.h" #endif -/* - * Compute wp->w_botline for the current wp->w_topline. Can be called after - * wp->w_topline changed. - */ +// Compute wp->w_botline for the current wp->w_topline. Can be called after +// wp->w_topline changed. static void comp_botline(win_T *wp) { linenr_T lnum; int done; - /* - * If w_cline_row is valid, start there. - * Otherwise have to start at w_topline. - */ + // If w_cline_row is valid, start there. + // Otherwise have to start at w_topline. check_cursor_moved(wp); if (wp->w_valid & VALID_CROW) { lnum = wp->w_cursor.lnum; @@ -105,7 +102,7 @@ void redraw_for_cursorline(win_T *wp) if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible() && (wp->w_p_rnu || win_cursorline_standout(wp))) { // win_line() will redraw the number column and cursorline only. - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } @@ -118,11 +115,11 @@ static void redraw_for_cursorcolumn(win_T *wp) if ((wp->w_valid & VALID_VIRTCOL) == 0 && !pum_visible()) { if (wp->w_p_cuc || ((HL_ATTR(HLF_LC) || win_hl_attr(wp, HLF_LC)) && using_hlsearch())) { // When 'cursorcolumn' is set or "CurSearch" is in use - // need to redraw with SOME_VALID. - redraw_later(wp, SOME_VALID); + // need to redraw with UPD_SOME_VALID. + redraw_later(wp, UPD_SOME_VALID); } else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE)) { - // When 'cursorlineopt' contains "screenline" need to redraw with VALID. - redraw_later(wp, VALID); + // When 'cursorlineopt' contains "screenline" need to redraw with UPD_VALID. + redraw_later(wp, UPD_VALID); } } // If the cursor moves horizontally when 'concealcursor' is active, then the @@ -133,21 +130,7 @@ static void redraw_for_cursorcolumn(win_T *wp) } } -/* - * Update curwin->w_topline and redraw if necessary. - * Used to update the screen before printing a message. - */ -void update_topline_redraw(void) -{ - update_topline(curwin); - if (must_redraw) { - update_screen(0); - } -} - -/* - * Update curwin->w_topline to move the cursor onto the screen. - */ +// Update curwin->w_topline to move the cursor onto the screen. void update_topline(win_T *wp) { linenr_T old_topline; @@ -157,6 +140,11 @@ void update_topline(win_T *wp) long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so; long save_so = *so_ptr; + // Cursor is updated instead when this is true for 'splitkeep'. + if (skip_update_topline) { + return; + } + // If there is no valid screen and when the window height is zero just use // the cursor line. if (!default_grid.chars || wp->w_height_inner == 0) { @@ -184,7 +172,7 @@ void update_topline(win_T *wp) // If the buffer is empty, always set topline to 1. if (buf_is_empty(curbuf)) { // special case - file is empty if (wp->w_topline != 1) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } wp->w_topline = 1; wp->w_botline = 2; @@ -250,14 +238,12 @@ void update_topline(win_T *wp) } } - /* - * If the cursor is below the bottom of the window, scroll the window - * to put the cursor on the window. - * When w_botline is invalid, recompute it first, to avoid a redraw later. - * If w_botline was approximated, we might need a redraw later in a few - * cases, but we don't want to spend (a lot of) time recomputing w_botline - * for every small change. - */ + // If the cursor is below the bottom of the window, scroll the window + // to put the cursor on the window. + // When w_botline is invalid, recompute it first, to avoid a redraw later. + // If w_botline was approximated, we might need a redraw later in a few + // cases, but we don't want to spend (a lot of) time recomputing w_botline + // for every small change. if (check_botline) { if (!(wp->w_valid & VALID_BOTLINE_AP)) { validate_botline(wp); @@ -328,17 +314,15 @@ void update_topline(win_T *wp) wp->w_viewport_invalid = true; win_check_anchored_floats(wp); - /* - * Need to redraw when topline changed. - */ + // Need to redraw when topline changed. if (wp->w_topline != old_topline || wp->w_topfill != old_topfill) { dollar_vcol = -1; if (wp->w_skipcol != 0) { wp->w_skipcol = 0; - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } else { - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } // May need to set w_skipcol when cursor in w_topline. if (wp->w_cursor.lnum == wp->w_topline) { @@ -349,9 +333,7 @@ void update_topline(win_T *wp) *so_ptr = save_so; } -/* - * Update win->w_topline to move the cursor onto the screen. - */ +// Update win->w_topline to move the cursor onto the screen. void update_topline_win(win_T *win) { switchwin_T switchwin; @@ -360,11 +342,9 @@ void update_topline_win(win_T *win) restore_win(&switchwin, true); } -/* - * Return the scrolljump value to use for the current window. - * When 'scrolljump' is positive use it as-is. - * When 'scrolljump' is negative use it as a percentage of the window height. - */ +// Return the scrolljump value to use for the current window. +// When 'scrolljump' is positive use it as-is. +// When 'scrolljump' is negative use it as a percentage of the window height. static int scrolljump_value(void) { long result = p_sj >= 0 ? p_sj : (curwin->w_height_inner * -p_sj) / 100; @@ -372,10 +352,8 @@ static int scrolljump_value(void) return (int)result; } -/* - * Return true when there are not 'scrolloff' lines above the cursor for the - * current window. - */ +// Return true when there are not 'scrolloff' lines above the cursor for the +// current window. static bool check_top_offset(void) { long so = get_scrolloff_value(curwin); @@ -412,9 +390,7 @@ void update_curswant(void) } } -/* - * Check if the cursor has moved. Set the w_valid flag accordingly. - */ +// Check if the cursor has moved. Set the w_valid flag accordingly. void check_cursor_moved(win_T *wp) { if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) { @@ -435,11 +411,9 @@ void check_cursor_moved(win_T *wp) } } -/* - * Call this function when some window settings have changed, which require - * the cursor position, botline and topline to be recomputed and the window to - * be redrawn. E.g, when changing the 'wrap' option or folding. - */ +// Call this function when some window settings have changed, which require +// the cursor position, botline and topline to be recomputed and the window to +// be redrawn. E.g, when changing the 'wrap' option or folding. void changed_window_setting(void) { changed_window_setting_win(curwin); @@ -450,12 +424,10 @@ void changed_window_setting_win(win_T *wp) wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE); - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } -/* - * Set wp->w_topline to a certain number. - */ +// Set wp->w_topline to a certain number. void set_topline(win_T *wp, linenr_T lnum) { linenr_T prev_topline = wp->w_topline; @@ -472,14 +444,12 @@ void set_topline(win_T *wp, linenr_T lnum) } wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE); // Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } -/* - * Call this function when the length of the cursor line (in screen - * characters) has changed, and the change is before the cursor. - * Need to take care of w_botline separately! - */ +// Call this function when the length of the cursor line (in screen +// characters) has changed, and the change is before the cursor. +// Need to take care of w_botline separately! void changed_cline_bef_curs(void) { curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL @@ -492,11 +462,9 @@ void changed_cline_bef_curs_win(win_T *wp) |VALID_CHEIGHT|VALID_TOPLINE); } -/* - * Call this function when the length of a line (in screen characters) above - * the cursor have changed. - * Need to take care of w_botline separately! - */ +// Call this function when the length of a line (in screen characters) above +// the cursor have changed. +// Need to take care of w_botline separately! void changed_line_abv_curs(void) { curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW @@ -509,9 +477,7 @@ void changed_line_abv_curs_win(win_T *wp) |VALID_CHEIGHT|VALID_TOPLINE); } -/* - * Make sure the value of curwin->w_botline is valid. - */ +// Make sure the value of curwin->w_botline is valid. void validate_botline(win_T *wp) { if (!(wp->w_valid & VALID_BOTLINE)) { @@ -519,9 +485,7 @@ void validate_botline(win_T *wp) } } -/* - * Mark curwin->w_botline as invalid (because of some change in the buffer). - */ +// Mark curwin->w_botline as invalid (because of some change in the buffer). void invalidate_botline(void) { curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); @@ -537,9 +501,7 @@ void approximate_botline_win(win_T *wp) wp->w_valid &= ~VALID_BOTLINE; } -/* - * Return true if curwin->w_wrow and curwin->w_wcol are valid. - */ +// Return true if curwin->w_wrow and curwin->w_wcol are valid. int cursor_valid(void) { check_cursor_moved(curwin); @@ -547,10 +509,8 @@ int cursor_valid(void) (VALID_WROW|VALID_WCOL); } -/* - * Validate cursor position. Makes sure w_wrow and w_wcol are valid. - * w_topline must be valid, you may need to call update_topline() first! - */ +// Validate cursor position. Makes sure w_wrow and w_wcol are valid. +// w_topline must be valid, you may need to call update_topline() first! void validate_cursor(void) { check_cursor_moved(curwin); @@ -559,10 +519,8 @@ void validate_cursor(void) } } -/* - * Compute wp->w_cline_row and wp->w_cline_height, based on the current value - * of wp->w_topline. - */ +// Compute wp->w_cline_row and wp->w_cline_height, based on the current value +// of wp->w_topline. static void curs_rows(win_T *wp) { // Check if wp->w_lines[].wl_size is invalid @@ -571,7 +529,7 @@ static void curs_rows(win_T *wp) || wp->w_lines[0].wl_lnum > wp->w_topline); int i = 0; wp->w_cline_row = 0; - for (linenr_T lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i) { + for (linenr_T lnum = wp->w_topline; lnum < wp->w_cursor.lnum; i++) { bool valid = false; if (!all_invalid && i < wp->w_lines_valid) { if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid) { @@ -587,7 +545,7 @@ static void curs_rows(win_T *wp) valid = true; } } else if (wp->w_lines[i].wl_lnum > lnum) { - --i; // hold at inserted lines + i--; // hold at inserted lines } } if (valid && (lnum != wp->w_topline || !win_may_fill(wp))) { @@ -633,17 +591,13 @@ static void curs_rows(win_T *wp) wp->w_valid |= VALID_CROW|VALID_CHEIGHT; } -/* - * Validate curwin->w_virtcol only. - */ +// Validate curwin->w_virtcol only. void validate_virtcol(void) { validate_virtcol_win(curwin); } -/* - * Validate wp->w_virtcol only. - */ +// Validate wp->w_virtcol only. void validate_virtcol_win(win_T *wp) { check_cursor_moved(wp); @@ -654,9 +608,7 @@ void validate_virtcol_win(win_T *wp) } } -/* - * Validate curwin->w_cline_height only. - */ +// Validate curwin->w_cline_height only. void validate_cheight(void) { check_cursor_moved(curwin); @@ -668,9 +620,7 @@ void validate_cheight(void) } } -/* - * Validate w_wcol and w_virtcol only. - */ +// Validate w_wcol and w_virtcol only. void validate_cursor_col(void) { validate_virtcol(); @@ -697,10 +647,8 @@ void validate_cursor_col(void) } } -/* - * Compute offset of a window, occupied by absolute or relative line number, - * fold column and sign column (these don't move when scrolling horizontally). - */ +// Compute offset of a window, occupied by absolute or relative line number, +// fold column and sign column (these don't move when scrolling horizontally). int win_col_off(win_T *wp) { return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) @@ -714,11 +662,9 @@ int curwin_col_off(void) return win_col_off(curwin); } -/* - * Return the difference in column offset for the second screen line of a - * wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in - * 'cpoptions'. - */ +// Return the difference in column offset for the second screen line of a +// wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in +// 'cpoptions'. int win_col_off2(win_T *wp) { if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL) { @@ -746,9 +692,7 @@ void curs_columns(win_T *wp, int may_scroll) long so = get_scrolloff_value(wp); long siso = get_sidescrolloff_value(wp); - /* - * First make sure that w_topline is valid (after moving the cursor). - */ + // First make sure that w_topline is valid (after moving the cursor). update_topline(wp); // Next make sure that w_cline_row is valid. @@ -756,9 +700,7 @@ void curs_columns(win_T *wp, int may_scroll) curs_rows(wp); } - /* - * Compute the number of virtual columns. - */ + // Compute the number of virtual columns. if (wp->w_cline_folded) { // In a folded line the cursor is always in the first column startcol = wp->w_virtcol = endcol = wp->w_leftcol; @@ -847,7 +789,7 @@ void curs_columns(win_T *wp, int may_scroll) wp->w_leftcol = new_leftcol; win_check_anchored_floats(wp); // screen has to be redrawn with new wp->w_leftcol - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } } wp->w_wcol -= wp->w_leftcol; @@ -954,7 +896,7 @@ void curs_columns(win_T *wp, int may_scroll) wp->w_skipcol = 0; } if (prev_skipcol != wp->w_skipcol) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } redraw_for_cursorcolumn(curwin); @@ -1033,6 +975,62 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, *ecolp = ecol + coloff; } +/// "screenpos({winid}, {lnum}, {col})" function +void f_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + tv_dict_alloc_ret(rettv); + dict_T *dict = rettv->vval.v_dict; + + win_T *wp = find_win_by_nr_or_id(&argvars[0]); + if (wp == NULL) { + return; + } + + pos_T pos = { + .lnum = (linenr_T)tv_get_number(&argvars[1]), + .col = (colnr_T)tv_get_number(&argvars[2]) - 1, + .coladd = 0 + }; + int row = 0; + int scol = 0, ccol = 0, ecol = 0; + textpos2screenpos(wp, &pos, &row, &scol, &ccol, &ecol, false); + + tv_dict_add_nr(dict, S_LEN("row"), row); + tv_dict_add_nr(dict, S_LEN("col"), scol); + tv_dict_add_nr(dict, S_LEN("curscol"), ccol); + tv_dict_add_nr(dict, S_LEN("endcol"), ecol); +} + +/// "virtcol2col({winid}, {lnum}, {col})" function +void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = -1; + + if (tv_check_for_number_arg(argvars, 0) == FAIL + || tv_check_for_number_arg(argvars, 1) == FAIL + || tv_check_for_number_arg(argvars, 2) == FAIL) { + return; + } + + win_T *wp = find_win_by_nr_or_id(&argvars[0]); + if (wp == NULL) { + return; + } + + bool error = false; + linenr_T lnum = (linenr_T)tv_get_number_chk(&argvars[1], &error); + if (error || lnum < 0 || lnum > wp->w_buffer->b_ml.ml_line_count) { + return; + } + + int screencol = (int)tv_get_number_chk(&argvars[2], &error); + if (error || screencol < 0) { + return; + } + + rettv->vval.v_number = vcol2col(wp, lnum, screencol); +} + /// Scroll the current window down by "line_count" logical lines. "CTRL-Y" /// /// @param line_count number of lines to scroll @@ -1053,7 +1051,7 @@ bool scrolldown(long line_count, int byfold) if (curwin->w_topline == 1) { break; } - --curwin->w_topline; + curwin->w_topline--; curwin->w_topfill = 0; // A sequence of folded lines only counts for one logical line linenr_T first; @@ -1068,7 +1066,7 @@ bool scrolldown(long line_count, int byfold) done += plines_win_nofill(curwin, curwin->w_topline, true); } } - --curwin->w_botline; // approximate w_botline + curwin->w_botline--; // approximate w_botline invalidate_botline(); } curwin->w_wrow += done; // keep w_wrow updated @@ -1079,10 +1077,8 @@ bool scrolldown(long line_count, int byfold) } check_topfill(curwin, true); - /* - * Compute the row number of the last row of the cursor line - * and move the cursor onto the displayed part of the window. - */ + // Compute the row number of the last row of the cursor line + // and move the cursor onto the displayed part of the window. int wrow = curwin->w_wrow; if (curwin->w_p_wrap && curwin->w_width_inner != 0) { validate_virtcol(); @@ -1130,7 +1126,7 @@ bool scrollup(long line_count, int byfold) linenr_T lnum = curwin->w_topline; while (line_count--) { if (curwin->w_topfill > 0) { - --curwin->w_topfill; + curwin->w_topfill--; } else { if (byfold) { (void)hasFolding(lnum, NULL, &lnum); @@ -1187,7 +1183,7 @@ void check_topfill(win_T *wp, bool down) int n = plines_win_nofill(wp, wp->w_topline, true); if (wp->w_topfill + n > wp->w_height_inner) { if (down && wp->w_topline > 1) { - --wp->w_topline; + wp->w_topline--; wp->w_topfill = 0; } else { wp->w_topfill = wp->w_height_inner - n; @@ -1200,10 +1196,8 @@ void check_topfill(win_T *wp, bool down) win_check_anchored_floats(curwin); } -/* - * Use as many filler lines as possible for w_topline. Make sure w_topline - * is still visible. - */ +// Use as many filler lines as possible for w_topline. Make sure w_topline +// is still visible. static void max_topfill(void) { int n = plines_win_nofill(curwin, curwin->w_topline, true); @@ -1217,10 +1211,8 @@ static void max_topfill(void) } } -/* - * Scroll the screen one line down, but don't do it if it would move the - * cursor off the screen. - */ +// Scroll the screen one line down, but don't do it if it would move the +// cursor off the screen. void scrolldown_clamp(void) { int can_fill = (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)); @@ -1249,22 +1241,20 @@ void scrolldown_clamp(void) } if (end_row < curwin->w_height_inner - get_scrolloff_value(curwin)) { if (can_fill) { - ++curwin->w_topfill; + curwin->w_topfill++; check_topfill(curwin, true); } else { - --curwin->w_topline; + curwin->w_topline--; curwin->w_topfill = 0; } (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - --curwin->w_botline; // approximate w_botline + curwin->w_botline--; // approximate w_botline curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); } } -/* - * Scroll the screen one line up, but don't do it if it would move the cursor - * off the screen. - */ +// Scroll the screen one line up, but don't do it if it would move the cursor +// off the screen. void scrollup_clamp(void) { if (curwin->w_topline == curbuf->b_ml.ml_line_count @@ -1296,12 +1286,10 @@ void scrollup_clamp(void) } } -/* - * Add one line above "lp->lnum". This can be a filler line, a closed fold or - * a (wrapped) text line. Uses and sets "lp->fill". - * Returns the height of the added line in "lp->height". - * Lines above the first one are incredibly high: MAXCOL. - */ +// Add one line above "lp->lnum". This can be a filler line, a closed fold or +// a (wrapped) text line. Uses and sets "lp->fill". +// Returns the height of the added line in "lp->height". +// Lines above the first one are incredibly high: MAXCOL. static void topline_back(win_T *wp, lineoff_T *lp) { if (lp->fill < win_get_fill(wp, lp->lnum)) { @@ -1309,7 +1297,7 @@ static void topline_back(win_T *wp, lineoff_T *lp) lp->fill++; lp->height = 1; } else { - --lp->lnum; + lp->lnum--; lp->fill = 0; if (lp->lnum < 1) { lp->height = MAXCOL; @@ -1322,12 +1310,10 @@ static void topline_back(win_T *wp, lineoff_T *lp) } } -/* - * Add one line below "lp->lnum". This can be a filler line, a closed fold or - * a (wrapped) text line. Uses and sets "lp->fill". - * Returns the height of the added line in "lp->height". - * Lines below the last one are incredibly high. - */ +// Add one line below "lp->lnum". This can be a filler line, a closed fold or +// a (wrapped) text line. Uses and sets "lp->fill". +// Returns the height of the added line in "lp->height". +// Lines below the last one are incredibly high. static void botline_forw(win_T *wp, lineoff_T *lp) { if (lp->fill < win_get_fill(wp, lp->lnum + 1)) { @@ -1335,7 +1321,7 @@ static void botline_forw(win_T *wp, lineoff_T *lp) lp->fill++; lp->height = 1; } else { - ++lp->lnum; + lp->lnum++; lp->fill = 0; assert(wp->w_buffer != 0); if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) { @@ -1349,11 +1335,9 @@ static void botline_forw(win_T *wp, lineoff_T *lp) } } -/* - * Switch from including filler lines below lp->lnum to including filler - * lines above loff.lnum + 1. This keeps pointing to the same line. - * When there are no filler lines nothing changes. - */ +// Switch from including filler lines below lp->lnum to including filler +// lines above loff.lnum + 1. This keeps pointing to the same line. +// When there are no filler lines nothing changes. static void botline_topline(lineoff_T *lp) { if (lp->fill > 0) { @@ -1362,11 +1346,9 @@ static void botline_topline(lineoff_T *lp) } } -/* - * Switch from including filler lines above lp->lnum to including filler - * lines below loff.lnum - 1. This keeps pointing to the same line. - * When there are no filler lines nothing changes. - */ +// Switch from including filler lines above lp->lnum to including filler +// lines below loff.lnum - 1. This keeps pointing to the same line. +// When there are no filler lines nothing changes. static void topline_botline(lineoff_T *lp) { if (lp->fill > 0) { @@ -1375,11 +1357,9 @@ static void topline_botline(lineoff_T *lp) } } -/* - * Recompute topline to put the cursor at the top of the window. - * Scroll at least "min_scroll" lines. - * If "always" is true, always set topline (for "zt"). - */ +// Recompute topline to put the cursor at the top of the window. +// Scroll at least "min_scroll" lines. +// If "always" is true, always set topline (for "zt"). void scroll_cursor_top(int min_scroll, int always) { int scrolled = 0; @@ -1394,13 +1374,11 @@ void scroll_cursor_top(int min_scroll, int always) off = mouse_dragging - 1; } - /* - * Decrease topline until: - * - it has become 1 - * - (part of) the cursor line is moved off the screen or - * - moved at least 'scrolljump' lines and - * - at least 'scrolloff' lines above and below the cursor - */ + // Decrease topline until: + // - it has become 1 + // - (part of) the cursor line is moved off the screen or + // - moved at least 'scrolljump' lines and + // - at least 'scrolloff' lines above and below the cursor validate_cheight(); int used = curwin->w_cline_height; // includes filler lines above if (curwin->w_cursor.lnum < curwin->w_topline) { @@ -1421,10 +1399,8 @@ void scroll_cursor_top(int min_scroll, int always) // Hide filler lines above cursor line by adding them to "extra". int extra = win_get_fill(curwin, curwin->w_cursor.lnum); - /* - * Check if the lines from "top" to "bot" fit in the window. If they do, - * set new_topline and advance "top" and "bot" to include more lines. - */ + // Check if the lines from "top" to "bot" fit in the window. If they do, + // set new_topline and advance "top" and "bot" to include more lines. while (top > 0) { int i = hasFolding(top, &top, NULL) ? 1 // count one logical line for a sequence of folded lines @@ -1445,9 +1421,7 @@ void scroll_cursor_top(int min_scroll, int always) scrolled += i; } - /* - * If scrolling is needed, scroll at least 'sj' lines. - */ + // If scrolling is needed, scroll at least 'sj' lines. if ((new_topline >= curwin->w_topline || scrolled > min_scroll) && extra >= off) { break; @@ -1459,18 +1433,14 @@ void scroll_cursor_top(int min_scroll, int always) bot++; } - /* - * If we don't have enough space, put cursor in the middle. - * This makes sure we get the same position when using "k" and "j" - * in a small window. - */ + // If we don't have enough space, put cursor in the middle. + // This makes sure we get the same position when using "k" and "j" + // in a small window. if (used > curwin->w_height_inner) { scroll_cursor_halfway(false); } else { - /* - * If "always" is false, only adjust topline to a lower value, higher - * value may happen with wrapping lines - */ + // If "always" is false, only adjust topline to a lower value, higher + // value may happen with wrapping lines if (new_topline < curwin->w_topline || always) { curwin->w_topline = new_topline; } @@ -1495,10 +1465,8 @@ void scroll_cursor_top(int min_scroll, int always) } } -/* - * Set w_empty_rows and w_filler_rows for window "wp", having used up "used" - * screen lines for text lines. - */ +// Set w_empty_rows and w_filler_rows for window "wp", having used up "used" +// screen lines for text lines. void set_empty_rows(win_T *wp, int used) { wp->w_filler_rows = 0; @@ -1577,13 +1545,11 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) } } - /* - * Stop counting lines to scroll when - * - hitting start of the file - * - scrolled nothing or at least 'sj' lines - * - at least 'so' lines below the cursor - * - lines between botline and cursor have been counted - */ + // Stop counting lines to scroll when + // - hitting start of the file + // - scrolled nothing or at least 'sj' lines + // - at least 'so' lines below the cursor + // - lines between botline and cursor have been counted if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum)) { loff.lnum = cln; boff.lnum = cln; @@ -1673,21 +1639,17 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) } } - /* - * Scroll up if the cursor is off the bottom of the screen a bit. - * Otherwise put it at 1/2 of the screen. - */ + // Scroll up if the cursor is off the bottom of the screen a bit. + // Otherwise put it at 1/2 of the screen. if (line_count >= curwin->w_height_inner && line_count > min_scroll) { scroll_cursor_halfway(false); } else { scrollup(line_count, true); } - /* - * If topline didn't change we need to restore w_botline and w_empty_rows - * (we changed them). - * If topline did change, update_screen() will set botline. - */ + // If topline didn't change we need to restore w_botline and w_empty_rows + // (we changed them). + // If topline did change, update_screen() will set botline. if (curwin->w_topline == old_topline && set_topbot) { curwin->w_botline = old_botline; curwin->w_empty_rows = old_empty_rows; @@ -1726,7 +1688,7 @@ void scroll_cursor_halfway(int atend) } below += boff.height; } else { - ++below; // count a "~" line + below++; // count a "~" line if (atend) { used++; } @@ -1760,18 +1722,14 @@ void scroll_cursor_halfway(int atend) curwin->w_valid |= VALID_TOPLINE; } -/* - * Correct the cursor position so that it is in a part of the screen at least - * 'so' lines from the top and bottom, if possible. - * If not possible, put it at the same position as scroll_cursor_halfway(). - * When called topline must be valid! - */ +// Correct the cursor position so that it is in a part of the screen at least +// 'so' lines from the top and bottom, if possible. +// If not possible, put it at the same position as scroll_cursor_halfway(). +// When called topline must be valid! void cursor_correct(void) { - /* - * How many lines we would like to have above/below the cursor depends on - * whether the first/last line of the file is on screen. - */ + // How many lines we would like to have above/below the cursor depends on + // whether the first/last line of the file is on screen. int above_wanted = (int)get_scrolloff_value(curwin); int below_wanted = (int)get_scrolloff_value(curwin); if (mouse_dragging > 0) { @@ -1795,10 +1753,8 @@ void cursor_correct(void) } } - /* - * If there are sufficient file-lines above and below the cursor, we can - * return now. - */ + // If there are sufficient file-lines above and below the cursor, we can + // return now. linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number if (cln >= curwin->w_topline + above_wanted && cln < curwin->w_botline - below_wanted @@ -1806,12 +1762,10 @@ void cursor_correct(void) return; } - /* - * Narrow down the area where the cursor can be put by taking lines from - * the top and the bottom until: - * - the desired context lines are found - * - the lines from the top is past the lines from the bottom - */ + // Narrow down the area where the cursor can be put by taking lines from + // the top and the bottom until: + // - the desired context lines are found + // - the lines from the top is past the lines from the bottom linenr_T topline = curwin->w_topline; linenr_T botline = curwin->w_botline - 1; // count filler lines as context @@ -1860,11 +1814,9 @@ void cursor_correct(void) curwin->w_viewport_invalid = true; } -/* - * move screen 'count' pages up or down and update screen - * - * return FAIL for failure, OK otherwise - */ +// move screen 'count' pages up or down and update screen +// +// return FAIL for failure, OK otherwise int onepage(Direction dir, long count) { long n; @@ -1899,7 +1851,7 @@ int onepage(Direction dir, long count) if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { // Vi compatible scrolling if (p_window <= 2) { - ++curwin->w_topline; + curwin->w_topline++; } else { curwin->w_topline += (linenr_T)p_window - 2; } @@ -1935,7 +1887,7 @@ int onepage(Direction dir, long count) if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { // Vi compatible scrolling (sort of) if (p_window <= 2) { - --curwin->w_topline; + curwin->w_topline--; } else { curwin->w_topline -= (linenr_T)p_window - 2; } @@ -2000,7 +1952,7 @@ int onepage(Direction dir, long count) max_topfill(); } if (curwin->w_topfill == loff.fill) { - --curwin->w_topline; + curwin->w_topline--; curwin->w_topfill = 0; } comp_botline(curwin); @@ -2040,22 +1992,20 @@ int onepage(Direction dir, long count) } } - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); return retval; } -/* - * Decide how much overlap to use for page-up or page-down scrolling. - * This is symmetric, so that doing both keeps the same lines displayed. - * Three lines are examined: - * - * before CTRL-F after CTRL-F / before CTRL-B - * etc. l1 - * l1 last but one line ------------ - * l2 last text line l2 top text line - * ------------- l3 second text line - * l3 etc. - */ +// Decide how much overlap to use for page-up or page-down scrolling. +// This is symmetric, so that doing both keeps the same lines displayed. +// Three lines are examined: +// +// before CTRL-F after CTRL-F / before CTRL-B +// etc. l1 +// l1 last but one line ------------ +// l2 last text line l2 top text line +// ------------- l3 second text line +// l3 etc. static void get_scroll_overlap(lineoff_T *lp, int dir) { int min_height = curwin->w_height_inner - 2; @@ -2125,9 +2075,7 @@ void halfpage(bool flag, linenr_T Prenum) validate_botline(curwin); int room = curwin->w_empty_rows + curwin->w_filler_rows; if (flag) { - /* - * scroll the text up - */ + // scroll the text up while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_topfill > 0) { i = 1; @@ -2144,7 +2092,7 @@ void halfpage(bool flag, linenr_T Prenum) curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); } @@ -2177,7 +2125,7 @@ void halfpage(bool flag, linenr_T Prenum) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { (void)hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum); - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; } } else { curwin->w_cursor.lnum += n; @@ -2185,9 +2133,7 @@ void halfpage(bool flag, linenr_T Prenum) check_cursor_lnum(); } } else { - /* - * scroll the text down - */ + // scroll the text down while (n > 0 && curwin->w_topline > 1) { if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { i = 1; @@ -2199,7 +2145,7 @@ void halfpage(bool flag, linenr_T Prenum) if (n < 0 && scrolled > 0) { break; } - --curwin->w_topline; + curwin->w_topline--; (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL); curwin->w_topfill = 0; } @@ -2207,7 +2153,7 @@ void halfpage(bool flag, linenr_T Prenum) VALID_BOTLINE|VALID_BOTLINE_AP); scrolled += i; if (curwin->w_cursor.lnum > 1) { - --curwin->w_cursor.lnum; + curwin->w_cursor.lnum--; curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); } } @@ -2218,7 +2164,7 @@ void halfpage(bool flag, linenr_T Prenum) curwin->w_cursor.lnum = 1; } else if (hasAnyFolding(curwin)) { while (--n >= 0 && curwin->w_cursor.lnum > 1) { - --curwin->w_cursor.lnum; + curwin->w_cursor.lnum--; (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); } @@ -2232,7 +2178,7 @@ void halfpage(bool flag, linenr_T Prenum) check_topfill(curwin, !flag); cursor_correct(); beginline(BL_SOL | BL_FIX); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } void do_check_cursorbind(void) @@ -2247,9 +2193,7 @@ void do_check_cursorbind(void) int old_VIsual_select = VIsual_select; int old_VIsual_active = VIsual_active; - /* - * loop through the cursorbound windows - */ + // loop through the cursorbound windows VIsual_select = VIsual_active = 0; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { curwin = wp; @@ -2284,7 +2228,7 @@ void do_check_cursorbind(void) } // Correct cursor for multi-byte character. mb_adjust_cursor(); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); // Only scroll when 'scrollbind' hasn't done this. if (!curwin->w_p_scb) { @@ -2294,9 +2238,7 @@ void do_check_cursorbind(void) } } - /* - * reset current-window - */ + // reset current-window VIsual_select = old_VIsual_select; VIsual_active = old_VIsual_active; curwin = old_curwin; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 1ca68979f4..71ed5ccf81 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -7,6 +7,7 @@ #include <string.h> #include <uv.h> +#include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" #include "nvim/api/vim.h" @@ -18,7 +19,6 @@ #include "nvim/event/rstream.h" #include "nvim/event/socket.h" #include "nvim/event/wstream.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/map.h" @@ -158,7 +158,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem } // frame.result was allocated in an arena - arena_mem_free(frame.result_mem, &rpc->unpacker->reuse_blk); + arena_mem_free(frame.result_mem); frame.result_mem = NULL; } @@ -244,7 +244,7 @@ static void parse_msgpack(Channel *channel) 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); + arena_mem_free(arena_finish(&p->arena)); } } else if (p->type == kMessageTypeResponse) { ChannelCallFrame *frame = kv_last(channel->rpc.call_stack); @@ -295,7 +295,7 @@ static void handle_request(Channel *channel, Unpacker *p, Array args) if (!p->handler.fn) { send_error(channel, p->type, p->request_id, p->unpack_error.msg); api_clear_error(&p->unpack_error); - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); return; } @@ -304,7 +304,8 @@ static void handle_request(Channel *channel, Unpacker *p, Array args) evdata->channel = channel; evdata->handler = p->handler; evdata->args = args; - evdata->used_mem = arena_finish(&p->arena); + evdata->used_mem = p->arena; + p->arena = (Arena)ARENA_EMPTY; evdata->request_id = p->request_id; channel_incref(channel); if (p->handler.fast) { @@ -344,7 +345,8 @@ static void request_event(void **argv) // channel was closed, abort any pending requests goto free_ret; } - Object result = handler.fn(channel->id, e->args, &error); + + Object result = handler.fn(channel->id, e->args, &e->used_mem, &error); if (e->type == kMessageTypeRequest || ERROR_SET(&error)) { // Send the response. msgpack_packer response; @@ -355,13 +357,14 @@ static void request_event(void **argv) &error, result, &out_buffer)); - } else { + } + if (!handler.arena_return) { api_free_object(result); } free_ret: - // e->args is allocated in an arena - arena_mem_free(e->used_mem, &channel->rpc.unpacker->reuse_blk); + // e->args (and possibly result) are allocated in an arena + arena_mem_free(arena_finish(&e->used_mem)); channel_decref(channel); xfree(e); api_clear_error(&error); @@ -624,7 +627,6 @@ static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32 1, // responses only go though 1 channel xfree); msgpack_sbuffer_clear(sbuffer); - api_free_object(arg); return rv; } @@ -642,7 +644,7 @@ void rpc_set_client_info(uint64_t id, Dictionary info) Dictionary rpc_client_info(Channel *chan) { - return copy_dictionary(chan->rpc.info); + return copy_dictionary(chan->rpc.info, NULL); } const char *rpc_client_name(Channel *chan) diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index e622ebddf5..404e68329a 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -27,7 +27,7 @@ typedef struct { MsgpackRpcRequestHandler handler; Array args; uint32_t request_id; - ArenaMem used_mem; + Arena used_mem; } RequestEvent; typedef struct { diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 488321be42..ddca9afad0 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -5,10 +5,10 @@ #include <msgpack.h> #include <stdbool.h> +#include "klib/kvec.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/assert.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/helpers.h" diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index b252f0998e..81b58764d7 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -94,7 +94,7 @@ char *server_address_new(const char *name) { static uint32_t count = 0; char fmt[ADDRESS_MAX_SIZE]; -#ifdef WIN32 +#ifdef MSWIN int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32, name ? name : "nvim", os_get_pid(), count++); #else @@ -173,7 +173,7 @@ int server_start(const char *addr) ((SocketWatcher **)watchers.ga_data)[watchers.ga_len++] = watcher; // Update v:servername, if not set. - if (STRLEN(get_vim_var_str(VV_SEND_SERVER)) == 0) { + if (strlen(get_vim_var_str(VV_SEND_SERVER)) == 0) { set_vservername(&watchers); } @@ -216,7 +216,7 @@ bool server_stop(char *endpoint) watchers.ga_len--; // Bump v:servername to the next available server, if any. - if (strequal(addr, (char *)get_vim_var_str(VV_SEND_SERVER))) { + if (strequal(addr, get_vim_var_str(VV_SEND_SERVER))) { set_vservername(&watchers); } diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index c8e9fdd4c3..24480835a1 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -181,13 +181,11 @@ void unpacker_init(Unpacker *p) p->unpack_error = (Error)ERROR_INIT; p->arena = (Arena)ARENA_EMPTY; - p->reuse_blk = NULL; } void unpacker_teardown(Unpacker *p) { - arena_mem_free(p->reuse_blk, NULL); - arena_mem_free(arena_finish(&p->arena), NULL); + arena_mem_free(arena_finish(&p->arena)); } bool unpacker_parse_header(Unpacker *p) @@ -308,7 +306,7 @@ bool unpacker_advance(Unpacker *p) p->state = 10; } else { p->state = p->type == kMessageTypeResponse ? 1 : 2; - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; } } @@ -322,7 +320,7 @@ bool unpacker_advance(Unpacker *p) goto done; } else { // unpack other ui events using mpack_parse() - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; } } @@ -416,13 +414,13 @@ redo: 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); + arena_mem_free(arena_finish(&p->arena)); p->grid_line_event = NULL; } return true; } else { p->state = 13; - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true); g = p->grid_line_event; } diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h index f39439be63..35048fb877 100644 --- a/src/nvim/msgpack_rpc/unpacker.h +++ b/src/nvim/msgpack_rpc/unpacker.h @@ -32,8 +32,6 @@ struct Unpacker { Error unpack_error; Arena arena; - // one length free-list of reusable blocks - ArenaMem reuse_blk; int nevents; int ncalls; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 2c7dadad0b..e058be9135 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -65,6 +65,8 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/tag.h" +#include "nvim/textformat.h" +#include "nvim/textobject.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -523,7 +525,7 @@ static bool normal_handle_special_visual_command(NormalState *s) && (nv_cmds[s->idx].cmd_flags & NV_STS) && !(mod_mask & MOD_MASK_SHIFT)) { end_visual_mode(); - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } // Keys that work different when 'keymodel' contains "startsel" @@ -627,18 +629,18 @@ static void normal_redraw_mode_message(NormalState *s) // If need to redraw, and there is a "keep_msg", redraw before the // delay if (must_redraw && keep_msg != NULL && !emsg_on_display) { - char_u *kmsg; + char *kmsg; kmsg = keep_msg; keep_msg = NULL; // Showmode() will clear keep_msg, but we want to use it anyway. // First update w_topline. setcursor(); - update_screen(0); + update_screen(); // now reset it, otherwise it's put in the history again keep_msg = kmsg; - kmsg = vim_strsave(keep_msg); + kmsg = xstrdup(keep_msg); msg_attr((const char *)kmsg, keep_msg_attr); xfree(kmsg); } @@ -1281,10 +1283,10 @@ static void normal_redraw(NormalState *s) validate_cursor(); if (VIsual_active) { - redraw_curbuf_later(INVERTED); // update inverted part - update_screen(0); + redraw_curbuf_later(UPD_INVERTED); // update inverted part + update_screen(); } else if (must_redraw) { - update_screen(0); + update_screen(); } else if (redraw_cmdline || clear_cmdline || redraw_mode) { showmode(); } @@ -1300,7 +1302,7 @@ static void normal_redraw(NormalState *s) // Display message after redraw. If an external message is still visible, // it contains the kept message already. if (keep_msg != NULL && !msg_ext_is_visible()) { - char_u *const p = vim_strsave(keep_msg); + char *const p = xstrdup(keep_msg); // msg_start() will set keep_msg to NULL, make a copy // first. Don't reset keep_msg, msg_attr_keep() uses it to @@ -1738,9 +1740,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) } // click in a tab selects that tab page - if (is_click - && cmdwin_type == 0 - && mouse_col < Columns) { + if (is_click && cmdwin_type == 0 && mouse_col < Columns) { in_tab_line = true; c1 = tab_page_click_defs[mouse_col].tabnr; switch (tab_page_click_defs[mouse_col].type) { @@ -1805,7 +1805,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) return false; } jump_flags = 0; - if (STRCMP(p_mousem, "popup_setpos") == 0) { + if (strcmp(p_mousem, "popup_setpos") == 0) { // First set the cursor position before showing the popup // menu. if (VIsual_active) { @@ -1838,8 +1838,8 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) } if (jump_flags) { jump_flags = jump_to_mouse(jump_flags, NULL, which_button); - redraw_curbuf_later(VIsual_active ? INVERTED : VALID); - update_screen(0); + redraw_curbuf_later(VIsual_active ? UPD_INVERTED : UPD_VALID); + update_screen(); setcursor(); ui_flush(); // Update before showing popup menu } @@ -2178,7 +2178,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) find_start_of_word(&VIsual); if (*p_sel == 'e' && *get_cursor_pos_ptr() != NUL) { curwin->w_cursor.col += - utfc_ptr2len((char *)get_cursor_pos_ptr()); + utfc_ptr2len(get_cursor_pos_ptr()); } find_end_of_word(&curwin->w_cursor); } @@ -2186,7 +2186,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) curwin->w_set_curswant = true; } if (is_click) { - redraw_curbuf_later(INVERTED); // update the inversion + redraw_curbuf_later(UPD_INVERTED); // update the inversion } } else if (VIsual_active && !old_active) { if (mod_mask & MOD_MASK_ALT) { @@ -2213,12 +2213,12 @@ static void find_start_of_word(pos_T *pos) int cclass; int col; - line = ml_get(pos->lnum); + line = (char_u *)ml_get(pos->lnum); cclass = get_mouse_class(line + pos->col); while (pos->col > 0) { col = pos->col - 1; - col -= utf_head_off(line, line + col); + col -= utf_head_off((char *)line, (char *)line + col); if (get_mouse_class(line + col) != cclass) { break; } @@ -2234,10 +2234,10 @@ static void find_end_of_word(pos_T *pos) int cclass; int col; - line = ml_get(pos->lnum); + line = (char_u *)ml_get(pos->lnum); if (*p_sel == 'e' && pos->col > 0) { pos->col--; - pos->col -= utf_head_off(line, line + pos->col); + pos->col -= utf_head_off((char *)line, (char *)line + pos->col); } cclass = get_mouse_class(line + pos->col); while (line[pos->col] != NUL) { @@ -2311,7 +2311,7 @@ void reset_VIsual_and_resel(void) { if (VIsual_active) { end_visual_mode(); - redraw_curbuf_later(INVERTED); // delete the inversion later + redraw_curbuf_later(UPD_INVERTED); // delete the inversion later } VIsual_reselect = false; } @@ -2321,7 +2321,7 @@ void reset_VIsual(void) { if (VIsual_active) { end_visual_mode(); - redraw_curbuf_later(INVERTED); // delete the inversion later + redraw_curbuf_later(UPD_INVERTED); // delete the inversion later VIsual_reselect = false; } } @@ -2414,7 +2414,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text // if i == 0: try to find an identifier // if i == 1: try to find any non-white text - char_u *ptr = ml_get_buf(wp->w_buffer, lnum, false); + char_u *ptr = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; i++) { // 1. skip to start of identifier/text col = startcol; @@ -2443,7 +2443,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text this_class = mb_get_class(ptr + col); } while (col > 0 && this_class != 0) { - prevcol = col - 1 - utf_head_off(ptr, ptr + col - 1); + prevcol = col - 1 - utf_head_off((char *)ptr, (char *)ptr + col - 1); prev_class = mb_get_class(ptr + prevcol); if (this_class != prev_class && (i == 0 @@ -2652,8 +2652,8 @@ void clear_showcmd(void) lines = bot - top + 1; if (VIsual_mode == Ctrl_V) { - char_u *const saved_sbr = p_sbr; - char_u *const saved_w_sbr = curwin->w_p_sbr; + char *const saved_sbr = p_sbr; + char *const saved_w_sbr = curwin->w_p_sbr; // Make 'sbr' empty for a moment to get the correct size. p_sbr = empty_option; @@ -2673,9 +2673,9 @@ void clear_showcmd(void) if (cursor_bot) { s = ml_get_pos(&VIsual); - e = get_cursor_pos_ptr(); + e = (char_u *)get_cursor_pos_ptr(); } else { - s = get_cursor_pos_ptr(); + s = (char_u *)get_cursor_pos_ptr(); e = ml_get_pos(&VIsual); } while ((*p_sel != 'e') ? s <= e : s < e) { @@ -2716,8 +2716,6 @@ void clear_showcmd(void) /// @return true if output has been written (and setcursor() has been called). bool add_to_showcmd(int c) { - char_u *p; - int i; static int ignore[] = { K_IGNORE, K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE, K_MOUSEMOVE, @@ -2740,19 +2738,19 @@ bool add_to_showcmd(int c) // Ignore keys that are scrollbar updates and mouse clicks if (IS_SPECIAL(c)) { - for (i = 0; ignore[i] != 0; i++) { + for (int i = 0; ignore[i] != 0; i++) { if (ignore[i] == c) { return false; } } } - p = transchar(c); + char *p = (char *)transchar(c); if (*p == ' ') { STRCPY(p, "<20>"); } size_t old_len = STRLEN(showcmd_buf); - size_t extra_len = STRLEN(p); + size_t extra_len = strlen(p); size_t limit = ui_has(kUIMessages) ? SHOWCMD_BUFLEN - 1 : SHOWCMD_COLS; if (old_len + extra_len > limit) { size_t overflow = old_len + extra_len - limit; @@ -2817,7 +2815,8 @@ void pop_showcmd(void) static void display_showcmd(void) { - if (!ui_has_messages()) { + if (p_ch == 0 && !ui_has(kUIMessages)) { + // TODO(bfredl): would be nice to show in global statusline, perhaps return; } @@ -2843,12 +2842,12 @@ static void display_showcmd(void) grid_puts_line_start(&msg_grid_adj, showcmd_row); if (!showcmd_is_clear) { - grid_puts(&msg_grid_adj, showcmd_buf, showcmd_row, sc_col, + grid_puts(&msg_grid_adj, (char *)showcmd_buf, showcmd_row, sc_col, HL_ATTR(HLF_MSG)); } // clear the rest of an old message by outputting up to SHOWCMD_COLS spaces - grid_puts(&msg_grid_adj, (char_u *)" " + len, showcmd_row, + grid_puts(&msg_grid_adj, (char *)" " + len, showcmd_row, sc_col + len, HL_ATTR(HLF_MSG)); grid_puts_line_flush(false); @@ -2956,7 +2955,7 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff) } } - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); cursor_correct(); curwin->w_redr_status = true; } @@ -3134,7 +3133,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ } else { par_pos = curwin->w_cursor; while (curwin->w_cursor.lnum > 1 - && *skipwhite((char *)get_cursor_line_ptr()) != NUL) { + && *skipwhite(get_cursor_line_ptr()) != NUL) { curwin->w_cursor.lnum--; } } @@ -3171,13 +3170,13 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ } break; } - if (get_leader_len((char *)get_cursor_line_ptr(), NULL, false, true) > 0) { + if (get_leader_len(get_cursor_line_ptr(), NULL, false, true) > 0) { // Ignore this line, continue at start of next line. curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; continue; } - bool valid = is_ident(get_cursor_line_ptr(), curwin->w_cursor.col); + bool valid = is_ident((char_u *)get_cursor_line_ptr(), curwin->w_cursor.col); // If the current position is not a valid identifier and a previous match is // present, favor that one instead. @@ -3232,7 +3231,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ /// @return true if able to move cursor, false otherwise. static bool nv_screengo(oparg_T *oap, int dir, long dist) { - int linelen = linetabsize(get_cursor_line_ptr()); + int linelen = linetabsize((char_u *)get_cursor_line_ptr()); bool retval = true; bool atend = false; int n; @@ -3303,7 +3302,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) } curwin->w_cursor.lnum--; - linelen = linetabsize(get_cursor_line_ptr()); + linelen = linetabsize((char_u *)get_cursor_line_ptr()); if (linelen > width1) { int w = (((linelen - width1 - 1) / width2) + 1) * width2; assert(curwin->w_curswant <= INT_MAX - w); @@ -3339,7 +3338,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) if (curwin->w_curswant >= width1) { curwin->w_curswant -= width2; } - linelen = linetabsize(get_cursor_line_ptr()); + linelen = linetabsize((char_u *)get_cursor_line_ptr()); } } } @@ -3361,7 +3360,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) virtcol -= vim_strsize((char *)get_showbreak_value(curwin)); } - int c = utf_ptr2char((char *)get_cursor_pos_ptr()); + int c = utf_ptr2char(get_cursor_pos_ptr()); if (dir == FORWARD && virtcol < curwin->w_curswant && (curwin->w_curswant <= (colnr_T)width1) && !vim_isprintc(c) && c > 255) { @@ -3490,7 +3489,7 @@ void scroll_redraw(int up, long count) if (moved) { curwin->w_viewport_invalid = true; } - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } /// Get the count specified after a 'z' command. Only the 'z<CR>', 'zl', 'zh', @@ -3656,7 +3655,7 @@ static void nv_zet(cmdarg_T *cap) case 't': scroll_cursor_top(0, true); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -3667,7 +3666,7 @@ static void nv_zet(cmdarg_T *cap) case 'z': scroll_cursor_halfway(true); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -3690,7 +3689,7 @@ static void nv_zet(cmdarg_T *cap) case 'b': scroll_cursor_bot(0, true); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -3742,7 +3741,7 @@ static void nv_zet(cmdarg_T *cap) } if (curwin->w_leftcol != col) { curwin->w_leftcol = col; - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } } break; @@ -3763,7 +3762,7 @@ static void nv_zet(cmdarg_T *cap) } if (curwin->w_leftcol != col) { curwin->w_leftcol = col; - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } } break; @@ -4057,7 +4056,7 @@ static void nv_colon(cmdarg_T *cap) } else if (cap->oap->op_type != OP_NOP && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count || cap->oap->start.col > - (colnr_T)STRLEN(ml_get(cap->oap->start.lnum)) + (colnr_T)strlen(ml_get(cap->oap->start.lnum)) || did_emsg)) { // The start of the operator has become invalid by the Ex command. clearopbeep(cap->oap); @@ -4098,7 +4097,7 @@ static void nv_clear(cmdarg_T *cap) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { wp->w_s->b_syn_slow = false; } - redraw_later(curwin, CLEAR); + redraw_later(curwin, UPD_CLEAR); } } @@ -4164,7 +4163,7 @@ void do_nv_ident(int c1, int c2) /// 'K' normal-mode command. Get the command to lookup the keyword under the /// cursor. -static size_t nv_K_getcmd(cmdarg_T *cap, char_u *kp, bool kp_help, bool kp_ex, char **ptr_arg, +static size_t nv_K_getcmd(cmdarg_T *cap, char *kp, bool kp_help, bool kp_ex, char **ptr_arg, size_t n, char *buf, size_t buf_size) { if (kp_help) { @@ -4201,8 +4200,8 @@ static size_t nv_K_getcmd(cmdarg_T *cap, char_u *kp, bool kp_help, bool kp_ex, c // When a count is given, turn it into a range. Is this // really what we want? - bool isman = (STRCMP(kp, "man") == 0); - bool isman_s = (STRCMP(kp, "man -s") == 0); + bool isman = (strcmp(kp, "man") == 0); + bool isman_s = (strcmp(kp, "man -s") == 0); if (cap->count0 != 0 && !(isman || isman_s)) { snprintf(buf, buf_size, ".,.+%" PRId64, (int64_t)(cap->count0 - 1)); } @@ -4216,7 +4215,7 @@ static size_t nv_K_getcmd(cmdarg_T *cap, char_u *kp, bool kp_help, bool kp_ex, c } STRCAT(buf, " "); if (cap->count0 != 0 && (isman || isman_s)) { - snprintf(buf + STRLEN(buf), buf_size - STRLEN(buf), "%" PRId64, + snprintf(buf + strlen(buf), buf_size - strlen(buf), "%" PRId64, (int64_t)cap->count0); STRCAT(buf, " "); } @@ -4234,12 +4233,12 @@ static size_t nv_K_getcmd(cmdarg_T *cap, char_u *kp, bool kp_help, bool kp_ex, c static void nv_ident(cmdarg_T *cap) { char *ptr = NULL; - char_u *p; + char *p; size_t n = 0; // init for GCC int cmdchar; bool g_cmd; // "g" command bool tag_cmd = false; - char_u *aux_ptr; + char *aux_ptr; if (cap->cmdchar == 'g') { // "g*", "g#", "g]" and "gCTRL-]" cmdchar = cap->nchar; @@ -4275,15 +4274,14 @@ static void nv_ident(cmdarg_T *cap) // Allocate buffer to put the command in. Inserting backslashes can // double the length of the word. p_kp / curbuf->b_p_kp could be added // and some numbers. - char_u *kp = *curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp; // 'keywordprg' - assert(*kp != NUL); // option.c:do_set() should default to ":help" if empty. - bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command - bool kp_help = (STRCMP(kp, ":he") == 0 || STRCMP(kp, ":help") == 0); + char *kp = *curbuf->b_p_kp == NUL ? (char *)p_kp : curbuf->b_p_kp; // 'keywordprg' + bool kp_help = (*kp == NUL || strcmp(kp, ":he") == 0 || strcmp(kp, ":help") == 0); if (kp_help && *skipwhite(ptr) == NUL) { emsg(_(e_noident)); // found white space only return; } - size_t buf_size = n * 2 + 30 + STRLEN(kp); + bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command + size_t buf_size = n * 2 + 30 + strlen(kp); char *buf = xmalloc(buf_size); buf[0] = NUL; @@ -4295,7 +4293,7 @@ static void nv_ident(cmdarg_T *cap) // Call setpcmark() first, so "*``" puts the cursor back where // it was. setpcmark(); - curwin->w_cursor.col = (colnr_T)(ptr - (char *)get_cursor_line_ptr()); + curwin->w_cursor.col = (colnr_T)(ptr - get_cursor_line_ptr()); if (!g_cmd && vim_iswordp((char_u *)ptr)) { STRCPY(buf, "\\<"); @@ -4337,45 +4335,45 @@ static void nv_ident(cmdarg_T *cap) ptr = xstrnsave(ptr, n); if (kp_ex) { // Escape the argument properly for an Ex command - p = (char_u *)vim_strsave_fnameescape((const char *)ptr, VSE_NONE); + p = vim_strsave_fnameescape((const char *)ptr, VSE_NONE); } else { // Escape the argument properly for a shell command - p = vim_strsave_shellescape((char_u *)ptr, true, true); + p = (char *)vim_strsave_shellescape((char_u *)ptr, true, true); } xfree(ptr); - char *newbuf = xrealloc(buf, STRLEN(buf) + STRLEN(p) + 1); + char *newbuf = xrealloc(buf, strlen(buf) + strlen(p) + 1); buf = newbuf; STRCAT(buf, p); xfree(p); } else { if (cmdchar == '*') { - aux_ptr = (char_u *)(p_magic ? "/.*~[^$\\" : "/^$\\"); + aux_ptr = (p_magic ? "/.*~[^$\\" : "/^$\\"); } else if (cmdchar == '#') { - aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\\" : "/?^$\\"); + aux_ptr = (p_magic ? "/?.*~[^$\\" : "/?^$\\"); } else if (tag_cmd) { if (curbuf->b_help) { // ":help" handles unescaped argument - aux_ptr = (char_u *)""; + aux_ptr = ""; } else { - aux_ptr = (char_u *)"\\|\"\n["; + aux_ptr = "\\|\"\n["; } } else { - aux_ptr = (char_u *)"\\|\"\n*?["; + aux_ptr = "\\|\"\n*?["; } - p = (char_u *)buf + STRLEN(buf); + p = buf + STRLEN(buf); while (n-- > 0) { // put a backslash before \ and some others - if (vim_strchr((char *)aux_ptr, *ptr) != NULL) { + if (vim_strchr(aux_ptr, *ptr) != NULL) { *p++ = '\\'; } // When current byte is a part of multibyte character, copy all // bytes of that character. const size_t len = (size_t)(utfc_ptr2len(ptr) - 1); for (size_t i = 0; i < len && n > 0; i++, n--) { - *p++ = (char_u)(*ptr++); + *p++ = *ptr++; } - *p++ = (char_u)(*ptr++); + *p++ = *ptr++; } *p = NUL; } @@ -4383,16 +4381,15 @@ static void nv_ident(cmdarg_T *cap) // Execute the command. if (cmdchar == '*' || cmdchar == '#') { if (!g_cmd - && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), (char_u *)ptr))) { + && vim_iswordp(mb_prevptr((char_u *)get_cursor_line_ptr(), (char_u *)ptr))) { STRCAT(buf, "\\>"); } // put pattern in search history init_history(); - add_to_history(HIST_SEARCH, (char_u *)buf, true, NUL); + add_to_history(HIST_SEARCH, buf, true, NUL); - (void)normal_search(cap, cmdchar == '*' ? '/' : '?', (char_u *)buf, 0, - NULL); + (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0, NULL); } else { g_tag_at_cursor = true; do_cmdline_cmd(buf); @@ -4427,8 +4424,8 @@ bool get_visual_text(cmdarg_T *cap, char **pp, size_t *lenp) return false; } if (VIsual_mode == 'V') { - *pp = (char *)get_cursor_line_ptr(); - *lenp = STRLEN(*pp); + *pp = get_cursor_line_ptr(); + *lenp = strlen(*pp); } else { if (lt(curwin->w_cursor, VIsual)) { *pp = (char *)ml_get_pos(&curwin->w_cursor); @@ -4453,7 +4450,7 @@ bool get_visual_text(cmdarg_T *cap, char **pp, size_t *lenp) static void nv_tagpop(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { - do_tag((char_u *)"", DT_POP, (int)cap->count1, false, true); + do_tag("", DT_POP, (int)cap->count1, false, true); } } @@ -4566,9 +4563,9 @@ static void nv_right(cmdarg_T *cap) // <Space> wraps to next line if 'whichwrap' has 's'. // 'l' wraps to next line if 'whichwrap' has 'l'. // CURS_RIGHT wraps to next line if 'whichwrap' has '>'. - if (((cap->cmdchar == ' ' && vim_strchr((char *)p_ww, 's') != NULL) - || (cap->cmdchar == 'l' && vim_strchr((char *)p_ww, 'l') != NULL) - || (cap->cmdchar == K_RIGHT && vim_strchr((char *)p_ww, '>') != NULL)) + if (((cap->cmdchar == ' ' && vim_strchr(p_ww, 's') != NULL) + || (cap->cmdchar == 'l' && vim_strchr(p_ww, 'l') != NULL) + || (cap->cmdchar == K_RIGHT && vim_strchr(p_ww, '>') != NULL)) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { // When deleting we also count the NL as a character. // Set cap->oap->inclusive when last char in the line is @@ -4602,7 +4599,7 @@ static void nv_right(cmdarg_T *cap) if (virtual_active()) { oneright(); } else { - curwin->w_cursor.col += utfc_ptr2len((char *)get_cursor_pos_ptr()); + curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); } } } @@ -4636,9 +4633,9 @@ static void nv_left(cmdarg_T *cap) // 'h' wraps to previous line if 'whichwrap' has 'h'. // CURS_LEFT wraps to previous line if 'whichwrap' has '<'. if ((((cap->cmdchar == K_BS || cap->cmdchar == Ctrl_H) - && vim_strchr((char *)p_ww, 'b') != NULL) - || (cap->cmdchar == 'h' && vim_strchr((char *)p_ww, 'h') != NULL) - || (cap->cmdchar == K_LEFT && vim_strchr((char *)p_ww, '<') != NULL)) + && vim_strchr(p_ww, 'b') != NULL) + || (cap->cmdchar == 'h' && vim_strchr(p_ww, 'h') != NULL) + || (cap->cmdchar == K_LEFT && vim_strchr(p_ww, '<') != NULL)) && curwin->w_cursor.lnum > 1) { curwin->w_cursor.lnum--; coladvance(MAXCOL); @@ -4650,7 +4647,7 @@ static void nv_left(cmdarg_T *cap) // Don't adjust op_end now, otherwise it won't work. if ((cap->oap->op_type == OP_DELETE || cap->oap->op_type == OP_CHANGE) && !LINEEMPTY(curwin->w_cursor.lnum)) { - char_u *cp = get_cursor_pos_ptr(); + char_u *cp = (char_u *)get_cursor_pos_ptr(); if (*cp != NUL) { curwin->w_cursor.col += utfc_ptr2len((char *)cp); @@ -4805,7 +4802,7 @@ static void nv_search(cmdarg_T *cap) // When using 'incsearch' the cursor may be moved to set a different search // start position. - cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, true); + cap->searchbuf = (char *)getcmdline(cap->cmdchar, cap->count1, 0, true); if (cap->searchbuf == NULL) { clearop(oap); @@ -4841,9 +4838,8 @@ static void nv_next(cmdarg_T *cap) /// @param opt extra flags for do_search() /// /// @return 0 for failure, 1 for found, 2 for found and line offset added. -static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt, int *wrapped) +static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrapped) { - int i; searchit_arg_T sia; cap->oap->motion_type = kMTCharWise; @@ -4852,8 +4848,8 @@ static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt, int *wrap curwin->w_set_curswant = true; CLEAR_FIELD(sia); - i = do_search(cap->oap, dir, dir, pat, cap->count1, - opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); + int i = do_search(cap->oap, dir, dir, (char_u *)pat, cap->count1, + opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); if (wrapped != NULL) { *wrapped = sia.sa_wrapped; } @@ -5363,7 +5359,7 @@ static void nv_replace(cmdarg_T *cap) } // Abort if not enough characters to replace. - ptr = get_cursor_pos_ptr(); + ptr = (char_u *)get_cursor_pos_ptr(); if (STRLEN(ptr) < (unsigned)cap->count1 || (mb_charlen(ptr) < cap->count1)) { clearopbeep(cap->oap); @@ -5552,7 +5548,7 @@ static void n_swapchar(cmdarg_T *cap) return; } - if (LINEEMPTY(curwin->w_cursor.lnum) && vim_strchr((char *)p_ww, '~') == NULL) { + if (LINEEMPTY(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL) { clearopbeep(cap->oap); return; } @@ -5568,7 +5564,7 @@ static void n_swapchar(cmdarg_T *cap) did_change |= swapchar(cap->oap->op_type, &curwin->w_cursor); inc_cursor(); if (gchar_cursor() == NUL) { - if (vim_strchr((char *)p_ww, '~') != NULL + if (vim_strchr(p_ww, '~') != NULL && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; @@ -5624,7 +5620,7 @@ static MarkMoveRes nv_mark_move_to(cmdarg_T *cap, MarkMove flags, fmark_T *fm) /// Handle commands that are operators in Visual mode. static void v_visop(cmdarg_T *cap) { - static char_u trans[] = "YyDdCcxdXdAAIIrr"; + static char trans[] = "YyDdCcxdXdAAIIrr"; // Uppercase means linewise, except in block mode, then "D" deletes till // the end of the line, and "C" replaces till EOL @@ -5636,7 +5632,7 @@ static void v_visop(cmdarg_T *cap) curwin->w_curswant = MAXCOL; } } - cap->cmdchar = (uint8_t)(*(vim_strchr((char *)trans, cap->cmdchar) + 1)); + cap->cmdchar = (uint8_t)(*(vim_strchr(trans, cap->cmdchar) + 1)); nv_operator(cap); } @@ -5819,7 +5815,7 @@ static void nv_visual(cmdarg_T *cap) showmode(); may_trigger_modechanged(); } - redraw_curbuf_later(INVERTED); // update the inversion + redraw_curbuf_later(UPD_INVERTED); // update the inversion } else { // start Visual mode if (cap->count0 > 0 && resel_VIsual_mode != NUL) { // use previously selected part @@ -5865,7 +5861,7 @@ static void nv_visual(cmdarg_T *cap) } else { curwin->w_set_curswant = true; } - redraw_curbuf_later(INVERTED); // show the inversion + redraw_curbuf_later(UPD_INVERTED); // show the inversion } else { if (!cap->arg) { // start Select mode when 'selectmode' contains "cmd" @@ -5900,7 +5896,7 @@ void start_selection(void) void may_start_select(int c) { VIsual_select = (c == 'o' || (stuff_empty() && typebuf_typed())) - && vim_strchr((char *)p_slm, c) != NULL; + && vim_strchr(p_slm, c) != NULL; } /// Start Visual mode "c". @@ -5931,7 +5927,7 @@ static void n_start_visual_mode(int c) } // Only need to redraw this line, unless still need to redraw an old // Visual area (when 'lazyredraw' is set). - if (curwin->w_redr_type < INVERTED) { + if (curwin->w_redr_type < UPD_INVERTED) { curwin->w_old_cursor_lnum = curwin->w_cursor.lnum; curwin->w_old_visual_lnum = curwin->w_cursor.lnum; } @@ -6018,7 +6014,7 @@ static void nv_gv_cmd(cmdarg_T *cap) may_start_select('c'); } setmouse(); - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); showmode(); } @@ -6071,7 +6067,7 @@ static void nv_g_underscore_cmd(cmdarg_T *cap) return; } - char_u *ptr = get_cursor_line_ptr(); + char_u *ptr = (char_u *)get_cursor_line_ptr(); // In Visual mode we may end up after the line. if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) { @@ -6154,7 +6150,7 @@ static void nv_gi_cmd(cmdarg_T *cap) if (curbuf->b_last_insert.mark.lnum != 0) { curwin->w_cursor = curbuf->b_last_insert.mark; check_cursor_lnum(); - int i = (int)STRLEN(get_cursor_line_ptr()); + int i = (int)strlen(get_cursor_line_ptr()); if (curwin->w_cursor.col > (colnr_T)i) { if (virtual_active()) { curwin->w_cursor.coladd += curwin->w_cursor.col - i; @@ -6282,7 +6278,7 @@ static void nv_g_cmd(cmdarg_T *cap) case 'M': oap->motion_type = kMTCharWise; oap->inclusive = false; - i = linetabsize(get_cursor_line_ptr()); + i = linetabsize((char_u *)get_cursor_line_ptr()); if (cap->count0 > 0 && cap->count0 <= 100) { coladvance((colnr_T)(i * cap->count0 / 100)); } else { @@ -6837,7 +6833,7 @@ bool unadjust_for_sel(void) mark_mb_adjustpos(curbuf, pp); } else if (pp->lnum > 1) { pp->lnum--; - pp->col = (colnr_T)STRLEN(ml_get(pp->lnum)); + pp->col = (colnr_T)strlen(ml_get(pp->lnum)); return true; } } @@ -6901,7 +6897,7 @@ static void nv_normal(cmdarg_T *cap) } if (VIsual_active) { end_visual_mode(); // stop Visual - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } } else { clearopbeep(cap->oap); @@ -6920,10 +6916,7 @@ static void nv_esc(cmdarg_T *cap) && cap->oap->regname == 0); if (cap->arg) { // true for CTRL-C - if (restart_edit == 0 - && cmdwin_type == 0 - && !VIsual_active - && no_reason) { + if (restart_edit == 0 && cmdwin_type == 0 && !VIsual_active && no_reason) { if (anyBufIsChanged()) { msg(_("Type :qa! and press <Enter> to abandon all changes" " and exit Nvim")); @@ -6955,7 +6948,7 @@ static void nv_esc(cmdarg_T *cap) end_visual_mode(); // stop Visual check_cursor_col(); // make sure cursor is not beyond EOL curwin->w_set_curswant = true; - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } else if (no_reason) { vim_beep(BO_ESC); } @@ -6974,7 +6967,7 @@ void set_cursor_for_append_to_line(void) coladvance(MAXCOL); State = save_State; } else { - curwin->w_cursor.col += (colnr_T)STRLEN(get_cursor_pos_ptr()); + curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); } } @@ -7075,8 +7068,8 @@ static void nv_object(cmdarg_T *cap) include = true; // "ax" = an object: include white space } // Make sure (), [], {} and <> are in 'matchpairs' - mps_save = curbuf->b_p_mps; - curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>"; + mps_save = (char_u *)curbuf->b_p_mps; + curbuf->b_p_mps = "(:),{:},[:],<:>"; switch (cap->nchar) { case 'w': // "aw" = a word @@ -7130,7 +7123,7 @@ static void nv_object(cmdarg_T *cap) break; } - curbuf->b_p_mps = mps_save; + curbuf->b_p_mps = (char *)mps_save; if (!flag) { clearopbeep(cap->oap); } diff --git a/src/nvim/normal.h b/src/nvim/normal.h index 9bda70eacd..0317080f4f 100644 --- a/src/nvim/normal.h +++ b/src/nvim/normal.h @@ -22,9 +22,7 @@ typedef enum { kMTUnknown = -1, ///< Unknown or invalid motion type } MotionType; -/* - * Arguments for operators. - */ +// Arguments for operators. typedef struct oparg_S { int op_type; // current pending operator type int regname; // register to use for the operator @@ -53,11 +51,9 @@ typedef struct oparg_S { // block } oparg_T; -/* - * Arguments for Normal mode commands. - */ +// Arguments for Normal mode commands. typedef struct cmdarg_S { - oparg_T *oap; // Operator arguments + oparg_T *oap; // Operator arguments int prechar; // prefix character (optional, always 'g') int cmdchar; // command character int nchar; // next command character (optional) @@ -69,7 +65,7 @@ typedef struct cmdarg_S { long count1; // count before command, default 1 int arg; // extra argument from nv_cmds[] int retval; // return: CA_* values - char_u *searchbuf; // return: pointer to search pattern or NULL + char *searchbuf; // return: pointer to search pattern or NULL } cmdarg_T; // values for retval: diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 3be4536f16..d3a47d77a2 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1,16 +1,15 @@ // 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 -/* - * ops.c: implementation of various operators: op_shift, op_delete, op_tilde, - * op_change, op_yank, do_put, do_join - */ +// ops.c: implementation of various operators: op_shift, op_delete, op_tilde, +// op_change, op_yank, do_put, do_join #include <assert.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/assert.h" #include "nvim/buffer.h" @@ -30,7 +29,6 @@ #include "nvim/globals.h" #include "nvim/indent.h" #include "nvim/indent_c.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/macros.h" #include "nvim/mark.h" @@ -51,6 +49,7 @@ #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/terminal.h" +#include "nvim/textformat.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -66,10 +65,8 @@ static bool clipboard_delay_update = false; // delay clipboard update static bool clipboard_needs_update = false; // clipboard was updated static bool clipboard_didwarn = false; -/* - * structure used by block_prep, op_delete and op_yank for blockwise operators - * also op_change, op_shift, op_insert, op_replace - AKelly - */ +// structure used by block_prep, op_delete and op_yank for blockwise operators +// also op_change, op_shift, op_insert, op_replace - AKelly struct block_def { int startspaces; // 'extra' cols before first char int endspaces; // 'extra' cols after last char @@ -78,9 +75,9 @@ struct block_def { colnr_T textcol; // index of chars (partially) in block colnr_T start_vcol; // start col of 1st char wholly inside block colnr_T end_vcol; // start col of 1st char wholly after block - int is_short; // TRUE if line is too short to fit in block - int is_MAX; // TRUE if curswant==MAXCOL when starting - int is_oneChar; // TRUE if block within one character + int is_short; // true if line is too short to fit in block + int is_MAX; // true if curswant==MAXCOL when starting + int is_oneChar; // true if block within one character int pre_whitesp; // screen cols of ws before block int pre_whitesp_c; // chars of ws before block colnr_T end_char_vcols; // number of vcols of post-block char @@ -95,11 +92,9 @@ struct block_def { #define OPF_LINES 1 // operator always works on lines #define OPF_CHANGE 2 // operator changes text -/* - * The names of operators. - * IMPORTANT: Index must correspond with defines in vim.h!!! - * The third field indicates whether the operator always works on lines. - */ +// The names of operators. +// IMPORTANT: Index must correspond with defines in vim.h!!! +// The third field indicates whether the operator always works on lines. static char opchars[][3] = { { NUL, NUL, 0 }, // OP_NOP @@ -181,13 +176,13 @@ int get_op_type(int char1, int char2) return i; } -/// @return TRUE if operator "op" always works on whole lines. +/// @return true if operator "op" always works on whole lines. int op_on_lines(int op) { return opchars[op][2] & OPF_LINES; } -/// @return TRUE if operator "op" changes text. +/// @return true if operator "op" changes text. int op_is_change(int op) { return opchars[op][2] & OPF_CHANGE; @@ -224,7 +219,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) } for (i = oap->line_count - 1; i >= 0; i--) { - first_char = *get_cursor_line_ptr(); + first_char = (uint8_t)(*get_cursor_line_ptr()); if (first_char == NUL) { // empty line curwin->w_cursor.col = 0; } else if (oap->motion_type == kMTBlockWise) { @@ -234,7 +229,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) // isn't set or 'cindent' isn't set or '#' isn't in 'cino'. shift_line(oap->op_type == OP_LSHIFT, p_sr, amount, false); } - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; } if (oap->motion_type == kMTBlockWise) { @@ -244,7 +239,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) curwin->w_cursor.lnum = oap->start.lnum; beginline(BL_SOL | BL_FIX); // shift_line() may have set cursor.col } else { - --curwin->w_cursor.lnum; // put cursor on last line, for ":>" + curwin->w_cursor.lnum--; // put cursor on last line, for ":>" } // The cursor line is not in a closed fold foldOpenCursor(); @@ -271,7 +266,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) // Set "'[" and "']" marks. curbuf->b_op_start = oap->start; curbuf->b_op_end.lnum = oap->end.lnum; - curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); + curbuf->b_op_end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); if (curbuf->b_op_end.col > 0) { curbuf->b_op_end.col--; } @@ -355,17 +350,15 @@ static void shift_block(oparg_T *oap, int amount) return; // multiplication overflow } - char_u *const oldp = get_cursor_line_ptr(); + char_u *const oldp = (char_u *)get_cursor_line_ptr(); int startcol, oldlen, newlen; if (!left) { - /* - * 1. Get start vcol - * 2. Total ws vcols - * 3. Divvy into TABs & spp - * 4. Construct new string - */ + // 1. Get start vcol + // 2. Total ws vcols + // 3. Divvy into TABs & spp + // 4. Construct new string total += bd.pre_whitesp; // all virtual WS up to & incl a split TAB colnr_T ws_vcol = bd.start_vcol - bd.pre_whitesp; char_u *old_textstart = bd.textstart; @@ -377,12 +370,20 @@ static void shift_block(oparg_T *oap, int amount) bd.startspaces = 0; } } - for (; ascii_iswhite(*bd.textstart);) { - // TODO(fmoralesc): is passing bd.textstart for start of the line OK? - incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, bd.start_vcol); + + // TODO(vim): is passing bd.textstart for start of the line OK? + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, + bd.start_vcol, (char *)bd.textstart, (char *)bd.textstart); + while (ascii_iswhite(*cts.cts_ptr)) { + incr = lbr_chartabsize_adv(&cts); total += incr; - bd.start_vcol += incr; + cts.cts_vcol += incr; } + bd.textstart = (char_u *)cts.cts_ptr; + bd.start_vcol = cts.cts_vcol; + clear_chartabsize_arg(&cts); + // OK, now total=all the VWS reqd, and textstart points at the 1st // non-ws char in the block. if (!curbuf->b_p_et) { @@ -419,13 +420,11 @@ static void shift_block(oparg_T *oap, int amount) // block shift char_u *non_white = bd.textstart; - /* - * Firstly, let's find the first non-whitespace character that is - * displayed after the block's start column and the character's column - * number. Also, let's calculate the width of all the whitespace - * characters that are displayed in the block and precede the searched - * non-whitespace character. - */ + // Firstly, let's find the first non-whitespace character that is + // displayed after the block's start column and the character's column + // number. Also, let's calculate the width of all the whitespace + // characters that are displayed in the block and precede the searched + // non-whitespace character. // If "bd.startspaces" is set, "bd.textstart" points to the character, // the part of which is displayed at the block's beginning. Let's start @@ -437,10 +436,16 @@ static void shift_block(oparg_T *oap, int amount) // The character's column is in "bd.start_vcol". colnr_T non_white_col = bd.start_vcol; - while (ascii_iswhite(*non_white)) { - incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col); - non_white_col += incr; + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, + non_white_col, (char *)bd.textstart, (char *)non_white); + while (ascii_iswhite(*cts.cts_ptr)) { + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + non_white_col = cts.cts_vcol; + non_white = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); const colnr_T block_space_width = non_white_col - oap->start_vcol; // We will shift by "total" or "block_space_width", whichever is less. @@ -461,17 +466,19 @@ static void shift_block(oparg_T *oap, int amount) if (bd.startspaces) { verbatim_copy_width -= bd.start_char_vcols; } - while (verbatim_copy_width < destination_col) { - char_u *line = verbatim_copy_end; - - // TODO: is passing verbatim_copy_end for start of the line OK? - incr = lbr_chartabsize(line, verbatim_copy_end, verbatim_copy_width); - if (verbatim_copy_width + incr > destination_col) { + init_chartabsize_arg(&cts, curwin, 0, verbatim_copy_width, + (char *)bd.textstart, (char *)verbatim_copy_end); + while (cts.cts_vcol < destination_col) { + incr = lbr_chartabsize(&cts); + if (cts.cts_vcol + incr > destination_col) { break; } - verbatim_copy_width += incr; - MB_PTR_ADV(verbatim_copy_end); + cts.cts_vcol += incr; + MB_PTR_ADV(cts.cts_ptr); } + verbatim_copy_width = cts.cts_vcol; + verbatim_copy_end = (char_u *)cts.cts_ptr; + clear_chartabsize_arg(&cts); // If "destination_col" is different from the width of the initial // part of the line that will be copied, it means we encountered a tab @@ -526,7 +533,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def continue; // OP_INSERT, line ends before block start } - oldp = ml_get(lnum); + oldp = (char_u *)ml_get(lnum); if (b_insert) { ts_val = bdp->start_char_vcols; @@ -555,7 +562,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def if (spaces > 0) { // avoid copying part of a multi-byte character - offset -= utf_head_off(oldp, oldp + offset); + offset -= utf_head_off((char *)oldp, (char *)oldp + offset); } if (spaces < 0) { // can happen when the cursor was moved spaces = 0; @@ -651,7 +658,7 @@ void op_reindent(oparg_T *oap, Indenter how) // indented, unless there is only one line. if (i != oap->line_count - 1 || oap->line_count == 1 || how != get_lisp_indent) { - l = (char_u *)skipwhite((char *)get_cursor_line_ptr()); + l = (char_u *)skipwhite(get_cursor_line_ptr()); if (*l == NUL) { // empty or blank line amount = 0; } else { @@ -674,15 +681,15 @@ void op_reindent(oparg_T *oap, Indenter how) curwin->w_cursor.lnum = start_lnum; beginline(BL_SOL | BL_FIX); - /* Mark changed lines so that they will be redrawn. When Visual - * highlighting was present, need to continue until the last line. When - * there is no change still need to remove the Visual highlighting. */ + // Mark changed lines so that they will be redrawn. When Visual + // highlighting was present, need to continue until the last line. When + // there is no change still need to remove the Visual highlighting. if (last_changed != 0) { changed_lines(first_changed, 0, oap->is_VIsual ? start_lnum + (linenr_T)oap->line_count : last_changed + 1, 0L, true); } else if (oap->is_VIsual) { - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } if (oap->line_count > p_report) { @@ -698,9 +705,7 @@ void op_reindent(oparg_T *oap, Indenter how) } } -/* - * Keep the last expression line here, for repeating. - */ +// Keep the last expression line here, for repeating. static char_u *expr_line = NULL; /// Get an expression for the "\"=expr1" or "CTRL-R =expr1" @@ -717,56 +722,56 @@ int get_expr_register(void) if (*new_line == NUL) { // use previous line xfree(new_line); } else { - set_expr_line(new_line); + set_expr_line((char *)new_line); } return '='; } /// Set the expression for the '=' register. /// Argument must be an allocated string. -void set_expr_line(char_u *new_line) +void set_expr_line(char *new_line) { xfree(expr_line); - expr_line = new_line; + expr_line = (char_u *)new_line; } /// Get the result of the '=' register expression. /// /// @return a pointer to allocated memory, or NULL for failure. -char_u *get_expr_line(void) +char *get_expr_line(void) { - char_u *expr_copy; - char_u *rv; + char *expr_copy; + char *rv; static int nested = 0; if (expr_line == NULL) { return NULL; } - /* Make a copy of the expression, because evaluating it may cause it to be - * changed. */ - expr_copy = vim_strsave(expr_line); + // Make a copy of the expression, because evaluating it may cause it to be + // changed. + expr_copy = xstrdup((char *)expr_line); - /* When we are invoked recursively limit the evaluation to 10 levels. - * Then return the string as-is. */ + // When we are invoked recursively limit the evaluation to 10 levels. + // Then return the string as-is. if (nested >= 10) { return expr_copy; } nested++; - rv = (char_u *)eval_to_string((char *)expr_copy, NULL, true); + rv = eval_to_string(expr_copy, NULL, true); nested--; xfree(expr_copy); return rv; } /// Get the '=' register expression itself, without evaluating it. -char_u *get_expr_line_src(void) +char *get_expr_line_src(void) { if (expr_line == NULL) { return NULL; } - return vim_strsave(expr_line); + return xstrdup((char *)expr_line); } /// @return whether `regname` is a valid name of a yank register. @@ -891,7 +896,6 @@ int do_record(int c) { char_u *p; static int regname; - static bool changed_cmdheight = false; yankreg_T *old_y_previous; int retval; @@ -902,18 +906,11 @@ int do_record(int c) retval = FAIL; } else { reg_recording = c; + // TODO(bfredl): showmode based messaging is currently missing with cmdheight=0 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 @@ -943,7 +940,7 @@ int do_record(int c) restore_v_event(dict, &save_v_event); reg_recorded = reg_recording; reg_recording = 0; - if (ui_has(kUIMessages)) { + if (p_ch == 0 || ui_has(kUIMessages)) { showmode(); } else { msg(""); @@ -959,12 +956,6 @@ 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; } @@ -997,7 +988,7 @@ static int stuff_yank(int regname, char_u *p) yankreg_T *reg = get_yank_register(regname, YREG_YANK); if (is_append_register(regname) && reg->y_array != NULL) { char **pp = &(reg->y_array[reg->y_size - 1]); - char_u *lp = xmalloc(STRLEN(*pp) + STRLEN(p) + 1); + char_u *lp = xmalloc(strlen(*pp) + STRLEN(p) + 1); STRCPY(lp, *pp); // TODO(philix): use xstpcpy() in stuff_yank() STRCAT(lp, p); @@ -1065,11 +1056,11 @@ static char_u *execreg_line_continuation(char **lines, size_t *idx) } } ga_append(&ga, NUL); - char_u *str = vim_strsave(ga.ga_data); + char *str = xstrdup(ga.ga_data); ga_clear(&ga); *idx = i; - return str; + return (char_u *)str; } /// Execute a yank register: copy it into the stuff buffer @@ -1110,7 +1101,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) // don't keep the cmdline containing @: XFREE_CLEAR(new_last_cmdline); // Escape all control characters with a CTRL-V - p = vim_strsave_escaped_ext(last_cmdline, + p = vim_strsave_escaped_ext((char_u *)last_cmdline, (char_u *)"\001\002\003\004\005\006\007" "\010\011\012\013\014\015\016\017" "\020\021\022\023\024\025\026\027" @@ -1125,7 +1116,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) } xfree(p); } else if (regname == '=') { - p = get_expr_line(); + p = (char_u *)get_expr_line(); if (p == NULL) { return FAIL; } @@ -1148,9 +1139,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) // Disallow remapping for ":@r". int remap = colon ? REMAP_NONE : REMAP_YES; - /* - * Insert lines into typeahead buffer, from last one to first one. - */ + // Insert lines into typeahead buffer, from last one to first one. put_reedit_in_typebuf(silent); char *escaped; for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included @@ -1260,11 +1249,9 @@ int insert_reg(int regname, bool literally_arg) bool allocated; const bool literally = literally_arg || is_literal_register(regname); - /* - * It is possible to get into an endless loop by having CTRL-R a in - * register a and then, in insert mode, doing CTRL-R a. - * If you hit CTRL-C, the loop will be broken here. - */ + // It is possible to get into an endless loop by having CTRL-R a in + // register a and then, in insert mode, doing CTRL-R a. + // If you hit CTRL-C, the loop will be broken here. os_breakcheck(); if (got_int) { return FAIL; @@ -1311,34 +1298,6 @@ int insert_reg(int regname, bool literally_arg) return retval; } -/// Stuff a string into the typeahead buffer, such that edit() will insert it -/// literally ("literally" true) or interpret is as typed characters. -static void stuffescaped(const char *arg, bool literally) -{ - while (*arg != NUL) { - // Stuff a sequence of normal ASCII characters, that's fast. Also - // stuff K_SPECIAL to get the effect of a special key when "literally" - // is true. - const char *const start = arg; - while ((*arg >= ' ' && *arg < DEL) || ((uint8_t)(*arg) == K_SPECIAL - && !literally)) { - arg++; - } - if (arg > start) { - stuffReadbuffLen(start, (arg - start)); - } - - // stuff a single special character - if (*arg != NUL) { - const int c = mb_cptr2char_adv((const char_u **)&arg); - if (literally && ((c < ' ' && c != TAB) || c == DEL)) { - stuffcharReadbuff(Ctrl_V); - } - stuffcharReadbuff(c); - } - } -} - /// If "regname" is a special register, return true and store a pointer to its /// value in "argp". /// @@ -1365,7 +1324,7 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) return true; case '=': // result of expression - *argp = (char *)get_expr_line(); + *argp = get_expr_line(); *allocated = true; return true; @@ -1373,7 +1332,7 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) if (last_cmdline == NULL && errmsg) { emsg(_(e_nolastcmd)); } - *argp = (char *)last_cmdline; + *argp = last_cmdline; return true; case '/': // last search-pattern @@ -1419,7 +1378,7 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) return false; } - *argp = (char *)ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false); + *argp = ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false); return true; case '_': // black hole: always empty @@ -1458,8 +1417,8 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) cmdline_paste_str((char_u *)"\r", literally); } - /* Check for CTRL-C, in case someone tries to paste a few thousand - * lines and gets bored. */ + // Check for CTRL-C, in case someone tries to paste a few thousand + // lines and gets bored. os_breakcheck(); if (got_int) { return FAIL; @@ -1514,17 +1473,15 @@ int op_delete(oparg_T *oap) mb_adjust_opend(oap); - /* - * Imitate the strange Vi behaviour: If the delete spans more than one - * line and motion_type == kMTCharWise and the result is a blank line, make the - * delete linewise. Don't do this for the change command or Visual mode. - */ + // Imitate the strange Vi behaviour: If the delete spans more than one + // line and motion_type == kMTCharWise and the result is a blank line, make the + // delete linewise. Don't do this for the change command or Visual mode. if (oap->motion_type == kMTCharWise && !oap->is_VIsual && oap->line_count > 1 && oap->motion_force == NUL && oap->op_type == OP_DELETE) { - ptr = ml_get(oap->end.lnum) + oap->end.col; + ptr = (char_u *)ml_get(oap->end.lnum) + oap->end.col; if (*ptr != NUL) { ptr += oap->inclusive; } @@ -1534,10 +1491,8 @@ int op_delete(oparg_T *oap) } } - /* - * Check for trying to delete (e.g. "D") in an empty line. - * Note: For the change operator it is ok. - */ + // Check for trying to delete (e.g. "D") in an empty line. + // Note: For the change operator it is ok. if (oap->motion_type != kMTLineWise && oap->line_count == 1 && oap->op_type == OP_DELETE @@ -1555,11 +1510,9 @@ int op_delete(oparg_T *oap) return OK; } - /* - * Do a yank of whatever we're about to delete. - * If a yank register was specified, put the deleted text into that - * register. For the black hole register '_' don't yank anything. - */ + // Do a yank of whatever we're about to delete. + // If a yank register was specified, put the deleted text into that + // register. For the black hole register '_' don't yank anything. if (oap->regname != '_') { yankreg_T *reg = NULL; int did_yank = false; @@ -1577,6 +1530,7 @@ int op_delete(oparg_T *oap) // Put deleted text into register 1 and shift number registers if the // delete contains a line break, or when using a specific operator (Vi // compatible) + if (oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) { shift_delete_registers(is_append_register(oap->regname)); reg = &y_regs[1]; @@ -1602,9 +1556,7 @@ int op_delete(oparg_T *oap) } } - /* - * block mode delete - */ + // block mode delete if (oap->motion_type == kMTBlockWise) { if (u_save((linenr_T)(oap->start.lnum - 1), (linenr_T)(oap->end.lnum + 1)) == FAIL) { @@ -1627,7 +1579,7 @@ int op_delete(oparg_T *oap) // If we delete a TAB, it may be replaced by several characters. // Thus the number of characters may increase! n = bd.textlen - bd.startspaces - bd.endspaces; - oldp = ml_get(lnum); + oldp = (char_u *)ml_get(lnum); newp = (char_u *)xmalloc(STRLEN(oldp) - (size_t)n + 1); // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); @@ -1672,7 +1624,7 @@ int op_delete(oparg_T *oap) beginline(0); // cursor in column 0 } - int old_len = (int)STRLEN(ml_get(curwin->w_cursor.lnum)); + int old_len = (int)strlen(ml_get(curwin->w_cursor.lnum)); truncate_line(false); // delete the rest of the line extmark_splice_cols(curbuf, @@ -1745,7 +1697,7 @@ int op_delete(oparg_T *oap) if (virtual_op) { // fix up things for virtualedit-delete: // break the tabs which are going to get in our way - char_u *curline = get_cursor_line_ptr(); + char_u *curline = (char_u *)get_cursor_line_ptr(); int len = (int)STRLEN(curline); if (oap->end.coladd != 0 @@ -1826,7 +1778,7 @@ setmarks: static void mb_adjust_opend(oparg_T *oap) { if (oap->inclusive) { - char *p = (char *)ml_get(oap->end.lnum); + char *p = ml_get(oap->end.lnum); oap->end.col += utf_cp_tail_off(p, p + oap->end.col); } } @@ -1835,7 +1787,7 @@ static void mb_adjust_opend(oparg_T *oap) static inline void pbyte(pos_T lp, int c) { assert(c <= UCHAR_MAX); - *(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c; + *(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char)c; if (!curbuf_splice_pending) { extmark_splice_cols(curbuf, (int)lp.lnum - 1, lp.col, 1, 1, kExtmarkUndo); } @@ -1883,9 +1835,7 @@ static int op_replace(oparg_T *oap, int c) return FAIL; } - /* - * block mode replace - */ + // block mode replace if (oap->motion_type == kMTBlockWise) { bd.is_MAX = (curwin->w_curswant == MAXCOL); for (; curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) { @@ -1936,7 +1886,7 @@ static int op_replace(oparg_T *oap, int c) num_chars = numc; numc *= utf_char2len(c); - oldp = get_cursor_line_ptr(); + oldp = (char_u *)get_cursor_line_ptr(); oldlen = (int)STRLEN(oldp); size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces; @@ -2000,9 +1950,9 @@ static int op_replace(oparg_T *oap, int c) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; curwin->w_cursor.col = 0; - oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); + oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); if (oap->end.col) { - --oap->end.col; + oap->end.col--; } } else if (!oap->inclusive) { dec(&(oap->end)); @@ -2011,10 +1961,12 @@ static int op_replace(oparg_T *oap, int c) // TODO(bfredl): we could batch all the splicing // done on the same line, at least while (ltoreq(curwin->w_cursor, oap->end)) { + bool done = false; + n = gchar_cursor(); if (n != NUL) { int new_byte_len = utf_char2len(c); - int old_byte_len = utfc_ptr2len((char *)get_cursor_pos_ptr()); + int old_byte_len = utfc_ptr2len(get_cursor_pos_ptr()); if (new_byte_len > 1 || old_byte_len > 1) { // This is slow, but it handles replacing a single-byte @@ -2023,6 +1975,7 @@ static int op_replace(oparg_T *oap, int c) oap->end.col += new_byte_len - old_byte_len; } replace_character(c); + done = true; } else { if (n == TAB) { int end_vcol = 0; @@ -2038,9 +1991,14 @@ static int op_replace(oparg_T *oap, int c) getvpos(&oap->end, end_vcol); } } - pbyte(curwin->w_cursor, c); + // with "coladd" set may move to just after a TAB + if (gchar_cursor() != NUL) { + pbyte(curwin->w_cursor, c); + done = true; + } } - } else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum) { + } + if (!done && virtual_op && curwin->w_cursor.lnum == oap->end.lnum) { int virtcols = oap->end.coladd; if (curwin->w_cursor.lnum == oap->start.lnum @@ -2090,7 +2048,7 @@ void op_tilde(oparg_T *oap) { pos_T pos; struct block_def bd; - int did_change = FALSE; + int did_change = false; if (u_save((linenr_T)(oap->start.lnum - 1), (linenr_T)(oap->end.lnum + 1)) == FAIL) { @@ -2114,9 +2072,9 @@ void op_tilde(oparg_T *oap) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; pos.col = 0; - oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); + oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); if (oap->end.col) { - --oap->end.col; + oap->end.col--; } } else if (!oap->inclusive) { dec(&(oap->end)); @@ -2143,7 +2101,7 @@ void op_tilde(oparg_T *oap) if (!did_change && oap->is_VIsual) { // No change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -2165,7 +2123,7 @@ void op_tilde(oparg_T *oap) /// @param length is rounded up to include the whole last multi-byte character. /// Also works correctly when the number of bytes changes. /// -/// @return TRUE if some character was changed. +/// @return true if some character was changed. static int swapchars(int op_type, pos_T *pos, int length) FUNC_ATTR_NONNULL_ALL { @@ -2235,7 +2193,7 @@ bool swapchar(int op_type, pos_T *pos) curwin->w_cursor = *pos; // don't use del_char(), it also removes composing chars - del_bytes(utf_ptr2len((char *)get_cursor_pos_ptr()), false, false); + del_bytes(utf_ptr2len(get_cursor_pos_ptr()), false, false); ins_char(nc); curwin->w_cursor = sp; } else { @@ -2250,7 +2208,7 @@ bool swapchar(int op_type, pos_T *pos) void op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; - char_u *firstline, *ins_text; + char *firstline, *ins_text; colnr_T ind_pre_col = 0, ind_post_col; int ind_pre_vcol = 0, ind_post_vcol = 0; struct block_def bd; @@ -2262,7 +2220,8 @@ void op_insert(oparg_T *oap, long count1) // vis block is still marked. Get rid of it now. curwin->w_cursor.lnum = oap->start.lnum; - update_screen(INVERTED); + redraw_curbuf_later(UPD_INVERTED); + update_screen(); if (oap->motion_type == kMTBlockWise) { // When 'virtualedit' is used, need to insert the extra spaces before @@ -2282,7 +2241,7 @@ void op_insert(oparg_T *oap, long count1) coladvance_force(oap->op_type == OP_APPEND ? oap->end_vcol + 1 : getviscol()); if (oap->op_type == OP_APPEND) { - --curwin->w_cursor.col; + curwin->w_cursor.col--; } curwin->w_ve_flags = old_ve_flags; } @@ -2296,17 +2255,17 @@ void op_insert(oparg_T *oap, long count1) if (oap->op_type == OP_APPEND) { firstline += bd.textlen; } - pre_textlen = (long)STRLEN(firstline); + pre_textlen = (long)strlen(firstline); } if (oap->op_type == OP_APPEND) { if (oap->motion_type == kMTBlockWise && curwin->w_cursor.coladd == 0) { // Move the cursor to the character right of the block. - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; while (*get_cursor_pos_ptr() != NUL && (curwin->w_cursor.col < bd.textcol + bd.textlen)) { - ++curwin->w_cursor.col; + curwin->w_cursor.col++; } if (bd.is_short && !bd.is_MAX) { // First line was too short, make it longer and adjust the @@ -2412,19 +2371,17 @@ void op_insert(oparg_T *oap, long count1) if (oap->op_type == OP_APPEND) { pre_textlen += bd2.textlen - bd.textlen; if (bd2.endspaces) { - --bd2.textlen; + bd2.textlen--; } } bd.textcol = bd2.textcol; bd.textlen = bd2.textlen; } - /* - * Subsequent calls to ml_get() flush the firstline data - take a - * copy of the required string. - */ + // Subsequent calls to ml_get() flush the firstline data - take a + // copy of the required string. firstline = ml_get(oap->start.lnum); - const size_t len = STRLEN(firstline); + const size_t len = strlen(firstline); colnr_T add = bd.textcol; colnr_T offset = 0; // offset when cursor was moved in insert mode if (oap->op_type == OP_APPEND) { @@ -2446,12 +2403,12 @@ void op_insert(oparg_T *oap, long count1) } else { firstline += add; } - ins_len = (long)STRLEN(firstline) - pre_textlen - offset; + ins_len = (long)strlen(firstline) - pre_textlen - offset; if (pre_textlen >= 0 && ins_len > 0) { - ins_text = vim_strnsave(firstline, (size_t)ins_len); + ins_text = xstrnsave(firstline, (size_t)ins_len); // block handled here if (u_save(oap->start.lnum, (linenr_T)(oap->end.lnum + 1)) == OK) { - block_insert(oap, ins_text, (oap->op_type == OP_INSERT), &bd); + block_insert(oap, (char_u *)ins_text, (oap->op_type == OP_INSERT), &bd); } curwin->w_cursor.col = oap->start.col; @@ -2463,7 +2420,7 @@ void op_insert(oparg_T *oap, long count1) /// handle a change operation /// -/// @return TRUE if edit() returns because of a CTRL-O command +/// @return true if edit() returns because of a CTRL-O command int op_change(oparg_T *oap) { colnr_T l; @@ -2489,10 +2446,10 @@ int op_change(oparg_T *oap) // save for undo if (curbuf->b_ml.ml_flags & ML_EMPTY) { if (u_save_cursor() == FAIL) { - return FALSE; + return false; } } else if (op_delete(oap) == FAIL) { - return FALSE; + return false; } if ((l > curwin->w_cursor.col) && !LINEEMPTY(curwin->w_cursor.lnum) @@ -2508,9 +2465,9 @@ int op_change(oparg_T *oap) || gchar_cursor() == NUL)) { coladvance_force(getviscol()); } - firstline = ml_get(oap->start.lnum); + firstline = (char_u *)ml_get(oap->start.lnum); pre_textlen = (long)STRLEN(firstline); - pre_indent = (long)getwhitecols(firstline); + pre_indent = (long)getwhitecols((char *)firstline); bd.textcol = curwin->w_cursor.col; } @@ -2518,20 +2475,18 @@ int op_change(oparg_T *oap) fix_indent(); } - retval = edit(NUL, FALSE, (linenr_T)1); + retval = edit(NUL, false, (linenr_T)1); - /* - * In Visual block mode, handle copying the new text to all lines of the - * block. - * Don't repeat the insert when Insert mode ended with CTRL-C. - */ + // In Visual block mode, handle copying the new text to all lines of the + // block. + // Don't repeat the insert when Insert mode ended with CTRL-C. if (oap->motion_type == kMTBlockWise && oap->start.lnum != oap->end.lnum && !got_int) { // Auto-indenting may have changed the indent. If the cursor was past // the indent, exclude that indent change from the inserted text. - firstline = ml_get(oap->start.lnum); + firstline = (char_u *)ml_get(oap->start.lnum); if (bd.textcol > (colnr_T)pre_indent) { - long new_indent = (long)getwhitecols(firstline); + long new_indent = (long)getwhitecols((char *)firstline); pre_textlen += new_indent - pre_indent; bd.textcol += (colnr_T)(new_indent - pre_indent); @@ -2557,7 +2512,7 @@ int op_change(oparg_T *oap) } else { vpos.coladd = 0; } - oldp = ml_get(linenr); + oldp = (char_u *)ml_get(linenr); newp = xmalloc(STRLEN(oldp) + (size_t)vpos.coladd + (size_t)ins_len + 1); // copy up to block start @@ -2701,14 +2656,14 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) break; case kMTLineWise: - reg->y_array[y_idx] = (char *)vim_strsave(ml_get(lnum)); + reg->y_array[y_idx] = xstrdup(ml_get(lnum)); break; case kMTCharWise: { colnr_T startcol = 0, endcol = MAXCOL; int is_oneChar = false; colnr_T cs, ce; - p = ml_get(lnum); + p = (char_u *)ml_get(lnum); bd.startspaces = 0; bd.endspaces = 0; @@ -2717,8 +2672,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) if (virtual_op) { getvcol(curwin, &oap->start, &cs, NULL, &ce); if (ce != cs && oap->start.coladd > 0) { - /* Part of a tab selected -- but don't - * double-count it. */ + // Part of a tab selected -- but don't double-count it. bd.startspaces = (ce - cs + 1) - oap->start.coladd; startcol++; @@ -2734,7 +2688,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) // Don't add space for double-wide // char; endcol will be on last byte // of multi-byte char. - && utf_head_off(p, p + endcol) == 0)) { + && utf_head_off((char *)p, (char *)p + endcol) == 0)) { if (oap->start.lnum == oap->end.lnum && oap->start.col == oap->end.col) { // Special case: inside a single char @@ -2786,8 +2740,8 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) // the new block, unless being Vi compatible. if (curr->y_type == kMTCharWise && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) { - pnew = xmalloc(STRLEN(curr->y_array[curr->y_size - 1]) - + STRLEN(reg->y_array[0]) + 1); + pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1]) + + strlen(reg->y_array[0]) + 1); STRCPY(pnew, curr->y_array[--j]); STRCAT(pnew, reg->y_array[0]); xfree(curr->y_array[j]); @@ -2819,7 +2773,10 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) } // redisplay now, so message is not deleted - update_topline_redraw(); + update_topline(curwin); + if (must_redraw) { + update_screen(); + } if (yank_type == kMTBlockWise) { smsg(NGETTEXT("block of %" PRId64 " line yanked%s", "block of %" PRId64 " lines yanked%s", yanklines), @@ -2867,7 +2824,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx, int s = bd->textlen + bd->endspaces; while (s > 0 && ascii_iswhite(*(bd->textstart + s - 1))) { - s = s - utf_head_off(bd->textstart, bd->textstart + s - 1) - 1; + s = s - utf_head_off((char *)bd->textstart, (char *)bd->textstart + s - 1) - 1; pnew--; } } @@ -2944,9 +2901,9 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) /// @param dir BACKWARD for 'P', FORWARD for 'p' void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) { - char_u *ptr; - char_u *newp; - char_u *oldp; + char *ptr; + char *newp; + char *oldp; int yanklen; size_t totlen = 0; // init for gcc linenr_T lnum = 0; @@ -2983,10 +2940,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curbuf->b_op_start = curwin->w_cursor; // default for '[ mark curbuf->b_op_end = curwin->w_cursor; // default for '] mark - /* - * Using inserted text works differently, because the register includes - * special characters (newlines, etc.). - */ + // Using inserted text works differently, because the register includes + // special characters (newlines, etc.). if (regname == '.' && !reg) { bool non_linewise_vis = (VIsual_active && VIsual_mode != 'V'); @@ -3035,10 +2990,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // curwin->w_cursor.col marks the byte position of the cursor in the // currunt line. It increases up to a max of - // STRLEN(ml_get(curwin->w_cursor.lnum)). With 'virtualedit' and the + // strlen(ml_get(curwin->w_cursor.lnum)). With 'virtualedit' and the // cursor past the end of the line, curwin->w_cursor.coladd is // incremented instead of curwin->w_cursor.col. - char_u *cursor_pos = get_cursor_pos_ptr(); + char_u *cursor_pos = (char_u *)get_cursor_pos_ptr(); bool one_past_line = (*cursor_pos == NUL); bool eol = false; if (!one_past_line) { @@ -3066,10 +3021,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) return; } - /* - * For special registers '%' (file name), '#' (alternate file name) and - * ':' (last command line), etc. we have to create a fake yank register. - */ + // For special registers '%' (file name), '#' (alternate file name) and + // ':' (last command line), etc. we have to create a fake yank register. if (!reg && get_spec_reg(regname, &insert_string, &allocated, true)) { if (insert_string == NULL) { return; @@ -3087,18 +3040,18 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (insert_string != NULL) { y_type = kMTCharWise; if (regname == '=') { - /* For the = register we need to split the string at NL - * characters. - * Loop twice: count the number of lines and save them. */ + // For the = register we need to split the string at NL + // characters. + // Loop twice: count the number of lines and save them. for (;;) { y_size = 0; - ptr = (char_u *)insert_string; + ptr = insert_string; while (ptr != NULL) { if (y_array != NULL) { - y_array[y_size] = (char *)ptr; + y_array[y_size] = ptr; } y_size++; - ptr = (char_u *)vim_strchr((char *)ptr, '\n'); + ptr = vim_strchr(ptr, '\n'); if (ptr != NULL) { if (y_array != NULL) { *ptr = NUL; @@ -3146,12 +3099,12 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (u_save_cursor() == FAIL) { goto end; } - char_u *p = get_cursor_pos_ptr(); + char *p = get_cursor_pos_ptr(); if (dir == FORWARD && *p != NUL) { MB_PTR_ADV(p); } - ptr = vim_strsave(p); - ml_append(curwin->w_cursor.lnum, (char *)ptr, (colnr_T)0, false); + ptr = xstrdup(p); + ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, false); xfree(ptr); oldp = get_cursor_line_ptr(); @@ -3159,8 +3112,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (dir == FORWARD && *p != NUL) { MB_PTR_ADV(p); } - ptr = vim_strnsave(oldp, (size_t)(p - oldp)); - ml_replace(curwin->w_cursor.lnum, (char *)ptr, false); + ptr = xstrnsave(oldp, (size_t)(p - oldp)); + ml_replace(curwin->w_cursor.lnum, ptr, false); nr_lines++; dir = FORWARD; } @@ -3219,7 +3172,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) goto end; } - yanklen = (int)STRLEN(y_array[0]); + yanklen = (int)strlen(y_array[0]); if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) { if (gchar_cursor() == TAB) { @@ -3242,9 +3195,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) lnum = curwin->w_cursor.lnum; col = curwin->w_cursor.col; - /* - * Block mode - */ + // Block mode if (y_type == kMTBlockWise) { int c = gchar_cursor(); colnr_T endcol2 = 0; @@ -3257,7 +3208,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } // move to start of next multi-byte character - curwin->w_cursor.col += utfc_ptr2len((char *)get_cursor_pos_ptr()); + curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); col++; } else { getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); @@ -3306,13 +3257,19 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } // get the old line and advance to the position to insert at oldp = get_cursor_line_ptr(); - oldlen = STRLEN(oldp); - for (ptr = oldp; vcol < col && *ptr;) { + oldlen = strlen(oldp); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0, oldp, oldp); + + while (cts.cts_vcol < col && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize_adv(oldp, &ptr, vcol); - vcol += incr; + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + vcol = cts.cts_vcol; + ptr = cts.cts_ptr; bd.textcol = (colnr_T)(ptr - oldp); + clear_chartabsize_arg(&cts); shortline = (vcol < col) || (vcol == col && !*ptr); @@ -3321,27 +3278,31 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } else if (vcol > col) { bd.endspaces = vcol - col; bd.startspaces = incr - bd.endspaces; - --bd.textcol; + bd.textcol--; delcount = 1; bd.textcol -= utf_head_off(oldp, oldp + bd.textcol); if (oldp[bd.textcol] != TAB) { - /* Only a Tab can be split into spaces. Other - * characters will have to be moved to after the - * block, causing misalignment. */ + // Only a Tab can be split into spaces. Other + // characters will have to be moved to after the + // block, causing misalignment. delcount = 0; bd.endspaces = 0; } } - yanklen = (int)STRLEN(y_array[i]); + yanklen = (int)strlen(y_array[i]); if ((flags & PUT_BLOCK_INNER) == 0) { // calculate number of spaces required to fill right side of // block spaces = y_width + 1; + init_chartabsize_arg(&cts, curwin, 0, 0, y_array[i], y_array[i]); for (int j = 0; j < yanklen; j++) { - spaces -= lbr_chartabsize(NULL, (char_u *)(&y_array[i][j]), 0); + spaces -= lbr_chartabsize(&cts); + cts.cts_ptr++; + cts.cts_vcol = 0; } + clear_chartabsize_arg(&cts); if (spaces < 0) { spaces = 0; } @@ -3355,9 +3316,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) break; } - totlen = (size_t)(count * (yanklen + spaces) - + bd.startspaces + bd.endspaces); - newp = (char_u *)xmalloc(totlen + oldlen + 1); + totlen = (size_t)(count * (yanklen + spaces) + bd.startspaces + bd.endspaces); + newp = xmalloc(totlen + oldlen + 1); // copy part up to cursor to new line ptr = newp; @@ -3390,11 +3350,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) int columns = (int)oldlen - bd.textcol - delcount + 1; assert(columns >= 0); memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns); - ml_replace(curwin->w_cursor.lnum, (char *)newp, false); + ml_replace(curwin->w_cursor.lnum, newp, false); extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, bd.textcol, delcount, (int)totlen + lines_appended, kExtmarkUndo); - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; if (i == 0) { curwin->w_cursor.col += bd.startspaces; } @@ -3418,7 +3378,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curwin->w_cursor.col++; // in Insert mode we might be after the NUL, correct for that - len = (colnr_T)STRLEN(get_cursor_line_ptr()); + len = (colnr_T)strlen(get_cursor_line_ptr()); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -3431,7 +3391,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next // char if (dir == FORWARD && gchar_cursor() != NUL) { - int bytelen = utfc_ptr2len((char *)get_cursor_pos_ptr()); + int bytelen = utfc_ptr2len(get_cursor_pos_ptr()); // put it on the next of the multi-byte character. col += bytelen; @@ -3482,7 +3442,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) totlen = (size_t)(count * yanklen); do { oldp = ml_get(lnum); - oldlen = STRLEN(oldp); + oldlen = strlen(oldp); if (lnum > start_lnum) { pos_T pos = { .lnum = lnum, @@ -3497,7 +3457,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) lnum++; continue; } - newp = (char_u *)xmalloc(totlen + oldlen + 1); + newp = xmalloc(totlen + oldlen + 1); memmove(newp, oldp, (size_t)col); ptr = newp + col; for (i = 0; i < (size_t)count; i++) { @@ -3505,7 +3465,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) ptr += yanklen; } STRMOVE(ptr, oldp + col); - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); // compute the byte offset for the last character first_byte_off = utf_head_off(newp, ptr - 1); @@ -3553,22 +3513,22 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // Then append y_array[0] to first line. lnum = new_cursor.lnum; ptr = ml_get(lnum) + col; - totlen = STRLEN(y_array[y_size - 1]); - newp = (char_u *)xmalloc((size_t)(STRLEN(ptr) + totlen + 1)); + totlen = strlen(y_array[y_size - 1]); + newp = xmalloc((size_t)(strlen(ptr) + totlen + 1)); STRCPY(newp, y_array[y_size - 1]); STRCAT(newp, ptr); // insert second line - ml_append(lnum, (char *)newp, (colnr_T)0, false); + ml_append(lnum, newp, (colnr_T)0, false); new_lnum++; xfree(newp); oldp = ml_get(lnum); - newp = (char_u *)xmalloc((size_t)col + (size_t)yanklen + 1); + newp = xmalloc((size_t)col + (size_t)yanklen + 1); // copy first part of line memmove(newp, oldp, (size_t)col); // append to first line memmove(newp + col, y_array[0], (size_t)yanklen + 1); - ml_replace(lnum, (char *)newp, false); + ml_replace(lnum, newp, false); curwin->w_cursor.lnum = lnum; i = 1; @@ -3588,7 +3548,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curwin->w_cursor.lnum = lnum; ptr = ml_get(lnum); if (cnt == count && i == y_size - 1) { - lendiff = (int)STRLEN(ptr); + lendiff = (int)strlen(ptr); } if (*ptr == '#' && preprocs_left()) { indent = 0; // Leave # lines at start @@ -3605,7 +3565,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curwin->w_cursor = old_pos; // remember how many chars were removed if (cnt == count && i == y_size - 1) { - lendiff -= (int)STRLEN(ml_get(lnum)); + lendiff -= (int)strlen(ml_get(lnum)); } } } @@ -3615,9 +3575,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_type == kMTCharWise || (y_type == kMTLineWise && flags & PUT_LINE_SPLIT)) { for (i = 0; i < y_size - 1; i++) { - totsize += (bcount_t)STRLEN(y_array[i]) + 1; + totsize += (bcount_t)strlen(y_array[i]) + 1; } - lastsize = (int)STRLEN(y_array[y_size - 1]); + lastsize = (int)strlen(y_array[y_size - 1]); totsize += lastsize; } if (y_type == kMTCharWise) { @@ -3661,13 +3621,13 @@ error: // Put the '] mark on the first byte of the last inserted character. // Correct the length for change in indent. curbuf->b_op_end.lnum = new_lnum; - len = STRLEN(y_array[y_size - 1]); + len = strlen(y_array[y_size - 1]); col = (colnr_T)len - lendiff; if (col > 1) { curbuf->b_op_end.col = col - 1; if (len > 0) { - curbuf->b_op_end.col -= utf_head_off((char_u *)y_array[y_size - 1], - (char_u *)y_array[y_size - 1] + len - 1); + curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1], + y_array[y_size - 1] + len - 1); } } else { curbuf->b_op_end.col = 0; @@ -3698,7 +3658,7 @@ error: // put cursor on first non-blank in first inserted line curwin->w_cursor.col = 0; if (dir == FORWARD) { - ++curwin->w_cursor.lnum; + curwin->w_cursor.lnum++; } beginline(BL_WHITE | BL_FIX); } else { // put cursor on first inserted character @@ -3708,7 +3668,7 @@ error: } msgmore(nr_lines); - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; end: if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { @@ -3722,7 +3682,7 @@ end: xfree(y_array); } - VIsual_active = FALSE; + VIsual_active = false; // If the cursor is past the end of the line put it at the end. adjust_cursor_eol(); @@ -3751,7 +3711,7 @@ void adjust_cursor_eol(void) } } -/// @return TRUE if lines starting with '#' should be left aligned. +/// @return true if lines starting with '#' should be left aligned. int preprocs_left(void) { return ((curbuf->b_p_si && !curbuf->b_p_cin) @@ -3837,7 +3797,7 @@ void ex_display(exarg_T *eap) bool do_show = false; for (size_t j = 0; !do_show && j < yb->y_size; j++) { - do_show = !message_filtered((char_u *)yb->y_array[j]); + do_show = !message_filtered(yb->y_array[j]); } if (do_show || yb->y_size == 0) { @@ -3858,14 +3818,13 @@ void ex_display(exarg_T *eap) for (p = (char_u *)yb->y_array[j]; *p != NUL && (n -= ptr2cells((char *)p)) >= 0; p++) { // -V1019 clen = utfc_ptr2len((char *)p); - msg_outtrans_len(p, clen); + msg_outtrans_len((char *)p, clen); p += clen - 1; } } if (n > 1 && yb->y_type == kMTLineWise) { msg_puts_attr("^J", attr); } - ui_flush(); // show one line at a time } os_breakcheck(); } @@ -3874,9 +3833,9 @@ void ex_display(exarg_T *eap) // display last inserted text if ((p = get_last_insert()) != NULL && (arg == NULL || vim_strchr((char *)arg, '.') != NULL) && !got_int - && !message_filtered(p)) { + && !message_filtered((char *)p)) { msg_puts("\n c \". "); - dis_msg(p, true); + dis_msg((char *)p, true); } // display last command line @@ -3889,9 +3848,9 @@ void ex_display(exarg_T *eap) // display current file name if (curbuf->b_fname != NULL && (arg == NULL || vim_strchr((char *)arg, '%') != NULL) && !got_int - && !message_filtered((char_u *)curbuf->b_fname)) { + && !message_filtered(curbuf->b_fname)) { msg_puts("\n c \"% "); - dis_msg((char_u *)curbuf->b_fname, false); + dis_msg(curbuf->b_fname, false); } // display alternate file name @@ -3899,25 +3858,25 @@ void ex_display(exarg_T *eap) char *fname; linenr_T dummy; - if (buflist_name_nr(0, &fname, &dummy) != FAIL && !message_filtered((char_u *)fname)) { + if (buflist_name_nr(0, &fname, &dummy) != FAIL && !message_filtered(fname)) { msg_puts("\n c \"# "); - dis_msg((char_u *)fname, false); + dis_msg(fname, false); } } // display last search pattern if (last_search_pat() != NULL && (arg == NULL || vim_strchr((char *)arg, '/') != NULL) && !got_int - && !message_filtered(last_search_pat())) { + && !message_filtered((char *)last_search_pat())) { msg_puts("\n c \"/ "); - dis_msg(last_search_pat(), false); + dis_msg((char *)last_search_pat(), false); } // display last used expression if (expr_line != NULL && (arg == NULL || vim_strchr((char *)arg, '=') != NULL) - && !got_int && !message_filtered(expr_line)) { + && !got_int && !message_filtered((char *)expr_line)) { msg_puts("\n c \"= "); - dis_msg(expr_line, false); + dis_msg((char *)expr_line, false); } } @@ -3925,7 +3884,7 @@ void ex_display(exarg_T *eap) /// truncate at end of screen line /// /// @param skip_esc if true, ignore trailing ESC -static void dis_msg(const char_u *p, bool skip_esc) +static void dis_msg(const char *p, bool skip_esc) FUNC_ATTR_NONNULL_ALL { int n; @@ -3934,8 +3893,8 @@ static void dis_msg(const char_u *p, bool skip_esc) n = Columns - 6; while (*p != NUL && !(*p == ESC && skip_esc && *(p + 1) == NUL) - && (n -= ptr2cells((char *)p)) >= 0) { - if ((l = utfc_ptr2len((char *)p)) > 1) { + && (n -= ptr2cells(p)) >= 0) { + if ((l = utfc_ptr2len(p)) > 1) { msg_outtrans_len(p, l); p += l; } else { @@ -3956,11 +3915,11 @@ static void dis_msg(const char_u *p, bool skip_esc) /// @param include_space - whether to skip space following the comment leader /// @param[out] is_comment - whether the current line ends with an unclosed /// comment. -char_u *skip_comment(char_u *line, bool process, bool include_space, bool *is_comment) +char *skip_comment(char *line, bool process, bool include_space, bool *is_comment) { char *comment_flags = NULL; int lead_len; - int leader_offset = get_last_leader_offset((char *)line, &comment_flags); + int leader_offset = get_last_leader_offset(line, &comment_flags); *is_comment = false; if (leader_offset != -1) { @@ -3982,7 +3941,7 @@ char_u *skip_comment(char_u *line, bool process, bool include_space, bool *is_co return line; } - lead_len = get_leader_len((char *)line, &comment_flags, false, include_space); + lead_len = get_leader_len(line, &comment_flags, false, include_space); if (lead_len == 0) { return line; @@ -4011,8 +3970,8 @@ char_u *skip_comment(char_u *line, bool process, bool include_space, bool *is_co } /// @param count number of lines (minimal 2) to join at cursor position. -/// @param save_undo when TRUE, save lines for undo first. -/// @param use_formatoptions set to FALSE when e.g. processing backspace and comment +/// @param save_undo when true, save lines for undo first. +/// @param use_formatoptions set to false when e.g. processing backspace and comment /// leaders should not be removed. /// @param setmark when true, sets the '[ and '] mark, else, the caller is expected /// to set those marks. @@ -4020,11 +3979,11 @@ char_u *skip_comment(char_u *line, bool process, bool include_space, bool *is_co /// @return FAIL for failure, OK otherwise int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions, bool setmark) { - char_u *curr = NULL; - char_u *curr_start = NULL; - char_u *cend; - char_u *newp; - char_u *spaces; // number of spaces inserted before a line + char *curr = NULL; + char *curr_start = NULL; + char *cend; + char *newp; + char *spaces; // number of spaces inserted before a line int endcurr1 = NUL; int endcurr2 = NUL; int currsize = 0; // size of the current line @@ -4033,7 +3992,7 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions colnr_T col = 0; int ret = OK; int *comments = NULL; - int remove_comments = (use_formatoptions == TRUE) + int remove_comments = (use_formatoptions == true) && has_format_option(FO_REMOVE_COMS); bool prev_was_comment = false; assert(count >= 1); @@ -4053,18 +4012,18 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions // Don't move anything, just compute the final line length // and setup the array of space strings lengths for (t = 0; t < (linenr_T)count; t++) { - curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t)); + curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t)); + curr = curr_start; if (t == 0 && setmark && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // Set the '[ mark. curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum; - curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr); + curwin->w_buffer->b_op_start.col = (colnr_T)strlen(curr); } if (remove_comments) { // We don't want to remove the comment leader if the // previous line is not a comment. if (t > 0 && prev_was_comment) { - char_u *new_curr = skip_comment(curr, true, insert_space, - &prev_was_comment); + char *new_curr = skip_comment(curr, true, insert_space, &prev_was_comment); comments[t] = (int)(new_curr - curr); curr = new_curr; } else { @@ -4073,26 +4032,26 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions } if (insert_space && t > 0) { - curr = (char_u *)skipwhite((char *)curr); + curr = skipwhite(curr); if (*curr != NUL && *curr != ')' && sumsize != 0 && endcurr1 != TAB && (!has_format_option(FO_MBYTE_JOIN) - || (utf_ptr2char((char *)curr) < 0x100 && endcurr1 < 0x100)) + || (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100)) && (!has_format_option(FO_MBYTE_JOIN2) - || (utf_ptr2char((char *)curr) < 0x100 && !utf_eat_space(endcurr1)) + || (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1)) || (endcurr1 < 0x100 - && !utf_eat_space(utf_ptr2char((char *)curr))))) { + && !utf_eat_space(utf_ptr2char(curr))))) { // don't add a space if the line is ending in a space if (endcurr1 == ' ') { endcurr1 = endcurr2; } else { - ++spaces[t]; + spaces[t]++; } // Extra space when 'joinspaces' set and line ends in '.', '?', or '!'. if (p_js && (endcurr1 == '.' || endcurr1 == '?' || endcurr1 == '!')) { - ++spaces[t]; + spaces[t]++; } } } @@ -4104,16 +4063,16 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions 0, spaces[t], spaces[t], kExtmarkUndo); } - currsize = (int)STRLEN(curr); + currsize = (int)strlen(curr); sumsize += currsize + spaces[t]; endcurr1 = endcurr2 = NUL; if (insert_space && currsize > 0) { cend = curr + currsize; MB_PTR_BACK(curr, cend); - endcurr1 = utf_ptr2char((char *)cend); + endcurr1 = utf_ptr2char(cend); if (cend > curr) { MB_PTR_BACK(curr, cend); - endcurr2 = utf_ptr2char((char *)cend); + endcurr2 = utf_ptr2char(cend); } } line_breakcheck(); @@ -4127,17 +4086,15 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions col = sumsize - currsize - spaces[count - 1]; // allocate the space for the new line - newp = (char_u *)xmalloc((size_t)sumsize + 1); + newp = xmalloc((size_t)sumsize + 1); cend = newp + sumsize; *cend = 0; - /* - * Move affected lines to the new long one. - * - * Move marks from each deleted line to the joined line, adjusting the - * column. This is not Vi compatible, but Vi deletes the marks, thus that - * should not really be a problem. - */ + // Move affected lines to the new long one. + // + // Move marks from each deleted line to the joined line, adjusting the + // column. This is not Vi compatible, but Vi deletes the marks, thus that + // should not really be a problem. curbuf_splice_pending++; @@ -4163,17 +4120,18 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions break; } - curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1)); + curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1)); + curr = curr_start; if (remove_comments) { curr += comments[t - 1]; } if (insert_space && t > 1) { - curr = (char_u *)skipwhite((char *)curr); + curr = skipwhite(curr); } - currsize = (int)STRLEN(curr); + currsize = (int)strlen(curr); } - ml_replace(curwin->w_cursor.lnum, (char *)newp, false); + ml_replace(curwin->w_cursor.lnum, newp, false); if (setmark && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // Set the '] mark. @@ -4186,11 +4144,9 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions changed_lines(curwin->w_cursor.lnum, currsize, curwin->w_cursor.lnum + 1, 0L, true); - /* - * Delete following lines. To do this we move the cursor there - * briefly, and then move it back. After del_lines() the cursor may - * have moved up (last line deleted), so the current lnum is kept in t. - */ + // Delete following lines. To do this we move the cursor there + // briefly, and then move it back. After del_lines() the cursor may + // have moved up (last line deleted), so the current lnum is kept in t. t = curwin->w_cursor.lnum; curwin->w_cursor.lnum++; del_lines((long)count - 1, false); @@ -4198,17 +4154,15 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions curbuf_splice_pending--; curbuf->deleted_bytes2 = 0; - /* - * Set the cursor column: - * Vi compatible: use the column of the first join - * vim: use the column of the last join - */ + // Set the cursor column: + // Vi compatible: use the column of the first join + // vim: use the column of the last join curwin->w_cursor.col = (vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col); check_cursor_col(); curwin->w_cursor.coladd = 0; - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; theend: xfree(spaces); @@ -4218,530 +4172,27 @@ theend: return ret; } -/// @return TRUE if the two comment leaders given are the same. -/// -/// @param lnum The first line. White-space is ignored. -/// -/// @note the whole of 'leader1' must match 'leader2_len' characters from 'leader2'. -static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, int leader2_len, - char_u *leader2_flags) -{ - int idx1 = 0, idx2 = 0; - char_u *p; - char_u *line1; - char_u *line2; - - if (leader1_len == 0) { - return leader2_len == 0; - } - - /* - * If first leader has 'f' flag, the lines can be joined only if the - * second line does not have a leader. - * If first leader has 'e' flag, the lines can never be joined. - * If first leader has 's' flag, the lines can only be joined if there is - * some text after it and the second line has the 'm' flag. - */ - if (leader1_flags != NULL) { - for (p = leader1_flags; *p && *p != ':'; ++p) { - if (*p == COM_FIRST) { - return leader2_len == 0; - } - if (*p == COM_END) { - return FALSE; - } - if (*p == COM_START) { - if (*(ml_get(lnum) + leader1_len) == NUL) { - return FALSE; - } - if (leader2_flags == NULL || leader2_len == 0) { - return FALSE; - } - for (p = leader2_flags; *p && *p != ':'; ++p) { - if (*p == COM_MIDDLE) { - return TRUE; - } - } - return FALSE; - } - } - } - - /* - * Get current line and next line, compare the leaders. - * The first line has to be saved, only one line can be locked at a time. - */ - line1 = vim_strsave(ml_get(lnum)); - for (idx1 = 0; ascii_iswhite(line1[idx1]); idx1++) {} - line2 = ml_get(lnum + 1); - for (idx2 = 0; idx2 < leader2_len; ++idx2) { - if (!ascii_iswhite(line2[idx2])) { - if (line1[idx1++] != line2[idx2]) { - break; - } - } else { - while (ascii_iswhite(line1[idx1])) { - idx1++; - } - } - } - xfree(line1); - - return idx2 == leader2_len && idx1 == leader1_len; -} - -/// Implementation of the format operator 'gq'. -/// -/// @param keep_cursor keep cursor on same text char -static void op_format(oparg_T *oap, int keep_cursor) -{ - linenr_T old_line_count = curbuf->b_ml.ml_line_count; - - // Place the cursor where the "gq" or "gw" command was given, so that "u" - // can put it back there. - curwin->w_cursor = oap->cursor_start; - - if (u_save((linenr_T)(oap->start.lnum - 1), - (linenr_T)(oap->end.lnum + 1)) == FAIL) { - return; - } - curwin->w_cursor = oap->start; - - if (oap->is_VIsual) { - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - } - - if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { - // Set '[ mark at the start of the formatted area - curbuf->b_op_start = oap->start; - } - - // For "gw" remember the cursor position and put it back below (adjusted - // for joined and split lines). - if (keep_cursor) { - saved_cursor = oap->cursor_start; - } - - format_lines((linenr_T)oap->line_count, keep_cursor); - - /* - * Leave the cursor at the first non-blank of the last formatted line. - * If the cursor was moved one line back (e.g. with "Q}") go to the next - * line, so "." will do the next lines. - */ - if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - ++curwin->w_cursor.lnum; - } - beginline(BL_WHITE | BL_FIX); - old_line_count = curbuf->b_ml.ml_line_count - old_line_count; - msgmore(old_line_count); - - if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { - // put '] mark on the end of the formatted area - curbuf->b_op_end = curwin->w_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) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_old_cursor_lnum != 0) { - // When lines have been inserted or deleted, adjust the end of - // the Visual area to be redrawn. - if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) { - wp->w_old_cursor_lnum += old_line_count; - } else { - wp->w_old_visual_lnum += old_line_count; - } - } - } - } -} - -/// Implementation of the format operator 'gq' for when using 'formatexpr'. -static void op_formatexpr(oparg_T *oap) -{ - if (oap->is_VIsual) { - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - } - - if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) { - // As documented: when 'formatexpr' returns non-zero fall back to - // internal formatting. - op_format(oap, false); - } -} - -/// @param c character to be inserted -int fex_format(linenr_T lnum, long count, int c) +/// Reset 'linebreak' and take care of side effects. +/// @return the previous value, to be passed to restore_lbr(). +static bool reset_lbr(void) { - int use_sandbox = was_set_insecurely(curwin, "formatexpr", OPT_LOCAL); - int r; - char_u *fex; - - /* - * Set v:lnum to the first line number and v:count to the number of lines. - * Set v:char to the character to be inserted (can be NUL). - */ - set_vim_var_nr(VV_LNUM, (varnumber_T)lnum); - set_vim_var_nr(VV_COUNT, (varnumber_T)count); - set_vim_var_char(c); - - // Make a copy, the option could be changed while calling it. - fex = vim_strsave(curbuf->b_p_fex); - // Evaluate the function. - if (use_sandbox) { - sandbox++; - } - r = (int)eval_to_number((char *)fex); - if (use_sandbox) { - sandbox--; - } - - set_vim_var_string(VV_CHAR, NULL, -1); - xfree(fex); - - return r; -} - -/// @param line_count number of lines to format, starting at the cursor position. -/// when negative, format until the end of the paragraph. -/// -/// Lines after the cursor line are saved for undo, caller must have saved the -/// first line. -/// -/// @param avoid_fex don't use 'formatexpr' -void format_lines(linenr_T line_count, int avoid_fex) -{ - bool is_not_par; // current line not part of parag. - bool next_is_not_par; // next line not part of paragraph - bool is_end_par; // at end of paragraph - bool prev_is_end_par = false; // prev. line not part of parag. - bool next_is_start_par = false; - int leader_len = 0; // leader len of current line - int next_leader_len; // leader len of next line - char_u *leader_flags = NULL; // flags for leader of current line - char_u *next_leader_flags = NULL; // flags for leader of next line - bool advance = true; - int second_indent = -1; // indent for second line (comment aware) - bool first_par_line = true; - int smd_save; - long count; - bool need_set_indent = true; // set indent of next paragraph - linenr_T first_line = curwin->w_cursor.lnum; - bool force_format = false; - const int old_State = State; - - // length of a line to force formatting: 3 * 'tw' - const int max_len = comp_textwidth(true) * 3; - - // check for 'q', '2' and '1' in 'formatoptions' - const bool do_comments = has_format_option(FO_Q_COMS); // format comments - int do_comments_list = 0; // format comments with 'n' or '2' - const bool do_second_indent = has_format_option(FO_Q_SECOND); - const bool do_number_indent = has_format_option(FO_Q_NUMBER); - const bool do_trail_white = has_format_option(FO_WHITE_PAR); - - // Get info about the previous and current line. - if (curwin->w_cursor.lnum > 1) { - is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1, - &leader_len, &leader_flags, do_comments); - } else { - is_not_par = true; - } - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum, - &next_leader_len, &next_leader_flags, do_comments - ); - is_end_par = (is_not_par || next_is_not_par); - if (!is_end_par && do_trail_white) { - is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); - } - - curwin->w_cursor.lnum--; - for (count = line_count; count != 0 && !got_int; --count) { - /* - * Advance to next paragraph. - */ - if (advance) { - curwin->w_cursor.lnum++; - prev_is_end_par = is_end_par; - is_not_par = next_is_not_par; - leader_len = next_leader_len; - leader_flags = next_leader_flags; - } - - /* - * The last line to be formatted. - */ - if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) { - next_is_not_par = true; - next_leader_len = 0; - next_leader_flags = NULL; - } else { - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1, - &next_leader_len, &next_leader_flags, do_comments - ); - if (do_number_indent) { - next_is_start_par = - (get_number_indent(curwin->w_cursor.lnum + 1) > 0); - } - } - advance = true; - is_end_par = (is_not_par || next_is_not_par || next_is_start_par); - if (!is_end_par && do_trail_white) { - is_end_par = !ends_in_white(curwin->w_cursor.lnum); - } - - /* - * Skip lines that are not in a paragraph. - */ - if (is_not_par) { - if (line_count < 0) { - break; - } - } else { - /* - * For the first line of a paragraph, check indent of second line. - * Don't do this for comments and empty lines. - */ - if (first_par_line - && (do_second_indent || do_number_indent) - && prev_is_end_par - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) { - if (leader_len == 0 && next_leader_len == 0) { - // no comment found - second_indent = - get_indent_lnum(curwin->w_cursor.lnum + 1); - } else { - second_indent = next_leader_len; - do_comments_list = 1; - } - } else if (do_number_indent) { - if (leader_len == 0 && next_leader_len == 0) { - // no comment found - second_indent = - get_number_indent(curwin->w_cursor.lnum); - } else { - // get_number_indent() is now "comment aware"... - second_indent = - get_number_indent(curwin->w_cursor.lnum); - do_comments_list = 1; - } - } - } - - /* - * When the comment leader changes, it's the end of the paragraph. - */ - if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count - || !same_leader(curwin->w_cursor.lnum, - leader_len, leader_flags, - next_leader_len, - next_leader_flags)) { - // Special case: If the next line starts with a line comment - // and this line has a line comment after some text, the - // paragraph doesn't really end. - if (next_leader_flags == NULL - || STRNCMP(next_leader_flags, "://", 3) != 0 - || check_linecomment(get_cursor_line_ptr()) == MAXCOL) { - is_end_par = true; - } - } - - /* - * If we have got to the end of a paragraph, or the line is - * getting long, format it. - */ - if (is_end_par || force_format) { - if (need_set_indent) { - int indent = 0; // amount of indent needed - - // Replace indent in first line of a paragraph with minimal - // number of tabs and spaces, according to current options. - // For the very first formatted line keep the current - // indent. - if (curwin->w_cursor.lnum == first_line) { - indent = get_indent(); - } else if (curbuf->b_p_lisp) { - indent = get_lisp_indent(); - } else { - if (cindent_on()) { - indent = *curbuf->b_p_inde != NUL ? get_expr_indent() : get_c_indent(); - } else { - indent = get_indent(); - } - } - (void)set_indent(indent, SIN_CHANGED); - } - - // put cursor on last non-space - State = MODE_NORMAL; // don't go past end-of-line - coladvance(MAXCOL); - while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) { - dec_cursor(); - } - - // do the formatting, without 'showmode' - State = MODE_INSERT; // for open_line() - smd_save = p_smd; - p_smd = FALSE; - insertchar(NUL, INSCHAR_FORMAT - + (do_comments ? INSCHAR_DO_COM : 0) - + (do_comments && do_comments_list - ? INSCHAR_COM_LIST : 0) - + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); - State = old_State; - p_smd = smd_save; - second_indent = -1; - // at end of par.: need to set indent of next par. - need_set_indent = is_end_par; - if (is_end_par) { - // When called with a negative line count, break at the - // end of the paragraph. - if (line_count < 0) { - break; - } - first_par_line = true; - } - force_format = false; - } - - /* - * When still in same paragraph, join the lines together. But - * first delete the leader from the second line. - */ - if (!is_end_par) { - advance = false; - curwin->w_cursor.lnum++; - curwin->w_cursor.col = 0; - if (line_count < 0 && u_save_cursor() == FAIL) { - break; - } - if (next_leader_len > 0) { - (void)del_bytes(next_leader_len, false, false); - mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L, - (long)-next_leader_len, 0); - } else if (second_indent > 0) { // the "leader" for FO_Q_SECOND - int indent = (int)getwhitecols_curline(); - - if (indent > 0) { - (void)del_bytes(indent, false, false); - mark_col_adjust(curwin->w_cursor.lnum, - (colnr_T)0, 0L, (long)-indent, 0); - } - } - curwin->w_cursor.lnum--; - if (do_join(2, TRUE, FALSE, FALSE, false) == FAIL) { - beep_flush(); - break; - } - first_par_line = false; - // If the line is getting long, format it next time - if (STRLEN(get_cursor_line_ptr()) > (size_t)max_len) { - force_format = true; - } else { - force_format = false; - } - } - } - line_breakcheck(); - } -} - -/// @return TRUE if line "lnum" ends in a white character. -static int ends_in_white(linenr_T lnum) -{ - char_u *s = ml_get(lnum); - size_t l; - - if (*s == NUL) { - return FALSE; - } - l = STRLEN(s) - 1; - return ascii_iswhite(s[l]); -} - -/// Blank lines, and lines containing only the comment leader, are left -/// untouched by the formatting. The function returns TRUE in this -/// case. It also returns TRUE when a line starts with the end of a comment -/// ('e' in comment flags), so that this line is skipped, and not joined to the -/// previous line. A new paragraph starts after a blank line, or when the -/// comment leader changes. -static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags, int do_comments) -{ - char_u *flags = NULL; // init for GCC - char_u *ptr; - - ptr = ml_get(lnum); - if (do_comments) { - *leader_len = get_leader_len((char *)ptr, (char **)leader_flags, false, true); - } else { - *leader_len = 0; - } - - if (*leader_len > 0) { - /* - * Search for 'e' flag in comment leader flags. - */ - flags = *leader_flags; - while (*flags && *flags != ':' && *flags != COM_END) { - flags++; - } + if (!curwin->w_p_lbr) { + return false; } - - return *skipwhite((char *)ptr + *leader_len) == NUL - || (*leader_len > 0 && *flags == COM_END) - || startPS(lnum, NUL, FALSE); + // changing 'linebreak' may require w_virtcol to be updated + curwin->w_p_lbr = false; + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); + return true; } -/// Used for auto-formatting. -/// -/// @return TRUE when a paragraph starts in line "lnum". -/// FALSE when the previous line is in the same paragraph. -int paragraph_start(linenr_T lnum) +/// Restore 'linebreak' and take care of side effects. +static void restore_lbr(bool lbr_saved) { - char_u *p; - int leader_len = 0; // leader len of current line - char_u *leader_flags = NULL; // flags for leader of current line - int next_leader_len = 0; // leader len of next line - char_u *next_leader_flags = NULL; // flags for leader of next line - - if (lnum <= 1) { - return TRUE; // start of the file - } - p = ml_get(lnum - 1); - if (*p == NUL) { - return TRUE; // after empty line - } - const bool do_comments = has_format_option(FO_Q_COMS); // format comments - if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) { - return true; // after non-paragraph line - } - - if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) { - return true; // "lnum" is not a paragraph line + if (!curwin->w_p_lbr && lbr_saved) { + // changing 'linebreak' may require w_virtcol to be updated + curwin->w_p_lbr = true; + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); } - - if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) { - return TRUE; // missing trailing space in previous line. - } - if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) { - return TRUE; // numbered item starts in "lnum". - } - if (!same_leader(lnum - 1, leader_len, leader_flags, - next_leader_len, next_leader_flags)) { - return TRUE; // change of comment leader. - } - return FALSE; } /// prepare a few things for block mode yank/delete/tilde @@ -4758,15 +4209,14 @@ int paragraph_start(linenr_T lnum) static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del) { int incr = 0; - char_u *pend; - char_u *pstart; - char_u *line; - char_u *prev_pstart; - char_u *prev_pend; - const int lbr_saved = curwin->w_p_lbr; - + char *pend; + char *pstart; + char *line; + char *prev_pstart; + char *prev_pend; // Avoid a problem with unwanted linebreaks in block mode. - curwin->w_p_lbr = false; + const bool lbr_saved = reset_lbr(); + bdp->startspaces = 0; bdp->endspaces = 0; bdp->textlen = 0; @@ -4780,22 +4230,28 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool bdp->start_char_vcols = 0; line = ml_get(lnum); - pstart = line; prev_pstart = line; - while (bdp->start_vcol < oap->start_vcol && *pstart) { + + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, lnum, bdp->start_vcol, line, line); + while (cts.cts_vcol < oap->start_vcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize(line, pstart, bdp->start_vcol); - bdp->start_vcol += incr; - if (ascii_iswhite(*pstart)) { + incr = lbr_chartabsize(&cts); + cts.cts_vcol += incr; + if (ascii_iswhite(*cts.cts_ptr)) { bdp->pre_whitesp += incr; bdp->pre_whitesp_c++; } else { bdp->pre_whitesp = 0; bdp->pre_whitesp_c = 0; } - prev_pstart = pstart; - MB_PTR_ADV(pstart); + prev_pstart = cts.cts_ptr; + MB_PTR_ADV(cts.cts_ptr); } + bdp->start_vcol = cts.cts_vcol; + pstart = cts.cts_ptr; + clear_chartabsize_arg(&cts); + bdp->start_char_vcols = incr; if (bdp->start_vcol < oap->start_vcol) { // line too short bdp->end_vcol = bdp->start_vcol; @@ -4831,13 +4287,18 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool } } } else { + init_chartabsize_arg(&cts, curwin, lnum, bdp->end_vcol, line, pend); prev_pend = pend; - while (bdp->end_vcol <= oap->end_vcol && *pend != NUL) { + while (cts.cts_vcol <= oap->end_vcol && *cts.cts_ptr != NUL) { // Count a tab for what it's worth (if list mode not on) - prev_pend = pend; - incr = lbr_chartabsize_adv(line, &pend, bdp->end_vcol); - bdp->end_vcol += incr; + prev_pend = cts.cts_ptr; + incr = lbr_chartabsize_adv(&cts); + cts.cts_vcol += incr; } + bdp->end_vcol = cts.cts_vcol; + pend = cts.cts_ptr; + clear_chartabsize_arg(&cts); + if (bdp->end_vcol <= oap->end_vcol && (!is_del || oap->op_type == OP_APPEND @@ -4868,8 +4329,8 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool bdp->textlen = (int)(pend - pstart); } bdp->textcol = (colnr_T)(pstart - line); - bdp->textstart = pstart; - curwin->w_p_lbr = lbr_saved; + bdp->textstart = (char_u *)pstart; + restore_lbr(lbr_saved); } /// Handle the add/subtract operator. @@ -4921,20 +4382,20 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) } else if (oap->motion_type == kMTLineWise) { curwin->w_cursor.col = 0; pos.col = 0; - length = (colnr_T)STRLEN(ml_get(pos.lnum)); + length = (colnr_T)strlen(ml_get(pos.lnum)); } else { // oap->motion_type == kMTCharWise if (pos.lnum == oap->start.lnum && !oap->inclusive) { dec(&(oap->end)); } - length = (colnr_T)STRLEN(ml_get(pos.lnum)); + length = (colnr_T)strlen(ml_get(pos.lnum)); pos.col = 0; if (pos.lnum == oap->start.lnum) { pos.col += oap->start.col; length -= oap->start.col; } if (pos.lnum == oap->end.lnum) { - length = (int)STRLEN(ml_get(oap->end.lnum)); + length = (int)strlen(ml_get(oap->end.lnum)); if (oap->end.col >= length) { oap->end.col = length - 1; } @@ -4962,7 +4423,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) if (!change_cnt && oap->is_VIsual) { // No change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); } // Set '[ mark if something changed. Keep the last end @@ -5010,12 +4471,12 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) pos_T endpos; colnr_T save_coladd = 0; - const bool do_hex = vim_strchr((char *)curbuf->b_p_nf, 'x') != NULL; // "heX" - const bool do_oct = vim_strchr((char *)curbuf->b_p_nf, 'o') != NULL; // "Octal" - const bool do_bin = vim_strchr((char *)curbuf->b_p_nf, 'b') != NULL; // "Bin" - const bool do_alpha = vim_strchr((char *)curbuf->b_p_nf, 'p') != NULL; // "alPha" + const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX" + const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal" + const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin" + const bool do_alpha = vim_strchr(curbuf->b_p_nf, 'p') != NULL; // "alPha" // "Unsigned" - const bool do_unsigned = vim_strchr((char *)curbuf->b_p_nf, 'u') != NULL; + const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; if (virtual_active()) { save_coladd = pos->coladd; @@ -5023,7 +4484,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } curwin->w_cursor = *pos; - ptr = ml_get(pos->lnum); + ptr = (char_u *)ml_get(pos->lnum); col = pos->col; if (*ptr == NUL || col + !!save_coladd >= (int)STRLEN(ptr)) { @@ -5035,14 +4496,14 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if (do_bin) { while (col > 0 && ascii_isbdigit(ptr[col])) { col--; - col -= utf_head_off(ptr, ptr + col); + col -= utf_head_off((char *)ptr, (char *)ptr + col); } } if (do_hex) { while (col > 0 && ascii_isxdigit(ptr[col])) { col--; - col -= utf_head_off(ptr, ptr + col); + col -= utf_head_off((char *)ptr, (char *)ptr + col); } } if (do_bin @@ -5050,7 +4511,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) && !((col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' - && !utf_head_off(ptr, ptr + col - 1) + && !utf_head_off((char *)ptr, (char *)ptr + col - 1) && ascii_isxdigit(ptr[col + 1])))) { // In case of binary/hexadecimal pattern overlap match, rescan @@ -5058,7 +4519,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) while (col > 0 && ascii_isdigit(ptr[col])) { col--; - col -= utf_head_off(ptr, ptr + col); + col -= utf_head_off((char *)ptr, (char *)ptr + col); } } @@ -5066,17 +4527,17 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) && col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' - && !utf_head_off(ptr, ptr + col - 1) + && !utf_head_off((char *)ptr, (char *)ptr + col - 1) && ascii_isxdigit(ptr[col + 1])) || (do_bin && col > 0 && (ptr[col] == 'B' || ptr[col] == 'b') && ptr[col - 1] == '0' - && !utf_head_off(ptr, ptr + col - 1) + && !utf_head_off((char *)ptr, (char *)ptr + col - 1) && ascii_isbdigit(ptr[col + 1]))) { // Found hexadecimal or binary number, move to its start. col--; - col -= utf_head_off(ptr, ptr + col); + col -= utf_head_off((char *)ptr, (char *)ptr + col); } else { // Search forward and then backward to find the start of number. col = pos->col; @@ -5109,7 +4570,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } if (col > pos->col && ptr[col - 1] == '-' - && !utf_head_off(ptr, ptr + col - 1) + && !utf_head_off((char *)ptr, (char *)ptr + col - 1) && !do_unsigned) { negative = true; was_positive = false; @@ -5155,7 +4616,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) curwin->w_cursor.col = col; } else { if (col > 0 && ptr[col - 1] == '-' - && !utf_head_off(ptr, ptr + col - 1) + && !utf_head_off((char *)ptr, (char *)ptr + col - 1) && !visual && !do_unsigned) { // negative number @@ -5170,7 +4631,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) : length); } - vim_str2nr(ptr + col, &pre, &length, + vim_str2nr((char *)ptr + col, &pre, &length, 0 + (do_bin ? STR2NR_BIN : 0) + (do_oct ? STR2NR_OCT : 0) + (do_hex ? STR2NR_HEX : 0), @@ -5314,7 +4775,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } *ptr = NUL; STRCAT(buf1, buf2); - ins_str(buf1); // insert the new number + ins_str((char *)buf1); // insert the new number endpos = curwin->w_cursor; if (curwin->w_cursor.col) { curwin->w_cursor.col--; @@ -5412,13 +4873,13 @@ void format_reg_type(MotionType reg_type, colnr_T reg_width, char *buf, size_t b /// Otherwise just return `s`. /// /// @return a void * for use in get_reg_contents(). -static void *get_reg_wrap_one_line(char_u *s, int flags) +static void *get_reg_wrap_one_line(char *s, int flags) { if (!(flags & kGRegList)) { return s; } list_T *const list = tv_list_alloc(1); - tv_list_append_allocated_string(list, (char *)s); + tv_list_append_allocated_string(list, s); return list; } @@ -5460,9 +4921,9 @@ void *get_reg_contents(int regname, int flags) return NULL; } if (allocated) { - return get_reg_wrap_one_line((char_u *)retval, flags); + return get_reg_wrap_one_line(retval, flags); } - return get_reg_wrap_one_line(vim_strsave((char_u *)retval), flags); + return get_reg_wrap_one_line(xstrdup(retval), flags); } yankreg_T *reg = get_yank_register(regname, YREG_PASTE); @@ -5479,16 +4940,12 @@ void *get_reg_contents(int regname, int flags) return list; } - /* - * Compute length of resulting string. - */ + // Compute length of resulting string. size_t len = 0; for (size_t i = 0; i < reg->y_size; i++) { - len += STRLEN(reg->y_array[i]); - /* - * Insert a newline between lines and after last line if - * y_type is kMTLineWise. - */ + len += strlen(reg->y_array[i]); + // Insert a newline between lines and after last line if + // y_type is kMTLineWise. if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { len++; } @@ -5496,18 +4953,14 @@ void *get_reg_contents(int regname, int flags) retval = xmalloc(len + 1); - /* - * Copy the lines of the yank register into the string. - */ + // Copy the lines of the yank register into the string. len = 0; for (size_t i = 0; i < reg->y_size; i++) { STRCPY(retval + len, reg->y_array[i]); - len += STRLEN(retval + len); + len += strlen(retval + len); - /* - * Insert a NL between lines and after the last line if y_type is - * kMTLineWise. - */ + // Insert a NL between lines and after the last line if y_type is + // kMTLineWise. if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { retval[len++] = '\n'; } @@ -5548,7 +5001,7 @@ static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous /// store `str` in register `name` /// /// @see write_reg_contents_ex -void write_reg_contents(int name, const char_u *str, ssize_t len, int must_append) +void write_reg_contents(int name, const char *str, ssize_t len, int must_append) { write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0L); } @@ -5557,9 +5010,9 @@ void write_reg_contents_lst(int name, char **strings, bool must_append, MotionTy colnr_T block_len) { if (name == '/' || name == '=') { - char_u *s = (char_u *)strings[0]; + char *s = strings[0]; if (strings[0] == NULL) { - s = (char_u *)""; + s = ""; } else if (strings[1] != NULL) { emsg(_("E883: search pattern and expression register may not " "contain two or more lines")); @@ -5579,7 +5032,7 @@ void write_reg_contents_lst(int name, char **strings, bool must_append, MotionTy return; } - str_to_reg(reg, yank_type, (char *)strings, STRLEN((char_u *)strings), + str_to_reg(reg, yank_type, (char *)strings, STRLEN(strings), block_len, true); finish_write_reg(name, reg, old_y_previous); } @@ -5602,16 +5055,16 @@ void write_reg_contents_lst(int name, char **strings, bool must_append, MotionTy /// is an uppercase letter. /// @param yank_type The motion type (kMTUnknown to auto detect) /// @param block_len width of visual block -void write_reg_contents_ex(int name, const char_u *str, ssize_t len, bool must_append, +void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_append, MotionType yank_type, colnr_T block_len) { if (len < 0) { - len = (ssize_t)STRLEN(str); + len = (ssize_t)strlen(str); } // Special case: '/' search pattern if (name == '/') { - set_last_search_pat(str, RE_SEARCH, TRUE, TRUE); + set_last_search_pat((char_u *)str, RE_SEARCH, true, true); return; } @@ -5619,14 +5072,14 @@ void write_reg_contents_ex(int name, const char_u *str, ssize_t len, bool must_a buf_T *buf; if (ascii_isdigit(*str)) { - int num = atoi((char *)str); + int num = atoi(str); buf = buflist_findnr(num); if (buf == NULL) { semsg(_(e_nobufnr), (int64_t)num); } } else { - buf = buflist_findnr(buflist_findpat((char *)str, (char *)str + STRLEN(str), + buf = buflist_findnr(buflist_findpat(str, str + strlen(str), true, false, false)); } if (buf == NULL) { @@ -5667,7 +5120,7 @@ void write_reg_contents_ex(int name, const char_u *str, ssize_t len, bool must_a if (!(reg = init_write_reg(name, &old_y_previous, must_append))) { return; } - str_to_reg(reg, yank_type, (char *)str, (size_t)len, block_len, false); + str_to_reg(reg, yank_type, str, (size_t)len, block_len, false); finish_write_reg(name, reg, old_y_previous); } @@ -5701,18 +5154,18 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, // Count the number of lines within the string if (str_list) { - for (char_u **ss = (char_u **)str; *ss != NULL; ++ss) { + for (char_u **ss = (char_u **)str; *ss != NULL; ss++) { newlines++; } } else { newlines = memcnt(str, '\n', len); if (yank_type == kMTCharWise || len == 0 || str[len - 1] != '\n') { extraline = 1; - ++newlines; // count extra newline at the end + newlines++; // count extra newline at the end } if (y_ptr->y_size > 0 && y_ptr->y_type == kMTCharWise) { append = true; - --newlines; // uncount newline when appending first line + newlines--; // uncount newline when appending first line } } @@ -5733,7 +5186,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, // Find the end of each line and save it into the array. if (str_list) { - for (char_u **ss = (char_u **)str; *ss != NULL; ++ss, ++lnum) { + for (char_u **ss = (char_u **)str; *ss != NULL; ss++, lnum++) { size_t ss_len = STRLEN(*ss); pp[lnum] = xmemdupz(*ss, ss_len); if (ss_len > maxlen) { @@ -5753,7 +5206,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, } // When appending, copy the previous line and free it after. - size_t extra = append ? STRLEN(pp[--lnum]) : 0; + size_t extra = append ? strlen(pp[--lnum]) : 0; char *s = xmallocz(line_len + extra); if (extra > 0) { memcpy(s, pp[lnum], extra); @@ -5883,12 +5336,12 @@ void cursor_pos_info(dict_T *dict) max_pos = VIsual; } if (*p_sel == 'e' && max_pos.col > 0) { - --max_pos.col; + max_pos.col--; } if (l_VIsual_mode == Ctrl_V) { - char_u *const saved_sbr = p_sbr; - char_u *const saved_w_sbr = curwin->w_p_sbr; + char *const saved_sbr = p_sbr; + char *const saved_w_sbr = curwin->w_p_sbr; // Make 'sbr' empty for a moment to get the correct size. p_sbr = empty_option; @@ -5896,8 +5349,7 @@ void cursor_pos_info(dict_T *dict) oparg.is_VIsual = true; oparg.motion_type = kMTBlockWise; oparg.op_type = OP_NOP; - getvcols(curwin, &min_pos, &max_pos, - &oparg.start_vcol, &oparg.end_vcol); + getvcols(curwin, &min_pos, &max_pos, &oparg.start_vcol, &oparg.end_vcol); p_sbr = saved_sbr; curwin->w_p_sbr = saved_w_sbr; if (curwin->w_curswant == MAXCOL) { @@ -5913,7 +5365,7 @@ void cursor_pos_info(dict_T *dict) line_count_selected = max_pos.lnum - min_pos.lnum + 1; } - for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) { + for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) { // Check for a CTRL-C every 100000 characters. if (byte_count > last_check) { os_breakcheck(); @@ -5938,7 +5390,7 @@ void cursor_pos_info(dict_T *dict) len = (long)bd.textlen; break; case 'V': - s = ml_get(lnum); + s = (char_u *)ml_get(lnum); len = MAXCOL; break; case 'v': { @@ -5947,7 +5399,7 @@ void cursor_pos_info(dict_T *dict) colnr_T end_col = (lnum == max_pos.lnum) ? max_pos.col - start_col + 1 : MAXCOL; - s = ml_get(lnum) + start_col; + s = (char_u *)ml_get(lnum) + start_col; len = end_col; } break; @@ -5968,14 +5420,14 @@ void cursor_pos_info(dict_T *dict) word_count_cursor += word_count; char_count_cursor += char_count; byte_count_cursor = byte_count - + line_count_info(ml_get(lnum), &word_count_cursor, + + line_count_info((char_u *)ml_get(lnum), &word_count_cursor, &char_count_cursor, (varnumber_T)curwin->w_cursor.col + 1, eol_size); } } // Add to the running totals - byte_count += line_count_info(ml_get(lnum), &word_count, &char_count, + byte_count += line_count_info((char_u *)ml_get(lnum), &word_count, &char_count, (varnumber_T)MAXCOL, eol_size); } @@ -6019,7 +5471,7 @@ void cursor_pos_info(dict_T *dict) (int64_t)byte_count_cursor, (int64_t)byte_count); } } else { - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); validate_virtcol(); col_print((char *)buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); @@ -6054,20 +5506,20 @@ void cursor_pos_info(dict_T *dict) bom_count = bomb_size(); if (dict == NULL && bom_count > 0) { - const size_t len = STRLEN(IObuff); + const size_t len = strlen(IObuff); vim_snprintf((char *)IObuff + len, IOSIZE - len, _("(+%" PRId64 " for BOM)"), (int64_t)bom_count); } if (dict == NULL) { // Don't shorten this message, the user asked for it. - p = p_shm; - p_shm = (char_u *)""; + p = (char_u *)p_shm; + p_shm = ""; if (p_ch < 1) { msg_start(); msg_scroll = true; } msg((char *)IObuff); - p_shm = p; + p_shm = (char *)p; } } @@ -6303,10 +5755,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank; // Avoid a problem with unwanted linebreaks in block mode - if (curwin->w_p_lbr) { - curwin->w_valid &= ~VALID_VIRTCOL; - } - curwin->w_p_lbr = false; + (void)reset_lbr(); oap->is_VIsual = VIsual_active; if (oap->motion_force == 'V') { oap->motion_type = kMTLineWise; @@ -6353,7 +5802,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) // If 'cpoptions' does not contain 'r', insert the search // pattern to really repeat the same command. if (vim_strchr(p_cpo, CPO_REDO) == NULL) { - AppendToRedobuffLit((char *)cap->searchbuf, -1); + AppendToRedobuffLit(cap->searchbuf, -1); } AppendToRedobuff(NL_STR); } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) { @@ -6363,7 +5812,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (repeat_cmdline == NULL) { ResetRedobuff(); } else { - AppendToRedobuffLit((char *)repeat_cmdline, -1); + AppendToRedobuffLit(repeat_cmdline, -1); AppendToRedobuff(NL_STR); XFREE_CLEAR(repeat_cmdline); } @@ -6413,10 +5862,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (lt(VIsual, curwin->w_cursor)) { VIsual.col = 0; curwin->w_cursor.col = - (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum)); + (colnr_T)strlen(ml_get(curwin->w_cursor.lnum)); } else { curwin->w_cursor.col = 0; - VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum)); + VIsual.col = (colnr_T)strlen(ml_get(VIsual.lnum)); } VIsual_mode = 'v'; } else if (VIsual_mode == 'v') { @@ -6446,7 +5895,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) || oap->motion_type == kMTLineWise) && hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - curwin->w_cursor.col = (colnr_T)STRLEN(get_cursor_line_ptr()); + curwin->w_cursor.col = (colnr_T)strlen(get_cursor_line_ptr()); } } oap->end = curwin->w_cursor; @@ -6464,7 +5913,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) curwin->w_cursor.col = 0; } if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) { - oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum)); + oap->start.col = (colnr_T)strlen(ml_get(oap->start.lnum)); } } oap->end = oap->start; @@ -6595,8 +6044,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) || oap->op_type == OP_FILTER) && oap->motion_force == NUL) { // Make sure redrawing is correct. - curwin->w_p_lbr = lbr_saved; - redraw_curbuf_later(INVERTED); + restore_lbr(lbr_saved); + redraw_curbuf_later(UPD_INVERTED); } } } @@ -6627,8 +6076,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) // 'modifiable is off or creating a fold. if (oap->is_VIsual && (oap->empty || !MODIFIABLE(curbuf) || oap->op_type == OP_FOLD)) { - curwin->w_p_lbr = lbr_saved; - redraw_curbuf_later(INVERTED); + restore_lbr(lbr_saved); + redraw_curbuf_later(UPD_INVERTED); } // If the end of an operator is in column one while oap->motion_type @@ -6648,7 +6097,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (inindent(0)) { oap->motion_type = kMTLineWise; } else { - oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); + oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); if (oap->end.col) { oap->end.col--; oap->inclusive = true; @@ -6703,7 +6152,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) CancelRedo(); } } else { - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); oap->excl_tr_ws = cap->cmdchar == 'z'; (void)op_yank(oap, !gui_yank); } @@ -6727,7 +6176,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) restart_edit = 0; // Restore linebreak, so that when the user edits it looks as before. - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); // Reset finish_op now, don't want it set inside edit(). finish_op = false; @@ -6798,9 +6247,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_FUNCTION: { redo_VIsual_T save_redo_VIsual = redo_VIsual; - // Restore linebreak, so that when the user edits it looks as - // before. - curwin->w_p_lbr = lbr_saved; + // Restore linebreak, so that when the user edits it looks as before. + restore_lbr(lbr_saved); // call 'operatorfunc' op_function(oap); @@ -6824,12 +6272,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) restart_edit = 0; // Restore linebreak, so that when the user edits it looks as before. - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); op_insert(oap, cap->count1); // Reset linebreak, so that formatting works correctly. - curwin->w_p_lbr = false; + (void)reset_lbr(); // TODO(brammool): when inserting in several lines, should format all // the lines. @@ -6850,7 +6298,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) CancelRedo(); } else { // Restore linebreak, so that when the user edits it looks as before. - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); op_replace(oap, cap->nchar); } @@ -6888,7 +6336,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) CancelRedo(); } else { VIsual_active = true; - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); op_addsub(oap, (linenr_T)cap->count1, redo_VIsual.rv_arg); VIsual_active = false; } @@ -6903,7 +6351,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (!p_sol && oap->motion_type == kMTLineWise && !oap->end_adjusted && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT || oap->op_type == OP_DELETE)) { - curwin->w_p_lbr = false; + (void)reset_lbr(); coladvance(curwin->w_curswant = old_col); } } else { @@ -6912,7 +6360,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) clearop(oap); motion_force = NUL; } - curwin->w_p_lbr = lbr_saved; + restore_lbr(lbr_saved); } /// Check if the default register (used in an unnamed paste) should be a @@ -7042,7 +6490,7 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines) void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) { - if (reg->y_size > 0 && STRLEN(reg->y_array[reg->y_size - 1]) == 0) { + if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { // a known-to-be charwise yank might have a final linebreak // but otherwise there is no line after the final newline if (reg->y_type != kMTCharWise) { @@ -7063,7 +6511,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) if (reg->y_type == kMTBlockWise) { size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { - size_t rowlen = STRLEN(reg->y_array[i]); + size_t rowlen = strlen(reg->y_array[i]); if (rowlen > maxlen) { maxlen = rowlen; } @@ -7150,7 +6598,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) reg->y_array[tv_idx++] = xstrdupnul((const char *)TV_LIST_ITEM_TV(li)->vval.v_string); }); - if (reg->y_size > 0 && STRLEN(reg->y_array[reg->y_size - 1]) == 0) { + if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { // a known-to-be charwise yank might have a final linebreak // but otherwise there is no line after the final newline if (reg->y_type != kMTCharWise) { @@ -7169,7 +6617,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) if (reg->y_type == kMTBlockWise) { size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { - size_t rowlen = STRLEN(reg->y_array[i]); + size_t rowlen = strlen(reg->y_array[i]); if (rowlen > maxlen) { maxlen = rowlen; } @@ -7419,13 +6867,13 @@ bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum, linenr_T end_lnum return end_col - start_col; } const char *first = (const char *)ml_get_buf(buf, start_lnum, false); - bcount_t deleted_bytes = (bcount_t)STRLEN(first) - start_col + 1; + bcount_t deleted_bytes = (bcount_t)strlen(first) - start_col + 1; for (linenr_T i = 1; i <= end_lnum - start_lnum - 1; i++) { if (start_lnum + i > max_lnum) { return deleted_bytes; } - deleted_bytes += (bcount_t)STRLEN(ml_get_buf(buf, start_lnum + i, false)) + 1; + deleted_bytes += (bcount_t)strlen(ml_get_buf(buf, start_lnum + i, false)) + 1; } if (end_lnum > max_lnum) { return deleted_bytes; diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 05893c9940..840e33a48c 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -23,15 +23,13 @@ typedef int (*Indenter)(void); #define PUT_LINE_FORWARD 32 // put linewise register below Visual sel. #define PUT_BLOCK_INNER 64 // in block mode, do not add trailing spaces -/* - * Registers: - * 0 = register for latest (unnamed) yank - * 1..9 = registers '1' to '9', for deletes - * 10..35 = registers 'a' to 'z' - * 36 = delete register '-' - * 37 = selection register '*' - * 38 = clipboard register '+' - */ +// Registers: +// 0 = register for latest (unnamed) yank +// 1..9 = registers '1' to '9', for deletes +// 10..35 = registers 'a' to 'z' +// 36 = delete register '-' +// 37 = selection register '*' +// 38 = clipboard register '+' #define DELETION_REGISTER 36 #define NUM_SAVED_REGISTERS 37 // The following registers should not be saved in ShaDa file: diff --git a/src/nvim/option.c b/src/nvim/option.c index 5c487a7c62..208112561a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -30,6 +30,7 @@ #include "nvim/arglist.h" #include "nvim/ascii.h" #include "nvim/buffer.h" +#include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor_shape.h" #include "nvim/decoration_provider.h" @@ -38,7 +39,6 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" -#include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/ex_session.h" @@ -52,6 +52,7 @@ #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/keycodes.h" +#include "nvim/locale.h" #include "nvim/macros.h" #include "nvim/mapping.h" #include "nvim/mbyte.h" @@ -71,6 +72,7 @@ #include "nvim/popupmenu.h" #include "nvim/regexp.h" #include "nvim/screen.h" +#include "nvim/search.h" #include "nvim/spell.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" @@ -81,7 +83,7 @@ #include "nvim/undo.h" #include "nvim/vim.h" #include "nvim/window.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/pty_conpty_win.h" #endif #include "nvim/api/extmark.h" @@ -91,33 +93,18 @@ #include "nvim/os/input.h" #include "nvim/os/lang.h" -/* - * The options that are local to a window or buffer have "indir" set to one of - * these values. Special values: - * PV_NONE: global option. - * PV_WIN is added: window-local option - * PV_BUF is added: buffer-local option - * PV_BOTH is added: global option which also has a local value. - */ -#define PV_BOTH 0x1000 -#define PV_WIN 0x2000 -#define PV_BUF 0x4000 -#define PV_MASK 0x0fff -#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x)) -#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) -#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) - -// WV_ and BV_ values get typecasted to this for the "indir" field -typedef enum { - PV_NONE = 0, - PV_MAXVAL = 0xffff, // to avoid warnings for value out of range -} idopt_T; - -/* - * Options local to a window have a value local to a buffer and global to all - * buffers. Indicate this by setting "var" to VAR_WIN. - */ -#define VAR_WIN ((char_u *)-1) +static char e_unknown_option[] + = N_("E518: Unknown option"); +static char e_not_allowed_in_modeline[] + = N_("E520: Not allowed in a modeline"); +static char e_not_allowed_in_modeline_when_modelineexpr_is_off[] + = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); +static char e_key_code_not_set[] + = N_("E846: Key code not set"); +static char e_number_required_after_equal[] + = N_("E521: Number required after ="); +static char e_preview_window_already_exists[] + = N_("E590: A preview window already exists"); static char *p_term = NULL; static char *p_ttytype = NULL; @@ -134,29 +121,14 @@ static int p_et_nopaste; static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; -static char_u *p_vsts_nopaste; - -typedef struct vimoption { - char *fullname; // full option name - char *shortname; // permissible abbreviation - uint32_t flags; // see below - char_u *var; // global option: pointer to variable; - // window-local option: VAR_WIN; - // buffer-local option: global value - idopt_T indir; // global option: PV_NONE; - // local option: indirect option index - char_u *def_val; // default values for variable (neovim!!) - LastSet last_set; // script in which the option was last set -} vimoption_T; - -/* - * options[] is initialized here. - * The order of the options MUST be alphabetic for ":set all" and findoption(). - * All option names MUST start with a lowercase letter (for findoption()). - * Exception: "t_" options are at the end. - * The options with a NULL variable are 'hidden': a set command for them is - * ignored and they are not printed. - */ +static char *p_vsts_nopaste; + +// options[] is initialized here. +// The order of the options MUST be alphabetic for ":set all" and findoption(). +// All option names MUST start with a lowercase letter (for findoption()). +// Exception: "t_" options are at the end. +// The options with a NULL variable are 'hidden': a set command for them is +// ignored and they are not printed. #ifdef INCLUDE_GENERATED_DECLARATIONS # include "options.generated.h" @@ -164,10 +136,24 @@ typedef struct vimoption { #define OPTION_COUNT ARRAY_SIZE(options) +typedef enum { + OP_NONE = 0, + OP_ADDING, ///< "opt+=arg" + OP_PREPENDING, ///< "opt^=arg" + OP_REMOVING, ///< "opt-=arg" +} set_op_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.c.generated.h" #endif +void set_init_tablocal(void) +{ + // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! + int ch_idx = findoption("cmdheight"); + p_ch = (long)options[ch_idx].def_val; +} + /// Initialize the options, first part. /// /// Called only once from main(), just after creating the first buffer. @@ -182,10 +168,8 @@ void set_init_1(bool clean_arg) langmap_init(); - /* - * Find default value for 'shell' option. - * Don't use it if it is empty. - */ + // Find default value for 'shell' option. + // Don't use it if it is empty. { const char *shell = os_getenv("SHELL"); if (shell != NULL) { @@ -200,10 +184,8 @@ void set_init_1(bool clean_arg) } } - /* - * Set the default for 'backupskip' to include environment variables for - * temp files. - */ + // Set the default for 'backupskip' to include environment variables for + // temp files. { #ifdef UNIX static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" }; @@ -285,7 +267,7 @@ void set_init_1(bool clean_arg) buf[j] = NUL; opt_idx = findoption("cdpath"); if (opt_idx >= 0) { - options[opt_idx].def_val = buf; + options[opt_idx].def_val = (char *)buf; options[opt_idx].flags |= P_DEF_ALLOCED; } else { xfree(buf); // cannot happen @@ -339,10 +321,8 @@ void set_init_1(bool clean_arg) rtp = NULL; // ownership taken } - /* - * Set all the options (except the terminal options) to their default - * value. Also set the global value for local options. - */ + // Set all the options (except the terminal options) to their default + // value. Also set the global value for local options. set_options_default(0); curbuf->b_p_initialized = true; @@ -365,15 +345,13 @@ void set_init_1(bool clean_arg) // didset_options() because it only depends on 'encoding'. init_spell_chartab(); - /* - * Expand environment variables and things like "~" for the defaults. - * If option_expand() returns non-NULL the variable is expanded. This can - * only happen for non-indirect options. - * Also set the default to the expanded value, so ":set" does not list - * them. - * Don't set the P_ALLOCED flag, because we don't want to free the - * default. - */ + // Expand environment variables and things like "~" for the defaults. + // If option_expand() returns non-NULL the variable is expanded. This can + // only happen for non-indirect options. + // Also set the default to the expanded value, so ":set" does not list + // them. + // Don't set the P_ALLOCED flag, because we don't want to free the + // default. for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) { if (options[opt_idx].flags & P_NO_DEF_EXP) { continue; @@ -383,7 +361,7 @@ void set_init_1(bool clean_arg) && options[opt_idx].var != NULL) { p = _(*(char **)options[opt_idx].var); } else { - p = (char *)option_expand(opt_idx, NULL); + p = option_expand(opt_idx, NULL); } if (p != NULL) { p = xstrdup(p); @@ -391,7 +369,7 @@ void set_init_1(bool clean_arg) if (options[opt_idx].flags & P_DEF_ALLOCED) { xfree(options[opt_idx].def_val); } - options[opt_idx].def_val = (char_u *)p; + options[opt_idx].def_val = p; options[opt_idx].flags |= P_DEF_ALLOCED; } } @@ -404,7 +382,7 @@ void set_init_1(bool clean_arg) // NOTE: mlterm's author is being asked to 'set' a variable // instead of an environment variable due to inheritance. if (os_env_exists("MLTERM")) { - set_option_value("tbidi", 1L, NULL, 0); + set_option_value_give_err("tbidi", 1L, NULL, 0); } didset_options2(); @@ -419,12 +397,12 @@ void set_init_1(bool clean_arg) // use utf-8 as 'default' if locale encoding can't be detected. p = (char_u *)xmemdupz(S_LEN("utf-8")); } - fenc_default = p; + fenc_default = (char *)p; #ifdef HAVE_WORKING_LIBINTL // GNU gettext 0.10.37 supports this feature: set the codeset used for // translated messages independently from the current locale. - (void)bind_textdomain_codeset(PROJECT_NAME, (char *)p_enc); + (void)bind_textdomain_codeset(PROJECT_NAME, p_enc); #endif // Set the default for 'helplang'. @@ -440,7 +418,7 @@ static void set_option_default(int opt_idx, int opt_flags) char_u *varp; // pointer to variable for current option int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags); + varp = (char_u *)get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags); uint32_t flags = options[opt_idx].flags; if (varp != NULL) { // skip hidden option, nothing to do for it if (flags & P_STRING) { @@ -448,12 +426,12 @@ static void set_option_default(int opt_idx, int opt_flags) // freeing and allocating the value. if (options[opt_idx].indir != PV_NONE) { set_string_option_direct(NULL, opt_idx, - (char *)options[opt_idx].def_val, opt_flags, 0); + options[opt_idx].def_val, opt_flags, 0); } else { if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { - free_string_option(*(char_u **)(varp)); + free_string_option(*(char **)(varp)); } - *(char_u **)varp = options[opt_idx].def_val; + *(char **)varp = options[opt_idx].def_val; options[opt_idx].flags &= ~P_ALLOCED; } } else if (flags & P_NUM) { @@ -532,9 +510,7 @@ static void set_string_default(const char *name, char *val, bool allocated) xfree(options[opt_idx].def_val); } - options[opt_idx].def_val = allocated - ? (char_u *)val - : (char_u *)xstrdup(val); + options[opt_idx].def_val = allocated ? val : xstrdup(val); options[opt_idx].flags |= P_DEF_ALLOCED; } } @@ -578,7 +554,7 @@ void set_number_default(char *name, long val) opt_idx = findoption(name); if (opt_idx >= 0) { - options[opt_idx].def_val = (char_u *)(intptr_t)val; + options[opt_idx].def_val = (char *)(intptr_t)val; } } @@ -590,14 +566,14 @@ void free_all_options(void) if (options[i].indir == PV_NONE) { // global option: free value and default value. if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) { - free_string_option(*(char_u **)options[i].var); + free_string_option(*(char **)options[i].var); } if (options[i].flags & P_DEF_ALLOCED) { free_string_option(options[i].def_val); } } else if (options[i].var != VAR_WIN && (options[i].flags & P_STRING)) { // buffer-local option: free global value - clear_string_option((char_u **)options[i].var); + clear_string_option((char **)options[i].var); } } free_operatorfunc_option(); @@ -620,10 +596,8 @@ void set_init_2(bool headless) } comp_col(); - /* - * 'window' is only for backwards compatibility with Vi. - * Default is Rows - 1. - */ + // 'window' is only for backwards compatibility with Vi. + // Default is Rows - 1. if (!option_was_set("window")) { p_window = Rows - 1; } @@ -649,41 +623,41 @@ void set_init_3(void) : !(options[idx_sp].flags & P_WAS_SET); size_t len = 0; - char_u *p = (char_u *)invocation_path_tail(p_sh, &len); - p = vim_strnsave(p, len); + char *p = (char *)invocation_path_tail((char_u *)p_sh, &len); + p = xstrnsave(p, len); { // // Default for p_sp is "| tee", for p_srr is ">". // For known shells it is changed here to include stderr. // - if (FNAMECMP(p, "csh") == 0 - || FNAMECMP(p, "tcsh") == 0) { + if (path_fnamecmp(p, "csh") == 0 + || path_fnamecmp(p, "tcsh") == 0) { if (do_sp) { - p_sp = (char_u *)"|& tee"; + p_sp = "|& tee"; options[idx_sp].def_val = p_sp; } if (do_srr) { - p_srr = (char_u *)">&"; + p_srr = ">&"; options[idx_srr].def_val = p_srr; } - } else if (FNAMECMP(p, "sh") == 0 - || FNAMECMP(p, "ksh") == 0 - || FNAMECMP(p, "mksh") == 0 - || FNAMECMP(p, "pdksh") == 0 - || FNAMECMP(p, "zsh") == 0 - || FNAMECMP(p, "zsh-beta") == 0 - || FNAMECMP(p, "bash") == 0 - || FNAMECMP(p, "fish") == 0 - || FNAMECMP(p, "ash") == 0 - || FNAMECMP(p, "dash") == 0) { + } else if (path_fnamecmp(p, "sh") == 0 + || path_fnamecmp(p, "ksh") == 0 + || path_fnamecmp(p, "mksh") == 0 + || path_fnamecmp(p, "pdksh") == 0 + || path_fnamecmp(p, "zsh") == 0 + || path_fnamecmp(p, "zsh-beta") == 0 + || path_fnamecmp(p, "bash") == 0 + || path_fnamecmp(p, "fish") == 0 + || path_fnamecmp(p, "ash") == 0 + || path_fnamecmp(p, "dash") == 0) { // Always use POSIX shell style redirection if we reach this if (do_sp) { - p_sp = (char_u *)"2>&1| tee"; + p_sp = "2>&1| tee"; options[idx_sp].def_val = p_sp; } if (do_srr) { - p_srr = (char_u *)">%s 2>&1"; + p_srr = ">%s 2>&1"; options[idx_srr].def_val = p_srr; } } @@ -717,7 +691,7 @@ void set_helplang_default(const char *lang) int idx = findoption("hlg"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { if (options[idx].flags & P_ALLOCED) { - free_string_option(p_hlg); + free_string_option((char *)p_hlg); } p_hlg = (char_u *)xmemdupz(lang, lang_len); // zh_CN becomes "cn", zh_TW becomes "tw". @@ -743,19 +717,17 @@ void set_title_defaults(void) { int idx1; - /* - * If GUI is (going to be) used, we can always set the window title and - * icon name. Saves a bit of time, because the X11 display server does - * not need to be contacted. - */ + // If GUI is (going to be) used, we can always set the window title and + // icon name. Saves a bit of time, because the X11 display server does + // not need to be contacted. idx1 = findoption("title"); if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = (char_u *)(intptr_t)0; + options[idx1].def_val = 0; p_title = 0; } idx1 = findoption("icon"); if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = (char_u *)(intptr_t)0; + options[idx1].def_val = 0; p_icon = 0; } } @@ -775,6 +747,349 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } +/// Part of do_set() for string options. +/// @return FAIL on failure, do not process further options. +static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, + uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen, + int *value_checked, char **errmsg) +{ + char *arg = *argp; + set_op_T op = op_arg; + char *varp = varp_arg; + char *save_arg = NULL; + char *s = NULL; + char_u *oldval = NULL; // previous value if *varp + char *newval; + char_u *origval = NULL; + char_u *origval_l = NULL; + char_u *origval_g = NULL; + char *saved_origval = NULL; + char *saved_origval_l = NULL; + char *saved_origval_g = NULL; + char *saved_newval = NULL; + unsigned newlen; + int comma; + char whichwrap[80]; + + // When using ":set opt=val" for a global option + // with a local value the local value will be + // reset, use the global value here. + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 + && ((int)options[opt_idx].indir & PV_BOTH)) { + varp = (char *)options[opt_idx].var; + } + + // The old value is kept until we are sure that the new value is valid. + oldval = *(char_u **)varp; + + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); + origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + + // A global-local string option might have an empty option as value to + // indicate that the global value should be used. + if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == (char_u *)empty_option) { + origval_l = origval_g; + } + } + + // When setting the local value of a global option, the old value may be + // the global value. + if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) { + origval = *(char_u **)get_varp(&options[opt_idx]); + } else { + origval = oldval; + } + + if (nextchar == '&') { // set to default val + newval = options[opt_idx].def_val; + // expand environment variables and ~ since the default value was + // already expanded, only required when an environment variable was set + // later + if (newval == NULL) { + newval = empty_option; + } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { + s = option_expand(opt_idx, newval); + if (s == NULL) { + s = newval; + } + newval = xstrdup(s); + } else { + newval = xstrdup(newval); + } + } else if (nextchar == '<') { // set to global val + newval = xstrdup(*(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); + } else { + arg++; // jump to after the '=' or ':' + + // Set 'keywordprg' to ":help" if an empty + // value was passed to :set by the user. + if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) { + save_arg = arg; + arg = ":help"; + } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) { + // Convert 'backspace' number to string, for + // adding, prepending and removing string. + int i = getdigits_int((char **)varp, true, 0); + switch (i) { + case 0: + *(char **)varp = empty_option; + break; + case 1: + *(char_u **)varp = (char_u *)xstrdup("indent,eol"); + break; + case 2: + *(char_u **)varp = (char_u *)xstrdup("indent,eol,start"); + break; + case 3: + *(char_u **)varp = (char_u *)xstrdup("indent,eol,nostop"); + break; + } + xfree(oldval); + if (origval == oldval) { + origval = *(char_u **)varp; + } + if (origval_l == oldval) { + origval_l = *(char_u **)varp; + } + if (origval_g == oldval) { + origval_g = *(char_u **)varp; + } + oldval = *(char_u **)varp; + } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) { + // Convert 'whichwrap' number to string, for backwards compatibility + // with Vim 3.0. + *whichwrap = NUL; + int i = getdigits_int(&arg, true, 0); + if (i & 1) { + xstrlcat(whichwrap, "b,", sizeof(whichwrap)); + } + if (i & 2) { + xstrlcat(whichwrap, "s,", sizeof(whichwrap)); + } + if (i & 4) { + xstrlcat(whichwrap, "h,l,", sizeof(whichwrap)); + } + if (i & 8) { + xstrlcat(whichwrap, "<,>,", sizeof(whichwrap)); + } + if (i & 16) { + xstrlcat(whichwrap, "[,],", sizeof(whichwrap)); + } + if (*whichwrap != NUL) { // remove trailing , + whichwrap[strlen(whichwrap) - 1] = NUL; + } + save_arg = arg; + arg = whichwrap; + } else if (*arg == '>' && (varp == (char *)&p_dir || varp == (char *)&p_bdir)) { + // Remove '>' before 'dir' and 'bdir', for backwards compatibility with + // version 3.0 + arg++; + } + + // Copy the new string into allocated memory. + // Can't use set_string_option_direct(), because we need to remove the + // backslashes. + + // get a bit too much + newlen = (unsigned)strlen(arg) + 1; + if (op != OP_NONE) { + newlen += (unsigned)STRLEN(origval) + 1; + } + newval = xmalloc(newlen); + s = newval; + + // Copy the string, skip over escaped chars. + // For MS-Windows backslashes before normal file name characters + // are not removed, and keep backslash at start, for "\\machine\path", + // but do remove it for "\\\\machine\\path". + // The reverse is found in ExpandOldSetting(). + while (*arg != NUL && !ascii_iswhite(*arg)) { + if (*arg == '\\' && arg[1] != NUL +#ifdef BACKSLASH_IN_FILENAME + && !((flags & P_EXPAND) + && vim_isfilec(arg[1]) + && !ascii_iswhite(arg[1]) + && (arg[1] != '\\' + || (s == newval && arg[2] != '\\'))) +#endif + ) { + arg++; // remove backslash + } + int i = utfc_ptr2len(arg); + if (i > 1) { + // copy multibyte char + memmove(s, arg, (size_t)i); + arg += i; + s += i; + } else { + *s++ = *arg++; + } + } + *s = NUL; + + // Expand environment variables and ~. + // Don't do it when adding without inserting a comma. + if (op == OP_NONE || (flags & P_COMMA)) { + s = option_expand(opt_idx, newval); + if (s != NULL) { + xfree(newval); + newlen = (unsigned)strlen(s) + 1; + if (op != OP_NONE) { + newlen += (unsigned)STRLEN(origval) + 1; + } + newval = xmalloc(newlen); + STRCPY(newval, s); + } + } + + // locate newval[] in origval[] when removing it + // and when adding to avoid duplicates + int len = 0; + if (op == OP_REMOVING || (flags & P_NODUP)) { + len = (int)STRLEN(newval); + s = (char *)find_dup_item(origval, (char_u *)newval, flags); + + // do not add if already there + if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { + op = OP_NONE; + STRCPY(newval, origval); + } + + // if no duplicate, move pointer to end of original value + if (s == NULL) { + s = (char *)origval + (int)STRLEN(origval); + } + } + + // concatenate the two strings; add a ',' if needed + if (op == OP_ADDING || op == OP_PREPENDING) { + comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL); + if (op == OP_ADDING) { + len = (int)STRLEN(origval); + // Strip a trailing comma, would get 2. + if (comma && len > 1 + && (flags & P_ONECOMMA) == P_ONECOMMA + && origval[len - 1] == ',' + && origval[len - 2] != '\\') { + len--; + } + memmove(newval + len + comma, newval, strlen(newval) + 1); + memmove(newval, origval, (size_t)len); + } else { + len = (int)strlen(newval); + STRMOVE(newval + len + comma, origval); + } + if (comma) { + newval[len] = ','; + } + } + + // Remove newval[] from origval[]. (Note: "len" has been set above and + // is used here). + if (op == OP_REMOVING) { + STRCPY(newval, origval); + if (*s) { + // may need to remove a comma + if (flags & P_COMMA) { + if (s == (char *)origval) { + // include comma after string + if (s[len] == ',') { + len++; + } + } else { + // include comma before string + s--; + len++; + } + } + STRMOVE(newval + (s - (char *)origval), s + len); + } + } + + if (flags & P_FLAGLIST) { + // Remove flags that appear twice. + for (s = newval; *s;) { + // if options have P_FLAGLIST and P_ONECOMMA such as + // 'whichwrap' + if (flags & P_ONECOMMA) { + if (*s != ',' && *(s + 1) == ',' + && vim_strchr(s + 2, *s) != NULL) { + // Remove the duplicated value and the next comma. + STRMOVE(s, s + 2); + continue; + } + } else { + if ((!(flags & P_COMMA) || *s != ',') + && vim_strchr(s + 1, *s) != NULL) { + STRMOVE(s, s + 1); + continue; + } + } + s++; + } + } + + if (save_arg != NULL) { + arg = save_arg; // arg was temporarily changed, restore it + } + } + + // Set the new value. + *(char_u **)(varp) = (char_u *)newval; + + // origval may be freed by did_set_string_option(), make a copy. + saved_origval = (origval != NULL) ? xstrdup((char *)origval) : NULL; + saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : NULL; + saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : NULL; + + // newval (and varp) may become invalid if the buffer is closed by + // autocommands. + saved_newval = (newval != NULL) ? xstrdup(newval) : NULL; + + { + uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); + const int secure_saved = secure; + + // When an option is set in the sandbox, from a modeline or in secure + // mode, then deal with side effects in secure mode. Also when the + // value was set with the P_INSECURE flag and is not completely + // replaced. + if ((opt_flags & OPT_MODELINE) + || sandbox != 0 + || (op != OP_NONE && (*p & P_INSECURE))) { + secure = 1; + } + + // Handle side effects, and set the global value 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 **)varp, (char *)oldval, + errbuf, errbuflen, + opt_flags, value_checked); + + secure = secure_saved; + } + + if (*errmsg == NULL) { + if (!starting) { + trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l, + saved_origval_g, saved_newval); + } + if (options[opt_idx].flags & P_UI_OPTION) { + ui_call_option_set(cstr_as_string(options[opt_idx].fullname), + STRING_OBJ(cstr_as_string(saved_newval))); + } + } + xfree(saved_origval); + xfree(saved_origval_l); + xfree(saved_origval_g); + xfree(saved_newval); + + *argp = arg; + return *errmsg == NULL ? OK : FAIL; +} + /// Parse 'arg' for option settings. /// /// 'arg' may be IObuff, but only when no errors can be present and option @@ -795,7 +1110,7 @@ int do_set(char *arg, int opt_flags) int opt_idx; char *errmsg; char errbuf[80]; - char_u *startarg; + char *startarg; int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name char_u nextchar; // next non-white char after option name int afterchar; // character just after option name @@ -806,9 +1121,7 @@ int do_set(char *arg, int opt_flags) uint32_t flags; // flags for current option char *varp = NULL; // pointer to variable for current option int did_show = false; // already showed one value - int adding; // "opt+=arg" - int prepending; // "opt^=arg" - int removing; // "opt-=arg" + set_op_T op = 0; if (*arg == NUL) { showoptions(0, opt_flags); @@ -818,14 +1131,12 @@ int do_set(char *arg, int opt_flags) while (*arg != NUL) { // loop to process all options errmsg = NULL; - startarg = (char_u *)arg; // remember for error message + startarg = arg; // remember for error message if (STRNCMP(arg, "all", 3) == 0 && !isalpha(arg[3]) && !(opt_flags & OPT_MODELINE)) { - /* - * ":set all" show all options. - * ":set all&" set all options to their default value. - */ + // ":set all" show all options. + // ":set all&" set all options to their default value. arg += 3; if (*arg == '&') { arg++; @@ -834,7 +1145,7 @@ int do_set(char *arg, int opt_flags) didset_options(); didset_options2(); ui_refresh_options(); - redraw_all_later(CLEAR); + redraw_all_later(UPD_CLEAR); } else { showoptions(1, opt_flags); did_show = true; @@ -897,25 +1208,23 @@ int do_set(char *arg, int opt_flags) len++; } - adding = false; - prepending = false; - removing = false; + op = OP_NONE; if (arg[len] != NUL && arg[len + 1] == '=') { if (arg[len] == '+') { - adding = true; // "+=" + op = OP_ADDING; // "+=" len++; } else if (arg[len] == '^') { - prepending = true; // "^=" + op = OP_PREPENDING; // "^=" len++; } else if (arg[len] == '-') { - removing = true; // "-=" + op = OP_REMOVING; // "-=" len++; } } nextchar = (uint8_t)arg[len]; if (opt_idx == -1 && key == 0) { // found a mismatch: skip - errmsg = N_("E518: Unknown option"); + errmsg = e_unknown_option; goto skip; } @@ -926,13 +1235,13 @@ int do_set(char *arg, int opt_flags) if (vim_strchr("=:!&<", nextchar) == NULL && (!(options[opt_idx].flags & P_BOOL) || nextchar == '?')) { - errmsg = _(e_unsupportedoption); + errmsg = e_unsupportedoption; } goto skip; } flags = options[opt_idx].flags; - varp = (char *)get_varp_scope(&(options[opt_idx]), opt_flags); + varp = get_varp_scope(&(options[opt_idx]), opt_flags); } else { flags = P_STRING; } @@ -953,11 +1262,11 @@ int do_set(char *arg, int opt_flags) // Disallow changing some options from modelines. if (opt_flags & OPT_MODELINE) { if (flags & (P_SECURE | P_NO_ML)) { - errmsg = N_("E520: Not allowed in a modeline"); + errmsg = e_not_allowed_in_modeline; goto skip; } if ((flags & P_MLE) && !p_mle) { - errmsg = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); + errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; goto skip; } // In diff mode some options are overruled. This avoids that @@ -1001,9 +1310,7 @@ int do_set(char *arg, int opt_flags) || (prefix == 1 && vim_strchr("=:&<", nextchar) == NULL && !(flags & P_BOOL))) { - /* - * print value - */ + // print value if (did_show) { msg_putchar('\n'); // cursor below last one } else { @@ -1025,7 +1332,7 @@ int do_set(char *arg, int opt_flags) } } } else { - errmsg = N_("E846: Key code not set"); + errmsg = e_key_code_not_set; goto skip; } if (nextchar != '?' @@ -1033,7 +1340,6 @@ int do_set(char *arg, int opt_flags) errmsg = e_trailing; } } else { - int value_is_replaced = !prepending && !adding && !removing; int value_checked = false; if (flags & P_BOOL) { // boolean @@ -1042,11 +1348,9 @@ int do_set(char *arg, int opt_flags) goto skip; } - /* - * ":set opt!": invert - * ":set opt&": reset to default value - * ":set opt<": reset to global value - */ + // ":set opt!": invert + // ":set opt&": reset to default value + // ":set opt<": reset to global value if (nextchar == '!') { value = *(int *)(varp) ^ 1; } else if (nextchar == '&') { @@ -1061,10 +1365,8 @@ int do_set(char *arg, int opt_flags) OPT_GLOBAL); } } else { - /* - * ":set invopt": invert - * ":set opt" or ":set noopt": set or reset - */ + // ":set invopt": invert + // ":set opt" or ":set noopt": set or reset if (nextchar != NUL && !ascii_iswhite(afterchar)) { errmsg = e_trailing; goto skip; @@ -1116,383 +1418,36 @@ int do_set(char *arg, int opt_flags) } } else if (*arg == '-' || ascii_isdigit(*arg)) { // Allow negative, octal and hex numbers. - vim_str2nr((char_u *)arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); + vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { - errmsg = N_("E521: Number required after ="); + errmsg = e_number_required_after_equal; goto skip; } } else { - errmsg = N_("E521: Number required after ="); + errmsg = e_number_required_after_equal; goto skip; } - if (adding) { + if (op == OP_ADDING) { value = *(long *)varp + value; } - if (prepending) { + if (op == OP_PREPENDING) { value = *(long *)varp * value; } - if (removing) { + if (op == OP_REMOVING) { value = *(long *)varp - value; } errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value, errbuf, sizeof(errbuf), opt_flags); } else if (opt_idx >= 0) { // String. - char_u *save_arg = NULL; - char_u *s = NULL; - char_u *oldval = NULL; // previous value if *varp - char_u *newval; - char_u *origval = NULL; - char_u *origval_l = NULL; - char_u *origval_g = NULL; - char *saved_origval = NULL; - char *saved_origval_l = NULL; - char *saved_origval_g = NULL; - char *saved_newval = NULL; - unsigned newlen; - int comma; - - // When using ":set opt=val" for a global option - // with a local value the local value will be - // reset, use the global value here. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 - && ((int)options[opt_idx].indir & PV_BOTH)) { - varp = (char *)options[opt_idx].var; - } - - // The old value is kept until we are sure that the - // new value is valid. - oldval = *(char_u **)varp; - - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); - origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - - // A global-local string option might have an empty - // option as value to indicate that the global - // value should be used. - if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == empty_option) { - origval_l = origval_g; - } - } - - // When setting the local value of a global - // option, the old value may be the global value. - if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) { - origval = *(char_u **)get_varp(&options[opt_idx]); - } else { - origval = oldval; - } - - if (nextchar == '&') { // set to default val - newval = options[opt_idx].def_val; - // expand environment variables and ~ since the - // default value was already expanded, only - // required when an environment variable was set - // later - if (newval == NULL) { - newval = empty_option; - } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { - s = option_expand(opt_idx, newval); - if (s == NULL) { - s = newval; - } - newval = vim_strsave(s); - } else { - newval = (char_u *)xstrdup((char *)newval); - } - } else if (nextchar == '<') { // set to global val - newval = vim_strsave(*(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); - } else { - arg++; // jump to after the '=' or ':' - - // Set 'keywordprg' to ":help" if an empty - // value was passed to :set by the user. - // Misuse errbuf[] for the resulting string. - if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) { - STRCPY(errbuf, ":help"); - save_arg = (char_u *)arg; - arg = errbuf; - } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) { - // Convert 'backspace' number to string, for - // adding, prepending and removing string. - i = getdigits_int((char **)varp, true, 0); - switch (i) { - case 0: - *(char_u **)varp = empty_option; - break; - case 1: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol"); - break; - case 2: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol,start"); - break; - case 3: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop"); - break; - } - xfree(oldval); - if (origval == oldval) { - origval = *(char_u **)varp; - } - if (origval_l == oldval) { - origval_l = *(char_u **)varp; - } - if (origval_g == oldval) { - origval_g = *(char_u **)varp; - } - oldval = *(char_u **)varp; - } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) { - // Convert 'whichwrap' number to string, for - // backwards compatibility with Vim 3.0. - // Misuse errbuf[] for the resulting string. - *errbuf = NUL; - i = getdigits_int(&arg, true, 0); - if (i & 1) { - STRLCAT(errbuf, "b,", sizeof(errbuf)); - } - if (i & 2) { - STRLCAT(errbuf, "s,", sizeof(errbuf)); - } - if (i & 4) { - STRLCAT(errbuf, "h,l,", sizeof(errbuf)); - } - if (i & 8) { - STRLCAT(errbuf, "<,>,", sizeof(errbuf)); - } - if (i & 16) { - STRLCAT(errbuf, "[,],", sizeof(errbuf)); - } - save_arg = (char_u *)arg; - arg = errbuf; - } else if (*arg == '>' - && (varp == (char *)&p_dir - || varp == (char *)&p_bdir)) { - // Remove '>' before 'dir' and 'bdir', for - // backwards compatibility with version 3.0 - arg++; - } - - /* - * Copy the new string into allocated memory. - * Can't use set_string_option_direct(), because - * we need to remove the backslashes. - */ - // get a bit too much - newlen = (unsigned)STRLEN(arg) + 1; - if (adding || prepending || removing) { - newlen += (unsigned)STRLEN(origval) + 1; - } - newval = xmalloc(newlen); - s = newval; - - /* - * Copy the string, skip over escaped chars. - * For WIN32 backslashes before normal - * file name characters are not removed, and keep - * backslash at start, for "\\machine\path", but - * do remove it for "\\\\machine\\path". - * The reverse is found in ExpandOldSetting(). - */ - while (*arg && !ascii_iswhite(*arg)) { - if (*arg == '\\' && arg[1] != NUL -#ifdef BACKSLASH_IN_FILENAME - && !((flags & P_EXPAND) - && vim_isfilec(arg[1]) - && !ascii_iswhite(arg[1]) - && (arg[1] != '\\' - || (s == newval - && arg[2] != '\\'))) -#endif - ) { - arg++; // remove backslash - } - i = utfc_ptr2len(arg); - if (i > 1) { - // copy multibyte char - memmove(s, arg, (size_t)i); - arg += i; - s += i; - } else { - *s++ = (uint8_t)(*arg++); - } - } - *s = NUL; - - /* - * Expand environment variables and ~. - * Don't do it when adding without inserting a - * comma. - */ - if (!(adding || prepending || removing) - || (flags & P_COMMA)) { - s = option_expand(opt_idx, newval); - if (s != NULL) { - xfree(newval); - newlen = (unsigned)STRLEN(s) + 1; - if (adding || prepending || removing) { - newlen += (unsigned)STRLEN(origval) + 1; - } - newval = xmalloc(newlen); - STRCPY(newval, s); - } - } - - // locate newval[] in origval[] when removing it - // and when adding to avoid duplicates - i = 0; // init for GCC - if (removing || (flags & P_NODUP)) { - i = (int)STRLEN(newval); - s = find_dup_item(origval, newval, flags); - - // do not add if already there - if ((adding || prepending) && s != NULL) { - prepending = false; - adding = false; - STRCPY(newval, origval); - } - - // if no duplicate, move pointer to end of - // original value - if (s == NULL) { - s = origval + (int)STRLEN(origval); - } - } - - // concatenate the two strings; add a ',' if - // needed - if (adding || prepending) { - comma = ((flags & P_COMMA) && *origval != NUL - && *newval != NUL); - if (adding) { - i = (int)STRLEN(origval); - // Strip a trailing comma, would get 2. - if (comma && i > 1 - && (flags & P_ONECOMMA) == P_ONECOMMA - && origval[i - 1] == ',' - && origval[i - 2] != '\\') { - i--; - } - memmove(newval + i + comma, newval, - STRLEN(newval) + 1); - memmove(newval, origval, (size_t)i); - } else { - i = (int)STRLEN(newval); - STRMOVE(newval + i + comma, origval); - } - if (comma) { - newval[i] = ','; - } - } - - // Remove newval[] from origval[]. (Note: "i" has - // been set above and is used here). - if (removing) { - STRCPY(newval, origval); - if (*s) { - // may need to remove a comma - if (flags & P_COMMA) { - if (s == origval) { - // include comma after string - if (s[i] == ',') { - i++; - } - } else { - // include comma before string - s--; - i++; - } - } - STRMOVE(newval + (s - origval), s + i); - } - } - - if (flags & P_FLAGLIST) { - // Remove flags that appear twice. - for (s = newval; *s;) { - // if options have P_FLAGLIST and P_ONECOMMA such as - // 'whichwrap' - if (flags & P_ONECOMMA) { - if (*s != ',' && *(s + 1) == ',' - && vim_strchr((char *)s + 2, *s) != NULL) { - // Remove the duplicated value and the next comma. - STRMOVE(s, s + 2); - continue; - } - } else { - if ((!(flags & P_COMMA) || *s != ',') - && vim_strchr((char *)s + 1, *s) != NULL) { - STRMOVE(s, s + 1); - continue; - } - } - s++; - } - } - - if (save_arg != NULL) { // number for 'whichwrap' - arg = (char *)save_arg; - } - } - - // Set the new value. - *(char_u **)(varp) = newval; - - // origval may be freed by - // did_set_string_option(), make a copy. - saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0; - saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : 0; - saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : 0; - - // newval (and varp) may become invalid if the - // buffer is closed by autocommands. - saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; - - { - uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); - const int secure_saved = secure; - - // When an option is set in the sandbox, from a - // modeline or in secure mode, then deal with side - // effects in secure mode. Also when the value was - // set with the P_INSECURE flag and is not - // completely replaced. - if ((opt_flags & OPT_MODELINE) - || sandbox != 0 - || (!value_is_replaced && (*p & P_INSECURE))) { - secure = 1; - } - - // Handle side effects, and set the global value - // 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, oldval, - errbuf, sizeof(errbuf), - opt_flags, &value_checked); - - secure = secure_saved; - } - - if (errmsg == NULL) { - if (!starting) { - trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l, - saved_origval_g, saved_newval); - } - if (options[opt_idx].flags & P_UI_OPTION) { - ui_call_option_set(cstr_as_string(options[opt_idx].fullname), - STRING_OBJ(cstr_as_string(saved_newval))); + if (do_set_string(opt_idx, opt_flags, &arg, nextchar, + op, flags, varp, errbuf, sizeof(errbuf), + &value_checked, &errmsg) == FAIL) { + if (errmsg != NULL) { + goto skip; } - } - xfree(saved_origval); - xfree(saved_origval_l); - xfree(saved_origval_g); - xfree(saved_newval); - - // If error detected, print the error message. - if (errmsg != NULL) { - goto skip; + break; } } else { // key code option(FIXME(tarruda): Show a warning or something @@ -1501,17 +1456,15 @@ int do_set(char *arg, int opt_flags) } if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); } } skip: - /* - * Advance to next argument. - * - skip until a blank found, taking care of backslashes - * - skip blanks - * - skip one "=val" argument (for hidden options ":set gfn =xx") - */ + // Advance to next argument. + // - skip until a blank found, taking care of backslashes + // - skip blanks + // - skip one "=val" argument (for hidden options ":set gfn =xx") for (i = 0; i < 2; i++) { while (*arg != NUL && !ascii_iswhite(*arg)) { if (*arg++ == '\\' && *arg != NUL) { @@ -1527,18 +1480,18 @@ skip: if (errmsg != NULL) { STRLCPY(IObuff, _(errmsg), IOSIZE); - i = (int)STRLEN(IObuff) + 2; - if (i + ((char_u *)arg - startarg) < IOSIZE) { + i = (int)strlen(IObuff) + 2; + if (i + (arg - startarg) < IOSIZE) { // append the argument with the error STRCAT(IObuff, ": "); - assert((char_u *)arg >= startarg); - memmove(IObuff + i, startarg, (size_t)((char_u *)arg - startarg)); - IObuff[i + ((char_u *)arg - startarg)] = NUL; + assert(arg >= startarg); + memmove(IObuff + i, startarg, (size_t)(arg - startarg)); + IObuff[i + (arg - startarg)] = NUL; } // make sure all characters are printable trans_characters((char *)IObuff, IOSIZE); - no_wait_return++; // wait_return done later + no_wait_return++; // wait_return() done later emsg((char *)IObuff); // show error highlighted no_wait_return--; @@ -1587,7 +1540,7 @@ void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked /// Convert a key name or string into a key value. /// Used for 'wildchar' and 'cedit' options. -static int string_to_key(char_u *arg) +int string_to_key(char_u *arg) { if (*arg == '<') { return find_key_option(arg + 1, true); @@ -1598,24 +1551,6 @@ static int string_to_key(char_u *arg) return *arg; } -/// Check value of 'cedit' and set cedit_key. -/// Returns NULL if value is OK, error message otherwise. -char *check_cedit(void) -{ - int n; - - if (*p_cedit == NUL) { - cedit_key = -1; - } else { - n = string_to_key(p_cedit); - if (vim_isprintc(n)) { - return e_invarg; - } - cedit_key = n; - } - return NULL; -} - // When changing 'title', 'titlestring', 'icon' or 'iconstring', call // maketitle() to create and display it. // When switching the title or icon off, call ui_set_{icon,title}(NULL) to get @@ -1632,10 +1567,8 @@ void did_set_title(void) /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL void set_options_bin(int oldval, int newval, int opt_flags) { - /* - * The option values that are changed when 'bin' changes are - * copied when 'bin is set and restored when 'bin' is reset. - */ + // The option values that are changed when 'bin' changes are + // copied when 'bin is set and restored when 'bin' is reset. if (newval) { if (!oldval) { // switched on if (!(opt_flags & OPT_GLOBAL)) { @@ -1702,16 +1635,14 @@ int get_shada_parameter(int type) /// Return NULL if the parameter is not specified in the string. char_u *find_shada_parameter(int type) { - char_u *p; - - for (p = p_shada; *p; p++) { + for (char *p = p_shada; *p; p++) { if (*p == type) { - return p + 1; + return (char_u *)p + 1; } if (*p == 'n') { // 'n' is always the last one break; } - p = (char_u *)vim_strchr((char *)p, ','); // skip until next ',' + p = vim_strchr(p, ','); // skip until next ',' if (p == NULL) { // hit the end without finding parameter break; } @@ -1723,7 +1654,7 @@ char_u *find_shada_parameter(int type) /// These string options cannot be indirect! /// If "val" is NULL expand the current value of the option. /// Return pointer to NameBuff, or NULL when not expanded. -static char_u *option_expand(int opt_idx, char_u *val) +static char *option_expand(int opt_idx, char *val) { // if option doesn't need expansion nothing to do if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) { @@ -1731,26 +1662,24 @@ static char_u *option_expand(int opt_idx, char_u *val) } if (val == NULL) { - val = *(char_u **)options[opt_idx].var; + val = *(char **)options[opt_idx].var; } // If val is longer than MAXPATHL no meaningful expansion can be done, // expand_env() would truncate the string. - if (val == NULL || STRLEN(val) > MAXPATHL) { + if (val == NULL || strlen(val) > MAXPATHL) { return NULL; } - /* - * Expanding this with NameBuff, expand_env() must not be passed IObuff. - * Escape spaces when expanding 'tags', they are used to separate file - * names. - * For 'spellsuggest' expand after "file:". - */ - expand_env_esc(val, NameBuff, MAXPATHL, + // Expanding this with NameBuff, expand_env() must not be passed IObuff. + // Escape spaces when expanding 'tags', they are used to separate file + // names. + // For 'spellsuggest' expand after "file:". + expand_env_esc((char_u *)val, (char_u *)NameBuff, MAXPATHL, (char_u **)options[opt_idx].var == &p_tags, false, - (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" : + (char_u **)options[opt_idx].var == (char_u **)&p_sps ? (char_u *)"file:" : NULL); - if (STRCMP(NameBuff, val) == 0) { // they are the same + if (strcmp(NameBuff, val) == 0) { // they are the same return NULL; } @@ -1804,7 +1733,7 @@ void check_options(void) for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) { if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) { - check_string_option((char_u **)get_varp(&(options[opt_idx]))); + check_string_option((char **)get_varp(&(options[opt_idx]))); } } } @@ -1863,10 +1792,10 @@ void redraw_titles(void) /// Return true if "val" is a valid name: only consists of alphanumeric ASCII /// characters or characters in "allowed". -bool valid_name(const char_u *val, const char *allowed) +bool valid_name(const char *val, const char *allowed) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - for (const char_u *s = val; *s != NUL; s++) { + for (const char_u *s = (char_u *)val; *s != NUL; s++) { if (!ASCII_ISALNUM(*s) && vim_strchr(allowed, *s) == NULL) { return false; @@ -1935,15 +1864,16 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; nlua_set_sctx(&script_ctx); - const LastSet last_set = { - .script_ctx = { - script_ctx.sc_sid, - script_ctx.sc_seq, - script_ctx.sc_lnum + SOURCING_LNUM - }, - current_channel_id + LastSet last_set = { + .script_ctx = script_ctx, + .channel_id = current_channel_id, }; + // Modeline already has the line number set. + if (!(opt_flags & OPT_MODELINE)) { + last_set.script_ctx.sc_lnum += SOURCING_LNUM; + } + // Remember where the option was set. For local options need to do that // in the buffer or window structure. if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) { @@ -1971,6 +1901,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va { int old_value = *(int *)varp; int old_global_value = 0; + char *errmsg = NULL; // Disallow changing some options from secure mode if ((secure || sandbox != 0) @@ -2075,7 +2006,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va paste_option_changed(); } else if ((int *)varp == &p_ic && p_hls) { // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } else if ((int *)varp == &p_hls) { // when 'hlsearch' is set or reset: reset no_hlsearch set_no_hlsearch(false); @@ -2092,7 +2023,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va FOR_ALL_WINDOWS_IN_TAB(win, curtab) { if (win->w_p_pvw && win != curwin) { curwin->w_p_pvw = false; - return N_("E590: A preview window already exists"); + return e_preview_window_already_exists; } } } @@ -2151,18 +2082,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } else if ((int *)varp == &curwin->w_p_spell) { // 'spell' if (curwin->w_p_spell) { - char *errmsg = did_set_spelllang(curwin); - if (errmsg != NULL) { - emsg(_(errmsg)); - } + errmsg = did_set_spelllang(curwin); } } if ((int *)varp == &curwin->w_p_arab) { if (curwin->w_p_arab) { - /* - * 'arabic' is set, handle various sub-settings. - */ + // 'arabic' is set, handle various sub-settings. if (!p_tbidi) { // set rightleft mode if (!curwin->w_p_rl) { @@ -2173,13 +2099,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Enable Arabic shaping (major part of what Arabic requires) if (!p_arshape) { p_arshape = true; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } } // Arabic requires a utf-8 encoding, inform the user if it's not // set. - if (STRCMP(p_enc, "utf-8") != 0) { + if (strcmp(p_enc, "utf-8") != 0) { static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); msg_source(HL_ATTR(HLF_W)); @@ -2191,11 +2117,9 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va p_deco = true; // Force-set the necessary keymap for arabic. - set_option_value("keymap", 0L, "arabic", OPT_LOCAL); + errmsg = set_option_value("keymap", 0L, "arabic", OPT_LOCAL); } else { - /* - * 'arabic' is reset, handle various sub-settings. - */ + // 'arabic' is reset, handle various sub-settings. if (!p_tbidi) { // reset rightleft mode if (curwin->w_p_rl) { @@ -2216,9 +2140,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } - /* - * End of handling side effects for bool options. - */ + // End of handling side effects for bool options. // after handling side effects, call autocommand @@ -2271,7 +2193,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } check_redraw(options[opt_idx].flags); - return NULL; + return errmsg; } /// Set the value of a number option, taking care of side effects @@ -2546,7 +2468,9 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // if p_ch changed value, change the command line height // Only compute the new window layout when startup has been // completed. Otherwise the frame sizes may be wrong. - if (p_ch != old_value && full_screen) { + if ((p_ch != old_value + || tabline_height() + global_stl_height() + topframe->fr_height != Rows - p_ch) + && full_screen) { command_height(); } } else if (pp == &p_uc) { @@ -2622,9 +2546,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, Rows = (int)p_lines; Columns = (int)p_columns; check_screensize(); - if (cmdline_row > Rows - p_ch && Rows > p_ch) { - assert(p_ch >= 0 && Rows - p_ch <= INT_MAX); - cmdline_row = (int)(Rows - p_ch); + int new_row = (int)(Rows - MAX(p_ch, 1)); + if (cmdline_row > new_row && Rows > p_ch) { + assert(p_ch >= 0 && new_row <= INT_MAX); + cmdline_row = new_row; } } if (p_window >= Rows || !option_was_set("window")) { @@ -2718,9 +2643,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, /// Called after an option changed: check if something needs to be redrawn. void check_redraw(uint32_t flags) { - // Careful: P_RCLR and P_RALL are a combination of other P_ flags - bool doclear = (flags & P_RCLR) == P_RCLR; - bool all = ((flags & P_RALL) == P_RALL || doclear); + // Careful: P_RALL is a combination of other P_ flags + bool all = (flags & P_RALL) == P_RALL; if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty status_redraw_all(); @@ -2730,15 +2654,13 @@ void check_redraw(uint32_t flags) changed_window_setting(); } if (flags & P_RBUF) { - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); } if (flags & P_RWINONLY) { - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } - if (doclear) { - redraw_all_later(CLEAR); - } else if (all) { - redraw_all_later(NOT_VALID); + if (all) { + redraw_all_later(UPD_NOT_VALID); } } @@ -2805,10 +2727,10 @@ int findoption_len(const char *const arg, const size_t len) } else { // Nvim: handle option aliases. if (STRNCMP(options[opt_idx].fullname, "viminfo", 7) == 0) { - if (STRLEN(options[opt_idx].fullname) == 7) { + if (strlen(options[opt_idx].fullname) == 7) { return findoption_len("shada", 5); } - assert(STRCMP(options[opt_idx].fullname, "viminfofile") == 0); + assert(strcmp(options[opt_idx].fullname, "viminfofile") == 0); return findoption_len("shadafile", 9); } } @@ -2888,7 +2810,7 @@ bool set_tty_option(const char *name, char *value) void set_tty_background(const char *value) { - if (option_was_set("bg") || strequal((char *)p_bg, value)) { + if (option_was_set("bg") || strequal(p_bg, value)) { // background is already set... ignore return; } @@ -2898,7 +2820,7 @@ void set_tty_background(const char *value) ? "autocmd VimEnter * ++once ++nested set bg=light" : "autocmd VimEnter * ++once ++nested set bg=dark"); } else { - set_option_value("bg", 0L, value, 0); + set_option_value_give_err("bg", 0L, value, 0); reset_option_was_set("bg"); } } @@ -2937,14 +2859,14 @@ getoption_T get_option_value(const char *name, long *numval, char **stringval, i return gov_unknown; } - char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags); + char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); if (options[opt_idx].flags & P_STRING) { if (varp == NULL) { // hidden option return gov_hidden_string; } if (stringval != NULL) { - if ((char_u **)varp == &p_pt) { // 'pastetoggle' + if ((char **)varp == &p_pt) { // 'pastetoggle' *stringval = str2special_save(*(char **)(varp), false, false); } else { *stringval = xstrdup(*(char **)(varp)); @@ -3063,7 +2985,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o // only getting a pointer, no need to use aucmd_prepbuf() curbuf = (buf_T *)from; curwin->w_buffer = curbuf; - varp = get_varp_scope(p, OPT_LOCAL); + varp = (char_u *)get_varp_scope(p, OPT_LOCAL); curbuf = save_curbuf; curwin->w_buffer = curbuf; } @@ -3071,7 +2993,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o win_T *save_curwin = curwin; curwin = (win_T *)from; curbuf = curwin->w_buffer; - varp = get_varp_scope(p, OPT_LOCAL); + varp = (char_u *)get_varp_scope(p, OPT_LOCAL); curwin = save_curwin; curbuf = curwin->w_buffer; } @@ -3094,47 +3016,10 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return rv; } -/// Return the flags for the option at 'opt_idx'. -uint32_t get_option_flags(int opt_idx) -{ - return options[opt_idx].flags; -} - -/// Set a flag for the option at 'opt_idx'. -void set_option_flag(int opt_idx, uint32_t flag) -{ - options[opt_idx].flags |= flag; -} - -/// Clear a flag for the option at 'opt_idx'. -void clear_option_flag(int opt_idx, uint32_t flag) -{ - options[opt_idx].flags &= ~flag; -} - -/// Returns true if the option at 'opt_idx' is a global option -bool is_global_option(int opt_idx) -{ - return options[opt_idx].indir == PV_NONE; -} - -/// Returns true if the option at 'opt_idx' is a global option which also has a -/// local value. -int is_global_local_option(int opt_idx) -{ - return options[opt_idx].indir & PV_BOTH; -} - -/// Returns true if the option at 'opt_idx' is a window-local option -bool is_window_local_option(int opt_idx) -{ - return options[opt_idx].var == VAR_WIN; -} - -/// Returns true if the option at 'opt_idx' is a hidden option -bool is_hidden_option(int opt_idx) +// Return information for option at 'opt_idx' +vimoption_T *get_option(int opt_idx) { - return options[opt_idx].var == NULL; + return &options[opt_idx]; } /// Set the value of an option @@ -3147,7 +3032,7 @@ bool is_hidden_option(int opt_idx) /// is cleared (the exact semantics of this depend /// on the option). /// -/// @return NULL on success, error message on error. +/// @return NULL on success, an untranslated error message on error. char *set_option_value(const char *const name, const long number, const char *const string, const int opt_flags) FUNC_ATTR_NONNULL_ARG(1) @@ -3177,7 +3062,7 @@ char *set_option_value(const char *const name, const long number, const char *co return set_string_option(opt_idx, s, opt_flags); } - varp = get_varp_scope(&(options[opt_idx]), opt_flags); + varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); if (varp != NULL) { // hidden option is not changed if (number == 0 && string != NULL) { int idx; @@ -3217,6 +3102,18 @@ char *set_option_value(const char *const name, const long number, const char *co return NULL; } +/// Call set_option_value() and when an error is returned report it. +/// +/// @param opt_flags OPT_LOCAL or 0 (both) +void set_option_value_give_err(const char *name, long number, const char *string, int opt_flags) +{ + char *errmsg = set_option_value(name, number, string, opt_flags); + + if (errmsg != NULL) { + emsg(_(errmsg)); + } +} + /// Return true if "name" is a string option. /// Returns false if option "name" does not exist. bool is_string_option(const char *name) @@ -3294,14 +3191,14 @@ static void showoptions(int all, int opt_flags) item_count = 0; for (p = &options[0]; p->fullname != NULL; p++) { // apply :filter /pat/ - if (message_filtered((char_u *)p->fullname)) { + if (message_filtered(p->fullname)) { continue; } varp = NULL; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { if (p->indir != PV_NONE) { - varp = get_varp_scope(p, opt_flags); + varp = (char_u *)get_varp_scope(p, opt_flags); } } else { varp = get_varp(p); @@ -3314,7 +3211,7 @@ static void showoptions(int all, int opt_flags) len = 1; // a toggle option fits always } else { option_value2string(p, opt_flags); - len = (int)STRLEN(p->fullname) + vim_strsize((char *)NameBuff) + 1; + len = (int)strlen(p->fullname) + vim_strsize((char *)NameBuff) + 1; } if ((len <= INC - GAP && run == 1) || (len > INC - GAP && run == 2)) { @@ -3323,9 +3220,7 @@ static void showoptions(int all, int opt_flags) } } - /* - * display the items - */ + // display the items if (run == 1) { assert(Columns <= INT_MAX - GAP && Columns + GAP >= INT_MIN + 3 @@ -3350,7 +3245,6 @@ static void showoptions(int all, int opt_flags) showoneopt(items[i], opt_flags); col += INC; } - ui_flush(); os_breakcheck(); } } @@ -3370,7 +3264,7 @@ static int optval_default(vimoption_T *p, char_u *varp) return *(int *)varp == (int)(intptr_t)p->def_val; } // P_STRING - return STRCMP(*(char_u **)varp, p->def_val) == 0; + return strcmp(*(char **)varp, p->def_val) == 0; } /// Send update to UIs with values of UI relevant options @@ -3405,13 +3299,12 @@ void ui_refresh_options(void) /// @param opt_flags OPT_LOCAL or OPT_GLOBAL static void showoneopt(vimoption_T *p, int opt_flags) { - char_u *varp; int save_silent = silent_mode; silent_mode = false; info_message = true; // use mch_msg(), not mch_errmsg() - varp = get_varp_scope(p, opt_flags); + char_u *varp = (char_u *)get_varp_scope(p, opt_flags); // for 'modified' we also need to check if 'ff' or 'fenc' changed. if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed @@ -3457,22 +3350,20 @@ static void showoneopt(vimoption_T *p, int opt_flags) int makeset(FILE *fd, int opt_flags, int local_only) { vimoption_T *p; - char_u *varp; // currently used value + char *varp; // currently used value char_u *varp_fresh; // local value char_u *varp_local = NULL; // fresh value char *cmd; int round; int pri; - /* - * Some options are never written: - * - Options that don't have a default (terminal name, columns, lines). - * - Terminal options. - * - Hidden options. - * - * Do the loop over "options[]" twice: once for options with the - * P_PRI_MKRC flag and once without. - */ + // Some options are never written: + // - Options that don't have a default (terminal name, columns, lines). + // - Terminal options. + // - Hidden options. + // + // Do the loop over "options[]" twice: once for options with the + // P_PRI_MKRC flag and once without. for (pri = 1; pri >= 0; pri--) { for (p = &options[0]; p->fullname; p++) { if (!(p->flags & P_NO_MKRC) @@ -3494,7 +3385,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) continue; } // Global values are only written when not at the default value. - if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) { + if ((opt_flags & OPT_GLOBAL) && optval_default(p, (char_u *)varp)) { continue; } @@ -3513,11 +3404,11 @@ int makeset(FILE *fd, int opt_flags, int local_only) // When fresh value of window-local option is not at the // default, need to write it too. if (!(opt_flags & OPT_GLOBAL) && !local_only) { - varp_fresh = get_varp_scope(p, OPT_GLOBAL); + varp_fresh = (char_u *)get_varp_scope(p, OPT_GLOBAL); if (!optval_default(p, varp_fresh)) { round = 1; - varp_local = varp; - varp = varp_fresh; + varp_local = (char_u *)varp; + varp = (char *)varp_fresh; } } } @@ -3525,7 +3416,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // Round 1: fresh value for window-local options. // Round 2: other values - for (; round <= 2; varp = varp_local, round++) { + for (; round <= 2; varp = (char *)varp_local, round++) { if (round == 1 || (opt_flags & OPT_GLOBAL)) { cmd = "set"; } else { @@ -3553,8 +3444,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) } do_endif = true; } - if (put_setstring(fd, cmd, p->fullname, (char_u **)varp, - p->flags) == FAIL) { + if (put_setstring(fd, cmd, p->fullname, (char **)varp, p->flags) == FAIL) { return FAIL; } if (do_endif) { @@ -3575,24 +3465,20 @@ int makeset(FILE *fd, int opt_flags, int local_only) int makefoldset(FILE *fd) { if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL - || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) - == FAIL - || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) - == FAIL - || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) - == FAIL + || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) == FAIL + || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) == FAIL + || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) == FAIL || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL - || put_setbool(fd, "setlocal", "fen", - curwin->w_p_fen) == FAIL) { + || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL) { return FAIL; } return OK; } -static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint64_t flags) +static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_t flags) { char_u *s; char_u *buf = NULL; @@ -3607,26 +3493,24 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint6 // options some characters have to be escaped with // CTRL-V or backslash if (valuep == &p_pt) { - s = *valuep; + s = (char_u *)(*valuep); while (*s != NUL) { - if (put_escstr(fd, (char_u *)str2special((const char **)&s, false, - false), 2) - == FAIL) { + if (put_escstr(fd, (char_u *)str2special((const char **)&s, false, false), 2) == FAIL) { return FAIL; } } } else if ((flags & P_EXPAND) != 0) { - size_t size = (size_t)STRLEN(*valuep) + 1; + size_t size = (size_t)strlen(*valuep) + 1; // replace home directory in the whole option value into "buf" buf = xmalloc(size); - home_replace(NULL, (char *)(*valuep), (char *)buf, size, false); + home_replace(NULL, *valuep, (char *)buf, size, false); // If the option value is longer than MAXPATHL, we need to append // each comma separated part of the option separately, so that it // can be expanded when read back. if (size >= MAXPATHL && (flags & P_COMMA) != 0 - && vim_strchr((char *)(*valuep), ',') != NULL) { + && vim_strchr(*valuep, ',') != NULL) { part = xmalloc(size); // write line break to clear the option, e.g. ':set rtp=' @@ -3654,7 +3538,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint6 return FAIL; } xfree(buf); - } else if (put_escstr(fd, *valuep, 2) == FAIL) { + } else if (put_escstr(fd, (char_u *)(*valuep), 2) == FAIL) { return FAIL; } } @@ -3780,7 +3664,7 @@ void unset_global_local_option(char *name, void *from) clear_string_option(&((win_T *)from)->w_p_stl); break; case PV_WBR: - clear_string_option((char_u **)&((win_T *)from)->w_p_wbr); + clear_string_option(&((win_T *)from)->w_p_wbr); break; case PV_UL: buf->b_p_ul = NO_LOCAL_UNDOLEVEL; @@ -3794,12 +3678,12 @@ void unset_global_local_option(char *name, void *from) case PV_LCS: clear_string_option(&((win_T *)from)->w_p_lcs); set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true); - redraw_later((win_T *)from, NOT_VALID); + redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_FCS: clear_string_option(&((win_T *)from)->w_p_fcs); set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true); - redraw_later((win_T *)from, NOT_VALID); + redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_VE: clear_string_option(&((win_T *)from)->w_p_ve); @@ -3809,83 +3693,76 @@ void unset_global_local_option(char *name, void *from) } /// Get pointer to option variable, depending on local or global scope. -static char_u *get_varp_scope(vimoption_T *p, int opt_flags) +char *get_varp_scope(vimoption_T *p, int opt_flags) { if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) { - return (char_u *)GLOBAL_WO(get_varp(p)); + return GLOBAL_WO(get_varp(p)); } - return p->var; + return (char *)p->var; } if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { switch ((int)p->indir) { case PV_FP: - return (char_u *)&(curbuf->b_p_fp); + return (char *)&(curbuf->b_p_fp); case PV_EFM: - return (char_u *)&(curbuf->b_p_efm); + return (char *)&(curbuf->b_p_efm); case PV_GP: - return (char_u *)&(curbuf->b_p_gp); + return (char *)&(curbuf->b_p_gp); case PV_MP: - return (char_u *)&(curbuf->b_p_mp); + return (char *)&(curbuf->b_p_mp); case PV_EP: - return (char_u *)&(curbuf->b_p_ep); + return (char *)&(curbuf->b_p_ep); case PV_KP: - return (char_u *)&(curbuf->b_p_kp); + return (char *)&(curbuf->b_p_kp); case PV_PATH: - return (char_u *)&(curbuf->b_p_path); + return (char *)&(curbuf->b_p_path); case PV_AR: - return (char_u *)&(curbuf->b_p_ar); + return (char *)&(curbuf->b_p_ar); case PV_TAGS: - return (char_u *)&(curbuf->b_p_tags); + return (char *)&(curbuf->b_p_tags); case PV_TC: - return (char_u *)&(curbuf->b_p_tc); + return (char *)&(curbuf->b_p_tc); case PV_SISO: - return (char_u *)&(curwin->w_p_siso); + return (char *)&(curwin->w_p_siso); case PV_SO: - return (char_u *)&(curwin->w_p_so); + return (char *)&(curwin->w_p_so); case PV_DEF: - return (char_u *)&(curbuf->b_p_def); + return (char *)&(curbuf->b_p_def); case PV_INC: - return (char_u *)&(curbuf->b_p_inc); + return (char *)&(curbuf->b_p_inc); case PV_DICT: - return (char_u *)&(curbuf->b_p_dict); + return (char *)&(curbuf->b_p_dict); case PV_TSR: - return (char_u *)&(curbuf->b_p_tsr); + return (char *)&(curbuf->b_p_tsr); case PV_TSRFU: - return (char_u *)&(curbuf->b_p_tsrfu); + return (char *)&(curbuf->b_p_tsrfu); case PV_TFU: - return (char_u *)&(curbuf->b_p_tfu); + return (char *)&(curbuf->b_p_tfu); case PV_SBR: - return (char_u *)&(curwin->w_p_sbr); + return (char *)&(curwin->w_p_sbr); case PV_STL: - return (char_u *)&(curwin->w_p_stl); + return (char *)&(curwin->w_p_stl); case PV_WBR: - return (char_u *)&(curwin->w_p_wbr); + return (char *)&(curwin->w_p_wbr); case PV_UL: - return (char_u *)&(curbuf->b_p_ul); + return (char *)&(curbuf->b_p_ul); case PV_LW: - return (char_u *)&(curbuf->b_p_lw); + return (char *)&(curbuf->b_p_lw); case PV_BKC: - return (char_u *)&(curbuf->b_p_bkc); + return (char *)&(curbuf->b_p_bkc); case PV_MENC: - return (char_u *)&(curbuf->b_p_menc); + return (char *)&(curbuf->b_p_menc); case PV_FCS: - return (char_u *)&(curwin->w_p_fcs); + return (char *)&(curwin->w_p_fcs); case PV_LCS: - return (char_u *)&(curwin->w_p_lcs); + return (char *)&(curwin->w_p_lcs); case PV_VE: - return (char_u *)&(curwin->w_p_ve); + return (char *)&(curwin->w_p_ve); } return NULL; // "cannot happen" } - return get_varp(p); -} - -/// Get pointer to option variable at 'opt_idx', depending on local or global -/// scope. -char_u *get_option_varp_scope(int opt_idx, int opt_flags) -{ - return get_varp_scope(&(options[opt_idx]), opt_flags); + return (char *)get_varp(p); } /// Get pointer to option variable. @@ -4197,25 +4074,13 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_wm); } -/// Return a pointer to the variable for option at 'opt_idx' -char_u *get_option_var(int opt_idx) -{ - return options[opt_idx].var; -} - -/// Return the full name of the option at 'opt_idx' -char *get_option_fullname(int opt_idx) -{ - return options[opt_idx].fullname; -} - /// Get the value of 'equalprg', either the buffer-local one or the global one. char_u *get_equalprg(void) { if (*curbuf->b_p_ep == NUL) { return p_ep; } - return curbuf->b_p_ep; + return (char_u *)curbuf->b_p_ep; } /// Copy options from one window to another. @@ -4227,6 +4092,14 @@ void win_copy_options(win_T *wp_from, win_T *wp_to) didset_window_options(wp_to, true); } +static char *copy_option_val(const char *val) +{ + if (val == empty_option) { + return empty_option; // no need to allocate memory + } + return xstrdup(val); +} + /// Copy the options from one winopt_T to another. /// Doesn't free the old option values in "to", use clear_winopt() for that. /// The 'scroll' option is not copied, because it depends on the window height. @@ -4235,21 +4108,23 @@ void copy_winopt(winopt_T *from, winopt_T *to) { to->wo_arab = from->wo_arab; to->wo_list = from->wo_list; + to->wo_lcs = copy_option_val(from->wo_lcs); + to->wo_fcs = copy_option_val(from->wo_fcs); to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; - to->wo_ve = vim_strsave(from->wo_ve); + to->wo_ve = copy_option_val(from->wo_ve); to->wo_ve_flags = from->wo_ve_flags; to->wo_nuw = from->wo_nuw; to->wo_rl = from->wo_rl; - to->wo_rlc = vim_strsave(from->wo_rlc); - to->wo_sbr = vim_strsave(from->wo_sbr); - to->wo_stl = vim_strsave(from->wo_stl); - to->wo_wbr = xstrdup(from->wo_wbr); + to->wo_rlc = copy_option_val(from->wo_rlc); + to->wo_sbr = copy_option_val(from->wo_sbr); + to->wo_stl = copy_option_val(from->wo_stl); + to->wo_wbr = copy_option_val(from->wo_wbr); to->wo_wrap = from->wo_wrap; to->wo_wrap_save = from->wo_wrap_save; to->wo_lbr = from->wo_lbr; to->wo_bri = from->wo_bri; - to->wo_briopt = vim_strsave(from->wo_briopt); + to->wo_briopt = copy_option_val(from->wo_briopt); to->wo_scb = from->wo_scb; to->wo_scb_save = from->wo_scb_save; to->wo_crb = from->wo_crb; @@ -4257,32 +4132,28 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_spell = from->wo_spell; to->wo_cuc = from->wo_cuc; to->wo_cul = from->wo_cul; - to->wo_culopt = vim_strsave(from->wo_culopt); - to->wo_cc = vim_strsave(from->wo_cc); + to->wo_culopt = copy_option_val(from->wo_culopt); + to->wo_cc = copy_option_val(from->wo_cc); to->wo_diff = from->wo_diff; to->wo_diff_saved = from->wo_diff_saved; - to->wo_cocu = vim_strsave(from->wo_cocu); + to->wo_cocu = copy_option_val(from->wo_cocu); to->wo_cole = from->wo_cole; - to->wo_fdc = vim_strsave(from->wo_fdc); - to->wo_fdc_save = from->wo_diff_saved - ? vim_strsave(from->wo_fdc_save) : empty_option; + to->wo_fdc = copy_option_val(from->wo_fdc); + to->wo_fdc_save = from->wo_diff_saved ? xstrdup(from->wo_fdc_save) : empty_option; to->wo_fen = from->wo_fen; to->wo_fen_save = from->wo_fen_save; - to->wo_fdi = vim_strsave(from->wo_fdi); + to->wo_fdi = copy_option_val(from->wo_fdi); to->wo_fml = from->wo_fml; to->wo_fdl = from->wo_fdl; to->wo_fdl_save = from->wo_fdl_save; - to->wo_fdm = vim_strsave(from->wo_fdm); - to->wo_fdm_save = from->wo_diff_saved - ? vim_strsave(from->wo_fdm_save) : empty_option; + to->wo_fdm = copy_option_val(from->wo_fdm); + to->wo_fdm_save = from->wo_diff_saved ? xstrdup(from->wo_fdm_save) : empty_option; to->wo_fdn = from->wo_fdn; - to->wo_fde = vim_strsave(from->wo_fde); - to->wo_fdt = vim_strsave(from->wo_fdt); - to->wo_fmr = vim_strsave(from->wo_fmr); - to->wo_scl = vim_strsave(from->wo_scl); - to->wo_winhl = vim_strsave(from->wo_winhl); - to->wo_fcs = vim_strsave(from->wo_fcs); - to->wo_lcs = vim_strsave(from->wo_lcs); + to->wo_fde = copy_option_val(from->wo_fde); + to->wo_fdt = copy_option_val(from->wo_fdt); + to->wo_fmr = copy_option_val(from->wo_fmr); + to->wo_scl = copy_option_val(from->wo_scl); + to->wo_winhl = copy_option_val(from->wo_winhl); to->wo_winbl = from->wo_winbl; // Copy the script context so that we know were the value was last set. @@ -4317,10 +4188,10 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_cocu); check_string_option(&wop->wo_briopt); check_string_option(&wop->wo_winhl); - check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_lcs); + check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_ve); - check_string_option((char_u **)&wop->wo_wbr); + check_string_option(&wop->wo_wbr); } /// Free the allocated memory inside a winopt_T. @@ -4343,10 +4214,10 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_cocu); clear_string_option(&wop->wo_briopt); clear_string_option(&wop->wo_winhl); - clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_lcs); + clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_ve); - clear_string_option((char_u **)&wop->wo_wbr); + clear_string_option(&wop->wo_wbr); } void didset_window_options(win_T *wp, bool valid_cursor) @@ -4396,10 +4267,8 @@ void buf_copy_options(buf_T *buf, int flags) int dont_do_help; int did_isk = false; - /* - * Skip this when the option defaults have not been set yet. Happens when - * main() allocates the first buffer. - */ + // Skip this when the option defaults have not been set yet. Happens when + // main() allocates the first buffer. if (p_cpo != NULL) { // // Always copy when entering and 'cpo' contains 'S'. @@ -4428,7 +4297,7 @@ void buf_copy_options(buf_T *buf, int flags) // (jumping back to a help file with CTRL-T or CTRL-O) dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; if (dont_do_help) { // don't free b_p_isk - save_p_isk = buf->b_p_isk; + save_p_isk = (char_u *)buf->b_p_isk; buf->b_p_isk = NULL; } // Always free the allocated strings. If not already initialized, @@ -4436,19 +4305,19 @@ void buf_copy_options(buf_T *buf, int flags) if (!buf->b_p_initialized) { free_buf_options(buf, true); buf->b_p_ro = false; // don't copy readonly - buf->b_p_fenc = vim_strsave(p_fenc); + buf->b_p_fenc = xstrdup(p_fenc); switch (*p_ffs) { case 'm': - buf->b_p_ff = vim_strsave((char_u *)FF_MAC); + buf->b_p_ff = xstrdup(FF_MAC); break; case 'd': - buf->b_p_ff = vim_strsave((char_u *)FF_DOS); + buf->b_p_ff = xstrdup(FF_DOS); break; case 'u': - buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); + buf->b_p_ff = xstrdup(FF_UNIX); break; default: - buf->b_p_ff = vim_strsave(p_ff); + buf->b_p_ff = xstrdup(p_ff); break; } buf->b_p_bh = empty_option; @@ -4493,42 +4362,40 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_swf = p_swf; COPY_OPT_SCTX(buf, BV_SWF); } - buf->b_p_cpt = vim_strsave(p_cpt); + buf->b_p_cpt = xstrdup(p_cpt); COPY_OPT_SCTX(buf, BV_CPT); #ifdef BACKSLASH_IN_FILENAME - buf->b_p_csl = vim_strsave(p_csl); + buf->b_p_csl = xstrdup(p_csl); COPY_OPT_SCTX(buf, BV_CSL); #endif - buf->b_p_cfu = vim_strsave(p_cfu); + buf->b_p_cfu = xstrdup(p_cfu); COPY_OPT_SCTX(buf, BV_CFU); - buf->b_p_ofu = vim_strsave(p_ofu); + buf->b_p_ofu = xstrdup(p_ofu); COPY_OPT_SCTX(buf, BV_OFU); - buf->b_p_tfu = vim_strsave(p_tfu); + buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); buf->b_p_sts_nopaste = p_sts_nopaste; - buf->b_p_vsts = vim_strsave(p_vsts); + buf->b_p_vsts = xstrdup(p_vsts); COPY_OPT_SCTX(buf, BV_VSTS); if (p_vsts && p_vsts != empty_option) { (void)tabstop_set(p_vsts, &buf->b_p_vsts_array); } else { buf->b_p_vsts_array = NULL; } - buf->b_p_vsts_nopaste = p_vsts_nopaste - ? vim_strsave(p_vsts_nopaste) - : NULL; - buf->b_p_com = vim_strsave(p_com); + buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL; + buf->b_p_com = xstrdup(p_com); COPY_OPT_SCTX(buf, BV_COM); - buf->b_p_cms = vim_strsave(p_cms); + buf->b_p_cms = xstrdup(p_cms); COPY_OPT_SCTX(buf, BV_CMS); - buf->b_p_fo = vim_strsave(p_fo); + buf->b_p_fo = xstrdup(p_fo); COPY_OPT_SCTX(buf, BV_FO); - buf->b_p_flp = vim_strsave(p_flp); + buf->b_p_flp = xstrdup(p_flp); COPY_OPT_SCTX(buf, BV_FLP); - buf->b_p_nf = vim_strsave(p_nf); + buf->b_p_nf = xstrdup(p_nf); COPY_OPT_SCTX(buf, BV_NF); - buf->b_p_mps = vim_strsave(p_mps); + buf->b_p_mps = xstrdup(p_mps); COPY_OPT_SCTX(buf, BV_MPS); buf->b_p_si = p_si; COPY_OPT_SCTX(buf, BV_SI); @@ -4538,18 +4405,18 @@ void buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_CI); buf->b_p_cin = p_cin; COPY_OPT_SCTX(buf, BV_CIN); - buf->b_p_cink = vim_strsave(p_cink); + buf->b_p_cink = xstrdup(p_cink); COPY_OPT_SCTX(buf, BV_CINK); - buf->b_p_cino = vim_strsave(p_cino); + buf->b_p_cino = xstrdup(p_cino); COPY_OPT_SCTX(buf, BV_CINO); - buf->b_p_cinsd = vim_strsave(p_cinsd); + buf->b_p_cinsd = xstrdup(p_cinsd); COPY_OPT_SCTX(buf, BV_CINSD); // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_option; buf->b_p_pi = p_pi; COPY_OPT_SCTX(buf, BV_PI); - buf->b_p_cinw = vim_strsave(p_cinw); + buf->b_p_cinw = xstrdup(p_cinw); COPY_OPT_SCTX(buf, BV_CINW); buf->b_p_lisp = p_lisp; COPY_OPT_SCTX(buf, BV_LISP); @@ -4558,25 +4425,25 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_smc = p_smc; COPY_OPT_SCTX(buf, BV_SMC); buf->b_s.b_syn_isk = empty_option; - buf->b_s.b_p_spc = vim_strsave(p_spc); + buf->b_s.b_p_spc = xstrdup(p_spc); COPY_OPT_SCTX(buf, BV_SPC); (void)compile_cap_prog(&buf->b_s); - buf->b_s.b_p_spf = vim_strsave(p_spf); + buf->b_s.b_p_spf = xstrdup(p_spf); COPY_OPT_SCTX(buf, BV_SPF); - buf->b_s.b_p_spl = vim_strsave(p_spl); + buf->b_s.b_p_spl = xstrdup(p_spl); COPY_OPT_SCTX(buf, BV_SPL); - buf->b_s.b_p_spo = vim_strsave(p_spo); + buf->b_s.b_p_spo = xstrdup(p_spo); COPY_OPT_SCTX(buf, BV_SPO); - buf->b_p_inde = vim_strsave(p_inde); + buf->b_p_inde = xstrdup(p_inde); COPY_OPT_SCTX(buf, BV_INDE); - buf->b_p_indk = vim_strsave(p_indk); + buf->b_p_indk = xstrdup(p_indk); COPY_OPT_SCTX(buf, BV_INDK); buf->b_p_fp = empty_option; - buf->b_p_fex = vim_strsave(p_fex); + buf->b_p_fex = xstrdup(p_fex); COPY_OPT_SCTX(buf, BV_FEX); - buf->b_p_sua = vim_strsave(p_sua); + buf->b_p_sua = xstrdup(p_sua); COPY_OPT_SCTX(buf, BV_SUA); - buf->b_p_keymap = vim_strsave(p_keymap); + buf->b_p_keymap = xstrdup(p_keymap); COPY_OPT_SCTX(buf, BV_KMAP); buf->b_kmap_state |= KEYMAP_INIT; // This isn't really an option, but copying the langmap and IME @@ -4603,38 +4470,36 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_tc_flags = 0; buf->b_p_def = empty_option; buf->b_p_inc = empty_option; - buf->b_p_inex = vim_strsave(p_inex); + buf->b_p_inex = xstrdup(p_inex); COPY_OPT_SCTX(buf, BV_INEX); buf->b_p_dict = empty_option; buf->b_p_tsr = empty_option; buf->b_p_tsrfu = empty_option; - buf->b_p_qe = vim_strsave(p_qe); + buf->b_p_qe = xstrdup(p_qe); COPY_OPT_SCTX(buf, BV_QE); buf->b_p_udf = p_udf; COPY_OPT_SCTX(buf, BV_UDF); buf->b_p_lw = empty_option; buf->b_p_menc = empty_option; - /* - * Don't copy the options set by ex_help(), use the saved values, - * when going from a help buffer to a non-help buffer. - * Don't touch these at all when BCO_NOHELP is used and going from - * or to a help buffer. - */ + // Don't copy the options set by ex_help(), use the saved values, + // when going from a help buffer to a non-help buffer. + // Don't touch these at all when BCO_NOHELP is used and going from + // or to a help buffer. if (dont_do_help) { - buf->b_p_isk = save_p_isk; + buf->b_p_isk = (char *)save_p_isk; if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { (void)tabstop_set(p_vts, &buf->b_p_vts_array); } else { buf->b_p_vts_array = NULL; } } else { - buf->b_p_isk = vim_strsave(p_isk); + buf->b_p_isk = xstrdup(p_isk); COPY_OPT_SCTX(buf, BV_ISK); did_isk = true; buf->b_p_ts = p_ts; COPY_OPT_SCTX(buf, BV_TS); - buf->b_p_vts = vim_strsave(p_vts); + buf->b_p_vts = xstrdup(p_vts); COPY_OPT_SCTX(buf, BV_VTS); if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { (void)tabstop_set(p_vts, &buf->b_p_vts_array); @@ -4650,10 +4515,8 @@ void buf_copy_options(buf_T *buf, int flags) } } - /* - * When the options should be copied (ignoring BCO_ALWAYS), set the - * flag that indicates that the options have been initialized. - */ + // When the options should be copied (ignoring BCO_ALWAYS), set the + // flag that indicates that the options have been initialized. if (should_copy) { buf->b_p_initialized = true; } @@ -4877,7 +4740,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi int num_normal = 0; // Nr of matching non-term-code settings int match; int count = 0; - char_u *str; + char *str; int loop; static char *(names[]) = { "all" }; int ic = regmatch->rm_ic; // remember the ignore-case flag @@ -4899,7 +4762,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi } } } - for (size_t opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL; + for (size_t opt_idx = 0; (str = options[opt_idx].fullname) != NULL; opt_idx++) { if (options[opt_idx].var == NULL) { continue; @@ -4909,7 +4772,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi continue; } match = false; - if (vim_regexec(regmatch, (char *)str, (colnr_T)0) + if (vim_regexec(regmatch, str, (colnr_T)0) || (options[opt_idx].shortname != NULL && vim_regexec(regmatch, options[opt_idx].shortname, @@ -4921,7 +4784,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi if (loop == 0) { num_normal++; } else { - (*file)[count++] = (char *)vim_strsave(str); + (*file)[count++] = xstrdup(str); } } } @@ -4932,7 +4795,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi } else { return OK; } - *file = xmalloc((size_t)(*num_file) * sizeof(char_u *)); + *file = xmalloc((size_t)(*num_file) * sizeof(char *)); } } return OK; @@ -4945,9 +4808,7 @@ void ExpandOldSetting(int *num_file, char ***file) *num_file = 0; *file = xmalloc(sizeof(char_u *)); - /* - * For a terminal key code expand_option_idx is < 0. - */ + // For a terminal key code expand_option_idx is < 0. if (expand_option_idx < 0) { expand_option_idx = findoption((const char *)expand_option_name); } @@ -4955,7 +4816,7 @@ void ExpandOldSetting(int *num_file, char ***file) if (expand_option_idx >= 0) { // Put string of option value in NameBuff. option_value2string(&options[expand_option_idx], expand_option_flags); - var = NameBuff; + var = (char_u *)NameBuff; } else { var = (char_u *)""; } @@ -4988,9 +4849,7 @@ void ExpandOldSetting(int *num_file, char ***file) /// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL static void option_value2string(vimoption_T *opp, int opt_flags) { - char_u *varp; - - varp = get_varp_scope(opp, opt_flags); + char_u *varp = (char_u *)get_varp_scope(opp, opt_flags); if (opp->flags & P_NUM) { long wc = 0; @@ -5012,7 +4871,7 @@ static void option_value2string(vimoption_T *opp, int opt_flags) } else if (opp->flags & P_EXPAND) { home_replace(NULL, (char *)varp, (char *)NameBuff, MAXPATHL, false); // Translate 'pastetoggle' into special key names. - } else if ((char_u **)opp->var == &p_pt) { + } else if ((char **)opp->var == &p_pt) { str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL); } else { STRLCPY(NameBuff, varp, MAXPATHL); @@ -5034,25 +4893,14 @@ static int wc_use_keyname(char_u *varp, long *wcp) return false; } -/// Return true if format option 'x' is in effect. -/// Take care of no formatting when 'paste' is set. -bool has_format_option(int x) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (p_paste) { - return false; - } - return vim_strchr((char *)curbuf->b_p_fo, x) != NULL; -} - /// @returns true if "x" is present in 'shortmess' option, or /// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS. bool shortmess(int x) { return (p_shm != NULL - && (vim_strchr((char *)p_shm, x) != NULL - || (vim_strchr((char *)p_shm, 'a') != NULL - && vim_strchr((char *)SHM_ALL_ABBREVIATIONS, x) != NULL))); + && (vim_strchr(p_shm, x) != NULL + || (vim_strchr(p_shm, 'a') != NULL + && vim_strchr(SHM_ALL_ABBREVIATIONS, x) != NULL))); } /// paste_option_changed() - Called after p_paste was set or reset. @@ -5066,10 +4914,8 @@ static void paste_option_changed(void) static int save_hkmap = 0; if (p_paste) { - /* - * Paste switched from off to on. - * Save the current values, so they can be restored later. - */ + // Paste switched from off to on. + // Save the current values, so they can be restored later. if (!old_p_paste) { // save options for each buffer FOR_ALL_BUFFERS(buf) { @@ -5082,7 +4928,7 @@ static void paste_option_changed(void) xfree(buf->b_p_vsts_nopaste); } buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option - ? vim_strsave(buf->b_p_vsts) + ? xstrdup(buf->b_p_vsts) : NULL; } @@ -5101,9 +4947,7 @@ static void paste_option_changed(void) if (p_vsts_nopaste) { xfree(p_vsts_nopaste); } - p_vsts_nopaste = p_vsts && p_vsts != empty_option - ? vim_strsave(p_vsts) - : NULL; + p_vsts_nopaste = p_vsts && p_vsts != empty_option ? xstrdup(p_vsts) : NULL; } // Always set the option values, also when 'paste' is set when it is @@ -5153,9 +4997,7 @@ static void paste_option_changed(void) if (buf->b_p_vsts) { free_string_option(buf->b_p_vsts); } - buf->b_p_vsts = buf->b_p_vsts_nopaste - ? vim_strsave(buf->b_p_vsts_nopaste) - : empty_option; + buf->b_p_vsts = buf->b_p_vsts_nopaste ? xstrdup(buf->b_p_vsts_nopaste) : empty_option; xfree(buf->b_p_vsts_array); if (buf->b_p_vsts && buf->b_p_vsts != empty_option) { (void)tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); @@ -5182,7 +5024,7 @@ static void paste_option_changed(void) if (p_vsts) { free_string_option(p_vsts); } - p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option; + p_vsts = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : empty_option; } old_p_paste = p_paste; @@ -5250,16 +5092,16 @@ void fill_breakat_flags(void) } if (p_breakat != NULL) { - for (p = p_breakat; *p; p++) { + for (p = (char_u *)p_breakat; *p; p++) { breakat_flags[*p] = true; } } } /// fill_culopt_flags() -- called when 'culopt' changes value -int fill_culopt_flags(char_u *val, win_T *wp) +int fill_culopt_flags(char *val, win_T *wp) { - char_u *p; + char *p; char_u culopt_flags_new = 0; if (val == NULL) { @@ -5302,7 +5144,7 @@ int fill_culopt_flags(char_u *val, win_T *wp) /// Set the callback function value for an option that accepts a function name, /// lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.) /// @return OK if the option is successfully set to a function, otherwise FAIL -int option_set_callback_func(char_u *optval, Callback *optcb) +int option_set_callback_func(char *optval, Callback *optcb) { if (optval == NULL || *optval == NUL) { callback_free(optcb); @@ -5314,7 +5156,7 @@ int option_set_callback_func(char_u *optval, Callback *optcb) || (STRNCMP(optval, "function(", 9) == 0) || (STRNCMP(optval, "funcref(", 8) == 0)) { // Lambda expression or a funcref - tv = eval_expr((char *)optval); + tv = eval_expr(optval); if (tv == NULL) { return FAIL; } @@ -5322,7 +5164,7 @@ int option_set_callback_func(char_u *optval, Callback *optcb) // treat everything else as a function name string tv = xcalloc(1, sizeof(*tv)); tv->v_type = VAR_STRING; - tv->vval.v_string = (char *)vim_strsave(optval); + tv->vval.v_string = xstrdup(optval); } Callback cb; @@ -5337,59 +5179,6 @@ int option_set_callback_func(char_u *optval, Callback *optcb) return OK; } -/// Read the 'wildmode' option, fill wim_flags[]. -int check_opt_wim(void) -{ - char_u new_wim_flags[4]; - char_u *p; - int i; - int idx = 0; - - for (i = 0; i < 4; i++) { - new_wim_flags[i] = 0; - } - - for (p = p_wim; *p; p++) { - for (i = 0; ASCII_ISALPHA(p[i]); i++) {} - if (p[i] != NUL && p[i] != ',' && p[i] != ':') { - return FAIL; - } - if (i == 7 && STRNCMP(p, "longest", 7) == 0) { - new_wim_flags[idx] |= WIM_LONGEST; - } else if (i == 4 && STRNCMP(p, "full", 4) == 0) { - new_wim_flags[idx] |= WIM_FULL; - } else if (i == 4 && STRNCMP(p, "list", 4) == 0) { - new_wim_flags[idx] |= WIM_LIST; - } else if (i == 8 && STRNCMP(p, "lastused", 8) == 0) { - new_wim_flags[idx] |= WIM_BUFLASTUSED; - } else { - return FAIL; - } - p += i; - if (*p == NUL) { - break; - } - if (*p == ',') { - if (idx == 3) { - return FAIL; - } - idx++; - } - } - - // fill remaining entries with last flag - while (idx < 3) { - new_wim_flags[idx + 1] = new_wim_flags[idx]; - idx++; - } - - // only when there are no errors, wim_flags[] is changed - for (i = 0; i < 4; i++) { - wim_flags[i] = new_wim_flags[i]; - } - return OK; -} - /// Check if backspacing over something is allowed. /// @param what BS_INDENT, BS_EOL, BS_START, or BS_NOSTOP bool can_bs(int what) @@ -5407,99 +5196,7 @@ bool can_bs(int what) case '0': return false; } - return vim_strchr((char *)p_bs, what) != NULL; -} - -/// Save the current values of 'fileformat' and 'fileencoding', so that we know -/// the file must be considered changed when the value is different. -void save_file_ff(buf_T *buf) -{ - buf->b_start_ffc = *buf->b_p_ff; - buf->b_start_eol = buf->b_p_eol; - buf->b_start_bomb = buf->b_p_bomb; - - // Only use free/alloc when necessary, they take time. - if (buf->b_start_fenc == NULL - || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) { - xfree(buf->b_start_fenc); - buf->b_start_fenc = (char *)vim_strsave(buf->b_p_fenc); - } -} - -/// Return true if 'fileformat' and/or 'fileencoding' has a different value -/// from when editing started (save_file_ff() called). -/// Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was -/// changed and 'binary' is not set. -/// Also when 'endofline' was changed and 'fixeol' is not set. -/// When "ignore_empty" is true don't consider a new, empty buffer to be -/// changed. -bool file_ff_differs(buf_T *buf, bool ignore_empty) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - // In a buffer that was never loaded the options are not valid. - if (buf->b_flags & BF_NEVERLOADED) { - return false; - } - if (ignore_empty - && (buf->b_flags & BF_NEW) - && buf->b_ml.ml_line_count == 1 - && *ml_get_buf(buf, (linenr_T)1, false) == NUL) { - return false; - } - if (buf->b_start_ffc != *buf->b_p_ff) { - return true; - } - if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) { - return true; - } - if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) { - return true; - } - if (buf->b_start_fenc == NULL) { - return *buf->b_p_fenc != NUL; - } - return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0; -} - -/// This is called when 'breakindentopt' is changed and when a window is -/// initialized -bool briopt_check(win_T *wp) -{ - int bri_shift = 0; - int bri_min = 20; - bool bri_sbr = false; - int bri_list = 0; - - 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(&p, true, 0); - } else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) { - p += 4; - bri_min = getdigits_int(&p, true, 0); - } else if (STRNCMP(p, "sbr", 3) == 0) { - p += 3; - bri_sbr = true; - } else if (STRNCMP(p, "list:", 5) == 0) { - p += 5; - bri_list = (int)getdigits(&p, false, 0); - } - if (*p != ',' && *p != NUL) { - return false; - } - if (*p == ',') { - p++; - } - } - - wp->w_briopt_shift = bri_shift; - wp->w_briopt_min = bri_min; - wp->w_briopt_sbr = bri_sbr; - wp->w_briopt_list = bri_list; - - return true; + return vim_strchr(p_bs, what) != NULL; } /// Get the local or global value of 'backupcopy'. @@ -5524,19 +5221,19 @@ char_u *get_showbreak_value(win_T *const win) FUNC_ATTR_WARN_UNUSED_RESULT { if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { - return p_sbr; + return (char_u *)p_sbr; } - if (STRCMP(win->w_p_sbr, "NONE") == 0) { - return empty_option; + if (strcmp(win->w_p_sbr, "NONE") == 0) { + return (char_u *)empty_option; } - return win->w_p_sbr; + return (char_u *)win->w_p_sbr; } /// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. int get_fileformat(const buf_T *buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - int c = *buf->b_p_ff; + int c = (unsigned char)(*buf->b_p_ff); if (buf->b_p_bin || c == 'u') { return EOL_UNIX; @@ -5563,7 +5260,7 @@ int get_fileformat_force(const buf_T *buf, const exarg_T *eap) ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { return EOL_UNIX; } - c = *buf->b_p_ff; + c = (unsigned char)(*buf->b_p_ff); } if (c == 'u') { return EOL_UNIX; @@ -5620,7 +5317,7 @@ void set_fileformat(int eol_style, int opt_flags) } /// Skip to next part of an option argument: skip space and comma -char_u *skip_to_option_part(const char_u *p) +char *skip_to_option_part(const char *p) { if (*p == ',') { p++; @@ -5628,7 +5325,7 @@ char_u *skip_to_option_part(const char_u *p) while (*p == ' ') { p++; } - return (char_u *)p; + return (char *)p; } /// Isolate one part of a string option separated by `sep_chars`. @@ -5663,7 +5360,7 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars if (*p != NUL && *p != ',') { // skip non-standard separator p++; } - p = (char *)skip_to_option_part((char_u *)p); // p points to next file name + p = skip_to_option_part(p); // p points to next file name *option = p; return len; @@ -5672,13 +5369,13 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars /// Return true when 'shell' has "csh" in the tail. int csh_like_shell(void) { - return strstr(path_tail((char *)p_sh), "csh") != NULL; + return strstr(path_tail(p_sh), "csh") != NULL; } /// Return true when 'shell' has "fish" in the tail. bool fish_like_shell(void) { - return strstr(path_tail((char *)p_sh), "fish") != NULL; + return strstr(path_tail(p_sh), "fish") != NULL; } /// Return the number of requested sign columns, based on current @@ -5836,7 +5533,7 @@ static Dictionary vimoption2dict(vimoption_T *opt) const char *type; Object def; // TODO(bfredl): do you even nocp? - char_u *def_val = opt->def_val; + char_u *def_val = (char_u *)opt->def_val; if (opt->flags & P_STRING) { type = "string"; def = CSTR_TO_OBJ(def_val ? (char *)def_val : ""); diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index ad8092add2..25ef1fc091 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -97,7 +97,7 @@ typedef enum { // Default values for 'errorformat'. // The "%f|%l| %m" one is used for when the contents of the quickfix window is // written to a file. -#ifdef WIN32 +#ifdef MSWIN # define DFLT_EFM \ "%f(%l) \\=: %t%*\\D%n: %m,%*[^\"]\"%f\"%*\\D%l: %m,%f(%l) \\=: %m,%*[^ ] %f %l: %m,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,%f|%l| %m" #else @@ -258,7 +258,7 @@ enum { SHM_SEARCHCOUNT = 'S', ///< Search sats: '[1/10]' }; /// Represented by 'a' flag. -#define SHM_ALL_ABBREVIATIONS ((char_u[]) { \ +#define SHM_ALL_ABBREVIATIONS ((char[]) { \ SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, \ 0, \ }) @@ -379,12 +379,10 @@ enum { #define LISPWORD_VALUE \ "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object" -/* - * The following are actual variables for the options - */ +// The following are actual variables for the options EXTERN long p_aleph; // 'aleph' -EXTERN char_u *p_ambw; ///< 'ambiwidth' +EXTERN char *p_ambw; ///< 'ambiwidth' EXTERN int p_acd; ///< 'autochdir' EXTERN int p_ai; ///< 'autoindent' EXTERN int p_bin; ///< 'binary' @@ -392,29 +390,29 @@ EXTERN int p_bomb; ///< 'bomb' EXTERN int p_bl; ///< 'buflisted' EXTERN int p_cin; ///< 'cindent' EXTERN long p_channel; ///< 'channel' -EXTERN char_u *p_cink; ///< 'cinkeys' -EXTERN char_u *p_cinsd; ///< 'cinscopedecls' -EXTERN char_u *p_cinw; ///< 'cinwords' -EXTERN char_u *p_cfu; ///< 'completefunc' -EXTERN char_u *p_ofu; ///< 'omnifunc' -EXTERN char_u *p_tsrfu; ///< 'thesaurusfunc' +EXTERN char *p_cink; ///< 'cinkeys' +EXTERN char *p_cinsd; ///< 'cinscopedecls' +EXTERN char *p_cinw; ///< 'cinwords' +EXTERN char *p_cfu; ///< 'completefunc' +EXTERN char *p_ofu; ///< 'omnifunc' +EXTERN char *p_tsrfu; ///< 'thesaurusfunc' EXTERN int p_ci; ///< 'copyindent' EXTERN int p_ar; // 'autoread' EXTERN int p_aw; // 'autowrite' EXTERN int p_awa; // 'autowriteall' -EXTERN char_u *p_bs; // 'backspace' -EXTERN char_u *p_bg; // 'background' +EXTERN char *p_bs; // 'backspace' +EXTERN char *p_bg; // 'background' EXTERN int p_bk; // 'backup' -EXTERN char_u *p_bkc; // 'backupcopy' +EXTERN char *p_bkc; // 'backupcopy' EXTERN unsigned int bkc_flags; ///< flags from 'backupcopy' #define BKC_YES 0x001 #define BKC_AUTO 0x002 #define BKC_NO 0x004 #define BKC_BREAKSYMLINK 0x008 #define BKC_BREAKHARDLINK 0x010 -EXTERN char_u *p_bdir; // 'backupdir' -EXTERN char_u *p_bex; // 'backupext' -EXTERN char_u *p_bo; // 'belloff' +EXTERN char *p_bdir; // 'backupdir' +EXTERN char *p_bex; // 'backupext' +EXTERN char *p_bo; // 'belloff' EXTERN char breakat_flags[256]; // which characters are in 'breakat' EXTERN unsigned bo_flags; @@ -440,87 +438,87 @@ EXTERN unsigned bo_flags; #define BO_WILD 0x40000 EXTERN char_u *p_bsk; // 'backupskip' -EXTERN char_u *p_breakat; // 'breakat' -EXTERN char_u *p_bh; ///< 'bufhidden' -EXTERN char_u *p_bt; ///< 'buftype' -EXTERN char_u *p_cmp; // 'casemap' +EXTERN char *p_breakat; // 'breakat' +EXTERN char *p_bh; ///< 'bufhidden' +EXTERN char *p_bt; ///< 'buftype' +EXTERN char *p_cmp; // 'casemap' EXTERN unsigned cmp_flags; #define CMP_INTERNAL 0x001 #define CMP_KEEPASCII 0x002 -EXTERN char_u *p_enc; // 'encoding' -EXTERN int p_deco; // 'delcombine' -EXTERN char_u *p_ccv; // 'charconvert' -EXTERN char_u *p_cino; ///< 'cinoptions' -EXTERN char_u *p_cedit; // 'cedit' -EXTERN char_u *p_cb; // 'clipboard' +EXTERN char *p_enc; // 'encoding' +EXTERN int p_deco; // 'delcombine' +EXTERN char *p_ccv; // 'charconvert' +EXTERN char *p_cino; ///< 'cinoptions' +EXTERN char *p_cedit; // 'cedit' +EXTERN char *p_cb; // 'clipboard' EXTERN unsigned cb_flags; #define CB_UNNAMED 0x001 #define CB_UNNAMEDPLUS 0x002 #define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS) EXTERN long p_cwh; // 'cmdwinheight' EXTERN long p_ch; // 'cmdheight' -EXTERN char_u *p_cms; ///< 'commentstring' -EXTERN char_u *p_cpt; ///< 'complete' +EXTERN char *p_cms; ///< 'commentstring' +EXTERN char *p_cpt; ///< 'complete' EXTERN long p_columns; // 'columns' EXTERN int p_confirm; // 'confirm' -EXTERN char_u *p_cot; // 'completeopt' +EXTERN char *p_cot; // 'completeopt' #ifdef BACKSLASH_IN_FILENAME EXTERN char_u *p_csl; // 'completeslash' #endif EXTERN long p_pb; // 'pumblend' EXTERN long p_ph; // 'pumheight' EXTERN long p_pw; // 'pumwidth' -EXTERN char_u *p_com; ///< 'comments' +EXTERN char *p_com; ///< 'comments' EXTERN char *p_cpo; // 'cpoptions' -EXTERN char_u *p_csprg; // 'cscopeprg' +EXTERN char *p_csprg; // 'cscopeprg' EXTERN int p_csre; // 'cscoperelative' -EXTERN char_u *p_csqf; // 'cscopequickfix' +EXTERN char *p_csqf; // 'cscopequickfix' #define CSQF_CMDS "sgdctefia" #define CSQF_FLAGS "+-0" EXTERN int p_cst; // 'cscopetag' EXTERN long p_csto; // 'cscopetagorder' EXTERN long p_cspc; // 'cscopepathcomp' EXTERN int p_csverbose; // 'cscopeverbose' -EXTERN char_u *p_debug; // 'debug' -EXTERN char_u *p_def; // 'define' -EXTERN char_u *p_inc; -EXTERN char_u *p_dip; // 'diffopt' -EXTERN char_u *p_dex; // 'diffexpr' -EXTERN char_u *p_dict; // 'dictionary' +EXTERN char *p_debug; // 'debug' +EXTERN char *p_def; // 'define' +EXTERN char *p_inc; +EXTERN char *p_dip; // 'diffopt' +EXTERN char *p_dex; // 'diffexpr' +EXTERN char *p_dict; // 'dictionary' EXTERN int p_dg; // 'digraph' -EXTERN char_u *p_dir; // 'directory' -EXTERN char_u *p_dy; // 'display' +EXTERN char *p_dir; // 'directory' +EXTERN char *p_dy; // 'display' EXTERN unsigned dy_flags; #define DY_LASTLINE 0x001 #define DY_TRUNCATE 0x002 #define DY_UHEX 0x004 -// code should use msg_use_msgsep() to check if msgsep is active +// legacy flag, not used #define DY_MSGSEP 0x008 EXTERN int p_ed; // 'edcompatible' -EXTERN char_u *p_ead; // 'eadirection' +EXTERN char *p_ead; // 'eadirection' EXTERN int p_emoji; // 'emoji' EXTERN int p_ea; // 'equalalways' -EXTERN char_u *p_ep; // 'equalprg' +EXTERN char_u *p_ep; // 'equalprg' EXTERN int p_eb; // 'errorbells' -EXTERN char_u *p_ef; // 'errorfile' -EXTERN char *p_efm; // 'errorformat' -EXTERN char *p_gefm; // 'grepformat' -EXTERN char_u *p_gp; // 'grepprg' +EXTERN char_u *p_ef; // 'errorfile' +EXTERN char *p_efm; // 'errorformat' +EXTERN char *p_gefm; // 'grepformat' +EXTERN char *p_gp; // 'grepprg' EXTERN int p_eol; ///< 'endofline' -EXTERN char_u *p_ei; // 'eventignore' +EXTERN char *p_ei; // 'eventignore' EXTERN int p_et; ///< 'expandtab' EXTERN int p_exrc; // 'exrc' -EXTERN char_u *p_fenc; ///< 'fileencoding' -EXTERN char_u *p_fencs; // 'fileencodings' -EXTERN char_u *p_ff; ///< 'fileformat' -EXTERN char *p_ffs; // 'fileformats' +EXTERN char *p_fenc; ///< 'fileencoding' +EXTERN char *p_fencs; // 'fileencodings' +EXTERN char *p_ff; ///< 'fileformat' +EXTERN char *p_ffs; // 'fileformats' EXTERN int p_fic; // 'fileignorecase' -EXTERN char_u *p_ft; ///< 'filetype' -EXTERN char_u *p_fcs; ///< 'fillchar' +EXTERN char *p_ft; ///< 'filetype' +EXTERN char *p_fcs; ///< 'fillchar' EXTERN int p_fixeol; ///< 'fixendofline' -EXTERN char_u *p_fcl; // 'foldclose' +EXTERN char *p_fcl; // 'foldclose' EXTERN long p_fdls; // 'foldlevelstart' -EXTERN char_u *p_fdo; // 'foldopen' +EXTERN char *p_fdo; // 'foldopen' EXTERN unsigned fdo_flags; #define FDO_ALL 0x001 #define FDO_BLOCK 0x002 @@ -533,76 +531,76 @@ EXTERN unsigned fdo_flags; #define FDO_INSERT 0x100 #define FDO_UNDO 0x200 #define FDO_JUMP 0x400 -EXTERN char_u *p_fex; ///< 'formatexpr' -EXTERN char_u *p_flp; ///< 'formatlistpat' -EXTERN char_u *p_fo; ///< 'formatoptions' -EXTERN char_u *p_fp; // 'formatprg' +EXTERN char *p_fex; ///< 'formatexpr' +EXTERN char *p_flp; ///< 'formatlistpat' +EXTERN char *p_fo; ///< 'formatoptions' +EXTERN char_u *p_fp; // 'formatprg' EXTERN int p_fs; // 'fsync' EXTERN int p_gd; // 'gdefault' -EXTERN char_u *p_pdev; // 'printdevice' -EXTERN char_u *p_penc; // 'printencoding' -EXTERN char_u *p_pexpr; // 'printexpr' -EXTERN char_u *p_pmfn; // 'printmbfont' -EXTERN char_u *p_pmcs; // 'printmbcharset' -EXTERN char_u *p_pfn; // 'printfont' -EXTERN char_u *p_popt; // 'printoptions' -EXTERN char_u *p_header; // 'printheader' -EXTERN char_u *p_guicursor; // 'guicursor' -EXTERN char_u *p_guifont; // 'guifont' -EXTERN char_u *p_guifontwide; // 'guifontwide' -EXTERN char_u *p_hf; // 'helpfile' +EXTERN char_u *p_pdev; // 'printdevice' +EXTERN char *p_penc; // 'printencoding' +EXTERN char *p_pexpr; // 'printexpr' +EXTERN char *p_pmfn; // 'printmbfont' +EXTERN char *p_pmcs; // 'printmbcharset' +EXTERN char *p_pfn; // 'printfont' +EXTERN char *p_popt; // 'printoptions' +EXTERN char_u *p_header; // 'printheader' +EXTERN char *p_guicursor; // 'guicursor' +EXTERN char_u *p_guifont; // 'guifont' +EXTERN char_u *p_guifontwide; // 'guifontwide' +EXTERN char *p_hf; // 'helpfile' EXTERN long p_hh; // 'helpheight' -EXTERN char_u *p_hlg; // 'helplang' +EXTERN char_u *p_hlg; // 'helplang' EXTERN int p_hid; // 'hidden' -EXTERN char_u *p_hl; // 'highlight' +EXTERN char *p_hl; // 'highlight' EXTERN int p_hls; // 'hlsearch' EXTERN long p_hi; // 'history' EXTERN int p_hkmap; // 'hkmap' EXTERN int p_hkmapp; // 'hkmapp' EXTERN int p_arshape; // 'arabicshape' EXTERN int p_icon; // 'icon' -EXTERN char_u *p_iconstring; // 'iconstring' +EXTERN char *p_iconstring; // 'iconstring' EXTERN int p_ic; // 'ignorecase' EXTERN long p_iminsert; ///< 'iminsert' EXTERN long p_imsearch; ///< 'imsearch' EXTERN int p_inf; ///< 'infercase' -EXTERN char_u *p_inex; ///< 'includeexpr' +EXTERN char *p_inex; ///< 'includeexpr' EXTERN int p_is; // 'incsearch' -EXTERN char_u *p_inde; ///< 'indentexpr' -EXTERN char_u *p_indk; ///< 'indentkeys' -EXTERN char_u *p_icm; // 'inccommand' -EXTERN char_u *p_isf; // 'isfname' -EXTERN char_u *p_isi; // 'isident' -EXTERN char_u *p_isk; ///< 'iskeyword' -EXTERN char_u *p_isp; // 'isprint' +EXTERN char *p_inde; ///< 'indentexpr' +EXTERN char *p_indk; ///< 'indentkeys' +EXTERN char *p_icm; // 'inccommand' +EXTERN char *p_isf; // 'isfname' +EXTERN char *p_isi; // 'isident' +EXTERN char *p_isk; ///< 'iskeyword' +EXTERN char *p_isp; // 'isprint' EXTERN int p_js; // 'joinspaces' -EXTERN char_u *p_jop; // 'jumpooptions' +EXTERN char *p_jop; // 'jumpooptions' EXTERN unsigned jop_flags; #define JOP_STACK 0x01 #define JOP_VIEW 0x02 -EXTERN char_u *p_keymap; ///< 'keymap' -EXTERN char_u *p_kp; // 'keywordprg' -EXTERN char_u *p_km; // 'keymodel' -EXTERN char_u *p_langmap; // 'langmap' +EXTERN char *p_keymap; ///< 'keymap' +EXTERN char_u *p_kp; // 'keywordprg' +EXTERN char *p_km; // 'keymodel' +EXTERN char *p_langmap; // 'langmap' EXTERN int p_lnr; // 'langnoremap' EXTERN int p_lrm; // 'langremap' -EXTERN char_u *p_lm; // 'langmenu' -EXTERN long p_lines; // 'lines' -EXTERN long p_linespace; // 'linespace' +EXTERN char_u *p_lm; // 'langmenu' +EXTERN long p_lines; // 'lines' +EXTERN long p_linespace; // 'linespace' EXTERN int p_lisp; ///< 'lisp' -EXTERN char_u *p_lispwords; // 'lispwords' +EXTERN char_u *p_lispwords; // 'lispwords' EXTERN long p_ls; // 'laststatus' EXTERN long p_stal; // 'showtabline' -EXTERN char_u *p_lcs; // 'listchars' +EXTERN char *p_lcs; // 'listchars' EXTERN int p_lz; // 'lazyredraw' EXTERN int p_lpl; // 'loadplugins' EXTERN int p_magic; // 'magic' -EXTERN char_u *p_menc; // 'makeencoding' -EXTERN char *p_mef; // 'makeef' -EXTERN char_u *p_mp; // 'makeprg' -EXTERN char_u *p_mps; ///< 'matchpairs' -EXTERN char_u *p_cc; // 'colorcolumn' +EXTERN char *p_menc; // 'makeencoding' +EXTERN char *p_mef; // 'makeef' +EXTERN char_u *p_mp; // 'makeprg' +EXTERN char *p_mps; ///< 'matchpairs' +EXTERN char_u *p_cc; // 'colorcolumn' EXTERN int p_cc_cols[256]; // array for 'colorcolumn' columns EXTERN long p_mat; // 'matchtime' EXTERN long p_mco; // 'maxcombine' @@ -610,60 +608,61 @@ EXTERN long p_mfd; // 'maxfuncdepth' EXTERN long p_mmd; // 'maxmapdepth' EXTERN long p_mmp; // 'maxmempattern' EXTERN long p_mis; // 'menuitems' -EXTERN char_u *p_msm; // 'mkspellmem' +EXTERN char *p_msm; // 'mkspellmem' EXTERN int p_ml; ///< 'modeline' -EXTERN int p_mle; // 'modelineexpr' +EXTERN int p_mle; // 'modelineexpr' EXTERN long p_mls; // 'modelines' EXTERN int p_ma; ///< 'modifiable' EXTERN int p_mod; ///< 'modified' -EXTERN char_u *p_mouse; // 'mouse' -EXTERN char_u *p_mousem; // 'mousemodel' -EXTERN int p_mousef; // 'mousefocus' -EXTERN char_u *p_mousescroll; // 'mousescroll' +EXTERN char *p_mouse; // 'mouse' +EXTERN char *p_mousem; // 'mousemodel' +EXTERN int p_mousemev; ///< 'mousemoveevent' +EXTERN int p_mousef; // 'mousefocus' +EXTERN char *p_mousescroll; // 'mousescroll' EXTERN long p_mousescroll_vert INIT(= MOUSESCROLL_VERT_DFLT); EXTERN long p_mousescroll_hor INIT(= MOUSESCROLL_HOR_DFLT); EXTERN long p_mouset; // 'mousetime' EXTERN int p_more; // 'more' -EXTERN char_u *p_nf; ///< 'nrformats' -EXTERN char_u *p_opfunc; // 'operatorfunc' -EXTERN char_u *p_para; // 'paragraphs' +EXTERN char *p_nf; ///< 'nrformats' +EXTERN char *p_opfunc; // 'operatorfunc' +EXTERN char_u *p_para; // 'paragraphs' EXTERN int p_paste; // 'paste' -EXTERN char_u *p_pt; // 'pastetoggle' -EXTERN char_u *p_pex; // 'patchexpr' -EXTERN char_u *p_pm; // 'patchmode' -EXTERN char_u *p_path; // 'path' -EXTERN char_u *p_cdpath; // 'cdpath' +EXTERN char *p_pt; // 'pastetoggle' +EXTERN char_u *p_pex; // 'patchexpr' +EXTERN char *p_pm; // 'patchmode' +EXTERN char_u *p_path; // 'path' +EXTERN char_u *p_cdpath; // 'cdpath' EXTERN int p_pi; ///< 'preserveindent' EXTERN long p_pyx; // 'pyxversion' -EXTERN char_u *p_qe; ///< 'quoteescape' +EXTERN char *p_qe; ///< 'quoteescape' EXTERN int p_ro; ///< 'readonly' -EXTERN char_u *p_rdb; // 'redrawdebug' +EXTERN char *p_rdb; // 'redrawdebug' EXTERN unsigned rdb_flags; #define RDB_COMPOSITOR 0x001 #define RDB_NOTHROTTLE 0x002 #define RDB_INVALID 0x004 #define RDB_NODELTA 0x008 -EXTERN long p_rdt; // 'redrawtime' -EXTERN long p_re; // 'regexpengine' -EXTERN long p_report; // 'report' -EXTERN long p_pvh; // 'previewheight' -EXTERN int p_ari; // 'allowrevins' -EXTERN int p_ri; // 'revins' -EXTERN int p_ru; // 'ruler' -EXTERN char_u *p_ruf; // 'rulerformat' -EXTERN char_u *p_pp; // 'packpath' -EXTERN char_u *p_qftf; // 'quickfixtextfunc' -EXTERN char_u *p_rtp; // 'runtimepath' -EXTERN long p_scbk; // 'scrollback' -EXTERN long p_sj; // 'scrolljump' -EXTERN long p_so; // 'scrolloff' -EXTERN char *p_sbo; // 'scrollopt' -EXTERN char_u *p_sections; // 'sections' -EXTERN int p_secure; // 'secure' -EXTERN char_u *p_sel; // 'selection' -EXTERN char_u *p_slm; // 'selectmode' -EXTERN char_u *p_ssop; // 'sessionoptions' +EXTERN long p_rdt; // 'redrawtime' +EXTERN long p_re; // 'regexpengine' +EXTERN long p_report; // 'report' +EXTERN long p_pvh; // 'previewheight' +EXTERN int p_ari; // 'allowrevins' +EXTERN int p_ri; // 'revins' +EXTERN int p_ru; // 'ruler' +EXTERN char *p_ruf; // 'rulerformat' +EXTERN char *p_pp; // 'packpath' +EXTERN char *p_qftf; // 'quickfixtextfunc' +EXTERN char *p_rtp; // 'runtimepath' +EXTERN long p_scbk; // 'scrollback' +EXTERN long p_sj; // 'scrolljump' +EXTERN long p_so; // 'scrolloff' +EXTERN char *p_sbo; // 'scrollopt' +EXTERN char *p_sections; // 'sections' +EXTERN int p_secure; // 'secure' +EXTERN char *p_sel; // 'selection' +EXTERN char *p_slm; // 'selectmode' +EXTERN char *p_ssop; // 'sessionoptions' EXTERN unsigned ssop_flags; #define SSOP_BUFFERS 0x001 @@ -685,23 +684,23 @@ EXTERN unsigned ssop_flags; #define SSOP_TERMINAL 0x10000 #define SSOP_SKIP_RTP 0x20000 -EXTERN char_u *p_sh; // 'shell' -EXTERN char_u *p_shcf; // 'shellcmdflag' -EXTERN char_u *p_sp; // 'shellpipe' -EXTERN char_u *p_shq; // 'shellquote' -EXTERN char_u *p_sxq; // 'shellxquote' -EXTERN char_u *p_sxe; // 'shellxescape' -EXTERN char_u *p_srr; // 'shellredir' +EXTERN char *p_sh; // 'shell' +EXTERN char_u *p_shcf; // 'shellcmdflag' +EXTERN char *p_sp; // 'shellpipe' +EXTERN char_u *p_shq; // 'shellquote' +EXTERN char *p_sxq; // 'shellxquote' +EXTERN char_u *p_sxe; // 'shellxescape' +EXTERN char *p_srr; // 'shellredir' EXTERN int p_stmp; // 'shelltemp' #ifdef BACKSLASH_IN_FILENAME EXTERN int p_ssl; // 'shellslash' #endif -EXTERN char_u *p_stl; // 'statusline' -EXTERN char *p_wbr; // 'winbar' +EXTERN char *p_stl; // 'statusline' +EXTERN char *p_wbr; // 'winbar' EXTERN int p_sr; // 'shiftround' EXTERN long p_sw; ///< 'shiftwidth' -EXTERN char_u *p_shm; // 'shortmess' -EXTERN char_u *p_sbr; // 'showbreak' +EXTERN char *p_shm; // 'shortmess' +EXTERN char *p_sbr; // 'showbreak' EXTERN int p_sc; // 'showcmd' EXTERN int p_sft; // 'showfulltag' EXTERN int p_sm; // 'showmatch' @@ -713,12 +712,12 @@ EXTERN int p_si; ///< 'smartindent' EXTERN int p_sta; // 'smarttab' EXTERN long p_sts; ///< 'softtabstop' EXTERN int p_sb; // 'splitbelow' -EXTERN char_u *p_sua; ///< 'suffixesadd' +EXTERN char *p_sua; ///< 'suffixesadd' EXTERN int p_swf; ///< 'swapfile' EXTERN long p_smc; ///< 'synmaxcol' EXTERN long p_tpm; // 'tabpagemax' -EXTERN char_u *p_tal; // 'tabline' -EXTERN char_u *p_tpf; // 'termpastefilter' +EXTERN char *p_tal; // 'tabline' +EXTERN char *p_tpf; // 'termpastefilter' EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter' #define TPF_BS 0x001 #define TPF_HT 0x002 @@ -727,16 +726,18 @@ EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter' #define TPF_DEL 0x010 #define TPF_C0 0x020 #define TPF_C1 0x040 -EXTERN char_u *p_tfu; ///< 'tagfunc' -EXTERN char_u *p_spc; ///< 'spellcapcheck' -EXTERN char_u *p_spf; ///< 'spellfile' -EXTERN char_u *p_spl; ///< 'spelllang' -EXTERN char_u *p_spo; // 'spelloptions' -EXTERN char_u *p_sps; // 'spellsuggest' +EXTERN char *p_tfu; ///< 'tagfunc' +EXTERN char *p_spc; ///< 'spellcapcheck' +EXTERN char *p_spf; ///< 'spellfile' +EXTERN char *p_spk; ///< 'splitkeep' +EXTERN char *p_spl; ///< 'spelllang' +EXTERN char *p_spo; // 'spelloptions' +EXTERN unsigned int spo_flags; +EXTERN char *p_sps; // 'spellsuggest' EXTERN int p_spr; // 'splitright' EXTERN int p_sol; // 'startofline' -EXTERN char_u *p_su; // 'suffixes' -EXTERN char_u *p_swb; // 'switchbuf' +EXTERN char_u *p_su; // 'suffixes' +EXTERN char *p_swb; // 'switchbuf' EXTERN unsigned swb_flags; // Keep in sync with p_swb_values in optionstr.c #define SWB_USEOPEN 0x001 @@ -745,10 +746,10 @@ EXTERN unsigned swb_flags; #define SWB_NEWTAB 0x008 #define SWB_VSPLIT 0x010 #define SWB_USELAST 0x020 -EXTERN char_u *p_syn; ///< 'syntax' +EXTERN char *p_syn; ///< 'syntax' EXTERN long p_ts; ///< 'tabstop' EXTERN int p_tbs; ///< 'tagbsearch' -EXTERN char_u *p_tc; ///< 'tagcase' +EXTERN char *p_tc; ///< 'tagcase' EXTERN unsigned tc_flags; ///< flags from 'tagcase' #define TC_FOLLOWIC 0x01 #define TC_IGNORE 0x02 @@ -767,7 +768,7 @@ EXTERN long p_tm; ///< 'timeoutlen' EXTERN int p_title; ///< 'title' EXTERN long p_titlelen; ///< 'titlelen' EXTERN char_u *p_titleold; ///< 'titleold' -EXTERN char_u *p_titlestring; ///< 'titlestring' +EXTERN char *p_titlestring; ///< 'titlestring' EXTERN char_u *p_tsr; ///< 'thesaurus' EXTERN int p_tgc; ///< 'termguicolors' EXTERN int p_ttimeout; ///< 'ttimeout' @@ -778,15 +779,15 @@ EXTERN long p_ul; ///< 'undolevels' EXTERN long p_ur; ///< 'undoreload' EXTERN long p_uc; ///< 'updatecount' EXTERN long p_ut; ///< 'updatetime' -EXTERN char_u *p_shada; ///< 'shada' +EXTERN char *p_shada; ///< 'shada' EXTERN char *p_shadafile; ///< 'shadafile' -EXTERN char_u *p_vsts; ///< 'varsofttabstop' -EXTERN char_u *p_vts; ///< 'vartabstop' +EXTERN char *p_vsts; ///< 'varsofttabstop' +EXTERN char *p_vts; ///< 'vartabstop' EXTERN char_u *p_vdir; ///< 'viewdir' -EXTERN char_u *p_vop; ///< 'viewoptions' +EXTERN char *p_vop; ///< 'viewoptions' EXTERN unsigned vop_flags; ///< uses SSOP_ flags EXTERN int p_vb; ///< 'visualbell' -EXTERN char_u *p_ve; ///< 'virtualedit' +EXTERN char *p_ve; ///< 'virtualedit' EXTERN unsigned ve_flags; #define VE_BLOCK 5U // includes "all" #define VE_INSERT 6U // includes "all" @@ -798,21 +799,21 @@ EXTERN long p_verbose; // 'verbose' #ifdef IN_OPTION_C char_u *p_vfile = (char_u *)""; // used before options are initialized #else -extern char_u *p_vfile; // 'verbosefile' +extern char *p_vfile; // 'verbosefile' #endif EXTERN int p_warn; // 'warn' -EXTERN char_u *p_wop; // 'wildoptions' +EXTERN char *p_wop; // 'wildoptions' EXTERN unsigned wop_flags; #define WOP_TAGFILE 0x01 #define WOP_PUM 0x02 EXTERN long p_window; // 'window' -EXTERN char_u *p_wak; // 'winaltkeys' -EXTERN char_u *p_wig; // 'wildignore' -EXTERN char_u *p_ww; // 'whichwrap' +EXTERN char *p_wak; // 'winaltkeys' +EXTERN char *p_wig; // 'wildignore' +EXTERN char *p_ww; // 'whichwrap' EXTERN long p_wc; // 'wildchar' EXTERN long p_wcm; // 'wildcharm' EXTERN int p_wic; // 'wildignorecase' -EXTERN char_u *p_wim; // 'wildmode' +EXTERN char *p_wim; // 'wildmode' EXTERN int p_wmnu; // 'wildmenu' EXTERN long p_wh; // 'winheight' EXTERN long p_wmh; // 'winminheight' @@ -924,11 +925,9 @@ enum { BV_COUNT, // must be the last one }; -/* - * "indir" values for window-local options. - * These need to be defined globally, so that the WV_COUNT can be used in the - * window structure. - */ +// "indir" values for window-local options. +// These need to be defined globally, so that the WV_COUNT can be used in the +// window structure. enum { WV_LIST = 0, WV_ARAB, @@ -972,8 +971,8 @@ enum { WV_WRAP, WV_SCL, WV_WINHL, - WV_FCS, WV_LCS, + WV_FCS, WV_WINBL, WV_WBR, WV_COUNT, // must be the last one @@ -992,4 +991,41 @@ typedef struct { uint64_t channel_id; /// Only used when script_id is SID_API_CLIENT. } LastSet; -#endif // NVIM_OPTION_DEFS_H +// WV_ and BV_ values get typecasted to this for the "indir" field +typedef enum { + PV_NONE = 0, + PV_MAXVAL = 0xffff, // to avoid warnings for value out of range +} idopt_T; + +typedef struct vimoption { + char *fullname; // full option name + char *shortname; // permissible abbreviation + uint32_t flags; // see below + char_u *var; // global option: pointer to variable; + // window-local option: VAR_WIN; + // buffer-local option: global value + idopt_T indir; // global option: PV_NONE; + // local option: indirect option index + char *def_val; // default values for variable (neovim!!) + LastSet last_set; // script in which the option was last set +} vimoption_T; + +// The options that are local to a window or buffer have "indir" set to one of +// these values. Special values: +// PV_NONE: global option. +// PV_WIN is added: window-local option +// PV_BUF is added: buffer-local option +// PV_BOTH is added: global option which also has a local value. +#define PV_BOTH 0x1000 +#define PV_WIN 0x2000 +#define PV_BUF 0x4000 +#define PV_MASK 0x0fff +#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x)) +#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) +#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) + +// Options local to a window have a value local to a buffer and global to all +// buffers. Indicate this by setting "var" to VAR_WIN. +#define VAR_WIN ((char_u *)-1) + +#endif // NVIM_OPTION_DEFS_H diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 2f941f5d0c..149d0bace4 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -20,7 +20,7 @@ -- lists: (nil), comma, onecomma, flags, flagscomma -- scopes: global, buffer, window -- redraw options: statuslines, current_window, curent_window_only, --- current_buffer, all_windows, everything, curswant +-- current_buffer, all_windows, curswant -- defaults: {condition=#if condition, if_true=default, if_false=default} -- #if condition: -- string: #ifdef string @@ -128,7 +128,6 @@ return { full_name='background', abbreviation='bg', short_desc=N_("\"dark\" or \"light\", used for highlight colors"), type='string', scope={'global'}, - redraw={'all_windows'}, varname='p_bg', defaults={if_true="dark"} }, @@ -395,7 +394,6 @@ return { short_desc=N_("number of columns in the display"), type='number', scope={'global'}, no_mkrc=true, - redraw={'everything'}, varname='p_columns', defaults={if_true=macros('DFLT_COLS')} }, @@ -422,7 +420,6 @@ return { full_name='compatible', abbreviation='cp', short_desc=N_("No description"), type='bool', scope={'global'}, - redraw={'all_windows'}, varname='p_force_off', -- pri_mkrc isn't needed here, optval_default() -- always returns TRUE for 'compatible' @@ -663,7 +660,7 @@ return { deny_duplicates=true, redraw={'all_windows'}, varname='p_dy', - defaults={if_true="lastline,msgsep"} + defaults={if_true="lastline"} }, { full_name='eadirection', abbreviation='ead', @@ -708,7 +705,6 @@ return { full_name='equalalways', abbreviation='ea', short_desc=N_("windows are automatically made the same size"), type='bool', scope={'global'}, - redraw={'all_windows'}, varname='p_ea', defaults={if_true=true} }, @@ -1014,7 +1010,7 @@ return { expand=true, varname='p_gp', defaults={ - condition='WIN32', + condition='MSWIN', -- Add an extra file name so that grep will always -- insert a file name in the match line. */ if_true="findstr /n $* nul", @@ -1051,7 +1047,6 @@ return { full_name='guioptions', abbreviation='go', short_desc=N_("GUI: Which components and options are used"), type='string', list='flags', scope={'global'}, - redraw={'all_windows'}, enable_if=false, }, { @@ -1195,7 +1190,6 @@ return { full_name='inccommand', abbreviation='icm', short_desc=N_("Live preview of substitution"), type='string', scope={'global'}, - redraw={'all_windows'}, varname='p_icm', defaults={if_true="nosplit"} }, @@ -1276,7 +1270,7 @@ return { deny_duplicates=true, varname='p_isi', defaults={ - condition='WIN32', + condition='MSWIN', if_true="@,48-57,_,128-167,224-235", if_false="@,48-57,_,192-255" } @@ -1403,7 +1397,6 @@ return { short_desc=N_("of lines in the display"), type='number', scope={'global'}, no_mkrc=true, - redraw={'everything'}, varname='p_lines', defaults={if_true=macros('DFLT_ROWS')} }, @@ -1622,6 +1615,14 @@ return { defaults={if_true="popup_setpos"} }, { + full_name='mousemoveevent', abbreviation='mousemev', + short_desc=N_("deliver mouse move events to input queue"), + type='bool', scope={'global'}, + redraw={'ui_option'}, + varname='p_mousemev', + defaults={if_true=false} + }, + { full_name='mousescroll', short_desc=N_("amount to scroll by when scrolling with a mouse"), type='string', list='comma', scope={'global'}, @@ -2015,7 +2016,6 @@ return { full_name='scrolloff', abbreviation='so', short_desc=N_("minimum nr. of lines above and below cursor"), type='number', scope={'global', 'window'}, - redraw={'all_windows'}, varname='p_so', defaults={if_true=0} }, @@ -2092,7 +2092,7 @@ return { expand=true, varname='p_sh', defaults={ - condition='WIN32', + condition='MSWIN', if_true="cmd.exe", if_false="sh" } @@ -2104,7 +2104,7 @@ return { secure=true, varname='p_shcf', defaults={ - condition='WIN32', + condition='MSWIN', if_true="/s /c", if_false="-c" } @@ -2116,7 +2116,7 @@ return { secure=true, varname='p_sp', defaults={ - condition='WIN32', + condition='MSWIN', if_true=">%s 2>&1", if_false="| tee", } @@ -2136,7 +2136,7 @@ return { secure=true, varname='p_srr', defaults={ - condition='WIN32', + condition='MSWIN', if_true=">%s 2>&1", if_false=">" } @@ -2163,7 +2163,7 @@ return { secure=true, varname='p_sxq', defaults={ - condition='WIN32', + condition='MSWIN', if_true="\"", if_false="", } @@ -2252,7 +2252,6 @@ return { full_name='sidescrolloff', abbreviation='siso', short_desc=N_("min. nr. of columns to left and right of cursor"), type='number', scope={'global', 'window'}, - redraw={'all_windows'}, varname='p_siso', defaults={if_true=0} }, @@ -2347,6 +2346,7 @@ return { secure=true, expand=true, varname='p_spo', + redraw={'current_buffer'}, defaults={if_true=""} }, { @@ -2357,6 +2357,13 @@ return { defaults={if_true=false} }, { + full_name='splitkeep', abbreviation='spk', + short_desc=N_("determines scroll behavior for split windows"), + type='string', scope={'global'}, + varname='p_spk', + defaults={if_true='cursor'} + }, + { full_name='splitright', abbreviation='spr', short_desc=N_("new window is put right of the current one"), type='bool', scope={'global'}, @@ -2444,7 +2451,7 @@ return { short_desc=N_("custom format for the console tab pages line"), type='string', scope={'global'}, modelineexpr=true, - redraw={'all_windows'}, + redraw={'statuslines'}, varname='p_tal', defaults={if_true=""} }, @@ -2859,7 +2866,8 @@ return { { full_name='winhighlight', abbreviation='winhl', short_desc=N_("Setup window-local highlights"); - type='string', scope={'window'}, + type='string', list='onecomma', scope={'window'}, + deny_duplicates=true, alloced=true, redraw={'current_window'}, defaults={if_true=""} diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index c50225dfdf..1da6fa15d7 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -18,6 +18,7 @@ #include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/vars.h" +#include "nvim/ex_getln.h" #include "nvim/hardcopy.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" @@ -45,8 +46,14 @@ # include "optionstr.c.generated.h" #endif -static char e_unclosed_expression_sequence[] = N_("E540: Unclosed expression sequence"); -static char e_unbalanced_groups[] = N_("E542: unbalanced groups"); +static char e_unclosed_expression_sequence[] + = N_("E540: Unclosed expression sequence"); +static char e_unbalanced_groups[] + = N_("E542: unbalanced groups"); +static char e_backupext_and_patchmode_are_equal[] + = N_("E589: 'backupext' and 'patchmode' are equal"); +static char e_showbreak_contains_unprintable_or_wide_character[] + = N_("E595: 'showbreak' contains unprintable or wide character"); static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL }; @@ -68,6 +75,7 @@ static char *(p_ssop_values[]) = { "buffers", "winpos", "resize", "winsize", "lo // Keep in sync with SWB_ flags in option_defs.h static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL }; +static char *(p_spk_values[]) = { "cursor", "screen", "topline", NULL }; static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL }; static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL }; static char *(p_wop_values[]) = { "tagfile", "pum", NULL }; @@ -100,16 +108,17 @@ static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2", "auto:3", "auto:4" "auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL }; +static char *(p_spo_values[]) = { "camel", "noplainbuffer", NULL }; static char *(p_icm_values[]) = { "nosplit", "split", NULL }; static char *(p_jop_values[]) = { "stack", "view", NULL }; static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL }; static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", NULL }; /// All possible flags for 'shm'. -static char_u SHM_ALL[] = { SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, - SHM_WRI, SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, - SHM_OVER, SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, - SHM_COMPLETIONMENU, SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT, 0, }; +static char SHM_ALL[] = { SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, + SHM_WRI, SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, + SHM_OVER, SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, + SHM_COMPLETIONMENU, SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT, 0, }; /// After setting various option values: recompute variables that depend on /// option values. @@ -170,7 +179,7 @@ void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *o set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); } - apply_autocmds(EVENT_OPTIONSET, get_option_fullname(opt_idx), NULL, false, NULL); + apply_autocmds(EVENT_OPTIONSET, get_option(opt_idx)->fullname, NULL, false, NULL); reset_v_option_vars(); } } @@ -245,17 +254,17 @@ void check_buf_options(buf_T *buf) /// Free the string allocated for an option. /// Checks for the string being empty_option. This may happen if we're out of -/// memory, vim_strsave() returned NULL, which was replaced by empty_option by +/// memory, xstrdup() returned NULL, which was replaced by empty_option by /// check_options(). /// Does NOT check for P_ALLOCED flag! -void free_string_option(char_u *p) +void free_string_option(char *p) { if (p != empty_option) { xfree(p); } } -void clear_string_option(char_u **pp) +void clear_string_option(char **pp) { if (*pp != empty_option) { xfree(*pp); @@ -263,7 +272,7 @@ void clear_string_option(char_u **pp) *pp = empty_option; } -void check_string_option(char_u **pp) +void check_string_option(char **pp) { if (*pp == NULL) { *pp = empty_option; @@ -272,20 +281,20 @@ void check_string_option(char_u **pp) /// Set global value for string option when it's a local option. /// -/// @param opt_idx option index +/// @param opt option /// @param varp pointer to option variable -static void set_string_option_global(int opt_idx, char_u **varp) +static void set_string_option_global(vimoption_T *opt, char **varp) { - char_u **p, *s; + char **p; // the global value is always allocated - if (is_window_local_option(opt_idx)) { - p = (char_u **)GLOBAL_WO(varp); + if (opt->var == VAR_WIN) { + p = (char **)GLOBAL_WO(varp); } else { - p = (char_u **)get_option_var(opt_idx); + p = (char **)opt->var; } - if (!is_global_option(opt_idx) && p != varp) { - s = vim_strsave(*varp); + if (opt->indir != PV_NONE && p != varp) { + char *s = xstrdup(*varp); free_string_option(*p); *p = s; } @@ -316,32 +325,34 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in } } - if (is_hidden_option(idx)) { // can't set hidden option + vimoption_T *opt = get_option(idx); + + if (opt->var == NULL) { // can't set hidden option return; } - assert((void *)get_option_var(idx) != (void *)&p_shada); + assert((void *)opt->var != (void *)&p_shada); s = xstrdup(val); { - varp = (char **)get_option_varp_scope(idx, both ? OPT_LOCAL : opt_flags); - if ((opt_flags & OPT_FREE) && (get_option_flags(idx) & P_ALLOCED)) { - free_string_option((char_u *)(*varp)); + varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); + if ((opt_flags & OPT_FREE) && (opt->flags & P_ALLOCED)) { + free_string_option(*varp); } *varp = s; // For buffer/window local option may also set the global value. if (both) { - set_string_option_global(idx, (char_u **)varp); + set_string_option_global(opt, varp); } - set_option_flag(idx, P_ALLOCED); + opt->flags |= P_ALLOCED; // When setting both values of a global option with a local value, // make the local value empty, so that the global value is used. - if (is_global_local_option(idx) && both) { - free_string_option((char_u *)(*varp)); - *varp = (char *)empty_option; + if ((opt->indir & PV_BOTH) && both) { + free_string_option(*varp); + *varp = empty_option; } if (set_sid != SID_NONE) { sctx_T script_ctx; @@ -381,28 +392,28 @@ void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, c /// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or /// #OPT_GLOBAL. /// -/// @return NULL on success, error message on error. +/// @return NULL on success, an untranslated error message on error. char *set_string_option(const int opt_idx, const char *const value, const int opt_flags) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT { - if (is_hidden_option(opt_idx)) { // don't set hidden option + vimoption_T *opt = get_option(opt_idx); + + if (opt->var == NULL) { // don't set hidden option return NULL; } char *const s = xstrdup(value); char **const varp - = (char **)get_option_varp_scope(opt_idx, - (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 - ? (is_global_local_option(opt_idx) - ? OPT_GLOBAL : OPT_LOCAL) - : opt_flags); + = (char **)get_varp_scope(opt, ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 + ? ((opt->indir & PV_BOTH) ? OPT_GLOBAL : OPT_LOCAL) + : opt_flags)); char *const oldval = *varp; char *oldval_l = NULL; char *oldval_g = NULL; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - oldval_l = *(char **)get_option_varp_scope(opt_idx, OPT_LOCAL); - oldval_g = *(char **)get_option_varp_scope(opt_idx, OPT_GLOBAL); + oldval_l = *(char **)get_varp_scope(opt, OPT_LOCAL); + oldval_g = *(char **)get_varp_scope(opt, OPT_GLOBAL); } *varp = s; @@ -413,21 +424,21 @@ char *set_string_option(const int opt_idx, const char *const value, const int op char *const saved_newval = xstrdup(s); int value_checked = false; - char *const r = did_set_string_option(opt_idx, (char_u **)varp, (char_u *)oldval, - NULL, 0, - opt_flags, &value_checked); - if (r == NULL) { + char *const errmsg = did_set_string_option(opt_idx, varp, oldval, + NULL, 0, + opt_flags, &value_checked); + if (errmsg == NULL) { did_set_option(opt_idx, opt_flags, true, value_checked); } // call autocommand after handling side effects - if (r == NULL) { + if (errmsg == NULL) { if (!starting) { trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g, saved_newval); } - if (get_option_flags(opt_idx) & P_UI_OPTION) { - ui_call_option_set(cstr_as_string(get_option_fullname(opt_idx)), + if (opt->flags & P_UI_OPTION) { + ui_call_option_set(cstr_as_string(opt->fullname), STRING_OBJ(cstr_as_string(saved_newval))); } } @@ -436,12 +447,12 @@ char *set_string_option(const int opt_idx, const char *const value, const int op xfree(saved_oldval_g); xfree(saved_newval); - return r; + return errmsg; } /// Return true if "val" is a valid 'filetype' name. /// Also used for 'syntax' and 'keymap'. -static bool valid_filetype(const char_u *val) +static bool valid_filetype(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return valid_name(val, ".-_"); @@ -456,7 +467,7 @@ static char *check_mousescroll(char *string) for (;;) { char *end = vim_strchr(string, ','); - size_t length = end ? (size_t)(end - string) : STRLEN(string); + size_t length = end ? (size_t)(end - string) : strlen(string); // Both "ver:" and "hor:" are 4 bytes long. // They should be followed by at least one digit. @@ -513,7 +524,7 @@ static char *check_mousescroll(char *string) /// Handle setting 'signcolumn' for value 'val' /// /// @return OK when the value is valid, FAIL otherwise -static int check_signcolumn(char_u *val) +static int check_signcolumn(char *val) { if (*val == NUL) { return FAIL; @@ -524,7 +535,7 @@ static int check_signcolumn(char_u *val) } // check for 'auto:<NUMBER>-<NUMBER>' - if (STRLEN(val) == 8 + if (strlen(val) == 8 && !STRNCMP(val, "auto:", 5) && ascii_isdigit(val[5]) && val[6] == '-' @@ -624,39 +635,38 @@ static int shada_idx = -1; /// @param value_checked value was checked to be safe, no need to set P_INSECURE /// /// @return NULL for success, or an untranslated error message for an error -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 *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, size_t errbuflen, + int opt_flags, int *value_checked) { char *errmsg = NULL; char *s, *p; int did_chartab = false; - char_u **gvarp; - bool free_oldval = (get_option_flags(opt_idx) & P_ALLOCED); + vimoption_T *opt = get_option(opt_idx); + bool free_oldval = (opt->flags & P_ALLOCED); bool value_changed = false; // Get the global option to compare with, otherwise we would have to check // two values for all local options. - gvarp = (char_u **)get_option_varp_scope(opt_idx, OPT_GLOBAL); + char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL); // Disallow changing some options from secure mode if ((secure || sandbox != 0) - && (get_option_flags(opt_idx) & P_SECURE)) { + && (opt->flags & P_SECURE)) { errmsg = e_secure; - } else if (((get_option_flags(opt_idx) & P_NFNAME) - && strpbrk((char *)(*varp), - (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) - || ((get_option_flags(opt_idx) & P_NDNAME) - && strpbrk((char *)(*varp), "*?[|;&<>\r\n") != NULL)) { + } else if (((opt->flags & P_NFNAME) + && strpbrk(*varp, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) + || ((opt->flags & P_NDNAME) + && strpbrk(*varp, "*?[|;&<>\r\n") != NULL)) { // Check for a "normal" directory or file name in some options. Disallow a // path separator (slash and/or backslash), wildcards and characters that // are often illegal in a file name. Be more permissive if "secure" is off. errmsg = e_invarg; } else if (gvarp == &p_bkc) { // 'backupcopy' - char_u *bkc = p_bkc; + char *bkc = p_bkc; unsigned int *flags = &bkc_flags; if (opt_flags & OPT_LOCAL) { - bkc = curbuf->b_p_bkc; + bkc = curbuf->b_p_bkc; flags = &curbuf->b_bkc_flags; } @@ -677,9 +687,9 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode' - if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex, + if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { - errmsg = N_("E589: 'backupext' and 'patchmode' are equal"); + errmsg = e_backupext_and_patchmode_are_equal; } } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt' if (briopt_check(curwin) == FAIL) { @@ -713,7 +723,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } else if (varp == &curwin->w_p_cc) { // 'colorcolumn' errmsg = check_colorcolumn(curwin); - } else if (varp == &p_hlg) { // 'helplang' + } else if (varp == (char **)&p_hlg) { // 'helplang' // Check for "", "ab", "ab,cd", etc. for (s = (char *)p_hlg; *s != NUL; s += 3) { if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { @@ -725,7 +735,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } } else if (varp == &p_hl) { // 'highlight' - if (STRCMP(*varp, HIGHLIGHT_INIT) != 0) { + if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { errmsg = e_unsupportedoption; } } else if (varp == &p_jop) { // 'jumpoptions' @@ -753,8 +763,8 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { errmsg = e_invarg; } - } else if (varp == (char_u **)&p_sbo) { // 'scrollopt' - if (check_opt_strings((char_u *)p_sbo, p_scbopt_values, true) != OK) { + } else if (varp == &p_sbo) { // 'scrollopt' + if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { errmsg = e_invarg; } } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth' @@ -775,7 +785,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // scheme and set the colors again. do_unlet(S_LEN("g:colors_name"), true); free_string_option(p_bg); - p_bg = vim_strsave((char_u *)(dark ? "dark" : "light")); + p_bg = xstrdup((dark ? "dark" : "light")); check_string_option(&p_bg); init_highlight(false, false); } @@ -804,7 +814,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (gvarp == &p_fenc) { if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) { errmsg = e_modifiable; - } else if (vim_strchr((char *)(*varp), ',') != NULL) { + } else if (vim_strchr(*varp, ',') != NULL) { // No comma allowed in 'fileencoding'; catches confusing it // with 'fileencodings'. errmsg = e_invarg; @@ -817,13 +827,13 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } if (errmsg == NULL) { - // canonize the value, so that STRCMP() can be used on it - p = (char *)enc_canonize(*varp); + // canonize the value, so that strcmp() can be used on it + p = enc_canonize(*varp); xfree(*varp); - *varp = (char_u *)p; + *varp = p; if (varp == &p_enc) { // only encoding=utf-8 allowed - if (STRCMP(p_enc, "utf-8") != 0) { + if (strcmp(p_enc, "utf-8") != 0) { errmsg = e_unsupportedoption; } else { spell_reload(); @@ -832,9 +842,9 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } else if (varp == &p_penc) { // Canonize printencoding if VIM standard one - p = (char *)enc_canonize(p_penc); + p = enc_canonize(p_penc); xfree(p_penc); - p_penc = (char_u *)p; + p_penc = p; } else if (varp == &curbuf->b_p_keymap) { if (!valid_filetype(*varp)) { errmsg = e_invarg; @@ -889,15 +899,15 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // Redraw needed when switching to/from "mac": a CR in the text // will be displayed differently. if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') { - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); } } - } else if (varp == (char_u **)&p_ffs) { // 'fileformats' - if (check_opt_strings((char_u *)p_ffs, p_ff_values, true) != OK) { + } else if (varp == &p_ffs) { // 'fileformats' + if (check_opt_strings(p_ffs, p_ff_values, true) != OK) { errmsg = e_invarg; } } else if (gvarp == &p_mps) { // 'matchpairs' - for (p = (char *)(*varp); *p != NUL; p++) { + for (p = *varp; *p != NUL; p++) { int x2 = -1; int x3 = -1; @@ -918,7 +928,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } } else if (gvarp == &p_com) { // 'comments' - for (s = (char *)(*varp); *s;) { + for (s = *varp; *s;) { while (*s && *s != ':') { if (vim_strchr(COM_ALL, *s) == NULL && !ascii_isdigit(*s) && *s != '-') { @@ -941,40 +951,33 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } s++; } - s = (char *)skip_to_option_part((char_u *)s); + s = skip_to_option_part(s); } - } else if (varp == &p_lcs) { // global 'listchars' - errmsg = set_chars_option(curwin, varp, false); + } else if (varp == &p_lcs || varp == &p_fcs) { // global 'listchars' or 'fillchars' + char **local_ptr = varp == &p_lcs ? &curwin->w_p_lcs : &curwin->w_p_fcs; + // only apply the global value to "curwin" when it does not have a local value + errmsg = + set_chars_option(curwin, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); if (errmsg == NULL) { - // The current window is set to use the global 'listchars' value. - // So clear the window-local value. + // If the current window is set to use the global + // 'listchars'/'fillchars' value, clear the window-local value. if (!(opt_flags & OPT_GLOBAL)) { - clear_string_option(&curwin->w_p_lcs); + clear_string_option(local_ptr); } FOR_ALL_TAB_WINDOWS(tp, wp) { + // If the current window has a local value need to apply it + // again, it was changed when setting the global value. // If no error was returned above, we don't expect an error // here, so ignore the return value. - (void)set_chars_option(wp, &wp->w_p_lcs, true); + local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs; + if (**local_ptr == NUL) { + (void)set_chars_option(wp, local_ptr, true); + } } - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } } else if (varp == &curwin->w_p_lcs) { // local 'listchars' errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &p_fcs) { // global 'fillchars' - errmsg = set_chars_option(curwin, varp, false); - if (errmsg == NULL) { - // The current window is set to use the global 'fillchars' value. - // So clear the window-local value. - if (!(opt_flags & OPT_GLOBAL)) { - clear_string_option(&curwin->w_p_fcs); - } - FOR_ALL_TAB_WINDOWS(tp, wp) { - // If no error was returned above, we don't expect an error - // here, so ignore the return value. - (void)set_chars_option(wp, &wp->w_p_fcs, true); - } - redraw_all_later(NOT_VALID); - } } else if (varp == &curwin->w_p_fcs) { // local 'fillchars' errmsg = set_chars_option(curwin, varp, true); } else if (varp == &p_cedit) { // 'cedit' @@ -987,14 +990,15 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } else if (varp == &p_shada) { // 'shada' // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo // option. - opt_idx = ((get_option_fullname(opt_idx)[0] == 'v') + opt_idx = ((opt->fullname[0] == 'v') ? (shada_idx == -1 ? ((shada_idx = findoption("shada"))) : shada_idx) : opt_idx); + opt = get_option(opt_idx); // Update free_oldval now that we have the opt_idx for 'shada', otherwise // there would be a disconnect between the check for P_ALLOCED at the start // of the function and the set of P_ALLOCED at the end of the function. - free_oldval = (get_option_flags(opt_idx) & P_ALLOCED); - for (s = (char *)p_shada; *s;) { + free_oldval = (opt->flags & P_ALLOCED); + for (s = p_shada; *s;) { // Check it's a valid character if (vim_strchr("!\"%'/:<@cfhnrs", *s) == NULL) { errmsg = illegal_char(errbuf, errbuflen, *s); @@ -1039,9 +1043,9 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er errmsg = N_("E528: Must specify a ' value"); } } else if (gvarp == &p_sbr) { // 'showbreak' - for (s = (char *)(*varp); *s;) { + for (s = *varp; *s;) { if (ptr2cells(s) != 1) { - errmsg = N_("E595: 'showbreak' contains unprintable or wide character"); + errmsg = e_showbreak_contains_unprintable_or_wide_character; } MB_PTR_ADV(s); } @@ -1060,7 +1064,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; // NULL => statusline syntax - if (vim_strchr((char *)(*varp), '%') && check_stl_option((char *)(*varp)) == NULL) { + if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { stl_syntax |= flagval; } else { stl_syntax &= ~flagval; @@ -1079,19 +1083,23 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (check_opt_strings(p_km, p_km_values, true) != OK) { errmsg = e_invarg; } else { - km_stopsel = (vim_strchr((char *)p_km, 'o') != NULL); - km_startsel = (vim_strchr((char *)p_km, 'a') != NULL); + km_stopsel = (vim_strchr(p_km, 'o') != NULL); + km_startsel = (vim_strchr(p_km, 'a') != NULL); } } else if (varp == &p_mousem) { // 'mousemodel' if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) { errmsg = e_invarg; } } else if (varp == &p_mousescroll) { // 'mousescroll' - errmsg = check_mousescroll((char *)p_mousescroll); + errmsg = check_mousescroll(p_mousescroll); } else if (varp == &p_swb) { // 'switchbuf' if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) { errmsg = e_invarg; } + } else if (varp == &p_spk) { // 'splitkeep' + if (check_opt_strings(p_spk, p_spk_values, false) != OK) { + errmsg = e_invarg; + } } else if (varp == &p_debug) { // 'debug' if (check_opt_strings(p_debug, p_debug_values, true) != OK) { errmsg = e_invarg; @@ -1127,7 +1135,8 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // When 'spellcapcheck' is set compile the regexp program. errmsg = compile_cap_prog(curwin->w_s); } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions' - if (**varp != NUL && STRCMP("camel", *varp) != 0) { + if (opt_strings_flags(curwin->w_s->b_p_spo, p_spo_values, &(curwin->w_s->b_p_spo_flags), + true) != OK) { errmsg = e_invarg; } } else if (varp == &p_sps) { // 'spellsuggest' @@ -1152,29 +1161,30 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } else { if (curwin->w_status_height || global_stl_height()) { curwin->w_redr_status = true; - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); } curbuf->b_help = (curbuf->b_p_bt[0] == 'h'); redraw_titles(); } - } else if (gvarp == &p_stl || gvarp == (char_u **)&p_wbr || varp == &p_tal || varp == &p_ruf) { + } else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal + || varp == &p_ruf) { // 'statusline', 'winbar', 'tabline' or 'rulerformat' int wid; if (varp == &p_ruf) { // reset ru_wid first ru_wid = 0; } - s = (char *)(*varp); + s = *varp; if (varp == &p_ruf && *s == '%') { // set ru_wid if 'ruf' starts with "%99(" if (*++s == '-') { // ignore a '-' s++; } wid = getdigits_int(&s, true, 0); - if (wid && *s == '(' && (errmsg = check_stl_option((char *)p_ruf)) == NULL) { + if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) { ru_wid = wid; } else { - errmsg = check_stl_option((char *)p_ruf); + errmsg = check_stl_option(p_ruf); } } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!" @@ -1184,12 +1194,12 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er comp_col(); } // add / remove window bars for 'winbar' - if (gvarp == (char_u **)&p_wbr) { + if (gvarp == &p_wbr) { set_winbar(true); } } else if (gvarp == &p_cpt) { // check if it is a valid value for 'complete' -- Acevedo - for (s = (char *)(*varp); *s;) { + for (s = *varp; *s;) { while (*s == ',' || *s == ' ') { s++; } @@ -1246,7 +1256,8 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er && (curwin->w_p_nu || curwin->w_p_rnu)) { curwin->w_nrwidth_line_count = 0; } - } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) { + } else if (varp == &curwin->w_p_fdc + || varp == &curwin->w_allbuf_opt.wo_fdc) { // 'foldcolumn' if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { errmsg = e_invarg; @@ -1255,13 +1266,13 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // 'pastetoggle': translate key codes like in a mapping if (*p_pt) { p = NULL; - (void)replace_termcodes((char *)p_pt, - STRLEN(p_pt), + (void)replace_termcodes(p_pt, + strlen(p_pt), &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS); if (p != NULL) { free_string_option(p_pt); - p_pt = (char_u *)p; + p_pt = p; } } } else if (varp == &p_bs) { // 'backspace' @@ -1280,10 +1291,10 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er unsigned int *flags; if (opt_flags & OPT_LOCAL) { - p = (char *)curbuf->b_p_tc; + p = curbuf->b_p_tc; flags = &curbuf->b_tc_flags; } else { - p = (char *)p_tc; + p = p_tc; flags = &tc_flags; } @@ -1291,7 +1302,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // make the local value empty: use the global value *flags = 0; } else if (*p == NUL - || opt_strings_flags((char_u *)p, p_tc_values, flags, false) != OK) { + || opt_strings_flags(p, p_tc_values, flags, false) != OK) { errmsg = e_invarg; } } else if (varp == &p_cmp) { // 'casemap' @@ -1317,16 +1328,16 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er foldUpdateAll(curwin); } } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker' - p = vim_strchr((char *)(*varp), ','); + p = vim_strchr(*varp, ','); if (p == NULL) { errmsg = N_("E536: comma required"); - } else if ((char_u *)p == *varp || p[1] == NUL) { + } else if (p == *varp || p[1] == NUL) { errmsg = e_invarg; } else if (foldmethodIsMarker(curwin)) { foldUpdateAll(curwin); } } else if (gvarp == &p_cms) { // 'commentstring' - if (**varp != NUL && strstr((char *)(*varp), "%s") == NULL) { + if (**varp != NUL && strstr(*varp, "%s") == NULL) { errmsg = N_("E537: 'commentstring' must be empty or contain %s"); } } else if (varp == &p_fdo) { // 'foldopen' @@ -1342,7 +1353,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er foldUpdateAll(curwin); } } else if (gvarp == &p_ve) { // 'virtualedit' - char_u *ve = p_ve; + char *ve = p_ve; unsigned int *flags = &ve_flags; if (opt_flags & OPT_LOCAL) { @@ -1356,7 +1367,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } else { if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { errmsg = e_invarg; - } else if (STRCMP(p_ve, oldval) != 0) { + } else if (strcmp(p_ve, oldval) != 0) { // Recompute cursor position in case the new 've' setting // changes something. validate_virtcol(); @@ -1365,7 +1376,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } else if (varp == &p_csqf) { if (p_csqf != NULL) { - p = (char *)p_csqf; + p = p_csqf; while (*p != NUL) { if (vim_strchr(CSQF_CMDS, *p) == NULL || p[1] == NUL @@ -1391,7 +1402,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (!valid_filetype(*varp)) { errmsg = e_invarg; } else { - value_changed = STRCMP(oldval, *varp) != 0; + value_changed = strcmp(oldval, *varp) != 0; // Since we check the value, there is no need to set P_INSECURE, // even when the value comes from a modeline. @@ -1401,7 +1412,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (!valid_filetype(*varp)) { errmsg = e_invarg; } else { - value_changed = STRCMP(oldval, *varp) != 0; + value_changed = strcmp(oldval, *varp) != 0; // Since we check the value, there is no need to set P_INSECURE, // even when the value comes from a modeline. @@ -1416,7 +1427,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er errmsg = e_invarg; } } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop' - char_u *cp; + char *cp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { XFREE_CLEAR(curbuf->b_p_vsts_array); @@ -1441,7 +1452,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop' - char_u *cp; + char *cp; if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { XFREE_CLEAR(curbuf->b_p_vts_array); @@ -1483,8 +1494,8 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er p = WW_ALL; } if (varp == &p_shm) { // 'shortmess' - p = (char *)SHM_ALL; - } else if (varp == (char_u **)&(p_cpo)) { // 'cpoptions' + p = SHM_ALL; + } else if (varp == &(p_cpo)) { // 'cpoptions' p = CPO_VI; } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' p = FO_ALL; @@ -1494,7 +1505,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er p = MOUSE_ALL; } if (p != NULL) { - for (s = (char *)(*varp); *s; s++) { + for (s = *varp; *s; s++) { if (vim_strchr(p, *s) == NULL) { errmsg = illegal_char(errbuf, errbuflen, *s); break; @@ -1520,18 +1531,18 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er if (free_oldval) { free_string_option(oldval); } - set_option_flag(opt_idx, P_ALLOCED); + opt->flags |= P_ALLOCED; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 - && is_global_local_option(opt_idx)) { + && (opt->indir & PV_BOTH)) { // global option with local value set to use global value; free // the local value and make it empty - p = (char *)get_option_varp_scope(opt_idx, OPT_LOCAL); - free_string_option(*(char_u **)p); - *(char_u **)p = empty_option; + p = get_varp_scope(opt, OPT_LOCAL); + free_string_option(*(char **)p); + *(char **)p = empty_option; } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) { // May set global value for local option. - set_string_option_global(opt_idx, varp); + set_string_option_global(opt, varp); } // Trigger the autocommand only after setting the flags. @@ -1542,7 +1553,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er syn_recursive++; // Only pass true for "force" when the value changed or not used // recursively, to avoid endless recurrence. - apply_autocmds(EVENT_SYNTAX, (char *)curbuf->b_p_syn, curbuf->b_fname, + apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, value_changed || syn_recursive == 1, curbuf); curbuf->b_flags |= BF_SYN_SET; syn_recursive--; @@ -1562,7 +1573,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er did_filetype = true; // Only pass true for "force" when the value changed or not // used recursively, to avoid endless recurrence. - apply_autocmds(EVENT_FILETYPE, (char *)curbuf->b_p_ft, curbuf->b_fname, + apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, value_changed || ft_recursive == 1, curbuf); ft_recursive--; // Just in case the old "curbuf" is now invalid @@ -1573,8 +1584,8 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } } if (varp == &(curwin->w_s->b_p_spl)) { - char_u fname[200]; - char_u *q = curwin->w_s->b_p_spl; + char fname[200]; + char *q = curwin->w_s->b_p_spl; // Skip the first name if it is "cjk". if (STRNCMP(q, "cjk,", 4) == 0) { @@ -1585,15 +1596,14 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er // They could set 'spellcapcheck' depending on the language. // Use the first name in 'spelllang' up to '_region' or // '.encoding'. - for (p = (char *)q; *p != NUL; p++) { + for (p = q; *p != NUL; p++) { if (!ASCII_ISALNUM(*p) && *p != '-') { break; } } - if (p > (char *)q) { - vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", - (int)(p - (char *)q), q); - source_runtime((char *)fname, DIP_ALL); + if (p > q) { + vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); + source_runtime(fname, DIP_ALL); } } } @@ -1603,11 +1613,11 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er } if (curwin->w_curswant != MAXCOL - && (get_option_flags(opt_idx) & (P_CURSWANT | P_RALL)) != 0) { + && (opt->flags & (P_CURSWANT | P_RALL)) != 0) { curwin->w_set_curswant = true; } - check_redraw(get_option_flags(opt_idx)); + check_redraw(opt->flags); return errmsg; } @@ -1617,7 +1627,7 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er /// @param list when true: accept a list of values /// /// @return OK for correct value, FAIL otherwise. Empty is always OK. -static int check_opt_strings(char_u *val, char **values, int list) +static int check_opt_strings(char *val, char **values, int list) { return opt_strings_flags(val, values, NULL, list); } @@ -1630,7 +1640,7 @@ static int check_opt_strings(char_u *val, char **values, int list) /// @param list when true: accept a list of values /// /// @return OK for correct value, FAIL otherwise. Empty is always OK. -static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool list) +static int opt_strings_flags(char *val, char **values, unsigned *flagp, bool list) { unsigned int new_flags = 0; @@ -1640,7 +1650,7 @@ static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool l return FAIL; } - size_t len = STRLEN(values[i]); + size_t len = strlen(values[i]); if (STRNCMP(values[i], val, len) == 0 && ((list && val[len] == ',') || val[len] == NUL)) { val += len + (val[len] == ','); @@ -1658,7 +1668,7 @@ static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool l } /// @return OK if "p" is a valid fileformat name, FAIL otherwise. -int check_ff_value(char_u *p) +int check_ff_value(char *p) { return check_opt_strings(p, p_ff_values, false); } diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 795bff66cb..bd79b43574 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -20,7 +20,7 @@ #include "nvim/version.h" #include "nvim/vim.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 #endif @@ -128,7 +128,7 @@ int os_setenv(const char *name, const char *value, int overwrite) if (name[0] == '\0') { return -1; } -#ifdef WIN32 +#ifdef MSWIN if (!overwrite && os_getenv(name) != NULL) { return 0; } @@ -143,7 +143,7 @@ int os_setenv(const char *name, const char *value, int overwrite) #endif uv_mutex_lock(&mutex); int r; -#ifdef WIN32 +#ifdef MSWIN // libintl uses getenv() for LC_ALL/LANG/etc., so we must use _putenv_s(). if (striequal(name, "LC_ALL") || striequal(name, "LANGUAGE") || striequal(name, "LANG") || striequal(name, "LC_MESSAGES")) { @@ -186,7 +186,7 @@ int os_unsetenv(const char *name) size_t os_get_fullenv_size(void) { size_t len = 0; -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); wchar_t *p = envstrings; size_t l; @@ -235,7 +235,7 @@ void os_free_fullenv(char **env) /// @param env_size size of `env`, @see os_fullenv_size void os_copy_fullenv(char **env, size_t env_size) { -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); if (!envstrings) { return; @@ -280,7 +280,7 @@ void os_copy_fullenv(char **env, size_t env_size) /// @return [allocated] environment variable's value, or NULL char *os_getenvname_at_index(size_t index) { -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); if (!envstrings) { return NULL; @@ -347,7 +347,7 @@ char *os_getenvname_at_index(size_t index) /// @return the process ID. int64_t os_get_pid(void) { -#ifdef _WIN32 +#ifdef MSWIN return (int64_t)GetCurrentProcessId(); #else return (int64_t)getpid(); @@ -368,7 +368,7 @@ void os_get_hostname(char *hostname, size_t size) } else { xstrlcpy(hostname, vutsname.nodename, size); } -#elif defined(WIN32) +#elif defined(MSWIN) wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1]; DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]); if (GetComputerNameW(host_utf16, &host_wsize) == 0) { @@ -418,7 +418,7 @@ void init_homedir(void) const char *var = os_getenv("HOME"); -#ifdef WIN32 +#ifdef MSWIN // Typically, $HOME is not defined on Windows, unless the user has // specifically defined it for Vim's sake. However, on Windows NT // platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for @@ -451,7 +451,7 @@ void init_homedir(void) var = NULL; const char *exp = os_getenv(os_buf); if (exp != NULL && *exp != NUL - && STRLEN(exp) + STRLEN(p) < MAXPATHL) { + && strlen(exp) + strlen(p) < MAXPATHL) { vim_snprintf(os_buf, MAXPATHL, "%s%s", exp, p + 1); var = os_buf; } @@ -476,7 +476,7 @@ void init_homedir(void) // Change to the directory and get the actual path. This resolves // links. Don't do it when we can't return. if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { - if (!os_chdir(var) && os_dirname(IObuff, IOSIZE) == OK) { + if (!os_chdir(var) && os_dirname((char_u *)IObuff, IOSIZE) == OK) { var = (char *)IObuff; } if (os_chdir(os_buf) != 0) { @@ -553,9 +553,9 @@ char_u *expand_env_save_opt(char_u *src, bool one) /// @param src Input string e.g. "$HOME/vim.hlp" /// @param dst[out] Where to put the result /// @param dstlen Maximum length of the result -void expand_env(char_u *src, char_u *dst, int dstlen) +void expand_env(char *src, char *dst, int dstlen) { - expand_env_esc(src, dst, dstlen, false, false, NULL); + expand_env_esc((char_u *)src, (char_u *)dst, dstlen, false, false, NULL); } /// Expand environment variable with path name and escaping. @@ -669,8 +669,8 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; - var = ExpandOne(&xpc, dst, NULL, - WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE); + var = (char_u *)ExpandOne(&xpc, (char *)dst, NULL, + WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE); mustfree = true; } #else @@ -684,7 +684,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // If 'shellslash' is set change backslashes to forward slashes. // Can't use slash_adjust(), p_ssl may be set temporarily. if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) { - char_u *p = vim_strsave(var); + char_u *p = xstrdup(var); if (mustfree) { xfree(var); @@ -765,12 +765,12 @@ static char *vim_version_dir(const char *vimdir) return NULL; } char *p = concat_fnames(vimdir, VIM_VERSION_NODOT, true); - if (os_isdir((char_u *)p)) { + if (os_isdir(p)) { return p; } xfree(p); p = concat_fnames(vimdir, RUNTIME_DIRNAME, true); - if (os_isdir((char_u *)p)) { + if (os_isdir(p)) { return p; } xfree(p); @@ -800,11 +800,11 @@ static char *vim_version_dir(const char *vimdir) /// @return The new pend including dirname or just pend static char *remove_tail(char *path, char *pend, char *dirname) { - size_t len = STRLEN(dirname); + size_t len = strlen(dirname); char *new_tail = pend - len - 1; if (new_tail >= path - && FNAMENCMP((char_u *)new_tail, (char_u *)dirname, len) == 0 + && path_fnamencmp(new_tail, dirname, len) == 0 && (new_tail == path || after_pathsep(path, new_tail))) { return new_tail; } @@ -900,7 +900,7 @@ char *vim_getenv(const char *name) // init_path() should have been called before now. assert(get_vim_var_str(VV_PROGPATH)[0] != NUL); -#ifdef WIN32 +#ifdef MSWIN if (strcmp(name, "HOME") == 0) { return xstrdup(homedir); } @@ -937,8 +937,8 @@ char *vim_getenv(const char *name) // - the directory name from 'helpfile' (unless it contains '$') // - the executable name from argv[0] if (vim_path == NULL) { - if (p_hf != NULL && vim_strchr((char *)p_hf, '$') == NULL) { - vim_path = (char *)p_hf; + if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL) { + vim_path = p_hf; } char exe_name[MAXPATHL]; @@ -957,7 +957,7 @@ char *vim_getenv(const char *name) char *vim_path_end = path_tail(vim_path); // remove "doc/" from 'helpfile', if present - if (vim_path == (char *)p_hf) { + if (vim_path == p_hf) { vim_path_end = remove_tail(vim_path, vim_path_end, "doc"); } @@ -976,7 +976,7 @@ char *vim_getenv(const char *name) assert(vim_path_end >= vim_path); vim_path = xstrndup(vim_path, (size_t)(vim_path_end - vim_path)); - if (!os_isdir((char_u *)vim_path)) { + if (!os_isdir(vim_path)) { xfree(vim_path); vim_path = NULL; } @@ -1056,7 +1056,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si } const char *homedir_env = os_getenv("HOME"); -#ifdef WIN32 +#ifdef MSWIN if (homedir_env == NULL) { homedir_env = os_getenv("USERPROFILE"); } @@ -1098,7 +1098,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si size_t len = dirlen; for (;;) { if (len - && FNAMENCMP(src, (char_u *)p, len) == 0 + && path_fnamencmp(src, p, len) == 0 && (vim_ispathsep(src[len]) || (!one && (src[len] == ',' || src[len] == ' ')) || src[len] == NUL)) { @@ -1146,7 +1146,7 @@ char *home_replace_save(buf_T *buf, const char *src) { size_t len = 3; // space for "~/" and trailing NUL if (src != NULL) { // just in case - len += STRLEN(src); + len += strlen(src); } char *dst = xmalloc(len); home_replace(buf, src, dst, len, true); @@ -1156,15 +1156,12 @@ char *home_replace_save(buf_T *buf, const char *src) /// Function given to ExpandGeneric() to obtain an environment variable name. char *get_env_name(expand_T *xp, int idx) { -#define ENVNAMELEN 100 - // this static buffer is needed to avoid a memory leak in ExpandGeneric - static char_u name[ENVNAMELEN]; assert(idx >= 0); char *envname = os_getenvname_at_index((size_t)idx); if (envname) { - STRLCPY(name, envname, ENVNAMELEN); + STRLCPY(xp->xp_buf, envname, EXPAND_BUF_LEN); xfree(envname); - return (char *)name; + return xp->xp_buf; } return NULL; } @@ -1177,7 +1174,7 @@ char *get_env_name(expand_T *xp, int idx) bool os_setenv_append_path(const char *fname) FUNC_ATTR_NONNULL_ALL { -#ifdef WIN32 +#ifdef MSWIN // 8191 (plus NUL) is considered the practical maximum. # define MAX_ENVPATHLEN 8192 #else diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 0d62a5f5f9..68e96eea6e 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -27,7 +27,7 @@ #include "nvim/path.h" #include "nvim/strings.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 #endif @@ -129,10 +129,10 @@ bool os_isrealdir(const char *name) /// Check if the given path exists and is a directory. /// /// @return `true` if `name` is a directory. -bool os_isdir(const char_u *name) +bool os_isdir(const char *name) FUNC_ATTR_NONNULL_ALL { - int32_t mode = os_getperm((const char *)name); + int32_t mode = os_getperm(name); if (mode < 0) { return false; } @@ -151,7 +151,7 @@ bool os_isdir(const char_u *name) int os_nodetype(const char *name) FUNC_ATTR_NONNULL_ALL { -#ifndef WIN32 // Unix +#ifndef MSWIN // Unix uv_stat_t statbuf; if (0 != os_stat(name, &statbuf)) { return NODE_NORMAL; // File doesn't exist. @@ -241,7 +241,7 @@ bool os_can_exe(const char *name, char **abspath, bool use_path) FUNC_ATTR_NONNULL_ARG(1) { if (!use_path || gettail_dir(name) != name) { -#ifdef WIN32 +#ifdef MSWIN if (is_executable_ext(name, abspath)) { #else // Must have path separator, cannot execute files in the current directory. @@ -270,7 +270,7 @@ static bool is_executable(const char *name, char **abspath) return false; } -#ifdef WIN32 +#ifdef MSWIN // Windows does not have exec bit; just check if the file exists and is not // a directory. const bool ok = S_ISREG(mode); @@ -287,7 +287,7 @@ static bool is_executable(const char *name, char **abspath) return ok; } -#ifdef WIN32 +#ifdef MSWIN /// Checks if file `name` is executable under any of these conditions: /// - extension is in $PATHEXT and `name` is executable /// - result of any $PATHEXT extension appended to `name` is executable @@ -351,7 +351,7 @@ static bool is_executable_in_path(const char *name, char **abspath) return false; } -#ifdef WIN32 +#ifdef MSWIN // Prepend ".;" to $PATH. size_t pathlen = strlen(path_env); char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2); @@ -374,7 +374,7 @@ static bool is_executable_in_path(const char *name, char **abspath) STRLCPY(buf, p, e - p + 1); append_path(buf, name, buf_len); -#ifdef WIN32 +#ifdef MSWIN if (is_executable_ext(buf, abspath)) { #else if (is_executable(buf, abspath)) { @@ -446,7 +446,7 @@ FILE *os_fopen(const char *path, const char *flags) default: abort(); } -#ifdef WIN32 +#ifdef MSWIN if (flags[1] == 'b') { iflags |= O_BINARY; } @@ -821,10 +821,10 @@ int os_fchown(int fd, uv_uid_t owner, uv_gid_t group) /// Check if a path exists. /// /// @return `true` if `path` exists -bool os_path_exists(const char_u *path) +bool os_path_exists(const char *path) { uv_stat_t statbuf; - return os_stat((char *)path, &statbuf) == kLibuvSuccess; + return os_stat(path, &statbuf) == kLibuvSuccess; } /// Sets file access and modification times. @@ -865,7 +865,7 @@ int os_file_is_writable(const char *name) int r; RUN_UV_FS_FUNC(r, uv_fs_access, name, W_OK, NULL); if (r == 0) { - return os_isdir((char_u *)name) ? 2 : 1; + return os_isdir(name) ? 2 : 1; } return 0; } @@ -911,11 +911,11 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di // We're done when it's "/" or "c:/". const size_t dirlen = strlen(dir); char *const curdir = xmemdupz(dir, dirlen); - char *const past_head = (char *)get_past_head((char_u *)curdir); + char *const past_head = get_past_head(curdir); char *e = curdir + dirlen; const char *const real_end = e; const char past_head_save = *past_head; - while (!os_isdir((char_u *)curdir)) { + while (!os_isdir(curdir)) { e = path_tail_with_sep(curdir); if (e <= past_head) { *past_head = NUL; @@ -1208,7 +1208,7 @@ char *os_realpath(const char *name, char *buf) return result == kLibuvSuccess ? buf : NULL; } -#ifdef WIN32 +#ifdef MSWIN # include <shlobj.h> /// When "fname" is the name of a shortcut (*.lnk) resolve the file it points diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index bfe6d59dc6..cb0dba8cac 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -38,6 +38,8 @@ static RBuffer *input_buffer = NULL; static bool input_eof = false; static int global_fd = -1; static bool blocking = false; +static int cursorhold_time = 0; ///< time waiting for CursorHold event +static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting started #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.c.generated.h" @@ -97,13 +99,25 @@ static void create_cursorhold_event(bool events_enabled) multiqueue_put(main_loop.events, cursorhold_event, 0); } +static void restart_cursorhold_wait(int tb_change_cnt) +{ + cursorhold_time = 0; + cursorhold_tb_change_cnt = tb_change_cnt; +} + /// Low level input function /// /// wait until either the input buffer is non-empty or, if `events` is not NULL /// until `events` is non-empty. int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events) { + // This check is needed so that feeding typeahead from RPC can prevent CursorHold. + if (tb_change_cnt != cursorhold_tb_change_cnt) { + restart_cursorhold_wait(tb_change_cnt); + } + if (maxlen && rbuffer_size(input_buffer)) { + restart_cursorhold_wait(tb_change_cnt); return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } @@ -118,18 +132,22 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return 0; } } else { - if ((result = inbuf_poll((int)p_ut, events)) == kInputNone) { + uint64_t wait_start = os_hrtime(); + cursorhold_time = MIN(cursorhold_time, (int)p_ut); + if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) { if (read_stream.closed && silent_mode) { // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). read_error_exit(); } - + restart_cursorhold_wait(tb_change_cnt); if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { create_cursorhold_event(events == main_loop.events); } else { before_blocking(); result = inbuf_poll(-1, events); } + } else { + cursorhold_time += (int)((os_hrtime() - wait_start) / 1000000); } } @@ -141,6 +159,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e } if (maxlen && rbuffer_size(input_buffer)) { + restart_cursorhold_wait(tb_change_cnt); // Safe to convert rbuffer_read to int, it will never overflow since we use // relatively small buffers. return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); @@ -287,36 +306,35 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) static int orig_mouse_row = 0; static uint64_t orig_mouse_time = 0; // time of previous mouse click - if (code == KE_LEFTRELEASE - || code == KE_RIGHTRELEASE - || code == KE_MIDDLERELEASE - || code == KE_MOUSEDOWN - || code == KE_MOUSEUP - || code == KE_MOUSELEFT - || code == KE_MOUSERIGHT) { + if ((code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) || code == KE_MOUSEMOVE) { return 0; } - uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) - - // compute the time elapsed since the previous mouse click and - // convert p_mouse from ms to ns - uint64_t timediff = mouse_time - orig_mouse_time; - uint64_t mouset = (uint64_t)p_mouset * 1000000; - if (code == orig_mouse_code - && timediff < mouset - && orig_num_clicks != 4 - && orig_mouse_grid == grid - && orig_mouse_col == col - && orig_mouse_row == row) { - orig_num_clicks++; - } else { - orig_num_clicks = 1; + + // For click events the number of clicks is updated. + if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE) { + uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) + // compute the time elapsed since the previous mouse click and + // convert p_mouse from ms to ns + uint64_t timediff = mouse_time - orig_mouse_time; + uint64_t mouset = (uint64_t)p_mouset * 1000000; + if (code == orig_mouse_code + && timediff < mouset + && orig_num_clicks != 4 + && orig_mouse_grid == grid + && orig_mouse_col == col + && orig_mouse_row == row) { + orig_num_clicks++; + } else { + orig_num_clicks = 1; + } + orig_mouse_code = code; + orig_mouse_time = mouse_time; } - orig_mouse_code = code; + // For drag and release events the number of clicks is kept. + orig_mouse_grid = grid; orig_mouse_col = col; orig_mouse_row = row; - orig_mouse_time = mouse_time; uint8_t modifiers = 0; if (orig_num_clicks == 2) { @@ -347,7 +365,8 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bu if (type != KS_EXTRA || !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE) - || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) { + || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT) + || mouse_code == KE_MOUSEMOVE)) { return bufsize; } diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index a4361859ec..a30e16eeba 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -7,7 +7,7 @@ #include <sys/stat.h> #include <sys/types.h> -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/win_defs.h" #else # include "nvim/os/unix_defs.h" @@ -43,7 +43,7 @@ /// Converts system error code to libuv error code. #define os_translate_sys_error uv_translate_sys_error -#ifdef WIN32 +#ifdef MSWIN # define os_strtok strtok_s #else # define os_strtok strtok_r diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c index e70bc71961..28aea08595 100644 --- a/src/nvim/os/process.c +++ b/src/nvim/os/process.c @@ -8,7 +8,7 @@ #include <uv.h> // for HANDLE (win32) -#ifdef WIN32 +#ifdef MSWIN # include <tlhelp32.h> // for CreateToolhelp32Snapshot #endif @@ -38,7 +38,7 @@ # include "os/process.c.generated.h" #endif -#ifdef WIN32 +#ifdef MSWIN static bool os_proc_tree_kill_rec(HANDLE process, int sig) { if (process == NULL) { @@ -114,7 +114,7 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) *proc_list = NULL; *proc_count = 0; -#ifdef WIN32 +#ifdef MSWIN PROCESSENTRY32 pe; // Snapshot of all processes. @@ -215,7 +215,7 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) return 0; } -#ifdef WIN32 +#ifdef MSWIN /// Gets various properties of the process identified by `pid`. /// /// @param pid Process to inspect. diff --git a/src/nvim/os/pty_conpty_win.h b/src/nvim/os/pty_conpty_win.h index 15e7c3da0c..0c25a5970e 100644 --- a/src/nvim/os/pty_conpty_win.h +++ b/src/nvim/os/pty_conpty_win.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_PTY_CONPTY_WIN_H #define NVIM_OS_PTY_CONPTY_WIN_H -#include "nvim/lib/kvec.h" +#include "klib/kvec.h" #include "nvim/os/input.h" #ifndef HPCON diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h index 94923499ca..07d346be22 100644 --- a/src/nvim/os/pty_process.h +++ b/src/nvim/os/pty_process.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_PTY_PROCESS_H #define NVIM_OS_PTY_PROCESS_H -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/pty_process_win.h" #else # include "nvim/os/pty_process_unix.h" diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index c5d6af0ff6..0b7af87267 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -31,11 +31,11 @@ #include <uv.h> +#include "klib/klist.h" #include "nvim/event/loop.h" #include "nvim/event/process.h" #include "nvim/event/rstream.h" #include "nvim/event/wstream.h" -#include "nvim/lib/klist.h" #include "nvim/log.h" #include "nvim/os/os.h" #include "nvim/os/pty_process_unix.h" diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index b793b8f9c6..750d2f342f 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -7,6 +7,7 @@ #include <string.h> #include <uv.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/charset.h" #include "nvim/eval.h" @@ -15,7 +16,6 @@ #include "nvim/event/rstream.h" #include "nvim/ex_cmds.h" #include "nvim/fileio.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/memline.h" @@ -52,11 +52,11 @@ 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((char_u *)pat[i]); + char *s = xstrdup(pat[i]); // Be compatible with expand_filename(): halve the number of // backslashes. backslash_halve(s); - (*file)[i] = (char *)s; + (*file)[i] = s; } *num_file = num_pat; } @@ -64,7 +64,7 @@ static void save_patterns(int num_pat, char **pat, int *num_file, char ***file) static bool have_wildcard(int num, char **file) { for (int i = 0; i < num; i++) { - if (path_has_wildcard((char_u *)file[i])) { + if (path_has_wildcard(file[i])) { return true; } } @@ -74,7 +74,7 @@ static bool have_wildcard(int num, char **file) static bool have_dollars(int num, char **file) { for (int i = 0; i < num; i++) { - if (vim_strchr((char *)file[i], '$') != NULL) { + if (vim_strchr(file[i], '$') != NULL) { return true; } } @@ -129,7 +129,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in bool is_fish_shell = #if defined(UNIX) - STRNCMP(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; + STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "fish", 4) == 0; #else false; #endif @@ -160,7 +160,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } // get a name for the temp file - if ((tempname = vim_tempname()) == NULL) { + if ((tempname = (char_u *)vim_tempname()) == NULL) { emsg(_(e_notmp)); return FAIL; } @@ -178,18 +178,18 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // STYLE_ECHO: space separated. // A shell we don't know, stay safe and use "echo". if (num_pat == 1 && *pat[0] == '`' - && (len = STRLEN(pat[0])) > 2 + && (len = strlen(pat[0])) > 2 && *(pat[0] + len - 1) == '`') { shell_style = STYLE_BT; } else if ((len = STRLEN(p_sh)) >= 3) { - if (STRCMP(p_sh + len - 3, "csh") == 0) { + if (strcmp(p_sh + len - 3, "csh") == 0) { shell_style = STYLE_GLOB; - } else if (STRCMP(p_sh + len - 3, "zsh") == 0) { + } else if (strcmp(p_sh + len - 3, "zsh") == 0) { shell_style = STYLE_PRINT; } } if (shell_style == STYLE_ECHO - && strstr(path_tail((char *)p_sh), "sh") != NULL) { + && strstr(path_tail(p_sh), "sh") != NULL) { shell_style = STYLE_VIMGLOB; } @@ -198,7 +198,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // Worst case: "unset nonomatch; print -N >" plus two is 29 len = STRLEN(tempname) + 29; if (shell_style == STYLE_VIMGLOB) { - len += STRLEN(sh_vimglob_func); + len += strlen(sh_vimglob_func); } for (i = 0; i < num_pat; i++) { @@ -503,12 +503,12 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // 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((char_u *)(*file)[i])) { + if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) { continue; } // check if this entry should be included - dir = (os_isdir((char_u *)(*file)[i])); + dir = (os_isdir((*file)[i])); if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) { continue; } @@ -519,7 +519,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in continue; } - p = xmalloc(STRLEN((*file)[i]) + 1 + dir); + p = xmalloc(strlen((*file)[i]) + 1 + dir); STRCPY(p, (*file)[i]); if (dir) { add_pathsep((char *)p); // add '/' to a directory name @@ -555,11 +555,11 @@ notfound: char **shell_build_argv(const char *cmd, const char *extra_args) FUNC_ATTR_NONNULL_RET { - size_t argc = tokenize(p_sh, NULL) + (cmd ? tokenize(p_shcf, NULL) : 0); + size_t argc = tokenize((char_u *)p_sh, NULL) + (cmd ? tokenize(p_shcf, NULL) : 0); char **rv = xmalloc((argc + 4) * sizeof(*rv)); // Split 'shell' - size_t i = tokenize(p_sh, rv); + size_t i = tokenize((char_u *)p_sh, rv); if (extra_args) { rv[i++] = xstrdup(extra_args); // Push a copy of `extra_args` @@ -700,7 +700,7 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) if (p_verbose > 3) { verbose_enter(); - smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd); + smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : (char *)cmd); msg_putchar('\n'); verbose_leave(); } @@ -746,7 +746,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret } // get a name for the temp file - char_u *tempname = vim_tempname(); + char_u *tempname = (char_u *)vim_tempname(); if (tempname == NULL) { emsg(_(e_notmp)); return NULL; @@ -805,7 +805,7 @@ done: /// char *output = NULL; /// size_t nread = 0; /// char *argv[] = {"ls", "-la", NULL}; -/// int exitcode = os_sytem(argv, NULL, 0, &output, &nread); +/// int exitcode = os_system(argv, NULL, 0, &output, &nread); /// /// @param argv The commandline arguments to be passed to the shell. `argv` /// will be consumed. @@ -911,7 +911,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu out_data_ring(NULL, SIZE_MAX); } if (forward_output) { - // caller should decide if wait_return is invoked + // caller should decide if wait_return() is invoked no_wait_return++; msg_end(); no_wait_return--; @@ -1106,13 +1106,13 @@ static void out_data_append_to_screen(char *output, size_t *count, bool eof) // incomplete UTF-8 sequence that could be composing with the last // complete sequence. // This will be corrected when we switch to vterm based implementation - int i = *p ? utfc_ptr2len_len((char_u *)p, (int)(end - p)) : 1; + int i = *p ? utfc_ptr2len_len(p, (int)(end - p)) : 1; if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) { *count = (size_t)(p - output); goto end; } - (void)msg_outtrans_len_attr((char_u *)p, i, 0); + (void)msg_outtrans_len_attr(p, i, 0); p += i; } } @@ -1208,7 +1208,7 @@ static void read_input(DynamicBuffer *buf) { size_t written = 0, l = 0, len = 0; linenr_T lnum = curbuf->b_op_start.lnum; - char_u *lp = ml_get(lnum); + char_u *lp = (char_u *)ml_get(lnum); for (;;) { l = strlen((char *)lp + written); @@ -1240,7 +1240,7 @@ static void read_input(DynamicBuffer *buf) if (lnum > curbuf->b_op_end.lnum) { break; } - lp = ml_get(lnum); + lp = (char_u *)ml_get(lnum); written = 0; } else if (len > 0) { written += len; @@ -1316,17 +1316,17 @@ static char *shell_xescape_xquote(const char *cmd) } const char *ecmd = cmd; - if (*p_sxe != NUL && STRCMP(p_sxq, "(") == 0) { + if (*p_sxe != NUL && strcmp(p_sxq, "(") == 0) { ecmd = (char *)vim_strsave_escaped_ext((char_u *)cmd, p_sxe, '^', false); } - size_t ncmd_size = strlen(ecmd) + STRLEN(p_sxq) * 2 + 1; + size_t ncmd_size = strlen(ecmd) + strlen(p_sxq) * 2 + 1; char *ncmd = xmalloc(ncmd_size); // When 'shellxquote' is ( append ). // When 'shellxquote' is "( append )". - if (STRCMP(p_sxq, "(") == 0) { + if (strcmp(p_sxq, "(") == 0) { vim_snprintf(ncmd, ncmd_size, "(%s)", ecmd); - } else if (STRCMP(p_sxq, "\"(") == 0) { + } else if (strcmp(p_sxq, "\"(") == 0) { vim_snprintf(ncmd, ncmd_size, "\"(%s)\"", ecmd); } else { vim_snprintf(ncmd, ncmd_size, "%s%s%s", p_sxq, ecmd, p_sxq); diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index e592570966..9aa8d8051b 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -4,7 +4,7 @@ #include <assert.h> #include <stdbool.h> #include <uv.h> -#ifndef WIN32 +#ifndef MSWIN # include <signal.h> // for sigset_t #endif @@ -34,7 +34,7 @@ static bool rejecting_deadly; void signal_init(void) { -#ifndef WIN32 +#ifndef MSWIN // Ensure a clean slate by unblocking all signals. For example, if SIGCHLD is // blocked, libuv may hang after spawning a subprocess on Linux. #5230 sigset_t mask; diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 59d315d44c..31d85ac2eb 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -21,7 +21,7 @@ static const char *xdg_env_vars[] = { [kXDGDataDirs] = "XDG_DATA_DIRS", }; -#ifdef WIN32 +#ifdef MSWIN static const char *const xdg_defaults_env_vars[] = { [kXDGConfigHome] = "LOCALAPPDATA", [kXDGDataHome] = "LOCALAPPDATA", @@ -37,7 +37,7 @@ static const char *const xdg_defaults_env_vars[] = { /// /// Used in case environment variables contain nothing. Need to be expanded. static const char *const xdg_defaults[] = { -#ifdef WIN32 +#ifdef MSWIN [kXDGConfigHome] = "~\\AppData\\Local", [kXDGDataHome] = "~\\AppData\\Local", [kXDGCacheHome] = "~\\AppData\\Local\\Temp", @@ -69,7 +69,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx) const char *env_val = os_getenv(env); -#ifdef WIN32 +#ifdef MSWIN if (env_val == NULL && xdg_defaults_env_vars[idx] != NULL) { env_val = os_getenv(xdg_defaults_env_vars[idx]); } @@ -107,7 +107,7 @@ char *get_xdg_home(const XDGVarType idx) { char *dir = stdpaths_get_xdg_var(idx); if (dir) { -#if defined(WIN32) +#if defined(MSWIN) dir = concat_fnames_realloc(dir, ((idx == kXDGDataHome || idx == kXDGStateHome) ? "nvim-data" : "nvim"), diff --git a/src/nvim/os/tty.c b/src/nvim/os/tty.c index 126b1b0044..1b15613a93 100644 --- a/src/nvim/os/tty.c +++ b/src/nvim/os/tty.c @@ -12,7 +12,7 @@ # include "os/tty.c.generated.h" #endif -#ifdef WIN32 +#ifdef MSWIN # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 # endif diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index bd34e917b2..33e6563c4c 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -14,7 +14,7 @@ #ifdef HAVE_PWD_H # include <pwd.h> #endif -#ifdef WIN32 +#ifdef MSWIN # include <lm.h> #endif @@ -56,7 +56,7 @@ int os_get_usernames(garray_T *users) } endpwent(); } -#elif defined(WIN32) +#elif defined(MSWIN) { DWORD nusers = 0, ntotal = 0, i; PUSER_INFO_0 uinfo; @@ -93,7 +93,7 @@ int os_get_usernames(garray_T *users) for (i = 0; i < users->ga_len; i++) { char *local_user = ((char **)users->ga_data)[i]; - if (STRCMP(local_user, user_env) == 0) { + if (strcmp(local_user, user_env) == 0) { break; } } @@ -208,14 +208,14 @@ char *get_users(expand_T *xp, int idx) /// @return 0 if name does not match any user name. /// 1 if name partially matches the beginning of a user name. /// 2 is name fully matches a user name. -int match_user(char_u *name) +int match_user(char *name) { - int n = (int)STRLEN(name); + int n = (int)strlen(name); int result = 0; init_users(); for (int i = 0; i < ga_users.ga_len; i++) { - if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) { + if (strcmp(((char **)ga_users.ga_data)[i], name) == 0) { return 2; // full match } if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) { diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index 1ae86d6bbe..4f8a242a51 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_WIN_DEFS_H #define NVIM_OS_WIN_DEFS_H -#ifndef WIN32 +#ifndef MSWIN # error Header must be included only when compiling for Windows. #endif diff --git a/src/nvim/path.c b/src/nvim/path.c index 1500254de5..9295905415 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -33,7 +33,7 @@ #include "nvim/vim.h" #include "nvim/window.h" -#define URL_SLASH 1 // path_is_url() has found "://" +#define URL_SLASH 1 // path_is_url() has found ":/" #define URL_BACKSLASH 2 // path_is_url() has found ":\\" #ifdef gen_expand_wildcards @@ -62,7 +62,7 @@ FileComparison path_full_compare(char *const s1, char *const s2, const bool chec FileID file_id_1, file_id_2; if (expandenv) { - expand_env((char_u *)s1, (char_u *)exp1, MAXPATHL); + expand_env(s1, exp1, MAXPATHL); } else { STRLCPY(exp1, s1, MAXPATHL); } @@ -73,7 +73,7 @@ FileComparison path_full_compare(char *const s1, char *const s2, const bool chec if (checkname) { vim_FullName(exp1, full1, MAXPATHL, false); vim_FullName(s2, full2, MAXPATHL, false); - if (FNAMECMP(full1, full2) == 0) { + if (path_fnamecmp(full1, full2) == 0) { return kEqualFileNames; } } @@ -104,7 +104,7 @@ char *path_tail(const char *fname) return ""; } - const char *tail = (char *)get_past_head((char_u *)fname); + const char *tail = get_past_head(fname); const char *p = tail; // Find last part of path. while (*p != NUL) { @@ -130,7 +130,7 @@ char *path_tail_with_sep(char *fname) assert(fname != NULL); // Don't remove the '/' from "c:/file". - char *past_head = (char *)get_past_head((char_u *)fname); + char *past_head = get_past_head(fname); char *tail = path_tail(fname); while (tail > past_head && after_pathsep(fname, tail)) { tail--; @@ -150,7 +150,7 @@ char *path_tail_with_sep(char *fname) const char_u *invocation_path_tail(const char_u *invocation, size_t *len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) { - const char_u *tail = get_past_head((char_u *)invocation); + const char_u *tail = (char_u *)get_past_head((char *)invocation); const char_u *p = tail; while (*p != NUL && *p != ' ') { bool was_sep = vim_ispathsep_nocolon(*p); @@ -190,7 +190,7 @@ const char *path_next_component(const char *fname) /// - 1 otherwise int path_head_length(void) { -#ifdef WIN32 +#ifdef MSWIN return 3; #else return 1; @@ -205,7 +205,7 @@ int path_head_length(void) /// - False otherwise bool is_path_head(const char_u *path) { -#ifdef WIN32 +#ifdef MSWIN return isalpha(path[0]) && path[1] == ':'; #else return vim_ispathsep(*path); @@ -215,13 +215,13 @@ bool is_path_head(const char_u *path) /// Get a pointer to one character past the head of a path name. /// Unix: after "/"; Win: after "c:\" /// If there is no head, path is returned. -char_u *get_past_head(const char_u *path) +char *get_past_head(const char *path) { - const char_u *retval = path; + const char *retval = path; -#ifdef WIN32 +#ifdef MSWIN // May skip "c:" - if (is_path_head(path)) { + if (is_path_head((char_u *)path)) { retval = path + 2; } #endif @@ -230,13 +230,11 @@ char_u *get_past_head(const char_u *path) retval++; } - return (char_u *)retval; + return (char *)retval; } -/* - * Return TRUE if 'c' is a path separator. - * Note that for MS-Windows this includes the colon. - */ +/// Return true if 'c' is a path separator. +/// Note that for MS-Windows this includes the colon. int vim_ispathsep(int c) { #ifdef UNIX @@ -250,9 +248,7 @@ int vim_ispathsep(int c) #endif } -/* - * Like vim_ispathsep(c), but exclude the colon for MS-Windows. - */ +// Like vim_ispathsep(c), but exclude the colon for MS-Windows. int vim_ispathsep_nocolon(int c) { return vim_ispathsep(c) @@ -262,9 +258,7 @@ int vim_ispathsep_nocolon(int c) ; } -/* - * return TRUE if 'c' is a path list separator. - */ +/// return true if 'c' is a path list separator. int vim_ispathlistsep(int c) { #ifdef UNIX @@ -314,16 +308,14 @@ void shorten_dir_len(char_u *str, int trim_len) /// Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" /// It's done in-place. -void shorten_dir(char_u *str) +void shorten_dir(char *str) { - shorten_dir_len(str, 1); + shorten_dir_len((char_u *)str, 1); } -/* - * Return TRUE if the directory of "fname" exists, FALSE otherwise. - * Also returns TRUE if there is no directory name. - * "fname" must be writable!. - */ +/// Return true if the directory of "fname" exists, false otherwise. +/// Also returns true if there is no directory name. +/// "fname" must be writable!. bool dir_of_file_exists(char_u *fname) { char *p = path_tail_with_sep((char *)fname); @@ -332,13 +324,19 @@ bool dir_of_file_exists(char_u *fname) } char c = *p; *p = NUL; - bool retval = os_isdir(fname); + bool retval = os_isdir((char *)fname); *p = c; return retval; } /// Compare two file names /// +/// On some systems case in a file name does not matter, on others it does. +/// +/// @note Does not account for maximum name lengths and things like "../dir", +/// thus it is not 100% accurate. OS may also use different algorithm for +/// case-insensitive comparison. +/// /// Handles '/' and '\\' correctly and deals with &fileignorecase option. /// /// @param[in] fname1 First file name. @@ -376,21 +374,21 @@ int path_fnamencmp(const char *const fname1, const char *const fname2, size_t le const char *p1 = fname1; const char *p2 = fname2; while (len > 0) { - c1 = utf_ptr2char((const char_u *)p1); - c2 = utf_ptr2char((const char_u *)p2); + c1 = utf_ptr2char(p1); + c2 = utf_ptr2char(p2); if ((c1 == NUL || c2 == NUL || (!((c1 == '/' || c1 == '\\') && (c2 == '\\' || c2 == '/')))) && (p_fic ? (c1 != c2 && CH_FOLD(c1) != CH_FOLD(c2)) : c1 != c2)) { break; } - len -= (size_t)utfc_ptr2len((const char_u *)p1); - p1 += utfc_ptr2len((const char_u *)p1); - p2 += utfc_ptr2len((const char_u *)p2); + len -= (size_t)utfc_ptr2len(p1); + p1 += utfc_ptr2len(p1); + p2 += utfc_ptr2len(p2); } return p_fic ? CH_FOLD(c1) - CH_FOLD(c2) : c1 - c2; #else if (p_fic) { - return mb_strnicmp((const char_u *)fname1, (const char_u *)fname2, len); + return mb_strnicmp(fname1, fname2, len); } return strncmp(fname1, fname2, len); #endif @@ -515,7 +513,7 @@ char *save_abs_path(const char *name) /// @param p The path to expand. /// @returns Unix: True if it contains one of "?[{`'$". /// @returns Windows: True if it contains one of "*?$[". -bool path_has_wildcard(const char_u *p) +bool path_has_wildcard(const char *p) FUNC_ATTR_NONNULL_ALL { for (; *p; MB_PTR_ADV(p)) { @@ -538,9 +536,7 @@ bool path_has_wildcard(const char_u *p) return false; } -/* - * Unix style wildcard expansion code. - */ +// Unix style wildcard expansion code. static int pstrcmp(const void *a, const void *b) { return pathcmp(*(char **)a, *(char **)b, -1); @@ -579,13 +575,13 @@ bool path_has_exp_wildcard(const char_u *p) /// @param path The path to search. /// @param flags Flags for regexp expansion. /// - EW_ICASE: Ignore case. -/// - EW_NOERROR: Silence error messeges. +/// - EW_NOERROR: Silence error messages. /// - EW_NOTWILD: Add matches literally. /// @returns the number of matches found. static size_t path_expand(garray_T *gap, const char_u *path, int flags) FUNC_ATTR_NONNULL_ALL { - return do_path_expand(gap, path, 0, flags, false); + return do_path_expand(gap, (char *)path, 0, flags, false); } static const char *scandir_next_with_dots(Directory *dir) @@ -606,7 +602,7 @@ static const char *scandir_next_with_dots(Directory *dir) /// Implementation of path_expand(). /// /// Chars before `path + wildoff` do not get expanded. -static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, int flags, +static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, int flags, bool didstar) FUNC_ATTR_NONNULL_ALL { @@ -633,20 +629,20 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, char_u *p = buf; char_u *s = buf; char_u *e = NULL; - const char_u *path_end = path; + const char_u *path_end = (char_u *)path; while (*path_end != NUL) { - /* May ignore a wildcard that has a backslash before it; it will - * be removed by rem_backslash() or file_pat_to_reg_pat() below. */ - if (path_end >= path + wildoff && rem_backslash(path_end)) { + // May ignore a wildcard that has a backslash before it; it will + // be removed by rem_backslash() or file_pat_to_reg_pat() below. + if (path_end >= (char_u *)path + wildoff && rem_backslash((char *)path_end)) { *p++ = *path_end++; } else if (vim_ispathsep_nocolon(*path_end)) { if (e != NULL) { break; } s = p + 1; - } else if (path_end >= path + wildoff + } else if (path_end >= (char_u *)path + wildoff && (vim_strchr("*?[{~$", *path_end) != NULL -#ifndef WIN32 +#ifndef MSWIN || (!p_fic && (flags & EW_ICASE) && mb_isalpha(utf_ptr2char((char *)path_end))) #endif )) { @@ -661,10 +657,10 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, *e = NUL; // Now we have one wildcard component between "s" and "e". - /* Remove backslashes between "wildoff" and the start of the wildcard - * component. */ - for (p = buf + wildoff; p < s; ++p) { - if (rem_backslash(p)) { + // Remove backslashes between "wildoff" and the start of the wildcard + // component. + for (p = buf + wildoff; p < s; p++) { + if (rem_backslash((char *)p)) { STRMOVE(p, p + 1); e--; s--; @@ -672,7 +668,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, } // Check for "**" between "s" and "e". - for (p = s; p < e; ++p) { + for (p = s; p < e; p++) { if (p[0] == '*' && p[1] == '*') { starstar = true; } @@ -708,13 +704,13 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, return 0; } - /* If "**" is by itself, this is the first time we encounter it and more - * is following then find matches without any directory. */ + // If "**" is by itself, this is the first time we encounter it and more + // is following then find matches without any directory. if (!didstar && stardepth < 100 && starstar && e - s == 2 && *path_end == '/') { STRCPY(s, path_end + 1); stardepth++; - (void)do_path_expand(gap, buf, (size_t)(s - buf), flags, true); + (void)do_path_expand(gap, (char *)buf, (size_t)(s - buf), flags, true); stardepth--; } *s = NUL; @@ -723,27 +719,27 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, char *dirpath = (*buf == NUL ? "." : (char *)buf); if (os_file_is_readable(dirpath) && os_scandir(&dir, dirpath)) { // Find all matching entries. - char_u *name; + char *name; scandir_next_with_dots(NULL); // initialize - while (!got_int && (name = (char_u *)scandir_next_with_dots(&dir)) != NULL) { + while (!got_int && (name = (char *)scandir_next_with_dots(&dir)) != NULL) { if ((name[0] != '.' || starts_with_dot || ((flags & EW_DODOT) && name[1] != NUL && (name[1] != '.' || name[2] != NUL))) // -V557 - && ((regmatch.regprog != NULL && vim_regexec(®match, (char *)name, 0)) + && ((regmatch.regprog != NULL && vim_regexec(®match, name, 0)) || ((flags & EW_NOTWILD) - && FNAMENCMP(path + (s - buf), name, e - s) == 0))) { + && path_fnamencmp(path + (s - buf), name, (size_t)(e - s)) == 0))) { STRCPY(s, name); len = STRLEN(buf); if (starstar && stardepth < 100) { - /* For "**" in the pattern first go deeper in the tree to - * find matches. */ - STRCPY(buf + len, "/**"); + // For "**" in the pattern first go deeper in the tree to + // find matches. + STRCPY(buf + len, "/**"); // NOLINT STRCPY(buf + len + 3, path_end); stardepth++; - (void)do_path_expand(gap, buf, len + 1, flags, true); + (void)do_path_expand(gap, (char *)buf, len + 1, flags, true); stardepth--; } @@ -751,18 +747,19 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, if (path_has_exp_wildcard(path_end)) { // handle more wildcards // need to expand another component of the path // remove backslashes for the remaining components only - (void)do_path_expand(gap, buf, len + 1, flags, false); + (void)do_path_expand(gap, (char *)buf, len + 1, flags, false); } else { FileInfo file_info; // no more wildcards, check if there is a match // remove backslashes for the remaining components only if (*path_end != NUL) { - backslash_halve(buf + len + 1); + backslash_halve((char *)buf + len + 1); } // add existing file or symbolic link - if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info) - : os_path_exists(buf)) { + if ((flags & EW_ALLLINKS) + ? os_fileinfo_link((char *)buf, &file_info) + : os_path_exists((char *)buf)) { addfile(gap, buf, flags); } } @@ -784,10 +781,8 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, return matches; } -/* - * Moves "*psep" back to the previous path separator in "path". - * Returns FAIL is "*psep" ends up at the beginning of "path". - */ +// Moves "*psep" back to the previous path separator in "path". +// Returns FAIL is "*psep" ends up at the beginning of "path". static int find_previous_pathsep(char_u *path, char_u **psep) { // skip the current separator @@ -806,25 +801,23 @@ static int find_previous_pathsep(char_u *path, char_u **psep) return FAIL; } -/* - * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap". - * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]". - */ -static bool is_unique(char_u *maybe_unique, garray_T *gap, int i) +/// Returns true if "maybe_unique" is unique wrt other_paths in "gap". +/// "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]". +static bool is_unique(char *maybe_unique, garray_T *gap, int i) { - char_u **other_paths = (char_u **)gap->ga_data; + char **other_paths = gap->ga_data; for (int j = 0; j < gap->ga_len; j++) { if (j == i) { continue; // don't compare it with itself } - size_t candidate_len = STRLEN(maybe_unique); - size_t other_path_len = STRLEN(other_paths[j]); + size_t candidate_len = strlen(maybe_unique); + size_t other_path_len = strlen(other_paths[j]); if (other_path_len < candidate_len) { continue; // it's different when it's shorter } - char_u *rival = other_paths[j] + other_path_len - candidate_len; - if (FNAMECMP(maybe_unique, rival) == 0 + char *rival = other_paths[j] + other_path_len - candidate_len; + if (path_fnamecmp(maybe_unique, rival) == 0 && (rival == other_paths[j] || vim_ispathsep(*(rival - 1)))) { return false; // match } @@ -832,33 +825,31 @@ static bool is_unique(char_u *maybe_unique, garray_T *gap, int i) return true; // no match found } -/* - * Split the 'path' option into an array of strings in garray_T. Relative - * paths are expanded to their equivalent fullpath. This includes the "." - * (relative to current buffer directory) and empty path (relative to current - * directory) notations. - * - * TODO: handle upward search (;) and path limiter (**N) notations by - * expanding each into their equivalent path(s). - */ +// Split the 'path' option into an array of strings in garray_T. Relative +// paths are expanded to their equivalent fullpath. This includes the "." +// (relative to current buffer directory) and empty path (relative to current +// directory) notations. +// +// TODO(vim): handle upward search (;) and path limiter (**N) notations by +// expanding each into their equivalent path(s). static void expand_path_option(char_u *curdir, garray_T *gap) { - char_u *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; - char_u *buf = xmalloc(MAXPATHL); + char_u *path_option = *curbuf->b_p_path == NUL ? p_path : (char_u *)curbuf->b_p_path; + char *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { - copy_option_part((char **)&path_option, (char *)buf, MAXPATHL, " ,"); + copy_option_part((char **)&path_option, buf, MAXPATHL, " ,"); if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1]))) { - /* Relative to current buffer: - * "/path/file" + "." -> "/path/" - * "/path/file" + "./subdir" -> "/path/subdir" */ + // Relative to current buffer: + // "/path/file" + "." -> "/path/" + // "/path/file" + "./subdir" -> "/path/subdir" if (curbuf->b_ffname == NULL) { continue; } char_u *p = (char_u *)path_tail(curbuf->b_ffname); size_t len = (size_t)(p - (char_u *)curbuf->b_ffname); - if (len + STRLEN(buf) >= MAXPATHL) { + if (len + strlen(buf) >= MAXPATHL) { continue; } if (buf[1] == NUL) { @@ -867,37 +858,35 @@ static void expand_path_option(char_u *curdir, garray_T *gap) STRMOVE(buf + len, buf + 2); } memmove(buf, curbuf->b_ffname, len); - simplify_filename(buf); + simplify_filename((char_u *)buf); } else if (buf[0] == NUL) { STRCPY(buf, curdir); // relative to current directory - } else if (path_with_url((char *)buf)) { + } else if (path_with_url(buf)) { continue; // URL can't be used here - } else if (!path_is_absolute(buf)) { + } else if (!path_is_absolute((char_u *)buf)) { // Expand relative path to their full path equivalent size_t len = STRLEN(curdir); - if (len + STRLEN(buf) + 3 > MAXPATHL) { + if (len + strlen(buf) + 3 > MAXPATHL) { continue; } STRMOVE(buf + len + 1, buf); STRCPY(buf, curdir); buf[len] = (char_u)PATHSEP; - simplify_filename(buf); + simplify_filename((char_u *)buf); } - GA_APPEND(char_u *, gap, vim_strsave(buf)); + GA_APPEND(char *, gap, xstrdup(buf)); } xfree(buf); } -/* - * Returns a pointer to the file or directory name in "fname" that matches the - * longest path in "ga"p, or NULL if there is no match. For example: - * - * path: /foo/bar/baz - * fname: /foo/bar/baz/quux.txt - * returns: ^this - */ +// Returns a pointer to the file or directory name in "fname" that matches the +// longest path in "ga"p, or NULL if there is no match. For example: +// +// path: /foo/bar/baz +// fname: /foo/bar/baz/quux.txt +// returns: ^this static char_u *get_path_cutoff(char_u *fname, garray_T *gap) { int maxlen = 0; @@ -908,7 +897,7 @@ static char_u *get_path_cutoff(char_u *fname, garray_T *gap) int j = 0; while ((fname[j] == path_part[i][j] -#ifdef WIN32 +#ifdef MSWIN || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j])) #endif ) // NOLINT(whitespace/parens) @@ -931,19 +920,17 @@ static char_u *get_path_cutoff(char_u *fname, garray_T *gap) return cutoff; } -/* - * Sorts, removes duplicates and modifies all the fullpath names in "gap" so - * that they are unique with respect to each other while conserving the part - * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". - */ +// Sorts, removes duplicates and modifies all the fullpath names in "gap" so +// that they are unique with respect to each other while conserving the part +// that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". static void uniquefy_paths(garray_T *gap, char_u *pattern) { - char_u **fnames = (char_u **)gap->ga_data; + char **fnames = gap->ga_data; bool sort_again = false; regmatch_T regmatch; garray_T path_ga; - char_u **in_curdir = NULL; - char_u *short_name; + char **in_curdir = NULL; + char *short_name; ga_remove_duplicate_strings(gap); ga_init(&path_ga, (int)sizeof(char_u *), 1); @@ -952,11 +939,11 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) // regex matches anywhere in the path. FIXME: is this valid for all // possible patterns? size_t len = STRLEN(pattern); - char_u *file_pattern = xmalloc(len + 2); + char *file_pattern = xmalloc(len + 2); file_pattern[0] = '*'; file_pattern[1] = NUL; STRCAT(file_pattern, pattern); - char *pat = file_pat_to_reg_pat((char *)file_pattern, NULL, NULL, true); + char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true); xfree(file_pattern); if (pat == NULL) { return; @@ -969,28 +956,28 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) return; } - char_u *curdir = xmalloc(MAXPATHL); - os_dirname(curdir, MAXPATHL); - expand_path_option(curdir, &path_ga); + char *curdir = xmalloc(MAXPATHL); + os_dirname((char_u *)curdir, MAXPATHL); + expand_path_option((char_u *)curdir, &path_ga); in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char_u *)); for (int i = 0; i < gap->ga_len && !got_int; i++) { - char_u *path = fnames[i]; + char *path = fnames[i]; int is_in_curdir; - char_u *dir_end = (char_u *)gettail_dir((const char *)path); - char_u *pathsep_p; - char_u *path_cutoff; + char *dir_end = (char *)gettail_dir((const char *)path); + char *pathsep_p; + char *path_cutoff; len = STRLEN(path); - is_in_curdir = FNAMENCMP(curdir, path, dir_end - path) == 0 + is_in_curdir = path_fnamencmp(curdir, path, (size_t)(dir_end - path)) == 0 && curdir[dir_end - path] == NUL; if (is_in_curdir) { - in_curdir[i] = vim_strsave(path); + in_curdir[i] = xstrdup(path); } // Shorten the filename while maintaining its uniqueness - path_cutoff = get_path_cutoff(path, &path_ga); + path_cutoff = (char *)get_path_cutoff((char_u *)path, &path_ga); // Don't assume all files can be reached without path when search // pattern starts with **/, so only remove path_cutoff @@ -998,26 +985,26 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) if (pattern[0] == '*' && pattern[1] == '*' && vim_ispathsep_nocolon(pattern[2]) && path_cutoff != NULL - && vim_regexec(®match, (char *)path_cutoff, (colnr_T)0) + && vim_regexec(®match, path_cutoff, (colnr_T)0) && is_unique(path_cutoff, gap, i)) { sort_again = true; - memmove(path, path_cutoff, STRLEN(path_cutoff) + 1); + memmove(path, path_cutoff, strlen(path_cutoff) + 1); } else { // Here all files can be reached without path, so get shortest // unique path. We start at the end of the path. */ pathsep_p = path + len - 1; - while (find_previous_pathsep(path, &pathsep_p)) { - if (vim_regexec(®match, (char *)pathsep_p + 1, (colnr_T)0) + while (find_previous_pathsep((char_u *)path, (char_u **)&pathsep_p)) { + if (vim_regexec(®match, pathsep_p + 1, (colnr_T)0) && is_unique(pathsep_p + 1, gap, i) && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) { sort_again = true; - memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); + memmove(path, pathsep_p + 1, strlen(pathsep_p)); break; } } } - if (path_is_absolute(path)) { + if (path_is_absolute((char_u *)path)) { // Last resort: shorten relative to curdir if possible. // 'possible' means: // 1. It is under the current directory. @@ -1031,7 +1018,7 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) short_name = path_shorten_fname(path, curdir); if (short_name != NULL && short_name > path + 1) { STRCPY(path, "."); - add_pathsep((char *)path); + add_pathsep(path); STRMOVE(path + STRLEN(path), short_name); } } @@ -1040,15 +1027,15 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) // Shorten filenames in /in/current/directory/{filename} for (int i = 0; i < gap->ga_len && !got_int; i++) { - char_u *rel_path; - char_u *path = in_curdir[i]; + char *rel_path; + char *path = in_curdir[i]; if (path == NULL) { continue; } - /* If the {filename} is not unique, change it to ./{filename}. - * Else reduce it to {filename} */ + // If the {filename} is not unique, change it to ./{filename}. + // Else reduce it to {filename} short_name = path_shorten_fname(path, curdir); if (short_name == NULL) { short_name = path; @@ -1058,9 +1045,9 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) continue; } - rel_path = xmalloc(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2); + rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2); STRCPY(rel_path, "."); - add_pathsep((char *)rel_path); + add_pathsep(rel_path); STRCAT(rel_path, short_name); xfree(fnames[i]); @@ -1143,16 +1130,14 @@ static int expand_in_path(garray_T *const gap, char_u *const pattern, const int if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath((char *)paths, pattern, gap, glob_flags); + globpath((char *)paths, (char *)pattern, gap, glob_flags); xfree(paths); return gap->ga_len; } -/* - * Return TRUE if "p" contains what looks like an environment variable. - * Allowing for escaping. - */ +/// Return true if "p" contains what looks like an environment variable. +/// Allowing for escaping. static bool has_env_var(char_u *p) { for (; *p; MB_PTR_ADV(p)) { @@ -1167,7 +1152,7 @@ static bool has_env_var(char_u *p) #ifdef SPECIAL_WILDCHAR -// Return TRUE if "p" contains a special wildcard character, one that Vim +// Return true if "p" contains a special wildcard character, one that Vim // cannot expand, requires using a shell. static bool has_special_wildchar(char_u *p) { @@ -1221,26 +1206,23 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i int add_pat; bool did_expand_in_path = false; - /* - * expand_env() is called to expand things like "~user". If this fails, - * it calls ExpandOne(), which brings us back here. In this case, always - * call the machine specific expansion function, if possible. Otherwise, - * return FAIL. - */ - if (recursive) + // expand_env() is called to expand things like "~user". If this fails, + // it calls ExpandOne(), which brings us back here. In this case, always + // call the machine specific expansion function, if possible. Otherwise, + // return FAIL. + if (recursive) { #ifdef SPECIAL_WILDCHAR - { return os_expand_wildcards(num_pat, pat, num_file, file, flags); } + return os_expand_wildcards(num_pat, pat, num_file, file, flags); #else - { return FAIL; } + return FAIL; #endif + } #ifdef SPECIAL_WILDCHAR - /* - * If there are any special wildcard characters which we cannot handle - * here, call machine specific function for all the expansion. This - * avoids starting the shell for each argument separately. - * For `=expr` do use the internal function. - */ + // If there are any special wildcard characters which we cannot handle + // here, call machine specific function for all the expansion. This + // avoids starting the shell for each argument separately. + // For `=expr` do use the internal function. for (int i = 0; i < num_pat; i++) { if (has_special_wildchar((char_u *)pat[i]) && !(vim_backtick((char_u *)pat[i]) && pat[i][1] == '=')) { @@ -1251,9 +1233,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i recursive = true; - /* - * The matching file names are stored in a growarray. Init it empty. - */ + // The matching file names are stored in a growarray. Init it empty. ga_init(&ga, (int)sizeof(char_u *), 30); for (int i = 0; i < num_pat && !got_int; i++) { @@ -1261,7 +1241,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i p = (char_u *)pat[i]; if (vim_backtick(p)) { - add_pat = expand_backtick(&ga, p, flags); + add_pat = expand_backtick(&ga, (char *)p, flags); if (add_pat == -1) { recursive = false; FreeWild(ga.ga_len, ga.ga_data); @@ -1275,40 +1255,37 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i p = expand_env_save_opt(p, true); if (p == NULL) { p = (char_u *)pat[i]; - } + } else { #ifdef UNIX - /* - * On Unix, if expand_env() can't expand an environment - * variable, use the shell to do that. Discard previously - * found file names and start all over again. - */ - else if (has_env_var(p) || *p == '~') { - xfree(p); - ga_clear_strings(&ga); - i = os_expand_wildcards(num_pat, pat, num_file, file, - flags | EW_KEEPDOLLAR); - recursive = false; - return i; - } + // On Unix, if expand_env() can't expand an environment + // variable, use the shell to do that. Discard previously + // found file names and start all over again. + if (has_env_var(p) || *p == '~') { + xfree(p); + ga_clear_strings(&ga); + i = os_expand_wildcards(num_pat, pat, num_file, file, + flags | EW_KEEPDOLLAR); + recursive = false; + return i; + } #endif + } } - /* - * If there are wildcards: Expand file names and add each match to - * the list. If there is no match, and EW_NOTFOUND is given, add - * the pattern. - * If there are no wildcards: Add the file name if it exists or - * when EW_NOTFOUND is given. - */ - if (path_has_exp_wildcard(p)) { + // If there are wildcards or case-insensitive expansion is + // required: Expand file names and add each match to the list. If + // there is no match, and EW_NOTFOUND is given, add the pattern. + // Otherwise: Add the file name if it exists or when EW_NOTFOUND is + // given. + if (path_has_exp_wildcard(p) || (flags & EW_ICASE)) { if ((flags & EW_PATH) && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) || (p[1] == '.' && vim_ispathsep(p[2]))))) { - /* :find completion where 'path' is used. - * Recursiveness is OK here. */ + // :find completion where 'path' is used. + // Recursiveness is OK here. recursive = false; add_pat = expand_in_path(&ga, p, flags); recursive = true; @@ -1322,10 +1299,10 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND))) { - char_u *t = backslash_halve_save(p); + char_u *t = (char_u *)backslash_halve_save((char *)p); - /* When EW_NOTFOUND is used, always add files and dirs. Makes - * "vim c:/" work. */ + // When EW_NOTFOUND is used, always add files and dirs. Makes + // "vim c:/" work. if (flags & EW_NOTFOUND) { addfile(&ga, t, flags | EW_DIR | EW_FILE); } else { @@ -1365,9 +1342,7 @@ void FreeWild(int count, char **files) xfree(files); } -/* - * Return TRUE if we can expand this backtick thing here. - */ +/// Return true if we can expand this backtick thing here. static int vim_backtick(char_u *p) { return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'; @@ -1378,14 +1353,14 @@ static int vim_backtick(char_u *p) /// Returns number of file names found, -1 if an error is encountered. /// /// @param flags EW_* flags -static int expand_backtick(garray_T *gap, char_u *pat, int flags) +static int expand_backtick(garray_T *gap, char *pat, int flags) { char *p; char *buffer; int cnt = 0; // Create the command: lop off the backticks. - char *cmd = (char *)vim_strnsave(pat + 1, STRLEN(pat) - 2); + char *cmd = xstrnsave(pat + 1, strlen(pat) - 2); if (*cmd == '=') { // `={expr}`: Expand expression buffer = eval_to_string(cmd + 1, &p, true); @@ -1440,7 +1415,7 @@ void slash_adjust(char_u *p) if (*p == '`') { // don't replace backslash in backtick quoted strings - const size_t len = STRLEN(p); + const size_t len = strlen(p); if (len > 2 && *(p + len - 1) == '`') { return; } @@ -1473,7 +1448,7 @@ void addfile(garray_T *gap, char_u *f, int flags) if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS) ? !os_fileinfo_link((char *)f, &file_info) - : !os_path_exists(f))) { + : !os_path_exists((char *)f))) { return; } @@ -1484,7 +1459,7 @@ void addfile(garray_T *gap, char_u *f, int flags) } #endif - isdir = os_isdir(f); + isdir = os_isdir((char *)f); if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) { return; } @@ -1502,21 +1477,17 @@ void addfile(garray_T *gap, char_u *f, int flags) #ifdef BACKSLASH_IN_FILENAME slash_adjust(p); #endif - /* - * Append a slash or backslash after directory names if none is present. - */ + // Append a slash or backslash after directory names if none is present. if (isdir && (flags & EW_ADDSLASH)) { add_pathsep((char *)p); } GA_APPEND(char_u *, gap, p); } -/* - * Converts a file name into a canonical form. It simplifies a file name into - * its simplest form by stripping out unneeded components, if any. The - * resulting file name is simplified in place and will either be the same - * length as that supplied, or shorter. - */ +// Converts a file name into a canonical form. It simplifies a file name into +// its simplest form by stripping out unneeded components, if any. The +// resulting file name is simplified in place and will either be the same +// length as that supplied, or shorter. void simplify_filename(char_u *filename) { int components = 0; @@ -1540,8 +1511,8 @@ void simplify_filename(char_u *filename) start = p; // remember start after "c:/" or "/" or "///" do { - /* At this point "p" is pointing to the char following a single "/" - * or "p" is at the "start" of the (absolute or relative) path name. */ + // At this point "p" is pointing to the char following a single "/" + // or "p" is at the "start" of the (absolute or relative) path name. if (vim_ispathsep(*p)) { STRMOVE(p, p + 1); // remove duplicate "/" } else if (p[0] == '.' @@ -1549,10 +1520,10 @@ void simplify_filename(char_u *filename) if (p == start && relative) { p += 1 + (p[1] != NUL); // keep single "." or leading "./" } else { - /* Strip "./" or ".///". If we are at the end of the file name - * and there is no trailing path separator, either strip "/." if - * we are after "start", or strip "." if we are at the beginning - * of an absolute path name . */ + // Strip "./" or ".///". If we are at the end of the file name + // and there is no trailing path separator, either strip "/." if + // we are after "start", or strip "." if we are at the beginning + // of an absolute path name. tail = p + 1; if (p[1] != NUL) { while (vim_ispathsep(*tail)) { @@ -1577,9 +1548,9 @@ void simplify_filename(char_u *filename) // Don't strip for an erroneous file name. if (!stripping_disabled) { - /* If the preceding component does not exist in the file - * system, we strip it. On Unix, we don't accept a symbolic - * link that refers to a non-existent file. */ + // If the preceding component does not exist in the file + // system, we strip it. On Unix, we don't accept a symbolic + // link that refers to a non-existent file. saved_char = p[-1]; p[-1] = NUL; FileInfo file_info; @@ -1595,16 +1566,16 @@ void simplify_filename(char_u *filename) } if (!do_strip) { - /* If the component exists in the file system, check - * that stripping it won't change the meaning of the - * file name. First get information about the - * unstripped file name. This may fail if the component - * to strip is not a searchable directory (but a regular - * file, for instance), since the trailing "/.." cannot - * be applied then. We don't strip it then since we - * don't want to replace an erroneous file name by - * a valid one, and we disable stripping of later - * components. */ + // If the component exists in the file system, check + // that stripping it won't change the meaning of the + // file name. First get information about the + // unstripped file name. This may fail if the component + // to strip is not a searchable directory (but a regular + // file, for instance), since the trailing "/.." cannot + // be applied then. We don't strip it then since we + // don't want to replace an erroneous file name by + // a valid one, and we disable stripping of later + // components. saved_char = *tail; *tail = NUL; if (os_fileinfo((char *)filename, &file_info)) { @@ -1614,13 +1585,13 @@ void simplify_filename(char_u *filename) } *tail = saved_char; if (do_strip) { - /* The check for the unstripped file name - * above works also for a symbolic link pointing to - * a searchable directory. But then the parent of - * the directory pointed to by the link must be the - * same as the stripped file name. (The latter - * exists in the file system since it is the - * component's parent directory.) */ + // The check for the unstripped file name + // above works also for a symbolic link pointing to + // a searchable directory. But then the parent of + // the directory pointed to by the link must be the + // same as the stripped file name. (The latter + // exists in the file system since it is the + // component's parent directory.) FileInfo new_file_info; if (p == start && relative) { os_fileinfo(".", &new_file_info); @@ -1633,26 +1604,26 @@ void simplify_filename(char_u *filename) if (!os_fileinfo_id_equal(&file_info, &new_file_info)) { do_strip = false; - /* We don't disable stripping of later - * components since the unstripped path name is - * still valid. */ + // We don't disable stripping of later + // components since the unstripped path name is + // still valid. } } } } if (!do_strip) { - /* Skip the ".." or "../" and reset the counter for the - * components that might be stripped later on. */ + // Skip the ".." or "../" and reset the counter for the + // components that might be stripped later on. p = tail; components = 0; } else { - /* Strip previous component. If the result would get empty - * and there is no trailing path separator, leave a single - * "." instead. If we are at the end of the file name and - * there is no trailing path separator and a preceding - * component is left after stripping, strip its trailing - * path separator as well. */ + // Strip previous component. If the result would get empty + // and there is no trailing path separator, leave a single + // "." instead. If we are at the end of the file name and + // there is no trailing path separator and a preceding + // component is left after stripping, strip its trailing + // path separator as well. if (p == start && relative && tail[-1] == '.') { *p++ = '.'; *p = NUL; @@ -1684,7 +1655,7 @@ void simplify_filename(char_u *filename) static char *eval_includeexpr(const char *const ptr, const size_t len) { set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - char *res = eval_to_string_safe((char *)curbuf->b_p_inex, NULL, + char *res = eval_to_string_safe(curbuf->b_p_inex, NULL, was_set_insecurely(curwin, "includeexpr", OPT_LOCAL)); set_vim_var_string(VV_FNAME, NULL, 0); return res; @@ -1694,56 +1665,55 @@ static char *eval_includeexpr(const char *const ptr, const size_t len) /// Otherwise like file_name_at_cursor(). /// /// @param rel_fname file we are searching relative to -char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, char_u *rel_fname) +char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname) { - char_u *file_name; - char_u *tofree = NULL; + char *file_name; + char *tofree = NULL; if (len == 0) { return NULL; } if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { - tofree = (char_u *)eval_includeexpr((char *)ptr, len); + tofree = eval_includeexpr(ptr, len); if (tofree != NULL) { ptr = tofree; - len = STRLEN(ptr); + len = strlen(ptr); } } if (options & FNAME_EXP) { - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, true, - rel_fname); + file_name = (char *)find_file_in_path((char_u *)ptr, len, options & ~FNAME_MESS, true, + (char_u *)rel_fname); - /* - * If the file could not be found in a normal way, try applying - * 'includeexpr' (unless done already). - */ + // If the file could not be found in a normal way, try applying + // 'includeexpr' (unless done already). if (file_name == NULL && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { - tofree = (char_u *)eval_includeexpr((char *)ptr, len); + tofree = eval_includeexpr(ptr, len); if (tofree != NULL) { ptr = tofree; - len = STRLEN(ptr); - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - TRUE, rel_fname); + len = strlen(ptr); + file_name = (char *)find_file_in_path((char_u *)ptr, len, options & ~FNAME_MESS, + true, (char_u *)rel_fname); } } if (file_name == NULL && (options & FNAME_MESS)) { - char_u c = ptr[len]; + char c = ptr[len]; ptr[len] = NUL; semsg(_("E447: Can't find file \"%s\" in path"), ptr); ptr[len] = c; } - /* Repeat finding the file "count" times. This matters when it - * appears several times in the path. */ + // Repeat finding the file "count" times. This matters when it + // appears several times in the path. while (file_name != NULL && --count > 0) { xfree(file_name); - file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname); + file_name = + (char *)find_file_in_path((char_u *)ptr, len, options, false, (char_u *)rel_fname); } } else { - file_name = vim_strnsave(ptr, len); + file_name = xstrnsave(ptr, len); } xfree(tofree); @@ -1751,12 +1721,26 @@ char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, return file_name; } -// Check if the "://" of a URL is at the pointer, return URL_SLASH. +/// Checks for a Windows drive letter ("C:/") at the start of the path. +/// +/// @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter +bool path_has_drive_letter(const char *p) + FUNC_ATTR_NONNULL_ALL +{ + return strlen(p) >= 2 + && ASCII_ISALPHA(p[0]) + && (p[1] == ':' || p[1] == '|') + && (strlen(p) == 2 || ((p[2] == '/') | (p[2] == '\\') | (p[2] == '?') | (p[2] == '#'))); +} + +// Check if the ":/" of a URL is at the pointer, return URL_SLASH. // Also check for ":\\", which MS Internet Explorer accepts, return // URL_BACKSLASH. int path_is_url(const char *p) { - if (strncmp(p, "://", 3) == 0) { + // In the spec ':' is enough to recognize a scheme + // https://url.spec.whatwg.org/#scheme-state + if (strncmp(p, ":/", 2) == 0) { return URL_SLASH; } else if (strncmp(p, ":\\\\", 3) == 0) { return URL_BACKSLASH; @@ -1781,6 +1765,10 @@ int path_with_url(const char *fname) return 0; } + if (path_has_drive_letter(fname)) { + return 0; + } + // check body: alpha or dash for (p = fname + 1; (isalpha(*p) || (*p == '-')); p++) {} @@ -1789,7 +1777,7 @@ int path_with_url(const char *fname) return 0; } - // "://" or ":\\" must follow + // ":/" or ":\\" must follow return path_is_url(p); } @@ -1802,9 +1790,7 @@ bool path_with_extension(const char *path, const char *extension) return strcmp(last_dot + 1, extension) == 0; } -/* - * Return TRUE if "name" is a full (absolute) path name or URL. - */ +/// Return true if "name" is a full (absolute) path name or URL. bool vim_isAbsName(char_u *name) { return path_with_url((char *)name) != 0 || path_is_absolute(name); @@ -1830,7 +1816,7 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force) if (strlen(fname) > (len - 1)) { xstrlcpy(buf, fname, len); // truncate -#ifdef WIN32 +#ifdef MSWIN slash_adjust((char_u *)buf); #endif return FAIL; @@ -1841,11 +1827,11 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force) return OK; } - int rv = path_to_absolute((char_u *)fname, (char_u *)buf, len, force); + int rv = path_to_absolute(fname, buf, len, force); if (rv == FAIL) { xstrlcpy(buf, fname, len); // something failed; use the filename } -#ifdef WIN32 +#ifdef MSWIN slash_adjust((char_u *)buf); #endif return rv; @@ -1900,7 +1886,7 @@ void path_fix_case(char *name) } // Open the directory where the file is located. - char *slash = (char *)STRRCHR(name, '/'); + char *slash = strrchr(name, '/'); char *tail; Directory dir; bool ok; @@ -1922,7 +1908,7 @@ void path_fix_case(char *name) while ((entry = (char *)os_scandir_next(&dir))) { // Only accept names that differ in case and are the same byte // length. TODO: accept different length name. - if (STRICMP(tail, entry) == 0 && STRLEN(tail) == STRLEN(entry)) { + if (STRICMP(tail, entry) == 0 && strlen(tail) == strlen(entry)) { char_u newname[MAXPATHL + 1]; // Verify the inode is equal. @@ -1941,21 +1927,17 @@ void path_fix_case(char *name) os_closedir(&dir); } -/* - * Return TRUE if "p" points to just after a path separator. - * Takes care of multi-byte characters. - * "b" must point to the start of the file name - */ +/// Return true if "p" points to just after a path separator. +/// Takes care of multi-byte characters. +/// "b" must point to the start of the file name int after_pathsep(const char *b, const char *p) { return p > b && vim_ispathsep(p[-1]) - && utf_head_off((char_u *)b, (char_u *)p - 1) == 0; + && utf_head_off(b, p - 1) == 0; } -/* - * Return TRUE if file names "f1" and "f2" are in the same directory. - * "f1" may be a short name, "f2" must be a full path. - */ +/// Return true if file names "f1" and "f2" are in the same directory. +/// "f1" may be a short name, "f2" must be a full path. bool same_directory(char_u *f1, char_u *f2) { char ffname[MAXPATHL]; @@ -1967,18 +1949,16 @@ bool same_directory(char_u *f1, char_u *f2) return false; } - (void)vim_FullName((char *)f1, (char *)ffname, MAXPATHL, FALSE); + (void)vim_FullName((char *)f1, (char *)ffname, MAXPATHL, false); t1 = path_tail_with_sep(ffname); t2 = path_tail_with_sep((char *)f2); return t1 - ffname == (char_u *)t2 - f2 && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0; } -/* - * Compare path "p[]" to "q[]". - * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" - * Return value like strcmp(p, q), but consider path separators. - */ +// Compare path "p[]" to "q[]". +// If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" +// Return value like strcmp(p, q), but consider path separators. int pathcmp(const char *p, const char *q, int maxlen) { int i, j; @@ -2063,7 +2043,7 @@ char_u *path_try_shorten_fname(char_u *full_path) char_u *p = full_path; if (os_dirname(dirname, MAXPATHL) == OK) { - p = path_shorten_fname(full_path, dirname); + p = (char_u *)path_shorten_fname((char *)full_path, (char *)dirname); if (p == NULL || *p == NUL) { p = full_path; } @@ -2079,27 +2059,27 @@ char_u *path_try_shorten_fname(char_u *full_path) /// @return /// - Pointer into `full_path` if shortened. /// - NULL if no shorter name is possible. -char_u *path_shorten_fname(char_u *full_path, char_u *dir_name) +char *path_shorten_fname(char *full_path, char *dir_name) { if (full_path == NULL) { return NULL; } assert(dir_name != NULL); - size_t len = STRLEN(dir_name); + size_t len = strlen(dir_name); // If dir_name is a path head, full_path can always be made relative. - if (len == (size_t)path_head_length() && is_path_head(dir_name)) { + if (len == (size_t)path_head_length() && is_path_head((char_u *)dir_name)) { return full_path + len; } // If full_path and dir_name do not match, it's impossible to make one // relative to the other. - if (FNAMENCMP(dir_name, full_path, len) != 0) { + if (path_fnamencmp(dir_name, full_path, len) != 0) { return NULL; } - char_u *p = full_path + len; + char_u *p = (char_u *)full_path + len; // If *p is not pointing to a path separator, this means that full_path's // last directory name is longer than *dir_name's last directory, so they @@ -2108,7 +2088,7 @@ char_u *path_shorten_fname(char_u *full_path, char_u *dir_name) return NULL; } - return p + 1; + return (char *)p + 1; } /// Invoke expand_wildcards() for one pattern @@ -2125,20 +2105,25 @@ 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 ***file, int flags) +int expand_wildcards_eval(char **pat, int *num_file, char ***file, int flags) { int ret = FAIL; - char_u *eval_pat = NULL; - char *exp_pat = (char *)(*pat); + char *eval_pat = NULL; + char *exp_pat = *pat; char *ignored_msg; size_t usedlen; + const bool is_cur_alt_file = *exp_pat == '%' || *exp_pat == '#'; + bool star_follows = false; - if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') { + if (is_cur_alt_file || *exp_pat == '<') { emsg_off++; - eval_pat = eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, NULL); + eval_pat = (char *)eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, + NULL, + true); emsg_off--; if (eval_pat != NULL) { - exp_pat = (char *)concat_str(eval_pat, (char_u *)exp_pat + usedlen); + star_follows = strcmp(exp_pat + usedlen, "*") == 0; + exp_pat = concat_str(eval_pat, exp_pat + usedlen); } } @@ -2147,6 +2132,16 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char ***file, int flags) } if (eval_pat != NULL) { + if (*num_file == 0 && is_cur_alt_file && star_follows) { + // Expanding "%" or "#" and the file does not exist: Add the + // pattern anyway (without the star) so that this works for remote + // files and non-file buffer names. + *file = xmalloc(sizeof(char *)); + **file = eval_pat; + eval_pat = NULL; + *num_file = 1; + ret = OK; + } xfree(exp_pat); xfree(eval_pat); } @@ -2182,9 +2177,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int return retval; } - /* - * Remove names that match 'wildignore'. - */ + // Remove names that match 'wildignore'. if (*p_wig) { char_u *ffname; @@ -2194,7 +2187,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int ffname = (char_u *)FullName_save((*files)[i], false); assert((*files)[i] != NULL); assert(ffname != NULL); - if (match_file_list(p_wig, (char_u *)(*files)[i], ffname)) { + if (match_file_list((char_u *)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,7 +2206,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int if (*num_files > 1 && !got_int) { non_suf_match = 0; for (i = 0; i < *num_files; i++) { - if (!match_suffix((char_u *)(*files)[i])) { + if (!match_suffix((*files)[i])) { // Move the name without matching suffix to the front of the list. p = (char_u *)(*files)[i]; for (j = i; j > non_suf_match; j--) { @@ -2233,29 +2226,27 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int return retval; } -/* - * Return TRUE if "fname" matches with an entry in 'suffixes'. - */ -int match_suffix(char_u *fname) +/// @return true if "fname" matches with an entry in 'suffixes'. +int match_suffix(char *fname) { #define MAXSUFLEN 30 // maximum length of a file suffix - char_u suf_buf[MAXSUFLEN]; + char suf_buf[MAXSUFLEN]; - size_t fnamelen = STRLEN(fname); + size_t fnamelen = strlen(fname); size_t setsuflen = 0; for (char_u *setsuf = p_su; *setsuf;) { setsuflen = copy_option_part((char **)&setsuf, (char *)suf_buf, MAXSUFLEN, ".,"); if (setsuflen == 0) { - char_u *tail = (char_u *)path_tail((char *)fname); + char *tail = path_tail(fname); // empty entry: match name without a '.' - if (vim_strchr((char *)tail, '.') == NULL) { + if (vim_strchr(tail, '.') == NULL) { setsuflen = 1; break; } } else { if (fnamelen >= setsuflen - && FNAMENCMP(suf_buf, fname + fnamelen - setsuflen, setsuflen) == 0) { + && path_fnamencmp(suf_buf, fname + fnamelen - setsuflen, setsuflen) == 0) { break; } setsuflen = 0; @@ -2273,7 +2264,7 @@ int path_full_dir_name(char *directory, char *buffer, size_t len) int SUCCESS = 0; int retval = OK; - if (STRLEN(directory) == 0) { + if (strlen(directory) == 0) { return os_dirname((char_u *)buffer, len); } @@ -2354,20 +2345,20 @@ int append_path(char *path, const char *to_append, size_t max_len) /// @param force also expand when "fname" is already absolute. /// /// @return FAIL for failure, OK for success. -static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int force) +static int path_to_absolute(const char *fname, char *buf, size_t len, int force) { - char_u *p; + char *p; *buf = NUL; char *relative_directory = xmalloc(len); char *end_of_path = (char *)fname; // expand it if forced or not an absolute path - if (force || !path_is_absolute(fname)) { - p = STRRCHR(fname, '/'); -#ifdef WIN32 + if (force || !path_is_absolute((char_u *)fname)) { + p = strrchr(fname, '/'); +#ifdef MSWIN if (p == NULL) { - p = STRRCHR(fname, '\\'); + p = strrchr(fname, '\\'); } #endif if (p != NULL) { @@ -2381,27 +2372,27 @@ static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int fo memcpy(relative_directory, fname, (size_t)(p - fname)); relative_directory[p - fname] = NUL; } - end_of_path = (char *)(p + 1); + end_of_path = p + 1; } else { relative_directory[0] = NUL; end_of_path = (char *)fname; } - if (FAIL == path_full_dir_name(relative_directory, (char *)buf, len)) { + if (FAIL == path_full_dir_name(relative_directory, buf, len)) { xfree(relative_directory); return FAIL; } } xfree(relative_directory); - return append_path((char *)buf, end_of_path, len); + return append_path(buf, end_of_path, len); } /// Check if file `fname` is a full (absolute) path. /// -/// @return `TRUE` if "fname" is absolute. +/// @return `true` if "fname" is absolute. int path_is_absolute(const char_u *fname) { -#ifdef WIN32 +#ifdef MSWIN if (*fname == NUL) { return false; } @@ -2449,8 +2440,8 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize) continue; } STRLCPY(NameBuff, dir, dir_len + 1); - STRLCAT(NameBuff, PATHSEPSTR, sizeof(NameBuff)); - STRLCAT(NameBuff, argv0, sizeof(NameBuff)); + xstrlcat(NameBuff, PATHSEPSTR, sizeof(NameBuff)); + xstrlcat(NameBuff, argv0, sizeof(NameBuff)); if (os_can_exe((char *)NameBuff, NULL, false)) { xstrlcpy(buf, (char *)NameBuff, bufsize); return; diff --git a/src/nvim/path.h b/src/nvim/path.h index 1006ef9ffb..37a0883c7f 100644 --- a/src/nvim/path.h +++ b/src/nvim/path.h @@ -18,8 +18,8 @@ #define EW_NOERROR 0x200 // no error for bad regexp #define EW_NOTWILD 0x400 // add match with literal name if exists #define EW_KEEPDOLLAR 0x800 // do not escape $, $var is expanded -/* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND -* is used when executing commands and EW_SILENT for interactive expanding. */ +// Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND +// is used when executing commands and EW_SILENT for interactive expanding. #define EW_ALLLINKS 0x1000 // also links not pointing to existing file #define EW_SHELLCMD 0x2000 // called from expand_shellcmd(), don't check // if executable is in $PATH diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 70bdbd8b1d..cbde0cfff9 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -98,7 +98,7 @@ int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight) /// "wp". Does not care about folding, 'wrap' or 'diff'. int plines_win_nofold(win_T *wp, linenr_T lnum) { - char_u *s; + char *s; unsigned int col; int width; @@ -106,7 +106,7 @@ int plines_win_nofold(win_T *wp, linenr_T lnum) if (*s == NUL) { // empty line return 1; } - col = win_linetabsize(wp, s, MAXCOL); + col = win_linetabsize(wp, lnum, (char_u *)s, MAXCOL); // If list mode is on, then the '$' at the end of the line may take up one // extra column. @@ -144,24 +144,28 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column) return lines + 1; } - char_u *line = ml_get_buf(wp->w_buffer, lnum, false); - char_u *s = line; + char_u *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); colnr_T col = 0; - while (*s != NUL && --column >= 0) { - col += win_lbr_chartabsize(wp, line, s, col, NULL); - MB_PTR_ADV(s); + chartabsize_T cts; + + init_chartabsize_arg(&cts, wp, lnum, 0, (char *)line, (char *)line); + while (*cts.cts_ptr != NUL && --column >= 0) { + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); + MB_PTR_ADV(cts.cts_ptr); } - // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in - // MODE_INSERT state, then col must be adjusted so that it represents the + // If *cts.cts_ptr is a TAB, and the TAB is not displayed as ^I, and we're not + // in MODE_INSERT state, then col must be adjusted so that it represents the // last screen position of the TAB. This only fixes an error when the TAB // wraps from one screen line to the next (when 'columns' is not a multiple // of 'ts') -- webb. - if (*s == TAB && (State & MODE_NORMAL) + col = cts.cts_vcol; + if (*cts.cts_ptr == TAB && (State & MODE_NORMAL) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { - col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1; + col += win_lbr_chartabsize(&cts, NULL) - 1; } + clear_chartabsize_arg(&cts); // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. int width = wp->w_width_inner - win_col_off(wp); @@ -223,13 +227,13 @@ int plines_m_win(win_T *wp, linenr_T first, linenr_T last) /// @param col /// /// @return Number of characters. -int win_chartabsize(win_T *wp, char_u *p, colnr_T col) +int win_chartabsize(win_T *wp, char *p, colnr_T col) { buf_T *buf = wp->w_buffer; if (*p == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { return tabstop_padding(col, buf->b_p_ts, buf->b_p_vts_array); } else { - return ptr2cells((char *)p); + return ptr2cells(p); } } @@ -241,24 +245,24 @@ int win_chartabsize(win_T *wp, char_u *p, colnr_T col) /// @return Number of characters the string will take on the screen. int linetabsize(char_u *s) { - return linetabsize_col(0, s); + return linetabsize_col(0, (char *)s); } -/// Like linetabsize(), but starting at column "startcol". +/// Like linetabsize(), but "s" starts at column "startcol". /// /// @param startcol /// @param s /// /// @return Number of characters the string will take on the screen. -int linetabsize_col(int startcol, char_u *s) +int linetabsize_col(int startcol, char *s) { - colnr_T col = startcol; - char_u *line = s; // pointer to start of line, for breakindent - - while (*s != NUL) { - col += lbr_chartabsize_adv(line, &s, col); + chartabsize_T cts; + init_chartabsize_arg(&cts, curwin, 0, startcol, s, s); + while (*cts.cts_ptr != NUL) { + cts.cts_vcol += lbr_chartabsize_adv(&cts); } - return (int)col; + clear_chartabsize_arg(&cts); + return cts.cts_vcol; } /// Like linetabsize(), but for a given window instead of the current one. @@ -268,19 +272,38 @@ int linetabsize_col(int startcol, char_u *s) /// @param len /// /// @return Number of characters the string will take on the screen. -unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) +unsigned int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) { - colnr_T col = 0; - - for (char_u *s = line; - *s != NUL && (len == MAXCOL || s < line + len); - MB_PTR_ADV(s)) { - col += win_lbr_chartabsize(wp, line, s, col, NULL); + chartabsize_T cts; + init_chartabsize_arg(&cts, wp, lnum, 0, (char *)line, (char *)line); + for (; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < (char *)line + len); + MB_PTR_ADV(cts.cts_ptr)) { + cts.cts_vcol += win_lbr_chartabsize(&cts, NULL); } + clear_chartabsize_arg(&cts); + return (unsigned int)cts.cts_vcol; +} - return (unsigned int)col; +/// Prepare the structure passed to chartabsize functions. +/// +/// "line" is the start of the line, "ptr" is the first relevant character. +/// When "lnum" is zero do not use text properties that insert text. +void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum FUNC_ATTR_UNUSED, + colnr_T col, char *line, char *ptr) +{ + cts->cts_win = wp; + cts->cts_vcol = col; + cts->cts_line = line; + cts->cts_ptr = ptr; + cts->cts_cur_text_width = 0; + // TODO(bfredl): actually lookup inline virtual text here + cts->cts_has_virt_text = false; } +/// Free any allocated item in "cts". +void clear_chartabsize_arg(chartabsize_T *cts) +{} + /// like win_chartabsize(), but also check for line breaks on the screen /// /// @param line @@ -288,16 +311,16 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) /// @param col /// /// @return The number of characters taken up on the screen. -int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col) +int lbr_chartabsize(chartabsize_T *cts) { if (!curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL - && !curwin->w_p_bri) { + && !curwin->w_p_bri && !cts->cts_has_virt_text) { if (curwin->w_p_wrap) { - return win_nolbr_chartabsize(curwin, s, col, NULL); + return win_nolbr_chartabsize(cts, NULL); } - return win_chartabsize(curwin, s, col); + return win_chartabsize(curwin, cts->cts_ptr, cts->cts_vcol); } - return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL); + return win_lbr_chartabsize(cts, NULL); } /// Call lbr_chartabsize() and advance the pointer. @@ -307,12 +330,12 @@ int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col) /// @param col /// /// @return The number of characters take up on the screen. -int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col) +int lbr_chartabsize_adv(chartabsize_T *cts) { int retval; - retval = lbr_chartabsize(line, *s, col); - MB_PTR_ADV(*s); + retval = lbr_chartabsize(cts); + MB_PTR_ADV(cts->cts_ptr); return retval; } @@ -322,17 +345,19 @@ int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col) /// string at start of line. Warning: *headp is only set if it's a non-zero /// value, init to 0 before calling. /// -/// @param wp -/// @param line -/// @param s -/// @param col +/// @param cts /// @param headp /// /// @return The number of characters taken up on the screen. -int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp) +int win_lbr_chartabsize(chartabsize_T *cts, int *headp) { + win_T *wp = cts->cts_win; + char *line = cts->cts_line; // start of the line + char_u *s = (char_u *)cts->cts_ptr; + colnr_T vcol = cts->cts_vcol; + colnr_T col2; - colnr_T col_adj = 0; // col + screen size of tab + colnr_T col_adj = 0; // vcol + screen size of tab colnr_T colmax; int added; int mb_added = 0; @@ -340,16 +365,23 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he char_u *ps; int n; + cts->cts_cur_text_width = 0; + // No 'linebreak', 'showbreak' and 'breakindent': return quickly. - if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL) { + if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL + && !cts->cts_has_virt_text) { if (wp->w_p_wrap) { - return win_nolbr_chartabsize(wp, s, col, headp); + return win_nolbr_chartabsize(cts, headp); } - return win_chartabsize(wp, s, col); + return win_chartabsize(wp, (char *)s, vcol); + } + + // First get normal size, without 'linebreak' or virtual text + int size = win_chartabsize(wp, (char *)s, vcol); + if (cts->cts_has_virt_text) { + // TODO(bfredl): inline virtual text } - // First get normal size, without 'linebreak' - int size = win_chartabsize(wp, s, col); int c = *s; if (*s == TAB) { col_adj = size - 1; @@ -365,15 +397,15 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he // Count all characters from first non-blank after a blank up to next // non-blank after a blank. numberextra = win_col_off(wp); - col2 = col; + col2 = vcol; colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); - if (col >= colmax) { + if (vcol >= colmax) { colmax += col_adj; n = colmax + win_col_off2(wp); if (n > 0) { - colmax += (((col - colmax) / n) + 1) * n - col_adj; + colmax += (((vcol - colmax) / n) + 1) * n - col_adj; } } @@ -383,21 +415,21 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he c = *s; if (!(c != NUL - && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) { + && (vim_isbreak(c) || col2 == vcol || !vim_isbreak((int)(*ps))))) { break; } - col2 += win_chartabsize(wp, s, col2); + col2 += win_chartabsize(wp, (char *)s, col2); if (col2 >= colmax) { // doesn't fit - size = colmax - col + col_adj; + size = colmax - vcol + col_adj; break; } } } else if ((size == 2) && (MB_BYTE2LEN(*s) > 1) && wp->w_p_wrap - && in_win_border(wp, col)) { + && in_win_border(wp, vcol)) { // Count the ">" in the last column. size++; mb_added = 1; @@ -409,40 +441,40 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he added = 0; char *const sbr = (char *)get_showbreak_value(wp); - if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0) { + if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { colnr_T sbrlen = 0; int numberwidth = win_col_off(wp); numberextra = numberwidth; - col += numberextra + mb_added; + vcol += numberextra + mb_added; - if (col >= (colnr_T)wp->w_width_inner) { - col -= wp->w_width_inner; + if (vcol >= (colnr_T)wp->w_width_inner) { + vcol -= wp->w_width_inner; numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp)); - if (col >= numberextra && numberextra > 0) { - col %= numberextra; + if (vcol >= numberextra && numberextra > 0) { + vcol %= numberextra; } if (*sbr != NUL) { sbrlen = (colnr_T)mb_charlen((char_u *)sbr); - if (col >= sbrlen) { - col -= sbrlen; + if (vcol >= sbrlen) { + vcol -= sbrlen; } } - if (col >= numberextra && numberextra > 0) { - col %= numberextra; - } else if (col > 0 && numberextra > 0) { - col += numberwidth - win_col_off2(wp); + if (vcol >= numberextra && numberextra > 0) { + vcol %= numberextra; + } else if (vcol > 0 && numberextra > 0) { + vcol += numberwidth - win_col_off2(wp); } numberwidth -= win_col_off2(wp); } - if (col == 0 || (col + size + sbrlen > (colnr_T)wp->w_width_inner)) { + if (vcol == 0 || (vcol + size + sbrlen > (colnr_T)wp->w_width_inner)) { if (*sbr != NUL) { if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) { // Calculate effective window width. int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth; - int prev_width = col ? ((colnr_T)wp->w_width_inner - (sbrlen + col)) + int prev_width = vcol ? ((colnr_T)wp->w_width_inner - (sbrlen + vcol)) : 0; if (width <= 0) { @@ -459,11 +491,11 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he } if (wp->w_p_bri) { - added += get_breakindent_win(wp, line); + added += get_breakindent_win(wp, (char_u *)line); } size += added; - if (col != 0) { + if (vcol != 0) { added = 0; } } @@ -485,8 +517,11 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he /// @param headp /// /// @return The number of characters take up on the screen. -static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) +static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp) { + win_T *wp = cts->cts_win; + char *s = cts->cts_ptr; + colnr_T col = cts->cts_vcol; int n; if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { @@ -494,11 +529,11 @@ static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) wp->w_buffer->b_p_ts, wp->w_buffer->b_p_vts_array); } - n = ptr2cells((char *)s); + n = ptr2cells(s); // Add one cell for a double-width character in the last column of the // window, displayed with a ">". - if ((n == 2) && (MB_BYTE2LEN(*s) > 1) && in_win_border(wp, col)) { + if ((n == 2) && (MB_BYTE2LEN((uint8_t)(*s)) > 1) && in_win_border(wp, col)) { if (headp != NULL) { *headp = 1; } diff --git a/src/nvim/plines.h b/src/nvim/plines.h index 32778b69f1..f463d82f10 100644 --- a/src/nvim/plines.h +++ b/src/nvim/plines.h @@ -3,6 +3,19 @@ #include "nvim/vim.h" +// Argument for lbr_chartabsize(). +typedef struct { + win_T *cts_win; + char *cts_line; // start of the line + char *cts_ptr; // current position in line + + bool cts_has_virt_text; // true if if a property inserts text + int cts_cur_text_width; // width of current inserted text + // TODO(bfredl): iterator in to the marktree for scanning virt text + + int cts_vcol; // virtual column at current position +} chartabsize_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "plines.h.generated.h" #endif diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 28f5723046..57896b74ce 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -37,7 +37,6 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) set(ENV{OLD_PO_FILE_INPUT} yes) set(ENV{OLD_PO_FILE_OUTPUT} yes) - set(NVIM_RELATIVE_SOURCES) foreach(SRC ${NVIM_SOURCES} ${NVIM_HEADERS}) file(RELATIVE_PATH RELATIVE_SRC ${CMAKE_CURRENT_SOURCE_DIR} ${SRC}) @@ -46,19 +45,14 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) set(NVIM_POT ${CMAKE_CURRENT_BINARY_DIR}/nvim.pot) + list(SORT NVIM_RELATIVE_SOURCES) add_custom_command( - OUTPUT nvim.pot - COMMAND ${CMAKE_COMMAND} - -DXGETTEXT_PRG=${XGETTEXT_PRG} - -DPOT_FILE=${NVIM_POT} - -DSEARCH_DIR=${CMAKE_CURRENT_SOURCE_DIR} - "\"-DSOURCES=${NVIM_RELATIVE_SOURCES}\"" - -P ${PROJECT_SOURCE_DIR}/cmake/RunXgettext.cmake + OUTPUT ${NVIM_POT} + COMMAND ${XGETTEXT_PRG} -o ${NVIM_POT} --default-domain=nvim + --add-comments --keyword=_ --keyword=N_ -D ${CMAKE_CURRENT_SOURCE_DIR} + ${NVIM_RELATIVE_SOURCES} DEPENDS ${NVIM_SOURCES}) - add_custom_target(potfile DEPENDS ${NVIM_POT}) - set_target_properties(potfile PROPERTIES FOLDER po) - set(LANGUAGE_MO_FILES) set(UPDATE_PO_TARGETS) @@ -68,11 +62,7 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) add_custom_command( OUTPUT ${moFile} - COMMAND ${CMAKE_COMMAND} - -DMSGFMT_PRG=${GETTEXT_MSGFMT_EXECUTABLE} - -DMO_FILE=${moFile} - -DPO_FILE=${poFile} - -P ${PROJECT_SOURCE_DIR}/cmake/RunMsgfmt.cmake + COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${moFile} ${poFile} DEPENDS ${poFile} ${NVIM_POT}) install_helper( @@ -101,8 +91,6 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) lang inputName outputName inputEnc outputEnc outputCharSet) set(inputFile ${CMAKE_CURRENT_SOURCE_DIR}/${inputName}.po) set(outputFile ${CMAKE_CURRENT_SOURCE_DIR}/${outputName}.po) - string(TOUPPER ${inputEnc} upperInputEnc) - string(TOLOWER ${inputEnc} lowerInputEnc) add_custom_target(update-po-${lang} COMMAND ${CMAKE_COMMAND} @@ -172,11 +160,8 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) set(poFile "${CMAKE_CURRENT_SOURCE_DIR}/${LANGUAGE}.po") add_custom_target(update-po-${LANGUAGE} - COMMAND ${CMAKE_COMMAND} - -DMSGMERGE_PRG=${GETTEXT_MSGMERGE_EXECUTABLE} - -DPO_FILE=${poFile} - -DPOT_FILE=${NVIM_POT} - -P ${PROJECT_SOURCE_DIR}/cmake/RunMsgmerge.cmake + COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} -q --update --backup=none --sort-by-file + ${poFile} ${NVIM_POT} COMMENT "Updating ${LANGUAGE}.po" DEPENDS ${NVIM_POT}) diff --git a/src/nvim/po/af.po b/src/nvim/po/af.po index 82345f8a46..d64789660e 100644 --- a/src/nvim/po/af.po +++ b/src/nvim/po/af.po @@ -5320,8 +5320,8 @@ msgstr "E424: Te veel verskillende uitlig-eienskappe in gebruik" msgid "E669: Unprintable character in group name" msgstr "E669: Onvertoonbare karakter in groepnaam" -msgid "W18: Invalid character in group name" -msgstr "W18: Ongeldige karakter groepnaam" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ongeldige karakter groepnaam" #~ msgid "E849: Too many highlight and syntax groups" #~ msgstr "" diff --git a/src/nvim/po/ca.po b/src/nvim/po/ca.po index 6c4d6ddd22..5869e6567c 100644 --- a/src/nvim/po/ca.po +++ b/src/nvim/po/ca.po @@ -5983,9 +5983,9 @@ msgstr "E424: Hi ha massa atributs de ressalt diferents en ús" msgid "E669: Unprintable character in group name" msgstr "E669: Caràcter no imprimible en el nom del grup" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Hi ha un caràcter no vàlid en el nom del grup" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Hi ha un caràcter no vàlid en el nom del grup" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/cs.cp1250.po b/src/nvim/po/cs.cp1250.po index 859039eb87..bce5c0fa76 100644 --- a/src/nvim/po/cs.cp1250.po +++ b/src/nvim/po/cs.cp1250.po @@ -6072,10 +6072,10 @@ msgstr "" msgid "E669: Unprintable character in group name" msgstr "" -#: ../syntax.c:7434 +#: ../highlight_group.c:1756 #, fuzzy -msgid "W18: Invalid character in group name" -msgstr "E182: Chybné jméno pøíkazu" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Chybné jméno pøíkazu" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/cs.po b/src/nvim/po/cs.po index 4d9ad58836..f4eab3f0d4 100644 --- a/src/nvim/po/cs.po +++ b/src/nvim/po/cs.po @@ -6072,10 +6072,10 @@ msgstr "" msgid "E669: Unprintable character in group name" msgstr "" -#: ../syntax.c:7434 +#: ../highlight_group.c:1756 #, fuzzy -msgid "W18: Invalid character in group name" -msgstr "E182: Chybné jméno pøíkazu" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Chybné jméno pøíkazu" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po index dfcc052288..1c3284f867 100644 --- a/src/nvim/po/da.po +++ b/src/nvim/po/da.po @@ -5599,8 +5599,8 @@ msgstr "E424: For mange forskellige fremhævningsattributter i brug" msgid "E669: Unprintable character in group name" msgstr "E669: Tegn som ikke kan udskrives i gruppenavn" -msgid "W18: Invalid character in group name" -msgstr "W18: Ugyldige tegn i gruppenavn" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ugyldige tegn i gruppenavn" msgid "E849: Too many highlight and syntax groups" msgstr "E849: For mange fremhævnings- og syntaksgrupper" diff --git a/src/nvim/po/de.po b/src/nvim/po/de.po index 2dde77e9f7..ce3fd77ede 100644 --- a/src/nvim/po/de.po +++ b/src/nvim/po/de.po @@ -5408,8 +5408,8 @@ msgid "E669: Unprintable character in group name" msgstr "E669: Nicht druckbare Zeichen im Namen der Gruppe" #: ../syntax.c:7304 -msgid "W18: Invalid character in group name" -msgstr "W18: Ungültiges Zeichen im Namen der Gruppe" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ungültiges Zeichen im Namen der Gruppe" #: ../syntax.c:7318 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/en_GB.po b/src/nvim/po/en_GB.po index 66cdba6f92..81ee9ed6a0 100644 --- a/src/nvim/po/en_GB.po +++ b/src/nvim/po/en_GB.po @@ -5730,8 +5730,8 @@ msgstr "" msgid "E669: Unprintable character in group name" msgstr "" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" msgstr "" #: ../syntax.c:7448 diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po index 1c503d0a84..263fb61b18 100644 --- a/src/nvim/po/eo.po +++ b/src/nvim/po/eo.po @@ -5378,8 +5378,8 @@ msgstr "E424: Tro da malsamaj atributoj de emfazo uzataj" msgid "E669: Unprintable character in group name" msgstr "E669: Nepresebla signo en nomo de grupo" -msgid "W18: Invalid character in group name" -msgstr "W18: Nevalida signo en nomo de grupo" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Nevalida signo en nomo de grupo" msgid "E849: Too many highlight and syntax groups" msgstr "E849: Tro da emfazaj kaj sintaksaj grupoj" diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po index adea651b7c..8a44f6a534 100644 --- a/src/nvim/po/es.po +++ b/src/nvim/po/es.po @@ -6053,9 +6053,9 @@ msgstr "E669: Carácter no imprimible en el nombre del grupo" # This is an error, but since there previously was no check only # * give a warning. -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Hay un carácter no válido en el nombre del grupo" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Hay un carácter no válido en el nombre del grupo" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/fi.po b/src/nvim/po/fi.po index f10d4ce977..1c0da244ba 100644 --- a/src/nvim/po/fi.po +++ b/src/nvim/po/fi.po @@ -5369,8 +5369,8 @@ msgstr "E424: Liikaa eri korostusattribuutteja" msgid "E669: Unprintable character in group name" msgstr "E669: Tulostuskelvoton merkki ryhmän nimessä" -msgid "W18: Invalid character in group name" -msgstr "W18: Virheellinen merkki ryhmän nimessä" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Virheellinen merkki ryhmän nimessä" msgid "E849: Too many highlight and syntax groups" msgstr "E849: Liikaa korostuksia ja syntaksiryhmiä" diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po index 614ba013e6..be2141cd6d 100644 --- a/src/nvim/po/fr.po +++ b/src/nvim/po/fr.po @@ -2040,8 +2040,8 @@ msgstr "" msgid "E669: Unprintable character in group name" msgstr "E669: Caractère non imprimable dans un nom de groupe" -msgid "W18: Invalid character in group name" -msgstr "W18: Caractère invalide dans un nom de groupe" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Caractère invalide dans un nom de groupe" msgid "E849: Too many highlight and syntax groups" msgstr "E849: Trop de groupes de surbrillance et de syntaxe" diff --git a/src/nvim/po/ga.po b/src/nvim/po/ga.po index 1c25ee481c..346f0faa84 100644 --- a/src/nvim/po/ga.po +++ b/src/nvim/po/ga.po @@ -5668,8 +5668,8 @@ msgstr "E424: An iomarca tréithe aibhsithe in úsáid" msgid "E669: Unprintable character in group name" msgstr "E669: Carachtar neamhghrafach in ainm grúpa" -msgid "W18: Invalid character in group name" -msgstr "W18: Carachtar neamhbhailí in ainm grúpa" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Carachtar neamhbhailí in ainm grúpa" msgid "E849: Too many highlight and syntax groups" msgstr "E849: An iomarca grúpaí aibhsithe agus comhréire" diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po index 313280c807..152ed2cbe3 100644 --- a/src/nvim/po/it.po +++ b/src/nvim/po/it.po @@ -6046,9 +6046,9 @@ msgstr "E424: Troppi gruppi evidenziazione differenti in uso" msgid "E669: Unprintable character in group name" msgstr "E669: Carattere non stampabile in un nome di gruppo" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Carattere non ammesso in un nome di gruppo" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Carattere non ammesso in un nome di gruppo" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/ko.UTF-8.po b/src/nvim/po/ko.UTF-8.po index b99c22caeb..09be710374 100644 --- a/src/nvim/po/ko.UTF-8.po +++ b/src/nvim/po/ko.UTF-8.po @@ -5913,9 +5913,9 @@ msgstr "E424: 너무 ë§Žì€ ë‹¤ë¥¸ 하ì´ë¼ì´íЏ ì†ì„±ì´ 사용ë˜ê³ 있습 msgid "E669: Unprintable character in group name" msgstr "E669: 그룹 ì´ë¦„ì— ì¶œë ¥í• ìˆ˜ 없는 문ìžê°€ 있습니다" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: 그룹 ì´ë¦„ì— ì´ìƒí•œ 문ìž" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: 그룹 ì´ë¦„ì— ì´ìƒí•œ 문ìž" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/nb.po b/src/nvim/po/nb.po index 2285d755cf..9bc730ae71 100644 --- a/src/nvim/po/nb.po +++ b/src/nvim/po/nb.po @@ -5930,9 +5930,9 @@ msgstr "E424: For mange forskjellige uthevingsattributter i bruk" msgid "E669: Unprintable character in group name" msgstr "E669: Ikke-skrivbart tegn i gruppenavn" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Ugyldig tegn i gruppenavn" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ugyldig tegn i gruppenavn" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/nl.po b/src/nvim/po/nl.po index 00d113c83c..4d2e55adc6 100644 --- a/src/nvim/po/nl.po +++ b/src/nvim/po/nl.po @@ -5913,8 +5913,8 @@ msgstr "" msgid "E669: Unprintable character in group name" msgstr "" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" msgstr "" #: ../syntax.c:7448 diff --git a/src/nvim/po/no.po b/src/nvim/po/no.po index 2285d755cf..9bc730ae71 100644 --- a/src/nvim/po/no.po +++ b/src/nvim/po/no.po @@ -5930,9 +5930,9 @@ msgstr "E424: For mange forskjellige uthevingsattributter i bruk" msgid "E669: Unprintable character in group name" msgstr "E669: Ikke-skrivbart tegn i gruppenavn" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Ugyldig tegn i gruppenavn" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ugyldig tegn i gruppenavn" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/pl.UTF-8.po b/src/nvim/po/pl.UTF-8.po index 5f1779d1bd..7e978113f6 100644 --- a/src/nvim/po/pl.UTF-8.po +++ b/src/nvim/po/pl.UTF-8.po @@ -5908,9 +5908,9 @@ msgstr "E424: Zbyt wiele różnych atrybutów podkreÅ›lania w użyciu" msgid "E669: Unprintable character in group name" msgstr "E669: Niedrukowalny znak w nazwie grupy" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: nieprawidÅ‚owy znak w nazwie grupy" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: nieprawidÅ‚owy znak w nazwie grupy" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/pt_BR.po b/src/nvim/po/pt_BR.po index 533d916de1..bfd64b4d28 100644 --- a/src/nvim/po/pt_BR.po +++ b/src/nvim/po/pt_BR.po @@ -6070,8 +6070,8 @@ msgid "E669: Unprintable character in group name" msgstr "E669: Caractere não-imprimível no nome do grupo" #: ../syntax.c:7320 -msgid "W18: Invalid character in group name" -msgstr "W18: Caractere inválido no nome do grupo" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Caractere inválido no nome do grupo" #: ../syntax.c:7334 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po index 7566036d3e..da356770d7 100644 --- a/src/nvim/po/ru.po +++ b/src/nvim/po/ru.po @@ -5977,9 +5977,9 @@ msgstr "E424: ИÑпользуетÑÑ Ñлишком много разных а msgid "E669: Unprintable character in group name" msgstr "E669: Ðепечатный Ñимвол в имени группы" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: ÐедопуÑтимый Ñимвол в имени группы" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: ÐедопуÑтимый Ñимвол в имени группы" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/sk.cp1250.po b/src/nvim/po/sk.cp1250.po index ff95c68a12..cb8b8c6abb 100644 --- a/src/nvim/po/sk.cp1250.po +++ b/src/nvim/po/sk.cp1250.po @@ -5940,9 +5940,9 @@ msgstr "E424: Používaných príliš ve¾a odlišných zvýrazòovacích vlastností" msgid "E669: Unprintable character in group name" msgstr "E669: Netlaèitelný znak v mene skupiny" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Chybný znak v mene skupiny" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Chybný znak v mene skupiny" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/sk.po b/src/nvim/po/sk.po index d35622726f..4f9e1fe185 100644 --- a/src/nvim/po/sk.po +++ b/src/nvim/po/sk.po @@ -5940,9 +5940,9 @@ msgstr "E424: Pou¾ívaných príli¹ veµa odli¹ných zvýrazòovacích vlastností" msgid "E669: Unprintable character in group name" msgstr "E669: Netlaèitelný znak v mene skupiny" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Chybný znak v mene skupiny" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Chybný znak v mene skupiny" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po index 3c45e1bf80..cbdf736d0f 100644 --- a/src/nvim/po/sr.po +++ b/src/nvim/po/sr.po @@ -6050,8 +6050,8 @@ msgstr "E424: У употреби је превише различитих Ð°Ñ‚Ñ msgid "E669: Unprintable character in group name" msgstr "E669: У имену групе је карактер који не може да Ñе штампа" -msgid "W18: Invalid character in group name" -msgstr "W18: Ðеважећи карактер у имену групе" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ðеважећи карактер у имену групе" msgid "E849: Too many highlight and syntax groups" msgstr "E849: Превише ÑинтакÑних и група иÑтицања" diff --git a/src/nvim/po/sv.po b/src/nvim/po/sv.po index d50c9d695d..406900f7b2 100644 --- a/src/nvim/po/sv.po +++ b/src/nvim/po/sv.po @@ -2056,8 +2056,8 @@ msgid "E669: Unprintable character in group name" msgstr "E669: Outskrivbart tecken i gruppnamn" #: ../syntax.c:7292 -msgid "W18: Invalid character in group name" -msgstr "W18: Ogiltigt tecken i gruppnamn" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ogiltigt tecken i gruppnamn" #: ../syntax.c:7306 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po index fae2fd4967..0cf91fa4d5 100644 --- a/src/nvim/po/tr.po +++ b/src/nvim/po/tr.po @@ -1,15 +1,15 @@ # 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. +# This file is distributed under the same license as the Nvim package. # Emir SARI <emir_sari@icloud.com>, 2019-2022 # msgid "" msgstr "" "Project-Id-Version: Neovim Turkish Localization Project\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-13 22:59+0300\n" -"PO-Revision-Date: 2022-07-20 05:00+0300\n" +"POT-Creation-Date: 2022-09-30 20:46+0300\n" +"PO-Revision-Date: 2022-07-22 23:00+0300\n" "Last-Translator: Emir SARI <emir_sari@icloud.com>\n" "Language-Team: Turkish <https://github.com/bitigchi/neovim>\n" "Language: tr\n" @@ -18,6 +18,21 @@ msgstr "" "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--" @@ -49,8 +64,9 @@ 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" -msgid "No matching autocommands" -msgstr "EÅŸleÅŸen otokomut yok" +#, c-format +msgid "No matching autocommands: %s" +msgstr "EÅŸleÅŸen otokomut yok: %s" msgid "E218: autocommand nesting too deep" msgstr "E218: Çok fazla iç içe geçmiÅŸ otokomut" @@ -79,24 +95,18 @@ msgstr "E216: Böyle bir olay yok: %s" msgid "E216: No such group or event: %s" msgstr "E216: Böyle bir grup veya olay yok: %s" -msgid "[Location List]" -msgstr "[Konum Listesi]" - -msgid "[Quickfix List]" -msgstr "[Hızlı Düzelt Listesi]" - msgid "E855: Autocommands caused command to abort" msgstr "E855: Otokomutlar komutun durmasına neden oldu" +msgid "E937: Attempt to delete a buffer that is in use" +msgstr "E937: Kullanımda olan bir arabellek silinmeye çalışılıyor" + msgid "E82: Cannot allocate any buffer, exiting..." 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 "E937: Attempt to delete a buffer that is in use" -msgstr "E937: Kullanımda olan bir arabellek silinmeye çalışılıyor" - msgid "E515: No buffers were unloaded" msgstr "E515: Hiçbir arabellek bellekten kaldırılmadı" @@ -125,8 +135,8 @@ msgstr "E88: İlk arabellekten öncesine gidilemez" msgid "" "E89: No write since last change for buffer %<PRId64> (add ! to override)" msgstr "" -"E89: %<PRId64> numaralı arabellek son deÄŸiÅŸiklikten sonra yazılmadı (geçersiz " -"kılmak için ! ekleyin)" +"E89: %<PRId64> numaralı arabellek son deÄŸiÅŸiklikten sonra yazılmadı " +"(geçersiz kılmak için ! ekleyin)" #, c-format msgid "E89: %s will be killed (add ! to override)" @@ -192,12 +202,6 @@ msgstr "[Adsız]" msgid "help" msgstr "yardım" -msgid "[Help]" -msgstr "[Yardım]" - -msgid "[Preview]" -msgstr "[Önizleme]" - msgid "All" msgstr "Tüm Belge" @@ -216,6 +220,12 @@ msgstr "[İstem]" msgid "[Scratch]" msgstr "[Geçici alan]" +msgid "[Location List]" +msgstr "[Konum Listesi]" + +msgid "[Quickfix List]" +msgstr "[Hızlı Düzelt Listesi]" + msgid "W10: Warning: Changing a readonly file" msgstr "W10: Uyarı: Saltokunur bir dosya deÄŸiÅŸtiriliyor" @@ -231,6 +241,15 @@ msgstr "Kapalı akışa veri gönderilemez" msgid "Can't send raw data to rpc channel" msgstr "rpc kanalına ham veri gönderilemez" +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 "E474: Failed to convert list to msgpack string buffer" msgstr "E474: Liste, msgpack dizi arabelleÄŸine dönüştürülemedi" @@ -339,7 +358,7 @@ msgid "E103: Buffer \"%s\" is not in diff mode" 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" +msgstr "E787: Arabellek beklenmedik bir biçimde deÄŸiÅŸtirildi" #, c-format msgid "E1214: Digraph must be just two characters: %s" @@ -441,140 +460,22 @@ 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" @@ -582,41 +483,6 @@ 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" @@ -652,10 +518,6 @@ 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" @@ -747,26 +609,6 @@ 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ÅŸ" @@ -852,8 +694,8 @@ 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" +"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" @@ -888,8 +730,8 @@ 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" +"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" @@ -1019,15 +861,15 @@ 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" +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" +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" @@ -1086,9 +928,6 @@ msgstr "E158: Geçersiz arabellek adı: %s" 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" @@ -1169,10 +1008,6 @@ 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'" @@ -1180,18 +1015,6 @@ msgstr "E962: Geçersiz eylem: '%s'" 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" @@ -1225,6 +1048,18 @@ msgid "E80: Error when closing file %s: %s" msgstr "E80: %s dosyası kapatılırken hata: %s" #, c-format +msgid "E1174: String required for argument %d" +msgstr "E1174: %d argümanı için dizi gerekiyor" + +#, c-format +msgid "E1142: Non-empty string required for argument %d" +msgstr "E1142: %d argümanı için boÅŸ olmayan dizi gerekiyor" + +#, c-format +msgid "E1210: Number required for argument %d" +msgstr "E1210: %d argümanı için sayı gerekiyor" + +#, c-format msgid "E5142: Failed to open file %s: %s" msgstr "E5142: %s dosyası açılamadı: %s" @@ -1236,6 +1071,18 @@ msgstr "E5143: %s dosyası yazılamadı: %s" msgid "E5144: Failed to close file %s: %s" msgstr "E5144: %s dosyası kapatılamadı: %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 "E6000: Argument is not a function or function name" msgstr "E6000: Argüman bir iÅŸlev veya iÅŸlev adı deÄŸil" @@ -1324,7 +1171,8 @@ 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" +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" @@ -1445,6 +1293,9 @@ msgstr "E126: :endfunction eksik" msgid "W22: Text found after :endfunction: %s" msgstr "W22: :endfunction sonrası metin bulundu: %s" +msgid "E1058: function nesting too deep" +msgstr "E1058: Pek çok iç içe geçmiÅŸ iÅŸlev" + #, c-format msgid "E707: Function name conflicts with variable: %s" msgstr "E707: İşlev adı ÅŸu deÄŸiÅŸken ile çakışıyor: %s" @@ -1468,6 +1319,72 @@ 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 "E18: Unexpected characters in :let" +msgstr "E18: :let içinde beklenmedik karakter" + +#, c-format +msgid "E940: Cannot lock or unlock variable %s" +msgstr "E940: DeÄŸiÅŸken %s kilitlenemiyor veya açılamıyor" + +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 "E108: No such variable: \"%s\"" +msgstr "E108: Böyle bir deÄŸiÅŸken yok: \"%s\"" + +#, 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 "tcp address must be host:port" msgstr "tcp adresi makine:kapı olmalı" @@ -1596,51 +1513,9 @@ msgstr "Dizginin bulunduÄŸu her satır: %s" msgid "Pattern not found: %s" msgstr "Dizgi bulunamadı: %s" -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" - -#, 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 "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\"?" @@ -1660,102 +1535,24 @@ 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 "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 "E464: Ambiguous use of user-defined command" +msgstr "E464: Kullanıcı tanımlı komutun belirsiz kullanımı" -msgid "E168: :finish used outside of a sourced file" -msgstr "E168: :finish kaynak alınmış bir dosyanın dışında kullanıldı" +msgid "E492: Not an editor command" +msgstr "E492: Bir düzenleyici komutu deÄŸil" -#, c-format -msgid "Current %slanguage: \"%s\"" -msgstr "Åžu anki %sdil: \"%s\"" +msgid "E498: no :source file name to substitute for \"<sfile>\"" +msgstr "E498: \"<kdosyası>\" yerine koymak için :source dosya adı yok" -#, c-format -msgid "E197: Cannot set language to \"%s\"" -msgstr "E197: \"%s\" diline ayarlanamıyor" +msgid "E489: no call stack to substitute for \"<stack>\"" +msgstr "E489: \"<yığın>\" yerine koymak için çaÄŸrı yığını yok" -#, 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 "E1274: No script file name to substitute for \"<script>\"" +msgstr "E1274: \"<betik>\" yerine koymak için betik dosyası adı yok" 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." @@ -1770,9 +1567,6 @@ msgstr "Çalıştırılıyor: %s" msgid "line %" msgstr "satır %" -msgid "E169: Command too recursive" -msgstr "E169: Komut çok özyineli" - #, c-format msgid "E605: Exception not caught: %s" msgstr "E605: Kural dışı durum yakalanmadı: %s" @@ -1783,11 +1577,11 @@ 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 "" +"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 "E493: Backwards range given" msgstr "E493: Geriye dönük erim verildi" @@ -1798,12 +1592,6 @@ msgstr "Geriye dönük erim verildi, takas edilebilir" msgid "E494: Use w or w>>" msgstr "E494: w veya w>> kullanı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 "E943: Command table needs to be updated, run 'make'" msgstr "E943: Komut tablosunun güncellenmesi gerekiyor, 'make' çalıştırın" @@ -1811,68 +1599,6 @@ 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 "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 "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" - -#, c-format msgid "E185: Cannot find color scheme '%s'" msgstr "E185: '%s' renk düzeni bulunamadı" @@ -1931,9 +1657,6 @@ msgstr "" msgid "E497: no autocommand match name to substitute for \"<amatch>\"" 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: \"<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" @@ -2051,9 +1774,6 @@ msgstr "E602: :try olmadan :endtry" msgid "E193: :endfunction not inside a function" 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" - msgid "E811: Not allowed to change buffer information now" msgstr "E811: Åžu anda arabellek bilgisi deÄŸiÅŸtirilemez" @@ -2088,15 +1808,6 @@ 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ı]" @@ -2133,6 +1844,10 @@ 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" +#, c-format +msgid "E676: No matching autocommands for buftype=%s buffer" +msgstr "E676: buftype=%s arabelleÄŸi için eÅŸleÅŸen otokomut yok" + msgid "is a directory" msgstr "bir dizin" @@ -2207,14 +1922,11 @@ 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" +msgstr "E204: Otokomut satır sayısını beklenmedik biçimde deÄŸiÅŸtirdi" msgid "is not a file or writable device" msgstr "bir dosya veya yazılabilir aygıt deÄŸil" @@ -2422,31 +2134,6 @@ msgstr "E222: Okunan arabelleÄŸe ekle" msgid "E223: recursive mapping" msgstr "E223: Özyineli eÅŸlemleme" -#, 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 "--No lines in buffer--" msgstr "--Arabellek içinde satır yok--" @@ -2473,6 +2160,9 @@ msgstr "" "E12: Geçerli dizin veya etiket aramasında exrc veya vimrc'den komutlara izin " "verilmiyor" +msgid "E169: Command too recursive" +msgstr "E169: Komut çok özyineli" + msgid "E171: Missing :endif" msgstr "E171: :endif eksik" @@ -2572,8 +2262,9 @@ msgstr "E906: rpc kanalı için geçersiz akış, 'rpc' kullanın" #, 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ı" +msgstr "" +"E5210: '%s' sözlük anahtarı, %<PRIu64> kanalında halihazırda arabelleklenmiÅŸ " +"akış için ayarlandı" #, c-format msgid "E364: Library call failed for \"%s()\"" @@ -2703,6 +2394,17 @@ 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: Saltokunur deÄŸiÅŸken \"%.*s\" deÄŸiÅŸtirilemiyor" @@ -2750,6 +2452,9 @@ msgstr "E48: Kum havuzunda izin verilmiyor" msgid "E523: Not allowed here" msgstr "E523: Burada izin verilmiyor" +msgid "E565: Not allowed to change text or change window" +msgstr "E565: Metin veya pencere deÄŸiÅŸtirmeye izin verilmiyor" + msgid "E359: Screen mode setting not supported" msgstr "E359: Ekran kipi ayarı desteklenmiyor" @@ -2842,6 +2547,9 @@ msgstr "E919: '%s' içinde dizin bulunamadı: \"%s\"" msgid "E952: Autocommand caused recursive behavior" msgstr "E952: Otokomut özyineli davranışa neden oldu" +msgid "E328: Menu only exists in another mode" +msgstr "E328: Menü yalnızca baÅŸka bir kipte mevcut" + msgid "E813: Cannot close autocmd window" msgstr "E813: Otokomut penceresi kapatılamıyor" @@ -2858,6 +2566,9 @@ msgstr "E856: Dosya adı pek uzun" msgid "E806: using Float as a String" msgstr "E806: Kayan Noktalı DeÄŸer, bir Dizi yerine kullanılıyor" +msgid "E788: Not allowed to edit another buffer now" +msgstr "E788: Åžu anda baÅŸka bir arabellek düzenlenemez" + #, c-format msgid "E5500: autocmd has thrown an exception: %s" msgstr "E5500: Otokomut, bir istisna attı: %s" @@ -2869,10 +2580,6 @@ msgid "E5521: <Cmd> mapping must end with <CR> before second <Cmd>" msgstr "E5521: <Cmd> eÅŸlemlemesi ikinci <Cmd>'den önce <CR> ile bitmelidir" #, c-format -msgid "E5522: <Cmd> mapping must not include %s key" -msgstr "E5522: <Cmd> eÅŸlemlemesi %s anahtarını içermemelidir" - -#, c-format msgid "E5555: API call: %s" msgstr "E5555: API çaÄŸrısı: %s" @@ -2898,9 +2605,17 @@ msgstr "E1240: Ortaya çıkan metin pek uzun" msgid "E1247: Line number out of range" msgstr "E1247: Satır numarası erim dışında" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Grup adında geçersiz karakter" + msgid "E1249: Highlight group name too long" msgstr "E1249: Vurgulama grubu adı pek uzun" +msgid "E5767: Cannot use :undo! to redo or move to a different undo branch" +msgstr "" +"E5767: Yinelemek veya baÅŸka bir geri al dalına taşımak için :undo! " +"kullanılamaz" + msgid "search hit TOP, continuing at BOTTOM" msgstr "Arama dosyanın BAÅžINI geçti, dosyanın SONUNDAN sürüyor" @@ -3003,6 +2718,45 @@ 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" + +#, 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 "E424: Too many different highlighting attributes in use" msgstr "E424: Çok fazla deÄŸiÅŸik vurgulama kuralları kullanılıyor" @@ -3025,6 +2779,9 @@ msgstr "E414: Grup ayarları mevcut, vurgulama baÄŸlantısı yok sayıldı" msgid "E415: unexpected equal sign: %s" msgstr "E415: Beklenmedik eÅŸittir imi: %s" +msgid "E423: Illegal argument" +msgstr "E423: İzin verilmeyen argüman" + #, c-format msgid "E416: missing equal sign: %s" msgstr "E416: Eksik eÅŸittir imi: %s" @@ -3054,9 +2811,6 @@ msgstr "E423: İzin verilmeyen argüman: %s" msgid "E669: Unprintable character in group name" msgstr "E669: Grup adında yazdırılamayan karakter" -msgid "W18: Invalid character in group name" -msgstr "W18: Grup adında geçersiz karakter" - msgid "E849: Too many highlight and syntax groups" msgstr "E849: Çok fazla vurgulama ve sözdizim grupları" @@ -3220,6 +2974,114 @@ msgstr "" msgid "Type number and <Enter> (q or empty cancels): " msgstr "Sayı girip <Enter>'a basın (q veya boÅŸ iptal eder): " +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ÅŸ" + +#, 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" + +#, 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" + +#, c-format +msgid "Current %slanguage: \"%s\"" +msgstr "Åžu anki %sdil: \"%s\"" + +#, c-format +msgid "E197: Cannot set language to \"%s\"" +msgstr "E197: \"%s\" diline ayarlanamıyor" + #, c-format msgid "E1502: Lua failed to grow stack to %i" msgstr "E1502: Lua, yığını %i olarak büyütemedi" @@ -3366,16 +3228,14 @@ msgid "Usage:\n" msgstr "Kullanım:\n" msgid " nvim [options] [file ...] Edit file(s)\n" -msgstr "" -"nvim [seçenekler] [dosya ...] Dosyaları düzenle\n" +msgstr "nvim [seçenekler] [dosya ...] Dosyaları düzenle\n" msgid " nvim [options] -t <tag> Edit file where tag is defined\n" msgstr "" "nvim [seçenekler] -t <etiket> Etiketin tanımlandığı dosyayı düzenle\n" msgid " nvim [options] -q [errorfile] Edit file with first error\n" -msgstr "" -"nvim [seçenekler] -q [hatadosyası] İlk hatalı dosyayı düzenle\n" +msgstr "nvim [seçenekler] -q [hatadosyası] İlk hatalı dosyayı düzenle\n" msgid "" "\n" @@ -3385,12 +3245,10 @@ msgstr "" "Seçenekler:\n" msgid " -- Only file names after this\n" -msgstr "" -"-- Yalnızca bundan sonraki dosya adları\n" +msgstr "-- Yalnızca bundan sonraki dosya adları\n" msgid " + Start at end of file\n" -msgstr "" -"+ Dosyanın sonunda baÅŸlat\n" +msgstr "+ Dosyanın sonunda baÅŸlat\n" msgid " --cmd <cmd> Execute <cmd> before any config\n" msgstr "" @@ -3401,40 +3259,31 @@ msgstr "" "+<komut>, -c <komut> Yapılandırma ve ilk dosya sonrası <komut> çalıştır\n" msgid " -b Binary mode\n" -msgstr "" -"-b İkili kip\n" +msgstr "-b İkili kip\n" msgid " -d Diff mode\n" -msgstr "" -"-d Diff kipi\n" +msgstr "-d Diff kipi\n" msgid " -e, -E Ex mode\n" -msgstr "" -"-e, -E Ex kipi\n" +msgstr "-e, -E Ex kipi\n" msgid " -es, -Es Silent (batch) mode\n" -msgstr "" -"-es, -Es Sessiz (toplu iÅŸ) kipi\n" +msgstr "-es, -Es Sessiz (toplu iÅŸ) kipi\n" msgid " -h, --help Print this help message\n" -msgstr "" -"-h, --help Bu yardım iletisini yazdır\n" +msgstr "-h, --help Bu yardım iletisini yazdır\n" msgid " -i <shada> Use this shada file\n" -msgstr "" -"-i <shada> Bu shada (paylaşılan veri) dosyasını kullan\n" +msgstr "-i <shada> Bu shada (paylaşılan veri) dosyasını kullan\n" msgid " -m Modifications (writing files) not allowed\n" -msgstr "" -"-m DeÄŸiÅŸikliklere (dosya yazmaya) izin verme\n" +msgstr "-m DeÄŸiÅŸikliklere (dosya yazmaya) izin verme\n" msgid " -M Modifications in text not allowed\n" -msgstr "" -"-M Metinde deÄŸiÅŸikliklere izin verme\n" +msgstr "-M Metinde deÄŸiÅŸikliklere izin verme\n" msgid " -n No swap file, use memory only\n" -msgstr "" -"-n Takas dosyası yok, yalnızca belleÄŸi kullan\n" +msgstr "-n Takas dosyası yok, yalnızca belleÄŸi kullan\n" msgid " -o[N] Open N windows (default: one per file)\n" msgstr "" @@ -3450,68 +3299,61 @@ msgstr "" "-p[N] N sekme sayfası aç (öntanımlı: dosya başına bir tane)\n" msgid " -r, -L List swap files\n" -msgstr "" -"-r, -L Takas dosyalarını listele\n" +msgstr "-r, -L Takas dosyalarını listele\n" msgid " -r <file> Recover edit state for this file\n" -msgstr "" -"-r <dosya> Bu dosyanın düzenleme durumunu kurtar\n" +msgstr "-r <dosya> Bu dosyanın düzenleme durumunu kurtar\n" msgid " -R Read-only mode\n" -msgstr "" -"-R Saltokunur kip\n" +msgstr "-R Saltokunur kip\n" msgid " -S <session> Source <session> after loading the first file\n" msgstr "" "-S <oturum> İlk dosyayı yükledikten sonra <oturum>'u kaynak al\n" msgid " -s <scriptin> Read Normal mode commands from <scriptin>\n" -msgstr "" -"-s <betikgir> Normal kip komutlarını <betikgir>'den oku\n" +msgstr "-s <betikgir> Normal kip komutlarını <betikgir>'den oku\n" msgid " -u <config> Use this config file\n" -msgstr "" -"-u <yapılandırma> Bu yapılandırma dosyasını kullan\n" +msgstr "-u <yapılandırma> Bu yapılandırma dosyasını kullan\n" msgid " -v, --version Print version information\n" -msgstr "" -"-v, --version Sürüm bilgisini yazdır\n" +msgstr "-v, --version Sürüm bilgisini yazdır\n" msgid " -V[N][file] Verbose [level][file]\n" -msgstr "" -"-V[N][dosya] Ayrıntılı bilgi ver [düzey][dosya]\n" +msgstr "-V[N][dosya] Ayrıntılı bilgi ver [düzey][dosya]\n" msgid " --api-info Write msgpack-encoded API metadata to stdout\n" +msgstr "--api-info stdout'a msgpack kodlu API üstverisi yaz\n" + +msgid "" +" --clean \"Factory defaults\" (skip user config and plugins, " +"shada)\n" msgstr "" -"--api-info stdout'a msgpack kodlu API üstverisi yaz\n" +" --clean \"Fabrika ayarları\" (yapılandırma/eklentileri atla, " +"shada)\n" msgid " --embed Use stdin/stdout as a msgpack-rpc channel\n" msgstr "" "--embed stdin/stdout'u msgpack-rpc kanalı olarak kullan\n" msgid " --headless Don't start a user interface\n" -msgstr "" -"--headless Bir kullanıcı arayüzü baÅŸlatma\n" +msgstr "--headless Bir kullanıcı arayüzü baÅŸlatma\n" msgid " --listen <address> Serve RPC API from this address\n" -msgstr "" -"--listen <adres> Bu adresten RPC API'si sun\n" +msgstr "--listen <adres> Bu adresten RPC API'si sun\n" msgid " --noplugin Don't load plugins\n" -msgstr "" -"--noplugin Eklentileri yükleme\n" +msgstr "--noplugin Eklentileri yükleme\n" msgid " --remote[-subcommand] Execute commands remotely on a server\n" -msgstr "" -"--remote[-subcommand] Bir sunucuda komutları uzaktan çalıştır\n" +msgstr "--remote[-subcommand] Bir sunucuda komutları uzaktan çalıştır\n" msgid " --server <address> Specify RPC server to send commands to\n" -msgstr "" -"--server <adres> Komut gönderilecek RPC sunucusunu belirt\n" +msgstr "--server <adres> Komut gönderilecek RPC sunucusunu belirt\n" msgid " --startuptime <file> Write startup timing messages to <file>\n" -msgstr "" -"--startuptime <dosya> BaÅŸlangıç zamanlama iletilerini <dosya>'ya yaz\n" +msgstr "--startuptime <dosya> BaÅŸlangıç zamanlama iletilerini <dosya>'ya yaz\n" msgid "" "\n" @@ -3520,6 +3362,42 @@ msgstr "" "\n" "Tüm seçenekler için \":help startup-options\" yazın.\n" +#, 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 girdiler eksik" + +#, 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" + msgid "No marks set" msgstr "İm ayarlanmamış" @@ -3588,6 +3466,29 @@ msgstr "E798: Kimlik, \":match\" için ayrılmış: %<PRId64>" msgid "E798: ID is reserved for \"match\": %<PRId64>" msgstr "E798: Kimlik, \":match\" için ayrılmış: %<PRId64>" +#, c-format +msgid "E1109: List item %d is not a List" +msgstr "E1109: Liste ögesi %d, bir Liste deÄŸil" + +#, c-format +msgid "E1110: List item %d does not contain 3 numbers" +msgstr "E1110: Liste ögesi %d, 3 adet sayı içermiyor" + +#, c-format +msgid "E1111: List item %d range invalid" +msgstr "E1111: Liste ögesi %d erimi geçersiz" + +#, c-format +msgid "E1112: List item %d cell width invalid" +msgstr "E1112: Liste ögesi %d hücre geniÅŸliÄŸi geçersiz" + +#, 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 üstü deÄŸerler desteklenir" + msgid "E293: block was not locked" msgstr "E293: Blok kilitlenmemiÅŸti" @@ -4003,8 +3904,8 @@ msgstr "E326: Çok fazla takas dosyası bulundu" 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" +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" @@ -4016,9 +3917,6 @@ 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" @@ -4053,9 +3951,15 @@ msgstr "E333: Menü yolu bir menü ögesine çıkmalı" 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ı denetleyin" + #, c-format msgid "Error detected while processing %s:" -msgstr "%s iÅŸlenirken hata tespit edildi:" +msgstr "%s iÅŸlenirken hata algılandı:" #, c-format msgid "line %4ld:" @@ -4117,10 +4021,10 @@ msgstr "" "İ&ptal" msgid "E349: No identifier under cursor" -msgstr "E349: İmleç altında bir tanımlayıcı yok" +msgstr "E349: İmleç altında tanımlayıcı yok" msgid "E348: No string under cursor" -msgstr "E348: İmleç altında bir dizi yok" +msgstr "E348: İmleç altında dizi yok" msgid "E352: Cannot erase folds with current 'foldmethod'" msgstr "E352: Åžu anki 'foldmethod' ile kıvırmalar silinemiyor" @@ -4177,22 +4081,24 @@ msgstr "%<PRId64> Sütun; " 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" +msgstr "" +"%s%<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; %<PRId64>/%<PRId64> " +"bayt seçildi" #, c-format msgid "" "Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; " "%<PRId64> of %<PRId64> Chars; %<PRId64> of %<PRId64> Bytes" msgstr "" -"%s%<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; " -"%<PRId64>/%<PRId64> karakter; %<PRId64>/%<PRId64> bayt 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 %<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; " +msgstr "" +"%s/%s sütun; %<PRId64>/%<PRId64> satır; %<PRId64>/%<PRId64> sözcük; " "%<PRId64>/%<PRId64> bayt" #, c-format @@ -4225,59 +4131,6 @@ msgstr "E846: Anahtar kodu ayarlanmamış" msgid "E521: Number required after =" msgstr "E521: = sonrası sayı gerekiyor" -#, c-format -msgid "E539: Illegal character <%s>" -msgstr "E539: İzin verilmeyen karakter <%s>" - -#, c-format -msgid "For option %s" -msgstr "%s seçeneÄŸi için" - -msgid "E589: 'backupext' and 'patchmode' are equal" -msgstr "E589: 'backupext' ve 'patchmode' birbirine eÅŸit" - -msgid "E834: Conflicts with value of 'listchars'" -msgstr "E834: 'listchars' deÄŸeriyle çakışmalar var" - -msgid "E835: Conflicts with value of 'fillchars'" -msgstr "E835: 'fillchars' deÄŸeriyle çakışmalar var" - -msgid "E524: Missing colon" -msgstr "E524: İki nokta eksik" - -msgid "E525: Zero length string" -msgstr "E525: Sıfır uzunlukta dizi" - -#, c-format -msgid "E526: Missing number after <%s>" -msgstr "E526: <%s> sonrası sayı eksik" - -msgid "E527: Missing comma" -msgstr "E527: Virgül eksik" - -msgid "E528: Must specify a ' value" -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" - -#, c-format -msgid "E535: Illegal character after <%c>" -msgstr "E535: <%c> sonrası izin verilmeyen karakter" - -msgid "E536: comma required" -msgstr "E536: Virgül gerekiyor" - -#, c-format -msgid "E537: 'commentstring' must be empty or contain %s" -msgstr "E537: 'commentstring' boÅŸ olmalı veya %s içermeli" - -msgid "E540: Unclosed expression sequence" -msgstr "E540: Kapatılmamış ifade sıralaması" - -msgid "E542: unbalanced groups" -msgstr "E542: DengelenmemiÅŸ gruplar" - msgid "E590: A preview window already exists" msgstr "E590: Bir önizleme penceresi hâlihazırda mevcut" @@ -4324,13 +4177,52 @@ msgstr "" msgid "E356: get_varp ERROR" msgstr "E356: get_varp HATASI" +msgid "E540: Unclosed expression sequence" +msgstr "E540: Kapatılmamış ifade sıralaması" + +msgid "E542: unbalanced groups" +msgstr "E542: DengelenmemiÅŸ gruplar" + +msgid "E589: 'backupext' and 'patchmode' are equal" +msgstr "E589: 'backupext' ve 'patchmode' birbirine eÅŸit" + +msgid "E595: 'showbreak' contains unprintable or wide character" +msgstr "E595: 'showbreak' yazdırılamaz veya geniÅŸ karakter içeriyor" + #, c-format -msgid "E357: 'langmap': Matching character missing for %s" -msgstr "E357: 'langmap': %s için eÅŸleÅŸen karakter eksik" +msgid "E539: Illegal character <%s>" +msgstr "E539: İzin verilmeyen karakter <%s>" #, c-format -msgid "E358: 'langmap': Extra characters after semicolon: %s" -msgstr "E358: 'langmap': Noktalı virgülden sonra ek karakterler: %s" +msgid "For option %s" +msgstr "%s seçeneÄŸi için" + +msgid "E524: Missing colon" +msgstr "E524: İki nokta eksik" + +msgid "E525: Zero length string" +msgstr "E525: Sıfır uzunlukta dizi" + +#, c-format +msgid "E526: Missing number after <%s>" +msgstr "E526: <%s> sonrası sayı eksik" + +msgid "E527: Missing comma" +msgstr "E527: Virgül eksik" + +msgid "E528: Must specify a ' value" +msgstr "E528: Bir ' deÄŸeri belirtmeli" + +#, c-format +msgid "E535: Illegal character after <%c>" +msgstr "E535: <%c> sonrası izin verilmeyen karakter" + +msgid "E536: comma required" +msgstr "E536: Virgül gerekiyor" + +#, c-format +msgid "E537: 'commentstring' must be empty or contain %s" +msgstr "E537: 'commentstring' boÅŸ olmalı veya %s içermeli" #, c-format msgid "dlerror = \"%s\"" @@ -4368,6 +4260,9 @@ msgstr "%a %b %d %H:%M:%S %Y" msgid "E447: Can't find file \"%s\" in path" msgstr "E447: \"%s\" dosyası yol içinde bulunamadı" +msgid "E750: First use \":profile start {fname}\"" +msgstr "E750: İlk kullanım \":profile start {dosyaadı}\"" + msgid "E553: No more items" msgstr "E553: Öge yok" @@ -4383,7 +4278,7 @@ msgstr "E372: Biçim dizisinde pek fazla %%%c" #, c-format msgid "E373: Unexpected %%%c in format string" -msgstr "E373: Biçimlendirme dizisinde beklenmeyen %%%c" +msgstr "E373: Biçimlendirme dizisinde beklenmedik %%%c" msgid "E374: Missing ] in format string" msgstr "E374: Biçimlendirme dizisinde ] eksik" @@ -4446,6 +4341,10 @@ 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" @@ -4492,13 +4391,16 @@ msgstr "E956: Dizgi özyineli olarak kullanılamaz" msgid "E1204: No Number allowed after .: '\\%%%c'" msgstr "E1204: . sonrası Sayıya izin verilmiyor: '\\%%%c'" +msgid "E1290: substitute nesting too deep" +msgstr "E1290: DeÄŸiÅŸtirme iç içe geçmesi pek derin" + #, c-format msgid "E554: Syntax error in %s{...}" -msgstr "E554: %s{...} içinde sözdizimi hatası" +msgstr "E554: %s{...} içinde sözdizim hatası" #, c-format msgid "E888: (NFA regexp) cannot repeat %s" -msgstr "E888: (BSO düzenli ifadesi) %s tekrar edemiyor" +msgstr "E888: (BSO düzenli ifadesi) %s yinelenemiyor" msgid "" "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " @@ -4530,6 +4432,77 @@ msgstr "\"%s\", çalışma zamanı yolu içinde aranıyor" msgid "not found in runtime path: \"%s\"" msgstr "çalışma zamanı yolu içinde bulunamadı: \"%s\"" +#, c-format +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ı" + +msgid "E834: Conflicts with value of 'listchars'" +msgstr "E834: 'listchars' deÄŸeriyle çakışmalar var" + +msgid "E835: Conflicts with value of 'fillchars'" +msgstr "E835: 'fillchars' deÄŸeriyle çakışmalar var" + msgid " TERMINAL" msgstr " UÇBİRİM" @@ -4545,6 +4518,9 @@ msgstr " GERİ AL" msgid " INSERT" msgstr " EKLE" +msgid " (terminal)" +msgstr " (uçbirim)" + msgid " (insert)" msgstr " (ekle)" @@ -4764,13 +4740,14 @@ msgstr "" #, c-format 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 " +msgstr "" +"%s dosyasını %s olarak yeniden adlandırmanızın nedeni yazma sırasında " "hatalar olması mı?" #, c-format 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." +msgstr "" +"%s dosyasını kaldırmayı veya el ile %s olarak yeniden adlandırmayı unutmayın." #, c-format msgid "System error while reading ShaDa file: %s" @@ -4801,8 +4778,8 @@ 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" +"Paylaşılan veri dosyası okunurken hata: %<PRIu64> konumunda bir öge var; " +"ancak pek uzun olduÄŸu belirtildi" #, c-format msgid "" @@ -4915,21 +4892,6 @@ 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" @@ -4940,6 +4902,9 @@ msgstr "E753: Bulunamadı: %s" msgid "E758: Truncated spell file" msgstr "E758: Kırpılmış yazım dosyası" +msgid "E1280: Illegal character in word" +msgstr "E1280: Sözcükte izin verilmeyen karakter" + #, c-format msgid "Trailing text in %s line %d: %s" msgstr "%s içinde %d. satır ucunda fazladan metin: %s" @@ -5058,10 +5023,10 @@ msgstr "%s içinde %d. satırda yinelenen ek: %s" #, c-format msgid "" -"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGESTin %s " +"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s " "line %d: %s" msgstr "" -"Ek aynı zamanda %s içinde %d. satırda BAD/RARE/KEEPCASE/NEEDAFFIX/" +"Sonek aynı zamanda %s içinde %d. satırda BAD/RARE/KEEPCASE/NEEDAFFIX/" "NEEDCOMPOUND/NOSUGGEST için de kullanılmış: %s" #, c-format @@ -5257,6 +5222,27 @@ 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 %<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 "[Help]" +msgstr "[Yardım]" + +msgid "[Preview]" +msgstr "[Önizleme]" + msgid "E766: Insufficient arguments for printf()" msgstr "E766: printf() için yetersiz argüman" @@ -5512,7 +5498,7 @@ msgid "Beep!" msgstr "Bip!" msgid "E881: Line count changed unexpectedly" -msgstr "E881: Satır sayısı beklenmeyen bir biçimde deÄŸiÅŸti" +msgstr "E881: Satır sayısı beklenmedik bir biçimde deÄŸiÅŸti" #, c-format msgid "E828: Cannot open undo file for writing: %s" @@ -5631,6 +5617,76 @@ msgstr "E439: Geri al listesi hasarlı" msgid "E440: undo line missing" msgstr "E440: Geri al satırı eksik" +msgid "E1208: -complete used without allowing arguments" +msgstr "E1208: -complete, argümanlara izin vermeden kullanıldı" + +#, 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 "" +"\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 "E181: Invalid attribute: %s" +msgstr "E181: Geçersiz öznitelik: %s" + +#, 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" + msgid "" "\n" "\n" @@ -5864,12 +5920,18 @@ msgstr "E15: Lambda için kapatma kıvrımlı ayracı eksik: %.*s" msgid "E109: Missing ':' after '?': %.*s" msgstr "E109: '?' sonrası ':' eksik: %.*s" +msgid "E1159: Cannot split a window when closing the buffer" +msgstr "E1159: Arabellek kapatılırken bir pencere bölünemez" + msgid "Already only one window" msgstr "Zaten tek pencere" 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 pencere kapatılırken baÅŸka bir 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" @@ -5886,4 +5948,4 @@ msgid "E445: Other window contains changes" msgstr "E445: DiÄŸer pencerede deÄŸiÅŸiklikler var" msgid "E446: No file name under cursor" -msgstr "E446: İmleç altında bir dosya adı yok" +msgstr "E446: İmleç altında dosya adı yok" diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index da87d50683..427abd9b77 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -3058,8 +3058,8 @@ msgstr "E423: Ðеправильний аргумент: %s" msgid "E669: Unprintable character in group name" msgstr "E669: Ðедруковний Ñимвол у назві групи" -msgid "W18: Invalid character in group name" -msgstr "W18: Ðекоректний Ñимвол у назві групи" +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ðекоректний Ñимвол у назві групи" msgid "E849: Too many highlight and syntax groups" msgstr "E849: Забагато груп підÑÐ²Ñ–Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– ÑинтакÑиÑу" diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po index c693f910d8..ad59718a30 100644 --- a/src/nvim/po/vi.po +++ b/src/nvim/po/vi.po @@ -5975,9 +5975,9 @@ msgstr "E424: Sá» dụng quá nhiá»u thuá»™c tÃnh chiếu sáng cú pháp" msgid "E669: Unprintable character in group name" msgstr "E669: Ký tá»± không thể tin ra trong tên nhóm" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: Ký tá»± không cho phép trong tên nhóm" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: Ký tá»± không cho phép trong tên nhóm" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po index 70c1389d7f..afa2f29029 100644 --- a/src/nvim/po/zh_CN.UTF-8.po +++ b/src/nvim/po/zh_CN.UTF-8.po @@ -734,9 +734,9 @@ msgid "E120: Using <SID> not in a script context: %s" msgstr "E120: <SID> ä¸èƒ½åœ¨ script 上下文外使用: %s" #: ../eval.c:7391 -#, fuzzy, c-format +#, c-format msgid "E725: Calling dict function without Dictionary: %s" -msgstr "E720: Dictionary ä¸ç¼ºå°‘冒å·: %s" +msgstr "E725: 调用å—典函数但是没有å—典:%s" #: ../eval.c:7453 #, fuzzy @@ -766,19 +766,16 @@ msgid "E737: Key already exists: %s" msgstr "E737: 键已å˜åœ¨: %s" #: ../eval.c:8692 -#, fuzzy msgid "extend() argument" -msgstr "--cmd 傿•°" +msgstr "extend() 傿•°" #: ../eval.c:8915 -#, fuzzy msgid "map() argument" -msgstr "-c 傿•°" +msgstr "map() 傿•°" #: ../eval.c:8916 -#, fuzzy msgid "filter() argument" -msgstr "-c 傿•°" +msgstr "filter() 傿•°" #: ../eval.c:9229 #, c-format @@ -849,9 +846,8 @@ msgid "E702: Sort compare function failed" msgstr "E702: Sort 比较函数失败" #: ../eval.c:13806 -#, fuzzy msgid "E882: Uniq compare function failed" -msgstr "E702: Sort 比较函数失败" +msgstr "E882: Uniq 比较函数失败" #: ../eval.c:14085 msgid "(Invalid)" @@ -864,31 +860,31 @@ msgstr "E677: 写临时文件出错" #: ../eval.c:16159 #, fuzzy msgid "E805: Using a Float as a Number" -msgstr "E745: å°† List 作数å—使用" +msgstr "E805: å°†æµ®ç‚¹æ•°å½“åšæ•°å—使用" #: ../eval.c:16162 msgid "E703: Using a Funcref as a Number" -msgstr "E703: å°† Funcref 作数å—使用" +msgstr "E703: å°†å‡½æ•°å½“åšæ•°å—使用" #: ../eval.c:16170 msgid "E745: Using a List as a Number" -msgstr "E745: å°† List 作数å—使用" +msgstr "E745: å°†åˆ—è¡¨å½“åšæ•°å—使用" #: ../eval.c:16173 msgid "E728: Using a Dictionary as a Number" -msgstr "E728: å°† Dictionary 作数å—使用" +msgstr "E728: å°†å—å…¸å½“åšæ•°å—使用" #: ../eval.c:16259 msgid "E729: using Funcref as a String" -msgstr "E729: å°† Funcref 作 String 使用" +msgstr "E729: 将函数当åšå—符串使用" #: ../eval.c:16262 msgid "E730: using List as a String" -msgstr "E730: å°† List 作 String 使用" +msgstr "E730: 将列表当åšå—符串使用" #: ../eval.c:16265 msgid "E731: using Dictionary as a String" -msgstr "E731: å°† Dictionary 作 String 使用" +msgstr "E731: å°†å—典当åšå—符串使用" #: ../eval.c:16619 #, c-format @@ -3053,11 +3049,11 @@ msgstr "E673: ä¸å…¼å®¹çš„多å—节编ç å’Œå—符集。" #: ../hardcopy.c:2238 msgid "E674: printmbcharset cannot be empty with multi-byte encoding." -msgstr "E674: printmbcharset 在多å—节编ç 下ä¸èƒ½ä¸ºç©ºã€‚" +msgstr "E674: printmbcharset 在多å—节编ç 下ä¸èƒ½ä¸ºç©º" #: ../hardcopy.c:2254 msgid "E675: No default font specified for multi-byte printing." -msgstr "E675: 没有指定多å—节打å°çš„默认å—体。" +msgstr "E675: 没有指定多å—节打å°çš„默认å—体" #: ../hardcopy.c:2426 msgid "E324: Can't open PostScript output file" @@ -4204,9 +4200,8 @@ msgstr "E329: 没有èœå• \"%s\"" #. Only a mnemonic or accelerator is not valid. #: ../menu.c:329 -#, fuzzy msgid "E792: Empty menu name" -msgstr "E749: 空的缓冲区" +msgstr "E792: 空的èœå•åç§°" #: ../menu.c:340 msgid "E330: Menu path must not lead to a sub-menu" @@ -4329,9 +4324,8 @@ msgid "E766: Insufficient arguments for printf()" msgstr "E766: printf() çš„å‚æ•°ä¸è¶³" #: ../message.c:3119 -#, fuzzy msgid "E807: Expected Float argument for printf()" -msgstr "E766: printf() çš„å‚æ•°ä¸è¶³" +msgstr "E807: 期盼浮点数作为printf()傿•°" #: ../message.c:3873 msgid "E767: Too many arguments to printf()" @@ -5675,9 +5669,9 @@ msgid "E781: .sug file doesn't match .spl file: %s" msgstr "E781: .sug 文件ä¸èƒ½åŒ¹é… .spl 文件: %s" #: ../spell.c:9305 -#, fuzzy, c-format +#, c-format msgid "E782: error while reading .sug file: %s" -msgstr "E47: 读å–错误文件失败" +msgstr "E782: 当读å–.sug 文件时错误" #. This should have been checked when generating the .spl #. file. @@ -5867,6 +5861,7 @@ msgstr "E410: 䏿£ç¡®çš„ :syntax å命令: %s" msgid "" " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN" msgstr "" +" 总 计 计 æ•° 匹 é… æœ€ æ…¢ çš„ å¹³ å‡ å å— æ¨¡ å¼" #: ../syntax.c:6146 msgid "E679: recursive loop loading syncolor.vim" @@ -5942,9 +5937,9 @@ msgstr "E424: 使用了太多ä¸åŒçš„高亮度属性" msgid "E669: Unprintable character in group name" msgstr "E669: 组åä¸å˜åœ¨ä¸å¯æ˜¾ç¤ºå—符" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: 组åä¸å«æœ‰æ— 效å—符" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: 组åä¸å«æœ‰æ— 效å—符" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" @@ -6103,14 +6098,13 @@ msgstr "Vim: 读错误,退出ä¸...\n" #. This happens when the FileChangedRO autocommand changes the #. * file in a way it becomes shorter. #: ../undo.c:379 -#, fuzzy msgid "E881: Line count changed unexpectedly" -msgstr "E787: æ„外地改å˜äº†ç¼“冲区" +msgstr "E881: 行数æ„外地改å˜äº†" #: ../undo.c:627 -#, fuzzy, c-format +#, c-format msgid "E828: Cannot open undo file for writing: %s" -msgstr "E212: æ— æ³•æ‰“å¼€å¹¶å†™å…¥æ–‡ä»¶" +msgstr "E828: æ— æ³•æ‰“å¼€æ’¤é”€æ–‡ä»¶åŽ»å†™å…¥" #: ../undo.c:717 #, c-format diff --git a/src/nvim/po/zh_TW.UTF-8.po b/src/nvim/po/zh_TW.UTF-8.po index e2fb2d39d4..e95b1e2cad 100644 --- a/src/nvim/po/zh_TW.UTF-8.po +++ b/src/nvim/po/zh_TW.UTF-8.po @@ -59,19 +59,19 @@ msgstr "無法傳é€å›žæ‡‰è¨Šæ¯" #: ../api/private/helpers.c:204 msgid "internal error: unknown option type" -msgstr "" +msgstr "內部錯誤: 未知的é¸é …類型" #: ../buffer.c:92 msgid "[Location List]" -msgstr "" +msgstr "[Location 列表]" #: ../buffer.c:93 msgid "[Quickfix List]" -msgstr "" +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..." @@ -349,7 +349,7 @@ msgstr "E103: ç·©è¡å€ \"%s\" 䏿˜¯åœ¨ diff 模å¼" #: ../diff.c:2193 msgid "E787: Buffer changed unexpectedly" -msgstr "" +msgstr "E787: æ„外地改變了緩è¡å€" #: ../digraph.c:1598 msgid "E104: Escape not allowed in digraph" @@ -365,7 +365,7 @@ msgstr "E105: 使用 :loadkeymap " #: ../digraph.c:1821 msgid "E791: Empty keymap entry" -msgstr "" +msgstr "E791: 空的éµä½æ˜ å°„é …" #: ../edit.c:82 msgid " Keyword completion (^N^P)" @@ -434,11 +434,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" @@ -556,7 +556,7 @@ msgstr "E118: å‡½å¼ %s 的引數éŽå¤š" #: ../eval.c:148 #, c-format msgid "E716: Key not present in Dictionary: %s" -msgstr "" +msgstr "E716: éµåœ¨å—å…¸ä¸ä¸å˜åœ¨: %s" #: ../eval.c:150 #, c-format @@ -581,7 +581,7 @@ msgstr "E360: ä¸èƒ½ç”¨ -f é¸é …執行 shell" #: ../eval.c:154 #, c-format msgid "E734: Wrong variable type for %s=" -msgstr "" +msgstr "E734: 錯誤的變數類型: %s=" #: ../eval.c:155 #, fuzzy, c-format @@ -595,19 +595,19 @@ msgstr "E461: ä¸åˆæ³•的變數å稱: %s" #: ../eval.c:157 msgid "E806: using Float as a String" -msgstr "" +msgstr "E806: 使用浮點數作為å—串" #: ../eval.c:1830 msgid "E687: Less targets than List items" -msgstr "" +msgstr "E687: ç›®æ¨™æ¯”åˆ—è¡¨é …æ•¸å°‘" #: ../eval.c:1834 msgid "E688: More targets than List items" -msgstr "" +msgstr "E688: ç›®æ¨™æ¯”åˆ—è¡¨é …æ•¸å¤š" #: ../eval.c:1906 msgid "Double ; in list of variables" -msgstr "" +msgstr "變數列表出ç¾å…©å€‹ ;" #: ../eval.c:2078 #, fuzzy, c-format @@ -616,23 +616,23 @@ msgstr "E138: 無法寫入 viminfo 檔案 %s !" #: ../eval.c:2391 msgid "E689: Can only index a List or Dictionary" -msgstr "" +msgstr "E689: åªèƒ½ç´¢å¼•一個列表或者å—å…¸" #: ../eval.c:2396 msgid "E708: [:] must come last" -msgstr "" +msgstr "E708: [:] å¿…é ˆåœ¨æœ€å¾Œ" #: ../eval.c:2439 msgid "E709: [:] requires a List value" -msgstr "" +msgstr "E709: [:] 需è¦ä¸€å€‹åˆ—表值" #: ../eval.c:2674 msgid "E710: List value has more items than target" -msgstr "" +msgstr "E710: åˆ—è¡¨å€¼çš„é …æ¯”ç›®æ¨™å¤š" #: ../eval.c:2678 msgid "E711: List value has not enough items" -msgstr "" +msgstr "E711: åˆ—è¡¨å€¼æ²’æœ‰è¶³å¤ å¤šçš„é …" #: ../eval.c:2867 #, fuzzy @@ -651,7 +651,7 @@ msgstr "E108: ç„¡æ¤è®Šæ•¸: \"%s\"" #: ../eval.c:3333 msgid "E743: variable nested too deep for (un)lock" -msgstr "" +msgstr "E743: (un)lock çš„è®Šæ•¸åµŒå¥—éŽæ·±" #: ../eval.c:3630 msgid "E109: Missing ':' after '?'" @@ -659,7 +659,7 @@ msgstr "E109: '?' 後缺少 ':'" #: ../eval.c:3893 msgid "E691: Can only compare List with List" -msgstr "" +msgstr "E691: åªèƒ½æ¯”較列表和列表" #: ../eval.c:3895 #, fuzzy @@ -668,7 +668,7 @@ msgstr "E449: æ”¶åˆ°ä¸æ£ç¢ºçš„é‹ç®—å¼" #: ../eval.c:3915 msgid "E735: Can only compare Dictionary with Dictionary" -msgstr "" +msgstr "E735: åªèƒ½æ¯”較å—典和å—å…¸" #: ../eval.c:3917 #, fuzzy @@ -677,7 +677,7 @@ msgstr "E116: å‡½å¼ %s çš„å¼•æ•¸ä¸æ£ç¢º" #: ../eval.c:3932 msgid "E693: Can only compare Funcref with Funcref" -msgstr "" +msgstr "E693: åªèƒ½æ¯”較Funcref å’Œ Funcref" #: ../eval.c:3934 #, fuzzy @@ -736,7 +736,7 @@ msgstr "E242: 找ä¸åˆ°é¡è‰²: %s" #: ../eval.c:6499 #, c-format msgid "E721: Duplicate key in Dictionary: \"%s\"" -msgstr "" +msgstr "E721: Dictionary ä¸å‡ºç¾é‡è¤‡çš„éµ: \"%s\"" #: ../eval.c:6517 #, fuzzy, c-format @@ -781,7 +781,7 @@ msgstr "E120: <SID> ä¸èƒ½åœ¨ script 本文外使用: %s" #: ../eval.c:7391 #, c-format msgid "E725: Calling dict function without Dictionary: %s" -msgstr "" +msgstr "E725: 調用å—典函å¼ä½†æ˜¯æ²’有å—å…¸: %s" #: ../eval.c:7453 #, fuzzy @@ -814,16 +814,15 @@ msgstr "E227: %s çš„ mapping 已經å˜åœ¨" #: ../eval.c:8692 msgid "extend() argument" -msgstr "" +msgstr "extend() åƒæ•¸" #: ../eval.c:8915 -#, fuzzy msgid "map() argument" -msgstr "vim [åƒæ•¸] " +msgstr "map() åƒæ•¸" #: ../eval.c:8916 msgid "filter() argument" -msgstr "" +msgstr "filter() åƒæ•¸" #: ../eval.c:9229 #, c-format @@ -857,19 +856,19 @@ msgstr "E596: 䏿£ç¢ºçš„å—åž‹" #: ../eval.c:11980 msgid "E726: Stride is zero" -msgstr "" +msgstr "E726: æ¥é•·ç‚ºé›¶" #: ../eval.c:11982 msgid "E727: Start past end" -msgstr "" +msgstr "E727: 起始值在終æ¢å€¼å¾Œ" #: ../eval.c:12024 ../eval.c:15297 msgid "<empty>" -msgstr "" +msgstr "<空>" #: ../eval.c:12282 msgid "remove() argument" -msgstr "" +msgstr "remove() åƒæ•¸" #: ../eval.c:12466 msgid "E655: Too many symbolic links (cycle?)" @@ -877,11 +876,11 @@ msgstr "E655: 太多層的符號éˆçµ(symlink) (循環?)" #: ../eval.c:12593 msgid "reverse() argument" -msgstr "" +msgstr "reverse() åƒæ•¸" #: ../eval.c:13721 msgid "sort() argument" -msgstr "" +msgstr "sort() åƒæ•¸" #: ../eval.c:13721 #, fuzzy @@ -895,7 +894,7 @@ msgstr "E237: ç„¡æ³•é¸æ“‡æ¤å°è¡¨æ©Ÿ" #: ../eval.c:13806 msgid "E882: Uniq compare function failed" -msgstr "" +msgstr "E882: Uniq 比較函å¼å¤±æ•—" #: ../eval.c:14085 msgid "(Invalid)" @@ -908,32 +907,31 @@ msgstr "E208: 寫入檔案 \"%s\" 錯誤" #: ../eval.c:16159 msgid "E805: Using a Float as a Number" -msgstr "" +msgstr "E805: å°‡æµ®é»žæ•¸ç•¶åšæ•¸å—使用" #: ../eval.c:16162 msgid "E703: Using a Funcref as a Number" -msgstr "" +msgstr "E703: 將函å¼ç•¶å𿕏å—使用" #: ../eval.c:16170 msgid "E745: Using a List as a Number" -msgstr "" +msgstr "E745: å°‡åˆ—è¡¨ç•¶åšæ•¸å—使用" #: ../eval.c:16173 msgid "E728: Using a Dictionary as a Number" -msgstr "" +msgstr "E728: å°‡å—å…¸ç•¶åšæ•¸å—使用" #: ../eval.c:16259 msgid "E729: using Funcref as a String" -msgstr "" +msgstr "E729: 將函å¼ç•¶åšå—串使用" #: ../eval.c:16262 -#, fuzzy msgid "E730: using List as a String" -msgstr "E374: æ ¼å¼åŒ–å—串裡少了 ]" +msgstr "E730: 將列表當åšå—串使用" #: ../eval.c:16265 msgid "E731: using Dictionary as a String" -msgstr "" +msgstr "E731: å°‡å—典當åšå—串使用" #: ../eval.c:16619 #, fuzzy, c-format @@ -953,12 +951,12 @@ msgstr "E128: 函å¼åç¨±ç¬¬ä¸€å€‹å—æ¯å¿…é ˆå¤§å¯«: %s" #: ../eval.c:16732 #, c-format msgid "E705: Variable name conflicts with existing function: %s" -msgstr "" +msgstr "E705: 變數å與已有函å¼åè¡çª: %s" #: ../eval.c:16763 #, c-format msgid "E741: Value is locked: %s" -msgstr "" +msgstr "E741: 值已鎖定: %s" #: ../eval.c:16764 ../eval.c:16769 ../message.c:1839 msgid "Unknown" @@ -971,7 +969,7 @@ msgstr "E284: ä¸èƒ½è¨å®š IC 數值" #: ../eval.c:16838 msgid "E698: variable nested too deep for making a copy" -msgstr "" +msgstr "E698: è®Šæ•¸åµŒå¥—éŽæ·±ç„¡æ³•複製" #: ../eval.c:17249 #, c-format @@ -1216,7 +1214,7 @@ msgstr "è¦è¦†å¯«å·²å˜åœ¨çš„æª”案 \"%.*s\"?" #: ../ex_cmds.c:2317 #, c-format msgid "Swap file \"%s\" exists, overwrite anyway?" -msgstr "" +msgstr "äº¤æ›æ–‡ä»¶ \"%s\" å·²å˜åœ¨ï¼Œç¢ºå¯¦éœ€è¦è¦†è“‹å—Žï¼Ÿ" #: ../ex_cmds.c:2326 #, fuzzy, c-format @@ -1456,7 +1454,7 @@ msgstr "%3d %s %s 第 %<PRId64> 行 " #: ../ex_cmds2.c:942 msgid "E750: First use \":profile start {fname}\"" -msgstr "" +msgstr "E750: 請先使用 :profile start <fname>" #: ../ex_cmds2.c:1269 #, fuzzy, c-format @@ -1555,7 +1553,7 @@ msgstr "vim [åƒæ•¸] " #: ../ex_cmds2.c:2771 msgid "environment variable" -msgstr "" +msgstr "環境變數" #: ../ex_cmds2.c:2773 #, fuzzy @@ -2047,7 +2045,7 @@ msgstr "E199: 已刪除掉作用ä¸çš„視窗或暫å˜å€" #: ../file_search.c:203 msgid "E854: path too long for completion" -msgstr "" +msgstr "E854: 補全用的路徑太長了" #: ../file_search.c:446 #, c-format @@ -2099,11 +2097,11 @@ msgstr "[未命å]" #: ../fileio.c:511 msgid "[New DIRECTORY]" -msgstr "" +msgstr "[新目錄]" #: ../fileio.c:529 ../fileio.c:532 msgid "[File too big]" -msgstr "" +msgstr "[文件太大]" #: ../fileio.c:534 msgid "[Permission Denied]" @@ -2265,7 +2263,7 @@ msgstr "E513: 無法寫入 -- 轉æ›å¤±æ•—" msgid "" "E513: write error, conversion failed in line %<PRId64> (make 'fenc' empty to " "override)" -msgstr "" +msgstr "E513: 寫入錯誤,轉æ›å¤±æ•— (è«‹å°‡ 'fenc' 置空以強制執行)" #: ../fileio.c:3448 msgid "E514: write error (file system full?)" @@ -2720,7 +2718,7 @@ msgstr "E49: 錯誤的æ²å‹•大å°" #: ../globals.h:1021 msgid "E901: Job table is full" -msgstr "" +msgstr "E901: 任務表已經滿" #: ../globals.h:1024 #, c-format @@ -2877,7 +2875,7 @@ msgstr "E42: 沒有錯誤" #: ../globals.h:1067 msgid "E776: No location list" -msgstr "" +msgstr "E776: 沒有ä½ç½®åˆ—表" #: ../globals.h:1068 msgid "E43: Damaged match string" @@ -2992,7 +2990,7 @@ msgstr "E473: 內部錯誤" #: ../globals.h:1104 msgid "E363: pattern uses more memory than 'maxmempattern'" -msgstr "" +msgstr "E363: 表é”å¼çš„å…§å˜è¶…出 'maxmempattern'" #: ../globals.h:1105 #, fuzzy @@ -3097,15 +3095,15 @@ msgstr "E621: \"%s\" è³‡æºæª”版本錯誤" #: ../hardcopy.c:2225 msgid "E673: Incompatible multi-byte encoding and character set." -msgstr "" +msgstr "E673: ä¸å…¼å®¹çš„多å—節編碼和å—元集" #: ../hardcopy.c:2238 msgid "E674: printmbcharset cannot be empty with multi-byte encoding." -msgstr "" +msgstr "E674: printmbcharset 在多å—節編碼下ä¸èƒ½ç‚ºç©º" #: ../hardcopy.c:2254 msgid "E675: No default font specified for multi-byte printing." -msgstr "" +msgstr "E675: 沒有指定多å—節打å°çš„默èªå—åž‹" #: ../hardcopy.c:2426 msgid "E324: Can't open PostScript output file" @@ -3267,6 +3265,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" @@ -3276,6 +3275,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" @@ -3509,7 +3518,7 @@ msgstr "-N\t\t\t'nocompatible' ä¸å®Œå…¨èˆ‡å‚³çµ± Vi 相容,å¯ä½¿ç”¨ Vim åŠ å #: ../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" @@ -3602,7 +3611,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" @@ -3794,7 +3803,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 @@ -4082,7 +4091,7 @@ msgstr "E317: 指標å€å¡Š id 錯 2" #: ../memline.c:3070 #, c-format msgid "E773: Symlink loop for \"%s\"" -msgstr "" +msgstr "E773: \"%s\" ç¬¦è™ŸéˆæŽ¥å‡ºç¾å¾ªç’°" #: ../memline.c:3221 msgid "E325: ATTENTION" @@ -4231,7 +4240,7 @@ msgstr "E329: 沒有那樣的é¸å–®" #. Only a mnemonic or accelerator is not valid. #: ../menu.c:329 msgid "E792: Empty menu name" -msgstr "" +msgstr "E792: 空的èœå–®å稱" #: ../menu.c:340 msgid "E330: Menu path must not lead to a sub-menu" @@ -4312,7 +4321,7 @@ msgstr "-- 尚有 --" #: ../message.c:2398 msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit " -msgstr "" +msgstr " ç©ºæ ¼/d/j: å±å¹•/é /行 下翻,b/u/k: 上翻,q: 退出 " #: ../message.c:3021 ../message.c:3031 msgid "Question" @@ -4357,7 +4366,7 @@ msgstr "E116: å‡½å¼ %s çš„å¼•æ•¸ä¸æ£ç¢º" #: ../message.c:3119 msgid "E807: Expected Float argument for printf()" -msgstr "" +msgstr "E807: 期盼浮點數作為printf()åƒæ•¸" #: ../message.c:3873 #, fuzzy @@ -4370,11 +4379,11 @@ msgstr "W10: 注æ„: ä½ æ£åœ¨ä¿®æ”¹ä¸€å€‹å”¯è®€æª”" #: ../misc1.c:2537 msgid "Type number and <Enter> or click with mouse (empty cancels): " -msgstr "" +msgstr "請輸入數å—並<Enter>æˆ–é»žæ“Šé¼ æ¨™ï¼ˆç©ºç™½å–æ¶ˆï¼‰: " #: ../misc1.c:2539 msgid "Type number and <Enter> (empty cancels): " -msgstr "" +msgstr "è«‹é¸æ“‡æ•¸å—並(<Enter> å–æ¶ˆ): " #: ../misc1.c:2585 msgid "1 more line" @@ -4400,7 +4409,7 @@ msgstr " (已䏿–·)" #: ../misc1.c:2635 msgid "Beep!" -msgstr "" +msgstr "Beep!" #: ../misc2.c:738 #, c-format @@ -4617,7 +4626,7 @@ msgstr "E520: ä¸èƒ½åœ¨ Modeline 裡出ç¾" #: ../option.c:2815 msgid "E846: Key code not set" -msgstr "" +msgstr "E846: 未è¨ç½®éµä½ä»£ç¢¼" #: ../option.c:2924 msgid "E521: Number required after =" @@ -4642,11 +4651,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" @@ -4884,7 +4893,7 @@ msgstr "E382: 無法寫入,'buftype' é¸é …å·²è¨å®š" #: ../quickfix.c:2812 msgid "E683: File name missing or invalid pattern" -msgstr "" +msgstr "E683: ç¼ºå°‘æ–‡ä»¶åæˆ–模å¼ç„¡æ•ˆ" #: ../quickfix.c:2911 #, fuzzy, c-format @@ -5022,25 +5031,26 @@ 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 @@ -5050,21 +5060,21 @@ msgstr "" #: ../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 @@ -5073,31 +5083,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 @@ -5270,17 +5281,17 @@ msgstr "E297: æš«å˜æª”寫入錯誤" #: ../spell.c:952 msgid "E758: Truncated spell file" -msgstr "" +msgstr "E758: 已截斷的拼寫文件" #: ../spell.c:953 #, c-format msgid "Trailing text in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,多餘的後續文本: %s" #: ../spell.c:954 #, c-format msgid "Affix name too long in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d è¡Œï¼Œé™„åŠ é …åå—太長: %s" #: ../spell.c:955 #, fuzzy @@ -5289,20 +5300,20 @@ msgstr "E431: Tag 檔 \"%s\" æ ¼å¼éŒ¯èª¤" #: ../spell.c:957 msgid "E762: Character in FOL, LOW or UPP is out of range" -msgstr "" +msgstr "E762: FOLã€LOW 或 UPP ä¸å—元超出範åœ" #: ../spell.c:958 msgid "Compressing word tree..." -msgstr "" +msgstr "壓縮單詞樹……" #: ../spell.c:1951 msgid "E756: Spell checking is not enabled" -msgstr "" +msgstr "E756: 拼寫檢查未啟用" #: ../spell.c:2249 #, c-format msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\"" -msgstr "" +msgstr "è¦å‘Š: 找ä¸åˆ°å–®è©žåˆ—表 \"%s.%s.spl\" or \"%s.ascii.spl\"" #: ../spell.c:2473 #, fuzzy, c-format @@ -5316,11 +5327,11 @@ msgstr "E307: %s 看起來ä¸åƒæ˜¯ Vim æš«å˜æª”" #: ../spell.c:2501 msgid "E771: Old spell file, needs to be updated" -msgstr "" +msgstr "E771: èˆŠçš„æ‹¼å¯«æ–‡ä»¶ï¼Œéœ€è¦æ›´æ–°" #: ../spell.c:2504 msgid "E772: Spell file is for newer version of Vim" -msgstr "" +msgstr "E772: 為更高版本的 Vim 所使用的拼寫文件" #: ../spell.c:2602 #, fuzzy @@ -5340,66 +5351,68 @@ msgstr "æœå°‹ tag 檔案 \"%s\"" #: ../spell.c:4589 ../spell.c:5635 ../spell.c:6140 #, c-format msgid "Conversion failure for word in %s line %d: %s" -msgstr "" +msgstr "單詞 %s 轉æ›å¤±æ•—,第 %d 行: %s" #: ../spell.c:4630 ../spell.c:6170 #, c-format msgid "Conversion in %s not supported: from %s to %s" -msgstr "" +msgstr "䏿”¯æŒ %s ä¸çš„轉æ›: 从 %s 到 %s" #: ../spell.c:4642 #, c-format msgid "Invalid value for FLAG in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,FLAG çš„å€¼æ— æ•ˆ: %s" #: ../spell.c:4655 #, c-format msgid "FLAG after using flags in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d è¡Œï¼Œåœ¨ä½¿ç”¨æ¨™å¿—å¾Œå‡ºç¾ FLAG: %s" #: ../spell.c:4723 #, c-format 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 é …ä¹‹å¾Œå®šç¾© COMPOUNDFORBIDFLAG (%s 第%d行)å¯èƒ½æœƒçµ¦å‡ºçš„éŒ¯èª¤çµæžœ" +"%d" #: ../spell.c:4747 #, c-format msgid "Wrong COMPOUNDRULES value in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,错误的 COMPOUNDMIN 值: %s" #: ../spell.c:4771 #, c-format msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,错误的 COMPOUNDWORDMAX 值: %s" #: ../spell.c:4777 #, c-format msgid "Wrong COMPOUNDMIN value in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,错误的 COMPOUNDMIN 值: %s" #: ../spell.c:4783 #, c-format msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,错误的 COMPOUNDSYLMAX 值: %s" #: ../spell.c:4795 #, c-format msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,错误的 CHECKCOMPOUNDPATTERN 值: %s" #: ../spell.c:4847 #, c-format msgid "Different combining flag in continued affix block in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d è¡Œï¼Œåœ¨é€£çºŒçš„é™„åŠ å¡Šç¨®å‡ºç¾ä¸åŒçš„çµ„åˆæ¨™èªŒ: %s" #: ../spell.c:4850 #, fuzzy, c-format @@ -5412,45 +5425,47 @@ msgid "" "Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s " "line %d: %s" msgstr "" +"%s 第 %d è¡Œï¼Œé™„åŠ é …è¢« BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST 使" +"用: %s" #: ../spell.c:4893 #, c-format msgid "Expected Y or N in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,æ¤è™•éœ€è¦ Y 或 N: %s" #: ../spell.c:4968 #, c-format msgid "Broken condition in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,錯誤的æ¢ä»¶: %s" #: ../spell.c:5091 #, c-format msgid "Expected REP(SAL) count in %s line %d" -msgstr "" +msgstr "%s 第 %d 行,æ¤è™•éœ€è¦ REP(SAL) 計數" #: ../spell.c:5120 #, c-format msgid "Expected MAP count in %s line %d" -msgstr "" +msgstr "%s 第 %d 行,æ¤è™•éœ€è¦ MAP 計數" #: ../spell.c:5132 #, c-format msgid "Duplicate character in MAP in %s line %d" -msgstr "" +msgstr "%s 第 %d 行,MAP ä¸å˜åœ¨é‡è¤‡çš„å—å…ƒ" #: ../spell.c:5176 #, c-format msgid "Unrecognized or duplicate item in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,無法è˜åˆ¥æˆ–é‡è¤‡çš„é …: %s" #: ../spell.c:5197 #, c-format msgid "Missing FOL/LOW/UPP line in %s" -msgstr "" +msgstr "%s ä¸ç¼ºå°‘ FOL/LOW/UPP 行" #: ../spell.c:5220 msgid "COMPOUNDSYLMAX used without SYLLABLE" -msgstr "" +msgstr "在没有 SYLLABLE 的情æ³ä¸‹ä½¿ç”¨äº† COMPOUNDSYLMAX" #: ../spell.c:5236 #, fuzzy @@ -5464,32 +5479,32 @@ msgstr "å¤ªå¤šç·¨è¼¯åƒæ•¸" #: ../spell.c:5240 msgid "Too many postponed prefixes and/or compound flags" -msgstr "" +msgstr "太多延é²å‰ç¶´å’Œ/æˆ–çµ„åˆæ¨™èªŒ" #: ../spell.c:5250 #, c-format msgid "Missing SOFO%s line in %s" -msgstr "" +msgstr "%s ä¸ç¼ºå°‘ SOFO%s 行" #: ../spell.c:5253 #, c-format msgid "Both SAL and SOFO lines in %s" -msgstr "" +msgstr "%s åŒæ™‚å‡ºç¾ SAL å’Œ SOFO 行" #: ../spell.c:5331 #, c-format msgid "Flag is not a number in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d è¡Œï¼Œæ¨™èªŒä¸æ˜¯æ•¸å—: %s" #: ../spell.c:5334 #, c-format msgid "Illegal flag in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,無效的標誌: %s" #: ../spell.c:5493 ../spell.c:5501 #, c-format msgid "%s value differs from what is used in another .aff file" -msgstr "" +msgstr "%s 的值與å¦ä¸€å€‹ .aff 文件ä¸ä½¿ç”¨çš„值ä¸ç›¸åŒ" #: ../spell.c:5602 #, fuzzy, c-format @@ -5499,12 +5514,12 @@ msgstr "掃瞄å—å…¸: %s" #: ../spell.c:5611 #, c-format msgid "E760: No word count in %s" -msgstr "" +msgstr "E760: %s 䏿²¡æœ‰å–®è©žè¨ˆæ•¸" #: ../spell.c:5669 #, c-format msgid "line %6d, word %6d - %s" -msgstr "" +msgstr "第 %6d 行,第 %6d 个單詞 - %s" #: ../spell.c:5691 #, fuzzy, c-format @@ -5514,17 +5529,17 @@ msgstr "æ¯ä¸€è¡Œéƒ½æ‰¾ä¸åˆ°: %s" #: ../spell.c:5694 #, c-format msgid "First duplicate word in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,首次出ç¾é‡è¤‡çš„單詞: %s" #: ../spell.c:5746 #, c-format msgid "%d duplicate word(s) in %s" -msgstr "" +msgstr "å˜åœ¨ %d 个é‡è¤‡çš„單詞,在 %s ä¸" #: ../spell.c:5748 #, c-format msgid "Ignored %d word(s) with non-ASCII characters in %s" -msgstr "" +msgstr "å¿½ç•¥äº†å«æœ‰éž ASCII å—元的 %d 个單詞,在 %s ä¸" #: ../spell.c:6115 #, fuzzy, c-format @@ -5534,42 +5549,42 @@ msgstr "從標準輸入讀å–..." #: ../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 msgid "/encoding= line after word ignored in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,å•è¯åŽçš„ /encoding= 行已被忽略: %s" #: ../spell.c:6180 #, c-format msgid "Duplicate /regions= line ignored in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,é‡å¤çš„ /regions= 行已被忽略: %s" #: ../spell.c:6185 #, c-format msgid "Too many regions in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,太多å€åŸŸ: %s" #: ../spell.c:6198 #, c-format msgid "/ line ignored in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,/ 行已被忽略: %s" #: ../spell.c:6224 #, fuzzy, c-format msgid "Invalid region nr in %s line %d: %s" -msgstr "E573: 䏿£ç¢ºçš„伺æœå™¨ id : %s" +msgstr "%s 第 %d 行,無效的å€åŸŸè™Ÿ: %s" #: ../spell.c:6230 #, c-format msgid "Unrecognized flags in %s line %d: %s" -msgstr "" +msgstr "%s 第 %d 行,ä¸å¯è˜åˆ¥çš„æ¨™èªŒ: %s" #: ../spell.c:6257 #, c-format msgid "Ignored %d words with non-ASCII characters" -msgstr "" +msgstr "å¿½ç•¥äº†å«æœ‰éž ASCII å—元的 %d 个單詞" #: ../spell.c:6656 #, c-format @@ -5578,23 +5593,23 @@ msgstr "" #: ../spell.c:7340 msgid "Reading back spell file..." -msgstr "" +msgstr "è¯»å–æ‹¼å¯«æ–‡ä»¶â€¦â€¦" #. Go through the trie of good words, soundfold each word and add it to #. the soundfold trie. #: ../spell.c:7357 msgid "Performing soundfolding..." -msgstr "" +msgstr "æ£åœ¨ soundfolding……" #: ../spell.c:7368 #, c-format msgid "Number of words after soundfolding: %<PRId64>" -msgstr "" +msgstr "soundfolding åŽçš„單詞数: %<PRId64>" #: ../spell.c:7476 #, c-format msgid "Total number of words: %d" -msgstr "" +msgstr "單詞总数: %d" #: ../spell.c:7655 #, fuzzy, c-format @@ -5604,11 +5619,11 @@ msgstr "寫入 viminfo 檔案 \"%s\" ä¸" #: ../spell.c:7707 ../spell.c:7927 #, c-format msgid "Estimated runtime memory use: %d bytes" -msgstr "" +msgstr "估計é‹è¡Œæ™‚的內å˜ç”¨é‡: %d ä½å…ƒ" #: ../spell.c:7820 msgid "E751: Output file name must not have region name" -msgstr "" +msgstr "E751: 輸出文件ä¸èƒ½å«æœ‰å€åŸŸå" #: ../spell.c:7822 #, fuzzy @@ -5622,7 +5637,7 @@ msgstr "E15: 䏿£ç¢ºçš„é‹ç®—å¼: %s" #: ../spell.c:7907 msgid "Warning: both compounding and NOBREAK specified" -msgstr "" +msgstr "è¦å‘Š: åŒæ™‚指定了 compounding å’Œ NOBREAK" #: ../spell.c:7920 #, fuzzy, c-format @@ -5631,30 +5646,30 @@ msgstr "寫入 viminfo 檔案 \"%s\" ä¸" #: ../spell.c:7925 msgid "Done!" -msgstr "" +msgstr "完æˆï¼" #: ../spell.c:8034 #, c-format msgid "E765: 'spellfile' does not have %<PRId64> entries" -msgstr "" +msgstr "E765: 'spellfile' 没有 %<PRId64> é …" #: ../spell.c:8074 #, c-format msgid "Word '%.*s' removed from %s" -msgstr "" +msgstr "从 %s ä¸åˆ 除了單詞" #: ../spell.c:8117 #, c-format msgid "Word '%.*s' added to %s" -msgstr "" +msgstr "å‘ %s 䏿·»åŠ äº†å–®è©ž" #: ../spell.c:8381 msgid "E763: Word characters differ between spell files" -msgstr "" +msgstr "E763: 拼寫文件之間的å—å…ƒä¸ç›¸åŒ" #: ../spell.c:8684 msgid "Sorry, no suggestions" -msgstr "" +msgstr "抱æ‰ï¼Œæ²¡æœ‰å»ºè®®" #: ../spell.c:8687 #, fuzzy, c-format @@ -5671,7 +5686,7 @@ msgstr "將變動å˜å„²è‡³ \"%.*s\"?" #: ../spell.c:8737 #, c-format msgid " < \"%.*s\"" -msgstr "" +msgstr " < \"%.*s\"" #: ../spell.c:8882 #, fuzzy @@ -5691,28 +5706,28 @@ msgstr "E307: %s 看起來ä¸åƒæ˜¯ Vim æš«å˜æª”" #: ../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 msgid "E782: error while reading .sug file: %s" -msgstr "E47: 讀å–錯誤檔案失敗" +msgstr "E782: 當讀å–.sug 文件時錯誤" #. This should have been checked when generating the .spl #. 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" @@ -5894,10 +5909,11 @@ msgstr "E410: 䏿£ç¢ºçš„ :syntax å命令: %s" msgid "" " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN" msgstr "" +" 總 計 計 數 匹 é… æœ€ æ…¢ çš„ å¹³ å‡ å å— æ¨¡ å¼" #: ../syntax.c:6146 msgid "E679: recursive loop loading syncolor.vim" -msgstr "" +msgstr "E679: åŠ è¼‰ syncolor.vim 时出ç¾åµŒå¥—循環" #: ../syntax.c:6256 #, c-format @@ -5969,13 +5985,13 @@ msgstr "E424: 使用了éŽå¤šç›¸ç•°çš„高亮度屬性" msgid "E669: Unprintable character in group name" msgstr "E669: 群組åç¨±ä¸æœ‰ç„¡æ³•列å°çš„å—å…ƒ" -#: ../syntax.c:7434 -msgid "W18: Invalid character in group name" -msgstr "W18: 群組åç¨±ä¸æœ‰ä¸æ£ç¢ºçš„å—å…ƒ" +#: ../highlight_group.c:1756 +msgid "E5248: Invalid character in group name" +msgstr "E5248: 群組åç¨±ä¸æœ‰ä¸æ£ç¢ºçš„å—å…ƒ" #: ../syntax.c:7448 msgid "E849: Too many highlight and syntax groups" -msgstr "" +msgstr "E849: 高亮和語法組éŽå¤š" #: ../tag.c:104 msgid "E555: at bottom of tag stack" @@ -6083,7 +6099,7 @@ msgstr "E435: 找ä¸åˆ° tag, 用猜的!" #: ../tag.c:2797 #, c-format msgid "Duplicate field name: %s" -msgstr "" +msgstr "é‡è¤‡çš„å—æ®µå: %s" #: ../term.c:1442 msgid "' not known. Available builtin terminals are:" @@ -6131,35 +6147,35 @@ msgstr "Vim: 讀å–輸入錯誤,離開ä¸...\n" #. * file in a way it becomes shorter. #: ../undo.c:379 msgid "E881: Line count changed unexpectedly" -msgstr "" +msgstr "E881: 行數æ„外地改變了" #: ../undo.c:627 -#, fuzzy, c-format +#, c-format msgid "E828: Cannot open undo file for writing: %s" -msgstr "E212: 無法以寫入模å¼é–‹å•Ÿ" +msgstr "E828: 無法打開撤銷文件去寫入" #: ../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 @@ -6174,7 +6190,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 @@ -6198,7 +6214,7 @@ msgstr "E484: 無法開啟檔案 %s" #: ../undo.c:1328 msgid "File contents changed, cannot use undo info" -msgstr "" +msgstr "文件內容已經改變,ä¸èƒ½ä½¿ç”¨æ’¤éŠ·ä¿¡æ¯" #: ../undo.c:1497 #, fuzzy, c-format @@ -6207,11 +6223,11 @@ msgstr "çµæŸåŸ·è¡Œ %s" #: ../undo.c:1586 ../undo.c:1812 msgid "Already at oldest change" -msgstr "" +msgstr "已經在最早的改變" #: ../undo.c:1597 ../undo.c:1814 msgid "Already at newest change" -msgstr "" +msgstr "已經在最新的改變" #: ../undo.c:1806 #, fuzzy, c-format @@ -6259,11 +6275,11 @@ msgstr "%<PRId64> 行 %s éŽ %d 次" #: ../undo.c:2228 msgid "before" -msgstr "" +msgstr "之å‰" #: ../undo.c:2228 msgid "after" -msgstr "" +msgstr "之後" #: ../undo.c:2325 #, fuzzy @@ -6272,7 +6288,7 @@ msgstr "沒有這個 mapping å°æ‡‰" #: ../undo.c:2330 msgid "number changes when saved" -msgstr "" +msgstr " 編號 改變 時間 ä¿å˜" #: ../undo.c:2360 #, fuzzy, c-format diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index a4afe97ac8..74376c8b8a 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -156,7 +156,6 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i if (pum_external) { if (array_changed) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array arr = arena_array(&arena, (size_t)size); for (int i = 0; i < size; i++) { Array item = arena_array(&arena, 4); @@ -168,7 +167,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i } ui_call_popupmenu_show(arr, selected, pum_win_row, cursor_col, pum_anchor_grid); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } else { ui_call_popupmenu_select(selected); return; @@ -525,7 +524,7 @@ void pum_redraw(void) } if (pum_rl) { - char *rt = (char *)reverse_text(st); + char *rt = reverse_text((char *)st); char *rt_start = rt; int size = vim_strsize(rt); @@ -543,14 +542,13 @@ void pum_redraw(void) size++; } } - grid_puts_len(&pum_grid, (char_u *)rt, (int)STRLEN(rt), row, - grid_col - size + 1, attr); + grid_puts_len(&pum_grid, rt, (int)strlen(rt), row, grid_col - size + 1, attr); xfree(rt_start); xfree(st); grid_col -= width; } else { // use grid_puts_len() to truncate the text - grid_puts(&pum_grid, st, row, grid_col, attr); + grid_puts(&pum_grid, (char *)st, row, grid_col, attr); xfree(st); grid_col += width; } @@ -561,11 +559,11 @@ void pum_redraw(void) // Display two spaces for a Tab. if (pum_rl) { - grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1, + grid_puts_len(&pum_grid, " ", 2, row, grid_col - 1, attr); grid_col -= 2; } else { - grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr); + grid_puts_len(&pum_grid, " ", 2, row, grid_col, attr); grid_col += 2; } totwidth += 2; @@ -704,7 +702,7 @@ static bool pum_set_selected(int n, int repeat) if ((pum_array[pum_selected].pum_info != NULL) && (Rows > 10) && (repeat <= 1) - && (vim_strchr((char *)p_cot, 'p') != NULL)) { + && (vim_strchr(p_cot, 'p') != NULL)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; int res = OK; @@ -744,11 +742,11 @@ static bool pum_set_selected(int n, int repeat) if (res == OK) { // Edit a new, empty buffer. Set options for a "wipeout" // buffer. - set_option_value("swf", 0L, NULL, OPT_LOCAL); - set_option_value("bl", 0L, NULL, OPT_LOCAL); - set_option_value("bt", 0L, "nofile", OPT_LOCAL); - set_option_value("bh", 0L, "wipe", OPT_LOCAL); - set_option_value("diff", 0L, NULL, OPT_LOCAL); + set_option_value_give_err("swf", 0L, NULL, OPT_LOCAL); + set_option_value_give_err("bl", 0L, NULL, OPT_LOCAL); + set_option_value_give_err("bt", 0L, "nofile", OPT_LOCAL); + set_option_value_give_err("bh", 0L, "wipe", OPT_LOCAL); + set_option_value_give_err("diff", 0L, NULL, OPT_LOCAL); } } @@ -802,7 +800,7 @@ static bool pum_set_selected(int n, int repeat) // Return cursor to where we were validate_cursor(); - redraw_later(curwin, SOME_VALID); + redraw_later(curwin, UPD_SOME_VALID); // When the preview window was resized we need to // update the view on the buffer. Only go back to @@ -820,7 +818,7 @@ static bool pum_set_selected(int n, int repeat) // TODO(bfredl): can simplify, get rid of the flag munging? // or at least eliminate extra redraw before win_enter()? pum_is_visible = false; - update_screen(0); + update_screen(); pum_is_visible = true; if (!resized && win_valid(curwin_save)) { @@ -832,7 +830,7 @@ static bool pum_set_selected(int n, int repeat) // May need to update the screen again when there are // autocommands involved. pum_is_visible = false; - update_screen(0); + update_screen(); pum_is_visible = true; } } @@ -1047,6 +1045,10 @@ void pum_show_popupmenu(vimmenu_T *menu) pum_selected = -1; pum_first = 0; + if (!p_mousemev) { + // Pretend 'mousemoveevent' is set. + ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(true)); + } for (;;) { pum_is_visible = true; @@ -1104,6 +1106,9 @@ void pum_show_popupmenu(vimmenu_T *menu) xfree(array); pum_undisplay(true); + if (!p_mousemev) { + ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(false)); + } } void pum_make_popup(const char *path_name, int use_mouse_pos) diff --git a/src/nvim/profile.c b/src/nvim/profile.c index d4f3756f4d..50a8a371f5 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -279,7 +279,7 @@ void ex_profile(exarg_T *eap) char *e; int len; - e = (char *)skiptowhite((char_u *)eap->arg); + e = skiptowhite(eap->arg); len = (int)(e - eap->arg); e = skipwhite(e); @@ -291,23 +291,23 @@ void ex_profile(exarg_T *eap) set_vim_var_nr(VV_PROFILING, 1L); } else if (do_profiling == PROF_NONE) { emsg(_("E750: First use \":profile start {fname}\"")); - } else if (STRCMP(eap->arg, "stop") == 0) { + } else if (strcmp(eap->arg, "stop") == 0) { profile_dump(); do_profiling = PROF_NONE; set_vim_var_nr(VV_PROFILING, 0L); profile_reset(); - } else if (STRCMP(eap->arg, "pause") == 0) { + } else if (strcmp(eap->arg, "pause") == 0) { if (do_profiling == PROF_YES) { pause_time = profile_start(); } do_profiling = PROF_PAUSED; - } else if (STRCMP(eap->arg, "continue") == 0) { + } else if (strcmp(eap->arg, "continue") == 0) { if (do_profiling == PROF_PAUSED) { pause_time = profile_end(pause_time); profile_set_wait(profile_add(profile_get_wait(), pause_time)); } do_profiling = PROF_YES; - } else if (STRCMP(eap->arg, "dump") == 0) { + } else if (strcmp(eap->arg, "dump") == 0) { profile_dump(); } else { // The rest is similar to ":breakadd". @@ -354,7 +354,7 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg) pexpand_what = PEXP_SUBCMD; xp->xp_pattern = (char *)arg; - char_u *const end_subcmd = skiptowhite((const char_u *)arg); + char_u *const end_subcmd = (char_u *)skiptowhite(arg); if (*end_subcmd == NUL) { return; } @@ -612,7 +612,7 @@ static void func_dump_profile(FILE *fd) .script_ctx = fp->uf_script_ctx, .channel_id = 0, }; - char *p = (char *)get_scriptname(last_set, &should_free); + char *p = get_scriptname(last_set, &should_free); fprintf(fd, " Defined: %s:%" PRIdLINENR "\n", p, fp->uf_script_ctx.sc_lnum); if (should_free) { @@ -721,14 +721,14 @@ static void script_dump_profile(FILE *fd) fprintf(fd, "\n"); fprintf(fd, "count total (s) self (s)\n"); - sfd = os_fopen((char *)si->sn_name, "r"); + sfd = os_fopen(si->sn_name, "r"); if (sfd == NULL) { fprintf(fd, "Cannot open file!\n"); } else { // Keep going till the end of file, so that trailing // continuation lines are listed. for (int i = 0;; i++) { - if (vim_fgets(IObuff, IOSIZE, sfd)) { + if (vim_fgets((char_u *)IObuff, IOSIZE, sfd)) { break; } // When a line has been truncated, append NL, taking care diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 17fbbe17b8..f9d139c466 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -67,9 +67,9 @@ struct qfline_S { char *qf_module; ///< module name for this error char *qf_pattern; ///< search pattern for the error char *qf_text; ///< description of the error - char qf_viscol; ///< set to TRUE if qf_col and qf_end_col is + char qf_viscol; ///< set to true if qf_col and qf_end_col is // screen column - char qf_cleared; ///< set to TRUE if line has been deleted + char qf_cleared; ///< set to true if line has been deleted char qf_type; ///< type of the error (mostly 'E'); 1 for :helpgrep char qf_valid; ///< valid error message detected }; @@ -100,7 +100,7 @@ typedef struct qf_list_S { qfline_T *qf_ptr; ///< pointer to the current error int qf_count; ///< number of errors (0 means empty list) int qf_index; ///< current index in the error list - int qf_nonevalid; ///< TRUE if not a single valid entry found + int qf_nonevalid; ///< true if not a single valid entry found char *qf_title; ///< title derived from the command that created ///< the error list or set by setqflist typval_T *qf_ctx; ///< context set by setqflist/setloclist @@ -548,9 +548,9 @@ static void free_efm_list(efm_T **efm_first) /// a regular expression pattern. static size_t efm_regpat_bufsz(char *efm) { - size_t 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); + sz += strlen(fmt_pat[i--].pattern); } #ifdef BACKSLASH_IN_FILENAME sz += 12; // "%f" can become twelve chars longer (see efm_to_regpat) @@ -607,7 +607,7 @@ static efm_T *parse_efm_option(char *efm) goto parse_efm_error; } // Advance to next part - efm = (char *)skip_to_option_part((char_u *)efm + len); // skip comma and spaces + efm = skip_to_option_part(efm + len); // skip comma and spaces } if (fmt_first == NULL) { // nothing found @@ -652,7 +652,7 @@ static int qf_get_next_str_line(qfstate_T *state) } char *p = vim_strchr(p_str, '\n'); - size_t len = (p != NULL) ? (size_t)(p - p_str) + 1 : STRLEN(p_str); + 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); @@ -688,7 +688,7 @@ static int qf_get_next_list_line(qfstate_T *state) return QF_END_OF_INPUT; } - size_t 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 { @@ -710,10 +710,10 @@ static int qf_get_next_buf_line(qfstate_T *state) if (state->buflnum > state->lnumlast) { return QF_END_OF_INPUT; } - char *p_buf = (char *)ml_get_buf(state->buf, state->buflnum, false); + char *p_buf = ml_get_buf(state->buf, state->buflnum, false); state->buflnum += 1; - size_t len = STRLEN(p_buf); + size_t len = strlen(p_buf); if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { @@ -738,7 +738,7 @@ retry: } bool discard = false; - state->linelen = STRLEN(IObuff); + state->linelen = strlen(IObuff); if (state->linelen == IOSIZE - 1 && !(IObuff[state->linelen - 1] == '\n')) { // The current line exceeds IObuff, continue reading using growbuf @@ -761,7 +761,7 @@ retry: } break; } - state->linelen = STRLEN(state->growbuf + growbuflen); + state->linelen = strlen(state->growbuf + growbuflen); growbuflen += state->linelen; if (state->growbuf[growbuflen - 1] == '\n') { break; @@ -786,7 +786,7 @@ retry: } break; } - if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 2] == '\n') { + if (strlen(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 2] == '\n') { break; } } @@ -799,7 +799,7 @@ retry: // Convert a line if it contains a non-ASCII character if (state->vc.vc_type != CONV_NONE && has_non_ascii((char_u *)state->linebuf)) { - char *line = (char *)string_convert(&state->vc, (char_u *)state->linebuf, &state->linelen); + char *line = string_convert(&state->vc, state->linebuf, &state->linelen); if (line != NULL) { if (state->linelen < IOSIZE) { STRLCPY(state->linebuf, line, state->linelen + 1); @@ -1000,7 +1000,7 @@ static int qf_setup_state(qfstate_T *pstate, char *restrict enc, const char *res { pstate->vc.vc_type = CONV_NONE; if (enc != NULL && *enc != NUL) { - convert_setup(&pstate->vc, (char_u *)enc, p_enc); + convert_setup(&pstate->vc, enc, p_enc); } if (efile != NULL @@ -1091,14 +1091,14 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu // 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; + efm = buf->b_p_efm; } else { efm = errorformat; } // If the errorformat didn't change between calls, then reuse the previously // parsed values. - if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) { + if (last_efm == NULL || (strcmp(last_efm, efm) != 0)) { // free the previously parsed data XFREE_CLEAR(last_efm); free_efm_list(&fmt_first); @@ -1175,7 +1175,7 @@ static void qf_store_title(qf_list_T *qfl, const char *title) XFREE_CLEAR(qfl->qf_title); if (title != NULL) { - size_t len = STRLEN(title) + 1; + size_t len = strlen(title) + 1; char *p = xmallocz(len); qfl->qf_title = p; @@ -1242,15 +1242,15 @@ static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int pre } // Expand ~/file and $HOME/file to full path. - char c = (char)(*rmp->endp[midx]); + char c = *rmp->endp[midx]; *rmp->endp[midx] = NUL; - expand_env(rmp->startp[midx], (char_u *)fields->namebuf, CMDBUFFSIZE); - *rmp->endp[midx] = (char_u)c; + expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE); + *rmp->endp[midx] = c; // For separate filename patterns (%O, %P and %Q), the specified file // should exist. if (vim_strchr("OPQ", prefix) != NULL - && !os_path_exists((char_u *)fields->namebuf)) { + && !os_path_exists(fields->namebuf)) { return QF_FAIL; } @@ -1264,7 +1264,7 @@ static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->enr = (int)atol((char *)rmp->startp[midx]); + fields->enr = (int)atol(rmp->startp[midx]); return QF_OK; } @@ -1275,7 +1275,7 @@ static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->lnum = (linenr_T)atol((char *)rmp->startp[midx]); + fields->lnum = (linenr_T)atol(rmp->startp[midx]); return QF_OK; } @@ -1286,7 +1286,7 @@ static int qf_parse_fmt_e(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->end_lnum = (linenr_T)atol((char *)rmp->startp[midx]); + fields->end_lnum = (linenr_T)atol(rmp->startp[midx]); return QF_OK; } @@ -1297,7 +1297,7 @@ static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->col = (int)atol((char *)rmp->startp[midx]); + fields->col = (int)atol(rmp->startp[midx]); return QF_OK; } @@ -1308,7 +1308,7 @@ static int qf_parse_fmt_k(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->end_col = (int)atol((char *)rmp->startp[midx]); + fields->end_col = (int)atol(rmp->startp[midx]); return QF_OK; } @@ -1319,7 +1319,7 @@ static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->type = (char)(*rmp->startp[midx]); + fields->type = *rmp->startp[midx]; return QF_OK; } @@ -1360,7 +1360,7 @@ static int qf_parse_fmt_r(regmatch_T *rmp, int midx, char **tail) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - *tail = (char *)rmp->startp[midx]; + *tail = rmp->startp[midx]; return QF_OK; } @@ -1372,7 +1372,7 @@ static int qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields) return QF_FAIL; } fields->col = 0; - for (char *match_ptr = (char *)rmp->startp[midx]; (char_u *)match_ptr != rmp->endp[midx]; + for (char *match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx]; match_ptr++) { fields->col++; if (*match_ptr == TAB) { @@ -1392,7 +1392,7 @@ static int qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields) if (rmp->startp[midx] == NULL) { return QF_FAIL; } - fields->col = (int)atol((char *)rmp->startp[midx]); + fields->col = (int)atol(rmp->startp[midx]); fields->use_viscol = true; return QF_OK; } @@ -1409,7 +1409,7 @@ static int qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields) len = CMDBUFFSIZE - 5; } STRCPY(fields->pattern, "^\\V"); - STRLCAT(fields->pattern, rmp->startp[midx], len + 4); + xstrlcat(fields->pattern, rmp->startp[midx], len + 4); fields->pattern[len + 3] = '\\'; fields->pattern[len + 4] = '$'; fields->pattern[len + 5] = NUL; @@ -1424,11 +1424,11 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields) return QF_FAIL; } size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]); - size_t dsize = STRLEN(fields->module) + len + 1; + size_t dsize = strlen(fields->module) + len + 1; if (dsize > CMDBUFFSIZE) { dsize = CMDBUFFSIZE; } - STRLCAT(fields->module, rmp->startp[midx], dsize); + xstrlcat(fields->module, rmp->startp[midx], dsize); return QF_OK; } @@ -1564,7 +1564,7 @@ static int qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl) static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl, char *tail) { fields->valid = false; - if (*fields->namebuf == NUL || os_path_exists((char_u *)fields->namebuf)) { + if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) { if (*fields->namebuf && idx == 'P') { qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack, true); } else if (idx == 'Q') { @@ -1609,8 +1609,8 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields) return QF_FAIL; } if (*fields->errmsg) { - size_t textlen = STRLEN(qfprev->qf_text); - size_t errlen = STRLEN(fields->errmsg); + size_t textlen = strlen(qfprev->qf_text); + size_t errlen = strlen(fields->errmsg); qfprev->qf_text = xrealloc(qfprev->qf_text, textlen + errlen + 2); qfprev->qf_text[textlen] = '\n'; STRCPY(qfprev->qf_text + textlen + 1, fields->errmsg); @@ -1891,7 +1891,7 @@ static qf_info_T *ll_get_or_alloc_list(win_T *wp) /// Get the quickfix/location list stack to use for the specified Ex command. /// For a location list command, returns the stack for the current window. If /// the location list is not found, then returns NULL and prints an error -/// message if 'print_emsg' is TRUE. +/// message if 'print_emsg' is true. static qf_info_T *qf_cmd_get_stack(exarg_T *eap, int print_emsg) { qf_info_T *qi = &ql_info; @@ -2069,7 +2069,7 @@ static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) // This should normally be true, but if make works without // "leaving directory"-messages we might have missed a // directory change. - if (!os_path_exists((char_u *)ptr)) { + if (!os_path_exists(ptr)) { xfree(ptr); directory = qf_guess_filepath(qfl, fname); if (directory) { @@ -2085,7 +2085,7 @@ static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) } if (qf_last_bufname != NULL - && STRCMP(bufname, qf_last_bufname) == 0 + && strcmp(bufname, qf_last_bufname) == 0 && bufref_valid(&qf_last_bufref)) { buf = qf_last_bufref.br_buf; xfree(ptr); @@ -2129,7 +2129,7 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi while (ds_new) { xfree((*stackptr)->dirname); (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, true); - if (os_isdir((char_u *)(*stackptr)->dirname)) { + if (os_isdir((*stackptr)->dirname)) { break; } @@ -2223,7 +2223,7 @@ static char *qf_guess_filepath(qf_list_T *qfl, char *filename) xfree(fullname); fullname = concat_fnames(ds_ptr->dirname, filename, true); - if (os_path_exists((char_u *)fullname)) { + if (os_path_exists(fullname)) { break; } @@ -2511,7 +2511,7 @@ static win_T *qf_find_win_with_normal_buf(void) } // Go to a window in any tabpage containing the specified file. Returns true -// if successfully jumped to the window. Otherwise returns FALSE. +// if successfully jumped to the window. Otherwise returns false. static bool qf_goto_tabwin_with_file(int fnum) { FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -2784,14 +2784,17 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf // Update the screen before showing the message, unless the screen // scrolled up. if (!msg_scrolled) { - update_topline_redraw(); + update_topline(curwin); + if (must_redraw) { + update_screen(); + } } snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, qf_get_curlist(qi)->qf_count, qf_ptr->qf_cleared ? _(" (line deleted)") : "", qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); // Add the message, skipping leading whitespace and newlines. - int len = (int)STRLEN(IObuff); + int len = (int)strlen(IObuff); qf_fmt_text(skipwhite(qf_ptr->qf_text), (char *)IObuff + len, IOSIZE - len); // Output the message. Overwrite to avoid scrolling when the 'O' @@ -2923,7 +2926,7 @@ 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) { - char *old_swb = (char *)p_swb; + char *old_swb = p_swb; unsigned old_swb_flags = swb_flags; const bool old_KeyTyped = KeyTyped; // getting file may reset it @@ -2932,7 +2935,7 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo } if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) { - emsg(_(e_quickfix)); + emsg(_(e_no_errors)); return; } @@ -2994,10 +2997,10 @@ theend: qfl->qf_ptr = qf_ptr; qfl->qf_index = qf_index; } - if (p_swb != (char_u *)old_swb && p_swb == empty_option) { + if (p_swb != old_swb && p_swb == empty_option) { // Restore old 'switchbuf' value, but not when an autocommand or // modeline has changed the value. - p_swb = (char_u *)old_swb; + p_swb = old_swb; swb_flags = old_swb_flags; } decr_quickfix_busy(); @@ -3038,23 +3041,23 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) // text of the entry. bool filter_entry = true; if (qfp->qf_module != NULL && *qfp->qf_module != NUL) { - filter_entry &= message_filtered((char_u *)qfp->qf_module); + filter_entry &= message_filtered(qfp->qf_module); } if (filter_entry && fname != NULL) { - filter_entry &= message_filtered((char_u *)fname); + filter_entry &= message_filtered(fname); } if (filter_entry && qfp->qf_pattern != NULL) { - filter_entry &= message_filtered((char_u *)qfp->qf_pattern); + filter_entry &= message_filtered(qfp->qf_pattern); } if (filter_entry) { - filter_entry &= message_filtered((char_u *)qfp->qf_text); + filter_entry &= message_filtered(qfp->qf_text); } if (filter_entry) { return; } msg_putchar('\n'); - msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); + msg_outtrans_attr((char *)IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); if (qfp->qf_lnum != 0) { msg_puts_attr(":", qfSepAttr); @@ -3064,7 +3067,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } else { qf_range_text(qfp, (char *)IObuff, IOSIZE); } - vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr)); + vim_snprintf((char *)IObuff + strlen(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr)); msg_puts_attr((const char *)IObuff, qfLineAttr); msg_puts_attr(":", qfSepAttr); if (qfp->qf_pattern != NULL) { @@ -3074,9 +3077,9 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) } msg_puts(" "); - char_u *tbuf = IObuff; + char *tbuf = IObuff; size_t tbuflen = IOSIZE; - size_t len = STRLEN(qfp->qf_text) + 3; + size_t len = strlen(qfp->qf_text) + 3; if (len > IOSIZE) { tbuf = xmalloc(len); @@ -3088,14 +3091,12 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) // with ^^^^. qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) ? skipwhite(qfp->qf_text) : qfp->qf_text, - (char *)tbuf, (int)tbuflen); + tbuf, (int)tbuflen); msg_prt_line(tbuf, false); if (tbuf != IObuff) { xfree(tbuf); } - - ui_flush(); // show one line at a time } // ":clist": list all errors @@ -3111,7 +3112,7 @@ void qf_list(exarg_T *eap) } if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) { - emsg(_(e_quickfix)); + emsg(_(e_no_errors)); return; } @@ -3180,7 +3181,7 @@ static void qf_fmt_text(const char *restrict text, char *restrict buf, int bufsi int i; const char *p = (char *)text; - for (i = 0; *p != NUL && i < bufsize - 1; ++i) { + for (i = 0; *p != NUL && i < bufsize - 1; i++) { if (*p == '\n') { buf[i] = ' '; while (*++p != NUL) { @@ -3200,18 +3201,18 @@ static void qf_fmt_text(const char *restrict text, char *restrict buf, int bufsi static void qf_range_text(const qfline_T *qfp, char *buf, int bufsize) { vim_snprintf(buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum); - int len = (int)STRLEN(buf); + int len = (int)strlen(buf); if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) { vim_snprintf(buf + len, (size_t)(bufsize - len), "-%" PRIdLINENR, qfp->qf_end_lnum); - len += (int)STRLEN(buf + len); + len += (int)strlen(buf + len); } if (qfp->qf_col > 0) { vim_snprintf(buf + len, (size_t)(bufsize - len), " col %d", qfp->qf_col); - len += (int)STRLEN(buf + len); + len += (int)strlen(buf + len); if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) { vim_snprintf(buf + len, (size_t)(bufsize - len), "-%d", qfp->qf_end_col); - len += (int)STRLEN(buf + len); + len += (int)strlen(buf + len); } } buf[len] = NUL; @@ -3232,13 +3233,13 @@ static void qf_msg(qf_info_T *qi, int which, char *lead) count); if (title != NULL) { - size_t len = STRLEN(buf); + size_t len = strlen(buf); if (len < 34) { memset(buf + len, ' ', 34 - len); buf[34] = NUL; } - STRLCAT(buf, title, IOSIZE); + xstrlcat(buf, title, IOSIZE); } trunc_string(buf, buf, Columns - 1, IOSIZE); msg(buf); @@ -3263,13 +3264,13 @@ void qf_age(exarg_T *eap) emsg(_("E380: At bottom of quickfix stack")); break; } - --qi->qf_curlist; + qi->qf_curlist--; } else { if (qi->qf_curlist >= qi->qf_listcount - 1) { emsg(_("E381: At top of quickfix stack")); break; } - ++qi->qf_curlist; + qi->qf_curlist++; } } qf_msg(qi, qi->qf_curlist, ""); @@ -3393,7 +3394,7 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount, found_one = true; if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) { if (amount == MAXLNUM) { - qfp->qf_cleared = TRUE; + qfp->qf_cleared = true; } else { qfp->qf_lnum += amount; } @@ -3467,7 +3468,7 @@ void qf_view_result(bool split) qi = GET_LOC_LIST(curwin); } if (qf_list_empty(qf_get_curlist(qi))) { - emsg(_(e_quickfix)); + emsg(_(e_no_errors)); return; } @@ -3558,12 +3559,12 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp static void qf_set_cwindow_options(void) { // switch off 'swapfile' - set_option_value("swf", 0L, NULL, OPT_LOCAL); - set_option_value("bt", 0L, "quickfix", OPT_LOCAL); - set_option_value("bh", 0L, "hide", OPT_LOCAL); + set_option_value_give_err("swf", 0L, NULL, OPT_LOCAL); + set_option_value_give_err("bt", 0L, "quickfix", OPT_LOCAL); + set_option_value_give_err("bh", 0L, "hide", OPT_LOCAL); RESET_BINDING(curwin); curwin->w_p_diff = false; - set_option_value("fdm", 0L, "manual", OPT_LOCAL); + set_option_value_give_err("fdm", 0L, "manual", OPT_LOCAL); } // Open a new quickfix or location list window, load the quickfix buffer and @@ -3710,7 +3711,7 @@ static void qf_win_goto(win_T *win, linenr_T lnum) curwin->w_cursor.coladd = 0; curwin->w_curswant = 0; update_topline(curwin); // scroll to show the line - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); curwin->w_redr_status = true; // update ruler curwin = old_curwin; curbuf = curwin->w_buffer; @@ -3747,7 +3748,7 @@ linenr_T qf_current_entry(win_T *wp) } /// Update the cursor position in the quickfix window to the current error. -/// Return TRUE if there is a quickfix window. +/// Return true if there is a quickfix window. /// /// @param old_qf_index previous qf_index or zero static bool qf_win_pos_update(qf_info_T *qi, int old_qf_index) @@ -3898,7 +3899,7 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) // Only redraw when added lines are visible. This avoids flickering when // the added lines are not visible. if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) { - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); } } } @@ -3917,7 +3918,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli int len; if (qfp->qf_module != NULL) { STRLCPY(IObuff, qfp->qf_module, IOSIZE); - len = (int)STRLEN(IObuff); + len = (int)strlen(IObuff); } else if (qfp->qf_fnum != 0 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { @@ -3937,7 +3938,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli } STRLCPY(IObuff, errbuf->b_fname, IOSIZE); } - len = (int)STRLEN(IObuff); + len = (int)strlen(IObuff); } else { len = 0; } @@ -3946,14 +3947,14 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli } if (qfp->qf_lnum > 0) { qf_range_text(qfp, (char *)IObuff + len, IOSIZE - len); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s", qf_types(qfp->qf_type, qfp->qf_nr)); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); } else if (qfp->qf_pattern != NULL) { qf_fmt_text(qfp->qf_pattern, (char *)IObuff + len, IOSIZE - len); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); } if (len < IOSIZE - 2) { IObuff[len++] = '|'; @@ -3967,7 +3968,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli (char *)IObuff + len, IOSIZE - len); } - if (ml_append_buf(buf, lnum, IObuff, + if (ml_append_buf(buf, lnum, (char_u *)IObuff, (colnr_T)STRLEN(IObuff) + 1, false) == FAIL) { return FAIL; } @@ -4108,7 +4109,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q // resembles reading a file into a buffer, it's more logical when using // autocommands. curbuf->b_ro_locked++; - set_option_value("ft", 0L, "qf", OPT_LOCAL); + set_option_value_give_err("ft", 0L, "qf", OPT_LOCAL); curbuf->b_p_ma = false; keep_filetype = true; // don't detect 'filetype' @@ -4118,7 +4119,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q curbuf->b_ro_locked--; // make sure it will be redrawn - redraw_curbuf_later(NOT_VALID); + redraw_curbuf_later(UPD_NOT_VALID); } // Restore KeyTyped, setting 'filetype' may reset it. @@ -4175,15 +4176,14 @@ static void qf_jump_first(qf_info_T *qi, unsigned save_qfid, int forceit) } } -// Return TRUE when using ":vimgrep" for ":grep". +// Return true when using ":vimgrep" for ":grep". int grep_internal(cmdidx_T cmdidx) { return (cmdidx == CMD_grep || cmdidx == CMD_lgrep || cmdidx == CMD_grepadd || cmdidx == CMD_lgrepadd) - && STRCMP("internal", - *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0; + && strcmp("internal", *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0; } // Return the make/grep autocmd name. @@ -4213,16 +4213,16 @@ static char *make_get_auname(cmdidx_T cmdidx) static char *make_get_fullcmd(const char *makecmd, const char *fname) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - size_t len = STRLEN(p_shq) * 2 + STRLEN(makecmd) + 1; + size_t len = STRLEN(p_shq) * 2 + strlen(makecmd) + 1; if (*p_sp != NUL) { - len += STRLEN(p_sp) + STRLEN(fname) + 3; + len += strlen(p_sp) + strlen(fname) + 3; } char *const cmd = xmalloc(len); snprintf(cmd, len, "%s%s%s", (char *)p_shq, (char *)makecmd, (char *)p_shq); // If 'shellpipe' empty: don't redirect to 'errorfile'. if (*p_sp != NUL) { - append_redir(cmd, len, (char *)p_sp, (char *)fname); + append_redir(cmd, len, p_sp, (char *)fname); } // Display the fully formed command. Output a newline if there's something @@ -4241,7 +4241,7 @@ 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 *enc = (*curbuf->b_p_menc != NUL) ? (char *)curbuf->b_p_menc : (char *)p_menc; + char *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; // Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". if (grep_internal(eap->cmdidx)) { @@ -4319,7 +4319,7 @@ static char *get_mef_name(void) static int off = 0; if (*p_mef == NUL) { - name = (char *)vim_tempname(); + name = vim_tempname(); if (name == NULL) { emsg(_(e_notmp)); } @@ -4328,7 +4328,7 @@ static char *get_mef_name(void) char *p; - for (p = p_mef; *p; ++p) { + for (p = p_mef; *p; p++) { if (p[0] == '#' && p[1] == '#') { break; } @@ -4345,9 +4345,9 @@ static char *get_mef_name(void) } else { off += 19; } - name = xmalloc(STRLEN(p_mef) + 30); + name = xmalloc(strlen(p_mef) + 30); STRCPY(name, p_mef); - snprintf(name + (p - p_mef), STRLEN(name), "%d%d", start, off); + snprintf(name + (p - p_mef), strlen(name), "%d%d", start, off); STRCAT(name, p + 2); // Don't accept a symbolic link, it's a security risk. FileInfo file_info; @@ -4832,7 +4832,7 @@ static void qf_get_nth_below_entry(qfline_T *entry_arg, linenr_T n, bool linewis } /// Get the nth quickfix entry above the specified entry. Searches backwards in -/// the list. If linewise is TRUE, then treat multiple entries on a single line +/// the list. If linewise is true, then treat multiple entries on a single line /// as one. static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n, bool linewise, int *errornr) FUNC_ATTR_NONNULL_ALL @@ -4898,7 +4898,7 @@ void ex_cbelow(exarg_T *eap) || eap->cmdidx == CMD_cafter) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; if (!(curbuf->b_has_qf_entry & buf_has_flag)) { - emsg(_(e_quickfix)); + emsg(_(e_no_errors)); return; } @@ -4910,7 +4910,7 @@ void ex_cbelow(exarg_T *eap) 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)); + emsg(_(e_no_errors)); return; } @@ -4981,7 +4981,7 @@ void ex_cfile(exarg_T *eap) set_string_option_direct("ef", -1, eap->arg, OPT_FREE, 0); } - char *enc = (*curbuf->b_p_menc != NUL) ? (char *)curbuf->b_p_menc : (char *)p_menc; + char *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; if (is_loclist_cmd(eap->cmdidx)) { wp = curwin; @@ -5075,7 +5075,7 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char *s) static void vgr_display_fname(char *fname) { msg_start(); - char *p = (char *)msg_strtrunc((char_u *)fname, true); + char *p = msg_strtrunc(fname, true); if (p == NULL) { msg_outtrans(fname); } else { @@ -5140,6 +5140,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5, 6) { bool found_match = false; + const size_t pat_len = strlen(spat); for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) { colnr_T col = 0; @@ -5154,7 +5155,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp fname, NULL, duplicate_name ? 0 : buf->b_fnum, - (char *)ml_get_buf(buf, regmatch->startpos[0].lnum + lnum, false), + ml_get_buf(buf, regmatch->startpos[0].lnum + lnum, false), regmatch->startpos[0].lnum + lnum, regmatch->endpos[0].lnum + lnum, regmatch->startpos[0].col + 1, @@ -5176,13 +5177,12 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col); - if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, false))) { + if (col > (colnr_T)strlen(ml_get_buf(buf, lnum, false))) { break; } } } else { - const size_t pat_len = STRLEN(spat); - char *const str = (char *)ml_get_buf(buf, lnum, false); + char *const str = ml_get_buf(buf, lnum, false); int score; uint32_t matches[MAX_FUZZY_MATCHES]; const size_t sz = sizeof(matches) / sizeof(matches[0]); @@ -5220,7 +5220,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = (colnr_T)matches[pat_len - 1] + col + 1; - if (col > (colnr_T)STRLEN(str)) { + if (col > (colnr_T)strlen(str)) { break; } } @@ -5262,7 +5262,7 @@ static bool existing_swapfile(const buf_T *buf) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { - const char *const fname = (char *)buf->b_ml.ml_mfp->mf_fname; + const char *const fname = buf->b_ml.ml_mfp->mf_fname; const size_t len = STRLEN(fname); return fname[len - 1] != 'p' || fname[len - 2] != 'w'; @@ -5305,7 +5305,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, &args->fnames, true) == FAIL) { + if (get_arglist_exp(p, &args->fcount, &args->fnames, true) == FAIL) { return FAIL; } if (args->fcount == 0) { @@ -5419,7 +5419,7 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo // directory we jumped to below. if (buf == *first_match_buf && *target_dir == NULL - && STRCMP(dirname_start, dirname_now) != 0) { + && strcmp(dirname_start, dirname_now) != 0) { *target_dir = xstrdup(dirname_now); } @@ -5429,7 +5429,7 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo // options! aco_save_T aco; aucmd_prepbuf(&aco, buf); - apply_autocmds(EVENT_FILETYPE, (char *)buf->b_p_ft, buf->b_fname, true, buf); + apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, true, buf); do_modelines(OPT_NOWIN); aucmd_restbuf(&aco); } @@ -5542,7 +5542,7 @@ static void restore_start_dir(char *dirname_start) char *dirname_now = xmalloc(MAXPATHL); os_dirname((char_u *)dirname_now, MAXPATHL); - if (STRCMP(dirname_start, dirname_now) != 0) { + if (strcmp(dirname_start, dirname_now) != 0) { // If the directory has changed, change it back by building up an // appropriate ex command and executing it. exarg_T ea = { @@ -5609,7 +5609,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin if (readfile_result == OK && !got_int && !(curbuf->b_flags & BF_NEW)) { - failed = FALSE; + failed = false; if (curbuf != newbuf) { // Bloody autocommands changed the buffer! Can happen when // using netrw and editing a remote file. Use the current @@ -5677,7 +5677,7 @@ static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) cleanup_T cs; // Reset the error/interrupt/exception state here so that aborting() - // returns FALSE when wiping out the buffer. Otherwise it doesn't + // returns false when wiping out the buffer. Otherwise it doesn't // work when got_int is set. enter_cleanup(&cs); @@ -6500,7 +6500,7 @@ static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di // If the specified index is '$', then use the last entry if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL - && STRCMP(di->di_tv.vval.v_string, "$") == 0) { + && strcmp(di->di_tv.vval.v_string, "$") == 0) { newidx = qfl->qf_count; } else { // Otherwise use the specified index @@ -6951,11 +6951,11 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch) } linenr_T lnum = 1; - while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) { + while (!vim_fgets((char_u *)IObuff, IOSIZE, fd) && !got_int) { char *line = (char *)IObuff; if (vim_regexec(p_regmatch, line, (colnr_T)0)) { - int l = (int)STRLEN(line); + int l = (int)strlen(line); // remove trailing CR, LF, spaces, etc. while (l > 0 && line[l - 1] <= ' ') { @@ -6970,8 +6970,8 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch) line, lnum, 0, - (int)(p_regmatch->startp[0] - (char_u *)line) + 1, // col - (int)(p_regmatch->endp[0] - (char_u *)line) + (int)(p_regmatch->startp[0] - line) + 1, // col + (int)(p_regmatch->endp[0] - line) + 1, // end_col false, // vis_col NULL, // search pattern @@ -6980,13 +6980,13 @@ static void hgr_search_file(qf_list_T *qfl, char *fname, regmatch_T *p_regmatch) true) // valid == QF_FAIL) { got_int = true; - if ((char_u *)line != IObuff) { + if (line != IObuff) { xfree(line); } break; } } - if ((char_u *)line != IObuff) { + if (line != IObuff) { xfree(line); } lnum++; @@ -7012,9 +7012,9 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p for (int fi = 0; fi < fcount && !got_int; fi++) { // Skip files for a different language. if (lang != NULL - && STRNICMP(lang, fnames[fi] + STRLEN(fnames[fi]) - 3, 2) != 0 + && STRNICMP(lang, fnames[fi] + strlen(fnames[fi]) - 3, 2) != 0 && !(STRNICMP(lang, "en", 2) == 0 - && STRNICMP("txt", fnames[fi] + STRLEN(fnames[fi]) - 3, 3) + && STRNICMP("txt", fnames[fi] + strlen(fnames[fi]) - 3, 3) == 0)) { continue; } @@ -7033,7 +7033,7 @@ static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char FUNC_ATTR_NONNULL_ARG(1, 2) { // Go through all directories in 'runtimepath' - char *p = (char *)p_rtp; + char *p = p_rtp; while (*p != NUL && !got_int) { copy_option_part(&p, (char *)NameBuff, MAXPATHL, ","); @@ -7062,9 +7062,10 @@ void ex_helpgrep(exarg_T *eap) } } + bool updated = false; // Make 'cpoptions' empty, the 'l' flag should not be used here. char *const save_cpo = p_cpo; - p_cpo = (char *)empty_option; + p_cpo = empty_option; bool new_qi = false; if (is_loclist_cmd(eap->cmdidx)) { @@ -7092,14 +7093,24 @@ void ex_helpgrep(exarg_T *eap) qfl->qf_ptr = qfl->qf_start; qfl->qf_index = 1; qf_list_changed(qfl); - qf_update_buffer(qi, NULL); + updated = true; } - if ((char_u *)p_cpo == empty_option) { + if (p_cpo == empty_option) { p_cpo = save_cpo; } else { - // Darn, some plugin changed the value. - free_string_option((char_u *)save_cpo); + // Darn, some plugin changed the value. If it's still empty it was + // changed and restored, need to restore in the complicated way. + if (*p_cpo == NUL) { + set_option_value_give_err("cpo", 0L, save_cpo, 0); + } + free_string_option(save_cpo); + } + + if (updated) { + // This may open a window and source scripts, do this after 'cpo' was + // restored. + qf_update_buffer(qi, NULL); } if (au_name != NULL) { @@ -7158,14 +7169,14 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T * } /// "getloclist()" function -void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getloclist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); get_qf_loc_list(false, wp, &argvars[1], rettv); } /// "getqflist()" functions -void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_getqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { get_qf_loc_list(true, NULL, &argvars[0], rettv); } @@ -7252,7 +7263,7 @@ skip_args: } /// "setloclist()" function -void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setloclist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = -1; @@ -7263,7 +7274,7 @@ void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "setqflist()" function -void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_setqflist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { set_qf_ll_list(NULL, argvars, rettv); } diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index b7ec4bf94e..e87382ff7c 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -137,7 +137,7 @@ static int re_multi_type(int c) return NOT_MULTI; } -static char_u *reg_prev_sub = NULL; +static char *reg_prev_sub = NULL; /* * REGEXP_INRANGE contains all characters which are always special in a [] @@ -227,8 +227,8 @@ static int get_char_class(char **pp) if ((*pp)[1] == ':') { for (i = 0; i < (int)ARRAY_SIZE(class_names); i++) { - if (STRNCMP(*pp + 2, class_names[i], STRLEN(class_names[i])) == 0) { - *pp += STRLEN(class_names[i]) + 2; + if (STRNCMP(*pp + 2, class_names[i], strlen(class_names[i])) == 0) { + *pp += strlen(class_names[i]) + 2; return i; } } @@ -488,10 +488,10 @@ static char_u *skip_anyof(char *p) /// When "newp" is not NULL and "dirc" is '?', make an allocated copy of the /// expression and change "\?" to "?". If "*newp" is not NULL the expression /// is changed in-place. -char_u *skip_regexp(char_u *startp, int dirc, int magic, char **newp) +char *skip_regexp(char *startp, int dirc, int magic, char **newp) { int mymagic; - char_u *p = startp; + char *p = startp; if (magic) { mymagic = MAGIC_ON; @@ -506,7 +506,7 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char **newp) } if ((p[0] == '[' && mymagic >= MAGIC_ON) || (p[0] == '\\' && p[1] == '[' && mymagic <= MAGIC_OFF)) { - p = skip_anyof((char *)p + 1); + p = (char *)skip_anyof(p + 1); if (p[0] == NUL) { break; } @@ -514,8 +514,8 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char **newp) if (dirc == '?' && newp != NULL && p[1] == '?') { // change "\?" to "?", make a copy first. if (*newp == NULL) { - *newp = (char *)vim_strsave(startp); - p = (char_u *)(*newp) + (p - startp); + *newp = xstrdup(startp); + p = *newp + (p - startp); } STRMOVE(p, p + 1); } else { @@ -1040,7 +1040,7 @@ static char_u *reg_getline(linenr_T lnum) // Must have matched the "\n" in the last line. return (char_u *)""; } - return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, false); + return (char_u *)ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, false); } static char_u *reg_startzp[NSUBEXP]; // Workspace to mark beginning @@ -1093,7 +1093,7 @@ void unref_extmatch(reg_extmatch_T *em) static int reg_prev_class(void) { if (rex.input > rex.line) { - return mb_get_class_tab(rex.input - 1 - utf_head_off(rex.line, rex.input - 1), + return mb_get_class_tab(rex.input - 1 - utf_head_off((char *)rex.line, (char *)rex.input - 1), rex.reg_buf->b_chartab); } return -1; @@ -1165,7 +1165,7 @@ static bool reg_match_visual(void) rex.line = reg_getline(rex.lnum); rex.input = rex.line + col; - unsigned int cols_u = win_linetabsize(wp, rex.line, col); + unsigned int cols_u = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, rex.line, col); assert(cols_u <= MAXCOL); colnr_T cols = (colnr_T)cols_u; if (cols < start || cols > end - (*p_sel == 'e')) { @@ -1282,7 +1282,7 @@ static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T e len = (int)STRLEN(p + ccol); } - if (cstrncmp(p + ccol, rex.input, &len) != 0) { + if (cstrncmp((char *)p + ccol, (char *)rex.input, &len) != 0) { return RA_NOMATCH; // doesn't match } if (bytelen != NULL) { @@ -1395,10 +1395,10 @@ static void mb_decompose(int c, int *c1, int *c2, int *c3) } } -// Compare two strings, ignore case if rex.reg_ic set. -// Return 0 if strings match, non-zero otherwise. -// Correct the length "*n" when composing characters are ignored. -static int cstrncmp(char_u *s1, char_u *s2, int *n) +/// Compare two strings, ignore case if rex.reg_ic set. +/// Return 0 if strings match, non-zero otherwise. +/// Correct the length "*n" when composing characters are ignored. +static int cstrncmp(char *s1, char *s2, int *n) { int result; @@ -1406,12 +1406,12 @@ static int cstrncmp(char_u *s1, char_u *s2, int *n) result = STRNCMP(s1, s2, *n); } else { assert(*n >= 0); - result = mb_strnicmp(s1, s2, (size_t)*n); + result = mb_strnicmp(s1, s2, (size_t)(*n)); } // if it failed and it's utf8 and we want to combineignore: if (result != 0 && rex.reg_icombine) { - char_u *str1, *str2; + char *str1, *str2; int c1, c2, c11, c12; int junk; @@ -1523,23 +1523,21 @@ static fptr_T do_Lower(int *d, int c) return (fptr_T)do_Lower; } -/* - * regtilde(): Replace tildes in the pattern by the old pattern. - * - * Short explanation of the tilde: It stands for the previous replacement - * pattern. If that previous pattern also contains a ~ we should go back a - * step further... But we insert the previous pattern into the current one - * and remember that. - * This still does not handle the case where "magic" changes. So require the - * user to keep his hands off of "magic". - * - * The tildes are parsed once before the first call to vim_regsub(). - */ -char_u *regtilde(char_u *source, int magic, bool preview) +/// regtilde(): Replace tildes in the pattern by the old pattern. +/// +/// Short explanation of the tilde: It stands for the previous replacement +/// pattern. If that previous pattern also contains a ~ we should go back a +/// step further... But we insert the previous pattern into the current one +/// and remember that. +/// This still does not handle the case where "magic" changes. So require the +/// user to keep his hands off of "magic". +/// +/// The tildes are parsed once before the first call to vim_regsub(). +char *regtilde(char *source, int magic, bool preview) { - char_u *newsub = source; - char_u *tmpsub; - char_u *p; + char *newsub = source; + char *tmpsub; + char *p; int len; int prevlen; @@ -1547,8 +1545,8 @@ char_u *regtilde(char_u *source, int magic, bool preview) if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic)) { if (reg_prev_sub != NULL) { // length = len(newsub) - 1 + len(prev_sub) + 1 - prevlen = (int)STRLEN(reg_prev_sub); - tmpsub = xmalloc(STRLEN(newsub) + (size_t)prevlen); + prevlen = (int)strlen(reg_prev_sub); + tmpsub = xmalloc(strlen(newsub) + (size_t)prevlen); // copy prefix len = (int)(p - newsub); // not including ~ memmove(tmpsub, newsub, (size_t)len); @@ -1575,7 +1573,7 @@ char_u *regtilde(char_u *source, int magic, bool preview) if (*p == '\\' && p[1]) { // skip escaped characters p++; } - p += utfc_ptr2len((char *)p) - 1; + p += utfc_ptr2len(p) - 1; } } @@ -1584,7 +1582,7 @@ char_u *regtilde(char_u *source, int magic, bool 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); - reg_prev_sub = vim_strsave(newsub); + reg_prev_sub = xstrdup(newsub); } return newsub; @@ -1607,12 +1605,12 @@ static regsubmatch_T rsm; // can only be used when can_f_submatch is true /// Put the submatches in "argv[argskip]" which is a list passed into /// call_func() by vim_regsub_both(). -static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, int argskip, int argcount) +static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, int argskip, ufunc_T *fp) FUNC_ATTR_NONNULL_ALL { typval_T *listarg = argv + argskip; - if (argcount == argskip) { + if (!fp->uf_varargs && fp->uf_args.ga_len <= argskip) { // called function doesn't take a submatches argument return argskip; } @@ -1623,14 +1621,14 @@ static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, int arg // There are always 10 list items in staticList10_T. listitem_T *li = tv_list_first(listarg->vval.v_list); for (int i = 0; i < 10; i++) { - char_u *s = rsm.sm_match->startp[i]; + char *s = rsm.sm_match->startp[i]; if (s == NULL || rsm.sm_match->endp[i] == NULL) { s = NULL; } else { - s = vim_strnsave(s, (size_t)(rsm.sm_match->endp[i] - s)); + s = xstrnsave(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; + TV_LIST_ITEM_TV(li)->vval.v_string = s; li = TV_LIST_ITEM_NEXT(argv->vval.v_list, li); } return argskip + 1; @@ -1717,7 +1715,7 @@ int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *de // When nesting more than a couple levels it's probably a mistake. #define MAX_REGSUB_NESTING 4 -static char_u *eval_result[MAX_REGSUB_NESTING] = { NULL, NULL, NULL, NULL }; +static char *eval_result[MAX_REGSUB_NESTING] = { NULL, NULL, NULL, NULL }; #if defined(EXITFREE) void free_resub_eval_result(void) @@ -1769,7 +1767,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des if (copy) { if (eval_result[nested] != NULL) { STRCPY(dest, eval_result[nested]); - dst += STRLEN(eval_result[nested]); + dst += strlen(eval_result[nested]); XFREE_CLEAR(eval_result[nested]); } } else { @@ -1805,8 +1803,8 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des argv[0].v_type = VAR_LIST; argv[0].vval.v_list = &matchList.sl_list; funcexe_T funcexe = FUNCEXE_INIT; - funcexe.argv_func = fill_submatch_list; - funcexe.evaluate = true; + funcexe.fe_argv_func = fill_submatch_list; + funcexe.fe_evaluate = true; if (expr->v_type == VAR_FUNC) { s = (char_u *)expr->vval.v_string; call_func((char *)s, -1, &rettv, 1, argv, &funcexe); @@ -1814,7 +1812,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des partial_T *partial = expr->vval.v_partial; s = (char_u *)partial_name(partial); - funcexe.partial = partial; + funcexe.fe_partial = partial; call_func((char *)s, -1, &rettv, 1, argv, &funcexe); } if (tv_list_len(&matchList.sl_list) > 0) { @@ -1826,21 +1824,21 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des eval_result[nested] = NULL; } else { char buf[NUMBUFLEN]; - eval_result[nested] = (char_u *)tv_get_string_buf_chk(&rettv, buf); + eval_result[nested] = (char *)tv_get_string_buf_chk(&rettv, buf); if (eval_result[nested] != NULL) { - eval_result[nested] = vim_strsave(eval_result[nested]); + eval_result[nested] = xstrdup(eval_result[nested]); } } tv_clear(&rettv); } else { - eval_result[nested] = (char_u *)eval_to_string((char *)source + 2, NULL, true); + eval_result[nested] = eval_to_string((char *)source + 2, NULL, true); } nesting--; if (eval_result[nested] != NULL) { int had_backslash = false; - for (s = eval_result[nested]; *s != NUL; MB_PTR_ADV(s)) { + for (s = (char_u *)eval_result[nested]; *s != NUL; MB_PTR_ADV(s)) { // Change NL to CR, so that it becomes a line break, // unless called from vim_regexec_nl(). // Skip over a backslashed character. @@ -1862,12 +1860,12 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des } if (had_backslash && (flags & REGSUB_BACKSLASH)) { // Backslashes will be consumed, need to double them. - s = vim_strsave_escaped(eval_result[nested], (char_u *)"\\"); + s = vim_strsave_escaped((char_u *)eval_result[nested], (char_u *)"\\"); xfree(eval_result[nested]); - eval_result[nested] = s; + eval_result[nested] = (char *)s; } - dst += STRLEN(eval_result[nested]); + dst += strlen(eval_result[nested]); } can_f_submatch = prev_can_f_submatch; @@ -2008,11 +2006,11 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des } } } else { - s = rex.reg_match->startp[no]; + s = (char_u *)rex.reg_match->startp[no]; if (rex.reg_match->endp[no] == NULL) { s = NULL; } else { - len = (int)(rex.reg_match->endp[no] - s); + len = (int)(rex.reg_match->endp[no] - (char *)s); } } if (s != NULL) { @@ -2112,36 +2110,33 @@ exit: return (int)((dst - dest) + 1); } -/* - * Call reg_getline() with the line numbers from the submatch. If a - * substitute() was used the reg_maxline and other values have been - * overwritten. - */ -static char_u *reg_getline_submatch(linenr_T lnum) +/// Call reg_getline() with the line numbers from the submatch. If a +/// substitute() was used the reg_maxline and other values have been +/// overwritten. +static char *reg_getline_submatch(linenr_T lnum) { - char_u *s; + char *s; linenr_T save_first = rex.reg_firstlnum; linenr_T save_max = rex.reg_maxline; rex.reg_firstlnum = rsm.sm_firstlnum; rex.reg_maxline = rsm.sm_maxline; - s = reg_getline(lnum); + s = (char *)reg_getline(lnum); rex.reg_firstlnum = save_first; rex.reg_maxline = save_max; return s; } -/* - * Used for the submatch() function: get the string from the n'th submatch in - * allocated memory. - * Returns NULL when not in a ":s" command and for a non-existing submatch. - */ -char_u *reg_submatch(int no) +/// Used for the submatch() function: get the string from the n'th submatch in +/// allocated memory. +/// +/// @return NULL when not in a ":s" command and for a non-existing submatch. +char *reg_submatch(int no) { - char_u *retval = NULL; - char_u *s; + char *retval = NULL; + char *s; int round; linenr_T lnum; @@ -2177,7 +2172,7 @@ char_u *reg_submatch(int no) } else { // Multiple lines: take start line from start col, middle // lines completely and end line up to end col. - len = (ssize_t)STRLEN(s); + len = (ssize_t)strlen(s); if (round == 2) { STRCPY(retval, s); retval[len] = '\n'; @@ -2189,7 +2184,7 @@ char_u *reg_submatch(int no) if (round == 2) { STRCPY(retval + len, s); } - len += (ssize_t)STRLEN(s); + len += (ssize_t)strlen(s); if (round == 2) { retval[len] = '\n'; } @@ -2215,7 +2210,7 @@ char_u *reg_submatch(int no) if (s == NULL || rsm.sm_match->endp[no] == NULL) { retval = NULL; } else { - retval = vim_strnsave(s, (size_t)(rsm.sm_match->endp[no] - s)); + retval = xstrnsave(s, (size_t)(rsm.sm_match->endp[no] - s)); } } @@ -2250,16 +2245,16 @@ list_T *reg_submatch_list(int no) list = tv_list_alloc(elnum - slnum + 1); - s = (const char *)reg_getline_submatch(slnum) + scol; + s = reg_getline_submatch(slnum) + scol; if (slnum == elnum) { tv_list_append_string(list, s, ecol - scol); } else { tv_list_append_string(list, s, -1); for (int i = 1; i < elnum - slnum; i++) { - s = (const char *)reg_getline_submatch(slnum + i); + s = reg_getline_submatch(slnum + i); tv_list_append_string(list, s, -1); } - s = (const char *)reg_getline_submatch(elnum); + s = reg_getline_submatch(elnum); tv_list_append_string(list, s, ecol); } } else { @@ -2469,12 +2464,12 @@ static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool && result == NFA_TOO_EXPENSIVE) { 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); + char *pat = xstrdup(((nfa_regprog_T *)rmp->regprog)->pattern); p_re = BACKTRACKING_ENGINE; vim_regfree(rmp->regprog); - report_re_switch(pat); - rmp->regprog = vim_regcomp((char *)pat, re_flags); + report_re_switch((char_u *)pat); + rmp->regprog = vim_regcomp(pat, re_flags); if (rmp->regprog != NULL) { rmp->regprog->re_in_use = true; result = rmp->regprog->engine->regexec_nl(rmp, line, col, nl); @@ -2560,16 +2555,16 @@ long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, && result == NFA_TOO_EXPENSIVE) { 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); + char *pat = xstrdup(((nfa_regprog_T *)rmp->regprog)->pattern); p_re = BACKTRACKING_ENGINE; regprog_T *prev_prog = rmp->regprog; - report_re_switch(pat); + report_re_switch((char_u *)pat); // checking for \z misuse was already done when compiling for NFA, // allow all here reg_do_extmatch = REX_ALL; - rmp->regprog = vim_regcomp((char *)pat, re_flags); + rmp->regprog = vim_regcomp(pat, re_flags); reg_do_extmatch = 0; if (rmp->regprog == NULL) { diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index 769d2ceeef..ac33fc0f13 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -1857,14 +1857,14 @@ static char_u *regatom(int *flagp) char_u *lp; ret = regnode(EXACTLY); - lp = reg_prev_sub; + lp = (char_u *)reg_prev_sub; while (*lp != NUL) { regc(*lp++); } regc(NUL); if (*reg_prev_sub != NUL) { *flagp |= HASWIDTH; - if ((lp - reg_prev_sub) == 1) { + if ((lp - (char_u *)reg_prev_sub) == 1) { *flagp |= SIMPLE; } } @@ -2469,7 +2469,7 @@ do_multibyte: // Need to get composing character too. for (;;) { l = utf_ptr2len((char *)regparse); - if (!utf_composinglike((char_u *)regparse, (char_u *)regparse + l)) { + if (!utf_composinglike(regparse, regparse + l)) { break; } regmbc(utf_ptr2char((char *)regparse)); @@ -3192,7 +3192,7 @@ static int regrepeat(char_u *p, long maxcount) case SKWORD: case SKWORD + ADD_NL: while (count < maxcount) { - if (vim_iswordp_buf(scan, rex.reg_buf) + if (vim_iswordp_buf((char *)scan, rex.reg_buf) && (testval || !ascii_isdigit(*scan))) { MB_PTR_ADV(scan); } else if (*scan == NUL) { @@ -3764,6 +3764,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case RE_VCOL: if (!re_num_cmp(win_linetabsize(rex.reg_win == NULL ? curwin : rex.reg_win, + rex.reg_firstlnum + rex.lnum, rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan)) { @@ -3828,7 +3829,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) break; case KWORD: - if (!vim_iswordp_buf(rex.input, rex.reg_buf)) { + if (!vim_iswordp_buf((char *)rex.input, rex.reg_buf)) { status = RA_NOMATCH; } else { ADVANCE_REGINPUT(); @@ -3837,7 +3838,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case SKWORD: if (ascii_isdigit(*rex.input) - || !vim_iswordp_buf(rex.input, rex.reg_buf)) { + || !vim_iswordp_buf((char *)rex.input, rex.reg_buf)) { status = RA_NOMATCH; } else { ADVANCE_REGINPUT(); @@ -4038,14 +4039,14 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) } else { // Need to match first byte again for multi-byte. len = (int)STRLEN(opnd); - if (cstrncmp(opnd, rex.input, &len) != 0) { + if (cstrncmp((char *)opnd, (char *)rex.input, &len) != 0) { status = RA_NOMATCH; } } // Check for following composing character, unless %C // follows (skips over all composing chars). if (status != RA_NOMATCH - && utf_composinglike(rex.input, rex.input + len) + && utf_composinglike((char *)rex.input, (char *)rex.input + len) && !rex.reg_icombine && OP(next) != RE_COMPOSING) { // raaron: This code makes a composing character get @@ -4269,7 +4270,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) } else { // Compare current input with back-ref in the same line. len = (int)(rex.reg_endp[no] - rex.reg_startp[no]); - if (cstrncmp(rex.reg_startp[no], rex.input, &len) != 0) { + if (cstrncmp((char *)rex.reg_startp[no], (char *)rex.input, &len) != 0) { status = RA_NOMATCH; } } @@ -4282,8 +4283,8 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) && rex.reg_endpos[no].lnum == rex.lnum) { // Compare back-ref within the current line. len = rex.reg_endpos[no].col - rex.reg_startpos[no].col; - if (cstrncmp(rex.line + rex.reg_startpos[no].col, - rex.input, &len) != 0) { + if (cstrncmp((char *)rex.line + rex.reg_startpos[no].col, + (char *)rex.input, &len) != 0) { status = RA_NOMATCH; } } else { @@ -4319,7 +4320,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) if (re_extmatch_in != NULL && re_extmatch_in->matches[no] != NULL) { int len = (int)STRLEN(re_extmatch_in->matches[no]); - if (cstrncmp(re_extmatch_in->matches[no], rex.input, &len) != 0) { + if (cstrncmp((char *)re_extmatch_in->matches[no], (char *)rex.input, &len) != 0) { status = RA_NOMATCH; } else { rex.input += len; @@ -4369,7 +4370,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case BRACE_COMPLEX + 8: case BRACE_COMPLEX + 9: no = op - BRACE_COMPLEX; - ++brace_count[no]; + brace_count[no]++; // If not matched enough times yet, try one more if (brace_count[no] <= (brace_min[no] <= brace_max[no] @@ -4764,8 +4765,8 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) reg_getline(rp->rs_un.regsave.rs_u.pos.lnum); rp->rs_un.regsave.rs_u.pos.col -= - utf_head_off(line, - line + rp->rs_un.regsave.rs_u.pos.col - 1) + utf_head_off((char *)line, + (char *)line + rp->rs_un.regsave.rs_u.pos.col - 1) + 1; } } else { @@ -4974,13 +4975,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, - (size_t)(reg_endzpos[i].col - reg_startzpos[i].col)); + (char_u *)xstrnsave((char *)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], (size_t)(reg_endzp[i] - reg_startzp[i])); + (char_u *)xstrnsave((char *)reg_startzp[i], (size_t)(reg_endzp[i] - reg_startzp[i])); } } } @@ -5027,8 +5028,8 @@ static long bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *time rex.reg_endpos = rex.reg_mmatch->endpos; } else { prog = (bt_regprog_T *)rex.reg_match->regprog; - rex.reg_startp = rex.reg_match->startp; - rex.reg_endp = rex.reg_match->endp; + rex.reg_startp = (char_u **)rex.reg_match->startp; + rex.reg_endp = (char_u **)rex.reg_match->endp; } // Be paranoid... @@ -5068,14 +5069,14 @@ static long bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *time // the loop to avoid overhead of conditions. if (!rex.reg_ic) { while ((s = (char_u *)vim_strchr((char *)s, c)) != NULL) { - if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0) { + if (cstrncmp((char *)s, (char *)prog->regmust, &prog->regmlen) == 0) { break; // Found it. } MB_PTR_ADV(s); } } else { while ((s = cstrchr(s, c)) != NULL) { - if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0) { + if (cstrncmp((char *)s, (char *)prog->regmust, &prog->regmlen) == 0) { break; // Found it. } MB_PTR_ADV(s); @@ -5593,7 +5594,7 @@ static char_u *regprop(char_u *op) case MOPEN + 7: case MOPEN + 8: case MOPEN + 9: - sprintf(buf + STRLEN(buf), "MOPEN%d", OP(op) - MOPEN); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "MOPEN%d", OP(op) - MOPEN); p = NULL; break; case MCLOSE + 0: @@ -5608,7 +5609,7 @@ static char_u *regprop(char_u *op) case MCLOSE + 7: case MCLOSE + 8: case MCLOSE + 9: - sprintf(buf + STRLEN(buf), "MCLOSE%d", OP(op) - MCLOSE); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "MCLOSE%d", OP(op) - MCLOSE); p = NULL; break; case BACKREF + 1: @@ -5620,7 +5621,7 @@ static char_u *regprop(char_u *op) case BACKREF + 7: case BACKREF + 8: case BACKREF + 9: - sprintf(buf + STRLEN(buf), "BACKREF%d", OP(op) - BACKREF); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "BACKREF%d", OP(op) - BACKREF); p = NULL; break; case NOPEN: @@ -5638,7 +5639,7 @@ static char_u *regprop(char_u *op) case ZOPEN + 7: case ZOPEN + 8: case ZOPEN + 9: - sprintf(buf + STRLEN(buf), "ZOPEN%d", OP(op) - ZOPEN); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZOPEN%d", OP(op) - ZOPEN); p = NULL; break; case ZCLOSE + 1: @@ -5650,7 +5651,7 @@ static char_u *regprop(char_u *op) case ZCLOSE + 7: case ZCLOSE + 8: case ZCLOSE + 9: - sprintf(buf + STRLEN(buf), "ZCLOSE%d", OP(op) - ZCLOSE); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZCLOSE%d", OP(op) - ZCLOSE); p = NULL; break; case ZREF + 1: @@ -5662,7 +5663,7 @@ static char_u *regprop(char_u *op) case ZREF + 7: case ZREF + 8: case ZREF + 9: - sprintf(buf + STRLEN(buf), "ZREF%d", OP(op) - ZREF); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZREF%d", OP(op) - ZREF); p = NULL; break; case STAR: @@ -5702,7 +5703,8 @@ static char_u *regprop(char_u *op) case BRACE_COMPLEX + 7: case BRACE_COMPLEX + 8: case BRACE_COMPLEX + 9: - sprintf(buf + STRLEN(buf), "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "BRACE_COMPLEX%d", + OP(op) - BRACE_COMPLEX); p = NULL; break; case MULTIBYTECODE: @@ -5712,7 +5714,7 @@ static char_u *regprop(char_u *op) p = "NEWL"; break; default: - sprintf(buf + STRLEN(buf), "corrupt %d", OP(op)); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "corrupt %d", OP(op)); p = NULL; break; } diff --git a/src/nvim/regexp_defs.h b/src/nvim/regexp_defs.h index b313dfe877..b24ed350e8 100644 --- a/src/nvim/regexp_defs.h +++ b/src/nvim/regexp_defs.h @@ -127,7 +127,7 @@ typedef struct { int has_zend; // pattern contains \ze int has_backref; // pattern contains \1 .. \9 int reghasz; - char_u *pattern; + char *pattern; int nsubexp; // number of () int nstate; nfa_state_T state[1]; // actually longer.. @@ -140,8 +140,8 @@ typedef struct { */ typedef struct { regprog_T *regprog; - char_u *startp[NSUBEXP]; - char_u *endp[NSUBEXP]; + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; bool rm_ic; } regmatch_T; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 554def5b8a..fbd4e26c75 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -1959,9 +1959,9 @@ static int nfa_regatom(void) emsg(_(e_nopresub)); return FAIL; } - for (lp = reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp)) { + for (lp = (char_u *)reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp)) { EMIT(utf_ptr2char((char *)lp)); - if (lp != reg_prev_sub) { + if (lp != (char_u *)reg_prev_sub) { EMIT(NFA_CONCAT); } } @@ -5421,8 +5421,8 @@ retempty: && sub->list.multi[subidx].end_lnum == rex.lnum) { len = sub->list.multi[subidx].end_col - sub->list.multi[subidx].start_col; - if (cstrncmp(rex.line + sub->list.multi[subidx].start_col, - rex.input, &len) == 0) { + if (cstrncmp((char *)rex.line + sub->list.multi[subidx].start_col, + (char *)rex.input, &len) == 0) { *bytelen = len; return true; } @@ -5441,7 +5441,7 @@ retempty: goto retempty; } len = (int)(sub->list.line[subidx].end - sub->list.line[subidx].start); - if (cstrncmp(sub->list.line[subidx].start, rex.input, &len) == 0) { + if (cstrncmp((char *)sub->list.line[subidx].start, (char *)rex.input, &len) == 0) { *bytelen = len; return true; } @@ -5466,7 +5466,7 @@ static int match_zref(int subidx, int *bytelen) } len = (int)STRLEN(re_extmatch_in->matches[subidx]); - if (cstrncmp(re_extmatch_in->matches[subidx], rex.input, &len) == 0) { + if (cstrncmp((char *)re_extmatch_in->matches[subidx], (char *)rex.input, &len) == 0) { *bytelen = len; return true; } @@ -5595,7 +5595,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T } if ((int)(rex.input - rex.line) >= state->val) { rex.input -= state->val; - rex.input -= utf_head_off(rex.line, rex.input); + rex.input -= utf_head_off((char *)rex.line, (char *)rex.input); } else { rex.input = rex.line; } @@ -6643,13 +6643,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; case NFA_KWORD: // \k - result = vim_iswordp_buf(rex.input, rex.reg_buf); + result = vim_iswordp_buf((char *)rex.input, rex.reg_buf); ADD_STATE_IF_MATCH(t->state); break; case NFA_SKWORD: // \K result = !ascii_isdigit(curc) - && vim_iswordp_buf(rex.input, rex.reg_buf); + && vim_iswordp_buf((char *)rex.input, rex.reg_buf); ADD_STATE_IF_MATCH(t->state); break; @@ -6910,7 +6910,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm result = col > t->state->val * ts; } if (!result) { - uintmax_t lts = win_linetabsize(wp, rex.line, col); + uintmax_t lts = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, rex.line, col); assert(t->state->val >= 0); result = nfa_re_num_cmp((uintmax_t)t->state->val, op, lts + 1); } @@ -7362,15 +7362,15 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm, int *ti && mpos->start_lnum == mpos->end_lnum && mpos->end_col >= mpos->start_col) { re_extmatch_out->matches[i] = - vim_strnsave(reg_getline(mpos->start_lnum) + mpos->start_col, - (size_t)(mpos->end_col - mpos->start_col)); + (char_u *)xstrnsave((char *)reg_getline(mpos->start_lnum) + 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, (size_t)(lpos->end - lpos->start)); + (char_u *)xstrnsave((char *)lpos->start, (size_t)(lpos->end - lpos->start)); } } } @@ -7402,8 +7402,8 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int rex.reg_endpos = rex.reg_mmatch->endpos; } else { prog = (nfa_regprog_T *)rex.reg_match->regprog; - rex.reg_startp = rex.reg_match->startp; - rex.reg_endp = rex.reg_match->endp; + rex.reg_startp = (char_u **)rex.reg_match->startp; + rex.reg_endp = (char_u **)rex.reg_match->endp; } // Be paranoid... @@ -7593,7 +7593,7 @@ static regprog_T *nfa_regcomp(char_u *expr, int re_flags) #endif // Remember whether this pattern has any \z specials in it. prog->reghasz = re_has_z; - prog->pattern = vim_strsave(expr); + prog->pattern = xstrdup((char *)expr); #ifdef REGEXP_DEBUG nfa_regengine.expr = NULL; #endif diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 914b21bb02..935bf4c507 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -100,10 +100,11 @@ void estack_pop(void) } /// Get the current value for <sfile> in allocated memory. -/// @param which ESTACK_SFILE for <sfile> and ESTACK_STACK for <stack>. +/// @param which ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or +/// ESTACK_SCRIPT for <script>. char *estack_sfile(estack_arg_T which) { - estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) { if (entry->es_name == NULL) { return NULL; @@ -111,6 +112,26 @@ char *estack_sfile(estack_arg_T which) return xstrdup(entry->es_name); } + // If evaluated in a function or autocommand, return the path of the script + // where it is defined, at script level the current script path is returned + // instead. + if (which == ESTACK_SCRIPT) { + // Walk the stack backwards, starting from the current frame. + for (int idx = exestack.ga_len - 1; idx >= 0; idx--, entry--) { + if (entry->es_type == ETYPE_UFUNC || entry->es_type == ETYPE_AUCMD) { + const sctx_T *const def_ctx = (entry->es_type == ETYPE_UFUNC + ? &entry->es_info.ufunc->uf_script_ctx + : &entry->es_info.aucmd->script_ctx); + return def_ctx->sc_sid > 0 + ? xstrdup((SCRIPT_ITEM(def_ctx->sc_sid).sn_name)) + : NULL; + } else if (entry->es_type == ETYPE_SCRIPT) { + return xstrdup(entry->es_name); + } + } + return NULL; + } + // Give information about each stack entry up to the root. // For a function we compose the call stack, as it was done in the past: // "function One[123]..Two[456]..Three" @@ -171,7 +192,7 @@ void runtime_init(void) void ex_runtime(exarg_T *eap) { char *arg = eap->arg; - char *p = (char *)skiptowhite((char_u *)arg); + char *p = skiptowhite(arg); ptrdiff_t len = p - arg; int flags = eap->forceit ? DIP_ALL : 0; @@ -205,9 +226,9 @@ static void source_callback(char *fname, void *cookie) /// When "flags" has DIP_ERR: give an error message if there is no match. /// /// return FAIL when no file could be sourced, OK otherwise. -int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie) +int do_in_path(char *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie) { - char_u *tail; + char *tail; int num_files; char **files; int i; @@ -215,21 +236,21 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback, // Make a copy of 'runtimepath'. Invoking the callback may change the // value. - char_u *rtp_copy = vim_strsave(path); + char *rtp_copy = xstrdup(path); char *buf = xmallocz(MAXPATHL); { if (p_verbose > 10 && name != NULL) { verbose_enter(); - smsg(_("Searching for \"%s\" in \"%s\""), name, (char *)path); + smsg(_("Searching for \"%s\" in \"%s\""), name, path); verbose_leave(); } // Loop over all entries in 'runtimepath'. - char *rtp = (char *)rtp_copy; + char *rtp = rtp_copy; while (*rtp != NUL && ((flags & DIP_ALL) || !did_one)) { // Copy the path from 'runtimepath' to buf[]. copy_option_part(&rtp, buf, MAXPATHL, ","); - size_t buflen = STRLEN(buf); + size_t buflen = strlen(buf); // Skip after or non-after directories. if (flags & (DIP_NOAFTER | DIP_AFTER)) { @@ -244,16 +265,16 @@ int do_in_path(char_u *path, char *name, int flags, DoInRuntimepathCB callback, if (name == NULL) { (*callback)(buf, cookie); did_one = true; - } else if (buflen + STRLEN(name) + 2 < MAXPATHL) { + } else if (buflen + strlen(name) + 2 < MAXPATHL) { add_pathsep(buf); - tail = (char_u *)buf + STRLEN(buf); + tail = buf + strlen(buf); // Loop over all patterns in "name" char *np = name; while (*np != NUL && ((flags & DIP_ALL) || !did_one)) { // Append the pattern from "name" to buf[]. - assert(MAXPATHL >= (tail - (char_u *)buf)); - copy_option_part(&np, (char *)tail, (size_t)(MAXPATHL - (tail - (char_u *)buf)), "\t "); + assert(MAXPATHL >= (tail - buf)); + copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); if (p_verbose > 10) { verbose_enter(); @@ -342,19 +363,19 @@ void runtime_search_path_unref(RuntimeSearchPath path, int *ref) /// When "flags" has DIP_ERR: give an error message if there is no match. /// /// return FAIL when no file could be sourced, OK otherwise. -int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie) +int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie) { - char_u *tail; + char *tail; int num_files; char **files; int i; bool did_one = false; - char_u buf[MAXPATHL]; + char buf[MAXPATHL]; if (p_verbose > 10 && name != NULL) { verbose_enter(); - smsg(_("Searching for \"%s\" in runtime path"), (char *)name); + smsg(_("Searching for \"%s\" in runtime path"), name); verbose_leave(); } @@ -376,17 +397,17 @@ int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void if (name == NULL) { (*callback)(item.path, cookie); - } else if (buflen + STRLEN(name) + 2 < MAXPATHL) { + } else if (buflen + strlen(name) + 2 < MAXPATHL) { STRCPY(buf, item.path); - add_pathsep((char *)buf); - tail = buf + STRLEN(buf); + add_pathsep(buf); + tail = buf + strlen(buf); // Loop over all patterns in "name" - char *np = (char *)name; + char *np = name; while (*np != NUL && ((flags & DIP_ALL) || !did_one)) { // Append the pattern from "name" to buf[]. assert(MAXPATHL >= (tail - buf)); - copy_option_part(&np, (char *)tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); + copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); if (p_verbose > 10) { verbose_enter(); @@ -398,7 +419,7 @@ 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 *(pat[]) = { (char *)buf }; + char *(pat[]) = { buf }; if (gen_expand_wildcards(1, pat, &num_files, &files, ew_flags) == OK) { for (i = 0; i < num_files; i++) { (*callback)(files[i], cookie); @@ -478,7 +499,7 @@ ArrayOf(String) runtime_get_named_common(bool lua, Array pat, bool all, if (lua) { if (item->has_lua == kNone) { size_t size = (size_t)snprintf(buf, buf_len, "%s/lua/", item->path); - item->has_lua = (size < buf_len && os_isdir((char_u *)buf)); + item->has_lua = (size < buf_len && os_isdir(buf)); } if (item->has_lua == kFalse) { continue; @@ -513,18 +534,18 @@ done: /// If "name" is NULL calls callback for each entry in "path". Cookie is /// passed by reference in this case, setting it to NULL indicates that callback /// has done its job. -int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback, - void *cookie) +int do_in_path_and_pp(char *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie) { int done = FAIL; if ((flags & DIP_NORTP) == 0) { - done |= do_in_path(path, (char *)((name && !*name) ? NULL : name), flags, callback, cookie); + done |= do_in_path(path, (name && !*name) ? NULL : name, flags, callback, + cookie); } if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) { char *start_dir = "pack/*/start/*/%s%s"; // NOLINT - size_t len = STRLEN(start_dir) + STRLEN(name) + 6; + size_t len = strlen(start_dir) + strlen(name) + 6; char *s = xmallocz(len); // TODO(bfredl): get rid of random allocations char *suffix = (flags & DIP_AFTER) ? "after/" : ""; @@ -535,7 +556,7 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c if (done == FAIL || (flags & DIP_ALL)) { start_dir = "start/*/%s%s"; // NOLINT - len = STRLEN(start_dir) + STRLEN(name) + 6; + len = strlen(start_dir) + strlen(name) + 6; s = xmallocz(len); vim_snprintf(s, len, start_dir, suffix, name); @@ -547,7 +568,7 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT)) { char *opt_dir = "pack/*/opt/*/%s"; // NOLINT - size_t len = STRLEN(opt_dir) + STRLEN(name); + size_t len = strlen(opt_dir) + strlen(name); char *s = xmallocz(len); vim_snprintf(s, len, opt_dir, name); @@ -557,7 +578,7 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c if (done == FAIL || (flags & DIP_ALL)) { opt_dir = "opt/*/%s"; // NOLINT - len = STRLEN(opt_dir) + STRLEN(name); + len = strlen(opt_dir) + strlen(name); s = xmallocz(len); vim_snprintf(s, len, opt_dir, name); @@ -604,18 +625,18 @@ static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_ } static void expand_pack_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used, - CharVec *after_path, char_u *pack_entry, size_t pack_entry_len) + CharVec *after_path, char *pack_entry, size_t pack_entry_len) { static char buf[MAXPATHL]; char *(start_pat[]) = { "/pack/*/start/*", "/start/*" }; // NOLINT for (int i = 0; i < 2; i++) { - if (pack_entry_len + STRLEN(start_pat[i]) + 1 > sizeof buf) { + if (pack_entry_len + strlen(start_pat[i]) + 1 > sizeof buf) { continue; } STRLCPY(buf, pack_entry, sizeof buf); STRLCPY(buf + pack_entry_len, start_pat[i], sizeof buf - pack_entry_len); expand_rtp_entry(search_path, rtp_used, buf, false); - size_t after_size = STRLEN(buf) + 7; + size_t after_size = strlen(buf) + 7; char *after = xmallocz(after_size); xstrlcpy(after, buf, after_size); xstrlcat(after, "/after", after_size); @@ -630,7 +651,7 @@ static bool path_is_after(char *buf, size_t buflen) // "after" dir in SOME codepaths not not in ALL codepaths. return buflen >= 5 && (!(buflen >= 6) || vim_ispathsep(buf[buflen - 6])) - && STRCMP(buf + buflen - 5, "after") == 0; + && strcmp(buf + buflen - 5, "after") == 0; } RuntimeSearchPath runtime_search_path_build(void) @@ -643,32 +664,32 @@ RuntimeSearchPath runtime_search_path_build(void) RuntimeSearchPath search_path = KV_INITIAL_VALUE; CharVec after_path = KV_INITIAL_VALUE; - static char_u buf[MAXPATHL]; - for (char *entry = (char *)p_pp; *entry != NUL;) { + static char buf[MAXPATHL]; + for (char *entry = p_pp; *entry != NUL;) { char *cur_entry = entry; - copy_option_part(&entry, (char *)buf, MAXPATHL, ","); + copy_option_part(&entry, buf, MAXPATHL, ","); - String the_entry = { .data = cur_entry, .size = STRLEN(buf) }; + String the_entry = { .data = cur_entry, .size = strlen(buf) }; kv_push(pack_entries, the_entry); map_put(String, handle_T)(&pack_used, the_entry, 0); } char *rtp_entry; - for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL;) { + for (rtp_entry = p_rtp; *rtp_entry != NUL;) { char *cur_entry = rtp_entry; - copy_option_part(&rtp_entry, (char *)buf, MAXPATHL, ","); - size_t buflen = STRLEN(buf); + copy_option_part(&rtp_entry, buf, MAXPATHL, ","); + size_t buflen = strlen(buf); - if (path_is_after((char *)buf, buflen)) { + if (path_is_after(buf, buflen)) { rtp_entry = cur_entry; break; } // fact: &rtp entries can contain wild chars - expand_rtp_entry(&search_path, &rtp_used, (char *)buf, false); + expand_rtp_entry(&search_path, &rtp_used, buf, false); - handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string((char *)buf), false); + handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string(buf), false); if (h) { (*h)++; expand_pack_entry(&search_path, &rtp_used, &after_path, buf, buflen); @@ -679,7 +700,7 @@ RuntimeSearchPath runtime_search_path_build(void) String item = kv_A(pack_entries, i); handle_T h = map_get(String, handle_T)(&pack_used, item); if (h == 0) { - expand_pack_entry(&search_path, &rtp_used, &after_path, (char_u *)item.data, item.size); + expand_pack_entry(&search_path, &rtp_used, &after_path, item.data, item.size); } } @@ -691,8 +712,8 @@ 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((char *)buf, STRLEN(buf))); + copy_option_part(&rtp_entry, buf, MAXPATHL, ","); + expand_rtp_entry(&search_path, &rtp_used, buf, path_is_after(buf, strlen(buf))); } // strings are not owned @@ -746,13 +767,13 @@ int do_in_runtimepath(char *name, int flags, DoInRuntimepathCB callback, void *c { int success = FAIL; if (!(flags & DIP_NORTP)) { - success |= do_in_cached_path((name && !*name) ? NULL : (char_u *)name, flags, callback, cookie); + success |= do_in_cached_path((name && !*name) ? NULL : name, flags, callback, cookie); flags = (flags & ~DIP_START) | DIP_NORTP; } // TODO(bfredl): we could integrate disabled OPT dirs into the cached path // which would effectivize ":packadd myoptpack" as well if ((flags & (DIP_START|DIP_OPT)) && (success == FAIL || (flags & DIP_ALL))) { - success |= do_in_path_and_pp(p_rtp, (char_u *)name, flags, callback, cookie); + success |= do_in_path_and_pp(p_rtp, name, flags, callback, cookie); } return success; } @@ -768,7 +789,7 @@ int source_runtime(char *name, int flags) } /// Just like source_runtime(), but use "path" instead of 'runtimepath'. -int source_in_path(char_u *path, char_u *name, int flags) +int source_in_path(char *path, char *name, int flags) { return do_in_path_and_pp(path, name, flags, source_callback, NULL); } @@ -792,17 +813,23 @@ static void source_all_matches(char *pat) /// /// @param fname the package path /// @param is_pack whether the added dir is a "pack/*/start/*/" style package -static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) +static int add_pack_dir_to_rtp(char *fname, bool is_pack) { - char_u *p4, *p3, *p2, *p1, *p; - char_u *buf = NULL; + char *p; + char *buf = NULL; char *afterdir = NULL; int retval = FAIL; - p4 = p3 = p2 = p1 = get_past_head(fname); + char *p1 = get_past_head(fname); + char *p2 = p1; + char *p3 = p1; + char *p4 = p1; for (p = p1; *p; MB_PTR_ADV(p)) { if (vim_ispathsep_nocolon(*p)) { - p4 = p3; p3 = p2; p2 = p1; p1 = p; + p4 = p3; + p3 = p2; + p2 = p1; + p1 = p; } } @@ -812,9 +839,9 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) // // find the part up to "pack" in 'runtimepath' p4++; // append pathsep in order to expand symlink - char_u c = *p4; + char c = *p4; *p4 = NUL; - char *const ffname = fix_fname((char *)fname); + char *const ffname = fix_fname(fname); *p4 = c; if (ffname == NULL) { @@ -833,10 +860,10 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) for (const char *entry = (const char *)p_rtp; *entry != NUL;) { const char *cur_entry = entry; - copy_option_part((char **)&entry, (char *)buf, MAXPATHL, ","); + copy_option_part((char **)&entry, buf, MAXPATHL, ","); if (insp == NULL) { - add_pathsep((char *)buf); - char *const rtp_ffname = fix_fname((char *)buf); + add_pathsep(buf); + char *const rtp_ffname = fix_fname(buf); if (rtp_ffname == NULL) { goto theend; } @@ -848,7 +875,7 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) } } - if ((p = (char_u *)strstr((char *)buf, "after")) != NULL + if ((p = strstr(buf, "after")) != NULL && p > buf && vim_ispathsep(p[-1]) && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',')) { @@ -864,18 +891,18 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) if (insp == NULL) { // Both "fname" and "after" not found, append at the end. - insp = (const char *)p_rtp + STRLEN(p_rtp); + insp = (const char *)p_rtp + strlen(p_rtp); } // check if rtp/pack/name/start/name/after exists - afterdir = concat_fnames((char *)fname, "after", true); + afterdir = concat_fnames(fname, "after", true); size_t afterlen = 0; - if (is_pack ? pack_has_entries((char_u *)afterdir) : os_isdir((char_u *)afterdir)) { + if (is_pack ? pack_has_entries(afterdir) : os_isdir(afterdir)) { afterlen = strlen(afterdir) + 1; // add one for comma } - const size_t oldlen = STRLEN(p_rtp); - const size_t addlen = STRLEN(fname) + 1; // add one for comma + const size_t oldlen = strlen(p_rtp); + const size_t addlen = strlen(fname) + 1; // add one for comma const size_t new_rtp_capacity = oldlen + addlen + afterlen + 1; // add one for NUL ------------------------------------------^ char *const new_rtp = try_malloc(new_rtp_capacity); @@ -923,7 +950,7 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) xstrlcat(new_rtp, afterdir, new_rtp_capacity); } - set_option_value("rtp", 0L, new_rtp, 0); + set_option_value_give_err("rtp", 0L, new_rtp, 0); xfree(new_rtp); retval = OK; @@ -937,29 +964,29 @@ theend: /// Load scripts in "plugin" directory of the package. /// For opt packages, also load scripts in "ftdetect" (start packages already /// load these from filetype.vim) -static int load_pack_plugin(bool opt, char_u *fname) +static int load_pack_plugin(bool opt, char *fname) { static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT - char *const ffname = fix_fname((char *)fname); - size_t len = strlen(ffname) + STRLEN(ftpat); - char_u *pat = xmallocz(len); + char *const ffname = fix_fname(fname); + size_t len = strlen(ffname) + strlen(ftpat); + char *pat = xmallocz(len); - vim_snprintf((char *)pat, len, "%s/plugin/**/*.vim", ffname); // NOLINT - source_all_matches((char *)pat); - vim_snprintf((char *)pat, len, "%s/plugin/**/*.lua", ffname); // NOLINT - source_all_matches((char *)pat); + vim_snprintf(pat, len, "%s/plugin/**/*.vim", ffname); // NOLINT + source_all_matches(pat); + vim_snprintf(pat, len, "%s/plugin/**/*.lua", ffname); // NOLINT + source_all_matches(pat); - char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes"); + char *cmd = xstrdup("g:did_load_filetypes"); // If runtime/filetype.vim wasn't loaded yet, the scripts will be // found when it loads. - if (opt && eval_to_number((char *)cmd) > 0) { + if (opt && eval_to_number(cmd) > 0) { do_cmdline_cmd("augroup filetypedetect"); - vim_snprintf((char *)pat, len, ftpat, ffname); - source_all_matches((char *)pat); + vim_snprintf(pat, len, ftpat, ffname); + source_all_matches(pat); vim_snprintf((char *)pat, len, "%s/ftdetect/*.lua", ffname); // NOLINT - source_all_matches((char *)pat); + source_all_matches(pat); do_cmdline_cmd("augroup END"); } xfree(cmd); @@ -974,7 +1001,7 @@ static int APP_ADD_DIR; static int APP_LOAD; static int APP_BOTH; -static void add_pack_plugin(bool opt, char_u *fname, void *cookie) +static void add_pack_plugin(bool opt, char *fname, void *cookie) { if (cookie != &APP_LOAD) { char *buf = xmalloc(MAXPATHL); @@ -983,7 +1010,7 @@ static void add_pack_plugin(bool opt, char_u *fname, void *cookie) const char *p = (const char *)p_rtp; while (*p != NUL) { copy_option_part((char **)&p, buf, MAXPATHL, ","); - if (path_fnamecmp(buf, (char *)fname) == 0) { + if (path_fnamecmp(buf, fname) == 0) { found = true; break; } @@ -1004,12 +1031,12 @@ static void add_pack_plugin(bool opt, char_u *fname, void *cookie) static void add_start_pack_plugin(char *fname, void *cookie) { - add_pack_plugin(false, (char_u *)fname, cookie); + add_pack_plugin(false, fname, cookie); } static void add_opt_pack_plugin(char *fname, void *cookie) { - add_pack_plugin(true, (char_u *)fname, cookie); + add_pack_plugin(true, fname, cookie); } /// Add all packages in the "start" directory to 'runtimepath'. @@ -1018,11 +1045,11 @@ void add_pack_start_dirs(void) do_in_path(p_pp, NULL, DIP_ALL + DIP_DIR, add_pack_start_dir, NULL); } -static bool pack_has_entries(char_u *buf) +static bool pack_has_entries(char *buf) { int num_files; char **files; - char *(pat[]) = { (char *)buf }; + char *(pat[]) = { buf }; if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) { FreeWild(num_files, files); } @@ -1031,14 +1058,14 @@ static bool pack_has_entries(char_u *buf) static void add_pack_start_dir(char *fname, void *cookie) { - static char_u buf[MAXPATHL]; + static char buf[MAXPATHL]; char *(start_pat[]) = { "/start/*", "/pack/*/start/*" }; // NOLINT for (int i = 0; i < 2; i++) { - if (STRLEN(fname) + STRLEN(start_pat[i]) + 1 > MAXPATHL) { + if (strlen(fname) + strlen(start_pat[i]) + 1 > MAXPATHL) { continue; } STRLCPY(buf, fname, MAXPATHL); - STRLCAT(buf, start_pat[i], sizeof buf); + xstrlcat(buf, start_pat[i], sizeof buf); if (pack_has_entries(buf)) { add_pack_dir_to_rtp(buf, true); } @@ -1072,12 +1099,12 @@ void ex_packloadall(exarg_T *eap) void load_plugins(void) { if (p_lpl) { - char_u *rtp_copy = p_rtp; - char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT - char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT + char *rtp_copy = p_rtp; + char *const plugin_pattern_vim = "plugin/**/*.vim"; // NOLINT + char *const plugin_pattern_lua = "plugin/**/*.lua"; // NOLINT if (!did_source_packages) { - rtp_copy = vim_strsave(p_rtp); + rtp_copy = xstrdup(p_rtp); add_pack_start_dirs(); } @@ -1094,8 +1121,8 @@ void load_plugins(void) } TIME_MSG("loading packages"); - source_runtime((char *)plugin_pattern_vim, DIP_ALL | DIP_AFTER); - source_runtime((char *)plugin_pattern_lua, DIP_ALL | DIP_AFTER); + source_runtime(plugin_pattern_vim, DIP_ALL | DIP_AFTER); + source_runtime(plugin_pattern_lua, DIP_ALL | DIP_AFTER); TIME_MSG("loading after plugins"); } } @@ -1113,14 +1140,15 @@ void ex_packadd(exarg_T *eap) continue; } - const size_t len = STRLEN(plugpat) + STRLEN(eap->arg) + 5; + const size_t len = strlen(plugpat) + strlen(eap->arg) + 5; char *pat = xmallocz(len); vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg); // The first round don't give a "not found" error, in the second round // only when nothing was found in the first round. - res = do_in_path(p_pp, pat, DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0), - round == 1 ? add_start_pack_plugin : add_opt_pack_plugin, - eap->forceit ? &APP_ADD_DIR : &APP_BOTH); + res = + do_in_path(p_pp, pat, DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0), + round == 1 ? add_start_pack_plugin : add_opt_pack_plugin, + eap->forceit ? &APP_ADD_DIR : &APP_BOTH); xfree(pat); } } @@ -1134,49 +1162,49 @@ void ex_packadd(exarg_T *eap) /// '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. -int ExpandRTDir(char_u *pat, int flags, int *num_file, char ***file, char *dirnames[]) +int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[]) { *num_file = 0; *file = NULL; - size_t pat_len = STRLEN(pat); + size_t pat_len = strlen(pat); garray_T ga; ga_init(&ga, (int)sizeof(char *), 10); // TODO(bfredl): this is bullshit, exandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = STRLEN(dirnames[i]) + pat_len + 7; - char_u *s = xmalloc(size); - snprintf((char *)s, size, "%s/%s*.vim", dirnames[i], pat); - globpath((char *)p_rtp, s, &ga, 0); + size_t size = strlen(dirnames[i]) + pat_len + 7; + char *s = xmalloc(size); + snprintf(s, size, "%s/%s*.vim", dirnames[i], pat); + globpath(p_rtp, s, &ga, 0); if (flags & DIP_LUA) { - snprintf((char *)s, size, "%s/%s*.lua", dirnames[i], pat); - globpath((char *)p_rtp, s, &ga, 0); + snprintf(s, size, "%s/%s*.lua", dirnames[i], pat); + globpath(p_rtp, s, &ga, 0); } xfree(s); } if (flags & DIP_START) { for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = STRLEN(dirnames[i]) + pat_len + 22; - char_u *s = xmalloc(size); - snprintf((char *)s, size, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + size_t size = strlen(dirnames[i]) + pat_len + 22; + char *s = xmalloc(size); + snprintf(s, size, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); if (flags & DIP_LUA) { - snprintf((char *)s, size, "pack/*/start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + snprintf(s, size, "pack/*/start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); } xfree(s); } for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = STRLEN(dirnames[i]) + pat_len + 22; - char_u *s = xmalloc(size); - snprintf((char *)s, size, "start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + size_t size = strlen(dirnames[i]) + pat_len + 22; + char *s = xmalloc(size); + snprintf(s, size, "start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); if (flags & DIP_LUA) { - snprintf((char *)s, size, "start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + snprintf(s, size, "start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); } xfree(s); } @@ -1184,34 +1212,34 @@ int ExpandRTDir(char_u *pat, int flags, int *num_file, char ***file, char *dirna if (flags & DIP_OPT) { for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = STRLEN(dirnames[i]) + pat_len + 20; - char_u *s = xmalloc(size); - snprintf((char *)s, size, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + size_t size = strlen(dirnames[i]) + pat_len + 20; + char *s = xmalloc(size); + snprintf(s, size, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); if (flags & DIP_LUA) { - snprintf((char *)s, size, "pack/*/opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + snprintf(s, size, "pack/*/opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); } xfree(s); } for (int i = 0; dirnames[i] != NULL; i++) { - size_t size = STRLEN(dirnames[i]) + pat_len + 20; - char_u *s = xmalloc(size); - snprintf((char *)s, size, "opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + size_t size = strlen(dirnames[i]) + pat_len + 20; + char *s = xmalloc(size); + snprintf(s, size, "opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); if (flags & DIP_LUA) { - snprintf((char *)s, size, "opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + snprintf(s, size, "opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); } xfree(s); } } for (int i = 0; i < ga.ga_len; i++) { - char_u *match = ((char_u **)ga.ga_data)[i]; - char_u *s = match; - char_u *e = s + STRLEN(s); + char *match = ((char **)ga.ga_data)[i]; + char *s = match; + char *e = s + strlen(s); if (e - s > 4 && (STRNICMP(e - 4, ".vim", 4) == 0 || ((flags & DIP_LUA) && STRNICMP(e - 4, ".lua", 4) == 0))) { @@ -1243,27 +1271,27 @@ int ExpandRTDir(char_u *pat, int flags, int *num_file, char ***file, char *dirna /// Expand loadplugin names: /// 'packpath'/pack/ * /opt/{pat} -int ExpandPackAddDir(char_u *pat, int *num_file, char ***file) +int ExpandPackAddDir(char *pat, int *num_file, char ***file) { garray_T ga; *num_file = 0; *file = NULL; - size_t pat_len = STRLEN(pat); + size_t pat_len = strlen(pat); ga_init(&ga, (int)sizeof(char *), 10); size_t buflen = pat_len + 26; - char_u *s = xmalloc(buflen); - snprintf((char *)s, buflen, "pack/*/opt/%s*", pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); - snprintf((char *)s, buflen, "opt/%s*", pat); // NOLINT - globpath((char *)p_pp, s, &ga, 0); + char *s = xmalloc(buflen); + snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT + globpath(p_pp, s, &ga, 0); + snprintf(s, buflen, "opt/%s*", pat); // NOLINT + globpath(p_pp, s, &ga, 0); xfree(s); for (int i = 0; i < ga.ga_len; i++) { - char_u *match = ((char_u **)ga.ga_data)[i]; - s = (char_u *)path_tail((char *)match); - memmove(match, s, STRLEN(s) + 1); + char *match = ((char **)ga.ga_data)[i]; + s = path_tail(match); + memmove(match, s, strlen(s) + 1); } if (GA_EMPTY(&ga)) { @@ -1423,7 +1451,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_ if (!after_pathsep(dest - 1, dest)) { *dest++ = PATHSEP; } -#if defined(WIN32) +#if defined(MSWIN) size_t size = (type == kXDGDataHome ? sizeof("nvim-data") - 1 : NVIM_SIZE); memmove(dest, (type == kXDGDataHome ? "nvim-data" : "nvim"), size); dest += size; @@ -1451,7 +1479,7 @@ char *get_lib_dir(void) // TODO(bfredl): too fragile? Ideally default_lib_dir would be made empty // in an appimage build if (strlen(default_lib_dir) != 0 - && os_isdir((const char_u *)default_lib_dir)) { + && os_isdir(default_lib_dir)) { return xstrdup(default_lib_dir); } @@ -1493,7 +1521,7 @@ char *runtimepath_default(bool clean_arg) if (data_home != NULL) { data_len = strlen(data_home); if (data_len != 0) { -#if defined(WIN32) +#if defined(MSWIN) size_t nvim_size = (sizeof("nvim-data") - 1); #else size_t nvim_size = NVIM_SIZE; @@ -1583,7 +1611,7 @@ static void cmd_source(char *fname, exarg_T *eap) // - after ":argdo", ":windo" or ":bufdo" // - another command follows // - inside a loop - openscript((char_u *)fname, global_busy || listcmd_busy || eap->nextcmd != NULL + openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL || eap->cstack->cs_idx >= 0); // ":source" read ex commands @@ -1636,7 +1664,7 @@ int source_level(void *cookie) /// If possible the handle is closed on exec(). static FILE *fopen_noinh_readbin(char *filename) { -#ifdef WIN32 +#ifdef MSWIN int fd_tmp = os_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0); #else int fd_tmp = os_open(filename, O_RDONLY, 0); @@ -1663,12 +1691,12 @@ static FILE *fopen_noinh_readbin(char *filename) /// /// @return true if this line did begin with a continuation (the next line /// should also be considered, if it exists); false otherwise -static bool concat_continued_line(garray_T *const ga, const int init_growsize, - const char_u *const p, size_t len) +static bool concat_continued_line(garray_T *const ga, const int init_growsize, const char *const p, + size_t len) FUNC_ATTR_NONNULL_ALL { - const char *const line = (char *)skipwhite_len(p, len); - len -= (size_t)((char_u *)line - p); + const char *const line = skipwhite_len((char *)p, len); + len -= (size_t)(line - p); // Skip lines starting with '\" ', concat lines starting with '\' if (len >= 3 && STRNCMP(line, "\"\\ ", 3) == 0) { return true; @@ -1700,19 +1728,19 @@ typedef struct { static char *get_str_line(int c, void *cookie, int indent, bool do_concat) { GetStrLineCookie *p = cookie; - if (STRLEN(p->buf) <= p->offset) { + if (strlen(p->buf) <= p->offset) { return NULL; } const char *line = p->buf + p->offset; - const char *eol = (char *)skip_to_newline((char_u *)line); + const char *eol = skip_to_newline(line); garray_T ga; - ga_init(&ga, sizeof(char_u), 400); + ga_init(&ga, sizeof(char), 400); ga_concat_len(&ga, line, (size_t)(eol - line)); if (do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) { while (eol[0] != NUL) { line = eol + 1; - const char_u *const next_eol = skip_to_newline((char_u *)line); - if (!concat_continued_line(&ga, 400, (char_u *)line, (size_t)(next_eol - (char_u *)line))) { + const char *const next_eol = skip_to_newline(line); + if (!concat_continued_line(&ga, 400, line, (size_t)(next_eol - line))) { break; } eol = (char *)next_eol; @@ -1742,7 +1770,7 @@ scriptitem_T *new_script_item(char *const name, scid_T *const sid_out) SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false; } - SCRIPT_ITEM(sid).sn_name = (char_u *)name; + SCRIPT_ITEM(sid).sn_name = name; new_script_vars(sid); // Allocate the local script variables to use for this script. return &SCRIPT_ITEM(sid); } @@ -1786,7 +1814,7 @@ static void cmd_source_buffer(const exarg_T *const eap) return; } garray_T ga; - ga_init(&ga, sizeof(char_u), 400); + ga_init(&ga, sizeof(char), 400); const linenr_T final_lnum = eap->line2; // Copy the contents to be executed. for (linenr_T curr_lnum = eap->line1; curr_lnum <= final_lnum; curr_lnum++) { @@ -1794,10 +1822,10 @@ static void cmd_source_buffer(const exarg_T *const eap) if (ga.ga_len > 400) { ga_set_growsize(&ga, MIN(ga.ga_len, 8000)); } - ga_concat(&ga, (char *)ml_get(curr_lnum)); + ga_concat(&ga, ml_get(curr_lnum)); ga_append(&ga, NL); } - ((char_u *)ga.ga_data)[ga.ga_len - 1] = NUL; + ((char *)ga.ga_data)[ga.ga_len - 1] = NUL; const GetStrLineCookie cookie = { .buf = ga.ga_data, .offset = 0, @@ -1858,7 +1886,7 @@ int do_source(char *fname, int check_other, int is_vimrc) if (fname_exp == NULL) { return retval; } - if (os_isdir((char_u *)fname_exp)) { + if (os_isdir(fname_exp)) { smsg(_("Cannot source a directory: \"%s\""), fname); goto theend; } @@ -1935,7 +1963,7 @@ int do_source(char *fname, int check_other, int is_vimrc) cookie.finished = false; // Check if this script has a breakpoint. - cookie.breakpoint = dbg_find_breakpoint(true, (char_u *)fname_exp, (linenr_T)0); + cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, (linenr_T)0); cookie.fname = fname_exp; cookie.dbg_tick = debug_tick; @@ -1964,7 +1992,7 @@ int do_source(char *fname, int check_other, int is_vimrc) si = get_current_script_id(&fname_exp, ¤t_sctx); // Keep the sourcing name/lnum, for recursive calls. - estack_push(ETYPE_SCRIPT, (char *)si->sn_name, 0); + estack_push(ETYPE_SCRIPT, si->sn_name, 0); if (l_do_profiling == PROF_YES) { bool forceit = false; @@ -1996,8 +2024,8 @@ int do_source(char *fname, int check_other, int is_vimrc) if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef && firstline[1] == 0xbb && firstline[2] == 0xbf) { // Found BOM; setup conversion, skip over BOM and recode the line. - convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc); - p = (char *)string_convert(&cookie.conv, (char_u *)firstline + 3, NULL); + convert_setup(&cookie.conv, "utf-8", p_enc); + p = string_convert(&cookie.conv, (char *)firstline + 3, NULL); if (p == NULL) { p = xstrdup((char *)firstline + 3); } @@ -2093,14 +2121,14 @@ scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx) // - If a script is deleted and another script is written, with a // different name, the inode may be re-used. si = &SCRIPT_ITEM(script_sctx.sc_sid); - if (si->sn_name != NULL && FNAMECMP(si->sn_name, *fnamep) == 0) { + if (si->sn_name != NULL && path_fnamecmp(si->sn_name, *fnamep) == 0) { // Found it! break; } } if (script_sctx.sc_sid == 0) { si = new_script_item(*fnamep, &script_sctx.sc_sid); - *fnamep = xstrdup((char *)si->sn_name); + *fnamep = xstrdup(si->sn_name); } if (ret_sctx != NULL) { *ret_sctx = script_sctx; @@ -2117,7 +2145,7 @@ void ex_scriptnames(exarg_T *eap) if (eap->line2 < 1 || eap->line2 > script_items.ga_len) { emsg(_(e_invarg)); } else { - eap->arg = (char *)SCRIPT_ITEM(eap->line2).sn_name; + eap->arg = SCRIPT_ITEM(eap->line2).sn_name; do_exedit(eap, NULL); } return; @@ -2125,9 +2153,9 @@ void ex_scriptnames(exarg_T *eap) for (int i = 1; i <= script_items.ga_len && !got_int; i++) { if (SCRIPT_ITEM(i).sn_name != NULL) { - home_replace(NULL, (char *)SCRIPT_ITEM(i).sn_name, (char *)NameBuff, MAXPATHL, true); + home_replace(NULL, SCRIPT_ITEM(i).sn_name, (char *)NameBuff, MAXPATHL, true); vim_snprintf((char *)IObuff, IOSIZE, "%3d: %s", i, NameBuff); - if (!message_filtered(IObuff)) { + if (!message_filtered((char *)IObuff)) { msg_putchar('\n'); msg_outtrans((char *)IObuff); line_breakcheck(); @@ -2151,40 +2179,40 @@ void scriptnames_slash_adjust(void) /// Get a pointer to a script name. Used for ":verbose set". /// Message appended to "Last set from " -char_u *get_scriptname(LastSet last_set, bool *should_free) +char *get_scriptname(LastSet last_set, bool *should_free) { *should_free = false; switch (last_set.script_ctx.sc_sid) { case SID_MODELINE: - return (char_u *)_("modeline"); + return _("modeline"); case SID_CMDARG: - return (char_u *)_("--cmd argument"); + return _("--cmd argument"); case SID_CARG: - return (char_u *)_("-c argument"); + return _("-c argument"); case SID_ENV: - return (char_u *)_("environment variable"); + return _("environment variable"); case SID_ERROR: - return (char_u *)_("error handler"); + return _("error handler"); case SID_WINLAYOUT: - return (char_u *)_("changed window size"); + return _("changed window size"); case SID_LUA: - return (char_u *)_("Lua"); + return _("Lua"); case SID_API_CLIENT: snprintf((char *)IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), last_set.channel_id); - return IObuff; + return (char *)IObuff; case SID_STR: - return (char_u *)_("anonymous :source"); + return _("anonymous :source"); default: { - char *const sname = (char *)SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name; + char *const sname = SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name; if (sname == NULL) { snprintf((char *)IObuff, IOSIZE, _("anonymous :source (script id %d)"), last_set.script_ctx.sc_sid); - return IObuff; + return (char *)IObuff; } *should_free = true; - return (char_u *)home_replace_save(NULL, sname); + return home_replace_save(NULL, sname); } } } @@ -2220,7 +2248,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) // If breakpoints have been added/deleted need to check for it. if (sp->dbg_tick < debug_tick) { - sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, SOURCING_LNUM); + sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -2259,11 +2287,10 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))) { garray_T ga; - ga_init(&ga, (int)sizeof(char_u), 400); + ga_init(&ga, (int)sizeof(char), 400); ga_concat(&ga, line); while (sp->nextline != NULL - && concat_continued_line(&ga, 400, (char_u *)sp->nextline, - STRLEN(sp->nextline))) { + && concat_continued_line(&ga, 400, sp->nextline, strlen(sp->nextline))) { xfree(sp->nextline); sp->nextline = get_one_sourceline(sp); } @@ -2277,7 +2304,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) char *s; // Convert the encoding of the script line. - s = (char *)string_convert(&sp->conv, (char_u *)line, NULL); + s = string_convert(&sp->conv, line, NULL); if (s != NULL) { xfree(line); line = s; @@ -2286,9 +2313,9 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) // Did we encounter a breakpoint? if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) { - dbg_breakpoint((char_u *)sp->fname, SOURCING_LNUM); + dbg_breakpoint(sp->fname, SOURCING_LNUM); // Find next breakpoint. - sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, SOURCING_LNUM); + sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } @@ -2326,7 +2353,7 @@ retry: break; } - len = ga.ga_len + (int)STRLEN(buf + ga.ga_len); + len = ga.ga_len + (int)strlen(buf + ga.ga_len); #ifdef USE_CRNL // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the // CTRL-Z by its own, or after a NL. @@ -2410,14 +2437,14 @@ void ex_scriptencoding(exarg_T *eap) } if (*eap->arg != NUL) { - name = (char *)enc_canonize((char_u *)eap->arg); + name = enc_canonize(eap->arg); } else { name = eap->arg; } // Setup for conversion from the specified encoding to 'encoding'. sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie); - convert_setup(&sp->conv, (char_u *)name, p_enc); + convert_setup(&sp->conv, name, p_enc); if (name != eap->arg) { xfree(name); diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index a255c6c096..053c71212e 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -47,10 +47,11 @@ typedef enum { ESTACK_NONE, ESTACK_SFILE, ESTACK_STACK, + ESTACK_SCRIPT, } estack_arg_T; typedef struct scriptitem_S { - char_u *sn_name; + char *sn_name; bool sn_prof_on; ///< true when script is/was profiled bool sn_pr_force; ///< forceit: profile functions in this script proftime_T sn_pr_child; ///< time set when going into first child diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b471b93192..bc440441e1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -69,7 +69,7 @@ bool conceal_cursor_line(const win_T *wp) } else { return false; } - return vim_strchr((char *)wp->w_p_cocu, c) != NULL; + return vim_strchr(wp->w_p_cocu, c) != NULL; } /// Whether cursorline is drawn in a special way @@ -155,8 +155,6 @@ void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endr } else { grid_fill(&wp->w_grid, row, endrow, n, wp->w_grid.cols, c1, c2, attr); } - - set_empty_rows(wp, row); } /// Compute the width of the foldcolumn. Based on 'foldcolumn' and how much @@ -277,7 +275,7 @@ static int wildmenu_match_len(expand_T *xp, char_u *s) /// These are backslashes used for escaping. Do show backslashes in help tags. static int skip_wildmenu_char(expand_T *xp, char_u *s) { - if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) + if ((rem_backslash((char *)s) && xp->xp_context != EXPAND_HELP) || ((xp->xp_context == EXPAND_MENUS || xp->xp_context == EXPAND_MENUNAMES) && (s[0] == '\t' @@ -442,7 +440,7 @@ void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int match, i // Put the wildmenu just above the command line. If there is // no room, scroll the screen one line up. if (cmdline_row == Rows - 1) { - msg_scroll_up(false); + msg_scroll_up(false, false); msg_scrolled++; } else { cmdline_row++; @@ -469,10 +467,10 @@ void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int match, i ScreenGrid *grid = (wild_menu_showing == WM_SCROLLED) ? &msg_grid_adj : &default_grid; - grid_puts(grid, buf, row, 0, attr); + grid_puts(grid, (char *)buf, row, 0, attr); if (selstart != NULL && highlight) { *selend = NUL; - grid_puts(grid, selstart, row, selstart_col, HL_ATTR(HLF_WM)); + grid_puts(grid, (char *)selstart, row, selstart_col, HL_ATTR(HLF_WM)); } grid_fill(grid, row, row + 1, clen, Columns, @@ -535,7 +533,7 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) curwin = old_curwin; if (p == NULL || *p == NUL) { if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) { - p = (char *)wp->w_buffer->b_p_keymap; + p = wp->w_buffer->b_p_keymap; } else { p = "lang"; } @@ -620,7 +618,7 @@ void setcursor_mayforce(bool force) // With 'rightleft' set and the cursor on a double-wide character, // position it on the leftmost column. col = curwin->w_width_inner - curwin->w_wcol - - ((utf_ptr2cells((char *)get_cursor_pos_ptr()) == 2 + - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2 && vim_isprintc(gchar_cursor())) ? 2 : 1); } @@ -734,13 +732,13 @@ int showmode(void) length = (Rows - msg_row) * Columns - 3; } if (edit_submode_extra != NULL) { - length -= vim_strsize((char *)edit_submode_extra); + length -= vim_strsize(edit_submode_extra); } if (length > 0) { if (edit_submode_pre != NULL) { - length -= vim_strsize((char *)edit_submode_pre); + length -= vim_strsize(edit_submode_pre); } - if (length - vim_strsize((char *)edit_submode) > 0) { + if (length - vim_strsize(edit_submode) > 0) { if (edit_submode_pre != NULL) { msg_puts_attr((const char *)edit_submode_pre, attr); } @@ -1013,7 +1011,7 @@ void draw_tabline(void) modified = false; - for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount) { + for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) { if (bufIsChanged(wp->w_buffer)) { modified = true; } @@ -1022,7 +1020,7 @@ void draw_tabline(void) if (modified || wincount > 1) { if (wincount > 1) { vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount); - len = (int)STRLEN(NameBuff); + len = (int)strlen(NameBuff); if (col + len >= Columns - 3) { break; } @@ -1031,7 +1029,7 @@ void draw_tabline(void) col += len; } if (modified) { - grid_puts_len(&default_grid, (char_u *)"+", 1, 0, col++, attr); + grid_puts_len(&default_grid, "+", 1, 0, col++, attr); } grid_putchar(&default_grid, ' ', 0, col++, attr); } @@ -1042,7 +1040,7 @@ void draw_tabline(void) get_trans_bufname(cwp->w_buffer); shorten_dir(NameBuff); len = vim_strsize((char *)NameBuff); - p = NameBuff; + p = (char_u *)NameBuff; while (len > room) { len -= ptr2cells((char *)p); MB_PTR_ADV(p); @@ -1051,7 +1049,7 @@ void draw_tabline(void) len = Columns - col - 1; } - grid_puts_len(&default_grid, p, (int)STRLEN(p), 0, col, attr); + grid_puts_len(&default_grid, (char *)p, (int)STRLEN(p), 0, col, attr); col += len; } grid_putchar(&default_grid, ' ', 0, col++, attr); @@ -1094,7 +1092,6 @@ void draw_tabline(void) static void ui_ext_tabline_update(void) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); size_t n_tabs = 0; FOR_ALL_TABS(tp) { @@ -1135,7 +1132,7 @@ static void ui_ext_tabline_update(void) } ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } void get_trans_bufname(buf_T *buf) @@ -1174,7 +1171,9 @@ bool redrawing(void) /// Return true if printing messages should currently be done. bool messaging(void) { - return !(p_lz && char_avail() && !KeyTyped) && ui_has_messages(); + // TODO(bfredl): with general support for "async" messages with p_ch, + // this should be re-enabled. + return !(p_lz && char_avail() && !KeyTyped) && (p_ch > 0 || ui_has(kUIMessages)); } #define COL_RULER 17 // columns needed by standard ruler @@ -1263,17 +1262,15 @@ int number_width(win_T *wp) /// Calls mb_cptr2char_adv(p) and returns the character. /// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used. /// Returns 0 for invalid hex or invalid UTF-8 byte. -static int get_encoded_char_adv(char_u **p) +static int get_encoded_char_adv(const char_u **p) { - char_u *s = *p; + const char_u *s = *p; if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) { int64_t num = 0; - int bytes; - int n; - for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) { + for (int bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) { *p += 2; - n = hexhex2nr(*p); + int n = hexhex2nr((char *)(*p)); if (n < 0) { return 0; } @@ -1284,8 +1281,8 @@ static int get_encoded_char_adv(char_u **p) } // TODO(bfredl): use schar_T representation and utfc_ptr2len - int clen = utf_ptr2len((char *)s); - int c = mb_cptr2char_adv((const char_u **)p); + int clen = utf_ptr2len((const char *)s); + int c = mb_cptr2char_adv(p); if (clen == 1 && c > 127) { // Invalid UTF-8 byte return 0; } @@ -1295,26 +1292,22 @@ static int get_encoded_char_adv(char_u **p) /// Handle setting 'listchars' or 'fillchars'. /// Assume monocell characters /// -/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs +/// @param varp either the global or the window-local value. +/// @param apply if false, do not store the flags, only check for errors. /// @return error message, NULL if it's OK. -char *set_chars_option(win_T *wp, char_u **varp, bool set) +char *set_chars_option(win_T *wp, char **varp, bool apply) { - int round, i, len, len2, entries; - char_u *p, *s; - int c1; - int c2 = 0; - int c3 = 0; - char_u *last_multispace = NULL; // Last occurrence of "multispace:" - char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" + const char_u *last_multispace = NULL; // Last occurrence of "multispace:" + const char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" int multispace_len = 0; // Length of lcs-multispace string int lead_multispace_len = 0; // Length of lcs-leadmultispace string + const bool is_listchars = (varp == &p_lcs || varp == &wp->w_p_lcs); struct chars_tab { - int *cp; ///< char value + int *cp; ///< char value char *name; ///< char id - int def; ///< default value + int def; ///< default value }; - struct chars_tab *tab; // XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case. struct chars_tab fcs_tab[] = { @@ -1335,7 +1328,9 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) { &wp->w_p_fcs_chars.diff, "diff", '-' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.eob, "eob", '~' }, + { &wp->w_p_fcs_chars.lastline, "lastline", '@' }, }; + struct chars_tab lcs_tab[] = { { &wp->w_p_lcs_chars.eol, "eol", NUL }, { &wp->w_p_lcs_chars.ext, "extends", NUL }, @@ -1348,30 +1343,33 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) { &wp->w_p_lcs_chars.conceal, "conceal", NUL }, }; - if (varp == &p_lcs || varp == &wp->w_p_lcs) { + struct chars_tab *tab; + int entries; + const char_u *value = (char_u *)(*varp); + if (is_listchars) { tab = lcs_tab; entries = ARRAY_SIZE(lcs_tab); if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) { - varp = &p_lcs; + value = (char_u *)p_lcs; // local value is empty, use the global value } } else { tab = fcs_tab; entries = ARRAY_SIZE(fcs_tab); if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) { - varp = &p_fcs; + value = (char_u *)p_fcs; // local value is empty, use the global value } } // first round: check for valid value, second round: assign values - for (round = 0; round <= (set ? 1 : 0); round++) { + for (int round = 0; round <= (apply ? 1 : 0); round++) { if (round > 0) { // After checking that the value is valid: set defaults - for (i = 0; i < entries; i++) { + for (int i = 0; i < entries; i++) { if (tab[i].cp != NULL) { *(tab[i].cp) = tab[i].def; } } - if (varp == &p_lcs || varp == &wp->w_p_lcs) { + if (is_listchars) { wp->w_p_lcs_chars.tab1 = NUL; wp->w_p_lcs_chars.tab3 = NUL; @@ -1393,19 +1391,20 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) } } } - p = *varp; + const char_u *p = value; while (*p) { + int i; for (i = 0; i < entries; i++) { - len = (int)STRLEN(tab[i].name); + const size_t len = strlen(tab[i].name); if (STRNCMP(p, tab[i].name, len) == 0 && p[len] == ':' && p[len + 1] != NUL) { - c2 = c3 = 0; - s = p + len + 1; - c1 = get_encoded_char_adv(&s); + const char_u *s = p + len + 1; + int c1 = get_encoded_char_adv(&s); if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; } + int c2 = 0, c3 = 0; if (tab[i].cp == &wp->w_p_lcs_chars.tab2) { if (*s == NUL) { return e_invarg; @@ -1438,19 +1437,19 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) } if (i == entries) { - len = (int)STRLEN("multispace"); - len2 = (int)STRLEN("leadmultispace"); - if ((varp == &p_lcs || varp == &wp->w_p_lcs) + const size_t len = strlen("multispace"); + const size_t len2 = strlen("leadmultispace"); + if (is_listchars && STRNCMP(p, "multispace", len) == 0 && p[len] == ':' && p[len + 1] != NUL) { - s = p + len + 1; + const char_u *s = p + len + 1; if (round == 0) { // Get length of lcs-multispace string in the first round last_multispace = p; multispace_len = 0; while (*s != NUL && *s != ',') { - c1 = get_encoded_char_adv(&s); + int c1 = get_encoded_char_adv(&s); if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; } @@ -1464,24 +1463,24 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) } else { int multispace_pos = 0; while (*s != NUL && *s != ',') { - c1 = get_encoded_char_adv(&s); + int c1 = get_encoded_char_adv(&s); if (p == last_multispace) { wp->w_p_lcs_chars.multispace[multispace_pos++] = c1; } } p = s; } - } else if ((varp == &p_lcs || varp == &wp->w_p_lcs) + } else if (is_listchars && STRNCMP(p, "leadmultispace", len2) == 0 && p[len2] == ':' && p[len2 + 1] != NUL) { - s = p + len2 + 1; + const char_u *s = p + len2 + 1; if (round == 0) { // get length of lcs-leadmultispace string in first round last_lmultispace = p; lead_multispace_len = 0; while (*s != NUL && *s != ',') { - c1 = get_encoded_char_adv(&s); + int c1 = get_encoded_char_adv(&s); if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; } @@ -1495,7 +1494,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) } else { int multispace_pos = 0; while (*s != NUL && *s != ',') { - c1 = get_encoded_char_adv(&s); + int c1 = get_encoded_char_adv(&s); if (p == last_lmultispace) { wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1; } @@ -1506,6 +1505,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set) return e_invarg; } } + if (*p == ',') { p++; } diff --git a/src/nvim/search.c b/src/nvim/search.c index c53d955974..ed0f25cba0 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * search.c: code for normal mode searching commands - */ +// search.c: code for normal mode searching commands #include <assert.h> #include <inttypes.h> @@ -106,10 +104,8 @@ static bool saved_spats_no_hlsearch = false; static char_u *mr_pattern = NULL; // pattern used by search_regcomp() static bool mr_pattern_alloced = false; // mr_pattern was allocated -/* - * Type used by find_pattern_in_path() to remember which included files have - * been searched already. - */ +// Type used by find_pattern_in_path() to remember which included files have +// been searched already. typedef struct SearchedFile { FILE *fp; // File pointer char_u *name; // Full name of file @@ -139,9 +135,7 @@ int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatc rc_did_emsg = false; magic = p_magic; - /* - * If no pattern given, use a previously defined pattern. - */ + // If no pattern given, use a previously defined pattern. if (pat == NULL || *pat == NUL) { if (pat_use == RE_LAST) { i = last_idx; @@ -161,7 +155,7 @@ int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatc magic = spats[i].magic; no_smartcase = spats[i].no_scs; } else if (options & SEARCH_HIS) { // put new pattern in history - add_to_history(HIST_SEARCH, pat, true, NUL); + add_to_history(HIST_SEARCH, (char *)pat, true, NUL); } if (mr_pattern_alloced) { @@ -170,24 +164,22 @@ int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatc } if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { - mr_pattern = reverse_text(pat); + mr_pattern = (char_u *)reverse_text((char *)pat); mr_pattern_alloced = true; } else { mr_pattern = pat; } - /* - * Save the currently used pattern in the appropriate place, - * unless the pattern should not be remembered. - */ + // Save the currently used pattern in the appropriate place, + // unless the pattern should not be remembered. if (!(options & SEARCH_KEEP) && (cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { // search or global command if (pat_save == RE_SEARCH || pat_save == RE_BOTH) { - save_re_pat(RE_SEARCH, pat, magic); + save_re_pat(RE_SEARCH, (char *)pat, magic); } // substitute or global command if (pat_save == RE_SUBST || pat_save == RE_BOTH) { - save_re_pat(RE_SUBST, pat, magic); + save_re_pat(RE_SUBST, (char *)pat, magic); } } @@ -200,19 +192,17 @@ int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatc return OK; } -/* - * Get search pattern used by search_regcomp(). - */ +// Get search pattern used by search_regcomp(). char_u *get_search_pat(void) { return mr_pattern; } -void save_re_pat(int idx, char_u *pat, int magic) +void save_re_pat(int idx, char *pat, int magic) { - if (spats[idx].pat != pat) { + if (spats[idx].pat != (char_u *)pat) { free_spat(&spats[idx]); - spats[idx].pat = vim_strsave(pat); + spats[idx].pat = (char_u *)xstrdup(pat); spats[idx].magic = magic; spats[idx].no_scs = no_smartcase; spats[idx].timestamp = os_time(); @@ -220,16 +210,14 @@ void save_re_pat(int idx, char_u *pat, int magic) last_idx = idx; // If 'hlsearch' set and search pat changed: need redraw. if (p_hls) { - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } set_no_hlsearch(false); } } -/* - * Save the search patterns, so they can be restored later. - * Used before/after executing autocommands and user functions. - */ +// Save the search patterns, so they can be restored later. +// Used before/after executing autocommands and user functions. static int save_level = 0; void save_search_patterns(void) @@ -237,11 +225,11 @@ void save_search_patterns(void) if (save_level++ == 0) { saved_spats[0] = spats[0]; if (spats[0].pat != NULL) { - saved_spats[0].pat = vim_strsave(spats[0].pat); + saved_spats[0].pat = (char_u *)xstrdup((char *)spats[0].pat); } saved_spats[1] = spats[1]; if (spats[1].pat != NULL) { - saved_spats[1].pat = vim_strsave(spats[1].pat); + saved_spats[1].pat = (char_u *)xstrdup((char *)spats[1].pat); } saved_spats_last_idx = last_idx; saved_spats_no_hlsearch = no_hlsearch; @@ -308,7 +296,7 @@ void save_last_search_pattern(void) saved_last_search_spat = spats[RE_SEARCH]; if (spats[RE_SEARCH].pat != NULL) { - saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat); + saved_last_search_spat.pat = (char_u *)xstrdup((char *)spats[RE_SEARCH].pat); } saved_last_idx = last_idx; saved_no_hlsearch = no_hlsearch; @@ -354,10 +342,8 @@ char_u *last_search_pattern(void) return spats[RE_SEARCH].pat; } -/* - * Return TRUE when case should be ignored for search pattern "pat". - * Uses the 'ignorecase' and 'smartcase' options. - */ +/// Return true when case should be ignored for search pattern "pat". +/// Uses the 'ignorecase' and 'smartcase' options. int ignorecase(char_u *pat) { return ignorecase_opt(pat, p_ic, p_scs); @@ -423,7 +409,7 @@ int last_csearch_forward(void) int last_csearch_until(void) { - return last_t_cmd == TRUE; + return last_t_cmd == true; } void set_last_csearch(int c, char_u *s, int len) @@ -452,19 +438,15 @@ char_u *last_search_pat(void) return spats[last_idx].pat; } -/* - * Reset search direction to forward. For "gd" and "gD" commands. - */ +// Reset search direction to forward. For "gd" and "gD" commands. void reset_search_dir(void) { spats[0].off.dir = '/'; set_vv_searchforward(); } -/* - * Set the last search pattern. For ":let @/ =" and ShaDa file. - * Also set the saved search pattern, so that this works in an autocommand. - */ +// Set the last search pattern. For ":let @/ =" and ShaDa file. +// Also set the saved search pattern, so that this works in an autocommand. void set_last_search_pat(const char_u *s, int idx, int magic, int setlast) { free_spat(&spats[idx]); @@ -480,8 +462,8 @@ void set_last_search_pat(const char_u *s, int idx, int magic, int setlast) spats[idx].no_scs = false; spats[idx].off.dir = '/'; set_vv_searchforward(); - spats[idx].off.line = FALSE; - spats[idx].off.end = FALSE; + spats[idx].off.line = false; + spats[idx].off.end = false; spats[idx].off.off = 0; if (setlast) { last_idx = idx; @@ -492,28 +474,26 @@ void set_last_search_pat(const char_u *s, int idx, int magic, int setlast) if (spats[idx].pat == NULL) { saved_spats[idx].pat = NULL; } else { - saved_spats[idx].pat = vim_strsave(spats[idx].pat); + saved_spats[idx].pat = (char_u *)xstrdup((char *)spats[idx].pat); } saved_spats_last_idx = last_idx; } // If 'hlsearch' set and search pat changed: need redraw. if (p_hls && idx == last_idx && !no_hlsearch) { - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } } -/* - * Get a regexp program for the last used search pattern. - * This is used for highlighting all matches in a window. - * Values returned in regmatch->regprog and regmatch->rmm_ic. - */ +// Get a regexp program for the last used search pattern. +// This is used for highlighting all matches in a window. +// Values returned in regmatch->regprog and regmatch->rmm_ic. void last_pat_prog(regmmatch_T *regmatch) { if (spats[last_idx].pat == NULL) { regmatch->regprog = NULL; return; } - ++emsg_off; // So it doesn't beep if bad expr + emsg_off++; // So it doesn't beep if bad expr (void)search_regcomp((char_u *)"", 0, last_idx, SEARCH_KEEP, regmatch); emsg_off--; } @@ -580,9 +560,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, return FAIL; } - /* - * find the string - */ + // find the string do { // loop for count // When not accepting a match at the start position set "extra_col" to a // non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1 @@ -593,7 +571,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, && pos->lnum <= buf->b_ml.ml_line_count && pos->col < MAXCOL - 2) { // Watch out for the "col" being MAXCOL - 2, used in a closed fold. - ptr = ml_get_buf(buf, pos->lnum, false); + ptr = (char_u *)ml_get_buf(buf, pos->lnum, false); if ((int)STRLEN(ptr) <= pos->col) { start_char_len = 1; } else { @@ -610,31 +588,29 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, start_pos = *pos; // remember start pos for detecting no match found = 0; // default: not found - at_first_line = TRUE; // default: start in first line + at_first_line = true; // default: start in first line if (pos->lnum == 0) { // correct lnum for when starting in line 0 pos->lnum = 1; pos->col = 0; - at_first_line = FALSE; // not in first line now + at_first_line = false; // not in first line now } - /* - * Start searching in current line, unless searching backwards and - * we're in column 0. - * If we are searching backwards, in column 0, and not including the - * current position, gain some efficiency by skipping back a line. - * Otherwise begin the search in the current line. - */ + // Start searching in current line, unless searching backwards and + // we're in column 0. + // If we are searching backwards, in column 0, and not including the + // current position, gain some efficiency by skipping back a line. + // Otherwise begin the search in the current line. if (dir == BACKWARD && start_pos.col == 0 && (options & SEARCH_START) == 0) { lnum = pos->lnum - 1; - at_first_line = FALSE; + at_first_line = false; } else { lnum = pos->lnum; } - for (loop = 0; loop <= 1; ++loop) { // loop twice if 'wrapscan' set + for (loop = 0; loop <= 1; loop++) { // loop twice if 'wrapscan' set for (; lnum > 0 && lnum <= buf->b_ml.ml_line_count; - lnum += dir, at_first_line = FALSE) { + lnum += dir, at_first_line = false) { // Stop after checking "stop_lnum", if it's set. if (stop_lnum != 0 && (dir == FORWARD ? lnum > stop_lnum : lnum < stop_lnum)) { @@ -666,14 +642,12 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, if (lnum + matchpos.lnum > buf->b_ml.ml_line_count) { ptr = (char_u *)""; } else { - ptr = ml_get_buf(buf, lnum + matchpos.lnum, false); + ptr = (char_u *)ml_get_buf(buf, lnum + matchpos.lnum, false); } - /* - * Forward search in the first line: match should be after - * the start position. If not, continue at the end of the - * match (this is vi compatible) or on the next char. - */ + // Forward search in the first line: match should be after + // the start position. If not, continue at the end of the + // match (this is vi compatible) or on the next char. if (dir == FORWARD && at_first_line) { match_ok = true; // When the match starts in a next line it's certainly @@ -689,11 +663,9 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, : ((int)matchpos.col - (ptr[matchpos.col] == NUL) < (int)start_pos.col + extra_col))) { - /* - * If vi-compatible searching, continue at the end - * of the match, otherwise continue one position - * forward. - */ + // If vi-compatible searching, continue at the end + // of the match, otherwise continue one position + // forward. if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) { if (nmatched > 1) { // end is in next line, thus no match in @@ -739,20 +711,18 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, } // Need to get the line pointer again, a multi-line search may // have made it invalid. - ptr = ml_get_buf(buf, lnum, false); + ptr = (char_u *)ml_get_buf(buf, lnum, false); } if (!match_ok) { continue; } } if (dir == BACKWARD) { - /* - * Now, if there are multiple matches on this line, - * we have to get the last one. Or the last one before - * the cursor, if we're on that line. - * When putting the new cursor at the end, compare - * relative to the end of the match. - */ + // Now, if there are multiple matches on this line, + // we have to get the last one. Or the last one before + // the cursor, if we're on that line. + // When putting the new cursor at the end, compare + // relative to the end of the match. match_ok = false; for (;;) { // Remember a position that is before the start @@ -824,13 +794,11 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, } // Need to get the line pointer again, a // multi-line search may have made it invalid. - ptr = ml_get_buf(buf, lnum + matchpos.lnum, false); + ptr = (char_u *)ml_get_buf(buf, lnum + matchpos.lnum, false); } - /* - * If there is only a match after the cursor, skip - * this match. - */ + // If there is only a match after the cursor, skip + // this match. if (!match_ok) { continue; } @@ -849,13 +817,13 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, if (endpos.col == 0) { if (pos->lnum > 1) { // just in case pos->lnum--; - pos->col = (colnr_T)STRLEN(ml_get_buf(buf, pos->lnum, false)); + pos->col = (colnr_T)strlen(ml_get_buf(buf, pos->lnum, false)); } } else { pos->col--; if (pos->lnum <= buf->b_ml.ml_line_count) { - ptr = ml_get_buf(buf, pos->lnum, false); - pos->col -= utf_head_off(ptr, ptr + pos->col); + ptr = (char_u *)ml_get_buf(buf, pos->lnum, false); + pos->col -= utf_head_off((char *)ptr, (char *)ptr + pos->col); } } if (end_pos != NULL) { @@ -901,7 +869,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, break; // if second loop, stop where started } } - at_first_line = FALSE; + at_first_line = false; // vim_regexec_multi() may clear "regprog" if (regmatch.regprog == NULL) { @@ -966,7 +934,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // A pattern like "\n\zs" may go past the last line. if (pos->lnum > buf->b_ml.ml_line_count) { pos->lnum = buf->b_ml.ml_line_count; - pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, false)); + pos->col = (int)strlen(ml_get_buf(buf, pos->lnum, false)); if (pos->col > 0) { pos->col--; } @@ -991,7 +959,7 @@ static int first_submatch(regmmatch_T *rp) { int submatch; - for (submatch = 1;; ++submatch) { + for (submatch = 1;; submatch++) { if (rp->startpos[submatch].lnum >= 0) { break; } @@ -1006,22 +974,22 @@ static int first_submatch(regmmatch_T *rp) /// Highest level string search function. /// Search for the 'count'th occurrence of pattern 'pat' in direction 'dirc' /// -/// Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this +/// Careful: If spats[0].off.line == true and spats[0].off.off == 0 this /// makes the movement linewise without moving the match position. /// /// @param dirc if 0: use previous dir. /// @param pat NULL or empty : use previous string. -/// @param options if TRUE and -/// SEARCH_REV == TRUE : go in reverse of previous dir. -/// SEARCH_ECHO == TRUE : echo the search command and handle options -/// SEARCH_MSG == TRUE : may give error message -/// SEARCH_OPT == TRUE : interpret optional flags -/// SEARCH_HIS == TRUE : put search pattern in history -/// SEARCH_NOOF == TRUE : don't add offset to position -/// SEARCH_MARK == TRUE : set previous context mark -/// SEARCH_KEEP == TRUE : keep previous search pattern -/// SEARCH_START == TRUE : accept match at curpos itself -/// SEARCH_PEEK == TRUE : check for typed char, cancel search +/// @param options if true and +/// SEARCH_REV == true : go in reverse of previous dir. +/// SEARCH_ECHO == true : echo the search command and handle options +/// SEARCH_MSG == true : may give error message +/// SEARCH_OPT == true : interpret optional flags +/// SEARCH_HIS == true : put search pattern in history +/// SEARCH_NOOF == true : don't add offset to position +/// SEARCH_MARK == true : set previous context mark +/// SEARCH_KEEP == true : keep previous search pattern +/// SEARCH_START == true : accept match at curpos itself +/// SEARCH_PEEK == true : check for typed char, cancel search /// @param oap can be NULL /// @param dirc '/' or '?' /// @param search_delim delimiter for search, e.g. '%' in s%regex%replacement @@ -1044,25 +1012,19 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, size_t len; bool has_offset = false; - /* - * A line offset is not remembered, this is vi compatible. - */ + // A line offset is not remembered, this is vi compatible. if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL) { spats[0].off.line = false; spats[0].off.off = 0; } - /* - * Save the values for when (options & SEARCH_KEEP) is used. - * (there is no "if ()" around this because gcc wants them initialized) - */ + // Save the values for when (options & SEARCH_KEEP) is used. + // (there is no "if ()" around this because gcc wants them initialized) old_off = spats[0].off; pos = curwin->w_cursor; // start searching at the cursor position - /* - * Find out the direction of the search. - */ + // Find out the direction of the search. if (dirc == 0) { dirc = (char_u)spats[0].off.dir; } else { @@ -1089,17 +1051,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, } } - /* - * Turn 'hlsearch' highlighting back on. - */ + // Turn 'hlsearch' highlighting back on. if (no_hlsearch && !(options & SEARCH_KEEP)) { - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); set_no_hlsearch(false); } - /* - * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar". - */ + // Repeat the search when pattern followed by ';', e.g. "/foo/;?bar". for (;;) { bool show_top_bot_msg = false; @@ -1121,15 +1079,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, } if (pat != NULL && *pat != NUL) { // look for (new) offset - /* - * Find end of regular expression. - * If there is a matching '/' or '?', toss it. - */ + // Find end of regular expression. + // If there is a matching '/' or '?', toss it. ps = (char_u *)strcopy; - p = skip_regexp(pat, search_delim, p_magic, &strcopy); + p = (char_u *)skip_regexp((char *)pat, search_delim, p_magic, &strcopy); if (strcopy != (char *)ps) { // made a copy of "pat" to change "\?" to "?" - searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy)); + searchcmdlen += (int)(STRLEN(pat) - strlen(strcopy)); pat = (char_u *)strcopy; searchstr = (char_u *)strcopy; } @@ -1137,8 +1093,8 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, dircp = p; // remember where we put the NUL *p++ = NUL; } - spats[0].off.line = FALSE; - spats[0].off.end = FALSE; + spats[0].off.line = false; + spats[0].off.end = false; spats[0].off.off = 0; // Check for a line offset or a character offset. // For get_address (echo off) we don't check for a character @@ -1252,7 +1208,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, memmove(msgbuf + STRLEN(p) + 1, off_buf, off_len); } - trunc = msg_strtrunc(msgbuf, true); + trunc = (char_u *)msg_strtrunc((char *)msgbuf, true); if (trunc != NULL) { xfree(msgbuf); msgbuf = trunc; @@ -1263,7 +1219,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, // it would be blanked out again very soon. Show it on the // left, but do reverse the text. if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { - char_u *r = reverse_text(trunc != NULL ? trunc : msgbuf); + char_u *r = (char_u *)reverse_text(trunc != NULL ? (char *)trunc : (char *)msgbuf); xfree(msgbuf); msgbuf = r; // move reversed text to beginning of buffer @@ -1289,16 +1245,14 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, } } - /* - * If there is a character offset, subtract it from the current - * position, so we don't get stuck at "?pat?e+2" or "/pat/s-2". - * Skip this if pos.col is near MAXCOL (closed fold). - * This is not done for a line offset, because then we would not be vi - * compatible. - */ + // If there is a character offset, subtract it from the current + // position, so we don't get stuck at "?pat?e+2" or "/pat/s-2". + // Skip this if pos.col is near MAXCOL (closed fold). + // This is not done for a line offset, because then we would not be vi + // compatible. if (!spats[0].off.line && spats[0].off.off && pos.col < MAXCOL - 2) { if (spats[0].off.off > 0) { - for (c = spats[0].off.off; c; --c) { + for (c = spats[0].off.off; c; c--) { if (decl(&pos) == -1) { break; } @@ -1308,7 +1262,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, pos.col = MAXCOL; } } else { - for (c = spats[0].off.off; c; ++c) { + for (c = spats[0].off.off; c; c++) { if (incl(&pos) == -1) { break; } @@ -1352,9 +1306,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, apply_autocmds(EVENT_SEARCHWRAPPED, NULL, NULL, false, NULL); } - /* - * Add character and/or line offset - */ + // Add character and/or line offset if (!(options & SEARCH_NOOF) || (pat != NULL && *pat == ';')) { pos_T org_pos = pos; @@ -1435,7 +1387,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, setpcmark(); } curwin->w_cursor = pos; - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; end_do_search: if ((options & SEARCH_KEEP) || (cmdmod.cmod_flags & CMOD_KEEPPATTERNS)) { @@ -1446,15 +1398,13 @@ end_do_search: return retval; } -/* - * search_for_exact_line(buf, pos, dir, pat) - * - * Search for a line starting with the given pattern (ignoring leading - * white-space), starting from pos and going in direction "dir". "pos" will - * contain the position of the match found. Blank lines match only if - * ADDING is set. If p_ic is set then the pattern must be in lowercase. - * Return OK for success, or FAIL if no line found. - */ +// search_for_exact_line(buf, pos, dir, pat) +// +// Search for a line starting with the given pattern (ignoring leading +// white-space), starting from pos and going in direction "dir". "pos" will +// contain the position of the match found. Blank lines match only if +// ADDING is set. If p_ic is set then the pattern must be in lowercase. +// Return OK for success, or FAIL if no line found. int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) { linenr_T start = 0; @@ -1493,22 +1443,21 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) if (start == 0) { start = pos->lnum; } - ptr = ml_get_buf(buf, pos->lnum, false); + ptr = (char_u *)ml_get_buf(buf, pos->lnum, false); p = (char_u *)skipwhite((char *)ptr); pos->col = (colnr_T)(p - ptr); // when adding lines the matching line may be empty but it is not // ignored because we are interested in the next line -- Acevedo - if ((compl_cont_status & CONT_ADDING) - && !(compl_cont_status & CONT_SOL)) { + if (compl_status_adding() && !compl_status_sol()) { if (mb_strcmp_ic((bool)p_ic, (const char *)p, (const char *)pat) == 0) { return OK; } } else if (*p != NUL) { // Ignore empty lines. // Expanding lines or words. - assert(compl_length >= 0); - if ((p_ic ? mb_strnicmp(p, pat, (size_t)compl_length) - : STRNCMP(p, pat, compl_length)) == 0) { + assert(ins_compl_len() >= 0); + if ((p_ic ? mb_strnicmp((char *)p, (char *)pat, (size_t)ins_compl_len()) + : STRNCMP(p, pat, ins_compl_len())) == 0) { return OK; } } @@ -1516,16 +1465,12 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) return FAIL; } -/* - * Character Searches - */ +// Character Searches -/* - * Search for a character in a line. If "t_cmd" is FALSE, move to the - * position of the character, otherwise move to just before the char. - * Do this "cap->count1" times. - * Return FAIL or OK. - */ +/// Search for a character in a line. If "t_cmd" is false, move to the +/// position of the character, otherwise move to just before the char. +/// Do this "cap->count1" times. +/// Return FAIL or OK. int searchc(cmdarg_T *cap, int t_cmd) FUNC_ATTR_NONNULL_ALL { @@ -1579,7 +1524,7 @@ int searchc(cmdarg_T *cap, int t_cmd) cap->oap->inclusive = true; } - p = get_cursor_line_ptr(); + p = (char_u *)get_cursor_line_ptr(); col = curwin->w_cursor.col; len = (int)STRLEN(p); @@ -1594,7 +1539,7 @@ int searchc(cmdarg_T *cap, int t_cmd) if (col == 0) { return FAIL; } - col -= utf_head_off(p, p + col - 1) + 1; + col -= utf_head_off((char *)p, (char *)p + col - 1) + 1; } if (lastc_bytelen == 1) { if (p[col] == c && stop) { @@ -1615,7 +1560,7 @@ int searchc(cmdarg_T *cap, int t_cmd) col += lastc_bytelen - 1; } else { // To previous char, which may be multi-byte. - col -= utf_head_off(p, p + col); + col -= utf_head_off((char *)p, (char *)p + col); } } curwin->w_cursor.col = col; @@ -1623,15 +1568,11 @@ int searchc(cmdarg_T *cap, int t_cmd) return OK; } -/* - * "Other" Searches - */ +// "Other" Searches -/* - * findmatch - find the matching paren or brace - * - * Improvement over vi: Braces inside quotes are ignored. - */ +// findmatch - find the matching paren or brace +// +// Improvement over vi: Braces inside quotes are ignored. pos_T *findmatch(oparg_T *oap, int initc) { return findmatchlimit(oap, initc, 0, 0); @@ -1646,7 +1587,7 @@ static bool check_prevcol(char_u *linep, int col, int ch, int *prevcol) { col--; if (col > 0) { - col -= utf_head_off(linep, linep + col); + col -= utf_head_off((char *)linep, (char *)linep + col); } if (prevcol) { *prevcol = col; @@ -1654,22 +1595,21 @@ static bool check_prevcol(char_u *linep, int col, int ch, int *prevcol) return col >= 0 && linep[col] == ch; } -/* - * Raw string start is found at linep[startpos.col - 1]. - * Return true if the matching end can be found between startpos and endpos. - */ -static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) +/// Raw string start is found at linep[startpos.col - 1]. +/// +/// @return true if the matching end can be found between startpos and endpos. +static bool find_rawstring_end(char *linep, pos_T *startpos, pos_T *endpos) { - char_u *p; + char *p; linenr_T lnum; for (p = linep + startpos->col + 1; *p && *p != '('; p++) {} size_t delim_len = (size_t)((p - linep) - startpos->col - 1); - char_u *delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len); + char *delim_copy = xstrnsave(linep + startpos->col + 1, delim_len); bool found = false; for (lnum = startpos->lnum; lnum <= endpos->lnum; lnum++) { - char_u *line = ml_get(lnum); + char *line = ml_get(lnum); for (p = line + (lnum == startpos->lnum ? startpos->col + 1 : 0); *p; p++) { if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) { @@ -1697,61 +1637,58 @@ static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) static void find_mps_values(int *initc, int *findc, bool *backwards, bool switchit) FUNC_ATTR_NONNULL_ALL { - char_u *ptr = curbuf->b_p_mps; + char *ptr = curbuf->b_p_mps; while (*ptr != NUL) { - if (utf_ptr2char((char *)ptr) == *initc) { + if (utf_ptr2char(ptr) == *initc) { if (switchit) { *findc = *initc; - *initc = utf_ptr2char((char *)ptr + utfc_ptr2len((char *)ptr) + 1); + *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); *backwards = true; } else { - *findc = utf_ptr2char((char *)ptr + utfc_ptr2len((char *)ptr) + 1); + *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); *backwards = false; } return; } - char_u *prev = ptr; - ptr += utfc_ptr2len((char *)ptr) + 1; - if (utf_ptr2char((char *)ptr) == *initc) { + char *prev = ptr; + ptr += utfc_ptr2len(ptr) + 1; + if (utf_ptr2char(ptr) == *initc) { if (switchit) { *findc = *initc; - *initc = utf_ptr2char((char *)prev); + *initc = utf_ptr2char(prev); *backwards = false; } else { - *findc = utf_ptr2char((char *)prev); + *findc = utf_ptr2char(prev); *backwards = true; } return; } - ptr += utfc_ptr2len((char *)ptr); + ptr += utfc_ptr2len(ptr); if (*ptr == ',') { ptr++; } } } -/* - * findmatchlimit -- find the matching paren or brace, if it exists within - * maxtravel lines of the cursor. A maxtravel of 0 means search until falling - * off the edge of the file. - * - * "initc" is the character to find a match for. NUL means to find the - * character at or after the cursor. Special values: - * '*' look for C-style comment / * - * '/' look for C-style comment / *, ignoring comment-end - * '#' look for preprocessor directives - * 'R' look for raw string start: R"delim(text)delim" (only backwards) - * - * flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#') - * FM_FORWARD search forwards (when initc is '/', '*' or '#') - * FM_BLOCKSTOP stop at start/end of block ({ or } in column 0) - * FM_SKIPCOMM skip comments (not implemented yet!) - * - * "oap" is only used to set oap->motion_type for a linewise motion, it can be - * NULL - */ - +// findmatchlimit -- find the matching paren or brace, if it exists within +// maxtravel lines of the cursor. A maxtravel of 0 means search until falling +// off the edge of the file. +// +// "initc" is the character to find a match for. NUL means to find the +// character at or after the cursor. Special values: +// '*' look for C-style comment / * +// '/' look for C-style comment / *, ignoring comment-end +// '#' look for preprocessor directives +// 'R' look for raw string start: R"delim(text)delim" (only backwards) +// +// flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#') +// FM_FORWARD search forwards (when initc is '/', '*' or '#') +// FM_BLOCKSTOP stop at start/end of block ({ or } in column 0) +// FM_SKIPCOMM skip comments (not implemented yet!) +// +// "oap" is only used to set oap->motion_type for a linewise motion, it can be +// NULL pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) { static pos_T pos; // current search position @@ -1773,7 +1710,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) pos = curwin->w_cursor; pos.coladd = 0; - char_u *linep = ml_get(pos.lnum); // pointer to current line + char_u *linep = (char_u *)ml_get(pos.lnum); // pointer to current line // vi compatible matching bool cpo_match = (vim_strchr(p_cpo, CPO_MATCH) != NULL); @@ -1789,12 +1726,10 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) dir = 0; } - /* - * if initc given, look in the table for the matching character - * '/' and '*' are special cases: look for start or end of comment. - * When '/' is used, we ignore running backwards into a star-slash, for - * "[*" command, we just want to find any comment. - */ + // if initc given, look in the table for the matching character + // '/' and '*' are special cases: look for start or end of comment. + // When '/' is used, we ignore running backwards into a star-slash, for + // "[*" command, we just want to find any comment. if (initc == '/' || initc == '*' || initc == 'R') { comment_dir = dir; if (initc == '/') { @@ -1812,18 +1747,14 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) return NULL; } } else { - /* - * Either initc is '#', or no initc was given and we need to look - * under the cursor. - */ + // Either initc is '#', or no initc was given and we need to look + // under the cursor. if (initc == '#') { hash_dir = dir; } else { - /* - * initc was not given, must look for something to match under - * or near the cursor. - * Only check for special things when 'cpo' doesn't have '%'. - */ + // initc was not given, must look for something to match under + // or near the cursor. + // Only check for special things when 'cpo' doesn't have '%'. if (!cpo_match) { // Are we before or at #if, #else etc.? ptr = (char_u *)skipwhite((char *)linep); @@ -1857,18 +1788,14 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } } - /* - * If we are not on a comment or the # at the start of a line, then - * look for brace anywhere on this line after the cursor. - */ + // If we are not on a comment or the # at the start of a line, then + // look for brace anywhere on this line after the cursor. if (!hash_dir && !comment_dir) { - /* - * Find the brace under or after the cursor. - * If beyond the end of the line, use the last character in - * the line. - */ + // Find the brace under or after the cursor. + // If beyond the end of the line, use the last character in + // the line. if (linep[pos.col] == NUL && pos.col) { - --pos.col; + pos.col--; } for (;;) { initc = utf_ptr2char((char *)linep + pos.col); @@ -1902,9 +1829,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } } if (hash_dir) { - /* - * Look for matching #if, #else, #elif, or #endif - */ + // Look for matching #if, #else, #elif, or #endif if (oap != NULL) { oap->motion_type = kMTLineWise; // Linewise for this case only } @@ -1928,7 +1853,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) break; } pos.lnum += hash_dir; - linep = ml_get(pos.lnum); + linep = (char_u *)ml_get(pos.lnum); line_breakcheck(); // check for CTRL-C typed ptr = (char_u *)skipwhite((char *)linep); if (*ptr != '#') { @@ -1982,17 +1907,15 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) // backward search: Check if this line contains a single-line comment if ((backwards && comment_dir) || lisp) { - comment_col = check_linecomment(linep); + comment_col = check_linecomment((char *)linep); } if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col) { lispcomm = true; // find match inside this comment } while (!got_int) { - /* - * Go to the next position, forward or backward. We could use - * inc() and dec() here, but that is much slower - */ + // Go to the next position, forward or backward. We could use + // inc() and dec() here, but that is much slower if (backwards) { // char to match is inside of comment, don't search outside if (lispcomm && pos.col < (colnr_T)comment_col) { @@ -2002,20 +1925,20 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) if (pos.lnum == 1) { // start of file break; } - --pos.lnum; + pos.lnum--; if (maxtravel > 0 && ++traveled > maxtravel) { break; } - linep = ml_get(pos.lnum); + linep = (char_u *)ml_get(pos.lnum); pos.col = (colnr_T)STRLEN(linep); // pos.col on trailing NUL do_quotes = -1; line_breakcheck(); // Check if this line contains a single-line comment if (comment_dir || lisp) { - comment_col = check_linecomment(linep); + comment_col = check_linecomment((char *)linep); } // skip comment if (lisp && comment_col != MAXCOL) { @@ -2023,7 +1946,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } } else { pos.col--; - pos.col -= utf_head_off(linep, linep + pos.col); + pos.col -= utf_head_off((char *)linep, (char *)linep + pos.col); } } else { // forward search if (linep[pos.col] == NUL @@ -2037,18 +1960,18 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) || lispcomm) { break; } - ++pos.lnum; + pos.lnum++; if (maxtravel && traveled++ > maxtravel) { break; } - linep = ml_get(pos.lnum); + linep = (char_u *)ml_get(pos.lnum); pos.col = 0; do_quotes = -1; line_breakcheck(); if (lisp) { // find comment pos in new line - comment_col = check_linecomment(linep); + comment_col = check_linecomment((char *)linep); } } else { pos.col += utfc_ptr2len((char *)linep + pos.col); @@ -2073,10 +1996,8 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) return &pos; } } else { // Searching backwards - /* - * A comment may contain / * or / /, it may also start or end - * with / * /. Ignore a / * after / / and after *. - */ + // A comment may contain / * or / /, it may also start or end + // with / * /. Ignore a / * after / / and after *. if (pos.col == 0) { continue; } else if (raw_string) { @@ -2087,13 +2008,13 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) // delimiter we can check if it ends before where we // started searching, or before the previously found // raw string start. - if (!find_rawstring_end(linep, &pos, + if (!find_rawstring_end((char *)linep, &pos, count > 0 ? &match_pos : &curwin->w_cursor)) { count++; match_pos = pos; match_pos.col--; } - linep = ml_get(pos.lnum); // may have been released + linep = (char_u *)ml_get(pos.lnum); // may have been released } } else if (linep[pos.col - 1] == '/' && linep[pos.col] == '*' @@ -2119,20 +2040,16 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) continue; } - /* - * If smart matching ('cpoptions' does not contain '%'), braces inside - * of quotes are ignored, but only if there is an even number of - * quotes in the line. - */ + // If smart matching ('cpoptions' does not contain '%'), braces inside + // of quotes are ignored, but only if there is an even number of + // quotes in the line. if (cpo_match) { do_quotes = 0; } else if (do_quotes == -1) { - /* - * Count the number of quotes in the line, skipping \" and '"'. - * Watch out for "\\". - */ + // Count the number of quotes in the line, skipping \" and '"'. + // Watch out for "\\". at_start = do_quotes; - for (ptr = linep; *ptr; ++ptr) { + for (ptr = linep; *ptr; ptr++) { if (ptr == linep + pos.col + backwards) { at_start = (do_quotes & 1); } @@ -2146,10 +2063,8 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } do_quotes &= 1; // result is 1 with even number of quotes - /* - * If we find an uneven count, check current line and previous - * one for a '\' at the end. - */ + // If we find an uneven count, check current line and previous + // one for a '\' at the end. if (!do_quotes) { inquote = false; if (ptr[-1] == '\\') { @@ -2163,7 +2078,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } } if (pos.lnum > 1) { - ptr = ml_get(pos.lnum - 1); + ptr = (char_u *)ml_get(pos.lnum - 1); if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\') { do_quotes = 1; if (start_in_quotes == kNone) { @@ -2177,7 +2092,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } // ml_get() only keeps one line, need to get linep again - linep = ml_get(pos.lnum); + linep = (char_u *)ml_get(pos.lnum); } } } @@ -2185,17 +2100,15 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) start_in_quotes = kFalse; } - /* - * If 'smartmatch' is set: - * Things inside quotes are ignored by setting 'inquote'. If we - * find a quote without a preceding '\' invert 'inquote'. At the - * end of a line not ending in '\' we reset 'inquote'. - * - * In lines with an uneven number of quotes (without preceding '\') - * we do not know which part to ignore. Therefore we only set - * inquote if the number of quotes in a line is even, unless this - * line or the previous one ends in a '\'. Complicated, isn't it? - */ + // If 'smartmatch' is set: + // Things inside quotes are ignored by setting 'inquote'. If we + // find a quote without a preceding '\' invert 'inquote'. At the + // end of a line not ending in '\' we reset 'inquote'. + // + // In lines with an uneven number of quotes (without preceding '\') + // we do not know which part to ignore. Therefore we only set + // inquote if the number of quotes in a line is even, unless this + // line or the previous one ends in a '\'. Complicated, isn't it? const int c = utf_ptr2char((char *)linep + pos.col); switch (c) { case NUL: @@ -2212,7 +2125,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) if (do_quotes) { int col; - for (col = pos.col - 1; col >= 0; --col) { + for (col = pos.col - 1; col >= 0; col--) { if (linep[col] != '\\') { break; } @@ -2224,13 +2137,11 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } break; - /* - * If smart matching ('cpoptions' does not contain '%'): - * Skip things in single quotes: 'x' or '\x'. Be careful for single - * single quotes, eg jon's. Things like '\233' or '\x3f' are not - * skipped, there is never a brace in them. - * Ignore this when finding matches for `'. - */ + // If smart matching ('cpoptions' does not contain '%'): + // Skip things in single quotes: 'x' or '\x'. Be careful for single + // single quotes, eg jon's. Things like '\233' or '\x3f' are not + // skipped, there is never a brace in them. + // Ignore this when finding matches for `'. case '\'': if (!cpo_match && initc != '\'' && findc != '\'') { if (backwards) { @@ -2258,10 +2169,8 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) FALLTHROUGH; default: - /* - * For Lisp skip over backslashed (), {} and []. - * (actually, we skip #\( et al) - */ + // For Lisp skip over backslashed (), {} and []. + // (actually, we skip #\( et al) if (curbuf->b_p_lisp && vim_strchr("(){}[]", c) != NULL && pos.col > 1 @@ -2306,15 +2215,15 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) /// Check if line[] contains a / / comment. /// @returns MAXCOL if not, otherwise return the column. -int check_linecomment(const char_u *line) +int check_linecomment(const char *line) { - const char_u *p = line; // scan from start + const char *p = line; // scan from start // skip Lispish one-line comments if (curbuf->b_p_lisp) { if (vim_strchr((char *)p, ';') != NULL) { // there may be comments bool in_str = false; // inside of string - while ((p = (char_u *)strpbrk((char *)p, "\";")) != NULL) { + while ((p = strpbrk((char *)p, "\";")) != NULL) { if (*p == '"') { if (in_str) { if (*(p - 1) != '\\') { // skip escaped quote @@ -2327,7 +2236,7 @@ int check_linecomment(const char_u *line) } } else if (!in_str && ((p - line) < 2 || (*(p - 1) != '\\' && *(p - 2) != '#')) - && !is_pos_in_string(line, (colnr_T)(p - line))) { + && !is_pos_in_string((char_u *)line, (colnr_T)(p - line))) { break; // found! } p++; @@ -2336,12 +2245,12 @@ int check_linecomment(const char_u *line) p = NULL; } } else { - while ((p = (char_u *)vim_strchr((char *)p, '/')) != NULL) { + while ((p = vim_strchr((char *)p, '/')) != NULL) { // Accept a double /, unless it's preceded with * and followed by *, // because * / / * is an end and start of a C comment. Only // accept the position if it is not inside a string. if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*') - && !is_pos_in_string(line, (colnr_T)(p - line))) { + && !is_pos_in_string((char_u *)line, (colnr_T)(p - line))) { break; } p++; @@ -2373,11 +2282,9 @@ void showmatch(int c) colnr_T save_dollar_vcol; char_u *p; - /* - * Only show match for chars in the 'matchpairs' option. - */ + // Only show match for chars in the 'matchpairs' option. // 'matchpairs' is "x:y,x:y" - for (p = curbuf->b_p_mps; *p != NUL; p++) { + for (p = (char_u *)curbuf->b_p_mps; *p != NUL; p++) { if (utf_ptr2char((char *)p) == c && (curwin->w_p_rl ^ p_ri)) { break; } @@ -2414,7 +2321,7 @@ void showmatch(int c) dollar_vcol = -1; } curwin->w_virtcol++; // do display ')' just before "$" - update_screen(VALID); // show the new char first + update_screen(); // show the new char first save_dollar_vcol = dollar_vcol; save_state = State; @@ -2431,10 +2338,8 @@ void showmatch(int c) // and has a higher column number. dollar_vcol = save_dollar_vcol; - /* - * brief pause, unless 'm' is present in 'cpo' and a character is - * available. - */ + // brief pause, unless 'm' is present in 'cpo' and a character is + // available. if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL) { os_delay((uint64_t)p_mat * 100L + 8, true); } else if (!char_avail()) { @@ -2449,1814 +2354,6 @@ void showmatch(int c) } } -// Find the start of the next sentence, searching in the direction specified -// by the "dir" argument. The cursor is positioned on the start of the next -// sentence when found. If the next sentence is found, return OK. Return FAIL -// otherwise. See ":h sentence" for the precise definition of a "sentence" -// text object. -int findsent(Direction dir, long count) -{ - pos_T pos, tpos; - int c; - int (*func)(pos_T *); - bool noskip = false; // do not skip blanks - - pos = curwin->w_cursor; - if (dir == FORWARD) { - func = incl; - } else { - func = decl; - } - - while (count--) { - const pos_T prev_pos = pos; - - // if on an empty line, skip up to a non-empty line - if (gchar_pos(&pos) == NUL) { - do { - if ((*func)(&pos) == -1) { - break; - } - } while (gchar_pos(&pos) == NUL); - if (dir == FORWARD) { - goto found; - } - // if on the start of a paragraph or a section and searching forward, - // go to the next line - } else if (dir == FORWARD && pos.col == 0 - && startPS(pos.lnum, NUL, false)) { - if (pos.lnum == curbuf->b_ml.ml_line_count) { - return FAIL; - } - pos.lnum++; - goto found; - } else if (dir == BACKWARD) { - decl(&pos); - } - - // go back to the previous non-white non-punctuation character - bool found_dot = false; - while (c = gchar_pos(&pos), ascii_iswhite(c) - || vim_strchr(".!?)]\"'", c) != NULL) { - tpos = pos; - if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD)) { - break; - } - if (found_dot) { - break; - } - if (vim_strchr(".!?", c) != NULL) { - found_dot = true; - } - if (vim_strchr(")]\"'", c) != NULL - && vim_strchr(".!?)]\"'", gchar_pos(&tpos)) == NULL) { - break; - } - decl(&pos); - } - - // remember the line where the search started - const int startlnum = pos.lnum; - const bool cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; - - for (;;) { // find end of sentence - c = gchar_pos(&pos); - if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) { - if (dir == BACKWARD && pos.lnum != startlnum) { - ++pos.lnum; - } - break; - } - if (c == '.' || c == '!' || c == '?') { - tpos = pos; - do { - if ((c = inc(&tpos)) == -1) { - break; - } - } while (vim_strchr(")]\"'", c = gchar_pos(&tpos)) - != NULL); - if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL - || (cpo_J && (c == ' ' && inc(&tpos) >= 0 - && gchar_pos(&tpos) == ' '))) { - pos = tpos; - if (gchar_pos(&pos) == NUL) { // skip NUL at EOL - inc(&pos); - } - break; - } - } - if ((*func)(&pos) == -1) { - if (count) { - return FAIL; - } - noskip = true; - break; - } - } -found: - // skip white space - while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) { - if (incl(&pos) == -1) { - break; - } - } - - if (equalpos(prev_pos, pos)) { - // didn't actually move, advance one character and try again - if ((*func)(&pos) == -1) { - if (count) { - return FAIL; - } - break; - } - count++; - } - } - - setpcmark(); - curwin->w_cursor = pos; - return OK; -} - -/// Find the next paragraph or section in direction 'dir'. -/// Paragraphs are currently supposed to be separated by empty lines. -/// If 'what' is NUL we go to the next paragraph. -/// If 'what' is '{' or '}' we go to the next section. -/// If 'both' is TRUE also stop at '}'. -/// -/// @param pincl Return: true if last char is to be included -/// -/// @return TRUE if the next paragraph or section was found. -bool findpar(bool *pincl, int dir, long count, int what, int both) -{ - linenr_T curr; - bool did_skip; // true after separating lines have been skipped - bool first; // true on first line - linenr_T fold_first; // first line of a closed fold - linenr_T fold_last; // last line of a closed fold - bool fold_skipped; // true if a closed fold was skipped this - // iteration - - curr = curwin->w_cursor.lnum; - - while (count--) { - did_skip = false; - for (first = true;; first = false) { - if (*ml_get(curr) != NUL) { - did_skip = true; - } - - // skip folded lines - fold_skipped = false; - if (first && hasFolding(curr, &fold_first, &fold_last)) { - curr = ((dir > 0) ? fold_last : fold_first) + dir; - fold_skipped = true; - } - - if (!first && did_skip && startPS(curr, what, both)) { - break; - } - - if (fold_skipped) { - curr -= dir; - } - if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) { - if (count) { - return false; - } - curr -= dir; - break; - } - } - } - setpcmark(); - if (both && *ml_get(curr) == '}') { // include line with '}' - curr++; - } - curwin->w_cursor.lnum = curr; - if (curr == curbuf->b_ml.ml_line_count && what != '}') { - char_u *line = ml_get(curr); - - // Put the cursor on the last character in the last line and make the - // motion inclusive. - if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) { - curwin->w_cursor.col--; - curwin->w_cursor.col -= utf_head_off(line, line + curwin->w_cursor.col); - *pincl = true; - } - } else { - curwin->w_cursor.col = 0; - } - return true; -} - -/* - * check if the string 's' is a nroff macro that is in option 'opt' - */ -static int inmacro(char_u *opt, char_u *s) -{ - char_u *macro; - - for (macro = opt; macro[0]; macro++) { - // Accept two characters in the option being equal to two characters - // in the line. A space in the option matches with a space in the - // line or the line having ended. - if ((macro[0] == s[0] - || (macro[0] == ' ' - && (s[0] == NUL || s[0] == ' '))) - && (macro[1] == s[1] - || ((macro[1] == NUL || macro[1] == ' ') - && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) { - break; - } - macro++; - if (macro[0] == NUL) { - break; - } - } - return macro[0] != NUL; -} - -/* - * startPS: return TRUE if line 'lnum' is the start of a section or paragraph. - * If 'para' is '{' or '}' only check for sections. - * If 'both' is TRUE also stop at '}' - */ -int startPS(linenr_T lnum, int para, int both) -{ - char_u *s; - - s = ml_get(lnum); - if (*s == para || *s == '\f' || (both && *s == '}')) { - return true; - } - if (*s == '.' && (inmacro(p_sections, s + 1) - || (!para && inmacro(p_para, s + 1)))) { - return true; - } - return false; -} - -/* - * The following routines do the word searches performed by the 'w', 'W', - * 'b', 'B', 'e', and 'E' commands. - */ - -/* - * To perform these searches, characters are placed into one of three - * classes, and transitions between classes determine word boundaries. - * - * The classes are: - * - * 0 - white space - * 1 - punctuation - * 2 or higher - keyword characters (letters, digits and underscore) - */ - -static int cls_bigword; // TRUE for "W", "B" or "E" - -/* - * cls() - returns the class of character at curwin->w_cursor - * - * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars - * from class 2 and higher are reported as class 1 since only white space - * boundaries are of interest. - */ -static int cls(void) -{ - int c; - - c = gchar_cursor(); - if (c == ' ' || c == '\t' || c == NUL) { - return 0; - } - - c = utf_class(c); - - // If cls_bigword is TRUE, report all non-blanks as class 1. - if (c != 0 && cls_bigword) { - return 1; - } - return c; -} - -/// fwd_word(count, type, eol) - move forward one word -/// -/// @return FAIL if the cursor was already at the end of the file. -/// If eol is TRUE, last word stops at end of line (for operators). -/// -/// @param bigword "W", "E" or "B" -int fwd_word(long count, int bigword, int eol) -{ - int sclass; // starting class - int i; - int last_line; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) { - // When inside a range of folded lines, move to the last char of the - // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); - } - sclass = cls(); - - /* - * We always move at least one character, unless on the last - * character in the buffer. - */ - last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); - i = inc_cursor(); - if (i == -1 || (i >= 1 && last_line)) { // started at last char in file - return FAIL; - } - if (i >= 1 && eol && count == 0) { // started at last char in line - return OK; - } - - /* - * Go one char past end of current word (if any) - */ - if (sclass != 0) { - while (cls() == sclass) { - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) { - return OK; - } - } - } - - /* - * go to next non-white - */ - while (cls() == 0) { - /* - * We'll stop if we land on a blank line - */ - if (curwin->w_cursor.col == 0 && *get_cursor_line_ptr() == NUL) { - break; - } - - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) { - return OK; - } - } - } - return OK; -} - -/* - * bck_word() - move backward 'count' words - * - * If stop is TRUE and we are already on the start of a word, move one less. - * - * Returns FAIL if top of the file was reached. - */ -int bck_word(long count, int bigword, int stop) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) { - /* When inside a range of folded lines, move to the first char of the - * first line. */ - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { - curwin->w_cursor.col = 0; - } - sclass = cls(); - if (dec_cursor() == -1) { // started at start of file - return FAIL; - } - - if (!stop || sclass == cls() || sclass == 0) { - /* - * Skip white space before the word. - * Stop on an empty line. - */ - while (cls() == 0) { - if (curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) { - goto finished; - } - if (dec_cursor() == -1) { // hit start of file, stop here - return OK; - } - } - - /* - * Move backward to start of this word. - */ - if (skip_chars(cls(), BACKWARD)) { - return OK; - } - } - - inc_cursor(); // overshot - forward one -finished: - stop = FALSE; - } - return OK; -} - -/* - * end_word() - move to the end of the word - * - * There is an apparent bug in the 'e' motion of the real vi. At least on the - * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e' - * motion crosses blank lines. When the real vi crosses a blank line in an - * 'e' motion, the cursor is placed on the FIRST character of the next - * non-blank line. The 'E' command, however, works correctly. Since this - * appears to be a bug, I have not duplicated it here. - * - * Returns FAIL if end of the file was reached. - * - * If stop is TRUE and we are already on the end of a word, move one less. - * If empty is TRUE stop on an empty line. - */ -int end_word(long count, int bigword, int stop, int empty) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) { - /* When inside a range of folded lines, move to the last char of the - * last line. */ - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); - } - sclass = cls(); - if (inc_cursor() == -1) { - return FAIL; - } - - /* - * If we're in the middle of a word, we just have to move to the end - * of it. - */ - if (cls() == sclass && sclass != 0) { - /* - * Move forward to end of the current word - */ - if (skip_chars(sclass, FORWARD)) { - return FAIL; - } - } else if (!stop || sclass == 0) { - /* - * We were at the end of a word. Go to the end of the next word. - * First skip white space, if 'empty' is TRUE, stop at empty line. - */ - while (cls() == 0) { - if (empty && curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) { - goto finished; - } - if (inc_cursor() == -1) { // hit end of file, stop here - return FAIL; - } - } - - /* - * Move forward to the end of this word. - */ - if (skip_chars(cls(), FORWARD)) { - return FAIL; - } - } - dec_cursor(); // overshot - one char backward -finished: - stop = FALSE; // we move only one word less - } - return OK; -} - -/// Move back to the end of the word. -/// -/// @param bigword TRUE for "B" -/// @param eol if true, then stop at end of line. -/// -/// @return FAIL if start of the file was reached. -int bckend_word(long count, int bigword, bool eol) -{ - int sclass; // starting class - int i; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) { - sclass = cls(); - if ((i = dec_cursor()) == -1) { - return FAIL; - } - if (eol && i == 1) { - return OK; - } - - /* - * Move backward to before the start of this word. - */ - if (sclass != 0) { - while (cls() == sclass) { - if ((i = dec_cursor()) == -1 || (eol && i == 1)) { - return OK; - } - } - } - - /* - * Move backward to end of the previous word - */ - while (cls() == 0) { - if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum)) { - break; - } - if ((i = dec_cursor()) == -1 || (eol && i == 1)) { - return OK; - } - } - } - return OK; -} - -/// Skip a row of characters of the same class. -/// -/// @return true when end-of-file reached, false otherwise. -static bool skip_chars(int cclass, int dir) -{ - while (cls() == cclass) { - if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) { - return true; - } - } - return false; -} - -/* - * Go back to the start of the word or the start of white space - */ -static void back_in_line(void) -{ - int sclass; // starting class - - sclass = cls(); - for (;;) { - if (curwin->w_cursor.col == 0) { // stop at start of line - break; - } - dec_cursor(); - if (cls() != sclass) { // stop at start of word - inc_cursor(); - break; - } - } -} - -static void find_first_blank(pos_T *posp) -{ - int c; - - while (decl(posp) != -1) { - c = gchar_pos(posp); - if (!ascii_iswhite(c)) { - incl(posp); - break; - } - } -} - -/// Skip count/2 sentences and count/2 separating white spaces. -/// -/// @param at_start_sent cursor is at start of sentence -static void findsent_forward(long count, bool at_start_sent) -{ - while (count--) { - findsent(FORWARD, 1L); - if (at_start_sent) { - find_first_blank(&curwin->w_cursor); - } - if (count == 0 || at_start_sent) { - decl(&curwin->w_cursor); - } - at_start_sent = !at_start_sent; - } -} - -/// Find word under cursor, cursor at end. -/// Used while an operator is pending, and in Visual mode. -/// -/// @param include TRUE: include word and white space -/// @param bigword FALSE == word, TRUE == WORD -int current_word(oparg_T *oap, long count, int include, int bigword) -{ - pos_T start_pos; - pos_T pos; - bool inclusive = true; - int include_white = FALSE; - - cls_bigword = bigword; - clearpos(&start_pos); - - // Correct cursor when 'selection' is exclusive - if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) { - dec_cursor(); - } - - /* - * When Visual mode is not active, or when the VIsual area is only one - * character, select the word and/or white space under the cursor. - */ - if (!VIsual_active || equalpos(curwin->w_cursor, VIsual)) { - /* - * Go to start of current word or white space. - */ - back_in_line(); - start_pos = curwin->w_cursor; - - /* - * If the start is on white space, and white space should be included - * (" word"), or start is not on white space, and white space should - * not be included ("word"), find end of word. - */ - if ((cls() == 0) == include) { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) { - return FAIL; - } - } else { - /* - * If the start is not on white space, and white space should be - * included ("word "), or start is on white space and white - * space should not be included (" "), find start of word. - * If we end up in the first column of the next line (single char - * word) back up to end of the line. - */ - fwd_word(1L, bigword, TRUE); - if (curwin->w_cursor.col == 0) { - decl(&curwin->w_cursor); - } else { - oneleft(); - } - - if (include) { - include_white = TRUE; - } - } - - if (VIsual_active) { - // should do something when inclusive == false ! - VIsual = start_pos; - redraw_curbuf_later(INVERTED); // update the inversion - } else { - oap->start = start_pos; - oap->motion_type = kMTCharWise; - } - count--; - } - - /* - * When count is still > 0, extend with more objects. - */ - while (count > 0) { - inclusive = true; - if (VIsual_active && lt(curwin->w_cursor, VIsual)) { - /* - * In Visual mode, with cursor at start: move cursor back. - */ - if (decl(&curwin->w_cursor) == -1) { - return FAIL; - } - if (include != (cls() != 0)) { - if (bck_word(1L, bigword, TRUE) == FAIL) { - return FAIL; - } - } else { - if (bckend_word(1L, bigword, true) == FAIL) { - return FAIL; - } - (void)incl(&curwin->w_cursor); - } - } else { - /* - * Move cursor forward one word and/or white area. - */ - if (incl(&curwin->w_cursor) == -1) { - return FAIL; - } - if (include != (cls() == 0)) { - if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1) { - return FAIL; - } - /* - * If end is just past a new-line, we don't want to include - * the first character on the line. - * Put cursor on last char of white. - */ - if (oneleft() == FAIL) { - inclusive = false; - } - } else { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) { - return FAIL; - } - } - } - count--; - } - - if (include_white && (cls() != 0 - || (curwin->w_cursor.col == 0 && !inclusive))) { - /* - * If we don't include white space at the end, move the start - * to include some white space there. This makes "daw" work - * better on the last word in a sentence (and "2daw" on last-but-one - * word). Also when "2daw" deletes "word." at the end of the line - * (cursor is at start of next line). - * But don't delete white space at start of line (indent). - */ - pos = curwin->w_cursor; // save cursor position - curwin->w_cursor = start_pos; - if (oneleft() == OK) { - back_in_line(); - if (cls() == 0 && curwin->w_cursor.col > 0) { - if (VIsual_active) { - VIsual = curwin->w_cursor; - } else { - oap->start = curwin->w_cursor; - } - } - } - curwin->w_cursor = pos; // put cursor back at end - } - - if (VIsual_active) { - if (*p_sel == 'e' && inclusive && ltoreq(VIsual, curwin->w_cursor)) { - inc_cursor(); - } - if (VIsual_mode == 'V') { - VIsual_mode = 'v'; - redraw_cmdline = true; // show mode later - } - } else { - oap->inclusive = inclusive; - } - - return OK; -} - -/* - * Find sentence(s) under the cursor, cursor at end. - * When Visual active, extend it by one or more sentences. - */ -int current_sent(oparg_T *oap, long count, int include) -{ - pos_T start_pos; - pos_T pos; - bool start_blank; - int c; - bool at_start_sent; - long ncount; - - start_pos = curwin->w_cursor; - pos = start_pos; - findsent(FORWARD, 1L); // Find start of next sentence. - - /* - * When the Visual area is bigger than one character: Extend it. - */ - if (VIsual_active && !equalpos(start_pos, VIsual)) { -extend: - if (lt(start_pos, VIsual)) { - /* - * Cursor at start of Visual area. - * Find out where we are: - * - in the white space before a sentence - * - in a sentence or just after it - * - at the start of a sentence - */ - at_start_sent = true; - decl(&pos); - while (lt(pos, curwin->w_cursor)) { - c = gchar_pos(&pos); - if (!ascii_iswhite(c)) { - at_start_sent = false; - break; - } - incl(&pos); - } - if (!at_start_sent) { - findsent(BACKWARD, 1L); - if (equalpos(curwin->w_cursor, start_pos)) { - at_start_sent = true; // exactly at start of sentence - } else { - // inside a sentence, go to its end (start of next) - findsent(FORWARD, 1L); - } - } - if (include) { // "as" gets twice as much as "is" - count *= 2; - } - while (count--) { - if (at_start_sent) { - find_first_blank(&curwin->w_cursor); - } - c = gchar_cursor(); - if (!at_start_sent || (!include && !ascii_iswhite(c))) { - findsent(BACKWARD, 1L); - } - at_start_sent = !at_start_sent; - } - } else { - /* - * Cursor at end of Visual area. - * Find out where we are: - * - just before a sentence - * - just before or in the white space before a sentence - * - in a sentence - */ - incl(&pos); - at_start_sent = true; - if (!equalpos(pos, curwin->w_cursor)) { // not just before a sentence - at_start_sent = false; - while (lt(pos, curwin->w_cursor)) { - c = gchar_pos(&pos); - if (!ascii_iswhite(c)) { - at_start_sent = true; - break; - } - incl(&pos); - } - if (at_start_sent) { // in the sentence - findsent(BACKWARD, 1L); - } else { // in/before white before a sentence - curwin->w_cursor = start_pos; - } - } - - if (include) { // "as" gets twice as much as "is" - count *= 2; - } - findsent_forward(count, at_start_sent); - if (*p_sel == 'e') { - ++curwin->w_cursor.col; - } - } - return OK; - } - - /* - * If the cursor started on a blank, check if it is just before the start - * of the next sentence. - */ - while (c = gchar_pos(&pos), ascii_iswhite(c)) { - incl(&pos); - } - if (equalpos(pos, curwin->w_cursor)) { - start_blank = true; - find_first_blank(&start_pos); // go back to first blank - } else { - start_blank = false; - findsent(BACKWARD, 1L); - start_pos = curwin->w_cursor; - } - if (include) { - ncount = count * 2; - } else { - ncount = count; - if (start_blank) { - ncount--; - } - } - if (ncount > 0) { - findsent_forward(ncount, true); - } else { - decl(&curwin->w_cursor); - } - - if (include) { - /* - * If the blank in front of the sentence is included, exclude the - * blanks at the end of the sentence, go back to the first blank. - * If there are no trailing blanks, try to include leading blanks. - */ - if (start_blank) { - find_first_blank(&curwin->w_cursor); - c = gchar_pos(&curwin->w_cursor); - if (ascii_iswhite(c)) { - decl(&curwin->w_cursor); - } - } else if (c = gchar_cursor(), !ascii_iswhite(c)) { - find_first_blank(&start_pos); - } - } - - if (VIsual_active) { - // Avoid getting stuck with "is" on a single space before a sentence. - if (equalpos(start_pos, curwin->w_cursor)) { - goto extend; - } - if (*p_sel == 'e') { - ++curwin->w_cursor.col; - } - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_cmdline = true; // show mode later - redraw_curbuf_later(INVERTED); // update the inversion - } else { - // include a newline after the sentence, if there is one - if (incl(&curwin->w_cursor) == -1) { - oap->inclusive = true; - } else { - oap->inclusive = false; - } - oap->start = start_pos; - oap->motion_type = kMTCharWise; - } - return OK; -} - -/// Find block under the cursor, cursor at end. -/// "what" and "other" are two matching parenthesis/brace/etc. -/// -/// @param include TRUE == include white space -/// @param what '(', '{', etc. -/// @param other ')', '}', etc. -int current_block(oparg_T *oap, long count, int include, int what, int other) -{ - pos_T old_pos; - pos_T *pos = NULL; - pos_T start_pos; - pos_T *end_pos; - pos_T old_start, old_end; - char *save_cpo; - bool sol = false; // '{' at start of line - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - - /* - * If we start on '(', '{', ')', '}', etc., use the whole block inclusive. - */ - if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) { - setpcmark(); - if (what == '{') { // ignore indent - while (inindent(1)) { - if (inc_cursor() != 0) { - break; - } - } - } - if (gchar_cursor() == what) { - // cursor on '(' or '{', move cursor just after it - ++curwin->w_cursor.col; - } - } else if (lt(VIsual, curwin->w_cursor)) { - old_start = VIsual; - curwin->w_cursor = VIsual; // cursor at low end of Visual - } else { - old_end = VIsual; - } - - // Search backwards for unclosed '(', '{', etc.. - // Put this position in start_pos. - // Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the - // user wants. - save_cpo = p_cpo; - p_cpo = vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"; - if ((pos = findmatch(NULL, what)) != NULL) { - while (count-- > 0) { - if ((pos = findmatch(NULL, what)) == NULL) { - break; - } - curwin->w_cursor = *pos; - start_pos = *pos; // the findmatch for end_pos will overwrite *pos - } - } else { - while (count-- > 0) { - if ((pos = findmatchlimit(NULL, what, FM_FORWARD, 0)) == NULL) { - break; - } - curwin->w_cursor = *pos; - start_pos = *pos; // the findmatch for end_pos will overwrite *pos - } - } - p_cpo = save_cpo; - - /* - * Search for matching ')', '}', etc. - * Put this position in curwin->w_cursor. - */ - if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL) { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - - // Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE. - // If the ending '}', ')' or ']' is only preceded by indent, skip that - // indent. But only if the resulting area is not smaller than what we - // started with. - while (!include) { - incl(&start_pos); - sol = (curwin->w_cursor.col == 0); - decl(&curwin->w_cursor); - while (inindent(1)) { - sol = true; - if (decl(&curwin->w_cursor) != 0) { - break; - } - } - - // In Visual mode, when the resulting area is not bigger than what we - // started with, extend it to the next block, and then exclude again. - // Don't try to expand the area if the area is empty. - if (!lt(start_pos, old_start) && !lt(old_end, curwin->w_cursor) - && !equalpos(start_pos, curwin->w_cursor) - && VIsual_active) { - curwin->w_cursor = old_start; - decl(&curwin->w_cursor); - if ((pos = findmatch(NULL, what)) == NULL) { - curwin->w_cursor = old_pos; - return FAIL; - } - start_pos = *pos; - curwin->w_cursor = *pos; - if ((end_pos = findmatch(NULL, other)) == NULL) { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - } else { - break; - } - } - - if (VIsual_active) { - if (*p_sel == 'e') { - inc(&curwin->w_cursor); - } - if (sol && gchar_cursor() != NUL) { - inc(&curwin->w_cursor); // include the line break - } - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } else { - oap->start = start_pos; - oap->motion_type = kMTCharWise; - oap->inclusive = false; - if (sol) { - incl(&curwin->w_cursor); - } else if (ltoreq(start_pos, curwin->w_cursor)) { - // Include the character under the cursor. - oap->inclusive = true; - } else { - // End is before the start (no text in between <>, [], etc.): don't - // operate on any text. - curwin->w_cursor = start_pos; - } - } - - return OK; -} - -/// @param end_tag when true, return true if the cursor is on "</aaa>". -/// -/// @return true if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". -static bool in_html_tag(bool end_tag) -{ - char_u *line = get_cursor_line_ptr(); - char_u *p; - int c; - int lc = NUL; - pos_T pos; - - for (p = line + curwin->w_cursor.col; p > line;) { - if (*p == '<') { // find '<' under/before cursor - break; - } - MB_PTR_BACK(line, p); - if (*p == '>') { // find '>' before cursor - break; - } - } - if (*p != '<') { - return false; - } - - pos.lnum = curwin->w_cursor.lnum; - pos.col = (colnr_T)(p - line); - - MB_PTR_ADV(p); - if (end_tag) { - // check that there is a '/' after the '<' - return *p == '/'; - } - - // check that there is no '/' after the '<' - if (*p == '/') { - return false; - } - - // check that the matching '>' is not preceded by '/' - for (;;) { - if (inc(&pos) < 0) { - return false; - } - c = *ml_get_pos(&pos); - if (c == '>') { - break; - } - lc = c; - } - return lc != '/'; -} - -/// Find tag block under the cursor, cursor at end. -/// -/// @param include true == include white space -int current_tagblock(oparg_T *oap, long count_arg, bool include) -{ - long count = count_arg; - pos_T old_pos; - pos_T start_pos; - pos_T end_pos; - pos_T old_start, old_end; - char_u *p; - char_u *cp; - int len; - bool do_include = include; - bool save_p_ws = p_ws; - int retval = FAIL; - int is_inclusive = true; - - p_ws = false; - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - if (!VIsual_active || *p_sel == 'e') { - decl(&old_end); // old_end is inclusive - } - /* - * If we start on "<aaa>" select that block. - */ - if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) { - setpcmark(); - - // ignore indent - while (inindent(1)) { - if (inc_cursor() != 0) { - break; - } - } - - if (in_html_tag(false)) { - // cursor on start tag, move to its '>' - while (*get_cursor_pos_ptr() != '>') { - if (inc_cursor() < 0) { - break; - } - } - } else if (in_html_tag(true)) { - // cursor on end tag, move to just before it - while (*get_cursor_pos_ptr() != '<') { - if (dec_cursor() < 0) { - break; - } - } - dec_cursor(); - old_end = curwin->w_cursor; - } - } else if (lt(VIsual, curwin->w_cursor)) { - old_start = VIsual; - curwin->w_cursor = VIsual; // cursor at low end of Visual - } else { - old_end = VIsual; - } - -again: - /* - * Search backwards for unclosed "<aaa>". - * Put this position in start_pos. - */ - for (long n = 0; n < count; n++) { - if (do_searchpair("<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", - "", - "</[^>]*>", BACKWARD, NULL, 0, - NULL, (linenr_T)0, 0L) <= 0) { - curwin->w_cursor = old_pos; - goto theend; - } - } - start_pos = curwin->w_cursor; - - /* - * Search for matching "</aaa>". First isolate the "aaa". - */ - inc_cursor(); - p = get_cursor_pos_ptr(); - for (cp = p; - *cp != NUL && *cp != '>' && !ascii_iswhite(*cp); - MB_PTR_ADV(cp)) {} - len = (int)(cp - p); - if (len == 0) { - curwin->w_cursor = old_pos; - goto theend; - } - const size_t spat_len = (size_t)len + 39; - char *const spat = xmalloc(spat_len); - 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 = (int)do_searchpair(spat, "", epat, FORWARD, NULL, 0, NULL, (linenr_T)0, 0L); - - xfree(spat); - xfree(epat); - - if (r < 1 || lt(curwin->w_cursor, old_end)) { - // Can't find other end or it's before the previous end. Could be a - // HTML tag that doesn't have a matching end. Search backwards for - // another starting tag. - count = 1; - curwin->w_cursor = start_pos; - goto again; - } - - if (do_include) { - // Include up to the '>'. - while (*get_cursor_pos_ptr() != '>') { - if (inc_cursor() < 0) { - break; - } - } - } else { - char_u *c = get_cursor_pos_ptr(); - // Exclude the '<' of the end tag. - // If the closing tag is on new line, do not decrement cursor, but make - // operation exclusive, so that the linefeed will be selected - if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0) { - // do not decrement cursor - is_inclusive = false; - } else if (*c == '<') { - dec_cursor(); - } - } - end_pos = curwin->w_cursor; - - if (!do_include) { - // Exclude the start tag. - curwin->w_cursor = start_pos; - while (inc_cursor() >= 0) { - if (*get_cursor_pos_ptr() == '>') { - inc_cursor(); - start_pos = curwin->w_cursor; - break; - } - } - curwin->w_cursor = end_pos; - - // If we are in Visual mode and now have the same text as before set - // "do_include" and try again. - if (VIsual_active - && equalpos(start_pos, old_start) - && equalpos(end_pos, old_end)) { - do_include = true; - curwin->w_cursor = old_start; - count = count_arg; - goto again; - } - } - - if (VIsual_active) { - // If the end is before the start there is no text between tags, select - // the char under the cursor. - if (lt(end_pos, start_pos)) { - curwin->w_cursor = start_pos; - } else if (*p_sel == 'e') { - inc_cursor(); - } - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } else { - oap->start = start_pos; - oap->motion_type = kMTCharWise; - if (lt(end_pos, start_pos)) { - // End is before the start: there is no text between tags; operate - // on an empty area. - curwin->w_cursor = start_pos; - oap->inclusive = false; - } else { - oap->inclusive = is_inclusive; - } - } - retval = OK; - -theend: - p_ws = save_p_ws; - return retval; -} - -/// @param include TRUE == include white space -/// @param type 'p' for paragraph, 'S' for section -int current_par(oparg_T *oap, long count, int include, int type) -{ - linenr_T start_lnum; - linenr_T end_lnum; - int white_in_front; - int dir; - int start_is_white; - int prev_start_is_white; - int retval = OK; - int do_white = FALSE; - int t; - int i; - - if (type == 'S') { // not implemented yet - return FAIL; - } - - start_lnum = curwin->w_cursor.lnum; - - /* - * When visual area is more than one line: extend it. - */ - if (VIsual_active && start_lnum != VIsual.lnum) { -extend: - if (start_lnum < VIsual.lnum) { - dir = BACKWARD; - } else { - dir = FORWARD; - } - for (i = (int)count; --i >= 0;) { - if (start_lnum == - (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) { - retval = FAIL; - break; - } - - prev_start_is_white = -1; - for (t = 0; t < 2; ++t) { - start_lnum += dir; - start_is_white = linewhite(start_lnum); - if (prev_start_is_white == start_is_white) { - start_lnum -= dir; - break; - } - for (;;) { - if (start_lnum == (dir == BACKWARD - ? 1 : curbuf->b_ml.ml_line_count)) { - break; - } - if (start_is_white != linewhite(start_lnum + dir) - || (!start_is_white - && startPS(start_lnum + (dir > 0 - ? 1 : 0), 0, 0))) { - break; - } - start_lnum += dir; - } - if (!include) { - break; - } - if (start_lnum == (dir == BACKWARD - ? 1 : curbuf->b_ml.ml_line_count)) { - break; - } - prev_start_is_white = start_is_white; - } - } - curwin->w_cursor.lnum = start_lnum; - curwin->w_cursor.col = 0; - return retval; - } - - /* - * First move back to the start_lnum of the paragraph or white lines - */ - white_in_front = linewhite(start_lnum); - while (start_lnum > 1) { - if (white_in_front) { // stop at first white line - if (!linewhite(start_lnum - 1)) { - break; - } - } else { // stop at first non-white line of start of paragraph - if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0)) { - break; - } - } - start_lnum--; - } - - /* - * Move past the end of any white lines. - */ - end_lnum = start_lnum; - while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum)) { - end_lnum++; - } - - end_lnum--; - i = (int)count; - if (!include && white_in_front) { - i--; - } - while (i--) { - if (end_lnum == curbuf->b_ml.ml_line_count) { - return FAIL; - } - - if (!include) { - do_white = linewhite(end_lnum + 1); - } - - if (include || !do_white) { - end_lnum++; - // skip to end of paragraph - while (end_lnum < curbuf->b_ml.ml_line_count - && !linewhite(end_lnum + 1) - && !startPS(end_lnum + 1, 0, 0)) { - end_lnum++; - } - } - - if (i == 0 && white_in_front && include) { - break; - } - - /* - * skip to end of white lines after paragraph - */ - if (include || do_white) { - while (end_lnum < curbuf->b_ml.ml_line_count - && linewhite(end_lnum + 1)) { - end_lnum++; - } - } - } - - /* - * If there are no empty lines at the end, try to find some empty lines at - * the start (unless that has been done already). - */ - if (!white_in_front && !linewhite(end_lnum) && include) { - while (start_lnum > 1 && linewhite(start_lnum - 1)) { - start_lnum--; - } - } - - if (VIsual_active) { - // Problem: when doing "Vipipip" nothing happens in a single white - // line, we get stuck there. Trap this here. - if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) { - goto extend; - } - if (VIsual.lnum != start_lnum) { - VIsual.lnum = start_lnum; - VIsual.col = 0; - } - VIsual_mode = 'V'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } else { - oap->start.lnum = start_lnum; - oap->start.col = 0; - oap->motion_type = kMTLineWise; - } - curwin->w_cursor.lnum = end_lnum; - curwin->w_cursor.col = 0; - - return OK; -} - -/// Search quote char from string line[col]. -/// Quote character escaped by one of the characters in "escape" is not counted -/// as a quote. -/// -/// @param escape escape characters, can be NULL -/// -/// @return column number of "quotechar" or -1 when not found. -static int find_next_quote(char_u *line, int col, int quotechar, char_u *escape) -{ - int c; - - for (;;) { - c = line[col]; - if (c == NUL) { - return -1; - } else if (escape != NULL && vim_strchr((char *)escape, c)) { - col++; - if (line[col] == NUL) { - return -1; - } - } else if (c == quotechar) { - break; - } - col += utfc_ptr2len((char *)line + col); - } - return col; -} - -/// Search backwards in "line" from column "col_start" to find "quotechar". -/// Quote character escaped by one of the characters in "escape" is not counted -/// as a quote. -/// -/// @param escape escape characters, can be NULL -/// -/// @return the found column or zero. -static int find_prev_quote(char_u *line, int col_start, int quotechar, char_u *escape) -{ - int n; - - while (col_start > 0) { - col_start--; - col_start -= utf_head_off(line, line + col_start); - n = 0; - if (escape != NULL) { - while (col_start - n > 0 && vim_strchr((char *)escape, - line[col_start - n - 1]) != NULL) { - n++; - } - } - if (n & 1) { - col_start -= n; // uneven number of escape chars, skip it - } else if (line[col_start] == quotechar) { - break; - } - } - return col_start; -} - -/// Find quote under the cursor, cursor at end. -/// -/// @param include true == include quote char -/// @param quotechar Quote character -/// -/// @return true if found, else false. -bool current_quote(oparg_T *oap, long count, bool include, int quotechar) - FUNC_ATTR_NONNULL_ALL -{ - char_u *line = get_cursor_line_ptr(); - int col_end; - int col_start = curwin->w_cursor.col; - bool inclusive = false; - bool vis_empty = true; // Visual selection <= 1 char - bool vis_bef_curs = false; // Visual starts before cursor - bool did_exclusive_adj = false; // adjusted pos for 'selection' - bool inside_quotes = false; // Looks like "i'" done before - bool selected_quote = false; // Has quote inside selection - int i; - bool restore_vis_bef = false; // resotre VIsual on abort - - // When 'selection' is "exclusive" move the cursor to where it would be - // with 'selection' "inclusive", so that the logic is the same for both. - // The cursor then is moved forward after adjusting the area. - if (VIsual_active) { - // this only works within one line - if (VIsual.lnum != curwin->w_cursor.lnum) { - return false; - } - - vis_bef_curs = lt(VIsual, curwin->w_cursor); - vis_empty = equalpos(VIsual, curwin->w_cursor); - if (*p_sel == 'e') { - if (vis_bef_curs) { - dec_cursor(); - did_exclusive_adj = true; - } else if (!vis_empty) { - dec(&VIsual); - did_exclusive_adj = true; - } - vis_empty = equalpos(VIsual, curwin->w_cursor); - if (!vis_bef_curs && !vis_empty) { - // VIsual needs to be start of Visual selection. - pos_T t = curwin->w_cursor; - - curwin->w_cursor = VIsual; - VIsual = t; - vis_bef_curs = true; - restore_vis_bef = true; - } - } - } - - if (!vis_empty) { - // Check if the existing selection exactly spans the text inside - // quotes. - if (vis_bef_curs) { - inside_quotes = VIsual.col > 0 - && line[VIsual.col - 1] == quotechar - && line[curwin->w_cursor.col] != NUL - && line[curwin->w_cursor.col + 1] == quotechar; - i = VIsual.col; - col_end = curwin->w_cursor.col; - } else { - inside_quotes = curwin->w_cursor.col > 0 - && line[curwin->w_cursor.col - 1] == quotechar - && line[VIsual.col] != NUL - && line[VIsual.col + 1] == quotechar; - i = curwin->w_cursor.col; - col_end = VIsual.col; - } - - // Find out if we have a quote in the selection. - while (i <= col_end) { - // check for going over the end of the line, which can happen if - // the line was changed after the Visual area was selected. - if (line[i] == NUL) { - break; - } - if (line[i++] == quotechar) { - selected_quote = true; - break; - } - } - } - - if (!vis_empty && line[col_start] == quotechar) { - // Already selecting something and on a quote character. Find the - // next quoted string. - if (vis_bef_curs) { - // Assume we are on a closing quote: move to after the next - // opening quote. - col_start = find_next_quote(line, col_start + 1, quotechar, NULL); - if (col_start < 0) { - goto abort_search; - } - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) { - // We were on a starting quote perhaps? - col_end = col_start; - col_start = curwin->w_cursor.col; - } - } else { - col_end = find_prev_quote(line, col_start, quotechar, NULL); - if (line[col_end] != quotechar) { - goto abort_search; - } - col_start = find_prev_quote(line, col_end, quotechar, - curbuf->b_p_qe); - if (line[col_start] != quotechar) { - // We were on an ending quote perhaps? - col_start = col_end; - col_end = curwin->w_cursor.col; - } - } - } else if (line[col_start] == quotechar || !vis_empty) { - int first_col = col_start; - - if (!vis_empty) { - if (vis_bef_curs) { - first_col = find_next_quote(line, col_start, quotechar, NULL); - } else { - first_col = find_prev_quote(line, col_start, quotechar, NULL); - } - } - // The cursor is on a quote, we don't know if it's the opening or - // closing quote. Search from the start of the line to find out. - // Also do this when there is a Visual area, a' may leave the cursor - // in between two strings. - col_start = 0; - for (;;) { - // Find open quote character. - col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0 || col_start > first_col) { - goto abort_search; - } - // Find close quote character. - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) { - goto abort_search; - } - // If is cursor between start and end quote character, it is - // target text object. - if (col_start <= first_col && first_col <= col_end) { - break; - } - col_start = col_end + 1; - } - } else { - // Search backward for a starting quote. - col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe); - if (line[col_start] != quotechar) { - // No quote before the cursor, look after the cursor. - col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0) { - goto abort_search; - } - } - - // Find close quote character. - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) { - goto abort_search; - } - } - - // When "include" is true, include spaces after closing quote or before - // the starting quote. - if (include) { - if (ascii_iswhite(line[col_end + 1])) { - while (ascii_iswhite(line[col_end + 1])) { - col_end++; - } - } else { - while (col_start > 0 && ascii_iswhite(line[col_start - 1])) { - col_start--; - } - } - } - - // Set start position. After vi" another i" must include the ". - // For v2i" include the quotes. - if (!include && count < 2 && (vis_empty || !inside_quotes)) { - col_start++; - } - curwin->w_cursor.col = col_start; - if (VIsual_active) { - // Set the start of the Visual area when the Visual area was empty, we - // were just inside quotes or the Visual area didn't start at a quote - // and didn't include a quote. - if (vis_empty - || (vis_bef_curs - && !selected_quote - && (inside_quotes - || (line[VIsual.col] != quotechar - && (VIsual.col == 0 - || line[VIsual.col - 1] != quotechar))))) { - VIsual = curwin->w_cursor; - redraw_curbuf_later(INVERTED); - } - } else { - oap->start = curwin->w_cursor; - oap->motion_type = kMTCharWise; - } - - // Set end position. - curwin->w_cursor.col = col_end; - if ((include || count > 1 - // After vi" another i" must include the ". - || (!vis_empty && inside_quotes) - ) && inc_cursor() == 2) { - inclusive = true; - } - if (VIsual_active) { - if (vis_empty || vis_bef_curs) { - // decrement cursor when 'selection' is not exclusive - if (*p_sel != 'e') { - dec_cursor(); - } - } else { - // Cursor is at start of Visual area. Set the end of the Visual - // area when it was just inside quotes or it didn't end at a - // quote. - if (inside_quotes - || (!selected_quote - && line[VIsual.col] != quotechar - && (line[VIsual.col] == NUL - || line[VIsual.col + 1] != quotechar))) { - dec_cursor(); - VIsual = curwin->w_cursor; - } - curwin->w_cursor.col = col_start; - } - if (VIsual_mode == 'V') { - VIsual_mode = 'v'; - redraw_cmdline = true; // show mode later - } - } else { - // Set inclusive and other oap's flags. - oap->inclusive = inclusive; - } - - return true; - -abort_search: - if (VIsual_active && *p_sel == 'e') { - if (did_exclusive_adj) { - inc_cursor(); - } - if (restore_vis_bef) { - pos_T t = curwin->w_cursor; - - curwin->w_cursor = VIsual; - VIsual = t; - } - } - return false; -} - /// Find next search match under cursor, cursor at end. /// Used while an operator is pending, and in Visual mode. /// @@ -4347,7 +2444,7 @@ int current_search(long count, bool forward) } else { // try again from end of buffer // searching backwards, so set pos to last line and col pos.lnum = curwin->w_buffer->b_ml.ml_line_count; - pos.col = (colnr_T)STRLEN(ml_get(curwin->w_buffer->b_ml.ml_line_count)); + pos.col = (colnr_T)strlen(ml_get(curwin->w_buffer->b_ml.ml_line_count)); } } } @@ -4389,7 +2486,7 @@ int current_search(long count, bool forward) may_start_select('c'); setmouse(); - redraw_curbuf_later(INVERTED); + redraw_curbuf_later(UPD_INVERTED); showmode(); return OK; @@ -4399,7 +2496,7 @@ int current_search(long count, bool forward) /// If move is true, check from the beginning of the buffer, /// else from position "cur". /// "direction" is FORWARD or BACKWARD. -/// Returns TRUE, FALSE or -1 for failure. +/// Returns true, false or -1 for failure. static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction) { regmmatch_T regmatch; @@ -4456,14 +2553,12 @@ static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direct return result; } -/* - * return TRUE if line 'lnum' is empty or has white chars only. - */ +/// return true if line 'lnum' is empty or has white chars only. int linewhite(linenr_T lnum) { char_u *p; - p = (char_u *)skipwhite((char *)ml_get(lnum)); + p = (char_u *)skipwhite(ml_get(lnum)); return *p == NUL; } @@ -4622,7 +2717,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); + lastpat = (char_u *)xstrdup((char *)spats[last_idx].pat); chgtick = (int)buf_get_changedtick(curbuf); lbuf = curbuf; lastpos = p; @@ -4637,7 +2732,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst } // "searchcount()" function -void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { pos_T pos = curwin->w_cursor; char_u *pattern = NULL; @@ -4732,7 +2827,7 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr) goto the_end; } xfree(spats[last_idx].pat); - spats[last_idx].pat = vim_strsave(pattern); + spats[last_idx].pat = (char_u *)xstrdup((char *)pattern); } if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) { goto the_end; // the previous pattern was never defined @@ -4869,7 +2964,7 @@ static int fuzzy_match_compute_score(const char_u *const str, const int strSz, if (currIdx > 0) { // Camel case const char_u *p = str; - int neighbor; + int neighbor = ' '; for (uint32_t sidx = 0; sidx < currIdx; sidx++) { neighbor = utf_ptr2char((char *)p); @@ -5008,7 +3103,7 @@ bool fuzzy_match(char_u *const str, const char_u *const pat_arg, const bool matc *outScore = 0; - char_u *const save_pat = vim_strsave(pat_arg); + char_u *const save_pat = (char_u *)xstrdup((char *)pat_arg); char_u *pat = save_pat; char_u *p = pat; @@ -5287,13 +3382,13 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, } /// "matchfuzzy()" function -void f_matchfuzzy(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matchfuzzy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { do_fuzzymatch(argvars, rettv, false); } /// "matchfuzzypos()" function -void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { do_fuzzymatch(argvars, rettv, true); } @@ -5303,13 +3398,13 @@ void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// mark. static char_u *get_line_and_copy(linenr_T lnum, char_u *buf) { - char_u *line = ml_get(lnum); + char_u *line = (char_u *)ml_get(lnum); STRLCPY(buf, line, LSIZE); return buf; } /// Find identifiers or defines in included files. -/// If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase. +/// If p_ic && compl_status_sol() then ptr must be in lowercase. /// /// @param ptr pointer to search pattern /// @param dir direction of expansion @@ -5351,7 +3446,6 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo int i; char_u *already = NULL; char_u *startp = NULL; - char_u *inc_opt = NULL; win_T *curwin_save = NULL; const int l_g_do_tagpreview = g_do_tagpreview; @@ -5362,9 +3456,9 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo file_line = xmalloc(LSIZE); if (type != CHECK_PATH && type != FIND_DEFINE - // when CONT_SOL is set compare "ptr" with the beginning of the line - // is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo - && !(compl_cont_status & CONT_SOL)) { + // when CONT_SOL is set compare "ptr" with the beginning of the + // line is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo + && !compl_status_sol()) { pat = xmalloc(len + 5); assert(len <= INT_MAX); sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr); @@ -5376,22 +3470,22 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo goto fpip_end; } } - inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc; + char *inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc; if (*inc_opt != NUL) { - incl_regmatch.regprog = vim_regcomp((char *)inc_opt, p_magic ? RE_MAGIC : 0); + incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0); if (incl_regmatch.regprog == NULL) { goto fpip_end; } - incl_regmatch.rm_ic = FALSE; // don't ignore case in incl. pat. + incl_regmatch.rm_ic = false; // don't ignore case in incl. pat. } if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) { def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL - ? (char *)p_def : (char *)curbuf->b_p_def, + ? p_def : curbuf->b_p_def, p_magic ? RE_MAGIC : 0); if (def_regmatch.regprog == NULL) { goto fpip_end; } - def_regmatch.rm_ic = FALSE; // don't ignore case in define pat. + def_regmatch.rm_ic = false; // don't ignore case in define pat. } files = xcalloc((size_t)max_path_depth, sizeof(SearchedFile)); old_files = max_path_depth; @@ -5412,19 +3506,19 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo char_u *p_fname = (curr_fname == (char_u *)curbuf->b_fname) ? (char_u *)curbuf->b_ffname : curr_fname; - if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL) { + if (inc_opt != NULL && strstr(inc_opt, "\\zs") != NULL) { // Use text from '\zs' to '\ze' (or end) of 'include'. - new_fname = find_file_name_in_path(incl_regmatch.startp[0], - (size_t)(incl_regmatch.endp[0] - - incl_regmatch.startp[0]), - FNAME_EXP|FNAME_INCL|FNAME_REL, - 1L, p_fname); + new_fname = (char_u *)find_file_name_in_path(incl_regmatch.startp[0], + (size_t)(incl_regmatch.endp[0] + - incl_regmatch.startp[0]), + FNAME_EXP|FNAME_INCL|FNAME_REL, + 1L, (char *)p_fname); } else { // Use text after match with 'include'. - new_fname = file_name_in_line(incl_regmatch.endp[0], 0, + new_fname = file_name_in_line((char_u *)incl_regmatch.endp[0], 0, FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL); } - already_searched = FALSE; + already_searched = false; if (new_fname != NULL) { // Check whether we have already searched in this file for (i = 0;; i++) { @@ -5441,7 +3535,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo msg_putchar('\n'); // cursor below last one */ if (!got_int) { // don't display if 'q' typed at "--more--" // message - msg_home_replace_hl(new_fname); + msg_home_replace_hl((char *)new_fname); msg_puts(_(" (includes previously listed match)")); prev_fname = NULL; } @@ -5471,7 +3565,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo for (i = 0; i < depth_displayed; i++) { msg_puts(" "); } - msg_home_replace(files[depth_displayed].name); + msg_home_replace((char *)files[depth_displayed].name); msg_puts(" -->\n"); } if (!got_int) { // don't display if 'q' typed @@ -5482,28 +3576,26 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo if (new_fname != NULL) { // using "new_fname" is more reliable, e.g., when // 'includeexpr' is set. - msg_outtrans_attr(new_fname, HL_ATTR(HLF_D)); + msg_outtrans_attr((char *)new_fname, HL_ATTR(HLF_D)); } else { - /* - * Isolate the file name. - * Include the surrounding "" or <> if present. - */ + // Isolate the file name. + // Include the surrounding "" or <> if present. if (inc_opt != NULL - && strstr((char *)inc_opt, "\\zs") != NULL) { + && strstr(inc_opt, "\\zs") != NULL) { // pattern contains \zs, use the match - p = incl_regmatch.startp[0]; + p = (char_u *)incl_regmatch.startp[0]; i = (int)(incl_regmatch.endp[0] - incl_regmatch.startp[0]); } else { // find the file name after the end of the match - for (p = incl_regmatch.endp[0]; + for (p = (char_u *)incl_regmatch.endp[0]; *p && !vim_isfilec(*p); p++) {} for (i = 0; vim_isfilec(p[i]); i++) {} } if (i == 0) { // Nothing found, use the rest of the line. - p = incl_regmatch.endp[0]; + p = (char_u *)incl_regmatch.endp[0]; i = (int)STRLEN(p); } else if (p > line) { // Avoid checking before the start of the line, can @@ -5518,7 +3610,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo } save_char = p[i]; p[i] = NUL; - msg_outtrans_attr(p, HL_ATTR(HLF_D)); + msg_outtrans_attr((char *)p, HL_ATTR(HLF_D)); p[i] = save_char; } @@ -5530,7 +3622,6 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo } } } - ui_flush(); // output each line directly } if (new_fname != NULL) { @@ -5544,7 +3635,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo bigger[i].fp = NULL; bigger[i].name = NULL; bigger[i].lnum = 0; - bigger[i].matched = FALSE; + bigger[i].matched = false; } for (i = old_files; i < max_path_depth; i++) { bigger[i + max_path_depth] = files[i]; @@ -5565,7 +3656,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo } files[depth].name = curr_fname = new_fname; files[depth].lnum = 0; - files[depth].matched = FALSE; + files[depth].matched = false; if (action == ACTION_EXPAND) { msg_hist_off = true; // reset in msg_trunc_attr() vim_snprintf((char *)IObuff, IOSIZE, @@ -5581,9 +3672,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo } } } else { - /* - * Check if the line is a define (type == FIND_DEFINE) - */ + // Check if the line is a define (type == FIND_DEFINE) p = line; search_line: define_matched = false; @@ -5592,24 +3681,21 @@ search_line: // Pattern must be first identifier after 'define', so skip // to that position before checking for match of pattern. Also // don't let it match beyond the end of this identifier. - p = def_regmatch.endp[0]; + p = (char_u *)def_regmatch.endp[0]; while (*p && !vim_iswordc(*p)) { p++; } define_matched = true; } - /* - * Look for a match. Don't do this if we are looking for a - * define and this line didn't match define_prog above. - */ + // Look for a match. Don't do this if we are looking for a + // define and this line didn't match define_prog above. if (def_regmatch.regprog == NULL || define_matched) { - if (define_matched - || (compl_cont_status & CONT_SOL)) { + if (define_matched || compl_status_sol()) { // compare the first "len" chars from "ptr" startp = (char_u *)skipwhite((char *)p); if (p_ic) { - matched = !mb_strnicmp(startp, ptr, len); + matched = !mb_strnicmp((char *)startp, (char *)ptr, len); } else { matched = !STRNCMP(startp, ptr, len); } @@ -5620,7 +3706,7 @@ search_line: } else if (regmatch.regprog != NULL && vim_regexec(®match, (char *)line, (colnr_T)(p - line))) { matched = true; - startp = regmatch.startp[0]; + startp = (char_u *)regmatch.startp[0]; // Check if the line is not a comment line (unless we are // looking for a define). A line starting with "# define" // is not considered to be a comment line. @@ -5631,16 +3717,14 @@ search_line: matched = false; } - /* - * Also check for a "/ *" or "/ /" before the match. - * Skips lines like "int backwards; / * normal index - * * /" when looking for "normal". - * Note: Doesn't skip "/ *" in comments. - */ + // Also check for a "/ *" or "/ /" before the match. + // Skips lines like "int backwards; / * normal index + // * /" when looking for "normal". + // Note: Doesn't skip "/ *" in comments. p = (char_u *)skipwhite((char *)line); if (matched || (p[0] == '/' && p[1] == '*') || p[0] == '*') { - for (p = line; *p && p < startp; ++p) { + for (p = line; *p && p < startp; p++) { if (matched && p[0] == '/' && (p[1] == '*' || p[1] == '/')) { @@ -5671,8 +3755,8 @@ search_line: } found = true; aux = p = startp; - if (compl_cont_status & CONT_ADDING) { - p += compl_length; + if (compl_status_adding()) { + p += ins_compl_len(); if (vim_iswordp(p)) { goto exit_matched; } @@ -5681,7 +3765,7 @@ search_line: p = find_word_end(p); i = (int)(p - aux); - if ((compl_cont_status & CONT_ADDING) && i == compl_length) { + if (compl_status_adding() && i == ins_compl_len()) { // IOSIZE > compl_length, so the STRNCPY works STRNCPY(IObuff, aux, i); @@ -5726,9 +3810,9 @@ search_line: cont_s_ipos = true; } IObuff[i] = NUL; - aux = IObuff; + aux = (char_u *)IObuff; - if (i == compl_length) { + if (i == ins_compl_len()) { goto exit_matched; } } @@ -5754,7 +3838,7 @@ search_line: } if (!got_int) { // don't display if 'q' typed // at "--more--" message - msg_home_replace_hl(curr_fname); + msg_home_replace_hl((char *)curr_fname); } prev_fname = curr_fname; } @@ -5820,14 +3904,14 @@ search_line: } if (action != ACTION_SHOW) { curwin->w_cursor.col = (colnr_T)(startp - line); - curwin->w_set_curswant = TRUE; + curwin->w_set_curswant = true; } if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were validate_cursor(); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } break; @@ -5838,7 +3922,7 @@ exit_matched: // are not at the end of it already if (def_regmatch.regprog == NULL && action == ACTION_EXPAND - && !(compl_cont_status & CONT_SOL) + && !compl_status_sol() && *startp != NUL && *(p = startp + utfc_ptr2len((char *)startp)) != NUL) { goto search_line; @@ -5852,11 +3936,9 @@ exit_matched: break; } - /* - * Read the next line. When reading an included file and encountering - * end-of-file, close the file and continue in the file that included - * it. - */ + // Read the next line. When reading an included file and encountering + // end-of-file, close the file and continue in the file that included + // it. while (depth >= 0 && !already && vim_fgets(line = file_line, LSIZE, files[depth].fp)) { fclose(files[depth].fp); @@ -5963,8 +4045,7 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action, msg_puts_attr((const char *)IObuff, HL_ATTR(HLF_N)); msg_puts(" "); } - msg_prt_line(line, FALSE); - ui_flush(); // show one line at a time + msg_prt_line((char *)line, false); // Definition continues until line that doesn't end with '\' if (got_int || type != FIND_DEFINE || p < line || *p != '\\') { @@ -5980,7 +4061,7 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action, if (++*lnum > curbuf->b_ml.ml_line_count) { break; } - line = ml_get(*lnum); + line = (char_u *)ml_get(*lnum); } msg_putchar('\n'); } diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c index 53c9cb7c81..012f145875 100644 --- a/src/nvim/sha256.c +++ b/src/nvim/sha256.c @@ -17,7 +17,7 @@ #include <stdio.h> // for snprintf(). #include "nvim/sha256.h" // for context_sha256_T -#include "nvim/vim.h" // for STRCPY()/STRLEN(). +#include "nvim/vim.h" // for STRCPY()/strlen(). #ifdef INCLUDE_GENERATED_DECLARATIONS # include "sha256.c.generated.h" diff --git a/src/nvim/shada.c b/src/nvim/shada.c index daa8e99d31..7580cc8897 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -11,6 +11,8 @@ #include <string.h> #include <uv.h> +#include "klib/khash.h" +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" @@ -25,8 +27,6 @@ #include "nvim/fileio.h" #include "nvim/garray.h" #include "nvim/globals.h" -#include "nvim/lib/khash.h" -#include "nvim/lib/kvec.h" #include "nvim/macros.h" #include "nvim/mark.h" #include "nvim/memory.h" @@ -752,7 +752,7 @@ static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd return error; } - assert(STRCMP(p_enc, "utf-8") == 0); + assert(strcmp(p_enc, "utf-8") == 0); return 0; } @@ -882,10 +882,10 @@ static const void *shada_hist_iter(const void *const iter, const uint8_t history .data = { .history_item = { .histtype = history_type, - .string = (char *)hist_he.hisstr, + .string = hist_he.hisstr, .sep = (char)(history_type == HIST_SEARCH - ? (char)hist_he.hisstr[STRLEN(hist_he.hisstr) + 1] - : 0), + ? hist_he.hisstr[strlen(hist_he.hisstr) + 1] + : 0), .additional_elements = hist_he.additional_elements, } } @@ -1008,7 +1008,7 @@ static inline void hms_to_he_array(const HistoryMergerState *const hms_p, HMLL_FORALL(&hms_p->hmll, cur_entry, { hist->timestamp = cur_entry->data.timestamp; hist->hisnum = (int)(hist - hist_array) + 1; - hist->hisstr = (char_u *)cur_entry->data.data.history_item.string; + hist->hisstr = cur_entry->data.data.history_item.string; hist->additional_elements = cur_entry->data.data.history_item.additional_elements; hist++; @@ -1053,7 +1053,7 @@ static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs, const char *cons kh_key(fname_bufs, k) = xstrdup(fname); FOR_ALL_BUFFERS(buf) { if (buf->b_ffname != NULL) { - if (FNAMECMP(fname, buf->b_ffname) == 0) { + if (path_fnamecmp(fname, buf->b_ffname) == 0) { kh_val(fname_bufs, k) = buf; return buf; } @@ -1238,7 +1238,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) // string is close to useless: you can only use it with :& or :~ and // that’s all because s//~ is not available until the first call to // regtilde. Vim was not calling this for some reason. - (void)(char *)regtilde((char_u *)cur_entry.data.sub_string.sub, p_magic, false); + (void)regtilde(cur_entry.data.sub_string.sub, p_magic, false); // Do not free shada entry: its allocated memory was saved above. break; case kSDItemHistoryEntry: @@ -1313,9 +1313,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T, fmark.timestamp, fmark.mark, cur_entry, (buf == NULL - ? (jl_entry.fname != NULL - && STRCMP(fm.fname, jl_entry.fname) == 0) - : fm.fmark.fnum == jl_entry.fmark.fnum), + ? (jl_entry.fname != NULL + && strcmp(fm.fname, jl_entry.fname) == 0) + : fm.fmark.fnum == jl_entry.fmark.fnum), free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE); #undef SDE_TO_XFMARK #undef ADJUST_IDX @@ -1477,7 +1477,7 @@ static char *shada_filename(const char *file) // because various expansions must have already be done by the shell. // If shell is not performing them then they should be done in main.c // where arguments are parsed, *not here*. - expand_env((char_u *)file, &(NameBuff[0]), MAXPATHL); + expand_env((char *)file, &(NameBuff[0]), MAXPATHL); file = (const char *)&(NameBuff[0]); } } @@ -3023,7 +3023,7 @@ shada_write_file_nomerge: {} if (tail != fname) { const char tail_save = *tail; *tail = NUL; - if (!os_isdir((char_u *)fname)) { + if (!os_isdir(fname)) { int ret; char *failed_dir; if ((ret = os_mkdir_recurse(fname, 0700, &failed_dir)) != 0) { @@ -3098,7 +3098,7 @@ shada_write_file_nomerge: {} } } #endif - if (vim_rename((char_u *)tempname, (char_u *)fname) == -1) { + if (vim_rename(tempname, fname) == -1) { semsg(_(RNERR "Can't rename ShaDa file from %s to %s!"), tempname, fname); } else { @@ -3996,12 +3996,12 @@ static bool shada_removable(const char *name) bool retval = false; char *new_name = home_replace_save(NULL, (char *)name); - for (p = (char *)p_shada; *p;) { + for (p = p_shada; *p;) { (void)copy_option_part(&p, part, ARRAY_SIZE(part), ", "); if (part[0] == 'r') { home_replace(NULL, part + 1, (char *)NameBuff, MAXPATHL, true); - size_t n = STRLEN(NameBuff); - if (mb_strnicmp((char_u *)NameBuff, (char_u *)new_name, n) == 0) { + size_t n = strlen(NameBuff); + if (mb_strnicmp(NameBuff, new_name, n) == 0) { retval = true; break; } diff --git a/src/nvim/sign.c b/src/nvim/sign.c index f1ddbfd147..9c517098b9 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -26,11 +26,11 @@ typedef struct sign sign_T; struct sign { - sign_T *sn_next; // next sign in list + sign_T *sn_next; // next sign in list int sn_typenr; // type number of sign - char_u *sn_name; // name of sign - char_u *sn_icon; // name of pixmap - char_u *sn_text; // text used instead of pixmap + char *sn_name; // name of sign + char *sn_icon; // name of pixmap + char *sn_text; // text used instead of pixmap int sn_line_hl; // highlight ID for line int sn_text_hl; // highlight ID for text int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set @@ -71,23 +71,22 @@ void init_signs(void) /// A new sign in group 'groupname' is added. If the group is not present, /// create it. Otherwise reference the group. -/// -static signgroup_T *sign_group_ref(const char_u *groupname) +static signgroup_T *sign_group_ref(const char *groupname) { hash_T hash; hashitem_T *hi; signgroup_T *group; - hash = hash_hash(groupname); - hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash); + hash = hash_hash((char_u *)groupname); + hi = hash_lookup(&sg_table, (char *)groupname, strlen(groupname), hash); if (HASHITEM_EMPTY(hi)) { // new group - group = xmalloc(sizeof(signgroup_T) + STRLEN(groupname)); + group = xmalloc(sizeof(signgroup_T) + strlen(groupname)); STRCPY(group->sg_name, groupname); group->sg_refcount = 1; group->sg_next_sign_id = 1; - hash_add_item(&sg_table, hi, group->sg_name, hash); + hash_add_item(&sg_table, hi, (char_u *)group->sg_name, hash); } else { // existing group group = HI2SG(hi); @@ -99,11 +98,11 @@ static signgroup_T *sign_group_ref(const char_u *groupname) /// A sign in group 'groupname' is removed. If all the signs in this group are /// removed, then remove the group. -static void sign_group_unref(char_u *groupname) +static void sign_group_unref(char *groupname) { signgroup_T *group; - hashitem_T *hi = hash_find(&sg_table, (char *)groupname); + hashitem_T *hi = hash_find(&sg_table, groupname); if (!HASHITEM_EMPTY(hi)) { group = HI2SG(hi); group->sg_refcount--; @@ -118,16 +117,16 @@ static void sign_group_unref(char_u *groupname) /// @return true if 'sign' is in 'group'. /// A sign can either be in the global group (sign->group == NULL) /// or in a named group. If 'group' is '*', then the sign is part of the group. -static bool sign_in_group(sign_entry_T *sign, const char_u *group) +static bool sign_in_group(sign_entry_T *sign, const char *group) { - return ((group != NULL && STRCMP(group, "*") == 0) + return ((group != NULL && strcmp(group, "*") == 0) || (group == NULL && sign->se_group == NULL) || (group != NULL && sign->se_group != NULL - && STRCMP(group, sign->se_group->sg_name) == 0)); + && strcmp(group, sign->se_group->sg_name) == 0)); } /// Get the next free sign identifier in the specified group -static int sign_group_get_next_signid(buf_T *buf, const char_u *groupname) +static int sign_group_get_next_signid(buf_T *buf, const char *groupname) { int id = 1; signgroup_T *group = NULL; @@ -154,7 +153,7 @@ static int sign_group_get_next_signid(buf_T *buf, const char_u *groupname) // Check whether this sign is already placed in the buffer found = true; FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if (id == sign->se_id && sign_in_group(sign, groupname)) { + if (id == sign->se_id && sign_in_group(sign, (char *)groupname)) { found = false; // sign identifier is in use break; } @@ -177,7 +176,7 @@ static int sign_group_get_next_signid(buf_T *buf, const char_u *groupname) /// @param typenr typenr of sign we are adding /// @param has_text_or_icon sign has text or icon static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int id, - const char_u *group, int prio, linenr_T lnum, int typenr, + const char *group, int prio, linenr_T lnum, int typenr, bool has_text_or_icon) { sign_entry_T *newsign = xmalloc(sizeof(sign_entry_T)); @@ -203,7 +202,7 @@ static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int // When adding first sign need to redraw the windows to create the // column for signs. if (buf->b_signlist == NULL) { - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); changed_line_abv_curs(); } @@ -224,7 +223,7 @@ static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int /// @param lnum line number which gets the mark /// @param typenr typenr of sign we are adding /// @param has_text_or_icon sign has text or icon -static void insert_sign_by_lnum_prio(buf_T *buf, sign_entry_T *prev, int id, const char_u *group, +static void insert_sign_by_lnum_prio(buf_T *buf, sign_entry_T *prev, int id, const char *group, int prio, linenr_T lnum, int typenr, bool has_text_or_icon) { sign_entry_T *sign; @@ -259,7 +258,7 @@ static sign_T *find_sign_by_typenr(int typenr) } /// Get the name of a sign by its typenr. -static char_u *sign_typenr2name(int typenr) +static char *sign_typenr2name(int typenr) { sign_T *sp; @@ -268,7 +267,7 @@ static char_u *sign_typenr2name(int typenr) return sp->sn_name; } } - return (char_u *)_("[Deleted]"); + return _("[Deleted]"); } /// Return information about a sign in a Dict @@ -280,7 +279,7 @@ static dict_T *sign_get_info(sign_entry_T *sign) ? (char *)"" : (char *)sign->se_group->sg_name)); tv_dict_add_nr(d, S_LEN("lnum"), sign->se_lnum); - tv_dict_add_str(d, S_LEN("name"), (char *)sign_typenr2name(sign->se_typenr)); + tv_dict_add_str(d, S_LEN("name"), sign_typenr2name(sign->se_typenr)); tv_dict_add_nr(d, S_LEN("priority"), sign->se_priority); return d; @@ -369,7 +368,7 @@ static void sign_sort_by_prio_on_line(buf_T *buf, sign_entry_T *sign) /// @param lnum line number which gets the mark /// @param typenr typenr of sign we are adding /// @param has_text_or_icon sign has text or icon -static void buf_addsign(buf_T *buf, int id, const char_u *groupname, int prio, linenr_T lnum, +static void buf_addsign(buf_T *buf, int id, const char *groupname, int prio, linenr_T lnum, int typenr, bool has_text_or_icon) { sign_entry_T *sign; // a sign in the signlist @@ -416,13 +415,13 @@ static void buf_addsign(buf_T *buf, int id, const char_u *groupname, int prio, l /// @param group sign group /// @param typenr typenr of sign we are adding /// @param prio sign priority -static linenr_T buf_change_sign_type(buf_T *buf, int markId, const char_u *group, int typenr, +static linenr_T buf_change_sign_type(buf_T *buf, int markId, const char *group, int typenr, int prio) { sign_entry_T *sign; // a sign in the signlist FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if (sign->se_id == markId && sign_in_group(sign, group)) { + if (sign->se_id == markId && sign_in_group(sign, (char *)group)) { sign->se_typenr = typenr; sign->se_priority = prio; sign_sort_by_prio_on_line(buf, sign); @@ -534,7 +533,7 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, SignTextAttrs sattrs[], HlPriAt /// /// @return the line number of the deleted sign. If multiple signs are deleted, /// then returns the line number of the last sign deleted. -static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group) +static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char *group) { sign_entry_T **lastp; // pointer to pointer to current sign sign_entry_T *sign; // a sign in a b_signlist @@ -555,10 +554,10 @@ static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group) lnum = sign->se_lnum; buf_signcols_del_check(buf, lnum, lnum); if (sign->se_group != NULL) { - sign_group_unref(sign->se_group->sg_name); + sign_group_unref((char *)sign->se_group->sg_name); } xfree(sign); - redraw_buf_line_later(buf, lnum); + redraw_buf_line_later(buf, lnum, false); // Check whether only one sign needs to be deleted // If deleting a sign with a specific identifier in a particular // group or deleting any sign at a particular line number, delete @@ -576,7 +575,7 @@ static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group) // When deleting the last sign the cursor position may change, because the // sign columns no longer shows. And the 'signcolumn' may be hidden. if (buf->b_signlist == NULL) { - redraw_buf_later(buf, NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); changed_line_abv_curs(); } @@ -590,7 +589,7 @@ static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group) /// @param buf buffer to store sign in /// @param id sign ID /// @param group sign group -static int buf_findsign(buf_T *buf, int id, char_u *group) +static int buf_findsign(buf_T *buf, int id, char *group) { sign_entry_T *sign; // a sign in the signlist @@ -609,7 +608,7 @@ static int buf_findsign(buf_T *buf, int id, char_u *group) /// @param buf buffer whose sign we are searching for /// @param lnum line number of sign /// @param groupname sign group name -static sign_entry_T *buf_getsign_at_line(buf_T *buf, linenr_T lnum, char_u *groupname) +static sign_entry_T *buf_getsign_at_line(buf_T *buf, linenr_T lnum, char *groupname) { sign_entry_T *sign; // a sign in the signlist @@ -633,7 +632,7 @@ static sign_entry_T *buf_getsign_at_line(buf_T *buf, linenr_T lnum, char_u *grou /// @param buf buffer whose sign we are searching for /// @param lnum line number of sign /// @param groupname sign group name -static int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname) +static int buf_findsign_id(buf_T *buf, linenr_T lnum, char *groupname) { sign_entry_T *sign; // a sign in the signlist @@ -661,13 +660,13 @@ void buf_delete_signs(buf_T *buf, char *group) lastp = &buf->b_signlist; for (sign = buf->b_signlist; sign != NULL; sign = next) { next = sign->se_next; - if (sign_in_group(sign, (char_u *)group)) { + if (sign_in_group(sign, group)) { *lastp = next; if (next != NULL) { next->se_prev = sign->se_prev; } if (sign->se_group != NULL) { - sign_group_unref(sign->se_group->sg_name); + sign_group_unref((char *)sign->se_group->sg_name); } xfree(sign); } else { @@ -678,7 +677,7 @@ void buf_delete_signs(buf_T *buf, char *group) } /// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers. -static void sign_list_placed(buf_T *rbuf, char_u *sign_group) +static void sign_list_placed(buf_T *rbuf, char *sign_group) { buf_T *buf; sign_entry_T *sign; @@ -725,7 +724,27 @@ static void sign_list_placed(buf_T *rbuf, char_u *sign_group) } } -/// Adjust a placed sign for inserted/deleted lines. +/// Adjust or delete a placed sign for inserted/deleted lines. +/// +/// @return the new line number of the sign, or 0 if the sign is in deleted lines. +static linenr_T sign_adjust_one(const linenr_T se_lnum, linenr_T line1, linenr_T line2, + linenr_T amount, linenr_T amount_after) +{ + if (se_lnum < line1) { + // Ignore changes to lines after the sign + return se_lnum; + } + if (se_lnum > line2) { + // Lines inserted or deleted before the sign + return se_lnum + amount_after; + } + if (amount == MAXLNUM) { // sign in deleted lines + return 0; + } + return se_lnum + amount; +} + +/// Adjust placed signs for inserted/deleted lines. void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after) { sign_entry_T *sign; // a sign in a b_signlist @@ -736,9 +755,7 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T int is_fixed = 0; int signcol = win_signcol_configured(curwin, &is_fixed); - bool delete = amount == MAXLNUM; - - if (delete) { + if (amount == MAXLNUM) { // deleting buf_signcols_del_check(curbuf, line1, line2); } @@ -746,11 +763,10 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T for (sign = curbuf->b_signlist; sign != NULL; sign = next) { next = sign->se_next; - new_lnum = sign->se_lnum; - if (sign->se_lnum >= line1 && sign->se_lnum <= line2) { - if (!delete) { - new_lnum += amount; - } else if (!is_fixed || signcol >= 2) { + + new_lnum = sign_adjust_one(sign->se_lnum, line1, line2, amount, amount_after); + if (new_lnum == 0) { // sign in deleted lines + if (!is_fixed || signcol >= 2) { *lastp = next; if (next) { next->se_prev = last; @@ -758,19 +774,23 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T xfree(sign); continue; } - } else if (sign->se_lnum > line2) { - new_lnum += amount_after; - } - // If the new sign line number is past the last line in the buffer, - // then don't adjust the line number. Otherwise, it will always be past - // the last line and will not be visible. - if (sign->se_lnum >= line1 && new_lnum <= curbuf->b_ml.ml_line_count) { - sign->se_lnum = new_lnum; + } else { + // If the new sign line number is past the last line in the buffer, + // then don't adjust the line number. Otherwise, it will always be past + // the last line and will not be visible. + if (new_lnum <= curbuf->b_ml.ml_line_count) { + sign->se_lnum = new_lnum; + } } last = sign; lastp = &sign->se_next; } + + new_lnum = sign_adjust_one(curbuf->b_signcols.sentinel, line1, line2, amount, amount_after); + if (new_lnum != 0) { + curbuf->b_signcols.sentinel = new_lnum; + } } /// Find index of a ":sign" subcmd from its name. @@ -778,14 +798,14 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T /// /// @param begin_cmd begin of sign subcmd /// @param end_cmd just after sign subcmd -static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd) +static int sign_cmd_idx(char *begin_cmd, char *end_cmd) { int idx; - char_u save = *end_cmd; + char save = *end_cmd; - *end_cmd = (char_u)NUL; + *end_cmd = NUL; for (idx = 0;; idx++) { - if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) { + if (cmds[idx] == NULL || strcmp(begin_cmd, cmds[idx]) == 0) { break; } } @@ -794,7 +814,7 @@ static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd) } /// Find a sign by name. Also returns pointer to the previous sign. -static sign_T *sign_find(const char_u *name, sign_T **sp_prev) +static sign_T *sign_find(const char *name, sign_T **sp_prev) { sign_T *sp; @@ -802,7 +822,7 @@ static sign_T *sign_find(const char_u *name, sign_T **sp_prev) *sp_prev = NULL; } for (sp = first_sign; sp != NULL; sp = sp->sn_next) { - if (STRCMP(sp->sn_name, name) == 0) { + if (strcmp(sp->sn_name, name) == 0) { break; } if (sp_prev != NULL) { @@ -814,7 +834,7 @@ static sign_T *sign_find(const char_u *name, sign_T **sp_prev) } /// Allocate a new sign -static sign_T *alloc_new_sign(char_u *name) +static sign_T *alloc_new_sign(char *name) { sign_T *sp; sign_T *lp; @@ -848,28 +868,28 @@ static sign_T *alloc_new_sign(char_u *name) next_sign_typenr = 1; // wrap around } - sp->sn_name = vim_strsave(name); + sp->sn_name = xstrdup(name); return sp; } /// Initialize the icon information for a new sign -static void sign_define_init_icon(sign_T *sp, char_u *icon) +static void sign_define_init_icon(sign_T *sp, char *icon) { xfree(sp->sn_icon); - sp->sn_icon = vim_strsave(icon); + sp->sn_icon = xstrdup(icon); backslash_halve(sp->sn_icon); } /// Initialize the text for a new sign -static int sign_define_init_text(sign_T *sp, char_u *text) +static int sign_define_init_text(sign_T *sp, char *text) { - char_u *s; - char_u *endp; + char *s; + char *endp; int cells; size_t len; - endp = text + (int)STRLEN(text); + endp = text + (int)strlen(text); for (s = text; s + 1 < endp; s++) { if (*s == '\\') { // Remove a backslash, so that it is possible @@ -880,11 +900,11 @@ static int sign_define_init_text(sign_T *sp, char_u *text) } // Count cells and check for non-printable chars cells = 0; - for (s = text; s < endp; s += utfc_ptr2len((char *)s)) { - if (!vim_isprintc(utf_ptr2char((char *)s))) { + for (s = text; s < endp; s += utfc_ptr2len(s)) { + if (!vim_isprintc(utf_ptr2char(s))) { break; } - cells += utf_ptr2cells((char *)s); + cells += utf_ptr2cells(s); } // Currently must be empty, one or two display cells if (s != endp || cells > 2) { @@ -900,7 +920,7 @@ static int sign_define_init_text(sign_T *sp, char_u *text) // Allocate one byte more if we need to pad up // with a space. len = (size_t)(endp - text + ((cells == 1) ? 1 : 0)); - sp->sn_text = vim_strnsave(text, len); + sp->sn_text = xstrnsave(text, len); if (cells == 1) { STRCPY(sp->sn_text + len - 1, " "); @@ -910,8 +930,8 @@ static int sign_define_init_text(sign_T *sp, char_u *text) } /// Define a new sign or update an existing sign -static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, - char_u *texthl, char_u *culhl, char *numhl) +static int sign_define_by_name(char *name, char *icon, char *linehl, char *text, char *texthl, + char *culhl, char *numhl) { sign_T *sp_prev; sign_T *sp; @@ -934,7 +954,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ // non-empty sign list. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer->b_signlist != NULL) { - redraw_buf_later(wp->w_buffer, NOT_VALID); + redraw_buf_later(wp->w_buffer, UPD_NOT_VALID); } } } @@ -952,7 +972,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ if (*linehl == NUL) { sp->sn_line_hl = 0; } else { - sp->sn_line_hl = syn_check_group((char *)linehl, STRLEN(linehl)); + sp->sn_line_hl = syn_check_group(linehl, strlen(linehl)); } } @@ -960,7 +980,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ if (*texthl == NUL) { sp->sn_text_hl = 0; } else { - sp->sn_text_hl = syn_check_group((char *)texthl, STRLEN(texthl)); + sp->sn_text_hl = syn_check_group(texthl, strlen(texthl)); } } @@ -968,7 +988,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ if (*culhl == NUL) { sp->sn_cul_hl = 0; } else { - sp->sn_cul_hl = syn_check_group((char *)culhl, STRLEN(culhl)); + sp->sn_cul_hl = syn_check_group(culhl, strlen(culhl)); } } @@ -976,7 +996,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ if (*numhl == NUL) { sp->sn_num_hl = 0; } else { - sp->sn_num_hl = syn_check_group(numhl, STRLEN(numhl)); + sp->sn_num_hl = syn_check_group(numhl, strlen(numhl)); } } @@ -984,7 +1004,7 @@ static int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_ } /// Free the sign specified by 'name'. -static int sign_undefine_by_name(const char_u *name) +static int sign_undefine_by_name(const char *name) { sign_T *sp_prev; sign_T *sp; @@ -1000,7 +1020,7 @@ static int sign_undefine_by_name(const char_u *name) } /// List the signs matching 'name' -static void sign_list_by_name(char_u *name) +static void sign_list_by_name(char *name) { sign_T *sp; @@ -1024,7 +1044,7 @@ static void may_force_numberwidth_recompute(buf_T *buf, int unplace) } /// Place a sign at the specified file location or update a sign. -static int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign_name, buf_T *buf, +static int sign_place(int *sign_id, const char *sign_group, const char *sign_name, buf_T *buf, linenr_T lnum, int prio) { sign_T *sp; @@ -1035,7 +1055,7 @@ static int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign } for (sp = first_sign; sp != NULL; sp = sp->sn_next) { - if (STRCMP(sp->sn_name, sign_name) == 0) { + if (strcmp(sp->sn_name, sign_name) == 0) { break; } } @@ -1044,7 +1064,7 @@ static int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign return FAIL; } if (*sign_id == 0) { - *sign_id = sign_group_get_next_signid(buf, sign_group); + *sign_id = sign_group_get_next_signid(buf, (char *)sign_group); } if (lnum > 0) { @@ -1053,17 +1073,17 @@ static int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign bool has_text_or_icon = sp->sn_text != NULL || sp->sn_icon != NULL; buf_addsign(buf, *sign_id, - sign_group, + (char *)sign_group, prio, lnum, sp->sn_typenr, has_text_or_icon); } else { // ":sign place {id} file={fname}": change sign type and/or priority - lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr, prio); + lnum = buf_change_sign_type(buf, *sign_id, (char *)sign_group, sp->sn_typenr, prio); } if (lnum > 0) { - redraw_buf_line_later(buf, lnum); + redraw_buf_line_later(buf, lnum, false); // When displaying signs in the 'number' column, if the width of the // number column is less than 2, then force recomputing the width. @@ -1077,15 +1097,15 @@ static int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign } /// Unplace the specified sign -static int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum) +static int sign_unplace(int sign_id, char *sign_group, buf_T *buf, linenr_T atlnum) { if (buf->b_signlist == NULL) { // No signs in the buffer return OK; } if (sign_id == 0) { // Delete all the signs in the specified buffer - redraw_buf_later(buf, NOT_VALID); - buf_delete_signs(buf, (char *)sign_group); + redraw_buf_later(buf, UPD_NOT_VALID); + buf_delete_signs(buf, sign_group); } else { linenr_T lnum; @@ -1094,7 +1114,7 @@ static int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T at if (lnum == 0) { return FAIL; } - redraw_buf_line_later(buf, lnum); + redraw_buf_line_later(buf, lnum, false); } // When all the signs in a buffer are removed, force recomputing the @@ -1108,7 +1128,7 @@ static int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T at } /// Unplace the sign at the current cursor line. -static void sign_unplace_at_cursor(char_u *groupname) +static void sign_unplace_at_cursor(char *groupname) { int id = -1; @@ -1121,7 +1141,7 @@ static void sign_unplace_at_cursor(char_u *groupname) } /// Jump to a sign. -static linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf) +static linenr_T sign_jump(int sign_id, char *sign_group, buf_T *buf) { linenr_T lnum; @@ -1140,7 +1160,7 @@ static linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf) emsg(_("E934: Cannot jump to a buffer that does not have a name")); return -1; } - size_t cmdlen = STRLEN(buf->b_fname) + 24; + size_t cmdlen = strlen(buf->b_fname) + 24; char *cmd = xmallocz(cmdlen); snprintf(cmd, cmdlen, "e +%" PRId64 " %s", (int64_t)lnum, buf->b_fname); @@ -1154,49 +1174,49 @@ static linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf) } /// ":sign define {name} ..." command -static void sign_define_cmd(char_u *sign_name, char_u *cmdline) -{ - char_u *arg; - char_u *p = cmdline; - char_u *icon = NULL; - char_u *text = NULL; - char_u *linehl = NULL; - char_u *texthl = NULL; - char_u *culhl = NULL; - char_u *numhl = NULL; +static void sign_define_cmd(char *sign_name, char *cmdline) +{ + char *arg; + char *p = cmdline; + char *icon = NULL; + char *text = NULL; + char *linehl = NULL; + char *texthl = NULL; + char *culhl = NULL; + char *numhl = NULL; int failed = false; // set values for a defined sign. for (;;) { - arg = (char_u *)skipwhite((char *)p); + arg = skipwhite(p); if (*arg == NUL) { break; } - p = (char_u *)skiptowhite_esc((char *)arg); + p = skiptowhite_esc(arg); if (STRNCMP(arg, "icon=", 5) == 0) { arg += 5; XFREE_CLEAR(icon); - icon = vim_strnsave(arg, (size_t)(p - arg)); + icon = xstrnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "text=", 5) == 0) { arg += 5; XFREE_CLEAR(text); - text = vim_strnsave(arg, (size_t)(p - arg)); + text = xstrnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "linehl=", 7) == 0) { arg += 7; XFREE_CLEAR(linehl); - linehl = vim_strnsave(arg, (size_t)(p - arg)); + linehl = xstrnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "texthl=", 7) == 0) { arg += 7; XFREE_CLEAR(texthl); - texthl = vim_strnsave(arg, (size_t)(p - arg)); + texthl = xstrnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "culhl=", 6) == 0) { arg += 6; XFREE_CLEAR(culhl); - culhl = vim_strnsave(arg, (size_t)(p - arg)); + culhl = xstrnsave(arg, (size_t)(p - arg)); } else if (STRNCMP(arg, "numhl=", 6) == 0) { arg += 6; XFREE_CLEAR(numhl); - numhl = vim_strnsave(arg, (size_t)(p - arg)); + numhl = xstrnsave(arg, (size_t)(p - arg)); } else { semsg(_(e_invarg2), arg); failed = true; @@ -1205,7 +1225,8 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) } if (!failed) { - sign_define_by_name(sign_name, icon, linehl, text, texthl, culhl, (char *)numhl); + sign_define_by_name(sign_name, icon, linehl, text, + texthl, culhl, numhl); } xfree(icon); @@ -1217,7 +1238,7 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) } /// ":sign place" command -static void sign_place_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group, +static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *sign_name, int id, char *group, int prio) { if (id <= 0) { @@ -1250,7 +1271,7 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, } /// ":sign unplace" command -static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group) +static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char *sign_name, int id, char *group) { if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) { emsg(_(e_invarg)); @@ -1272,7 +1293,7 @@ static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int i // :sign unplace * group=* FOR_ALL_BUFFERS(cbuf) { if (cbuf->b_signlist != NULL) { - buf_delete_signs(cbuf, (char *)group); + buf_delete_signs(cbuf, group); } } } @@ -1307,7 +1328,7 @@ static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int i /// :sign jump {id} buffer={nr} /// :sign jump {id} group={group} file={fname} /// :sign jump {id} group={group} buffer={nr} -static void sign_jump_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group) +static void sign_jump_cmd(buf_T *buf, linenr_T lnum, char *sign_name, int id, char *group) { if (sign_name == NULL && group == NULL && id == -1) { emsg(_(e_argreq)); @@ -1329,30 +1350,30 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, /// ":sign jump" commands. /// The supported arguments are: line={lnum} name={name} group={group} /// priority={prio} and file={fname} or buffer={nr}. -static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *signid, - char_u **group, int *prio, buf_T **buf, linenr_T *lnum) +static int parse_sign_cmd_args(int cmd, char *arg, char **sign_name, int *signid, char **group, + int *prio, buf_T **buf, linenr_T *lnum) { - char_u *arg1; - char_u *name; - char_u *filename = NULL; + char *arg1; + char *name; + char *filename = NULL; int lnum_arg = false; // first arg could be placed sign id arg1 = arg; if (ascii_isdigit(*arg)) { - *signid = getdigits_int((char **)&arg, true, 0); + *signid = getdigits_int(&arg, true, 0); if (!ascii_iswhite(*arg) && *arg != NUL) { *signid = -1; arg = arg1; } else { - arg = (char_u *)skipwhite((char *)arg); + arg = skipwhite(arg); } } while (*arg != NUL) { if (STRNCMP(arg, "line=", 5) == 0) { arg += 5; - *lnum = atoi((char *)arg); + *lnum = atoi(arg); arg = skiptowhite(arg); lnum_arg = true; } else if (STRNCMP(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE) { @@ -1382,18 +1403,18 @@ static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *si } } else if (STRNCMP(arg, "priority=", 9) == 0) { arg += 9; - *prio = atoi((char *)arg); + *prio = atoi(arg); arg = skiptowhite(arg); } else if (STRNCMP(arg, "file=", 5) == 0) { arg += 5; filename = arg; - *buf = buflist_findname_exp((char *)arg); + *buf = buflist_findname_exp(arg); break; } else if (STRNCMP(arg, "buffer=", 7) == 0) { arg += 7; filename = arg; - *buf = buflist_findnr(getdigits_int((char **)&arg, true, 0)); - if (*skipwhite((char *)arg) != NUL) { + *buf = buflist_findnr(getdigits_int(&arg, true, 0)); + if (*skipwhite(arg) != NUL) { semsg(_(e_trailing_arg), arg); } break; @@ -1401,7 +1422,7 @@ static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *si emsg(_(e_invarg)); return FAIL; } - arg = (char_u *)skipwhite((char *)arg); + arg = skipwhite(arg); } if (filename != NULL && *buf == NULL) { @@ -1421,8 +1442,8 @@ static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *si /// ":sign" command void ex_sign(exarg_T *eap) { - char_u *arg = (char_u *)eap->arg; - char_u *p; + char *arg = eap->arg; + char *p; int idx; sign_T *sp; @@ -1433,7 +1454,7 @@ void ex_sign(exarg_T *eap) semsg(_("E160: Unknown sign command: %s"), arg); return; } - arg = (char_u *)skipwhite((char *)p); + arg = skipwhite(p); if (idx <= SIGNCMD_LIST) { // Define, undefine or list signs. @@ -1445,7 +1466,7 @@ void ex_sign(exarg_T *eap) } else if (*arg == NUL) { emsg(_("E156: Missing sign name")); } else { - char_u *name; + char *name; // Isolate the sign name. If it's a number skip leading zeroes, // so that "099" and "99" are the same sign. But keep "0". @@ -1456,7 +1477,7 @@ void ex_sign(exarg_T *eap) while (arg[0] == '0' && arg[1] != NUL) { arg++; } - name = vim_strsave(arg); + name = xstrdup(arg); if (idx == SIGNCMD_DEFINE) { sign_define_cmd(name, p); @@ -1474,8 +1495,8 @@ void ex_sign(exarg_T *eap) } else { int id = -1; linenr_T lnum = -1; - char_u *sign_name = NULL; - char_u *group = NULL; + char *sign_name = NULL; + char *group = NULL; int prio = SIGN_DEF_PRIO; buf_T *buf = NULL; @@ -1500,12 +1521,12 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) { const char *p; - tv_dict_add_str(retdict, S_LEN("name"), (char *)sp->sn_name); + tv_dict_add_str(retdict, S_LEN("name"), sp->sn_name); if (sp->sn_icon != NULL) { - tv_dict_add_str(retdict, S_LEN("icon"), (char *)sp->sn_icon); + tv_dict_add_str(retdict, S_LEN("icon"), sp->sn_icon); } if (sp->sn_text != NULL) { - tv_dict_add_str(retdict, S_LEN("text"), (char *)sp->sn_text); + tv_dict_add_str(retdict, S_LEN("text"), sp->sn_text); } if (sp->sn_line_hl > 0) { p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, false); @@ -1539,13 +1560,13 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) /// If 'name' is NULL, return a list of all the defined signs. /// Otherwise, return information about the specified sign. -static void sign_getlist(const char_u *name, list_T *retlist) +static void sign_getlist(const char *name, list_T *retlist) { sign_T *sp = first_sign; dict_T *dict; if (name != NULL) { - sp = sign_find(name, NULL); + sp = sign_find((char *)name, NULL); if (sp == NULL) { return; } @@ -1577,8 +1598,8 @@ list_T *get_buffer_signs(buf_T *buf) return l; } -/// Return information about all the signs placed in a buffer -static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group, +/// @return information about all the signs placed in a buffer +static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const char *sign_group, list_T *retlist) { dict_T *d; @@ -1594,7 +1615,7 @@ static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const tv_dict_add_list(d, S_LEN("signs"), l); FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if (!sign_in_group(sign, sign_group)) { + if (!sign_in_group(sign, (char *)sign_group)) { continue; } if ((lnum == 0 && sign_id == 0) @@ -1609,7 +1630,7 @@ static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const /// Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the /// sign placed at the line number. If 'lnum' is zero, return all the signs /// placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers. -static void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group, +static void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, const char *sign_group, list_T *retlist) { if (buf != NULL) { @@ -1629,12 +1650,12 @@ static void sign_list_defined(sign_T *sp) smsg("sign %s", sp->sn_name); if (sp->sn_icon != NULL) { msg_puts(" icon="); - msg_outtrans((char *)sp->sn_icon); + msg_outtrans(sp->sn_icon); msg_puts(_(" (not supported)")); } if (sp->sn_text != NULL) { msg_puts(" text="); - msg_outtrans((char *)sp->sn_text); + msg_outtrans(sp->sn_text); } if (sp->sn_line_hl > 0) { msg_puts(" linehl="); @@ -1710,8 +1731,8 @@ static enum { EXP_SIGN_GROUPS, // expand with name of placed sign groups } expand_what; -// Return the n'th sign name (used for command line completion) -static char_u *get_nth_sign_name(int idx) +/// @return the n'th sign name (used for command line completion) +static char *get_nth_sign_name(int idx) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // Complete with name of signs already defined @@ -1724,8 +1745,8 @@ static char_u *get_nth_sign_name(int idx) return NULL; } -// Return the n'th sign group name (used for command line completion) -static char_u *get_nth_sign_group_name(int idx) +/// @return the n'th sign group name (used for command line completion) +static char *get_nth_sign_group_name(int idx) { // Complete with name of sign groups already defined int current_idx = 0; @@ -1735,7 +1756,7 @@ static char_u *get_nth_sign_group_name(int idx) todo--; if (current_idx++ == idx) { signgroup_T *const group = HI2SG(hi); - return group->sg_name; + return (char *)group->sg_name; } } } @@ -1768,26 +1789,26 @@ char *get_sign_name(expand_T *xp, int idx) return unplace_arg[idx]; } case EXP_SIGN_NAMES: - return (char *)get_nth_sign_name(idx); + return get_nth_sign_name(idx); case EXP_SIGN_GROUPS: - return (char *)get_nth_sign_group_name(idx); + return get_nth_sign_group_name(idx); default: return NULL; } } /// Handle command line completion for :sign command. -void set_context_in_sign_cmd(expand_T *xp, char_u *arg) +void set_context_in_sign_cmd(expand_T *xp, char *arg) { - char_u *end_subcmd; - char_u *last; + char *end_subcmd; + char *last; int cmd_idx; - char_u *begin_subcmd_args; + char *begin_subcmd_args; // Default: expand subcommands. xp->xp_context = EXPAND_SIGN; expand_what = EXP_SUBCMD; - xp->xp_pattern = (char *)arg; + xp->xp_pattern = arg; end_subcmd = skiptowhite(arg); if (*end_subcmd == NUL) { @@ -1801,7 +1822,7 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) // :sign {subcmd} {subcmd_args} // | // begin_subcmd_args - begin_subcmd_args = (char_u *)skipwhite((char *)end_subcmd); + begin_subcmd_args = skipwhite(end_subcmd); // Expand last argument of subcmd. // @@ -1810,21 +1831,21 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) // p // Loop until reaching last argument. - char_u *p = begin_subcmd_args; + char *p = begin_subcmd_args; do { - p = (char_u *)skipwhite((char *)p); + p = skipwhite(p); last = p; p = skiptowhite(p); } while (*p != NUL); - p = (char_u *)vim_strchr((char *)last, '='); + p = vim_strchr(last, '='); // :sign define {name} {args}... {last}= // | | // last p if (p == NULL) { // Expand last argument name (before equal sign). - xp->xp_pattern = (char *)last; + xp->xp_pattern = last; switch (cmd_idx) { case SIGNCMD_DEFINE: expand_what = EXP_DEFINE; @@ -1854,7 +1875,7 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) } } else { // Expand last argument value (after equal sign). - xp->xp_pattern = (char *)p + 1; + xp->xp_pattern = p + 1; switch (cmd_idx) { case SIGNCMD_DEFINE: if (STRNCMP(last, "texthl", 6) == 0 @@ -1928,8 +1949,8 @@ static int sign_define_from_dict(const char *name_arg, dict_T *dict) numhl = tv_dict_get_string(dict, "numhl", true); } - if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl, - (char_u *)text, (char_u *)texthl, (char_u *)culhl, numhl) + if (sign_define_by_name(name, icon, linehl, + text, texthl, culhl, numhl) == OK) { retval = 0; } @@ -1964,7 +1985,7 @@ static void sign_define_multiple(list_T *l, list_T *retlist) } /// "sign_define()" function -void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_define(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *name; @@ -1995,7 +2016,7 @@ void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "sign_getdefined()" function -void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_getdefined(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *name = NULL; @@ -2005,11 +2026,11 @@ void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr) name = tv_get_string(&argvars[0]); } - sign_getlist((const char_u *)name, rettv->vval.v_list); + sign_getlist(name, rettv->vval.v_list); } /// "sign_getplaced()" function -void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *buf = NULL; dict_T *dict; @@ -2062,12 +2083,11 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - sign_get_placed(buf, lnum, sign_id, (const char_u *)group, - rettv->vval.v_list); + sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list); } /// "sign_jump()" function -void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_jump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int sign_id; char *sign_group = NULL; @@ -2103,7 +2123,7 @@ void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr) goto cleanup; } - rettv->vval.v_number = sign_jump(sign_id, (char_u *)sign_group, buf); + rettv->vval.v_number = sign_jump(sign_id, sign_group, buf); cleanup: xfree(sign_group); @@ -2115,8 +2135,8 @@ static int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *n typval_T *buf_tv, dict_T *dict) { int sign_id = 0; - char_u *group = NULL; - char_u *sign_name = NULL; + char *group = NULL; + char *sign_name = NULL; buf_T *buf = NULL; dictitem_T *di; linenr_T lnum = 0; @@ -2154,14 +2174,14 @@ static int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *n if (group_tv == NULL) { group = NULL; // global group } else { - group = (char_u *)tv_get_string_chk(group_tv); + group = (char *)tv_get_string_chk(group_tv); if (group == NULL) { goto cleanup; } if (group[0] == '\0') { // global sign group group = NULL; } else { - group = vim_strsave(group); + group = xstrdup(group); } } @@ -2175,7 +2195,7 @@ static int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *n if (name_tv == NULL) { goto cleanup; } - sign_name = (char_u *)tv_get_string_chk(name_tv); + sign_name = (char *)tv_get_string_chk(name_tv); if (sign_name == NULL) { goto cleanup; } @@ -2225,7 +2245,7 @@ cleanup: } /// "sign_place()" function -void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_place(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { dict_T *dict = NULL; @@ -2243,7 +2263,7 @@ void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "sign_placelist()" function. Place multiple signs. -void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_placelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int sign_id; @@ -2269,13 +2289,13 @@ void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// Undefine multiple signs static void sign_undefine_multiple(list_T *l, list_T *retlist) { - char_u *name; + char *name; int retval; TV_LIST_ITER_CONST(l, li, { retval = -1; - name = (char_u *)tv_get_string_chk(TV_LIST_ITEM_TV(li)); - if (name != NULL && (sign_undefine_by_name(name) == OK)) { + name = (char *)tv_get_string_chk(TV_LIST_ITEM_TV(li)); + if (name != NULL && (sign_undefine_by_name((char *)name) == OK)) { retval = 0; } tv_list_append_number(retlist, retval); @@ -2283,7 +2303,7 @@ static void sign_undefine_multiple(list_T *l, list_T *retlist) } /// "sign_undefine()" function -void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_undefine(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *name; @@ -2308,7 +2328,7 @@ void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - if (sign_undefine_by_name((const char_u *)name) == OK) { + if (sign_undefine_by_name(name) == OK) { rettv->vval.v_number = 0; } } @@ -2321,20 +2341,20 @@ static int sign_unplace_from_dict(typval_T *group_tv, dict_T *dict) dictitem_T *di; int sign_id = 0; buf_T *buf = NULL; - char_u *group = NULL; + char *group = NULL; int retval = -1; // sign group if (group_tv != NULL) { - group = (char_u *)tv_get_string(group_tv); + group = (char *)tv_get_string(group_tv); } else { - group = (char_u *)tv_dict_get_string(dict, "group", false); + group = tv_dict_get_string(dict, "group", false); } if (group != NULL) { if (group[0] == '\0') { // global sign group group = NULL; } else { - group = vim_strsave(group); + group = xstrdup(group); } } @@ -2373,7 +2393,7 @@ cleanup: } /// "sign_unplace()" function -void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_unplace(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { dict_T *dict = NULL; @@ -2396,7 +2416,7 @@ void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "sign_unplacelist()" function -void f_sign_unplacelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_sign_unplacelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int retval; diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index a4fb325ec8..16e783aab7 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -10,9 +10,9 @@ // Sign group typedef struct signgroup_S { - uint16_t sg_refcount; // number of signs in this group - int sg_next_sign_id; // next sign id for this group - char_u sg_name[1]; // sign group name + uint16_t sg_refcount; // number of signs in this group + int sg_next_sign_id; // next sign id for this group + char sg_name[1]; // sign group name } signgroup_T; // Macros to get the sign group structure from the group name @@ -34,7 +34,7 @@ struct sign_entry { /// Sign attributes. Used by the screen refresh routines. typedef struct { - char_u *text; + char *text; int hl_attr_id; int priority; } SignTextAttrs; @@ -51,4 +51,4 @@ typedef enum { SIGN_TEXT, } SignType; -#endif // NVIM_SIGN_DEFS_H +#endif // NVIM_SIGN_DEFS_H diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 1e44d328b3..7d2b58ff46 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -56,50 +56,60 @@ // Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a // specific word. -#include <assert.h> -#include <inttypes.h> -#include <limits.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <wctype.h> - -// for offsetof() -#include <stddef.h> - -#include "nvim/ascii.h" -#include "nvim/buffer.h" -#include "nvim/change.h" -#include "nvim/charset.h" -#include "nvim/cursor.h" -#include "nvim/drawscreen.h" -#include "nvim/edit.h" -#include "nvim/ex_cmds.h" -#include "nvim/ex_docmd.h" -#include "nvim/func_attr.h" -#include "nvim/garray.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" -#include "nvim/memory.h" -#include "nvim/message.h" -#include "nvim/normal.h" -#include "nvim/option.h" -#include "nvim/os/input.h" -#include "nvim/os/os.h" -#include "nvim/os_unix.h" -#include "nvim/path.h" -#include "nvim/regexp.h" -#include "nvim/search.h" -#include "nvim/spell.h" -#include "nvim/spellfile.h" -#include "nvim/spellsuggest.h" -#include "nvim/strings.h" -#include "nvim/syntax.h" -#include "nvim/undo.h" +#include <assert.h> // for assert +#include <inttypes.h> // for uint32_t, uint16_t, uint8_t +#include <limits.h> // for INT_MAX +#include <stdbool.h> // for false, true, bool +#include <stddef.h> // for NULL, size_t, ptrdiff_t +#include <stdio.h> // for snprintf +#include <string.h> // for memmove, strstr, memcpy, memset + +#include "nvim/ascii.h" // for NUL, ascii_isdigit, ascii_iswhite +#include "nvim/autocmd.h" // for apply_autocmds +#include "nvim/buffer.h" // for bufref_valid, set_bufref, buf_is_empty +#include "nvim/buffer_defs.h" // for win_T, synblock_T, buf_T, w_p_... +#include "nvim/change.h" // for changed_bytes +#include "nvim/charset.h" // for skipwhite, getwhitecols, skipbin +#include "nvim/cursor.h" // for get_cursor_line_ptr +#include "nvim/decoration.h" +#include "nvim/drawscreen.h" // for NOT_VALID, redraw_later +#include "nvim/eval/typval.h" // for semsg +#include "nvim/ex_cmds.h" // for do_sub_msg +#include "nvim/ex_cmds_defs.h" // for exarg_T +#include "nvim/ex_docmd.h" // for do_cmdline_cmd +#include "nvim/garray.h" // for garray_T, GA_EMPTY, GA_APPEND_... +#include "nvim/gettext.h" // for _, N_ +#include "nvim/hashtab.h" // for hash_clear_all, hash_init, has... +#include "nvim/highlight_defs.h" // for HLF_COUNT, hlf_T, HLF_SPB, HLF... +#include "nvim/insexpand.h" // for ins_compl_add_infercase, ins_c... +#include "nvim/log.h" // for ELOG +#include "nvim/macros.h" // for MB_PTR_ADV, MB_PTR_BACK, ASCII... +#include "nvim/mark.h" // for clearpos +#include "nvim/mbyte.h" // for utf_ptr2char, utf_char2bytes +#include "nvim/memline.h" // for ml_append, ml_get_buf, ml_close +#include "nvim/memline_defs.h" // for memline_T +#include "nvim/memory.h" // for xfree, xmalloc, xcalloc, xstrdup +#include "nvim/message.h" // for emsg, msg_puts, give_warning +#include "nvim/option.h" // for copy_option_part, set_option_v... +#include "nvim/option_defs.h" // for p_ws, OPT_LOCAL, p_enc, SHM_SE... +#include "nvim/os/fs.h" // for os_remove +#include "nvim/os/input.h" // for line_breakcheck +#include "nvim/os/os_defs.h" // for MAXPATHL +#include "nvim/path.h" // for path_full_compare, path_tail... +#include "nvim/pos.h" // for pos_T, colnr_T, linenr_T +#include "nvim/regexp.h" // for vim_regfree, vim_regexec, vim_... +#include "nvim/regexp_defs.h" // for regmatch_T, regprog_T +#include "nvim/runtime.h" // for DIP_ALL, do_in_runtimepath +#include "nvim/search.h" // for SEARCH_KEEP, for do_search +#include "nvim/spell.h" // for FUNC_ATTR_NONNULL_ALL, FUNC_AT... +#include "nvim/spell_defs.h" // for slang_T, langp_T, MAXWLEN, sal... +#include "nvim/spellfile.h" // for spell_load_file +#include "nvim/spellsuggest.h" // for spell_suggest_list +#include "nvim/strings.h" // for vim_strchr, vim_snprintf, conc... +#include "nvim/syntax.h" // for syn_get_id, syntax_present +#include "nvim/types.h" // for char_u +#include "nvim/undo.h" // for u_save_cursor +#include "nvim/vim.h" // for curwin, strlen, STRLCPY, STRNCMP // Result values. Lower number is accepted over higher one. #define SP_BANNED (-1) @@ -184,8 +194,8 @@ int did_set_spelltab; char *e_format = N_("E759: Format error in spell file"); // Remember what "z?" replaced. -char_u *repl_from = NULL; -char_u *repl_to = NULL; +char *repl_from = NULL; +char *repl_to = NULL; /// Main spell-checking function. /// "ptr" points to a character that could be the start of a word. @@ -209,11 +219,9 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou matchinf_T mi; // Most things are put in "mi" so that it can // be passed to functions quickly. size_t nrlen = 0; // found a number first - int c; size_t wrongcaplen = 0; - int lpi; bool count_word = docount; - bool use_camel_case = *wp->w_s->b_p_spo != NUL; + bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; bool camel_case = false; // A word never starts at a space or a control character. Return quickly @@ -236,7 +244,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) { mi.mi_end = (char_u *)skipbin((char *)ptr + 2); } else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { - mi.mi_end = skiphex(ptr + 2); + mi.mi_end = (char_u *)skiphex((char *)ptr + 2); } else { mi.mi_end = (char_u *)skipdigits((char *)ptr); } @@ -250,7 +258,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou bool this_upper = false; // init for gcc if (use_camel_case) { - c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char((char *)mi.mi_fend); this_upper = SPELL_ISUPPER(c); } @@ -258,7 +266,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou MB_PTR_ADV(mi.mi_fend); if (use_camel_case) { const bool prev_upper = this_upper; - c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char((char *)mi.mi_fend); this_upper = SPELL_ISUPPER(c); camel_case = !prev_upper && this_upper; } @@ -267,7 +275,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) { // Check word starting with capital letter. - c = utf_ptr2char((char *)ptr); + int c = utf_ptr2char((char *)ptr); if (!SPELL_ISUPPER(c)) { wrongcaplen = (size_t)(mi.mi_fend - ptr); } @@ -308,7 +316,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // Loop over the languages specified in 'spelllang'. // We check them all, because a word may be matched longer in another // language. - for (lpi = 0; lpi < wp->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < wp->w_s->b_langp.ga_len; lpi++) { mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, lpi); // If reloading fails the language is still in the list but everything @@ -361,7 +369,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou int r = vim_regexec(®match, (char *)ptr, 0); wp->w_s->b_cap_prog = regmatch.regprog; if (r) { - *capcol = (int)(regmatch.endp[0] - ptr); + *capcol = (int)(regmatch.endp[0] - (char *)ptr); } } @@ -468,7 +476,6 @@ static void find_word(matchinf_T *mip, int mode) int endlen[MAXWLEN]; // length at possible word endings idx_T endidx[MAXWLEN]; // possible word endings int endidxcnt = 0; - int len; int c; // Repeat advancing in the tree until: @@ -480,7 +487,7 @@ static void find_word(matchinf_T *mip, int mode) flen = fold_more(mip); } - len = byts[arridx++]; + int len = byts[arridx++]; // If the first possible byte is a zero the word could end here. // Remember this index, we first check for the longest word. @@ -565,7 +572,7 @@ static void find_word(matchinf_T *mip, int mode) arridx = endidx[endidxcnt]; wlen = endlen[endidxcnt]; - if (utf_head_off(ptr, ptr + wlen) > 0) { + if (utf_head_off((char *)ptr, (char *)ptr + wlen) > 0) { continue; // not at first byte of character } if (spell_iswordp(ptr + wlen, mip->mi_win)) { @@ -597,7 +604,7 @@ 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++) { + for (int 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 @@ -616,11 +623,10 @@ static void find_word(matchinf_T *mip, int mode) || !spell_valid_case(mip->mi_capflags, (int)flags)) { continue; } - } - // When mode is FIND_PREFIX the word must support the prefix: - // check the prefix ID and the condition. Do that for the list at - // mip->mi_prefarridx that find_prefix() filled. - else if (mode == FIND_PREFIX && !prefix_found) { + } else if (mode == FIND_PREFIX && !prefix_found) { + // When mode is FIND_PREFIX the word must support the prefix: + // check the prefix ID and the condition. Do that for the list at + // mip->mi_prefarridx that find_prefix() filled. c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, (int)flags, mip->mi_word + mip->mi_cprefixlen, slang, @@ -752,9 +758,8 @@ static void find_word(matchinf_T *mip, int mode) // COMPOUNDRULE, discard the compounded word. continue; } - } - // Check NEEDCOMPOUND: can't use word without compounding. - else if (flags & WF_NEEDCOMP) { + } else if (flags & WF_NEEDCOMP) { + // skip if word is only valid in a compound continue; } @@ -792,14 +797,14 @@ static void find_word(matchinf_T *mip, int mode) #if 0 c = mip->mi_compoff; #endif - ++mip->mi_complen; + mip->mi_complen++; if (flags & WF_COMPROOT) { - ++mip->mi_compextra; + mip->mi_compextra++; } // For NOBREAK we need to try all NOBREAK languages, at least // to find the ".add" file(s). - for (int lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; lpi++) { if (slang->sl_nobreak) { mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi); if (mip->mi_lp->lp_slang->sl_fidxs == NULL @@ -833,9 +838,9 @@ static void find_word(matchinf_T *mip, int mode) break; } } - --mip->mi_complen; + mip->mi_complen--; if (flags & WF_COMPROOT) { - --mip->mi_compextra; + mip->mi_compextra--; } mip->mi_lp = save_lp; @@ -905,16 +910,13 @@ static void find_word(matchinf_T *mip, int mode) /// @param gap &sl_comppat bool match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap) { - char_u *p; - int len; - for (int i = 0; i + 1 < gap->ga_len; i += 2) { - p = ((char_u **)gap->ga_data)[i + 1]; + char_u *p = ((char_u **)gap->ga_data)[i + 1]; if (STRNCMP(ptr + wlen, p, STRLEN(p)) == 0) { // Second part matches at start of following compound word, now // check if first part matches at end of previous word. p = ((char_u **)gap->ga_data)[i]; - len = (int)STRLEN(p); + int len = (int)STRLEN(p); if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0) { return true; } @@ -960,16 +962,12 @@ bool can_compound(slang_T *slang, const char_u *word, const char_u *flags) // Caller must check that slang->sl_comprules is not NULL. bool match_compoundrule(slang_T *slang, char_u *compflags) { - char_u *p; - int i; - int c; - // loop over all the COMPOUNDRULE entries - for (p = slang->sl_comprules; *p != NUL; ++p) { + for (char_u *p = slang->sl_comprules; *p != NUL; p++) { // loop over the flags in the compound word we have made, match // them against the current rule entry - for (i = 0;; ++i) { - c = compflags[i]; + for (int i = 0;; i++) { + int c = compflags[i]; if (c == NUL) { // found a rule that matches for the flags we have so far return true; @@ -1018,12 +1016,9 @@ bool match_compoundrule(slang_T *slang, char_u *compflags) int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, bool cond_req) { - int prefcnt; - int pidx; - int prefid = (int)((unsigned)flags >> 24); - for (prefcnt = totprefcnt - 1; prefcnt >= 0; prefcnt--) { - pidx = slang->sl_pidxs[arridx + prefcnt]; + for (int prefcnt = totprefcnt - 1; prefcnt >= 0; prefcnt--) { + int pidx = slang->sl_pidxs[arridx + prefcnt]; // Check the prefix ID. if (prefid != (pidx & 0xff)) { @@ -1063,30 +1058,23 @@ int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang static void find_prefix(matchinf_T *mip, int mode) { idx_T arridx = 0; - int len; int wlen = 0; - int flen; - int c; - char_u *ptr; - idx_T lo, hi, m; slang_T *slang = mip->mi_lp->lp_slang; - char_u *byts; - idx_T *idxs; - byts = slang->sl_pbyts; + char_u *byts = slang->sl_pbyts; if (byts == NULL) { return; // array is empty } // We use the case-folded word here, since prefixes are always // case-folded. - ptr = mip->mi_fword; - flen = mip->mi_fwordlen; // available case-folded bytes + char_u *ptr = mip->mi_fword; + int flen = mip->mi_fwordlen; // available case-folded bytes if (mode == FIND_COMPOUND) { // Skip over the previously found word(s). ptr += mip->mi_compoff; flen -= mip->mi_compoff; } - idxs = slang->sl_pidxs; + idx_T *idxs = slang->sl_pidxs; // Repeat advancing in the tree until: // - there is a byte that doesn't match, @@ -1097,7 +1085,7 @@ static void find_prefix(matchinf_T *mip, int mode) flen = fold_more(mip); } - len = byts[arridx++]; + int len = byts[arridx++]; // If the first possible byte is a zero the prefix could end here. // Check if the following word matches and supports the prefix. @@ -1137,11 +1125,11 @@ static void find_prefix(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - c = ptr[wlen]; - lo = arridx; - hi = arridx + len - 1; + int c = ptr[wlen]; + idx_T lo = arridx; + idx_T hi = arridx + len - 1; while (lo < hi) { - m = (lo + hi) / 2; + idx_T m = (lo + hi) / 2; if (byts[m] > c) { hi = m - 1; } else if (byts[m] < c) { @@ -1169,10 +1157,7 @@ static void find_prefix(matchinf_T *mip, int mode) // Return the length of the folded chars in bytes. static int fold_more(matchinf_T *mip) { - int flen; - char_u *p; - - p = mip->mi_fend; + char_u *p = mip->mi_fend; do { MB_PTR_ADV(mip->mi_fend); } while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win)); @@ -1185,7 +1170,7 @@ static int fold_more(matchinf_T *mip) (void)spell_casefold(mip->mi_win, p, (int)(mip->mi_fend - p), mip->mi_fword + mip->mi_fwordlen, MAXWLEN - mip->mi_fwordlen); - flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen); + int flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen); mip->mi_fwordlen += flen; return flen; } @@ -1214,6 +1199,24 @@ bool no_spell_checking(win_T *wp) return false; } +static void decor_spell_nav_start(win_T *wp) +{ + decor_state = (DecorState){ 0 }; + decor_redraw_reset(wp->w_buffer, &decor_state); +} + +static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, int col, + char **decor_error) +{ + if (*decor_lnum != lnum) { + decor_providers_invoke_spell(wp, lnum - 1, col, lnum - 1, -1, decor_error); + decor_redraw_line(wp->w_buffer, lnum - 1, &decor_state); + *decor_lnum = lnum; + } + decor_redraw_col(wp->w_buffer, col, col, false, &decor_state); + return decor_state.spell; +} + /// Moves to the next spell error. /// "curline" is false for "[s", "]s", "[S" and "]S". /// "curline" is true to find word under/after cursor in the same line. @@ -1227,21 +1230,16 @@ bool no_spell_checking(win_T *wp) /// @return 0 if not found, length of the badly spelled word otherwise. size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp) { - linenr_T lnum; pos_T found_pos; size_t found_len = 0; - char_u *line; - char_u *p; - char_u *endp; hlf_T attr = HLF_COUNT; size_t len; int has_syntax = syntax_present(wp); - int col; - bool can_spell; + colnr_T col; char_u *buf = NULL; size_t buflen = 0; int skip = 0; - int capcol = -1; + colnr_T capcol = -1; bool found_one = false; bool wrapped = false; @@ -1249,6 +1247,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att return 0; } + size_t ret = 0; + // Start looking for bad word at the start of the line, because we can't // start halfway through a word, we don't know where it starts or ends. // @@ -1258,11 +1258,24 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // We concatenate the start of the next line, so that wrapped words work // (e.g. "et<line-break>cetera"). Doesn't work when searching backwards // though... - lnum = wp->w_cursor.lnum; + linenr_T lnum = wp->w_cursor.lnum; clearpos(&found_pos); + char *decor_error = NULL; + // Ephemeral extmarks are currently stored in the global decor_state. + // When looking for spell errors, we need to: + // - temporarily reset decor_state + // - run the _on_spell_nav decor callback for each line we look at + // - detect if any spell marks are present + // - restore decor_state to the value saved here. + // TODO(lewis6991): un-globalize decor_state and allow ephemeral marks to be stored into a + // temporary DecorState. + DecorState saved_decor_start = decor_state; + linenr_T decor_lnum = -1; + decor_spell_nav_start(wp); + while (!got_int) { - line = ml_get_buf(wp->w_buffer, lnum, false); + char_u *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); len = STRLEN(line); if (buflen < len + MAXWLEN + 2) { @@ -1279,17 +1292,17 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // For checking first word with a capital skip white space. if (capcol == 0) { - capcol = (int)getwhitecols(line); + capcol = (colnr_T)getwhitecols((char *)line); } else if (curline && wp == curwin) { // For spellbadword(): check if first word needs a capital. - col = (int)getwhitecols(line); + col = (colnr_T)getwhitecols((char *)line); if (check_need_cap(lnum, col)) { capcol = col; } // Need to get the line again, may have looked at the previous // one. - line = ml_get_buf(wp->w_buffer, lnum, false); + line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); } // Copy the line into "buf" and append the start of the next line if @@ -1299,11 +1312,11 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att STRCPY(buf, line); if (lnum < wp->w_buffer->b_ml.ml_line_count) { spell_cat_line(buf + STRLEN(buf), - ml_get_buf(wp->w_buffer, lnum + 1, false), + (char_u *)ml_get_buf(wp->w_buffer, lnum + 1, false), MAXWLEN); } - p = buf + skip; - endp = buf + len; + char_u *p = buf + skip; + char_u *endp = buf + len; while (p < endp) { // When searching backward don't search after the cursor. Unless // we wrapped around the end of the buffer. @@ -1329,30 +1342,37 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att || ((colnr_T)(curline ? p - buf + (ptrdiff_t)len : p - buf) > wp->w_cursor.col)) { - if (has_syntax) { - col = (int)(p - buf); - (void)syn_get_id(wp, lnum, (colnr_T)col, - FALSE, &can_spell, FALSE); - if (!can_spell) { - attr = HLF_COUNT; + col = (colnr_T)(p - buf); + + bool can_spell = decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error); + + if (!can_spell) { + if (has_syntax) { + (void)syn_get_id(wp, lnum, col, false, &can_spell, false); + } else { + can_spell = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0; } - } else { - can_spell = true; + } + + if (!can_spell) { + attr = HLF_COUNT; } if (can_spell) { found_one = true; - found_pos.lnum = lnum; - found_pos.col = (int)(p - buf); - found_pos.coladd = 0; + found_pos = (pos_T) { + .lnum = lnum, + .col = col, + .coladd = 0 + }; if (dir == FORWARD) { // No need to search further. wp->w_cursor = found_pos; - xfree(buf); if (attrp != NULL) { *attrp = attr; } - return len; + ret = len; + goto theend; } else if (curline) { // Insert mode completion: put cursor after // the bad word. @@ -1376,8 +1396,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att if (dir == BACKWARD && found_pos.lnum != 0) { // Use the last match in the line (before the cursor). wp->w_cursor = found_pos; - xfree(buf); - return found_len; + ret = found_len; + goto theend; } if (curline) { @@ -1447,8 +1467,12 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att line_breakcheck(); } +theend: + decor_state_free(&decor_state); + xfree(decor_error); + decor_state = saved_decor_start; xfree(buf); - return 0; + return ret; } // For spell checking: concatenate the start of the following line "line" into @@ -1457,10 +1481,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // to skip those bytes if the word was OK. void spell_cat_line(char_u *buf, char_u *line, int maxlen) { - char_u *p; - int n; - - p = (char_u *)skipwhite((char *)line); + char_u *p = (char_u *)skipwhite((char *)line); while (vim_strchr("*#/\"\t", *p) != NULL) { p = (char_u *)skipwhite((char *)p + 1); } @@ -1468,7 +1489,7 @@ void spell_cat_line(char_u *buf, char_u *line, int maxlen) if (*p != NUL) { // Only worth concatenating if there is something else than spaces to // concatenate. - n = (int)(p - line) + 1; + int n = (int)(p - line) + 1; if (n < maxlen - 1) { memset(buf, ' ', (size_t)n); STRLCPY(buf + n, p, maxlen - n); @@ -1483,7 +1504,6 @@ static void spell_load_lang(char_u *lang) char fname_enc[85]; int r; spelload_T sl; - int round; // Copy the language name to pass it to spell_load_cb() as a cookie. // It's truncated when an error is detected. @@ -1493,7 +1513,7 @@ static void spell_load_lang(char_u *lang) // We may retry when no spell file is found for the language, an // autocommand may load it then. - for (round = 1; round <= 2; ++round) { + for (int round = 1; round <= 2; round++) { // Find the first spell file for "lang" in 'runtimepath' and load it. vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, "spell/%s.%s.spl", lang, spell_enc()); @@ -1530,7 +1550,7 @@ static void spell_load_lang(char_u *lang) } } else if (sl.sl_slang != NULL) { // At least one file was loaded, now load ALL the additions. - STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl"); + STRCPY(fname_enc + strlen(fname_enc) - 3, "add.spl"); do_in_runtimepath((char *)fname_enc, DIP_ALL, spell_load_cb, &sl); } } @@ -1539,8 +1559,8 @@ static void spell_load_lang(char_u *lang) // use "latin1" for "latin9". And limit to 60 characters (just in case). char_u *spell_enc(void) { - if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) { - return p_enc; + if (STRLEN(p_enc) < 60 && strcmp(p_enc, "iso-8859-15") != 0) { + return (char_u *)p_enc; } return (char_u *)"latin1"; } @@ -1553,15 +1573,15 @@ static void int_wordlist_spl(char_u *fname) int_wordlist, spell_enc()); } -// Allocate a new slang_T for language "lang". "lang" can be NULL. -// Caller must fill "sl_next". -slang_T *slang_alloc(char_u *lang) +/// Allocate a new slang_T for language "lang". "lang" can be NULL. +/// Caller must fill "sl_next". +slang_T *slang_alloc(char *lang) FUNC_ATTR_NONNULL_RET { slang_T *lp = xcalloc(1, sizeof(slang_T)); if (lang != NULL) { - lp->sl_name = vim_strsave(lang); + lp->sl_name = xstrdup(lang); } ga_init(&lp->sl_rep, sizeof(fromto_T), 10); ga_init(&lp->sl_repsal, sizeof(fromto_T), 10); @@ -1624,7 +1644,7 @@ void slang_clear(slang_T *lp) GA_DEEP_CLEAR(gap, salitem_T, free_salitem); } - for (int i = 0; i < lp->sl_prefixcnt; ++i) { + for (int i = 0; i < lp->sl_prefixcnt; i++) { vim_regfree(lp->sl_prefprog[i]); } lp->sl_prefixcnt = 0; @@ -1673,9 +1693,7 @@ void slang_clear_sug(slang_T *lp) static void spell_load_cb(char *fname, void *cookie) { spelload_T *slp = (spelload_T *)cookie; - slang_T *slang; - - slang = spell_load_file((char_u *)fname, slp->sl_lang, NULL, false); + slang_T *slang = spell_load_file(fname, (char *)slp->sl_lang, NULL, false); if (slang != NULL) { // When a previously loaded file has NOBREAK also use it for the // ".add" files. @@ -1698,9 +1716,6 @@ static void spell_load_cb(char *fname, void *cookie) /// @param[in] count 1 to count once, 10 to init void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count) { - hash_T hash; - hashitem_T *hi; - wordcount_T *wc; char_u buf[MAXWLEN]; char_u *p; @@ -1713,9 +1728,10 @@ void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count) p = buf; } - hash = hash_hash(p); + wordcount_T *wc; + hash_T hash = hash_hash(p); const size_t p_len = STRLEN(p); - hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash); + hashitem_T *hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash); if (HASHITEM_EMPTY(hi)) { wc = xmalloc(sizeof(wordcount_T) + p_len); memcpy(wc->wc_word, p, p_len + 1); @@ -1734,9 +1750,7 @@ void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count) // Like strchr() but independent of locale. bool byte_in_str(char_u *str, int n) { - char_u *p; - - for (p = str; *p != NUL; ++p) { + for (char_u *p = str; *p != NUL; p++) { if (*p == n) { return true; } @@ -1748,19 +1762,16 @@ bool byte_in_str(char_u *str, int n) // in "slang->sl_syl_items". int init_syl_tab(slang_T *slang) { - char_u *p; - char_u *s; - int l; - ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4); - p = (char_u *)vim_strchr((char *)slang->sl_syllable, '/'); + char_u *p = (char_u *)vim_strchr((char *)slang->sl_syllable, '/'); while (p != NULL) { *p++ = NUL; if (*p == NUL) { // trailing slash break; } - s = p; + char_u *s = p; p = (char_u *)vim_strchr((char *)p, '/'); + int l; if (p == NULL) { l = (int)STRLEN(s); } else { @@ -1786,8 +1797,6 @@ static int count_syllables(slang_T *slang, const char_u *word) int cnt = 0; bool skip = false; int len; - syl_item_T *syl; - int c; if (slang->sl_syllable == NULL) { return 0; @@ -1803,8 +1812,8 @@ static int count_syllables(slang_T *slang, const char_u *word) // Find longest match of syllable items. len = 0; - for (int i = 0; i < slang->sl_syl_items.ga_len; ++i) { - syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i; + for (int i = 0; i < slang->sl_syl_items.ga_len; i++) { + syl_item_T *syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i; if (syl->sy_len > len && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0) { len = syl->sy_len; @@ -1815,12 +1824,12 @@ static int count_syllables(slang_T *slang, const char_u *word) skip = false; } else { // No recognized syllable item, at least a syllable char then? - c = utf_ptr2char((char *)p); + int c = utf_ptr2char((char *)p); len = utfc_ptr2len((char *)p); if (vim_strchr((char *)slang->sl_syllable, c) == NULL) { skip = false; // No, search for next syllable } else if (!skip) { - ++cnt; // Yes, count it + cnt++; // Yes, count it skip = true; // don't count following syllable chars } } @@ -1828,31 +1837,31 @@ static int count_syllables(slang_T *slang, const char_u *word) return cnt; } -// Parse 'spelllang' and set w_s->b_langp accordingly. -// Returns NULL if it's OK, an error message otherwise. +/// Parse 'spelllang' and set w_s->b_langp accordingly. +/// @return NULL if it's OK, an untranslated error message otherwise. char *did_set_spelllang(win_T *wp) { garray_T ga; char *splp; - char_u *region; - char_u region_cp[3]; + char *region; + char region_cp[3]; bool filename; int region_mask; slang_T *slang; int c; - char_u lang[MAXWLEN + 1]; - char_u spf_name[MAXPATHL]; + char lang[MAXWLEN + 1]; + char spf_name[MAXPATHL]; int len; - char_u *p; + char *p; int round; char *spf; - char_u *use_region = NULL; + char *use_region = NULL; bool dont_use_region = false; bool nobreak = false; langp_T *lp, *lp2; static bool recursive = false; char *ret_msg = NULL; - char_u *spl_copy; + char *spl_copy; bufref_T bufref; set_bufref(&bufref, wp->w_buffer); @@ -1870,22 +1879,22 @@ char *did_set_spelllang(win_T *wp) // Make a copy of 'spelllang', the SpellFileMissing autocommands may change // it under our fingers. - spl_copy = vim_strsave(wp->w_s->b_p_spl); + spl_copy = xstrdup(wp->w_s->b_p_spl); wp->w_s->b_cjk = 0; // Loop over comma separated language names. - for (splp = (char *)spl_copy; *splp != NUL;) { + for (splp = spl_copy; *splp != NUL;) { // Get one language name. copy_option_part(&splp, (char *)lang, MAXWLEN, ","); region = NULL; - len = (int)STRLEN(lang); + len = (int)strlen(lang); - if (!valid_spelllang(lang)) { + if (!valid_spelllang((char *)lang)) { continue; } - if (STRCMP(lang, "cjk") == 0) { + if (strcmp(lang, "cjk") == 0) { wp->w_s->b_cjk = 1; continue; } @@ -1893,11 +1902,11 @@ char *did_set_spelllang(win_T *wp) // If the name ends in ".spl" use it as the name of the spell file. // If there is a region name let "region" point to it and remove it // from the name. - if (len > 4 && FNAMECMP(lang + len - 4, ".spl") == 0) { + if (len > 4 && path_fnamecmp(lang + len - 4, ".spl") == 0) { filename = true; // Locate a region and remove it from the file name. - p = (char_u *)vim_strchr(path_tail((char *)lang), '_'); + p = vim_strchr(path_tail((char *)lang), '_'); if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2]) && !ASCII_ISALPHA(p[3])) { STRLCPY(region_cp, p + 1, 3); @@ -1909,7 +1918,7 @@ char *did_set_spelllang(win_T *wp) // Check if we loaded this language before. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)lang, (char *)slang->sl_fname, false, true) + if (path_full_compare((char *)lang, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -1934,7 +1943,7 @@ char *did_set_spelllang(win_T *wp) if (region != NULL) { // If the region differs from what was used before then don't // use it for 'spellfile'. - if (use_region != NULL && STRCMP(region, use_region) != 0) { + if (use_region != NULL && strcmp(region, use_region) != 0) { dont_use_region = true; } use_region = region; @@ -1943,9 +1952,9 @@ char *did_set_spelllang(win_T *wp) // If not found try loading the language now. if (slang == NULL) { if (filename) { - (void)spell_load_file(lang, lang, NULL, false); + (void)spell_load_file((char *)lang, (char *)lang, NULL, false); } else { - spell_load_lang(lang); + spell_load_lang((char_u *)lang); // SpellFileMissing autocommands may do anything, including // destroying the buffer we are using... if (!bufref_valid(&bufref)) { @@ -1958,12 +1967,12 @@ char *did_set_spelllang(win_T *wp) // Loop over the languages, there can be several files for "lang". for (slang = first_lang; slang != NULL; slang = slang->sl_next) { if (filename - ? path_full_compare((char *)lang, (char *)slang->sl_fname, false, true) == kEqualFiles + ? path_full_compare((char *)lang, slang->sl_fname, false, true) == kEqualFiles : STRICMP(lang, slang->sl_name) == 0) { region_mask = REGION_ALL; if (!filename && region != NULL) { // find region in sl_regions - c = find_region(slang->sl_regions, region); + c = find_region(slang->sl_regions, (char_u *)region); if (c == REGION_ALL) { if (slang->sl_add) { if (*slang->sl_regions != NUL) { @@ -1999,24 +2008,24 @@ char *did_set_spelllang(win_T *wp) // round 1: load first name in 'spellfile'. // round 2: load second name in 'spellfile. // etc. - spf = (char *)curwin->w_s->b_p_spf; + spf = curwin->w_s->b_p_spf; for (round = 0; round == 0 || *spf != NUL; round++) { if (round == 0) { // Internal wordlist, if there is one. if (int_wordlist == NULL) { continue; } - int_wordlist_spl(spf_name); + int_wordlist_spl((char_u *)spf_name); } else { // One entry in 'spellfile'. copy_option_part(&spf, (char *)spf_name, MAXPATHL - 5, ","); STRCAT(spf_name, ".spl"); // If it was already found above then skip it. - for (c = 0; c < ga.ga_len; ++c) { + for (c = 0; c < ga.ga_len; c++) { p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL - && path_full_compare((char *)spf_name, (char *)p, false, true) == kEqualFiles) { + && path_full_compare((char *)spf_name, p, false, true) == kEqualFiles) { break; } } @@ -2027,7 +2036,7 @@ char *did_set_spelllang(win_T *wp) // Check if it was loaded already. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)spf_name, (char *)slang->sl_fname, false, true) + if (path_full_compare((char *)spf_name, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -2040,12 +2049,12 @@ char *did_set_spelllang(win_T *wp) STRCPY(lang, "internal wordlist"); } else { STRLCPY(lang, path_tail((char *)spf_name), MAXWLEN + 1); - p = (char_u *)vim_strchr((char *)lang, '.'); + p = vim_strchr((char *)lang, '.'); if (p != NULL) { *p = NUL; // truncate at ".encoding.add" } } - slang = spell_load_file(spf_name, lang, NULL, true); + slang = spell_load_file((char *)spf_name, (char *)lang, NULL, true); // If one of the languages has NOBREAK we assume the addition // files also have this. @@ -2057,7 +2066,7 @@ char *did_set_spelllang(win_T *wp) region_mask = REGION_ALL; if (use_region != NULL && !dont_use_region) { // find region in sl_regions - c = find_region(slang->sl_regions, use_region); + c = find_region(slang->sl_regions, (char_u *)use_region); if (c != REGION_ALL) { region_mask = 1 << c; } else if (*slang->sl_regions != NUL) { @@ -2085,7 +2094,7 @@ char *did_set_spelllang(win_T *wp) // For each language figure out what language to use for sound folding and // REP items. If the language doesn't support it itself use another one // with the same name. E.g. for "en-math" use "en". - for (int i = 0; i < ga.ga_len; ++i) { + for (int i = 0; i < ga.ga_len; i++) { lp = LANGP_ENTRY(ga, i); // sound folding @@ -2094,7 +2103,7 @@ char *did_set_spelllang(win_T *wp) lp->lp_sallang = lp->lp_slang; } else { // find first similar language that does sound folding - for (int j = 0; j < ga.ga_len; ++j) { + for (int j = 0; j < ga.ga_len; j++) { lp2 = LANGP_ENTRY(ga, j); if (!GA_EMPTY(&lp2->lp_slang->sl_sal) && STRNCMP(lp->lp_slang->sl_name, @@ -2111,7 +2120,7 @@ char *did_set_spelllang(win_T *wp) lp->lp_replang = lp->lp_slang; } else { // find first similar language that has REP items - for (int j = 0; j < ga.ga_len; ++j) { + for (int j = 0; j < ga.ga_len; j++) { lp2 = LANGP_ENTRY(ga, j); if (!GA_EMPTY(&lp2->lp_slang->sl_rep) && STRNCMP(lp->lp_slang->sl_name, @@ -2122,7 +2131,7 @@ char *did_set_spelllang(win_T *wp) } } } - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); theend: xfree(spl_copy); @@ -2137,8 +2146,8 @@ static void clear_midword(win_T *wp) XFREE_CLEAR(wp->w_s->b_spell_ismw_mb); } -// Use the "sl_midword" field of language "lp" for buffer "buf". -// They add up to any currently used midword characters. +/// Use the "sl_midword" field of language "lp" for buffer "buf". +/// They add up to any currently used midword characters. static void use_midword(slang_T *lp, win_T *wp) FUNC_ATTR_NONNULL_ALL { @@ -2146,18 +2155,18 @@ static void use_midword(slang_T *lp, win_T *wp) return; } - for (char_u *p = lp->sl_midword; *p != NUL;) { - const int c = utf_ptr2char((char *)p); - const int l = utfc_ptr2len((char *)p); + for (char *p = (char *)lp->sl_midword; *p != NUL;) { + const int c = utf_ptr2char(p); + const int l = utfc_ptr2len(p); if (c < 256 && l <= 2) { 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, (size_t)l); + wp->w_s->b_spell_ismw_mb = xstrnsave(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, (size_t)n + (size_t)l); + const int n = (int)strlen(wp->w_s->b_spell_ismw_mb); + char *bp = xstrnsave(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); @@ -2198,9 +2207,6 @@ int captype(char_u *word, char_u *end) FUNC_ATTR_NONNULL_ARG(1) { char_u *p; - int firstcap; - bool allcap; - bool past_second = false; // past second word char // find first letter for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p)) { @@ -2209,7 +2215,9 @@ int captype(char_u *word, char_u *end) } } int c = mb_ptr2char_adv((const char_u **)&p); - firstcap = allcap = SPELL_ISUPPER(c); + bool allcap; + bool firstcap = allcap = SPELL_ISUPPER(c); + bool past_second = false; // past second word char // Need to check all letters to find a word with mixed upper/lower. // But a word with an upper char only at start is a ONECAP. @@ -2242,9 +2250,8 @@ int captype(char_u *word, char_u *end) // Delete the internal wordlist and its .spl file. void spell_delete_wordlist(void) { - char_u fname[MAXPATHL] = { 0 }; - if (int_wordlist != NULL) { + char_u fname[MAXPATHL] = { 0 }; os_remove((char *)int_wordlist); int_wordlist_spl(fname); os_remove((char *)fname); @@ -2255,15 +2262,13 @@ void spell_delete_wordlist(void) // Free all languages. void spell_free_all(void) { - slang_T *slang; - // Go through all buffers and handle 'spelllang'. <VN> FOR_ALL_BUFFERS(buf) { ga_clear(&buf->b_s.b_langp); } while (first_lang != NULL) { - slang = first_lang; + slang_T *slang = first_lang; first_lang = slang->sl_next; slang_free(slang); } @@ -2320,7 +2325,7 @@ buf_T *open_spellbuf(void) void close_spellbuf(buf_T *buf) { if (buf != NULL) { - ml_close(buf, TRUE); + ml_close(buf, true); xfree(buf); } } @@ -2328,28 +2333,26 @@ void close_spellbuf(buf_T *buf) // Init the chartab used for spelling for ASCII. void clear_spell_chartab(spelltab_T *sp) { - int i; - // Init everything to false (zero). CLEAR_FIELD(sp->st_isw); CLEAR_FIELD(sp->st_isu); - for (i = 0; i < 256; i++) { + for (int 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 // that is done separately. - for (i = '0'; i <= '9'; ++i) { + for (int i = '0'; i <= '9'; i++) { sp->st_isw[i] = true; } - for (i = 'A'; i <= 'Z'; ++i) { + for (int i = 'A'; i <= 'Z'; i++) { sp->st_isw[i] = true; sp->st_isu[i] = true; sp->st_fold[i] = (char_u)(i + 0x20); } - for (i = 'a'; i <= 'z'; ++i) { + for (int i = 'a'; i <= 'z'; i++) { sp->st_isw[i] = true; sp->st_upper[i] = (char_u)(i - 0x20); } @@ -2361,11 +2364,9 @@ void clear_spell_chartab(spelltab_T *sp) // locale. For utf-8 we don't use isalpha() but our own functions. void init_spell_chartab(void) { - int i; - did_set_spelltab = false; clear_spell_chartab(&spelltab); - for (i = 128; i < 256; i++) { + for (int i = 128; i < 256; i++) { int f = utf_fold(i); int u = mb_toupper(i); @@ -2388,8 +2389,6 @@ void init_spell_chartab(void) bool spell_iswordp(const char_u *p, const win_T *wp) FUNC_ATTR_NONNULL_ALL { - int c; - const int l = utfc_ptr2len((char *)p); const char_u *s = p; if (l == 1) { @@ -2398,16 +2397,16 @@ bool spell_iswordp(const char_u *p, const win_T *wp) s = p + 1; // skip a mid-word character } } else { - c = utf_ptr2char((char *)p); + int c = utf_ptr2char((char *)p); if (c < 256 ? wp->w_s->b_spell_ismw[c] : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr((char *)wp->w_s->b_spell_ismw_mb, c) != NULL)) { + && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) { s = p + l; } } - c = utf_ptr2char((char *)s); + int c = utf_ptr2char((char *)s); if (c > 255) { return spell_mb_isword_class(mb_get_class(s), wp); } @@ -2448,7 +2447,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp) if (*p < 256 ? wp->w_s->b_spell_ismw[*p] : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr((char *)wp->w_s->b_spell_ismw_mb, + && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL)) { s = p + 1; } else { @@ -2508,30 +2507,26 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle bool check_need_cap(linenr_T lnum, colnr_T col) { bool need_cap = false; - char_u *line; - char_u *line_copy = NULL; - char_u *p; - colnr_T endcol; - regmatch_T regmatch; if (curwin->w_s->b_cap_prog == NULL) { return false; } - line = get_cursor_line_ptr(); - endcol = 0; - if (getwhitecols(line) >= (int)col) { + char_u *line = (char_u *)get_cursor_line_ptr(); + char_u *line_copy = NULL; + colnr_T endcol = 0; + if (getwhitecols((char *)line) >= (int)col) { // At start of line, check if previous line is empty or sentence // ends there. if (lnum == 1) { need_cap = true; } else { - line = ml_get(lnum - 1); + line = (char_u *)ml_get(lnum - 1); if (*skipwhite((char *)line) == NUL) { need_cap = true; } else { // Append a space in place of the line break. - line_copy = concat_str(line, (char_u *)" "); + line_copy = (char_u *)concat_str((char *)line, " "); line = line_copy; endcol = (colnr_T)STRLEN(line); } @@ -2542,16 +2537,18 @@ bool check_need_cap(linenr_T lnum, colnr_T col) if (endcol > 0) { // Check if sentence ends before the bad word. - regmatch.regprog = curwin->w_s->b_cap_prog; - regmatch.rm_ic = FALSE; - p = line + endcol; + regmatch_T regmatch = { + .regprog = curwin->w_s->b_cap_prog, + .rm_ic = false + }; + char_u *p = line + endcol; for (;;) { MB_PTR_BACK(line, p); if (p == line || spell_iswordp_nmw(p, curwin)) { break; } if (vim_regexec(®match, (char *)p, 0) - && regmatch.endp[0] == line + endcol) { + && (char_u *)regmatch.endp[0] == line + endcol) { need_cap = true; break; } @@ -2568,10 +2565,6 @@ bool check_need_cap(linenr_T lnum, colnr_T col) void ex_spellrepall(exarg_T *eap) { pos_T pos = curwin->w_cursor; - char_u *frompat; - int addlen; - char_u *line; - char_u *p; bool save_ws = p_ws; linenr_T prev_lnum = 0; @@ -2579,10 +2572,11 @@ void ex_spellrepall(exarg_T *eap) emsg(_("E752: No previous spell replacement")); return; } - addlen = (int)(STRLEN(repl_to) - STRLEN(repl_from)); + int addlen = (int)(strlen(repl_to) - strlen(repl_from)); - frompat = xmalloc(STRLEN(repl_from) + 7); - sprintf((char *)frompat, "\\V\\<%s\\>", repl_from); + size_t frompatlen = strlen(repl_from) + 7; + char_u *frompat = xmalloc(frompatlen); + snprintf((char *)frompat, frompatlen, "\\V\\<%s\\>", repl_from); p_ws = false; sub_nsubs = 0; @@ -2596,13 +2590,13 @@ void ex_spellrepall(exarg_T *eap) // Only replace when the right word isn't there yet. This happens // when changing "etc" to "etc.". - line = get_cursor_line_ptr(); + char_u *line = (char_u *)get_cursor_line_ptr(); if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col, - repl_to, STRLEN(repl_to)) != 0) { - p = xmalloc(STRLEN(line) + (size_t)addlen + 1); + repl_to, strlen(repl_to)) != 0) { + char_u *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)); + STRCAT(p, line + curwin->w_cursor.col + strlen(repl_from)); ml_replace(curwin->w_cursor.lnum, (char *)p, false); changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); @@ -2612,7 +2606,7 @@ void ex_spellrepall(exarg_T *eap) } sub_nsubs++; } - curwin->w_cursor.col += (colnr_T)STRLEN(repl_to); + curwin->w_cursor.col += (colnr_T)strlen(repl_to); } p_ws = save_ws; @@ -2747,13 +2741,12 @@ char *eval_soundfold(const char *const word) /// @param[in,out] res destination for soundfolded word void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res) { - char_u fword[MAXWLEN]; - char_u *word; - if (slang->sl_sofo) { // SOFOFROM and SOFOTO used spell_soundfold_sofo(slang, inword, res); } else { + char_u fword[MAXWLEN]; + char_u *word; // SAL items used. Requires the word to be case-folded. if (folded) { word = inword; @@ -2820,29 +2813,26 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN] = { 0 }; int wres[MAXWLEN] = { 0 }; - int l; int *ws; int *pf; - int i, j, z; + int j, z; int reslen; - int n, k = 0; + int k = 0; int z0; int k0; int n0; - int c; int pri; int p0 = -333; int c0; bool did_white = false; - int wordlen; // Convert the multi-byte string to a wide-character string. // Remove accents, if wanted. We actually remove all non-word characters. // But keep white space. - wordlen = 0; + int wordlen = 0; for (const char_u *s = inword; *s != NUL;) { const char_u *t = s; - c = mb_cptr2char_adv(&s); + int c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (utf_class(c) == 0) { if (did_white) { @@ -2861,13 +2851,14 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } word[wordlen] = NUL; + int c; // This algorithm comes from Aspell phonet.cpp. // Converted from C++ to C. Added support for multi-byte chars. // Changed to keep spaces. - i = reslen = z = 0; + int i = reslen = z = 0; while ((c = word[i]) != NUL) { // Start with the first rule that has the character in the word. - n = slang->sl_sal_first[c & 0xff]; + int n = slang->sl_sal_first[c & 0xff]; z0 = 0; if (n >= 0) { @@ -2875,7 +2866,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // If c is 0x300 need extra check for the end of the array, as // (c & 0xff) is NUL. for (; ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff) - && ws[0] != NUL; ++n) { + && ws[0] != NUL; n++) { // Quickly skip entries that don't match the word. Most // entries are less than three chars, optimize for that. if (c != ws[0]) { @@ -2887,7 +2878,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) continue; } if (k > 2) { - for (j = 2; j < k; ++j) { + for (j = 2; j < k; j++) { if (word[i + j] != ws[j]) { break; } @@ -2948,7 +2939,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // Test follow-up rule for "word[i + k]"; loop over // all entries with the same index byte. for (; ((ws = smp[n0].sm_lead_w)[0] & 0xff) - == (c0 & 0xff); ++n0) { + == (c0 & 0xff); n0++) { // Quickly skip entries that don't match the word. if (c0 != ws[0]) { continue; @@ -2960,7 +2951,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } if (k0 > 2) { pf = word + i + k + 1; - for (j = 2; j < k0; ++j) { + for (j = 2; j < k0; j++) { if (*pf++ != ws[j]) { break; } @@ -3102,8 +3093,8 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } // Convert wide characters in "wres" to a multi-byte string in "res". - l = 0; - for (n = 0; n < reslen; n++) { + int l = 0; + for (int n = 0; n < reslen; n++) { l += utf_char2bytes(wres[n], (char *)res + l); if (l + MB_MAXBYTES > MAXWLEN) { break; @@ -3143,20 +3134,19 @@ void ex_spellinfo(exarg_T *eap) // ":spelldump" void ex_spelldump(exarg_T *eap) { - char *spl; - long dummy; - if (no_spell_checking(curwin)) { return; } + char *spl; + long dummy; (void)get_option_value("spl", &dummy, &spl, OPT_LOCAL); // Create a new empty buffer in a new window. do_cmdline_cmd("new"); // enable spelling locally in the new window - set_option_value("spell", true, "", OPT_LOCAL); - set_option_value("spl", dummy, spl, OPT_LOCAL); + set_option_value_give_err("spell", true, "", OPT_LOCAL); + set_option_value_give_err("spl", dummy, spl, OPT_LOCAL); xfree(spl); if (!buf_is_empty(curbuf)) { @@ -3169,7 +3159,7 @@ void ex_spelldump(exarg_T *eap) if (curbuf->b_ml.ml_line_count > 1) { ml_delete(curbuf->b_ml.ml_line_count, false); } - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } /// Go through all possible words and: @@ -3181,24 +3171,23 @@ void ex_spelldump(exarg_T *eap) /// @param ic ignore case /// @param dir direction for adding matches /// @param dumpflags_arg DUMPFLAG_* -void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) +void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) { langp_T *lp; slang_T *slang; idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; - char_u word[MAXWLEN]; + char word[MAXWLEN]; int c; - char_u *byts; + char *byts; idx_T *idxs; linenr_T lnum = 0; - int round; int depth; int n; int flags; - char_u *region_names = NULL; // region names being used + char *region_names = NULL; // region names being used bool do_region = true; // dump region names and numbers - char_u *p; + char *p; int dumpflags = dumpflags_arg; int patlen; @@ -3208,11 +3197,11 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) if (ic) { dumpflags |= DUMPFLAG_ICASE; } else { - n = captype(pat, NULL); + n = captype((char_u *)pat, NULL); if (n == WF_ONECAP) { dumpflags |= DUMPFLAG_ONECAP; } else if (n == WF_ALLCAP - && (int)STRLEN(pat) > utfc_ptr2len((char *)pat)) { + && (int)STRLEN(pat) > utfc_ptr2len(pat)) { dumpflags |= DUMPFLAG_ALLCAP; } } @@ -3220,13 +3209,13 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // Find out if we can support regions: All languages must support the same // regions or none at all. - for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - p = lp->lp_slang->sl_regions; + p = (char *)lp->lp_slang->sl_regions; if (p[0] != 0) { if (region_names == NULL) { // first language with regions region_names = p; - } else if (STRCMP(region_names, p) != 0) { + } else if (strcmp(region_names, p) != 0) { do_region = false; // region names are different break; } @@ -3243,7 +3232,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } // Loop over all files loaded for the entries in 'spelllang'. - for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); slang = lp->lp_slang; if (slang->sl_fbyts == NULL) { // reloading failed @@ -3258,21 +3247,21 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // When matching with a pattern and there are no prefixes only use // parts of the tree that match "pat". if (pat != NULL && slang->sl_pbyts == NULL) { - patlen = (int)STRLEN(pat); + patlen = (int)strlen(pat); } else { patlen = -1; } // round 1: case-folded tree // round 2: keep-case tree - for (round = 1; round <= 2; ++round) { + for (int round = 1; round <= 2; round++) { if (round == 1) { dumpflags &= ~DUMPFLAG_KEEPCASE; - byts = slang->sl_fbyts; + byts = (char *)slang->sl_fbyts; idxs = slang->sl_fidxs; } else { dumpflags |= DUMPFLAG_KEEPCASE; - byts = slang->sl_kbyts; + byts = (char *)slang->sl_kbyts; idxs = slang->sl_kidxs; } if (byts == NULL) { @@ -3291,8 +3280,8 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } else { // Do one more byte at this node. n = arridx[depth] + curi[depth]; - ++curi[depth]; - c = byts[n]; + curi[depth]++; + c = (uint8_t)byts[n]; if (c == 0 || depth >= MAXWLEN - 1) { // End of word or reached maximum length, deal with the // word. @@ -3315,7 +3304,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // when it's the first one. c = (int)((unsigned)flags >> 24); if (c == 0 || curi[depth] == 2) { - dump_word(slang, word, pat, dir, + dump_word(slang, (char_u *)word, (char_u *)pat, dir, dumpflags, flags, lnum); if (pat == NULL) { lnum++; @@ -3324,13 +3313,13 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // Apply the prefix, if there is one. if (c != 0) { - lnum = dump_prefixes(slang, word, pat, dir, + lnum = dump_prefixes(slang, (char_u *)word, (char_u *)pat, dir, dumpflags, flags, lnum); } } } else { // Normal char, go one level deeper. - word[depth++] = (char_u)c; + word[depth++] = (char)c; arridx[depth] = idxs[n]; curi[depth] = 1; @@ -3342,7 +3331,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // ignore case... assert(depth >= 0); if (depth <= patlen - && mb_strnicmp(word, pat, (size_t)depth) != 0) { + && mb_strnicmp((char *)word, pat, (size_t)depth) != 0) { depth--; } } @@ -3359,10 +3348,8 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, { bool keepcap = false; char_u *p; - char_u *tw; char_u cword[MAXWLEN]; char_u badword[MAXWLEN + 10]; - int i; int flags = wordflags; if (dumpflags & DUMPFLAG_ONECAP) { @@ -3384,7 +3371,7 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, keepcap = true; } } - tw = p; + char_u *tw = p; if (pat == NULL) { // Add flags and regions after a slash. @@ -3400,7 +3387,7 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, STRCAT(badword, "?"); } if (flags & WF_REGION) { - for (i = 0; i < 7; i++) { + for (int i = 0; i < 7; i++) { if (flags & (0x10000 << i)) { const size_t badword_len = STRLEN(badword); snprintf((char *)badword + badword_len, @@ -3420,13 +3407,13 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, if (!HASHITEM_EMPTY(hi)) { vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d", tw, HI2WC(hi)->wc_count); - p = IObuff; + p = (char_u *)IObuff; } } ml_append(lnum, (char *)p, (colnr_T)0, false); } else if (((dumpflags & DUMPFLAG_ICASE) - ? mb_strnicmp(p, pat, STRLEN(pat)) == 0 + ? mb_strnicmp((char *)p, (char *)pat, STRLEN(pat)) == 0 : STRNCMP(p, pat, STRLEN(pat)) == 0) && ins_compl_add_infercase(p, (int)STRLEN(p), p_ic, NULL, *dir, false) == OK) { @@ -3451,34 +3438,27 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi char_u prefix[MAXWLEN]; char_u word_up[MAXWLEN]; bool has_word_up = false; - int c; - char_u *byts; - idx_T *idxs; linenr_T lnum = startlnum; - int depth; - int n; - int len; - int i; // If the word starts with a lower-case letter make the word with an // upper-case letter in word_up[]. - c = utf_ptr2char((char *)word); + int c = utf_ptr2char((char *)word); if (SPELL_TOUPPER(c) != c) { onecap_copy(word, word_up, true); has_word_up = true; } - byts = slang->sl_pbyts; - idxs = slang->sl_pidxs; + char_u *byts = slang->sl_pbyts; + idx_T *idxs = slang->sl_pidxs; if (byts != NULL) { // array not is empty // Loop over all prefixes, building them byte-by-byte in prefix[]. // When at the end of a prefix check that it supports "flags". - depth = 0; + int depth = 0; arridx[0] = 0; curi[0] = 1; while (depth >= 0 && !got_int) { - n = arridx[depth]; - len = byts[n]; + int n = arridx[depth]; + int len = byts[n]; if (curi[depth] > len) { // Done all bytes at this node, go up one level. depth--; @@ -3486,11 +3466,12 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi } else { // Do one more byte at this node. n += curi[depth]; - ++curi[depth]; + curi[depth]++; c = byts[n]; if (c == 0) { // End of prefix, find out how many IDs there are. - for (i = 1; i < len; ++i) { + int i; + for (i = 1; i < len; i++) { if (byts[n + i] != 0) { break; } @@ -3501,8 +3482,7 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi if (c != 0) { STRLCPY(prefix + depth, word, MAXWLEN - depth); dump_word(slang, prefix, pat, dir, dumpflags, - (c & WF_RAREPFX) ? (flags | WF_RARE) - : flags, lnum); + (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; } @@ -3517,8 +3497,7 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi if (c != 0) { STRLCPY(prefix + depth, word_up, MAXWLEN - depth); dump_word(slang, prefix, pat, dir, dumpflags, - (c & WF_RAREPFX) ? (flags | WF_RARE) - : flags, lnum); + (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; } @@ -3556,16 +3535,14 @@ char_u *spell_to_word_end(char_u *start, win_T *win) // Returns the column number of the word. int spell_word_start(int startcol) { - char_u *line; - char_u *p; - int col = 0; - if (no_spell_checking(curwin)) { return startcol; } + char_u *line = (char_u *)get_cursor_line_ptr(); + char_u *p; + // Find a word character before "startcol". - line = get_cursor_line_ptr(); for (p = line + startcol; p > line;) { MB_PTR_BACK(line, p); if (spell_iswordp_nmw(p, curwin)) { @@ -3573,6 +3550,8 @@ int spell_word_start(int startcol) } } + int col = 0; + // Go back to start of the word. while (p > line) { col = (int)(p - line); @@ -3608,18 +3587,18 @@ int expand_spelling(linenr_T lnum, char_u *pat, char ***matchp) return ga.ga_len; } -/// Return true if "val" is a valid 'spelllang' value. -bool valid_spelllang(const char_u *val) +/// @return true if "val" is a valid 'spelllang' value. +bool valid_spelllang(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return valid_name(val, ".-_,@"); } -/// Return true if "val" is a valid 'spellfile' value. -bool valid_spellfile(const char_u *val) +/// @return true if "val" is a valid 'spellfile' value. +bool valid_spellfile(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - for (const char_u *s = val; *s != NUL; s++) { + for (const char_u *s = (char_u *)val; *s != NUL; s++) { if (!vim_isfilec(*s) && *s != ',' && *s != ' ') { return false; } @@ -3632,9 +3611,9 @@ char *did_set_spell_option(bool is_spellfile) char *errmsg = NULL; if (is_spellfile) { - int l = (int)STRLEN(curwin->w_s->b_p_spf); + int l = (int)strlen(curwin->w_s->b_p_spf); if (l > 0 - && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { + && (l < 4 || strcmp(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { errmsg = e_invarg; } } @@ -3657,14 +3636,13 @@ char *compile_cap_prog(synblock_T *synblock) FUNC_ATTR_NONNULL_ALL { regprog_T *rp = synblock->b_cap_prog; - char_u *re; if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) { synblock->b_cap_prog = NULL; } else { // Prepend a ^ so that we only match at one column - re = concat_str((char_u *)"^", synblock->b_p_spc); - synblock->b_cap_prog = vim_regcomp((char *)re, RE_MAGIC); + char *re = concat_str("^", synblock->b_p_spc); + synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC); xfree(re); if (synblock->b_cap_prog == NULL) { synblock->b_cap_prog = rp; // restore the previous program diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index 61f722b9ee..2c4aebe420 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -115,9 +115,9 @@ typedef struct slang_S slang_T; struct slang_S { slang_T *sl_next; // next language - char_u *sl_name; // language name "en", "en.rare", "nl", etc. - char_u *sl_fname; // name of .spl file - bool sl_add; // true if it's a .add file. + char *sl_name; // language name "en", "en.rare", "nl", etc. + char *sl_fname; // name of .spl file + bool sl_add; // true if it's a .add file. char_u *sl_fbyts; // case-folded word bytes long sl_fbyts_len; // length of sl_fbyts @@ -252,7 +252,7 @@ typedef struct wordcount_S { #define MAXWORDCOUNT 0xffff // Remember what "z?" replaced. -extern char_u *repl_from; -extern char_u *repl_to; +extern char *repl_from; +extern char *repl_to; #endif // NVIM_SPELL_DEFS_H diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index be1373f617..611c43e85e 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -355,12 +355,12 @@ struct affentry_S { // Affix header from ".aff" file. Used for af_pref and af_suff. typedef struct affheader_S { - char_u ah_key[AH_KEY_LEN]; // key for hashtab == name of affix + char ah_key[AH_KEY_LEN]; // key for hashtab == name of affix unsigned ah_flag; // affix name as number, uses "af_flagtype" int ah_newID; // prefix ID after renumbering; 0 if not used int ah_combine; // suffix may combine with prefix int ah_follows; // another affix block should be following - affentry_T *ah_first; // first affix entry + affentry_T *ah_first; // first affix entry } affheader_T; #define HI2AH(hi) ((affheader_T *)(hi)->hi_key) @@ -440,7 +440,7 @@ typedef struct spellinfo_S { sblock_T *si_blocks; // memory blocks used long si_blocks_cnt; // memory blocks allocated - int si_did_emsg; // TRUE when ran out of memory + int si_did_emsg; // true when ran out of memory long si_compress_cnt; // words to add before lowering // compression limit @@ -454,7 +454,7 @@ typedef struct spellinfo_S { int si_ascii; // handling only ASCII words int si_add; // addition file - int si_clear_chartab; // when TRUE clear char tables + int si_clear_chartab; // when true clear char tables int si_region; // region mask vimconv_T si_conv; // for conversion to 'encoding' int si_memtot; // runtime memory used @@ -572,10 +572,10 @@ static inline int spell_check_magic_string(FILE *const fd) /// @param silent no error if file doesn't exist /// /// @return the slang_T the spell file was loaded into. NULL for error. -slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool silent) +slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) { FILE *fd; - char_u *p; + char *p; int n; int len; slang_T *lp = NULL; @@ -583,7 +583,7 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile int res; bool did_estack_push = false; - fd = os_fopen((char *)fname, "r"); + fd = os_fopen(fname, "r"); if (fd == NULL) { if (!silent) { semsg(_(e_notopen), fname); @@ -604,16 +604,16 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile lp = slang_alloc(lang); // Remember the file name, used to reload the file when it's updated. - lp->sl_fname = vim_strsave(fname); + lp->sl_fname = xstrdup(fname); // Check for .add.spl. - lp->sl_add = strstr(path_tail((char *)fname), SPL_FNAME_ADD) != NULL; + lp->sl_add = strstr(path_tail(fname), SPL_FNAME_ADD) != NULL; } else { lp = old_lp; } // Set sourcing_name, so that error messages mention the file name. - estack_push(ETYPE_SPELL, (char *)fname, 0); + estack_push(ETYPE_SPELL, fname, 0); did_estack_push = true; // <HEADER>: <fileID> @@ -697,11 +697,11 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile break; case SN_MAP: - p = READ_STRING(fd, len); // <mapstr> + p = (char *)READ_STRING(fd, len); // <mapstr> if (p == NULL) { goto endFAIL; } - set_map_str(lp, p); + set_map_str(lp, (char_u *)p); xfree(p); break; @@ -845,12 +845,12 @@ static void tree_count_words(char_u *byts, idx_T *idxs) } else { // Do one more byte at this node. n = arridx[depth] + curi[depth]; - ++curi[depth]; + curi[depth]++; c = byts[n]; if (c == 0) { // End of word, count it. - ++wordcount[depth]; + wordcount[depth]++; // Skip over any other NUL bytes (same word with different // flags). @@ -869,12 +869,12 @@ static void tree_count_words(char_u *byts, idx_T *idxs) } } -// Load the .sug files for languages that have one and weren't loaded yet. +/// Load the .sug files for languages that have one and weren't loaded yet. void suggest_load_files(void) { langp_T *lp; slang_T *slang; - char_u *dotp; + char *dotp; FILE *fd; char_u buf[MAXWLEN]; int i; @@ -885,7 +885,7 @@ void suggest_load_files(void) int c; // Do this for all languages that support sound folding. - for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); slang = lp->lp_slang; if (slang->sl_sugtime != 0 && !slang->sl_sugloaded) { @@ -894,12 +894,12 @@ void suggest_load_files(void) // don't try again and again. slang->sl_sugloaded = true; - dotp = STRRCHR(slang->sl_fname, '.'); - if (dotp == NULL || FNAMECMP(dotp, ".spl") != 0) { + dotp = strrchr(slang->sl_fname, '.'); + if (dotp == NULL || path_fnamecmp(dotp, ".spl") != 0) { continue; } STRCPY(dotp, ".sug"); - fd = os_fopen((char *)slang->sl_fname, "r"); + fd = os_fopen(slang->sl_fname, "r"); if (fd == NULL) { goto nextone; } @@ -960,7 +960,7 @@ someerror: // Read all the wordnr lists into the buffer, one NUL terminated // list per line. ga_init(&ga, 1, 100); - for (wordnr = 0; wordnr < wcount; ++wordnr) { + for (wordnr = 0; wordnr < wcount; wordnr++) { ga.ga_len = 0; for (;;) { c = getc(fd); // <sugline> @@ -1142,10 +1142,10 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first) } // Fill the first-index table. - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < 256; i++) { first[i] = -1; } - for (int i = 0; i < gap->ga_len; ++i) { + 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] = (int16_t)i; @@ -1200,7 +1200,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) // Read up to the first special char into sm_lead. int i = 0; - for (; i < ccnt; ++i) { + for (; i < ccnt; i++) { c = getc(fd); // <salfrom> if (vim_strchr("0123456789(-<^$", c) != NULL) { break; @@ -1213,7 +1213,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) // Put (abc) chars in sm_oneof, if any. if (c == '(') { smp->sm_oneof = p; - for (++i; i < ccnt; ++i) { + for (++i; i < ccnt; i++) { c = getc(fd); // <salfrom> if (c == ')') { break; @@ -1299,7 +1299,7 @@ static int read_words_section(FILE *fd, slang_T *lp, int len) while (done < len) { // Read one word at a time. - for (i = 0;; ++i) { + for (i = 0;; i++) { c = getc(fd); if (c == EOF) { return SP_TRUNCERROR; @@ -1597,7 +1597,7 @@ static void set_sal_first(slang_T *lp) garray_T *gap = &lp->sl_sal; sfirst = lp->sl_sal_first; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < 256; i++) { sfirst[i] = -1; } smp = (salitem_T *)gap->ga_data; @@ -1732,7 +1732,7 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx byts[idx++] = (char_u)len; // Read the byte values, flag/region bytes and shared indexes. - for (i = 1; i <= len; ++i) { + for (i = 1; i <= len; i++) { c = getc(fd); // <byte> if (c < 0) { return SP_TRUNCERROR; @@ -1795,7 +1795,7 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx // Recursively read the children for non-shared siblings. // Skip the end-of-word ones (zero byte value) and the shared ones (and // remove SHARED_MASK) - for (i = 1; i <= len; ++i) { + for (i = 1; i <= len; i++) { if (byts[startidx + i] != 0) { if (idxs[startidx + i] & SHARED_MASK) { idxs[startidx + i] &= ~SHARED_MASK; @@ -1822,13 +1822,13 @@ static void spell_reload_one(char_u *fname, bool added_word) bool didit = false; for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)fname, (char *)slang->sl_fname, false, true) == kEqualFiles) { + if (path_full_compare((char *)fname, slang->sl_fname, false, true) == kEqualFiles) { slang_clear(slang); - if (spell_load_file(fname, NULL, slang, false) == NULL) { + if (spell_load_file((char *)fname, NULL, slang, false) == NULL) { // reloading failed, clear the language slang_clear(slang); } - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); didit = true; } } @@ -1863,7 +1863,7 @@ static long compress_added = 500000; // word count // Sets "sps_flags". int spell_check_msm(void) { - char *p = (char *)p_msm; + char *p = p_msm; long start = 0; long incr = 0; long added = 0; @@ -1924,7 +1924,7 @@ static void spell_clear_flags(wordnode_T *node) wordnode_T *np; for (np = node; np != NULL; np = np->wn_sibling) { - np->wn_u1.index = FALSE; + np->wn_u1.index = false; spell_clear_flags(np->wn_child); } } @@ -1940,7 +1940,7 @@ static void spell_print_node(wordnode_T *node, int depth) msg((char_u *)line2); msg((char_u *)line3); } else { - node->wn_u1.index = TRUE; + node->wn_u1.index = true; if (node->wn_byte != NUL) { if (node->wn_child != NULL) { @@ -1994,7 +1994,7 @@ static void spell_print_tree(wordnode_T *root) } } -#endif // SPELL_PRINTTREE +#endif // SPELL_PRINTTREE // Reads the affix file "fname". // Returns an afffile_T, NULL for complete failure. @@ -2005,17 +2005,17 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) char_u *line; char_u *pc = NULL; #define MAXITEMCNT 30 - char_u *(items[MAXITEMCNT]); + char *(items[MAXITEMCNT]); int itemcnt; - char_u *p; + char *p; int lnum = 0; affheader_T *cur_aff = NULL; bool did_postpone_prefix = false; int aff_todo = 0; hashtab_T *tp; - char_u *low = NULL; - char_u *fol = NULL; - char_u *upp = NULL; + char *low = NULL; + char *fol = NULL; + char *upp = NULL; int do_rep; int do_repsal; int do_sal; @@ -2042,7 +2042,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } vim_snprintf((char *)IObuff, IOSIZE, _("Reading affix file %s..."), fname); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); // Only do REP lines when not done in another .aff file already. do_rep = GA_EMPTY(&spin->si_rep); @@ -2075,7 +2075,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Convert from "SET" to 'encoding' when needed. xfree(pc); if (spin->si_conv.vc_type != CONV_NONE) { - pc = string_convert(&spin->si_conv, rline, NULL); + pc = (char_u *)string_convert(&spin->si_conv, (char *)rline, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %d: %s"), fname, lnum, rline); @@ -2090,8 +2090,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Split the line up in white separated items. Put a NUL after each // item. itemcnt = 0; - for (p = line;;) { - while (*p != NUL && *p <= ' ') { // skip white space and CR/NL + for (p = (char *)line;;) { + while (*p != NUL && (uint8_t)(*p) <= ' ') { // skip white space and CR/NL p++; } if (*p == NUL) { @@ -2103,11 +2103,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) items[itemcnt++] = p; // A few items have arbitrary text argument, don't split them. if (itemcnt == 2 && spell_info_item(items[0])) { - while (*p >= ' ' || *p == TAB) { // skip until CR/NL + while ((uint8_t)(*p) >= ' ' || *p == TAB) { // skip until CR/NL p++; } } else { - while (*p > ' ') { // skip until white space or CR/NL + while ((uint8_t)(*p) > ' ') { // skip until white space or CR/NL p++; } } @@ -2121,21 +2121,20 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (itemcnt > 0) { if (is_aff_rule(items, itemcnt, "SET", 2) && aff->af_enc == NULL) { // Setup for conversion from "ENC" to 'encoding'. - aff->af_enc = enc_canonize(items[1]); + aff->af_enc = (char_u *)enc_canonize((char *)items[1]); if (!spin->si_ascii - && convert_setup(&spin->si_conv, aff->af_enc, - p_enc) == FAIL) { + && convert_setup(&spin->si_conv, (char *)aff->af_enc, p_enc) == FAIL) { smsg(_("Conversion in %s not supported: from %s to %s"), fname, aff->af_enc, p_enc); } spin->si_conv.vc_fail = true; } else if (is_aff_rule(items, itemcnt, "FLAG", 2) && aff->af_flagtype == AFT_CHAR) { - if (STRCMP(items[1], "long") == 0) { + if (strcmp(items[1], "long") == 0) { aff->af_flagtype = AFT_LONG; - } else if (STRCMP(items[1], "num") == 0) { + } else if (strcmp(items[1], "num") == 0) { aff->af_flagtype = AFT_NUM; - } else if (STRCMP(items[1], "caplong") == 0) { + } else if (strcmp(items[1], "caplong") == 0) { aff->af_flagtype = AFT_CAPLONG; } else { smsg(_("Invalid value for FLAG in %s line %d: %s"), @@ -2158,8 +2157,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } else if (spell_info_item(items[0]) && itemcnt > 1) { p = getroom(spin, (spin->si_info == NULL ? 0 : STRLEN(spin->si_info)) - + STRLEN(items[0]) - + STRLEN(items[1]) + 3, false); + + strlen(items[0]) + + strlen(items[1]) + 3, false); if (spin->si_info != NULL) { STRCPY(p, spin->si_info); STRCAT(p, "\n"); @@ -2167,10 +2166,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) STRCAT(p, items[0]); STRCAT(p, " "); STRCAT(p, items[1]); - spin->si_info = p; - } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) - && midword == NULL) { - midword = getroom_save(spin, items[1]); + spin->si_info = (char_u *)p; + } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) { + midword = (char_u *)getroom_save(spin, (char_u *)items[1]); } else if (is_aff_rule(items, itemcnt, "TRY", 2)) { // ignored, we look in the tree for what chars may appear } @@ -2178,44 +2176,44 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) else if ((is_aff_rule(items, itemcnt, "RAR", 2) || is_aff_rule(items, itemcnt, "RARE", 2)) && aff->af_rare == 0) { - aff->af_rare = affitem2flag(aff->af_flagtype, items[1], + aff->af_rare = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } // TODO: remove "KEP" later else if ((is_aff_rule(items, itemcnt, "KEP", 2) || is_aff_rule(items, itemcnt, "KEEPCASE", 2)) && aff->af_keepcase == 0) { - aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1], + aff->af_keepcase = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if ((is_aff_rule(items, itemcnt, "BAD", 2) || is_aff_rule(items, itemcnt, "FORBIDDENWORD", 2)) && aff->af_bad == 0) { - aff->af_bad = affitem2flag(aff->af_flagtype, items[1], + aff->af_bad = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2) && aff->af_needaffix == 0) { - aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1], + aff->af_needaffix = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2) && aff->af_circumfix == 0) { - aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1], + aff->af_circumfix = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2) && aff->af_nosuggest == 0) { - aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1], + aff->af_nosuggest = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if ((is_aff_rule(items, itemcnt, "NEEDCOMPOUND", 2) || is_aff_rule(items, itemcnt, "ONLYINCOMPOUND", 2)) && aff->af_needcomp == 0) { - aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1], + aff->af_needcomp = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2) && aff->af_comproot == 0) { - aff->af_comproot = affitem2flag(aff->af_flagtype, items[1], + aff->af_comproot = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2) && aff->af_compforbid == 0) { - aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1], + aff->af_compforbid = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); if (aff->af_pref.ht_used > 0) { smsg(_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"), @@ -2223,7 +2221,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } } else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2) && aff->af_comppermit == 0) { - aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1], + aff->af_comppermit = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); if (aff->af_pref.ht_used > 0) { smsg(_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"), @@ -2233,10 +2231,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) && compflags == NULL) { // Turn flag "c" into COMPOUNDRULE compatible string "c+", // "Na" into "Na+", "1234" into "1234+". - p = getroom(spin, STRLEN(items[1]) + 2, false); + p = getroom(spin, strlen(items[1]) + 2, false); STRCPY(p, items[1]); STRCAT(p, "+"); - compflags = p; + compflags = (char_u *)p; } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) { // We don't use the count, but do check that it's a number and // not COMPOUNDRULE mistyped. @@ -2249,7 +2247,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (compflags != NULL || *skipdigits((char *)items[1]) != NUL) { // Concatenate this string to previously defined ones, // using a slash to separate them. - l = (int)STRLEN(items[1]) + 1; + l = (int)strlen(items[1]) + 1; if (compflags != NULL) { l += (int)STRLEN(compflags) + 1; } @@ -2259,7 +2257,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) STRCAT(p, "/"); } STRCAT(p, items[1]); - compflags = p; + compflags = (char_u *)p; } } else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2) && compmax == 0) { @@ -2301,19 +2299,19 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Only add the couple if it isn't already there. for (i = 0; i < gap->ga_len - 1; i += 2) { - if (STRCMP(((char **)(gap->ga_data))[i], items[1]) == 0 - && STRCMP(((char **)(gap->ga_data))[i + 1], items[2]) == 0) { + if (strcmp(((char **)(gap->ga_data))[i], items[1]) == 0 + && strcmp(((char **)(gap->ga_data))[i + 1], items[2]) == 0) { break; } } if (i >= gap->ga_len) { ga_grow(gap, 2); - ((char **)(gap->ga_data))[gap->ga_len++] = (char *)getroom_save(spin, items[1]); - ((char **)(gap->ga_data))[gap->ga_len++] = (char *)getroom_save(spin, items[2]); + ((char **)(gap->ga_data))[gap->ga_len++] = getroom_save(spin, (char_u *)items[1]); + ((char **)(gap->ga_data))[gap->ga_len++] = getroom_save(spin, (char_u *)items[2]); } } else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2) && syllable == NULL) { - syllable = getroom_save(spin, items[1]); + syllable = (char_u *)getroom_save(spin, (char_u *)items[1]); } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) { spin->si_nobreak = true; } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) { @@ -2326,8 +2324,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) aff->af_pfxpostpone = true; } else if (is_aff_rule(items, itemcnt, "IGNOREEXTRA", 1)) { aff->af_ignoreextra = true; - } else if ((STRCMP(items[0], "PFX") == 0 - || STRCMP(items[0], "SFX") == 0) + } else if ((strcmp(items[0], "PFX") == 0 + || strcmp(items[0], "SFX") == 0) && aff_todo == 0 && itemcnt >= 4) { int lasti = 4; @@ -2358,9 +2356,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } else { // New affix letter. cur_aff = getroom(spin, sizeof(*cur_aff), true); - cur_aff->ah_flag = affitem2flag(aff->af_flagtype, items[1], + cur_aff->ah_flag = affitem2flag(aff->af_flagtype, (char_u *)items[1], fname, lnum); - if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN) { + if (cur_aff->ah_flag == 0 || strlen(items[1]) >= AH_KEY_LEN) { break; } if (cur_aff->ah_flag == aff->af_bad @@ -2377,14 +2375,14 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) fname, lnum, items[1]); } STRCPY(cur_aff->ah_key, items[1]); - hash_add(tp, cur_aff->ah_key); + hash_add(tp, (char_u *)cur_aff->ah_key); cur_aff->ah_combine = (*items[2] == 'Y'); } // Check for the "S" flag, which apparently means that another // block with the same affix name is following. - if (itemcnt > lasti && STRCMP(items[lasti], "S") == 0) { + if (itemcnt > lasti && strcmp(items[lasti], "S") == 0) { lasti++; cur_aff->ah_follows = true; } else { @@ -2400,7 +2398,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) smsg(_(e_afftrailing), fname, lnum, items[lasti]); } - if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0) { + if (strcmp(items[2], "Y") != 0 && strcmp(items[2], "N") != 0) { smsg(_("Expected Y or N in %s line %d: %s"), fname, lnum, items[2]); } @@ -2423,10 +2421,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } aff_todo = atoi((char *)items[3]); - } else if ((STRCMP(items[0], "PFX") == 0 - || STRCMP(items[0], "SFX") == 0) + } else if ((strcmp(items[0], "PFX") == 0 + || strcmp(items[0], "SFX") == 0) && aff_todo > 0 - && STRCMP(cur_aff->ah_key, items[1]) == 0 + && strcmp(cur_aff->ah_key, items[1]) == 0 && itemcnt >= 5) { affentry_T *aff_entry; bool upper = false; @@ -2436,7 +2434,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // mean mistakes go unnoticed. Require a comment-starter. // Hunspell uses a "-" item. if (itemcnt > lasti && *items[lasti] != '#' - && (STRCMP(items[lasti], "-") != 0 + && (strcmp(items[lasti], "-") != 0 || itemcnt != lasti + 1)) { smsg(_(e_afftrailing), fname, lnum, items[lasti]); } @@ -2445,11 +2443,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) aff_todo--; aff_entry = getroom(spin, sizeof(*aff_entry), true); - if (STRCMP(items[2], "0") != 0) { - aff_entry->ae_chop = getroom_save(spin, items[2]); + if (strcmp(items[2], "0") != 0) { + aff_entry->ae_chop = (char_u *)getroom_save(spin, (char_u *)items[2]); } - if (STRCMP(items[3], "0") != 0) { - aff_entry->ae_add = getroom_save(spin, items[3]); + if (strcmp(items[3], "0") != 0) { + aff_entry->ae_add = (char_u *)getroom_save(spin, (char_u *)items[3]); // Recognize flags on the affix: abcd/XYZ aff_entry->ae_flags = (char_u *)vim_strchr((char *)aff_entry->ae_add, '/'); @@ -2466,10 +2464,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) aff_entry->ae_next = cur_aff->ah_first; cur_aff->ah_first = aff_entry; - if (STRCMP(items[4], ".") != 0) { + if (strcmp(items[4], ".") != 0) { char_u buf[MAXLINELEN]; - aff_entry->ae_cond = getroom_save(spin, items[4]); + aff_entry->ae_cond = (char_u *)getroom_save(spin, (char_u *)items[4]); if (*items[0] == 'P') { sprintf((char *)buf, "^%s", items[4]); } else { @@ -2504,10 +2502,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (c_up != c && (aff_entry->ae_cond == NULL || utf_ptr2char((char *)aff_entry->ae_cond) == c)) { - p = aff_entry->ae_add + p = (char *)aff_entry->ae_add + STRLEN(aff_entry->ae_add); MB_PTR_BACK(aff_entry->ae_add, p); - if (utf_ptr2char((char *)p) == c_up) { + if (utf_ptr2char(p) == c_up) { upper = true; aff_entry->ae_chop = NULL; *p = NUL; @@ -2517,8 +2515,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // upper-case letter. if (aff_entry->ae_cond != NULL) { char_u buf[MAXLINELEN]; - onecap_copy(items[4], buf, true); - aff_entry->ae_cond = getroom_save(spin, buf); + onecap_copy((char_u *)items[4], buf, true); + aff_entry->ae_cond = (char_u *)getroom_save(spin, buf); if (aff_entry->ae_cond != NULL) { sprintf((char *)buf, "^%s", aff_entry->ae_cond); @@ -2536,10 +2534,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) int n; // Find a previously used condition. - for (idx = spin->si_prefcond.ga_len - 1; idx >= 0; - --idx) { - p = ((char_u **)spin->si_prefcond.ga_data)[idx]; - if (str_equal(p, aff_entry->ae_cond)) { + for (idx = spin->si_prefcond.ga_len - 1; idx >= 0; idx--) { + p = ((char **)spin->si_prefcond.ga_data)[idx]; + if (str_equal(p, (char *)aff_entry->ae_cond)) { break; } } @@ -2548,14 +2545,14 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) idx = spin->si_prefcond.ga_len; pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond); *pp = (aff_entry->ae_cond == NULL) ? - NULL : getroom_save(spin, aff_entry->ae_cond); + NULL : (char_u *)getroom_save(spin, aff_entry->ae_cond); } // Add the prefix to the prefix tree. if (aff_entry->ae_add == NULL) { - p = (char_u *)""; + p = ""; } else { - p = aff_entry->ae_add; + p = (char *)aff_entry->ae_add; } // PFX_FLAGS is a negative number, so that @@ -2573,24 +2570,24 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (aff_entry->ae_compforbid) { n |= WFP_COMPFORBID; } - tree_add_word(spin, p, spin->si_prefroot, n, + tree_add_word(spin, (char_u *)p, spin->si_prefroot, n, idx, cur_aff->ah_newID); did_postpone_prefix = true; } // Didn't actually use ah_newID, backup si_newprefID. if (aff_todo == 0 && !did_postpone_prefix) { - --spin->si_newprefID; + spin->si_newprefID--; cur_aff->ah_newID = 0; } } } } else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL) { - fol = vim_strsave(items[1]); + fol = xstrdup(items[1]); } else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL) { - low = vim_strsave(items[1]); + low = xstrdup(items[1]); } else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL) { - upp = vim_strsave(items[1]); + upp = xstrdup(items[1]); } else if (is_aff_rule(items, itemcnt, "REP", 2) || is_aff_rule(items, itemcnt, "REPSAL", 2)) { // Ignore REP/REPSAL count @@ -2598,8 +2595,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) smsg(_("Expected REP(SAL) count in %s line %d"), fname, lnum); } - } else if ((STRCMP(items[0], "REP") == 0 - || STRCMP(items[0], "REPSAL") == 0) + } else if ((strcmp(items[0], "REP") == 0 + || strcmp(items[0], "REPSAL") == 0) && itemcnt >= 3) { // REP/REPSAL item // Myspell ignores extra arguments, we require it starts with @@ -2621,8 +2618,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } } add_fromto(spin, items[0][3] == 'S' - ? &spin->si_repsal - : &spin->si_rep, items[1], items[2]); + ? &spin->si_repsal + : &spin->si_rep, (char_u *)items[1], (char_u *)items[2]); } } else if (is_aff_rule(items, itemcnt, "MAP", 2)) { // MAP item or count @@ -2642,7 +2639,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if ((!GA_EMPTY(&spin->si_map) && vim_strchr(spin->si_map.ga_data, c) != NULL) - || vim_strchr((char *)p, c) != NULL) { + || vim_strchr(p, c) != NULL) { smsg(_("Duplicate character in MAP in %s line %d"), fname, lnum); } @@ -2659,32 +2656,32 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (do_sal) { // SAL item (sounds-a-like) // Either one of the known keys or a from-to pair. - if (STRCMP(items[1], "followup") == 0) { + if (strcmp(items[1], "followup") == 0) { spin->si_followup = sal_to_bool(items[2]); - } else if (STRCMP(items[1], "collapse_result") == 0) { + } else if (strcmp(items[1], "collapse_result") == 0) { spin->si_collapse = sal_to_bool(items[2]); - } else if (STRCMP(items[1], "remove_accents") == 0) { + } else if (strcmp(items[1], "remove_accents") == 0) { spin->si_rem_accents = sal_to_bool(items[2]); } else { // when "to" is "_" it means empty - add_fromto(spin, &spin->si_sal, items[1], - STRCMP(items[2], "_") == 0 ? (char_u *)"" - : items[2]); + add_fromto(spin, &spin->si_sal, (char_u *)items[1], + strcmp(items[2], "_") == 0 ? (char_u *)"" + : (char_u *)items[2]); } } } else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2) && sofofrom == NULL) { - sofofrom = getroom_save(spin, items[1]); + sofofrom = (char_u *)getroom_save(spin, (char_u *)items[1]); } else if (is_aff_rule(items, itemcnt, "SOFOTO", 2) && sofoto == NULL) { - sofoto = getroom_save(spin, items[1]); - } else if (STRCMP(items[0], "COMMON") == 0) { + sofoto = (char_u *)getroom_save(spin, (char_u *)items[1]); + } else if (strcmp(items[0], "COMMON") == 0) { int i; for (i = 1; i < itemcnt; i++) { if (HASHITEM_EMPTY(hash_find(&spin->si_commonwords, (char *)items[i]))) { - p = vim_strsave(items[i]); - hash_add(&spin->si_commonwords, p); + p = xstrdup(items[i]); + hash_add(&spin->si_commonwords, (char_u *)p); } } } else { @@ -2747,7 +2744,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } if (syllable != NULL) { - aff_check_string(spin->si_syllable, syllable, "SYLLABLE"); + aff_check_string((char *)spin->si_syllable, (char *)syllable, "SYLLABLE"); spin->si_syllable = syllable; } @@ -2758,15 +2755,15 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } else if (!GA_EMPTY(&spin->si_sal)) { smsg(_("Both SAL and SOFO lines in %s"), fname); } else { - aff_check_string(spin->si_sofofr, sofofrom, "SOFOFROM"); - aff_check_string(spin->si_sofoto, sofoto, "SOFOTO"); + aff_check_string((char *)spin->si_sofofr, (char *)sofofrom, "SOFOFROM"); + aff_check_string((char *)spin->si_sofoto, (char *)sofoto, "SOFOTO"); spin->si_sofofr = sofofrom; spin->si_sofoto = sofoto; } } if (midword != NULL) { - aff_check_string(spin->si_midword, midword, "MIDWORD"); + aff_check_string((char *)spin->si_midword, (char *)midword, "MIDWORD"); spin->si_midword = midword; } @@ -2775,11 +2772,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) return aff; } -// Returns true when items[0] equals "rulename", there are "mincount" items or -// a comment is following after item "mincount". -static bool is_aff_rule(char_u **items, int itemcnt, char *rulename, int mincount) +/// @return true when items[0] equals "rulename", there are "mincount" items or +/// a comment is following after item "mincount". +static bool is_aff_rule(char **items, int itemcnt, char *rulename, int mincount) { - return STRCMP(items[0], rulename) == 0 + return strcmp(items[0], rulename) == 0 && (itemcnt == mincount || (itemcnt > mincount && items[mincount][0] == '#')); } @@ -2816,15 +2813,15 @@ static void aff_process_flags(afffile_T *affile, affentry_T *entry) } } -// Returns true if "s" is the name of an info item in the affix file. -static bool spell_info_item(char_u *s) +/// @return true if "s" is the name of an info item in the affix file. +static bool spell_info_item(char *s) { - return STRCMP(s, "NAME") == 0 - || STRCMP(s, "HOME") == 0 - || STRCMP(s, "VERSION") == 0 - || STRCMP(s, "AUTHOR") == 0 - || STRCMP(s, "EMAIL") == 0 - || STRCMP(s, "COPYRIGHT") == 0; + return strcmp(s, "NAME") == 0 + || strcmp(s, "HOME") == 0 + || strcmp(s, "VERSION") == 0 + || strcmp(s, "AUTHOR") == 0 + || strcmp(s, "EMAIL") == 0 + || strcmp(s, "COPYRIGHT") == 0; } // Turn an affix flag name into a number, according to the FLAG type. @@ -3016,23 +3013,23 @@ static void aff_check_number(int spinval, int affval, char *name) } } -// Give a warning when "spinval" and "affval" strings are set and not the same. -static void aff_check_string(char_u *spinval, char_u *affval, char *name) +/// Give a warning when "spinval" and "affval" strings are set and not the same. +static void aff_check_string(char *spinval, char *affval, char *name) { - if (spinval != NULL && STRCMP(spinval, affval) != 0) { + if (spinval != NULL && strcmp(spinval, affval) != 0) { smsg(_("%s value differs from what is used in another .aff file"), name); } } -// Returns true if strings "s1" and "s2" are equal. Also consider both being -// NULL as equal. -static bool str_equal(char_u *s1, char_u *s2) +/// @return true if strings "s1" and "s2" are equal. Also consider both being +/// NULL as equal. +static bool str_equal(char *s1, char *s2) { if (s1 == NULL || s2 == NULL) { return s1 == s2; } - return STRCMP(s1, s2) == 0; + return strcmp(s1, s2) == 0; } // Add a from-to item to "gap". Used for REP and SAL items. @@ -3043,15 +3040,15 @@ static void add_fromto(spellinfo_T *spin, garray_T *gap, char_u *from, char_u *t fromto_T *ftp = GA_APPEND_VIA_PTR(fromto_T, gap); (void)spell_casefold(curwin, from, (int)STRLEN(from), word, MAXWLEN); - ftp->ft_from = getroom_save(spin, word); + ftp->ft_from = (char_u *)getroom_save(spin, word); (void)spell_casefold(curwin, to, (int)STRLEN(to), word, MAXWLEN); - ftp->ft_to = getroom_save(spin, word); + ftp->ft_to = (char_u *)getroom_save(spin, word); } -// Converts a boolean argument in a SAL line to true or false; -static bool sal_to_bool(char_u *s) +/// Converts a boolean argument in a SAL line to true or false; +static bool sal_to_bool(char *s) { - return STRCMP(s, "1") == 0 || STRCMP(s, "true") == 0; + return strcmp(s, "1") == 0 || strcmp(s, "true") == 0; } // Free the structure filled by spell_read_aff(). @@ -3068,7 +3065,7 @@ static void spell_free_aff(afffile_T *aff) // All this trouble to free the "ae_prog" items... for (ht = &aff->af_pref;; ht = &aff->af_suff) { todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) { + for (hi = ht->ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; ah = HI2AH(hi); @@ -3125,7 +3122,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) vim_snprintf((char *)IObuff, IOSIZE, _("Reading dictionary file %s..."), fname); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); // start with a message for the first line spin->si_msg_count = 999999; @@ -3157,7 +3154,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) // Convert from "SET" to 'encoding' when needed. if (spin->si_conv.vc_type != CONV_NONE) { - pc = string_convert(&spin->si_conv, line, NULL); + pc = (char_u *)string_convert(&spin->si_conv, (char *)line, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %d: %s"), fname, lnum, line); @@ -3199,7 +3196,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) _("line %6d, word %6ld - %s"), lnum, spin->si_foldwcount + spin->si_keepwcount, w); msg_start(); - msg_outtrans_long_attr(message, 0); + msg_outtrans_long_attr((char *)message, 0); msg_clr_eos(); msg_didout = false; msg_col = 0; @@ -3208,7 +3205,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) } // Store the word in the hashtable to be able to find duplicates. - dw = getroom_save(spin, w); + dw = (char_u *)getroom_save(spin, w); if (dw == NULL) { retval = FAIL; xfree(pc); @@ -3434,7 +3431,7 @@ static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afff int use_condit; todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0 && retval == OK; ++hi) { + for (hi = ht->ht_array; todo > 0 && retval == OK; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; ah = HI2AH(hi); @@ -3540,8 +3537,8 @@ static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afff // Combine the prefix IDs. Avoid adding the // same ID twice. - for (i = 0; i < pfxlen; ++i) { - for (j = 0; j < use_pfxlen; ++j) { + for (i = 0; i < pfxlen; i++) { + for (j = 0; j < use_pfxlen; j++) { if (pfxlist[i] == use_pfxlist[j]) { break; } @@ -3562,9 +3559,8 @@ static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afff // Combine the list of compound flags. // Concatenate them to the prefix IDs list. // Avoid adding the same ID twice. - for (i = pfxlen; pfxlist[i] != NUL; ++i) { - for (j = use_pfxlen; - use_pfxlist[j] != NUL; ++j) { + for (i = pfxlen; pfxlist[i] != NUL; i++) { + for (j = use_pfxlen; use_pfxlist[j] != NUL; j++) { if (pfxlist[i] == use_pfxlist[j]) { break; } @@ -3679,7 +3675,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) } vim_snprintf((char *)IObuff, IOSIZE, _("Reading word file %s..."), fname); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); // Read all the lines in the file one by one. while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int) { @@ -3704,7 +3700,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) // Convert from "/encoding={encoding}" to 'encoding' when needed. xfree(pc); if (spin->si_conv.vc_type != CONV_NONE) { - pc = string_convert(&spin->si_conv, rline, NULL); + pc = (char_u *)string_convert(&spin->si_conv, (char *)rline, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %ld: %s"), fname, lnum, rline); @@ -3726,14 +3722,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) smsg(_("/encoding= line after word ignored in %s line %ld: %s"), fname, lnum, line - 1); } else { - char_u *enc; + char *enc; // Setup for conversion to 'encoding'. line += 9; - enc = enc_canonize(line); + enc = enc_canonize((char *)line); if (!spin->si_ascii - && convert_setup(&spin->si_conv, enc, - p_enc) == FAIL) { + && convert_setup(&spin->si_conv, enc, p_enc) == FAIL) { smsg(_("Conversion in %s not supported: from %s to %s"), fname, line, p_enc); } @@ -3824,7 +3819,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) if (spin->si_ascii && non_ascii > 0) { vim_snprintf((char *)IObuff, IOSIZE, _("Ignored %d words with non-ASCII characters"), non_ascii); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); } return retval; @@ -3858,7 +3853,7 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align) bl->sb_next = spin->si_blocks; spin->si_blocks = bl; bl->sb_used = 0; - ++spin->si_blocks_cnt; + spin->si_blocks_cnt++; } p = bl->sb_data + bl->sb_used; @@ -3867,9 +3862,10 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align) return p; } -// Make a copy of a string into memory allocated with getroom(). -// Returns NULL when out of memory. -static char_u *getroom_save(spellinfo_T *spin, char_u *s) +/// Make a copy of a string into memory allocated with getroom(). +/// +/// @return NULL when out of memory. +static char *getroom_save(spellinfo_T *spin, char_u *s) { const size_t s_size = STRLEN(s) + 1; return memcpy(getroom(spin, s_size, false), s, s_size); @@ -3897,13 +3893,13 @@ static wordnode_T *wordtree_alloc(spellinfo_T *spin) /// Return true if "word" contains valid word characters. /// Control characters and trailing '/' are invalid. Space is OK. -static bool valid_spell_word(const char_u *word, const char_u *end) +static bool valid_spell_word(const char *word, const char *end) { - if (!utf_valid_string(word, end)) { + if (!utf_valid_string((char_u *)word, (char_u *)end)) { return false; } - for (const char_u *p = word; *p != NUL && p < end; p += utfc_ptr2len((const char *)p)) { - if (*p < ' ' || (p[0] == '/' && p[1] == NUL)) { + for (const char *p = word; *p != NUL && p < end; p += utfc_ptr2len(p)) { + if ((uint8_t)(*p) < ' ' || (p[0] == '/' && p[1] == NUL)) { return false; } } @@ -3931,7 +3927,7 @@ static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, co int res = OK; // Avoid adding illegal bytes to the word tree. - if (!valid_spell_word(word, word + len)) { + if (!valid_spell_word((char *)word, (char *)word + len)) { return FAIL; } @@ -3945,7 +3941,7 @@ static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, co break; } } - ++spin->si_foldwcount; + spin->si_foldwcount++; if (res == OK && (ct == WF_KEEPCAP || (flags & WF_KEEPCAP))) { for (const char_u *p = pfxlist; res == OK; p++) { @@ -3957,7 +3953,7 @@ static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, co break; } } - ++spin->si_keepwcount; + spin->si_keepwcount++; } return res; } @@ -3976,12 +3972,12 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int int i; // Add each byte of the word to the tree, including the NUL at the end. - for (i = 0;; ++i) { + for (i = 0;; i++) { // When there is more than one reference to this node we need to make // a copy, so that we can modify it. Copy the whole list of siblings // (we don't optimize for a partly shared list of siblings). if (node != NULL && node->wn_refs > 1) { - --node->wn_refs; + node->wn_refs--; copyprev = prev; for (copyp = node; copyp != NULL; copyp = copyp->wn_sibling) { // Allocate a new node and copy the info. @@ -3991,7 +3987,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int } np->wn_child = copyp->wn_child; if (np->wn_child != NULL) { - ++np->wn_child->wn_refs; // child gets extra ref + np->wn_child->wn_refs++; // child gets extra ref } np->wn_byte = copyp->wn_byte; if (np->wn_byte == NUL) { @@ -4078,7 +4074,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int #endif // count nr of words added since last message - ++spin->si_msg_count; + spin->si_msg_count++; if (spin->si_compress_cnt > 1) { if (--spin->si_compress_cnt == 1) { @@ -4173,7 +4169,7 @@ static int deref_wordnode(spellinfo_T *spin, wordnode_T *node) free_wordnode(spin, np); cnt++; } - ++cnt; // length field + cnt++; // length field } return cnt; } @@ -4185,7 +4181,7 @@ static void free_wordnode(spellinfo_T *spin, wordnode_T *n) { n->wn_child = spin->si_first_free; spin->si_first_free = n; - ++spin->si_free_count; + spin->si_free_count++; } // Compress a tree: find tails that are identical and can be shared. @@ -4216,7 +4212,7 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root, const char *n vim_snprintf((char *)IObuff, IOSIZE, _("Compressed %s of %ld nodes; %ld (%ld%%) remaining"), name, tot, tot - n, perc); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); } #ifdef SPELL_PRINTTREE spell_print_tree(root->wn_sibling); @@ -4264,7 +4260,7 @@ static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, lo // Found one! Now use that child in place of the // current one. This means the current child and all // its siblings is unlinked from the tree. - ++tp->wn_refs; + tp->wn_refs++; compressed += deref_wordnode(spin, child); np->wn_child = tp; break; @@ -4341,23 +4337,24 @@ static bool node_equal(wordnode_T *n1, wordnode_T *n2) return p1 == NULL && p2 == NULL; } -// Function given to qsort() to sort the REP items on "from" string. +/// Function given to qsort() to sort the REP items on "from" string. static int rep_compare(const void *s1, const void *s2) { fromto_T *p1 = (fromto_T *)s1; fromto_T *p2 = (fromto_T *)s2; - return STRCMP(p1->ft_from, p2->ft_from); + return strcmp((char *)p1->ft_from, (char *)p2->ft_from); } -// Write the Vim .spl file "fname". -// Return OK/FAIL. -static int write_vim_spell(spellinfo_T *spin, char_u *fname) +/// Write the Vim .spl file "fname". +/// +/// @return OK/FAIL. +static int write_vim_spell(spellinfo_T *spin, char *fname) { int retval = OK; int regionmask; - FILE *fd = os_fopen((char *)fname, "w"); + FILE *fd = os_fopen(fname, "w"); if (fd == NULL) { semsg(_(e_notopen), fname); return FAIL; @@ -4422,7 +4419,7 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) put_bytes(fd, 1 + 128 + 2 + l, 4); // <sectionlen> fputc(128, fd); // <charflagslen> - for (size_t i = 128; i < 256; ++i) { + for (size_t i = 128; i < 256; i++) { flags = 0; if (spelltab.st_isw[i]) { flags |= CF_WORD; @@ -4466,7 +4463,7 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) // round 1: SN_REP section // round 2: SN_SAL section (unless SN_SOFO is used) // round 3: SN_REPSAL section - for (unsigned int round = 1; round <= 3; ++round) { + for (unsigned int round = 1; round <= 3; round++) { garray_T *gap; if (round == 1) { gap = &spin->si_rep; @@ -4500,13 +4497,13 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) // Compute the length of what follows. size_t l = 2; // count <repcount> or <salcount> assert(gap->ga_len >= 0); - for (size_t i = 0; i < (size_t)gap->ga_len; ++i) { + for (size_t i = 0; i < (size_t)gap->ga_len; i++) { fromto_T *ftp = &((fromto_T *)gap->ga_data)[i]; l += 1 + STRLEN(ftp->ft_from); // count <*fromlen> and <*from> l += 1 + STRLEN(ftp->ft_to); // count <*tolen> and <*to> } if (round == 2) { - ++l; // count <salflags> + l++; // count <salflags> } put_bytes(fd, l, 4); // <sectionlen> @@ -4525,11 +4522,11 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) } put_bytes(fd, (uintmax_t)gap->ga_len, 2); // <repcount> or <salcount> - for (size_t i = 0; i < (size_t)gap->ga_len; ++i) { + for (size_t i = 0; i < (size_t)gap->ga_len; i++) { // <rep> : <repfromlen> <repfrom> <reptolen> <repto> // <sal> : <salfromlen> <salfrom> <saltolen> <salto> fromto_T *ftp = &((fromto_T *)gap->ga_data)[i]; - for (unsigned int rr = 1; rr <= 2; ++rr) { + for (unsigned int rr = 1; rr <= 2; rr++) { char_u *p = rr == 1 ? ftp->ft_from : ftp->ft_to; l = STRLEN(p); assert(l < INT_MAX); @@ -4566,13 +4563,13 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) // round 1: count the bytes // round 2: write the bytes - for (unsigned int round = 1; round <= 2; ++round) { + for (unsigned int round = 1; round <= 2; round++) { size_t todo; size_t len = 0; hashitem_T *hi; todo = spin->si_commonwords.ht_used; - for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi) { + for (hi = spin->si_commonwords.ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { size_t l = STRLEN(hi->hi_key) + 1; len += l; @@ -4643,7 +4640,7 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) size_t l = STRLEN(spin->si_compflags); assert(spin->si_comppat.ga_len >= 0); for (size_t i = 0; i < (size_t)spin->si_comppat.ga_len; i++) { - l += STRLEN(((char **)(spin->si_comppat.ga_data))[i]) + 1; + l += strlen(((char **)(spin->si_comppat.ga_data))[i]) + 1; } put_bytes(fd, l + 7, 4); // <sectionlen> @@ -4655,9 +4652,9 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) put_bytes(fd, (uintmax_t)spin->si_comppat.ga_len, 2); // <comppatcount> for (size_t i = 0; i < (size_t)spin->si_comppat.ga_len; i++) { char *p = ((char **)(spin->si_comppat.ga_data))[i]; - assert(STRLEN(p) < INT_MAX); - putc((int)STRLEN(p), fd); // <comppatlen> - fwv &= fwrite(p, STRLEN(p), 1, fd); // <comppattext> + assert(strlen(p) < INT_MAX); + putc((int)strlen(p), fd); // <comppatlen> + fwv &= fwrite(p, strlen(p), 1, fd); // <comppattext> } // <compflags> fwv &= fwrite(spin->si_compflags, STRLEN(spin->si_compflags), 1, fd); @@ -4689,7 +4686,7 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname) // <LWORDTREE> <KWORDTREE> <PREFIXTREE> spin->si_memtot = 0; - for (unsigned int round = 1; round <= 3; ++round) { + for (unsigned int round = 1; round <= 3; round++) { wordnode_T *tree; if (round == 1) { tree = spin->si_foldroot->wn_sibling; @@ -4878,12 +4875,12 @@ void ex_mkspell(exarg_T *eap) { int fcount; char **fnames; - char_u *arg = (char_u *)eap->arg; + char *arg = eap->arg; bool ascii = false; if (STRNCMP(arg, "-ascii", 6) == 0) { ascii = true; - arg = (char_u *)skipwhite((char *)arg + 6); + arg = skipwhite(arg + 6); } // Expand all the remaining arguments (e.g., $VIMRUNTIME). @@ -4896,7 +4893,7 @@ void ex_mkspell(exarg_T *eap) // Create the .sug file. // Uses the soundfold info in "spin". // Writes the file with the name "wfname", with ".spl" changed to ".sug". -static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname) +static void spell_make_sugfile(spellinfo_T *spin, char *wfname) { char_u *fname = NULL; int len; @@ -4909,13 +4906,13 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname) // of the code for the soundfolding stuff. // It might have been done already by spell_reload_one(). for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)wfname, (char *)slang->sl_fname, false, true) + if (path_full_compare(wfname, slang->sl_fname, false, true) == kEqualFiles) { break; } } if (slang == NULL) { - spell_message(spin, (char_u *)_("Reading back spell file...")); + spell_message(spin, _("Reading back spell file...")); slang = spell_load_file(wfname, NULL, NULL, false); if (slang == NULL) { return; @@ -4933,7 +4930,7 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname) // Go through the trie of good words, soundfold each word and add it to // the soundfold trie. - spell_message(spin, (char_u *)_("Performing soundfolding...")); + spell_message(spin, _("Performing soundfolding...")); if (sug_filltree(spin, slang) == FAIL) { goto theend; } @@ -4950,7 +4947,7 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname) (int64_t)spin->si_spellbuf->b_ml.ml_line_count); // Compress the soundfold trie. - spell_message(spin, (char_u *)_(msg_compressing)); + spell_message(spin, _(msg_compressing)); wordtree_compress(spin, spin->si_foldroot, "case-folded"); // Write the .sug file. @@ -5015,7 +5012,7 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang) } else { // Do one more byte at this node. n = arridx[depth] + curi[depth]; - ++curi[depth]; + curi[depth]++; c = byts[n]; if (c == 0) { @@ -5196,7 +5193,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname) vim_snprintf((char *)IObuff, IOSIZE, _("Writing suggestion file %s..."), fname); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); // <SUGHEADER>: <fileID> <versionnr> <timestamp> if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) { // <fileID> @@ -5233,9 +5230,9 @@ static void sug_write(spellinfo_T *spin, char_u *fname) assert(wcount >= 0); put_bytes(fd, (uintmax_t)wcount, 4); // <sugwcount> - for (linenr_T lnum = 1; lnum <= wcount; ++lnum) { + for (linenr_T lnum = 1; lnum <= wcount; lnum++) { // <sugline>: <sugnr> ... NUL - char_u *line = ml_get_buf(spin->si_spellbuf, lnum, false); + char_u *line = (char_u *)ml_get_buf(spin->si_spellbuf, lnum, false); size_t len = STRLEN(line) + 1; if (fwrite(line, len, 1, fd) == 0) { emsg(_(e_write)); @@ -5252,7 +5249,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname) vim_snprintf((char *)IObuff, IOSIZE, _("Estimated runtime memory use: %d bytes"), spin->si_memtot); - spell_message(spin, IObuff); + spell_message(spin, (char *)IObuff); theend: // close the file @@ -5271,7 +5268,6 @@ theend: static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool added_word) { char_u *fname = NULL; - char_u *wfname; char **innames; int incount; afffile_T *(afile[MAXREGIONS]); @@ -5299,43 +5295,43 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool innames = &fnames[fcount == 1 ? 0 : 1]; incount = fcount - 1; - wfname = xmalloc(MAXPATHL); + char *wfname = xmalloc(MAXPATHL); if (fcount >= 1) { len = (int)STRLEN(fnames[0]); - if (fcount == 1 && len > 4 && STRCMP(fnames[0] + len - 4, ".add") == 0) { + if (fcount == 1 && len > 4 && strcmp(fnames[0] + len - 4, ".add") == 0) { // For ":mkspell path/en.latin1.add" output file is // "path/en.latin1.add.spl". incount = 1; - vim_snprintf((char *)wfname, MAXPATHL, "%s.spl", fnames[0]); + vim_snprintf(wfname, MAXPATHL, "%s.spl", fnames[0]); } else if (fcount == 1) { // For ":mkspell path/vim" output file is "path/vim.latin1.spl". incount = 1; - vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL, + vim_snprintf(wfname, MAXPATHL, SPL_FNAME_TMPL, fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc()); - } else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) { + } else if (len > 4 && strcmp(fnames[0] + len - 4, ".spl") == 0) { // Name ends in ".spl", use as the file name. STRLCPY(wfname, fnames[0], MAXPATHL); } else { // Name should be language, make the file name from it. - vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL, + vim_snprintf(wfname, MAXPATHL, SPL_FNAME_TMPL, fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc()); } // Check for .ascii.spl. - if (strstr(path_tail((char *)wfname), SPL_FNAME_ASCII) != NULL) { + if (strstr(path_tail(wfname), SPL_FNAME_ASCII) != NULL) { spin.si_ascii = true; } // Check for .add.spl. - if (strstr(path_tail((char *)wfname), SPL_FNAME_ADD) != NULL) { + if (strstr(path_tail(wfname), SPL_FNAME_ADD) != NULL) { spin.si_add = true; } } if (incount <= 0) { emsg(_(e_invarg)); // need at least output and input names - } else if (vim_strchr(path_tail((char *)wfname), '_') != NULL) { + } else if (vim_strchr(path_tail(wfname), '_') != NULL) { emsg(_("E751: Output file name must not have region name")); } else if (incount > MAXREGIONS) { semsg(_("E754: Only up to %d regions supported"), MAXREGIONS); @@ -5355,12 +5351,12 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool // Init the aff and dic pointers. // Get the region names if there are more than 2 arguments. - for (i = 0; i < incount; ++i) { + for (i = 0; i < incount; i++) { afile[i] = NULL; if (incount > 1) { - len = (int)STRLEN(innames[i]); - if (STRLEN(path_tail((char *)innames[i])) < 5 + len = (int)strlen(innames[i]); + if (strlen(path_tail(innames[i])) < 5 || innames[i][len - 3] != '_') { semsg(_("E755: Invalid region in %s"), innames[i]); goto theend; @@ -5387,12 +5383,12 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool // Read all the .aff and .dic files. // Text is converted to 'encoding'. // Words are stored in the case-folded and keep-case trees. - for (i = 0; i < incount && !error; ++i) { + for (i = 0; i < incount && !error; i++) { spin.si_conv.vc_type = CONV_NONE; spin.si_region = 1 << i; vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[i]); - if (os_path_exists(fname)) { + if (os_path_exists((char *)fname)) { // Read the .aff file. Will init "spin->si_conv" based on the // "SET" line. afile[i] = spell_read_aff(&spin, fname); @@ -5424,7 +5420,7 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool if (!error && !got_int) { // Combine tails in the tree. - spell_message(&spin, (char_u *)_(msg_compressing)); + spell_message(&spin, _(msg_compressing)); wordtree_compress(&spin, spin.si_foldroot, "case-folded"); wordtree_compress(&spin, spin.si_keeproot, "keep-case"); wordtree_compress(&spin, spin.si_prefroot, "prefixes"); @@ -5434,18 +5430,18 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool // Write the info in the spell file. vim_snprintf((char *)IObuff, IOSIZE, _("Writing spell file %s..."), wfname); - spell_message(&spin, IObuff); + spell_message(&spin, (char *)IObuff); error = write_vim_spell(&spin, wfname) == FAIL; - spell_message(&spin, (char_u *)_("Done!")); + spell_message(&spin, _("Done!")); vim_snprintf((char *)IObuff, IOSIZE, _("Estimated runtime memory use: %d bytes"), spin.si_memtot); - spell_message(&spin, IObuff); + spell_message(&spin, (char *)IObuff); // If the file is loaded need to reload it. if (!error) { - spell_reload_one(wfname, added_word); + spell_reload_one((char_u *)wfname, added_word); } } @@ -5459,7 +5455,7 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool hash_clear_all(&spin.si_commonwords, 0); // Free the .aff file structures. - for (i = 0; i < incount; ++i) { + for (i = 0; i < incount; i++) { if (afile[i] != NULL) { spell_free_aff(afile[i]); } @@ -5482,14 +5478,14 @@ theend: // Display a message for spell file processing when 'verbose' is set or using // ":mkspell". "str" can be IObuff. -static void spell_message(const spellinfo_T *spin, char_u *str) +static void spell_message(const spellinfo_T *spin, char *str) FUNC_ATTR_NONNULL_ALL { if (spin->si_verbose || p_verbose > 2) { if (!spin->si_verbose) { verbose_enter(); } - msg((char *)str); + msg(str); ui_flush(); if (!spin->si_verbose) { verbose_leave(); @@ -5503,7 +5499,7 @@ static void spell_message(const spellinfo_T *spin, char_u *str) // ":[count]spellrare {word}" void ex_spell(exarg_T *eap) { - spell_add_word((char_u *)eap->arg, (int)STRLEN(eap->arg), + spell_add_word((char_u *)eap->arg, (int)strlen(eap->arg), eap->cmdidx == CMD_spellwrong ? SPELL_ADD_BAD : eap->cmdidx == CMD_spellrare ? SPELL_ADD_RARE : SPELL_ADD_GOOD, eap->forceit ? 0 : (int)eap->line2, @@ -5527,14 +5523,14 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo int i; char_u *spf; - if (!valid_spell_word(word, word + len)) { + if (!valid_spell_word((char *)word, (char *)word + len)) { emsg(_(e_illegal_character_in_word)); return; } if (idx == 0) { // use internal wordlist if (int_wordlist == NULL) { - int_wordlist = vim_tempname(); + int_wordlist = (char_u *)vim_tempname(); if (int_wordlist == NULL) { return; } @@ -5553,7 +5549,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo } fnamebuf = xmalloc(MAXPATHL); - for (spf = curwin->w_s->b_p_spf, i = 1; *spf != NUL; i++) { + for (spf = (char_u *)curwin->w_s->b_p_spf, i = 1; *spf != NUL; i++) { copy_option_part((char **)&spf, (char *)fnamebuf, MAXPATHL, ","); if (i == idx) { break; @@ -5667,7 +5663,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo buf_reload(buf, buf->b_orig_mode, false); } - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } xfree(fnamebuf); } @@ -5681,14 +5677,14 @@ static void init_spellfile(void) char_u *rtp; char_u *lend; bool aspath = false; - char_u *lstart = curbuf->b_s.b_p_spl; + char_u *lstart = (char_u *)curbuf->b_s.b_p_spl; if (*curwin->w_s->b_p_spl != NUL && !GA_EMPTY(&curwin->w_s->b_langp)) { buf = xmalloc(MAXPATHL); // Find the end of the language name. Exclude the region. If there // is a path separator remember the start of the tail. - for (lend = curwin->w_s->b_p_spl; *lend != NUL + for (lend = (char_u *)curwin->w_s->b_p_spl; *lend != NUL && vim_strchr(",._", *lend) == NULL; lend++) { if (vim_ispathsep(*lend)) { aspath = true; @@ -5698,13 +5694,12 @@ static void init_spellfile(void) // Loop over all entries in 'runtimepath'. Use the first one where we // are allowed to write. - rtp = p_rtp; + rtp = (char_u *)p_rtp; while (*rtp != NUL) { if (aspath) { // Use directory of an entry with path, e.g., for // "/dir/lg.utf-8.spl" use "/dir". - STRLCPY(buf, curbuf->b_s.b_p_spl, - lstart - curbuf->b_s.b_p_spl); + STRLCPY(buf, curbuf->b_s.b_p_spl, lstart - (char_u *)curbuf->b_s.b_p_spl); } else { // Copy the path from 'runtimepath' to buf[]. copy_option_part((char **)&rtp, (char *)buf, MAXPATHL, ","); @@ -5713,8 +5708,7 @@ static void init_spellfile(void) // Use the first language name from 'spelllang' and the // encoding used in the first loaded .spl file. if (aspath) { - STRLCPY(buf, curbuf->b_s.b_p_spl, - lend - curbuf->b_s.b_p_spl + 1); + STRLCPY(buf, curbuf->b_s.b_p_spl, lend - (char_u *)curbuf->b_s.b_p_spl + 1); } else { // Create the "spell" directory if it doesn't exist yet. l = (int)STRLEN(buf); @@ -5728,14 +5722,14 @@ static void init_spellfile(void) "/%.*s", (int)(lend - lstart), lstart); } l = (int)STRLEN(buf); - fname = LANGP_ENTRY(curwin->w_s->b_langp, 0) + fname = (char_u *)LANGP_ENTRY(curwin->w_s->b_langp, 0) ->lp_slang->sl_fname; vim_snprintf((char *)buf + l, MAXPATHL - (size_t)l, ".%s.add", ((fname != NULL && strstr(path_tail((char *)fname), ".ascii.") != NULL) ? "ascii" : (const char *)spell_enc())); - set_option_value("spellfile", 0L, (const char *)buf, OPT_LOCAL); + set_option_value_give_err("spellfile", 0L, (const char *)buf, OPT_LOCAL); break; } aspath = false; @@ -5759,7 +5753,7 @@ static void set_spell_charflags(char_u *flags, int cnt, char_u *fol) clear_spell_chartab(&new_st); - for (i = 0; i < 128; ++i) { + for (i = 0; i < 128; i++) { if (i < cnt) { new_st.st_isw[i + 128] = (flags[i] & CF_WORD) != 0; new_st.st_isu[i + 128] = (flags[i] & CF_UPPER) != 0; @@ -5783,7 +5777,7 @@ static int set_spell_finish(spelltab_T *new_st) if (did_set_spelltab) { // check that it's the same table - for (i = 0; i < 256; ++i) { + for (i = 0; i < 256; i++) { if (spelltab.st_isw[i] != new_st->st_isw[i] || spelltab.st_isu[i] != new_st->st_isu[i] || spelltab.st_fold[i] != new_st->st_fold[i] @@ -5815,7 +5809,7 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap, size_t *fwv) // <prefcond> : <condlen> <condstr> char *p = ((char **)gap->ga_data)[i]; if (p != NULL) { - size_t len = STRLEN(p); + size_t len = strlen(p); if (fd != NULL) { assert(len <= INT_MAX); fputc((int)len, fd); @@ -5846,7 +5840,7 @@ static void set_map_str(slang_T *lp, char_u *map) lp->sl_has_map = true; // Init the array and hash tables empty. - for (i = 0; i < 256; ++i) { + for (i = 0; i < 256; i++) { lp->sl_map_array[i] = 0; } hash_init(&lp->sl_map_hash); @@ -5878,7 +5872,7 @@ static void set_map_str(slang_T *lp, char_u *map) utf_char2bytes(headc, b + cl + 1); b[cl + 1 + headcl] = NUL; hash = hash_hash((char_u *)b); - hi = hash_lookup(&lp->sl_map_hash, (const char *)b, STRLEN(b), hash); + hi = hash_lookup(&lp->sl_map_hash, (const char *)b, strlen(b), hash); if (HASHITEM_EMPTY(hi)) { hash_add_item(&lp->sl_map_hash, hi, (char_u *)b, hash); } else { diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index b4a9bed437..f2a0da188e 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -65,8 +65,8 @@ typedef struct suginfo_S { /// One word suggestion. Used in "si_ga". typedef struct { - char_u *st_word; ///< suggested word, allocated string - int st_wordlen; ///< STRLEN(st_word) + char *st_word; ///< suggested word, allocated string + int st_wordlen; ///< strlen(st_word) int st_orglen; ///< length of replaced text int st_score; ///< lower is better int st_altscore; ///< used when st_score compares equal @@ -354,13 +354,13 @@ int spell_check_sps(void) { char *p; char *s; - char_u buf[MAXPATHL]; + char buf[MAXPATHL]; int f; sps_flags = 0; sps_limit = 9999; - for (p = (char *)p_sps; *p != NUL;) { + for (p = p_sps; *p != NUL;) { copy_option_part(&p, (char *)buf, MAXPATHL, ","); f = 0; @@ -370,11 +370,11 @@ int spell_check_sps(void) if (*s != NUL && !ascii_isdigit(*s)) { f = -1; } - } else if (STRCMP(buf, "best") == 0) { + } else if (strcmp(buf, "best") == 0) { f = SPS_BEST; - } else if (STRCMP(buf, "fast") == 0) { + } else if (strcmp(buf, "fast") == 0) { f = SPS_FAST; - } else if (STRCMP(buf, "double") == 0) { + } else if (strcmp(buf, "double") == 0) { f = SPS_DOUBLE; } else if (STRNCMP(buf, "expr:", 5) != 0 && STRNCMP(buf, "file:", 5) != 0 @@ -407,7 +407,7 @@ int spell_check_sps(void) /// When "count" is non-zero use that suggestion. void spell_suggest(int count) { - char_u *line; + char *line; pos_T prev_cursor = curwin->w_cursor; char_u wcopy[MAXWLEN + 2]; char_u *p; @@ -454,9 +454,9 @@ void spell_suggest(int count) // cursor. curwin->w_cursor = prev_cursor; line = get_cursor_line_ptr(); - p = line + curwin->w_cursor.col; + p = (char_u *)line + curwin->w_cursor.col; // Backup to before start of word. - while (p > line && spell_iswordp_nmw(p, curwin)) { + while (p > (char_u *)line && spell_iswordp_nmw(p, curwin)) { MB_PTR_BACK(line, p); } // Forward to start of word. @@ -468,7 +468,7 @@ void spell_suggest(int count) beep_flush(); return; } - curwin->w_cursor.col = (colnr_T)(p - line); + curwin->w_cursor.col = (colnr_T)(p - (char_u *)line); } // Get the word and its length. @@ -477,7 +477,7 @@ void spell_suggest(int count) need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col); // Make a copy of current line since autocommands may free the line. - line = vim_strsave(get_cursor_line_ptr()); + line = xstrdup(get_cursor_line_ptr()); spell_suggest_timeout = 5000; // Get the list of suggestions. Limit to 'lines' - 2 or the number in @@ -487,7 +487,7 @@ void spell_suggest(int count) } else { limit = sps_limit; } - spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit, + spell_find_suggest((char_u *)line + curwin->w_cursor.col, badlen, &sug, limit, true, need_cap, true); if (GA_EMPTY(&sug.su_ga)) { @@ -533,7 +533,7 @@ void spell_suggest(int count) } vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1); if (cmdmsg_rl) { - rl_mirror(IObuff); + rl_mirror((char_u *)IObuff); } msg_puts((const char *)IObuff); @@ -559,7 +559,7 @@ void spell_suggest(int count) } if (cmdmsg_rl) { // Mirror the numbers, but keep the leading space. - rl_mirror(IObuff + 1); + rl_mirror((char_u *)IObuff + 1); } msg_advance(30); msg_puts((const char *)IObuff); @@ -593,20 +593,20 @@ 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, (size_t)sug.su_badlen); + repl_from = xstrnsave((char *)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); + repl_to = xstrdup((char *)IObuff); } else { // Replacing su_badlen or more, use the whole word. - repl_from = vim_strnsave(sug.su_badptr, (size_t)stp->st_orglen); - repl_to = vim_strsave(stp->st_word); + repl_from = xstrnsave((char *)sug.su_badptr, (size_t)stp->st_orglen); + repl_to = xstrdup(stp->st_word); } // Replace the word. p = xmalloc(STRLEN(line) - (size_t)stp->st_orglen + (size_t)stp->st_wordlen + 1); - c = (int)(sug.su_badptr - line); + c = (int)(sug.su_badptr - (char_u *)line); memmove(p, line, (size_t)c); STRCPY(p + c, stp->st_word); STRCAT(p, sug.su_badptr + stp->st_orglen); @@ -678,7 +678,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma char_u buf[MAXPATHL]; char *p; bool do_combine = false; - char_u *sps_copy; + char *sps_copy; static bool expr_busy = false; int c; langp_T *lp; @@ -748,7 +748,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma c = utf_ptr2char((char *)su->su_badptr); if (!SPELL_ISUPPER(c) && attr == HLF_COUNT) { make_case_word(su->su_badword, buf, WF_ONECAP); - add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE, + add_suggestion(su, &su->su_ga, (char *)buf, su->su_badlen, SCORE_ICASE, 0, true, su->su_sallang, false); } @@ -758,10 +758,10 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma } // Make a copy of 'spellsuggest', because the expression may change it. - sps_copy = vim_strsave(p_sps); + sps_copy = xstrdup(p_sps); // Loop over the items in 'spellsuggest'. - for (p = (char *)sps_copy; *p != NUL;) { + for (p = sps_copy; *p != NUL;) { copy_option_part(&p, (char *)buf, MAXPATHL, ","); if (STRNCMP(buf, "expr:", 5) == 0) { @@ -814,7 +814,7 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr) // Get the word and the score from the items. score = get_spellword(TV_LIST_ITEM_TV(li)->vval.v_list, &p); if (score >= 0 && score <= su->su_maxscore) { - add_suggestion(su, &su->su_ga, (const char_u *)p, su->su_badlen, + add_suggestion(su, &su->su_ga, p, su->su_badlen, score, 0, true, su->su_sallang, false); } } @@ -864,7 +864,7 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname) p = cword; } - add_suggestion(su, &su->su_ga, p, su->su_badlen, + add_suggestion(su, &su->su_ga, (char *)p, su->su_badlen, SCORE_FILE, 0, true, su->su_sallang, false); } } @@ -972,7 +972,7 @@ static void suggest_try_special(suginfo_T *su) char_u word[MAXWLEN]; // Recognize a word that is repeated: "the the". - char_u *p = skiptowhite(su->su_fbadword); + char_u *p = (char_u *)skiptowhite((char *)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) { @@ -985,7 +985,7 @@ static void suggest_try_special(suginfo_T *su) // Give a soundalike score of 0, compute the score as if deleting one // character. - add_suggestion(su, &su->su_ga, word, su->su_badlen, + add_suggestion(su, &su->su_ga, (char *)word, su->su_badlen, RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false); } } @@ -1114,7 +1114,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so { char_u tword[MAXWLEN]; // good word collected so far trystate_T stack[MAXWLEN]; - char_u preword[MAXWLEN * 3] = { 0 }; // word found with proper case; + char preword[MAXWLEN * 3] = { 0 }; // word found with proper case; // concatenation of prefix compound // words and split word. NUL terminated // when going deeper but not when coming @@ -1241,7 +1241,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // and make find_keepcap_word() works. tword[sp->ts_twordlen] = NUL; make_case_word(tword + sp->ts_splitoff, - preword + sp->ts_prewordlen, flags); + (char_u *)preword + sp->ts_prewordlen, flags); sp->ts_prewordlen = (char_u)STRLEN(preword); sp->ts_splitoff = sp->ts_twordlen; } @@ -1326,11 +1326,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_fidx - sp->ts_splitfidx) == 0) { preword[sp->ts_prewordlen] = NUL; newscore = score_wordcount_adj(slang, sp->ts_score, - preword + sp->ts_prewordlen, + (char_u *)preword + sp->ts_prewordlen, sp->ts_prewordlen > 0); // Add the suggestion if the score isn't too bad. if (newscore <= su->su_maxscore) { - add_suggestion(su, &su->su_ga, preword, + add_suggestion(su, &su->su_ga, (char *)preword, sp->ts_splitfidx - repextra, newscore, 0, false, lp->lp_sallang, false); @@ -1362,15 +1362,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_twordlen - sp->ts_splitoff + 1); // Verify CHECKCOMPOUNDPATTERN rules. - if (match_checkcompoundpattern(preword, sp->ts_prewordlen, + if (match_checkcompoundpattern((char_u *)preword, sp->ts_prewordlen, &slang->sl_comppat)) { compound_ok = false; } if (compound_ok) { - p = preword; - while (*skiptowhite(p) != NUL) { - p = (char_u *)skipwhite((char *)skiptowhite(p)); + p = (char_u *)preword; + while (*skiptowhite((char *)p) != NUL) { + p = (char_u *)skipwhite(skiptowhite((char *)p)); } if (fword_ends && !can_compound(slang, p, compflags + sp->ts_compsplit)) { @@ -1381,7 +1381,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } // Get pointer to last char of previous word. - p = preword + sp->ts_prewordlen; + p = (char_u *)preword + sp->ts_prewordlen; MB_PTR_BACK(preword, p); } } @@ -1394,7 +1394,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } else if (flags & WF_KEEPCAP) { // Must find the word in the keep-case tree. find_keepcap_word(slang, tword + sp->ts_splitoff, - preword + sp->ts_prewordlen); + (char_u *)preword + sp->ts_prewordlen); } else { // Include badflags: If the badword is onecap or allcap // use that for the goodword too. But if the badword is @@ -1413,14 +1413,14 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so c &= ~WF_ONECAP; } make_case_word(tword + sp->ts_splitoff, - preword + sp->ts_prewordlen, c); + (char_u *)preword + sp->ts_prewordlen, c); } if (!soundfold) { // Don't use a banned word. It may appear again as a good // word, thus remember it. if (flags & WF_BANNED) { - add_banned(su, preword + sp->ts_prewordlen); + add_banned(su, (char_u *)preword + sp->ts_prewordlen); break; } if ((sp->ts_complen == sp->ts_compsplit @@ -1445,7 +1445,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } if (!spell_valid_case(su->su_badflags, - captype(preword + sp->ts_prewordlen, NULL))) { + captype((char_u *)preword + sp->ts_prewordlen, NULL))) { newscore += SCORE_ICASE; } } @@ -1457,7 +1457,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so && compound_ok) { // The badword also ends: add suggestions. #ifdef DEBUG_TRIEWALK - if (soundfold && STRCMP(preword, "smwrd") == 0) { + if (soundfold && strcmp(preword, "smwrd") == 0) { int j; // print the stack of changes that brought us here @@ -1470,14 +1470,14 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (soundfold) { // For soundfolded words we need to find the original // words, the edit distance and then add them. - add_sound_suggest(su, preword, sp->ts_score, lp); + add_sound_suggest(su, (char_u *)preword, sp->ts_score, lp); } else if (sp->ts_fidx > 0) { // Give a penalty when changing non-word char to word // char, e.g., "thes," -> "these". p = fword + sp->ts_fidx; MB_PTR_BACK(fword, p); if (!spell_iswordp(p, curwin) && *preword != NUL) { - p = preword + STRLEN(preword); + p = (char_u *)preword + STRLEN(preword); MB_PTR_BACK(preword, p); if (spell_iswordp(p, curwin)) { newscore += SCORE_NONWORD; @@ -1487,25 +1487,25 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Give a bonus to words seen before. score = score_wordcount_adj(slang, sp->ts_score + newscore, - preword + sp->ts_prewordlen, + (char_u *)preword + sp->ts_prewordlen, sp->ts_prewordlen > 0); // Add the suggestion if the score isn't too bad. if (score <= su->su_maxscore) { - add_suggestion(su, &su->su_ga, preword, + add_suggestion(su, &su->su_ga, (char *)preword, sp->ts_fidx - repextra, score, 0, false, lp->lp_sallang, false); if (su->su_badflags & WF_MIXCAP) { // We really don't know if the word should be // upper or lower case, add both. - c = captype(preword, NULL); + c = captype((char_u *)preword, NULL); if (c == 0 || c == WF_ALLCAP) { make_case_word(tword + sp->ts_splitoff, - preword + sp->ts_prewordlen, + (char_u *)preword + sp->ts_prewordlen, c == 0 ? WF_ALLCAP : 0); - add_suggestion(su, &su->su_ga, preword, + add_suggestion(su, &su->su_ga, (char *)preword, sp->ts_fidx - repextra, score + SCORE_ICASE, 0, false, lp->lp_sallang, false); @@ -1589,9 +1589,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so && (flags & WF_NEEDCOMP)) { break; } - p = preword; - while (*skiptowhite(p) != NUL) { - p = (char_u *)skipwhite((char *)skiptowhite(p)); + p = (char_u *)preword; + while (*skiptowhite((char *)p) != NUL) { + p = (char_u *)skipwhite(skiptowhite((char *)p)); } if (sp->ts_complen > sp->ts_compsplit && !can_compound(slang, p, @@ -1607,7 +1607,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Give a bonus to words seen before. newscore = score_wordcount_adj(slang, newscore, - preword + sp->ts_prewordlen, true); + (char_u *)preword + sp->ts_prewordlen, true); } if (TRY_DEEPER(su, stack, depth, newscore)) { @@ -1633,7 +1633,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (!try_compound && !fword_ends) { STRCAT(preword, " "); } - sp->ts_prewordlen = (char_u)STRLEN(preword); + sp->ts_prewordlen = (char_u)strlen(preword); sp->ts_splitoff = sp->ts_twordlen; sp->ts_splitfidx = sp->ts_fidx; @@ -2494,7 +2494,7 @@ static void score_comp_sal(suginfo_T *su) if (score < SCORE_MAXMAX) { // Add the suggestion. sstp = &SUG(su->su_sga, su->su_sga.ga_len); - sstp->st_word = vim_strsave(stp->st_word); + sstp->st_word = xstrdup(stp->st_word); sstp->st_wordlen = stp->st_wordlen; sstp->st_score = score; sstp->st_altscore = 0; @@ -2515,8 +2515,8 @@ static void score_combine(suginfo_T *su) garray_T *gap; langp_T *lp; suggest_T *stp; - char_u *p; - char_u badsound[MAXWLEN]; + char *p; + char badsound[MAXWLEN]; int round; slang_T *slang = NULL; @@ -2526,11 +2526,11 @@ static void score_combine(suginfo_T *su) if (!GA_EMPTY(&lp->lp_slang->sl_sal)) { // soundfold the bad word slang = lp->lp_slang; - spell_soundfold(slang, su->su_fbadword, true, badsound); + spell_soundfold(slang, su->su_fbadword, true, (char_u *)badsound); for (int i = 0; i < su->su_ga.ga_len; i++) { stp = &SUG(su->su_ga, i); - stp->st_altscore = stp_sal_score(stp, su, slang, badsound); + stp->st_altscore = stp_sal_score(stp, su, slang, (char_u *)badsound); if (stp->st_altscore == SCORE_MAXMAX) { stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4; } else { @@ -2551,8 +2551,7 @@ static void score_combine(suginfo_T *su) // Add the alternate score to su_sga. for (int i = 0; i < su->su_sga.ga_len; i++) { stp = &SUG(su->su_sga, i); - stp->st_altscore = spell_edit_score(slang, - su->su_badword, stp->st_word); + stp->st_altscore = spell_edit_score(slang, su->su_badword, (char_u *)stp->st_word); if (stp->st_score == SCORE_MAXMAX) { stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8; } else { @@ -2582,7 +2581,7 @@ static void score_combine(suginfo_T *su) p = SUG(*gap, i).st_word; int j; for (j = 0; j < ga.ga_len; j++) { - if (STRCMP(stp[j].st_word, p) == 0) { + if (strcmp(stp[j].st_word, p) == 0) { break; } } @@ -2637,7 +2636,7 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * // space. if (ascii_iswhite(su->su_badptr[su->su_badlen]) && *skiptowhite(stp->st_word) == NUL) { - for (p = fword; *(p = skiptowhite(p)) != NUL;) { + for (p = fword; *(p = (char_u *)skiptowhite((char *)p)) != NUL;) { STRMOVE(p, p + 1); } } @@ -2654,13 +2653,13 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * su->su_badptr + su->su_badlen - lendiff, lendiff + 1); pgood = goodword; } else { - pgood = stp->st_word; + pgood = (char_u *)stp->st_word; } // Sound-fold the word and compute the score for the difference. spell_soundfold(slang, pgood, false, goodsound); - return soundalike_score(goodsound, pbad); + return soundalike_score((char *)goodsound, (char *)pbad); } /// structure used to store soundfolded words that add_sound_suggest() has @@ -2807,7 +2806,7 @@ static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_ } // Go over the list of good words that produce this soundfold word - nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false); + nrline = (char_u *)ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false); orgnr = 0; while (*nrline != NUL) { // The wordnr was stored in a minimal nr of bytes as an offset to the @@ -2883,7 +2882,7 @@ badword: if (sps_flags & SPS_DOUBLE) { // Add the suggestion if the score isn't too bad. if (score <= su->su_maxscore) { - add_suggestion(su, &su->su_sga, p, su->su_badlen, + add_suggestion(su, &su->su_sga, (char *)p, su->su_badlen, score, 0, false, slang, false); } } else { @@ -2931,7 +2930,7 @@ badword: // Add the suggestion if the score isn't too bad. goodscore = RESCORE(goodscore, score); if (goodscore <= su->su_sfmaxscore) { - add_suggestion(su, &su->su_ga, p, su->su_badlen, + add_suggestion(su, &su->su_ga, (char *)p, su->su_badlen, goodscore, score, true, slang, true); } } @@ -3061,7 +3060,7 @@ static bool similar_chars(slang_T *slang, int c1, int c2) /// @param had_bonus value for st_had_bonus /// @param slang language for sound folding /// @param maxsf su_maxscore applies to soundfold score, su_sfmaxscore to the total score. -static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, int badlenarg, +static void add_suggestion(suginfo_T *su, garray_T *gap, const char *goodword, int badlenarg, int score, int altscore, bool had_bonus, slang_T *slang, bool maxsf) { int goodlen; // len of goodword changed @@ -3071,7 +3070,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, // Minimize "badlen" for consistency. Avoids that changing "the the" to // "thee the" is added next to changing the first "the" the "thee". - const char_u *pgood = goodword + STRLEN(goodword); + const char *pgood = goodword + strlen(goodword); char_u *pbad = su->su_badptr + badlenarg; for (;;) { goodlen = (int)(pgood - goodword); @@ -3100,7 +3099,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, // being replaced "thes," -> "these" is a different suggestion from // "thes" -> "these". stp = &SUG(*gap, 0); - for (i = gap->ga_len; --i >= 0; ++stp) { + for (i = gap->ga_len; --i >= 0; stp++) { if (stp->st_wordlen == goodlen && stp->st_orglen == badlen && STRNCMP(stp->st_word, goodword, goodlen) == 0) { @@ -3144,7 +3143,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, (size_t)goodlen); + stp->st_word = xstrnsave(goodword, (size_t)goodlen); stp->st_wordlen = goodlen; stp->st_score = score; stp->st_altscore = altscore; @@ -3307,15 +3306,15 @@ static int cleanup_suggestions(garray_T *gap, int maxscore, int keep) /// /// @param goodstart sound-folded good word /// @param badstart sound-folded bad word -static int soundalike_score(char_u *goodstart, char_u *badstart) +static int soundalike_score(char *goodstart, char *badstart) { - char_u *goodsound = goodstart; - char_u *badsound = badstart; + char *goodsound = goodstart; + char *badsound = badstart; int goodlen; int badlen; int n; - char_u *pl, *ps; - char_u *pl2, *ps2; + char *pl, *ps; + char *pl2, *ps2; int score = 0; // Adding/inserting "*" at the start (word starts with vowel) shouldn't be @@ -3346,8 +3345,8 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) } } - goodlen = (int)STRLEN(goodsound); - badlen = (int)STRLEN(badsound); + goodlen = (int)strlen(goodsound); + badlen = (int)strlen(badsound); // Return quickly if the lengths are too different to be fixed by two // changes. @@ -3380,7 +3379,7 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) ps++; } // strings must be equal after second delete - if (STRCMP(pl + 1, ps) == 0) { + if (strcmp(pl + 1, ps) == 0) { return score + SCORE_DEL * 2; } @@ -3404,12 +3403,12 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) // 2: delete then swap, then rest must be equal if (pl2[0] == ps2[1] && pl2[1] == ps2[0] - && STRCMP(pl2 + 2, ps2 + 2) == 0) { + && strcmp(pl2 + 2, ps2 + 2) == 0) { return score + SCORE_DEL + SCORE_SWAP; } // 3: delete then substitute, then the rest must be equal - if (STRCMP(pl2 + 1, ps2 + 1) == 0) { + if (strcmp(pl2 + 1, ps2 + 1) == 0) { return score + SCORE_DEL + SCORE_SUBST; } @@ -3422,7 +3421,7 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) ps2++; } // delete a char and then strings must be equal - if (STRCMP(pl2 + 1, ps2) == 0) { + if (strcmp(pl2 + 1, ps2) == 0) { return score + SCORE_SWAP + SCORE_DEL; } } @@ -3435,7 +3434,7 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) ps2++; } // delete a char and then strings must be equal - if (STRCMP(pl2 + 1, ps2) == 0) { + if (strcmp(pl2 + 1, ps2) == 0) { return score + SCORE_SUBST + SCORE_DEL; } @@ -3463,12 +3462,12 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) } // 3: swap and swap again if (pl2[0] == ps2[1] && pl2[1] == ps2[0] - && STRCMP(pl2 + 2, ps2 + 2) == 0) { + && strcmp(pl2 + 2, ps2 + 2) == 0) { return score + SCORE_SWAP + SCORE_SWAP; } // 4: swap and substitute - if (STRCMP(pl2 + 1, ps2 + 1) == 0) { + if (strcmp(pl2 + 1, ps2 + 1) == 0) { return score + SCORE_SWAP + SCORE_SUBST; } } @@ -3486,12 +3485,12 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) // 6: substitute and swap if (pl2[0] == ps2[1] && pl2[1] == ps2[0] - && STRCMP(pl2 + 2, ps2 + 2) == 0) { + && strcmp(pl2 + 2, ps2 + 2) == 0) { return score + SCORE_SUBST + SCORE_SWAP; } // 7: substitute and substitute - if (STRCMP(pl2 + 1, ps2 + 1) == 0) { + if (strcmp(pl2 + 1, ps2 + 1) == 0) { return score + SCORE_SUBST + SCORE_SUBST; } @@ -3502,7 +3501,7 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) pl2++; ps2++; } - if (STRCMP(pl2 + 1, ps2) == 0) { + if (strcmp(pl2 + 1, ps2) == 0) { return score + SCORE_INS + SCORE_DEL; } @@ -3513,7 +3512,7 @@ static int soundalike_score(char_u *goodstart, char_u *badstart) pl2++; ps2++; } - if (STRCMP(pl2, ps2 + 1) == 0) { + if (strcmp(pl2, ps2 + 1) == 0) { return score + SCORE_INS + SCORE_DEL; } diff --git a/src/nvim/state.c b/src/nvim/state.c index 61740800a1..7712fcd39a 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -3,6 +3,7 @@ #include <assert.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/drawscreen.h" @@ -10,7 +11,6 @@ #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" #include "nvim/option.h" @@ -57,7 +57,7 @@ getkey: // Duplicate display updating logic in vgetorpeek() if (((State & MODE_INSERT) != 0 || p_lz) && (State & MODE_CMDLINE) == 0 && must_redraw != 0 && !need_wait_return) { - update_screen(0); + update_screen(); setcursor(); // put cursor back where it belongs } // Flush screen updates before blocking @@ -65,7 +65,7 @@ getkey: // Call `os_inchar` directly to block for events or user input without // consuming anything from `input_buffer`(os/input.c) or calling the // mapping engine. - (void)os_inchar(NULL, 0, -1, 0, main_loop.events); + (void)os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); // If an event was put into the queue, we send K_EVENT directly. if (!multiqueue_empty(main_loop.events)) { key = K_EVENT; @@ -237,7 +237,7 @@ void may_trigger_modechanged(void) char pattern_buf[2 * MODE_MAX_LENGTH]; get_mode(curr_mode); - if (STRCMP(curr_mode, last_mode) == 0) { + if (strcmp(curr_mode, last_mode) == 0) { return; } diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index e868a79b9a..33c5c3a347 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -77,13 +77,14 @@ void win_redr_status(win_T *wp) width = is_stl_global ? Columns : wp->w_width; get_trans_bufname(wp->w_buffer); - p = NameBuff; + p = (char_u *)NameBuff; len = (int)STRLEN(p); - if (bt_help(wp->w_buffer) - || wp->w_p_pvw - || bufIsChanged(wp->w_buffer) - || wp->w_buffer->b_p_ro) { + if ((bt_help(wp->w_buffer) + || wp->w_p_pvw + || bufIsChanged(wp->w_buffer) + || wp->w_buffer->b_p_ro) + && len < MAXPATHL - 1) { *(p + len++) = ' '; } if (bt_help(wp->w_buffer)) { @@ -100,7 +101,7 @@ void win_redr_status(win_T *wp) } if (wp->w_buffer->b_p_ro) { snprintf((char *)p + len, MAXPATHL - (size_t)len, "%s", _("[RO]")); - // len += (int)STRLEN(p + len); // dead assignment + // len += (int)strlen(p + len); // dead assignment } this_ru_col = ru_col - (Columns - width); @@ -132,14 +133,14 @@ void win_redr_status(win_T *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_puts(&default_grid, (char *)p, row, col, attr); grid_fill(&default_grid, row, row + 1, len + col, this_ru_col + col, fillchar, fillchar, attr); if (get_keymap_str(wp, "<%s>", (char *)NameBuff, MAXPATHL) - && this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) { + && this_ru_col - len > (int)(strlen(NameBuff) + 1)) { grid_puts(&default_grid, NameBuff, row, - (int)((size_t)this_ru_col - STRLEN(NameBuff) - 1), attr); + (int)((size_t)this_ru_col - strlen(NameBuff) - 1), attr); } win_redr_ruler(wp, true); @@ -266,7 +267,7 @@ void win_redr_ruler(win_T *wp, bool always) off = 0; } - if (!part_of_status && !ui_has_messages()) { + if (!part_of_status && p_ch == 0 && !ui_has(kUIMessages)) { return; } @@ -286,7 +287,7 @@ void win_redr_ruler(win_T *wp, bool always) vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",", (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? (int64_t)0L : (int64_t)wp->w_cursor.lnum); - size_t len = STRLEN(buffer); + size_t len = strlen(buffer); col_print(buffer + len, RULER_BUF_LEN - len, empty_line ? 0 : (int)wp->w_cursor.col + 1, (int)virtcol + 1); @@ -294,7 +295,7 @@ void win_redr_ruler(win_T *wp, bool always) // Add a "50%" if there is room for it. // On the last line, don't print in the last column (scrolls the // screen up on some terminals). - int i = (int)STRLEN(buffer); + int i = (int)strlen(buffer); get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1); int o = i + vim_strsize(buffer + i + 1); if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen @@ -342,9 +343,9 @@ void win_redr_ruler(win_T *wp, bool always) } ScreenGrid *grid = part_of_status ? &default_grid : &msg_grid_adj; - grid_puts(grid, (char_u *)buffer, row, this_ru_col + off, attr); + grid_puts(grid, buffer, row, this_ru_col + off, attr); grid_fill(grid, row, row + 1, - this_ru_col + off + (int)STRLEN(buffer), off + width, fillchar, + this_ru_col + off + (int)strlen(buffer), off + width, fillchar, fillchar, attr); } @@ -426,7 +427,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) int len; int fillchar; char buf[MAXPATHL]; - char_u *stl; + char *stl; char *p; stl_hlrec_t *hltab; StlClickRecord *tabtab; @@ -455,7 +456,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) maxwidth = Columns; use_sandbox = was_set_insecurely(wp, "tabline", 0); } else if (draw_winbar) { - stl = (char_u *)((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr); + stl = ((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr); row = -1; // row zero is first row of text col = 0; grid = &wp->w_grid; @@ -497,7 +498,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) if (*++stl == '-') { stl++; } - if (atoi((char *)stl)) { + if (atoi(stl)) { while (ascii_isdigit(*stl)) { stl++; } @@ -544,9 +545,9 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) // Make a copy, because the statusline may include a function call that // might change the option value and free the memory. - stl = vim_strsave(stl); + stl = xstrdup(stl); width = - build_stl_str_hl(ewp, buf, sizeof(buf), (char *)stl, use_sandbox, + build_stl_str_hl(ewp, buf, sizeof(buf), stl, use_sandbox, fillchar, maxwidth, &hltab, &tabtab); xfree(stl); ewp->w_p_crb = p_crb_save; @@ -571,8 +572,8 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) p = buf; for (n = 0; hltab[n].start != NULL; n++) { int textlen = (int)(hltab[n].start - p); - grid_puts_len(grid, (char_u *)p, textlen, row, col, curattr); - col += vim_strnsize((char_u *)p, textlen); + grid_puts_len(grid, p, textlen, row, col, curattr); + col += vim_strnsize(p, textlen); p = hltab[n].start; if (hltab[n].userhl == 0) { @@ -586,8 +587,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) } } // Make sure to use an empty string instead of p, if p is beyond buf + len. - grid_puts(grid, p >= buf + len ? (char_u *)"" : (char_u *)p, row, col, - curattr); + grid_puts(grid, p >= buf + len ? "" : p, row, col, curattr); grid_puts_line_flush(false); @@ -608,7 +608,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) .type = kStlClickDisabled, }; for (n = 0; tabtab[n].start != NULL; n++) { - len += vim_strnsize((char_u *)p, (int)(tabtab[n].start - p)); + len += vim_strnsize(p, (int)(tabtab[n].start - p)); while (col < len) { click_defs[col++] = cur_click_def; } @@ -712,13 +712,13 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san } // Get line & check if empty (cursorpos will show "0-1"). - const char *line_ptr = (char *)ml_get_buf(wp->w_buffer, lnum, false); + const char *line_ptr = ml_get_buf(wp->w_buffer, lnum, false); bool empty_line = (*line_ptr == NUL); // Get the byte value now, in case we need it below. This is more // efficient than making a copy of the line. int byteval; - const size_t len = STRLEN(line_ptr); + const size_t len = strlen(line_ptr); if (wp->w_cursor.col > (colnr_T)len) { // Line may have changed since checking the cursor column, or the lnum // was adjusted above. @@ -1191,8 +1191,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san && strchr((const char *)str, '%') != NULL && evaldepth < MAX_STL_EVAL_DEPTH) { size_t parsed_usefmt = (size_t)(block_start - usefmt); - size_t str_length = STRLEN(str); - size_t fmt_length = STRLEN(fmt_p); + size_t str_length = strlen(str); + size_t fmt_length = strlen(fmt_p); size_t new_fmt_len = parsed_usefmt + str_length + fmt_length + 3; char *new_fmt = xmalloc(new_fmt_len * sizeof(char)); char *new_fmt_p = new_fmt; @@ -1329,7 +1329,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san // in the temporary buffer // (including the brackets and null terminating character) if (*wp->w_buffer->b_p_ft != NUL - && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) { + && strlen(wp->w_buffer->b_p_ft) < TMPLEN - 3) { vim_snprintf(buf_tmp, sizeof(buf_tmp), "[%s]", wp->w_buffer->b_p_ft); str = buf_tmp; @@ -1342,7 +1342,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san // in the temporary buffer // (including the comma and null terminating character) if (*wp->w_buffer->b_p_ft != NUL - && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) { + && strlen(wp->w_buffer->b_p_ft) < TMPLEN - 2) { vim_snprintf(buf_tmp, sizeof(buf_tmp), ",%s", wp->w_buffer->b_p_ft); // Uppercase the file extension for (char *t = buf_tmp; *t != 0; t++) { @@ -1562,7 +1562,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san // Advance the output buffer position to the end of the // number we just printed - out_p += STRLEN(out_p); + out_p += strlen(out_p); // Otherwise, there was nothing to print so mark the item as empty } else { @@ -1670,7 +1670,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san if (width + 1 < maxwidth) { // Advance the pointer to the end of the string - trunc_p = trunc_p + STRLEN(trunc_p); + trunc_p = trunc_p + strlen(trunc_p); } // Fill up for half a double-wide character. @@ -1706,7 +1706,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san // add characters at the separate marker (if there is one) to // fill up the available space. } else if (width < maxwidth - && STRLEN(out) + (size_t)(maxwidth - width) + 1 < outlen) { + && strlen(out) + (size_t)(maxwidth - width) + 1 < outlen) { // Find how many separators there are, which we will use when // figuring out how many groups there are. int num_separators = 0; diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 78312c738c..10173fac1d 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -49,53 +49,31 @@ #include "nvim/vim.h" #include "nvim/window.h" -/// Copy "string" into newly allocated memory. -char_u *vim_strsave(const char_u *string) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL -{ - return (char_u *)xstrdup((char *)string); -} - /// Copy up to `len` bytes of `string` into newly allocated memory and /// terminate with a NUL. The allocated memory always has size `len + 1`, even /// when `string` is shorter. -char_u *vim_strnsave(const char_u *string, size_t len) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL -{ - // strncpy is intentional: some parts of Vim use `string` shorter than `len` - // and expect the remainder to be zeroed out. - return (char_u *)strncpy(xmallocz(len), (char *)string, len); -} - -/// A clone of vim_strnsave() that uses char* instead of char_u* char *xstrnsave(const char *string, size_t len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { return strncpy(xmallocz(len), string, len); // NOLINT(runtime/printf) } -/* - * Same as vim_strsave(), but any characters found in esc_chars are preceded - * by a backslash. - */ +// Same as vim_strsave(), but any characters found in esc_chars are preceded +// by a backslash. char_u *vim_strsave_escaped(const char_u *string, const char_u *esc_chars) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { return vim_strsave_escaped_ext(string, esc_chars, '\\', false); } -/* - * Same as vim_strsave_escaped(), but when "bsl" is true also escape - * characters where rem_backslash() would remove the backslash. - * Escape the characters with "cc". - */ +// Same as vim_strsave_escaped(), but when "bsl" is true also escape +// characters where rem_backslash() would remove the backslash. +// Escape the characters with "cc". char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, char_u cc, bool bsl) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - /* - * First count the number of backslashes required. - * Then allocate the memory and insert them. - */ + // First count the number of backslashes required. + // Then allocate the memory and insert them. size_t length = 1; // count the trailing NUL for (const char_u *p = string; *p; p++) { const size_t l = (size_t)(utfc_ptr2len((char *)p)); @@ -104,10 +82,10 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, c p += l - 1; continue; } - if (vim_strchr((char *)esc_chars, *p) != NULL || (bsl && rem_backslash(p))) { + if (vim_strchr((char *)esc_chars, *p) != NULL || (bsl && rem_backslash((char *)p))) { length++; // count a backslash } - ++length; // count an ordinary char + length++; // count an ordinary char } char_u *escaped_string = xmalloc(length); @@ -120,7 +98,7 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, c p += l - 1; // skip multibyte char continue; } - if (vim_strchr((char *)esc_chars, *p) != NULL || (bsl && rem_backslash(p))) { + if (vim_strchr((char *)esc_chars, *p) != NULL || (bsl && rem_backslash((char *)p))) { *p2++ = cc; } *p2++ = *p; @@ -178,16 +156,14 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length) return ret; } -/* - * Escape "string" for use as a shell argument with system(). - * This uses single quotes, except when we know we need to use double quotes - * (MS-Windows without 'shellslash' set). - * Escape a newline, depending on the 'shell' option. - * When "do_special" is true also replace "!", "%", "#" and things starting - * with "<" like "<cfile>". - * When "do_newline" is false do not escape newline unless it is csh shell. - * Returns the result in allocated memory. - */ +// Escape "string" for use as a shell argument with system(). +// This uses single quotes, except when we know we need to use double quotes +// (MS-Windows without 'shellslash' set). +// Escape a newline, depending on the 'shell' option. +// When "do_special" is true also replace "!", "%", "#" and things starting +// with "<" like "<cfile>". +// When "do_newline" is false do not escape newline unless it is csh shell. +// Returns the result in allocated memory. char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_newline) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { @@ -197,10 +173,10 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n int csh_like; bool fish_like; - /* Only csh and similar shells expand '!' within single quotes. For sh and - * the like we must not put a backslash before it, it will be taken - * literally. If do_special is set the '!' will be escaped twice. - * Csh also needs to have "\n" escaped twice when do_special is set. */ + // Only csh and similar shells expand '!' within single quotes. For sh and + // the like we must not put a backslash before it, it will be taken + // literally. If do_special is set the '!' will be escaped twice. + // Csh also needs to have "\n" escaped twice when do_special is set. csh_like = csh_like_shell(); // Fish shell uses '\' as an escape character within single quotes, so '\' @@ -210,7 +186,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n // First count the number of extra bytes required. size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) { -#ifdef WIN32 +#ifdef MSWIN if (!p_ssl) { if (*p == '"') { length++; // " -> "" @@ -222,13 +198,13 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n } if ((*p == '\n' && (csh_like || do_newline)) || (*p == '!' && (csh_like || do_special))) { - ++length; // insert backslash + length++; // insert backslash if (csh_like && do_special) { - ++length; // insert backslash + length++; // insert backslash } } if (do_special && find_cmdline_var(p, &l) >= 0) { - ++length; // insert backslash + length++; // insert backslash p += l - 1; } if (*p == '\\' && fish_like) { @@ -241,7 +217,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n d = (char *)escaped_string; // add opening quote -#ifdef WIN32 +#ifdef MSWIN if (!p_ssl) { *d++ = '"'; } else @@ -249,7 +225,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n *d++ = '\''; for (const char *p = (char *)string; *p != NUL;) { -#ifdef WIN32 +#ifdef MSWIN if (!p_ssl) { if (*p == '"') { *d++ = '"'; @@ -293,7 +269,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n } // add terminating quote and finish with a NUL -#ifdef WIN32 +#ifdef MSWIN if (!p_ssl) { *d++ = '"'; } else @@ -304,35 +280,29 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n return escaped_string; } -/* - * Like vim_strsave(), but make all characters uppercase. - * This uses ASCII lower-to-upper case translation, language independent. - */ +// Like vim_strsave(), but make all characters uppercase. +// This uses ASCII lower-to-upper case translation, language independent. char_u *vim_strsave_up(const char_u *string) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char_u *p1; + char *p1; - p1 = vim_strsave(string); - vim_strup(p1); - return p1; + p1 = xstrdup((char *)string); + vim_strup((char_u *)p1); + return (char_u *)p1; } -/* - * Like vim_strnsave(), but make all characters uppercase. - * This uses ASCII lower-to-upper case translation, language independent. - */ -char_u *vim_strnsave_up(const char_u *string, size_t len) +/// Like xstrnsave(), but make all characters uppercase. +/// This uses ASCII lower-to-upper case translation, language independent. +char *vim_strnsave_up(const char *string, size_t len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char_u *p1 = vim_strnsave(string, len); - vim_strup(p1); + char *p1 = xstrnsave(string, len); + vim_strup((char_u *)p1); return p1; } -/* - * ASCII lower-to-upper case translation, language independent. - */ +// ASCII lower-to-upper case translation, language independent. void vim_strup(char_u *p) FUNC_ATTR_NONNULL_ALL { @@ -371,7 +341,7 @@ char *strcase_save(const char *const orig, bool upper) int newl = utf_char2len(uc); if (newl != l) { // TODO(philix): use xrealloc() in strcase_save() - char *s = xmalloc(STRLEN(res) + (size_t)(1 + newl - l)); + char *s = xmalloc(strlen(res) + (size_t)(1 + newl - l)); memcpy(s, res, (size_t)(p - res)); STRCPY(s + (p - res) + newl, p + l); p = s + (p - res); @@ -386,9 +356,7 @@ char *strcase_save(const char *const orig, bool upper) return res; } -/* - * delete spaces at the end of a string - */ +// delete spaces at the end of a string void del_trailing_spaces(char_u *ptr) FUNC_ATTR_NONNULL_ALL { @@ -413,11 +381,9 @@ size_t xstrnlen(const char *s, size_t n) #endif #if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) -/* - * Compare two strings, ignoring case, using current locale. - * Doesn't work for multi-byte characters. - * return 0 for match, < 0 for smaller, > 0 for bigger - */ +// Compare two strings, ignoring case, using current locale. +// Doesn't work for multi-byte characters. +// return 0 for match, < 0 for smaller, > 0 for bigger int vim_stricmp(const char *s1, const char *s2) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { @@ -439,11 +405,9 @@ int vim_stricmp(const char *s1, const char *s2) #endif #if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) -/* - * Compare two strings, for length "len", ignoring case, using current locale. - * Doesn't work for multi-byte characters. - * return 0 for match, < 0 for smaller, > 0 for bigger - */ +// Compare two strings, for length "len", ignoring case, using current locale. +// Doesn't work for multi-byte characters. +// return 0 for match, < 0 for smaller, > 0 for bigger int vim_strnicmp(const char *s1, const char *s2, size_t len) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { @@ -488,9 +452,7 @@ char *vim_strchr(const char *const string, const int c) } } -/* - * Sort an array of strings. - */ +// Sort an array of strings. #ifdef INCLUDE_GENERATED_DECLARATIONS # include "strings.c.generated.h" @@ -498,25 +460,23 @@ char *vim_strchr(const char *const string, const int c) static int sort_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL { - return STRCMP(*(char **)s1, *(char **)s2); + return strcmp(*(char **)s1, *(char **)s2); } void sort_strings(char **files, int count) { - qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare); + qsort((void *)files, (size_t)count, sizeof(char *), sort_compare); } -/* - * Return true if string "s" contains a non-ASCII character (128 or higher). - * When "s" is NULL false is returned. - */ +// Return true if string "s" contains a non-ASCII character (128 or higher). +// When "s" is NULL false is returned. bool has_non_ascii(const char_u *s) FUNC_ATTR_PURE { const char_u *p; if (s != NULL) { - for (p = s; *p != NUL; ++p) { + for (p = s; *p != NUL; p++) { if (*p >= 128) { return true; } @@ -540,14 +500,12 @@ bool has_non_ascii_len(const char *const s, const size_t len) return false; } -/* - * Concatenate two strings and return the result in allocated memory. - */ -char_u *concat_str(const char_u *restrict str1, const char_u *restrict str2) +/// Concatenate two strings and return the result in allocated memory. +char *concat_str(const char *restrict str1, const char *restrict str2) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - size_t l = STRLEN(str1); - char_u *dest = xmalloc(l + STRLEN(str2) + 1); + size_t l = strlen(str1); + char *dest = xmalloc(l + strlen(str2) + 1); STRCPY(dest, str1); STRCPY(dest + l, str2); return dest; @@ -1511,15 +1469,15 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...) /// Reverse text into allocated memory. /// /// @return the allocated string. -char_u *reverse_text(char_u *s) +char *reverse_text(char *s) FUNC_ATTR_NONNULL_RET { // Reverse the pattern. - size_t len = STRLEN(s); - char_u *rev = xmalloc(len + 1); + size_t len = strlen(s); + char *rev = xmalloc(len + 1); size_t rev_i = len; for (size_t s_i = 0; s_i < len; s_i++) { - const int mb_len = utfc_ptr2len((char *)s + s_i); + const int mb_len = utfc_ptr2len(s + s_i); rev_i -= (size_t)mb_len; memmove(rev + rev_i, s + s_i, (size_t)mb_len); s_i += (size_t)mb_len - 1; @@ -1540,7 +1498,7 @@ char_u *reverse_text(char_u *s) char *strrep(const char *src, const char *what, const char *rep) { char *pos = (char *)src; - size_t whatlen = STRLEN(what); + size_t whatlen = strlen(what); // Count occurrences size_t count = 0; @@ -1553,8 +1511,8 @@ char *strrep(const char *src, const char *what, const char *rep) return NULL; } - size_t replen = STRLEN(rep); - char *ret = xmalloc(STRLEN(src) + count * (replen - whatlen) + 1); + 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); diff --git a/src/nvim/strings.h b/src/nvim/strings.h index 9ef1eb5816..6ad9daf5bf 100644 --- a/src/nvim/strings.h +++ b/src/nvim/strings.h @@ -5,8 +5,8 @@ #include <stdbool.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/eval/typval.h" -#include "nvim/lib/kvec.h" #include "nvim/types.h" /// Append string to string and return pointer to the next byte diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 2a3ec56451..575d475b87 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * syntax.c: code for syntax highlighting - */ +// syntax.c: code for syntax highlighting #include <assert.h> #include <ctype.h> @@ -93,22 +91,20 @@ typedef struct syn_pattern { int16_t *sp_cont_list; // cont. group IDs, if non-zero int16_t *sp_next_list; // next group IDs, if non-zero struct sp_syn sp_syn; // struct passed to in_id_list() - char_u *sp_pattern; // regexp to match, pattern + char *sp_pattern; // regexp to match, pattern regprog_T *sp_prog; // regexp to match, program syn_time_T sp_time; } synpat_T; typedef struct syn_cluster_S { char_u *scl_name; // syntax cluster name - char_u *scl_name_u; // uppercase of scl_name + char *scl_name_u; // uppercase of scl_name int16_t *scl_list; // IDs in this syntax cluster } syn_cluster_T; -/* - * For the current state we need to remember more than just the idx. - * When si_m_endpos.lnum is 0, the items other than si_idx are unknown. - * (The end positions have the column number of the next char) - */ +// For the current state we need to remember more than just the idx. +// When si_m_endpos.lnum is 0, the items other than si_idx are unknown. +// (The end positions have the column number of the next char) typedef struct state_item { int si_idx; // index of syntax pattern or // KEYWORD_IDX @@ -133,10 +129,8 @@ typedef struct state_item { // pattern } stateitem_T; -/* - * Struct to reduce the number of arguments to get_syn_options(), it's used - * very often. - */ +// Struct to reduce the number of arguments to get_syn_options(), it's used +// very often. typedef struct { int flags; // flags for contained and transparent bool keyword; // true for ":syn keyword" @@ -184,9 +178,7 @@ static char *(spo_name_tab[SPO_COUNT]) = #define NONE_IDX (-2) // value of sp_sync_idx for "NONE" -/* - * Flags for b_syn_sync_flags: - */ +// Flags for b_syn_sync_flags: #define SF_CCOMMENT 0x01 // sync on a C-style comment #define SF_MATCH 0x02 // sync by matching a pattern @@ -194,9 +186,7 @@ static char *(spo_name_tab[SPO_COUNT]) = #define MAXKEYWLEN 80 // maximum length of a keyword -/* - * The attributes of the syntax item that has been recognized. - */ +// The attributes of the syntax item that has been recognized. static int current_attr = 0; // attr of current syntax word static int current_id = 0; // ID of current char for syn_get_id() static int current_trans_id = 0; // idem, transparency removed @@ -204,23 +194,19 @@ static int current_flags = 0; static int current_seqnr = 0; static int current_sub_char = 0; -/* - * Methods of combining two clusters - */ +// Methods of combining two clusters #define CLUSTER_REPLACE 1 // replace first list with second #define CLUSTER_ADD 2 // add second list to first #define CLUSTER_SUBTRACT 3 // subtract second list from first #define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data)) -/* - * Syntax group IDs have different types: - * 0 - 19999 normal syntax groups - * 20000 - 20999 ALLBUT indicator (current_syn_inc_tag added) - * 21000 - 21999 TOP indicator (current_syn_inc_tag added) - * 22000 - 22999 CONTAINED indicator (current_syn_inc_tag added) - * 23000 - 32767 cluster IDs (subtract SYNID_CLUSTER for the cluster ID) - */ +// Syntax group IDs have different types: +// 0 - 19999 normal syntax groups +// 20000 - 20999 ALLBUT indicator (current_syn_inc_tag added) +// 21000 - 21999 TOP indicator (current_syn_inc_tag added) +// 22000 - 22999 CONTAINED indicator (current_syn_inc_tag added) +// 23000 - 32767 cluster IDs (subtract SYNID_CLUSTER for the cluster ID) #define SYNID_ALLBUT MAX_HL_ID // syntax group ID for contains=ALLBUT #define SYNID_TOP 21000 // syntax group ID for contains=TOP #define SYNID_CONTAINED 22000 // syntax group ID for contains=CONTAINED @@ -234,21 +220,17 @@ static int current_sub_char = 0; // 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 - * files from leaking into ALLBUT lists, we assign a unique ID to the - * rules in each ":syn include"'d file. - */ +// Another Annoying Hack(TM): To prevent rules from other ":syn include"'d +// files from leaking into ALLBUT lists, we assign a unique ID to the +// rules in each ":syn include"'d file. static int current_syn_inc_tag = 0; static int running_syn_inc_tag = 0; -/* - * In a hashtable item "hi_key" points to "keyword" in a keyentry. - * This avoids adding a pointer to the hashtable item. - * KE2HIKEY() converts a var pointer to a hashitem key pointer. - * HIKEY2KE() converts a hashitem key pointer to a var pointer. - * HI2KE() converts a hashitem pointer to a var pointer. - */ +// In a hashtable item "hi_key" points to "keyword" in a keyentry. +// This avoids adding a pointer to the hashtable item. +// KE2HIKEY() converts a var pointer to a hashitem key pointer. +// HIKEY2KE() converts a hashitem key pointer to a var pointer. +// HI2KE() converts a hashitem pointer to a var pointer. static keyentry_T dumkey; #define KE2HIKEY(kp) ((kp)->keyword) #define HIKEY2KE(p) ((keyentry_T *)((p) - (dumkey.keyword - (char_u *)&dumkey))) @@ -256,11 +238,9 @@ static keyentry_T dumkey; // -V:HI2KE:782 -/* - * To reduce the time spent in keepend(), remember at which level in the state - * stack the first item with "keepend" is present. When "-1", there is no - * "keepend" on the stack. - */ +// To reduce the time spent in keepend(), remember at which level in the state +// stack the first item with "keepend" is present. When "-1", there is no +// "keepend" on the stack. static int keepend_level = -1; static char msg_no_items[] = N_("No Syntax items defined for this buffer"); @@ -272,13 +252,11 @@ static char msg_no_items[] = N_("No Syntax items defined for this buffer"); static int next_seqnr = 1; // value to use for si_seqnr -/* - * The next possible match in the current line for any pattern is remembered, - * to avoid having to try for a match in each column. - * If next_match_idx == -1, not tried (in this line) yet. - * If next_match_col == MAXCOL, no match found in this line. - * (All end positions have the column of the char after the end) - */ +// The next possible match in the current line for any pattern is remembered, +// to avoid having to try for a match in each column. +// If next_match_idx == -1, not tried (in this line) yet. +// If next_match_col == MAXCOL, no match found in this line. +// (All end positions have the column of the char after the end) static int next_match_col; // column for start of next match static lpos_T next_match_m_endpos; // position for end of next match static lpos_T next_match_h_startpos; // pos. for highl. start of next match @@ -290,17 +268,13 @@ static lpos_T next_match_eoe_pos; // pos. for end of end pattern static int next_match_end_idx; // ID of group for end pattn or zero static reg_extmatch_T *next_match_extmatch = NULL; -/* - * A state stack is an array of integers or stateitem_T, stored in a - * garray_T. A state stack is invalid if its itemsize entry is zero. - */ +// A state stack is an array of integers or stateitem_T, stored in a +// garray_T. A state stack is invalid if its itemsize entry is zero. #define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0) #define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0) -/* - * The current state (within the line) of the recognition engine. - * When current_state.ga_itemsize is 0 the current state is invalid. - */ +// The current state (within the line) of the recognition engine. +// When current_state.ga_itemsize is 0 the current state is invalid. static win_T *syn_win; // current window for highlighting static buf_T *syn_buf; // current buffer for highlighting static synblock_T *syn_block; // current buffer for highlighting @@ -328,13 +302,11 @@ void syn_set_timeout(proftime_T *tm) syn_tm = tm; } -/* - * Start the syntax recognition for a line. This function is normally called - * from the screen updating, once for each displayed line. - * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get - * it. Careful: curbuf and curwin are likely to point to another buffer and - * window. - */ +// Start the syntax recognition for a line. This function is normally called +// from the screen updating, once for each displayed line. +// The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get +// it. Careful: curbuf and curwin are likely to point to another buffer and +// window. void syntax_start(win_T *wp, linenr_T lnum) { synstate_T *p; @@ -348,11 +320,9 @@ void syntax_start(win_T *wp, linenr_T lnum) current_sub_char = NUL; - /* - * After switching buffers, invalidate current_state. - * Also do this when a change was made, the current state may be invalid - * then. - */ + // After switching buffers, invalidate current_state. + // Also do this when a change was made, the current state may be invalid + // then. if (syn_block != wp->w_s || syn_buf != wp->w_buffer || changedtick != buf_get_changedtick(syn_buf)) { @@ -363,18 +333,14 @@ void syntax_start(win_T *wp, linenr_T lnum) changedtick = buf_get_changedtick(syn_buf); syn_win = wp; - /* - * Allocate syntax stack when needed. - */ + // Allocate syntax stack when needed. syn_stack_alloc(); if (syn_block->b_sst_array == NULL) { return; // out of memory } syn_block->b_sst_lasttick = display_tick; - /* - * If the state of the end of the previous line is useful, store it. - */ + // If the state of the end of the previous line is useful, store it. if (VALID_STATE(¤t_state) && current_lnum < lnum && current_lnum < syn_buf->b_ml.ml_line_count) { @@ -384,11 +350,9 @@ void syntax_start(win_T *wp, linenr_T lnum) (void)store_current_state(); } - /* - * If the current_lnum is now the same as "lnum", keep the current - * state (this happens very often!). Otherwise invalidate - * current_state and figure it out below. - */ + // If the current_lnum is now the same as "lnum", keep the current + // state (this happens very often!). Otherwise invalidate + // current_state and figure it out below. if (current_lnum != lnum) { invalidate_current_state(); } @@ -396,10 +360,8 @@ void syntax_start(win_T *wp, linenr_T lnum) invalidate_current_state(); } - /* - * Try to synchronize from a saved state in b_sst_array[]. - * Only do this if lnum is not before and not to far beyond a saved state. - */ + // Try to synchronize from a saved state in b_sst_array[]. + // Only do this if lnum is not before and not to far beyond a saved state. if (INVALID_STATE(¤t_state) && syn_block->b_sst_array != NULL) { // Find last valid saved state before start_lnum. for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next) { @@ -418,10 +380,8 @@ void syntax_start(win_T *wp, linenr_T lnum) } } - /* - * If "lnum" is before or far beyond a line with a saved state, need to - * re-synchronize. - */ + // If "lnum" is before or far beyond a line with a saved state, need to + // re-synchronize. if (INVALID_STATE(¤t_state)) { syn_sync(wp, lnum, last_valid); if (current_lnum == 1) { @@ -436,10 +396,8 @@ void syntax_start(win_T *wp, linenr_T lnum) first_stored = current_lnum; } - /* - * Advance from the sync point or saved state until the current line. - * Save some entries for syncing with later on. - */ + // Advance from the sync point or saved state until the current line. + // Save some entries for syncing with later on. if (syn_block->b_sst_len <= Rows) { dist = 999999; } else { @@ -506,10 +464,8 @@ void syntax_start(win_T *wp, linenr_T lnum) syn_start_line(); } -/* - * We cannot simply discard growarrays full of state_items or buf_states; we - * have to manually release their extmatch pointers first. - */ +// We cannot simply discard growarrays full of state_items or buf_states; we +// have to manually release their extmatch pointers first. static void clear_syn_state(synstate_T *p) { if (p->sst_stacksize > SST_FIX_STATES) { @@ -522,24 +478,20 @@ static void clear_syn_state(synstate_T *p) } } -/* - * Cleanup the current_state stack. - */ +// Cleanup the current_state stack. static void clear_current_state(void) { #define UNREF_STATEITEM_EXTMATCH(si) unref_extmatch((si)->si_extmatch) GA_DEEP_CLEAR(¤t_state, stateitem_T, UNREF_STATEITEM_EXTMATCH); } -/* - * Try to find a synchronisation point for line "lnum". - * - * This sets current_lnum and the current state. One of three methods is - * used: - * 1. Search backwards for the end of a C-comment. - * 2. Search backwards for given sync patterns. - * 3. Simply start on a given number of lines above "lnum". - */ +// Try to find a synchronisation point for line "lnum". +// +// This sets current_lnum and the current state. One of three methods is +// used: +// 1. Search backwards for the end of a C-comment. +// 2. Search backwards for given sync patterns. +// 3. Simply start on a given number of lines above "lnum". static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) { buf_T *curbuf_save; @@ -560,19 +512,15 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) lpos_T found_m_endpos; colnr_T prev_current_col; - /* - * Clear any current state that might be hanging around. - */ + // Clear any current state that might be hanging around. invalidate_current_state(); - /* - * Start at least "minlines" back. Default starting point for parsing is - * there. - * Start further back, to avoid that scrolling backwards will result in - * resyncing for every line. Now it resyncs only one out of N lines, - * where N is minlines * 1.5, or minlines * 2 if minlines is small. - * Watch out for overflow when minlines is MAXLNUM. - */ + // Start at least "minlines" back. Default starting point for parsing is + // there. + // Start further back, to avoid that scrolling backwards will result in + // resyncing for every line. Now it resyncs only one out of N lines, + // where N is minlines * 1.5, or minlines * 2 if minlines is small. + // Watch out for overflow when minlines is MAXLNUM. if (syn_block->b_syn_sync_minlines > start_lnum) { start_lnum = 1; } else { @@ -595,9 +543,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) } current_lnum = start_lnum; - /* - * 1. Search backwards for the end of a C-style comment. - */ + // 1. Search backwards for the end of a C-style comment. if (syn_block->b_syn_sync_flags & SF_CCOMMENT) { // Need to make syn_buf the current buffer for a moment, to be able to // use find_start_comment(). @@ -606,11 +552,9 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) curbuf_save = curbuf; curbuf = syn_buf; - /* - * Skip lines that end in a backslash. - */ - for (; start_lnum > 1; --start_lnum) { - line = ml_get(start_lnum - 1); + // Skip lines that end in a backslash. + for (; start_lnum > 1; start_lnum--) { + line = (char_u *)ml_get(start_lnum - 1); if (*line == NUL || *(line + STRLEN(line) - 1) != '\\') { break; } @@ -622,11 +566,9 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) wp->w_cursor.lnum = start_lnum; wp->w_cursor.col = 0; - /* - * If the line is inside a comment, need to find the syntax item that - * defines the comment. - * Restrict the search for the end of a comment to b_syn_sync_maxlines. - */ + // If the line is inside a comment, need to find the syntax item that + // defines the comment. + // Restrict the search for the end of a comment to b_syn_sync_maxlines. if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL) { for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) { if (SYN_ITEMS(syn_block)[idx].sp_syn.id @@ -644,11 +586,8 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) wp->w_cursor = cursor_save; curwin = curwin_save; curbuf = curbuf_save; - } - /* - * 2. Search backwards for given sync patterns. - */ - else if (syn_block->b_syn_sync_flags & SF_MATCH) { + } else if (syn_block->b_syn_sync_flags & SF_MATCH) { + // 2. Search backwards for given sync patterns. if (syn_block->b_syn_sync_maxlines != 0 && start_lnum > syn_block->b_syn_sync_maxlines) { break_lnum = start_lnum - syn_block->b_syn_sync_maxlines; @@ -675,19 +614,15 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) break; } - /* - * Check if the previous line has the line-continuation pattern. - */ + // Check if the previous line has the line-continuation pattern. if (lnum > 1 && syn_match_linecont(lnum - 1)) { continue; } - /* - * Start with nothing on the state stack - */ + // Start with nothing on the state stack validate_current_state(); - for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum) { + for (current_lnum = lnum; current_lnum < end_lnum; current_lnum++) { syn_start_line(); for (;;) { had_sync_point = syn_finish_line(true); @@ -712,10 +647,8 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) found_current_lnum = current_lnum; found_current_col = current_col; found_m_endpos = cur_si->si_m_endpos; - /* - * Continue after the match (be aware of a zero-length - * match). - */ + // Continue after the match (be aware of a zero-length + // match). if (found_m_endpos.lnum > current_lnum) { current_lnum = found_m_endpos.lnum; current_col = found_m_endpos.col; @@ -743,27 +676,21 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) } } - /* - * If a sync point was encountered, break here. - */ + // If a sync point was encountered, break here. if (found_flags) { - /* - * Put the item that was specified by the sync point on the - * state stack. If there was no item specified, make the - * state stack empty. - */ + // Put the item that was specified by the sync point on the + // state stack. If there was no item specified, make the + // state stack empty. clear_current_state(); if (found_match_idx >= 0) { push_current_state(found_match_idx); update_si_attr(current_state.ga_len - 1); } - /* - * When using "grouphere", continue from the sync point - * match, until the end of the line. Parsing starts at - * the next line. - * For "groupthere" the parsing starts at start_lnum. - */ + // When using "grouphere", continue from the sync point + // match, until the end of the line. Parsing starts at + // the next line. + // For "groupthere" the parsing starts at start_lnum. if (found_flags & HL_SYNC_HERE) { if (!GA_EMPTY(¤t_state)) { cur_si = &CUR_STATE(current_state.ga_len - 1); @@ -797,7 +724,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) validate_current_state(); } -static void save_chartab(char_u *chartab) +static void save_chartab(char *chartab) { if (syn_block->b_syn_isk != empty_option) { memmove(chartab, syn_buf->b_chartab, (size_t)32); @@ -805,23 +732,21 @@ static void save_chartab(char_u *chartab) } } -static void restore_chartab(char_u *chartab) +static void restore_chartab(char *chartab) { if (syn_win->w_s->b_syn_isk != empty_option) { memmove(syn_buf->b_chartab, chartab, (size_t)32); } } -/* - * Return TRUE if the line-continuation pattern matches in line "lnum". - */ +/// Return true if the line-continuation pattern matches in line "lnum". static int syn_match_linecont(linenr_T lnum) { if (syn_block->b_syn_linecont_prog != NULL) { regmmatch_T regmatch; // chartab array for syn iskeyword char_u buf_chartab[32]; - save_chartab(buf_chartab); + save_chartab((char *)buf_chartab); regmatch.rmm_ic = syn_block->b_syn_linecont_ic; regmatch.regprog = syn_block->b_syn_linecont_prog; @@ -829,24 +754,20 @@ static int syn_match_linecont(linenr_T lnum) IF_SYN_TIME(&syn_block->b_syn_linecont_time)); syn_block->b_syn_linecont_prog = regmatch.regprog; - restore_chartab(buf_chartab); + restore_chartab((char *)buf_chartab); return r; } - return FALSE; + return false; } -/* - * Prepare the current state for the start of a line. - */ +// Prepare the current state for the start of a line. static void syn_start_line(void) { current_finished = false; current_col = 0; - /* - * Need to update the end of a start/skip/end that continues from the - * previous line and regions that have "keepend". - */ + // Need to update the end of a start/skip/end that continues from the + // previous line and regions that have "keepend". if (!GA_EMPTY(¤t_state)) { syn_update_ends(true); check_state_ends(); @@ -878,23 +799,21 @@ static void syn_update_ends(bool startofline) cur_si->si_m_endpos.lnum = 0; cur_si->si_m_endpos.col = 0; cur_si->si_h_endpos = cur_si->si_m_endpos; - cur_si->si_ends = TRUE; + cur_si->si_ends = true; } } } - /* - * Need to update the end of a start/skip/end that continues from the - * previous line. And regions that have "keepend", because they may - * influence contained items. If we've just removed "extend" - * (startofline == 0) then we should update ends of normal regions - * contained inside "keepend" because "extend" could have extended - * these "keepend" regions as well as contained normal regions. - * Then check for items ending in column 0. - */ + // Need to update the end of a start/skip/end that continues from the + // previous line. And regions that have "keepend", because they may + // influence contained items. If we've just removed "extend" + // (startofline == 0) then we should update ends of normal regions + // contained inside "keepend" because "extend" could have extended + // these "keepend" regions as well as contained normal regions. + // Then check for items ending in column 0. int i = current_state.ga_len - 1; if (keepend_level >= 0) { - for (; i > keepend_level; --i) { + for (; i > keepend_level; i--) { if (CUR_STATE(i).si_flags & HL_EXTEND) { break; } @@ -925,37 +844,35 @@ static void syn_update_ends(bool startofline) ///////////////////////////////////////// // Handling of the state stack cache. -/* - * EXPLANATION OF THE SYNTAX STATE STACK CACHE - * - * To speed up syntax highlighting, the state stack for the start of some - * lines is cached. These entries can be used to start parsing at that point. - * - * The stack is kept in b_sst_array[] for each buffer. There is a list of - * valid entries. b_sst_first points to the first one, then follow sst_next. - * The entries are sorted on line number. The first entry is often for line 2 - * (line 1 always starts with an empty stack). - * There is also a list for free entries. This construction is used to avoid - * having to allocate and free memory blocks too often. - * - * When making changes to the buffer, this is logged in b_mod_*. When calling - * update_screen() to update the display, it will call - * syn_stack_apply_changes() for each displayed buffer to adjust the cached - * entries. The entries which are inside the changed area are removed, - * because they must be recomputed. Entries below the changed have their line - * number adjusted for deleted/inserted lines, and have their sst_change_lnum - * set to indicate that a check must be made if the changed lines would change - * the cached entry. - * - * When later displaying lines, an entry is stored for each line. Displayed - * lines are likely to be displayed again, in which case the state at the - * start of the line is needed. - * For not displayed lines, an entry is stored for every so many lines. These - * entries will be used e.g., when scrolling backwards. The distance between - * entries depends on the number of lines in the buffer. For small buffers - * the distance is fixed at SST_DIST, for large buffers there is a fixed - * number of entries SST_MAX_ENTRIES, and the distance is computed. - */ +// EXPLANATION OF THE SYNTAX STATE STACK CACHE +// +// To speed up syntax highlighting, the state stack for the start of some +// lines is cached. These entries can be used to start parsing at that point. +// +// The stack is kept in b_sst_array[] for each buffer. There is a list of +// valid entries. b_sst_first points to the first one, then follow sst_next. +// The entries are sorted on line number. The first entry is often for line 2 +// (line 1 always starts with an empty stack). +// There is also a list for free entries. This construction is used to avoid +// having to allocate and free memory blocks too often. +// +// When making changes to the buffer, this is logged in b_mod_*. When calling +// update_screen() to update the display, it will call +// syn_stack_apply_changes() for each displayed buffer to adjust the cached +// entries. The entries which are inside the changed area are removed, +// because they must be recomputed. Entries below the changed have their line +// number adjusted for deleted/inserted lines, and have their sst_change_lnum +// set to indicate that a check must be made if the changed lines would change +// the cached entry. +// +// When later displaying lines, an entry is stored for each line. Displayed +// lines are likely to be displayed again, in which case the state at the +// start of the line is needed. +// For not displayed lines, an entry is stored for every so many lines. These +// entries will be used e.g., when scrolling backwards. The distance between +// entries depends on the number of lines in the buffer. For small buffers +// the distance is fixed at SST_DIST, for large buffers there is a fixed +// number of entries SST_MAX_ENTRIES, and the distance is computed. static void syn_stack_free_block(synblock_T *block) { @@ -970,10 +887,8 @@ static void syn_stack_free_block(synblock_T *block) block->b_sst_len = 0; } } -/* - * Free b_sst_array[] for buffer "buf". - * Used when syntax items changed to force resyncing everywhere. - */ +// Free b_sst_array[] for buffer "buf". +// Used when syntax items changed to force resyncing everywhere. void syn_stack_free_all(synblock_T *block) { syn_stack_free_block(block); @@ -986,12 +901,10 @@ void syn_stack_free_all(synblock_T *block) } } -/* - * Allocate the syntax state stack for syn_buf when needed. - * If the number of entries in b_sst_array[] is much too big or a bit too - * small, reallocate it. - * Also used to allocate b_sst_array[] for the first time. - */ +// Allocate the syntax state stack for syn_buf when needed. +// If the number of entries in b_sst_array[] is much too big or a bit too +// small, reallocate it. +// Also used to allocate b_sst_array[] for the first time. static void syn_stack_alloc(void) { synstate_T *to, *from; @@ -1058,12 +971,10 @@ static void syn_stack_alloc(void) } } -/* - * Check for changes in a buffer to affect stored syntax states. Uses the - * b_mod_* fields. - * Called from update_screen(), before screen is being updated, once for each - * displayed buffer. - */ +// Check for changes in a buffer to affect stored syntax states. Uses the +// b_mod_* fields. +// Called from update_screen(), before screen is being updated, once for each +// displayed buffer. void syn_stack_apply_changes(buf_T *buf) { syn_stack_apply_changes_block(&buf->b_s, buf); @@ -1139,11 +1050,9 @@ static bool syn_stack_cleanup(void) dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1; } - /* - * Go through the list to find the "tick" for the oldest entry that can - * be removed. Set "above" when the "tick" for the oldest entry is above - * "b_sst_lasttick" (the display tick wraps around). - */ + // Go through the list to find the "tick" for the oldest entry that can + // be removed. Set "above" when the "tick" for the oldest entry is above + // "b_sst_lasttick" (the display tick wraps around). tick = syn_block->b_sst_lasttick; bool above = false; prev = syn_block->b_sst_first; @@ -1160,10 +1069,8 @@ static bool syn_stack_cleanup(void) } } - /* - * Go through the list to make the entries for the oldest tick at an - * interval of several lines. - */ + // Go through the list to make the entries for the oldest tick at an + // interval of several lines. prev = syn_block->b_sst_first; for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) { if (p->sst_tick == tick && prev->sst_lnum + dist > p->sst_lnum) { @@ -1177,22 +1084,18 @@ static bool syn_stack_cleanup(void) return retval; } -/* - * Free the allocated memory for a syn_state item. - * Move the entry into the free list. - */ +// Free the allocated memory for a syn_state item. +// Move the entry into the free list. static void syn_stack_free_entry(synblock_T *block, synstate_T *p) { clear_syn_state(p); p->sst_next = block->b_sst_firstfree; block->b_sst_firstfree = p; - ++block->b_sst_freecount; + block->b_sst_freecount++; } -/* - * Find an entry in the list of state stacks at or before "lnum". - * Returns NULL when there is no entry or the first entry is after "lnum". - */ +// Find an entry in the list of state stacks at or before "lnum". +// Returns NULL when there is no entry or the first entry is after "lnum". static synstate_T *syn_stack_find_entry(linenr_T lnum) { synstate_T *p, *prev; @@ -1209,10 +1112,8 @@ static synstate_T *syn_stack_find_entry(linenr_T lnum) return prev; } -/* - * Try saving the current state in b_sst_array[]. - * The current state must be valid for the start of the current_lnum line! - */ +// Try saving the current state in b_sst_array[]. +// The current state must be valid for the start of the current_lnum line! static synstate_T *store_current_state(void) { int i; @@ -1221,11 +1122,9 @@ static synstate_T *store_current_state(void) stateitem_T *cur_si; synstate_T *sp = syn_stack_find_entry(current_lnum); - /* - * If the current state contains a start or end pattern that continues - * from the previous line, we can't use it. Don't store it then. - */ - for (i = current_state.ga_len - 1; i >= 0; --i) { + // If the current state contains a start or end pattern that continues + // from the previous line, we can't use it. Don't store it then. + for (i = current_state.ga_len - 1; i >= 0; i--) { cur_si = &CUR_STATE(i); if (cur_si->si_h_startpos.lnum >= current_lnum || cur_si->si_m_endpos.lnum >= current_lnum @@ -1256,9 +1155,7 @@ static synstate_T *store_current_state(void) sp = NULL; } } else if (sp == NULL || sp->sst_lnum != current_lnum) { - /* - * Add a new entry - */ + // Add a new entry // If no free items, cleanup the array first. if (syn_block->b_sst_freecount == 0) { (void)syn_stack_cleanup(); @@ -1273,7 +1170,7 @@ static synstate_T *store_current_state(void) // list, after *sp p = syn_block->b_sst_firstfree; syn_block->b_sst_firstfree = p->sst_next; - --syn_block->b_sst_freecount; + syn_block->b_sst_freecount--; if (sp == NULL) { // Insert in front of the list p->sst_next = syn_block->b_sst_first; @@ -1302,7 +1199,7 @@ static synstate_T *store_current_state(void) } else { bp = sp->sst_union.sst_stack; } - for (i = 0; i < sp->sst_stacksize; ++i) { + for (i = 0; i < sp->sst_stacksize; i++) { bp[i].bs_idx = CUR_STATE(i).si_idx; bp[i].bs_flags = (int)CUR_STATE(i).si_flags; bp[i].bs_seqnr = CUR_STATE(i).si_seqnr; @@ -1318,9 +1215,7 @@ static synstate_T *store_current_state(void) return sp; } -/* - * Copy a state stack from "from" in b_sst_array[] to current_state; - */ +// Copy a state stack from "from" in b_sst_array[] to current_state; static void load_current_state(synstate_T *from) { int i; @@ -1336,7 +1231,7 @@ static void load_current_state(synstate_T *from) } else { bp = from->sst_union.sst_stack; } - for (i = 0; i < from->sst_stacksize; ++i) { + for (i = 0; i < from->sst_stacksize; i++) { CUR_STATE(i).si_idx = bp[i].bs_idx; CUR_STATE(i).si_flags = bp[i].bs_flags; CUR_STATE(i).si_seqnr = bp[i].bs_seqnr; @@ -1345,7 +1240,7 @@ static void load_current_state(synstate_T *from) if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND)) { keepend_level = i; } - CUR_STATE(i).si_ends = FALSE; + CUR_STATE(i).si_ends = false; CUR_STATE(i).si_m_lnum = 0; if (CUR_STATE(i).si_idx >= 0) { CUR_STATE(i).si_next_list = @@ -1424,16 +1319,14 @@ static bool syn_stack_equal(synstate_T *sp) return i < 0 ? true : false; } -/* - * We stop parsing syntax above line "lnum". If the stored state at or below - * this line depended on a change before it, it now depends on the line below - * the last parsed line. - * The window looks like this: - * line which changed - * displayed line - * displayed line - * lnum -> line below window - */ +// We stop parsing syntax above line "lnum". If the stored state at or below +// this line depended on a change before it, it now depends on the line below +// the last parsed line. +// The window looks like this: +// line which changed +// displayed line +// displayed line +// lnum -> line below window void syntax_end_parsing(linenr_T lnum) { synstate_T *sp; @@ -1448,9 +1341,8 @@ void syntax_end_parsing(linenr_T lnum) } } -/* - * End of handling of the state stack. - ****************************************/ +// End of handling of the state stack. +// ************************************** static void invalidate_current_state(void) { @@ -1475,33 +1367,25 @@ bool syntax_check_changed(linenr_T lnum) bool retval = true; synstate_T *sp; - /* - * Check the state stack when: - * - lnum is just below the previously syntaxed line. - * - lnum is not before the lines with saved states. - * - lnum is not past the lines with saved states. - * - lnum is at or before the last changed line. - */ + // Check the state stack when: + // - lnum is just below the previously syntaxed line. + // - lnum is not before the lines with saved states. + // - lnum is not past the lines with saved states. + // - lnum is at or before the last changed line. if (VALID_STATE(¤t_state) && lnum == current_lnum + 1) { sp = syn_stack_find_entry(lnum); if (sp != NULL && sp->sst_lnum == lnum) { - /* - * finish the previous line (needed when not all of the line was - * drawn) - */ + // finish the previous line (needed when not all of the line was + // drawn) (void)syn_finish_line(false); - /* - * Compare the current state with the previously saved state of - * the line. - */ + // Compare the current state with the previously saved state of + // the line. if (syn_stack_equal(sp)) { retval = false; } - /* - * Store the current state in b_sst_array[] for later use. - */ + // Store the current state in b_sst_array[] for later use. current_lnum++; (void)store_current_state(); } @@ -1551,7 +1435,7 @@ static bool syn_finish_line(const bool syncing) /// "col" is normally 0 for the first use in a line, and increments by one each /// time. It's allowed to skip characters and to stop before the end of the /// line. But only a "col" after a previously used column is allowed. -/// When "can_spell" is not NULL set it to TRUE when spell-checking should be +/// When "can_spell" is not NULL set it to true when spell-checking should be /// done. /// /// @param keep_state keep state of char at "col" @@ -1589,9 +1473,7 @@ int get_syntax_attr(const colnr_T col, bool *const can_spell, const bool keep_st validate_current_state(); } - /* - * Skip from the current column to "col", get the attributes for "col". - */ + // Skip from the current column to "col", get the attributes for "col". while (current_col <= col) { attr = syn_current_attr(false, true, can_spell, current_col == col ? keep_state : false); @@ -1636,15 +1518,11 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con bool zero_width_next_list = false; garray_T zero_width_next_ga; - /* - * No character, no attributes! Past end of line? - * Do try matching with an empty line (could be the start of a region). - */ - line = syn_getcurline(); + // No character, no attributes! Past end of line? + // Do try matching with an empty line (could be the start of a region). + line = (char_u *)syn_getcurline(); if (line[current_col] == NUL && current_col != 0) { - /* - * If we found a match after the last column, use it. - */ + // If we found a match after the last column, use it. if (next_match_idx >= 0 && next_match_col >= (int)current_col && next_match_col != MAXCOL) { (void)push_next_match(); @@ -1661,11 +1539,9 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con current_state_stored = false; } - /* - * When in the previous column there was a match but it could not be used - * (empty match or already matched in this column) need to try again in - * the next column. - */ + // When in the previous column there was a match but it could not be used + // (empty match or already matched in this column) need to try again in + // the next column. if (try_next_column) { next_match_idx = -1; try_next_column = false; @@ -1681,25 +1557,21 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con ga_init(&zero_width_next_ga, (int)sizeof(int), 10); // use syntax iskeyword option - save_chartab(buf_chartab); + save_chartab((char *)buf_chartab); - /* - * Repeat matching keywords and patterns, to find contained items at the - * same column. This stops when there are no extra matches at the current - * column. - */ + // Repeat matching keywords and patterns, to find contained items at the + // same column. This stops when there are no extra matches at the current + // column. do { found_match = false; keep_next_list = false; int syn_id = 0; - /* - * 1. Check for a current state. - * Only when there is no current state, or if the current state may - * contain other things, we need to check for keywords and patterns. - * Always need to check for contained items if some item has the - * "containedin" argument (takes extra time!). - */ + // 1. Check for a current state. + // Only when there is no current state, or if the current state may + // contain other things, we need to check for keywords and patterns. + // Always need to check for contained items if some item has the + // "containedin" argument (takes extra time!). if (current_state.ga_len) { cur_si = &CUR_STATE(current_state.ga_len - 1); } else { @@ -1708,18 +1580,17 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con if (syn_block->b_syn_containedin || cur_si == NULL || cur_si->si_cont_list != NULL) { - /* - * 2. Check for keywords, if on a keyword char after a non-keyword - * char. Don't do this when syncing. - */ + // 2. Check for keywords, if on a keyword char after a non-keyword + // char. Don't do this when syncing. if (do_keywords) { - line = syn_getcurline(); + line = (char_u *)syn_getcurline(); const char_u *cur_pos = line + current_col; - if (vim_iswordp_buf(cur_pos, syn_buf) + if (vim_iswordp_buf((char *)cur_pos, syn_buf) && (current_col == 0 - || !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1), + || !vim_iswordp_buf((char *)cur_pos - 1 - + utf_head_off((char *)line, (char *)cur_pos - 1), syn_buf))) { - syn_id = check_keyword_id(line, (int)current_col, &endcol, &flags, + syn_id = check_keyword_id((char *)line, (int)current_col, &endcol, &flags, &next_list, cur_si, &cchar); if (syn_id != 0) { push_current_state(KEYWORD_IDX); @@ -1732,7 +1603,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con cur_si->si_m_endpos.col = endcol; cur_si->si_h_endpos.lnum = current_lnum; cur_si->si_h_endpos.col = endcol; - cur_si->si_ends = TRUE; + cur_si->si_ends = true; cur_si->si_end_idx = 0; cur_si->si_flags = flags; cur_si->si_seqnr = next_seqnr++; @@ -1763,21 +1634,15 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * 3. Check for patterns (only if no keyword found). - */ + // 3. Check for patterns (only if no keyword found). if (syn_id == 0 && syn_block->b_syn_patterns.ga_len) { - /* - * If we didn't check for a match yet, or we are past it, check - * for any match with a pattern. - */ + // If we didn't check for a match yet, or we are past it, check + // for any match with a pattern. if (next_match_idx < 0 || next_match_col < (int)current_col) { - /* - * Check all relevant patterns for a match at this - * position. This is complicated, because matching with a - * pattern takes quite a bit of time, thus we want to - * avoid doing it when it's not needed. - */ + // Check all relevant patterns for a match at this + // position. This is complicated, because matching with a + // pattern takes quite a bit of time, thus we want to + // avoid doing it when it's not needed. next_match_idx = 0; // no match in this line yet next_match_col = MAXCOL; for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) { @@ -1819,9 +1684,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con continue; } - /* - * Compute the first column of the match. - */ + // Compute the first column of the match. syn_add_start_off(&pos, ®match, spp, SPO_MS_OFF, -1); if (pos.lnum > current_lnum) { @@ -1836,19 +1699,15 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con // matches in the current line spp->sp_startcol = startcol; - /* - * If a previously found match starts at a lower - * column number, don't use this one. - */ + // If a previously found match starts at a lower + // column number, don't use this one. if (startcol >= next_match_col) { continue; } - /* - * If we matched this pattern at this position - * before, skip it. Must retry in the next - * column, because it may match from there. - */ + // If we matched this pattern at this position + // before, skip it. Must retry in the next + // column, because it may match from there. if (did_match_already(idx, &zero_width_next_ga)) { try_next_column = true; continue; @@ -1866,10 +1725,8 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con syn_add_end_off(&eos_pos, ®match, spp, SPO_RS_OFF, 0); - /* - * Grab the external submatches before they get - * overwritten. Reference count doesn't change. - */ + // Grab the external submatches before they get + // overwritten. Reference count doesn't change. unref_extmatch(cur_extmatch); cur_extmatch = re_extmatch_out; re_extmatch_out = NULL; @@ -1880,12 +1737,10 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con end_idx = 0; hl_endpos.lnum = 0; - /* - * For a "oneline" the end must be found in the - * same line too. Search for it after the end of - * the match with the start pattern. Set the - * resulting end positions at the same time. - */ + // For a "oneline" the end must be found in the + // same line too. Search for it after the end of + // the match with the start pattern. Set the + // resulting end positions at the same time. if (spp->sp_type == SPTYPE_START && (spp->sp_flags & HL_ONELINE)) { lpos_T startpos; @@ -1896,23 +1751,18 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con if (endpos.lnum == 0) { continue; // not found } - } - /* - * For a "match" the size must be > 0 after the - * end offset needs has been added. Except when - * syncing. - */ - else if (spp->sp_type == SPTYPE_MATCH) { + } else if (spp->sp_type == SPTYPE_MATCH) { + // For a "match" the size must be > 0 after the + // end offset needs has been added. Except when + // syncing. syn_add_end_off(&hl_endpos, ®match, spp, SPO_HE_OFF, 0); syn_add_end_off(&endpos, ®match, spp, SPO_ME_OFF, 0); if (endpos.lnum == current_lnum && (int)endpos.col + syncing < startcol) { - /* - * If an empty string is matched, may need - * to try matching again at next column. - */ + // If an empty string is matched, may need + // to try matching again at next column. if (regmatch.startpos[0].col == regmatch.endpos[0].col) { try_next_column = true; } @@ -1920,9 +1770,8 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * keep the best match so far in next_match_* - */ + // keep the best match so far in next_match_* + // Highlighting must start after startpos and end // before endpos. if (hl_startpos.lnum == current_lnum @@ -1947,9 +1796,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * If we found a match at the current column, use it. - */ + // If we found a match at the current column, use it. if (next_match_idx >= 0 && next_match_col == (int)current_col) { synpat_T *lspp; @@ -1977,17 +1824,13 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * Handle searching for nextgroup match. - */ + // Handle searching for nextgroup match. if (current_next_list != NULL && !keep_next_list) { - /* - * If a nextgroup was not found, continue looking for one if: - * - this is an empty line and the "skipempty" option was given - * - we are on white space and the "skipwhite" option was given - */ + // If a nextgroup was not found, continue looking for one if: + // - this is an empty line and the "skipempty" option was given + // - we are on white space and the "skipwhite" option was given if (!found_match) { - line = syn_getcurline(); + line = (char_u *)syn_getcurline(); if (((current_next_flags & HL_SKIPWHITE) && ascii_iswhite(line[current_col])) || ((current_next_flags & HL_SKIPEMPTY) @@ -1996,14 +1839,12 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * If a nextgroup was found: Use it, and continue looking for - * contained matches. - * If a nextgroup was not found: Continue looking for a normal - * match. - * When did set current_next_list for a zero-width item and no - * match was found don't loop (would get stuck). - */ + // If a nextgroup was found: Use it, and continue looking for + // contained matches. + // If a nextgroup was not found: Continue looking for a normal + // match. + // When did set current_next_list for a zero-width item and no + // match was found don't loop (would get stuck). current_next_list = NULL; next_match_idx = -1; if (!zero_width_next_list) { @@ -2012,19 +1853,17 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } while (found_match); - restore_chartab(buf_chartab); + restore_chartab((char *)buf_chartab); - /* - * Use attributes from the current state, if within its highlighting. - * If not, use attributes from the current-but-one state, etc. - */ + // Use attributes from the current state, if within its highlighting. + // If not, use attributes from the current-but-one state, etc. current_attr = 0; current_id = 0; current_trans_id = 0; current_flags = 0; current_seqnr = 0; if (cur_si != NULL) { - for (int idx = current_state.ga_len - 1; idx >= 0; --idx) { + for (int idx = current_state.ga_len - 1; idx >= 0; idx--) { sip = &CUR_STATE(idx); if ((current_lnum > sip->si_h_startpos.lnum || (current_lnum == sip->si_h_startpos.lnum @@ -2046,10 +1885,8 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con if (can_spell != NULL) { struct sp_syn sps; - /* - * set "can_spell" to TRUE if spell checking is supposed to be - * done in the current item. - */ + // set "can_spell" to true if spell checking is supposed to be + // done in the current item. if (syn_block->b_spell_cluster_id == 0) { // There is no @Spell cluster: Do spelling for items without // @NoSpell cluster. @@ -2085,14 +1922,12 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con } } - /* - * Check for end of current state (and the states before it) at the - * next column. Don't do this for syncing, because we would miss a - * single character match. - * First check if the current state ends at the current column. It - * may be for an empty match and a containing item might end in the - * current column. - */ + // Check for end of current state (and the states before it) at the + // next column. Don't do this for syncing, because we would miss a + // single character match. + // First check if the current state ends at the current column. It + // may be for an empty match and a containing item might end in the + // current column. if (!syncing && !keep_state) { check_state_ends(); if (!GA_EMPTY(¤t_state) @@ -2112,7 +1947,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con // nextgroup ends at end of line, unless "skipnl" or "skipempty" present if (current_next_list != NULL - && (line = syn_getcurline())[current_col] != NUL + && (line = (char_u *)syn_getcurline())[current_col] != NUL && line[current_col + 1] == NUL && !(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))) { current_next_list = NULL; @@ -2152,9 +1987,7 @@ static bool did_match_already(int idx, garray_T *gap) return false; } -/* - * Push the next match onto the stack. - */ +// Push the next match onto the stack. static stateitem_T *push_next_match(void) { stateitem_T *cur_si; @@ -2163,15 +1996,11 @@ static stateitem_T *push_next_match(void) spp = &(SYN_ITEMS(syn_block)[next_match_idx]); - /* - * Push the item in current_state stack; - */ + // Push the item in current_state stack; push_current_state(next_match_idx); { - /* - * If it's a start-skip-end type that crosses lines, figure out how - * much it continues in this line. Otherwise just fill in the length. - */ + // If it's a start-skip-end type that crosses lines, figure out how + // much it continues in this line. Otherwise just fill in the length. cur_si = &CUR_STATE(current_state.ga_len - 1); cur_si->si_h_startpos = next_match_h_startpos; cur_si->si_m_startcol = current_col; @@ -2192,7 +2021,7 @@ static stateitem_T *push_next_match(void) } else { cur_si->si_m_endpos = next_match_m_endpos; cur_si->si_h_endpos = next_match_h_endpos; - cur_si->si_ends = TRUE; + cur_si->si_ends = true; cur_si->si_flags |= next_match_flags; cur_si->si_eoe_pos = next_match_eoe_pos; cur_si->si_end_idx = next_match_end_idx; @@ -2204,10 +2033,8 @@ static stateitem_T *push_next_match(void) update_si_attr(current_state.ga_len - 1); save_flags = cur_si->si_flags & (HL_CONCEAL | HL_CONCEALENDS); - /* - * If the start pattern has another highlight group, push another item - * on the stack for the start pattern. - */ + // If the start pattern has another highlight group, push another item + // on the stack for the start pattern. if (spp->sp_type == SPTYPE_START && spp->sp_syn_match_id != 0) { push_current_state(next_match_idx); cur_si = &CUR_STATE(current_state.ga_len - 1); @@ -2216,7 +2043,7 @@ static stateitem_T *push_next_match(void) cur_si->si_m_lnum = current_lnum; cur_si->si_m_endpos = next_match_eos_pos; cur_si->si_h_endpos = next_match_eos_pos; - cur_si->si_ends = TRUE; + cur_si->si_ends = true; cur_si->si_end_idx = 0; cur_si->si_flags = HL_MATCH; cur_si->si_seqnr = next_seqnr++; @@ -2235,9 +2062,7 @@ static stateitem_T *push_next_match(void) return cur_si; } -/* - * Check for end of current state (and the states before it). - */ +// Check for end of current state (and the states before it). static void check_state_ends(void) { stateitem_T *cur_si; @@ -2249,12 +2074,10 @@ static void check_state_ends(void) && (cur_si->si_m_endpos.lnum < current_lnum || (cur_si->si_m_endpos.lnum == current_lnum && cur_si->si_m_endpos.col <= current_col))) { - /* - * If there is an end pattern group ID, highlight the end pattern - * now. No need to pop the current item from the stack. - * Only do this if the end pattern continues beyond the current - * position. - */ + // If there is an end pattern group ID, highlight the end pattern + // now. No need to pop the current item from the stack. + // Only do this if the end pattern continues beyond the current + // position. if (cur_si->si_end_idx && (cur_si->si_eoe_pos.lnum > current_lnum || (cur_si->si_eoe_pos.lnum == current_lnum @@ -2331,10 +2154,8 @@ static void check_state_ends(void) } } -/* - * Update an entry in the current_state stack for a match or region. This - * fills in si_attr, si_next_list and si_cont_list. - */ +// Update an entry in the current_state stack for a match or region. This +// fills in si_attr, si_next_list and si_cont_list. static void update_si_attr(int idx) { stateitem_T *sip = &CUR_STATE(idx); @@ -2359,11 +2180,9 @@ static void update_si_attr(int idx) sip->si_cont_list = spp->sp_cont_list; } - /* - * For transparent items, take attr from outer item. - * Also take cont_list, if there is none. - * Don't do this for the matchgroup of a start or end pattern. - */ + // For transparent items, take attr from outer item. + // Also take cont_list, if there is none. + // Don't do this for the matchgroup of a start or end pattern. if ((spp->sp_flags & HL_TRANSP) && !(sip->si_flags & HL_MATCH)) { if (idx == 0) { sip->si_attr = 0; @@ -2382,10 +2201,8 @@ static void update_si_attr(int idx) } } -/* - * Check the current stack for patterns with "keepend" flag. - * Propagate the match-end to contained items, until a "skipend" item is found. - */ +// Check the current stack for patterns with "keepend" flag. +// Propagate the match-end to contained items, until a "skipend" item is found. static void check_keepend(void) { int i; @@ -2393,20 +2210,16 @@ static void check_keepend(void) lpos_T maxpos_h; stateitem_T *sip; - /* - * This check can consume a lot of time; only do it from the level where - * there really is a keepend. - */ + // This check can consume a lot of time; only do it from the level where + // there really is a keepend. if (keepend_level < 0) { return; } - /* - * Find the last index of an "extend" item. "keepend" items before that - * won't do anything. If there is no "extend" item "i" will be - * "keepend_level" and all "keepend" items will work normally. - */ - for (i = current_state.ga_len - 1; i > keepend_level; --i) { + // Find the last index of an "extend" item. "keepend" items before that + // won't do anything. If there is no "extend" item "i" will be + // "keepend_level" and all "keepend" items will work normally. + for (i = current_state.ga_len - 1; i > keepend_level; i--) { if (CUR_STATE(i).si_flags & HL_EXTEND) { break; } @@ -2416,13 +2229,13 @@ static void check_keepend(void) maxpos.col = 0; maxpos_h.lnum = 0; maxpos_h.col = 0; - for (; i < current_state.ga_len; ++i) { + for (; i < current_state.ga_len; i++) { sip = &CUR_STATE(i); if (maxpos.lnum != 0) { limit_pos_zero(&sip->si_m_endpos, &maxpos); limit_pos_zero(&sip->si_h_endpos, &maxpos_h); limit_pos_zero(&sip->si_eoe_pos, &maxpos); - sip->si_ends = TRUE; + sip->si_ends = true; } if (sip->si_ends && (sip->si_flags & HL_KEEPEND)) { if (maxpos.lnum == 0 @@ -2465,10 +2278,8 @@ static void update_si_end(stateitem_T *sip, int startcol, bool force) return; } - /* - * We need to find the end of the region. It may continue in the next - * line. - */ + // We need to find the end of the region. It may continue in the next + // line. int end_idx = 0; lpos_T startpos = { .lnum = current_lnum, @@ -2482,12 +2293,12 @@ static void update_si_end(stateitem_T *sip, int startcol, bool force) // No end pattern matched. if (SYN_ITEMS(syn_block)[sip->si_idx].sp_flags & HL_ONELINE) { // a "oneline" never continues in the next line - sip->si_ends = TRUE; + sip->si_ends = true; sip->si_m_endpos.lnum = current_lnum; - sip->si_m_endpos.col = (colnr_T)STRLEN(syn_getcurline()); + sip->si_m_endpos.col = (colnr_T)strlen(syn_getcurline()); } else { // continues in the next line - sip->si_ends = FALSE; + sip->si_ends = false; sip->si_m_endpos.lnum = 0; } sip->si_h_endpos = sip->si_m_endpos; @@ -2496,15 +2307,13 @@ static void update_si_end(stateitem_T *sip, int startcol, bool force) sip->si_m_endpos = endpos; sip->si_h_endpos = hl_endpos; sip->si_eoe_pos = end_endpos; - sip->si_ends = TRUE; + sip->si_ends = true; sip->si_end_idx = end_idx; } } -/* - * Add a new state to the current state stack. - * It is cleared and the index set to "idx". - */ +// Add a new state to the current state stack. +// It is cleared and the index set to "idx". static void push_current_state(int idx) { stateitem_T *p = GA_APPEND_VIA_PTR(stateitem_T, ¤t_state); @@ -2512,14 +2321,12 @@ static void push_current_state(int idx) p->si_idx = idx; } -/* - * Remove a state from the current_state stack. - */ +// Remove a state from the current_state stack. static void pop_current_state(void) { if (!GA_EMPTY(¤t_state)) { unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch); - --current_state.ga_len; + current_state.ga_len--; } // after the end of a pattern, try matching a keyword or pattern next_match_idx = -1; @@ -2565,20 +2372,16 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ return; } - /* - * Check for being called with a START pattern. - * Can happen with a match that continues to the next line, because it - * contained a region. - */ + // Check for being called with a START pattern. + // Can happen with a match that continues to the next line, because it + // contained a region. spp = &(SYN_ITEMS(syn_block)[idx]); if (spp->sp_type != SPTYPE_START) { *hl_endpos = *startpos; return; } - /* - * Find the SKIP or first END pattern after the last START pattern. - */ + // Find the SKIP or first END pattern after the last START pattern. for (;;) { spp = &(SYN_ITEMS(syn_block)[idx]); if (spp->sp_type != SPTYPE_START) { @@ -2587,9 +2390,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ idx++; } - /* - * Lookup the SKIP pattern (if present) - */ + // Lookup the SKIP pattern (if present) if (spp->sp_type == SPTYPE_SKIP) { spp_skip = spp; idx++; @@ -2606,14 +2407,12 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ best_regmatch.startpos[0].col = 0; // avoid compiler warning // use syntax iskeyword option - save_chartab(buf_chartab); + save_chartab((char *)buf_chartab); for (;;) { - /* - * Find end pattern that matches first after "matchcol". - */ + // Find end pattern that matches first after "matchcol". best_idx = -1; - for (idx = start_idx; idx < syn_block->b_syn_patterns.ga_len; ++idx) { + for (idx = start_idx; idx < syn_block->b_syn_patterns.ga_len; idx++) { int lc_col = matchcol; spp = &(SYN_ITEMS(syn_block)[idx]); @@ -2640,18 +2439,14 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ } } - /* - * If all end patterns have been tried, and there is no match, the - * item continues until end-of-line. - */ + // If all end patterns have been tried, and there is no match, the + // item continues until end-of-line. if (best_idx == -1) { break; } - /* - * If the skip pattern matches before the end pattern, - * continue searching after the skip pattern. - */ + // If the skip pattern matches before the end pattern, + // continue searching after the skip pattern. if (spp_skip != NULL) { int lc_col = matchcol - spp_skip->sp_offsets[SPO_LC_OFF]; @@ -2673,7 +2468,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ break; } - line = ml_get_buf(syn_buf, startpos->lnum, false); + line = (char_u *)ml_get_buf(syn_buf, startpos->lnum, false); int line_len = (int)STRLEN(line); // take care of an empty match or negative offset @@ -2697,10 +2492,8 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ } } - /* - * Match from start pattern to end pattern. - * Correct for match and highlight offset of end pattern. - */ + // Match from start pattern to end pattern. + // Correct for match and highlight offset of end pattern. spp = &(SYN_ITEMS(syn_block)[best_idx]); syn_add_end_off(m_endpos, &best_regmatch, spp, SPO_ME_OFF, 1); // can't end before the start @@ -2717,9 +2510,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ // can't end after the match limit_pos(end_endpos, m_endpos); - /* - * If the end group is highlighted differently, adjust the pointers. - */ + // If the end group is highlighted differently, adjust the pointers. if (spp->sp_syn_match_id != spp->sp_syn.id && spp->sp_syn_match_id != 0) { *end_idx = best_idx; if (spp->sp_off_flags & (1 << (SPO_RE_OFF + SPO_COUNT))) { @@ -2757,16 +2548,14 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ m_endpos->lnum = 0; } - restore_chartab(buf_chartab); + restore_chartab((char *)buf_chartab); // Remove external matches. unref_extmatch(re_extmatch_in); re_extmatch_in = NULL; } -/* - * Limit "pos" not to be after "limit". - */ +// Limit "pos" not to be after "limit". static void limit_pos(lpos_T *pos, lpos_T *limit) { if (pos->lnum > limit->lnum) { @@ -2776,9 +2565,7 @@ static void limit_pos(lpos_T *pos, lpos_T *limit) } } -/* - * Limit "pos" not to be after "limit", unless pos->lnum is zero. - */ +// Limit "pos" not to be after "limit", unless pos->lnum is zero. static void limit_pos_zero(lpos_T *pos, lpos_T *limit) { if (pos->lnum == 0) { @@ -2817,7 +2604,7 @@ static void syn_add_end_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp if (result->lnum > syn_buf->b_ml.ml_line_count) { col = 0; } else if (off != 0) { - base = ml_get_buf(syn_buf, result->lnum, false); + base = (char_u *)ml_get_buf(syn_buf, result->lnum, false); p = base + col; if (off > 0) { while (off-- > 0 && *p != NUL) { @@ -2859,10 +2646,10 @@ static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *s if (result->lnum > syn_buf->b_ml.ml_line_count) { // a "\n" at the end of the pattern may take us below the last line result->lnum = syn_buf->b_ml.ml_line_count; - col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, false)); + col = (int)strlen(ml_get_buf(syn_buf, result->lnum, false)); } if (off != 0) { - base = ml_get_buf(syn_buf, result->lnum, false); + base = (char_u *)ml_get_buf(syn_buf, result->lnum, false); p = base + col; if (off > 0) { while (off-- && *p != NUL) { @@ -2878,18 +2665,14 @@ static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *s result->col = col; } -/* - * Get current line in syntax buffer. - */ -static char_u *syn_getcurline(void) +/// Get current line in syntax buffer. +static char *syn_getcurline(void) { return ml_get_buf(syn_buf, current_lnum, false); } -/* - * Call vim_regexec() to find a match with "rmp" in "syn_buf". - * Returns TRUE when there is a match. - */ +// Call vim_regexec() to find a match with "rmp" in "syn_buf". +// Returns true when there is a match. static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st) { int timed_out = 0; @@ -2916,9 +2699,9 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T if (profile_cmp(pt, st->slowest) < 0) { st->slowest = pt; } - ++st->count; + st->count++; if (r > 0) { - ++st->match; + st->match++; } } if (timed_out && !syn_win->w_s->b_syn_slow) { @@ -2929,9 +2712,9 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T if (r > 0) { rmp->startpos[0].lnum += lnum; rmp->endpos[0].lnum += lnum; - return TRUE; + return true; } - return FALSE; + return false; } /// Check one position in a line for a matching keyword. @@ -2944,16 +2727,16 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T /// @param next_listp return: next_list of matching keyword /// @param cur_si item at the top of the stack /// @param ccharp conceal substitution char -static int check_keyword_id(char_u *const line, const int startcol, int *const endcolp, +static int check_keyword_id(char *const line, const int startcol, int *const endcolp, long *const flagsp, int16_t **const next_listp, stateitem_T *const cur_si, int *const ccharp) { // Find first character after the keyword. First character was already // checked. - char_u *const kwp = line + startcol; + char *const kwp = line + startcol; int kwlen = 0; do { - kwlen += utfc_ptr2len((char *)kwp + kwlen); + kwlen += utfc_ptr2len(kwp + kwlen); } while (vim_iswordp_buf(kwp + kwlen, syn_buf)); if (kwlen > MAXKEYWLEN) { @@ -2969,13 +2752,13 @@ static int check_keyword_id(char_u *const line, const int startcol, int *const e // matching case if (syn_block->b_keywtab.ht_used != 0) { - kp = match_keyword(keyword, &syn_block->b_keywtab, cur_si); + kp = match_keyword((char *)keyword, &syn_block->b_keywtab, cur_si); } // ignoring case if (kp == NULL && syn_block->b_keywtab_ic.ht_used != 0) { - str_foldcase(kwp, kwlen, keyword, MAXKEYWLEN + 1); - kp = match_keyword(keyword, &syn_block->b_keywtab_ic, cur_si); + str_foldcase((char_u *)kwp, kwlen, keyword, MAXKEYWLEN + 1); + kp = match_keyword((char *)keyword, &syn_block->b_keywtab_ic, cur_si); } if (kp != NULL) { @@ -2994,9 +2777,9 @@ static int check_keyword_id(char_u *const line, const int startcol, int *const e /// When current_next_list is non-zero accept only that group, otherwise: /// Accept a not-contained keyword at toplevel. /// Accept a keyword at other levels only if it is in the contains list. -static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht, stateitem_T *cur_si) +static keyentry_T *match_keyword(char *keyword, hashtab_T *ht, stateitem_T *cur_si) { - hashitem_T *hi = hash_find(ht, (char *)keyword); + hashitem_T *hi = hash_find(ht, keyword); if (!HASHITEM_EMPTY(hi)) { for (keyentry_T *kp = HI2KE(hi); kp != NULL; kp = kp->ke_next) { if (current_next_list != 0 @@ -3012,20 +2795,18 @@ static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht, stateitem_T *cu return NULL; } -/* - * Handle ":syntax conceal" command. - */ +// Handle ":syntax conceal" command. static void syn_cmd_conceal(exarg_T *eap, int syncing) { char_u *arg = (char_u *)eap->arg; char_u *next; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd((char *)arg); if (eap->skip) { return; } - next = skiptowhite(arg); + next = (char_u *)skiptowhite((char *)arg); if (*arg == NUL) { if (curwin->w_s->b_syn_conceal) { msg("syntax conceal on"); @@ -3041,15 +2822,13 @@ static void syn_cmd_conceal(exarg_T *eap, int syncing) } } -/* - * Handle ":syntax case" command. - */ +/// Handle ":syntax case" command. static void syn_cmd_case(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *next; + char *arg = eap->arg; + char *next; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd(arg); if (eap->skip) { return; } @@ -3076,7 +2855,7 @@ static void syn_cmd_foldlevel(exarg_T *eap, int syncing) char_u *arg = (char_u *)eap->arg; char_u *arg_end; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd((char *)arg); if (eap->skip) { return; } @@ -3093,7 +2872,7 @@ static void syn_cmd_foldlevel(exarg_T *eap, int syncing) return; } - arg_end = skiptowhite(arg); + arg_end = (char_u *)skiptowhite((char *)arg); if (STRNICMP(arg, "start", 5) == 0 && arg_end - arg == 5) { curwin->w_s->b_syn_foldlevel = SYNFLD_START; } else if (STRNICMP(arg, "minimum", 7) == 0 && arg_end - arg == 7) { @@ -3109,15 +2888,13 @@ static void syn_cmd_foldlevel(exarg_T *eap, int syncing) } } -/* - * Handle ":syntax spell" command. - */ +/// Handle ":syntax spell" command. static void syn_cmd_spell(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *next; + char *arg = eap->arg; + char *next; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd(arg); if (eap->skip) { return; } @@ -3143,26 +2920,26 @@ static void syn_cmd_spell(exarg_T *eap, int syncing) } // assume spell checking changed, force a redraw - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } /// Handle ":syntax iskeyword" command. static void syn_cmd_iskeyword(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u save_chartab[32]; - char_u *save_isk; + char *arg = eap->arg; + char save_chartab[32]; + char *save_isk; if (eap->skip) { return; } - arg = (char_u *)skipwhite((char *)arg); + arg = skipwhite(arg); if (*arg == NUL) { msg_puts("\n"); if (curwin->w_s->b_syn_isk != empty_option) { msg_puts("syntax iskeyword "); - msg_outtrans((char *)curwin->w_s->b_syn_isk); + msg_outtrans(curwin->w_s->b_syn_isk); } else { msg_outtrans(_("syntax iskeyword not set")); } @@ -3173,7 +2950,7 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing) } else { memmove(save_chartab, curbuf->b_chartab, (size_t)32); save_isk = curbuf->b_p_isk; - curbuf->b_p_isk = vim_strsave(arg); + curbuf->b_p_isk = xstrdup(arg); buf_init_chartab(curbuf, false); memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, (size_t)32); @@ -3183,12 +2960,10 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing) curbuf->b_p_isk = save_isk; } } - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } -/* - * Clear all syntax info for one buffer. - */ +// Clear all syntax info for one buffer. void syntax_clear(synblock_T *block) { block->b_syn_error = false; // clear previous error @@ -3236,9 +3011,7 @@ void syntax_clear(synblock_T *block) running_syn_inc_tag = 0; } -/* - * Get rid of ownsyntax for window "wp". - */ +// Get rid of ownsyntax for window "wp". void reset_synblock(win_T *wp) { if (wp->w_s != &wp->w_buffer->b_s) { @@ -3248,9 +3021,7 @@ void reset_synblock(win_T *wp) } } -/* - * Clear syncing info for one buffer. - */ +// Clear syncing info for one buffer. static void syntax_sync_clear(void) { // free the syntax patterns @@ -3273,26 +3044,22 @@ static void syntax_sync_clear(void) syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } -/* - * Remove one pattern from the buffer's pattern list. - */ +// Remove one pattern from the buffer's pattern list. static void syn_remove_pattern(synblock_T *block, int idx) { synpat_T *spp; spp = &(SYN_ITEMS(block)[idx]); if (spp->sp_flags & HL_FOLD) { - --block->b_syn_folditems; + block->b_syn_folditems--; } syn_clear_pattern(block, idx); memmove(spp, spp + 1, sizeof(synpat_T) * (size_t)(block->b_syn_patterns.ga_len - idx - 1)); block->b_syn_patterns.ga_len--; } -/* - * Clear and free one syntax pattern. When clearing all, must be called from - * last to first! - */ +// Clear and free one syntax pattern. When clearing all, must be called from +// last to first! static void syn_clear_pattern(synblock_T *block, int i) { xfree(SYN_ITEMS(block)[i].sp_pattern); @@ -3305,9 +3072,7 @@ static void syn_clear_pattern(synblock_T *block, int i) } } -/* - * Clear and free one syntax cluster. - */ +// Clear and free one syntax cluster. static void syn_clear_cluster(synblock_T *block, int i) { xfree(SYN_CLSTR(block)[i].scl_name); @@ -3315,34 +3080,28 @@ static void syn_clear_cluster(synblock_T *block, int i) xfree(SYN_CLSTR(block)[i].scl_list); } -/* - * Handle ":syntax clear" command. - */ +/// Handle ":syntax clear" command. static void syn_cmd_clear(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *arg_end; + char *arg = eap->arg; + char *arg_end; int id; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd(arg); if (eap->skip) { return; } - /* - * We have to disable this within ":syn include @group filename", - * because otherwise @group would get deleted. - * Only required for Vim 5.x syntax files, 6.0 ones don't contain ":syn - * clear". - */ + // We have to disable this within ":syn include @group filename", + // because otherwise @group would get deleted. + // Only required for Vim 5.x syntax files, 6.0 ones don't contain ":syn + // clear". if (curwin->w_s->b_syn_topgrp != 0) { return; } if (ends_excmd(*arg)) { - /* - * No argument: Clear all syntax items. - */ + // No argument: Clear all syntax items. if (syncing) { syntax_sync_clear(); } else { @@ -3353,9 +3112,7 @@ static void syn_cmd_clear(exarg_T *eap, int syncing) do_unlet(S_LEN("w:current_syntax"), true); } } else { - /* - * Clear the group IDs that are in the argument. - */ + // Clear the group IDs that are in the argument. while (!ends_excmd(*arg)) { arg_end = skiptowhite(arg); if (*arg == '@') { @@ -3372,7 +3129,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, (size_t)(arg_end - arg)); + id = syn_name2id_len(arg, (size_t)(arg_end - arg)); if (id == 0) { semsg(_(e_nogroup), arg); break; @@ -3380,16 +3137,14 @@ static void syn_cmd_clear(exarg_T *eap, int syncing) syn_clear_one(id, syncing); } } - arg = (char_u *)skipwhite((char *)arg_end); + arg = skipwhite(arg_end); } } - redraw_curbuf_later(SOME_VALID); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } -/* - * Clear one syntax group for the current buffer. - */ +// Clear one syntax group for the current buffer. static void syn_clear_one(const int id, const bool syncing) { synpat_T *spp; @@ -3410,37 +3165,29 @@ static void syn_clear_one(const int id, const bool syncing) } } -/* - * Handle ":syntax on" command. - */ +// Handle ":syntax on" command. static void syn_cmd_on(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "syntax"); } -/* - * Handle ":syntax reset" command. - * It actually resets highlighting, not syntax. - */ +// Handle ":syntax reset" command. +// It actually resets highlighting, not syntax. static void syn_cmd_reset(exarg_T *eap, int syncing) { - eap->nextcmd = (char *)check_nextcmd((char_u *)eap->arg); + eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { init_highlight(true, true); } } -/* - * Handle ":syntax manual" command. - */ +// Handle ":syntax manual" command. static void syn_cmd_manual(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "manual"); } -/* - * Handle ":syntax off" command. - */ +// Handle ":syntax off" command. static void syn_cmd_off(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "nosyntax"); @@ -3449,7 +3196,7 @@ static void syn_cmd_off(exarg_T *eap, int syncing) static void syn_cmd_onoff(exarg_T *eap, char *name) FUNC_ATTR_NONNULL_ALL { - eap->nextcmd = (char *)check_nextcmd((char_u *)eap->arg); + eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { did_syntax_onoff = true; char buf[100]; @@ -3471,13 +3218,13 @@ void syn_maybe_enable(void) /// Handle ":syntax [list]" command: list current syntax words. /// -/// @param syncing when TRUE: list syncing items +/// @param syncing when true: list syncing items static void syn_cmd_list(exarg_T *eap, int syncing) { char_u *arg = (char_u *)eap->arg; char_u *arg_end; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd((char *)arg); if (eap->skip) { return; } @@ -3520,23 +3267,19 @@ static void syn_cmd_list(exarg_T *eap, int syncing) msg_puts_title(_("\n--- Syntax items ---")); } if (ends_excmd(*arg)) { - /* - * No argument: List all group IDs and all syntax clusters. - */ + // No argument: List all group IDs and all syntax clusters. for (int id = 1; id <= highlight_num_groups() && !got_int; id++) { syn_list_one(id, syncing, false); } - for (int id = 0; id < curwin->w_s->b_syn_clusters.ga_len && !got_int; ++id) { + for (int id = 0; id < curwin->w_s->b_syn_clusters.ga_len && !got_int; id++) { syn_list_cluster(id); } } else { - /* - * List the group IDs and syntax clusters that are in the argument. - */ + // List the group IDs and syntax clusters that are in the argument. while (!ends_excmd(*arg) && !got_int) { - arg_end = skiptowhite(arg); + arg_end = (char_u *)skiptowhite((char *)arg); if (*arg == '@') { - int id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1)); + int id = syn_scl_namen2id((char *)arg + 1, (int)(arg_end - arg - 1)); if (id == 0) { semsg(_("E392: No such syntax cluster: %s"), arg); } else { @@ -3553,7 +3296,7 @@ static void syn_cmd_list(exarg_T *eap, int syncing) arg = (char_u *)skipwhite((char *)arg_end); } } - eap->nextcmd = (char *)check_nextcmd(arg); + eap->nextcmd = check_nextcmd((char *)arg); } static void syn_lines_msg(void) @@ -3702,7 +3445,7 @@ static void syn_list_flags(struct name_list *nlist, int flags, int attr) { int i; - for (i = 0; nlist[i].flag != 0; ++i) { + for (i = 0; nlist[i].flag != 0; i++) { if (flags & nlist[i].flag) { msg_puts_attr(nlist[i].name, attr); msg_putchar(' '); @@ -3710,9 +3453,7 @@ static void syn_list_flags(struct name_list *nlist, int flags, int attr) } } -/* - * List one syntax cluster, for ":syntax" or "syntax list syntax_name". - */ +// List one syntax cluster, for ":syntax" or "syntax list syntax_name". static void syn_list_cluster(int id) { int endcol = 15; @@ -3790,14 +3531,14 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const msg_putchar(c); // output the pattern, in between a char that is not in the pattern - for (i = 0; vim_strchr((char *)spp->sp_pattern, sepchars[i]) != NULL;) { + for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL;) { if (sepchars[++i] == NUL) { i = 0; // no good char found, just use the first one break; } } msg_putchar(sepchars[i]); - msg_outtrans((char *)spp->sp_pattern); + msg_outtrans(spp->sp_pattern); msg_putchar(sepchars[i]); // output any pattern options @@ -3925,7 +3666,7 @@ static void syn_clear_keyword(int id, hashtab_T *ht) hash_lock(ht); todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) { + for (hi = ht->ht_array; todo > 0; hi++) { if (HASHITEM_EMPTY(hi)) { continue; } @@ -3956,9 +3697,7 @@ static void syn_clear_keyword(int id, hashtab_T *ht) hash_unlock(ht); } -/* - * Clear a whole keyword table. - */ +// Clear a whole keyword table. static void clear_keywtab(hashtab_T *ht) { hashitem_T *hi; @@ -3967,7 +3706,7 @@ static void clear_keywtab(hashtab_T *ht) keyentry_T *kp_next; todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) { + for (hi = ht->ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; for (kp = HI2KE(hi); kp != NULL; kp = kp_next) { @@ -3989,16 +3728,17 @@ static void clear_keywtab(hashtab_T *ht) /// @param flags flags for this keyword /// @param cont_in_list containedin for this keyword /// @param next_list nextgroup for this keyword -static void add_keyword(char_u *const name, const int id, const int flags, +static void add_keyword(char *const name, const int id, const int flags, int16_t *const cont_in_list, int16_t *const next_list, const int conceal_char) { - char_u name_folded[MAXKEYWLEN + 1]; - const char_u *const name_ic = (curwin->w_s->b_syn_ic) - ? str_foldcase(name, (int)STRLEN(name), name_folded, sizeof(name_folded)) + char name_folded[MAXKEYWLEN + 1]; + const char *const name_ic = (curwin->w_s->b_syn_ic) + ? (char *)str_foldcase((char_u *)name, (int)strlen(name), (char_u *)name_folded, + sizeof(name_folded)) : name; - keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + STRLEN(name_ic)); + keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + strlen(name_ic)); STRCPY(kp->keyword, name_ic); kp->k_syn.id = (int16_t)id; kp->k_syn.inc_tag = current_syn_inc_tag; @@ -4006,7 +3746,7 @@ static void add_keyword(char_u *const name, const int id, const int flags, kp->k_char = conceal_char; kp->k_syn.cont_in_list = copy_id_list(cont_in_list); if (cont_in_list != NULL) { - curwin->w_s->b_syn_containedin = TRUE; + curwin->w_s->b_syn_containedin = true; } kp->next_list = copy_id_list(next_list); @@ -4039,17 +3779,13 @@ static void add_keyword(char_u *const name, const int id, const int flags, /// /// @return a pointer to the first argument. /// Return NULL if the end of the command was found instead of further args. -static char_u *get_group_name(char_u *arg, char_u **name_end) +static char *get_group_name(char *arg, char **name_end) { - char_u *rest; - *name_end = skiptowhite(arg); - rest = (char_u *)skipwhite((char *)(*name_end)); + char *rest = skipwhite(*name_end); - /* - * Check if there are enough arguments. The first argument may be a - * pattern, where '|' is allowed, so only check for NUL. - */ + // Check if there are enough arguments. The first argument may be a + // pattern, where '|' is allowed, so only check for NUL. if (ends_excmd(*arg) || *rest == NUL) { return NULL; } @@ -4063,13 +3799,13 @@ static char_u *get_group_name(char_u *arg, char_u **name_end) /// /// @param arg next argument to be checked /// @param opt various things -/// @param skip TRUE if skipping over command +/// @param skip true if skipping over command /// /// @return a pointer to the next argument (which isn't an option). /// Return NULL for any error; -static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_char, int skip) +static char *get_syn_options(char *arg, syn_opt_arg_T *opt, int *conceal_char, int skip) { - char_u *gname_start, *gname; + char *gname_start, *gname; int syn_id; int len = 0; char *p; @@ -4108,11 +3844,9 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha } for (;;) { - /* - * This is used very often when a large number of keywords is defined. - * Need to skip quickly when no option name is found. - * Also avoid tolower(), it's slow. - */ + // This is used very often when a large number of keywords is defined. + // Need to skip quickly when no option name is found. + // Also avoid tolower(), it's slow. if (strchr(first_letters, *arg) == NULL) { break; } @@ -4120,8 +3854,8 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0;) { p = flagtab[fidx].name; int i; - for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) { - if (arg[len] != (char_u)p[i] && arg[len] != (char_u)p[i + 1]) { + for (i = 0, len = 0; p[i] != NUL; i += 2, len++) { + if (arg[len] != p[i] && arg[len] != p[i + 1]) { break; } } @@ -4161,16 +3895,16 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha } } else if (flagtab[fidx].argtype == 11 && arg[5] == '=') { // cchar=? - *conceal_char = utf_ptr2char((char *)arg + 6); - arg += utfc_ptr2len((char *)arg + 6) - 1; + *conceal_char = utf_ptr2char(arg + 6); + arg += utfc_ptr2len(arg + 6) - 1; if (!vim_isprintc_strict(*conceal_char)) { emsg(_("E844: invalid cchar value")); return NULL; } - arg = (char_u *)skipwhite((char *)arg + 7); + arg = skipwhite(arg + 7); } else { opt->flags |= flagtab[fidx].flags; - arg = (char_u *)skipwhite((char *)arg + len); + arg = skipwhite(arg + len); if (flagtab[fidx].flags == HL_SYNC_HERE || flagtab[fidx].flags == HL_SYNC_THERE) { @@ -4183,11 +3917,11 @@ 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, (size_t)(arg - gname_start)); - if (STRCMP(gname, "NONE") == 0) { + gname = xstrnsave(gname_start, (size_t)(arg - gname_start)); + if (strcmp(gname, "NONE") == 0) { *opt->sync_idx = NONE_IDX; } else { - syn_id = syn_name2id((char *)gname); + syn_id = syn_name2id(gname); int i; for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0;) { if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id @@ -4204,7 +3938,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha } xfree(gname); - arg = (char_u *)skipwhite((char *)arg); + arg = skipwhite(arg); } else if (flagtab[fidx].flags == HL_FOLD && foldmethodIsSyntax(curwin)) { // Need to update folds later. @@ -4216,11 +3950,9 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha return arg; } -/* - * Adjustments to syntax item when declared in a ":syn include"'d file. - * Set the contained flag, and if the item is not already contained, add it - * to the specified top-level group, if any. - */ +// Adjustments to syntax item when declared in a ":syn include"'d file. +// Set the contained flag, and if the item is not already contained, add it +// to the specified top-level group, if any. static void syn_incl_toplevel(int id, int *flagsp) { if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0) { @@ -4239,21 +3971,19 @@ static void syn_incl_toplevel(int id, int *flagsp) } } -/* - * Handle ":syntax include [@{group-name}] filename" command. - */ +// Handle ":syntax include [@{group-name}] filename" command. static void syn_cmd_include(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; + char *arg = eap->arg; int sgl_id = 1; - char_u *group_name_end; - char_u *rest; + char *group_name_end; + char *rest; char *errormsg = NULL; int prev_toplvl_grp; int prev_syn_inc_tag; bool source = false; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd(arg); if (eap->skip) { return; } @@ -4270,13 +4000,11 @@ static void syn_cmd_include(exarg_T *eap, int syncing) return; } // separate_nextcmd() and expand_filename() depend on this - eap->arg = (char *)rest; + eap->arg = rest; } - /* - * Everything that's left, up to the next command, should be the - * filename to include. - */ + // Everything that's left, up to the next command, should be the + // filename to include. eap->argt |= (EX_XFILE | EX_NOSPC); separate_nextcmd(eap); if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute((char_u *)eap->arg)) { @@ -4292,10 +4020,8 @@ static void syn_cmd_include(exarg_T *eap, int syncing) } } - /* - * Save and restore the existing top-level grouplist id and ":syn - * include" tag around the actual inclusion. - */ + // Save and restore the existing top-level grouplist id and ":syn + // include" tag around the actual inclusion. if (running_syn_inc_tag >= MAX_SYN_INC_TAG) { emsg(_("E847: Too many syntax includes")); return; @@ -4313,18 +4039,16 @@ static void syn_cmd_include(exarg_T *eap, int syncing) current_syn_inc_tag = prev_syn_inc_tag; } -/* - * Handle ":syntax keyword {group-name} [{option}] keyword .." command. - */ +// Handle ":syntax keyword {group-name} [{option}] keyword .." command. static void syn_cmd_keyword(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *group_name_end; + char *arg = eap->arg; + char *group_name_end; int syn_id; - char_u *rest; - char_u *keyword_copy = NULL; - char_u *p; - char_u *kw; + char *rest; + char *keyword_copy = NULL; + char *p; + char *kw; syn_opt_arg_T syn_opt_arg; int cnt; int conceal_char = NUL; @@ -4335,11 +4059,11 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) if (eap->skip) { syn_id = -1; } else { - syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg)); + syn_id = syn_check_group(arg, (size_t)(group_name_end - arg)); } if (syn_id != 0) { // Allocate a buffer, for removing backslashes in the keyword. - keyword_copy = xmalloc(STRLEN(rest) + 1); + keyword_copy = xmalloc(strlen(rest) + 1); } if (keyword_copy != NULL) { syn_opt_arg.flags = 0; @@ -4354,7 +4078,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) // 1: collect the options and copy the keywords to keyword_copy. cnt = 0; p = keyword_copy; - for (; rest != NULL && !ends_excmd(*rest); rest = (char_u *)skipwhite((char *)rest)) { + for (; rest != NULL && !ends_excmd(*rest); rest = skipwhite(rest)) { rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); if (rest == NULL || ends_excmd(*rest)) { break; @@ -4375,8 +4099,8 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) syn_incl_toplevel(syn_id, &syn_opt_arg.flags); // 2: Add an entry for each keyword. - for (kw = keyword_copy; --cnt >= 0; kw += STRLEN(kw) + 1) { - for (p = (char_u *)vim_strchr((char *)kw, '[');;) { + for (kw = keyword_copy; --cnt >= 0; kw += strlen(kw) + 1) { + for (p = vim_strchr(kw, '[');;) { if (p != NULL) { *p = NUL; } @@ -4399,7 +4123,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) kw = p + 1; break; // skip over the "]" } - const int l = utfc_ptr2len((char *)p + 1); + const int l = utfc_ptr2len(p + 1); memmove(p, p + 1, (size_t)l); p += l; @@ -4415,12 +4139,12 @@ error: } if (rest != NULL) { - eap->nextcmd = (char *)check_nextcmd(rest); + eap->nextcmd = check_nextcmd(rest); } else { semsg(_(e_invarg2), arg); } - redraw_curbuf_later(SOME_VALID); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } @@ -4428,12 +4152,11 @@ error: /// /// Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .." /// -/// @param syncing TRUE for ":syntax sync match .. " +/// @param syncing true for ":syntax sync match .. " static void syn_cmd_match(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *group_name_end; - char_u *rest; + char *arg = eap->arg; + char *group_name_end; synpat_T item; // the item found in the line int syn_id; syn_opt_arg_T syn_opt_arg; @@ -4441,7 +4164,7 @@ static void syn_cmd_match(exarg_T *eap, int syncing) int conceal_char = NUL; // Isolate the group name, check for validity - rest = get_group_name(arg, &group_name_end); + char *rest = get_group_name(arg, &group_name_end); // Get options before the pattern syn_opt_arg.flags = 0; @@ -4465,18 +4188,14 @@ static void syn_cmd_match(exarg_T *eap, int syncing) rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); if (rest != NULL) { // all arguments are valid - /* - * Check for trailing command and illegal trailing arguments. - */ - eap->nextcmd = (char *)check_nextcmd(rest); + // Check for trailing command and illegal trailing arguments. + eap->nextcmd = check_nextcmd(rest); if (!ends_excmd(*rest) || eap->skip) { rest = NULL; } else { - if ((syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg))) != 0) { + if ((syn_id = syn_check_group(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 - */ + // Store the pattern in the syn_items list synpat_T *spp = GA_APPEND_VIA_PTR(synpat_T, &curwin->w_s->b_syn_patterns); *spp = item; @@ -4490,7 +4209,7 @@ static void syn_cmd_match(exarg_T *eap, int syncing) spp->sp_syn.cont_in_list = syn_opt_arg.cont_in_list; spp->sp_cchar = conceal_char; if (syn_opt_arg.cont_in_list != NULL) { - curwin->w_s->b_syn_containedin = TRUE; + curwin->w_s->b_syn_containedin = true; } spp->sp_next_list = syn_opt_arg.next_list; @@ -4499,19 +4218,17 @@ static void syn_cmd_match(exarg_T *eap, int syncing) curwin->w_s->b_syn_sync_flags |= SF_MATCH; } if (syn_opt_arg.flags & HL_FOLD) { - ++curwin->w_s->b_syn_folditems; + curwin->w_s->b_syn_folditems++; } - redraw_curbuf_later(SOME_VALID); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. return; // don't free the progs and patterns now } } } - /* - * Something failed, free the allocated memory. - */ + // Something failed, free the allocated memory. vim_regfree(item.sp_prog); xfree(item.sp_pattern); xfree(syn_opt_arg.cont_list); @@ -4526,15 +4243,15 @@ static void syn_cmd_match(exarg_T *eap, int syncing) /// Handle ":syntax region {group-name} [matchgroup={group-name}] /// start {start} .. [skip {skip}] end {end} .. [{options}]". /// -/// @param syncing TRUE for ":syntax sync region .." +/// @param syncing true for ":syntax sync region .." static void syn_cmd_region(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *group_name_end; - char_u *rest; // next arg, NULL on error - char_u *key_end; - char_u *key = NULL; - char_u *p; + char *arg = eap->arg; + char *group_name_end; + char *rest; // next arg, NULL on error + char *key_end; + char *key = NULL; + char *p; int item; #define ITEM_START 0 #define ITEM_SKIP 1 @@ -4589,13 +4306,13 @@ static void syn_cmd_region(exarg_T *eap, int syncing) } xfree(key); key = vim_strnsave_up(rest, (size_t)(key_end - rest)); - if (STRCMP(key, "MATCHGROUP") == 0) { + if (strcmp(key, "MATCHGROUP") == 0) { item = ITEM_MATCHGROUP; - } else if (STRCMP(key, "START") == 0) { + } else if (strcmp(key, "START") == 0) { item = ITEM_START; - } else if (STRCMP(key, "END") == 0) { + } else if (strcmp(key, "END") == 0) { item = ITEM_END; - } else if (STRCMP(key, "SKIP") == 0) { + } else if (strcmp(key, "SKIP") == 0) { if (pat_ptrs[ITEM_SKIP] != NULL) { // One skip pattern allowed. illegal = true; break; @@ -4604,13 +4321,13 @@ static void syn_cmd_region(exarg_T *eap, int syncing) } else { break; } - rest = (char_u *)skipwhite((char *)key_end); + rest = skipwhite(key_end); if (*rest != '=') { rest = NULL; semsg(_("E398: Missing '=': %s"), arg); break; } - rest = (char_u *)skipwhite((char *)rest + 1); + rest = skipwhite(rest + 1); if (*rest == NUL) { not_enough = true; break; @@ -4621,19 +4338,17 @@ 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, (size_t)(p - rest)); + matchgroup_id = syn_check_group(rest, (size_t)(p - rest)); if (matchgroup_id == 0) { illegal = true; break; } } - rest = (char_u *)skipwhite((char *)p); + rest = skipwhite(p); } else { - /* - * Allocate room for a syn_pattern, and link it in the list of - * syn_patterns for this item, at the start (because the list is - * used from end to start). - */ + // Allocate room for a syn_pattern, and link it in the list of + // syn_patterns for this item, at the start (because the list is + // used from end to start). ppp = xmalloc(sizeof(struct pat_ptr)); ppp->pp_next = pat_ptrs[item]; pat_ptrs[item] = ppp; @@ -4671,22 +4386,18 @@ static void syn_cmd_region(exarg_T *eap, int syncing) } if (rest != NULL) { - /* - * Check for trailing garbage or command. - * If OK, add the item. - */ - eap->nextcmd = (char *)check_nextcmd(rest); + // Check for trailing garbage or command. + // If OK, add the item. + eap->nextcmd = check_nextcmd(rest); if (!ends_excmd(*rest) || eap->skip) { rest = NULL; } else { ga_grow(&(curwin->w_s->b_syn_patterns), pat_count); - if ((syn_id = syn_check_group((char *)arg, (size_t)(group_name_end - arg))) != 0) { + if ((syn_id = syn_check_group(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 - */ + // Store the start/skip/end in the syn_items list int idx = curwin->w_s->b_syn_patterns.ga_len; - for (item = ITEM_START; item <= ITEM_END; ++item) { + for (item = ITEM_START; item <= ITEM_END; item++) { for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp->pp_next) { SYN_ITEMS(curwin->w_s)[idx] = *(ppp->pp_synp); SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing; @@ -4705,7 +4416,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing) SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list = syn_opt_arg.cont_in_list; if (syn_opt_arg.cont_in_list != NULL) { - curwin->w_s->b_syn_containedin = TRUE; + curwin->w_s->b_syn_containedin = true; } SYN_ITEMS(curwin->w_s)[idx].sp_next_list = syn_opt_arg.next_list; @@ -4713,22 +4424,20 @@ static void syn_cmd_region(exarg_T *eap, int syncing) curwin->w_s->b_syn_patterns.ga_len++; idx++; if (syn_opt_arg.flags & HL_FOLD) { - ++curwin->w_s->b_syn_folditems; + curwin->w_s->b_syn_folditems++; } } } - redraw_curbuf_later(SOME_VALID); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. success = true; // don't free the progs and patterns now } } } - /* - * Free the allocated memory. - */ - for (item = ITEM_START; item <= ITEM_END; ++item) { + // Free the allocated memory. + for (item = ITEM_START; item <= ITEM_END; item++) { for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next) { if (!success && ppp->pp_synp != NULL) { vim_regfree(ppp->pp_synp->sp_prog); @@ -4771,9 +4480,7 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con const int16_t *g2; int16_t *clstr = NULL; - /* - * Handle degenerate cases. - */ + // Handle degenerate cases. if (*clstr2 == NULL) { return; } @@ -4809,13 +4516,9 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con g2 = *clstr2; int count = 0; - /* - * First, loop through the lists until one of them is empty. - */ + // First, loop through the lists until one of them is empty. while (*g1 && *g2) { - /* - * We always want to add from the first list. - */ + // We always want to add from the first list. if (*g1 < *g2) { if (round == 2) { clstr[count] = *g1; @@ -4824,10 +4527,8 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con g1++; continue; } - /* - * We only want to add from the second list if we're adding the - * lists. - */ + // We only want to add from the second list if we're adding the + // lists. if (list_op == CLUSTER_ADD) { if (round == 2) { clstr[count] = *g2; @@ -4840,11 +4541,9 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con g2++; } - /* - * Now add the leftovers from whichever list didn't get finished - * first. As before, we only want to add from the second list if - * we're adding the lists. - */ + // Now add the leftovers from whichever list didn't get finished + // first. As before, we only want to add from the second list if + // we're adding the lists. for (; *g1; g1++, count++) { if (round == 2) { clstr[count] = *g1; @@ -4859,10 +4558,8 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con } if (round == 1) { - /* - * If the group ended up empty, we don't need to allocate any - * space for it. - */ + // If the group ended up empty, we don't need to allocate any + // space for it. if (count == 0) { clstr = NULL; break; @@ -4872,24 +4569,22 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, con } } - /* - * Finally, put the new list in place. - */ + // Finally, put the new list in place. xfree(*clstr1); xfree(*clstr2); *clstr1 = clstr; } -// Lookup a syntax cluster name and return its ID. -// If it is not found, 0 is returned. -static int syn_scl_name2id(char_u *name) +/// Lookup a syntax cluster name and return its ID. +/// If it is not found, 0 is returned. +static int syn_scl_name2id(char *name) { // Avoid using stricmp() too much, it's slow on some systems - char_u *name_u = vim_strsave_up(name); + char *name_u = (char *)vim_strsave_up((char_u *)name); int i; for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0;) { if (SYN_CLSTR(curwin->w_s)[i].scl_name_u != NULL - && STRCMP(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0) { + && strcmp(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0) { break; } } @@ -4897,25 +4592,24 @@ static int syn_scl_name2id(char_u *name) return i < 0 ? 0 : i + SYNID_CLUSTER; } -/* - * Like syn_scl_name2id(), but take a pointer + length argument. - */ -static int syn_scl_namen2id(char_u *linep, int len) +/// Like syn_scl_name2id(), but take a pointer + length argument. +static int syn_scl_namen2id(char *linep, int len) { - char_u *name = vim_strnsave(linep, (size_t)len); + char *name = xstrnsave(linep, (size_t)len); int id = syn_scl_name2id(name); xfree(name); return id; } -// Find syntax cluster name in the table and return its ID. -// The argument is a pointer to the name and the length of the name. -// If it doesn't exist yet, a new entry is created. -// Return 0 for failure. -static int syn_check_cluster(char_u *pp, int len) +/// Find syntax cluster name in the table and return its ID. +/// The argument is a pointer to the name and the length of the name. +/// If it doesn't exist yet, a new entry is created. +/// +/// @return 0 for failure. +static int syn_check_cluster(char *pp, int len) { - char_u *name = vim_strnsave(pp, (size_t)len); + char *name = xstrnsave(pp, (size_t)len); int id = syn_scl_name2id(name); if (id == 0) { // doesn't exist yet id = syn_add_cluster(name); @@ -4925,14 +4619,13 @@ static int syn_check_cluster(char_u *pp, int len) return id; } -// Add new syntax cluster and return its ID. -// "name" must be an allocated string, it will be consumed. -// Return 0 for failure. -static int syn_add_cluster(char_u *name) +/// Add new syntax cluster and return its ID. +/// "name" must be an allocated string, it will be consumed. +/// +/// @return 0 for failure. +static int syn_add_cluster(char *name) { - /* - * First call for this growarray: init growing array. - */ + // First call for this growarray: init growing array. if (curwin->w_s->b_syn_clusters.ga_data == NULL) { curwin->w_s->b_syn_clusters.ga_itemsize = sizeof(syn_cluster_T); ga_set_growsize(&curwin->w_s->b_syn_clusters, 10); @@ -4948,8 +4641,8 @@ static int syn_add_cluster(char_u *name) syn_cluster_T *scp = GA_APPEND_VIA_PTR(syn_cluster_T, &curwin->w_s->b_syn_clusters); CLEAR_POINTER(scp); - scp->scl_name = name; - scp->scl_name_u = vim_strsave_up(name); + scp->scl_name = (char_u *)name; + scp->scl_name_u = (char *)vim_strsave_up((char_u *)name); scp->scl_list = NULL; if (STRICMP(name, "Spell") == 0) { @@ -4962,20 +4655,18 @@ static int syn_add_cluster(char_u *name) return len + SYNID_CLUSTER; } -/* - * Handle ":syntax cluster {cluster-name} [contains={groupname},..] - * [add={groupname},..] [remove={groupname},..]". - */ +// Handle ":syntax cluster {cluster-name} [contains={groupname},..] +// [add={groupname},..] [remove={groupname},..]". static void syn_cmd_cluster(exarg_T *eap, int syncing) { - char_u *arg = (char_u *)eap->arg; - char_u *group_name_end; - char_u *rest; + char *arg = eap->arg; + char *group_name_end; + char *rest; bool got_clstr = false; int opt_len; int list_op; - eap->nextcmd = (char *)find_nextcmd(arg); + eap->nextcmd = find_nextcmd(arg); if (eap->skip) { return; } @@ -5021,7 +4712,7 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing) } if (got_clstr) { - redraw_curbuf_later(SOME_VALID); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all. } } @@ -5034,21 +4725,18 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing) } } -/* - * On first call for current buffer: Init growing array. - */ +// On first call for current buffer: Init growing array. static void init_syn_patterns(void) { curwin->w_s->b_syn_patterns.ga_itemsize = sizeof(synpat_T); ga_set_growsize(&curwin->w_s->b_syn_patterns, 10); } -/* - * Get one pattern for a ":syntax match" or ":syntax region" command. - * Stores the pattern and program in a synpat_T. - * Returns a pointer to the next argument, or NULL in case of an error. - */ -static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) +/// Get one pattern for a ":syntax match" or ":syntax region" command. +/// Stores the pattern and program in a synpat_T. +/// +/// @return a pointer to the next argument, or NULL in case of an error. +static char *get_syn_pattern(char *arg, synpat_T *ci) { char *end; int *p; @@ -5060,18 +4748,18 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) return NULL; } - end = (char *)skip_regexp(arg + 1, *arg, true, NULL); - if (*end != (char)(*arg)) { // end delimiter not found + end = skip_regexp(arg + 1, *arg, true, NULL); + if (*end != *arg) { // end delimiter not found semsg(_("E401: Pattern delimiter not found: %s"), arg); return NULL; } // store the pattern and compiled regexp program - ci->sp_pattern = vim_strnsave(arg + 1, (size_t)(end - (char *)arg) - 1); + ci->sp_pattern = xstrnsave(arg + 1, (size_t)(end - arg) - 1); // Make 'cpoptions' empty, to avoid the 'l' flag cpo_save = p_cpo; - p_cpo = ""; - ci->sp_prog = vim_regcomp((char *)ci->sp_pattern, RE_MAGIC); + p_cpo = empty_option; + ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC); p_cpo = cpo_save; if (ci->sp_prog == NULL) { @@ -5080,9 +4768,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) ci->sp_ic = curwin->w_s->b_syn_ic; syn_clear_time(&ci->sp_time); - /* - * Check for a match, highlight or region offset. - */ + // Check for a match, highlight or region offset. end++; do { for (idx = SPO_COUNT; --idx >= 0;) { @@ -5137,43 +4823,41 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) semsg(_("E402: Garbage after pattern: %s"), arg); return NULL; } - return (char_u *)skipwhite(end); + return skipwhite(end); } -/* - * Handle ":syntax sync .." command. - */ +/// Handle ":syntax sync .." command. static void syn_cmd_sync(exarg_T *eap, int syncing) { - char_u *arg_start = (char_u *)eap->arg; + char *arg_start = eap->arg; char *arg_end; - char_u *key = NULL; - char_u *next_arg; + char *key = NULL; + char *next_arg; int illegal = false; int finished = false; char *cpo_save; if (ends_excmd(*arg_start)) { - syn_cmd_list(eap, TRUE); + syn_cmd_list(eap, true); return; } while (!ends_excmd(*arg_start)) { - arg_end = (char *)skiptowhite(arg_start); - next_arg = (char_u *)skipwhite(arg_end); + arg_end = skiptowhite(arg_start); + next_arg = skipwhite(arg_end); xfree(key); - key = vim_strnsave_up(arg_start, (size_t)(arg_end - (char *)arg_start)); - if (STRCMP(key, "CCOMMENT") == 0) { + 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; } if (!ends_excmd(*next_arg)) { - arg_end = (char *)skiptowhite(next_arg); + arg_end = skiptowhite(next_arg); if (!eap->skip) { curwin->w_s->b_syn_sync_id = - (int16_t)syn_check_group((char *)next_arg, (size_t)(arg_end - (char *)next_arg)); + (int16_t)syn_check_group(next_arg, (size_t)(arg_end - next_arg)); } - next_arg = (char_u *)skipwhite(arg_end); + next_arg = skipwhite(arg_end); } else if (!eap->skip) { curwin->w_s->b_syn_sync_id = (int16_t)syn_name2id("Comment"); } @@ -5182,14 +4866,14 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) || STRNCMP(key, "MAXLINES", 8) == 0 || STRNCMP(key, "LINEBREAKS", 10) == 0) { if (key[4] == 'S') { - arg_end = (char *)key + 6; + arg_end = key + 6; } else if (key[0] == 'L') { - arg_end = (char *)key + 11; + arg_end = key + 11; } else { - arg_end = (char *)key + 9; + arg_end = key + 9; } if (arg_end[-1] != '=' || !ascii_isdigit(*arg_end)) { - illegal = TRUE; + illegal = true; break; } linenr_T n = getdigits_int32(&arg_end, false, 0); @@ -5202,23 +4886,23 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) curwin->w_s->b_syn_sync_minlines = n; } } - } else if (STRCMP(key, "FROMSTART") == 0) { + } else if (strcmp(key, "FROMSTART") == 0) { if (!eap->skip) { curwin->w_s->b_syn_sync_minlines = MAXLNUM; curwin->w_s->b_syn_sync_maxlines = 0; } - } else if (STRCMP(key, "LINECONT") == 0) { + } else if (strcmp(key, "LINECONT") == 0) { if (*next_arg == NUL) { // missing pattern illegal = true; break; } if (curwin->w_s->b_syn_linecont_pat != NULL) { emsg(_("E403: syntax sync: line continuations pattern specified twice")); - finished = TRUE; + finished = true; break; } - arg_end = (char *)skip_regexp(next_arg + 1, *next_arg, true, NULL); - if (*arg_end != (char)(*next_arg)) { // end delimiter not found + arg_end = skip_regexp(next_arg + 1, *next_arg, true, NULL); + if (*arg_end != *next_arg) { // end delimiter not found illegal = true; break; } @@ -5226,14 +4910,14 @@ 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, (size_t)(arg_end - (char *)next_arg) - 1); + xstrnsave(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 cpo_save = p_cpo; - p_cpo = ""; + p_cpo = empty_option; curwin->w_s->b_syn_linecont_prog = - vim_regcomp((char *)curwin->w_s->b_syn_linecont_pat, RE_MAGIC); + vim_regcomp(curwin->w_s->b_syn_linecont_pat, RE_MAGIC); p_cpo = cpo_save; syn_clear_time(&curwin->w_s->b_syn_linecont_time); @@ -5243,19 +4927,19 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) break; } } - next_arg = (char_u *)skipwhite(arg_end + 1); + next_arg = skipwhite(arg_end + 1); } else { - eap->arg = (char *)next_arg; - if (STRCMP(key, "MATCH") == 0) { - syn_cmd_match(eap, TRUE); - } else if (STRCMP(key, "REGION") == 0) { - syn_cmd_region(eap, TRUE); - } else if (STRCMP(key, "CLEAR") == 0) { - syn_cmd_clear(eap, TRUE); + eap->arg = next_arg; + if (strcmp(key, "MATCH") == 0) { + syn_cmd_match(eap, true); + } else if (strcmp(key, "REGION") == 0) { + syn_cmd_region(eap, true); + } else if (strcmp(key, "CLEAR") == 0) { + syn_cmd_clear(eap, true); } else { - illegal = TRUE; + illegal = true; } - finished = TRUE; + finished = true; break; } arg_start = next_arg; @@ -5264,8 +4948,8 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) if (illegal) { semsg(_("E404: Illegal arguments: %s"), arg_start); } else if (!finished) { - eap->nextcmd = (char *)check_nextcmd(arg_start); - redraw_curbuf_later(SOME_VALID); + eap->nextcmd = check_nextcmd(arg_start); + redraw_curbuf_later(UPD_SOME_VALID); syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. } } @@ -5279,7 +4963,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) /// @param list where to store the resulting list, if not NULL, the list is silently skipped! /// /// @return FAIL for some error, OK for success. -static int get_id_list(char_u **const arg, const int keylen, int16_t **const list, const bool skip) +static int get_id_list(char **const arg, const int keylen, int16_t **const list, const bool skip) { char *p = NULL; char *end; @@ -5296,7 +4980,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis // grow when a regexp is used. In that case round 1 is done once again. for (int round = 1; round <= 2; round++) { // skip "contains" - p = skipwhite((char *)(*arg) + keylen); + p = skipwhite(*arg + keylen); if (*p != '=') { semsg(_("E405: Missing equal sign: %s"), *arg); break; @@ -5313,10 +4997,10 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) {} 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 - || STRCMP(name + 1, "TOP") == 0 - || STRCMP(name + 1, "CONTAINED") == 0) { + if (strcmp(name + 1, "ALLBUT") == 0 + || strcmp(name + 1, "ALL") == 0 + || strcmp(name + 1, "TOP") == 0 + || strcmp(name + 1, "CONTAINED") == 0) { if (TOUPPER_ASC(**arg) != 'C') { semsg(_("E407: %s not allowed here"), name + 1); failed = true; @@ -5345,12 +5029,10 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis if (skip) { id = -1; } else { - id = syn_check_cluster((char_u *)name + 2, (int)(end - p - 1)); + id = syn_check_cluster(name + 2, (int)(end - p - 1)); } } else { - /* - * Handle full group name. - */ + // Handle full group name. if (strpbrk(name + 1, "\\.*^$~[") == NULL) { id = syn_check_group((name + 1), (size_t)(end - p)); } else { @@ -5364,7 +5046,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis break; } - regmatch.rm_ic = TRUE; + regmatch.rm_ic = true; id = 0; for (int i = highlight_num_groups(); --i >= 0;) { if (vim_regexec(®match, (char *)highlight_group_name(i), (colnr_T)0)) { @@ -5421,7 +5103,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis } } - *arg = (char_u *)p; + *arg = p; if (failed || retval == NULL) { xfree(retval); return FAIL; @@ -5435,9 +5117,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis return OK; } -/* - * Make a copy of an ID list. - */ +// Make a copy of an ID list. static int16_t *copy_id_list(const int16_t *const list) { if (list == NULL) { @@ -5472,7 +5152,7 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in static int depth = 0; int r; - // If ssp has a "containedin" list and "cur_si" is in it, return TRUE. + // If ssp has a "containedin" list and "cur_si" is in it, return true. if (cur_si != NULL && ssp->cont_in_list != NULL && !(cur_si->si_flags & HL_MATCH)) { // Ignore transparent items without a contains argument. Double check @@ -5486,54 +5166,48 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in &(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn), SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags & HL_CONTAINED)) { - return TRUE; + return true; } } if (list == NULL) { - return FALSE; + return false; } - /* - * If list is ID_LIST_ALL, we are in a transparent item that isn't - * inside anything. Only allow not-contained groups. - */ + // If list is ID_LIST_ALL, we are in a transparent item that isn't + // inside anything. Only allow not-contained groups. if (list == ID_LIST_ALL) { return !contained; } - /* - * If the first item is "ALLBUT", return TRUE if "id" is NOT in the - * contains list. We also require that "id" is at the same ":syn include" - * level as the list. - */ + // If the first item is "ALLBUT", return true if "id" is NOT in the + // contains list. We also require that "id" is at the same ":syn include" + // level as the list. item = *list; if (item >= SYNID_ALLBUT && item < SYNID_CLUSTER) { if (item < SYNID_TOP) { // ALL or ALLBUT: accept all groups in the same file if (item - SYNID_ALLBUT != ssp->inc_tag) { - return FALSE; + return false; } } else if (item < SYNID_CONTAINED) { // TOP: accept all not-contained groups in the same file if (item - SYNID_TOP != ssp->inc_tag || contained) { - return FALSE; + return false; } } else { // CONTAINED: accept all contained groups in the same file if (item - SYNID_CONTAINED != ssp->inc_tag || !contained) { - return FALSE; + return false; } } item = *++list; - retval = FALSE; + retval = false; } else { - retval = TRUE; + retval = true; } - /* - * Return "retval" if id is in the contains list. - */ + // Return "retval" if id is in the contains list. while (item != 0) { if (item == id) { return retval; @@ -5585,21 +5259,19 @@ static struct subcommand subcommands[] = { NULL, NULL } }; -/* - * ":syntax". - * This searches the subcommands[] table for the subcommand name, and calls a - * syntax_subcommand() function to do the rest. - */ +/// ":syntax". +/// This searches the subcommands[] table for the subcommand name, and calls a +/// syntax_subcommand() function to do the rest. void ex_syntax(exarg_T *eap) { - char_u *arg = (char_u *)eap->arg; - char_u *subcmd_end; + char *arg = eap->arg; + char *subcmd_end; 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, (size_t)(subcmd_end - arg)); + char *const subcmd_name = xstrnsave(arg, (size_t)(subcmd_end - arg)); if (eap->skip) { // skip error messages for all subcommands emsg_skip++; } @@ -5608,8 +5280,8 @@ void ex_syntax(exarg_T *eap) semsg(_("E410: Invalid :syntax subcommand: %s"), subcmd_name); break; } - if (STRCMP(subcmd_name, (char_u *)subcommands[i].name) == 0) { - eap->arg = skipwhite((char *)subcmd_end); + if (strcmp(subcmd_name, subcommands[i].name) == 0) { + eap->arg = skipwhite(subcmd_end); (subcommands[i].func)(eap, false); break; } @@ -5622,8 +5294,8 @@ void ex_syntax(exarg_T *eap) void ex_ownsyntax(exarg_T *eap) { - char_u *old_value; - char_u *new_value; + char *old_value; + char *new_value; if (curwin->w_s == &curwin->w_buffer->b_s) { curwin->w_s = xcalloc(1, sizeof(synblock_T)); @@ -5640,25 +5312,25 @@ void ex_ownsyntax(exarg_T *eap) } // Save value of b:current_syntax. - old_value = get_var_value("b:current_syntax"); + old_value = (char *)get_var_value("b:current_syntax"); if (old_value != NULL) { - old_value = vim_strsave(old_value); + old_value = xstrdup(old_value); } // Apply the "syntax" autocommand event, this finds and loads the syntax file. apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, true, curbuf); // Move value of b:current_syntax to w:current_syntax. - new_value = get_var_value("b:current_syntax"); + new_value = (char *)get_var_value("b:current_syntax"); if (new_value != NULL) { - set_internal_string_var("w:current_syntax", (char *)new_value); + set_internal_string_var("w:current_syntax", new_value); } // Restore value of b:current_syntax. if (old_value == NULL) { do_unlet(S_LEN("b:current_syntax"), true); } else { - set_internal_string_var("b:current_syntax", (char *)old_value); + set_internal_string_var("b:current_syntax", old_value); xfree(old_value); } } @@ -5675,22 +5347,19 @@ static enum { EXP_SUBCMD, // expand ":syn" sub-commands EXP_CASE, // expand ":syn case" arguments EXP_SPELL, // expand ":syn spell" arguments - EXP_SYNC, // expand ":syn sync" arguments + EXP_SYNC, // expand ":syn sync" arguments + EXP_CLUSTER, // expand ":syn list @cluster" arguments } expand_what; -/* - * Reset include_link, include_default, include_none to 0. - * Called when we are done expanding. - */ +// Reset include_link, include_default, include_none to 0. +// Called when we are done expanding. void reset_expand_highlight(void) { include_link = include_default = include_none = 0; } -/* - * Handle command line completion for :match and :echohl command: Add "None" - * as highlight group. - */ +// Handle command line completion for :match and :echohl command: Add "None" +// as highlight group. void set_context_in_echohl_cmd(expand_T *xp, const char *arg) { xp->xp_context = EXPAND_HIGHLIGHT; @@ -5698,9 +5367,7 @@ void set_context_in_echohl_cmd(expand_T *xp, const char *arg) include_none = 1; } -/* - * Handle command line completion for :syntax command. - */ +// Handle command line completion for :syntax command. void set_context_in_syntax_cmd(expand_T *xp, const char *arg) { // Default: expand subcommands. @@ -5712,10 +5379,10 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg) // (part of) subcommand already typed if (*arg != NUL) { - const char *p = (const char *)skiptowhite((const char_u *)arg); + const char *p = (const char *)skiptowhite(arg); if (*p != NUL) { // Past first word. xp->xp_pattern = skipwhite(p); - if (*skiptowhite((char_u *)xp->xp_pattern) != NUL) { + if (*skiptowhite(xp->xp_pattern) != NUL) { xp->xp_context = EXPAND_NOTHING; } else if (STRNICMP(arg, "case", p - arg) == 0) { expand_what = EXP_CASE; @@ -5723,10 +5390,16 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg) expand_what = EXP_SPELL; } else if (STRNICMP(arg, "sync", p - arg) == 0) { expand_what = EXP_SYNC; + } else if (STRNICMP(arg, "list", p - arg) == 0) { + p = skipwhite(p); + if (*p == '@') { + expand_what = EXP_CLUSTER; + } else { + xp->xp_context = EXPAND_HIGHLIGHT; + } } else if (STRNICMP(arg, "keyword", p - arg) == 0 || STRNICMP(arg, "region", p - arg) == 0 - || STRNICMP(arg, "match", p - arg) == 0 - || STRNICMP(arg, "list", p - arg) == 0) { + || STRNICMP(arg, "match", p - arg) == 0) { xp->xp_context = EXPAND_HIGHLIGHT; } else { xp->xp_context = EXPAND_NOTHING; @@ -5735,10 +5408,8 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg) } } -/* - * Function given to ExpandGeneric() to obtain the list syntax names for - * expansion. - */ +// Function given to ExpandGeneric() to obtain the list syntax names for +// expansion. char *get_syntax_name(expand_T *xp, int idx) { switch (expand_what) { @@ -5760,6 +5431,14 @@ char *get_syntax_name(expand_T *xp, int idx) "maxlines=", "minlines=", "region", NULL }; return sync_args[idx]; } + case EXP_CLUSTER: + if (idx < curwin->w_s->b_syn_clusters.ga_len) { + vim_snprintf(xp->xp_buf, EXPAND_BUF_LEN, "@%s", + SYN_CLSTR(curwin->w_s)[idx].scl_name); + return xp->xp_buf; + } else { + return NULL; + } } return NULL; } @@ -5786,12 +5465,10 @@ int syn_get_id(win_T *wp, linenr_T lnum, colnr_T col, int trans, bool *spellp, i return trans ? current_trans_id : current_id; } -/* - * Get extra information about the syntax item. Must be called right after - * get_syntax_attr(). - * Stores the current item sequence nr in "*seqnrp". - * Returns the current flags. - */ +// Get extra information about the syntax item. Must be called right after +// get_syntax_attr(). +// Stores the current item sequence nr in "*seqnrp". +// Returns the current flags. int get_syntax_info(int *seqnrp) { *seqnrp = current_seqnr; @@ -5815,24 +5492,20 @@ int syn_get_concealed_id(win_T *wp, linenr_T lnum, colnr_T col) return 0; } -/* - * Return conceal substitution character - */ +// Return conceal substitution character int syn_get_sub_char(void) { return current_sub_char; } -/* - * Return the syntax ID at position "i" in the current stack. - * The caller must have called syn_get_id() before to fill the stack. - * Returns -1 when "i" is out of range. - */ +// Return the syntax ID at position "i" in the current stack. +// The caller must have called syn_get_id() before to fill the stack. +// Returns -1 when "i" is out of range. int syn_get_stack_item(int i) { if (i >= current_state.ga_len) { // Need to invalidate the state, because we didn't properly finish it - // for the last character, "keep_state" was TRUE. + // for the last character, "keep_state" was true. invalidate_current_state(); current_col = MAXCOL; return -1; @@ -5890,18 +5563,16 @@ int syn_get_foldlevel(win_T *wp, linenr_T lnum) return level; } -/* - * ":syntime". - */ +// ":syntime". void ex_syntime(exarg_T *eap) { - if (STRCMP(eap->arg, "on") == 0) { + if (strcmp(eap->arg, "on") == 0) { syn_time_on = true; - } else if (STRCMP(eap->arg, "off") == 0) { + } else if (strcmp(eap->arg, "off") == 0) { syn_time_on = false; - } else if (STRCMP(eap->arg, "clear") == 0) { + } else if (strcmp(eap->arg, "clear") == 0) { syntime_clear(); - } else if (STRCMP(eap->arg, "report") == 0) { + } else if (strcmp(eap->arg, "report") == 0) { syntime_report(); } else { semsg(_(e_invarg2), eap->arg); @@ -5916,9 +5587,7 @@ static void syn_clear_time(syn_time_T *st) st->match = 0; } -/* - * Clear the syntax timing for the current buffer. - */ +// Clear the syntax timing for the current buffer. static void syntime_clear(void) { synpat_T *spp; @@ -5927,16 +5596,14 @@ static void syntime_clear(void) msg(_(msg_no_items)); return; } - for (int idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx) { + for (int idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; idx++) { spp = &(SYN_ITEMS(curwin->w_s)[idx]); syn_clear_time(&spp->sp_time); } } -/* - * Function given to ExpandGeneric() to obtain the possible arguments of the - * ":syntime {on,off,clear,report}" command. - */ +// Function given to ExpandGeneric() to obtain the possible arguments of the +// ":syntime {on,off,clear,report}" command. char *get_syntime_arg(expand_T *xp, int idx) { switch (idx) { @@ -5960,9 +5627,7 @@ static int syn_compare_syntime(const void *v1, const void *v2) return profile_cmp(s1->total, s2->total); } -/* - * Clear the syntax timing for the current buffer. - */ +// Clear the syntax timing for the current buffer. static void syntime_report(void) { if (!syntax_present(curwin)) { @@ -5976,7 +5641,7 @@ static void syntime_report(void) proftime_T total_total = profile_zero(); int total_count = 0; time_entry_T *p; - for (int idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx) { + for (int idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; idx++) { synpat_T *spp = &(SYN_ITEMS(curwin->w_s)[idx]); if (spp->sp_time.count > 0) { p = GA_APPEND_VIA_PTR(time_entry_T, &ga); @@ -5989,7 +5654,7 @@ static void syntime_report(void) 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; + p->pattern = (char_u *)spp->sp_pattern; } } @@ -6002,7 +5667,7 @@ static void syntime_report(void) msg_puts_title(_(" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN")); msg_puts("\n"); - for (int idx = 0; idx < ga.ga_len && !got_int; ++idx) { + for (int idx = 0; idx < ga.ga_len && !got_int; idx++) { p = ((time_entry_T *)ga.ga_data) + idx; msg_puts(profile_msg(p->total)); @@ -6033,7 +5698,7 @@ static void syntime_report(void) if (len > (int)STRLEN(p->pattern)) { len = (int)STRLEN(p->pattern); } - msg_outtrans_len(p->pattern, len); + msg_outtrans_len((char *)p->pattern, len); msg_puts("\n"); } ga_clear(&ga); diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 65c56bf01b..a8d8eebb0d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1,9 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * Code to handle tags and the tag stack - */ +// Code to handle tags and the tag stack #include <assert.h> #include <inttypes.h> @@ -51,12 +49,10 @@ #include "nvim/vim.h" #include "nvim/window.h" -/* - * Structure to hold pointers to various items in a tag line. - */ +// Structure to hold pointers to various items in a tag line. typedef struct tag_pointers { // filled in by parse_tag_line(): - char_u *tagname; // start of tag name (skip "file:") + char *tagname; // start of tag name (skip "file:") char_u *tagname_end; // char after tag name char_u *fname; // first char of file name char_u *fname_end; // char after file name @@ -65,16 +61,14 @@ typedef struct tag_pointers { char_u *command_end; // first char after command char_u *tag_fname; // file name of the tags file. This is used // when 'tr' is set. - char_u *tagkind; // "kind:" value - char_u *tagkind_end; // end of tagkind - char_u *user_data; // user_data string + char_u *tagkind; // "kind:" value + char_u *tagkind_end; // end of tagkind + char *user_data; // user_data string char_u *user_data_end; // end of user_data - linenr_T tagline; // "line:" value + linenr_T tagline; // "line:" value } tagptrs_T; -/* - * Structure to hold info about the tag pattern being used. - */ +// Structure to hold info about the tag pattern being used. typedef struct { char_u *pat; // the pattern int len; // length of pat[] @@ -101,7 +95,7 @@ static char *mt_names[MT_COUNT/2] = { "FSC", "F C", "F ", "FS ", " SC", " C", " ", " S " }; #define NOTAGFILE 99 // return value for jumpto_tag -static char_u *nofile_fname = NULL; // fname for NOTAGFILE error +static char *nofile_fname = NULL; // fname for NOTAGFILE error #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tag.c.generated.h" @@ -114,12 +108,10 @@ static char_u *recurmsg static char_u *tfu_inv_ret_msg = (char_u *)N_("E987: invalid return value from tagfunc"); -static char_u *tagmatchname = NULL; // name of last used tag +static char *tagmatchname = NULL; // name of last used tag -/* - * Tag for preview window is remembered separately, to avoid messing up the - * normal tagstack. - */ +// Tag for preview window is remembered separately, to avoid messing up the +// normal tagstack. static taggy_T ptag_entry = { NULL, INIT_FMARK, 0, 0, NULL }; static int tfu_in_use = false; // disallow recursive call of tagfunc @@ -149,7 +141,7 @@ static int tfu_in_use = false; // disallow recursive call of tagfunc /// @param tag tag (pattern) to jump to /// @param forceit :ta with ! /// @param verbose print "tag not found" message -bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) +bool do_tag(char *tag, int type, int count, int forceit, int verbose) { taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; @@ -215,7 +207,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) new_tag = true; if (g_do_tagpreview != 0) { tagstack_clear_entry(&ptag_entry); - ptag_entry.tagname = vim_strsave(tag); + ptag_entry.tagname = xstrdup(tag); } } else { if (g_do_tagpreview != 0) { @@ -232,20 +224,18 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) )) { if (g_do_tagpreview != 0) { if (ptag_entry.tagname != NULL - && STRCMP(ptag_entry.tagname, tag) == 0) { + && strcmp(ptag_entry.tagname, tag) == 0) { // Jumping to same tag: keep the current match, so that // the CursorHold autocommand example works. cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else { tagstack_clear_entry(&ptag_entry); - ptag_entry.tagname = vim_strsave(tag); + ptag_entry.tagname = xstrdup(tag); } } else { - /* - * If the last used entry is not at the top, delete all tag - * stack entries above it. - */ + // If the last used entry is not at the top, delete all tag + // stack entries above it. while (tagstackidx < tagstacklen) { tagstack_clear_entry(&tagstack[--tagstacklen]); } @@ -261,7 +251,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) } // put the tag name in the tag stack - tagstack[tagstackidx].tagname = vim_strsave(tag); + tagstack[tagstackidx].tagname = xstrdup(tag); curwin->w_tagstacklen = tagstacklen; @@ -299,10 +289,8 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) // tagstack before it's used. saved_fmark = tagstack[tagstackidx].fmark; if (saved_fmark.fnum != curbuf->b_fnum) { - /* - * Jump to other file. If this fails (e.g. because the - * file was changed) keep original position in tag stack. - */ + // Jump to other file. If this fails (e.g. because the + // file was changed) keep original position in tag stack. if (buflist_getfile(saved_fmark.fnum, saved_fmark.mark.lnum, GETF_SETMARK, forceit) == FAIL) { tagstackidx = oldtagstackidx; // back to old posn @@ -339,11 +327,9 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) // ":tag" (no argument): go to newer pattern save_pos = true; // save the cursor position below if ((tagstackidx += count - 1) >= tagstacklen) { - /* - * Beyond the last one, just give an error message and - * go to the last one. Don't store the cursor - * position. - */ + // Beyond the last one, just give an error message and + // go to the last one. Don't store the cursor + // position. tagstackidx = tagstacklen - 1; emsg(_(topmsg)); save_pos = false; @@ -400,9 +386,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) ptag_entry.cur_fnum = cur_fnum; } } else { - /* - * For ":tag [arg]" or ":tselect" remember position before the jump. - */ + // For ":tag [arg]" or ":tselect" remember position before the jump. saved_fmark = tagstack[tagstackidx].fmark; if (save_pos) { tagstack[tagstackidx].fmark.mark = curwin->w_cursor; @@ -431,12 +415,10 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) } } - /* - * Repeat searching for tags, when a file has not been found. - */ + // Repeat searching for tags, when a file has not been found. for (;;) { int other_name; - char_u *name; + char *name; // When desired match not found yet, try to find it (and others). if (use_tagstack) { @@ -446,13 +428,13 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) } else { name = tag; } - other_name = (tagmatchname == NULL || STRCMP(tagmatchname, name) != 0); + other_name = (tagmatchname == NULL || strcmp(tagmatchname, name) != 0); if (new_tag || (cur_match >= num_matches && max_num_matches != MAXCOL) || other_name) { if (other_name) { xfree(tagmatchname); - tagmatchname = vim_strsave(name); + tagmatchname = xstrdup(name); } if (type == DT_SELECT || type == DT_JUMP @@ -484,7 +466,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) } if (find_tags(name, &new_num_matches, &new_matches, flags, - max_num_matches, buf_ffname) == OK + max_num_matches, (char *)buf_ffname) == OK && new_num_matches < max_num_matches) { max_num_matches = MAXCOL; // If less than max_num_matches // found: all matches found. @@ -501,10 +483,10 @@ 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((char_u *)matches[j], &tagp); + parse_match(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) { + parse_match(new_matches[i], &tagp2); + if (strcmp(tagp.tagname, tagp2.tagname) == 0) { char_u *p = (char_u *)new_matches[i]; for (k = i; k > idx; k--) { new_matches[k] = new_matches[k - 1]; @@ -539,7 +521,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) print_tag_list(new_tag, use_tagstack, num_matches, matches); ask_for_selection = true; } else if (type == DT_LTAG) { - if (add_llist_tags(tag, num_matches, matches) == FAIL) { + if (add_llist_tags((char_u *)tag, num_matches, matches) == FAIL) { goto end_do_tag; } @@ -584,12 +566,11 @@ 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((char_u *)matches[cur_match], &tagp2) == OK + if (use_tfu && parse_match(matches[cur_match], &tagp2) == OK && tagp2.user_data) { XFREE_CLEAR(tagstack[tagstackidx].user_data); - tagstack[tagstackidx].user_data = vim_strnsave(tagp2.user_data, - (size_t)(tagp2.user_data_end - - tagp2.user_data)); + tagstack[tagstackidx].user_data = + xstrnsave(tagp2.user_data, (size_t)(tagp2.user_data_end - (char_u *)tagp2.user_data)); } tagstackidx++; @@ -598,10 +579,8 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) ptag_entry.cur_fnum = cur_fnum; } - /* - * Only when going to try the next match, report that the previous - * file didn't exist. Otherwise an emsg() is given below. - */ + // Only when going to try the next match, report that the previous + // file didn't exist. Otherwise an emsg() is given below. if (nofile_fname != NULL && error_cur_match != cur_match) { smsg(_("File \"%s\" does not exist"), nofile_fname); } @@ -640,9 +619,7 @@ bool do_tag(char_u *tag, int type, int count, int forceit, int verbose) vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name); set_vim_var_string(VV_SWAPCOMMAND, (char *)IObuff, -1); - /* - * Jump to the desired match. - */ + // Jump to the desired match. i = jumpto_tag((char_u *)matches[cur_match], forceit, type != DT_CSCOPE); set_vim_var_string(VV_SWAPCOMMAND, NULL, -1); @@ -704,8 +681,8 @@ 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((char_u *)matches[0], &tagp); - taglen = (int)(tagp.tagname_end - tagp.tagname + 2); + parse_match(matches[0], &tagp); + taglen = (int)(tagp.tagname_end - (char_u *)tagp.tagname + 2); if (taglen < 18) { taglen = 18; } @@ -722,7 +699,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((char_u *)matches[i], &tagp); + parse_match(matches[i], &tagp); if (!new_tag && ( (g_do_tagpreview != 0 && i == ptag_entry.cur_match) @@ -737,12 +714,12 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char mt_names[matches[i][0] & MT_MASK]); msg_puts((char *)IObuff); if (tagp.tagkind != NULL) { - msg_outtrans_len(tagp.tagkind, + msg_outtrans_len((char *)tagp.tagkind, (int)(tagp.tagkind_end - tagp.tagkind)); } msg_advance(13); msg_outtrans_len_attr(tagp.tagname, - (int)(tagp.tagname_end - tagp.tagname), + (int)(tagp.tagname_end - (char_u *)tagp.tagname), HL_ATTR(HLF_T)); msg_putchar(' '); taglen_advance(taglen); @@ -751,7 +728,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char // it and put "..." in the middle p = tag_full_fname(&tagp); if (p != NULL) { - msg_outtrans_attr(p, HL_ATTR(HLF_D)); + msg_outtrans_attr((char *)p, HL_ATTR(HLF_D)); XFREE_CLEAR(p); } if (msg_col > 0) { @@ -793,7 +770,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char } msg_advance(15); } - p = msg_outtrans_one(p, attr); + p = (char_u *)msg_outtrans_one((char *)p, attr); if (*p == TAB) { msg_puts_attr(" ", attr); break; @@ -851,7 +828,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char msg_putchar(' '); p++; } else { - p = msg_outtrans_one(p, 0); + p = (char_u *)msg_outtrans_one((char *)p, 0); } // don't display the "$/;\"" and "$?;\"" @@ -896,10 +873,10 @@ static int add_llist_tags(char_u *tag, int num_matches, char **matches) long lnum; dict_T *dict; - parse_match((char_u *)matches[i], &tagp); + parse_match(matches[i], &tagp); // Save the tag name - len = (int)(tagp.tagname_end - tagp.tagname); + len = (int)(tagp.tagname_end - (char_u *)tagp.tagname); if (len > 128) { len = 128; } @@ -1005,9 +982,7 @@ static int add_llist_tags(char_u *tag, int num_matches, char **matches) return OK; } -/* - * Free cached tags. - */ +// Free cached tags. void tag_freematch(void) { XFREE_CLEAR(tagmatchname); @@ -1023,9 +998,7 @@ static void taglen_advance(int l) } } -/* - * Print the tag stack - */ +// Print the tag stack void do_tags(exarg_T *eap) { int i; @@ -1036,7 +1009,7 @@ void do_tags(exarg_T *eap) // Highlight title msg_puts_title(_("\n # TO tag FROM line in file/text")); - for (i = 0; i < tagstacklen; ++i) { + for (i = 0; i < tagstacklen; i++) { if (tagstack[i].tagname != NULL) { name = fm_getname(&(tagstack[i].fmark), 30); if (name == NULL) { // file name not available @@ -1051,22 +1024,19 @@ void do_tags(exarg_T *eap) tagstack[i].tagname, tagstack[i].fmark.mark.lnum); msg_outtrans((char *)IObuff); - msg_outtrans_attr(name, tagstack[i].fmark.fnum == curbuf->b_fnum + msg_outtrans_attr((char *)name, tagstack[i].fmark.fnum == curbuf->b_fnum ? HL_ATTR(HLF_D) : 0); xfree(name); } - ui_flush(); // show one line at a time } if (tagstackidx == tagstacklen) { // idx at top of stack msg_puts("\n>"); } } -/* - * Compare two strings, for length "len", ignoring case the ASCII way. - * return 0 for match, < 0 for smaller, > 0 for bigger - * Make sure case is folded to uppercase in comparison (like for 'sort -f') - */ +// Compare two strings, for length "len", ignoring case the ASCII way. +// return 0 for match, < 0 for smaller, > 0 for bigger +// Make sure case is folded to uppercase in comparison (like for 'sort -f') static int tag_strnicmp(char_u *s1, char_u *s2, size_t len) { int i; @@ -1086,9 +1056,7 @@ static int tag_strnicmp(char_u *s1, char_u *s2, size_t len) return 0; // strings match } -/* - * Extract info from the tag search pattern "pats->pat". - */ +// Extract info from the tag search pattern "pats->pat". static void prepare_pats(pat_T *pats, int has_re) { pats->head = pats->pat; @@ -1184,7 +1152,7 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl flags & TAG_REGEXP ? "r": ""); save_pos = curwin->w_cursor; - result = call_vim_function((char *)curbuf->b_p_tfu, 3, args, &rettv); + result = call_vim_function(curbuf->b_p_tfu, 3, args, &rettv); curwin->w_cursor = save_pos; // restore the cursor position d->dv_refcount--; @@ -1203,7 +1171,7 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl taglist = rettv.vval.v_list; TV_LIST_ITER_CONST(taglist, li, { - char_u *res_name; + char *res_name; char_u *res_fname; char_u *res_cmd; char_u *res_kind; @@ -1222,34 +1190,34 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl res_kind = NULL; TV_DICT_ITER(TV_LIST_ITEM_TV(li)->vval.v_dict, di, { - const char_u *dict_key = di->di_key; + const char *dict_key = (char *)di->di_key; typval_T *tv = &di->di_tv; if (tv->v_type != VAR_STRING || tv->vval.v_string == NULL) { continue; } - len += STRLEN(tv->vval.v_string) + 1; // Space for "\tVALUE" - if (!STRCMP(dict_key, "name")) { - res_name = (char_u *)tv->vval.v_string; + len += strlen(tv->vval.v_string) + 1; // Space for "\tVALUE" + if (!strcmp(dict_key, "name")) { + res_name = tv->vval.v_string; continue; } - if (!STRCMP(dict_key, "filename")) { + if (!strcmp(dict_key, "filename")) { res_fname = (char_u *)tv->vval.v_string; continue; } - if (!STRCMP(dict_key, "cmd")) { + if (!strcmp(dict_key, "cmd")) { res_cmd = (char_u *)tv->vval.v_string; continue; } has_extra = 1; - if (!STRCMP(dict_key, "kind")) { + if (!strcmp(dict_key, "kind")) { res_kind = (char_u *)tv->vval.v_string; continue; } // Other elements will be stored as "\tKEY:VALUE" // Allocate space for the key and the colon - len += STRLEN(dict_key) + 1; + len += strlen(dict_key) + 1; }); if (has_extra) { @@ -1261,10 +1229,10 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl break; } - char_u *const mfp = name_only ? vim_strsave(res_name) : xmalloc(len + 2); + char *const mfp = name_only ? xstrdup(res_name) : xmalloc(len + 2); if (!name_only) { - char_u *p = mfp; + char_u *p = (char_u *)mfp; *p++ = MT_GL_OTH + 1; // mtt *p++ = TAG_SEP; // no tag file name @@ -1291,22 +1259,22 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl } TV_DICT_ITER(TV_LIST_ITEM_TV(li)->vval.v_dict, di, { - const char_u *dict_key = di->di_key; + const char *dict_key = (char *)di->di_key; typval_T *tv = &di->di_tv; if (tv->v_type != VAR_STRING || tv->vval.v_string == NULL) { continue; } - if (!STRCMP(dict_key, "name")) { + if (!strcmp(dict_key, "name")) { continue; } - if (!STRCMP(dict_key, "filename")) { + if (!strcmp(dict_key, "filename")) { continue; } - if (!STRCMP(dict_key, "cmd")) { + if (!strcmp(dict_key, "cmd")) { continue; } - if (!STRCMP(dict_key, "kind")) { + if (!strcmp(dict_key, "kind")) { continue; } @@ -1365,8 +1333,8 @@ 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 ***matchesp, int flags, int mincount, - char_u *buf_ffname) +int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int mincount, + char *buf_ffname) { FILE *fp; char_u *lbuf; // line buffer @@ -1409,7 +1377,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi int cmplen; int match; // matches - int match_no_ic = 0; // matches with rm_ic == FALSE + int match_no_ic = 0; // matches with rm_ic == false int match_re; // match with regexp int matchoff = 0; int save_emsg_off; @@ -1425,7 +1393,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi int help_pri = 0; char_u *help_lang_find = NULL; // lang to be found char_u help_lang[3]; // lang of current tags file - char_u *saved_pat = NULL; // copy of pat[] + char *saved_pat = NULL; // copy of pat[] bool is_txt = false; pat_T orgpat; // holds unconverted pattern info @@ -1441,7 +1409,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi int help_only = (flags & TAG_HELP); int name_only = (flags & TAG_NAMES); int noic = (flags & TAG_NOIC); - int get_it_again = FALSE; + int get_it_again = false; int use_cscope = (flags & TAG_CSCOPE); int verbose = (flags & TAG_VERBOSE); int use_tfu = ((flags & TAG_NO_TAGFUNC) == 0); @@ -1459,23 +1427,21 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi p_ic = false; break; case TC_FOLLOWSCS: - p_ic = ignorecase(pat); + p_ic = ignorecase((char_u *)pat); break; case TC_SMART: - p_ic = ignorecase_opt(pat, true, true); + p_ic = ignorecase_opt((char_u *)pat, true, true); break; default: abort(); } help_save = curbuf->b_help; - orgpat.pat = pat; + orgpat.pat = (char_u *)pat; orgpat.regmatch.regprog = NULL; vimconv.vc_type = CONV_NONE; - /* - * Allocate memory for the buffers that are used - */ + // Allocate memory for the buffers that are used lbuf = xmalloc((size_t)lbuf_size); tag_fname = xmalloc(MAXPATHL + 1); for (mtt = 0; mtt < MT_COUNT; mtt++) { @@ -1485,9 +1451,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi STRCPY(tag_fname, "from cscope"); // for error messages - /* - * Initialize a few variables - */ + // Initialize a few variables if (help_only) { // want tags from help file curbuf->b_help = true; // will be restored later } else if (use_cscope) { @@ -1496,16 +1460,16 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi curbuf->b_help = false; } - orgpat.len = (int)STRLEN(pat); + orgpat.len = (int)strlen(pat); if (curbuf->b_help) { // When "@ab" is specified use only the "ab" language, otherwise // search all languages. if (orgpat.len > 3 && pat[orgpat.len - 3] == '@' && ASCII_ISALPHA(pat[orgpat.len - 2]) && ASCII_ISALPHA(pat[orgpat.len - 1])) { - saved_pat = vim_strnsave(pat, (size_t)orgpat.len - 3); - help_lang_find = &pat[orgpat.len - 2]; - orgpat.pat = saved_pat; + saved_pat = xstrnsave(pat, (size_t)orgpat.len - 3); + help_lang_find = (char_u *)&pat[orgpat.len - 2]; + orgpat.pat = (char_u *)saved_pat; orgpat.len -= 3; } } @@ -1514,7 +1478,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi } save_emsg_off = emsg_off; - emsg_off = TRUE; // don't want error for invalid RE here + emsg_off = true; // don't want error for invalid RE here prepare_pats(&orgpat, has_re); emsg_off = save_emsg_off; if (has_re && orgpat.regmatch.regprog == NULL) { @@ -1527,40 +1491,39 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi if (*curbuf->b_p_tfu != NUL && use_tfu && !tfu_in_use) { tfu_in_use = true; - retval = find_tagfunc_tags(pat, &ga_match[0], &match_count, - flags, buf_ffname); + retval = find_tagfunc_tags((char_u *)pat, &ga_match[0], &match_count, flags, + (char_u *)buf_ffname); tfu_in_use = false; if (retval != NOTDONE) { goto findtag_end; } } - /* - * When finding a specified number of matches, first try with matching - * case, so binary search can be used, and try ignore-case matches in a - * second loop. - * When finding all matches, 'tagbsearch' is off, or there is no fixed - * string to look for, ignore case right away to avoid going though the - * tags files twice. - * When the tag file is case-fold sorted, it is either one or the other. - * Only ignore case when TAG_NOIC not used or 'ignorecase' set. - */ + // When finding a specified number of matches, first try with matching + // case, so binary search can be used, and try ignore-case matches in a + // second loop. + // When finding all matches, 'tagbsearch' is off, or there is no fixed + // string to look for, ignore case right away to avoid going though the + // tags files twice. + // When the tag file is case-fold sorted, it is either one or the other. + // Only ignore case when TAG_NOIC not used or 'ignorecase' set. + // Set a flag if the file extension is .txt if ((flags & TAG_KEEP_LANG) && help_lang_find == NULL && curbuf->b_fname != NULL - && (i = (int)STRLEN(curbuf->b_fname)) > 4 + && (i = (int)strlen(curbuf->b_fname)) > 4 && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) { is_txt = true; } orgpat.regmatch.rm_ic = ((p_ic || !noic) && (findall || orgpat.headlen == 0 || !p_tbs)); - for (round = 1; round <= 2; ++round) { + for (round = 1; round <= 2; round++) { linear = (orgpat.headlen == 0 || !p_tbs || round == 2); // Try tag file names from tags option one by one. for (first_file = true; - use_cscope || get_tagfname(&tn, first_file, tag_fname) == OK; + use_cscope || get_tagfname(&tn, first_file, (char *)tag_fname) == OK; first_file = false) { // A file that doesn't exist is silently ignored. Only when not a // single file is found, an error message is given (further on). @@ -1594,14 +1557,14 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi if ((flags & TAG_KEEP_LANG) && help_lang_find == NULL && curbuf->b_fname != NULL - && (i = (int)STRLEN(curbuf->b_fname)) > 4 + && (i = (int)strlen(curbuf->b_fname)) > 4 && curbuf->b_fname[i - 1] == 'x' && curbuf->b_fname[i - 4] == '.' && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) { help_pri = 0; } else { help_pri = 1; - for (s = p_hlg; *s != NUL; ++s) { + for (s = p_hlg; *s != NUL; s++) { if (STRNICMP(s, help_lang, 2) == 0) { break; } @@ -1635,9 +1598,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi state = TS_START; // we're at the start of the file - /* - * Read and parse the lines in the file one by one - */ + // Read and parse the lines in the file one by one for (;;) { // check for CTRL-C typed, more often when jumping around if (state == TS_BINARY || state == TS_SKIP_BACK) { @@ -1662,9 +1623,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi if (get_it_again) { goto line_read_in; } - /* - * For binary search: compute the next offset to use. - */ + // For binary search: compute the next offset to use. if (state == TS_BINARY) { offset = search_info.low_offset + ((search_info.high_offset - search_info.low_offset) / 2); @@ -1683,10 +1642,8 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi } } - /* - * When jumping around in the file, first read a line to find the - * start of the next line. - */ + // When jumping around in the file, first read a line to find the + // start of the next line. if (state == TS_BINARY || state == TS_SKIP_BACK) { // Adjust the search file offset to the correct position search_info.curr_offset_used = search_info.curr_offset; @@ -1704,7 +1661,7 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi eof = vim_fgets(lbuf, lbuf_size, fp); } // skip empty and blank lines - while (!eof && vim_isblankline(lbuf)) { + while (!eof && vim_isblankline((char *)lbuf)) { search_info.curr_offset = vim_ftell(fp); eof = vim_fgets(lbuf, lbuf_size, fp); } @@ -1715,17 +1672,15 @@ int find_tags(char_u *pat, int *num_matches, char ***matchesp, int flags, int mi search_info.curr_offset = search_info.curr_offset_used; continue; } - } - /* - * Not jumping around in the file: Read the next line. - */ - else { + } else { + // Not jumping around in the file: Read the next line. + // skip empty and blank lines do { eof = use_cscope ? cs_fgets(lbuf, lbuf_size) : vim_fgets(lbuf, lbuf_size, fp); - } while (!eof && vim_isblankline(lbuf)); + } while (!eof && vim_isblankline((char *)lbuf)); if (eof) { break; // end of file @@ -1740,7 +1695,7 @@ line_read_in: // Convert every line. Converting the pattern from 'enc' to // the tags file encoding doesn't work, because characters are // not recognized. - conv_line = string_convert(&vimconv, lbuf, NULL); + conv_line = (char_u *)string_convert(&vimconv, (char *)lbuf, NULL); if (conv_line != NULL) { // Copy or swap lbuf and conv_line. len = (int)STRLEN(conv_line) + 1; @@ -1755,10 +1710,8 @@ line_read_in: } } - /* - * When still at the start of the file, check for Emacs tags file - * format, and for "not sorted" flag. - */ + // When still at the start of the file, check for Emacs tags file + // format, and for "not sorted" flag. if (state == TS_START) { // The header ends when the line sorts below "!_TAG_". When // case is folded lower case letters sort before "_". @@ -1769,9 +1722,7 @@ line_read_in: goto parse_line; } - /* - * Read header line. - */ + // Read header line. if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) { tag_file_sorted = lbuf[18]; } @@ -1780,7 +1731,7 @@ line_read_in: // encoding to 'encoding'. for (p = lbuf + 20; *p > ' ' && *p < 127; p++) {} *p = NUL; - convert_setup(&vimconv, lbuf + 20, p_enc); + convert_setup(&vimconv, (char *)lbuf + 20, p_enc); } // Read the next line. Unrecognized flags are ignored. @@ -1789,15 +1740,13 @@ line_read_in: // Headers ends. - /* - * When there is no tag head, or ignoring case, need to do a - * linear search. - * When no "!_TAG_" is found, default to binary search. If - * the tag file isn't sorted, the second loop will find it. - * When "!_TAG_FILE_SORTED" found: start binary search if - * flag set. - * For cscope, it's always linear. - */ + // When there is no tag head, or ignoring case, need to do a + // linear search. + // When no "!_TAG_" is found, default to binary search. If + // the tag file isn't sorted, the second loop will find it. + // When "!_TAG_FILE_SORTED" found: start binary search if + // flag set. + // For cscope, it's always linear. if (linear || use_cscope) { state = TS_LINEAR; } else if (tag_file_sorted == NUL) { @@ -1864,7 +1813,7 @@ parse_line: // This speeds up tag searching a lot! if (orgpat.headlen) { CLEAR_FIELD(tagp); - tagp.tagname = lbuf; + tagp.tagname = (char *)lbuf; tagp.tagname_end = (char_u *)vim_strchr((char *)lbuf, TAB); if (tagp.tagname_end == NULL) { // Corrupted tag line. @@ -1872,11 +1821,9 @@ parse_line: break; } - /* - * Skip this line if the length of the tag is different and - * there is no regexp, or the tag is too short. - */ - cmplen = (int)(tagp.tagname_end - tagp.tagname); + // Skip this line if the length of the tag is different and + // there is no regexp, or the tag is too short. + cmplen = (int)(tagp.tagname_end - (char_u *)tagp.tagname); if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength' cmplen = (int)p_tl; } @@ -1887,9 +1834,7 @@ parse_line: } if (state == TS_BINARY) { - /* - * Simplistic check for unsorted tags file. - */ + // Simplistic check for unsorted tags file. i = (int)tagp.tagname[0]; if (sortic) { i = TOUPPER_ASC(tagp.tagname[0]); @@ -1898,20 +1843,16 @@ parse_line: sort_error = true; } - /* - * Compare the current tag with the searched tag. - */ + // Compare the current tag with the searched tag. if (sortic) { - tagcmp = tag_strnicmp(tagp.tagname, orgpat.head, + tagcmp = tag_strnicmp((char_u *)tagp.tagname, orgpat.head, (size_t)cmplen); } else { tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen); } - /* - * A match with a shorter tag means to search forward. - * A match with a longer tag means to search backward. - */ + // A match with a shorter tag means to search forward. + // A match with a longer tag means to search backward. if (tagcmp == 0) { if (cmplen < orgpat.headlen) { tagcmp = -1; @@ -1935,7 +1876,7 @@ parse_line: search_info.low_char = TOUPPER_ASC(tagp.tagname[0]); } else { - search_info.low_char = tagp.tagname[0]; + search_info.low_char = (uint8_t)tagp.tagname[0]; } continue; } @@ -1947,7 +1888,7 @@ parse_line: search_info.high_char = TOUPPER_ASC(tagp.tagname[0]); } else { - search_info.high_char = tagp.tagname[0]; + search_info.high_char = (uint8_t)tagp.tagname[0]; } continue; } @@ -1956,7 +1897,7 @@ parse_line: break; } else if (state == TS_SKIP_BACK) { assert(cmplen >= 0); - if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { + if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) { state = TS_STEP_FORWARD; } else { // Have to skip back more. Restore the curr_offset @@ -1966,7 +1907,7 @@ parse_line: continue; } else if (state == TS_STEP_FORWARD) { assert(cmplen >= 0); - if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { + if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) { if ((off_T)vim_ftell(fp) > search_info.match_offset) { break; // past last match } else { @@ -1977,7 +1918,7 @@ parse_line: // skip this match if it can't match assert(cmplen >= 0); } - if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { + if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) { continue; } @@ -1999,21 +1940,19 @@ parse_line: break; } - /* - * First try matching with the pattern literally (also when it is - * a regexp). - */ - cmplen = (int)(tagp.tagname_end - tagp.tagname); + // First try matching with the pattern literally (also when it is + // a regexp). + cmplen = (int)(tagp.tagname_end - (char_u *)tagp.tagname); if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength' cmplen = (int)p_tl; } // if tag length does not match, don't try comparing if (orgpat.len != cmplen) { - match = FALSE; + match = false; } else { if (orgpat.regmatch.rm_ic) { assert(cmplen >= 0); - match = mb_strnicmp(tagp.tagname, orgpat.pat, (size_t)cmplen) == 0; + match = mb_strnicmp(tagp.tagname, (char *)orgpat.pat, (size_t)cmplen) == 0; if (match) { match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0); @@ -2023,21 +1962,19 @@ parse_line: } } - /* - * Has a regexp: Also find tags matching regexp. - */ - match_re = FALSE; + // Has a regexp: Also find tags matching regexp. + match_re = false; if (!match && orgpat.regmatch.regprog != NULL) { int cc; cc = *tagp.tagname_end; *tagp.tagname_end = NUL; - match = vim_regexec(&orgpat.regmatch, (char *)tagp.tagname, (colnr_T)0); + match = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0); if (match) { matchoff = (int)(orgpat.regmatch.startp[0] - tagp.tagname); if (orgpat.regmatch.rm_ic) { orgpat.regmatch.rm_ic = false; - match_no_ic = vim_regexec(&orgpat.regmatch, (char *)tagp.tagname, (colnr_T)0); + match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0); orgpat.regmatch.rm_ic = true; } } @@ -2054,7 +1991,8 @@ parse_line: mtt = MT_GL_OTH; } else { // Decide in which array to store this match. - is_current = test_for_current(tagp.fname, tagp.fname_end, tag_fname, + is_current = test_for_current((char *)tagp.fname, (char *)tagp.fname_end, + (char *)tag_fname, buf_ffname); is_static = test_for_static(&tagp); @@ -2090,7 +2028,7 @@ parse_line: // detecting duplicates. // The format is {tagname}@{lang}NUL{heuristic}NUL *tagp.tagname_end = NUL; - len = (size_t)(tagp.tagname_end - tagp.tagname); + len = (size_t)(tagp.tagname_end - (char_u *)tagp.tagname); mfp = xmalloc(sizeof(char) + len + 10 + ML_EXTRA + 1); p = (char_u *)mfp; @@ -2098,7 +2036,7 @@ parse_line: p[len] = '@'; STRCPY(p + len + 1, help_lang); snprintf((char *)p + len + 1 + ML_EXTRA, STRLEN(p) + len + 1 + ML_EXTRA, "%06d", - help_heuristic((char *)tagp.tagname, + help_heuristic(tagp.tagname, match_re ? matchoff : 0, !match_no_ic) + help_pri); @@ -2124,7 +2062,7 @@ parse_line: } get_it_again = false; } else { - len = (size_t)(tagp.tagname_end - tagp.tagname); + len = (size_t)(tagp.tagname_end - (char_u *)tagp.tagname); mfp = xmalloc(sizeof(char) + len + 1); STRLCPY(mfp, tagp.tagname, len + 1); @@ -2172,7 +2110,7 @@ parse_line: hash = hash_hash((char_u *)mfp); } hi = hash_lookup(&ht_match[mtt], (const char *)mfp, - STRLEN(mfp), hash); + strlen(mfp), hash); if (HASHITEM_EMPTY(hi)) { hash_add_item(&ht_match[mtt], hi, (char_u *)mfp, hash); ga_grow(&ga_match[mtt], 1); @@ -2211,9 +2149,7 @@ parse_line: sort_error = false; } - /* - * Stop searching if sufficient tags have been found. - */ + // Stop searching if sufficient tags have been found. if (match_count >= mincount) { retval = OK; stop_searching = true; @@ -2236,7 +2172,7 @@ parse_line: if (use_cscope) { break; } - orgpat.regmatch.rm_ic = TRUE; // try another time while ignoring case + orgpat.regmatch.rm_ic = true; // try another time while ignoring case } if (!stop_searching) { @@ -2251,10 +2187,8 @@ findtag_end: vim_regfree(orgpat.regmatch.regprog); xfree(tag_fname); - /* - * Move the matches from the ga_match[] arrays into one list of - * matches. When retval == FAIL, free the matches. - */ + // Move the matches from the ga_match[] arrays into one list of + // matches. When retval == FAIL, free the matches. if (retval == FAIL) { match_count = 0; } @@ -2303,19 +2237,17 @@ findtag_end: static garray_T tag_fnames = GA_EMPTY_INIT_VALUE; -/* - * Callback function for finding all "tags" and "tags-??" files in - * 'runtimepath' doc directories. - */ +// Callback function for finding all "tags" and "tags-??" files in +// 'runtimepath' doc directories. static void found_tagfile_cb(char *fname, void *cookie) { - char_u *const tag_fname = vim_strsave((char_u *)fname); + char *const tag_fname = xstrdup(fname); #ifdef BACKSLASH_IN_FILENAME slash_adjust(tag_fname); #endif - simplify_filename(tag_fname); - GA_APPEND(char_u *, &tag_fnames, tag_fname); + simplify_filename((char_u *)tag_fname); + GA_APPEND(char *, &tag_fnames, tag_fname); } #if defined(EXITFREE) @@ -2334,25 +2266,23 @@ void free_tag_stuff(void) /// For help files, use "tags" file only. /// /// @param tnp holds status info -/// @param first TRUE when first file name is wanted +/// @param first true when first file name is wanted /// @param buf pointer to buffer of MAXPATHL chars /// /// @return FAIL if no more tag file names, OK otherwise. -int get_tagfname(tagname_T *tnp, int first, char_u *buf) +int get_tagfname(tagname_T *tnp, int first, char *buf) { - char_u *fname = NULL; - char_u *r_ptr; + char *fname = NULL; + char *r_ptr; if (first) { CLEAR_POINTER(tnp); } if (curbuf->b_help) { - /* - * For help files it's done in a completely different way: - * Find "doc/tags" and "doc/tags-??" in all directories in - * 'runtimepath'. - */ + // For help files it's done in a completely different way: + // Find "doc/tags" and "doc/tags-??" in all directories in + // 'runtimepath'. if (first) { ga_clear_strings(&tag_fnames); ga_init(&tag_fnames, (int)sizeof(char *), 10); @@ -2366,16 +2296,16 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf) if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) { return FAIL; } - ++tnp->tn_hf_idx; + tnp->tn_hf_idx++; STRCPY(buf, p_hf); STRCPY(path_tail((char *)buf), "tags"); #ifdef BACKSLASH_IN_FILENAME slash_adjust(buf); #endif - simplify_filename(buf); + simplify_filename((char_u *)buf); for (int i = 0; i < tag_fnames.ga_len; i++) { - if (STRCMP(buf, ((char **)(tag_fnames.ga_data))[i]) == 0) { + if (strcmp(buf, ((char **)(tag_fnames.ga_data))[i]) == 0) { return FAIL; // avoid duplicate file names } } @@ -2388,24 +2318,22 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf) if (first) { // Init. We make a copy of 'tags', because autocommands may change // the value without notifying us. - tnp->tn_tags = vim_strsave((*curbuf->b_p_tags != NUL) ? curbuf->b_p_tags : p_tags); - tnp->tn_np = (char *)tnp->tn_tags; + tnp->tn_tags = xstrdup((*curbuf->b_p_tags != NUL) ? curbuf->b_p_tags : (char *)p_tags); + tnp->tn_np = tnp->tn_tags; } - /* - * Loop until we have found a file name that can be used. - * There are two states: - * tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'. - * tnp->tn_did_filefind_init == TRUE: find next file in this part. - */ + // Loop until we have found a file name that can be used. + // There are two states: + // tnp->tn_did_filefind_init == false: setup for next part in 'tags'. + // tnp->tn_did_filefind_init == true: find next file in this part. for (;;) { if (tnp->tn_did_filefind_init) { - fname = vim_findfile(tnp->tn_search_ctx); + fname = (char *)vim_findfile(tnp->tn_search_ctx); if (fname != NULL) { break; } - tnp->tn_did_filefind_init = FALSE; + tnp->tn_did_filefind_init = false; } else { char_u *filename = NULL; @@ -2416,26 +2344,24 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf) return FAIL; } - /* - * Copy next file name into buf. - */ + // Copy next file name into buf. buf[0] = NUL; - (void)copy_option_part(&tnp->tn_np, (char *)buf, MAXPATHL - 1, " ,"); + (void)copy_option_part(&tnp->tn_np, buf, MAXPATHL - 1, " ,"); - r_ptr = vim_findfile_stopdir(buf); + r_ptr = (char *)vim_findfile_stopdir((char_u *)buf); // move the filename one char forward and truncate the // filepath with a NUL - filename = (char_u *)path_tail((char *)buf); + filename = (char_u *)path_tail(buf); STRMOVE(filename + 1, filename); *filename++ = NUL; - tnp->tn_search_ctx = vim_findfile_init(buf, filename, + tnp->tn_search_ctx = vim_findfile_init(buf, (char *)filename, r_ptr, 100, - FALSE, // don't free visited list + false, // don't free visited list FINDFILE_FILE, // we search for a file - tnp->tn_search_ctx, true, (char_u *)curbuf->b_ffname); + tnp->tn_search_ctx, true, curbuf->b_ffname); if (tnp->tn_search_ctx != NULL) { - tnp->tn_did_filefind_init = TRUE; + tnp->tn_did_filefind_init = true; } } } @@ -2445,9 +2371,7 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf) return OK; } -/* - * Free the contents of a tagname_T that was filled by get_tagfname(). - */ +// Free the contents of a tagname_T that was filled by get_tagfname(). void tagname_free(tagname_T *tnp) { xfree(tnp->tn_tags); @@ -2459,7 +2383,7 @@ void tagname_free(tagname_T *tnp) /// Parse one line from the tags file. Find start/end of tag name, start/end of /// file name and start of search pattern. /// -/// If is_etag is TRUE, tagp->fname and tagp->fname_end are not set. +/// If is_etag is true, tagp->fname and tagp->fname_end are not set. /// /// @param lbuf line to be parsed /// @@ -2469,7 +2393,7 @@ static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp) char_u *p; // Isolate the tagname, from lbuf up to the first white - tagp->tagname = lbuf; + tagp->tagname = (char *)lbuf; p = (char_u *)vim_strchr((char *)lbuf, TAB); if (p == NULL) { return FAIL; @@ -2499,20 +2423,18 @@ static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp) return OK; } -/* - * Check if tagname is a static tag - * - * Static tags produced by the older ctags program have the format: - * 'file:tag file /pattern'. - * This is only recognized when both occurrence of 'file' are the same, to - * avoid recognizing "string::string" or ":exit". - * - * Static tags produced by the new ctags program have the format: - * 'tag file /pattern/;"<Tab>file:' " - * - * Return TRUE if it is a static tag and adjust *tagname to the real tag. - * Return FALSE if it is not a static tag. - */ +// Check if tagname is a static tag +// +// Static tags produced by the older ctags program have the format: +// 'file:tag file /pattern'. +// This is only recognized when both occurrence of 'file' are the same, to +// avoid recognizing "string::string" or ":exit". +// +// Static tags produced by the new ctags program have the format: +// 'tag file /pattern/;"<Tab>file:' " +// +// Return true if it is a static tag and adjust *tagname to the real tag. +// Return false if it is not a static tag. static bool test_for_static(tagptrs_T *tagp) { char_u *p; @@ -2522,11 +2444,11 @@ static bool test_for_static(tagptrs_T *tagp) while ((p = (char_u *)vim_strchr((char *)p, '\t')) != NULL) { p++; if (STRNCMP(p, "file:", 5) == 0) { - return TRUE; + return true; } } - return FALSE; + return false; } // Returns the length of a matching tag line. @@ -2550,18 +2472,17 @@ static size_t matching_line_len(const char_u *const lbuf) /// @param tagp output: pointers into the line /// /// @return OK or FAIL. -static int parse_match(char_u *lbuf, tagptrs_T *tagp) +static int parse_match(char *lbuf, tagptrs_T *tagp) { int retval; - char_u *p; - char_u *pc, *pt; + char *p; + char *pc, *pt; - tagp->tag_fname = lbuf + 1; + tagp->tag_fname = (char_u *)lbuf + 1; lbuf += STRLEN(tagp->tag_fname) + 2; // Find search pattern and the file name for non-etags. - retval = parse_tag_line(lbuf, - tagp); + retval = parse_tag_line((char_u *)lbuf, tagp); tagp->tagkind = NULL; tagp->user_data = NULL; @@ -2570,32 +2491,32 @@ static int parse_match(char_u *lbuf, tagptrs_T *tagp) if (retval == OK) { // Try to find a kind field: "kind:<kind>" or just "<kind>" - p = tagp->command; - if (find_extra(&p) == OK) { - tagp->command_end = p; - if (p > tagp->command && p[-1] == '|') { - tagp->command_end = p - 1; // drop trailing bar + p = (char *)tagp->command; + if (find_extra((char_u **)&p) == OK) { + tagp->command_end = (char_u *)p; + if (p > (char *)tagp->command && p[-1] == '|') { + tagp->command_end = (char_u *)p - 1; // drop trailing bar } p += 2; // skip ";\"" if (*p++ == TAB) { // Accept ASCII alphabetic kind characters and any multi-byte // character. - while (ASCII_ISALPHA(*p) || utfc_ptr2len((char *)p) > 1) { + while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { if (STRNCMP(p, "kind:", 5) == 0) { - tagp->tagkind = p + 5; + tagp->tagkind = (char_u *)p + 5; } else if (STRNCMP(p, "user_data:", 10) == 0) { tagp->user_data = p + 10; } else if (STRNCMP(p, "line:", 5) == 0) { - tagp->tagline = atoi((char *)p + 5); + tagp->tagline = atoi(p + 5); } if (tagp->tagkind != NULL && tagp->user_data != NULL) { break; } - pc = (char_u *)vim_strchr((char *)p, ':'); - pt = (char_u *)vim_strchr((char *)p, '\t'); + pc = vim_strchr(p, ':'); + pt = vim_strchr(p, '\t'); if (pc == NULL || (pt != NULL && pc > pt)) { - tagp->tagkind = p; + tagp->tagkind = (char_u *)p; } if (pt == NULL) { break; @@ -2606,31 +2527,30 @@ static int parse_match(char_u *lbuf, tagptrs_T *tagp) } } if (tagp->tagkind != NULL) { - for (p = tagp->tagkind; + for (p = (char *)tagp->tagkind; *p && *p != '\t' && *p != '\r' && *p != '\n'; MB_PTR_ADV(p)) {} - tagp->tagkind_end = p; + tagp->tagkind_end = (char_u *)p; } if (tagp->user_data != NULL) { for (p = tagp->user_data; *p && *p != '\t' && *p != '\r' && *p != '\n'; MB_PTR_ADV(p)) {} - tagp->user_data_end = p; + tagp->user_data_end = (char_u *)p; } } return retval; } -/* - * Find out the actual file name of a tag. Concatenate the tags file name - * with the matching tag file name. - * Returns an allocated string. - */ +// Find out the actual file name of a tag. Concatenate the tags file name +// with the matching tag file name. +// Returns an allocated string. static char_u *tag_full_fname(tagptrs_T *tagp) { int c = *tagp->fname_end; *tagp->fname_end = NUL; - char_u *fullname = expand_tag_fname(tagp->fname, tagp->tag_fname, false); + char_u *fullname = + (char_u *)expand_tag_fname((char *)tagp->fname, (char *)tagp->tag_fname, false); *tagp->fname_end = (char_u)c; return fullname; @@ -2640,7 +2560,7 @@ static char_u *tag_full_fname(tagptrs_T *tagp) /// /// @param lbuf_arg line from the tags file for this tag /// @param forceit :ta with ! -/// @param keep_help keep help flag (FALSE for cscope) +/// @param keep_help keep help flag (false for cscope) /// /// @return OK for success, NOTAGFILE when file not found, FAIL otherwise. static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) @@ -2653,7 +2573,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) char_u *pbuf; // search pattern buffer char_u *pbuf_end; char_u *tofree_fname = NULL; - char_u *fname; + char *fname; tagptrs_T tagp; int retval = FAIL; int getfile_result = GETFILE_UNUSED; @@ -2669,14 +2589,14 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) pbuf = xmalloc(LSIZE); // parse the match line into the tagp structure - if (parse_match(lbuf, &tagp) == FAIL) { + if (parse_match((char *)lbuf, &tagp) == FAIL) { tagp.fname_end = NULL; goto erret; } // truncate the file name, so it can be used as a string *tagp.fname_end = NUL; - fname = tagp.fname; + fname = (char *)tagp.fname; // copy the command to pbuf[], remove trailing CR/NL str = tagp.command; @@ -2689,9 +2609,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) *pbuf_end = NUL; { - /* - * Remove the "<Tab>fieldname:value" stuff; we don't need it here. - */ + // Remove the "<Tab>fieldname:value" stuff; we don't need it here. str = pbuf; if (find_extra(&str) == OK) { pbuf_end = str; @@ -2699,24 +2617,19 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) } } - /* - * Expand file name, when needed (for environment variables). - * If 'tagrelative' option set, may change file name. - */ - fname = expand_tag_fname(fname, tagp.tag_fname, true); - tofree_fname = fname; // free() it later + // Expand file name, when needed (for environment variables). + // If 'tagrelative' option set, may change file name. + fname = expand_tag_fname(fname, (char *)tagp.tag_fname, true); + tofree_fname = (char_u *)fname; // free() it later - /* - * Check if the file with the tag exists before abandoning the current - * file. Also accept a file name for which there is a matching BufReadCmd - * autocommand event (e.g., http://sys/file). - */ + // Check if the file with the tag exists before abandoning the current + // file. Also accept a file name for which there is a matching BufReadCmd + // autocommand event (e.g., http://sys/file). if (!os_path_exists(fname) - && !has_autocmd(EVENT_BUFREADCMD, (char *)fname, - NULL)) { + && !has_autocmd(EVENT_BUFREADCMD, fname, NULL)) { retval = NOTAGFILE; xfree(nofile_fname); - nofile_fname = vim_strsave(fname); + nofile_fname = xstrdup(fname); goto erret; } @@ -2726,19 +2639,15 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) postponed_split = 0; // don't split again below curwin_save = curwin; // Save current window - /* - * If we are reusing a window, we may change dir when - * entering it (autocommands) so turn the tag filename - * into a fullpath - */ + // If we are reusing a window, we may change dir when + // entering it (autocommands) so turn the tag filename + // into a fullpath if (!curwin->w_p_pvw) { - full_fname = (char_u *)FullName_save((char *)fname, FALSE); - fname = full_fname; + full_fname = (char_u *)FullName_save(fname, false); + fname = (char *)full_fname; - /* - * Make the preview window the current window. - * Open a preview window when needed. - */ + // Make the preview window the current window. + // Open a preview window when needed. prepare_tagpreview(true); } } @@ -2746,7 +2655,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) // If it was a CTRL-W CTRL-] command split window now. For ":tab tag" // open a new tab page. if (postponed_split && (swb_flags & (SWB_USEOPEN | SWB_USETAB))) { - buf_T *const existing_buf = buflist_findname_exp((char *)fname); + buf_T *const existing_buf = buflist_findname_exp(fname); if (existing_buf != NULL) { const win_T *wp = NULL; @@ -2791,7 +2700,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) if (getfile_result == GETFILE_UNUSED) { // Careful: getfile() may trigger autocommands and call jumpto_tag() // recursively. - getfile_result = getfile(0, (char *)fname, NULL, true, (linenr_T)0, forceit); + getfile_result = getfile(0, fname, NULL, true, (linenr_T)0, forceit); } keep_help_flag = false; @@ -2804,36 +2713,32 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) // Save value of no_hlsearch, jumping to a tag is not a real search const bool save_no_hlsearch = no_hlsearch; - /* - * If 'cpoptions' contains 't', store the search pattern for the "n" - * command. If 'cpoptions' does not contain 't', the search pattern - * is not stored. - */ + // If 'cpoptions' contains 't', store the search pattern for the "n" + // command. If 'cpoptions' does not contain 't', the search pattern + // is not stored. if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) { search_options = 0; } else { search_options = SEARCH_KEEP; } - /* - * If the command is a search, try here. - * - * Reset 'smartcase' for the search, since the search pattern was not - * typed by the user. - * Only use do_search() when there is a full search command, without - * anything following. - */ + // If the command is a search, try here. + // + // Reset 'smartcase' for the search, since the search pattern was not + // typed by the user. + // Only use do_search() when there is a full search command, without + // anything following. str = pbuf; if (pbuf[0] == '/' || pbuf[0] == '?') { - str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1; + str = (char_u *)skip_regexp((char *)pbuf + 1, pbuf[0], false, NULL) + 1; } if (str > pbuf_end - 1) { // search command with nothing following save_p_ws = p_ws; save_p_ic = p_ic; save_p_scs = p_scs; p_ws = true; // need 'wrapscan' for backward searches - p_ic = FALSE; // don't ignore case now - p_scs = FALSE; + p_ic = false; // don't ignore case now + p_scs = false; save_lnum = curwin->w_cursor.lnum; if (tagp.tagline > 0) { // start search before line from "line:" field @@ -2849,9 +2754,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) int found = 1; int cc; - /* - * try again, ignore case now - */ + // try again, ignore case now p_ic = true; if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, (long)1, search_options, NULL)) { @@ -2876,10 +2779,8 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) emsg(_("E434: Can't find tag pattern")); curwin->w_cursor.lnum = save_lnum; } else { - /* - * Only give a message when really guessed, not when 'ic' - * is set and match found while ignoring case. - */ + // Only give a message when really guessed, not when 'ic' + // is set and match found while ignoring case. if (found == 2 || !save_p_ic) { msg(_("E435: Couldn't find tag, just guessing!")); if (!msg_scrolled && msg_silent == 0) { @@ -2928,10 +2829,8 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) } if (retval == OK) { - /* - * For a help buffer: Put the cursor line at the top of the window, - * the help subject will be below it. - */ + // For a help buffer: Put the cursor line at the top of the window, + // the help subject will be below it. if (curbuf->b_help) { set_topline(curwin, curwin->w_cursor.lnum); } @@ -2944,7 +2843,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were validate_cursor(); - redraw_later(curwin, VALID); + redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } @@ -2967,19 +2866,18 @@ erret: return retval; } -// If "expand" is true, expand wildcards in fname. -// If 'tagrelative' option set, change fname (name of file containing tag) -// according to tag_fname (name of tag file containing fname). -// Returns a pointer to allocated memory. -static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, const bool expand) +/// If "expand" is true, expand wildcards in fname. +/// If 'tagrelative' option set, change fname (name of file containing tag) +/// according to tag_fname (name of tag file containing fname). +/// +/// @return a pointer to allocated memory. +static char *expand_tag_fname(char *fname, char *const tag_fname, const bool expand) { - char_u *p; - char_u *expanded_fname = NULL; + char *p; + char *expanded_fname = NULL; expand_T xpc; - /* - * Expand file name (for environment variables) when needed. - */ + // Expand file name (for environment variables) when needed. if (expand && path_has_wildcard(fname)) { ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; @@ -2990,20 +2888,18 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, const bo } } - char_u *retval; + char *retval; if ((p_tr || curbuf->b_help) - && !vim_isAbsName(fname) - && (p = (char_u *)path_tail((char *)tag_fname)) != tag_fname) { + && !vim_isAbsName((char_u *)fname) + && (p = path_tail(tag_fname)) != tag_fname) { retval = xmalloc(MAXPATHL); STRCPY(retval, tag_fname); STRLCPY(retval + (p - tag_fname), fname, MAXPATHL - (p - tag_fname)); - /* - * Translate names like "src/a/../b/file.c" into "src/b/file.c". - */ - simplify_filename(retval); + // Translate names like "src/a/../b/file.c" into "src/b/file.c". + simplify_filename((char_u *)retval); } else { - retval = vim_strsave(fname); + retval = xstrdup(fname); } xfree(expanded_fname); @@ -3011,36 +2907,32 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, const bo return retval; } -/* - * Check if we have a tag for the buffer with name "buf_ffname". - * This is a bit slow, because of the full path compare in path_full_compare(). - * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current - * file. - */ -static int test_for_current(char_u *fname, char_u *fname_end, char_u *tag_fname, char_u *buf_ffname) +/// Check if we have a tag for the buffer with name "buf_ffname". +/// This is a bit slow, because of the full path compare in path_full_compare(). +/// +/// @return true if tag for file "fname" if tag file "tag_fname" is for current +/// file. +static int test_for_current(char *fname, char *fname_end, char *tag_fname, char *buf_ffname) { int c; - int retval = FALSE; - char_u *fullname; + int retval = false; if (buf_ffname != NULL) { // if the buffer has a name { - c = *fname_end; + c = (unsigned char)(*fname_end); *fname_end = NUL; } - fullname = expand_tag_fname(fname, tag_fname, true); - retval = (path_full_compare((char *)fullname, (char *)buf_ffname, true, true) & kEqualFiles); + char *fullname = expand_tag_fname(fname, tag_fname, true); + retval = (path_full_compare(fullname, buf_ffname, true, true) & kEqualFiles); xfree(fullname); - *fname_end = (char_u)c; + *fname_end = (char)c; } return retval; } -/* - * Find the end of the tagaddress. - * Return OK if ";\"" is following, FAIL otherwise. - */ +// Find the end of the tagaddress. +// Return OK if ";\"" is following, FAIL otherwise. static int find_extra(char_u **pp) { char_u *str = *pp; @@ -3051,7 +2943,7 @@ static int find_extra(char_u **pp) if (ascii_isdigit(*str)) { str = (char_u *)skipdigits((char *)str + 1); } else if (*str == '/' || *str == '?') { - str = skip_regexp(str + 1, *str, false, NULL); + str = (char_u *)skip_regexp((char *)str + 1, *str, false, NULL); if (*str != first_char) { str = NULL; } else { @@ -3107,13 +2999,13 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char ***file) extra_flag = 0; } if (pat[0] == '/') { - ret = find_tags(pat + 1, num_file, file, + ret = find_tags((char *)pat + 1, num_file, file, TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC, - TAG_MANY, (char_u *)curbuf->b_ffname); + TAG_MANY, curbuf->b_ffname); } else { - ret = find_tags(pat, num_file, file, + ret = find_tags((char *)pat, num_file, file, TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC | TAG_NOIC, - TAG_MANY, (char_u *)curbuf->b_ffname); + TAG_MANY, curbuf->b_ffname); } if (ret == OK && !tagnames) { // Reorganize the tags for display and matching as strings of: @@ -3121,8 +3013,8 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char ***file) for (i = 0; i < *num_file; i++) { size_t len; - parse_match((char_u *)(*file)[i], &t_p); - len = (size_t)(t_p.tagname_end - t_p.tagname); + parse_match((*file)[i], &t_p); + len = (size_t)(t_p.tagname_end - (char_u *)t_p.tagname); if (len > name_buf_size - 3) { char_u *buf; @@ -3150,8 +3042,7 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char ***file) /// /// @param start start of the value /// @param end after the value; can be NULL -static int add_tag_field(dict_T *dict, const char *field_name, const char_u *start, - const char_u *end) +static int add_tag_field(dict_T *dict, const char *field_name, const char *start, const char *end) FUNC_ATTR_NONNULL_ARG(1, 2) { int len = 0; @@ -3169,7 +3060,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char_u *sta char_u *buf = xmalloc(MAXPATHL); if (start != NULL) { if (end == NULL) { - end = start + STRLEN(start); + end = start + strlen(start); while (end > start && (end[-1] == '\r' || end[-1] == '\n')) { end--; } @@ -3181,7 +3072,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char_u *sta STRLCPY(buf, start, len + 1); } buf[len] = NUL; - retval = tv_dict_add_str(dict, field_name, STRLEN(field_name), + retval = tv_dict_add_str(dict, field_name, strlen(field_name), (const char *)buf); xfree(buf); return retval; @@ -3198,11 +3089,11 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) tagptrs_T tp; bool is_static; - ret = find_tags(pat, &num_matches, &matches, - TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname); + ret = find_tags((char *)pat, &num_matches, &matches, + TAG_REGEXP | TAG_NOIC, MAXCOL, (char *)buf_fname); if (ret == OK && num_matches > 0) { for (i = 0; i < num_matches; i++) { - int parse_result = parse_match((char_u *)matches[i], &tp); + int parse_result = parse_match(matches[i], &tp); // Avoid an unused variable warning in release builds. (void)parse_result; @@ -3220,11 +3111,11 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) tv_list_append_dict(list, dict); full_fname = tag_full_fname(&tp); - if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL - || add_tag_field(dict, "filename", full_fname, NULL) == FAIL - || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL - || add_tag_field(dict, "kind", tp.tagkind, - tp.tagkind ? tp.tagkind_end : NULL) == FAIL + if (add_tag_field(dict, "name", tp.tagname, (char *)tp.tagname_end) == FAIL + || add_tag_field(dict, "filename", (char *)full_fname, NULL) == FAIL + || add_tag_field(dict, "cmd", (char *)tp.command, (char *)tp.command_end) == FAIL + || add_tag_field(dict, "kind", (char *)tp.tagkind, + tp.tagkind ? (char *)tp.tagkind_end : NULL) == FAIL || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) { ret = FAIL; } @@ -3259,7 +3150,7 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) p++; } n[len] = NUL; - if (add_tag_field(dict, (char *)n, s, p) == FAIL) { + if (add_tag_field(dict, (char *)n, (char *)s, (char *)p) == FAIL) { ret = FAIL; } n[len] = ':'; @@ -3351,9 +3242,9 @@ static void tagstack_shift(win_T *wp) wp->w_tagstacklen--; } -// Push a new item to the tag stack -static void tagstack_push_item(win_T *wp, char_u *tagname, int cur_fnum, int cur_match, pos_T mark, - int fnum, char_u *user_data) +/// Push a new item to the tag stack +static void tagstack_push_item(win_T *wp, char *tagname, int cur_fnum, int cur_match, pos_T mark, + int fnum, char *user_data) { taggy_T *tagstack = wp->w_tagstack; int idx = wp->w_tagstacklen; // top of the stack @@ -3376,13 +3267,13 @@ static void tagstack_push_item(win_T *wp, char_u *tagname, int cur_fnum, int cur tagstack[idx].user_data = user_data; } -// Add a list of items to the tag stack in the specified window +/// Add a list of items to the tag stack in the specified window static void tagstack_push_items(win_T *wp, list_T *l) { listitem_T *li; dictitem_T *di; dict_T *itemdict; - char_u *tagname; + char *tagname; pos_T mark; int fnum; @@ -3401,8 +3292,7 @@ static void tagstack_push_items(win_T *wp, list_T *l) if (list2fpos(&di->di_tv, &mark, &fnum, NULL, false) != OK) { continue; } - if ((tagname = (char_u *)tv_dict_get_string(itemdict, "tagname", true)) - == NULL) { + if ((tagname = tv_dict_get_string(itemdict, "tagname", true)) == NULL) { continue; } @@ -3414,7 +3304,7 @@ static void tagstack_push_items(win_T *wp, list_T *l) (int)tv_dict_get_number(itemdict, "bufnr"), (int)tv_dict_get_number(itemdict, "matchnr") - 1, mark, fnum, - (char_u *)tv_dict_get_string(itemdict, "user_data", true)); + tv_dict_get_string(itemdict, "user_data", true)); } } diff --git a/src/nvim/tag.h b/src/nvim/tag.h index 0b4039afb6..7f2ef8d6d7 100644 --- a/src/nvim/tag.h +++ b/src/nvim/tag.h @@ -34,7 +34,7 @@ // Structure used for get_tagfname(). typedef struct { - char_u *tn_tags; // value of 'tags' when starting + char *tn_tags; // value of 'tags' when starting char *tn_np; // current position in tn_tags int tn_did_filefind_init; int tn_hf_idx; diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 08fcefaa88..50574b292d 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -111,15 +111,19 @@ struct terminal { // - receive data from libvterm as a result of key presses. char textbuf[0x1fff]; - ScrollbackLine **sb_buffer; // Scrollback buffer storage for libvterm - size_t sb_current; // number of rows pushed to sb_buffer - size_t sb_size; // sb_buffer size + ScrollbackLine **sb_buffer; // Scrollback storage. + size_t sb_current; // Lines stored in sb_buffer. + size_t sb_size; // Capacity of sb_buffer. // "virtual index" that points to the first sb_buffer row that we need to // push to the terminal buffer when refreshing the scrollback. When negative, // it actually points to entries that are no longer in sb_buffer (because the // window height has increased) and must be deleted from the terminal buffer int sb_pending; + char *title; // VTermStringFragment buffer + size_t title_len; // number of rows pushed to sb_buffer + size_t title_size; // sb_buffer size + // buf_T instance that acts as a "drawing surface" for libvterm // we can't store a direct reference to the buffer because the // refresh_timer_cb may be called after the buffer was freed, and there's @@ -150,7 +154,7 @@ static VTermScreenCallbacks vterm_screen_callbacks = { .movecursor = term_movecursor, .settermprop = term_settermprop, .bell = term_bell, - .sb_pushline = term_sb_push, + .sb_pushline = term_sb_push, // Called before a line goes offscreen. .sb_popline = term_sb_pop, }; @@ -230,7 +234,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts) set_option_value("wrap", false, NULL, OPT_LOCAL); set_option_value("list", false, NULL, OPT_LOCAL); if (buf->b_ffname != NULL) { - buf_set_term_title(buf, buf->b_ffname); + buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname)); } RESET_BINDING(curwin); // Reset cursor in current window. @@ -418,15 +422,15 @@ bool terminal_enter(void) // placed at end of buffer to "follow" output. #11072 handle_T save_curwin = curwin->handle; bool save_w_p_cul = curwin->w_p_cul; - char_u *save_w_p_culopt = NULL; + char *save_w_p_culopt = NULL; char_u save_w_p_culopt_flags = curwin->w_p_culopt_flags; int save_w_p_cuc = curwin->w_p_cuc; long save_w_p_so = curwin->w_p_so; long save_w_p_siso = curwin->w_p_siso; if (curwin->w_p_cul && curwin->w_p_culopt_flags & CULOPT_NBR) { - if (STRCMP(curwin->w_p_culopt, "number")) { + if (strcmp(curwin->w_p_culopt, "number")) { save_w_p_culopt = curwin->w_p_culopt; - curwin->w_p_culopt = (char_u *)xstrdup("number"); + curwin->w_p_culopt = xstrdup("number"); } curwin->w_p_culopt_flags = CULOPT_NBR; } else { @@ -518,7 +522,7 @@ static int terminal_check(VimState *state) terminal_check_cursor(); if (must_redraw) { - update_screen(0); + update_screen(); } if (need_maketitle) { // Update title in terminal-mode. #7248 @@ -636,6 +640,7 @@ void terminal_destroy(Terminal **termpp) xfree(term->sb_buffer[i]); } xfree(term->sb_buffer); + xfree(term->title); vterm_free(term->vt); xfree(term); *termpp = NULL; // coverity[dead-store] @@ -688,7 +693,7 @@ void terminal_paste(long count, char **y_array, size_t y_size) return; } vterm_keyboard_start_paste(curbuf->terminal->vt); - size_t buff_len = STRLEN(y_array[0]); + size_t buff_len = strlen(y_array[0]); char_u *buff = xmalloc(buff_len); for (int i = 0; i < count; i++) { // -V756 // feed the lines to the terminal @@ -697,7 +702,7 @@ void terminal_paste(long count, char **y_array, size_t y_size) // terminate the previous line terminal_send(curbuf->terminal, "\n", 1); } - size_t len = STRLEN(y_array[j]); + size_t len = strlen(y_array[j]); if (len > buff_len) { buff = xrealloc(buff, len); buff_len = len; @@ -754,6 +759,22 @@ static int get_rgb(VTermState *state, VTermColor color) return RGB_(color.rgb.red, color.rgb.green, color.rgb.blue); } +static int get_underline_hl_flag(VTermScreenCellAttrs attrs) +{ + switch (attrs.underline) { + case VTERM_UNDERLINE_OFF: + return 0; + case VTERM_UNDERLINE_SINGLE: + return HL_UNDERLINE; + case VTERM_UNDERLINE_DOUBLE: + return HL_UNDERDOUBLE; + case VTERM_UNDERLINE_CURLY: + return HL_UNDERCURL; + default: + return HL_UNDERLINE; + } +} + void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *term_attrs) { int height, width; @@ -790,7 +811,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0) | (cell.attrs.italic ? HL_ITALIC : 0) | (cell.attrs.reverse ? HL_INVERSE : 0) - | (cell.attrs.underline ? HL_UNDERLINE : 0) + | get_underline_hl_flag(cell.attrs) | (cell.attrs.strike ? HL_STRIKETHROUGH: 0) | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0) | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0); @@ -858,13 +879,13 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data) return 1; } -static void buf_set_term_title(buf_T *buf, char *title) +static void buf_set_term_title(buf_T *buf, const char *title, size_t len) FUNC_ATTR_NONNULL_ALL { Error err = ERROR_INIT; dict_set_var(buf->b_vars, STATIC_CSTR_AS_STRING("term_title"), - STRING_OBJ(cstr_as_string(title)), + STRING_OBJ(((String){ .data = (char *)title, .size = len })), false, false, &err); @@ -887,7 +908,30 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) case VTERM_PROP_TITLE: { buf_T *buf = handle_get_buffer(term->buf_handle); - buf_set_term_title(buf, val->string); + VTermStringFragment frag = val->string; + + if (frag.initial && frag.final) { + buf_set_term_title(buf, frag.str, frag.len); + break; + } + + if (frag.initial) { + term->title_len = 0; + term->title_size = MAX(frag.len, 1024); + term->title = xmalloc(sizeof(char *) * term->title_size); + } else if (term->title_len + frag.len > term->title_size) { + term->title_size *= 2; + term->title = xrealloc(term->title, sizeof(char *) * term->title_size); + } + + memcpy(term->title + term->title_len, frag.str, frag.len); + term->title_len += frag.len; + + if (frag.final) { + buf_set_term_title(buf, term->title, term->title_len); + xfree(term->title); + term->title = NULL; + } break; } @@ -908,7 +952,10 @@ static int term_bell(void *data) return 1; } -// Scrollback push handler (from pangoterm). +/// Scrollback push handler: called just before a line goes offscreen (and libvterm will forget it), +/// giving us a chance to store it. +/// +/// Code adapted from pangoterm. static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) { Terminal *term = data; @@ -1375,7 +1422,7 @@ static bool send_mouse_event(Terminal *term, int c) curwin->w_redr_status = true; curwin = save_curwin; curbuf = curwin->w_buffer; - redraw_later(mouse_win, NOT_VALID); + redraw_later(mouse_win, UPD_NOT_VALID); invalidate_terminal(term, -1, -1); // Only need to exit focus if the scrolled window is the terminal window return mouse_win == curwin; diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index fcd3d5724c..ce23141c7a 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -114,6 +114,13 @@ if has('win32') let $PROMPT = '$P$G' endif +if has('mac') + " In MacOS, when starting a shell in a terminal, a bash deprecation warning + " message is displayed. This breaks the terminal test. Disable the warning + " message. + let $BASH_SILENCE_DEPRECATION_WARNING = 1 +endif + " Prepare for calling test_garbagecollect_now(). let v:testing = 1 @@ -418,7 +425,7 @@ for s:test in sort(s:tests) set belloff=all let prev_error = '' let total_errors = [] - let run_nr = 1 + let g:run_nr = 1 " A test can set g:test_is_flaky to retry running the test. let g:test_is_flaky = 0 @@ -437,10 +444,10 @@ for s:test in sort(s:tests) call add(s:messages, 'Found errors in ' . s:test . ':') call extend(s:messages, v:errors) - call add(total_errors, 'Run ' . run_nr . ':') + call add(total_errors, 'Run ' . g:run_nr . ':') call extend(total_errors, v:errors) - if run_nr == 5 || prev_error == v:errors[0] + if g:run_nr >= 5 || prev_error == v:errors[0] call add(total_errors, 'Flaky test failed too often, giving up') let v:errors = total_errors break @@ -455,7 +462,7 @@ for s:test in sort(s:tests) let prev_error = v:errors[0] let v:errors = [] - let run_nr += 1 + let g:run_nr += 1 call RunTheTest(s:test) diff --git a/src/nvim/testdir/script_util.vim b/src/nvim/testdir/script_util.vim index 9913b1dfaf..28d6a621d6 100644 --- a/src/nvim/testdir/script_util.vim +++ b/src/nvim/testdir/script_util.vim @@ -48,7 +48,7 @@ endfunc " delete it afterwards. However, if an exception is thrown the file may remain, " the caller should call DeleteTheScript() afterwards. let s:script_name = '' -function! ExecAsScript(funcname) +func ExecAsScript(funcname) " Make a script from the function passed as argument. let s:script_name = MakeScript(a:funcname) @@ -56,9 +56,9 @@ function! ExecAsScript(funcname) exec "source" s:script_name call delete(s:script_name) let s:script_name = '' -endfunction +endfunc -function! DeleteTheScript() +func DeleteTheScript() if s:script_name call delete(s:script_name) let s:script_name = '' diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim index 6bc3607b69..f895287469 100644 --- a/src/nvim/testdir/setup.vim +++ b/src/nvim/testdir/setup.vim @@ -5,7 +5,7 @@ if exists('s:did_load') set directory& set directory^=. set display= - set fillchars=vert:\|,fold:- + set fillchars=vert:\|,foldsep:\|,fold:- set formatoptions=tcq set fsync set laststatus=1 @@ -45,6 +45,11 @@ mapclear! aunmenu * tlunmenu * +" roughly equivalent to test_setmouse() in Vim +func Ntest_setmouse(row, col) + call nvim_input_mouse('move', '', '', 0, a:row - 1, a:col - 1) +endfunc + " Prevent Nvim log from writing to stderr. let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log' diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim index 521c3fcd57..0fd65e8f5a 100644 --- a/src/nvim/testdir/test_arglist.vim +++ b/src/nvim/testdir/test_arglist.vim @@ -509,18 +509,14 @@ func Test_arglist_autocmd() new " redefine arglist; go to Xxx1 next! Xxx1 Xxx2 Xxx3 - " open window for all args; Reading Xxx2 will change the arglist and the - " third window will get Xxx1: - " win 1: Xxx1 - " win 2: Xxx2 - " win 3: Xxx1 - all + " open window for all args; Reading Xxx2 will try to change the arglist and + " that will fail + call assert_fails("all", "E1156:") call assert_equal('test file Xxx1', getline(1)) wincmd w - wincmd w - call assert_equal('test file Xxx1', getline(1)) - rewind call assert_equal('test file Xxx2', getline(1)) + wincmd w + call assert_equal('test file Xxx3', getline(1)) autocmd! BufReadPost Xxx2 enew! | only @@ -591,4 +587,153 @@ func Test_quit_with_arglist() call delete('.c.swp') endfunc +" Test for ":all" not working when in the cmdline window +func Test_all_not_allowed_from_cmdwin() + au BufEnter * all + next x + " Use try/catch here, somehow assert_fails() doesn't work on MS-Windows + " console. + let caught = 'no' + try + exe ":norm! 7q?apat\<CR>" + catch /E11:/ + let caught = 'yes' + endtry + call assert_equal('yes', caught) + au! BufEnter +endfunc + +func Test_clear_arglist_in_all() + n 0 00 000 0000 00000 000000 + au WinNew 0 n 0 + call assert_fails("all", "E1156") + au! * +endfunc + +" Test for the :all command +func Test_all_command() + %argdelete + + " :all command should not close windows with files in the argument list, + " but can rearrange the windows. + args Xargnew1 Xargnew2 + %bw! + edit Xargold1 + split Xargnew1 + let Xargnew1_winid = win_getid() + split Xargold2 + split Xargnew2 + let Xargnew2_winid = win_getid() + split Xargold3 + all + call assert_equal(2, winnr('$')) + call assert_equal([Xargnew1_winid, Xargnew2_winid], + \ [win_getid(1), win_getid(2)]) + call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')], + \ [winbufnr(1), winbufnr(2)]) + + " :all command should close windows for files which are not in the + " argument list in the current tab page. + %bw! + edit Xargold1 + split Xargold2 + tabedit Xargold3 + split Xargold4 + tabedit Xargold5 + tabfirst + all + call assert_equal(3, tabpagenr('$')) + call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')], tabpagebuflist(1)) + call assert_equal([bufnr('Xargold4'), bufnr('Xargold3')], tabpagebuflist(2)) + call assert_equal([bufnr('Xargold5')], tabpagebuflist(3)) + + " :tab all command should close windows for files which are not in the + " argument list across all the tab pages. + %bw! + edit Xargold1 + split Xargold2 + tabedit Xargold3 + split Xargold4 + tabedit Xargold5 + tabfirst + args Xargnew1 Xargnew2 + tab all + call assert_equal(2, tabpagenr('$')) + call assert_equal([bufnr('Xargnew1')], tabpagebuflist(1)) + call assert_equal([bufnr('Xargnew2')], tabpagebuflist(2)) + + " If a count is specified, then :all should open only that many windows. + %bw! + args Xargnew1 Xargnew2 Xargnew3 Xargnew4 Xargnew5 + all 3 + call assert_equal(3, winnr('$')) + call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2'), bufnr('Xargnew3')], + \ [winbufnr(1), winbufnr(2), winbufnr(3)]) + + " The :all command should not open more than 'tabpagemax' tab pages. + " If there are more files, then they should be opened in the last tab page. + %bw! + set tabpagemax=3 + tab all + call assert_equal(3, tabpagenr('$')) + call assert_equal([bufnr('Xargnew1')], tabpagebuflist(1)) + call assert_equal([bufnr('Xargnew2')], tabpagebuflist(2)) + call assert_equal([bufnr('Xargnew3'), bufnr('Xargnew4'), bufnr('Xargnew5')], + \ tabpagebuflist(3)) + set tabpagemax& + + " Without the 'hidden' option, modified buffers should not be closed. + args Xargnew1 Xargnew2 + %bw! + edit Xargtemp1 + call setline(1, 'temp buffer 1') + split Xargtemp2 + call setline(1, 'temp buffer 2') + all + call assert_equal(4, winnr('$')) + call assert_equal([bufnr('Xargtemp2'), bufnr('Xargtemp1'), bufnr('Xargnew1'), + \ bufnr('Xargnew2')], + \ [winbufnr(1), winbufnr(2), winbufnr(3), winbufnr(4)]) + + " With the 'hidden' option set, both modified and unmodified buffers in + " closed windows should be hidden. + set hidden + all + call assert_equal(2, winnr('$')) + call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')], + \ [winbufnr(1), winbufnr(2)]) + call assert_equal([1, 1, 0, 0], [getbufinfo('Xargtemp1')[0].hidden, + \ getbufinfo('Xargtemp2')[0].hidden, + \ getbufinfo('Xargnew1')[0].hidden, + \ getbufinfo('Xargnew2')[0].hidden]) + set nohidden + + " When 'winheight' is set to a large value, :all should open only one + " window. + args Xargnew1 Xargnew2 Xargnew3 Xargnew4 Xargnew5 + %bw! + set winheight=9999 + call assert_fails('all', 'E36:') + call assert_equal([1, bufnr('Xargnew1')], [winnr('$'), winbufnr(1)]) + set winheight& + + " When 'winwidth' is set to a large value, :vert all should open only one + " window. + %bw! + set winwidth=9999 + call assert_fails('vert all', 'E36:') + call assert_equal([1, bufnr('Xargnew1')], [winnr('$'), winbufnr(1)]) + set winwidth& + + " empty argument list tests + %bw! + %argdelete + call assert_equal('', execute('args')) + all + call assert_equal(1, winnr('$')) + + %argdelete + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim index fdd8b0bef6..8723a0a38d 100644 --- a/src/nvim/testdir/test_assert.vim +++ b/src/nvim/testdir/test_assert.vim @@ -278,19 +278,18 @@ func Test_assert_with_msg() endfunc func Test_mouse_position() - throw 'Skipped: Nvim does not have test_setmouse()' let save_mouse = &mouse set mouse=a new call setline(1, ['line one', 'line two']) call assert_equal([0, 1, 1, 0], getpos('.')) - call test_setmouse(1, 5) + call Ntest_setmouse(1, 5) call feedkeys("\<LeftMouse>", "xt") call assert_equal([0, 1, 5, 0], getpos('.')) - call test_setmouse(2, 20) + call Ntest_setmouse(2, 20) call feedkeys("\<LeftMouse>", "xt") call assert_equal([0, 2, 8, 0], getpos('.')) - call test_setmouse(5, 1) + call Ntest_setmouse(5, 1) call feedkeys("\<LeftMouse>", "xt") call assert_equal([0, 2, 1, 0], getpos('.')) bwipe! diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 716511210d..025bda4515 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -148,6 +148,12 @@ func Test_autocmd_bufunload_with_tabnext() quit endfunc +func Test_argdelete_in_next() + au BufNew,BufEnter,BufLeave,BufWinEnter * argdel + call assert_fails('next a b', 'E1156:') + au! BufNew,BufEnter,BufLeave,BufWinEnter * +endfunc + func Test_autocmd_bufwinleave_with_tabfirst() tabedit augroup sample @@ -341,6 +347,39 @@ func Test_WinScrolled_close_curwin() call delete('Xtestout') endfunc +func Test_WinScrolled_long_wrapped() + CheckRunVimInTerminal + + let lines =<< trim END + set scrolloff=0 + let height = winheight(0) + let width = winwidth(0) + let g:scrolled = 0 + au WinScrolled * let g:scrolled += 1 + call setline(1, repeat('foo', height * width)) + call cursor(1, height * width) + END + call writefile(lines, 'Xtest_winscrolled_long_wrapped') + let buf = RunVimInTerminal('-S Xtest_winscrolled_long_wrapped', {'rows': 6}) + + call term_sendkeys(buf, ":echo g:scrolled\<CR>") + call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000) + + call term_sendkeys(buf, 'gj') + call term_sendkeys(buf, ":echo g:scrolled\<CR>") + call WaitForAssert({-> assert_match('^1 ', term_getline(buf, 6))}, 1000) + + call term_sendkeys(buf, '0') + call term_sendkeys(buf, ":echo g:scrolled\<CR>") + call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000) + + call term_sendkeys(buf, '$') + call term_sendkeys(buf, ":echo g:scrolled\<CR>") + call WaitForAssert({-> assert_match('^3 ', term_getline(buf, 6))}, 1000) + + call delete('Xtest_winscrolled_long_wrapped') +endfunc + func Test_WinClosed() " Test that the pattern is matched against the closed window's ID, and both " <amatch> and <afile> are set to it. @@ -414,6 +453,26 @@ func Test_WinClosed_throws_with_tabs() augroup! test-WinClosed endfunc +" This used to trigger WinClosed twice for the same window, and the window's +" buffer was NULL in the second autocommand. +func Test_WinClosed_switch_tab() + edit Xa + split Xb + split Xc + tab split + new + augroup test-WinClosed + autocmd WinClosed * tabprev | bwipe! + augroup END + close + " Check that the tabline has been fully removed + call assert_equal([1, 1], win_screenpos(0)) + + autocmd! test-WinClosed + augroup! test-WinClosed + %bwipe! +endfunc + func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' @@ -493,6 +552,28 @@ func Test_BufReadCmdHelpJump() au! BufReadCmd endfunc +" BufReadCmd is triggered for a "nofile" buffer. Check all values. +func Test_BufReadCmdNofile() + for val in ['nofile', + \ 'nowrite', + \ 'acwrite', + \ 'quickfix', + \ 'help', + "\ 'terminal', + \ 'prompt', + "\ 'popup', + \ ] + new somefile + exe 'set buftype=' .. val + au BufReadCmd somefile call setline(1, 'triggered') + edit + call assert_equal('triggered', getline(1)) + + au! BufReadCmd + bwipe! + endfor +endfunc + func Test_augroup_deleted() " This caused a crash before E936 was introduced augroup x @@ -587,9 +668,28 @@ func Test_BufEnter() " On MS-Windows we can't edit the directory, make sure we wipe the right " buffer. bwipe! Xdir - call delete('Xdir', 'd') au! BufEnter + + " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter + " for historic reasons. Also test other 'buftype' values. + for val in ['nofile', + \ 'nowrite', + \ 'acwrite', + \ 'quickfix', + \ 'help', + "\ 'terminal', + \ 'prompt', + "\ 'popup', + \ ] + new somefile + exe 'set buftype=' .. val + au BufEnter somefile call setline(1, 'some text') + edit + call assert_equal('some text', getline(1)) + bwipe! + au! BufEnter + endfor endfunc " Closing a window might cause an endless loop @@ -1766,6 +1866,21 @@ func Test_BufReadCmd() au! BufWriteCmd endfunc +func Test_BufWriteCmd() + autocmd BufWriteCmd Xbufwritecmd let g:written = 1 + new + file Xbufwritecmd + set buftype=acwrite + call mkdir('Xbufwritecmd') + write + " BufWriteCmd should be triggered even if a directory has the same name + call assert_equal(1, g:written) + call delete('Xbufwritecmd', 'd') + unlet g:written + au! BufWriteCmd + bwipe! +endfunc + func SetChangeMarks(start, end) exe a:start .. 'mark [' exe a:end .. 'mark ]' @@ -1939,6 +2054,7 @@ endfunc func Test_autocommand_all_events() call assert_fails('au * * bwipe', 'E1155:') call assert_fails('au * x bwipe', 'E1155:') + call assert_fails('au! * x bwipe', 'E1155:') endfunc func Test_autocmd_user() @@ -2724,6 +2840,30 @@ func Test_autocmd_FileReadCmd() delfunc ReadFileCmd endfunc +" Test for passing invalid arguments to autocmd +func Test_autocmd_invalid_args() + " Additional character after * for event + call assert_fails('autocmd *a Xfile set ff=unix', 'E215:') + augroup Test + augroup END + " Invalid autocmd event + call assert_fails('autocmd Bufabc Xfile set ft=vim', 'E216:') + " Invalid autocmd event in a autocmd group + call assert_fails('autocmd Test Bufabc Xfile set ft=vim', 'E216:') + augroup! Test + " Execute all autocmds + call assert_fails('doautocmd * BufEnter', 'E217:') + call assert_fails('augroup! x1a2b3', 'E367:') + call assert_fails('autocmd BufNew <buffer=999> pwd', 'E680:') +endfunc + +" Test for deep nesting of autocmds +func Test_autocmd_deep_nesting() + autocmd BufEnter Xfile doautocmd BufEnter Xfile + call assert_fails('doautocmd BufEnter Xfile', 'E218:') + autocmd! BufEnter Xfile +endfunc + " Tests for SigUSR1 autocmd event, which is only available on posix systems. func Test_autocmd_sigusr1() CheckUnix @@ -2871,6 +3011,15 @@ func Test_Visual_doautoall_redraw() %bwipe! endfunc +" This was using freed memory. +func Test_BufNew_arglocal() + arglocal + au BufNew * arglocal + call assert_fails('drop xx', 'E1156:') + + au! BufNew +endfunc + func Test_autocmd_closes_window() au BufNew,BufWinLeave * e %e file yyy diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim index af42b3857d..70529c14d5 100644 --- a/src/nvim/testdir/test_blob.vim +++ b/src/nvim/testdir/test_blob.vim @@ -294,7 +294,7 @@ func Test_blob_index() call assert_equal(2, index(0zDEADBEEF, 0xBE)) call assert_equal(-1, index(0zDEADBEEF, 0)) call assert_equal(2, index(0z11111111, 0x11, 2)) - call assert_equal(3, index(0z11110111, 0x11, 2)) + call assert_equal(3, 0z11110111->index(0x11, 2)) call assert_equal(2, index(0z11111111, 0x11, -2)) call assert_equal(3, index(0z11110111, 0x11, -2)) diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim index 67be3e6747..4def3b5df9 100644 --- a/src/nvim/testdir/test_buffer.vim +++ b/src/nvim/testdir/test_buffer.vim @@ -154,6 +154,24 @@ func Test_bdelete_cmd() set nobuflisted enew call assert_fails('bdelete ' .. bnr, 'E516:') + + " Deleting more than one buffer + new Xbuf1 + new Xbuf2 + exe 'bdel ' .. bufnr('Xbuf2') .. ' ' .. bufnr('Xbuf1') + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xbuf1')[0].loaded) + call assert_equal(0, getbufinfo('Xbuf2')[0].loaded) + + " Deleting more than one buffer and an invalid buffer + new Xbuf1 + new Xbuf2 + let cmd = "exe 'bdel ' .. bufnr('Xbuf2') .. ' xxx ' .. bufnr('Xbuf1')" + call assert_fails(cmd, 'E94:') + call assert_equal(2, winnr('$')) + call assert_equal(1, getbufinfo('Xbuf1')[0].loaded) + call assert_equal(0, getbufinfo('Xbuf2')[0].loaded) + %bwipe! endfunc @@ -168,6 +186,194 @@ func Test_buffer_error() %bwipe endfunc +" Test for the status messages displayed when unloading, deleting or wiping +" out buffers +func Test_buffer_statusmsg() + CheckEnglish + set report=1 + new Xbuf1 + new Xbuf2 + let bnr = bufnr() + exe "normal 2\<C-G>" + call assert_match('buf ' .. bnr .. ':', v:statusmsg) + bunload Xbuf1 Xbuf2 + call assert_equal('2 buffers unloaded', v:statusmsg) + bdel Xbuf1 Xbuf2 + call assert_equal('2 buffers deleted', v:statusmsg) + bwipe Xbuf1 Xbuf2 + call assert_equal('2 buffers wiped out', v:statusmsg) + set report& +endfunc + +" Test for quitting the 'swapfile exists' dialog with the split buffer +" command. +func Test_buffer_sbuf_cleanup() + call writefile([], 'Xfile') + " first open the file in a buffer + new Xfile + let bnr = bufnr() + close + " create the swap file + call writefile([], '.Xfile.swp') + " Remove the catch-all that runtest.vim adds + au! SwapExists + augroup BufTest + au! + autocmd SwapExists Xfile let v:swapchoice='q' + augroup END + exe 'sbuf ' . bnr + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + + " test for :sball + sball + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + + %bw! + set shortmess+=F + let v:statusmsg = '' + edit Xfile + call assert_equal('', v:statusmsg) + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + set shortmess& + + call delete('Xfile') + call delete('.Xfile.swp') + augroup BufTest + au! + augroup END + augroup! BufTest +endfunc + +" Test for deleting a modified buffer with :confirm +func Test_bdel_with_confirm() + " requires a UI to be active + throw 'Skipped: use test/functional/legacy/buffer_spec.lua' + CheckUnix + CheckNotGui + CheckFeature dialog_con + new + call setline(1, 'test') + call assert_fails('bdel', 'E89:') + call feedkeys('c', 'L') + confirm bdel + call assert_equal(2, winnr('$')) + call assert_equal(1, &modified) + call feedkeys('n', 'L') + confirm bdel + call assert_equal(1, winnr('$')) +endfunc + +" Test for editing another buffer from a modified buffer with :confirm +func Test_goto_buf_with_confirm() + " requires a UI to be active + throw 'Skipped: use test/functional/legacy/buffer_spec.lua' + CheckUnix + CheckNotGui + CheckFeature dialog_con + new Xfile + enew + call setline(1, 'test') + call assert_fails('b Xfile', 'E37:') + call feedkeys('c', 'L') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call feedkeys('y', 'L') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call feedkeys('n', 'L') + confirm b Xfile + call assert_equal('Xfile', @%) + close! +endfunc + +" Test for splitting buffer with 'switchbuf' +func Test_buffer_switchbuf() + new Xfile + wincmd w + set switchbuf=useopen + sbuf Xfile + call assert_equal(1, winnr()) + call assert_equal(2, winnr('$')) + set switchbuf=usetab + tabnew + sbuf Xfile + call assert_equal(1, tabpagenr()) + call assert_equal(2, tabpagenr('$')) + set switchbuf& + %bw +endfunc + +" Test for BufAdd autocommand wiping out the buffer +func Test_bufadd_autocmd_bwipe() + %bw! + augroup BufAdd_Wipe + au! + autocmd BufAdd Xfile %bw! + augroup END + edit Xfile + call assert_equal('', @%) + call assert_equal(0, bufexists('Xfile')) + augroup BufAdd_Wipe + au! + augroup END + augroup! BufAdd_Wipe +endfunc + +" Test for trying to load a buffer with text locked +" <C-\>e in the command line is used to lock the text +func Test_load_buf_with_text_locked() + new Xfile1 + edit Xfile2 + let cmd = ":\<C-\>eexecute(\"normal \<C-O>\")\<CR>\<C-C>" + call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') + %bw! +endfunc + +" Test for using CTRL-^ to edit the alternative file keeping the cursor +" position with 'nostartofline'. Also test using the 'buf' command. +func Test_buffer_edit_altfile() + call writefile(repeat(['one two'], 50), 'Xfile1') + call writefile(repeat(['five six'], 50), 'Xfile2') + set nosol + edit Xfile1 + call cursor(25, 5) + edit Xfile2 + call cursor(30, 4) + exe "normal \<C-^>" + call assert_equal([0, 25, 5, 0], getpos('.')) + exe "normal \<C-^>" + call assert_equal([0, 30, 4, 0], getpos('.')) + buf Xfile1 + call assert_equal([0, 25, 5, 0], getpos('.')) + buf Xfile2 + call assert_equal([0, 30, 4, 0], getpos('.')) + set sol& + call delete('Xfile1') + call delete('Xfile2') +endfunc + +" Test for running the :sball command with a maximum window count and a +" modified buffer +func Test_sball_with_count() + %bw! + edit Xfile1 + call setline(1, ['abc']) + new Xfile2 + new Xfile3 + new Xfile4 + 2sball + call assert_equal(bufnr('Xfile4'), winbufnr(1)) + call assert_equal(bufnr('Xfile1'), winbufnr(2)) + call assert_equal(0, getbufinfo('Xfile2')[0].loaded) + call assert_equal(0, getbufinfo('Xfile3')[0].loaded) + %bw! +endfunc + func Test_badd_options() new SomeNewBuffer setlocal numberwidth=3 diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim index 579d3a5eb5..3b5bcbce89 100644 --- a/src/nvim/testdir/test_bufline.vim +++ b/src/nvim/testdir/test_bufline.vim @@ -19,7 +19,7 @@ func Test_setbufline_getbufline() let b = bufnr('%') wincmd w call assert_equal(1, setbufline(b, 5, ['x'])) - call assert_equal(1, setbufline(bufnr('$') + 1, 1, ['x'])) + call assert_equal(1, ['x']->setbufline(bufnr('$') + 1, 1)) call assert_equal(0, setbufline(b, 4, ['d', 'e'])) call assert_equal(['c'], b->getbufline(3)) call assert_equal(['d'], getbufline(b, 4)) @@ -187,4 +187,24 @@ func Test_deletebufline_select_mode() bwipe! endfunc +func Test_setbufline_startup_nofile() + let before =<< trim [CODE] + set shortmess+=F + file Xresult + set buftype=nofile + call setbufline('', 1, 'success') + [CODE] + let after =<< trim [CODE] + set buftype= + write + quit + [CODE] + + if !RunVim(before, after, '--clean') + return + endif + call assert_equal(['success'], readfile('Xresult')) + call delete('Xresult') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim index a1e53df774..d6d44d1901 100644 --- a/src/nvim/testdir/test_cd.vim +++ b/src/nvim/testdir/test_cd.vim @@ -113,7 +113,7 @@ func Test_chdir_func() call assert_equal('z', fnamemodify(3->getcwd(2), ':t')) tabnext | wincmd t call assert_match('^\[tabpage\] .*/y$', trim(execute('verbose pwd'))) - call chdir('..') + eval '..'->chdir() call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t')) call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t')) call assert_equal('z', fnamemodify(getcwd(3, 2), ':t')) diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim index edf36b413b..a4ebce5af9 100644 --- a/src/nvim/testdir/test_clientserver.vim +++ b/src/nvim/testdir/test_clientserver.vim @@ -2,6 +2,11 @@ source check.vim CheckFeature job + +if !has('clientserver') + call assert_fails('call remote_startserver("local")', 'E942:') +endif + CheckFeature clientserver source shared.vim @@ -59,15 +64,16 @@ func Test_client_server() " the GUI and check that the remote command still works. " Need to wait for the GUI to start up, otherwise the send hangs in trying " to send to the terminal window. - if has('gui_athena') || has('gui_motif') - " For those GUIs, ignore the 'failed to create input context' error. + if has('gui_motif') + " For this GUI ignore the 'failed to create input context' error. call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>") else call remote_send(name, ":gui -f\<CR>") endif " Wait for the server to be up and answering requests. - sleep 100m - call WaitForAssert({-> assert_true(name->remote_expr("v:version", "", 1) != "")}) + " When using valgrind this can be very, very slow. + sleep 1 + call WaitForAssert({-> assert_match('\d', name->remote_expr("v:version", "", 1))}, 10000) call remote_send(name, ":let testvar = 'maybe'\<CR>") call WaitForAssert({-> assert_equal('maybe', remote_expr(name, "testvar", "", 2))}) @@ -178,6 +184,7 @@ func Test_client_server() call assert_fails("let x = remote_peek([])", 'E730:') call assert_fails("let x = remote_read('vim10')", 'E277:') + call assert_fails("call server2client('abc', 'xyz')", 'E258:') 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 35886d42c5..3f8e141afa 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -3,6 +3,7 @@ source check.vim source screendump.vim source view_util.vim +source shared.vim func Test_complete_tab() call writefile(['testfile'], 'Xtestfile') @@ -126,13 +127,74 @@ func Test_wildmenu_screendump() call delete('XTest_wildmenu') endfunc +func Test_redraw_in_autocmd() + CheckScreendump + + let lines =<< trim END + set cmdheight=2 + autocmd CmdlineChanged * redraw + END + call writefile(lines, 'XTest_redraw', 'D') + + let buf = RunVimInTerminal('-S XTest_redraw', {'rows': 8}) + call term_sendkeys(buf, ":for i in range(3)\<CR>") + call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_1', {}) + + call term_sendkeys(buf, "let i =") + call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_2', {}) + + " clean up + call term_sendkeys(buf, "\<CR>") + call StopVimInTerminal(buf) +endfunc + +func Test_redrawstatus_in_autocmd() + CheckScreendump + + let lines =<< trim END + set laststatus=2 + set statusline=%=:%{getcmdline()} + autocmd CmdlineChanged * redrawstatus + END + call writefile(lines, 'XTest_redrawstatus', 'D') + + let buf = RunVimInTerminal('-S XTest_redrawstatus', {'rows': 8}) + " :redrawstatus is postponed if messages have scrolled + call term_sendkeys(buf, ":echo \"one\\ntwo\\nthree\\nfour\"\<CR>") + call term_sendkeys(buf, ":foobar") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_1', {}) + " it is not postponed if messages have not scrolled + call term_sendkeys(buf, "\<Esc>:for in in range(3)") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_2', {}) + " with cmdheight=1 messages have scrolled when typing :endfor + call term_sendkeys(buf, "\<CR>:endfor") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_3', {}) + call term_sendkeys(buf, "\<CR>:set cmdheight=2\<CR>") + " with cmdheight=2 messages haven't scrolled when typing :for or :endfor + call term_sendkeys(buf, ":for in in range(3)") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_4', {}) + call term_sendkeys(buf, "\<CR>:endfor") + call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_5', {}) + + " clean up + call term_sendkeys(buf, "\<CR>") + call StopVimInTerminal(buf) +endfunc + func Test_changing_cmdheight() CheckScreendump let lines =<< trim END set cmdheight=1 laststatus=2 + func EchoTwo() + set laststatus=2 + set cmdheight=5 + echo 'foo' + echo 'bar' + set cmdheight=1 + endfunc END - call writefile(lines, 'XTest_cmdheight') + call writefile(lines, 'XTest_cmdheight', 'D') let buf = RunVimInTerminal('-S XTest_cmdheight', {'rows': 8}) call term_sendkeys(buf, ":resize -3\<CR>") @@ -150,14 +212,27 @@ func Test_changing_cmdheight() call term_sendkeys(buf, ":set cmdheight-=2\<CR>") call VerifyScreenDump(buf, 'Test_changing_cmdheight_4', {}) - " reducing window size and then setting cmdheight + " reducing window size and then setting cmdheight call term_sendkeys(buf, ":resize -1\<CR>") call term_sendkeys(buf, ":set cmdheight=1\<CR>") call VerifyScreenDump(buf, 'Test_changing_cmdheight_5', {}) + " setting 'cmdheight' works after outputting two messages + call term_sendkeys(buf, ":call EchoTwo()\<CR>") + call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {}) + + " clean up + call StopVimInTerminal(buf) +endfunc + +func Test_cmdheight_tabline() + CheckScreendump + + let buf = RunVimInTerminal('-c "set ls=2" -c "set stal=2" -c "set cmdheight=1"', {'rows': 6}) + call VerifyScreenDump(buf, 'Test_cmdheight_tabline_1', {}) + " clean up call StopVimInTerminal(buf) - call delete('XTest_cmdheight') endfunc func Test_map_completion() @@ -243,7 +318,7 @@ func Test_match_completion() return endif hi Aardig ctermfg=green - call feedkeys(":match \<Tab>\<Home>\"\<CR>", 'xt') + call feedkeys(":match A\<Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"match Aardig', getreg(':')) call feedkeys(":match \<S-Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"match none', getreg(':')) @@ -254,9 +329,7 @@ func Test_highlight_completion() return endif hi Aardig ctermfg=green - call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt') - call assert_equal('"hi Aardig', getreg(':')) - call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt') + call feedkeys(":hi default A\<Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"hi default Aardig', getreg(':')) call feedkeys(":hi clear Aa\<Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"hi clear Aardig', getreg(':')) @@ -514,6 +587,7 @@ func Test_getcompletion() call delete('Xtags') set tags& + call assert_fails("call getcompletion('\\\\@!\\\\@=', 'buffer')", 'E871:') call assert_fails('call getcompletion("", "burp")', 'E475:') call assert_fails('call getcompletion("abc", [])', 'E475:') endfunc @@ -926,6 +1000,10 @@ func Test_cmdline_complete_various() call feedkeys(":all abc\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal("\"all abc\<C-A>", @:) + " completion for :wincmd with :horizontal modifier + call feedkeys(":horizontal wincm\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal("\"horizontal wincmd", @:) + " completion for a command with a command modifier call feedkeys(":topleft new\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal("\"topleft new", @:) @@ -1051,6 +1129,18 @@ func Test_cmdline_write_alternatefile() bw! endfunc +func Test_cmdline_expand_cur_alt_file() + enew + file http://some.com/file.txt + call feedkeys(":e %\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e http://some.com/file.txt', @:) + edit another + call feedkeys(":e #\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e http://some.com/file.txt', @:) + bwipe + bwipe http://some.com/file.txt +endfunc + " using a leading backslash here set cpo+=C @@ -1260,6 +1350,16 @@ func Test_cmdline_overstrike() let &encoding = encoding_save endfunc +func Test_cmdwin_bug() + let winid = win_getid() + sp + try + call feedkeys("q::call win_gotoid(" .. winid .. ")\<CR>:q\<CR>", 'x!') + catch /^Vim\%((\a\+)\)\=:E11/ + endtry + bw! +endfunc + func Test_cmdwin_restore() CheckScreendump @@ -1452,6 +1552,32 @@ func Test_cmdwin_tabpage() tabclose! endfunc +func Test_cmdwin_interrupted() + CheckScreendump + + " aborting the :smile output caused the cmdline window to use the current + " buffer. + let lines =<< trim [SCRIPT] + au WinNew * smile + [SCRIPT] + call writefile(lines, 'XTest_cmdwin') + + let buf = RunVimInTerminal('-S XTest_cmdwin', {'rows': 18}) + " open cmdwin + call term_sendkeys(buf, "q:") + call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 18))}) + " quit more prompt for :smile command + call term_sendkeys(buf, "q") + call WaitForAssert({-> assert_match('^$', term_getline(buf, 18))}) + " execute a simple command + call term_sendkeys(buf, "aecho 'done'\<CR>") + call VerifyScreenDump(buf, 'Test_cmdwin_interrupted', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XTest_cmdwin') +endfunc + " Test for backtick expression in the command line func Test_cmd_backtick() CheckNotMSWindows " FIXME: see #19297 @@ -1809,6 +1935,36 @@ func Test_read_shellcmd() endif endfunc +" Test for going up and down the directory tree using 'wildmenu' +func Test_wildmenu_dirstack() + CheckUnix + %bw! + call mkdir('Xdir1/dir2/dir3', 'p') + call writefile([], 'Xdir1/file1_1.txt') + call writefile([], 'Xdir1/file1_2.txt') + call writefile([], 'Xdir1/dir2/file2_1.txt') + call writefile([], 'Xdir1/dir2/file2_2.txt') + call writefile([], 'Xdir1/dir2/dir3/file3_1.txt') + call writefile([], 'Xdir1/dir2/dir3/file3_2.txt') + cd Xdir1/dir2/dir3 + set wildmenu + + call feedkeys(":e \<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e file3_1.txt', @:) + call feedkeys(":e \<Tab>\<Up>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e ../dir3/', @:) + call feedkeys(":e \<Tab>\<Up>\<Up>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e ../../dir2/', @:) + call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e ../../dir2/dir3/', @:) + call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<Down>\<C-B>\"\<CR>", 'xt') + call assert_equal('"e ../../dir2/dir3/file3_1.txt', @:) + + cd - + call delete('Xdir1', 'rf') + set wildmenu& +endfunc + " Test for recalling newer or older cmdline from history with <Up>, <Down>, " <S-Up>, <S-Down>, <PageUp>, <PageDown>, <C-p>, or <C-n>. func Test_recalling_cmdline() @@ -2129,4 +2285,57 @@ func Test_wildmenu_pum_disable_while_shown() set wildoptions& wildmenu& endfunc +func Test_setcmdline() + func SetText(text, pos) + autocmd CmdlineChanged * let g:cmdtype = expand('<afile>') + call assert_equal(0, setcmdline(a:text)) + call assert_equal(a:text, getcmdline()) + call assert_equal(len(a:text) + 1, getcmdpos()) + call assert_equal(getcmdtype(), g:cmdtype) + unlet g:cmdtype + autocmd! CmdlineChanged + + call assert_equal(0, setcmdline(a:text, a:pos)) + call assert_equal(a:text, getcmdline()) + call assert_equal(a:pos, getcmdpos()) + + call assert_fails('call setcmdline("' .. a:text .. '", -1)', 'E487:') + call assert_fails('call setcmdline({}, 0)', 'E1174:') + call assert_fails('call setcmdline("' .. a:text .. '", {})', 'E1210:') + + return '' + endfunc + + call feedkeys(":\<C-R>=SetText('set rtp?', 2)\<CR>\<CR>", 'xt') + call assert_equal('set rtp?', @:) + + call feedkeys(":let g:str = input('? ')\<CR>", 't') + call feedkeys("\<C-R>=SetText('foo', 4)\<CR>\<CR>", 'xt') + call assert_equal('foo', g:str) + unlet g:str + + delfunc SetText + + " setcmdline() returns 1 when not editing the command line. + call assert_equal(1, 'foo'->setcmdline()) + + " Called in custom function + func CustomComplete(A, L, P) + call assert_equal(0, setcmdline("DoCmd ")) + return "January\nFebruary\nMars\n" + endfunc + + com! -nargs=* -complete=custom,CustomComplete DoCmd : + call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"DoCmd January February Mars', @:) + delcom DoCmd + delfunc CustomComplete + + " Called in <expr> + cnoremap <expr>a setcmdline('let foo=') + call feedkeys(":a\<CR>", 'tx') + call assert_equal('let foo=0', @:) + cunmap a +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_comments.vim b/src/nvim/testdir/test_comments.vim new file mode 100644 index 0000000000..c34b85c42d --- /dev/null +++ b/src/nvim/testdir/test_comments.vim @@ -0,0 +1,277 @@ +" Tests for the various flags in the 'comments' option + +" Test for the 'n' flag in 'comments' +func Test_comment_nested() + new + setlocal comments=n:> fo+=ro + exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH" + exe "normal 5GOE\<C-C>6GoG" + let expected =<< trim END + > A + > B + > C + > D + >>>> E + >>>> F + >>>> G + >>>> H + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for the 'b' flag in 'comments' +func Test_comment_blank() + new + setlocal comments=b:* fo+=ro + exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD" + let expected =<< trim END + A + *B + * C + * D + * E + * F + *G + H + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for the 'f' flag in 'comments' (only the first line has a comment +" string) +func Test_comment_firstline() + new + setlocal comments=f:- fo+=ro + exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>" + call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$')) + %d + setlocal comments=:- + exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>" + call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$')) + close! +endfunc + +" Test for the 's', 'm' and 'e' flags in 'comments' +" Test for automatically adding comment leaders in insert mode +func Test_comment_threepiece() + new + setlocal expandtab + call setline(1, ["\t/*"]) + setlocal formatoptions=croql + call cursor(1, 3) + call feedkeys("A\<cr>\<cr>/", 'tnix') + call assert_equal(["\t/*", " *", " */"], getline(1, '$')) + + " If a comment ends in a single line, then don't add it in the next line + %d + call setline(1, '/* line1 */') + call feedkeys("A\<CR>next line", 'xt') + call assert_equal(['/* line1 */', 'next line'], getline(1, '$')) + + %d + " Copy the trailing indentation from the leader comment to a new line + setlocal autoindent noexpandtab + call feedkeys("a\t/*\tone\ntwo\n/", 'xt') + call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$')) + close! +endfunc + +" Test for the 'r' flag in 'comments' (right align comment) +func Test_comment_rightalign() + new + setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro + exe "normal i=\<C-C>o\t /***\nD\n/" + exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG" + let expected =<< trim END + = + A + /*** + ** B + ** C + ** D + ** E + ** F + ******/ + G + END + call assert_equal(expected, getline(1, '$')) + close! +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, '$')) + close! +endfunc + +" Test for using a multibyte character as a comment leader +func Test_comment_multibyte_leader() + new + let t =<< trim END + { + X + Xa + Xaï¼¹ + XY + XYZ + X ï¼¹ + X YZ + XX + XXa + XXY + } + END + call setline(1, t) + call cursor(2, 1) + + set tw=2 fo=cqm comments=n:X + exe "normal gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgq" + let t =<< trim END + X + Xa + Xaï¼¹ + XY + XYZ + X ï¼¹ + X YZ + XX + XXa + XXY + END + exe "normal o\n" . join(t, "\n") + + let expected =<< trim END + { + X + Xa + Xa + XY + XY + XY + XZ + X ï¼¹ + X ï¼¹ + X Z + XX + XXa + XXY + + X + Xa + Xa + XY + XY + XY + XZ + X ï¼¹ + X ï¼¹ + X Z + XX + XXa + XXY + } + END + call assert_equal(expected, getline(1, '$')) + + set tw& fo& comments& + close! +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, '$')) + close! +endfunc + +" Test for formatting lines with and without comments +func Test_comment_format_lines() + new + call setline(1, ['one', '/* two */', 'three']) + normal gggqG + call assert_equal(['one', '/* two */', 'three'], getline(1, '$')) + close! +endfunc + +" Test for using 'a' in 'formatoptions' with comments +func Test_comment_autoformat() + new + setlocal formatoptions+=a + call feedkeys("a- one\n- two\n", 'xt') + call assert_equal(['- one', '- two', ''], getline(1, '$')) + + %d + call feedkeys("a\none\n", 'xt') + call assert_equal(['', 'one', ''], getline(1, '$')) + + setlocal formatoptions+=aw + %d + call feedkeys("aone \ntwo\n", 'xt') + call assert_equal(['one two', ''], getline(1, '$')) + + %d + call feedkeys("aone\ntwo\n", 'xt') + call assert_equal(['one', 'two', ''], getline(1, '$')) + + close! +endfunc + +" Test for joining lines with comments ('j' flag in 'formatoptions') +func Test_comment_join_lines_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)) + close! +endfunc + +" Test for formatting lines where only the first line has a comment. +func Test_comment_format_firstline_comment() + new + setlocal formatoptions=tcq + call setline(1, ['- one two', 'three']) + normal gggqG + call assert_equal(['- one two three'], getline(1, '$')) + + %d + call setline(1, ['- one', '- two']) + normal gggqG + call assert_equal(['- one', '- two'], getline(1, '$')) + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim index 3b8a5f27ad..9801a45915 100644 --- a/src/nvim/testdir/test_cursor_func.vim +++ b/src/nvim/testdir/test_cursor_func.vim @@ -22,7 +22,7 @@ func Test_move_cursor() call cursor(3, 0) call assert_equal([3, 1, 0, 1], getcurpos()[1:]) " below last line goes to last line - call cursor(9, 1) + eval [9, 1]->cursor() call assert_equal([4, 1, 0, 1], getcurpos()[1:]) " pass string arguments call cursor('3', '3') @@ -32,7 +32,7 @@ func Test_move_cursor() call cursor(1, 1, 1) call assert_equal([1, 1, 1], getcurpos()[1:3]) - call assert_equal(-1, cursor(-1, -1)) + call assert_fails('call cursor(-1, -1)', 'E475:') quit! endfunc @@ -353,8 +353,14 @@ func Test_setcursorcharpos() normal G call setcursorcharpos([1, 1]) call assert_equal([1, 1], [line('.'), col('.')]) + call setcursorcharpos([2, 7, 0]) call assert_equal([2, 9], [line('.'), col('.')]) + call setcursorcharpos([0, 7, 0]) + call assert_equal([2, 9], [line('.'), col('.')]) + call setcursorcharpos(0, 7, 0) + call assert_equal([2, 9], [line('.'), col('.')]) + call setcursorcharpos(3, 4) call assert_equal([3, 1], [line('.'), col('.')]) call setcursorcharpos([3, 1]) @@ -373,4 +379,26 @@ func Test_setcursorcharpos() %bw! endfunc +" Test for virtcol2col() +func Test_virtcol2col() + new + call setline(1, ["a\tb\tc"]) + call assert_equal(1, virtcol2col(0, 1, 1)) + call assert_equal(2, virtcol2col(0, 1, 2)) + call assert_equal(2, virtcol2col(0, 1, 8)) + call assert_equal(3, virtcol2col(0, 1, 9)) + call assert_equal(4, virtcol2col(0, 1, 10)) + call assert_equal(4, virtcol2col(0, 1, 16)) + call assert_equal(5, virtcol2col(0, 1, 17)) + call assert_equal(-1, virtcol2col(10, 1, 1)) + call assert_equal(-1, virtcol2col(0, 10, 1)) + call assert_equal(-1, virtcol2col(0, -1, 1)) + call assert_equal(-1, virtcol2col(0, 1, -1)) + call assert_equal(5, virtcol2col(0, 1, 20)) + call assert_fails('echo virtcol2col("0", 1, 20)', 'E1210:') + call assert_fails('echo virtcol2col(0, "1", 20)', 'E1210:') + call assert_fails('echo virtcol2col(0, 1, "1")', 'E1210:') + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim index e85e9304a3..47646125db 100644 --- a/src/nvim/testdir/test_cursorline.vim +++ b/src/nvim/testdir/test_cursorline.vim @@ -3,26 +3,26 @@ source check.vim source screendump.vim -function! s:screen_attr(lnum) abort +func s:screen_attr(lnum) abort return map(range(1, 8), 'screenattr(a:lnum, v:val)') -endfunction +endfunc -function! s:test_windows(h, w) abort +func s:test_windows(h, w) abort call NewWindow(a:h, a:w) -endfunction +endfunc -function! s:close_windows() abort +func s:close_windows() abort call CloseWindow() -endfunction +endfunc -function! s:new_hi() abort +func s:new_hi() abort redir => save_hi silent! hi CursorLineNr redir END let save_hi = join(split(substitute(save_hi, '\s*xxx\s*', ' ', ''), "\n"), '') exe 'hi' save_hi 'ctermbg=0 guibg=Black' return save_hi -endfunction +endfunc func Test_cursorline_highlight1() let save_hi = s:new_hi() diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim index e038c0096a..2be94409ca 100644 --- a/src/nvim/testdir/test_debugger.vim +++ b/src/nvim/testdir/test_debugger.vim @@ -15,14 +15,18 @@ func CheckCWD() endfunc command! -nargs=0 -bar CheckCWD call CheckCWD() +" "options" argument can contain: +" 'msec' - time to wait for a match +" 'match' - "pattern" to use "lines" as pattern instead of text func CheckDbgOutput(buf, lines, options = {}) " Verify the expected output let lnum = 20 - len(a:lines) + let msec = get(a:options, 'msec', 1000) for l in a:lines if get(a:options, 'match', 'equal') ==# 'pattern' - call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, 200) + call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, msec) else - call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200) + call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, msec) endif let lnum += 1 endfor @@ -198,7 +202,7 @@ func Test_Debugger() " Start a debug session, so that reading the last line from the terminal " works properly. - call RunDbgCmd(buf, ':debug echo Foo()') + call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()']) " No breakpoints call RunDbgCmd(buf, 'breakl', ['No breakpoints defined']) @@ -814,9 +818,10 @@ func Test_Backtrace_CmdLine() \ '-S Xtest1.vim -c "debug call GlobalFunction()"', \ {'wait_for_ruler': 0}) - " Need to wait for the vim-in-terminal to be ready + " Need to wait for the vim-in-terminal to be ready. + " With valgrind this can take quite long. call CheckDbgOutput(buf, ['command line', - \ 'cmd: call GlobalFunction()']) + \ 'cmd: call GlobalFunction()'], #{msec: 5000}) " At this point the ontly thing in the stack is the cmdline call RunDbgCmd(buf, 'backtrace', [ @@ -967,14 +972,14 @@ func Test_debug_backtrace_level() " set a breakpoint and source file1.vim let buf = RunVimInTerminal( \ '-c "breakadd file 1 Xtest1.vim" -S Xtest1.vim', - \ #{ wait_for_ruler: 0 } ) + \ #{wait_for_ruler: 0}) call CheckDbgOutput(buf, [ \ 'Breakpoint in "' .. file1 .. '" line 1', \ 'Entering Debug mode. Type "cont" to continue.', \ 'command line..script ' .. file1, \ 'line 1: let s:file1_var = ''file1''' - \ ]) + \ ], #{msec: 5000}) " step through the initial declarations call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] ) diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index ea453b7174..1cb71664bd 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -744,17 +744,13 @@ func Test_diff_hlID() call diff_hlID(-1, 1)->synIDattr("name")->assert_equal("") - call assert_equal(diff_hlID(1, 1), hlID("DiffChange")) call diff_hlID(1, 1)->synIDattr("name")->assert_equal("DiffChange") - call assert_equal(diff_hlID(1, 2), hlID("DiffText")) call diff_hlID(1, 2)->synIDattr("name")->assert_equal("DiffText") call diff_hlID(2, 1)->synIDattr("name")->assert_equal("") - call assert_equal(diff_hlID(3, 1), hlID("DiffAdd")) call diff_hlID(3, 1)->synIDattr("name")->assert_equal("DiffAdd") - call diff_hlID(4, 1)->synIDattr("name")->assert_equal("") + eval 4->diff_hlID(1)->synIDattr("name")->assert_equal("") wincmd w - call assert_equal(diff_hlID(1, 1), hlID("DiffChange")) call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange") call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "") call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "") diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim index acc34e5e7c..f08dff8605 100644 --- a/src/nvim/testdir/test_digraph.vim +++ b/src/nvim/testdir/test_digraph.vim @@ -211,6 +211,8 @@ func Test_digraphs() call Put_Dig("00") call Put_Dig("el") call assert_equal(['â€', 'ü', '∞', 'l'], getline(line('.')-3,line('.'))) + call assert_fails('exe "digraph a\<Esc> 100"', 'E104:') + call assert_fails('exe "digraph \<Esc>a 100"', 'E104:') call assert_fails('digraph xy z', 'E39:') call assert_fails('digraph x', 'E1214:') bw! @@ -491,6 +493,17 @@ func Test_show_digraph_cp1251() bwipe! endfunc +" Test for error in a keymap file +func Test_loadkeymap_error() + if !has('keymap') + return + endif + call assert_fails('loadkeymap', 'E105:') + call writefile(['loadkeymap', 'a'], 'Xkeymap') + call assert_fails('source Xkeymap', 'E791:') + call delete('Xkeymap') +endfunc + " Test for the characters displayed on the screen when entering a digraph func Test_entering_digraph() CheckRunVimInTerminal diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim index 6938abbc28..13796449ab 100644 --- a/src/nvim/testdir/test_display.vim +++ b/src/nvim/testdir/test_display.vim @@ -309,6 +309,88 @@ func Test_eob_fillchars() close endfunc +" Test for 'foldopen', 'foldclose' and 'foldsep' in 'fillchars' +func Test_fold_fillchars() + new + set fdc=2 foldenable foldmethod=manual + call setline(1, ['one', 'two', 'three', 'four', 'five']) + 2,4fold + " First check for the default setting for a closed fold + let lines = ScreenLines([1, 3], 8) + let expected = [ + \ ' one ', + \ '+ +-- 3', + \ ' five ' + \ ] + call assert_equal(expected, lines) + normal 2Gzo + " check the characters for an open fold + let lines = ScreenLines([1, 5], 8) + let expected = [ + \ ' one ', + \ '- two ', + \ '| three ', + \ '| four ', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + " change the setting + set fillchars=vert:\|,fold:-,eob:~,foldopen:[,foldclose:],foldsep:- + + " check the characters for an open fold + let lines = ScreenLines([1, 5], 8) + let expected = [ + \ ' one ', + \ '[ two ', + \ '- three ', + \ '- four ', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + " check the characters for a closed fold + normal 2Gzc + let lines = ScreenLines([1, 3], 8) + let expected = [ + \ ' one ', + \ '] +-- 3', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + %bw! + set fillchars& fdc& foldmethod& foldenable& +endfunc + +func Test_local_fillchars() + CheckScreendump + + let lines =<< trim END + call setline(1, ['window 1']->repeat(3)) + setlocal fillchars=stl:1,stlnc:a,vert:=,eob:x + vnew + call setline(1, ['window 2']->repeat(3)) + setlocal fillchars=stl:2,stlnc:b,vert:+,eob:y + new + wincmd J + call setline(1, ['window 3']->repeat(3)) + setlocal fillchars=stl:3,stlnc:c,vert:<,eob:z + vnew + call setline(1, ['window 4']->repeat(3)) + setlocal fillchars=stl:4,stlnc:d,vert:>,eob:o + END + call writefile(lines, 'Xdisplayfillchars') + let buf = RunVimInTerminal('-S Xdisplayfillchars', #{rows: 12}) + call VerifyScreenDump(buf, 'Test_display_fillchars_1', {}) + + call term_sendkeys(buf, ":wincmd k\r") + call VerifyScreenDump(buf, 'Test_display_fillchars_2', {}) + + call StopVimInTerminal(buf) + call delete('Xdisplayfillchars') +endfunc + func Test_display_linebreak_breakat() new vert resize 25 @@ -325,30 +407,49 @@ func Test_display_linebreak_breakat() let &breakat=_breakat endfunc -func Test_display_lastline() - CheckScreendump - +func Run_Test_display_lastline(euro) let lines =<< trim END - call setline(1, ['aaa', 'b'->repeat(100)]) + call setline(1, ['aaa', 'b'->repeat(200)]) set display=truncate + vsplit 100wincmd < END - call writefile(lines, 'XdispLastline') + if a:euro != '' + let lines[2] = 'set fillchars=vert:\|,lastline:€' + endif + call writefile(lines, 'XdispLastline', 'D') let buf = RunVimInTerminal('-S XdispLastline', #{rows: 10}) - call VerifyScreenDump(buf, 'Test_display_lastline_1', {}) + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}1', {}) call term_sendkeys(buf, ":set display=lastline\<CR>") - call VerifyScreenDump(buf, 'Test_display_lastline_2', {}) + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}2', {}) call term_sendkeys(buf, ":100wincmd >\<CR>") - call VerifyScreenDump(buf, 'Test_display_lastline_3', {}) + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}3', {}) call term_sendkeys(buf, ":set display=truncate\<CR>") - call VerifyScreenDump(buf, 'Test_display_lastline_4', {}) + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}4', {}) + + call term_sendkeys(buf, ":close\<CR>") + call term_sendkeys(buf, ":3split\<CR>") + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}5', {}) + + call term_sendkeys(buf, ":close\<CR>") + call term_sendkeys(buf, ":2vsplit\<CR>") + call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}6', {}) call StopVimInTerminal(buf) - call delete('XdispLastline') +endfunc + +func Test_display_lastline() + CheckScreendump + + call Run_Test_display_lastline('') + call Run_Test_display_lastline('euro_') + + call assert_fails(':set fillchars=lastline:', 'E474:') + call assert_fails(':set fillchars=lastline:〇', 'E474:') endfunc diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index e26bbdc5be..9783ed19a7 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -713,23 +713,32 @@ endfunc func Test_edit_CTRL_N() " Check keyword completion - new - set complete=. - call setline(1, ['INFER', 'loWER', '', '', ]) - call cursor(3, 1) - call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix") - call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix') - call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$')) - %d - call setline(1, ['INFER', 'loWER', '', '', ]) - call cursor(3, 1) - set ignorecase infercase - call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix") - call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix') - call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$')) - - set noignorecase noinfercase complete& - bw! + " for e in ['latin1', 'utf-8'] + for e in ['utf-8'] + exe 'set encoding=' .. e + new + set complete=. + call setline(1, ['INFER', 'loWER', '', '', ]) + call cursor(3, 1) + call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix") + call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix') + call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'), e) + %d + call setline(1, ['INFER', 'loWER', '', '', ]) + call cursor(3, 1) + set ignorecase infercase + call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix") + call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix') + call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'), e) + set noignorecase noinfercase + %d + call setline(1, ['one word', 'two word']) + exe "normal! Goo\<C-P>\<C-X>\<C-P>" + call assert_equal('one word', getline(3)) + %d + set complete& + bw! + endfor endfunc func Test_edit_CTRL_O() @@ -893,6 +902,24 @@ func Test_edit_CTRL_T() bw! endfunc +" Test thesaurus completion with different encodings +func Test_thesaurus_complete_with_encoding() + call writefile(['angry furious mad enraged'], 'Xthesaurus') + set thesaurus=Xthesaurus + " for e in ['latin1', 'utf-8'] + for e in ['utf-8'] + exe 'set encoding=' .. e + new + call setline(1, 'mad') + call cursor(1, 1) + call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix') + call assert_equal(['mad', ''], getline(1, '$')) + bw! + endfor + set thesaurus= + call delete('Xthesaurus') +endfunc + " Test 'thesaurusfunc' func MyThesaurus(findstart, base) let mythesaurus = [ @@ -1201,15 +1228,11 @@ func Test_edit_MOUSE() call assert_equal(24, line('w0')) call assert_equal([0, 24, 2, 0], getpos('.')) - " call test_setmouse(4, 3) - call nvim_input_mouse('left', 'press', '', 0, 3, 2) " set mouse position - call getchar() " discard mouse event but keep mouse position + call Ntest_setmouse(4, 3) call feedkeys("A\<LeftMouse>\<esc>", 'tnix') call assert_equal([0, 27, 2, 0], getpos('.')) set mousemodel=extend - " call test_setmouse(5, 3) - call nvim_input_mouse('right', 'press', '', 0, 4, 2) " set mouse position - call getchar() " discard mouse event but keep mouse position + call Ntest_setmouse(5, 3) call feedkeys("A\<RightMouse>\<esc>\<esc>", 'tnix') call assert_equal([0, 28, 2, 0], getpos('.')) set mousemodel& @@ -1904,4 +1927,76 @@ func Test_read_invalid() set encoding=utf-8 endfunc +" Test for the 'revins' option +func Test_edit_revins() + CheckFeature rightleft + new + set revins + exe "normal! ione\ttwo three" + call assert_equal("eerht owt\teno", getline(1)) + call setline(1, "one\ttwo three") + normal! gg$bi a + call assert_equal("one\ttwo a three", getline(1)) + exe "normal! $bi\<BS>\<BS>" + call assert_equal("one\ttwo a ree", getline(1)) + exe "normal! 0wi\<C-W>" + call assert_equal("one\t a ree", getline(1)) + exe "normal! 0wi\<C-U>" + call assert_equal("one\t ", getline(1)) + " newline in insert mode starts at the end of the line + call setline(1, 'one two three') + exe "normal! wi\nfour" + call assert_equal(['one two three', 'ruof'], getline(1, '$')) + set revins& + bw! +endfunc + +" Test for getting the character of the line below after "p" +func Test_edit_put_CTRL_E() + " set encoding=latin1 + new + let @" = '' + sil! norm orggRx + sil! norm pr + call assert_equal(['r', 'r'], getline(1, 2)) + bwipe! + set encoding=utf-8 +endfunc + +" Test toggling of input method. See :help i_CTRL-^ +func Test_edit_CTRL_hat() + CheckFeature xim + + " FIXME: test fails with Motif GUI. + " test also fails when running in the GUI. + CheckFeature gui_gtk + CheckNotGui + + new + + call assert_equal(0, &iminsert) + call feedkeys("i\<C-^>", 'xt') + call assert_equal(2, &iminsert) + call feedkeys("i\<C-^>", 'xt') + call assert_equal(0, &iminsert) + + bwipe! +endfunc + +" Weird long file name was going over the end of NameBuff +func Test_edit_overlong_file_name() + CheckUnix + + file 0000000000000000000000000000 + file %%%%%%%%%%%%%%%%%%%%%%%%%% + file %%%%%% + set readonly + set ls=2 + + redraw! + set noreadonly ls& + bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim index eff1376d3c..dc110af356 100644 --- a/src/nvim/testdir/test_eval_stuff.vim +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -1,5 +1,8 @@ " Tests for various eval things. +source view_util.vim +source shared.vim + function s:foo() abort try return [] == 0 @@ -87,22 +90,47 @@ func Test_for_over_null_string() let &enc = save_enc endfunc +func Test_for_invalid_line_count() + let lines =<< trim END + 111111111111111111111111 for line in ['one'] + endfor + END + call writefile(lines, 'XinvalidFor') + " only test that this doesn't crash + call RunVim([], [], '-u NONE -e -s -S XinvalidFor -c qa') + + call delete('XinvalidFor') +endfunc + func Test_readfile_binary() new call setline(1, ['one', 'two', 'three']) setlocal ff=dos - silent write XReadfile - let lines = readfile('XReadfile') + silent write XReadfile_bin + let lines = 'XReadfile_bin'->readfile() call assert_equal(['one', 'two', 'three'], lines) - let lines = readfile('XReadfile', '', 2) + let lines = readfile('XReadfile_bin', '', 2) call assert_equal(['one', 'two'], lines) - let lines = readfile('XReadfile', 'b') + let lines = readfile('XReadfile_bin', 'b') call assert_equal(["one\r", "two\r", "three\r", ""], lines) - let lines = readfile('XReadfile', 'b', 2) + let lines = readfile('XReadfile_bin', 'b', 2) call assert_equal(["one\r", "two\r"], lines) bwipe! - call delete('XReadfile') + call delete('XReadfile_bin') +endfunc + +func Test_readfile_bom() + call writefile(["\ufeffFOO", "FOO\ufeffBAR"], 'XReadfile_bom') + call assert_equal(['FOO', 'FOOBAR'], readfile('XReadfile_bom')) + call delete('XReadfile_bom') +endfunc + +func Test_readfile_max() + call writefile(range(1, 4), 'XReadfile_max') + call assert_equal(['1', '2'], readfile('XReadfile_max', '', 2)) + call assert_equal(['3', '4'], readfile('XReadfile_max', '', -2)) + call delete('XReadfile_max') endfunc func Test_let_errmsg() diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim index dac7a6989d..7692d4fc55 100644 --- a/src/nvim/testdir/test_excmd.vim +++ b/src/nvim/testdir/test_excmd.vim @@ -230,7 +230,6 @@ endfunc " Test for the :language command func Test_language_cmd() CheckNotMSWindows " FIXME: why does this fail on Windows CI? - CheckNotBSD " FIXME: why does this fail on OpenBSD CI? CheckFeature multi_lang call assert_fails('language ctype non_existing_lang', 'E197:') @@ -568,10 +567,12 @@ endfunc " Test for the :verbose command func Test_verbose_cmd() - call assert_equal([' verbose=1'], split(execute('verbose set vbs'), "\n")) + set verbose=3 + call assert_match(' verbose=1\n\s*Last set from ', execute('verbose set vbs'), "\n") call assert_equal([' verbose=0'], split(execute('0verbose set vbs'), "\n")) - let l = execute("4verbose set verbose | set verbose") - call assert_equal([' verbose=4', ' verbose=0'], split(l, "\n")) + set verbose=0 + call assert_match(' verbose=4\n\s*Last set from .*\n verbose=0', + \ execute("4verbose set verbose | set verbose")) endfunc " Test for the :delete command and the related abbreviated commands @@ -661,6 +662,12 @@ func Sandbox_tests() if has('unix') call assert_fails('cd `pwd`', 'E48:') endif + " some options cannot be changed in a sandbox + call assert_fails('set exrc', 'E48:') + call assert_fails('set cdpath', 'E48:') + if has('xim') && has('gui_gtk') + call assert_fails('set imstyle', 'E48:') + endif endfunc func Test_sandbox() diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim index ce414e4b11..aa131a49ff 100644 --- a/src/nvim/testdir/test_expand.vim +++ b/src/nvim/testdir/test_expand.vim @@ -116,13 +116,21 @@ func Test_source_sfile() :call assert_equal('edit <cword>', expandcmd("edit <cword>")) :call assert_equal('edit <cexpr>', expandcmd("edit <cexpr>")) :call assert_fails('autocmd User MyCmd echo "<sfile>"', 'E498:') + : + :call assert_equal('', expand('<script>')) + :verbose echo expand('<script>') + :call add(v:errors, v:errmsg) + :verbose echo expand('<sfile>') + :call add(v:errors, v:errmsg) :call writefile(v:errors, 'Xresult') :qall! - [SCRIPT] call writefile(lines, 'Xscript') if RunVim([], [], '--clean -s Xscript') - call assert_equal([], readfile('Xresult')) + call assert_equal([ + \ 'E1274: No script file name to substitute for "<script>"', + \ 'E498: no :source file name to substitute for "<sfile>"'], + \ readfile('Xresult')) endif call delete('Xscript') call delete('Xresult') @@ -147,4 +155,63 @@ func Test_expandcmd_shell_nonomatch() call assert_equal('$*', expandcmd('$*')) endfunc +func Test_expand_script_source() + let lines0 =<< trim [SCRIPT] + call extend(g:script_level, [expand('<script>:t')]) + so Xscript1 + func F0() + call extend(g:func_level, [expand('<script>:t')]) + endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) + [SCRIPT] + + let lines1 =<< trim [SCRIPT] + call extend(g:script_level, [expand('<script>:t')]) + so Xscript2 + func F1() + call extend(g:func_level, [expand('<script>:t')]) + endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) + [SCRIPT] + + let lines2 =<< trim [SCRIPT] + call extend(g:script_level, [expand('<script>:t')]) + func F2() + call extend(g:func_level, [expand('<script>:t')]) + endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) + [SCRIPT] + + call writefile(lines0, 'Xscript0') + call writefile(lines1, 'Xscript1') + call writefile(lines2, 'Xscript2') + + " Check the expansion of <script> at different levels. + let g:script_level = [] + let g:func_level = [] + let g:au_level = [] + + so Xscript0 + call F0() + call F1() + call F2() + doautocmd User + + call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level) + call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_level) + call assert_equal(['Xscript2', 'Xscript1', 'Xscript0'], g:au_level) + + unlet g:script_level g:func_level + delfunc F0 + delfunc F1 + delfunc F2 + + call delete('Xscript0') + call delete('Xscript1') + call delete('Xscript2') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim index df01d84f19..80bfdb8553 100644 --- a/src/nvim/testdir/test_expand_func.vim +++ b/src/nvim/testdir/test_expand_func.vim @@ -107,10 +107,15 @@ endfunc func Test_expand() new - call assert_equal("", expand('%:S')) + call assert_equal("", expand('%:S')) call assert_equal('3', '<slnum>'->expand()) call assert_equal(['4'], expand('<slnum>', v:false, v:true)) " Don't add any line above this, otherwise <slnum> will change. + call assert_equal("", expand('%')) + set verbose=1 + call assert_equal("", expand('%')) + set verbose=0 + call assert_equal("", expand('%:p')) quit endfunc diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 5b10e691e5..15622cd6fe 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -547,6 +547,7 @@ func Test_funcref() call assert_fails('echo funcref("{")', 'E475:') let OneByRef = funcref("One", repeat(["foo"], 20)) call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:') + call assert_fails('echo function("min") =~ function("min")', 'E694:') endfunc func Test_setmatches() diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim index b77f02afd1..fef0eb732f 100644 --- a/src/nvim/testdir/test_filechanged.vim +++ b/src/nvim/testdir/test_filechanged.vim @@ -140,7 +140,8 @@ func Test_FileChangedShell_edit() endfunc func Test_FileChangedShell_edit_dialog() - throw 'Skipped: requires a UI to be active' + " requires a UI to be active + throw 'Skipped: use test/functional/legacy/filechanged_spec.lua' CheckNotGui CheckUnix " Using low level feedkeys() does not work on MS-Windows. @@ -190,7 +191,8 @@ func Test_FileChangedShell_edit_dialog() endfunc func Test_file_changed_dialog() - throw 'Skipped: requires a UI to be active' + " requires a UI to be active + throw 'Skipped: use test/functional/legacy/filechanged_spec.lua' CheckUnix CheckNotGui au! FileChangedShell diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index e3a8370661..d123d469a6 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -88,6 +88,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'], + \ 'blueprint': ['file.blp'], \ 'bsdl': ['file.bsd', 'file.bsdl'], \ 'bst': ['file.bst'], \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'], @@ -107,6 +108,7 @@ let s:filename_checks = { \ 'ch': ['file.chf'], \ 'chaiscript': ['file.chai'], \ 'chaskell': ['file.chs'], + \ 'chatito': ['file.chatito'], \ 'chill': ['file..ch'], \ 'chordpro': ['file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'], \ 'cl': ['file.eni'], @@ -209,11 +211,14 @@ let s:filename_checks = { \ 'gdmo': ['file.mo', 'file.gdmo'], \ 'gdresource': ['file.tscn', 'file.tres'], \ 'gdscript': ['file.gd'], + \ 'gdshader': ['file.gdshader', 'file.shader'], \ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'], \ 'gemtext': ['file.gmi', 'file.gemini'], \ 'gift': ['file.gift'], + \ 'gitattributes': ['file.git/info/attributes', '.gitattributes', '/.config/git/attributes', '/etc/gitattributes', '/usr/local/etc/gitattributes', 'some.git/info/attributes'], \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'], \ 'gitconfig': ['file.git/config', 'file.git/config.worktree', 'file.git/worktrees/x/config.worktree', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/usr/local/etc/gitconfig', '/etc/gitconfig.d/file', 'any/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'], + \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'], \ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'], \ 'gitrebase': ['git-rebase-todo'], \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'], @@ -235,6 +240,7 @@ let s:filename_checks = { \ 'grub': ['/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf', 'any/boot/grub/grub.conf', 'any/boot/grub/menu.lst', 'any/etc/grub.conf'], \ 'gsp': ['file.gsp'], \ 'gtkrc': ['.gtkrc', 'gtkrc', '.gtkrc-file', 'gtkrc-file'], + \ 'gyp': ['file.gyp', 'file.gypi'], \ 'hack': ['file.hack', 'file.hackpartial'], \ 'haml': ['file.haml'], \ 'hamster': ['file.hsm'], @@ -250,6 +256,7 @@ let s:filename_checks = { \ 'hex': ['file.hex', 'file.h32'], \ 'hgcommit': ['hg-editor-file.txt'], \ 'hjson': ['file.hjson'], + \ 'hlsplaylist': ['file.m3u', 'file.m3u8'], \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'], \ 'hollywood': ['file.hws'], \ 'hoon': ['file.hoon'], @@ -274,7 +281,7 @@ let s:filename_checks = { \ 'jam': ['file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'], \ 'java': ['file.java', 'file.jav'], \ 'javacc': ['file.jj', 'file.jjt'], - \ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'], + \ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'], \ 'javascript.glimmer': ['file.gjs'], \ 'javascriptreact': ['file.jsx'], \ 'jess': ['file.clp'], @@ -284,6 +291,7 @@ let s:filename_checks = { \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'], \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc'], + \ 'jsonnet': ['file.jsonnet', 'file.libjsonnet'], \ 'jsp': ['file.jsp'], \ 'julia': ['file.jl'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'], @@ -320,8 +328,9 @@ let s:filename_checks = { \ 'lpc': ['file.lpc', 'file.ulpc'], \ 'lsl': ['file.lsl'], \ 'lss': ['file.lss'], - \ 'lua': ['file.lua', 'file.rockspec', 'file.nse'], + \ 'lua': ['file.lua', 'file.rockspec', 'file.nse', '.luacheckrc'], \ 'lynx': ['lynx.cfg'], + \ 'lyrics': ['file.lrc'], \ 'm3build': ['m3makefile', 'm3overrides'], \ 'm3quake': ['file.quake', 'cm3.cfg'], \ 'm4': ['file.at'], @@ -378,6 +387,7 @@ let s:filename_checks = { \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'], \ 'netrc': ['.netrc'], \ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'], + \ 'nim': ['file.nim', 'file.nims', 'file.nimble'], \ 'ninja': ['file.ninja'], \ 'nix': ['file.nix'], \ 'nqc': ['file.nqc'], @@ -403,10 +413,10 @@ let s:filename_checks = { \ 'pccts': ['file.g'], \ 'pcmk': ['file.pcmk'], \ 'pdf': ['file.pdf'], - \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'], + \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc', '.latexmkrc', 'latexmkrc'], \ 'pf': ['pf.conf'], \ 'pfmain': ['main.cf'], - \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'], + \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt', 'file.theme'], \ 'pike': ['file.pike', 'file.pmod'], \ 'pilrc': ['file.rcp'], \ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'], @@ -417,6 +427,7 @@ let s:filename_checks = { \ 'plsql': ['file.pls', 'file.plsql'], \ 'po': ['file.po', 'file.pot'], \ 'pod': ['file.pod'], + \ 'poefilter': ['file.filter'], \ 'poke': ['file.pk'], \ 'postscr': ['file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'], \ 'pov': ['file.pov'], @@ -525,13 +536,15 @@ let s:filename_checks = { \ 'squid': ['squid.conf'], \ 'squirrel': ['file.nut'], \ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'], + \ 'srt': ['file.srt'], + \ 'ssa': ['file.ass', 'file.ssa'], \ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config', 'any/.ssh/file.conf'], \ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'], \ 'st': ['file.st'], \ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'], \ 'stp': ['file.stp'], \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'], - \ 'supercollider': ['file.quark'], + \ 'supercollider': ['file.quark'], \ 'surface': ['file.sface'], \ 'svelte': ['file.svelte'], \ 'svg': ['file.svg'], @@ -572,6 +585,7 @@ let s:filename_checks = { \ 'tssop': ['file.tssop'], \ 'tsv': ['file.tsv'], \ 'twig': ['file.twig'], + \ 'typescript': ['file.mts', 'file.cts'], \ 'typescript.glimmer': ['file.gts'], \ 'typescriptreact': ['file.tsx'], \ 'uc': ['file.uc'], @@ -588,6 +602,10 @@ let s:filename_checks = { \ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'], \ 'vala': ['file.vala'], \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'], + \ 'vdf': ['file.vdf'], + \ 'vdmpp': ['file.vpp', 'file.vdmpp'], + \ 'vdmrt': ['file.vdmrt'], + \ 'vdmsl': ['file.vdm', 'file.vdmsl'], \ 'vera': ['file.vr', 'file.vri', 'file.vrh'], \ 'verilog': ['file.v'], \ 'verilogams': ['file.va', 'file.vams'], @@ -918,7 +936,9 @@ func Test_d_file() call assert_equal('d', &filetype) bwipe! + " clean up filetype off + call delete('Xfile.d') endfunc func Test_dat_file() @@ -1346,7 +1366,7 @@ func Test_mod_file() unlet g:filetype_mod bwipe! - " RAPID header start with a line containing only "%%%", + " RAPID header start with a line containing only "%%%", " but is not always present. call writefile(['%%%'], 'modfile.mod') split modfile.mod @@ -1362,7 +1382,7 @@ func Test_mod_file() bwipe! call delete('modfile.Mod') - " RAPID is not case sensitive, embedded spaces, sysmodule, + " RAPID is not case sensitive, embedded spaces, sysmodule, " file starts with empty line(s). call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'modfile.MOD') split modfile.MOD @@ -1490,7 +1510,7 @@ func Test_prg_file() unlet g:filetype_prg bwipe! - " RAPID header start with a line containing only "%%%", + " RAPID header start with a line containing only "%%%", " but is not always present. call writefile(['%%%'], 'prgfile.prg') split prgfile.prg @@ -1506,7 +1526,7 @@ func Test_prg_file() bwipe! call delete('prgfile.Prg') - " RAPID is not case sensitive, embedded spaces, sysmodule, + " RAPID is not case sensitive, embedded spaces, sysmodule, " file starts with empty line(s). call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'prgfile.PRG') split prgfile.PRG @@ -1617,7 +1637,7 @@ func Test_sys_file() unlet g:filetype_sys bwipe! - " RAPID header start with a line containing only "%%%", + " RAPID header start with a line containing only "%%%", " but is not always present. call writefile(['%%%'], 'sysfile.sys') split sysfile.sys @@ -1633,7 +1653,7 @@ func Test_sys_file() bwipe! call delete('sysfile.Sys') - " RAPID is not case sensitive, embedded spaces, sysmodule, + " RAPID is not case sensitive, embedded spaces, sysmodule, " file starts with empty line(s). call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'sysfile.SYS') split sysfile.SYS @@ -1820,6 +1840,44 @@ func Test_sig_file() filetype off endfunc +" Test dist#ft#FTsil() +func Test_sil_file() + filetype on + + split Xfile.sil + call assert_equal('sil', &filetype) + bwipe! + + let lines =<< trim END + // valid + let protoErasedPathA = \ABCProtocol.a + + // also valid + let protoErasedPathA = + \ABCProtocol.a + END + call writefile(lines, 'Xfile.sil') + + split Xfile.sil + call assert_equal('sil', &filetype) + bwipe! + + " SILE + + call writefile(['% some comment'], 'Xfile.sil') + split Xfile.sil + call assert_equal('sile', &filetype) + bwipe! + + call writefile(['\begin[papersize=a6]{document}foo\end{document}'], 'Xfile.sil') + split Xfile.sil + call assert_equal('sile', &filetype) + bwipe! + + call delete('Xfile.sil') + filetype off +endfunc + func Test_inc_file() filetype on diff --git a/src/nvim/testdir/test_fnamemodify.vim b/src/nvim/testdir/test_fnamemodify.vim index 5ae2a5ee17..258a2093bd 100644 --- a/src/nvim/testdir/test_fnamemodify.vim +++ b/src/nvim/testdir/test_fnamemodify.vim @@ -11,6 +11,7 @@ func Test_fnamemodify() call assert_equal('/', fnamemodify('.', ':p')[-1:]) call assert_equal('r', fnamemodify('.', ':p:h')[-1:]) call assert_equal('t', fnamemodify('test.out', ':p')[-1:]) + call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':p')) call assert_equal('test.out', fnamemodify('test.out', ':.')) call assert_equal('a', fnamemodify('../testdir/a', ':.')) call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~')) @@ -95,4 +96,9 @@ func Test_fnamemodify_er() call assert_equal('', fnamemodify(v:_null_string, v:_null_string)) endfunc +func Test_fnamemodify_fail() + call assert_fails('call fnamemodify({}, ":p")', 'E731:') + call assert_fails('call fnamemodify("x", {})', 'E731:') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 44b6f0373e..7ad0cb5884 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -462,6 +462,12 @@ func Test_tolower() " invalid memory. call tolower("\xC0\x80\xC0") call tolower("123\xC0\x80\xC0") + + " Test in latin1 encoding + let save_enc = &encoding + " set encoding=latin1 + call assert_equal("abc", tolower("ABC")) + let &encoding = save_enc endfunc func Test_toupper() @@ -533,6 +539,12 @@ func Test_toupper() " invalid memory. call toupper("\xC0\x80\xC0") call toupper("123\xC0\x80\xC0") + + " Test in latin1 encoding + let save_enc = &encoding + " set encoding=latin1 + call assert_equal("ABC", toupper("abc")) + let &encoding = save_enc endfunc func Test_tr() @@ -1096,6 +1108,10 @@ func Test_filewritable() call assert_equal(0, filewritable('doesnotexist')) + call mkdir('Xdir') + call assert_equal(2, filewritable('Xdir')) + call delete('Xdir', 'd') + call delete('Xfilewritable') bw! endfunc @@ -1270,15 +1286,11 @@ func Test_inputlist() 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 Ntest_setmouse(&lines - 3, 2) 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 Ntest_setmouse(&lines - 6, 2) call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx') call assert_equal(-2, c) @@ -1420,12 +1432,15 @@ func Test_trim() call assert_equal("vim", trim(" vim ", " ", 0)) call assert_equal("vim ", trim(" vim ", " ", 1)) call assert_equal(" vim", trim(" vim ", " ", 2)) - call assert_fails('call trim(" vim ", " ", [])', 'E745:') - call assert_fails('call trim(" vim ", " ", -1)', 'E475:') - call assert_fails('call trim(" vim ", " ", 3)', 'E475:') + call assert_fails('eval trim(" vim ", " ", [])', 'E745:') + call assert_fails('eval trim(" vim ", " ", -1)', 'E475:') + call assert_fails('eval trim(" vim ", " ", 3)', 'E475:') + call assert_fails('eval trim(" vim ", 0)', 'E475:') let chars = join(map(range(1, 0x20) + [0xa0], {n -> n->nr2char()}), '') call assert_equal("x", trim(chars . "x" . chars)) + + call assert_fails('let c=trim([])', 'E730:') endfunc " Test for reg_recording() and reg_executing() @@ -1534,13 +1549,12 @@ func Test_getchar() call assert_equal(0, getchar(0)) call setline(1, 'xxxx') - " call test_setmouse(1, 3) - " let v:mouse_win = 9 - " let v:mouse_winid = 9 - " let v:mouse_lnum = 9 - " let v:mouse_col = 9 - " call feedkeys("\<S-LeftMouse>", '') - call nvim_input_mouse('left', 'press', 'S', 0, 0, 2) + call Ntest_setmouse(1, 3) + let v:mouse_win = 9 + let v:mouse_winid = 9 + let v:mouse_lnum = 9 + let v:mouse_col = 9 + call feedkeys("\<S-LeftMouse>", '') call assert_equal("\<S-LeftMouse>", getchar()) call assert_equal(1, v:mouse_win) call assert_equal(win_getid(1), v:mouse_winid) @@ -1697,6 +1711,63 @@ func Test_platform_name() endif endfunc +" Test confirm({msg} [, {choices} [, {default} [, {type}]]]) +func Test_confirm() + " requires a UI to be active + throw 'Skipped: use test/functional/vimscript/input_spec.lua' + if !has('unix') || has('gui_running') + return + endif + + call feedkeys('o', 'L') + let a = confirm('Press O to proceed') + call assert_equal(1, a) + + call feedkeys('y', 'L') + let a = 'Are you sure?'->confirm("&Yes\n&No") + call assert_equal(1, a) + + call feedkeys('n', 'L') + let a = confirm('Are you sure?', "&Yes\n&No") + call assert_equal(2, a) + + " confirm() should return 0 when pressing CTRL-C. + call feedkeys("\<C-c>", 'L') + let a = confirm('Are you sure?', "&Yes\n&No") + call assert_equal(0, a) + + " <Esc> requires another character to avoid it being seen as the start of an + " escape sequence. Zero should be harmless. + eval "\<Esc>0"->feedkeys('L') + let a = confirm('Are you sure?', "&Yes\n&No") + call assert_equal(0, a) + + " Default choice is returned when pressing <CR>. + call feedkeys("\<CR>", 'L') + let a = confirm('Are you sure?', "&Yes\n&No") + call assert_equal(1, a) + + call feedkeys("\<CR>", 'L') + let a = confirm('Are you sure?', "&Yes\n&No", 2) + call assert_equal(2, a) + + call feedkeys("\<CR>", 'L') + let a = confirm('Are you sure?', "&Yes\n&No", 0) + call assert_equal(0, a) + + " Test with the {type} 4th argument + for type in ['Error', 'Question', 'Info', 'Warning', 'Generic'] + call feedkeys('y', 'L') + let a = confirm('Are you sure?', "&Yes\n&No\n", 1, type) + call assert_equal(1, a) + endfor + + call assert_fails('call confirm([])', 'E730:') + call assert_fails('call confirm("Are you sure?", [])', 'E730:') + call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", [])', 'E745:') + call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", 0, [])', 'E730:') +endfunc + func Test_readdir() call mkdir('Xdir') call writefile([], 'Xdir/foo.txt') @@ -1724,7 +1795,7 @@ func Test_readdir() let files = readdir('Xdir', {x -> len(add(l, x)) == 2 ? -1 : 1}) call assert_equal(1, len(files)) - call delete('Xdir', 'rf') + eval 'Xdir'->delete('rf') endfunc func Test_delete_rf() @@ -1767,6 +1838,7 @@ endfunc func Test_char2nr() call assert_equal(12354, char2nr('ã‚', 1)) + call assert_equal(120, 'x'->char2nr()) endfunc func Test_charclass() @@ -1819,6 +1891,24 @@ func Test_bufadd_bufload() exe 'bwipe ' .. buf2 call assert_equal(0, bufexists(buf2)) + " When 'buftype' is "nofile" then bufload() does not read the file. + " Other values too. + for val in [['nofile', 0], + \ ['nowrite', 1], + \ ['acwrite', 1], + \ ['quickfix', 0], + \ ['help', 1], + "\ ['terminal', 0], + \ ['prompt', 0], + "\ ['popup', 0], + \ ] + bwipe! XotherName + let buf = bufadd('XotherName') + call setbufvar(buf, '&bt', val[0]) + call bufload(buf) + call assert_equal(val[1] ? ['some', 'text'] : [''], getbufline(buf, 1, '$'), val[0]) + endfor + bwipe someName bwipe XotherName call assert_equal(0, bufexists('someName')) @@ -1830,6 +1920,32 @@ func Test_eval() call assert_fails("call eval('5 a')", 'E488:') endfunc +" Test for the keytrans() function +func Test_keytrans() + call assert_equal('<Space>', keytrans(' ')) + call assert_equal('<lt>', keytrans('<')) + call assert_equal('<lt>Tab>', keytrans('<Tab>')) + call assert_equal('<Tab>', keytrans("\<Tab>")) + call assert_equal('<C-V>', keytrans("\<C-V>")) + call assert_equal('<BS>', keytrans("\<BS>")) + call assert_equal('<Home>', keytrans("\<Home>")) + call assert_equal('<C-Home>', keytrans("\<C-Home>")) + call assert_equal('<M-Home>', keytrans("\<M-Home>")) + call assert_equal('<C-Space>', keytrans("\<C-Space>")) + call assert_equal('<M-Space>', keytrans("\<*M-Space>")) + call assert_equal('<M-x>', "\<*M-x>"->keytrans()) + call assert_equal('<C-I>', "\<*C-I>"->keytrans()) + call assert_equal('<S-3>', "\<*S-3>"->keytrans()) + call assert_equal('Ï€', 'Ï€'->keytrans()) + call assert_equal('<M-Ï€>', "\<M-Ï€>"->keytrans()) + call assert_equal('Ä›', 'Ä›'->keytrans()) + call assert_equal('<M-Ä›>', "\<M-Ä›>"->keytrans()) + call assert_equal('', ''->keytrans()) + call assert_equal('', v:_null_string->keytrans()) + call assert_fails('call keytrans(1)', 'E1174:') + call assert_fails('call keytrans()', 'E119:') +endfunc + " Test for the nr2char() function func Test_nr2char() " set encoding=latin1 @@ -1872,9 +1988,7 @@ endfunc func Test_getmousepos() enew! call setline(1, "\t\t\t1234") - " call test_setmouse(1, 1) - call nvim_input_mouse('left', 'press', '', 0, 0, 0) - call getchar() " wait for and consume the mouse press + call Ntest_setmouse(1, 1) call assert_equal(#{ \ screenrow: 1, \ screencol: 1, @@ -1884,9 +1998,7 @@ func Test_getmousepos() \ line: 1, \ column: 1, \ }, getmousepos()) - " call test_setmouse(1, 25) - call nvim_input_mouse('left', 'press', '', 0, 0, 24) - call getchar() " wait for and consume the mouse press + call Ntest_setmouse(1, 25) call assert_equal(#{ \ screenrow: 1, \ screencol: 25, @@ -1896,9 +2008,7 @@ func Test_getmousepos() \ line: 1, \ column: 4, \ }, getmousepos()) - " call test_setmouse(1, 50) - call nvim_input_mouse('left', 'press', '', 0, 0, 49) - call getchar() " wait for and consume the mouse press + call Ntest_setmouse(1, 50) call assert_equal(#{ \ screenrow: 1, \ screencol: 50, @@ -1911,9 +2021,7 @@ func Test_getmousepos() " If the mouse is positioned past the last buffer line, "line" and "column" " should act like it's positioned on the last buffer line. - " call test_setmouse(2, 25) - call nvim_input_mouse('left', 'press', '', 0, 1, 24) - call getchar() " wait for and consume the mouse press + call Ntest_setmouse(2, 25) call assert_equal(#{ \ screenrow: 2, \ screencol: 25, @@ -1923,9 +2031,7 @@ func Test_getmousepos() \ line: 1, \ column: 4, \ }, getmousepos()) - " call test_setmouse(2, 50) - call nvim_input_mouse('left', 'press', '', 0, 1, 49) - call getchar() " wait for and consume the mouse press + call Ntest_setmouse(2, 50) call assert_equal(#{ \ screenrow: 2, \ screencol: 50, @@ -1938,6 +2044,27 @@ func Test_getmousepos() bwipe! endfunc +" Test for glob() +func Test_glob() + call assert_equal('', glob(v:_null_string)) + call assert_equal('', globpath(v:_null_string, v:_null_string)) + + call writefile([], 'Xglob1') + call writefile([], 'XGLOB2') + set wildignorecase + " Sort output of glob() otherwise we end up with different + " ordering depending on whether file system is case-sensitive. + call assert_equal(['XGLOB2', 'Xglob1'], sort(glob('Xglob[12]', 0, 1))) + " wildignorecase shall be applied even when the pattern contains no wildcards. + call assert_equal('XGLOB2', glob('xglob2')) + set wildignorecase& + + call delete('Xglob1') + call delete('XGLOB2') + + call assert_fails("call glob('*', 0, {})", 'E728:') +endfunc + func HasDefault(msg = 'msg') return a:msg endfunc diff --git a/src/nvim/testdir/test_gui.vim b/src/nvim/testdir/test_gui.vim new file mode 100644 index 0000000000..c3f1f3163a --- /dev/null +++ b/src/nvim/testdir/test_gui.vim @@ -0,0 +1,43 @@ + +func Test_colorscheme() + " call assert_equal('16777216', &t_Co) + + let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default' + let g:color_count = 0 + augroup TestColors + au! + au ColorScheme * let g:color_count += 1 + \ | let g:after_colors = g:color_count + \ | let g:color_after = expand('<amatch>') + au ColorSchemePre * let g:color_count += 1 + \ | let g:before_colors = g:color_count + \ | let g:color_pre = expand('<amatch>') + augroup END + + colorscheme torte + redraw! + call assert_equal('dark', &background) + call assert_equal(1, g:before_colors) + call assert_equal(2, g:after_colors) + call assert_equal('torte', g:color_pre) + call assert_equal('torte', g:color_after) + call assert_equal("\ntorte", execute('colorscheme')) + + let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g') + " FIXME: temporarily check less while the colorscheme changes + " call assert_match("\nSearch xxx term=reverse cterm=reverse ctermfg=196 ctermbg=16 gui=reverse guifg=#ff0000 guibg=#000000", a) + " call assert_match("\nSearch xxx term=reverse ", a) + + call assert_fails('colorscheme does_not_exist', 'E185:') + call assert_equal('does_not_exist', g:color_pre) + call assert_equal('torte', g:color_after) + + exec 'colorscheme' colorscheme_saved + augroup TestColors + au! + augroup END + unlet g:color_count g:after_colors g:before_colors + redraw! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_help.vim b/src/nvim/testdir/test_help.vim index dbb36facee..19c0fcd820 100644 --- a/src/nvim/testdir/test_help.vim +++ b/src/nvim/testdir/test_help.vim @@ -141,6 +141,17 @@ func Test_helptag_cmd() call delete('Xdir', 'rf') endfunc +" Test for setting the 'helpheight' option in the help window +func Test_help_window_height() + let &cmdheight = &lines - 24 + set helpheight=10 + help + set helpheight=14 + call assert_equal(14, winheight(0)) + set helpheight& cmdheight=1 + close +endfunc + func Test_help_long_argument() try exe 'help \%' .. repeat('0', 1021) diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index efdf44a0d6..e84c45c635 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -722,7 +722,7 @@ func Test_1_highlight_Normalgroup_exists() elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3') " expect is DEFAULT_FONT of gui_gtk_x11.c call assert_match('hi Normal\s*font=Monospace 10', hlNormal) - elseif has('gui_motif') || has('gui_athena') + elseif has('gui_motif') " expect is DEFAULT_FONT of gui_x11.c call assert_match('hi Normal\s*font=7x13', hlNormal) elseif has('win32') @@ -731,7 +731,8 @@ func Test_1_highlight_Normalgroup_exists() endif endfunc -function Test_no_space_before_xxx() +" Do this test last, sometimes restoring the columns doesn't work +func Test_z_no_space_before_xxx() " Note: we need to create this highlight group in the test because it does not exist in Neovim execute('hi StatusLineTermNC ctermfg=green') let l:org_columns = &columns @@ -739,7 +740,7 @@ function Test_no_space_before_xxx() let l:hi_StatusLineTermNC = join(split(execute('hi StatusLineTermNC'))) call assert_match('StatusLineTermNC xxx', l:hi_StatusLineTermNC) let &columns = l:org_columns -endfunction +endfunc " Test for :highlight command errors func Test_highlight_cmd_errors() diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim index feb521e232..f1c31dee04 100644 --- a/src/nvim/testdir/test_history.vim +++ b/src/nvim/testdir/test_history.vim @@ -95,6 +95,23 @@ function Test_History() call assert_fails('call histnr([])', 'E730:') call assert_fails('history xyz', 'E488:') call assert_fails('history ,abc', 'E488:') + call assert_fails('call histdel(":", "\\%(")', 'E53:') +endfunction + +function Test_history_truncates_long_entry() + " History entry short enough to fit on the screen should not be truncated. + call histadd(':', 'echo x' .. repeat('y', &columns - 17) .. 'z') + let a = execute('history : -1') + + call assert_match("^\n # cmd history\n" + \ .. "> *\\d\\+ echo x" .. repeat('y', &columns - 17) .. 'z$', a) + + " Long history entry should be truncated to fit on the screen, with, '...' + " inserted in the string to indicate the that there is truncation. + call histadd(':', 'echo x' .. repeat('y', &columns - 16) .. 'z') + let a = execute('history : -1') + call assert_match("^\n # cmd history\n" + \ .. "> *\\d\\+ echo xy\\+\.\.\.y\\+z$", a) endfunction function Test_Search_history_window() diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 179218e48a..f706322a85 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -44,11 +44,11 @@ func Test_ins_complete() exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>" call assert_equal('run1 run2', getline('.')) - set cpt=.,w,i + set cpt=.,\ ,w,i " i-add-expands and switches to local exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>" call assert_equal("Makefile\tto\trun3", getline('.')) - " add-expands lines (it would end in an empty line if it didn't ignored + " add-expands lines (it would end in an empty line if it didn't ignore " itself) exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>" call assert_equal("Makefile\tto\trun3", getline('.')) @@ -68,6 +68,11 @@ func Test_ins_complete() call assert_equal('Xtest11.one', getline('.')) normal ddk + " Test for expanding a non-existing filename + exe "normal oa1b2X3Y4\<C-X>\<C-F>" + call assert_equal('a1b2X3Y4', getline('.')) + normal ddk + set cpt=w " checks make_cyclic in other window exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>" @@ -682,6 +687,42 @@ func Test_complete_func_error() call assert_equal([], complete_info(['items']).items) endfunc +" Test for recursively starting completion mode using complete() +func Test_recursive_complete_func() + func ListColors() + call complete(5, ["red", "blue"]) + return '' + endfunc + new + call setline(1, ['a1', 'a2']) + set complete=. + exe "normal Goa\<C-X>\<C-L>\<C-R>=ListColors()\<CR>\<C-N>" + call assert_equal('a2blue', getline(3)) + delfunc ListColors + bw! +endfunc + +" Test for using complete() with completeopt+=longest +func Test_complete_with_longest() + new + inoremap <buffer> <f3> <cmd>call complete(1, ["iaax", "iaay", "iaaz"])<cr> + + " default: insert first match + set completeopt& + call setline(1, ['i']) + exe "normal Aa\<f3>\<esc>" + call assert_equal('iaax', getline(1)) + + " with longest: insert longest prefix + set completeopt+=longest + call setline(1, ['i']) + exe "normal Aa\<f3>\<esc>" + call assert_equal('iaa', getline(1)) + set completeopt& + bwipe! +endfunc + + " Test for completing words following a completed word in a line func Test_complete_wrapscan() " complete words from another buffer @@ -721,6 +762,17 @@ func Test_complete_across_line() close! endfunc +" Test for completing words with a '.' at the end of a word. +func Test_complete_joinspaces() + new + call setline(1, ['one two.', 'three. four']) + set joinspaces + exe "normal Goon\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>" + call assert_equal("one two. three. four", getline(3)) + set joinspaces& + bw! +endfunc + " Test for using CTRL-L to add one character when completing matching func Test_complete_add_onechar() new @@ -741,6 +793,39 @@ func Test_complete_add_onechar() close! endfunc +" Test for using CTRL-X CTRL-L to complete whole lines lines +func Test_complete_wholeline() + new + " complete one-line + call setline(1, ['a1', 'a2']) + exe "normal ggoa\<C-X>\<C-L>" + call assert_equal(['a1', 'a1', 'a2'], getline(1, '$')) + " go to the next match (wrapping around the buffer) + exe "normal 2GCa\<C-X>\<C-L>\<C-N>" + call assert_equal(['a1', 'a', 'a2'], getline(1, '$')) + " go to the next match + exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>" + call assert_equal(['a1', 'a2', 'a2'], getline(1, '$')) + exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>\<C-N>" + call assert_equal(['a1', 'a1', 'a2'], getline(1, '$')) + " repeat the test using CTRL-L + " go to the next match (wrapping around the buffer) + exe "normal 2GCa\<C-X>\<C-L>\<C-L>" + call assert_equal(['a1', 'a2', 'a2'], getline(1, '$')) + " go to the next match + exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>" + call assert_equal(['a1', 'a', 'a2'], getline(1, '$')) + exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>\<C-L>" + call assert_equal(['a1', 'a1', 'a2'], getline(1, '$')) + %d + " use CTRL-X CTRL-L to add one more line + call setline(1, ['a1', 'b1']) + setlocal complete=. + exe "normal ggOa\<C-X>\<C-L>\<C-X>\<C-L>\<C-X>\<C-L>" + call assert_equal(['a1', 'b1', '', 'a1', 'b1'], getline(1, '$')) + bw! +endfunc + " Test insert completion with 'cindent' (adjust the indent) func Test_complete_with_cindent() new @@ -829,6 +914,25 @@ func Test_complete_stop() close! endfunc +" Test for typing CTRL-R in insert completion mode to insert a register +" content. +func Test_complete_reginsert() + new + call setline(1, ['a1', 'a12', 'a123', 'a1234']) + + " if a valid CTRL-X mode key is returned from <C-R>=, then it should be + " processed. Otherwise, CTRL-X mode should be stopped and the key should be + " inserted. + exe "normal Goa\<C-P>\<C-R>=\"\\<C-P>\"\<CR>" + call assert_equal('a123', getline(5)) + let @r = "\<C-P>\<C-P>" + exe "normal GCa\<C-P>\<C-R>r" + call assert_equal('a12', getline(5)) + exe "normal GCa\<C-P>\<C-R>=\"x\"\<CR>" + call assert_equal('a1234x', getline(5)) + bw! +endfunc + func Test_issue_7021() CheckMSWindows @@ -842,6 +946,322 @@ func Test_issue_7021() set completeslash= endfunc +" Test for 'longest' setting in 'completeopt' with latin1 and utf-8 encodings +func Test_complete_longest_match() + " for e in ['latin1', 'utf-8'] + for e in ['utf-8'] + exe 'set encoding=' .. e + new + set complete=. + set completeopt=menu,longest + call setline(1, ['pfx_a1', 'pfx_a12', 'pfx_a123', 'pfx_b1']) + exe "normal Gopfx\<C-P>" + call assert_equal('pfx_', getline(5)) + bw! + endfor + + " Test for completing additional words with longest match set + new + call setline(1, ['abc1', 'abd2']) + exe "normal Goab\<C-P>\<C-X>\<C-P>" + call assert_equal('ab', getline(3)) + bw! + set complete& completeopt& +endfunc + +" Test for removing the first displayed completion match and selecting the +" match just before that. +func Test_complete_erase_firstmatch() + new + call setline(1, ['a12', 'a34', 'a56']) + set complete=. + exe "normal Goa\<C-P>\<BS>\<BS>3\<CR>" + call assert_equal('a34', getline('$')) + set complete& + bw! +endfunc + +" Test for completing words from unloaded buffers +func Test_complete_from_unloadedbuf() + call writefile(['abc'], "Xfile1") + call writefile(['def'], "Xfile2") + edit Xfile1 + edit Xfile2 + new | close + enew + bunload Xfile1 Xfile2 + set complete=u + " complete from an unloaded buffer + exe "normal! ia\<C-P>" + call assert_equal('abc', getline(1)) + exe "normal! od\<C-P>" + call assert_equal('def', getline(2)) + set complete& + %bw! + call delete("Xfile1") + call delete("Xfile2") +endfunc + +" Test for completing whole lines from unloaded buffers +func Test_complete_wholeline_unloadedbuf() + call writefile(['a line1', 'a line2', 'a line3'], "Xfile1") + edit Xfile1 + enew + set complete=u + exe "normal! ia\<C-X>\<C-L>\<C-P>" + call assert_equal('a line2', getline(1)) + %d + " completing from an unlisted buffer should fail + bdel Xfile1 + exe "normal! ia\<C-X>\<C-L>\<C-P>" + call assert_equal('a', getline(1)) + set complete& + %bw! + call delete("Xfile1") +endfunc + +" Test for completing words from unlisted buffers +func Test_complete_from_unlistedbuf() + call writefile(['abc'], "Xfile1") + call writefile(['def'], "Xfile2") + edit Xfile1 + edit Xfile2 + new | close + bdel Xfile1 Xfile2 + set complete=U + " complete from an unlisted buffer + exe "normal! ia\<C-P>" + call assert_equal('abc', getline(1)) + exe "normal! od\<C-P>" + call assert_equal('def', getline(2)) + set complete& + %bw! + call delete("Xfile1") + call delete("Xfile2") +endfunc + +" Test for completing whole lines from unlisted buffers +func Test_complete_wholeline_unlistedbuf() + call writefile(['a line1', 'a line2', 'a line3'], "Xfile1") + edit Xfile1 + enew + set complete=U + " completing from a unloaded buffer should fail + exe "normal! ia\<C-X>\<C-L>\<C-P>" + call assert_equal('a', getline(1)) + %d + bdel Xfile1 + exe "normal! ia\<C-X>\<C-L>\<C-P>" + call assert_equal('a line2', getline(1)) + set complete& + %bw! + call delete("Xfile1") +endfunc + +" Test for adding a multibyte character using CTRL-L in completion mode +func Test_complete_mbyte_char_add() + new + set complete=. + call setline(1, 'abÄ—') + exe "normal! oa\<C-P>\<BS>\<BS>\<C-L>\<C-L>" + call assert_equal('abÄ—', getline(2)) + " Test for a leader with multibyte character + %d + call setline(1, 'abÄ—Ä•') + exe "normal! oabÄ—\<C-P>" + call assert_equal('abÄ—Ä•', getline(2)) + bw! +endfunc + +" Test for using <C-X><C-P> for local expansion even if 'complete' is set to +" not to complete matches from the local buffer. Also test using multiple +" <C-X> to cancel the current completion mode. +func Test_complete_local_expansion() + new + set complete=t + call setline(1, ['abc', 'def']) + exe "normal! Go\<C-X>\<C-P>" + call assert_equal("def", getline(3)) + exe "normal! Go\<C-P>" + call assert_equal("", getline(4)) + exe "normal! Go\<C-X>\<C-N>" + call assert_equal("abc", getline(5)) + exe "normal! Go\<C-N>" + call assert_equal("", getline(6)) + + " use multiple <C-X> to cancel the previous completion mode + exe "normal! Go\<C-P>\<C-X>\<C-P>" + call assert_equal("", getline(7)) + exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-P>" + call assert_equal("", getline(8)) + exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-X>\<C-P>" + call assert_equal("abc", getline(9)) + + " interrupt the current completion mode + set completeopt=menu,noinsert + exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-X>\<C-P>\<C-Y>" + call assert_equal("abc", getline(10)) + + " when only one <C-X> is used to interrupt, do normal expansion + exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-P>" + call assert_equal("", getline(11)) + set completeopt& + + " using two <C-X> in non-completion mode and restarting the same mode + exe "normal! God\<C-X>\<C-X>\<C-P>\<C-X>\<C-X>\<C-P>\<C-Y>" + call assert_equal("def", getline(12)) + + " test for adding a match from the original empty text + %d + call setline(1, 'abc def g') + exe "normal! o\<C-X>\<C-P>\<C-N>\<C-X>\<C-P>" + call assert_equal('def', getline(2)) + exe "normal! 0C\<C-X>\<C-N>\<C-P>\<C-X>\<C-N>" + call assert_equal('abc', getline(2)) + + bw! +endfunc + +" Test for undoing changes after a insert-mode completion +func Test_complete_undo() + new + set complete=. + " undo with 'ignorecase' + call setline(1, ['ABOVE', 'BELOW']) + set ignorecase + exe "normal! Goab\<C-G>u\<C-P>" + call assert_equal("ABOVE", getline(3)) + undo + call assert_equal("ab", getline(3)) + set ignorecase& + %d + " undo with longest match + set completeopt=menu,longest + call setline(1, ['above', 'about']) + exe "normal! Goa\<C-G>u\<C-P>" + call assert_equal("abo", getline(3)) + undo + call assert_equal("a", getline(3)) + set completeopt& + %d + " undo for line completion + call setline(1, ['above that change', 'below that change']) + exe "normal! Goabove\<C-G>u\<C-X>\<C-L>" + call assert_equal("above that change", getline(3)) + undo + call assert_equal("above", getline(3)) + + bw! +endfunc + +" Test for completing a very long word +func Test_complete_long_word() + set complete& + new + call setline(1, repeat('x', 950) .. ' one two three') + exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>" + call assert_equal(repeat('x', 950) .. ' one two three', getline(2)) + %d + " should fail when more than 950 characters are in a word + call setline(1, repeat('x', 951) .. ' one two three') + exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>" + call assert_equal(repeat('x', 951), getline(2)) + + " Test for adding a very long word to an existing completion + %d + call setline(1, ['abc', repeat('x', 1016) .. '012345']) + exe "normal! Goab\<C-P>\<C-X>\<C-P>" + call assert_equal('abc ' .. repeat('x', 1016) .. '0123', getline(3)) + bw! +endfunc + +" Test for some fields in the complete items used by complete() +func Test_complete_items() + func CompleteItems(idx) + let items = [[#{word: "one", dup: 1, user_data: 'u1'}, #{word: "one", dup: 1, user_data: 'u2'}], + \ [#{word: "one", dup: 0, user_data: 'u3'}, #{word: "one", dup: 0, user_data: 'u4'}], + \ [#{word: "one", icase: 1, user_data: 'u7'}, #{word: "oNE", icase: 1, user_data: 'u8'}], + \ [#{user_data: 'u9'}], + \ [#{word: "", user_data: 'u10'}], + \ [#{word: "", empty: 1, user_data: 'u11'}]] + call complete(col('.'), items[a:idx]) + return '' + endfunc + new + exe "normal! i\<C-R>=CompleteItems(0)\<CR>\<C-N>\<C-Y>" + call assert_equal('u2', v:completed_item.user_data) + call assert_equal('one', getline(1)) + exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-Y>" + call assert_equal('u3', v:completed_item.user_data) + call assert_equal('one', getline(2)) + exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-N>" + call assert_equal('', getline(3)) + set completeopt=menu,noinsert + exe "normal! o\<C-R>=CompleteItems(2)\<CR>one\<C-N>\<C-Y>" + call assert_equal('oNE', getline(4)) + call assert_equal('u8', v:completed_item.user_data) + set completeopt& + exe "normal! o\<C-R>=CompleteItems(3)\<CR>" + call assert_equal('', getline(5)) + exe "normal! o\<C-R>=CompleteItems(4)\<CR>" + call assert_equal('', getline(6)) + exe "normal! o\<C-R>=CompleteItems(5)\<CR>" + call assert_equal('', getline(7)) + call assert_equal('u11', v:completed_item.user_data) + " pass invalid argument to complete() + let cmd = "normal! o\<C-R>=complete(1, [[]])\<CR>" + call assert_fails('exe cmd', 'E730:') + bw! + delfunc CompleteItems +endfunc + +" Test for the "refresh" item in the dict returned by an insert completion +" function +func Test_complete_item_refresh_always() + let g:CallCount = 0 + func! Tcomplete(findstart, base) + if a:findstart + " locate the start of the word + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] =~ '\a' + let start -= 1 + endwhile + return start + else + let g:CallCount += 1 + let res = ["update1", "update12", "update123"] + return #{words: res, refresh: 'always'} + endif + endfunc + new + set completeopt=menu,longest + set completefunc=Tcomplete + exe "normal! iup\<C-X>\<C-U>\<BS>\<BS>\<BS>\<BS>\<BS>" + call assert_equal('up', getline(1)) + call assert_equal(2, g:CallCount) + set completeopt& + set completefunc& + bw! + delfunc Tcomplete +endfunc + +" Test for completing from a thesaurus file without read permission +func Test_complete_unreadable_thesaurus_file() + CheckUnix + CheckNotRoot + + call writefile(['about', 'above'], 'Xfile') + call setfperm('Xfile', '---r--r--') + new + set complete=sXfile + exe "normal! ia\<C-P>" + call assert_equal('a', getline(1)) + bw! + call delete('Xfile') + set complete& +endfunc + " Test to ensure 'Scanning...' messages are not recorded in messages history func Test_z1_complete_no_history() new @@ -857,7 +1277,7 @@ 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> + inoremap <buffer> <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)) @@ -884,4 +1304,52 @@ func Test_complete_smartindent() delfunction! FooBarComplete endfunc +func Test_complete_overrun() + " this was going past the end of the copied text + new + sil norm si”0s0 + bwipe! +endfunc + +func Test_infercase_very_long_line() + " this was truncating the line when inferring case + new + let longLine = "blah "->repeat(300) + let verylongLine = "blah "->repeat(400) + call setline(1, verylongLine) + call setline(2, longLine) + set ic infercase + exe "normal 2Go\<C-X>\<C-L>\<Esc>" + call assert_equal(longLine, getline(3)) + + " check that the too long text is NUL terminated + %del + norm o + norm 1987ax + exec "norm ox\<C-X>\<C-L>" + call assert_equal(repeat('x', 1987), getline(3)) + + bwipe! + set noic noinfercase +endfunc + +func Test_ins_complete_add() + " this was reading past the end of allocated memory + new + norm o + norm 7o€€ + sil! norm o + + bwipe! +endfunc + +func Test_ins_complete_end_of_line() + " this was reading past the end of the line + new + norm 8o€ý + sil! norm o + + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim index c1fe47d1c9..c178c87d3e 100644 --- a/src/nvim/testdir/test_lambda.vim +++ b/src/nvim/testdir/test_lambda.vim @@ -308,3 +308,21 @@ func Test_lambda_error() " This was causing a crash call assert_fails('ec{@{->{d->()()', 'E15') endfunc + +func Test_closure_error() + let l =<< trim END + func F1() closure + return 1 + endfunc + END + call writefile(l, 'Xscript') + let caught_932 = 0 + try + source Xscript + catch /E932:/ + let caught_932 = 1 + endtry + call assert_equal(1, caught_932) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 2f4e1db4a1..9cef6905a5 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -165,6 +165,13 @@ func Test_dict() call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d) call filter(d, 'v:key =~ ''[ac391]''') call assert_equal({'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}, d) + + " allow key starting with number at the start, not a curly expression + call assert_equal({'1foo': 77}, #{1foo: 77}) + + " #{expr} is not a curly expression + let x = 'x' + call assert_equal(#{g: x}, #{g:x}) endfunc " Dictionary identity @@ -604,20 +611,23 @@ func Test_reverse_sort_uniq() call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l))) call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(l)) call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(reverse(l))) - call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l)) - call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l))) - call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l)))) - call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l))) - - let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four'] - call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n')) - - let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] - call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1)) - call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) - call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l))) + if has('float') + call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l)) + call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l))) + call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l)))) + call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l))) + + let l = [7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four'] + call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n')) + + let l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] + call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1)) + call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i')) + call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l))) + endif call assert_fails('call reverse("")', 'E899:') + call assert_fails('call uniq([1, 2], {x, y -> []})', 'E882:') endfunc " reduce a list or a blob diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index affa0f96fa..1cbdba5d76 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -7,6 +7,7 @@ CheckOption linebreak CheckFeature conceal source view_util.vim +source screendump.vim function s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) @@ -133,6 +134,45 @@ func Test_linebreak_with_visual_operations() call s:close_windows() endfunc +" Test that cursor is drawn at correct position after an operator when +" 'linebreak' is enabled. +func Test_linebreak_reset_restore() + CheckScreendump + + " f_wincol() calls validate_cursor() + let lines =<< trim END + set linebreak showcmd noshowmode formatexpr=wincol()-wincol() + call setline(1, repeat('a', &columns - 10) .. ' bbbbbbbbbb c') + END + call writefile(lines, 'XlbrResetRestore', 'D') + let buf = RunVimInTerminal('-S XlbrResetRestore', {'rows': 8}) + + call term_sendkeys(buf, '$v$') + call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])}) + call term_sendkeys(buf, 'zo') + call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])}) + + call term_sendkeys(buf, '$v$') + call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])}) + call term_sendkeys(buf, 'gq') + call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])}) + + call term_sendkeys(buf, "$\<C-V>$") + call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])}) + call term_sendkeys(buf, 'I') + call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])}) + + call term_sendkeys(buf, "\<Esc>$v$") + call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])}) + call term_sendkeys(buf, 's') + call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])}) + call VerifyScreenDump(buf, 'Test_linebreak_reset_restore_1', {}) + + " clean up + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) +endfunc + func Test_virtual_block() call s:test_windows('setl sbr=+') call setline(1, [ diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim index dad4c81a7b..f903f5b934 100644 --- a/src/nvim/testdir/test_maparg.vim +++ b/src/nvim/testdir/test_maparg.vim @@ -158,11 +158,11 @@ func Test_range_map() call assert_equal("abcd", getline(1)) endfunc -func One_mapset_test(keys) - exe 'nnoremap ' .. a:keys .. ' original<CR>' +func One_mapset_test(keys, rhs) + exe 'nnoremap ' .. a:keys .. ' ' .. a:rhs 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(a:rhs, orig.rhs) call assert_equal('n', orig.mode) exe 'nunmap ' .. a:keys @@ -172,15 +172,16 @@ func One_mapset_test(keys) 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(a:rhs, 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>') + call One_mapset_test('K', 'original<CR>') + call One_mapset_test('<F3>', 'original<CR>') + call One_mapset_test('<F3>', '<lt>Nop>') " Check <> key conversion new @@ -203,6 +204,26 @@ func Test_mapset() iunmap K + " Test that <Nop> is restored properly + inoremap K <Nop> + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('', getline(1)) + + let orig = maparg('K', 'i', 0, 1) + call assert_equal('K', orig.lhs) + call assert_equal('<Nop>', orig.rhs) + call assert_equal('i', orig.mode) + + inoremap K foo + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('foo', getline(1)) + + call mapset('i', 0, orig) + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('', getline(1)) + + iunmap K + " Test literal <CR> using a backslash let cpo_save = &cpo set cpo-=B @@ -248,6 +269,8 @@ func Test_mapset() bwipe! call assert_fails('call mapset([], v:false, {})', 'E730:') + call assert_fails('call mapset("i", 0, "")', 'E715:') + call assert_fails('call mapset("i", 0, {})', 'E460:') endfunc func Check_ctrlb_map(d, check_alt) diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index e1d0b9a9ba..bde3624adf 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -975,6 +975,21 @@ func Test_abbreviate_multi_byte() bwipe! endfunc +" Test for abbreviations with 'latin1' encoding +func Test_abbreviate_latin1_encoding() + " set encoding=latin1 + call assert_fails('abbr ab#$c ABC', 'E474:') + new + iabbr <buffer> #i #include + iabbr <buffer> ## #enddef + exe "normal i#i\<C-]>" + call assert_equal('#include', getline(1)) + exe "normal 0Di##\<C-]>" + call assert_equal('#enddef', getline(1)) + %bw! + set encoding=utf-8 +endfunc ++ " Test for <Plug> always being mapped, even when used with "noremap". func Test_plug_remap() let g:foo = 0 @@ -1006,15 +1021,14 @@ func Test_plug_remap() endfunc func Test_mouse_drag_mapped_start_select() - CheckFunction test_setmouse set mouse=a set selectmode=key,mouse func ClickExpr() - call test_setmouse(1, 1) + call Ntest_setmouse(1, 1) return "\<LeftMouse>" endfunc func DragExpr() - call test_setmouse(1, 2) + call Ntest_setmouse(1, 2) return "\<LeftDrag>" endfunc nnoremap <expr> <F2> ClickExpr() @@ -1036,14 +1050,13 @@ endfunc " Test for mapping <LeftDrag> in Insert mode func Test_mouse_drag_insert_map() - CheckFunction test_setmouse set mouse=a func ClickExpr() - call test_setmouse(1, 1) + call Ntest_setmouse(1, 1) return "\<LeftMouse>" endfunc func DragExpr() - call test_setmouse(1, 2) + call Ntest_setmouse(1, 2) return "\<LeftDrag>" endfunc inoremap <expr> <F2> ClickExpr() @@ -1129,4 +1142,14 @@ func Test_map_after_timed_out_nop() call delete('Xtest_map_after_timed_out_nop') endfunc +func Test_using_past_typeahead() + nnoremap :00 0 + exe "norm :set \x80\xfb0=0\<CR>" + exe "sil norm :0\x0f\<C-U>\<CR>" + + exe "norm :set \x80\xfb0=\<CR>" + nunmap :00 +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim index 70271aa32f..4f22e54563 100644 --- a/src/nvim/testdir/test_match.vim +++ b/src/nvim/testdir/test_match.vim @@ -2,6 +2,7 @@ " matchaddpos(), matcharg(), matchdelete(), and setmatches(). source screendump.vim +source check.vim function Test_match() highlight MyGroup1 term=bold ctermbg=red guibg=red @@ -35,8 +36,8 @@ function Test_match() let m1 = matchadd("MyGroup1", "TODO") let m2 = matchadd("MyGroup2", "FIXME", 42) let m3 = matchadd("MyGroup3", "XXX", 60, 17) - let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, - \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, + let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1000}, + \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 1001}, \ {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}] call assert_equal(ans, getmatches()) @@ -117,7 +118,7 @@ function Test_match() call clearmatches() call setline(1, 'abcdΣabcdef') - eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]]) + eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]], 10, 42) 1 redraw! let v1 = screenattr(1, 1) @@ -128,7 +129,7 @@ function Test_match() let v8 = screenattr(1, 8) let v9 = screenattr(1, 9) let v10 = screenattr(1, 10) - call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches()) + call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches()) call assert_notequal(v1, v4) call assert_equal(v5, v4) call assert_equal(v6, v1) @@ -142,7 +143,7 @@ function Test_match() let m=getmatches() call clearmatches() call setmatches(m) - call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches()) + call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 1106}], getmatches()) highlight MyGroup1 NONE highlight MyGroup2 NONE @@ -160,7 +161,7 @@ func Test_matchadd_error() call clearmatches() " Nvim: not an error anymore: call matchadd('GroupDoesNotExist', 'X') - call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 13}], getmatches()) + call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 1206}], getmatches()) call assert_fails("call matchadd('Search', '\\(')", 'E475:') call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:') call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:') @@ -219,6 +220,21 @@ func Test_matchaddpos() set hlsearch& endfunc +" Add 12 match positions (previously the limit was 8 positions). +func Test_matchaddpos_dump() + CheckScreendump + + let lines =<< trim END + call setline(1, ['1234567890123']->repeat(14)) + call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]})) + END + call writefile(lines, 'Xmatchaddpos', 'D') + let buf = RunVimInTerminal('-S Xmatchaddpos', #{rows: 14}) + call VerifyScreenDump(buf, 'Test_matchaddpos_1', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_matchaddpos_otherwin() syntax on new @@ -237,8 +253,8 @@ func Test_matchaddpos_otherwin() let savematches = getmatches(winid) let expect = [ - \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 4}, - \ {'group': 'Error', 'id': 5, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]}, + \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 1000}, + \ {'group': 'Error', 'id': 1001, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]}, \] call assert_equal(expect, savematches) diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim index 75992d3313..db7ec92bf8 100644 --- a/src/nvim/testdir/test_menu.vim +++ b/src/nvim/testdir/test_menu.vim @@ -481,6 +481,35 @@ func Test_popup_menu() unmenu PopUp endfunc +" Test for MenuPopup autocommand +func Test_autocmd_MenuPopup() + CheckNotGui + + set mouse=a + set mousemodel=popup + aunmenu * + autocmd MenuPopup * exe printf( + \ 'anoremenu PopUp.Foo <Cmd>let g:res = ["%s", "%s"]<CR>', + \ expand('<afile>'), expand('<amatch>')) + + call feedkeys("\<RightMouse>\<Down>\<CR>", 'tnix') + call assert_equal(['n', 'n'], g:res) + + call feedkeys("v\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix') + call assert_equal(['v', 'v'], g:res) + + call feedkeys("gh\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix') + call assert_equal(['s', 's'], g:res) + + call feedkeys("i\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix') + call assert_equal(['i', 'i'], g:res) + + autocmd! MenuPopup + aunmenu PopUp.Foo + unlet g:res + set mouse& mousemodel& +endfunc + " Test for listing the menus using the :menu command func Test_show_menus() " In the GUI, tear-off menu items are present in the output below diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 3a607ff533..42a1fdcfe2 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -171,6 +171,38 @@ func Test_echospace() set ruler& showcmd& endfunc +func Test_warning_scroll() + CheckRunVimInTerminal + let lines =<< trim END + call test_override('ui_delay', 50) + set noruler + set readonly + undo + END + call writefile(lines, 'XTestWarningScroll', 'D') + let buf = RunVimInTerminal('', #{rows: 8}) + + " When the warning comes from a script, messages are scrolled so that the + " stacktrace is visible. + call term_sendkeys(buf, ":source XTestWarningScroll\n") + " only match the final colon in the line that shows the source + call WaitForAssert({-> assert_match(':$', term_getline(buf, 5))}) + call WaitForAssert({-> assert_equal('line 4:W10: Warning: Changing a readonly file', term_getline(buf, 6))}) + call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 7))}) + call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 8))}) + call term_sendkeys(buf, "\n") + + " When the warning does not come from a script, messages are not scrolled. + call term_sendkeys(buf, ":enew\n") + call term_sendkeys(buf, ":set readonly\n") + call term_sendkeys(buf, 'u') + call WaitForAssert({-> assert_equal('W10: Warning: Changing a readonly file', term_getline(buf, 8))}) + call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 8))}) + + " clean up + call StopVimInTerminal(buf) +endfunc + " Test more-prompt (see :help more-prompt). func Test_message_more() CheckRunVimInTerminal @@ -284,6 +316,66 @@ func Test_message_more() call StopVimInTerminal(buf) endfunc +" Test more-prompt scrollback +func Test_message_more_scrollback() + CheckRunVimInTerminal + + let lines =<< trim END + set t_ut= + hi Normal ctermfg=15 ctermbg=0 + for i in range(100) + echo i + endfor + END + call writefile(lines, 'XmoreScrollback', 'D') + let buf = RunVimInTerminal('-S XmoreScrollback', {'rows': 10}) + call VerifyScreenDump(buf, 'Test_more_scrollback_1', {}) + + call term_sendkeys(buf, 'f') + call TermWait(buf) + call term_sendkeys(buf, 'b') + call VerifyScreenDump(buf, 'Test_more_scrollback_2', {}) + + call term_sendkeys(buf, 'q') + call TermWait(buf) + call StopVimInTerminal(buf) +endfunc + +" Test verbose message before echo command +func Test_echo_verbose_system() + CheckRunVimInTerminal + CheckUnix + + let buf = RunVimInTerminal('', {'rows': 10}) + call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>") + " Note that the screendump is filtered to remove the name of the temp file + call VerifyScreenDump(buf, 'Test_verbose_system_1', {}) + + " display a page and go back, results in exactly the same view + call term_sendkeys(buf, ' ') + call TermWait(buf) + call term_sendkeys(buf, 'b') + call VerifyScreenDump(buf, 'Test_verbose_system_1', {}) + + " do the same with 'cmdheight' set to 2 + call term_sendkeys(buf, 'q') + call TermWait(buf) + call term_sendkeys(buf, ":set ch=2\<CR>") + call TermWait(buf) + call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>") + call VerifyScreenDump(buf, 'Test_verbose_system_2', {}) + + call term_sendkeys(buf, ' ') + call TermWait(buf) + call term_sendkeys(buf, 'b') + call VerifyScreenDump(buf, 'Test_verbose_system_2', {}) + + call term_sendkeys(buf, 'q') + call TermWait(buf) + call StopVimInTerminal(buf) +endfunc + + func Test_ask_yesno() CheckRunVimInTerminal let buf = RunVimInTerminal('', {'rows': 6}) @@ -325,14 +417,14 @@ func Test_quit_long_message() let content =<< trim END echom range(9999)->join("\x01") END - call writefile(content, 'Xtest_quit_message') - let buf = RunVimInTerminal('-S Xtest_quit_message', #{rows: 6}) + call writefile(content, 'Xtest_quit_message', 'D') + let buf = RunVimInTerminal('-S Xtest_quit_message', #{rows: 10, wait_for_ruler: 0}) + call WaitForAssert({-> assert_match('^-- More --', term_getline(buf, 10))}) call term_sendkeys(buf, "q") call VerifyScreenDump(buf, 'Test_quit_long_message', {}) " clean up call StopVimInTerminal(buf) - call delete('Xtest_quit_message') endfunc " this was missing a terminating NUL @@ -398,7 +490,7 @@ func Test_cmdheight_zero() " Check change/restore cmdheight when macro call feedkeys("qa", "xt") - call assert_equal(1, &cmdheight) + call assert_equal(0, &cmdheight) call feedkeys("q", "xt") call assert_equal(0, &cmdheight) diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim index 8ec408e62e..ccc775560f 100644 --- a/src/nvim/testdir/test_mksession.vim +++ b/src/nvim/testdir/test_mksession.vim @@ -942,6 +942,19 @@ func Test_mkvimrc() endfor call s:ClearMappings() + + " the 'pastetoggle', 'wildchar' and 'wildcharm' option values should be + " stored as key names in the vimrc file + set pastetoggle=<F5> + set wildchar=<F6> + set wildcharm=<F7> + call assert_fails('mkvimrc Xtestvimrc') + mkvimrc! Xtestvimrc + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set pastetoggle=<F5>')) + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildchar=<F6>')) + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildcharm=<F7>')) + set pastetoggle& wildchar& wildcharm& + call delete('Xtestvimrc') endfunc diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim index b3fe79f545..613722fdbd 100644 --- a/src/nvim/testdir/test_modeline.vim +++ b/src/nvim/testdir/test_modeline.vim @@ -1,5 +1,7 @@ " Tests for parsing the modeline. +source check.vim + func Test_modeline_invalid() " This was reading allocated memory in the past. call writefile(['vi:0', 'nothing'], 'Xmodeline') @@ -281,6 +283,88 @@ func Test_modeline_fails_modelineexpr() call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') endfunc +func Test_modeline_setoption_verbose() + let modeline = &modeline + set modeline + + let lines =<< trim END + 1 vim:ts=2 + 2 two + 3 three + 4 four + 5 five + 6 six + 7 seven + 8 eight + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 1$', info[-1]) + bwipe! + + let lines =<< trim END + 1 one + 2 two + 3 three + 4 vim:ts=4 + 5 five + 6 six + 7 seven + 8 eight + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 4$', info[-1]) + bwipe! + + let lines =<< trim END + 1 one + 2 two + 3 three + 4 four + 5 five + 6 six + 7 seven + 8 vim:ts=8 + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 8$', info[-1]) + bwipe! + + let &modeline = modeline + call delete('Xmodeline') +endfunc + +" Test for the 'modeline' default value in compatible and non-compatible modes +" for root and non-root accounts +func Test_modeline_default() + " set compatible + " call assert_false(&modeline) + set nocompatible + call assert_equal(IsRoot() ? 0 : 1, &modeline) + " set compatible&vi + " call assert_false(&modeline) + set compatible&vim + call assert_equal(IsRoot() ? 0 : 1, &modeline) + set compatible& modeline& +endfunc + +" Some options cannot be set from the modeline when 'diff' option is set +func Test_modeline_diff_buffer() + call writefile(['vim: diff foldmethod=marker wrap'], 'Xfile') + set foldmethod& nowrap + new Xfile + call assert_equal('manual', &foldmethod) + call assert_false(&wrap) + set wrap& + call delete('Xfile') + bw +endfunc + func Test_modeline_disable() set modeline call writefile(['vim: sw=2', 'vim: nomodeline', 'vim: sw=3'], 'Xmodeline_disable') diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 2092b508ea..4f842189b6 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -1455,6 +1455,7 @@ func Test_normal21_nv_hat() edit Xfoo | %bw call assert_fails(':buffer #', 'E86') call assert_fails(':execute "normal! \<C-^>"', 'E23') + call assert_fails("normal i\<C-R>#", 'E23:') " Test for the expected behavior when switching between two named buffers. edit Xfoo | edit Xbar diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index fdfc1c0f89..ada6d2406b 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -22,6 +22,21 @@ func Test_whichwrap() set whichwrap=h,h,h call assert_equal('h', &whichwrap) + " For compatibility with Vim 3.0 and before, number values are also + " supported for 'whichwrap' + set whichwrap=1 + call assert_equal('b', &whichwrap) + set whichwrap=2 + call assert_equal('s', &whichwrap) + set whichwrap=4 + call assert_equal('h,l', &whichwrap) + set whichwrap=8 + call assert_equal('<,>', &whichwrap) + set whichwrap=16 + call assert_equal('[,]', &whichwrap) + set whichwrap=31 + call assert_equal('b,s,h,l,<,>,[,]', &whichwrap) + set whichwrap& endfunc @@ -234,6 +249,7 @@ func Test_complete() new call feedkeys("i\<C-N>\<Esc>", 'xt') bwipe! + call assert_fails('set complete=ix', 'E535:') set complete& endfun @@ -266,6 +282,15 @@ func Test_set_completion() call feedkeys(":set fileencodings:\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:) + " Expand key codes. + " call feedkeys(":set <H\<C-A>\<C-B>\"\<CR>", 'tx') + " call assert_equal('"set <Help> <Home>', @:) + + " Expand terminal options. + " call feedkeys(":set t_A\<C-A>\<C-B>\"\<CR>", 'tx') + " call assert_equal('"set t_AB t_AF t_AU t_AL', @:) + " call assert_fails('call feedkeys(":set <t_afoo>=\<C-A>\<CR>", "xt")', 'E474:') + " Expand directories. call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx') call assert_match('./samples/ ', @:) @@ -361,6 +386,15 @@ func Test_set_errors() call assert_fails('set winminwidth=10 winwidth=9', 'E592:') call assert_fails("set showbreak=\x01", 'E595:') call assert_fails('set t_foo=', 'E846:') + call assert_fails('set tabstop??', 'E488:') + call assert_fails('set wrapscan!!', 'E488:') + call assert_fails('set tabstop&&', 'E488:') + call assert_fails('set wrapscan<<', 'E488:') + call assert_fails('set wrapscan=1', 'E474:') + call assert_fails('set autoindent@', 'E488:') + call assert_fails('set wildchar=<abc>', 'E474:') + call assert_fails('set cmdheight=1a', 'E521:') + call assert_fails('set invcmdheight', 'E474:') if has('python') || has('python3') call assert_fails('set pyxversion=6', 'E474:') endif @@ -384,6 +418,7 @@ func Test_set_errors() set nomodifiable call assert_fails('set fileencoding=latin1', 'E21:') set modifiable& + " call assert_fails('set t_#-&', 'E522:') endfunc func CheckWasSet(name) @@ -431,32 +466,37 @@ func Test_copy_context() endfunc func Test_set_ttytype() - " Nvim does not support 'ttytype'. - if !has('nvim') && !has('gui_running') && has('unix') - " Setting 'ttytype' used to cause a double-free when exiting vim and - " when vim is compiled with -DEXITFREE. - set ttytype=ansi - call assert_equal('ansi', &ttytype) - call assert_equal(&ttytype, &term) - set ttytype=xterm - call assert_equal('xterm', &ttytype) - call assert_equal(&ttytype, &term) - try - set ttytype= - call assert_report('set ttytype= did not fail') - catch /E529/ - endtry - - " Some systems accept any terminal name and return dumb settings, - " check for failure of finding the entry and for missing 'cm' entry. - try - set ttytype=xxx - call assert_report('set ttytype=xxx did not fail') - catch /E522\|E437/ - endtry - - set ttytype& - call assert_equal(&ttytype, &term) + throw "Skipped: Nvim does not support 'ttytype'" + CheckUnix + CheckNotGui + + " Setting 'ttytype' used to cause a double-free when exiting vim and + " when vim is compiled with -DEXITFREE. + set ttytype=ansi + call assert_equal('ansi', &ttytype) + call assert_equal(&ttytype, &term) + set ttytype=xterm + call assert_equal('xterm', &ttytype) + call assert_equal(&ttytype, &term) + try + set ttytype= + call assert_report('set ttytype= did not fail') + catch /E529/ + endtry + + " Some systems accept any terminal name and return dumb settings, + " check for failure of finding the entry and for missing 'cm' entry. + try + set ttytype=xxx + call assert_report('set ttytype=xxx did not fail') + catch /E522\|E437/ + endtry + + set ttytype& + call assert_equal(&ttytype, &term) + + if has('gui') && !has('gui_running') + call assert_fails('set term=gui', 'E531:') endif endfunc @@ -774,7 +814,13 @@ func Test_shell() CheckUnix let save_shell = &shell set shell= - call assert_fails('shell', 'E91:') + let caught_e91 = 0 + try + shell + catch /E91:/ + let caught_e91 = 1 + endtry + call assert_equal(1, caught_e91) let &shell = save_shell endfunc @@ -833,6 +879,108 @@ func Test_debug_option() set debug& endfunc +" Test for the default CDPATH option +func Test_opt_default_cdpath() + CheckFeature file_in_path + let after =<< trim [CODE] + call assert_equal(',/path/to/dir1,/path/to/dir2', &cdpath) + call writefile(v:errors, 'Xtestout') + qall + [CODE] + if has('unix') + let $CDPATH='/path/to/dir1:/path/to/dir2' + else + let $CDPATH='/path/to/dir1;/path/to/dir2' + endif + if RunVim([], after, '') + call assert_equal([], readfile('Xtestout')) + call delete('Xtestout') + endif +endfunc + +" Test for setting keycodes using set +func Test_opt_set_keycode() + call assert_fails('set <t_k1=l', 'E474:') + call assert_fails('set <Home=l', 'E474:') + set <t_k9>=abcd + " call assert_equal('abcd', &t_k9) + set <t_k9>& + set <F9>=xyz + " call assert_equal('xyz', &t_k9) + set <t_k9>& +endfunc + +" Test for changing options in a sandbox +func Test_opt_sandbox() + for opt in ['backupdir', 'cdpath', 'exrc'] + call assert_fails('sandbox set ' .. opt .. '?', 'E48:') + endfor +endfunc + +" Test for setting an option with local value to global value +func Test_opt_local_to_global() + setglobal equalprg=gprg + setlocal equalprg=lprg + call assert_equal('gprg', &g:equalprg) + call assert_equal('lprg', &l:equalprg) + call assert_equal('lprg', &equalprg) + set equalprg< + call assert_equal('', &l:equalprg) + call assert_equal('gprg', &equalprg) + setglobal equalprg=gnewprg + setlocal equalprg=lnewprg + setlocal equalprg< + call assert_equal('gnewprg', &l:equalprg) + call assert_equal('gnewprg', &equalprg) + set equalprg& + + " Test for setting the global/local value of a boolean option + setglobal autoread + setlocal noautoread + call assert_false(&autoread) + set autoread< + call assert_true(&autoread) + setglobal noautoread + setlocal autoread + setlocal autoread< + call assert_false(&autoread) + set autoread& +endfunc + +func Test_set_in_sandbox() + " Some boolean options cannot be set in sandbox, some can. + call assert_fails('sandbox set modelineexpr', 'E48:') + sandbox set number + call assert_true(&number) + set number& + + " Some boolean options cannot be set in sandbox, some can. + if has('python') || has('python3') + call assert_fails('sandbox set pyxversion=3', 'E48:') + endif + sandbox set tabstop=4 + call assert_equal(4, &tabstop) + set tabstop& + + " Some string options cannot be set in sandbox, some can. + call assert_fails('sandbox set backupdir=/tmp', 'E48:') + sandbox set filetype=perl + call assert_equal('perl', &filetype) + set filetype& +endfunc + +" Test for incrementing, decrementing and multiplying a number option value +func Test_opt_num_op() + set shiftwidth=4 + set sw+=2 + call assert_equal(6, &sw) + set sw-=2 + call assert_equal(4, &sw) + set sw^=2 + call assert_equal(8, &sw) + set shiftwidth& +endfunc + " Test for setting option values using v:false and v:true func Test_opt_boolean() set number& @@ -969,6 +1117,64 @@ func Test_opt_reset_scroll() call delete('Xscroll') endfunc +" Test for setting an option to a Vi or Vim default +func Test_opt_default() + throw 'Skipped: Nvim has different defaults' + set formatoptions&vi + call assert_equal('vt', &formatoptions) + set formatoptions&vim + call assert_equal('tcq', &formatoptions) +endfunc + +" Test for the 'cmdheight' option +func Test_cmdheight() + %bw! + let ht = &lines + set cmdheight=9999 + call assert_equal(1, winheight(0)) + call assert_equal(ht - 1, &cmdheight) + set cmdheight& +endfunc + +" To specify a control character as a option value, '^' can be used +func Test_opt_control_char() + set wildchar=^v + call assert_equal("\<C-V>", nr2char(&wildchar)) + set wildcharm=^r + call assert_equal("\<C-R>", nr2char(&wildcharm)) + " Bug: This doesn't work for the 'cedit' and 'termwinkey' options + set wildchar& wildcharm& +endfunc + +" Test for the 'errorbells' option +func Test_opt_errorbells() + set errorbells + call assert_beeps('s/a1b2/x1y2/') + set noerrorbells +endfunc + +func Test_opt_scrolljump() + help + resize 10 + + " Test with positive 'scrolljump'. + set scrolljump=2 + norm! Lj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':3, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + " Test with negative 'scrolljump' (percentage of window height). + set scrolljump=-40 + norm! ggLj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':5, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + set scrolljump& + bw +endfunc + " Test for the 'cdhome' option func Test_opt_cdhome() if has('unix') || has('vms') @@ -1003,4 +1209,18 @@ func Test_switchbuf_reset() only! endfunc +" :set empty string for global 'keywordprg' falls back to ":help" +func Test_keywordprg_empty() + let k = &keywordprg + set keywordprg=man + call assert_equal('man', &keywordprg) + set keywordprg= + call assert_equal(':help', &keywordprg) + set keywordprg=man + call assert_equal('man', &keywordprg) + call assert_equal("\n keywordprg=:help", execute('set kp= kp?')) + let &keywordprg = k +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_paste.vim b/src/nvim/testdir/test_paste.vim new file mode 100644 index 0000000000..dad3c2c6a0 --- /dev/null +++ b/src/nvim/testdir/test_paste.vim @@ -0,0 +1,76 @@ + +" Test for 'pastetoggle' +func Test_pastetoggle() + new + set pastetoggle=<F4> + set nopaste + call feedkeys("iHello\<F4>", 'xt') + call assert_true(&paste) + call feedkeys("i\<F4>", 'xt') + call assert_false(&paste) + call assert_equal('Hello', getline(1)) + " command-line completion for 'pastetoggle' value + call feedkeys(":set pastetoggle=\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"set pastetoggle=<F4>', @:) + set pastetoggle& + bwipe! +endfunc + +" Test for restoring option values when 'paste' is disabled +func Test_paste_opt_restore() + set autoindent expandtab ruler showmatch + if has('rightleft') + set revins hkmap + endif + set smarttab softtabstop=3 textwidth=27 wrapmargin=12 + if has('vartabs') + set varsofttabstop=10,20 + endif + + " enabling 'paste' should reset the above options + set paste + call assert_false(&autoindent) + call assert_false(&expandtab) + if has('rightleft') + call assert_false(&revins) + call assert_false(&hkmap) + endif + call assert_false(&ruler) + call assert_false(&showmatch) + call assert_false(&smarttab) + call assert_equal(0, &softtabstop) + call assert_equal(0, &textwidth) + call assert_equal(0, &wrapmargin) + if has('vartabs') + call assert_equal('', &varsofttabstop) + endif + + " disabling 'paste' should restore the option values + set nopaste + call assert_true(&autoindent) + call assert_true(&expandtab) + if has('rightleft') + call assert_true(&revins) + call assert_true(&hkmap) + endif + call assert_true(&ruler) + call assert_true(&showmatch) + call assert_true(&smarttab) + call assert_equal(3, &softtabstop) + call assert_equal(27, &textwidth) + call assert_equal(12, &wrapmargin) + if has('vartabs') + call assert_equal('10,20', &varsofttabstop) + endif + + set autoindent& expandtab& ruler& showmatch& + if has('rightleft') + set revins& hkmap& + endif + set smarttab& softtabstop& textwidth& wrapmargin& + if has('vartabs') + set varsofttabstop& + endif +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index 3d1e3fa6db..067e5d14e5 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -1129,15 +1129,15 @@ func Test_CompleteChanged() autocmd! AAAAA_Group set complete& completeopt& - delfunc! OnPumchange + delfunc! OnPumChange bw! endfunc -function! GetPumPosition() +func GetPumPosition() call assert_true( pumvisible() ) let g:pum_pos = pum_getpos() return '' -endfunction +endfunc func Test_pum_getpos() new diff --git a/src/nvim/testdir/test_preview.vim b/src/nvim/testdir/test_preview.vim index 6c4ae414d3..b7b908e761 100644 --- a/src/nvim/testdir/test_preview.vim +++ b/src/nvim/testdir/test_preview.vim @@ -1,5 +1,8 @@ " Tests for the preview window +source check.vim +CheckFeature quickfix + func Test_Psearch() " this used to cause ml_get errors help @@ -13,6 +16,8 @@ func Test_Psearch() endfunc func Test_window_preview() + CheckFeature quickfix + " Open a preview window pedit Xa call assert_equal(2, winnr('$')) @@ -32,6 +37,8 @@ func Test_window_preview() endfunc func Test_window_preview_from_help() + CheckFeature quickfix + filetype on call writefile(['/* some C code */'], 'Xpreview.c') help diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index fdb6f13e2b..4225b91bc4 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -40,8 +40,8 @@ func Test_profile_func() call writefile(lines, 'Xprofile_func.vim') call system(GetVimCommand() \ . ' -es --clean' - \ . ' -c "so Xprofile_func.vim"' - \ . ' -c "qall!"') + \ . ' --cmd "so Xprofile_func.vim"' + \ . ' --cmd "qall!"') call assert_equal(0, v:shell_error) let lines = readfile('Xprofile_func.log') @@ -475,7 +475,7 @@ func Test_profdel_func() call Foo3() [CODE] call writefile(lines, 'Xprofile_file.vim') - call system(GetVimCommandClean() . ' -es -c "so Xprofile_file.vim" -c q') + call system(GetVimCommandClean() . ' -es --cmd "so Xprofile_file.vim" --cmd q') call assert_equal(0, v:shell_error) let lines = readfile('Xprofile_file.log') diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index 8f94a8572b..9b8a776c95 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -223,7 +223,7 @@ func Test_prompt_buffer_getbufinfo() %bwipe! endfunc -function! Test_prompt_while_writing_to_hidden_buffer() +func Test_prompt_while_writing_to_hidden_buffer() throw 'skipped: TODO' call CanTestPromptBuffer() CheckUnix diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index f6d573d76b..8c9e39570f 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -85,6 +85,12 @@ func s:setup_commands(cchar) endif endfunc +" This must be run before any error lists are created. +func Test_AA_cc_no_errors() + call assert_fails('cc', 'E42:') + call assert_fails('ll', 'E42:') +endfunc + " Tests for the :clist and :llist commands func XlistTests(cchar) call s:setup_commands(a:cchar) diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim index 93865869fa..6a6719da8b 100644 --- a/src/nvim/testdir/test_quotestar.vim +++ b/src/nvim/testdir/test_quotestar.vim @@ -98,16 +98,17 @@ func Do_test_quotestar_for_x11() " Running in a terminal and the GUI is available: Tell the server to open " the GUI and check that the remote command still works. - " Need to wait for the GUI to start up, otherwise the send hangs in trying - " to send to the terminal window. - if has('gui_athena') || has('gui_motif') + if has('gui_motif') " For those GUIs, ignore the 'failed to create input context' error. call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>") else call remote_send(name, ":gui -f\<CR>") endif " Wait for the server in the GUI to be up and answering requests. + " First need to wait for the GUI to start up, otherwise the send hangs in + " trying to send to the terminal window. " On some systems and with valgrind this can be very slow. + sleep 1 call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))}, 10000) call remote_send(name, ":let @* = 'maybe'\<CR>") diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim index 14b9724d67..2253242a7c 100644 --- a/src/nvim/testdir/test_regexp_utf8.vim +++ b/src/nvim/testdir/test_regexp_utf8.vim @@ -258,8 +258,7 @@ func Test_multibyte_chars() " When there is no match use only the first two items. let tl = [] - " Multi-byte character tests. These will fail unless vim is compiled - " with Multibyte (FEAT_MBYTE) or BIG/HUGE features. + " Multi-byte character tests. call add(tl, [2, '[[:alpha:][=a=]]\+', '879 aiaãâaiuvna ', 'aiaãâaiuvna']) call add(tl, [2, '[[=a=]]\+', 'ddaãâbcd', 'aãâ']) " equivalence classes call add(tl, [2, '[^ม ]\+', 'มม oijasoifjos ifjoisj f osij j มมมมม abcd', 'oijasoifjos']) diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 3d1bbfb726..0cf55c7d0b 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -956,24 +956,24 @@ func Test_incsearch_search_dump() call delete('Xis_search_script') endfunc -func Test_hlsearch_block_visual_match() +func Test_hlsearch_dump() + CheckOption hlsearch CheckScreendump - let lines =<< trim END - set hlsearch - call setline(1, ['aa', 'bbbb', 'cccccc']) - END - call writefile(lines, 'Xhlsearch_block') - let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60}) + call writefile([ + \ 'set hlsearch cursorline', + \ 'call setline(1, ["xxx", "xxx", "xxx"])', + \ '/.*', + \ '2', + \ ], 'Xhlsearch_script') + let buf = RunVimInTerminal('-S Xhlsearch_script', {'rows': 6, 'cols': 50}) + call VerifyScreenDump(buf, 'Test_hlsearch_1', {}) - call term_sendkeys(buf, "G\<C-V>$kk\<Esc>") - sleep 100m - call term_sendkeys(buf, "/\\%V\<CR>") - sleep 100m - call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {}) + call term_sendkeys(buf, "/\\_.*\<CR>") + call VerifyScreenDump(buf, 'Test_hlsearch_2', {}) call StopVimInTerminal(buf) - call delete('Xhlsearch_block') + call delete('Xhlsearch_script') endfunc func Test_hlsearch_and_visual() @@ -996,6 +996,26 @@ func Test_hlsearch_and_visual() call delete('Xhlvisual_script') endfunc +func Test_hlsearch_block_visual_match() + CheckScreendump + + let lines =<< trim END + set hlsearch + call setline(1, ['aa', 'bbbb', 'cccccc']) + END + call writefile(lines, 'Xhlsearch_block') + let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60}) + + call term_sendkeys(buf, "G\<C-V>$kk\<Esc>") + sleep 100m + call term_sendkeys(buf, "/\\%V\<CR>") + sleep 100m + call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {}) + + call StopVimInTerminal(buf) + call delete('Xhlsearch_block') +endfunc + func Test_incsearch_substitute() CheckFunction test_override CheckOption incsearch @@ -1017,6 +1037,21 @@ func Test_incsearch_substitute() call Incsearch_cleanup() endfunc +func Test_incsearch_substitute_long_line() + CheckFunction test_override + new + call test_override("char_avail", 1) + set incsearch + + call repeat('x', 100000)->setline(1) + call feedkeys(':s/\%c', 'xt') + redraw + call feedkeys("\<Esc>", 'xt') + + call Incsearch_cleanup() + bwipe! +endfunc + func Test_hlsearch_cursearch() CheckScreendump @@ -1341,21 +1376,6 @@ func Test_subst_word_under_cursor() set noincsearch endfunc -func Test_incsearch_substitute_long_line() - CheckFunction test_override - new - call test_override("char_avail", 1) - set incsearch - - call repeat('x', 100000)->setline(1) - call feedkeys(':s/\%c', 'xt') - redraw - call feedkeys("\<Esc>", 'xt') - - call Incsearch_cleanup() - bwipe! -endfunc - func Test_search_undefined_behaviour() CheckFeature terminal diff --git a/src/nvim/testdir/test_set.vim b/src/nvim/testdir/test_set.vim index 2b1e9eeee0..7215772a00 100644 --- a/src/nvim/testdir/test_set.vim +++ b/src/nvim/testdir/test_set.vim @@ -26,4 +26,23 @@ function Test_set_add() let &wig = wig_save endfunction + +" :set, :setlocal, :setglobal without arguments show values of options. +func Test_set_no_arg() + set textwidth=79 + let a = execute('set') + call assert_match("^\n--- Options ---\n.*textwidth=79\\>", a) + set textwidth& + + setlocal textwidth=78 + let a = execute('setlocal') + call assert_match("^\n--- Local option values ---\n.*textwidth=78\\>", a) + setlocal textwidth& + + setglobal textwidth=77 + let a = execute('setglobal') + call assert_match("^\n--- Global option values ---\n.*textwidth=77\\>", a) + setglobal textwidth& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index 39fafbf7b4..b30a5e7edb 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -431,7 +431,7 @@ endfunction " Test the -reverse and +reverse arguments (for GUI only). func Test_reverse() CheckCanRunGui - CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena + CheckAnyOf Feature:gui_gtk Feature:gui_motif let after =<< trim [CODE] call writefile([&background], "Xtest_reverse") @@ -452,7 +452,7 @@ endfunc " Test the -background and -foreground arguments (for GUI only). func Test_background_foreground() CheckCanRunGui - CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena + CheckAnyOf Feature:gui_gtk Feature:gui_motif " Is there a better way to check the effect of -background & -foreground " other than merely looking at &background (dark or light)? @@ -479,7 +479,7 @@ func Test_font() if has('gui_gtk') let font = 'Courier 14' - elseif has('gui_motif') || has('gui_athena') + elseif has('gui_motif') let font = '-misc-fixed-bold-*' else throw 'Skipped: test does not set a valid font for this GUI' @@ -501,10 +501,10 @@ endfunc " Test the -geometry argument (for GUI only). func Test_geometry() CheckCanRunGui - CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena + CheckAnyOf Feature:gui_gtk Feature:gui_motif - if has('gui_motif') || has('gui_athena') - " FIXME: With GUI Athena or Motif, the value of getwinposx(), + if has('gui_motif') + " FIXME: With GUI Motif the value of getwinposx(), " getwinposy() and getwinpos() do not match exactly the " value given in -geometry. Why? " So only check &columns and &lines for those GUIs. @@ -533,7 +533,7 @@ endfunc " Test the -iconic argument (for GUI only). func Test_iconic() CheckCanRunGui - CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena + CheckAnyOf Feature:gui_gtk Feature:gui_motif call RunVim([], [], '-f -g -iconic -cq') @@ -603,7 +603,7 @@ func Test_invalid_args() call assert_equal(0, v:shell_error) if has('quickfix') - " Detect invalid repeated arguments '-t foo -t foo", '-q foo -q foo'. + " Detect invalid repeated arguments '-t foo -t foo', '-q foo -q foo'. for opt in ['-t', '-q'] let out = split(system(GetVimCommand() .. repeat(' ' .. opt .. ' foo', 2)), "\n") call assert_equal(1, v:shell_error) @@ -855,7 +855,7 @@ func Test_t_arg() call writefile([' first', ' second', ' third'], 'Xfile1') for t_arg in ['-t second', '-tsecond'] - if RunVim(before, after, '-t second') + if RunVim(before, after, t_arg) call assert_equal(['Xfile1:L2C5'], readfile('Xtestout'), t_arg) call delete('Xtestout') endif diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index b3a80072d9..88a3c13d65 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -1,6 +1,8 @@ " Tests for the substitute (:s) command source shared.vim +source check.vim +source screendump.vim func Test_multiline_subst() enew! @@ -637,12 +639,16 @@ endfunc func SubReplacer(text, submatches) return a:text .. a:submatches[0] .. a:text endfunc +func SubReplacerVar(text, ...) + return a:text .. a:1[0] .. a:text +endfunc func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches) return a:t3 .. a:submatches[0] .. a:t11 endfunc func Test_substitute_partial() call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g')) + call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar', ['foo']), 'g')) " 19 arguments plus one is just OK let Replacer = function('SubReplacer20', repeat(['foo'], 19)) @@ -668,6 +674,21 @@ func Test_sub_cmd_9() bw! endfunc +func Test_sub_highlight_zero_match() + CheckRunVimInTerminal + + let lines =<< trim END + call setline(1, ['one', 'two', 'three']) + END + call writefile(lines, 'XscriptSubHighlight', 'D') + let buf = RunVimInTerminal('-S XscriptSubHighlight', #{rows: 8, cols: 60}) + call term_sendkeys(buf, ":%s/^/ /c\<CR>") + call VerifyScreenDump(buf, 'Test_sub_highlight_zer_match_1', {}) + + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) +endfunc + func Test_nocatch_sub_failure_handling() " normal error results in all replacements func Foo() diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim index 923e1cbf50..34d1d585ce 100644 --- a/src/nvim/testdir/test_swap.vim +++ b/src/nvim/testdir/test_swap.vim @@ -2,6 +2,7 @@ source check.vim source shared.vim +source term_util.vim func s:swapname() return trim(execute('swapname')) @@ -374,24 +375,26 @@ func Test_swap_prompt_splitwin() call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))}) call StopVimInTerminal(buf) - " This caused Vim to crash when typing "q". - " TODO: it does not actually reproduce the crash. - call writefile(['au BufAdd * set virtualedit=all'], 'Xvimrc') - - let buf = RunVimInTerminal('-u Xvimrc Xfile1', {'rows': 20, 'wait_for_ruler': 0}) - call TermWait(buf) - call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 20))}) + " This caused Vim to crash when typing "q" at the swap file prompt. + let buf = RunVimInTerminal('-c "au bufadd * let foo_w = wincol()"', {'rows': 18}) + call term_sendkeys(buf, ":e Xfile1\<CR>") + call WaitForAssert({-> assert_match('More', term_getline(buf, 18))}) + call term_sendkeys(buf, " ") + call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 18))}) call term_sendkeys(buf, "q") + call TermWait(buf) + " check that Vim is still running + call term_sendkeys(buf, ":echo 'hello'\<CR>") + call WaitForAssert({-> assert_match('^hello', term_getline(buf, 18))}) + call term_sendkeys(buf, ":%bwipe!\<CR>") + call StopVimInTerminal(buf) %bwipe! call delete('Xfile1') - call delete('Xvimrc') endfunc func Test_swap_symlink() - if !has("unix") - return - endif + CheckUnix call writefile(['text'], 'Xtestfile') silent !ln -s -f Xtestfile Xtestlink diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index 7ba0149971..ccff01486e 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -188,22 +188,26 @@ func Test_syntax_completion() call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:) " Check that clearing "Aap" avoids it showing up before Boolean. - hi Aap ctermfg=blue + hi @Aap ctermfg=blue call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_match('^"syn list Aap Boolean Character ', @:) - hi clear Aap + call assert_match('^"syn list @Aap @boolean @character ', @:) + hi clear @Aap call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_match('^"syn list Boolean Character ', @:) + call assert_match('^"syn list @boolean @character ', @:) call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_match('^"syn match Boolean Character ', @:) + call assert_match('^"syn match @boolean @character ', @:) + + syn cluster Aax contains=Aap + call feedkeys(":syn list @A\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_match('^"syn list @Aax', @:) endfunc func Test_echohl_completion() call feedkeys(":echohl no\<C-A>\<C-B>\"\<CR>", 'tx') " call assert_equal('"echohl NonText Normal none', @:) - call assert_equal('"echohl NonText Normal NormalFloat NormalNC none', @:) + call assert_equal('"echohl NonText Normal NormalFloat none', @:) endfunc func Test_syntax_arg_skipped() @@ -389,7 +393,7 @@ func Test_invalid_name() syn keyword Nop yes call assert_fails("syntax keyword Wr\x17ong bar", 'E669:') syntax keyword @Wrong bar - call assert_match('W18:', execute('1messages')) + call assert_fails("syntax keyword @#Wrong bar", 'E5248:') syn clear hi clear Nop hi clear @Wrong diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim index 18692f42c9..bfa8a277bd 100644 --- a/src/nvim/testdir/test_system.vim +++ b/src/nvim/testdir/test_system.vim @@ -141,3 +141,41 @@ func Test_system_with_shell_quote() call delete('Xdir with spaces', 'rf') endtry endfunc + +" Test for 'shellxquote' +func Test_Shellxquote() + CheckUnix + + let save_shell = &shell + let save_sxq = &shellxquote + let save_sxe = &shellxescape + + call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') + call setfperm('Xtestshell', "r-x------") + set shell=./Xtestshell + + set shellxquote=\\" + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) + + set shellxquote=( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) + + set shellxquote=\\"( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) + + set shellxescape=\"&<<()@^ + set shellxquote=( + call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) + + let &shell = save_shell + let &shellxquote = save_sxq + let &shellxescape = save_sxe + call delete('Xtestshell') + call delete('Xlog') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim index eda485c512..99bc2d1d37 100644 --- a/src/nvim/testdir/test_termcodes.vim +++ b/src/nvim/testdir/test_termcodes.vim @@ -1,4 +1,30 @@ +" Test for translation of special key codes (<xF1>, <xF2>, etc.) +func Test_Keycode_Translation() + let keycodes = [ + \ ["<xUp>", "<Up>"], + \ ["<xDown>", "<Down>"], + \ ["<xLeft>", "<Left>"], + \ ["<xRight>", "<Right>"], + \ ["<xHome>", "<Home>"], + \ ["<xEnd>", "<End>"], + \ ["<zHome>", "<Home>"], + \ ["<zEnd>", "<End>"], + \ ["<xF1>", "<F1>"], + \ ["<xF2>", "<F2>"], + \ ["<xF3>", "<F3>"], + \ ["<xF4>", "<F4>"], + \ ["<S-xF1>", "<S-F1>"], + \ ["<S-xF2>", "<S-F2>"], + \ ["<S-xF3>", "<S-F3>"], + \ ["<S-xF4>", "<S-F4>"]] + for [k1, k2] in keycodes + exe "nnoremap " .. k1 .. " 2wx" + call assert_true(maparg(k1, 'n', 0, 1).lhs == k2) + exe "nunmap " .. k1 + endfor +endfunc + " Test for terminal keycodes that doesn't have termcap entries func Test_special_term_keycodes() new diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim index 0fc56083aa..4eb6e69adf 100644 --- a/src/nvim/testdir/test_textformat.vim +++ b/src/nvim/testdir/test_textformat.vim @@ -962,78 +962,6 @@ func Test_tw_2_fo_tm_noai() bwipe! endfunc -func Test_tw_2_fo_cqm_com() - new - let t =<< trim END - { - X - Xa - Xaï¼¹ - XY - XYZ - X ï¼¹ - X YZ - XX - XXa - XXY - } - END - call setline(1, t) - call cursor(2, 1) - - set tw=2 fo=cqm comments=n:X - exe "normal gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgq" - let t =<< trim END - X - Xa - Xaï¼¹ - XY - XYZ - X ï¼¹ - X YZ - XX - XXa - XXY - END - exe "normal o\n" . join(t, "\n") - - let expected =<< trim END - { - X - Xa - Xa - XY - XY - XY - XZ - X ï¼¹ - X ï¼¹ - X Z - XX - XXa - XXY - - X - Xa - Xa - XY - XY - XY - XZ - X ï¼¹ - X ï¼¹ - X Z - XX - XXa - XXY - } - END - call assert_equal(expected, getline(1, '$')) - - set tw& fo& comments& - bwipe! -endfunc - func Test_tw_2_fo_tm_replace() new let t =<< trim END @@ -1161,140 +1089,6 @@ func Test_whichwrap_multi_byte() bwipe! endfunc -" Test for automatically adding comment leaders in insert mode -func Test_threepiece_comment() - new - setlocal expandtab - call setline(1, ["\t/*"]) - setlocal formatoptions=croql - call cursor(1, 3) - call feedkeys("A\<cr>\<cr>/", 'tnix') - call assert_equal(["\t/*", " *", " */"], getline(1, '$')) - - " If a comment ends in a single line, then don't add it in the next line - %d - call setline(1, '/* line1 */') - call feedkeys("A\<CR>next line", 'xt') - call assert_equal(['/* line1 */', 'next line'], getline(1, '$')) - - %d - " Copy the trailing indentation from the leader comment to a new line - setlocal autoindent noexpandtab - call feedkeys("a\t/*\tone\ntwo\n/", 'xt') - call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$')) - close! -endfunc - -" Test for the 'f' flag in 'comments' (only the first line has the comment -" string) -func Test_firstline_comment() - new - setlocal comments=f:- fo+=ro - exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>" - call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$')) - %d - setlocal comments=:- - exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>" - call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$')) - %bw! -endfunc - -" Test for the 'r' flag in 'comments' (right align comment) -func Test_comment_rightalign() - new - setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro - exe "normal i=\<C-C>o\t /***\nD\n/" - exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG" - let expected =<< trim END - = - A - /*** - ** B - ** C - ** D - ** E - ** F - ******/ - G - END - call assert_equal(expected, getline(1, '$')) - %bw! -endfunc - -" Test for the 'b' flag in 'comments' -func Test_comment_blank() - new - setlocal comments=b:* fo+=ro - exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD" - let expected =<< trim END - A - *B - * C - * D - * E - * F - *G - H - END - call assert_equal(expected, getline(1, '$')) - %bw! -endfunc - -" Test for the 'n' flag in comments -func Test_comment_nested() - new - setlocal comments=n:> fo+=ro - exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH" - exe "normal 5GOE\<C-C>6GoG" - let expected =<< trim END - > A - > B - > C - > D - >>>> E - >>>> F - >>>> G - >>>> H - END - call assert_equal(expected, getline(1, '$')) - %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 @@ -1334,25 +1128,6 @@ 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 @@ -1487,53 +1262,6 @@ func Test_fo_2() close! endfunc -" Test for formatting lines where only the first line has a comment. -func Test_fo_gq_with_firstline_comment() - new - setlocal formatoptions=tcq - call setline(1, ['- one two', 'three']) - normal gggqG - call assert_equal(['- one two three'], getline(1, '$')) - - %d - call setline(1, ['- one', '- two']) - normal gggqG - call assert_equal(['- one', '- two'], getline(1, '$')) - close! -endfunc - -" Test for trying to join a comment line with a non-comment line -func Test_join_comments() - new - call setline(1, ['one', '/* two */', 'three']) - normal gggqG - call assert_equal(['one', '/* two */', 'three'], getline(1, '$')) - close! -endfunc - -" Test for using 'a' in 'formatoptions' with comments -func Test_autoformat_comments() - new - setlocal formatoptions+=a - call feedkeys("a- one\n- two\n", 'xt') - call assert_equal(['- one', '- two', ''], getline(1, '$')) - - %d - call feedkeys("a\none\n", 'xt') - call assert_equal(['', 'one', ''], getline(1, '$')) - - setlocal formatoptions+=aw - %d - call feedkeys("aone \ntwo\n", 'xt') - call assert_equal(['one two', ''], getline(1, '$')) - - %d - call feedkeys("aone\ntwo\n", 'xt') - call assert_equal(['one', 'two', ''], getline(1, '$')) - - 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() diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index 6adf503f14..b3a22614b0 100644 --- a/src/nvim/testdir/test_timers.vim +++ b/src/nvim/testdir/test_timers.vim @@ -349,11 +349,13 @@ func Test_nocatch_timer_garbage_collect() let a = {'foo', 'bar'} endfunc func FeedChar(id) - call feedkeys('x', 't') + call feedkeys(":\<CR>", 't') endfunc call timer_start(300, 'FeedChar') call timer_start(100, 'CauseAnError') - let x = getchar() + let x = getchar() " wait for error in timer + let x = getchar(0) " read any remaining chars + let x = getchar(0) set ut& call test_override('no_wait_return', 1) diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim index 646594e482..d71bb5bbb8 100644 --- a/src/nvim/testdir/test_trycatch.vim +++ b/src/nvim/testdir/test_trycatch.vim @@ -2027,16 +2027,179 @@ func Test_try_catch_verbose() endtry redir END let expected = [ - \ 'Exception thrown: Vim(echo):E121: Undefined variable: i', - \ '', - \ 'Exception caught: Vim(echo):E121: Undefined variable: i', - \ '', - \ 'Exception finished: Vim(echo):E121: Undefined variable: i' - \ ] + \ 'Exception thrown: Vim(echo):E121: Undefined variable: i', '', + \ 'Exception caught: Vim(echo):E121: Undefined variable: i', '', + \ 'Exception finished: Vim(echo):E121: Undefined variable: i'] call assert_equal(expected, split(msg, "\n")) + + " Test for verbose messages displayed when an exception is discarded + redir => msg + try + try + throw 'abc' + finally + throw 'xyz' + endtry + catch + endtry + redir END + let expected = [ + \ 'Exception thrown: abc', '', + \ 'Exception made pending: abc', '', + \ 'Exception thrown: xyz', '', + \ 'Exception discarded: abc', '', + \ 'Exception caught: xyz', '', + \ 'Exception finished: xyz'] + call assert_equal(expected, split(msg, "\n")) + + " Test for messages displayed when :throw is resumed after :finally + redir => msg + try + try + throw 'abc' + finally + endtry + catch + endtry + redir END + let expected = [ + \ 'Exception thrown: abc', '', + \ 'Exception made pending: abc', '', + \ 'Exception resumed: abc', '', + \ 'Exception caught: abc', '', + \ 'Exception finished: abc'] + call assert_equal(expected, split(msg, "\n")) + + " Test for messages displayed when :break is resumed after :finally + redir => msg + for i in range(1) + try + break + finally + endtry + endfor + redir END + let expected = [':break made pending', '', ':break resumed'] + call assert_equal(expected, split(msg, "\n")) + + " Test for messages displayed when :continue is resumed after :finally + redir => msg + for i in range(1) + try + continue + finally + endtry + endfor + redir END + let expected = [':continue made pending', '', ':continue resumed'] + call assert_equal(expected, split(msg, "\n")) + + " Test for messages displayed when :return is resumed after :finally + func Xtest() + try + return 'vim' + finally + endtry + endfunc + redir => msg + call Xtest() + redir END + let expected = [ + \ 'calling Xtest()', '', + \ ':return vim made pending', '', + \ ':return vim resumed', '', + \ 'Xtest returning ''vim''', '', + \ 'continuing in Test_try_catch_verbose'] + call assert_equal(expected, split(msg, "\n")) + delfunc Xtest + + " Test for messages displayed when :finish is resumed after :finally + call writefile(['try', 'finish', 'finally', 'endtry'], 'Xscript') + redir => msg + source Xscript + redir END + let expected = [ + \ ':finish made pending', '', + \ ':finish resumed', '', + \ 'finished sourcing Xscript', + \ 'continuing in Test_try_catch_verbose'] + call assert_equal(expected, split(msg, "\n")[1:]) + call delete('Xscript') + + " Test for messages displayed when a pending :continue is discarded by an + " exception in a finally handler + redir => msg + try + for i in range(1) + try + continue + finally + throw 'abc' + endtry + endfor + catch + endtry + redir END + let expected = [ + \ ':continue made pending', '', + \ 'Exception thrown: abc', '', + \ ':continue discarded', '', + \ 'Exception caught: abc', '', + \ 'Exception finished: abc'] + call assert_equal(expected, split(msg, "\n")) + set verbose& endfunc +" Test for throwing an exception from a BufEnter autocmd {{{1 +func Test_BufEnter_exception() + augroup bufenter_exception + au! + autocmd BufEnter Xfile1 throw 'abc' + augroup END + + let caught_abc = 0 + try + sp Xfile1 + catch /^abc/ + let caught_abc = 1 + endtry + call assert_equal(1, caught_abc) + call assert_equal(1, winnr('$')) + + augroup bufenter_exception + au! + augroup END + augroup! bufenter_exception + %bwipe! + + " Test for recursively throwing exceptions in autocmds + augroup bufenter_exception + au! + autocmd BufEnter Xfile1 throw 'bufenter' + autocmd BufLeave Xfile1 throw 'bufleave' + augroup END + + let ex_count = 0 + try + try + sp Xfile1 + catch /^bufenter/ + let ex_count += 1 + endtry + catch /^bufleave/ + let ex_count += 10 + endtry + call assert_equal(10, ex_count) + call assert_equal(2, winnr('$')) + + augroup bufenter_exception + au! + augroup END + augroup! bufenter_exception + %bwipe! +endfunc + " Test for using throw in a called function with following error {{{1 func Test_user_command_throw_in_function_call() let lines =<< trim END diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim index 5231ef7b4f..c14624f5b4 100644 --- a/src/nvim/testdir/test_user_func.vim +++ b/src/nvim/testdir/test_user_func.vim @@ -169,3 +169,10 @@ endfunc func Test_failed_call_in_try() try | call UnknownFunc() | catch | endtry endfunc + +" Test for listing user-defined functions +func Test_function_list() + call assert_fails("function Xabc", 'E123:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim index e37fe43b22..1065dd16e2 100644 --- a/src/nvim/testdir/test_usercommands.vim +++ b/src/nvim/testdir/test_usercommands.vim @@ -101,6 +101,10 @@ function Test_cmdmods() call assert_equal('vertical', g:mods) vert MyCmd call assert_equal('vertical', g:mods) + horizontal MyCmd + call assert_equal('horizontal', g:mods) + hor MyCmd + call assert_equal('horizontal', g:mods) aboveleft belowright botright browse confirm hide keepalt keepjumps \ keepmarks keeppatterns lockmarks noautocmd noswapfile silent diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim index 68fe15ff93..0acd7fc1e5 100644 --- a/src/nvim/testdir/test_vartabs.vim +++ b/src/nvim/testdir/test_vartabs.vim @@ -429,4 +429,18 @@ func Test_varsofttabstop() close! endfunc +" Setting 'shiftwidth' to a negative value, should set it to either the value +" of 'tabstop' (if 'vartabstop' is not set) or to the first value in +" 'vartabstop' +func Test_shiftwidth_vartabstop() + throw 'Skipped: Nvim removed this behavior in #6377' + setlocal tabstop=7 vartabstop= + call assert_fails('set shiftwidth=-1', 'E487:') + call assert_equal(7, &shiftwidth) + setlocal tabstop=7 vartabstop=5,7,10 + call assert_fails('set shiftwidth=-1', 'E487:') + call assert_equal(5, &shiftwidth) + setlocal shiftwidth& vartabstop& tabstop& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_viminfo.vim b/src/nvim/testdir/test_viminfo.vim new file mode 100644 index 0000000000..2d6d598011 --- /dev/null +++ b/src/nvim/testdir/test_viminfo.vim @@ -0,0 +1,21 @@ + +" Test for errors in setting 'viminfo' +func Test_viminfo_option_error() + " Missing number + call assert_fails('set viminfo=\"', 'E526:') + for c in split("'/:<@s", '\zs') + call assert_fails('set viminfo=' .. c, 'E526:') + endfor + + " Missing comma + call assert_fails('set viminfo=%10!', 'E527:') + call assert_fails('set viminfo=!%10', 'E527:') + call assert_fails('set viminfo=h%10', 'E527:') + call assert_fails('set viminfo=c%10', 'E527:') + call assert_fails('set viminfo=:10%10', 'E527:') + + " Missing ' setting + call assert_fails('set viminfo=%10', 'E528:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 0f204cdd0c..3487a028ca 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -756,23 +756,23 @@ endfunc XpathINIT -function! NULL() +func NULL() Xpath 'a' return 0 -endfunction +endfunc -function! ZERO() +func ZERO() Xpath 'b' return 0 -endfunction +endfunc -function! F0() +func! F0() Xpath 'c' -endfunction +endfunc -function! F1(arg) +func! F1(arg) Xpath 'e' -endfunction +endfunc let V0 = 1 @@ -1370,10 +1370,10 @@ endfunc " Test 95: lines of :append, :change, :insert {{{1 "------------------------------------------------------------------------------- -function! DefineFunction(name, body) +func DefineFunction(name, body) let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n") exec func -endfunction +endfunc func Test_script_lines() " :append @@ -1829,6 +1829,9 @@ func Test_missing_end() endtry call assert_equal(1, caught_e733) + " Using endfunc with :if + call assert_fails('exe "if 1 | endfunc | endif"', 'E193:') + " Missing 'in' in a :for statement call assert_fails('for i range(1) | endfor', 'E690:') endfunc @@ -1875,6 +1878,15 @@ func Test_deep_nest() @a let @a = '' endfunc + + " Deep nesting of function ... endfunction + func Test5() + let @a = join(repeat(['function X()'], 51), "\n") + let @a ..= "\necho v:true\n" + let @a ..= join(repeat(['endfunction'], 51), "\n") + @a + let @a = '' + endfunc [SCRIPT] call writefile(lines, 'Xscript') @@ -1882,20 +1894,31 @@ func Test_deep_nest() " Deep nesting of if ... endif call term_sendkeys(buf, ":call Test1()\n") + call term_wait(buf) call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))}) " Deep nesting of for ... endfor call term_sendkeys(buf, ":call Test2()\n") + call term_wait(buf) call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))}) " Deep nesting of while ... endwhile call term_sendkeys(buf, ":call Test3()\n") + call term_wait(buf) call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))}) " Deep nesting of try ... endtry call term_sendkeys(buf, ":call Test4()\n") + call term_wait(buf) call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))}) + " Deep nesting of function ... endfunction + call term_sendkeys(buf, ":call Test5()\n") + call term_wait(buf) + call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))}) + call term_sendkeys(buf, "\<C-C>\n") + call term_wait(buf) + "let l = '' "for i in range(1, 6) " let l ..= term_getline(buf, i) . "\n" diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim index 522ca17675..e712896562 100644 --- a/src/nvim/testdir/test_virtualedit.vim +++ b/src/nvim/testdir/test_virtualedit.vim @@ -481,4 +481,53 @@ func Test_global_local_virtualedit() set virtualedit& endfunc +func Test_virtualedit_mouse() + let save_mouse = &mouse + set mouse=a + set virtualedit=all + new + + call setline(1, ["text\tword"]) + redraw + call Ntest_setmouse(1, 4) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 4, 0, 4], getcurpos()) + call Ntest_setmouse(1, 5) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 5, 0, 5], getcurpos()) + call Ntest_setmouse(1, 6) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 5, 1, 6], getcurpos()) + call Ntest_setmouse(1, 7) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 5, 2, 7], getcurpos()) + call Ntest_setmouse(1, 8) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 5, 3, 8], getcurpos()) + call Ntest_setmouse(1, 9) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 6, 0, 9], getcurpos()) + call Ntest_setmouse(1, 15) + call feedkeys("\<LeftMouse>", "xt") + call assert_equal([0, 1, 10, 2, 15], getcurpos()) + + bwipe! + let &mouse = save_mouse + set virtualedit& +endfunc + +" this was replacing the NUL at the end of the line +func Test_virtualedit_replace_after_tab() + new + s/\v/ 0 + set ve=all + let @" = '' + sil! norm vPvr0 + + call assert_equal("\t0", getline(1)) + set ve& + bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 9c1ad0c099..65665d36c0 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1492,5 +1492,4 @@ func Test_switch_buffer_ends_visual_mode() exe 'bwipe!' buf2 endfunc - " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim index 83a3216534..c4ce4d638c 100644 --- a/src/nvim/testdir/test_window_cmd.vim +++ b/src/nvim/testdir/test_window_cmd.vim @@ -1,5 +1,8 @@ " Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...) +source check.vim +source screendump.vim + func Test_window_cmd_ls0_with_split() set ls=0 set splitbelow @@ -343,6 +346,46 @@ func Test_window_height() bw Xa Xb Xc endfunc +func Test_wincmd_equal() + edit Xone + below split Xtwo + rightbelow vsplit Xthree + call assert_equal('Xone', bufname(winbufnr(1))) + call assert_equal('Xtwo', bufname(winbufnr(2))) + call assert_equal('Xthree', bufname(winbufnr(3))) + + " Xone and Xtwo should be about the same height + let [wh1, wh2] = [winheight(1), winheight(2)] + call assert_inrange(wh1 - 1, wh1 + 1, wh2) + " Xtwo and Xthree should be about the same width + let [ww2, ww3] = [winwidth(2), winwidth(3)] + call assert_inrange(ww2 - 1, ww2 + 1, ww3) + + 1wincmd w + 10wincmd _ + 2wincmd w + 20wincmd | + call assert_equal(10, winheight(1)) + call assert_equal(20, winwidth(2)) + + " equalizing horizontally doesn't change the heights + hor wincmd = + call assert_equal(10, winheight(1)) + let [ww2, ww3] = [winwidth(2), winwidth(3)] + call assert_inrange(ww2 - 1, ww2 + 1, ww3) + + 2wincmd w + 20wincmd | + call assert_equal(20, winwidth(2)) + " equalizing vertically doesn't change the widths + vert wincmd = + call assert_equal(20, winwidth(2)) + let [wh1, wh2] = [winheight(1), winheight(2)] + call assert_inrange(wh1 - 1, wh1 + 1, wh2) + + bwipe Xone Xtwo Xthree +endfunc + func Test_window_width() e Xa vsplit Xb @@ -393,7 +436,15 @@ func Test_window_width() call assert_inrange(ww1, ww1 + 1, ww2) call assert_inrange(ww3, ww3 + 1, ww2) - bw Xa Xb Xc + " when the current window width is less than the new 'winwidth', the current + " window width should be increased. + enew | only + split + 10vnew + set winwidth=15 + call assert_equal(15, winwidth(0)) + + %bw! endfunc func Test_equalalways_on_close() @@ -1424,4 +1475,272 @@ func Test_win_move_statusline() %bwipe! endfunc +func Test_win_equal_last_status() + let save_lines = &lines + set lines=20 + set splitbelow + set laststatus=0 + + split | split | quit + call assert_equal(winheight(1), winheight(2)) + + let &lines = save_lines + set splitbelow& + set laststatus& +endfunc + +" Test "screen" and "cursor" values for 'splitkeep' with a sequence of +" split operations for various options: with and without a winbar, +" tabline, for each possible value of 'laststatus', 'scrolloff', +" 'equalalways', and with the cursor at the top, middle and bottom. +func Test_splitkeep_options() + " disallow window resizing + " let save_WS = &t_WS + " set t_WS= + + let gui = has("gui_running") + inoremap <expr> c "<cmd>copen<bar>wincmd k<CR>" + for run in range(0, 20) + let &splitkeep = run > 10 ? 'topline' : 'screen' + let &scrolloff = (!(run % 4) ? 0 : run) + let &laststatus = (run % 3) + let &splitbelow = (run % 3) + let &equalalways = (run % 2) + " Nvim: both windows have a winbar after splitting + " let wsb = (run % 2) && &splitbelow + let wsb = 0 + let tl = (gui ? 0 : ((run % 5) ? 1 : 0)) + let pos = !(run % 3) ? 'H' : ((run % 2) ? 'M' : 'L') + tabnew | tabonly! | redraw + execute (run % 5) ? 'tabnew' : '' + " execute (run % 2) ? 'nnoremenu 1.10 WinBar.Test :echo' : '' + let &winbar = (run % 2) ? '%f' : '' + call setline(1, range(1, 256)) + " No scroll for restore_snapshot + norm G + try + copen | close | colder + catch /E380/ + endtry + call assert_equal(257 - winheight(0), line("w0")) + + " No scroll for firstwin horizontal split + execute 'norm gg' . pos + split | redraw | wincmd k + call assert_equal(1, line("w0")) + call assert_equal(&scroll, winheight(0) / 2) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + + " No scroll when resizing windows + wincmd k | resize +2 | redraw + call assert_equal(1, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + + " No scroll when dragging statusline + call win_move_statusline(1, -3) + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + wincmd k + call assert_equal(1, line("w0")) + + " No scroll when changing shellsize + set lines+=2 + call assert_equal(1, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + set lines-=2 + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + wincmd k + call assert_equal(1, line("w0")) + + " No scroll when equalizing windows + wincmd = + call assert_equal(1, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + wincmd k + call assert_equal(1, line("w0")) + + " No scroll in windows split multiple times + vsplit | split | 4wincmd w + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + 1wincmd w | quit | wincmd l | split + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + + " No scroll in small window + 2wincmd w | only | 5split | wincmd k + call assert_equal(1, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + + " No scroll for vertical split + quit | vsplit | wincmd l + call assert_equal(1, line("w0")) + wincmd h + call assert_equal(1, line("w0")) + + " No scroll in windows split and quit multiple times + quit | redraw | split | split | quit | redraw + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0")) + + " No scroll for new buffer + 1wincmd w | only | copen | wincmd k + call assert_equal(1, line("w0")) + only + call assert_equal(1, line("w0")) + above copen | wincmd j + call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl, line("w0")) + + " No scroll when opening cmdwin, and no cursor move when closing cmdwin. + only | norm ggL + let curpos = getcurpos() + norm q: + call assert_equal(1, line("w0")) + call assert_equal(curpos, getcurpos()) + + " Scroll when cursor becomes invalid in insert mode + norm Lic + call assert_equal(curpos, getcurpos()) + + " No scroll when topline not equal to 1 + only | execute "norm gg5\<C-e>" | split | wincmd k + call assert_equal(6, line("w0")) + wincmd j + call assert_equal(&spk == 'topline' ? 6 : 5 + win_screenpos(0)[0] - tl - wsb, line("w0")) + endfor + + tabnew | tabonly! | %bwipeout! + iunmap c + set scrolloff& + set splitbelow& + set laststatus& + set equalalways& + set splitkeep& + " let &t_WS = save_WS +endfunc + +function Test_splitkeep_cmdwin_cursor_position() + set splitkeep=screen + call setline(1, range(&lines)) + + " No scroll when cursor is at near bottom of window and cusor position + " recompution (done by line('w0') in this test) happens while in cmdwin. + normal! G + let firstline = line('w0') + autocmd CmdwinEnter * ++once autocmd WinEnter * ++once call line('w0') + execute "normal! q:\<C-w>q" + redraw! + call assert_equal(firstline, line('w0')) + + " User script can change cursor position successfully while in cmdwin and it + " shouldn't be changed when closing cmdwin. + execute "normal! Gq:\<Cmd>call win_execute(winnr('#')->win_getid(), 'call cursor(1, 1)')\<CR>\<C-w>q" + call assert_equal(1, line('.')) + call assert_equal(1, col('.')) + + execute "normal! Gq:\<Cmd>autocmd WinEnter * ++once call cursor(1, 1)\<CR>\<C-w>q" + call assert_equal(1, line('.')) + call assert_equal(1, col('.')) + + %bwipeout! + set splitkeep& +endfunction + +function Test_splitkeep_misc() + set splitkeep=screen + set splitbelow + + call setline(1, range(1, &lines)) + norm Gzz + let top = line('w0') + " No scroll when aucmd_win is opened + call setbufvar(bufnr("test", 1) , '&buftype', 'nofile') + call assert_equal(top, line('w0')) + " No scroll when tab is changed/closed + tab help | close + call assert_equal(top, line('w0')) + " No scroll when help is closed and buffer line count < window height + norm ggdG + call setline(1, range(1, &lines - 10)) + norm G + let top = line('w0') + help | quit + call assert_equal(top, line('w0')) + " No error when resizing window in autocmd and buffer length changed + autocmd FileType qf exe "resize" line('$') + cexpr getline(1, '$') + copen + wincmd p + norm dd + cexpr getline(1, '$') + + %bwipeout! + set splitbelow& + set splitkeep& +endfunc + +function Test_splitkeep_callback() + CheckScreendump + let lines =<< trim END + set splitkeep=screen + call setline(1, range(&lines)) + function C1(a, b) + split | wincmd p + endfunction + function C2(a, b) + close | split + endfunction + nn j <cmd>call job_start([&sh, &shcf, "true"], { 'exit_cb': 'C1' })<CR> + nn t <cmd>call popup_create(term_start([&sh, &shcf, "true"], + \ { 'hidden': 1, 'exit_cb': 'C2' }), {})<CR> + END + call writefile(lines, 'XTestSplitkeepCallback', 'D') + let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8}) + + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_splitkeep_callback_1', {}) + + call term_sendkeys(buf, ":quit\<CR>Ht") + call VerifyScreenDump(buf, 'Test_splitkeep_callback_2', {}) + + call term_sendkeys(buf, ":set sb\<CR>:quit\<CR>Gj") + call VerifyScreenDump(buf, 'Test_splitkeep_callback_3', {}) + + call term_sendkeys(buf, ":quit\<CR>Gt") + call VerifyScreenDump(buf, 'Test_splitkeep_callback_4', {}) +endfunc + +function Test_splitkeep_fold() + CheckScreendump + + let lines =<< trim END + set splitkeep=screen + set foldmethod=marker + set number + let line = 1 + for n in range(1, &lines) + call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/', + \ 'after fold']) + let line += 8 + endfor + END + call writefile(lines, 'XTestSplitkeepFold', 'D') + let buf = RunVimInTerminal('-S XTestSplitkeepFold', #{rows: 10}) + + call term_sendkeys(buf, "L:wincmd s\<CR>") + call VerifyScreenDump(buf, 'Test_splitkeep_fold_1', {}) + + call term_sendkeys(buf, ":quit\<CR>") + call VerifyScreenDump(buf, 'Test_splitkeep_fold_2', {}) + + call term_sendkeys(buf, "H:below split\<CR>") + call VerifyScreenDump(buf, 'Test_splitkeep_fold_3', {}) + + call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>") + call VerifyScreenDump(buf, 'Test_splitkeep_fold_4', {}) +endfunction + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index a8735bcaf1..adc05ab979 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -216,6 +216,12 @@ func Test_saveas() syntax off %bw! call delete('Xsaveas.pl') + + " :saveas fails for "nofile" buffer + set buftype=nofile + call assert_fails('saveas Xsafile', 'E676: No matching autocommands for buftype=nofile buffer') + + bwipe! endfunc func Test_write_errors() diff --git a/src/nvim/testdir/view_util.vim b/src/nvim/testdir/view_util.vim index 1cdce21602..a4d0e56af9 100644 --- a/src/nvim/testdir/view_util.vim +++ b/src/nvim/testdir/view_util.vim @@ -19,7 +19,7 @@ endfunc " Get text on the screen, including composing characters. " ScreenLines(lnum, width) or " ScreenLines([start, end], width) -function! ScreenLines(lnum, width) abort +func ScreenLines(lnum, width) abort redraw! if type(a:lnum) == v:t_list let start = a:lnum[0] @@ -33,9 +33,9 @@ function! ScreenLines(lnum, width) abort let lines += [join(map(range(1, a:width), 'screenstring(l, v:val)'), '')] endfor return lines -endfunction +endfunc -function! ScreenAttrs(lnum, width) abort +func ScreenAttrs(lnum, width) abort redraw! if type(a:lnum) == v:t_list let start = a:lnum[0] @@ -49,16 +49,16 @@ function! ScreenAttrs(lnum, width) abort let attrs += [map(range(1, a:width), 'screenattr(l, v:val)')] endfor return attrs -endfunction +endfunc -function! NewWindow(height, width) abort +func NewWindow(height, width) abort exe a:height . 'new' exe a:width . 'vsp' set winfixwidth winfixheight redraw! -endfunction +endfunc -function! CloseWindow() abort +func CloseWindow() abort bw! redraw! -endfunction +endfunc diff --git a/src/nvim/testing.c b/src/nvim/testing.c index e70e9f2cbd..348d5c6e29 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -326,19 +326,19 @@ static int assert_beeps(typval_T *argvars, bool no_beep) } /// "assert_beeps(cmd [, error])" function -void f_assert_beeps(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_beeps(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_beeps(argvars, false); } /// "assert_nobeep(cmd [, error])" function -void f_assert_nobeep(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_nobeep(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_beeps(argvars, true); } /// "assert_equal(expected, actual[, msg])" function -void f_assert_equal(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_equal(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL); } @@ -419,7 +419,7 @@ static int assert_equalfile(typval_T *argvars) line2[lineidx] = NUL; ga_concat(&ga, " after \""); ga_concat(&ga, line1); - if (STRCMP(line1, line2) != 0) { + if (strcmp(line1, line2) != 0) { ga_concat(&ga, "\" vs \""); ga_concat(&ga, line2); } @@ -433,19 +433,19 @@ static int assert_equalfile(typval_T *argvars) } /// "assert_equalfile(fname-one, fname-two[, msg])" function -void f_assert_equalfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_equalfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_equalfile(argvars); } /// "assert_notequal(expected, actual[, msg])" function -void f_assert_notequal(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_notequal(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL); } /// "assert_exception(string[, msg])" function -void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_exception(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { garray_T ga; @@ -457,7 +457,7 @@ void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr) ga_clear(&ga); rettv->vval.v_number = 1; } else if (error != NULL - && strstr((char *)get_vim_var_str(VV_EXCEPTION), error) == NULL) { + && strstr(get_vim_var_str(VV_EXCEPTION), error) == NULL) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], get_vim_var_tv(VV_EXCEPTION), ASSERT_OTHER); @@ -468,7 +468,7 @@ void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "assert_fails(cmd [, error [, msg]])" function -void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_fails(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { const char *const cmd = tv_get_string_chk(&argvars[0]); garray_T ga; @@ -493,7 +493,7 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *const error = tv_get_string_buf_chk(&argvars[1], buf); if (error == NULL - || strstr((char *)get_vim_var_str(VV_ERRMSG), error) == NULL) { + || strstr(get_vim_var_str(VV_ERRMSG), error) == NULL) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], get_vim_var_tv(VV_ERRMSG), ASSERT_OTHER); @@ -513,7 +513,7 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) } // "assert_false(actual[, msg])" function -void f_assert_false(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_false(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_bool(argvars, false); } @@ -574,25 +574,25 @@ static int assert_inrange(typval_T *argvars) } /// "assert_inrange(lower, upper[, msg])" function -void f_assert_inrange(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_inrange(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_inrange(argvars); } /// "assert_match(pattern, actual[, msg])" function -void f_assert_match(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_match(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH); } /// "assert_notmatch(pattern, actual[, msg])" function -void f_assert_notmatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_notmatch(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH); } /// "assert_report(msg)" function -void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_report(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { garray_T ga; @@ -604,13 +604,13 @@ void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "assert_true(actual[, msg])" function -void f_assert_true(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_assert_true(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { rettv->vval.v_number = assert_bool(argvars, true); } /// "test_garbagecollect_now()" function -void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { // This is dangerous, any Lists and Dicts used internally may be freed // while still in use. @@ -618,7 +618,7 @@ void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// "test_write_list_log()" function -void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, FunPtr fptr) +void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, EvalFuncData fptr) { const char *const fname = tv_get_string_chk(&argvars[0]); if (fname == NULL) { diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c new file mode 100644 index 0000000000..25728ef0f1 --- /dev/null +++ b/src/nvim/textformat.c @@ -0,0 +1,1127 @@ +// 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 + +// textformat.c: text formatting functions + +#include <stdbool.h> + +#include "nvim/ascii.h" +#include "nvim/change.h" +#include "nvim/charset.h" +#include "nvim/cursor.h" +#include "nvim/drawscreen.h" +#include "nvim/edit.h" +#include "nvim/eval.h" +#include "nvim/getchar.h" +#include "nvim/globals.h" +#include "nvim/indent.h" +#include "nvim/indent_c.h" +#include "nvim/mbyte.h" +#include "nvim/memline.h" +#include "nvim/move.h" +#include "nvim/normal.h" +#include "nvim/ops.h" +#include "nvim/option.h" +#include "nvim/os/input.h" +#include "nvim/pos.h" +#include "nvim/search.h" +#include "nvim/strings.h" +#include "nvim/textformat.h" +#include "nvim/textobject.h" +#include "nvim/undo.h" +#include "nvim/vim.h" +#include "nvim/window.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "textformat.c.generated.h" +#endif + +static bool did_add_space = false; ///< auto_format() added an extra space + ///< under the cursor + +#define WHITECHAR(cc) (ascii_iswhite(cc) \ + && !utf_iscomposing(utf_ptr2char((char *)get_cursor_pos_ptr() + 1))) + +/// Return true if format option 'x' is in effect. +/// Take care of no formatting when 'paste' is set. +bool has_format_option(int x) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (p_paste) { + return false; + } + return vim_strchr(curbuf->b_p_fo, x) != NULL; +} + +/// Format text at the current insert position. +/// +/// If the INSCHAR_COM_LIST flag is present, then the value of second_indent +/// will be the comment leader length sent to open_line(). +/// +/// @param c character to be inserted (can be NUL) +void internal_format(int textwidth, int second_indent, int flags, bool format_only, int c) +{ + int cc; + int save_char = NUL; + bool haveto_redraw = false; + const bool fo_ins_blank = has_format_option(FO_INS_BLANK); + const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK); + const bool fo_rigor_tw = has_format_option(FO_RIGOROUS_TW); + const bool fo_white_par = has_format_option(FO_WHITE_PAR); + bool first_line = true; + colnr_T leader_len; + bool no_leader = false; + int do_comments = (flags & INSCHAR_DO_COM); + int has_lbr = curwin->w_p_lbr; + + // make sure win_lbr_chartabsize() counts correctly + curwin->w_p_lbr = false; + + // When 'ai' is off we don't want a space under the cursor to be + // deleted. Replace it with an 'x' temporarily. + if (!curbuf->b_p_ai + && !(State & VREPLACE_FLAG)) { + cc = gchar_cursor(); + if (ascii_iswhite(cc)) { + save_char = cc; + pchar_cursor('x'); + } + } + + // Repeat breaking lines, until the current line is not too long. + while (!got_int) { + int startcol; // Cursor column at entry + int wantcol; // column at textwidth border + int foundcol; // column for start of spaces + int end_foundcol = 0; // column for start of word + colnr_T len; + colnr_T virtcol; + int orig_col = 0; + char *saved_text = NULL; + colnr_T col; + colnr_T end_col; + bool did_do_comment = false; + + virtcol = get_nolist_virtcol() + + char2cells(c != NUL ? c : gchar_cursor()); + if (virtcol <= (colnr_T)textwidth) { + break; + } + + if (no_leader) { + do_comments = false; + } else if (!(flags & INSCHAR_FORMAT) + && has_format_option(FO_WRAP_COMS)) { + do_comments = true; + } + + // Don't break until after the comment leader + if (do_comments) { + char_u *line = (char_u *)get_cursor_line_ptr(); + leader_len = get_leader_len((char *)line, NULL, false, true); + if (leader_len == 0 && curbuf->b_p_cin) { + // Check for a line comment after code. + int comment_start = check_linecomment((char *)line); + if (comment_start != MAXCOL) { + leader_len = get_leader_len((char *)line + comment_start, NULL, false, true); + if (leader_len != 0) { + leader_len += comment_start; + } + } + } + } else { + leader_len = 0; + } + + // If the line doesn't start with a comment leader, then don't + // start one in a following broken line. Avoids that a %word + // moved to the start of the next line causes all following lines + // to start with %. + if (leader_len == 0) { + no_leader = true; + } + if (!(flags & INSCHAR_FORMAT) + && leader_len == 0 + && !has_format_option(FO_WRAP)) { + break; + } + if ((startcol = curwin->w_cursor.col) == 0) { + break; + } + + // find column of textwidth border + coladvance((colnr_T)textwidth); + wantcol = curwin->w_cursor.col; + + curwin->w_cursor.col = startcol; + foundcol = 0; + int skip_pos = 0; + + // Find position to break at. + // Stop at first entered white when 'formatoptions' has 'v' + while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) + || (flags & INSCHAR_FORMAT) + || curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) { + if (curwin->w_cursor.col == startcol && c != NUL) { + cc = c; + } else { + cc = gchar_cursor(); + } + if (WHITECHAR(cc)) { + // remember position of blank just before text + end_col = curwin->w_cursor.col; + + // find start of sequence of blanks + int wcc = 0; // counter for whitespace chars + while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) { + dec_cursor(); + cc = gchar_cursor(); + + // Increment count of how many whitespace chars in this + // group; we only need to know if it's more than one. + if (wcc < 2) { + wcc++; + } + } + if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) { + break; // only spaces in front of text + } + + // Don't break after a period when 'formatoptions' has 'p' and + // there are less than two spaces. + if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) { + continue; + } + + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) { + break; + } + + if (has_format_option(FO_ONE_LETTER)) { + // do not break after one-letter words + if (curwin->w_cursor.col == 0) { + break; // one-letter word at begin + } + // do not break "#a b" when 'tw' is 2 + if (curwin->w_cursor.col <= leader_len) { + break; + } + col = curwin->w_cursor.col; + dec_cursor(); + cc = gchar_cursor(); + + if (WHITECHAR(cc)) { + continue; // one-letter, continue + } + curwin->w_cursor.col = col; + } + + inc_cursor(); + + end_foundcol = end_col + 1; + foundcol = curwin->w_cursor.col; + if (curwin->w_cursor.col <= (colnr_T)wantcol) { + break; + } + } else if ((cc >= 0x100 || !utf_allow_break_before(cc)) && fo_multibyte) { + int ncc; + bool allow_break; + + // Break after or before a multi-byte character. + if (curwin->w_cursor.col != startcol) { + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) { + break; + } + col = curwin->w_cursor.col; + inc_cursor(); + ncc = gchar_cursor(); + allow_break = utf_allow_break(cc, ncc); + + // If we have already checked this position, skip! + if (curwin->w_cursor.col != skip_pos && allow_break) { + foundcol = curwin->w_cursor.col; + end_foundcol = foundcol; + if (curwin->w_cursor.col <= (colnr_T)wantcol) { + break; + } + } + curwin->w_cursor.col = col; + } + + if (curwin->w_cursor.col == 0) { + break; + } + + ncc = cc; + col = curwin->w_cursor.col; + + dec_cursor(); + cc = gchar_cursor(); + + if (WHITECHAR(cc)) { + continue; // break with space + } + // Don't break until after the comment leader. + if (curwin->w_cursor.col < leader_len) { + break; + } + + curwin->w_cursor.col = col; + skip_pos = curwin->w_cursor.col; + + allow_break = utf_allow_break(cc, ncc); + + // Must handle this to respect line break prohibition. + if (allow_break) { + foundcol = curwin->w_cursor.col; + end_foundcol = foundcol; + } + if (curwin->w_cursor.col <= (colnr_T)wantcol) { + const bool ncc_allow_break = utf_allow_break_before(ncc); + + if (allow_break) { + break; + } + if (!ncc_allow_break && !fo_rigor_tw) { + // Enable at most 1 punct hang outside of textwidth. + if (curwin->w_cursor.col == startcol) { + // We are inserting a non-breakable char, postpone + // line break check to next insert. + end_foundcol = foundcol = 0; + break; + } + + // Neither cc nor ncc is NUL if we are here, so + // it's safe to inc_cursor. + col = curwin->w_cursor.col; + + inc_cursor(); + cc = ncc; + ncc = gchar_cursor(); + // handle insert + ncc = (ncc != NUL) ? ncc : c; + + allow_break = utf_allow_break(cc, ncc); + + if (allow_break) { + // Break only when we are not at end of line. + end_foundcol = foundcol = ncc == NUL? 0 : curwin->w_cursor.col; + break; + } + curwin->w_cursor.col = col; + } + } + } + if (curwin->w_cursor.col == 0) { + break; + } + dec_cursor(); + } + + if (foundcol == 0) { // no spaces, cannot break line + curwin->w_cursor.col = startcol; + break; + } + + // Going to break the line, remove any "$" now. + undisplay_dollar(); + + // Offset between cursor position and line break is used by replace + // stack functions. MODE_VREPLACE does not use this, and backspaces + // over the text instead. + if (State & VREPLACE_FLAG) { + orig_col = startcol; // Will start backspacing from here + } else { + replace_offset = startcol - end_foundcol; + } + + // adjust startcol for spaces that will be deleted and + // characters that will remain on top line + curwin->w_cursor.col = foundcol; + while ((cc = gchar_cursor(), WHITECHAR(cc)) + && (!fo_white_par || curwin->w_cursor.col < startcol)) { + inc_cursor(); + } + startcol -= curwin->w_cursor.col; + if (startcol < 0) { + startcol = 0; + } + + if (State & VREPLACE_FLAG) { + // In MODE_VREPLACE state, we will backspace over the text to be + // wrapped, so save a copy now to put on the next line. + saved_text = xstrdup(get_cursor_pos_ptr()); + curwin->w_cursor.col = orig_col; + saved_text[startcol] = NUL; + + // Backspace over characters that will move to the next line + if (!fo_white_par) { + backspace_until_column(foundcol); + } + } else { + // put cursor after pos. to break line + if (!fo_white_par) { + curwin->w_cursor.col = foundcol; + } + } + + // Split the line just before the margin. + // Only insert/delete lines, but don't really redraw the window. + open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX + + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) + + (do_comments ? OPENLINE_DO_COM : 0) + + OPENLINE_FORMAT + + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0), + ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent), + &did_do_comment); + if (!(flags & INSCHAR_COM_LIST)) { + old_indent = 0; + } + + // If a comment leader was inserted, may also do this on a following + // line. + if (did_do_comment) { + no_leader = false; + } + + replace_offset = 0; + if (first_line) { + if (!(flags & INSCHAR_COM_LIST)) { + // This section is for auto-wrap of numeric lists. When not + // in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST + // flag will be set and open_line() will handle it (as seen + // above). The code here (and in get_number_indent()) will + // recognize comments if needed... + if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) { + second_indent = get_number_indent(curwin->w_cursor.lnum - 1); + } + if (second_indent >= 0) { + if (State & VREPLACE_FLAG) { + change_indent(INDENT_SET, second_indent, false, NUL, true); + } else if (leader_len > 0 && second_indent - leader_len > 0) { + int padding = second_indent - leader_len; + + // We started at the first_line of a numbered list + // that has a comment. the open_line() function has + // inserted the proper comment leader and positioned + // the cursor at the end of the split line. Now we + // add the additional whitespace needed after the + // comment leader for the numbered list. + for (int i = 0; i < padding; i++) { + ins_str(" "); + } + changed_bytes(curwin->w_cursor.lnum, leader_len); + } else { + (void)set_indent(second_indent, SIN_CHANGED); + } + } + } + first_line = false; + } + + if (State & VREPLACE_FLAG) { + // In MODE_VREPLACE state we have backspaced over the text to be + // moved, now we re-insert it into the new line. + ins_bytes(saved_text); + xfree(saved_text); + } else { + // Check if cursor is not past the NUL off the line, cindent + // may have added or removed indent. + curwin->w_cursor.col += startcol; + len = (colnr_T)strlen(get_cursor_line_ptr()); + if (curwin->w_cursor.col > len) { + curwin->w_cursor.col = len; + } + } + + haveto_redraw = true; + set_can_cindent(true); + // moved the cursor, don't autoindent or cindent now + did_ai = false; + did_si = false; + can_si = false; + can_si_back = false; + line_breakcheck(); + } + + if (save_char != NUL) { // put back space after cursor + pchar_cursor((char_u)save_char); + } + + curwin->w_p_lbr = has_lbr; + + if (!format_only && haveto_redraw) { + update_topline(curwin); + redraw_curbuf_later(UPD_VALID); + } +} + +/// Blank lines, and lines containing only the comment leader, are left +/// untouched by the formatting. The function returns true in this +/// case. It also returns true when a line starts with the end of a comment +/// ('e' in comment flags), so that this line is skipped, and not joined to the +/// previous line. A new paragraph starts after a blank line, or when the +/// comment leader changes. +static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags, bool do_comments) +{ + char_u *flags = NULL; // init for GCC + char_u *ptr; + + ptr = (char_u *)ml_get(lnum); + if (do_comments) { + *leader_len = get_leader_len((char *)ptr, (char **)leader_flags, false, true); + } else { + *leader_len = 0; + } + + if (*leader_len > 0) { + // Search for 'e' flag in comment leader flags. + flags = *leader_flags; + while (*flags && *flags != ':' && *flags != COM_END) { + flags++; + } + } + + return *skipwhite((char *)ptr + *leader_len) == NUL + || (*leader_len > 0 && *flags == COM_END) + || startPS(lnum, NUL, false); +} + +/// @return true if line "lnum" ends in a white character. +static bool ends_in_white(linenr_T lnum) +{ + char_u *s = (char_u *)ml_get(lnum); + size_t l; + + if (*s == NUL) { + return false; + } + l = STRLEN(s) - 1; + return ascii_iswhite(s[l]); +} + +/// @return true if the two comment leaders given are the same. +/// +/// @param lnum The first line. White-space is ignored. +/// +/// @note the whole of 'leader1' must match 'leader2_len' characters from 'leader2'. +static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int leader2_len, + char *leader2_flags) +{ + int idx1 = 0, idx2 = 0; + char *p; + char *line1; + char *line2; + + if (leader1_len == 0) { + return leader2_len == 0; + } + + // If first leader has 'f' flag, the lines can be joined only if the + // second line does not have a leader. + // If first leader has 'e' flag, the lines can never be joined. + // If first leader has 's' flag, the lines can only be joined if there is + // some text after it and the second line has the 'm' flag. + if (leader1_flags != NULL) { + for (p = leader1_flags; *p && *p != ':'; p++) { + if (*p == COM_FIRST) { + return leader2_len == 0; + } + if (*p == COM_END) { + return false; + } + if (*p == COM_START) { + if (*(ml_get(lnum) + leader1_len) == NUL) { + return false; + } + if (leader2_flags == NULL || leader2_len == 0) { + return false; + } + for (p = leader2_flags; *p && *p != ':'; p++) { + if (*p == COM_MIDDLE) { + return true; + } + } + return false; + } + } + } + + // Get current line and next line, compare the leaders. + // The first line has to be saved, only one line can be locked at a time. + line1 = xstrdup(ml_get(lnum)); + for (idx1 = 0; ascii_iswhite(line1[idx1]); idx1++) {} + line2 = ml_get(lnum + 1); + for (idx2 = 0; idx2 < leader2_len; idx2++) { + if (!ascii_iswhite(line2[idx2])) { + if (line1[idx1++] != line2[idx2]) { + break; + } + } else { + while (ascii_iswhite(line1[idx1])) { + idx1++; + } + } + } + xfree(line1); + + return idx2 == leader2_len && idx1 == leader1_len; +} + +/// Used for auto-formatting. +/// +/// @return true when a paragraph starts in line "lnum". +/// false when the previous line is in the same paragraph. +static bool paragraph_start(linenr_T lnum) +{ + char_u *p; + int leader_len = 0; // leader len of current line + char_u *leader_flags = NULL; // flags for leader of current line + int next_leader_len = 0; // leader len of next line + char_u *next_leader_flags = NULL; // flags for leader of next line + + if (lnum <= 1) { + return true; // start of the file + } + p = (char_u *)ml_get(lnum - 1); + if (*p == NUL) { + return true; // after empty line + } + const bool do_comments = has_format_option(FO_Q_COMS); // format comments + if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) { + return true; // after non-paragraph line + } + + if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) { + return true; // "lnum" is not a paragraph line + } + + if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) { + return true; // missing trailing space in previous line. + } + if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) { + return true; // numbered item starts in "lnum". + } + if (!same_leader(lnum - 1, leader_len, (char *)leader_flags, + next_leader_len, (char *)next_leader_flags)) { + return true; // change of comment leader. + } + return false; +} + +/// Called after inserting or deleting text: When 'formatoptions' includes the +/// 'a' flag format from the current line until the end of the paragraph. +/// Keep the cursor at the same position relative to the text. +/// The caller must have saved the cursor line for undo, following ones will be +/// saved here. +/// +/// @param trailblank when true also format with trailing blank +/// @param prev_line may start in previous line +void auto_format(bool trailblank, bool prev_line) +{ + pos_T pos; + colnr_T len; + char *old; + char *new, *pnew; + int wasatend; + int cc; + + if (!has_format_option(FO_AUTO)) { + return; + } + + pos = curwin->w_cursor; + old = get_cursor_line_ptr(); + + // may remove added space + check_auto_format(false); + + // Don't format in Insert mode when the cursor is on a trailing blank, the + // user might insert normal text next. Also skip formatting when "1" is + // in 'formatoptions' and there is a single character before the cursor. + // Otherwise the line would be broken and when typing another non-white + // next they are not joined back together. + wasatend = (pos.col == (colnr_T)strlen(old)); + if (*old != NUL && !trailblank && wasatend) { + dec_cursor(); + cc = gchar_cursor(); + if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 + && has_format_option(FO_ONE_LETTER)) { + dec_cursor(); + } + cc = gchar_cursor(); + if (WHITECHAR(cc)) { + curwin->w_cursor = pos; + return; + } + curwin->w_cursor = pos; + } + + // With the 'c' flag in 'formatoptions' and 't' missing: only format + // comments. + if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) + && get_leader_len(old, NULL, false, true) == 0) { + return; + } + + // May start formatting in a previous line, so that after "x" a word is + // moved to the previous line if it fits there now. Only when this is not + // the start of a paragraph. + if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) { + curwin->w_cursor.lnum--; + if (u_save_cursor() == FAIL) { + return; + } + } + + // Do the formatting and restore the cursor position. "saved_cursor" will + // be adjusted for the text formatting. + saved_cursor = pos; + format_lines((linenr_T) - 1, false); + curwin->w_cursor = saved_cursor; + saved_cursor.lnum = 0; + + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { + // "cannot happen" + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance(MAXCOL); + } else { + check_cursor_col(); + } + + // Insert mode: If the cursor is now after the end of the line while it + // previously wasn't, the line was broken. Because of the rule above we + // need to add a space when 'w' is in 'formatoptions' to keep a paragraph + // formatted. + if (!wasatend && has_format_option(FO_WHITE_PAR)) { + new = get_cursor_line_ptr(); + len = (colnr_T)strlen(new); + if (curwin->w_cursor.col == len) { + pnew = xstrnsave(new, (size_t)len + 2); + pnew[len] = ' '; + pnew[len + 1] = NUL; + ml_replace(curwin->w_cursor.lnum, pnew, false); + // remove the space later + did_add_space = true; + } else { + // may remove added space + check_auto_format(false); + } + } + + check_cursor(); +} + +/// When an extra space was added to continue a paragraph for auto-formatting, +/// delete it now. The space must be under the cursor, just after the insert +/// position. +/// +/// @param end_insert true when ending Insert mode +void check_auto_format(bool end_insert) +{ + int c = ' '; + int cc; + + if (did_add_space) { + cc = gchar_cursor(); + if (!WHITECHAR(cc)) { + // Somehow the space was removed already. + did_add_space = false; + } else { + if (!end_insert) { + inc_cursor(); + c = gchar_cursor(); + dec_cursor(); + } + if (c != NUL) { + // The space is no longer at the end of the line, delete it. + del_char(false); + did_add_space = false; + } + } + } +} + +/// Find out textwidth to be used for formatting: +/// if 'textwidth' option is set, use it +/// else if 'wrapmargin' option is set, use curwin->w_width_inner-'wrapmargin' +/// if invalid value, use 0. +/// Set default to window width (maximum 79) for "gq" operator. +/// +/// @param ff force formatting (for "gq" command) +int comp_textwidth(bool ff) +{ + int textwidth = (int)curbuf->b_p_tw; + if (textwidth == 0 && curbuf->b_p_wm) { + // The width is the window width minus 'wrapmargin' minus all the + // things that add to the margin. + textwidth = curwin->w_width_inner - (int)curbuf->b_p_wm; + if (cmdwin_type != 0) { + textwidth -= 1; + } + textwidth -= win_fdccol_count(curwin); + textwidth -= win_signcol_count(curwin); + + if (curwin->w_p_nu || curwin->w_p_rnu) { + textwidth -= 8; + } + } + if (textwidth < 0) { + textwidth = 0; + } + if (ff && textwidth == 0) { + textwidth = curwin->w_width_inner - 1; + if (textwidth > 79) { + textwidth = 79; + } + } + return textwidth; +} + +/// Implementation of the format operator 'gq'. +/// +/// @param keep_cursor keep cursor on same text char +void op_format(oparg_T *oap, bool keep_cursor) +{ + linenr_T old_line_count = curbuf->b_ml.ml_line_count; + + // Place the cursor where the "gq" or "gw" command was given, so that "u" + // can put it back there. + curwin->w_cursor = oap->cursor_start; + + if (u_save((linenr_T)(oap->start.lnum - 1), + (linenr_T)(oap->end.lnum + 1)) == FAIL) { + return; + } + curwin->w_cursor = oap->start; + + if (oap->is_VIsual) { + // When there is no change: need to remove the Visual selection + redraw_curbuf_later(UPD_INVERTED); + } + + if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { + // Set '[ mark at the start of the formatted area + curbuf->b_op_start = oap->start; + } + + // For "gw" remember the cursor position and put it back below (adjusted + // for joined and split lines). + if (keep_cursor) { + saved_cursor = oap->cursor_start; + } + + format_lines((linenr_T)oap->line_count, keep_cursor); + + // Leave the cursor at the first non-blank of the last formatted line. + // If the cursor was moved one line back (e.g. with "Q}") go to the next + // line, so "." will do the next lines. + if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { + curwin->w_cursor.lnum++; + } + beginline(BL_WHITE | BL_FIX); + old_line_count = curbuf->b_ml.ml_line_count - old_line_count; + msgmore(old_line_count); + + if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { + // put '] mark on the end of the formatted area + curbuf->b_op_end = curwin->w_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) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_old_cursor_lnum != 0) { + // When lines have been inserted or deleted, adjust the end of + // the Visual area to be redrawn. + if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) { + wp->w_old_cursor_lnum += old_line_count; + } else { + wp->w_old_visual_lnum += old_line_count; + } + } + } + } +} + +/// Implementation of the format operator 'gq' for when using 'formatexpr'. +void op_formatexpr(oparg_T *oap) +{ + if (oap->is_VIsual) { + // When there is no change: need to remove the Visual selection + redraw_curbuf_later(UPD_INVERTED); + } + + if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) { + // As documented: when 'formatexpr' returns non-zero fall back to + // internal formatting. + op_format(oap, false); + } +} + +/// @param c character to be inserted +int fex_format(linenr_T lnum, long count, int c) +{ + int use_sandbox = was_set_insecurely(curwin, "formatexpr", OPT_LOCAL); + int r; + + // Set v:lnum to the first line number and v:count to the number of lines. + // Set v:char to the character to be inserted (can be NUL). + set_vim_var_nr(VV_LNUM, (varnumber_T)lnum); + set_vim_var_nr(VV_COUNT, (varnumber_T)count); + set_vim_var_char(c); + + // Make a copy, the option could be changed while calling it. + char *fex = xstrdup(curbuf->b_p_fex); + // Evaluate the function. + if (use_sandbox) { + sandbox++; + } + r = (int)eval_to_number(fex); + if (use_sandbox) { + sandbox--; + } + + set_vim_var_string(VV_CHAR, NULL, -1); + xfree(fex); + + return r; +} + +/// @param line_count number of lines to format, starting at the cursor position. +/// when negative, format until the end of the paragraph. +/// +/// Lines after the cursor line are saved for undo, caller must have saved the +/// first line. +/// +/// @param avoid_fex don't use 'formatexpr' +void format_lines(linenr_T line_count, bool avoid_fex) +{ + bool is_not_par; // current line not part of parag. + bool next_is_not_par; // next line not part of paragraph + bool is_end_par; // at end of paragraph + bool prev_is_end_par = false; // prev. line not part of parag. + bool next_is_start_par = false; + int leader_len = 0; // leader len of current line + int next_leader_len; // leader len of next line + char_u *leader_flags = NULL; // flags for leader of current line + char_u *next_leader_flags = NULL; // flags for leader of next line + bool advance = true; + int second_indent = -1; // indent for second line (comment aware) + bool first_par_line = true; + int smd_save; + long count; + bool need_set_indent = true; // set indent of next paragraph + linenr_T first_line = curwin->w_cursor.lnum; + bool force_format = false; + const int old_State = State; + + // length of a line to force formatting: 3 * 'tw' + const int max_len = comp_textwidth(true) * 3; + + // check for 'q', '2' and '1' in 'formatoptions' + const bool do_comments = has_format_option(FO_Q_COMS); // format comments + int do_comments_list = 0; // format comments with 'n' or '2' + const bool do_second_indent = has_format_option(FO_Q_SECOND); + const bool do_number_indent = has_format_option(FO_Q_NUMBER); + const bool do_trail_white = has_format_option(FO_WHITE_PAR); + + // Get info about the previous and current line. + if (curwin->w_cursor.lnum > 1) { + is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1, + &leader_len, &leader_flags, do_comments); + } else { + is_not_par = true; + } + next_is_not_par = fmt_check_par(curwin->w_cursor.lnum, + &next_leader_len, &next_leader_flags, do_comments); + is_end_par = (is_not_par || next_is_not_par); + if (!is_end_par && do_trail_white) { + is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); + } + + curwin->w_cursor.lnum--; + for (count = line_count; count != 0 && !got_int; count--) { + // Advance to next paragraph. + if (advance) { + curwin->w_cursor.lnum++; + prev_is_end_par = is_end_par; + is_not_par = next_is_not_par; + leader_len = next_leader_len; + leader_flags = next_leader_flags; + } + + // The last line to be formatted. + if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) { + next_is_not_par = true; + next_leader_len = 0; + next_leader_flags = NULL; + } else { + next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1, + &next_leader_len, &next_leader_flags, do_comments); + if (do_number_indent) { + next_is_start_par = + (get_number_indent(curwin->w_cursor.lnum + 1) > 0); + } + } + advance = true; + is_end_par = (is_not_par || next_is_not_par || next_is_start_par); + if (!is_end_par && do_trail_white) { + is_end_par = !ends_in_white(curwin->w_cursor.lnum); + } + + // Skip lines that are not in a paragraph. + if (is_not_par) { + if (line_count < 0) { + break; + } + } else { + // For the first line of a paragraph, check indent of second line. + // Don't do this for comments and empty lines. + if (first_par_line + && (do_second_indent || do_number_indent) + && prev_is_end_par + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { + if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) { + if (leader_len == 0 && next_leader_len == 0) { + // no comment found + second_indent = + get_indent_lnum(curwin->w_cursor.lnum + 1); + } else { + second_indent = next_leader_len; + do_comments_list = 1; + } + } else if (do_number_indent) { + if (leader_len == 0 && next_leader_len == 0) { + // no comment found + second_indent = + get_number_indent(curwin->w_cursor.lnum); + } else { + // get_number_indent() is now "comment aware"... + second_indent = + get_number_indent(curwin->w_cursor.lnum); + do_comments_list = 1; + } + } + } + + // When the comment leader changes, it's the end of the paragraph. + if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count + || !same_leader(curwin->w_cursor.lnum, + leader_len, (char *)leader_flags, + next_leader_len, + (char *)next_leader_flags)) { + // Special case: If the next line starts with a line comment + // and this line has a line comment after some text, the + // paragraph doesn't really end. + if (next_leader_flags == NULL + || STRNCMP(next_leader_flags, "://", 3) != 0 + || check_linecomment(get_cursor_line_ptr()) == MAXCOL) { + is_end_par = true; + } + } + + // If we have got to the end of a paragraph, or the line is + // getting long, format it. + if (is_end_par || force_format) { + if (need_set_indent) { + int indent = 0; // amount of indent needed + + // Replace indent in first line of a paragraph with minimal + // number of tabs and spaces, according to current options. + // For the very first formatted line keep the current + // indent. + if (curwin->w_cursor.lnum == first_line) { + indent = get_indent(); + } else if (curbuf->b_p_lisp) { + indent = get_lisp_indent(); + } else { + if (cindent_on()) { + indent = *curbuf->b_p_inde != NUL ? get_expr_indent() : get_c_indent(); + } else { + indent = get_indent(); + } + } + (void)set_indent(indent, SIN_CHANGED); + } + + // put cursor on last non-space + State = MODE_NORMAL; // don't go past end-of-line + coladvance(MAXCOL); + while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) { + dec_cursor(); + } + + // do the formatting, without 'showmode' + State = MODE_INSERT; // for open_line() + smd_save = p_smd; + p_smd = false; + insertchar(NUL, INSCHAR_FORMAT + + (do_comments ? INSCHAR_DO_COM : 0) + + (do_comments && do_comments_list ? INSCHAR_COM_LIST : 0) + + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); + State = old_State; + p_smd = smd_save; + second_indent = -1; + // at end of par.: need to set indent of next par. + need_set_indent = is_end_par; + if (is_end_par) { + // When called with a negative line count, break at the + // end of the paragraph. + if (line_count < 0) { + break; + } + first_par_line = true; + } + force_format = false; + } + + // When still in same paragraph, join the lines together. But + // first delete the leader from the second line. + if (!is_end_par) { + advance = false; + curwin->w_cursor.lnum++; + curwin->w_cursor.col = 0; + if (line_count < 0 && u_save_cursor() == FAIL) { + break; + } + if (next_leader_len > 0) { + (void)del_bytes(next_leader_len, false, false); + mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L, + (long)-next_leader_len, 0); + } else if (second_indent > 0) { // the "leader" for FO_Q_SECOND + int indent = (int)getwhitecols_curline(); + + if (indent > 0) { + (void)del_bytes(indent, false, false); + mark_col_adjust(curwin->w_cursor.lnum, + (colnr_T)0, 0L, (long)-indent, 0); + } + } + curwin->w_cursor.lnum--; + if (do_join(2, true, false, false, false) == FAIL) { + beep_flush(); + break; + } + first_par_line = false; + // If the line is getting long, format it next time + if (strlen(get_cursor_line_ptr()) > (size_t)max_len) { + force_format = true; + } else { + force_format = false; + } + } + } + line_breakcheck(); + } +} diff --git a/src/nvim/textformat.h b/src/nvim/textformat.h new file mode 100644 index 0000000000..3c918a028b --- /dev/null +++ b/src/nvim/textformat.h @@ -0,0 +1,10 @@ +#ifndef NVIM_TEXTFORMAT_H +#define NVIM_TEXTFORMAT_H + +#include "nvim/normal.h" // for oparg_T +#include "nvim/pos.h" // for linenr_T + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "textformat.h.generated.h" +#endif +#endif // NVIM_TEXTFORMAT_H diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c new file mode 100644 index 0000000000..e6b330cbf1 --- /dev/null +++ b/src/nvim/textobject.c @@ -0,0 +1,1742 @@ +// 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 + +// textobject.c: functions for text objects + +#include <stdbool.h> + +#include "nvim/ascii.h" +#include "nvim/cursor.h" +#include "nvim/drawscreen.h" +#include "nvim/edit.h" +#include "nvim/eval/funcs.h" +#include "nvim/fold.h" +#include "nvim/globals.h" +#include "nvim/indent.h" +#include "nvim/mark.h" +#include "nvim/mbyte.h" +#include "nvim/memline.h" +#include "nvim/normal.h" +#include "nvim/pos.h" +#include "nvim/search.h" +#include "nvim/textformat.h" +#include "nvim/textobject.h" +#include "nvim/vim.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "textobject.c.generated.h" +#endif + +/// Find the start of the next sentence, searching in the direction specified +/// by the "dir" argument. The cursor is positioned on the start of the next +/// sentence when found. If the next sentence is found, return OK. Return FAIL +/// otherwise. See ":h sentence" for the precise definition of a "sentence" +/// text object. +int findsent(Direction dir, long count) +{ + pos_T pos, tpos; + int c; + int (*func)(pos_T *); + bool noskip = false; // do not skip blanks + + pos = curwin->w_cursor; + if (dir == FORWARD) { + func = incl; + } else { + func = decl; + } + + while (count--) { + const pos_T prev_pos = pos; + + // if on an empty line, skip up to a non-empty line + if (gchar_pos(&pos) == NUL) { + do { + if ((*func)(&pos) == -1) { + break; + } + } while (gchar_pos(&pos) == NUL); + if (dir == FORWARD) { + goto found; + } + // if on the start of a paragraph or a section and searching forward, + // go to the next line + } else if (dir == FORWARD && pos.col == 0 + && startPS(pos.lnum, NUL, false)) { + if (pos.lnum == curbuf->b_ml.ml_line_count) { + return FAIL; + } + pos.lnum++; + goto found; + } else if (dir == BACKWARD) { + decl(&pos); + } + + // go back to the previous non-white non-punctuation character + bool found_dot = false; + while (c = gchar_pos(&pos), ascii_iswhite(c) + || vim_strchr(".!?)]\"'", c) != NULL) { + tpos = pos; + if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD)) { + break; + } + if (found_dot) { + break; + } + if (vim_strchr(".!?", c) != NULL) { + found_dot = true; + } + if (vim_strchr(")]\"'", c) != NULL + && vim_strchr(".!?)]\"'", gchar_pos(&tpos)) == NULL) { + break; + } + decl(&pos); + } + + // remember the line where the search started + const int startlnum = pos.lnum; + const bool cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; + + for (;;) { // find end of sentence + c = gchar_pos(&pos); + if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, false))) { + if (dir == BACKWARD && pos.lnum != startlnum) { + pos.lnum++; + } + break; + } + if (c == '.' || c == '!' || c == '?') { + tpos = pos; + do { + if ((c = inc(&tpos)) == -1) { + break; + } + } while (vim_strchr(")]\"'", c = gchar_pos(&tpos)) + != NULL); + if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL + || (cpo_J && (c == ' ' && inc(&tpos) >= 0 + && gchar_pos(&tpos) == ' '))) { + pos = tpos; + if (gchar_pos(&pos) == NUL) { // skip NUL at EOL + inc(&pos); + } + break; + } + } + if ((*func)(&pos) == -1) { + if (count) { + return FAIL; + } + noskip = true; + break; + } + } +found: + // skip white space + while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) { + if (incl(&pos) == -1) { + break; + } + } + + if (equalpos(prev_pos, pos)) { + // didn't actually move, advance one character and try again + if ((*func)(&pos) == -1) { + if (count) { + return FAIL; + } + break; + } + count++; + } + } + + setpcmark(); + curwin->w_cursor = pos; + return OK; +} + +/// Find the next paragraph or section in direction 'dir'. +/// Paragraphs are currently supposed to be separated by empty lines. +/// If 'what' is NUL we go to the next paragraph. +/// If 'what' is '{' or '}' we go to the next section. +/// If 'both' is true also stop at '}'. +/// +/// @param pincl Return: true if last char is to be included +/// +/// @return true if the next paragraph or section was found. +bool findpar(bool *pincl, int dir, long count, int what, bool both) +{ + linenr_T curr; + bool did_skip; // true after separating lines have been skipped + bool first; // true on first line + linenr_T fold_first; // first line of a closed fold + linenr_T fold_last; // last line of a closed fold + bool fold_skipped; // true if a closed fold was skipped this + // iteration + + curr = curwin->w_cursor.lnum; + + while (count--) { + did_skip = false; + for (first = true;; first = false) { + if (*ml_get(curr) != NUL) { + did_skip = true; + } + + // skip folded lines + fold_skipped = false; + if (first && hasFolding(curr, &fold_first, &fold_last)) { + curr = ((dir > 0) ? fold_last : fold_first) + dir; + fold_skipped = true; + } + + if (!first && did_skip && startPS(curr, what, both)) { + break; + } + + if (fold_skipped) { + curr -= dir; + } + if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) { + if (count) { + return false; + } + curr -= dir; + break; + } + } + } + setpcmark(); + if (both && *ml_get(curr) == '}') { // include line with '}' + curr++; + } + curwin->w_cursor.lnum = curr; + if (curr == curbuf->b_ml.ml_line_count && what != '}') { + char_u *line = (char_u *)ml_get(curr); + + // Put the cursor on the last character in the last line and make the + // motion inclusive. + if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) { + curwin->w_cursor.col--; + curwin->w_cursor.col -= utf_head_off((char *)line, (char *)line + curwin->w_cursor.col); + *pincl = true; + } + } else { + curwin->w_cursor.col = 0; + } + return true; +} + +/// check if the string 's' is a nroff macro that is in option 'opt' +static bool inmacro(char_u *opt, char_u *s) +{ + char_u *macro; + + for (macro = opt; macro[0]; macro++) { + // Accept two characters in the option being equal to two characters + // in the line. A space in the option matches with a space in the + // line or the line having ended. + if ((macro[0] == s[0] + || (macro[0] == ' ' + && (s[0] == NUL || s[0] == ' '))) + && (macro[1] == s[1] + || ((macro[1] == NUL || macro[1] == ' ') + && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) { + break; + } + macro++; + if (macro[0] == NUL) { + break; + } + } + return macro[0] != NUL; +} + +/// startPS: return true if line 'lnum' is the start of a section or paragraph. +/// If 'para' is '{' or '}' only check for sections. +/// If 'both' is true also stop at '}' +bool startPS(linenr_T lnum, int para, bool both) +{ + char_u *s; + + s = (char_u *)ml_get(lnum); + if (*s == para || *s == '\f' || (both && *s == '}')) { + return true; + } + if (*s == '.' && (inmacro((char_u *)p_sections, s + 1) + || (!para && inmacro(p_para, s + 1)))) { + return true; + } + return false; +} + +// The following routines do the word searches performed by the 'w', 'W', +// 'b', 'B', 'e', and 'E' commands. + +// To perform these searches, characters are placed into one of three +// classes, and transitions between classes determine word boundaries. +// +// The classes are: +// +// 0 - white space +// 1 - punctuation +// 2 or higher - keyword characters (letters, digits and underscore) + +static bool cls_bigword; ///< true for "W", "B" or "E" + +/// cls() - returns the class of character at curwin->w_cursor +/// +/// If a 'W', 'B', or 'E' motion is being done (cls_bigword == true), chars +/// from class 2 and higher are reported as class 1 since only white space +/// boundaries are of interest. +static int cls(void) +{ + int c; + + c = gchar_cursor(); + if (c == ' ' || c == '\t' || c == NUL) { + return 0; + } + + c = utf_class(c); + + // If cls_bigword is true, report all non-blanks as class 1. + if (c != 0 && cls_bigword) { + return 1; + } + return c; +} + +/// fwd_word(count, type, eol) - move forward one word +/// +/// @return FAIL if the cursor was already at the end of the file. +/// If eol is true, last word stops at end of line (for operators). +/// +/// @param bigword "W", "E" or "B" +int fwd_word(long count, bool bigword, bool eol) +{ + int sclass; // starting class + int i; + int last_line; + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) { + // When inside a range of folded lines, move to the last char of the + // last line. + if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(MAXCOL); + } + sclass = cls(); + + // We always move at least one character, unless on the last + // character in the buffer. + last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); + i = inc_cursor(); + if (i == -1 || (i >= 1 && last_line)) { // started at last char in file + return FAIL; + } + if (i >= 1 && eol && count == 0) { // started at last char in line + return OK; + } + + // Go one char past end of current word (if any) + if (sclass != 0) { + while (cls() == sclass) { + i = inc_cursor(); + if (i == -1 || (i >= 1 && eol && count == 0)) { + return OK; + } + } + } + + // go to next non-white + while (cls() == 0) { + // We'll stop if we land on a blank line + if (curwin->w_cursor.col == 0 && *get_cursor_line_ptr() == NUL) { + break; + } + + i = inc_cursor(); + if (i == -1 || (i >= 1 && eol && count == 0)) { + return OK; + } + } + } + return OK; +} + +/// bck_word() - move backward 'count' words +/// +/// If stop is true and we are already on the start of a word, move one less. +/// +/// Returns FAIL if top of the file was reached. +int bck_word(long count, bool bigword, bool stop) +{ + int sclass; // starting class + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) { + // When inside a range of folded lines, move to the first char of the + // first line. + if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { + curwin->w_cursor.col = 0; + } + sclass = cls(); + if (dec_cursor() == -1) { // started at start of file + return FAIL; + } + + if (!stop || sclass == cls() || sclass == 0) { + // Skip white space before the word. + // Stop on an empty line. + while (cls() == 0) { + if (curwin->w_cursor.col == 0 + && LINEEMPTY(curwin->w_cursor.lnum)) { + goto finished; + } + if (dec_cursor() == -1) { // hit start of file, stop here + return OK; + } + } + + // Move backward to start of this word. + if (skip_chars(cls(), BACKWARD)) { + return OK; + } + } + + inc_cursor(); // overshot - forward one +finished: + stop = false; + } + return OK; +} + +/// end_word() - move to the end of the word +/// +/// There is an apparent bug in the 'e' motion of the real vi. At least on the +/// System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e' +/// motion crosses blank lines. When the real vi crosses a blank line in an +/// 'e' motion, the cursor is placed on the FIRST character of the next +/// non-blank line. The 'E' command, however, works correctly. Since this +/// appears to be a bug, I have not duplicated it here. +/// +/// Returns FAIL if end of the file was reached. +/// +/// If stop is true and we are already on the end of a word, move one less. +/// If empty is true stop on an empty line. +int end_word(long count, bool bigword, bool stop, bool empty) +{ + int sclass; // starting class + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) { + // When inside a range of folded lines, move to the last char of the + // last line. + if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(MAXCOL); + } + sclass = cls(); + if (inc_cursor() == -1) { + return FAIL; + } + + // If we're in the middle of a word, we just have to move to the end + // of it. + if (cls() == sclass && sclass != 0) { + // Move forward to end of the current word + if (skip_chars(sclass, FORWARD)) { + return FAIL; + } + } else if (!stop || sclass == 0) { + // We were at the end of a word. Go to the end of the next word. + // First skip white space, if 'empty' is true, stop at empty line. + while (cls() == 0) { + if (empty && curwin->w_cursor.col == 0 + && LINEEMPTY(curwin->w_cursor.lnum)) { + goto finished; + } + if (inc_cursor() == -1) { // hit end of file, stop here + return FAIL; + } + } + + // Move forward to the end of this word. + if (skip_chars(cls(), FORWARD)) { + return FAIL; + } + } + dec_cursor(); // overshot - one char backward +finished: + stop = false; // we move only one word less + } + return OK; +} + +/// Move back to the end of the word. +/// +/// @param bigword true for "B" +/// @param eol if true, then stop at end of line. +/// +/// @return FAIL if start of the file was reached. +int bckend_word(long count, bool bigword, bool eol) +{ + int sclass; // starting class + int i; + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) { + sclass = cls(); + if ((i = dec_cursor()) == -1) { + return FAIL; + } + if (eol && i == 1) { + return OK; + } + + // Move backward to before the start of this word. + if (sclass != 0) { + while (cls() == sclass) { + if ((i = dec_cursor()) == -1 || (eol && i == 1)) { + return OK; + } + } + } + + // Move backward to end of the previous word + while (cls() == 0) { + if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum)) { + break; + } + if ((i = dec_cursor()) == -1 || (eol && i == 1)) { + return OK; + } + } + } + return OK; +} + +/// Skip a row of characters of the same class. +/// +/// @return true when end-of-file reached, false otherwise. +static bool skip_chars(int cclass, int dir) +{ + while (cls() == cclass) { + if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) { + return true; + } + } + return false; +} + +/// Go back to the start of the word or the start of white space +static void back_in_line(void) +{ + int sclass; // starting class + + sclass = cls(); + for (;;) { + if (curwin->w_cursor.col == 0) { // stop at start of line + break; + } + dec_cursor(); + if (cls() != sclass) { // stop at start of word + inc_cursor(); + break; + } + } +} + +static void find_first_blank(pos_T *posp) +{ + int c; + + while (decl(posp) != -1) { + c = gchar_pos(posp); + if (!ascii_iswhite(c)) { + incl(posp); + break; + } + } +} + +/// Skip count/2 sentences and count/2 separating white spaces. +/// +/// @param at_start_sent cursor is at start of sentence +static void findsent_forward(long count, bool at_start_sent) +{ + while (count--) { + findsent(FORWARD, 1L); + if (at_start_sent) { + find_first_blank(&curwin->w_cursor); + } + if (count == 0 || at_start_sent) { + decl(&curwin->w_cursor); + } + at_start_sent = !at_start_sent; + } +} + +/// Find word under cursor, cursor at end. +/// Used while an operator is pending, and in Visual mode. +/// +/// @param include true: include word and white space +/// @param bigword false == word, true == WORD +int current_word(oparg_T *oap, long count, bool include, bool bigword) +{ + pos_T start_pos; + pos_T pos; + bool inclusive = true; + int include_white = false; + + cls_bigword = bigword; + clearpos(&start_pos); + + // Correct cursor when 'selection' is exclusive + if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) { + dec_cursor(); + } + + // When Visual mode is not active, or when the VIsual area is only one + // character, select the word and/or white space under the cursor. + if (!VIsual_active || equalpos(curwin->w_cursor, VIsual)) { + // Go to start of current word or white space. + back_in_line(); + start_pos = curwin->w_cursor; + + // If the start is on white space, and white space should be included + // (" word"), or start is not on white space, and white space should + // not be included ("word"), find end of word. + if ((cls() == 0) == include) { + if (end_word(1L, bigword, true, true) == FAIL) { + return FAIL; + } + } else { + // If the start is not on white space, and white space should be + // included ("word "), or start is on white space and white + // space should not be included (" "), find start of word. + // If we end up in the first column of the next line (single char + // word) back up to end of the line. + fwd_word(1L, bigword, true); + if (curwin->w_cursor.col == 0) { + decl(&curwin->w_cursor); + } else { + oneleft(); + } + + if (include) { + include_white = true; + } + } + + if (VIsual_active) { + // should do something when inclusive == false ! + VIsual = start_pos; + redraw_curbuf_later(UPD_INVERTED); // update the inversion + } else { + oap->start = start_pos; + oap->motion_type = kMTCharWise; + } + count--; + } + + // When count is still > 0, extend with more objects. + while (count > 0) { + inclusive = true; + if (VIsual_active && lt(curwin->w_cursor, VIsual)) { + // In Visual mode, with cursor at start: move cursor back. + if (decl(&curwin->w_cursor) == -1) { + return FAIL; + } + if (include != (cls() != 0)) { + if (bck_word(1L, bigword, true) == FAIL) { + return FAIL; + } + } else { + if (bckend_word(1L, bigword, true) == FAIL) { + return FAIL; + } + (void)incl(&curwin->w_cursor); + } + } else { + // Move cursor forward one word and/or white area. + if (incl(&curwin->w_cursor) == -1) { + return FAIL; + } + if (include != (cls() == 0)) { + if (fwd_word(1L, bigword, true) == FAIL && count > 1) { + return FAIL; + } + // If end is just past a new-line, we don't want to include + // the first character on the line. + // Put cursor on last char of white. + if (oneleft() == FAIL) { + inclusive = false; + } + } else { + if (end_word(1L, bigword, true, true) == FAIL) { + return FAIL; + } + } + } + count--; + } + + if (include_white && (cls() != 0 + || (curwin->w_cursor.col == 0 && !inclusive))) { + // If we don't include white space at the end, move the start + // to include some white space there. This makes "daw" work + // better on the last word in a sentence (and "2daw" on last-but-one + // word). Also when "2daw" deletes "word." at the end of the line + // (cursor is at start of next line). + // But don't delete white space at start of line (indent). + pos = curwin->w_cursor; // save cursor position + curwin->w_cursor = start_pos; + if (oneleft() == OK) { + back_in_line(); + if (cls() == 0 && curwin->w_cursor.col > 0) { + if (VIsual_active) { + VIsual = curwin->w_cursor; + } else { + oap->start = curwin->w_cursor; + } + } + } + curwin->w_cursor = pos; // put cursor back at end + } + + if (VIsual_active) { + if (*p_sel == 'e' && inclusive && ltoreq(VIsual, curwin->w_cursor)) { + inc_cursor(); + } + if (VIsual_mode == 'V') { + VIsual_mode = 'v'; + redraw_cmdline = true; // show mode later + } + } else { + oap->inclusive = inclusive; + } + + return OK; +} + +/// Find sentence(s) under the cursor, cursor at end. +/// When Visual active, extend it by one or more sentences. +int current_sent(oparg_T *oap, long count, bool include) +{ + pos_T start_pos; + pos_T pos; + bool start_blank; + int c; + bool at_start_sent; + long ncount; + + start_pos = curwin->w_cursor; + pos = start_pos; + findsent(FORWARD, 1L); // Find start of next sentence. + + // When the Visual area is bigger than one character: Extend it. + if (VIsual_active && !equalpos(start_pos, VIsual)) { +extend: + if (lt(start_pos, VIsual)) { + // Cursor at start of Visual area. + // Find out where we are: + // - in the white space before a sentence + // - in a sentence or just after it + // - at the start of a sentence + at_start_sent = true; + decl(&pos); + while (lt(pos, curwin->w_cursor)) { + c = gchar_pos(&pos); + if (!ascii_iswhite(c)) { + at_start_sent = false; + break; + } + incl(&pos); + } + if (!at_start_sent) { + findsent(BACKWARD, 1L); + if (equalpos(curwin->w_cursor, start_pos)) { + at_start_sent = true; // exactly at start of sentence + } else { + // inside a sentence, go to its end (start of next) + findsent(FORWARD, 1L); + } + } + if (include) { // "as" gets twice as much as "is" + count *= 2; + } + while (count--) { + if (at_start_sent) { + find_first_blank(&curwin->w_cursor); + } + c = gchar_cursor(); + if (!at_start_sent || (!include && !ascii_iswhite(c))) { + findsent(BACKWARD, 1L); + } + at_start_sent = !at_start_sent; + } + } else { + // Cursor at end of Visual area. + // Find out where we are: + // - just before a sentence + // - just before or in the white space before a sentence + // - in a sentence + incl(&pos); + at_start_sent = true; + if (!equalpos(pos, curwin->w_cursor)) { // not just before a sentence + at_start_sent = false; + while (lt(pos, curwin->w_cursor)) { + c = gchar_pos(&pos); + if (!ascii_iswhite(c)) { + at_start_sent = true; + break; + } + incl(&pos); + } + if (at_start_sent) { // in the sentence + findsent(BACKWARD, 1L); + } else { // in/before white before a sentence + curwin->w_cursor = start_pos; + } + } + + if (include) { // "as" gets twice as much as "is" + count *= 2; + } + findsent_forward(count, at_start_sent); + if (*p_sel == 'e') { + curwin->w_cursor.col++; + } + } + return OK; + } + + // If the cursor started on a blank, check if it is just before the start + // of the next sentence. + while (c = gchar_pos(&pos), ascii_iswhite(c)) { + incl(&pos); + } + if (equalpos(pos, curwin->w_cursor)) { + start_blank = true; + find_first_blank(&start_pos); // go back to first blank + } else { + start_blank = false; + findsent(BACKWARD, 1L); + start_pos = curwin->w_cursor; + } + if (include) { + ncount = count * 2; + } else { + ncount = count; + if (start_blank) { + ncount--; + } + } + if (ncount > 0) { + findsent_forward(ncount, true); + } else { + decl(&curwin->w_cursor); + } + + if (include) { + // If the blank in front of the sentence is included, exclude the + // blanks at the end of the sentence, go back to the first blank. + // If there are no trailing blanks, try to include leading blanks. + if (start_blank) { + find_first_blank(&curwin->w_cursor); + c = gchar_pos(&curwin->w_cursor); + if (ascii_iswhite(c)) { + decl(&curwin->w_cursor); + } + } else if (c = gchar_cursor(), !ascii_iswhite(c)) { + find_first_blank(&start_pos); + } + } + + if (VIsual_active) { + // Avoid getting stuck with "is" on a single space before a sentence. + if (equalpos(start_pos, curwin->w_cursor)) { + goto extend; + } + if (*p_sel == 'e') { + curwin->w_cursor.col++; + } + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_cmdline = true; // show mode later + redraw_curbuf_later(UPD_INVERTED); // update the inversion + } else { + // include a newline after the sentence, if there is one + if (incl(&curwin->w_cursor) == -1) { + oap->inclusive = true; + } else { + oap->inclusive = false; + } + oap->start = start_pos; + oap->motion_type = kMTCharWise; + } + return OK; +} + +/// Find block under the cursor, cursor at end. +/// "what" and "other" are two matching parenthesis/brace/etc. +/// +/// @param include true == include white space +/// @param what '(', '{', etc. +/// @param other ')', '}', etc. +int current_block(oparg_T *oap, long count, bool include, int what, int other) +{ + pos_T old_pos; + pos_T *pos = NULL; + pos_T start_pos; + pos_T *end_pos; + pos_T old_start, old_end; + char *save_cpo; + bool sol = false; // '{' at start of line + + old_pos = curwin->w_cursor; + old_end = curwin->w_cursor; // remember where we started + old_start = old_end; + + // If we start on '(', '{', ')', '}', etc., use the whole block inclusive. + if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) { + setpcmark(); + if (what == '{') { // ignore indent + while (inindent(1)) { + if (inc_cursor() != 0) { + break; + } + } + } + if (gchar_cursor() == what) { + // cursor on '(' or '{', move cursor just after it + curwin->w_cursor.col++; + } + } else if (lt(VIsual, curwin->w_cursor)) { + old_start = VIsual; + curwin->w_cursor = VIsual; // cursor at low end of Visual + } else { + old_end = VIsual; + } + + // Search backwards for unclosed '(', '{', etc.. + // Put this position in start_pos. + // Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the + // user wants. + save_cpo = p_cpo; + p_cpo = vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"; + if ((pos = findmatch(NULL, what)) != NULL) { + while (count-- > 0) { + if ((pos = findmatch(NULL, what)) == NULL) { + break; + } + curwin->w_cursor = *pos; + start_pos = *pos; // the findmatch for end_pos will overwrite *pos + } + } else { + while (count-- > 0) { + if ((pos = findmatchlimit(NULL, what, FM_FORWARD, 0)) == NULL) { + break; + } + curwin->w_cursor = *pos; + start_pos = *pos; // the findmatch for end_pos will overwrite *pos + } + } + p_cpo = save_cpo; + + // Search for matching ')', '}', etc. + // Put this position in curwin->w_cursor. + if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL) { + curwin->w_cursor = old_pos; + return FAIL; + } + curwin->w_cursor = *end_pos; + + // Try to exclude the '(', '{', ')', '}', etc. when "include" is false. + // If the ending '}', ')' or ']' is only preceded by indent, skip that + // indent. But only if the resulting area is not smaller than what we + // started with. + while (!include) { + incl(&start_pos); + sol = (curwin->w_cursor.col == 0); + decl(&curwin->w_cursor); + while (inindent(1)) { + sol = true; + if (decl(&curwin->w_cursor) != 0) { + break; + } + } + + // In Visual mode, when the resulting area is not bigger than what we + // started with, extend it to the next block, and then exclude again. + // Don't try to expand the area if the area is empty. + if (!lt(start_pos, old_start) && !lt(old_end, curwin->w_cursor) + && !equalpos(start_pos, curwin->w_cursor) + && VIsual_active) { + curwin->w_cursor = old_start; + decl(&curwin->w_cursor); + if ((pos = findmatch(NULL, what)) == NULL) { + curwin->w_cursor = old_pos; + return FAIL; + } + start_pos = *pos; + curwin->w_cursor = *pos; + if ((end_pos = findmatch(NULL, other)) == NULL) { + curwin->w_cursor = old_pos; + return FAIL; + } + curwin->w_cursor = *end_pos; + } else { + break; + } + } + + if (VIsual_active) { + if (*p_sel == 'e') { + inc(&curwin->w_cursor); + } + if (sol && gchar_cursor() != NUL) { + inc(&curwin->w_cursor); // include the line break + } + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_curbuf_later(UPD_INVERTED); // update the inversion + showmode(); + } else { + oap->start = start_pos; + oap->motion_type = kMTCharWise; + oap->inclusive = false; + if (sol) { + incl(&curwin->w_cursor); + } else if (ltoreq(start_pos, curwin->w_cursor)) { + // Include the character under the cursor. + oap->inclusive = true; + } else { + // End is before the start (no text in between <>, [], etc.): don't + // operate on any text. + curwin->w_cursor = start_pos; + } + } + + return OK; +} + +/// @param end_tag when true, return true if the cursor is on "</aaa>". +/// +/// @return true if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". +static bool in_html_tag(bool end_tag) +{ + char_u *line = (char_u *)get_cursor_line_ptr(); + char_u *p; + int c; + int lc = NUL; + pos_T pos; + + for (p = line + curwin->w_cursor.col; p > line;) { + if (*p == '<') { // find '<' under/before cursor + break; + } + MB_PTR_BACK(line, p); + if (*p == '>') { // find '>' before cursor + break; + } + } + if (*p != '<') { + return false; + } + + pos.lnum = curwin->w_cursor.lnum; + pos.col = (colnr_T)(p - line); + + MB_PTR_ADV(p); + if (end_tag) { + // check that there is a '/' after the '<' + return *p == '/'; + } + + // check that there is no '/' after the '<' + if (*p == '/') { + return false; + } + + // check that the matching '>' is not preceded by '/' + for (;;) { + if (inc(&pos) < 0) { + return false; + } + c = *ml_get_pos(&pos); + if (c == '>') { + break; + } + lc = c; + } + return lc != '/'; +} + +/// Find tag block under the cursor, cursor at end. +/// +/// @param include true == include white space +int current_tagblock(oparg_T *oap, long count_arg, bool include) +{ + long count = count_arg; + pos_T old_pos; + pos_T start_pos; + pos_T end_pos; + pos_T old_start, old_end; + char_u *p; + char_u *cp; + int len; + bool do_include = include; + bool save_p_ws = p_ws; + int retval = FAIL; + int is_inclusive = true; + + p_ws = false; + + old_pos = curwin->w_cursor; + old_end = curwin->w_cursor; // remember where we started + old_start = old_end; + if (!VIsual_active || *p_sel == 'e') { + decl(&old_end); // old_end is inclusive + } + + // If we start on "<aaa>" select that block. + if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) { + setpcmark(); + + // ignore indent + while (inindent(1)) { + if (inc_cursor() != 0) { + break; + } + } + + if (in_html_tag(false)) { + // cursor on start tag, move to its '>' + while (*get_cursor_pos_ptr() != '>') { + if (inc_cursor() < 0) { + break; + } + } + } else if (in_html_tag(true)) { + // cursor on end tag, move to just before it + while (*get_cursor_pos_ptr() != '<') { + if (dec_cursor() < 0) { + break; + } + } + dec_cursor(); + old_end = curwin->w_cursor; + } + } else if (lt(VIsual, curwin->w_cursor)) { + old_start = VIsual; + curwin->w_cursor = VIsual; // cursor at low end of Visual + } else { + old_end = VIsual; + } + +again: + // Search backwards for unclosed "<aaa>". + // Put this position in start_pos. + for (long n = 0; n < count; n++) { + if (do_searchpair("<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", + "", + "</[^>]*>", BACKWARD, NULL, 0, + NULL, (linenr_T)0, 0L) <= 0) { + curwin->w_cursor = old_pos; + goto theend; + } + } + start_pos = curwin->w_cursor; + + // Search for matching "</aaa>". First isolate the "aaa". + inc_cursor(); + p = (char_u *)get_cursor_pos_ptr(); + for (cp = p; + *cp != NUL && *cp != '>' && !ascii_iswhite(*cp); + MB_PTR_ADV(cp)) {} + len = (int)(cp - p); + if (len == 0) { + curwin->w_cursor = old_pos; + goto theend; + } + const size_t spat_len = (size_t)len + 39; + char *const spat = xmalloc(spat_len); + 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 = (int)do_searchpair(spat, "", epat, FORWARD, NULL, 0, NULL, (linenr_T)0, 0L); + + xfree(spat); + xfree(epat); + + if (r < 1 || lt(curwin->w_cursor, old_end)) { + // Can't find other end or it's before the previous end. Could be a + // HTML tag that doesn't have a matching end. Search backwards for + // another starting tag. + count = 1; + curwin->w_cursor = start_pos; + goto again; + } + + if (do_include) { + // Include up to the '>'. + while (*get_cursor_pos_ptr() != '>') { + if (inc_cursor() < 0) { + break; + } + } + } else { + char_u *c = (char_u *)get_cursor_pos_ptr(); + // Exclude the '<' of the end tag. + // If the closing tag is on new line, do not decrement cursor, but make + // operation exclusive, so that the linefeed will be selected + if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0) { + // do not decrement cursor + is_inclusive = false; + } else if (*c == '<') { + dec_cursor(); + } + } + end_pos = curwin->w_cursor; + + if (!do_include) { + // Exclude the start tag. + curwin->w_cursor = start_pos; + while (inc_cursor() >= 0) { + if (*get_cursor_pos_ptr() == '>') { + inc_cursor(); + start_pos = curwin->w_cursor; + break; + } + } + curwin->w_cursor = end_pos; + + // If we are in Visual mode and now have the same text as before set + // "do_include" and try again. + if (VIsual_active + && equalpos(start_pos, old_start) + && equalpos(end_pos, old_end)) { + do_include = true; + curwin->w_cursor = old_start; + count = count_arg; + goto again; + } + } + + if (VIsual_active) { + // If the end is before the start there is no text between tags, select + // the char under the cursor. + if (lt(end_pos, start_pos)) { + curwin->w_cursor = start_pos; + } else if (*p_sel == 'e') { + inc_cursor(); + } + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_curbuf_later(UPD_INVERTED); // update the inversion + showmode(); + } else { + oap->start = start_pos; + oap->motion_type = kMTCharWise; + if (lt(end_pos, start_pos)) { + // End is before the start: there is no text between tags; operate + // on an empty area. + curwin->w_cursor = start_pos; + oap->inclusive = false; + } else { + oap->inclusive = is_inclusive; + } + } + retval = OK; + +theend: + p_ws = save_p_ws; + return retval; +} + +/// @param include true == include white space +/// @param type 'p' for paragraph, 'S' for section +int current_par(oparg_T *oap, long count, bool include, int type) +{ + linenr_T start_lnum; + linenr_T end_lnum; + int white_in_front; + int dir; + int start_is_white; + int prev_start_is_white; + int retval = OK; + int do_white = false; + int t; + int i; + + if (type == 'S') { // not implemented yet + return FAIL; + } + + start_lnum = curwin->w_cursor.lnum; + + // When visual area is more than one line: extend it. + if (VIsual_active && start_lnum != VIsual.lnum) { +extend: + if (start_lnum < VIsual.lnum) { + dir = BACKWARD; + } else { + dir = FORWARD; + } + for (i = (int)count; --i >= 0;) { + if (start_lnum == + (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) { + retval = FAIL; + break; + } + + prev_start_is_white = -1; + for (t = 0; t < 2; t++) { + start_lnum += dir; + start_is_white = linewhite(start_lnum); + if (prev_start_is_white == start_is_white) { + start_lnum -= dir; + break; + } + for (;;) { + if (start_lnum == (dir == BACKWARD + ? 1 : curbuf->b_ml.ml_line_count)) { + break; + } + if (start_is_white != linewhite(start_lnum + dir) + || (!start_is_white + && startPS(start_lnum + (dir > 0 + ? 1 : 0), 0, 0))) { + break; + } + start_lnum += dir; + } + if (!include) { + break; + } + if (start_lnum == (dir == BACKWARD + ? 1 : curbuf->b_ml.ml_line_count)) { + break; + } + prev_start_is_white = start_is_white; + } + } + curwin->w_cursor.lnum = start_lnum; + curwin->w_cursor.col = 0; + return retval; + } + + // First move back to the start_lnum of the paragraph or white lines + white_in_front = linewhite(start_lnum); + while (start_lnum > 1) { + if (white_in_front) { // stop at first white line + if (!linewhite(start_lnum - 1)) { + break; + } + } else { // stop at first non-white line of start of paragraph + if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0)) { + break; + } + } + start_lnum--; + } + + // Move past the end of any white lines. + end_lnum = start_lnum; + while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum)) { + end_lnum++; + } + + end_lnum--; + i = (int)count; + if (!include && white_in_front) { + i--; + } + while (i--) { + if (end_lnum == curbuf->b_ml.ml_line_count) { + return FAIL; + } + + if (!include) { + do_white = linewhite(end_lnum + 1); + } + + if (include || !do_white) { + end_lnum++; + // skip to end of paragraph + while (end_lnum < curbuf->b_ml.ml_line_count + && !linewhite(end_lnum + 1) + && !startPS(end_lnum + 1, 0, 0)) { + end_lnum++; + } + } + + if (i == 0 && white_in_front && include) { + break; + } + + // skip to end of white lines after paragraph + if (include || do_white) { + while (end_lnum < curbuf->b_ml.ml_line_count + && linewhite(end_lnum + 1)) { + end_lnum++; + } + } + } + + // If there are no empty lines at the end, try to find some empty lines at + // the start (unless that has been done already). + if (!white_in_front && !linewhite(end_lnum) && include) { + while (start_lnum > 1 && linewhite(start_lnum - 1)) { + start_lnum--; + } + } + + if (VIsual_active) { + // Problem: when doing "Vipipip" nothing happens in a single white + // line, we get stuck there. Trap this here. + if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) { + goto extend; + } + if (VIsual.lnum != start_lnum) { + VIsual.lnum = start_lnum; + VIsual.col = 0; + } + VIsual_mode = 'V'; + redraw_curbuf_later(UPD_INVERTED); // update the inversion + showmode(); + } else { + oap->start.lnum = start_lnum; + oap->start.col = 0; + oap->motion_type = kMTLineWise; + } + curwin->w_cursor.lnum = end_lnum; + curwin->w_cursor.col = 0; + + return OK; +} + +/// Search quote char from string line[col]. +/// Quote character escaped by one of the characters in "escape" is not counted +/// as a quote. +/// +/// @param escape escape characters, can be NULL +/// +/// @return column number of "quotechar" or -1 when not found. +static int find_next_quote(char_u *line, int col, int quotechar, char_u *escape) +{ + int c; + + for (;;) { + c = line[col]; + if (c == NUL) { + return -1; + } else if (escape != NULL && vim_strchr((char *)escape, c)) { + col++; + if (line[col] == NUL) { + return -1; + } + } else if (c == quotechar) { + break; + } + col += utfc_ptr2len((char *)line + col); + } + return col; +} + +/// Search backwards in "line" from column "col_start" to find "quotechar". +/// Quote character escaped by one of the characters in "escape" is not counted +/// as a quote. +/// +/// @param escape escape characters, can be NULL +/// +/// @return the found column or zero. +static int find_prev_quote(char_u *line, int col_start, int quotechar, char_u *escape) +{ + int n; + + while (col_start > 0) { + col_start--; + col_start -= utf_head_off((char *)line, (char *)line + col_start); + n = 0; + if (escape != NULL) { + while (col_start - n > 0 && vim_strchr((char *)escape, + line[col_start - n - 1]) != NULL) { + n++; + } + } + if (n & 1) { + col_start -= n; // uneven number of escape chars, skip it + } else if (line[col_start] == quotechar) { + break; + } + } + return col_start; +} + +/// Find quote under the cursor, cursor at end. +/// +/// @param include true == include quote char +/// @param quotechar Quote character +/// +/// @return true if found, else false. +bool current_quote(oparg_T *oap, long count, bool include, int quotechar) + FUNC_ATTR_NONNULL_ALL +{ + char_u *line = (char_u *)get_cursor_line_ptr(); + int col_end; + int col_start = curwin->w_cursor.col; + bool inclusive = false; + bool vis_empty = true; // Visual selection <= 1 char + bool vis_bef_curs = false; // Visual starts before cursor + bool did_exclusive_adj = false; // adjusted pos for 'selection' + bool inside_quotes = false; // Looks like "i'" done before + bool selected_quote = false; // Has quote inside selection + int i; + bool restore_vis_bef = false; // restore VIsual on abort + + // When 'selection' is "exclusive" move the cursor to where it would be + // with 'selection' "inclusive", so that the logic is the same for both. + // The cursor then is moved forward after adjusting the area. + if (VIsual_active) { + // this only works within one line + if (VIsual.lnum != curwin->w_cursor.lnum) { + return false; + } + + vis_bef_curs = lt(VIsual, curwin->w_cursor); + vis_empty = equalpos(VIsual, curwin->w_cursor); + if (*p_sel == 'e') { + if (vis_bef_curs) { + dec_cursor(); + did_exclusive_adj = true; + } else if (!vis_empty) { + dec(&VIsual); + did_exclusive_adj = true; + } + vis_empty = equalpos(VIsual, curwin->w_cursor); + if (!vis_bef_curs && !vis_empty) { + // VIsual needs to be start of Visual selection. + pos_T t = curwin->w_cursor; + + curwin->w_cursor = VIsual; + VIsual = t; + vis_bef_curs = true; + restore_vis_bef = true; + } + } + } + + if (!vis_empty) { + // Check if the existing selection exactly spans the text inside + // quotes. + if (vis_bef_curs) { + inside_quotes = VIsual.col > 0 + && line[VIsual.col - 1] == quotechar + && line[curwin->w_cursor.col] != NUL + && line[curwin->w_cursor.col + 1] == quotechar; + i = VIsual.col; + col_end = curwin->w_cursor.col; + } else { + inside_quotes = curwin->w_cursor.col > 0 + && line[curwin->w_cursor.col - 1] == quotechar + && line[VIsual.col] != NUL + && line[VIsual.col + 1] == quotechar; + i = curwin->w_cursor.col; + col_end = VIsual.col; + } + + // Find out if we have a quote in the selection. + while (i <= col_end) { + // check for going over the end of the line, which can happen if + // the line was changed after the Visual area was selected. + if (line[i] == NUL) { + break; + } + if (line[i++] == quotechar) { + selected_quote = true; + break; + } + } + } + + if (!vis_empty && line[col_start] == quotechar) { + // Already selecting something and on a quote character. Find the + // next quoted string. + if (vis_bef_curs) { + // Assume we are on a closing quote: move to after the next + // opening quote. + col_start = find_next_quote(line, col_start + 1, quotechar, NULL); + if (col_start < 0) { + goto abort_search; + } + col_end = find_next_quote(line, col_start + 1, quotechar, (char_u *)curbuf->b_p_qe); + if (col_end < 0) { + // We were on a starting quote perhaps? + col_end = col_start; + col_start = curwin->w_cursor.col; + } + } else { + col_end = find_prev_quote(line, col_start, quotechar, NULL); + if (line[col_end] != quotechar) { + goto abort_search; + } + col_start = find_prev_quote(line, col_end, quotechar, (char_u *)curbuf->b_p_qe); + if (line[col_start] != quotechar) { + // We were on an ending quote perhaps? + col_start = col_end; + col_end = curwin->w_cursor.col; + } + } + } else if (line[col_start] == quotechar || !vis_empty) { + int first_col = col_start; + + if (!vis_empty) { + if (vis_bef_curs) { + first_col = find_next_quote(line, col_start, quotechar, NULL); + } else { + first_col = find_prev_quote(line, col_start, quotechar, NULL); + } + } + // The cursor is on a quote, we don't know if it's the opening or + // closing quote. Search from the start of the line to find out. + // Also do this when there is a Visual area, a' may leave the cursor + // in between two strings. + col_start = 0; + for (;;) { + // Find open quote character. + col_start = find_next_quote(line, col_start, quotechar, NULL); + if (col_start < 0 || col_start > first_col) { + goto abort_search; + } + // Find close quote character. + col_end = find_next_quote(line, col_start + 1, quotechar, (char_u *)curbuf->b_p_qe); + if (col_end < 0) { + goto abort_search; + } + // If is cursor between start and end quote character, it is + // target text object. + if (col_start <= first_col && first_col <= col_end) { + break; + } + col_start = col_end + 1; + } + } else { + // Search backward for a starting quote. + col_start = find_prev_quote(line, col_start, quotechar, (char_u *)curbuf->b_p_qe); + if (line[col_start] != quotechar) { + // No quote before the cursor, look after the cursor. + col_start = find_next_quote(line, col_start, quotechar, NULL); + if (col_start < 0) { + goto abort_search; + } + } + + // Find close quote character. + col_end = find_next_quote(line, col_start + 1, quotechar, (char_u *)curbuf->b_p_qe); + if (col_end < 0) { + goto abort_search; + } + } + + // When "include" is true, include spaces after closing quote or before + // the starting quote. + if (include) { + if (ascii_iswhite(line[col_end + 1])) { + while (ascii_iswhite(line[col_end + 1])) { + col_end++; + } + } else { + while (col_start > 0 && ascii_iswhite(line[col_start - 1])) { + col_start--; + } + } + } + + // Set start position. After vi" another i" must include the ". + // For v2i" include the quotes. + if (!include && count < 2 && (vis_empty || !inside_quotes)) { + col_start++; + } + curwin->w_cursor.col = col_start; + if (VIsual_active) { + // Set the start of the Visual area when the Visual area was empty, we + // were just inside quotes or the Visual area didn't start at a quote + // and didn't include a quote. + if (vis_empty + || (vis_bef_curs + && !selected_quote + && (inside_quotes + || (line[VIsual.col] != quotechar + && (VIsual.col == 0 + || line[VIsual.col - 1] != quotechar))))) { + VIsual = curwin->w_cursor; + redraw_curbuf_later(UPD_INVERTED); + } + } else { + oap->start = curwin->w_cursor; + oap->motion_type = kMTCharWise; + } + + // Set end position. + curwin->w_cursor.col = col_end; + if ((include || count > 1 + // After vi" another i" must include the ". + || (!vis_empty && inside_quotes)) && inc_cursor() == 2) { + inclusive = true; + } + if (VIsual_active) { + if (vis_empty || vis_bef_curs) { + // decrement cursor when 'selection' is not exclusive + if (*p_sel != 'e') { + dec_cursor(); + } + } else { + // Cursor is at start of Visual area. Set the end of the Visual + // area when it was just inside quotes or it didn't end at a + // quote. + if (inside_quotes + || (!selected_quote + && line[VIsual.col] != quotechar + && (line[VIsual.col] == NUL + || line[VIsual.col + 1] != quotechar))) { + dec_cursor(); + VIsual = curwin->w_cursor; + } + curwin->w_cursor.col = col_start; + } + if (VIsual_mode == 'V') { + VIsual_mode = 'v'; + redraw_cmdline = true; // show mode later + } + } else { + // Set inclusive and other oap's flags. + oap->inclusive = inclusive; + } + + return true; + +abort_search: + if (VIsual_active && *p_sel == 'e') { + if (did_exclusive_adj) { + inc_cursor(); + } + if (restore_vis_bef) { + pos_T t = curwin->w_cursor; + + curwin->w_cursor = VIsual; + VIsual = t; + } + } + return false; +} diff --git a/src/nvim/textobject.h b/src/nvim/textobject.h new file mode 100644 index 0000000000..26f88613fd --- /dev/null +++ b/src/nvim/textobject.h @@ -0,0 +1,11 @@ +#ifndef NVIM_TEXTOBJECT_H +#define NVIM_TEXTOBJECT_H + +#include "nvim/normal.h" // for oparg_T +#include "nvim/pos.h" // for linenr_T +#include "nvim/vim.h" // for Direction + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "textobject.h.generated.h" +#endif +#endif // NVIM_TEXTOBJECT_H diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 61a59bcf06..fbeca26274 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -15,7 +15,7 @@ #include "nvim/tui/input.h" #include "nvim/tui/tui.h" #include "nvim/vim.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/os_win_console.h" #endif #include "nvim/event/rstream.h" @@ -143,7 +143,7 @@ void tinput_init(TermInput *input, Loop *loop) // If stdin is not a pty, switch to stderr. For cases like: // echo q | nvim -es // ls *.md | xargs nvim -#ifdef WIN32 +#ifdef MSWIN if (!os_isatty(input->in_fd)) { input->in_fd = os_get_conin_fd(); } @@ -159,14 +159,10 @@ void tinput_init(TermInput *input, Loop *loop) term = ""; // termkey_new_abstract assumes non-null (#2745) } -#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART); termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL); termkey_start(input->tk); -#else - input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8); -#endif int curflags = termkey_get_canonflags(input->tk); termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); @@ -233,12 +229,12 @@ static void tinput_wait_enqueue(void **argv) if (ui_client_channel_id) { Array args = ARRAY_DICT_INIT; Error err = ERROR_INIT; - ADD(args, STRING_OBJ(copy_string(keys))); + ADD(args, STRING_OBJ(copy_string(keys, NULL))); // TODO(bfredl): could be non-blocking now with paste? ArenaMem res_mem = NULL; Object result = rpc_send_call(ui_client_channel_id, "nvim_input", args, &res_mem, &err); consumed = result.type == kObjectTypeInteger ? (size_t)result.data.integer : 0; - arena_mem_free(res_mem, NULL); + arena_mem_free(res_mem); } else { consumed = input_enqueue(keys); } @@ -398,8 +394,16 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) button = last_pressed_button; } - if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG - && ev != TERMKEY_MOUSE_RELEASE)) { + if (ev == TERMKEY_MOUSE_UNKNOWN && !(key->code.mouse[0] & 0x20)) { + int code = key->code.mouse[0] & ~0x3c; + if (code == 66 || code == 67) { + ev = TERMKEY_MOUSE_PRESS; + button = code - 60; + } + } + + if ((button == 0 && ev != TERMKEY_MOUSE_RELEASE) + || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG && ev != TERMKEY_MOUSE_RELEASE)) { return; } @@ -431,8 +435,11 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) if (button == 4) { len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp"); } else if (button == 5) { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, - "ScrollWheelDown"); + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelDown"); + } else if (button == 6) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelLeft"); + } else if (button == 7) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelRight"); } else { len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse"); last_pressed_button = button; @@ -442,7 +449,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag"); break; case TERMKEY_MOUSE_RELEASE: - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release"); + len += (size_t)snprintf(buf + len, sizeof(buf) - len, button ? "Release" : "MouseMove"); + last_pressed_button = 0; break; case TERMKEY_MOUSE_UNKNOWN: abort(); diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 51df57938c..0b60394850 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -26,9 +26,7 @@ typedef struct term_input { ExtkeysType extkeys_type; long ttimeoutlen; TermKey *tk; -#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook -#endif TimeWatcher timer_handle; Loop *loop; Stream read_stream; diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index ce48059b94..229e340dc3 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -189,7 +189,7 @@ void terminfo_info_msg(const unibi_term *const ut) msg_printf_attr(0, " %-25s %-10s = ", unibi_name_str(i), unibi_short_name_str(i)); // Most of these strings will contain escape sequences. - msg_outtrans_special((char_u *)s, false, 0); + msg_outtrans_special(s, false, 0); msg_putchar('\n'); } } @@ -216,7 +216,7 @@ void terminfo_info_msg(const unibi_term *const ut) msg_puts("Extended string capabilities:\n"); for (size_t i = 0; i < unibi_count_ext_str(ut); i++) { msg_printf_attr(0, " %-25s = ", unibi_get_ext_str_name(ut, i)); - msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false, 0); + msg_outtrans_special(unibi_get_ext_str(ut, i), false, 0); msg_putchar('\n'); } } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 38e8c15762..1cb1c34ad3 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -13,13 +13,13 @@ # include <termios.h> #endif +#include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/ascii.h" #include "nvim/event/loop.h" #include "nvim/event/signal.h" #include "nvim/highlight.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/map.h" @@ -31,7 +31,7 @@ #include "nvim/os/tty.h" #include "nvim/ui.h" #include "nvim/vim.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/os_win_console.h" #endif #include "nvim/cursor_shape.h" @@ -103,6 +103,7 @@ struct TUIData { bool immediate_wrap_after_last_column; bool bce; bool mouse_enabled; + bool mouse_move_enabled; bool busy, is_invisible, want_invisible; bool cork, overflow; bool cursor_color_changed; @@ -117,6 +118,7 @@ struct TUIData { ModeShape showing_mode; struct { int enable_mouse, disable_mouse; + int enable_mouse_move, disable_mouse_move; int enable_bracketed_paste, disable_bracketed_paste; int enable_lr_margin, disable_lr_margin; int enter_strikethrough_mode; @@ -236,6 +238,8 @@ static void terminfo_start(UI *ui) data->showing_mode = SHAPE_IDX_N; data->unibi_ext.enable_mouse = -1; data->unibi_ext.disable_mouse = -1; + data->unibi_ext.enable_mouse_move = -1; + data->unibi_ext.disable_mouse_move = -1; data->unibi_ext.set_cursor_color = -1; data->unibi_ext.reset_cursor_color = -1; data->unibi_ext.enable_bracketed_paste = -1; @@ -259,7 +263,7 @@ static void terminfo_start(UI *ui) data->input.tui_data = data; const char *term = os_getenv("TERM"); -#ifdef WIN32 +#ifdef MSWIN os_tty_guess_term(&term, data->out_fd); os_setenv("TERM", term, 1); // Old os_getenv() pointer is invalid after os_setenv(), fetch it again. @@ -349,7 +353,7 @@ static void terminfo_start(UI *ui) if (ret) { ELOG("uv_tty_init failed: %s", uv_strerror(ret)); } -#ifdef WIN32 +#ifdef MSWIN ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW); if (ret) { ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret)); @@ -481,9 +485,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui) // TODO(bfredl): zero hl is empty, send this explicitly? kv_push(data->attrs, HLATTRS_INIT); -#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 data->input.tk_ti_hook_fn = tui_tk_ti_getstr; -#endif tinput_init(&data->input, &tui_loop); tui_terminal_start(ui); @@ -1138,6 +1140,9 @@ static void tui_mouse_on(UI *ui) TUIData *data = ui->data; if (!data->mouse_enabled) { unibi_out_ext(ui, data->unibi_ext.enable_mouse); + if (data->mouse_move_enabled) { + unibi_out_ext(ui, data->unibi_ext.enable_mouse_move); + } data->mouse_enabled = true; } } @@ -1146,6 +1151,9 @@ static void tui_mouse_off(UI *ui) { TUIData *data = ui->data; if (data->mouse_enabled) { + if (data->mouse_move_enabled) { + unibi_out_ext(ui, data->unibi_ext.disable_mouse_move); + } unibi_out_ext(ui, data->unibi_ext.disable_mouse); data->mouse_enabled = false; } @@ -1405,13 +1413,16 @@ static void suspend_event(void **argv) static void tui_suspend(UI *ui) { -#ifdef UNIX TUIData *data = ui->data; +#ifdef UNIX // kill(0, SIGTSTP) won't stop the UI thread, so we must poll for SIGCONT // before continuing. This is done in another callback to avoid // loop_poll_events recursion multiqueue_put_event(data->loop->fast_events, event_create(suspend_event, 1, ui)); +#else + // Resume the main thread as suspending isn't implemented. + CONTINUE(data->bridge); #endif } @@ -1457,9 +1468,18 @@ static void tui_screenshot(UI *ui, String path) static void tui_option_set(UI *ui, String name, Object value) { TUIData *data = ui->data; - if (strequal(name.data, "termguicolors")) { + if (strequal(name.data, "mousemoveevent")) { + if (data->mouse_move_enabled != value.data.boolean) { + if (data->mouse_enabled) { + tui_mouse_off(ui); + data->mouse_move_enabled = value.data.boolean; + tui_mouse_on(ui); + } else { + data->mouse_move_enabled = value.data.boolean; + } + } + } else if (strequal(name.data, "termguicolors")) { ui->rgb = value.data.boolean; - data->print_attr_id = -1; invalidate(ui, 0, data->grid.height, 0, data->grid.width); } else if (strequal(name.data, "ttimeout")) { @@ -1597,7 +1617,7 @@ static void unibi_goto(UI *ui, int row, int col) memset(&vars, 0, sizeof(vars)); \ data->cork = true; \ retry: \ - unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL); \ + unibi_format(vars, vars + 26, str, data->params, out, ui, pad, ui); \ if (data->overflow) { \ data->bufpos = orig_pos; \ flush_buf(ui); \ @@ -1628,6 +1648,7 @@ static void out(void *ctx, const char *str, size_t len) if (len > available) { if (data->cork) { + // Called by unibi_format(): avoid flush_buf() halfway an escape sequence. data->overflow = true; return; } else { @@ -1639,6 +1660,30 @@ static void out(void *ctx, const char *str, size_t len) data->bufpos += len; } +/// Called by unibi_format() for padding instructions. +/// The following parameter descriptions are extracted from unibi_format(3) and terminfo(5). +/// +/// @param ctx the same as `ctx2` passed to unibi_format() +/// @param delay the delay in tenths of milliseconds +/// @param scale padding is proportional to the number of lines affected +/// @param force padding is mandatory +static void pad(void *ctx, size_t delay, int scale FUNC_ATTR_UNUSED, int force) +{ + if (!force) { + return; + } + + UI *ui = ctx; + TUIData *data = ui->data; + + if (data->overflow) { + return; + } + + flush_buf(ui); + loop_uv_run(data->loop, (int)(delay / 10), false); +} + static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str, const char *val) { if (!unibi_get_str(ut, str)) { @@ -1791,7 +1836,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col } } -#ifdef WIN32 +#ifdef MSWIN // XXX: workaround libuv implicit LF => CRLF conversion. #10558 unibi_set_str(ut, unibi_cursor_down, "\x1b[B"); #endif @@ -2135,13 +2180,17 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version, "\x1b[?1002h\x1b[?1006h"); data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse", "\x1b[?1002l\x1b[?1006l"); + data->unibi_ext.enable_mouse_move = (int)unibi_add_ext_str(ut, "ext.enable_mouse_move", + "\x1b[?1003h"); + data->unibi_ext.disable_mouse_move = (int)unibi_add_ext_str(ut, "ext.disable_mouse_move", + "\x1b[?1003l"); // Extended underline. // terminfo will have Smulx for this (but no support for colors yet). data->unibi_ext.set_underline_style = unibi_find_ext_str(ut, "Smulx"); if (data->unibi_ext.set_underline_style == -1) { int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty - if (vte_version >= 5102 + if (vte_version >= 5102 || konsolev >= 221170 || (ext_bool_Su != -1 && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) { data->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style", @@ -2230,7 +2279,6 @@ static void flush_buf(UI *ui) data->overflow = false; } -#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 /// Try to get "kbs" code from stty because "the terminfo kbs entry is extremely /// unreliable." (Vim, Bash, and tmux also do this.) /// @@ -2239,14 +2287,14 @@ static void flush_buf(UI *ui) static const char *tui_get_stty_erase(void) { static char stty_erase[2] = { 0 }; -# if defined(HAVE_TERMIOS_H) +#if defined(HAVE_TERMIOS_H) struct termios t; if (tcgetattr(input_global_fd(), &t) != -1) { stty_erase[0] = (char)t.c_cc[VERASE]; stty_erase[1] = '\0'; DLOG("stty/termios:erase=%s", stty_erase); } -# endif +#endif return stty_erase; } @@ -2280,4 +2328,3 @@ static const char *tui_tk_ti_getstr(const char *name, const char *value, void *d return value; } -#endif diff --git a/src/nvim/types.h b/src/nvim/types.h index 477102276c..fb10bf21d9 100644 --- a/src/nvim/types.h +++ b/src/nvim/types.h @@ -22,7 +22,16 @@ typedef int handle_T; // absent callback etc. typedef int LuaRef; -typedef void (*FunPtr)(void); +/// Type used for VimL VAR_FLOAT values +typedef double float_T; + +typedef struct MsgpackRpcRequestHandler MsgpackRpcRequestHandler; + +typedef union { + float_T (*float_func)(float_T); + const MsgpackRpcRequestHandler *api_handler; + void *nullptr; +} EvalFuncData; typedef handle_T NS; diff --git a/src/nvim/ui.c b/src/nvim/ui.c index da671a3ad1..2c9510bf34 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -198,13 +198,16 @@ void ui_refresh(void) ext_widgets[i] = true; } + UI *compositor = uis[0]; + bool inclusive = ui_override(); - for (size_t i = 0; i < ui_count; i++) { + for (size_t i = 1; i < ui_count; i++) { UI *ui = uis[i]; width = MIN(ui->width, width); height = MIN(ui->height, height); for (UIExtension j = 0; (int)j < kUIExtCount; j++) { - ext_widgets[j] &= (ui->ui_ext[j] || inclusive); + bool in_compositor = ui->composed && compositor->ui_ext[j]; + ext_widgets[j] &= (ui->ui_ext[j] || in_compositor || inclusive); } } @@ -336,7 +339,7 @@ void vim_beep(unsigned val) // When 'debug' contains "beep" produce a message. If we are sourcing // a script or executing a function give the user a hint where the beep // comes from. - if (vim_strchr((char *)p_debug, 'e') != NULL) { + if (vim_strchr(p_debug, 'e') != NULL) { msg_source(HL_ATTR(HLF_W)); msg_attr(_("Beep!"), HL_ATTR(HLF_W)); } @@ -507,7 +510,7 @@ void ui_flush(void) return; } cmdline_ui_flush(); - win_ui_flush(); + win_ui_flush(false); msg_ext_ui_flush(); msg_scroll_flush(); @@ -517,11 +520,10 @@ void ui_flush(void) } if (pending_mode_info_update) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array style = mode_style_array(&arena); bool enabled = (*p_guicursor != NUL); ui_call_mode_info_set(enabled, style); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); pending_mode_info_update = false; } if (pending_mode_update && !starting) { @@ -566,7 +568,7 @@ void ui_check_mouse(void) // - 'a' is in 'mouse' and "c" is in MOUSE_A, or // - the current buffer is a help file and 'h' is in 'mouse' and we are in a // normal editing mode (not at hit-return message). - for (char_u *p = p_mouse; *p; p++) { + for (char *p = p_mouse; *p; p++) { switch (*p) { case 'a': if (vim_strchr(MOUSE_A, checkfor) != NULL) { @@ -612,12 +614,6 @@ 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.h b/src/nvim/ui.h index 7dd2f5bce3..9034e7b764 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -47,8 +47,6 @@ enum { typedef int LineFlags; -EXTERN ArenaMem ui_ext_fixblk INIT(= NULL); - struct ui_t { bool rgb; bool override; ///< Force highest-requested UI capabilities. @@ -71,6 +69,11 @@ struct ui_t { void (*inspect)(UI *ui, Dictionary *info); }; +typedef struct ui_event_callback { + LuaRef cb; + bool ext_widgets[kUIGlobalCount]; +} UIEventCallback; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui.h.generated.h" diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index 84098e9476..809d278029 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -194,9 +194,9 @@ static void ui_bridge_suspend_event(void **argv) static void ui_bridge_option_set(UI *ui, String name, Object value) { - String copy_name = copy_string(name); + String copy_name = copy_string(name, NULL); Object *copy_value = xmalloc(sizeof(Object)); - *copy_value = copy_object(value); + *copy_value = copy_object(value, NULL); UI_BRIDGE_CALL(ui, option_set, 4, ui, copy_name.data, INT2PTR(copy_name.size), copy_value); // TODO(bfredl): when/if TUI/bridge teardown is refactored to use events, the diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index a586fec3bf..265c54f72d 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -55,7 +55,7 @@ UIClientHandler ui_client_get_redraw_handler(const char *name, size_t name_len, /// 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) +Object handle_ui_client_redraw(uint64_t channel_id, Array args, Arena *arena, Error *error) { api_set_error(error, kErrorTypeValidation, "'redraw' cannot be sent as a request"); return NIL; diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 2216e25db9..47c83b8ed1 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -11,15 +11,16 @@ #include <stdbool.h> #include <stdio.h> +#include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" -#include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/lua/executor.h" #include "nvim/main.h" +#include "nvim/map.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/os/os.h" @@ -54,6 +55,8 @@ static bool msg_was_scrolled = false; static int msg_sep_row = -1; static schar_T msg_sep_char = { ' ', NUL }; +static PMap(uint32_t) ui_event_cbs = MAP_INIT; + static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose; void ui_comp_init(void) @@ -69,14 +72,18 @@ void ui_comp_init(void) compositor->grid_cursor_goto = ui_comp_grid_cursor_goto; compositor->raw_line = ui_comp_raw_line; compositor->msg_set_pos = ui_comp_msg_set_pos; + compositor->event = ui_comp_event; // Be unopinionated: will be attached together with a "real" ui anyway compositor->width = INT_MAX; compositor->height = INT_MAX; - for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + for (UIExtension i = kUIGlobalCount; (int)i < kUIExtCount; i++) { compositor->ui_ext[i] = true; } + // TODO(bfredl): one day. in the future. + compositor->ui_ext[kUIMultigrid] = false; + // TODO(bfredl): this will be more complicated if we implement // hlstate per UI (i e reduce hl ids for non-hlstate UIs) compositor->ui_ext[kUIHlState] = false; @@ -87,6 +94,15 @@ void ui_comp_init(void) ui_attach_impl(compositor, 0); } +void ui_comp_free_all_mem(void) +{ + UIEventCallback *event_cb; + map_foreach_value(&ui_event_cbs, event_cb, { + free_ui_event_callback(event_cb); + }) + pmap_destroy(uint32_t)(&ui_event_cbs); +} + void ui_comp_syn_init(void) { dbghl_normal = syn_check_group(S_LEN("RedrawDebugNormal")); @@ -122,7 +138,7 @@ bool ui_comp_should_draw(void) /// /// TODO(bfredl): later on the compositor should just use win_float_pos events, /// though that will require slight event order adjustment: emit the win_pos -/// events in the beginning of update_screen(0), rather than in ui_flush() +/// events in the beginning of update_screen(), rather than in ui_flush() bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width, bool valid, bool on_top) { @@ -469,6 +485,10 @@ static void compose_debug(Integer startrow, Integer endrow, Integer startcol, In endcol = MIN(endcol, default_grid.cols); int attr = syn_id2attr(syn_id); + if (delay) { + debug_delay(endrow - startrow); + } + for (int row = (int)startrow; row < endrow; row++) { ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false, (const schar_T *)linebuf, @@ -570,12 +590,14 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol /// The screen is invalid and will soon be cleared /// /// Don't redraw floats until screen is cleared -void ui_comp_set_screen_valid(bool valid) +bool ui_comp_set_screen_valid(bool valid) { + bool old_val = valid_screen; valid_screen = valid; if (!valid) { msg_sep_row = -1; } + return old_val; } static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrolled, @@ -594,7 +616,7 @@ static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrol if (row > msg_current_row && ui_comp_should_draw()) { compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.cols); } else if (row < msg_current_row && ui_comp_should_draw() - && msg_current_row < Rows) { + && (msg_current_row < Rows || (scrolled && !msg_was_scrolled))) { int delta = msg_current_row - (int)row; if (msg_grid.blending) { int first_row = MAX((int)row - (scrolled?1:0), 0); @@ -676,3 +698,72 @@ static void ui_comp_grid_resize(UI *ui, Integer grid, Integer width, Integer hei } } } + +static void ui_comp_event(UI *ui, char *name, Array args) +{ + Error err = ERROR_INIT; + UIEventCallback *event_cb; + bool handled = false; + + map_foreach_value(&ui_event_cbs, event_cb, { + Object res = nlua_call_ref(event_cb->cb, name, args, false, &err); + if (res.type == kObjectTypeBoolean && res.data.boolean == true) { + handled = true; + } + }) + + if (!handled) { + ui_composed_call_event(name, args); + } +} + +static void ui_comp_update_ext(void) +{ + memset(compositor->ui_ext, 0, ARRAY_SIZE(compositor->ui_ext)); + + for (size_t i = 0; i < kUIGlobalCount; i++) { + UIEventCallback *event_cb; + + map_foreach_value(&ui_event_cbs, event_cb, { + if (event_cb->ext_widgets[i]) { + compositor->ui_ext[i] = true; + break; + } + }) + } +} + +void free_ui_event_callback(UIEventCallback *event_cb) +{ + api_free_luaref(event_cb->cb); + xfree(event_cb); +} + +void ui_comp_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets) +{ + UIEventCallback *event_cb = xcalloc(1, sizeof(UIEventCallback)); + event_cb->cb = cb; + memcpy(event_cb->ext_widgets, ext_widgets, ARRAY_SIZE(event_cb->ext_widgets)); + if (event_cb->ext_widgets[kUIMessages]) { + event_cb->ext_widgets[kUICmdline] = true; + } + + UIEventCallback **item = (UIEventCallback **)pmap_ref(uint32_t)(&ui_event_cbs, ns_id, true); + if (*item) { + free_ui_event_callback(*item); + } + *item = event_cb; + + ui_comp_update_ext(); + ui_refresh(); +} + +void ui_comp_remove_cb(uint32_t ns_id) +{ + if (pmap_has(uint32_t)(&ui_event_cbs, ns_id)) { + free_ui_event_callback(pmap_get(uint32_t)(&ui_event_cbs, ns_id)); + pmap_del(uint32_t)(&ui_event_cbs, ns_id); + } + ui_comp_update_ext(); + ui_refresh(); +} diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 75a09b244c..1a9066d7f1 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -81,6 +81,7 @@ #include <string.h> #include "auto/config.h" +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/buffer.h" #include "nvim/buffer_updates.h" @@ -94,7 +95,6 @@ #include "nvim/fold.h" #include "nvim/garray.h" #include "nvim/getchar.h" -#include "nvim/lib/kvec.h" #include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -621,7 +621,7 @@ void u_compute_hash(buf_T *buf, char_u *hash) context_sha256_T ctx; sha256_start(&ctx); for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { - char_u *p = ml_get_buf(buf, lnum, false); + char_u *p = (char_u *)ml_get_buf(buf, lnum, false); sha256_update(&ctx, p, (uint32_t)(STRLEN(p) + 1)); } sha256_finish(&ctx, hash); @@ -651,7 +651,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) char fname_buf[MAXPATHL]; // Expand symlink in the file name, so that we put the undo file with the // actual file instead of with the symlink. - if (resolve_symlink((const char_u *)ffname, (char_u *)fname_buf) == OK) { + if (resolve_symlink(ffname, fname_buf) == OK) { ffname = fname_buf; } #endif @@ -685,7 +685,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) *p-- = NUL; } - bool has_directory = os_isdir((char_u *)dir_name); + bool has_directory = os_isdir(dir_name); if (!has_directory && *dirp == NUL && !reading) { // Last directory in the list does not exist, create it. int ret; @@ -713,7 +713,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) // When reading check if the file exists. if (undo_file_name != NULL - && (!reading || os_path_exists((char_u *)undo_file_name))) { + && (!reading || os_path_exists(undo_file_name))) { break; } XFREE_CLEAR(undo_file_name); @@ -771,9 +771,9 @@ static bool serialize_header(bufinfo_T *bi, char_u *hash) // Write buffer-specific data. undo_write_bytes(bi, (uintmax_t)buf->b_ml.ml_line_count, 4); - size_t len = buf->b_u_line_ptr ? STRLEN(buf->b_u_line_ptr) : 0; + size_t len = buf->b_u_line_ptr ? strlen(buf->b_u_line_ptr) : 0; undo_write_bytes(bi, len, 4); - if (len > 0 && !undo_write(bi, buf->b_u_line_ptr, len)) { + if (len > 0 && !undo_write(bi, (char_u *)buf->b_u_line_ptr, len)) { return false; } undo_write_bytes(bi, (uintmax_t)buf->b_u_line_lnum, 4); @@ -1034,11 +1034,11 @@ static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep) undo_write_bytes(bi, (uintmax_t)uep->ue_size, 4); for (size_t i = 0; i < (size_t)uep->ue_size; i++) { - size_t len = STRLEN(uep->ue_array[i]); + size_t len = strlen(uep->ue_array[i]); if (!undo_write_bytes(bi, len, 4)) { return false; } - if (len > 0 && !undo_write(bi, uep->ue_array[i], len)) { + if (len > 0 && !undo_write(bi, (char_u *)uep->ue_array[i], len)) { return false; } } @@ -1064,7 +1064,7 @@ static u_entry_T *unserialize_uep(bufinfo_T *bi, bool *error, const char *file_n memset(array, 0, sizeof(char_u *) * (size_t)uep->ue_size); } } - uep->ue_array = array; + uep->ue_array = (char **)array; for (size_t i = 0; i < (size_t)uep->ue_size; i++) { int line_len = undo_read_4c(bi); @@ -1177,7 +1177,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, // If the undo file already exists, verify that it actually is an undo // file, and delete it. - if (os_path_exists((char_u *)file_name)) { + if (os_path_exists(file_name)) { if (name == NULL || !forceit) { // Check we can read it and it's an undo file. fd = os_open(file_name, O_RDONLY, 0); @@ -1593,7 +1593,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx]; curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx]; curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx]; - curbuf->b_u_line_ptr = line_ptr; + curbuf->b_u_line_ptr = (char *)line_ptr; curbuf->b_u_line_lnum = line_lnum; curbuf->b_u_line_colnr = line_colnr; curbuf->b_u_numhead = num_head; @@ -1771,16 +1771,16 @@ void u_redo(int count) /// Undo and remove the branch from the undo tree. /// Also moves the cursor (as a "normal" undo would). -bool u_undo_and_forget(int count) +/// +/// @param do_buf_event If `true`, send the changedtick with the buffer updates +bool u_undo_and_forget(int count, bool do_buf_event) { if (curbuf->b_u_synced == false) { u_sync(true); count = 1; } undo_undoes = true; - u_doit(count, true, - // Don't send nvim_buf_lines_event for u_undo_and_forget(). - false); + u_doit(count, true, do_buf_event); if (curbuf->b_u_curhead == NULL) { // nothing was undone. @@ -2283,7 +2283,7 @@ static void u_undoredo(int undo, bool do_buf_event) // line. long i; for (i = 0; i < newsize && i < oldsize; i++) { - if (STRCMP(uep->ue_array[i], ml_get(top + 1 + (linenr_T)i)) != 0) { + if (strcmp(uep->ue_array[i], ml_get(top + 1 + (linenr_T)i)) != 0) { break; } } @@ -2305,7 +2305,7 @@ static void u_undoredo(int undo, bool do_buf_event) // delete backwards, it goes faster in most cases long i; linenr_T lnum; - for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) { + for (lnum = bot - 1, i = oldsize; --i >= 0; lnum--) { // what can we do when we run out of memory? newarray[i] = u_save_line(lnum); // remember we deleted the last line in the buffer, and a @@ -2327,9 +2327,9 @@ static void u_undoredo(int undo, bool do_buf_event) // If the file is empty, there is an empty line 1 that we // should get rid of, by replacing it with the new line if (empty_buffer && lnum == 0) { - ml_replace((linenr_T)1, (char *)uep->ue_array[i], true); + ml_replace((linenr_T)1, uep->ue_array[i], true); } else { - ml_append(lnum, (char *)uep->ue_array[i], (colnr_T)0, false); + ml_append(lnum, uep->ue_array[i], (colnr_T)0, false); } xfree(uep->ue_array[i]); } @@ -2363,7 +2363,7 @@ static void u_undoredo(int undo, bool do_buf_event) u_newcount += newsize; u_oldcount += oldsize; uep->ue_size = oldsize; - uep->ue_array = newarray; + uep->ue_array = (char **)newarray; uep->ue_bot = top + newsize + 1; // insert this entry in front of the new entry list @@ -2560,7 +2560,7 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == curbuf && wp->w_p_cole > 0) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } } } @@ -2636,14 +2636,14 @@ void ex_undolist(exarg_T *eap) if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark && uhp->uh_walk != mark) { vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ", uhp->uh_seq, changes); - undo_fmt_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), uhp->uh_time); + undo_fmt_time((char_u *)IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), uhp->uh_time); if (uhp->uh_save_nr > 0) { - while (STRLEN(IObuff) < 33) { + while (strlen(IObuff) < 33) { STRCAT(IObuff, " "); } vim_snprintf_add((char *)IObuff, IOSIZE, " %3ld", uhp->uh_save_nr); } - GA_APPEND(char_u *, &ga, vim_strsave(IObuff)); + GA_APPEND(char *, &ga, xstrdup((char *)IObuff)); } uhp->uh_walk = mark; @@ -2744,7 +2744,7 @@ void u_find_first_changed(void) linenr_T lnum; for (lnum = 1; lnum < curbuf->b_ml.ml_line_count && lnum <= uep->ue_size; lnum++) { - if (STRCMP(ml_get_buf(curbuf, lnum, false), uep->ue_array[lnum - 1]) != 0) { + if (strcmp(ml_get_buf(curbuf, lnum, false), uep->ue_array[lnum - 1]) != 0) { clearpos(&(uhp->uh_cursor)); uhp->uh_cursor.lnum = lnum; return; @@ -2960,7 +2960,7 @@ void u_saveline(linenr_T lnum) } else { curbuf->b_u_line_colnr = 0; } - curbuf->b_u_line_ptr = u_save_line(lnum); + curbuf->b_u_line_ptr = (char *)u_save_line(lnum); } /// clear the line saved for the "U" command @@ -2992,12 +2992,12 @@ void u_undoline(void) } char_u *oldp = u_save_line(curbuf->b_u_line_lnum); - ml_replace(curbuf->b_u_line_lnum, (char *)curbuf->b_u_line_ptr, true); + ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true); changed_bytes(curbuf->b_u_line_lnum, 0); extmark_splice_cols(curbuf, (int)curbuf->b_u_line_lnum - 1, 0, (colnr_T)STRLEN(oldp), - (colnr_T)STRLEN(curbuf->b_u_line_ptr), kExtmarkUndo); + (colnr_T)strlen(curbuf->b_u_line_ptr), kExtmarkUndo); xfree(curbuf->b_u_line_ptr); - curbuf->b_u_line_ptr = oldp; + curbuf->b_u_line_ptr = (char *)oldp; colnr_T t = curbuf->b_u_line_colnr; if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) { @@ -3027,16 +3027,16 @@ void u_blockfree(buf_T *buf) /// @param lnum the line to copy static char_u *u_save_line(linenr_T lnum) { - return u_save_line_buf(curbuf, lnum); + return (char_u *)u_save_line_buf(curbuf, lnum); } /// Allocate memory and copy line into it /// /// @param lnum line to copy /// @param buf buffer to copy from -static char_u *u_save_line_buf(buf_T *buf, linenr_T lnum) +static char *u_save_line_buf(buf_T *buf, linenr_T lnum) { - return vim_strsave(ml_get_buf(buf, lnum, false)); + return xstrdup(ml_get_buf(buf, lnum, false)); } /// Check if the 'modified' flag is set, or 'ff' has changed (only need to diff --git a/src/nvim/undo_defs.h b/src/nvim/undo_defs.h index 4b64f97919..7c065c540b 100644 --- a/src/nvim/undo_defs.h +++ b/src/nvim/undo_defs.h @@ -21,11 +21,11 @@ typedef struct { typedef struct u_entry u_entry_T; struct u_entry { - u_entry_T *ue_next; // pointer to next entry in list + u_entry_T *ue_next; // pointer to next entry in list linenr_T ue_top; // number of line above undo block linenr_T ue_bot; // number of line below undo block linenr_T ue_lcount; // linecount when u_save called - char_u **ue_array; // array of lines in undo block + char **ue_array; // array of lines in undo block long ue_size; // number of lines in ue_array #ifdef U_DEBUG int ue_magic; // magic number to check allocation diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 59b8d10200..c3cf0b6df8 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -106,7 +106,7 @@ static struct { /// Return NULL if there is no matching command. /// /// @param *p end of the command (possibly including count) -/// @param full set to TRUE for a full match +/// @param full set to true for a full match /// @param xp used for completion, NULL otherwise /// @param complp completion flags or NULL char *find_ucmd(exarg_T *eap, char *p, int *full, expand_T *xp, int *complp) @@ -127,7 +127,7 @@ char *find_ucmd(exarg_T *eap, char *p, int *full, expand_T *xp, int *complp) for (j = 0; j < gap->ga_len; j++) { uc = USER_CMD_GA(gap, j); cp = eap->cmd; - np = (char *)uc->uc_name; + np = uc->uc_name; k = 0; while (k < len && *np != NUL && *cp++ == *np++) { k++; @@ -167,7 +167,7 @@ char *find_ucmd(exarg_T *eap, char *p, int *full, expand_T *xp, int *complp) } if (xp != NULL) { xp->xp_luaref = uc->uc_compl_luaref; - xp->xp_arg = (char *)uc->uc_compl_arg; + xp->xp_arg = uc->uc_compl_arg; xp->xp_script_ctx = uc->uc_script_ctx; xp->xp_script_ctx.sc_lnum += SOURCING_LNUM; } @@ -216,7 +216,7 @@ const char *set_context_in_user_cmd(expand_T *xp, const char *arg_in) // Check for attributes while (*arg == '-') { arg++; // Skip "-". - p = (const char *)skiptowhite((const char_u *)arg); + p = (const char *)skiptowhite(arg); if (*p == NUL) { // Cursor is still in the attribute. p = strchr(arg, '='); @@ -248,7 +248,7 @@ const char *set_context_in_user_cmd(expand_T *xp, const char *arg_in) } // After the attributes comes the new command name. - p = (const char *)skiptowhite((const char_u *)arg); + p = (const char *)skiptowhite(arg); if (*p == NUL) { xp->xp_context = EXPAND_USER_COMMANDS; xp->xp_pattern = (char *)arg; @@ -272,15 +272,15 @@ char *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx) const buf_T *const buf = prevwin_curwin()->w_buffer; if (idx < buf->b_ucmds.ga_len) { - return (char *)USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; + return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; } idx -= buf->b_ucmds.ga_len; if (idx < ucmds.ga_len) { - char *name = (char *)USER_CMD(idx)->uc_name; + char *name = 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) { + if (strcmp(name, USER_CMD_GA(&buf->b_ucmds, i)->uc_name) == 0) { // global command is overruled by buffer-local one return ""; } @@ -297,14 +297,14 @@ char *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx) char *get_user_command_name(int idx, int cmdidx) { if (cmdidx == CMD_USER && idx < ucmds.ga_len) { - return (char *)USER_CMD(idx)->uc_name; + return USER_CMD(idx)->uc_name; } if (cmdidx == CMD_USER_BUF) { // In cmdwin, the alternative buffer should be used. const buf_T *const buf = prevwin_curwin()->w_buffer; if (idx < buf->b_ucmds.ga_len) { - return (char *)USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; + return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; } } return NULL; @@ -435,7 +435,7 @@ static void uc_list(char *name, size_t name_len) } msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); - len = (int)STRLEN(cmd->uc_name) + 4; + len = (int)strlen(cmd->uc_name) + 4; do { msg_putchar(' '); @@ -476,14 +476,14 @@ static void uc_list(char *name, size_t name_len) // -count=N snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "c", (int64_t)cmd->uc_def); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); } else if (a & EX_DFLALL) { IObuff[len++] = '%'; } else if (cmd->uc_def >= 0) { // -range=N snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "", (int64_t)cmd->uc_def); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); } else { IObuff[len++] = '.'; } @@ -498,7 +498,7 @@ static void uc_list(char *name, size_t name_len) if (addr_type_complete[j].expand != ADDR_LINES && addr_type_complete[j].expand == cmd->uc_addr_type) { STRCPY(IObuff + len, addr_type_complete[j].shortname); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); break; } } @@ -511,7 +511,7 @@ static void uc_list(char *name, size_t name_len) char *cmd_compl = get_command_complete(cmd->uc_compl); if (cmd_compl != NULL) { STRCPY(IObuff + len, get_command_complete(cmd->uc_compl)); - len += (int)STRLEN(IObuff + len); + len += (int)strlen(IObuff + len); } do { @@ -559,7 +559,7 @@ int parse_addr_type_arg(char *value, int vallen, cmd_addr_T *addr_type_arg) int i, a, b; for (i = 0; addr_type_complete[i].expand != ADDR_NONE; i++) { - a = (int)STRLEN(addr_type_complete[i].name) == vallen; + a = (int)strlen(addr_type_complete[i].name) == vallen; b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; if (a && b) { *addr_type_arg = addr_type_complete[i].expand; @@ -607,7 +607,7 @@ int parse_compl_arg(const char *value, int vallen, int *complp, uint32_t *argt, if (get_command_complete(i) == NULL) { continue; } - if ((int)STRLEN(command_complete[i]) == valend + if ((int)strlen(command_complete[i]) == valend && STRNCMP(value, command_complete[i], valend) == 0) { *complp = i; if (i == EXPAND_BUFFERS) { @@ -816,7 +816,7 @@ int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, char *rep_buf = NULL; garray_T *gap; - replace_termcodes(rep, STRLEN(rep), &rep_buf, 0, NULL, CPO_TO_CPO_FLAGS); + replace_termcodes(rep, strlen(rep), &rep_buf, 0, NULL, CPO_TO_CPO_FLAGS); if (rep_buf == NULL) { // Can't replace termcodes - try using the string as is rep_buf = xstrdup(rep); @@ -837,7 +837,7 @@ int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, size_t len; cmd = USER_CMD_GA(gap, i); - len = STRLEN(cmd->uc_name); + len = strlen(cmd->uc_name); cmp = STRNCMP(name, cmd->uc_name, name_len); if (cmp == 0) { if (name_len < len) { @@ -883,17 +883,17 @@ int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, gap->ga_len++; - cmd->uc_name = (char_u *)p; + cmd->uc_name = p; } - cmd->uc_rep = (char_u *)rep_buf; + cmd->uc_rep = rep_buf; cmd->uc_argt = argt; cmd->uc_def = def; cmd->uc_compl = compl; cmd->uc_script_ctx = current_sctx; cmd->uc_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&cmd->uc_script_ctx); - cmd->uc_compl_arg = (char_u *)compl_arg; + cmd->uc_compl_arg = compl_arg; cmd->uc_compl_luaref = compl_luaref; cmd->uc_preview_luaref = preview_luaref; cmd->uc_addr_type = addr_type; @@ -930,7 +930,7 @@ void ex_command(exarg_T *eap) // Check for attributes while (*p == '-') { p++; - end = (char *)skiptowhite((char_u *)p); + end = skiptowhite(p); if (uc_scan_attr(p, (size_t)(end - p), &argt, &def, &flags, &compl, (char_u **)&compl_arg, &addr_type_arg) == FAIL) { return; @@ -1006,7 +1006,7 @@ void ex_delcommand(exarg_T *eap) for (;;) { for (i = 0; i < gap->ga_len; i++) { cmd = USER_CMD_GA(gap, i); - res = STRCMP(arg, cmd->uc_name); + res = strcmp(arg, cmd->uc_name); if (res <= 0) { break; } @@ -1061,11 +1061,11 @@ bool uc_split_args_iter(const char *arg, size_t arglen, size_t *end, char *buf, buf[l++] = arg[++pos]; } else { buf[l++] = arg[pos]; - if (ascii_iswhite(arg[pos + 1])) { - *end = pos + 1; - *len = l; - return false; - } + } + if (ascii_iswhite(arg[pos + 1])) { + *end = pos + 1; + *len = l; + return false; } } @@ -1198,7 +1198,7 @@ static char *uc_split_args(char *arg, char **args, size_t *arglens, size_t argc, static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods) { - size_t result = STRLEN(mod_str); + size_t result = strlen(mod_str); if (*multi_mods) { result++; } @@ -1247,6 +1247,10 @@ size_t add_win_cmd_modifers(char *buf, const cmdmod_T *cmod, bool *multi_mods) if (cmod->cmod_split & WSP_VERT) { result += add_cmd_modifier(buf, "vertical", multi_mods); } + // :horizontal + if (cmod->cmod_split & WSP_HOR) { + result += add_cmd_modifier(buf, "horizontal", multi_mods); + } return result; } @@ -1401,13 +1405,13 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar switch (quote) { case 0: // No quoting, no splitting - result = STRLEN(eap->arg); + result = strlen(eap->arg); if (buf != NULL) { STRCPY(buf, eap->arg); } break; case 1: // Quote, but don't split - result = STRLEN(eap->arg) + 2; + result = strlen(eap->arg) + 2; for (p = eap->arg; *p; p++) { if (*p == '\\' || *p == '"') { result++; @@ -1471,7 +1475,7 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar size_t num_len; snprintf(num_buf, sizeof(num_buf), "%" PRId64, (int64_t)num); - num_len = STRLEN(num_buf); + num_len = strlen(num_buf); result = num_len; if (quote) { @@ -1569,7 +1573,7 @@ int do_ucmd(exarg_T *eap, bool preview) // Second round: copy result into "buf". buf = NULL; for (;;) { - p = (char *)cmd->uc_rep; // source + p = cmd->uc_rep; // source q = buf; // destination totlen = 0; @@ -1633,7 +1637,7 @@ int do_ucmd(exarg_T *eap, bool preview) break; } - totlen += STRLEN(p); // Add on the trailing characters + totlen += strlen(p); // Add on the trailing characters buf = xmalloc(totlen + 1); } diff --git a/src/nvim/usercmd.h b/src/nvim/usercmd.h index 637862b216..4d2cf0d9de 100644 --- a/src/nvim/usercmd.h +++ b/src/nvim/usercmd.h @@ -4,14 +4,14 @@ #include "nvim/ex_cmds_defs.h" typedef struct ucmd { - char_u *uc_name; // The command name + char *uc_name; // The command name uint32_t uc_argt; // The argument type - char_u *uc_rep; // The command's replacement string + char *uc_rep; // The command's replacement string long uc_def; // The default value for a range/count int uc_compl; // completion type cmd_addr_T uc_addr_type; // The command's address type sctx_T uc_script_ctx; // SCTX where the command was defined - char_u *uc_compl_arg; // completion argument if any + char *uc_compl_arg; // completion argument if any LuaRef uc_compl_luaref; // Reference to Lua completion function LuaRef uc_preview_luaref; // Reference to Lua preview function LuaRef uc_luaref; // Reference to Lua function diff --git a/src/nvim/version.c b/src/nvim/version.c index 0667243bc3..d4d406482d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -2016,7 +2016,7 @@ void ex_version(exarg_T *eap) /// Output a string for the version message. If it's going to wrap, output a /// newline, unless the message is too long to fit on the screen anyway. -/// When "wrap" is TRUE wrap the string in []. +/// When "wrap" is true wrap the string in []. /// @param s /// @param wrap static void version_msg_wrap(char *s, int wrap) @@ -2072,7 +2072,7 @@ void list_in_columns(char **items, int size, int current) // Find the length of the longest item, use that + 1 as the column width. int i; for (i = 0; size < 0 ? items[i] != NULL : i < size; i++) { - int l = vim_strsize((char *)items[i]) + (i == current ? 2 : 0); + int l = vim_strsize(items[i]) + (i == current ? 2 : 0); if (l > width) { width = l; @@ -2084,7 +2084,7 @@ void list_in_columns(char **items, int size, int current) if (Columns < width) { // Not enough screen columns - show one per line for (i = 0; i < item_count; i++) { - version_msg_wrap((char *)items[i], i == current); + version_msg_wrap(items[i], i == current); if (msg_col > 0 && i < item_count - 1) { msg_putchar('\n'); } @@ -2106,7 +2106,7 @@ void list_in_columns(char **items, int size, int current) if (idx == current) { msg_putchar('['); } - msg_puts((char *)items[idx]); + msg_puts(items[idx]); if (idx == current) { msg_putchar(']'); } @@ -2200,7 +2200,7 @@ void maybe_intro_message(void) if (buf_is_empty(curbuf) && (curbuf->b_fname == NULL) && (firstwin->w_next == NULL) - && (vim_strchr((char *)p_shm, SHM_INTRO) == NULL)) { + && (vim_strchr(p_shm, SHM_INTRO) == NULL)) { intro_message(false); } } @@ -2209,7 +2209,7 @@ void maybe_intro_message(void) /// Only used when starting Vim on an empty file, without a file name. /// Or with the ":intro" command (for Sven :-). /// -/// @param colon TRUE for ":intro" +/// @param colon true for ":intro" void intro_message(int colon) { int i; @@ -2256,7 +2256,7 @@ void intro_message(int colon) row = blanklines / 2; if (((row >= 2) && (Columns >= 50)) || colon) { - for (i = 0; i < (int)ARRAY_SIZE(lines); ++i) { + for (i = 0; i < (int)ARRAY_SIZE(lines); i++) { p = lines[i]; if (sponsor != 0) { @@ -2274,7 +2274,7 @@ void intro_message(int colon) } if (*p != NUL) { - do_intro_line(row, (char_u *)_(p), 0); + do_intro_line(row, _(p), 0); } row++; } @@ -2287,15 +2287,14 @@ void intro_message(int colon) } } -static void do_intro_line(long row, char_u *mesg, int attr) +static void do_intro_line(long row, char *mesg, int attr) { - long col; - char_u *p; + char *p; int l; int clen; // Center the message horizontally. - col = vim_strsize((char *)mesg); + long col = vim_strsize(mesg); col = (Columns - col) / 2; @@ -2310,8 +2309,8 @@ static void do_intro_line(long row, char_u *mesg, int attr) for (l = 0; p[l] != NUL && (l == 0 || (p[l] != '<' && p[l - 1] != '>')); l++) { - clen += ptr2cells((char *)p + l); - l += utfc_ptr2len((char *)p + l) - 1; + clen += ptr2cells(p + l); + l += utfc_ptr2len(p + l) - 1; } assert(row <= INT_MAX && col <= INT_MAX); grid_puts_len(&default_grid, p, l, (int)row, (int)col, @@ -2325,7 +2324,8 @@ static void do_intro_line(long row, char_u *mesg, int attr) /// @param eap void ex_intro(exarg_T *eap) { + // TODO(bfredl): use msg_grid instead! screenclear(); - intro_message(TRUE); - wait_return(TRUE); + intro_message(true); + wait_return(true); } diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 09b949bb20..5b7ff7ba52 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -167,15 +167,6 @@ enum { #define MIN_SWAP_PAGE_SIZE 1048 #define MAX_SWAP_PAGE_SIZE 50000 -// Boolean constants - -#ifndef TRUE -# define FALSE 0 // note: this is an int, not a long! -# define TRUE 1 -#endif - -#define MAYBE 2 // sometimes used for a variant on TRUE - #define STATUS_HEIGHT 1 // height of a status line under a window #define QF_WINHEIGHT 10 // default height for quickfix window @@ -214,7 +205,6 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() #define STRCPY(d, s) strcpy((char *)(d), (char *)(s)) #define STRNCPY(d, s, n) strncpy((char *)(d), (char *)(s), (size_t)(n)) #define STRLCPY(d, s, n) xstrlcpy((char *)(d), (char *)(s), (size_t)(n)) -#define STRCMP(d, s) strcmp((char *)(d), (char *)(s)) #define STRNCMP(d, s, n) strncmp((char *)(d), (char *)(s), (size_t)(n)) #ifdef HAVE_STRCASECMP # define STRICMP(d, s) strcasecmp((char *)(d), (char *)(s)) @@ -239,11 +229,7 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() # endif #endif -#define STRRCHR(s, c) (char_u *)strrchr((const char *)(s), (c)) - -#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) -#define STRNCAT(d, s, n) strncat((char *)(d), (char *)(s), (size_t)(n)) -#define STRLCAT(d, s, n) xstrlcat((char *)(d), (char *)(s), (size_t)(n)) +#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) // NOLINT(runtime/printf) // Character used as separated in autoload function/variable names. #define AUTOLOAD_CHAR '#' @@ -258,23 +244,6 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() #include "nvim/path.h" -/// Compare file names -/// -/// On some systems case in a file name does not matter, on others it does. -/// -/// @note Does not account for maximum name lengths and things like "../dir", -/// thus it is not 100% accurate. OS may also use different algorithm for -/// case-insensitive comparison. -/// -/// @param[in] x First file name to compare. -/// @param[in] y Second file name to compare. -/// -/// @return 0 for equal file names, non-zero otherwise. -#define FNAMECMP(x, y) path_fnamecmp((const char *)(x), (const char *)(y)) -#define FNAMENCMP(x, y, n) path_fnamencmp((const char *)(x), \ - (const char *)(y), \ - (size_t)(n)) - // Enums need a typecast to be used as array index. #define HL_ATTR(n) hl_attr_active[(int)(n)] @@ -287,7 +256,7 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() // functions of these names. The declarations would break if the defines had // been seen at that stage. But it must be before globals.h, where error_ga // is declared. -#ifndef WIN32 +#ifndef MSWIN # define mch_errmsg(str) fprintf(stderr, "%s", (str)) # define mch_msg(str) printf("%s", (str)) #endif diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 387b9d61f2..4564831824 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -55,19 +55,17 @@ #include <stddef.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/assert.h" #include "nvim/charset.h" #include "nvim/eval/typval.h" -#include "nvim/lib/kvec.h" #include "nvim/memory.h" #include "nvim/types.h" #include "nvim/vim.h" #include "nvim/viml/parser/expressions.h" #include "nvim/viml/parser/parser.h" -#define VIM_STR2NR(s, ...) vim_str2nr((const char_u *)(s), __VA_ARGS__) - typedef kvec_withinit_t(ExprASTNode **, 16) ExprASTStack; /// Which nodes may be wanted @@ -371,7 +369,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) significand_part = significand_part * 10 + (pline.data[i] - '0'); } if (exp_start) { - VIM_STR2NR(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part, + vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part, (int)(ret.len - exp_start), false); } if (exp_negative) { @@ -389,7 +387,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) } else { int len; int prep; - VIM_STR2NR(pline.data, &prep, &len, STR2NR_ALL, NULL, + vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL, &ret.data.num.val.integer, (int)pline.size, false); ret.len = (size_t)len; const uint8_t bases[] = { @@ -696,8 +694,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) // Everything else is not valid. default: - ret.len = (size_t)utfc_ptr2len_len((const char_u *)pline.data, - (int)pline.size); + ret.len = (size_t)utfc_ptr2len_len(pline.data, (int)pline.size); ret.type = kExprLexInvalid; ret.data.err.type = kExprLexPlainIdentifier; ret.data.err.msg = _("E15: Unidentified character: %.*s"); diff --git a/src/nvim/viml/parser/parser.h b/src/nvim/viml/parser/parser.h index b8835127e7..404dc5a0d1 100644 --- a/src/nvim/viml/parser/parser.h +++ b/src/nvim/viml/parser/parser.h @@ -5,8 +5,8 @@ #include <stdbool.h> #include <stddef.h> +#include "klib/kvec.h" #include "nvim/func_attr.h" -#include "nvim/lib/kvec.h" #include "nvim/mbyte.h" #include "nvim/memory.h" @@ -142,9 +142,7 @@ static inline void viml_preader_get_line(ParserInputReader *const preader, .allocated = true, .size = pline.size, }; - cpline.data = (char *)string_convert(&preader->conv, - (char_u *)pline.data, - &cpline.size); + cpline.data = string_convert(&preader->conv, (char *)pline.data, &cpline.size); if (pline.allocated) { xfree((void *)pline.data); } diff --git a/src/nvim/window.c b/src/nvim/window.c index 9a3a7040ed..9be7a91667 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -215,7 +215,7 @@ newwindow: case Ctrl_Q: case 'q': reset_VIsual_and_resel(); // stop Visual mode - cmd_with_count("quit", (char_u *)cbuf, sizeof(cbuf), Prenum); + cmd_with_count("quit", cbuf, sizeof(cbuf), Prenum); do_cmdline_cmd(cbuf); break; @@ -223,7 +223,7 @@ newwindow: case Ctrl_C: case 'c': reset_VIsual_and_resel(); // stop Visual mode - cmd_with_count("close", (char_u *)cbuf, sizeof(cbuf), Prenum); + cmd_with_count("close", cbuf, sizeof(cbuf), Prenum); do_cmdline_cmd(cbuf); break; @@ -256,7 +256,7 @@ newwindow: case 'o': CHECK_CMDWIN; reset_VIsual_and_resel(); // stop Visual mode - cmd_with_count("only", (char_u *)cbuf, sizeof(cbuf), Prenum); + cmd_with_count("only", cbuf, sizeof(cbuf), Prenum); do_cmdline_cmd(cbuf); break; @@ -417,10 +417,12 @@ newwindow: | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT)); break; - // make all windows the same height - case '=': - win_equal(NULL, false, 'b'); + // make all windows the same width and/or height + case '=': { + int mod = cmdmod.cmod_split & (WSP_VERT | WSP_HOR); + win_equal(NULL, false, mod == WSP_VERT ? 'v' : mod == WSP_HOR ? 'h' : 'b'); break; + } // increase current window height case '+': @@ -622,12 +624,12 @@ wingotofile: } } -static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, int64_t Prenum) +static void cmd_with_count(char *cmd, char *bufp, size_t bufsize, int64_t Prenum) { size_t len = STRLCPY(bufp, cmd, bufsize); if (Prenum > 0 && len < bufsize) { - vim_snprintf((char *)bufp + len, bufsize - len, "%" PRId64, Prenum); + vim_snprintf(bufp + len, bufsize - len, "%" PRId64, Prenum); } } @@ -712,7 +714,7 @@ win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err) win_config_float(wp, fconfig); win_set_inner_size(wp, true); wp->w_pos_changed = true; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); return wp; } @@ -727,38 +729,38 @@ void win_set_minimal_style(win_T *wp) // Hide EOB region: use " " fillchar and cleared highlighting if (wp->w_p_fcs_chars.eob != ' ') { - char_u *old = wp->w_p_fcs; + char_u *old = (char_u *)wp->w_p_fcs; wp->w_p_fcs = ((*old == NUL) - ? (char_u *)xstrdup("eob: ") - : concat_str(old, (char_u *)",eob: ")); - free_string_option(old); + ? xstrdup("eob: ") + : concat_str((char *)old, ",eob: ")); + free_string_option((char *)old); } // TODO(bfredl): this could use a highlight namespace directly, - // and avoid pecularities around window options - char_u *old = wp->w_p_winhl; + // and avoid peculiarities around window options + char_u *old = (char_u *)wp->w_p_winhl; wp->w_p_winhl = ((*old == NUL) - ? (char_u *)xstrdup("EndOfBuffer:") - : concat_str(old, (char_u *)",EndOfBuffer:")); - free_string_option(old); + ? xstrdup("EndOfBuffer:") + : concat_str((char *)old, ",EndOfBuffer:")); + free_string_option((char *)old); parse_winhl_opt(wp); // signcolumn: use 'auto' - if (wp->w_p_scl[0] != 'a' || STRLEN(wp->w_p_scl) >= 8) { + if (wp->w_p_scl[0] != 'a' || strlen(wp->w_p_scl) >= 8) { free_string_option(wp->w_p_scl); - wp->w_p_scl = (char_u *)xstrdup("auto"); + wp->w_p_scl = xstrdup("auto"); } // foldcolumn: use '0' if (wp->w_p_fdc[0] != '0') { free_string_option(wp->w_p_fdc); - wp->w_p_fdc = (char_u *)xstrdup("0"); + wp->w_p_fdc = xstrdup("0"); } // colorcolumn: cleared if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) { free_string_option(wp->w_p_cc); - wp->w_p_cc = (char_u *)xstrdup(""); + wp->w_p_cc = xstrdup(""); } } @@ -797,12 +799,12 @@ void win_config_float(win_T *wp, FloatConfig fconfig) } win_set_inner_size(wp, true); - must_redraw = MAX(must_redraw, VALID); + must_redraw = MAX(must_redraw, UPD_VALID); wp->w_pos_changed = true; if (change_external || change_border) { wp->w_hl_needs_update = true; - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } // compute initial position @@ -839,7 +841,7 @@ void win_config_float(win_T *wp, FloatConfig fconfig) // changing border style while keeping border only requires redrawing border if (fconfig.border) { wp->w_redr_border = true; - redraw_later(wp, VALID); + redraw_later(wp, UPD_VALID); } } @@ -869,8 +871,9 @@ int win_fdccol_count(win_T *wp) } } -void ui_ext_win_position(win_T *wp) +void ui_ext_win_position(win_T *wp, bool validate) { + wp->w_pos_changed = false; if (!wp->w_floating) { ui_call_win_pos(wp->w_grid_alloc.handle, wp->handle, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_height); @@ -908,6 +911,11 @@ void ui_ext_win_position(win_T *wp) grid->handle, row, col, c.focusable, wp->w_grid_alloc.zindex); } else { + bool valid = (wp->w_redr_type == 0); + if (!valid && !validate) { + wp->w_pos_changed = true; + return; + } // TODO(bfredl): ideally, compositor should work like any multigrid UI // and use standard win_pos events. bool east = c.anchor & kFloatAnchorEast; @@ -921,14 +929,13 @@ void ui_ext_win_position(win_T *wp) comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0); wp->w_winrow = comp_row; wp->w_wincol = comp_col; - bool valid = (wp->w_redr_type == 0); ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col, wp->w_height_outer, wp->w_width_outer, valid, false); ui_check_cursor_grid(wp->w_grid_alloc.handle); wp->w_grid_alloc.focusable = wp->w_float_config.focusable; if (!valid) { wp->w_grid_alloc.valid = false; - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } } } else { @@ -968,21 +975,19 @@ static int check_split_disallowed(void) return OK; } -/* - * split the current window, implements CTRL-W s and :split - * - * "size" is the height or width for the new window, 0 to use half of current - * height or width. - * - * "flags": - * WSP_ROOM: require enough room for new window - * WSP_VERT: vertical split. - * WSP_TOP: open window at the top-left of the screen (help window). - * WSP_BOT: open window at the bottom-right of the screen (quickfix window). - * WSP_HELP: creating the help window, keep layout snapshot - * - * return FAIL for failure, OK otherwise - */ +// split the current window, implements CTRL-W s and :split +// +// "size" is the height or width for the new window, 0 to use half of current +// height or width. +// +// "flags": +// WSP_ROOM: require enough room for new window +// WSP_VERT: vertical split. +// WSP_TOP: open window at the top-left of the screen (help window). +// WSP_BOT: open window at the bottom-right of the screen (quickfix window). +// WSP_HELP: creating the help window, keep layout snapshot +// +// return FAIL for failure, OK otherwise int win_split(int size, int flags) { if (check_split_disallowed() == FAIL) { @@ -1012,12 +1017,10 @@ int win_split(int size, int flags) return win_split_ins(size, flags, NULL, 0); } -/* - * When "new_wp" is NULL: split the current window in two. - * When "new_wp" is not NULL: insert this window at the far - * top/left/right/bottom. - * return FAIL for failure, OK otherwise - */ +// When "new_wp" is NULL: split the current window in two. +// When "new_wp" is not NULL: insert this window at the far +// top/left/right/bottom. +// return FAIL for failure, OK otherwise int win_split_ins(int size, int flags, win_T *new_wp, int dir) { win_T *wp = new_wp; @@ -1067,10 +1070,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) layout = FR_ROW; - /* - * Check if we are able to split the current window and compute its - * width. - */ + // Check if we are able to split the current window and compute its + // width. // Current window requires at least 1 space. wmw1 = (p_wmw == 0 ? 1 : (int)p_wmw); needed = wmw1 + 1; @@ -1241,9 +1242,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } } - /* - * allocate new window structure and link it in the window list - */ + // allocate new window structure and link it in the window list if ((flags & WSP_TOP) == 0 && ((flags & WSP_BOT) || (flags & WSP_BELOW) @@ -1280,9 +1279,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) CLEAR_FIELD(wp->w_border_adj); } - /* - * Reorganise the tree of frames to insert the new window. - */ + // Reorganise the tree of frames to insert the new window. if (flags & (WSP_TOP | WSP_BOT)) { if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0) || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0)) { @@ -1299,9 +1296,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } else { curfrp = oldwin->w_frame; if (flags & WSP_BELOW) { - before = FALSE; + before = false; } else if (flags & WSP_ABOVE) { - before = TRUE; + before = true; } else if (flags & WSP_VERT) { before = !p_spr; } else { @@ -1474,8 +1471,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) // Both windows need redrawing. Update all status lines, in case they // show something related to the window count or position. - redraw_later(wp, NOT_VALID); - redraw_later(oldwin, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); + redraw_later(oldwin, UPD_NOT_VALID); status_redraw_all(); if (need_status) { @@ -1487,11 +1484,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) msg_col = 0; // put position back at start of line } - /* - * equalize the window sizes. - */ + // equalize the window sizes. if (do_equal || dir != 0) { win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v')); + } else if (*p_spk != 'c' && wp != aucmd_win) { + win_fix_scroll(false); } // Don't change the window height/width to 'winheight' / 'winwidth' if a @@ -1525,13 +1522,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) return OK; } -/* - * Initialize window "newp" from window "oldp". - * Used when splitting a window and when creating a new tab page. - * The windows will both edit the same buffer. - * WSP_NEWLOC may be specified in flags to prevent the location list from - * being copied. - */ +// Initialize window "newp" from window "oldp". +// Used when splitting a window and when creating a new tab page. +// The windows will both edit the same buffer. +// WSP_NEWLOC may be specified in flags to prevent the location list from +// being copied. static void win_init(win_T *newp, win_T *oldp, int flags) { int i; @@ -1565,15 +1560,21 @@ static void win_init(win_T *newp, win_T *oldp, int flags) newp->w_prevdir = (oldp->w_prevdir == NULL) ? NULL : xstrdup(oldp->w_prevdir); + if (*p_spk != 'c') { + newp->w_botline = oldp->w_botline; + newp->w_prev_height = oldp->w_height; + newp->w_prev_winrow = oldp->w_winrow; + } + // copy tagstack and folds for (i = 0; i < oldp->w_tagstacklen; i++) { taggy_T *tag = &newp->w_tagstack[i]; *tag = oldp->w_tagstack[i]; if (tag->tagname != NULL) { - tag->tagname = vim_strsave(tag->tagname); + tag->tagname = xstrdup(tag->tagname); } if (tag->user_data != NULL) { - tag->user_data = vim_strsave(tag->user_data); + tag->user_data = xstrdup(tag->user_data); } } newp->w_tagstackidx = oldp->w_tagstackidx; @@ -1589,15 +1590,13 @@ static void win_init(win_T *newp, win_T *oldp, int flags) newp->w_winbar_height = oldp->w_winbar_height; } -/* - * Initialize window "newp" from window "old". - * Only the essential things are copied. - */ +// Initialize window "newp" from window "old". +// Only the essential things are copied. static void win_init_some(win_T *newp, win_T *oldp) { // Use the same argument list. newp->w_alist = oldp->w_alist; - ++newp->w_alist->al_refcount; + newp->w_alist->al_refcount++; newp->w_arg_idx = oldp->w_arg_idx; // copy options from existing window @@ -1669,9 +1668,7 @@ bool win_valid_any_tab(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT return false; } -/* - * Return the number of windows. - */ +// Return the number of windows. int win_count(void) { int count = 0; @@ -1723,7 +1720,7 @@ int make_windows(int count, bool vertical) block_autocmds(); // todo is number of windows left to create - for (todo = count - 1; todo > 0; --todo) { + for (todo = count - 1; todo > 0; todo--) { if (vertical) { if (win_split(curwin->w_width - (curwin->w_width - todo) / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL) { @@ -1744,9 +1741,7 @@ int make_windows(int count, bool vertical) return count - todo; } -/* - * Exchange current and next window - */ +// Exchange current and next window static void win_exchange(long Prenum) { frame_T *frp; @@ -1766,9 +1761,7 @@ static void win_exchange(long Prenum) return; } - /* - * find window to exchange with - */ + // find window to exchange with if (Prenum) { frp = curwin->w_frame->fr_parent->fr_child; while (frp != NULL && --Prenum > 0) { @@ -1787,14 +1780,12 @@ static void win_exchange(long Prenum) } wp = frp->fr_win; - /* - * 1. remove curwin from the list. Remember after which window it was in wp2 - * 2. insert curwin before wp in the list - * if wp != wp2 - * 3. remove wp from the list - * 4. insert wp after wp2 - * 5. exchange the status line height, winbar height, hsep height and vsep width. - */ + // 1. remove curwin from the list. Remember after which window it was in wp2 + // 2. insert curwin before wp in the list + // if wp != wp2 + // 3. remove wp from the list + // 4. insert wp after wp2 + // 5. exchange the status line height, winbar height, hsep height and vsep width. wp2 = curwin->w_prev; frp2 = curwin->w_frame->fr_prev; if (wp->w_prev != curwin) { @@ -1837,8 +1828,8 @@ static void win_exchange(long Prenum) } win_enter(wp, true); - redraw_later(curwin, NOT_VALID); - redraw_later(wp, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } // rotate windows: if upwards true the second window becomes the first one @@ -1922,12 +1913,10 @@ static void win_rotate(bool upwards, int count) wp1->w_pos_changed = true; wp2->w_pos_changed = true; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } -/* - * Move the current window to the very top/bottom/left/right of the screen. - */ +// Move the current window to the very top/bottom/left/right of the screen. static void win_totop(int size, int flags) { int dir = 0; @@ -1971,10 +1960,8 @@ static void win_totop(int size, int flags) } } -/* - * Move window "win1" to below/right of "win2" and make "win1" the current - * window. Only works within the same frame! - */ +// Move window "win1" to below/right of "win2" and make "win1" the current +// window. Only works within the same frame! void win_move_after(win_T *win1, win_T *win2) { int height; @@ -2034,7 +2021,7 @@ void win_move_after(win_T *win1, win_T *win2) frame_append(win2->w_frame, win1->w_frame); (void)win_comp_pos(); // recompute w_winrow for all windows - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } win_enter(win1, false); @@ -2074,7 +2061,7 @@ static int get_maximum_wincount(frame_T *fr, int height) } /// Make all windows the same height. -///'next_curwin' will soon be the current window, make sure it has enough rows. +/// 'next_curwin' will soon be the current window, make sure it has enough rows. /// /// @param next_curwin pointer to current window to be or NULL /// @param current do only frame with current window @@ -2082,11 +2069,14 @@ static int get_maximum_wincount(frame_T *fr, int height) void win_equal(win_T *next_curwin, bool current, int dir) { if (dir == 0) { - dir = *p_ead; + dir = (unsigned char)(*p_ead); } win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current, topframe, dir, 0, tabline_height(), Columns, topframe->fr_height); + if (*p_spk != 'c' && next_curwin != aucmd_win) { + win_fix_scroll(true); + } } /// Set a frame to a new position and height, spreading the available room @@ -2125,7 +2115,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int frame_new_height(topfr, height, false, false); topfr->fr_win->w_wincol = col; frame_new_width(topfr, width, false, false); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } } else if (topfr->fr_layout == FR_ROW) { topfr->fr_width = width; @@ -2144,11 +2134,9 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int totwincount = (n + extra_sep) / ((int)p_wmw + 1); has_next_curwin = frame_has_win(topfr, next_curwin); - /* - * Compute width for "next_curwin" window and room available for - * other windows. - * "m" is the minimal width when counting p_wiw for "next_curwin". - */ + // Compute width for "next_curwin" window and room available for + // other windows. + // "m" is the minimal width when counting p_wiw for "next_curwin". m = frame_minwidth(topfr, next_curwin); room = width - m; if (room < 0) { @@ -2200,7 +2188,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } if (has_next_curwin) { - --totwincount; // don't count curwin + totwincount--; // don't count curwin } } @@ -2262,7 +2250,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int // Compute maximum number of windows vertically in this frame. n = frame_minheight(topfr, NOWIN); // add one for the bottom window if it doesn't have a statusline or separator - if (row + height == cmdline_row && p_ls == 0) { + if (row + height >= cmdline_row && p_ls == 0) { extra_sep = STATUS_HEIGHT; } else if (global_stl_height() > 0) { extra_sep = 1; @@ -2272,11 +2260,9 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int totwincount = get_maximum_wincount(topfr, n + extra_sep); has_next_curwin = frame_has_win(topfr, next_curwin); - /* - * Compute height for "next_curwin" window and room available for - * other windows. - * "m" is the minimal height when counting p_wh for "next_curwin". - */ + // Compute height for "next_curwin" window and room available for + // other windows. + // "m" is the minimal height when counting p_wh for "next_curwin". m = frame_minheight(topfr, next_curwin); room = height - m; if (room < 0) { @@ -2330,7 +2316,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } if (has_next_curwin) { - --totwincount; // don't count curwin + totwincount--; // don't count curwin } } @@ -2436,7 +2422,7 @@ void entering_window(win_T *const win) void win_init_empty(win_T *wp) { - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); wp->w_lines_valid = 0; wp->w_cursor.lnum = 1; wp->w_curswant = wp->w_cursor.col = 0; @@ -2464,7 +2450,6 @@ void curwin_init(void) void close_windows(buf_T *buf, bool keep_curwin) { tabpage_T *tp, *nexttp; - int h = tabline_height(); RedrawingDisabled++; @@ -2489,7 +2474,8 @@ void close_windows(buf_T *buf, bool keep_curwin) for (tp = first_tabpage; tp != NULL; tp = nexttp) { nexttp = tp->tp_next; if (tp != curtab) { - FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + // Start from tp_lastwin to close floating windows with the same buffer first. + for (win_T *wp = tp->tp_lastwin; wp != NULL; wp = wp->w_prev) { if (wp->w_buffer == buf && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { win_close_othertab(wp, false, tp); @@ -2504,11 +2490,6 @@ void close_windows(buf_T *buf, bool keep_curwin) } RedrawingDisabled--; - - redraw_tabline = true; - if (h != tabline_height()) { - win_new_screen_rows(); - } } /// Check that the specified window is the last one. @@ -2592,16 +2573,13 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev free_buf = false; } - /* - * Closing the last window in a tab page. First go to another tab - * page and then close the window and the tab page. This avoids that - * curwin and curtab are invalid while we are freeing memory, they may - * be used in GUI events. - * Don't trigger autocommands yet, they may use wrong values, so do - * that below. - */ + // Closing the last window in a tab page. First go to another tab + // page and then close the window and the tab page. This avoids that + // curwin and curtab are invalid while we are freeing memory, they may + // be used in GUI events. + // Don't trigger autocommands yet, they may use wrong values, so do + // that below. goto_tabpage_tp(alt_tabpage(), false, true); - redraw_tabline = true; // save index for tabclosed event char_u prev_idx[NUMBUFLEN]; @@ -2610,12 +2588,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev // Safety check: Autocommands may have closed the window when jumping // to the other tab page. if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) { - int h = tabline_height(); - win_close_othertab(win, free_buf, prev_curtab); - if (h != tabline_height()) { - win_new_screen_rows(); - } } entering_window(curwin); @@ -2743,10 +2716,8 @@ int win_close(win_T *win, bool free_buf, bool force) } } - /* - * Be careful: If autocommands delete the window or cause this window - * to be the last one left, return now. - */ + // Be careful: If autocommands delete the window or cause this window + // to be the last one left, return now. if (wp->w_buffer != curbuf) { reset_VIsual_and_resel(); // stop Visual mode @@ -2821,7 +2792,10 @@ int win_close(win_T *win, bool free_buf, bool force) if (curtab != prev_curtab && win_valid_any_tab(win) && win->w_buffer == NULL) { // Need to close the window anyway, since the buffer is NULL. + // Don't trigger autocmds with a NULL buffer. + block_autocmds(); win_close_othertab(win, false, prev_curtab); + unblock_autocmds(); return FAIL; } @@ -2858,10 +2832,8 @@ int win_close(win_T *win, bool free_buf, bool force) if (win == curwin) { curwin = wp; if (wp->w_p_pvw || bt_quickfix(wp->w_buffer)) { - /* - * If the cursor goes to the preview or the quickfix window, try - * finding another window to go to. - */ + // If the cursor goes to the preview or the quickfix window, try + // finding another window to go to. for (;;) { if (wp->w_next == NULL) { wp = firstwin; @@ -2886,12 +2858,20 @@ int win_close(win_T *win, bool free_buf, bool force) } if (!was_floating) { + // If last window has a status line now and we don't want one, + // remove the status line. Do this before win_equal(), because + // it may change the height of a window. + last_status(false); + if (!curwin->w_floating && p_ea && (*p_ead == 'b' || *p_ead == dir)) { // If the frame of the closed window contains the new current window, // only resize that frame. Otherwise resize all windows. win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir); } else { (void)win_comp_pos(); + if (*p_spk != 'c') { + win_fix_scroll(false); + } } } @@ -2906,12 +2886,6 @@ int win_close(win_T *win, bool free_buf, bool force) split_disallowed--; - /* - * If last window has a status line now and we don't want one, - * remove the status line. - */ - last_status(false); - // After closing the help window, try restoring the window layout from // before it was opened. if (help_window) { @@ -2935,7 +2909,10 @@ int win_close(win_T *win, bool free_buf, bool force) } curwin->w_pos_changed = true; - redraw_all_later(NOT_VALID); + if (!was_floating) { + // TODO(bfredl): how about no? + redraw_all_later(UPD_NOT_VALID); + } return OK; } @@ -2953,13 +2930,11 @@ static void do_autocmd_winclosed(win_T *win) recursive = false; } -/* - * Close window "win" in tab page "tp", which is not the current tab page. - * This may be the last window in that tab page and result in closing the tab, - * thus "tp" may become invalid! - * Caller must check if buffer is hidden and whether the tabline needs to be - * updated. - */ +// Close window "win" in tab page "tp", which is not the current tab page. +// This may be the last window in that tab page and result in closing the tab, +// thus "tp" may become invalid! +// Caller must check if buffer is hidden and whether the tabline needs to be +// updated. void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) { int dir; @@ -3020,6 +2995,8 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) vim_snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(tp)); } + int h = tabline_height(); + if (tp == first_tabpage) { first_tabpage = tp->tp_next; } else { @@ -3034,6 +3011,10 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) ptp->tp_next = tp->tp_next; } free_tp = true; + redraw_tabline = true; + if (h != tabline_height()) { + win_new_screen_rows(); + } if (has_event(EVENT_TABCLOSED)) { apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer); @@ -3101,7 +3082,7 @@ void win_free_all(void) cmdwin_type = 0; while (first_tabpage->tp_next != NULL) { - tabpage_close(TRUE); + tabpage_close(true); } while (lastwin != NULL && lastwin->w_floating) { @@ -3141,16 +3122,12 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) frame_T *frp_close = win->w_frame; win_T *wp; - /* - * If there is only one window there is nothing to remove. - */ + // If there is only one window there is nothing to remove. if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) { return NULL; } - /* - * Remove the window from its frame. - */ + // Remove the window from its frame. frp2 = win_altframe(win, tp); wp = frame2win(frp2); @@ -3337,9 +3314,7 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp) return target_fr; } -/* - * Return the tabpage that will be used if the current one is closed. - */ +// Return the tabpage that will be used if the current one is closed. static tabpage_T *alt_tabpage(void) { tabpage_T *tp; @@ -3354,9 +3329,7 @@ static tabpage_T *alt_tabpage(void) return tp; } -/* - * Find the left-upper window in frame "frp". - */ +// Find the left-upper window in frame "frp". win_T *frame2win(frame_T *frp) { while (frp->fr_win == NULL) { @@ -3560,10 +3533,8 @@ static bool frame_fixed_width(frame_T *frp) return true; } -/* - * Add a status line to windows at the bottom of "frp". - * Note: Does not check if there is room! - */ +// Add a status line to windows at the bottom of "frp". +// Note: Does not check if there is room! static void frame_add_statusline(frame_T *frp) { win_T *wp; @@ -3700,7 +3671,7 @@ static void frame_add_vsep(const frame_T *frp) wp = frp->fr_win; if (wp->w_vsep_width == 0) { if (wp->w_width > 0) { // don't make it negative - --wp->w_width; + wp->w_width--; } wp->w_vsep_width = 1; } @@ -3751,17 +3722,13 @@ static void frame_add_hsep(const frame_T *frp) } } -/* - * Set frame width from the window it contains. - */ +// Set frame width from the window it contains. static void frame_fix_width(win_T *wp) { wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width; } -/* - * Set frame height from the window it contains. - */ +// Set frame height from the window it contains. static void frame_fix_height(win_T *wp) FUNC_ATTR_NONNULL_ALL { @@ -3916,16 +3883,13 @@ void close_others(int message, int forceit) } } -/* - * Allocate the first window and put an empty buffer in it. - * Called from main(). - * - * Return FAIL when something goes wrong. - */ -int win_alloc_first(void) +// Allocate the first window and put an empty buffer in it. +// Only called from main(). +void win_alloc_first(void) { if (win_alloc_firstwin(NULL) == FAIL) { - return FAIL; + // allocating first buffer before any autocmds should not fail. + abort(); } first_tabpage = alloc_tabpage(); @@ -3934,8 +3898,6 @@ int win_alloc_first(void) curtab->tp_firstwin = firstwin; curtab->tp_lastwin = lastwin; curtab->tp_curwin = curwin; - - return OK; } // Init `aucmd_win`. This can only be done after the first window @@ -3952,12 +3914,10 @@ void win_alloc_aucmd_win(void) RESET_BINDING(aucmd_win); } -/* - * Allocate the first window or the first window in a new tab page. - * When "oldwin" is NULL create an empty buffer for it. - * When "oldwin" is not NULL copy info from it to the new window. - * Return FAIL when something goes wrong (out of memory). - */ +// Allocate the first window or the first window in a new tab page. +// When "oldwin" is NULL create an empty buffer for it. +// When "oldwin" is not NULL copy info from it to the new window. +// Return FAIL when something goes wrong (out of memory). static int win_alloc_firstwin(win_T *oldwin) { curwin = win_alloc(NULL, false); @@ -3989,9 +3949,7 @@ static int win_alloc_firstwin(win_T *oldwin) return OK; } -/* - * Create a frame for window "wp". - */ +// Create a frame for window "wp". static void new_frame(win_T *wp) { frame_T *frp = xcalloc(1, sizeof(frame_T)); @@ -4001,12 +3959,11 @@ static void new_frame(win_T *wp) frp->fr_win = wp; } -/* - * Initialize the window and frame size to the maximum. - */ +// Initialize the window and frame size to the maximum. void win_init_size(void) { firstwin->w_height = (int)ROWS_AVAIL; + firstwin->w_prev_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; @@ -4017,9 +3974,7 @@ void win_init_size(void) topframe->fr_width = Columns; } -/* - * Allocate a new tabpage_T and init the values. - */ +// Allocate a new tabpage_T and init the values. static tabpage_T *alloc_tabpage(void) { static int last_tp_handle = 0; @@ -4030,7 +3985,7 @@ static tabpage_T *alloc_tabpage(void) // Init t: variables. tp->tp_vars = tv_dict_alloc(); init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE); - tp->tp_diff_invalid = TRUE; + tp->tp_diff_invalid = true; tp->tp_ch_used = p_ch; return tp; @@ -4042,7 +3997,7 @@ void free_tabpage(tabpage_T *tp) pmap_del(handle_T)(&tabpage_handles, tp->handle); diff_clear(tp); - for (idx = 0; idx < SNAP_COUNT; ++idx) { + for (idx = 0; idx < SNAP_COUNT; idx++) { clear_snapshot(tp, idx); } vars_clear(&tp->tp_vars->dv_hashtab); // free all t: variables @@ -4115,12 +4070,13 @@ int win_new_tabpage(int after, char_u *filename) win_init_size(); firstwin->w_winrow = tabline_height(); + firstwin->w_prev_winrow = firstwin->w_winrow; win_comp_scroll(curwin); newtp->tp_topframe = topframe; last_status(false); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); tabpage_check_windows(old_curtab); @@ -4141,11 +4097,9 @@ int win_new_tabpage(int after, char_u *filename) return FAIL; } -/* - * Open a new tab page if ":tab cmd" was used. It will edit the same buffer, - * like with ":split". - * Returns OK if a new tab page was created, FAIL otherwise. - */ +// Open a new tab page if ":tab cmd" was used. It will edit the same buffer, +// like with ":split". +// Returns OK if a new tab page was created, FAIL otherwise. int may_open_tabpage(void) { int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab; @@ -4158,10 +4112,8 @@ int may_open_tabpage(void) return FAIL; } -/* - * Create up to "maxcount" tabpages with empty windows. - * Returns the number of resulting tab pages. - */ +// Create up to "maxcount" tabpages with empty windows. +// Returns the number of resulting tab pages. int make_tabpages(int maxcount) { int count = maxcount; @@ -4172,13 +4124,11 @@ int make_tabpages(int maxcount) count = (int)p_tpm; } - /* - * Don't execute autocommands while creating the tab pages. Must do that - * when putting the buffers in the windows. - */ + // Don't execute autocommands while creating the tab pages. Must do that + // when putting the buffers in the windows. block_autocmds(); - for (todo = count - 1; todo > 0; --todo) { + for (todo = count - 1; todo > 0; todo--) { if (win_new_tabpage(0, NULL) == FAIL) { break; } @@ -4242,9 +4192,7 @@ void close_tabpage(tabpage_T *tab) free_tabpage(tab); } -/* - * Find tab page "n" (first one is 1). Returns NULL when not found. - */ +// Find tab page "n" (first one is 1). Returns NULL when not found. tabpage_T *find_tabpage(int n) { tabpage_T *tp; @@ -4256,10 +4204,8 @@ tabpage_T *find_tabpage(int n) return tp; } -/* - * Get index of tab page "tp". First one has index 1. - * When not found returns number of tab pages plus one. - */ +// Get index of tab page "tp". First one has index 1. +// When not found returns number of tab pages plus one. int tabpage_index(tabpage_T *ftp) { int i = 1; @@ -4348,13 +4294,18 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a // 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; + if (msg_grid.chars && p_ch < curtab->tp_ch_used) { + // TODO(bfredl): a bit expensive, should be enough to invalidate the + // region between the old and the new p_ch. + grid_invalidate(&msg_grid); + } } p_ch = curtab->tp_ch_used; // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is // changed but p_ch and tp_ch_used are not changed. Thus we also need to // check cmdline_row. - if ((row < cmdline_row) && (cmdline_row <= Rows - p_ch)) { + if (row < cmdline_row && cmdline_row <= Rows - p_ch) { clear_cmdline = true; } @@ -4378,7 +4329,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a } } - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } /// tells external UI that windows and inline floats in old_curtab are invisible @@ -4410,10 +4361,8 @@ static void tabpage_check_windows(tabpage_T *old_curtab) } } -/* - * Go to tab page "n". For ":tab N" and "Ngt". - * When "n" is 9999 go to the last tab page. - */ +// Go to tab page "n". For ":tab N" and "Ngt". +// When "n" is 9999 go to the last tab page. void goto_tabpage(int n) { tabpage_T *tp = NULL; // shut up compiler @@ -4445,7 +4394,7 @@ void goto_tabpage(int n) // "gT": go to previous tab page, wrap around end. "N gT" repeats // this N times. ttp = curtab; - for (i = n; i < 0; ++i) { + for (i = n; i < 0; i++) { for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL; tp = tp->tp_next) {} ttp = tp; @@ -4479,6 +4428,7 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le // Don't repeat a message in another tab page. set_keep_msg(NULL, 0); + skip_win_fix_scroll = true; if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer, trigger_leave_autocmds) == OK) { if (valid_tabpage(tp)) { @@ -4489,6 +4439,7 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le trigger_leave_autocmds); } } + skip_win_fix_scroll = false; } /// Go to the last accessed tab page, if there is one. @@ -4502,10 +4453,8 @@ bool goto_tabpage_lastused(void) return false; } -/* - * Enter window "wp" in tab page "tp". - * Also updates the GUI tab. - */ +// Enter window "wp" in tab page "tp". +// Also updates the GUI tab. void goto_tabpage_win(tabpage_T *tp, win_T *wp) { goto_tabpage_tp(tp, true, true); @@ -4568,13 +4517,11 @@ void tabpage_move(int nr) redraw_tabline = true; } -/* - * Go to another window. - * When jumping to another buffer, stop Visual mode. Do this before - * changing windows so we can yank the selection into the '*' register. - * When jumping to another window on the same buffer, adjust its cursor - * position to keep the same Visual area. - */ +// Go to another window. +// When jumping to another buffer, stop Visual mode. Do this before +// changing windows so we can yank the selection into the '*' register. +// When jumping to another window on the same buffer, adjust its cursor +// position to keep the same Visual area. void win_goto(win_T *wp) { win_T *owp = curwin; @@ -4601,9 +4548,7 @@ void win_goto(win_T *wp) } } -/* - * Find the tabpage for window "win". - */ +// Find the tabpage for window "win". tabpage_T *win_find_tabpage(win_T *win) { FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -4636,10 +4581,8 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count) } while (count--) { - /* - * First go upwards in the tree of frames until we find an upwards or - * downwards neighbor. - */ + // First go upwards in the tree of frames until we find an upwards or + // downwards neighbor. fr = foundfr; for (;;) { if (fr == tp->tp_topframe) { @@ -4656,9 +4599,7 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count) fr = fr->fr_parent; } - /* - * Now go downwards to find the bottom or top frame in it. - */ + // Now go downwards to find the bottom or top frame in it. for (;;) { if (nfr->fr_layout == FR_LEAF) { foundfr = nfr; @@ -4719,10 +4660,8 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count) } while (count--) { - /* - * First go upwards in the tree of frames until we find a left or - * right neighbor. - */ + // First go upwards in the tree of frames until we find a left or + // right neighbor. fr = foundfr; for (;;) { if (fr == tp->tp_topframe) { @@ -4739,9 +4678,7 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count) fr = fr->fr_parent; } - /* - * Now go downwards to find the leftmost or rightmost frame in it. - */ + // Now go downwards to find the leftmost or rightmost frame in it. for (;;) { if (nfr->fr_layout == FR_LEAF) { foundfr = nfr; @@ -4833,7 +4770,9 @@ static void win_enter_ext(win_T *const wp, const int flags) // Might need to scroll the old window before switching, e.g., when the // cursor was moved. - update_topline(curwin); + if (*p_spk == 'c') { + update_topline(curwin); + } // may have to copy the buffer options when 'cpo' contains 'S' if (wp->w_buffer != curbuf) { @@ -4841,7 +4780,7 @@ static void win_enter_ext(win_T *const wp, const int flags) } if (!curwin_invalid) { prevwin = curwin; // remember for CTRL-W p - curwin->w_redr_status = TRUE; + curwin->w_redr_status = true; } curwin = wp; curbuf = wp->w_buffer; @@ -4850,7 +4789,11 @@ static void win_enter_ext(win_T *const wp, const int flags) if (!virtual_active()) { curwin->w_cursor.coladd = 0; } - changed_line_abv_curs(); // assume cursor position needs updating + if (*p_spk == 'c') { + changed_line_abv_curs(); // assume cursor position needs updating + } else { + win_fix_cursor(true); + } fix_current_dir(); @@ -4872,7 +4815,7 @@ static void win_enter_ext(win_T *const wp, const int flags) curwin->w_redr_status = true; redraw_tabline = true; if (restart_edit) { - redraw_later(curwin, VALID); // causes status line redraw + redraw_later(curwin, UPD_VALID); // causes status line redraw } // change background color according to NormalNC, @@ -4880,11 +4823,11 @@ static void win_enter_ext(win_T *const wp, const int flags) if (curwin->w_hl_attr_normal != curwin->w_hl_attr_normalnc) { // TODO(bfredl): eventually we should be smart enough // to only recompose the window, not redraw it. - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } if (prevwin) { if (prevwin->w_hl_attr_normal != prevwin->w_hl_attr_normalnc) { - redraw_later(prevwin, NOT_VALID); + redraw_later(prevwin, UPD_NOT_VALID); } } @@ -5034,9 +4977,7 @@ static win_T *win_alloc(win_T *after, bool hidden) // initialized yet. gui_create_scrollbar() may trigger a FocusGained // event. block_autocmds(); - /* - * link the window in the window list - */ + // link the window in the window list if (!hidden) { win_append(after, new_wp); } @@ -5066,8 +5007,7 @@ static win_T *win_alloc(win_T *after, bool hidden) foldInitWin(new_wp); unblock_autocmds(); - new_wp->w_match_head = NULL; - new_wp->w_next_match_id = 4; + new_wp->w_next_match_id = 1000; // up to 1000 can be picked by the user return new_wp; } @@ -5200,9 +5140,7 @@ void win_free_grid(win_T *wp, bool reinit) } } -/* - * Append window "wp" in the window list after window "after". - */ +// Append window "wp" in the window list after window "after". void win_append(win_T *after, win_T *wp) { win_T *before; @@ -5248,9 +5186,7 @@ void win_remove(win_T *wp, tabpage_T *tp) } } -/* - * Append frame "frp" in a frame list after frame "after". - */ +// Append frame "frp" in a frame list after frame "after". static void frame_append(frame_T *after, frame_T *frp) { frp->fr_next = after->fr_next; @@ -5261,9 +5197,7 @@ static void frame_append(frame_T *after, frame_T *frp) frp->fr_prev = after; } -/* - * Insert frame "frp" in a frame list before frame "before". - */ +// Insert frame "frp" in a frame list before frame "before". static void frame_insert(frame_T *before, frame_T *frp) { frp->fr_next = before; @@ -5276,9 +5210,7 @@ static void frame_insert(frame_T *before, frame_T *frp) } } -/* - * Remove a frame from a frame list. - */ +// Remove a frame from a frame list. static void frame_remove(frame_T *frp) { if (frp->fr_prev != NULL) { @@ -5335,6 +5267,10 @@ void win_new_screen_rows(void) win_reconfig_floats(); // The size of floats might change compute_cmdrow(); curtab->tp_ch_used = p_ch; + + if (*p_spk != 'c' && !skip_win_fix_scroll) { + win_fix_scroll(true); + } } /// Called from win_new_screensize() after Columns changed. @@ -5367,6 +5303,7 @@ void may_trigger_winscrolled(void) win_T *wp = curwin; if (wp->w_last_topline != wp->w_topline || wp->w_last_leftcol != wp->w_leftcol + || wp->w_last_skipcol != wp->w_skipcol || wp->w_last_width != wp->w_width || wp->w_last_height != wp->w_height) { char winid[NUMBUFLEN]; @@ -5380,15 +5317,14 @@ void may_trigger_winscrolled(void) if (win_valid_any_tab(wp)) { wp->w_last_topline = wp->w_topline; wp->w_last_leftcol = wp->w_leftcol; + wp->w_last_skipcol = wp->w_skipcol; wp->w_last_width = wp->w_width; wp->w_last_height = wp->w_height; } } } -/* - * Save the size of all windows in "gap". - */ +// Save the size of all windows in "gap". void win_size_save(garray_T *gap) { ga_init(gap, (int)sizeof(int), 1); @@ -5455,12 +5391,10 @@ void win_reconfig_floats(void) } } -/* - * Update the position of the windows in frame "topfrp", using the width and - * height of the frames. - * "*row" and "*col" are the top-left position of the frame. They are updated - * to the bottom-right position plus one. - */ +// Update the position of the windows in frame "topfrp", using the width and +// height of the frames. +// "*row" and "*col" are the top-left position of the frame. They are updated +// to the bottom-right position plus one. static void frame_comp_pos(frame_T *topfrp, int *row, int *col) { win_T *wp; @@ -5475,7 +5409,7 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col) // position changed, redraw wp->w_winrow = *row; wp->w_wincol = *col; - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); wp->w_redr_status = true; wp->w_pos_changed = true; } @@ -5496,19 +5430,15 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col) } } -/* - * Set current window height and take care of repositioning other windows to - * fit around it. - */ +// Set current window height and take care of repositioning other windows to +// fit around it. void win_setheight(int height) { win_setheight_win(height, curwin); } -/* - * Set the window height of window "win" and take care of repositioning other - * windows to fit around it. - */ +// Set the window height of window "win" and take care of repositioning other +// windows to fit around it. void win_setheight_win(int height, win_T *win) { // Always keep current window at least one line high, even when 'winminheight' is zero. @@ -5518,7 +5448,7 @@ void win_setheight_win(int height, win_T *win) if (win->w_floating) { win->w_float_config.height = height; win_config_float(win, win->w_float_config); - redraw_later(win, NOT_VALID); + redraw_later(win, UPD_VALID); } else { frame_setheight(win->w_frame, height + win->w_hsep_height + win->w_status_height); @@ -5538,24 +5468,27 @@ void win_setheight_win(int height, win_T *win) curtab->tp_ch_used = p_ch; msg_row = row; msg_col = 0; - redraw_all_later(NOT_VALID); + + if (*p_spk != 'c') { + win_fix_scroll(true); + } + + redraw_all_later(UPD_NOT_VALID); redraw_cmdline = true; } } -/* - * Set the height of a frame to "height" and take care that all frames and - * windows inside it are resized. Also resize frames on the left and right if - * the are in the same FR_ROW frame. - * - * Strategy: - * If the frame is part of a FR_COL frame, try fitting the frame in that - * frame. If that doesn't work (the FR_COL frame is too small), recursively - * go to containing frames to resize them and make room. - * If the frame is part of a FR_ROW frame, all frames must be resized as well. - * Check for the minimal height of the FR_ROW frame. - * At the top level we can also use change the command line height. - */ +// Set the height of a frame to "height" and take care that all frames and +// windows inside it are resized. Also resize frames on the left and right if +// the are in the same FR_ROW frame. +// +// Strategy: +// If the frame is part of a FR_COL frame, try fitting the frame in that +// frame. If that doesn't work (the FR_COL frame is too small), recursively +// go to containing frames to resize them and make room. +// If the frame is part of a FR_ROW frame, all frames must be resized as well. +// Check for the minimal height of the FR_ROW frame. +// At the top level we can also use change the command line height. static void frame_setheight(frame_T *curfrp, int height) { int room; // total number of lines available @@ -5591,17 +5524,14 @@ static void frame_setheight(frame_T *curfrp, int height) } frame_setheight(curfrp->fr_parent, height); } else { - /* - * Column of frames: try to change only frames in this column. - */ - /* - * Do this twice: - * 1: compute room available, if it's not enough try resizing the - * containing frame. - * 2: compute the room available and adjust the height to it. - * Try not to reduce the height of a window with 'winfixheight' set. - */ - for (run = 1; run <= 2; ++run) { + // Column of frames: try to change only frames in this column. + + // Do this twice: + // 1: compute room available, if it's not enough try resizing the + // containing frame. + // 2: compute the room available and adjust the height to it. + // Try not to reduce the height of a window with 'winfixheight' set. + for (run = 1; run <= 2; run++) { room = 0; room_reserved = 0; FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) { @@ -5635,13 +5565,11 @@ static void frame_setheight(frame_T *curfrp, int height) } frame_setheight(curfrp->fr_parent, height + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1); - //NOTREACHED + // NOTREACHED } - /* - * Compute the number of lines we will take from others frames (can be - * negative!). - */ + // Compute the number of lines we will take from others frames (can be + // negative!). take = height - curfrp->fr_height; // If there is not enough room, also reduce the height of a window @@ -5664,17 +5592,13 @@ static void frame_setheight(frame_T *curfrp, int height) topframe->fr_height += room_cmdline; } - /* - * set the current frame to the new height - */ + // set the current frame to the new height frame_new_height(curfrp, height, false, false); - /* - * First take lines from the frames after the current frame. If - * that is not enough, takes lines from frames above the current - * frame. - */ - for (run = 0; run < 2; ++run) { + // First take lines from the frames after the current frame. If + // that is not enough, takes lines from frames above the current + // frame. + for (run = 0; run < 2; run++) { if (run == 0) { frp = curfrp->fr_next; // 1st run: start with next window } else { @@ -5714,10 +5638,8 @@ static void frame_setheight(frame_T *curfrp, int height) } } -/* - * Set current window width and take care of repositioning other windows to - * fit around it. - */ +// Set current window width and take care of repositioning other windows to +// fit around it. void win_setwidth(int width) { win_setwidth_win(width, curwin); @@ -5740,23 +5662,21 @@ void win_setwidth_win(int width, win_T *wp) if (wp->w_floating) { wp->w_float_config.width = width; win_config_float(wp, wp->w_float_config); - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } else { frame_setwidth(wp->w_frame, width + wp->w_vsep_width); // recompute the window positions (void)win_comp_pos(); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } } -/* - * Set the width of a frame to "width" and take care that all frames and - * windows inside it are resized. Also resize frames above and below if the - * are in the same FR_ROW frame. - * - * Strategy is similar to frame_setheight(). - */ +// Set the width of a frame to "width" and take care that all frames and +// windows inside it are resized. Also resize frames above and below if the +// are in the same FR_ROW frame. +// +// Strategy is similar to frame_setheight(). static void frame_setwidth(frame_T *curfrp, int width) { int room; // total number of lines available @@ -5785,15 +5705,13 @@ static void frame_setwidth(frame_T *curfrp, int width) } frame_setwidth(curfrp->fr_parent, width); } else { - /* - * Row of frames: try to change only frames in this row. - * - * Do this twice: - * 1: compute room available, if it's not enough try resizing the - * containing frame. - * 2: compute the room available and adjust the width to it. - */ - for (run = 1; run <= 2; ++run) { + // Row of frames: try to change only frames in this row. + // + // Do this twice: + // 1: compute room available, if it's not enough try resizing the + // containing frame. + // 2: compute the room available and adjust the width to it. + for (run = 1; run <= 2; run++) { room = 0; room_reserved = 0; FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) { @@ -5819,10 +5737,8 @@ static void frame_setwidth(frame_T *curfrp, int width) + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1); } - /* - * Compute the number of lines we will take from others frames (can be - * negative!). - */ + // Compute the number of lines we will take from others frames (can be + // negative!). take = width - curfrp->fr_width; // If there is not enough room, also reduce the width of a window @@ -5836,17 +5752,13 @@ static void frame_setwidth(frame_T *curfrp, int width) room_reserved = 0; } - /* - * set the current frame to the new width - */ + // set the current frame to the new width frame_new_width(curfrp, width, false, false); - /* - * First take lines from the frames right of the current frame. If - * that is not enough, takes lines from frames left of the current - * frame. - */ - for (run = 0; run < 2; ++run) { + // First take lines from the frames right of the current frame. If + // that is not enough, takes lines from frames left of the current + // frame. + for (run = 0; run < 2; run++) { if (run == 0) { frp = curfrp->fr_next; // 1st run: start with next window } else { @@ -6012,10 +5924,8 @@ void win_drag_status_line(win_T *dragwin, int offset) return; } - /* - * Grow frame fr by "offset" lines. - * Doesn't happen when dragging the last status line up. - */ + // Grow frame fr by "offset" lines. + // Doesn't happen when dragging the last status line up. if (fr != NULL) { frame_new_height(fr, fr->fr_height + offset, up, false); } @@ -6025,9 +5935,7 @@ void win_drag_status_line(win_T *dragwin, int offset) } else { fr = curfr->fr_next; // next frame gets smaller } - /* - * Now make the other frames smaller. - */ + // Now make the other frames smaller. while (fr != NULL && offset > 0) { n = frame_minheight(fr, NULL); if (fr->fr_height - offset <= n) { @@ -6051,13 +5959,16 @@ void win_drag_status_line(win_T *dragwin, int offset) cmdline_row = row; p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1); curtab->tp_ch_used = p_ch; - redraw_all_later(SOME_VALID); + + if (*p_spk != 'c') { + win_fix_scroll(true); + } + + redraw_all_later(UPD_SOME_VALID); showmode(); } -/* - * Separator line of dragwin is dragged "offset" lines right (negative is left). - */ +// Separator line of dragwin is dragged "offset" lines right (negative is left). void win_drag_vsep_line(win_T *dragwin, int offset) { frame_T *curfr; @@ -6158,7 +6069,7 @@ void win_drag_vsep_line(win_T *dragwin, int offset) } } (void)win_comp_pos(); - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } #define FRACTION_MULT 16384L @@ -6175,6 +6086,99 @@ void set_fraction(win_T *wp) } } +/// Handle scroll position for 'splitkeep'. Replaces scroll_to_fraction() +/// call from win_set_inner_size(). Instead we iterate over all windows in a +/// tabpage and calculate the new scroll position. +/// TODO(luukvbaal): Ensure this also works with wrapped lines. +/// Requires topline to be able to be set to a bufferline with some +/// offset(row-wise scrolling/smoothscroll). +void win_fix_scroll(int resize) +{ + linenr_T lnum; + + skip_update_topline = true; + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + // Skip when window height has not changed or when floating. + if (!wp->w_floating && wp->w_height != wp->w_prev_height) { + // If window has moved update botline to keep the same screenlines. + if (*p_spk == 's' && wp->w_winrow != wp->w_prev_winrow + && wp->w_botline - 1 <= wp->w_buffer->b_ml.ml_line_count) { + lnum = wp->w_cursor.lnum; + int diff = (wp->w_winrow - wp->w_prev_winrow) + + (wp->w_height - wp->w_prev_height); + wp->w_cursor.lnum = wp->w_botline - 1; + // Add difference in height and row to botline. + if (diff > 0) { + cursor_down_inner(wp, diff); + } else { + cursor_up_inner(wp, -diff); + } + // Bring the new cursor position to the bottom of the screen. + wp->w_fraction = FRACTION_MULT; + scroll_to_fraction(wp, wp->w_prev_height); + wp->w_cursor.lnum = lnum; + } else if (wp == curwin) { + wp->w_valid &= ~VALID_CROW; + } + invalidate_botline_win(wp); + validate_botline(wp); + } + win_comp_scroll(wp); + wp->w_prev_height = wp->w_height; + wp->w_prev_winrow = wp->w_winrow; + } + skip_update_topline = false; + // Ensure cursor is valid when not in normal mode or when resized. + if (!(get_real_state() & (MODE_NORMAL|MODE_CMDLINE|MODE_TERMINAL))) { + win_fix_cursor(false); + } else if (resize) { + win_fix_cursor(true); + } +} + +/// Make sure the cursor position is valid for 'splitkeep'. +/// If it is not, put the cursor position in the jumplist and move it. +/// If we are not in normal mode, scroll to make valid instead. +static void win_fix_cursor(int normal) +{ + win_T *wp = curwin; + long so = get_scrolloff_value(wp); + linenr_T nlnum = 0; + linenr_T lnum = wp->w_cursor.lnum; + + if (wp->w_buffer->b_ml.ml_line_count < wp->w_height + || skip_win_fix_cursor) { + return; + } + + // Determine valid cursor range. + so = MIN(wp->w_height_inner / 2, so); + wp->w_cursor.lnum = wp->w_topline; + linenr_T top = cursor_down_inner(wp, so); + wp->w_cursor.lnum = wp->w_botline - 1; + linenr_T bot = cursor_up_inner(wp, so); + wp->w_cursor.lnum = lnum; + // Check if cursor position is above or below valid cursor range. + if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1) { + nlnum = bot; + } else if (lnum < top && wp->w_topline != 1) { + nlnum = (so == wp->w_height / 2) ? bot : top; + } + + if (nlnum) { // Cursor is invalid for current scroll position. + if (normal) { + // Save to jumplist and set cursor to avoid scrolling. + setmark('\''); + wp->w_cursor.lnum = nlnum; + } else { + // Scroll instead when not in normal mode. + wp->w_fraction = (nlnum == bot) ? FRACTION_MULT : 0; + scroll_to_fraction(wp, wp->w_prev_height); + validate_botline(curwin); + } + } +} + // Set the height of a window. // "height" excludes any window toolbar. // This takes care of the things inside the window, not what happens to the @@ -6193,6 +6197,9 @@ void win_new_height(win_T *wp, int height) wp->w_height = height; wp->w_pos_changed = true; win_set_inner_size(wp, true); + if (wp->w_status_height) { + wp->w_redr_status = true; + } } void scroll_to_fraction(win_T *wp, int prev_height) @@ -6210,10 +6217,8 @@ void scroll_to_fraction(win_T *wp, int prev_height) && (!wp->w_p_scb || wp == curwin) && (height < wp->w_buffer->b_ml.ml_line_count || wp->w_topline > 1)) { - /* - * Find a value for w_topline that shows the cursor at the same - * relative position in the window as before (more or less). - */ + // Find a value for w_topline that shows the cursor at the same + // relative position in the window as before (more or less). lnum = wp->w_cursor.lnum; if (lnum < 1) { // can happen when starting up lnum = 1; @@ -6233,11 +6238,9 @@ void scroll_to_fraction(win_T *wp, int prev_height) } if (sline < 0) { - /* - * Cursor line would go off top of screen if w_wrow was this high. - * Make cursor line the first line in the window. If not enough - * room use w_skipcol; - */ + // Cursor line would go off top of screen if w_wrow was this high. + // Make cursor line the first line in the window. If not enough + // room use w_skipcol; wp->w_wrow = line_size; if (wp->w_wrow >= wp->w_height_inner && (wp->w_width_inner - win_col_off(wp)) > 0) { @@ -6269,10 +6272,8 @@ void scroll_to_fraction(win_T *wp, int prev_height) } if (sline < 0) { - /* - * Line we want at top would go off top of screen. Use next - * line instead. - */ + // Line we want at top would go off top of screen. Use next + // line instead. (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); lnum++; wp->w_wrow -= line_size + sline; @@ -6296,7 +6297,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) } win_comp_scroll(wp); - redraw_later(wp, SOME_VALID); + redraw_later(wp, UPD_SOME_VALID); wp->w_redr_status = true; invalidate_botline_win(wp); } @@ -6316,7 +6317,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) if (height != prev_height) { if (height > 0 && valid_cursor) { - if (wp == curwin) { + if (wp == curwin && *p_spk == 'c') { // w_wrow needs to be valid. When setting 'laststatus' this may // call win_new_height() recursively. validate_cursor(); @@ -6333,11 +6334,10 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) // There is no point in adjusting the scroll position when exiting. Some // values might be invalid. - // Skip scroll_to_fraction() when 'cmdheight' was set to one from zero. - if (!exiting && !made_cmdheight_nonzero && valid_cursor) { + if (valid_cursor && !exiting && *p_spk == 'c') { scroll_to_fraction(wp, prev_height); } - redraw_later(wp, NOT_VALID); // SOME_VALID?? + redraw_later(wp, UPD_SOME_VALID); } if (width != wp->w_width_inner) { @@ -6347,11 +6347,13 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) changed_line_abv_curs_win(wp); invalidate_botline_win(wp); if (wp == curwin) { + skip_update_topline = (*p_spk != 'c'); update_topline(wp); curs_columns(wp, true); // validate w_wrow + skip_update_topline = false; } } - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } if (wp->w_buffer->terminal) { @@ -6388,7 +6390,7 @@ void win_comp_scroll(win_T *wp) { const long old_w_p_scr = wp->w_p_scr; - wp->w_p_scr = wp->w_height / 2; + wp->w_p_scr = wp->w_height_inner / 2; if (wp->w_p_scr == 0) { wp->w_p_scr = 1; } @@ -6399,9 +6401,7 @@ void win_comp_scroll(win_T *wp) } } -/* - * command_height: called whenever p_ch has been changed - */ +/// command_height: called whenever p_ch has been changed. void command_height(void) { int h; @@ -6413,11 +6413,8 @@ void command_height(void) // p_ch was changed in another tab page. curtab->tp_ch_used = p_ch; - // If the space for the command line is already more than 'cmdheight' there - // is nothing to do (window size must have decreased). - if (p_ch > old_p_ch && cmdline_row <= Rows - p_ch) { - return; - } + // Update cmdline_row to what it should be: just below the last window. + cmdline_row = topframe->fr_height + tabline_height() + global_stl_height(); // If cmdline_row is smaller than what it is supposed to be for 'cmdheight' // then set old_p_ch to what it would be, so that the windows get resized @@ -6484,10 +6481,8 @@ void command_height(void) } } -/* - * Resize frame "frp" to be "n" lines higher (negative for less high). - * Also resize the frames it is contained in. - */ +// Resize frame "frp" to be "n" lines higher (negative for less high). +// Also resize the frames it is contained in. static void frame_add_height(frame_T *frp, int n) { frame_new_height(frp, frp->fr_height + n, false, false); @@ -6500,11 +6495,9 @@ static void frame_add_height(frame_T *frp, int n) } } -/* - * Get the file name at the cursor. - * If Visual mode is active, use the selected text if it's in one line. - * Returns the name in allocated memory, NULL for failure. - */ +// Get the file name at the cursor. +// If Visual mode is active, use the selected text if it's in one line. +// Returns the name in allocated memory, NULL for failure. char_u *grab_file_name(long count, linenr_T *file_lnum) { int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC; @@ -6520,27 +6513,25 @@ char_u *grab_file_name(long count, linenr_T *file_lnum) *file_lnum = (linenr_T)getdigits_long(&p, false, 0); } - return find_file_name_in_path((char_u *)ptr, len, options, count, (char_u *)curbuf->b_ffname); + return (char_u *)find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); } return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); } -/* - * Return the file name under or after the cursor. - * - * The 'path' option is searched if the file name is not absolute. - * The string returned has been alloc'ed and should be freed by the caller. - * NULL is returned if the file name or file is not found. - * - * options: - * FNAME_MESS give error messages - * FNAME_EXP expand to path - * FNAME_HYP check for hypertext link - * FNAME_INCL apply "includeexpr" - */ +// Return the file name under or after the cursor. +// +// The 'path' option is searched if the file name is not absolute. +// The string returned has been alloc'ed and should be freed by the caller. +// NULL is returned if the file name or file is not found. +// +// options: +// FNAME_MESS give error messages +// FNAME_EXP expand to path +// FNAME_HYP check for hypertext link +// FNAME_INCL apply "includeexpr" char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum) { - return file_name_in_line(get_cursor_line_ptr(), + return file_name_in_line((char_u *)get_cursor_line_ptr(), curwin->w_cursor.col, options, count, (char_u *)curbuf->b_ffname, file_lnum); } @@ -6557,11 +6548,9 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u bool in_type = true; bool is_url = false; - /* - * search forward for what could be the start of a file name - */ + // search forward for what could be the start of a file name ptr = (char *)line + col; - while (*ptr != NUL && !vim_isfilec(*ptr)) { + while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) { MB_PTR_ADV(ptr); } if (*ptr == NUL) { // nothing found @@ -6571,26 +6560,23 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u return NULL; } - /* - * Search backward for first char of the file name. - * Go one char back to ":" before "//" even when ':' is not in 'isfname'. - */ + // Search backward for first char of the file name. + // Go one char back to ":" before "//" even when ':' is not in 'isfname'. while ((char_u *)ptr > line) { - if ((len = (size_t)(utf_head_off(line, (char_u *)ptr - 1))) > 0) { + if ((len = (size_t)(utf_head_off((char *)line, ptr - 1))) > 0) { ptr -= len + 1; - } else if (vim_isfilec(ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { + } else if (vim_isfilec((uint8_t)ptr[-1]) + || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { ptr--; } else { break; } } - /* - * Search forward for the last char of the file name. - * Also allow "://" when ':' is not in 'isfname'. - */ + // Search forward for the last char of the file name. + // Also allow ":/" when ':' is not in 'isfname'. len = 0; - while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ') + while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ') || ((options & FNAME_HYP) && path_is_url(ptr + len)) || (is_url && vim_strchr(":?&=", ptr[len]) != NULL)) { // After type:// we also include :, ?, & and = as valid characters, so that @@ -6611,10 +6597,8 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u len += (size_t)(utfc_ptr2len(ptr + len)); } - /* - * If there is trailing punctuation, remove it. - * But don't remove "..", could be a directory name. - */ + // If there is trailing punctuation, remove it. + // But don't remove "..", could be a directory name. if (len > 2 && vim_strchr(".,:;!", ptr[len - 1]) != NULL && ptr[len - 2] != '.') { len--; @@ -6629,10 +6613,10 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u // Also accept " line 999" with and without the same translation as // used in last_set_msg(). p = ptr + len; - if (STRNCMP(p, line_english, STRLEN(line_english)) == 0) { - p += STRLEN(line_english); - } else if (STRNCMP(p, line_transl, STRLEN(line_transl)) == 0) { - p += STRLEN(line_transl); + if (STRNCMP(p, line_english, strlen(line_english)) == 0) { + p += strlen(line_english); + } else if (STRNCMP(p, line_transl, strlen(line_transl)) == 0) { + p += strlen(line_transl); } else { p = skipwhite(p); } @@ -6647,7 +6631,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u } } - return find_file_name_in_path((char_u *)ptr, len, options, count, rel_fname); + return (char_u *)find_file_name_in_path(ptr, len, options, count, (char *)rel_fname); } /// Add or remove a status line from window(s), according to the @@ -6761,6 +6745,10 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global) } comp_col(); } + // Set prev_height when difference is due to 'laststatus'. + if (abs(wp->w_height - wp->w_prev_height) == 1) { + wp->w_prev_height = wp->w_height; + } } else if (wp->w_status_height != 0 && is_stl_global) { // If statusline is global and the window has a statusline, replace it with a horizontal // separator @@ -6771,7 +6759,6 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global) wp->w_hsep_height = 0; comp_col(); } - redraw_all_later(SOME_VALID); } else { // For a column or row frame, recursively call this function for all child frames FOR_ALL_FRAMES(fp, fr->fr_child) { @@ -6968,21 +6955,17 @@ void reset_lnums(void) } } -/* - * A snapshot of the window sizes, to restore them after closing the help - * window. - * Only these fields are used: - * fr_layout - * fr_width - * fr_height - * fr_next - * fr_child - * fr_win (only valid for the old curwin, NULL otherwise) - */ +// A snapshot of the window sizes, to restore them after closing the help +// window. +// Only these fields are used: +// fr_layout +// fr_width +// fr_height +// fr_next +// fr_child +// fr_win (only valid for the old curwin, NULL otherwise) -/* - * Create a snapshot of the current frame sizes. - */ +// Create a snapshot of the current frame sizes. void make_snapshot(int idx) { clear_snapshot(curtab, idx); @@ -7006,9 +6989,7 @@ static void make_snapshot_rec(frame_T *fr, frame_T **frp) } } -/* - * Remove any existing snapshot. - */ +// Remove any existing snapshot. static void clear_snapshot(tabpage_T *tp, int idx) { clear_snapshot_rec(tp->tp_snapshot[idx]); @@ -7071,7 +7052,7 @@ void restore_snapshot(int idx, int close_curwin) if (wp != NULL && close_curwin) { win_goto(wp); } - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } clear_snapshot(curtab, idx); } @@ -7093,11 +7074,9 @@ static int check_snapshot_rec(frame_T *sn, frame_T *fr) return OK; } -/* - * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all - * following frames and children. - * Returns a pointer to the old current window, or NULL. - */ +// Copy the size of snapshot frame "sn" to frame "fr". Do the same for all +// following frames and children. +// Returns a pointer to the old current window, or NULL. static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr) { win_T *wp = NULL; @@ -7296,7 +7275,7 @@ char *check_colorcolumn(win_T *wp) return NULL; // buffer was closed } - for (s = (char *)wp->w_p_cc; *s != NUL && count < 255;) { + for (s = wp->w_p_cc; *s != NUL && count < 255;) { if (*s == '-' || *s == '+') { // -N and +N: add to 'textwidth' col = (*s == '-') ? -1 : 1; @@ -7394,19 +7373,6 @@ int win_getid(typval_T *argvars) return 0; } -int win_gotoid(typval_T *argvars) -{ - int id = (int)tv_get_number(&argvars[0]); - - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp->handle == id) { - goto_tabpage_win(tp, wp); - return 1; - } - } - return 0; -} - void win_get_tabwin(handle_T id, int *tabnr, int *winnr) { *tabnr = 0; @@ -7520,16 +7486,16 @@ void get_framelayout(const frame_T *fr, list_T *l, bool outer) } } -void win_ui_flush(void) +void win_ui_flush(bool validate) { FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_pos_changed && wp->w_grid_alloc.chars != NULL) { if (tp == curtab) { - ui_ext_win_position(wp); + ui_ext_win_position(wp, validate); } else { ui_call_win_hide(wp->w_grid_alloc.handle); + wp->w_pos_changed = false; } - wp->w_pos_changed = false; } if (tp == curtab) { ui_ext_win_viewport(wp); diff --git a/src/nvim/window.h b/src/nvim/window.h index b75b8abd9b..a564a0cfad 100644 --- a/src/nvim/window.h +++ b/src/nvim/window.h @@ -17,14 +17,15 @@ #define FNAME_UNESC 32 // remove backslashes used for escaping // arguments for win_split() -#define WSP_ROOM 1 // require enough room -#define WSP_VERT 2 // split vertically -#define WSP_TOP 4 // window at top-left of shell -#define WSP_BOT 8 // window at bottom-right of shell -#define WSP_HELP 16 // creating the help window -#define WSP_BELOW 32 // put new window below/right -#define WSP_ABOVE 64 // put new window above/left -#define WSP_NEWLOC 128 // don't copy location list +#define WSP_ROOM 0x01 // require enough room +#define WSP_VERT 0x02 // split/equalize vertically +#define WSP_HOR 0x04 // equalize horizontally +#define WSP_TOP 0x08 // window at top-left of shell +#define WSP_BOT 0x10 // window at bottom-right of shell +#define WSP_HELP 0x20 // creating the help window +#define WSP_BELOW 0x40 // put new window below/right +#define WSP_ABOVE 0x80 // put new window above/left +#define WSP_NEWLOC 0x100 // don't copy location list // Minimum screen size #define MIN_COLUMNS 12 // minimal columns for screen @@ -44,8 +45,8 @@ typedef struct { do { \ win_T *const wp_ = (wp); \ const pos_T curpos_ = wp_->w_cursor; \ - char_u cwd_[MAXPATHL]; \ - char_u autocwd_[MAXPATHL]; \ + char cwd_[MAXPATHL]; \ + char autocwd_[MAXPATHL]; \ bool apply_acd_ = false; \ int cwd_status_ = FAIL; \ /* Getting and setting directory can be slow on some systems, only do */ \ @@ -55,13 +56,13 @@ typedef struct { && (curwin->w_localdir != NULL || wp->w_localdir != NULL \ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \ || p_acd)) { \ - cwd_status_ = os_dirname(cwd_, MAXPATHL); \ + cwd_status_ = os_dirname((char_u *)cwd_, MAXPATHL); \ } \ /* If 'acd' is set, check we are using that directory. If yes, then */ \ /* apply 'acd' afterwards, otherwise restore the current directory. */ \ if (cwd_status_ == OK && p_acd) { \ do_autochdir(); \ - apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && STRCMP(cwd_, autocwd_) == 0; \ + apply_acd_ = os_dirname((char_u *)autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \ } \ switchwin_T switchwin_; \ if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \ @@ -72,7 +73,7 @@ typedef struct { if (apply_acd_) { \ do_autochdir(); \ } else if (cwd_status_ == OK) { \ - os_chdir((char *)cwd_); \ + os_chdir(cwd_); \ } \ /* Update the status line if the cursor moved. */ \ if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \ |