diff options
Diffstat (limited to 'src')
195 files changed, 9448 insertions, 6692 deletions
diff --git a/src/mpack/mpack_core.c b/src/mpack/mpack_core.c index 4ee67a032a..3424f444b9 100644 --- a/src/mpack/mpack_core.c +++ b/src/mpack/mpack_core.c @@ -173,6 +173,9 @@ MPACK_API int mpack_write(mpack_tokbuf_t *tokbuf, char **buf, size_t *buflen, int mpack_rtoken(const char **buf, size_t *buflen, mpack_token_t *tok) { + if (*buflen == 0) { + return MPACK_EOF; + } unsigned char t = ADVANCE(buf, buflen); if (t < 0x80) { /* positive fixint */ diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index b95709526b..7b56af59da 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -22,24 +22,19 @@ find_package(TreeSitter REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${TreeSitter_INCLUDE_DIRS}) target_link_libraries(main_lib INTERFACE ${TreeSitter_LIBRARIES}) -find_package(UNIBILIUM 2.0 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${UNIBILIUM_INCLUDE_DIRS}) -target_link_libraries(main_lib INTERFACE ${UNIBILIUM_LIBRARIES}) +find_package(unibilium 2.0 REQUIRED) +target_link_libraries(main_lib INTERFACE unibilium) find_package(LibTermkey 0.22 REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIRS}) target_link_libraries(main_lib INTERFACE ${LIBTERMKEY_LIBRARIES}) -find_package(LIBVTERM 0.3 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBVTERM_INCLUDE_DIRS}) -target_link_libraries(main_lib INTERFACE ${LIBVTERM_LIBRARIES}) +find_package(libvterm 0.3 REQUIRED) +target_link_libraries(main_lib INTERFACE libvterm) -if(Iconv_FOUND) - target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${Iconv_INCLUDE_DIRS}) - if(Iconv_LIBRARIES) - target_link_libraries(main_lib INTERFACE ${Iconv_LIBRARIES}) - endif() -endif() +find_package(Iconv REQUIRED) +target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${Iconv_INCLUDE_DIRS}) +target_link_libraries(main_lib INTERFACE ${Iconv_LIBRARIES}) option(ENABLE_LIBINTL "enable libintl" ON) if(ENABLE_LIBINTL) @@ -57,7 +52,7 @@ if(PREFER_LUA) find_package(Lua 5.1 EXACT REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUA_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUA_LIBRARIES}) - # Passive (not REQUIRED): if LUAJIT_FOUND is not set, nvim-test is skipped. + # Passive (not REQUIRED): if LUAJIT_FOUND is not set, fixtures for unittests is skipped. find_package(LuaJit) else() find_package(LuaJit REQUIRED) @@ -65,12 +60,6 @@ else() target_link_libraries(main_lib INTERFACE ${LUAJIT_LIBRARIES}) endif() -# Determine platform's threading library. Set CMAKE_THREAD_PREFER_PTHREAD -# explicitly to indicate a strong preference for pthread. -set(CMAKE_THREAD_PREFER_PTHREAD ON) -find_package(Threads REQUIRED) -target_link_libraries(main_lib INTERFACE ${CMAKE_THREAD_LIBS_INIT}) - option(ENABLE_IWYU "Run include-what-you-use with the compiler." OFF) if(ENABLE_IWYU) find_program(IWYU_PRG NAMES include-what-you-use iwyu) @@ -85,13 +74,18 @@ if(ENABLE_IWYU) string(APPEND iwyu_flags "-Xiwyu;--mapping_file=${PROJECT_SOURCE_DIR}/cmake.config/iwyu/gcc.symbols.imp") set_target_properties(nvim PROPERTIES C_INCLUDE_WHAT_YOU_USE "${iwyu_flags}") - target_compile_definitions(nvim PRIVATE EXITFREE) + target_compile_definitions(main_lib INTERFACE EXITFREE) endif() if(MSVC) - # XXX: /W4 gives too many warnings. #3241 - target_compile_options(main_lib INTERFACE -W1 -wd4311) + # TODO(dundargoc): bump warning level + target_compile_options(main_lib INTERFACE -W2) + + # Disable warnings that give too many false positives. + target_compile_options(main_lib INTERFACE -wd4311 -wd4146) target_compile_definitions(main_lib INTERFACE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE) + + target_sources(main_lib INTERFACE ${CMAKE_CURRENT_LIST_DIR}/os/nvim.manifest) else() target_compile_options(main_lib INTERFACE -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion @@ -179,24 +173,6 @@ if(CI_BUILD) endif() endif() -list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}") -list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}") -check_c_source_compiles(" -#include <unibilium.h> - -int -main(void) -{ - unibi_str_from_var(unibi_var_from_str(\"\")); - return unibi_num_from_var(unibi_var_from_num(0)); -} -" UNIBI_HAS_VAR_FROM) -list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}") -list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}") -if(UNIBI_HAS_VAR_FROM) - target_compile_definitions(main_lib INTERFACE NVIM_UNIBI_HAS_VAR_FROM) -endif() - list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}") check_c_source_compiles(" #include <msgpack.h> @@ -455,8 +431,11 @@ endforeach() list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) -if(NOT MSVC) - # xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306 +# xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306 +if(MSVC) + set_source_files_properties( + ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /wd4090 /wd4244") +else() set_source_files_properties( ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion -Wno-strict-prototypes") endif() @@ -564,11 +543,11 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES} add_custom_command( OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA} ${API_METADATA} ${LUA_API_C_BINDINGS} - COMMAND ${LUA_PRG} ${API_DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} - ${GENERATED_API_DISPATCH} - ${GENERATED_FUNCS_METADATA} ${API_METADATA} - ${LUA_API_C_BINDINGS} - ${API_HEADERS} + COMMAND ${LUA_GEN_PRG} ${API_DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} + ${GENERATED_API_DISPATCH} + ${GENERATED_FUNCS_METADATA} ${API_METADATA} + ${LUA_API_C_BINDINGS} + ${API_HEADERS} DEPENDS ${API_HEADERS} ${MSGPACK_RPC_HEADERS} @@ -613,12 +592,12 @@ add_custom_command( ${GENERATED_UI_EVENTS_REMOTE} ${GENERATED_UI_EVENTS_METADATA} ${GENERATED_UI_EVENTS_CLIENT} - COMMAND ${LUA_PRG} ${API_UI_EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} - ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h - ${GENERATED_UI_EVENTS_CALL} - ${GENERATED_UI_EVENTS_REMOTE} - ${GENERATED_UI_EVENTS_METADATA} - ${GENERATED_UI_EVENTS_CLIENT} + COMMAND ${LUA_GEN_PRG} ${API_UI_EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h + ${GENERATED_UI_EVENTS_CALL} + ${GENERATED_UI_EVENTS_REMOTE} + ${GENERATED_UI_EVENTS_METADATA} + ${GENERATED_UI_EVENTS_CLIENT} DEPENDS ${API_UI_EVENTS_GENERATOR} ${GENERATOR_C_GRAMMAR} @@ -685,8 +664,6 @@ foreach(hfile ${NVIM_GENERATED_FOR_HEADERS}) endif() endforeach() -# Our dependencies come first. - if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") target_link_libraries(main_lib INTERFACE pthread c++abi) endif() @@ -702,6 +679,14 @@ if(UNIX) endif() endif() +if(NOT LUAJIT_FOUND) + message(STATUS "luajit not found, skipping unit tests") +elseif(CMAKE_BUILD_TYPE MATCHES Debug) + glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) + list(APPEND NVIM_SOURCES ${UNIT_TEST_FIXTURES}) + target_compile_definitions(main_lib INTERFACE UNIT_TESTING) +endif() + target_sources(nvim PRIVATE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) @@ -855,38 +840,11 @@ endif() set_target_properties( libnvim PROPERTIES - POSITION_INDEPENDENT_CODE ON OUTPUT_NAME ${LIBNVIM_NAME} ) target_compile_definitions(libnvim PRIVATE MAKE_LIB) target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv_lib) -if(NOT LUAJIT_FOUND) - message(STATUS "luajit not found, skipping nvim-test (unit tests) target") -else() - glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) - add_library( - nvim-test - MODULE - EXCLUDE_FROM_ALL - ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES} - ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} - ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS} - ${UNIT_TEST_FIXTURES} - ) - target_link_libraries(nvim-test PRIVATE ${LUAJIT_LIBRARIES} main_lib PUBLIC libuv_lib) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_link_libraries(nvim-test PRIVATE "-framework CoreServices") - endif() - target_include_directories(nvim-test PRIVATE ${LUAJIT_INCLUDE_DIRS}) - set_target_properties( - nvim-test - PROPERTIES - POSITION_INDEPENDENT_CODE ON - ) - target_compile_definitions(nvim-test PRIVATE UNIT_TESTING) -endif() - if(CLANG_ASAN_UBSAN) message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.") if(CI_BUILD) @@ -977,7 +935,9 @@ add_glob_target( TARGET lintc-clint COMMAND ${PROJECT_SOURCE_DIR}/src/clint.py FLAGS --output=${LINT_OUTPUT_FORMAT} - FILES ${LINT_NVIM_SOURCES}) + FILES ${LINT_NVIM_SOURCES} + EXCLUDE + tui/terminfo_defs.h) add_custom_target(uncrustify-version COMMAND ${CMAKE_COMMAND} diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 931363e199..a2cb297b15 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -404,7 +404,7 @@ cleanup: /// - match: (string) expanded value of |<amatch>| /// - buf: (number) expanded value of |<abuf>| /// - file: (string) expanded value of |<afile>| -/// - data: (any) arbitrary data passed to |nvim_exec_autocmds()| +/// - data: (any) arbitrary data passed from |nvim_exec_autocmds()| /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} /// - once (boolean) optional: defaults to false. Run the autocommand diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 44e7ed3986..ab3b3485e4 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -698,7 +698,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (opts->sign_text.type == kObjectTypeString) { - if (!init_sign_text((char **)&decor.sign_text, + if (!init_sign_text(&decor.sign_text, opts->sign_text.data.string.data)) { api_set_error(err, kErrorTypeValidation, "sign_text is not a valid value"); goto error; diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 8f909e937f..30dcef6127 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -1,8 +1,8 @@ return { - context = { + { 'context', { "types"; - }; - set_decoration_provider = { + }}; + { 'set_decoration_provider', { "on_start"; "on_buf"; "on_win"; @@ -10,8 +10,8 @@ return { "on_end"; "_on_hl_def"; "_on_spell_nav"; - }; - set_extmark = { + }}; + { 'set_extmark', { "id"; "end_line"; "end_row"; @@ -39,8 +39,8 @@ return { "conceal"; "spell"; "ui_watched"; - }; - keymap = { + }}; + { 'keymap', { "noremap"; "nowait"; "silent"; @@ -50,11 +50,11 @@ return { "callback"; "desc"; "replace_keycodes"; - }; - get_commands = { + }}; + { 'get_commands', { "builtin"; - }; - user_command = { + }}; + { 'user_command', { "addr"; "bang"; "bar"; @@ -67,8 +67,8 @@ return { "preview"; "range"; "register"; - }; - float_config = { + }}; + { 'float_config', { "row"; "col"; "width"; @@ -85,25 +85,25 @@ return { "title_pos"; "style"; "noautocmd"; - }; - runtime = { + }}; + { 'runtime', { "is_lua"; "do_source"; - }; - eval_statusline = { + }}; + { 'eval_statusline', { "winid"; "maxwidth"; "fillchar"; "highlights"; "use_winbar"; "use_tabline"; - }; - option = { + }}; + { 'option', { "scope"; "win"; "buf"; - }; - highlight = { + }}; + { 'highlight', { "bold"; "standout"; "strikethrough"; @@ -114,6 +114,7 @@ return { "underdashed"; "italic"; "reverse"; + "altfont"; "nocombine"; "default"; "cterm"; @@ -128,8 +129,8 @@ return { "blend"; "fg_indexed"; "bg_indexed"; - }; - highlight_cterm = { + }}; + { 'highlight_cterm', { "bold"; "standout"; "strikethrough"; @@ -140,16 +141,17 @@ return { "underdashed"; "italic"; "reverse"; + "altfont"; "nocombine"; - }; + }}; -- Autocmds - clear_autocmds = { + { 'clear_autocmds', { "buffer"; "event"; "group"; "pattern"; - }; - create_autocmd = { + }}; + { 'create_autocmd', { "buffer"; "callback"; "command"; @@ -158,24 +160,24 @@ return { "nested"; "once"; "pattern"; - }; - exec_autocmds = { + }}; + { 'exec_autocmds', { "buffer"; "group"; "modeline"; "pattern"; "data"; - }; - get_autocmds = { + }}; + { 'get_autocmds', { "event"; "group"; "pattern"; "buffer"; - }; - create_augroup = { + }}; + { 'create_augroup', { "clear"; - }; - cmd = { + }}; + { 'cmd', { "cmd"; "range"; "count"; @@ -187,12 +189,12 @@ return { "nargs"; "addr"; "nextcmd"; - }; - cmd_magic = { + }}; + { 'cmd_magic', { "file"; "bar"; - }; - cmd_mods = { + }}; + { 'cmd_mods', { "silent"; "emsg_silent"; "unsilent"; @@ -213,16 +215,15 @@ return { "verbose"; "vertical"; "split"; - }; - cmd_mods_filter = { + }}; + { 'cmd_mods_filter', { "pattern"; "force"; - }; - cmd_opts = { + }}; + { 'cmd_opts', { "output"; - }; - echo_opts = { + }}; + { 'echo_opts', { "verbose"; - }; + }}; } - diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 7770ba39d8..58ff552ab7 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -358,7 +358,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) } case kObjectTypeLuaRef: { - char *name = (char *)register_luafunc(api_new_luaref(obj.data.luaref)); + char *name = 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/helpers.c b/src/nvim/api/private/helpers.c index 4ff600618d..519f2cc5bf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -33,7 +33,6 @@ #include "nvim/pos.h" #include "nvim/ui.h" #include "nvim/version.h" -#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/funcs_metadata.generated.h" @@ -151,7 +150,18 @@ bool try_end(Error *err) xfree(msg); } } else if (did_throw) { - api_set_error(err, kErrorTypeException, "%s", current_exception->value); + if (*current_exception->throw_name != NUL) { + if (current_exception->throw_lnum != 0) { + api_set_error(err, kErrorTypeException, "%s, line %" PRIdLINENR ": %s", + current_exception->throw_name, current_exception->throw_lnum, + current_exception->value); + } else { + api_set_error(err, kErrorTypeException, "%s: %s", + current_exception->throw_name, current_exception->value); + } + } else { + api_set_error(err, kErrorTypeException, "%s", current_exception->value); + } discard_current_exception(); } diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 32b294c0ce..e67607a7e4 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -13,7 +13,11 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" +#include "nvim/autocmd.h" #include "nvim/channel.h" +#include "nvim/event/loop.h" +#include "nvim/event/wstream.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/main.h" @@ -27,13 +31,12 @@ #include "nvim/types.h" #include "nvim/ui.h" #include "nvim/vim.h" -#include "nvim/window.h" #define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf)) #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/ui.c.generated.h" -# include "ui_events_remote.generated.h" +# include "ui_events_remote.generated.h" // IWYU pragma: export #endif static PMap(uint64_t) connected_uis = MAP_INIT; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 65b08ecade..a53b30dd8a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1834,7 +1834,7 @@ Dictionary nvim__stats(void) /// - "width" Requested width of the UI /// - "rgb" true if the UI uses RGB colors (false implies |cterm-colors|) /// - "ext_..." Requested UI extensions, see |ui-option| -/// - "chan" Channel id of remote UI or 0 for TUI +/// - "chan" |channel-id| of remote UI Array nvim_list_uis(void) FUNC_API_SINCE(4) { @@ -2271,7 +2271,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * if (sp->userhl == 0) { grpname = get_default_stl_hl(wp, use_winbar); } else if (sp->userhl < 0) { - grpname = (char *)syn_id2name(-sp->userhl); + grpname = syn_id2name(-sp->userhl); } else { snprintf(user_group, sizeof(user_group), "User%d", sp->userhl); grpname = user_group; diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index f81d26b486..0ffeac1bff 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -278,7 +278,7 @@ Dictionary nvim_win_get_config(Window window, Error *err) String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T)); int hi_id = config->border_hl_ids[i]; - char *hi_name = (char *)syn_id2name(hi_id); + char *hi_name = syn_id2name(hi_id); if (hi_name[0]) { ADD(tuple, STRING_OBJ(s)); ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name))); diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index df8ad165ba..e2c234ab29 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -369,11 +369,16 @@ void nvim_win_hide(Window window, Error *err) tabpage_T *tabpage = win_find_tabpage(win); TryState tstate; try_enter(&tstate); - if (tabpage == curtab) { + + // Never close the autocommand window. + if (is_aucmd_win(win)) { + emsg(_(e_autocmd_close)); + } else if (tabpage == curtab) { win_close(win, false, false); } else { win_close_othertab(win, false, tabpage); } + vim_ignored = try_leave(&tstate, err); } diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index 2c0cb771c3..a75ee3bbd5 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -127,10 +127,22 @@ return { 'WinScrolled', -- after a window was scrolled or resized }, aliases = { - BufCreate = 'BufAdd', - BufRead = 'BufReadPost', - BufWrite = 'BufWritePre', - FileEncoding = 'EncodingChanged', + { + 'BufCreate', + 'BufAdd' + }, + { + 'BufRead', + 'BufReadPost' + }, + { + 'BufWrite', + 'BufWritePre' + }, + { + 'FileEncoding', + 'EncodingChanged' + }, }, -- List of nvim-specific events or aliases for the purpose of generating -- syntax file diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index cd1059eb0d..5dcb10751f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -88,6 +88,7 @@ #include "nvim/regexp.h" #include "nvim/runtime.h" #include "nvim/screen.h" +#include "nvim/search.h" #include "nvim/sign.h" #include "nvim/spell.h" #include "nvim/statusline.h" @@ -2254,12 +2255,13 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, regmatch_T regmatch; regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0); - if (regmatch.regprog == NULL) { - xfree(pat); - return -1; - } FOR_ALL_BUFFERS_BACKWARDS(buf) { + if (regmatch.regprog == NULL) { + // invalid pattern, possibly after switching engine + xfree(pat); + return -1; + } if (buf->b_p_bl == find_listed && (!diffmode || diff_mode_buf(buf)) && buflist_match(®match, buf, false) != NULL) { @@ -2337,7 +2339,6 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) int round; char *p; int attempt; - char *patc; bufmatch_T *matches = NULL; *num_file = 0; // return values in case of FAIL @@ -2347,31 +2348,34 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) return FAIL; } - // Make a copy of "pat" and change "^" to "\(^\|[\/]\)". - if (*pat == '^') { - patc = xmalloc(strlen(pat) + 11); - STRCPY(patc, "\\(^\\|[\\/]\\)"); - STRCPY(patc + 11, pat + 1); - } else { - patc = pat; + const bool fuzzy = cmdline_fuzzy_complete(pat); + + char *patc = NULL; + // Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular + // expression matching) + if (!fuzzy) { + if (*pat == '^') { + patc = xmalloc(strlen(pat) + 11); + STRCPY(patc, "\\(^\\|[\\/]\\)"); + STRCPY(patc + 11, pat + 1); + } else { + patc = pat; + } } + fuzmatch_str_T *fuzmatch = NULL; // attempt == 0: try match with '\<', match at start of word // attempt == 1: try match without '\<', match anywhere - for (attempt = 0; attempt <= 1; attempt++) { - if (attempt > 0 && patc == pat) { - break; // there was no anchor, no need to try again - } - + for (attempt = 0; attempt <= (fuzzy ? 0 : 1); attempt++) { regmatch_T regmatch; - regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC); - if (regmatch.regprog == NULL) { - if (patc != pat) { - xfree(patc); + if (!fuzzy) { + if (attempt > 0 && patc == pat) { + break; // there was no anchor, no need to try again } - return FAIL; + regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC); } + int score = 0; // round == 1: Count the matches. // round == 2: Build the array to keep the matches. for (round = 1; round <= 2; round++) { @@ -2387,64 +2391,108 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) continue; } } - p = buflist_match(®match, buf, p_wic); - if (p != NULL) { - if (round == 1) { - count++; - } else { - if (options & WILD_HOME_REPLACE) { - p = home_replace_save(buf, p); - } else { - p = xstrdup(p); + + if (!fuzzy) { + if (regmatch.regprog == NULL) { + // invalid pattern, possibly after recompiling + if (patc != pat) { + xfree(patc); } - if (matches != NULL) { - matches[count].buf = buf; - matches[count].match = p; - count++; - } else { - (*file)[count++] = p; + return FAIL; + } + p = buflist_match(®match, buf, p_wic); + } else { + p = NULL; + // first try matching with the short file name + if ((score = fuzzy_match_str(buf->b_sfname, pat)) != 0) { + p = buf->b_sfname; + } + if (p == NULL) { + // next try matching with the full path file name + if ((score = fuzzy_match_str(buf->b_ffname, pat)) != 0) { + p = buf->b_ffname; } } } + + if (p == NULL) { + continue; + } + + if (round == 1) { + count++; + continue; + } + + if (options & WILD_HOME_REPLACE) { + p = home_replace_save(buf, p); + } else { + p = xstrdup(p); + } + + if (!fuzzy) { + if (matches != NULL) { + matches[count].buf = buf; + matches[count].match = p; + count++; + } else { + (*file)[count++] = p; + } + } else { + fuzmatch[count].idx = count; + fuzmatch[count].str = p; + fuzmatch[count].score = score; + count++; + } } if (count == 0) { // no match found, break here break; } if (round == 1) { - *file = xmalloc((size_t)count * sizeof(**file)); - - if (options & WILD_BUFLASTUSED) { - matches = xmalloc((size_t)count * sizeof(*matches)); + if (!fuzzy) { + *file = xmalloc((size_t)count * sizeof(**file)); + if (options & WILD_BUFLASTUSED) { + matches = xmalloc((size_t)count * sizeof(*matches)); + } + } else { + fuzmatch = xmalloc((size_t)count * sizeof(fuzmatch_str_T)); } } } - vim_regfree(regmatch.regprog); - if (count) { // match(es) found, break here - break; + + if (!fuzzy) { + vim_regfree(regmatch.regprog); + if (count) { // match(es) found, break here + break; + } } } - if (patc != pat) { + if (!fuzzy && patc != pat) { xfree(patc); } - if (matches != NULL) { - if (count > 1) { - qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare); - } - - // if the current buffer is first in the list, place it at the end - if (matches[0].buf == curbuf) { - for (int i = 1; i < count; i++) { - (*file)[i - 1] = matches[i].match; + if (!fuzzy) { + if (matches != NULL) { + if (count > 1) { + qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare); } - (*file)[count - 1] = matches[0].match; - } else { - for (int i = 0; i < count; i++) { - (*file)[i] = matches[i].match; + + // if the current buffer is first in the list, place it at the end + if (matches[0].buf == curbuf) { + for (int i = 1; i < count; i++) { + (*file)[i - 1] = matches[i].match; + } + (*file)[count - 1] = matches[0].match; + } else { + for (int i = 0; i < count; i++) { + (*file)[i] = matches[i].match; + } } + xfree(matches); } - xfree(matches); + } else { + fuzzymatches_to_strmatches(fuzmatch, file, count, false); } *num_file = count; @@ -2452,6 +2500,7 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options) } /// Check for a match on the file name for buffer "buf" with regprog "prog". +/// Note that rmp->regprog may become NULL when switching regexp engine. /// /// @param ignore_case When true, ignore case. Use 'fic' otherwise. static char *buflist_match(regmatch_T *rmp, buf_T *buf, bool ignore_case) @@ -2464,7 +2513,8 @@ static char *buflist_match(regmatch_T *rmp, buf_T *buf, bool ignore_case) return match; } -/// Try matching the regexp in "prog" with file name "name". +/// Try matching the regexp in "rmp->regprog" with file name "name". +/// Note that rmp->regprog may become NULL when switching regexp engine. /// /// @param ignore_case When true, ignore case. Use 'fileignorecase' otherwise. /// @@ -3293,7 +3343,7 @@ void maketitle(void) (SPACE_FOR_DIR - (size_t)(buf_p - buf)), true); #ifdef BACKSLASH_IN_FILENAME // Avoid "c:/name" to be reduced to "c". - if (isalpha((uint8_t)buf_p) && *(buf_p + 1) == ':') { + if (isalpha((uint8_t)(*buf_p)) && *(buf_p + 1) == ':') { buf_p += 2; } #endif @@ -3779,7 +3829,7 @@ static int chk_modeline(linenr_T lnum, int flags) && (s[0] != 'V' || strncmp(skipwhite(e + 1), "set", 3) == 0) && (s[3] == ':' - || (VIM_VERSION_100 >= vers && isdigit(s[3])) + || (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') || (VIM_VERSION_100 > vers && s[3] == '>') || (VIM_VERSION_100 == vers && s[3] == '='))) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index f01edd1ad2..4c99191170 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1392,6 +1392,7 @@ struct window_S { int w_prev_fraction_row; linenr_T w_nrwidth_line_count; // line count when ml_nrwidth_width was computed. + linenr_T w_statuscol_line_count; // line count when 'statuscolumn' width was computed. int w_nrwidth_width; // nr of chars to print line count. qf_info_T *w_llist; // Location list for this window diff --git a/src/nvim/change.c b/src/nvim/change.c index e8c4af9879..06696610b0 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -418,14 +418,7 @@ void appended_lines(linenr_T lnum, linenr_T count) /// Like appended_lines(), but adjust marks first. void appended_lines_mark(linenr_T lnum, long count) { - // Skip mark_adjust when adding a line after the last one, there can't - // be marks there. But it's still needed in diff mode. - if (lnum + count < curbuf->b_ml.ml_line_count || curwin->w_p_diff) { - mark_adjust(lnum + 1, (linenr_T)MAXLNUM, (linenr_T)count, 0L, kExtmarkUndo); - } else { - extmark_adjust(curbuf, lnum + 1, (linenr_T)MAXLNUM, (linenr_T)count, 0L, - kExtmarkUndo); - } + mark_adjust(lnum + 1, (linenr_T)MAXLNUM, (linenr_T)count, 0L, kExtmarkUndo); changed_lines(lnum + 1, 0, lnum + 1, (linenr_T)count, true); } @@ -1694,13 +1687,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } // Postpone calling changed_lines(), because it would mess up folding // with markers. - // Skip mark_adjust when adding a line after the last one, there can't - // be marks there. But still needed in diff mode. - if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count - || curwin->w_p_diff) { - mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, - kExtmarkNOOP); - } + mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, kExtmarkNOOP); did_append = true; } else { // In MODE_VREPLACE state we are starting to replace the next line. diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 4115743e1c..5aec9ccf9d 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -13,6 +13,7 @@ #include <string.h> #include "auto/config.h" +#include "klib/kvec.h" #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" @@ -35,6 +36,7 @@ #include "nvim/plines.h" #include "nvim/pos.h" #include "nvim/state.h" +#include "nvim/strings.h" #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -144,19 +146,19 @@ int buf_init_chartab(buf_T *buf, int global) // options Each option is a list of characters, character numbers or // ranges, separated by commas, e.g.: "200-210,x,#-178,-" for (i = global ? 0 : 3; i <= 3; i++) { - const char_u *p; + const char *p; if (i == 0) { // first round: 'isident' - p = (char_u *)p_isi; + p = p_isi; } else if (i == 1) { // second round: 'isprint' - p = (char_u *)p_isp; + p = p_isp; } else if (i == 2) { // third round: 'isfname' - p = (char_u *)p_isf; + p = p_isf; } else { // i == 3 // fourth round: 'iskeyword' - p = (char_u *)buf->b_p_isk; + p = buf->b_p_isk; } while (*p) { @@ -252,8 +254,8 @@ int buf_init_chartab(buf_T *buf, int global) c++; } - c = *p; - p = (char_u *)skip_to_option_part((char *)p); + c = (uint8_t)(*p); + p = skip_to_option_part(p); if ((c == ',') && (*p == NUL)) { // Trailing comma is not allowed. @@ -538,9 +540,9 @@ static char_u transchar_charbuf[11]; /// @param[in] c Character to translate. /// /// @return translated character into a static buffer. -char_u *transchar(int c) +char *transchar(int c) { - return transchar_buf(curbuf, c); + return (char *)transchar_buf(curbuf, c); } char_u *transchar_buf(const buf_T *buf, int c) @@ -582,7 +584,7 @@ char_u *transchar_byte(const int c) transchar_nonprint(curbuf, transchar_charbuf, c); return transchar_charbuf; } - return transchar(c); + return (char_u *)transchar(c); } /// Convert non-printable characters to 2..4 printable ones diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index b5ec3e7032..5e4b49db24 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -89,9 +89,42 @@ static int compl_match_arraysize; static int compl_startcol; static int compl_selected; -#define SHOW_FILE_TEXT(m) (showtail \ - ? showmatches_gettail(matches[m], false) \ - : matches[m]) +#define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : matches[m]) + +/// Returns true if fuzzy completion is supported for a given cmdline completion +/// context. +static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +{ + return (wop_flags & WOP_FUZZY) + && xp->xp_context != EXPAND_BOOL_SETTINGS + && xp->xp_context != EXPAND_COLORS + && xp->xp_context != EXPAND_COMPILER + && xp->xp_context != EXPAND_DIRECTORIES + && xp->xp_context != EXPAND_FILES + && xp->xp_context != EXPAND_FILES_IN_PATH + && xp->xp_context != EXPAND_FILETYPE + && xp->xp_context != EXPAND_HELP + && xp->xp_context != EXPAND_LUA + && xp->xp_context != EXPAND_OLD_SETTING + && xp->xp_context != EXPAND_OWNSYNTAX + && xp->xp_context != EXPAND_PACKADD + && xp->xp_context != EXPAND_RUNTIME + && xp->xp_context != EXPAND_SHELLCMD + && xp->xp_context != EXPAND_TAGS + && xp->xp_context != EXPAND_TAGS_LISTFILES + && xp->xp_context != EXPAND_USER_LIST + && xp->xp_context != EXPAND_USER_LUA; +} + +/// Returns true if fuzzy completion for cmdline completion is enabled and +/// "fuzzystr" is not empty. If search pattern is empty, then don't use fuzzy +/// matching. +bool cmdline_fuzzy_complete(const char *const fuzzystr) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +{ + return (wop_flags & WOP_FUZZY) && *fuzzystr != NUL; +} /// Sort function for the completion matches. /// <SNR> functions should be sorted to the end. @@ -110,71 +143,75 @@ static int sort_func_compare(const void *s1, const void *s2) } /// Escape special characters in the cmdline completion matches. -static void ExpandEscape(expand_T *xp, char *str, int numfiles, char **files, int options) +static void wildescape(expand_T *xp, const char *str, int numfiles, char **files) { - int i; char *p; const int vse_what = xp->xp_context == EXPAND_BUFFERS ? VSE_BUFFER : VSE_NONE; - // May change home directory back to "~" - if (options & WILD_HOME_REPLACE) { - tilde_replace(str, numfiles, files); - } - - if (options & WILD_ESCAPE) { - if (xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_FILES_IN_PATH - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS - || xp->xp_context == EXPAND_DIRECTORIES) { - // Insert a backslash into a file name before a space, \, %, # - // and wildmatch characters, except '~'. - for (i = 0; i < numfiles; i++) { - // for ":set path=" we need to escape spaces twice - if (xp->xp_backslash == XP_BS_THREE) { - p = vim_strsave_escaped(files[i], " "); - xfree(files[i]); - files[i] = p; + if (xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_FILES_IN_PATH + || xp->xp_context == EXPAND_SHELLCMD + || xp->xp_context == EXPAND_BUFFERS + || xp->xp_context == EXPAND_DIRECTORIES) { + // Insert a backslash into a file name before a space, \, %, # + // and wildmatch characters, except '~'. + for (int i = 0; i < numfiles; i++) { + // for ":set path=" we need to escape spaces twice + if (xp->xp_backslash == XP_BS_THREE) { + p = vim_strsave_escaped(files[i], " "); + xfree(files[i]); + files[i] = p; #if defined(BACKSLASH_IN_FILENAME) - p = vim_strsave_escaped(files[i], (char_u *)" "); - xfree(files[i]); - files[i] = p; + p = vim_strsave_escaped(files[i], " "); + xfree(files[i]); + files[i] = p; #endif - } + } #ifdef BACKSLASH_IN_FILENAME - p = vim_strsave_fnameescape((const char *)files[i], vse_what); + p = vim_strsave_fnameescape(files[i], vse_what); #else - p = vim_strsave_fnameescape((const char *)files[i], - xp->xp_shell ? VSE_SHELL : vse_what); + p = vim_strsave_fnameescape(files[i], xp->xp_shell ? VSE_SHELL : vse_what); #endif - xfree(files[i]); - files[i] = p; + xfree(files[i]); + files[i] = p; - // If 'str' starts with "\~", replace "~" at start of - // files[i] with "\~". - if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') { - escape_fname(&files[i]); - } + // If 'str' starts with "\~", replace "~" at start of + // files[i] with "\~". + if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') { + escape_fname(&files[i]); } - xp->xp_backslash = XP_BS_NONE; + } + xp->xp_backslash = XP_BS_NONE; - // If the first file starts with a '+' escape it. Otherwise it - // could be seen as "+cmd". - if (*files[0] == '+') { - escape_fname(&files[0]); - } - } else if (xp->xp_context == EXPAND_TAGS) { - // Insert a backslash before characters in a tag name that - // would terminate the ":tag" command. - for (i = 0; i < numfiles; i++) { - p = vim_strsave_escaped(files[i], "\\|\""); - xfree(files[i]); - files[i] = p; - } + // If the first file starts with a '+' escape it. Otherwise it + // could be seen as "+cmd". + if (*files[0] == '+') { + escape_fname(&files[0]); + } + } else if (xp->xp_context == EXPAND_TAGS) { + // Insert a backslash before characters in a tag name that + // would terminate the ":tag" command. + for (int i = 0; i < numfiles; i++) { + p = vim_strsave_escaped(files[i], "\\|\""); + xfree(files[i]); + files[i] = p; } } } +/// Escape special characters in the cmdline completion matches. +static void ExpandEscape(expand_T *xp, char *str, int numfiles, char **files, int options) +{ + // May change home directory back to "~" + if (options & WILD_HOME_REPLACE) { + tilde_replace(str, numfiles, files); + } + + if (options & WILD_ESCAPE) { + wildescape(xp, str, numfiles, files); + } +} + /// Return FAIL if this is not an appropriate context in which to do /// completion of anything, return OK if it is (even if there are no matches). /// For the caller, this means that the character is just passed through like a @@ -215,12 +252,19 @@ int nextwild(expand_T *xp, int type, int options, bool escape) assert(ccline->cmdpos >= i); xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i; - if (type == WILD_NEXT || type == WILD_PREV || type == WILD_PUM_WANT) { + if (type == WILD_NEXT || type == WILD_PREV + || type == WILD_PAGEUP || type == WILD_PAGEDOWN + || type == WILD_PUM_WANT) { // Get next/previous match for a previous expanded pattern. p2 = ExpandOne(xp, NULL, NULL, 0, type); } else { + if (cmdline_fuzzy_completion_supported(xp)) { + // If fuzzy matching, don't modify the search string + p1 = xstrdup(xp->xp_pattern); + } else { + p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + } // Translate string into pattern and expand it. - p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); const int use_options = (options | WILD_HOME_REPLACE | WILD_ADD_SLASH @@ -296,7 +340,7 @@ static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches, compl_match_array = xmalloc(sizeof(pumitem_T) * (size_t)compl_match_arraysize); for (int i = 0; i < numMatches; i++) { compl_match_array[i] = (pumitem_T){ - .pum_text = SHOW_FILE_TEXT(i), + .pum_text = SHOW_MATCH(i), .pum_info = NULL, .pum_extra = NULL, .pum_kind = NULL, @@ -397,7 +441,6 @@ static int wildmenu_match_len(expand_T *xp, char *s) /// @param matches list of matches static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int match, int showtail) { -#define L_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : matches[m]) int row; char *buf; int len; @@ -426,7 +469,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m highlight = false; } // count 1 for the ending ">" - clen = wildmenu_match_len(xp, L_MATCH(match)) + 3; + clen = wildmenu_match_len(xp, SHOW_MATCH(match)) + 3; if (match == 0) { first_match = 0; } else if (match < first_match) { @@ -436,7 +479,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m } else { // check if match fits on the screen for (i = first_match; i < match; i++) { - clen += wildmenu_match_len(xp, L_MATCH(i)) + 2; + clen += wildmenu_match_len(xp, SHOW_MATCH(i)) + 2; } if (first_match > 0) { clen += 2; @@ -447,7 +490,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m // if showing the last match, we can add some on the left clen = 2; for (i = match; i < num_matches; i++) { - clen += wildmenu_match_len(xp, L_MATCH(i)) + 2; + clen += wildmenu_match_len(xp, SHOW_MATCH(i)) + 2; if ((long)clen >= Columns) { break; } @@ -459,7 +502,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m } if (add_left) { while (first_match > 0) { - clen += wildmenu_match_len(xp, L_MATCH(first_match - 1)) + 2; + clen += wildmenu_match_len(xp, SHOW_MATCH(first_match - 1)) + 2; if ((long)clen >= Columns) { break; } @@ -479,13 +522,13 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m clen = len; i = first_match; - while (clen + wildmenu_match_len(xp, L_MATCH(i)) + 2 < Columns) { + while (clen + wildmenu_match_len(xp, SHOW_MATCH(i)) + 2 < Columns) { if (i == match) { selstart = buf + len; selstart_col = clen; } - s = L_MATCH(i); + s = SHOW_MATCH(i); // Check for menu separators - replace with '|' emenu = (xp->xp_context == EXPAND_MENUS || xp->xp_context == EXPAND_MENUNAMES); @@ -592,6 +635,44 @@ static char *get_next_or_prev_match(int mode, expand_T *xp, int *p_findex, char findex--; } else if (mode == WILD_NEXT) { findex++; + } else if (mode == WILD_PAGEUP) { + if (findex == 0) { + // at the first entry, don't select any entries + findex = -1; + } else if (findex == -1) { + // no entry is selected. select the last entry + findex = xp->xp_numfiles - 1; + } else { + // go up by the pum height + int ht = pum_get_height(); + if (ht > 3) { + ht -= 2; + } + findex -= ht; + if (findex < 0) { + // few entries left, select the first entry + findex = 0; + } + } + } else if (mode == WILD_PAGEDOWN) { + if (findex == xp->xp_numfiles - 1) { + // at the last entry, don't select any entries + findex = -1; + } else if (findex == -1) { + // no entry is selected. select the first entry + findex = 0; + } else { + // go down by the pum height + int ht = pum_get_height(); + if (ht > 3) { + ht -= 2; + } + findex += ht; + if (findex >= xp->xp_numfiles) { + // few entries left, select the last entry + findex = xp->xp_numfiles - 1; + } + } } else { // mode == WILD_PUM_WANT assert(pum_want.active); findex = pum_want.item; @@ -769,7 +850,9 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode) int i; // first handle the case of using an old match - if (mode == WILD_NEXT || mode == WILD_PREV || mode == WILD_PUM_WANT) { + if (mode == WILD_NEXT || mode == WILD_PREV + || mode == WILD_PAGEUP || mode == WILD_PAGEDOWN + || mode == WILD_PUM_WANT) { return get_next_or_prev_match(mode, xp, &findex, orig_save); } @@ -897,7 +980,7 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in // Expansion was done before and special characters // were escaped, need to halve backslashes. Also // $HOME has been replaced with ~/. - char *exp_path = (char *)expand_env_save_opt(matches[j], true); + char *exp_path = expand_env_save_opt(matches[j], true); char *path = exp_path != NULL ? exp_path : matches[j]; char *halved_slash = backslash_halve_save(path); isdir = os_isdir(halved_slash); @@ -910,14 +993,14 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in isdir = os_isdir(matches[j]); } if (showtail) { - p = SHOW_FILE_TEXT(j); + p = SHOW_MATCH(j); } else { home_replace(NULL, matches[j], NameBuff, MAXPATHL, true); p = NameBuff; } } else { isdir = false; - p = SHOW_FILE_TEXT(j); + p = SHOW_MATCH(j); } lastlen = msg_outtrans_attr(p, isdir ? dir_attr : 0); } @@ -990,7 +1073,7 @@ int showmatches(expand_T *xp, int wildmenu) home_replace(NULL, matches[i], NameBuff, MAXPATHL, true); j = vim_strsize(NameBuff); } else { - j = vim_strsize(SHOW_FILE_TEXT(i)); + j = vim_strsize(SHOW_MATCH(i)); } if (j > maxlen) { maxlen = j; @@ -1092,7 +1175,7 @@ static bool expand_showtail(expand_T *xp) // separator, on DOS the '*' "path\*\file" must not be skipped. if (rem_backslash(s)) { s++; - } else if (vim_strchr("*?[", *s) != NULL) { + } else if (vim_strchr("*?[", (uint8_t)(*s)) != NULL) { return false; } } @@ -1133,6 +1216,7 @@ char *addstar(char *fname, size_t len, int context) || context == EXPAND_OWNSYNTAX || context == EXPAND_FILETYPE || context == EXPAND_PACKADD + || context == EXPAND_RUNTIME || ((context == EXPAND_TAGS_LISTFILES || context == EXPAND_TAGS) && fname[0] == '/')) { retval = xstrnsave(fname, len); @@ -1292,13 +1376,16 @@ static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, in { const char *p = NULL; size_t len = 0; + const bool fuzzy = cmdline_fuzzy_complete(cmd); // 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 'k' command can directly be followed by any character, but do + // accept "keepmarks", "keepalt" and "keepjumps". As fuzzy matching can + // find matches anywhere in the command name, do this only for command + // expansion based on regular expression and not for fuzzy matching. // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' - if (*cmd == 'k' && cmd[1] != 'e') { + if (!fuzzy && (*cmd == 'k' && cmd[1] != 'e')) { eap->cmdidx = CMD_k; p = cmd + 1; } else { @@ -1320,7 +1407,7 @@ static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, in } } // check for non-alpha command - if (p == cmd && vim_strchr("@*!=><&~#", *p) != NULL) { + if (p == cmd && vim_strchr("@*!=><&~#", (uint8_t)(*p)) != NULL) { p++; } len = (size_t)(p - cmd); @@ -1332,7 +1419,11 @@ static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, in eap->cmdidx = excmd_get_cmdidx(cmd, len); - if (cmd[0] >= 'A' && cmd[0] <= 'Z') { + // User defined commands support alphanumeric characters. + // Also when doing fuzzy expansion for non-shell commands, support + // alphanumeric characters. + if ((cmd[0] >= 'A' && cmd[0] <= 'Z') + || (fuzzy && eap->cmdidx != CMD_bang && *p != NUL)) { while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card p++; } @@ -1346,7 +1437,7 @@ static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, in } if (eap->cmdidx == CMD_SIZE) { - if (*cmd == 's' && vim_strchr("cgriI", cmd[1]) != NULL) { + if (*cmd == 's' && vim_strchr("cgriI", (uint8_t)cmd[1]) != NULL) { eap->cmdidx = CMD_substitute; p = cmd + 1; } else if (cmd[0] >= 'A' && cmd[0] <= 'Z') { @@ -1615,6 +1706,78 @@ static const char *set_context_in_lang_cmd(expand_T *xp, const char *arg) return NULL; } +static enum { + EXP_BREAKPT_ADD, ///< expand ":breakadd" sub-commands + EXP_BREAKPT_DEL, ///< expand ":breakdel" sub-commands + EXP_PROFDEL, ///< expand ":profdel" sub-commands +} breakpt_expand_what; + +/// Set the completion context for the :breakadd command. Always returns NULL. +static const char *set_context_in_breakadd_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) +{ + xp->xp_context = EXPAND_BREAKPOINT; + xp->xp_pattern = (char *)arg; + + if (cmdidx == CMD_breakadd) { + breakpt_expand_what = EXP_BREAKPT_ADD; + } else if (cmdidx == CMD_breakdel) { + breakpt_expand_what = EXP_BREAKPT_DEL; + } else { + breakpt_expand_what = EXP_PROFDEL; + } + + const char *p = skipwhite(arg); + if (*p == NUL) { + return NULL; + } + const char *subcmd_start = p; + + if (strncmp("file ", p, 5) == 0 || strncmp("func ", p, 5) == 0) { + // :breakadd file [lnum] <filename> + // :breakadd func [lnum] <funcname> + p += 4; + p = skipwhite(p); + + // skip line number (if specified) + if (ascii_isdigit(*p)) { + p = skipdigits(p); + if (*p != ' ') { + xp->xp_context = EXPAND_NOTHING; + return NULL; + } + p = skipwhite(p); + } + if (strncmp("file", subcmd_start, 4) == 0) { + xp->xp_context = EXPAND_FILES; + } else { + xp->xp_context = EXPAND_USER_FUNC; + } + xp->xp_pattern = (char *)p; + } else if (strncmp("expr ", p, 5) == 0) { + // :breakadd expr <expression> + xp->xp_context = EXPAND_EXPRESSION; + xp->xp_pattern = skipwhite(p + 5); + } + + return NULL; +} + +static const char *set_context_in_scriptnames_cmd(expand_T *xp, const char *arg) +{ + xp->xp_context = EXPAND_NOTHING; + xp->xp_pattern = NULL; + + char *p = skipwhite(arg); + if (ascii_isdigit(*p)) { + return NULL; + } + + xp->xp_context = EXPAND_SCRIPTNAMES; + xp->xp_pattern = p; + + return NULL; +} + /// 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 @@ -1931,6 +2094,10 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa xp->xp_pattern = (char *)arg; break; + case CMD_runtime: + set_context_in_runtime_cmd(xp, arg); + break; + #ifdef HAVE_WORKING_LIBINTL case CMD_language: return set_context_in_lang_cmd(xp, arg); @@ -1969,6 +2136,14 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa xp->xp_pattern = (char *)arg; break; + case CMD_breakadd: + case CMD_profdel: + case CMD_breakdel: + return set_context_in_breakadd_cmd(xp, arg, cmdidx); + + case CMD_scriptnames: + return set_context_in_scriptnames_cmd(xp, arg); + case CMD_lua: xp->xp_context = EXPAND_LUA; break; @@ -2002,7 +2177,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff) // 1. skip comment lines and leading space, colons or bars const char *cmd; - for (cmd = buff; vim_strchr(" \t:|", *cmd) != NULL; cmd++) {} + for (cmd = buff; vim_strchr(" \t:|", (uint8_t)(*cmd)) != NULL; cmd++) {} xp->xp_pattern = (char *)cmd; if (*cmd == NUL) { @@ -2180,7 +2355,7 @@ void set_cmd_context(expand_T *xp, char *str, int len, int col, int use_ccline) } else if (use_ccline && ccline->input_fn) { xp->xp_context = ccline->xp_context; xp->xp_pattern = ccline->cmdbuff; - xp->xp_arg = (char *)ccline->xp_arg; + xp->xp_arg = ccline->xp_arg; } else { while (nextcomm != NULL) { nextcomm = set_one_cmd_context(xp, nextcomm); @@ -2226,7 +2401,12 @@ int expand_cmdline(expand_T *xp, const char *str, int col, int *matchcount, char // add star to file name, or convert to regexp if not exp. files. assert((str + col) - xp->xp_pattern >= 0); xp->xp_pattern_len = (size_t)((str + col) - xp->xp_pattern); - file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + if (cmdline_fuzzy_completion_supported(xp)) { + // If fuzzy matching, don't modify the search string + file_str = xstrdup(xp->xp_pattern); + } else { + file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); + } if (p_wic) { options += WILD_ICASE; @@ -2316,6 +2496,45 @@ static char *get_behave_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) } /// Function given to ExpandGeneric() to obtain the possible arguments of the +/// ":breakadd {expr, file, func, here}" command. +/// ":breakdel {func, file, here}" command. +static char *get_breakadd_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) +{ + char *opts[] = { "expr", "file", "func", "here" }; + + if (idx >= 0 && idx <= 3) { + // breakadd {expr, file, func, here} + if (breakpt_expand_what == EXP_BREAKPT_ADD) { + return opts[idx]; + } else if (breakpt_expand_what == EXP_BREAKPT_DEL) { + // breakdel {func, file, here} + if (idx <= 2) { + return opts[idx + 1]; + } + } else { + // profdel {func, file} + if (idx <= 1) { + return opts[idx + 1]; + } + } + } + return NULL; +} + +/// Function given to ExpandGeneric() to obtain the possible arguments for the +/// ":scriptnames" command. +static char *get_scriptnames_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) +{ + if (!SCRIPT_ID_VALID(idx + 1)) { + return NULL; + } + + scriptitem_T *si = &SCRIPT_ITEM(idx + 1); + home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, true); + return NameBuff; +} + +/// Function given to ExpandGeneric() to obtain the possible arguments of the /// ":messages {clear}" command. static char *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) { @@ -2360,7 +2579,7 @@ static char *get_healthcheck_names(expand_T *xp FUNC_ATTR_UNUSED, int idx) } /// Do the expansion based on xp->xp_context and "rmp". -static int ExpandOther(expand_T *xp, regmatch_T *rmp, char ***matches, int *numMatches) +static int ExpandOther(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int *numMatches) { typedef CompleteListItemGetter ExpandFunc; static struct expgen { @@ -2399,6 +2618,8 @@ static int ExpandOther(expand_T *xp, regmatch_T *rmp, char ***matches, int *numM { EXPAND_ENV_VARS, get_env_name, true, true }, { EXPAND_USER, get_users, true, false }, { EXPAND_ARGLIST, get_arglist_name, true, false }, + { EXPAND_BREAKPOINT, get_breakadd_arg, true, true }, + { EXPAND_SCRIPTNAMES, get_scriptnames_arg, true, false }, { EXPAND_CHECKHEALTH, get_healthcheck_names, true, false }, }; int ret = FAIL; @@ -2410,7 +2631,7 @@ static int ExpandOther(expand_T *xp, regmatch_T *rmp, char ***matches, int *numM if (tab[i].ic) { rmp->rm_ic = true; } - ExpandGeneric(xp, rmp, matches, numMatches, tab[i].func, tab[i].escaped); + ExpandGeneric(pat, xp, rmp, matches, numMatches, tab[i].func, tab[i].escaped); ret = OK; break; } @@ -2450,9 +2671,11 @@ static int map_wildopts_to_ewflags(int options) /// @param options WILD_ flags static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numMatches, int options) { - regmatch_T regmatch; + regmatch_T regmatch = { .rm_ic = false }; int ret; int flags = map_wildopts_to_ewflags(options); + const bool fuzzy = cmdline_fuzzy_complete(pat) + && cmdline_fuzzy_completion_supported(xp); if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES @@ -2493,11 +2716,11 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM } if (xp->xp_context == EXPAND_COLORS) { char *directories[] = { "colors", NULL }; - return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_LUA, numMatches, matches, directories); + return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches, directories); } if (xp->xp_context == EXPAND_COMPILER) { char *directories[] = { "compiler", NULL }; - return ExpandRTDir(pat, DIP_LUA, numMatches, matches, directories); + return ExpandRTDir(pat, 0, numMatches, matches, directories); } if (xp->xp_context == EXPAND_OWNSYNTAX) { char *directories[] = { "syntax", NULL }; @@ -2505,7 +2728,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM } if (xp->xp_context == EXPAND_FILETYPE) { char *directories[] = { "syntax", "indent", "ftplugin", NULL }; - return ExpandRTDir(pat, DIP_LUA, numMatches, matches, directories); + return ExpandRTDir(pat, 0, numMatches, matches, directories); } if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, matches, numMatches); @@ -2516,6 +2739,9 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM if (xp->xp_context == EXPAND_PACKADD) { return ExpandPackAddDir(pat, numMatches, matches); } + if (xp->xp_context == EXPAND_RUNTIME) { + return expand_runtime_cmd(pat, numMatches, matches); + } // When expanding a function name starting with s:, match the <SNR>nr_ // prefix. @@ -2533,26 +2759,30 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM return nlua_expand_pat(xp, pat, numMatches, matches); } - regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); - if (regmatch.regprog == NULL) { - return FAIL; - } + if (!fuzzy) { + regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); + if (regmatch.regprog == NULL) { + return FAIL; + } - // set ignore-case according to p_ic, p_scs and pat - regmatch.rm_ic = ignorecase(pat); + // set ignore-case according to p_ic, p_scs and pat + regmatch.rm_ic = ignorecase(pat); + } if (xp->xp_context == EXPAND_SETTINGS || xp->xp_context == EXPAND_BOOL_SETTINGS) { - ret = ExpandSettings(xp, ®match, numMatches, matches); + ret = ExpandSettings(xp, ®match, pat, numMatches, matches, fuzzy); } else if (xp->xp_context == EXPAND_MAPPINGS) { - ret = ExpandMappings(®match, numMatches, matches); + ret = ExpandMappings(pat, ®match, numMatches, matches); } else if (xp->xp_context == EXPAND_USER_DEFINED) { - ret = ExpandUserDefined(xp, ®match, matches, numMatches); + ret = ExpandUserDefined(pat, xp, ®match, matches, numMatches); } else { - ret = ExpandOther(xp, ®match, matches, numMatches); + ret = ExpandOther(pat, xp, ®match, matches, numMatches); } - vim_regfree(regmatch.regprog); + if (!fuzzy) { + vim_regfree(regmatch.regprog); + } xfree(tofree); return ret; @@ -2565,72 +2795,107 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM /// program. Matching strings are copied into an array, which is returned. /// /// @param func returns a string from the list -static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches, - CompleteListItemGetter func, int escaped) +static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regmatch, + char ***matches, int *numMatches, CompleteListItemGetter func, + int escaped) { - int i; - size_t count = 0; - char *str; + const bool fuzzy = cmdline_fuzzy_complete(pat); + *matches = NULL; + *numMatches = 0; - // count the number of matching names - for (i = 0;; i++) { - str = (*func)(xp, i); - if (str == NULL) { // end of list - break; - } - if (*str == NUL) { // skip empty strings - continue; - } - if (vim_regexec(regmatch, str, (colnr_T)0)) { - count++; - } - } - if (count == 0) { - return; + garray_T ga; + if (!fuzzy) { + ga_init(&ga, sizeof(char *), 30); + } else { + ga_init(&ga, sizeof(fuzmatch_str_T), 30); } - assert(count < INT_MAX); - *numMatches = (int)count; - *matches = xmalloc(count * sizeof(char *)); - // copy the matching names into allocated memory - count = 0; - for (i = 0;; i++) { - str = (*func)(xp, i); + for (int i = 0;; i++) { + char *str = (*func)(xp, i); if (str == NULL) { // End of list. break; } if (*str == NUL) { // Skip empty strings. continue; } - if (vim_regexec(regmatch, str, (colnr_T)0)) { - if (escaped) { - str = vim_strsave_escaped(str, " \t\\."); + + bool match; + int score = 0; + if (xp->xp_pattern[0] != NUL) { + if (!fuzzy) { + match = vim_regexec(regmatch, str, (colnr_T)0); } else { - str = xstrdup(str); + score = fuzzy_match_str(str, pat); + match = (score != 0); } - (*matches)[count++] = str; - if (func == get_menu_names) { - // Test for separator added by get_menu_names(). - str += strlen(str) - 1; - if (*str == '\001') { - *str = '.'; - } + } else { + match = true; + } + + if (!match) { + continue; + } + + if (escaped) { + str = vim_strsave_escaped(str, " \t\\."); + } else { + str = xstrdup(str); + } + + if (fuzzy) { + GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ + .idx = ga.ga_len, + .str = str, + .score = score, + })); + } else { + GA_APPEND(char *, &ga, str); + } + + if (func == get_menu_names) { + // Test for separator added by get_menu_names(). + str += strlen(str) - 1; + if (*str == '\001') { + *str = '.'; } } } - // Sort the results. Keep menu's in the specified order. - if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) { - if (xp->xp_context == EXPAND_EXPRESSION - || xp->xp_context == EXPAND_FUNCTIONS - || xp->xp_context == EXPAND_USER_FUNC) { + if (ga.ga_len == 0) { + return; + } + + // Sort the matches when using regular expression matching and sorting + // applies to the completion context. Menus and scriptnames should be kept + // in the specified order. + const bool sort_matches = !fuzzy + && xp->xp_context != EXPAND_MENUNAMES + && xp->xp_context != EXPAND_MENUS + && xp->xp_context != EXPAND_SCRIPTNAMES; + + // <SNR> functions should be sorted to the end. + const bool funcsort = xp->xp_context == EXPAND_EXPRESSION + || xp->xp_context == EXPAND_FUNCTIONS + || xp->xp_context == EXPAND_USER_FUNC; + + // Sort the matches. + if (sort_matches) { + if (funcsort) { // <SNR> functions should be sorted to the end. - qsort((void *)(*matches), (size_t)(*numMatches), sizeof(char *), sort_func_compare); + qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(char *), sort_func_compare); } else { - sort_strings(*matches, *numMatches); + sort_strings(ga.ga_data, ga.ga_len); } } + if (!fuzzy) { + *matches = ga.ga_data; + *numMatches = ga.ga_len; + } else { + fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, funcsort); + *numMatches = ga.ga_len; + } + // Reset the variables used for special highlight names expansion, so that // they don't show up when getting normal highlight names by ID. reset_expand_highlight(); @@ -2647,30 +2912,31 @@ static void expand_shellcmd_onedir(char *buf, char *s, size_t l, char *pat, char // Expand matches in one directory of $PATH. int ret = expand_wildcards(1, &buf, numMatches, matches, flags); - if (ret == OK) { - ga_grow(gap, *numMatches); - { - for (int i = 0; i < *numMatches; i++) { - char *name = (*matches)[i]; - - if (strlen(name) > l) { - // Check if this name was already found. - hash_T hash = hash_hash((char_u *)name + l); - hashitem_T *hi = - hash_lookup(ht, (const char *)(name + l), strlen(name + l), hash); - if (HASHITEM_EMPTY(hi)) { - // Remove the path that was prepended. - STRMOVE(name, name + l); - ((char **)gap->ga_data)[gap->ga_len++] = name; - hash_add_item(ht, hi, (char_u *)name, hash); - name = NULL; - } - } - xfree(name); + if (ret != OK) { + return; + } + + ga_grow(gap, *numMatches); + + for (int i = 0; i < *numMatches; i++) { + char *name = (*matches)[i]; + + if (strlen(name) > l) { + // Check if this name was already found. + hash_T hash = hash_hash(name + l); + hashitem_T *hi = + hash_lookup(ht, (const char *)(name + l), strlen(name + l), hash); + if (HASHITEM_EMPTY(hi)) { + // Remove the path that was prepended. + STRMOVE(name, name + l); + ((char **)gap->ga_data)[gap->ga_len++] = name; + hash_add_item(ht, hi, name, hash); + name = NULL; } - xfree(*matches); } + xfree(name); } + xfree(*matches); } /// Complete a shell command. @@ -2710,7 +2976,7 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int path = "."; } else { // For an absolute name we don't use $PATH. - if (!path_is_absolute((char_u *)pat)) { + if (!path_is_absolute(pat)) { path = vim_getenv("PATH"); } if (path == NULL) { @@ -2809,22 +3075,28 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T return ret; } -/// Expand names with a function defined by the user. -static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches) +/// Expand names with a function defined by the user (EXPAND_USER_DEFINED and +/// EXPAND_USER_LIST). +static int ExpandUserDefined(const char *const pat, expand_T *xp, regmatch_T *regmatch, + char ***matches, int *numMatches) { - char *e; - garray_T ga; - + const bool fuzzy = cmdline_fuzzy_complete(pat); *matches = NULL; *numMatches = 0; - char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp); + char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp); if (retstr == NULL) { return FAIL; } - ga_init(&ga, (int)sizeof(char *), 3); - for (char *s = retstr; *s != NUL; s = e) { + garray_T ga; + if (!fuzzy) { + ga_init(&ga, (int)sizeof(char *), 3); + } else { + ga_init(&ga, (int)sizeof(fuzmatch_str_T), 3); + } + + for (char *s = retstr, *e; *s != NUL; s = e) { e = vim_strchr(s, '\n'); if (e == NULL) { e = s + strlen(s); @@ -2832,10 +3104,31 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches const char keep = *e; *e = NUL; - const bool skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0; + bool match; + int score = 0; + if (xp->xp_pattern[0] != NUL) { + if (!fuzzy) { + match = vim_regexec(regmatch, s, (colnr_T)0); + } else { + score = fuzzy_match_str(s, pat); + match = (score != 0); + } + } else { + match = true; // match everything + } + *e = keep; - if (!skip) { - GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s))); + + if (match) { + if (!fuzzy) { + GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s))); + } else { + GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ + .idx = ga.ga_len, + .str = xstrnsave(s, (size_t)(e - s)), + .score = score, + })); + } } if (*e != NUL) { @@ -2843,8 +3136,18 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches } } xfree(retstr); - *matches = ga.ga_data; - *numMatches = ga.ga_len; + + if (ga.ga_len == 0) { + return OK; + } + + if (!fuzzy) { + *matches = ga.ga_data; + *numMatches = ga.ga_len; + } else { + fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, false); + *numMatches = ga.ga_len; + } return OK; } @@ -2907,11 +3210,12 @@ 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 *file, garray_T *ga, int expand_options) +/// If "dirs" is true only expand directory names. +void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dirs) { expand_T xpc; ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; + xpc.xp_context = dirs ? EXPAND_DIRECTORIES : EXPAND_FILES; char *buf = xmalloc(MAXPATHL); @@ -3077,8 +3381,7 @@ static int wildmenu_process_key_filenames(CmdlineInfo *cclp, int key, expand_T * j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j); if (vim_ispathsep(cclp->cmdbuff[j]) #ifdef BACKSLASH_IN_FILENAME - && vim_strchr((const char_u *)" *?[{`$%#", cclp->cmdbuff[j + 1]) - == NULL + && vim_strchr(" *?[{`$%#", (uint8_t)cclp->cmdbuff[j + 1]) == NULL #endif ) { if (found) { @@ -3231,14 +3534,23 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false); xpc.xp_pattern_len = strlen(xpc.xp_pattern); } - if (xpc.xp_context == EXPAND_SIGN) { set_context_in_sign_cmd(&xpc, xpc.xp_pattern); xpc.xp_pattern_len = strlen(xpc.xp_pattern); } + if (xpc.xp_context == EXPAND_RUNTIME) { + set_context_in_runtime_cmd(&xpc, xpc.xp_pattern); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + } theend: - pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); + if (cmdline_fuzzy_completion_supported(&xpc)) { + // when fuzzy matching, don't modify the search string + pat = xstrdup(xpc.xp_pattern); + } else { + pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); + } + ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); tv_list_alloc_ret(rettv, xpc.xp_numfiles); diff --git a/src/nvim/cmdexpand.h b/src/nvim/cmdexpand.h index cdd6192086..810e289f7c 100644 --- a/src/nvim/cmdexpand.h +++ b/src/nvim/cmdexpand.h @@ -19,8 +19,8 @@ enum { WILD_ALL_KEEP = 8, WILD_CANCEL = 9, WILD_APPLY = 10, - // WILD_PAGEUP = 11, not ported yet - // WILD_PAGEDOWN = 12, not ported yet + WILD_PAGEUP = 11, + WILD_PAGEDOWN = 12, WILD_PUM_WANT = 13, }; diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index d12ac87bbb..2df82d9355 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -280,7 +280,7 @@ static HistoryType get_histtype(const char *const name, const size_t len, const } } - if (vim_strchr(":=@>?/", name[0]) != NULL && len == 1) { + if (vim_strchr(":=@>?/", (uint8_t)name[0]) != NULL && len == 1) { return hist_char2type(name[0]); } @@ -437,7 +437,7 @@ int clr_history(const int histype) /// Remove all entries matching {str} from a history. /// /// @param histype may be one of the HIST_ values. -static int del_history_entry(int histype, char_u *str) +static int del_history_entry(int histype, char *str) { if (hislen == 0 || histype < 0 || histype >= HIST_COUNT || *str == NUL || hisidx[histype] < 0) { @@ -446,7 +446,7 @@ static int del_history_entry(int histype, char_u *str) const int idx = hisidx[histype]; regmatch_T regmatch; - regmatch.regprog = vim_regcomp((char *)str, RE_MAGIC + RE_STRING); + regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING); if (regmatch.regprog == NULL) { return false; } @@ -560,7 +560,7 @@ void f_histdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // string given: remove all matching entries char buf[NUMBUFLEN]; n = del_history_entry(get_histtype(str, strlen(str), false), - (char_u *)tv_get_string_buf(&argvars[1], buf)); + (char *)tv_get_string_buf(&argvars[1], buf)); } rettv->vval.v_number = n; } @@ -611,7 +611,7 @@ void ex_history(exarg_T *eap) int idx; int i, j, k; char *end; - char_u *arg = (char_u *)eap->arg; + char *arg = eap->arg; if (hislen == 0) { msg(_("'history' option is zero")); @@ -619,12 +619,12 @@ void ex_history(exarg_T *eap) } if (!(ascii_isdigit(*arg) || *arg == '-' || *arg == ',')) { - end = (char *)arg; + end = arg; while (ASCII_ISALPHA(*end) - || vim_strchr(":=@>/?", *end) != NULL) { + || vim_strchr(":=@>/?", (uint8_t)(*end)) != NULL) { end++; } - histype1 = get_histtype((const char *)arg, (size_t)(end - (char *)arg), false); + histype1 = get_histtype(arg, (size_t)(end - arg), false); if (histype1 == HIST_INVALID) { if (STRNICMP(arg, "all", end - (char *)arg) == 0) { histype1 = 0; @@ -637,7 +637,7 @@ void ex_history(exarg_T *eap) histype2 = histype1; } } else { - end = (char *)arg; + end = arg; } if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) { semsg(_(e_trailing_arg), end); diff --git a/src/nvim/context.c b/src/nvim/context.c index b064a92b74..9de6c16536 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -5,7 +5,9 @@ #include <assert.h> #include <stdbool.h> +#include <stdint.h> #include <stdio.h> +#include <string.h> #include "nvim/api/private/converter.h" #include "nvim/api/private/helpers.h" @@ -23,8 +25,6 @@ #include "nvim/message.h" #include "nvim/option.h" #include "nvim/shada.h" -#include "nvim/types.h" -#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "context.c.generated.h" diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 3dfbcd1f81..f7e70a78ce 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -403,7 +403,7 @@ void ex_debug(exarg_T *eap) debug_break_level = debug_break_level_save; } -static char_u *debug_breakpoint_name = NULL; +static char *debug_breakpoint_name = NULL; static linenr_T debug_breakpoint_lnum; /// When debugging or a breakpoint is set on a skipped command, no debug prompt @@ -412,7 +412,7 @@ static linenr_T debug_breakpoint_lnum; /// a skipped command decides itself that a debug prompt should be displayed, it /// can do so by calling dbg_check_skipped(). static int debug_skipped; -static char_u *debug_skipped_name; +static char *debug_skipped_name; /// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is /// at or below the break level. But only when the line is actually @@ -426,8 +426,8 @@ void dbg_check_breakpoint(exarg_T *eap) if (!eap->skip) { char *p; // replace K_SNR with "<SNR>" - if (debug_breakpoint_name[0] == K_SPECIAL - && debug_breakpoint_name[1] == KS_EXTRA + if ((uint8_t)debug_breakpoint_name[0] == K_SPECIAL + && (uint8_t)debug_breakpoint_name[1] == KS_EXTRA && debug_breakpoint_name[2] == KE_SNR) { p = "<SNR>"; } else { @@ -802,7 +802,7 @@ static linenr_T debuggy_find(bool file, char *fname, linenr_T after, garray_T *g // while matching should abort it. prev_got_int = got_int; got_int = false; - if (vim_regexec_prog(&bp->dbg_prog, false, (char_u *)name, (colnr_T)0)) { + if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) { lnum = bp->dbg_lnum; if (fp != NULL) { *fp = bp->dbg_forceit; @@ -857,6 +857,6 @@ static linenr_T debuggy_find(bool file, char *fname, linenr_T after, garray_T *g 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 = (char_u *)name; + debug_breakpoint_name = name; debug_breakpoint_lnum = lnum; } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 037eb9f0d9..63c55ec602 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -7,6 +7,7 @@ #include "nvim/decoration.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" +#include "nvim/fold.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/memory.h" @@ -407,7 +408,7 @@ void decor_redraw_signs(buf_T *buf, int row, int *num_signs, SignTextAttrs sattr } if (j < SIGN_SHOW_MAX) { sattrs[j] = (SignTextAttrs) { - .text = (char *)decor->sign_text, + .text = decor->sign_text, .hl_attr_id = decor->sign_hl_id == 0 ? 0 : syn_id2attr(decor->sign_hl_id), .priority = decor->priority }; @@ -550,7 +551,8 @@ void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true, ns_id, mark_id); } -int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) +/// @param has_fold whether line "lnum" has a fold, or kNone when not calculated yet +int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fold) { buf_T *buf = wp->w_buffer; if (!buf->b_virt_line_blocks) { @@ -564,6 +566,10 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) int end_row = (int)lnum; MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, row, 0, itr); + bool below_fold = lnum > 1 && hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL); + if (has_fold == kNone) { + has_fold = hasFoldingWin(wp, lnum, NULL, NULL, true, NULL); + } while (true) { mtkey_t mark = marktree_itr_current(itr); if (mark.pos.row < 0 || mark.pos.row >= end_row) { @@ -572,8 +578,9 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines) goto next_mark; } bool above = mark.pos.row > (lnum - 2); + bool has_fold_cur = above ? has_fold : below_fold; Decoration *decor = mark.decor_full; - if (decor && decor->virt_lines_above == above) { + if (!has_fold_cur && decor && decor->virt_lines_above == above) { virt_lines += (int)kv_size(decor->virt_lines); if (lines) { kv_splice(*lines, decor->virt_lines); diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index cee1eb2f94..c9ec8ede7f 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -58,7 +58,7 @@ struct Decoration { DecorPriority priority; int col; // fixed col value, like win_col int virt_text_width; // width of virt_text - char_u *sign_text; + char *sign_text; int sign_hl_id; int number_hl_id; int line_hl_id; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 45f00cb41e..032de561b3 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1218,7 +1218,7 @@ void ex_diffpatch(exarg_T *eap) fullname = FullName_save(eap->arg, false); esc_name = vim_strsave_shellescape(fullname != NULL ? fullname : eap->arg, true, true); #else - esc_name = (char *)vim_strsave_shellescape(eap->arg, true, true); + esc_name = vim_strsave_shellescape(eap->arg, true, true); #endif size_t buflen = strlen(tmp_orig) + strlen(esc_name) + strlen(tmp_new) + 16; buf = xmalloc(buflen); @@ -1575,7 +1575,7 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle) // --- file1 2018-03-20 13:23:35.783153140 +0100 // +++ file2 2018-03-20 13:23:41.183156066 +0100 // @@ -1,3 +1,5 @@ - if (isdigit(*line)) { + if (isdigit((uint8_t)(*line))) { *diffstyle = DIFF_ED; } else if ((strncmp(line, "@@ ", 3) == 0)) { *diffstyle = DIFF_UNIFIED; @@ -1593,7 +1593,7 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle) } if (*diffstyle == DIFF_ED) { - if (!isdigit(*line)) { + if (!isdigit((uint8_t)(*line))) { continue; // not the start of a diff block } if (parse_diff_ed(line, hunk) == FAIL) { @@ -2293,7 +2293,7 @@ static bool diff_equal_char(const char *const p1, const char *const p2, int *con static int diff_cmp(char *s1, char *s2) { if ((diff_flags & DIFF_IBLANK) - && (*(char_u *)skipwhite(s1) == NUL || *skipwhite(s2) == NUL)) { + && (*skipwhite(s1) == NUL || *skipwhite(s2) == NUL)) { return 0; } diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 33038dfb9f..a057978a5e 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1489,7 +1489,7 @@ int do_digraph(int c) /// Find a digraph for "val". If found return the string to display it. /// If not found return NULL. -char_u *get_digraph_for_char(int val_arg) +char *get_digraph_for_char(int val_arg) { const int val = val_arg; const digr_T *dp; @@ -1506,7 +1506,7 @@ char_u *get_digraph_for_char(int val_arg) r[0] = dp->char1; r[1] = dp->char2; r[2] = NUL; - return r; + return (char *)r; } dp++; } @@ -1749,16 +1749,16 @@ static void digraph_getlist_appendpair(const digr_T *dp, list_T *l) list_T *l2 = tv_list_alloc(2); tv_list_append_list(l, l2); - char_u buf[30]; - buf[0] = dp->char1; - buf[1] = dp->char2; + char buf[30]; + buf[0] = (char)dp->char1; + buf[1] = (char)dp->char2; buf[2] = NUL; - tv_list_append_string(l2, (char *)buf, -1); + tv_list_append_string(l2, buf, -1); - char_u *p = buf; - p += utf_char2bytes(dp->result, (char *)p); + char *p = buf; + p += utf_char2bytes(dp->result, p); *p = NUL; - tv_list_append_string(l2, (char *)buf, -1); + tv_list_append_string(l2, buf, -1); } void digraph_getlist_common(bool list_all, typval_T *rettv) @@ -1824,7 +1824,7 @@ struct dg_header_entry { static void printdigraph(const digr_T *dp, result_T *previous) FUNC_ATTR_NONNULL_ARG(1) { - char_u buf[30]; + char buf[30]; int list_width = 13; if (dp->result == 0) { @@ -1854,29 +1854,29 @@ static void printdigraph(const digr_T *dp, result_T *previous) } } - char_u *p = &buf[0]; - *p++ = dp->char1; - *p++ = dp->char2; + char *p = &buf[0]; + *p++ = (char)dp->char1; + *p++ = (char)dp->char2; *p++ = ' '; *p = NUL; - msg_outtrans((char *)buf); + msg_outtrans(buf); p = buf; // add a space to draw a composing char on if (utf_iscomposing(dp->result)) { *p++ = ' '; } - p += utf_char2bytes(dp->result, (char *)p); + p += utf_char2bytes(dp->result, p); *p = NUL; - msg_outtrans_attr((char *)buf, HL_ATTR(HLF_8)); + msg_outtrans_attr(buf, HL_ATTR(HLF_8)); p = buf; if (char2cells(dp->result) == 1) { *p++ = ' '; } assert(p >= buf); - vim_snprintf((char *)p, sizeof(buf) - (size_t)(p - buf), " %3d", dp->result); - msg_outtrans((char *)buf); + vim_snprintf(p, sizeof(buf) - (size_t)(p - buf), " %3d", dp->result); + msg_outtrans(buf); } /// Get the two digraph characters from a typval. @@ -1885,7 +1885,7 @@ static int get_digraph_chars(const typval_T *arg, int *char1, int *char2) { char buf_chars[NUMBUFLEN]; const char *chars = tv_get_string_buf_chk(arg, buf_chars); - const char_u *p = (const char_u *)chars; + const char *p = chars; if (p != NULL) { if (*p != NUL) { @@ -1917,7 +1917,7 @@ static bool digraph_set_common(const typval_T *argchars, const typval_T *argdigr if (digraph == NULL) { return false; } - const char_u *p = (const char_u *)digraph; + const char *p = digraph; int n = mb_cptr2char_adv(&p); if (*p != NUL) { semsg(_(e_digraph_argument_must_be_one_character_str), digraph); diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 8fc1a4b029..01ff207c2b 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -400,40 +400,56 @@ static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int /// Prepare and build the 'statuscolumn' string for line "lnum" in window "wp". /// Fill "stcp" with the built status column string and attributes. +/// This can be called three times per win_line(), once for virt_lines, once for +/// the start of the buffer line "lnum" and once for the wrapped lines. /// /// @param[out] stcp Status column attributes static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines, - int cul_attr, int sign_num_attr, int sign_cul_attr, char_u *extra, - foldinfo_T foldinfo, SignTextAttrs *sattrs, statuscol_T *stcp) + int cul_attr, int sign_num_attr, int sign_cul_attr, statuscol_T *stcp, + foldinfo_T foldinfo, SignTextAttrs *sattrs) { - long relnum = 0; - bool wrapped = row != startrow + filler_lines; + long relnum = -1; bool use_cul = use_cursor_line_sign(wp, lnum); + int virtnum = row - startrow - filler_lines; - // Set num, fold and sign text and attrs, empty when wrapped - if (row == startrow) { - relnum = labs(get_cursor_rel_lnum(wp, lnum)); + // When called the first time for line "lnum" set num_attr + if (stcp->num_attr == 0) { stcp->num_attr = sign_num_attr ? sign_num_attr : get_line_number_attr(wp, lnum, row, startrow, filler_lines); - + } + // When called for the first non-filler row of line "lnum" set num v:vars and fold column + if (virtnum == 0) { + relnum = labs(get_cursor_rel_lnum(wp, lnum)); if (compute_foldcolumn(wp, 0)) { size_t n = fill_foldcolumn(stcp->fold_text, wp, foldinfo, lnum); stcp->fold_text[n] = NUL; stcp->fold_attr = win_hl_attr(wp, use_cul ? HLF_CLF : HLF_FC); } } - + // Make sure to clear->set->clear sign column for filler->first->wrapped lines int i = 0; for (; i < wp->w_scwidth; i++) { - SignTextAttrs *sattr = wrapped ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth); + SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth); stcp->sign_text[i] = sattr && sattr->text ? sattr->text : " "; stcp->sign_attr[i] = sattr ? (use_cul && sign_cul_attr ? sign_cul_attr : sattr->hl_attr_id) : win_hl_attr(wp, use_cul ? HLF_CLS : HLF_SC); } stcp->sign_text[i] = NULL; - int width = build_statuscol_str(wp, row == startrow, wrapped, lnum, relnum, - stcp->width, ' ', stcp->text, &stcp->hlrec, stcp); + // When a buffer's line count has changed, make a best estimate for the full + // width of the status column by building with "w_nrwidth_line_count". Add + // potentially truncated width and rebuild before drawing anything. + if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) { + wp->w_statuscol_line_count = wp->w_nrwidth_line_count; + set_vim_var_nr(VV_VIRTNUM, 0); + build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, stcp->width, + ' ', stcp->text, &stcp->hlrec, stcp); + stcp->width += stcp->truncate; + } + set_vim_var_nr(VV_VIRTNUM, virtnum); + + int width = build_statuscol_str(wp, lnum, relnum, stcp->width, + ' ', stcp->text, &stcp->hlrec, stcp); // Force a redraw in case of error or when truncated if (*wp->w_p_stc == NUL || (stcp->truncate > 0 && wp->w_nrwidth < MAX_NUMBERWIDTH)) { if (stcp->truncate) { // Avoid truncating 'statuscolumn' @@ -466,9 +482,8 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i /// /// @param stcp Status column attributes /// @param[out] draw_state Current draw state in win_line() -static void get_statuscol_display_info(LineDrawState *draw_state, int *char_attr, int *n_extrap, - int *c_extrap, int *c_finalp, char_u *extra, char **pp_extra, - statuscol_T *stcp) +static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_state, int *char_attr, + int *n_extrap, int *c_extrap, int *c_finalp, char **pp_extra) { *c_extrap = NUL; *c_finalp = NUL; @@ -509,7 +524,7 @@ static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, && (wp->w_p_culopt_flags & CULOPT_LINE))); } -static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, size_t buf_len) +static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) { long num; char *fmt = "%*ld "; @@ -527,7 +542,7 @@ static inline void get_line_number_str(win_T *wp, linenr_T lnum, char_u *buf, si } } - snprintf((char *)buf, buf_len, fmt, number_width(wp), num); + snprintf(buf, buf_len, fmt, number_width(wp), num); } static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) @@ -608,7 +623,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int row; // row in the window, excl w_winrow ScreenGrid *grid = &wp->w_grid; // grid specific to the window - char_u extra[57]; // sign, line number and 'fdc' must + char extra[57]; // sign, line number and 'fdc' must // fit in here int n_extra = 0; // number of extra chars char *p_extra = NULL; // string of extra chars, plus NUL @@ -802,7 +817,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, nextline[SPWORDLEN] = NUL; if (lnum < wp->w_buffer->b_ml.ml_line_count) { line = ml_get_buf(wp->w_buffer, lnum + 1, false); - spell_cat_line(nextline + SPWORDLEN, (char_u *)line, SPWORDLEN); + spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); } // When a word wrapped from the previous line the start of the current @@ -936,7 +951,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, area_highlighting = true; } VirtLines virt_lines = KV_INITIAL_VALUE; - int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines); + int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); filler_lines += n_virt_lines; if (lnum == wp->w_topline) { filler_lines = wp->w_topfill; @@ -1128,7 +1143,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // no bad word found at line start, don't check until end of a // word spell_hlf = HLF_COUNT; - word_end = (int)(spell_to_word_end((char_u *)ptr, wp) - (char_u *)line + 1); + word_end = (int)(spell_to_word_end(ptr, wp) - line + 1); } else { // bad word found, use attributes until end of word assert(len <= INT_MAX); @@ -1200,6 +1215,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } int sign_idx = 0; + int virt_line_index; + int virt_line_offset = -1; // Repeat for the whole displayed line. for (;;) { int has_match_conc = 0; ///< match wants to conceal @@ -1226,9 +1243,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - // Skip fold, sign and number states if 'statuscolumn' is set. - if (draw_state == WL_FOLD - 1 && n_extra == 0 && statuscol.draw) { - draw_state = WL_STC - 1; + if (draw_state == WL_FOLD - 1 && n_extra == 0) { + if (filler_todo > 0) { + int index = filler_todo - (filler_lines - n_virt_lines); + if (index > 0) { + virt_line_index = (int)kv_size(virt_lines) - index; + assert(virt_line_index >= 0); + virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp); + } + } + if (!virt_line_offset) { + // Skip the column states if there is a "virt_left_col" line. + draw_state = WL_BRI - 1; + } else if (statuscol.draw) { + // Skip fold, sign and number states if 'statuscolumn' is set. + draw_state = WL_STC - 1; + } } if (draw_state == WL_FOLD - 1 && n_extra == 0) { @@ -1259,7 +1289,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_scwidth > 0) { get_sign_display_info(false, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, - &c_extra, &c_final, (char *)extra, sizeof(extra), + &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, &char_attr, sign_idx, sign_cul_attr); sign_idx++; @@ -1284,29 +1314,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) { get_sign_display_info(true, wp, lnum, sattrs, row, startrow, filler_lines, filler_todo, - &c_extra, &c_final, (char *)extra, sizeof(extra), + &c_extra, &c_final, extra, sizeof(extra), &p_extra, &n_extra, &char_attr, sign_idx, sign_cul_attr); } else { // Draw the line number (empty space after wrapping). if (row == startrow + filler_lines) { - get_line_number_str(wp, lnum, (char_u *)extra, sizeof(extra)); + get_line_number_str(wp, lnum, extra, sizeof(extra)); if (wp->w_skipcol > 0) { - for (p_extra = (char *)extra; *p_extra == ' '; p_extra++) { + for (p_extra = extra; *p_extra == ' '; p_extra++) { *p_extra = '-'; } } if (wp->w_p_rl) { // reverse line numbers // like rl_mirror(), but keep the space at the end - char *p2 = skipwhite((char *)extra); + char *p2 = skipwhite(extra); p2 = skiptowhite(p2) - 1; - for (char *p1 = skipwhite((char *)extra); p1 < p2; p1++, p2--) { + for (char *p1 = skipwhite(extra); p1 < p2; p1++, p2--) { const char t = *p1; *p1 = *p2; *p2 = t; } } - p_extra = (char *)extra; + p_extra = extra; c_extra = NUL; } else { c_extra = ' '; @@ -1327,14 +1357,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Draw the 'statuscolumn' if option is set. if (statuscol.draw) { if (statuscol.textp == NULL) { - get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr, sign_num_attr, - sign_cul_attr, extra, foldinfo, sattrs, &statuscol); + get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr, + sign_num_attr, sign_cul_attr, &statuscol, foldinfo, sattrs); if (wp->w_redr_statuscol) { - return 0; + break; } } - get_statuscol_display_info(&draw_state, &char_attr, &n_extra, &c_extra, - &c_final, extra, &p_extra, &statuscol); + get_statuscol_display_info(&statuscol, &draw_state, &char_attr, + &n_extra, &c_extra, &c_final, &p_extra); } } @@ -1413,7 +1443,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } char_attr = win_hl_attr(wp, HLF_DED); } - char *const sbr = (char *)get_showbreak_value(wp); + char *const sbr = get_showbreak_value(wp); if (*sbr != NUL && need_showbreak) { // Draw 'showbreak' at the start of each broken line. p_extra = sbr; @@ -1488,7 +1518,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col == win_col_offset && n_extra == 0 - && row == startrow) { + && row == startrow + filler_lines) { char_attr = win_hl_attr(wp, HLF_FL); linenr_T lnume = lnum + foldinfo.fi_lines - 1; @@ -1509,7 +1539,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col < grid->cols && n_extra == 0 - && row == startrow) { + && row == startrow + filler_lines) { // fill rest of line with 'fold' c_extra = wp->w_p_fcs_chars.fold; c_final = NUL; @@ -1521,7 +1551,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && has_fold && col >= grid->cols && n_extra != 0 - && row == startrow) { + && row == startrow + filler_lines) { // Truncate the folding. n_extra = 0; } @@ -1710,14 +1740,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, || (mb_l > 1 && (!vim_isprintc(mb_c)))) { // Illegal UTF-8 byte: display as <xx>. // Non-BMP character : display as ? or fullwidth ?. - transchar_hex((char *)extra, mb_c); + transchar_hex(extra, mb_c); if (wp->w_p_rl) { // reverse - rl_mirror((char *)extra); + rl_mirror(extra); } - p_extra = (char *)extra; + p_extra = extra; c = (uint8_t)(*p_extra); - mb_c = mb_ptr2char_adv((const char_u **)&p_extra); + mb_c = mb_ptr2char_adv((const char **)&p_extra); mb_utf8 = (c >= 0x80); n_extra = (int)strlen(p_extra); c_extra = NUL; @@ -1805,7 +1835,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, syntax_attr = get_syntax_attr((colnr_T)v - 1, has_spell ? &can_spell : NULL, false); - if (did_emsg) { + if (did_emsg) { // -V547 wp->w_s->b_syn_error = true; has_syntax = false; } else { @@ -1890,7 +1920,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, p = prev_ptr; } cap_col -= (int)(prev_ptr - line); - size_t tmplen = spell_check(wp, (char_u *)p, &spell_hlf, &cap_col, nochange); + size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange); assert(tmplen <= INT_MAX); len = (int)tmplen; word_end = (int)v + len; @@ -1960,7 +1990,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // We have just drawn the showbreak value, no need to add // space for it again. if (vcol == vcol_sbr) { - n_extra -= mb_charlen((char *)get_showbreak_value(wp)); + n_extra -= mb_charlen(get_showbreak_value(wp)); if (n_extra < 0) { n_extra = 0; } @@ -2056,12 +2086,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length - char_u *const sbr = get_showbreak_value(wp); + char *const sbr = get_showbreak_value(wp); // Only adjust the tab_len, when at the first column after the // showbreak value was drawn. if (*sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) { - vcol_adjusted = vcol - mb_charlen((char *)sbr); + vcol_adjusted = vcol - mb_charlen(sbr); } // tab amount depends on current column tab_len = tabstop_padding((colnr_T)vcol_adjusted, @@ -2734,7 +2764,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. if ((wp->w_p_rl ? (col < 0) : (col >= grid->cols)) - && foldinfo.fi_lines == 0 + && (!has_fold || virt_line_offset >= 0) && (draw_state != WL_LINE || *ptr != NUL || filler_todo > 0 @@ -2751,15 +2781,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && !wp->w_p_rl; // Not right-to-left. int draw_col = col - boguscols; - if (filler_todo > 0) { - int index = filler_todo - (filler_lines - n_virt_lines); - if (index > 0) { - int i = (int)kv_size(virt_lines) - index; - assert(i >= 0); - int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset; - draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line, - kHlModeReplace, grid->cols, 0); - } + if (virt_line_offset >= 0) { + draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line, + kHlModeReplace, grid->cols, 0); } else { draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row); } @@ -2819,16 +2843,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, need_showbreak = true; } if (statuscol.draw) { - if (row == startrow + 1 || row == startrow + filler_lines) { + if (row == startrow + filler_lines + 1 || row == startrow + filler_lines) { // Re-evaluate 'statuscolumn' for the first wrapped row and non filler line statuscol.textp = NULL; - } else { // Otherwise just reset the text/hlrec pointers + } else if (statuscol.textp) { + // Draw the already built 'statuscolumn' on the next wrapped or filler line statuscol.textp = statuscol.text; statuscol.hlrecp = statuscol.hlrec; } // Fall back to default columns if the 'n' flag isn't in 'cpo' statuscol.draw = vim_strchr(p_cpo, CPO_NUMCOL) == NULL; } filler_todo--; + virt_line_offset = -1; // When the filler lines are actually below the last line of the // file, don't draw the line itself, break here. if (filler_todo == 0 && (wp->w_botfill || end_fill)) { diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 568dbe99c0..04c342e068 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -126,12 +126,14 @@ static char *provider_err = NULL; void conceal_check_cursor_line(void) { bool should_conceal = conceal_cursor_line(curwin); - if (curwin->w_p_cole > 0 && (conceal_cursor_used != should_conceal)) { - redrawWinline(curwin, curwin->w_cursor.lnum); - // Need to recompute cursor column, e.g., when starting Visual mode - // without concealing. - curs_columns(curwin, true); + if (curwin->w_p_cole <= 0 || conceal_cursor_used == should_conceal) { + return; } + + redrawWinline(curwin, curwin->w_cursor.lnum); + // Need to recompute cursor column, e.g., when starting Visual mode + // without concealing. + curs_columns(curwin, true); } /// Resize default_grid to Rows and Columns. @@ -837,25 +839,29 @@ static bool vsep_connected(win_T *wp, WindowCorner corner) /// Draw the vertical separator right of window "wp" static void draw_vsep_win(win_T *wp) { - if (wp->w_vsep_width) { - // draw the vertical separator right of this window - int hl; - int c = fillchar_vsep(wp, &hl); - grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), - W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); + if (!wp->w_vsep_width) { + return; } + + // draw the vertical separator right of this window + int hl; + int c = fillchar_vsep(wp, &hl); + grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp), + W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); } /// Draw the horizontal separator below window "wp" static void draw_hsep_win(win_T *wp) { - if (wp->w_hsep_height) { - // draw the horizontal separator below this window - int hl; - int c = fillchar_hsep(wp, &hl); - grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, - wp->w_wincol, W_ENDCOL(wp), c, c, hl); + if (!wp->w_hsep_height) { + return; } + + // draw the horizontal separator below this window + int hl; + int c = fillchar_hsep(wp, &hl); + grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1, + wp->w_wincol, W_ENDCOL(wp), c, c, hl); } /// Get the separator connector for specified window corner of window "wp" @@ -1906,7 +1912,7 @@ static void win_update(win_T *wp, DecorProviders *providers) if (j > 0 && !wp->w_botfill && row < wp->w_grid.rows) { // Display filler text below last line. win_line() will check // for ml_line_count+1 and only draw filler lines - foldinfo_T info = FOLDINFO_INIT; + foldinfo_T info = { 0 }; row = win_line(wp, wp->w_botline, row, wp->w_grid.rows, false, false, info, &line_providers, &provider_err); } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b83e732cec..96df6a3044 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -107,10 +107,9 @@ 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 -static char_u *last_insert = NULL; // the text of the previous insert, - // K_SPECIAL is escaped -static int last_insert_skip; // nr of chars in front of previous insert -static int new_insert_skip; // nr of chars in front of current insert +static char *last_insert = NULL; // the text of the previous insert, K_SPECIAL is escaped +static int last_insert_skip; // nr of chars in front of previous insert +static int new_insert_skip; // nr of chars in front of current insert static int did_restart_edit; // "restart_edit" when calling edit() static bool can_cindent; // may do cindenting on this line @@ -324,7 +323,7 @@ static void insert_enter(InsertState *s) // Get the current length of the redo buffer, those characters have to be // skipped if we want to get to the inserted characters. - s->ptr = (char *)get_inserted(); + s->ptr = get_inserted(); if (s->ptr == NULL) { new_insert_skip = 0; } else { @@ -558,12 +557,12 @@ static int insert_execute(VimState *state, int key) // completion: Add to "compl_leader". if (ins_compl_accept_char(s->c)) { // Trigger InsertCharPre. - char_u *str = do_insert_char_pre(s->c); - char_u *p; + char *str = do_insert_char_pre(s->c); + char *p; if (str != NULL) { for (p = str; *p != NUL; MB_PTR_ADV(p)) { - ins_compl_addleader(utf_ptr2char((char *)p)); + ins_compl_addleader(utf_ptr2char(p)); } xfree(str); } else { @@ -1122,7 +1121,7 @@ normalchar: if (!p_paste) { // Trigger InsertCharPre. - char *str = (char *)do_insert_char_pre(s->c); + char *str = do_insert_char_pre(s->c); char *p; if (str != NULL) { @@ -1544,8 +1543,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 = (char_u *)get_cursor_line_ptr(); - curwin->w_cursor.col -= utf_head_off((char *)p, (char *)p + col); + char *p = get_cursor_line_ptr(); + curwin->w_cursor.col -= utf_head_off(p, p + col); curs_columns(curwin, false); // Recompute w_wrow and w_wcol if (curwin->w_wcol < curwin->w_grid.cols) { edit_putchar('$', false); @@ -1579,7 +1578,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang int last_vcol; int insstart_less; // reduction for Insstart.col int new_cursor_col; - char_u *ptr; + char *ptr; int save_p_list; int start_col; colnr_T vc; @@ -1658,9 +1657,9 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang // Advance the cursor until we reach the right screen column. last_vcol = 0; - ptr = (char_u *)get_cursor_line_ptr(); + ptr = get_cursor_line_ptr(); chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, 0, 0, (char *)ptr, (char *)ptr); + init_chartabsize_arg(&cts, curwin, 0, 0, ptr, ptr); while (cts.cts_vcol <= (int)curwin->w_virtcol) { last_vcol = cts.cts_vcol; if (cts.cts_vcol > 0) { @@ -1683,7 +1682,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang ptr = xmallocz(i); memset(ptr, ' ', i); new_cursor_col += (int)i; - ins_str((char *)ptr); + ins_str(ptr); xfree(ptr); } @@ -2062,8 +2061,8 @@ 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 = (char_u *)get_cursor_line_ptr(); - int i = get_leader_len((char *)line, &p, false, true); + char *line = get_cursor_line_ptr(); + int i = get_leader_len(line, &p, false, true); if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) { // Just checking // Skip middle-comment string while (*p && p[-1] != ':') { // find end of middle flags @@ -2304,11 +2303,11 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) // 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 = (char *)get_inserted(); + ptr = get_inserted(); if (did_restart_edit == 0 || (ptr != NULL && (int)strlen(ptr) > new_insert_skip)) { xfree(last_insert); - last_insert = (char_u *)ptr; + last_insert = ptr; last_insert_skip = new_insert_skip; } else { xfree(ptr); @@ -2414,7 +2413,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) // Used for the replace command. void set_last_insert(int c) { - char_u *s; + char *s; xfree(last_insert); last_insert = xmalloc(MB_MAXBYTES * 3 + 5); @@ -2423,7 +2422,7 @@ void set_last_insert(int c) if (c < ' ' || c == DEL) { *s++ = Ctrl_V; } - s = add_char2buf(c, s); + s = (char *)add_char2buf(c, (char_u *)s); *s++ = ESC; *s++ = NUL; last_insert_skip = 0; @@ -2738,12 +2737,12 @@ char_u *get_last_insert(void) if (last_insert == NULL) { return NULL; } - return last_insert + last_insert_skip; + return (char_u *)last_insert + last_insert_skip; } // 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 *get_last_insert_save(void) { char *s; int len; @@ -2751,13 +2750,13 @@ char_u *get_last_insert_save(void) if (last_insert == NULL) { return NULL; } - s = xstrdup((char *)last_insert + last_insert_skip); + s = xstrdup(last_insert + last_insert_skip); len = (int)strlen(s); if (len > 0 && s[len - 1] == ESC) { // remove trailing ESC s[len - 1] = NUL; } - return (char_u *)s; + return s; } /// Check the word in front of the cursor for an abbreviation. @@ -3127,7 +3126,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) // make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>, // <:> and <!> so that people can re-indent on o, O, e, 0, <, // >, *, : and ! keys if they really really want to. - if (vim_strchr("<>!*oOe0:", look[1]) != NULL + if (vim_strchr("<>!*oOe0:", (uint8_t)look[1]) != NULL && keytyped == look[1]) { return true; } @@ -3182,7 +3181,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) // TODO(@brammool): multi-byte if (keytyped == (int)(uint8_t)p[-1] || (icase && keytyped < 256 - && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) { + && TOLOWER_LOC(keytyped) == TOLOWER_LOC((uint8_t)p[-1]))) { line = get_cursor_pos_ptr(); assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX); if ((curwin->w_cursor.col == (colnr_T)(p - look) @@ -3475,7 +3474,7 @@ static void ins_ctrl_hat(void) State |= MODE_LANGMAP; } } - set_iminsert_global(); + set_iminsert_global(curbuf); showmode(); // Show/unshow value of 'keymap' in status lines. status_redraw_curbuf(); @@ -3661,8 +3660,7 @@ static bool ins_start_select(int c) static void ins_insert(int replaceState) { set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" : - replaceState == MODE_VREPLACE ? "v" : - "r"), 1); + replaceState == MODE_VREPLACE ? "v" : "r"), 1); ins_apply_autocmds(EVENT_INSERTCHANGE); if (State & REPLACE_FLAG) { State = MODE_INSERT | (State & MODE_LANGMAP); @@ -4503,7 +4501,7 @@ static bool ins_tab(void) if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 || get_sts_value() > 0 || (p_sta && ind))) { - char_u *ptr; + char *ptr; char *saved_line = NULL; // init for GCC pos_T pos; pos_T fpos; @@ -4518,9 +4516,9 @@ static bool ins_tab(void) pos = curwin->w_cursor; cursor = &pos; saved_line = xstrdup(get_cursor_line_ptr()); - ptr = (char_u *)saved_line + pos.col; + ptr = saved_line + pos.col; } else { - ptr = (char_u *)get_cursor_pos_ptr(); + ptr = get_cursor_pos_ptr(); cursor = &curwin->w_cursor; } @@ -4548,9 +4546,9 @@ static bool ins_tab(void) getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); - char_u *tab = (char_u *)"\t"; + char *tab = "\t"; chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, 0, vcol, (char *)tab, (char *)tab); + init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab); // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' // and 'linebreak' adding extra virtual columns. @@ -4579,13 +4577,13 @@ static bool ins_tab(void) if (change_col >= 0) { int repl_off = 0; // Skip over the spaces we need. - init_chartabsize_arg(&cts, curwin, 0, vcol, (char *)ptr, (char *)ptr); + init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, 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; + ptr = cts.cts_ptr; vcol = cts.cts_vcol; clear_chartabsize_arg(&cts); @@ -4762,8 +4760,8 @@ static int ins_digraph(void) int ins_copychar(linenr_T lnum) { int c; - char_u *ptr, *prev_ptr; - char_u *line; + char *ptr, *prev_ptr; + char *line; if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { vim_beep(BO_COPY); @@ -4771,25 +4769,25 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - line = (char_u *)ml_get(lnum); + line = ml_get(lnum); prev_ptr = line; validate_virtcol(); chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, lnum, 0, (char *)line, (char *)line); + init_chartabsize_arg(&cts, curwin, lnum, 0, line, line); while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) { - prev_ptr = (char_u *)cts.cts_ptr; + prev_ptr = cts.cts_ptr; cts.cts_vcol += lbr_chartabsize_adv(&cts); } if (cts.cts_vcol > curwin->w_virtcol) { ptr = prev_ptr; } else { - ptr = (char_u *)cts.cts_ptr; + ptr = cts.cts_ptr; } clear_chartabsize_arg(&cts); - c = utf_ptr2char((char *)ptr); + c = utf_ptr2char(ptr); if (c == NUL) { vim_beep(BO_COPY); } @@ -4838,7 +4836,7 @@ static int ins_ctrl_ey(int tc) static void ins_try_si(int c) { pos_T *pos, old_pos; - char_u *ptr; + char *ptr; int i; bool temp; @@ -4852,7 +4850,7 @@ static void ins_try_si(int c) // 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); + ptr = ml_get(pos->lnum); i = pos->col; if (i > 0) { // skip blanks before '{' while (--i > 0 && ascii_iswhite(ptr[i])) {} @@ -4877,7 +4875,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(ml_get(--(curwin->w_cursor.lnum))); + ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum))); // ignore empty lines and lines starting with '#'. if (*ptr != '#' && *ptr != NUL) { @@ -4928,7 +4926,7 @@ colnr_T get_nolist_virtcol(void) // "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) +static char *do_insert_char_pre(int c) { char buf[MB_MAXBYTES + 1]; const int save_State = State; @@ -4959,7 +4957,7 @@ static char_u *do_insert_char_pre(int c) // Restore the State, it may have been changed. State = save_State; - return (char_u *)res; + return res; } bool get_can_cindent(void) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index f9825496a5..4392ea306f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -268,7 +268,7 @@ static struct vimvar { VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO), VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO), VV(VV_RELNUM, "relnum", VAR_NUMBER, VV_RO), - VV(VV_WRAP, "wrap", VAR_BOOL, VV_RO), + VV(VV_VIRTNUM, "virtnum", VAR_NUMBER, VV_RO), }; #undef VV @@ -1485,9 +1485,9 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const tv_clear(&var1); break; // existing variable, need to check if it can be changed - } else if (!(flags & GLV_READ_ONLY) && var_check_ro(lp->ll_di->di_flags, - (const char *)name, - (size_t)(p - name))) { + } else if (!(flags & GLV_READ_ONLY) + && (var_check_ro(lp->ll_di->di_flags, name, (size_t)(p - name)) + || var_check_lock(lp->ll_di->di_flags, name, (size_t)(p - name)))) { tv_clear(&var1); return NULL; } @@ -1618,7 +1618,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool semsg(_(e_letwrong), op); return; } - if (var_check_lock(lp->ll_blob->bv_lock, lp->ll_name, TV_CSTRING)) { + if (value_check_lock(lp->ll_blob->bv_lock, lp->ll_name, TV_CSTRING)) { return; } @@ -1648,7 +1648,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool // the end is an error otherwise. if (lp->ll_n1 < gap->ga_len || lp->ll_n1 == gap->ga_len) { ga_grow(&lp->ll_blob->bv_ga, 1); - tv_blob_set(lp->ll_blob, (int)lp->ll_n1, (char_u)val); + tv_blob_set(lp->ll_blob, (int)lp->ll_n1, (uint8_t)val); if (lp->ll_n1 == gap->ga_len) { gap->ga_len++; } @@ -1681,10 +1681,10 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool set_var_const(lp->ll_name, lp->ll_name_len, rettv, copy, is_const); } *endp = (char)cc; - } else if (var_check_lock(lp->ll_newkey == NULL - ? lp->ll_tv->v_lock - : lp->ll_tv->vval.v_dict->dv_lock, - lp->ll_name, TV_CSTRING)) { + } else if (value_check_lock(lp->ll_newkey == NULL + ? lp->ll_tv->v_lock + : lp->ll_tv->vval.v_dict->dv_lock, + lp->ll_name, TV_CSTRING)) { // Skip } else if (lp->ll_range) { listitem_T *ll_li = lp->ll_li; @@ -1698,8 +1698,8 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool // Check whether any of the list items is locked for (ri = tv_list_first(rettv->vval.v_list); ri != NULL && ll_li != NULL;) { - if (var_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name, - TV_CSTRING)) { + if (value_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name, + TV_CSTRING)) { return; } ri = TV_LIST_ITEM_NEXT(rettv->vval.v_list, ri); @@ -2185,7 +2185,7 @@ int pattern_match(const char *pat, const char *text, bool ic) regmatch.regprog = vim_regcomp((char *)pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { regmatch.rm_ic = ic; - matches = vim_regexec_nl(®match, (char_u *)text, (colnr_T)0); + matches = vim_regexec_nl(®match, (char *)text, (colnr_T)0); vim_regfree(regmatch.regprog); } p_cpo = save_cpo; @@ -2543,7 +2543,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') { len = 5; } - if (!isalnum(p[len]) && p[len] != '_') { + if (!isalnum((uint8_t)p[len]) && p[len] != '_') { type = len == 2 ? EXPR_IS : EXPR_ISNOT; } } @@ -2660,10 +2660,10 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) blob_T *const b = tv_blob_alloc(); for (int i = 0; i < tv_blob_len(b1); i++) { - ga_append(&b->bv_ga, (char)tv_blob_get(b1, i)); + ga_append(&b->bv_ga, tv_blob_get(b1, i)); } for (int i = 0; i < tv_blob_len(b2); i++) { - ga_append(&b->bv_ga, (char)tv_blob_get(b2, i)); + ga_append(&b->bv_ga, tv_blob_get(b2, i)); } tv_clear(rettv); @@ -2887,12 +2887,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) /// @return OK or FAIL. static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) { - varnumber_T n; - int len; - char *s; - const char *start_leader, *end_leader; int ret = OK; - char *alias; static int recurse = 0; // Initialise variable so that tv_clear() can't mistake this for a @@ -2900,11 +2895,11 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) rettv->v_type = VAR_UNKNOWN; // Skip '!', '-' and '+' characters. They are handled later. - start_leader = *arg; + const char *start_leader = *arg; while (**arg == '!' || **arg == '-' || **arg == '+') { *arg = skipwhite(*arg + 1); } - end_leader = *arg; + const char *end_leader = *arg; // Limit recursion to 1000 levels. At least at 10000 we run out of stack // and crash. With MSVC the stack is smaller. @@ -2931,88 +2926,9 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) case '6': case '7': case '8': - case '9': { - char *p = skipdigits(*arg + 1); - int get_float = false; - - // We accept a float when the format matches - // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very - // strict to avoid backwards compatibility problems. - // Don't look for a float after the "." operator, so that - // ":let vers = 1.2.3" doesn't fail. - if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) { - get_float = true; - p = skipdigits(p + 2); - if (*p == 'e' || *p == 'E') { - p++; - if (*p == '-' || *p == '+') { - p++; - } - if (!ascii_isdigit(*p)) { - get_float = false; - } else { - p = skipdigits(p + 1); - } - } - if (ASCII_ISALPHA(*p) || *p == '.') { - get_float = false; - } - } - if (get_float) { - float_T f; - - *arg += string2float(*arg, &f); - if (evaluate) { - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = f; - } - } else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) { - blob_T *blob = NULL; - // Blob constant: 0z0123456789abcdef - if (evaluate) { - blob = tv_blob_alloc(); - } - char *bp; - for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) { - if (!ascii_isxdigit(bp[1])) { - if (blob != NULL) { - emsg(_("E973: Blob literal should have an even number of hex " - "characters")); - ga_clear(&blob->bv_ga); - XFREE_CLEAR(blob); - } - ret = FAIL; - break; - } - if (blob != NULL) { - ga_append(&blob->bv_ga, (char)((hex2nr(*bp) << 4) + hex2nr(*(bp + 1)))); - } - if (bp[2] == '.' && ascii_isxdigit(bp[3])) { - bp++; - } - } - if (blob != NULL) { - tv_blob_set_ret(rettv, blob); - } - *arg = bp; - } else { - // decimal, hex or octal number - vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true); - if (len == 0) { - if (evaluate) { - semsg(_(e_invexpr2), *arg); - } - ret = FAIL; - break; - } - *arg += len; - if (evaluate) { - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n; - } - } + case '9': + ret = get_number_tv(arg, rettv, evaluate, want_string); break; - } // String constant: "string". case '"': @@ -3090,8 +3006,9 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) if (ret == NOTDONE) { // Must be a variable or function name. // Can also be a curly-braces kind of name: {expr}. - s = *arg; - len = get_name_len((const char **)arg, &alias, evaluate, true); + char *s = *arg; + char *alias; + int len = get_name_len((const char **)arg, &alias, evaluate, true); if (alias != NULL) { s = alias; } @@ -3716,6 +3633,91 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval return ret; } +/// Allocate a variable for a number constant. Also deals with "0z" for blob. +/// +/// @return OK or FAIL. +static int get_number_tv(char **arg, typval_T *rettv, bool evaluate, bool want_string) +{ + char *p = skipdigits(*arg + 1); + bool get_float = false; + + // We accept a float when the format matches + // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very + // strict to avoid backwards compatibility problems. + // Don't look for a float after the "." operator, so that + // ":let vers = 1.2.3" doesn't fail. + if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) { + get_float = true; + p = skipdigits(p + 2); + if (*p == 'e' || *p == 'E') { + p++; + if (*p == '-' || *p == '+') { + p++; + } + if (!ascii_isdigit(*p)) { + get_float = false; + } else { + p = skipdigits(p + 1); + } + } + if (ASCII_ISALPHA(*p) || *p == '.') { + get_float = false; + } + } + if (get_float) { + float_T f; + *arg += string2float(*arg, &f); + if (evaluate) { + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f; + } + } else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) { + // Blob constant: 0z0123456789abcdef + blob_T *blob = NULL; + if (evaluate) { + blob = tv_blob_alloc(); + } + char *bp; + for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) { + if (!ascii_isxdigit(bp[1])) { + if (blob != NULL) { + emsg(_("E973: Blob literal should have an even number of hex characters")); + ga_clear(&blob->bv_ga); + XFREE_CLEAR(blob); + } + return FAIL; + } + if (blob != NULL) { + ga_append(&blob->bv_ga, (uint8_t)((hex2nr(*bp) << 4) + hex2nr(*(bp + 1)))); + } + if (bp[2] == '.' && ascii_isxdigit(bp[3])) { + bp++; + } + } + if (blob != NULL) { + tv_blob_set_ret(rettv, blob); + } + *arg = bp; + } else { + // decimal, hex or octal number + int len; + varnumber_T n; + vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true); + if (len == 0) { + if (evaluate) { + semsg(_(e_invexpr2), *arg); + } + return FAIL; + } + *arg += len; + if (evaluate) { + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n; + } + } + return OK; +} + /// Allocate a variable for a string constant. /// /// @return OK or FAIL. @@ -3777,7 +3779,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) case 'U': if (ascii_isxdigit(p[1])) { int n, nr; - int c = toupper(*p); + int c = toupper((uint8_t)(*p)); if (c == 'X') { n = 2; @@ -3828,7 +3830,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) if (p[1] != '*') { flags |= FSK_SIMPLIFY; } - extra = trans_special((const char **)&p, strlen(p), (char_u *)name, flags, false, NULL); + extra = trans_special((const char **)&p, strlen(p), name, flags, false, NULL); if (extra != 0) { name += extra; if (name >= rettv->vval.v_string + len) { @@ -3924,7 +3926,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((char_u *)pt->pt_name); + func_unref(pt->pt_name); xfree(pt->pt_name); } else { func_ptr_unref(pt->pt_func); @@ -4490,7 +4492,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((char_u *)pt->pt_name, pt->pt_func, copyID); + abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID); if (pt->pt_dict != NULL) { typval_T dtv; @@ -4507,7 +4509,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack break; } case VAR_FUNC: - abort = set_ref_in_func((char_u *)tv->vval.v_string, NULL, copyID); + abort = set_ref_in_func(tv->vval.v_string, NULL, copyID); break; case VAR_UNKNOWN: case VAR_BOOL: @@ -4795,12 +4797,12 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) } else if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL || (!map - && var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE))) { + && value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE))) { return; } } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL - || (!map && var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) { + || (!map && value_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) { return; } } else { @@ -4839,7 +4841,7 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) dictitem_T *di = TV_DICT_HI2DI(hi); if (map - && (var_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE) + && (value_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE) || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE))) { break; } @@ -4879,7 +4881,7 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) } if (map) { if (tv.vval.v_number != val) { - tv_blob_set(b, i, (char_u)tv.vval.v_number); + tv_blob_set(b, i, (uint8_t)tv.vval.v_number); } } else if (rem) { char *const p = argvars[0].vval.v_blob->bv_ga.ga_data; @@ -4899,8 +4901,8 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) } for (listitem_T *li = tv_list_first(l); li != NULL;) { if (map - && var_check_lock(TV_LIST_ITEM_TV(li)->v_lock, arg_errmsg, - TV_TRANSLATE)) { + && value_check_lock(TV_LIST_ITEM_TV(li)->v_lock, arg_errmsg, + TV_TRANSLATE)) { break; } vimvars[VV_KEY].vv_nr = idx; @@ -5000,7 +5002,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) // Don't check an autoload name for existence here. } else if (trans_name != NULL && (is_funcref - ? find_func((char_u *)trans_name) == NULL + ? find_func(trans_name) == NULL : !translated_function_exists((const char *)trans_name))) { semsg(_("E700: Unknown function: %s"), s); } else { @@ -5099,12 +5101,12 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) func_ptr_ref(pt->pt_func); xfree(name); } else if (is_funcref) { - pt->pt_func = find_func((char_u *)trans_name); + pt->pt_func = find_func(trans_name); func_ptr_ref(pt->pt_func); xfree(name); } else { pt->pt_name = name; - func_ref((char_u *)name); + func_ref(name); } rettv->v_type = VAR_PARTIAL; @@ -5113,7 +5115,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) // result is a VAR_FUNC rettv->v_type = VAR_FUNC; rettv->vval.v_string = name; - func_ref((char_u *)name); + func_ref(name); } } theend: @@ -5529,12 +5531,12 @@ bool callback_from_typval(Callback *const callback, const typval_T *const arg) if (callback->data.funcref == NULL) { callback->data.funcref = xstrdup(name); } - func_ref((char_u *)callback->data.funcref); + func_ref(callback->data.funcref); callback->type = kCallbackFuncref; } } else if (nlua_is_table_from_lua(arg)) { // TODO(tjdvries): UnifiedCallback - char *name = (char *)nlua_register_table_as_callable(arg); + char *name = nlua_register_table_as_callable(arg); if (name != NULL) { callback->data.funcref = xstrdup(name); @@ -6302,7 +6304,7 @@ int get_id_len(const char **const arg) // slice "[n:]". Also "xx:" is not a namespace. len = (int)(p - *arg); if (len > 1 - || (len == 1 && vim_strchr(namespace_char, **arg) == NULL)) { + || (len == 1 && vim_strchr(namespace_char, (uint8_t)(**arg)) == NULL)) { break; } } @@ -6430,7 +6432,7 @@ const char *find_name_end(const char *arg, const char **expr_start, const char * // slice "[n:]". Also "xx:" is not a namespace. But {ns}: is. len = (int)(p - arg); if ((len > 1 && p[-1] != '}') - || (len == 1 && vim_strchr(namespace_char, *arg) == NULL)) { + || (len == 1 && vim_strchr(namespace_char, (uint8_t)(*arg)) == NULL)) { break; } } @@ -7408,7 +7410,7 @@ void ex_echo(exarg_T *eap) /// ":echohl {name}". void ex_echohl(exarg_T *eap) { - echo_attr = syn_name2attr((char_u *)eap->arg); + echo_attr = syn_name2attr(eap->arg); } /// ":execute expr1 ..." execute the result of an expression. @@ -8081,7 +8083,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char if (regmatch.regprog != NULL) { char *tail = str; char *end = str + strlen(str); - while (vim_regexec_nl(®match, (char_u *)str, (colnr_T)(tail - str))) { + while (vim_regexec_nl(®match, str, (colnr_T)(tail - str))) { // Skip empty match except for first match. if (regmatch.startp[0] == regmatch.endp[0]) { if (zero_width == regmatch.startp[0]) { @@ -8100,7 +8102,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char // - The text up to where the match is. // - The substituted text. // - The text after the match. - sublen = vim_regsub(®match, (char_u *)sub, expr, (char_u *)tail, 0, REGSUB_MAGIC); + sublen = vim_regsub(®match, sub, expr, tail, 0, REGSUB_MAGIC); ga_grow(&ga, (int)((end - tail) + sublen - (regmatch.endp[0] - regmatch.startp[0]))); @@ -8108,8 +8110,8 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char 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, + (void)vim_regsub(®match, sub, expr, + (char *)ga.ga_data + ga.ga_len + i, sublen, REGSUB_COPY | REGSUB_MAGIC); ga.ga_len += i + sublen - 1; tail = regmatch.endp[0]; @@ -8297,7 +8299,7 @@ bool eval_has_provider(const char *feat) if (get_var_tv(buf, len, &tv, NULL, false, true) == FAIL) { // Show a hint if Call() is defined but g:loaded_xx_provider is missing. snprintf(buf, sizeof(buf), "provider#%s#Call", name); - if (!!find_func((char_u *)buf) && p_lpl) { + if (!!find_func(buf) && p_lpl) { semsg("provider: %s: missing required variable g:loaded_%s_provider", name, name); } @@ -8312,7 +8314,7 @@ bool eval_has_provider(const char *feat) if (ok) { // Call() must be defined if provider claims to be working. snprintf(buf, sizeof(buf), "provider#%s#Call", name); - if (!find_func((char_u *)buf)) { + if (!find_func(buf)) { semsg("provider: %s: g:loaded_%s_provider=2 but %s is not defined", name, name, buf); ok = false; @@ -8335,10 +8337,10 @@ void eval_fmt_source_name_line(char *buf, size_t bufsize) /// ":checkhealth [plugins]" void ex_checkhealth(exarg_T *eap) { - bool found = !!find_func((char_u *)"health#check"); + bool found = !!find_func("health#check"); if (!found && script_autoload("health#check", sizeof("health#check") - 1, false)) { - found = !!find_func((char_u *)"health#check"); + found = !!find_func("health#check"); } if (!found) { const char *vimruntime_env = os_getenv("VIMRUNTIME"); diff --git a/src/nvim/eval.h b/src/nvim/eval.h index d67414f12f..86bc76e793 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -166,7 +166,7 @@ typedef enum { VV__NULL_BLOB, // Blob with NULL value. For test purposes only. VV_LUA, VV_RELNUM, - VV_WRAP, + VV_VIRTNUM, } VimVarIndex; /// All recognized msgpack types diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 14be6aba73..9a5ab51c71 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -26,7 +26,7 @@ return { acos={args=1, base=1, float_func="acos"}, -- WJMc add={args=2, base=1}, ['and']={args=2, base=1}, - api_info={}, + api_info={fast=true}, append={args=2, base=2}, appendbufline={args=3, base=3}, argc={args={0, 1}}, @@ -64,14 +64,14 @@ return { bufwinid={args=1, base=1}, bufwinnr={args=1, base=1}, byte2line={args=1, base=1}, - byteidx={args=2, base=1}, - byteidxcomp={args=2, base=1}, + byteidx={args=2, base=1, fast=true}, + byteidxcomp={args=2, base=1, fast=true}, call={args={2, 3}, base=1}, ceil={args=1, base=1, float_func="ceil"}, changenr={}, chanclose={args={1, 2}}, chansend={args=2}, - char2nr={args={1, 2}, base=1}, + char2nr={args={1, 2}, base=1, fast=true}, charclass={args=1, base=1}, charcol={args={1, 2}, base=1}, charidx={args={2, 3}, base=1}, @@ -100,7 +100,7 @@ return { deletebufline={args={2,3}, base=1}, dictwatcheradd={args=3}, dictwatcherdel={args=3}, - did_filetype={}, + did_filetype={fast=true}, diff_filler={args=1, base=1}, diff_hlID={args=2, base=1}, digraph_get={args=1, base=1}, @@ -108,11 +108,11 @@ return { digraph_set={args=2, base=1}, digraph_setlist={args=1, base=1}, empty={args=1, base=1}, - environ={}, - escape={args=2, base=1}, + environ={fast=true}, + escape={args=2, base=1, fast=true}, eval={args=1, base=1}, eventhandler={}, - executable={args=1, base=1}, + executable={args=1, base=1, fast=true}, execute={args={1, 2}, base=1}, exepath={args=1, base=1}, exists={args=1, base=1}, @@ -122,8 +122,8 @@ return { extend={args={2, 3}, base=1}, feedkeys={args={1, 2}, base=1}, file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete - filereadable={args=1, base=1}, - filewritable={args=1, base=1}, + filereadable={args=1, base=1, fast=true}, + filewritable={args=1, base=1, fast=true}, filter={args=2, base=1}, finddir={args={1, 3}, base=1}, findfile={args={1, 3}, base=1}, @@ -131,8 +131,8 @@ return { float2nr={args=1, base=1}, floor={args=1, base=1, float_func="floor"}, fmod={args=2, base=1}, - fnameescape={args=1, base=1}, - fnamemodify={args=2, base=1}, + fnameescape={args=1, base=1, fast=true}, + fnamemodify={args=2, base=1, fast=true}, foldclosed={args=1, base=1}, foldclosedend={args=1, base=1}, foldlevel={args=1, base=1}, @@ -148,6 +148,7 @@ return { getbufline={args={2, 3}, base=1}, getbufoneline={args=2, base=1}, getbufvar={args={2, 3}, base=1}, + getcellwidths={}, getchangelist={args={0, 1}, base=1}, getchar={args={0, 1}}, getcharmod={}, @@ -166,17 +167,17 @@ return { getcwd={args={0, 2}, base=1}, getenv={args=1, base=1}, getfontname={args={0, 1}}, - getfperm={args=1, base=1}, - getfsize={args=1, base=1}, - getftime={args=1, base=1}, - getftype={args=1, base=1}, + getfperm={args=1, base=1, fast=true}, + getfsize={args=1, base=1, fast=true}, + getftime={args=1, base=1, fast=true}, + getftype={args=1, base=1, fast=true}, getjumplist={args={0, 2}, base=1}, getline={args={1, 2}, base=1}, getloclist={args={1, 2}}, getmarklist={args={0, 1}, base=1}, getmatches={args={0, 1}}, getmousepos={}, - getpid={}, + getpid={fast=true}, getpos={args=1, base=1}, getqflist={args={0, 1}}, getreg={args={0, 3}, base=1}, @@ -207,7 +208,7 @@ return { histnr={args=1, base=1}, hlID={args=1, base=1}, hlexists={args=1, base=1}, - hostname={}, + hostname={fast=true}, iconv={args=3, base=1, fast=true}, indent={args=1, base=1}, index={args={2, 4}, base=1}, @@ -220,7 +221,7 @@ return { insert={args={2, 3}, base=1}, interrupt={args=0}, invert={args=1, base=1}, - isdirectory={args=1, base=1}, + isdirectory={args=1, base=1, fast=true}, isinf={args=1, base=1}, islocked={args=1, base=1}, isnan={args=1, base=1}, @@ -299,13 +300,13 @@ return { reg_executing={}, reg_recording={}, reg_recorded={}, - reltime={args={0, 2}, base=1}, - reltimefloat={args=1, base=1}, - reltimestr={args=1, base=1}, + reltime={args={0, 2}, base=1, fast=true}, + reltimefloat={args=1, base=1, fast=true}, + reltimestr={args=1, base=1, fast=true}, remove={args={2, 3}, base=1}, rename={args=2, base=1}, - ['repeat']={args=2, base=1}, - resolve={args=1, base=1}, + ['repeat']={args=2, base=1, fast=true}, + resolve={args=1, base=1, fast=true}, reverse={args=1, base=1}, round={args=1, base=1, float_func="round"}, rpcnotify={args=varargs(2)}, @@ -373,24 +374,24 @@ return { split={args={1, 3}, base=1}, sqrt={args=1, base=1, float_func="sqrt"}, srand={args={0, 1}, base=1}, - stdpath={args=1}, + stdpath={args=1, fast=true}, str2float={args=1, base=1}, str2list={args={1, 2}, base=1}, str2nr={args={1, 3}, base=1}, strcharlen={args=1, base=1}, - strcharpart={args={2, 3}, base=1}, + strcharpart={args={2, 3}, base=1, fast=true}, strchars={args={1, 2}, base=1}, strdisplaywidth={args={1, 2}, base=1}, strftime={args={1, 2}, base=1}, strgetchar={args=2, base=1}, - stridx={args={2, 3}, base=1}, + stridx={args={2, 3}, base=1, fast=true}, string={args=1, base=1}, strlen={args=1, base=1}, - strpart={args={2, 4}, base=1}, + strpart={args={2, 4}, base=1, fast=true}, strptime={args=2, base=1}, strridx={args={2, 3}, base=1}, - strtrans={args=1, base=1}, - strwidth={args=1, base=1}, + strtrans={args=1, base=1, fast=true}, + strwidth={args=1, base=1, fast=true}, submatch={args={1, 2}, base=1}, substitute={args=4, base=1}, swapinfo={args=1, base=1}, @@ -418,12 +419,12 @@ return { timer_start={args={2, 3}, base=1}, timer_stop={args=1, base=1}, timer_stopall={args=0}, - tolower={args=1, base=1}, - toupper={args=1, base=1}, + tolower={args=1, base=1, fast=true}, + toupper={args=1, base=1, fast=true}, tr={args=3, base=1}, trim={args={1, 3}, base=1}, trunc={args=1, base=1, float_func="trunc"}, - type={args=1, base=1}, + type={args=1, base=1, fast=true}, undofile={args=1, base=1}, undotree={}, uniq={args={1, 3}, base=1}, @@ -446,7 +447,7 @@ return { win_splitmove={args={2, 3}, base=1}, winbufnr={args=1, base=1}, wincol={}, - windowsversion={}, + windowsversion={fast=true}, winheight={args=1, base=1}, winlayout={args={0, 1}, base=1}, winline={}, diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c index 72eb0f8d67..2f37d1ba2e 100644 --- a/src/nvim/eval/buffer.c +++ b/src/nvim/eval/buffer.c @@ -9,6 +9,7 @@ #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/cursor.h" #include "nvim/eval.h" @@ -277,9 +278,9 @@ void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "bufadd(expr)" function void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char_u *name = (char_u *)tv_get_string(&argvars[0]); + char *name = (char *)tv_get_string(&argvars[0]); - rettv->vval.v_number = buflist_add(*name == NUL ? NULL : (char *)name, 0); + rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0); } /// "bufexists(expr)" function diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 03d4862550..c2f1eae8af 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -309,7 +309,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s if (buf_[i_] == '\'') { \ ga_append(gap, '\''); \ } \ - ga_append(gap, buf_[i_]); \ + ga_append(gap, (uint8_t)buf_[i_]); \ } \ ga_append(gap, '\''); \ } \ diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h index e66dab1cff..41e7614fc0 100644 --- a/src/nvim/eval/encode.h +++ b/src/nvim/eval/encode.h @@ -4,6 +4,7 @@ #include <msgpack.h> #include <msgpack/pack.h> #include <stddef.h> +#include <string.h> #include "nvim/eval.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 86d6063b01..9caea2fef1 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -51,7 +51,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons blob_T *const b1 = tv1->vval.v_blob; blob_T *const b2 = tv2->vval.v_blob; for (int i = 0; i < tv_blob_len(b2); i++) { - ga_append(&b1->bv_ga, (char)tv_blob_get(b2, i)); + ga_append(&b1->bv_ga, tv_blob_get(b2, i)); } } return OK; @@ -69,7 +69,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons if (tv2->v_type == VAR_LIST) { break; } - if (vim_strchr("+-*/%", *op) != NULL) { + if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { // nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr varnumber_T n = tv_get_number(tv1); if (tv2->v_type == VAR_FLOAT) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d6b9ca20fc..48f3cd4293 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -244,11 +244,11 @@ int call_internal_func(const char *const fname, const int argcount, typval_T *co } /// Invoke a method for base->method(). -int call_internal_method(const char_u *const fname, const int argcount, typval_T *const argvars, +int call_internal_method(const char *const fname, const int argcount, typval_T *const argvars, typval_T *const rettv, typval_T *const basetv) FUNC_ATTR_NONNULL_ALL { - const EvalFuncDef *const fdef = find_internal_func((const char *)fname); + const EvalFuncDef *const fdef = find_internal_func(fname); if (fdef == NULL) { return FCERR_UNKNOWN; } else if (fdef->base_arg == BASE_NONE) { @@ -362,20 +362,20 @@ 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) { list_T *const l = argvars[0].vval.v_list; - if (!var_check_lock(tv_list_locked(l), N_("add() argument"), - TV_TRANSLATE)) { + if (!value_check_lock(tv_list_locked(l), N_("add() argument"), + TV_TRANSLATE)) { tv_list_append_tv(l, &argvars[1]); tv_copy(&argvars[0], rettv); } } else if (argvars[0].v_type == VAR_BLOB) { blob_T *const b = argvars[0].vval.v_blob; if (b != NULL - && !var_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) { + && !value_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) { bool error = false; const varnumber_T n = tv_get_number_chk(&argvars[1], &error); if (!error) { - ga_append(&b->bv_ga, (char)n); + ga_append(&b->bv_ga, (uint8_t)n); tv_copy(&argvars[0], rettv); } } @@ -557,7 +557,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) func = partial_name(partial); } else if (nlua_is_table_from_lua(&argvars[0])) { // TODO(tjdevries): UnifiedCallback - func = (char *)nlua_register_table_as_callable(&argvars[0]); + func = nlua_register_table_as_callable(&argvars[0]); owned = true; } else { func = (char *)tv_get_string(&argvars[0]); @@ -572,16 +572,16 @@ static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (argvars[2].v_type != VAR_DICT) { emsg(_(e_dictreq)); if (owned) { - func_unref((char_u *)func); + func_unref(func); } return; } selfdict = argvars[2].vval.v_dict; } - func_call((char_u *)func, &argvars[1], partial, selfdict, rettv); + func_call(func, &argvars[1], partial, selfdict, rettv); if (owned) { - func_unref((char_u *)func); + func_unref(func); } } @@ -1419,7 +1419,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) hlID = HLF_CHD; // Changed line. } } - rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)(hlID + 1); + rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (hlID + 1); } /// "empty({expr})" function @@ -1695,7 +1695,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) #ifdef BACKSLASH_IN_FILENAME if (path != NULL) { - slash_adjust((char_u *)path); + slash_adjust(path); } #endif @@ -1749,7 +1749,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; bool error = false; #ifdef BACKSLASH_IN_FILENAME - char_u *p_csl_save = p_csl; + char *p_csl_save = p_csl; // avoid using 'completeslash' here p_csl = empty_option; @@ -1770,7 +1770,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } size_t len; char *errormsg = NULL; - char *result = (char *)eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL, false); + char *result = eval_vars((char *)s, s, &len, NULL, &errormsg, NULL, false); if (p_verbose == 0) { emsg_off--; } else if (errormsg != NULL) { @@ -1896,9 +1896,9 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) list_T *list = argvars[0].vval.v_list; if (list != NULL - && !var_check_lock(tv_list_locked(list), - N_("flatten() argument"), - TV_TRANSLATE) + && !value_check_lock(tv_list_locked(list), + N_("flatten() argument"), + TV_TRANSLATE) && tv_list_flatten(list, maxdepth) == OK) { tv_copy(&argvars[0], rettv); } @@ -1915,7 +1915,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) list_T *const l1 = argvars[0].vval.v_list; list_T *const l2 = argvars[1].vval.v_list; - if (!var_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { + if (!value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) { listitem_T *item; if (argvars[2].v_type != VAR_UNKNOWN) { long before = (long)tv_get_number_chk(&argvars[2], &error); @@ -1944,13 +1944,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) dict_T *const d1 = argvars[0].vval.v_dict; dict_T *const d2 = argvars[1].vval.v_dict; if (d1 == NULL) { - const bool locked = var_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); + const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); (void)locked; assert(locked == true); } else if (d2 == NULL) { // Do nothing tv_copy(&argvars[0], rettv); - } else if (!var_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { + } else if (!value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { const char *action = "force"; // Check the third argument. if (argvars[2].v_type != VAR_UNKNOWN) { @@ -2022,7 +2022,7 @@ static void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) { char *fresult = NULL; - char *path = *curbuf->b_p_path == NUL ? (char *)p_path : curbuf->b_p_path; + char *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; int count = 1; bool first = true; bool error = false; @@ -2248,7 +2248,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); assert(name != NULL); if (rettv->v_type == VAR_FUNC) { - func_ref((char_u *)name); + func_ref((char *)name); } if (*what == 'n' && pt->pt_name == NULL && pt->pt_func != NULL) { // use <SNR> instead of the byte code @@ -2982,8 +2982,8 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const char *const file = tv_get_string_buf_chk(&argvars[1], buf1); if (file != NULL && !error) { garray_T ga; - ga_init(&ga, (int)sizeof(char_u *), 10); - globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags); + ga_init(&ga, (int)sizeof(char *), 10); + globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false); if (rettv->v_type == VAR_STRING) { rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); @@ -3064,9 +3064,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "conceal", "cursorbind", "cursorshape", -#ifdef DEBUG - "debug", -#endif "dialog_con", "diff", "digraphs", @@ -3082,9 +3079,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "fork", #endif "gettext", -#if defined(HAVE_ICONV) "iconv", -#endif "insert_expand", "jumplist", "keymap", @@ -3556,8 +3551,8 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) blob_T *const b = argvars[0].vval.v_blob; if (b == NULL - || var_check_lock(b->bv_lock, N_("insert() argument"), - TV_TRANSLATE)) { + || value_check_lock(b->bv_lock, N_("insert() argument"), + TV_TRANSLATE)) { return; } @@ -3584,16 +3579,16 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } ga_grow(&b->bv_ga, 1); - char_u *const p = (char_u *)b->bv_ga.ga_data; + uint8_t *const p = (uint8_t *)b->bv_ga.ga_data; memmove(p + before + 1, p + before, (size_t)(len - before)); - *(p + before) = (char_u)val; + *(p + before) = (uint8_t)val; b->bv_ga.ga_len++; tv_copy(&argvars[0], rettv); } else if (argvars[0].v_type != VAR_LIST) { semsg(_(e_listblobarg), "insert()"); - } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), - N_("insert() argument"), TV_TRANSLATE)) { + } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), + N_("insert() argument"), TV_TRANSLATE)) { long before = 0; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); @@ -4488,7 +4483,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, } } - match = vim_regexec_nl(®match, (char_u *)str, startcol); + match = vim_regexec_nl(®match, str, startcol); if (match && --nth <= 0) { break; @@ -5885,7 +5880,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) q[-1] = NUL; q = path_tail(p); } - if (q > p && !path_is_absolute((const char_u *)buf)) { + if (q > p && !path_is_absolute(buf)) { // Symlink is relative to directory of argument. Replace the // symlink with the resolved name in the same directory. const size_t p_len = strlen(p); @@ -5976,7 +5971,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const int len = tv_blob_len(b); for (int i = 0; i < len / 2; i++) { - const char_u tmp = tv_blob_get(b, i); + const uint8_t tmp = tv_blob_get(b, i); tv_blob_set(b, i, tv_blob_get(b, len - i - 1)); tv_blob_set(b, len - i - 1, tmp); } @@ -5985,8 +5980,8 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_listblobarg), "reverse()"); } else { list_T *const l = argvars[0].vval.v_list; - if (!var_check_lock(tv_list_locked(l), N_("reverse() argument"), - TV_TRANSLATE)) { + if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"), + TV_TRANSLATE)) { tv_list_reverse(l); tv_list_set_ret(rettv, l); } @@ -6228,7 +6223,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) // Repeat until {skip} returns false. for (;;) { subpatnum - = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1, options, RE_SEARCH, &sia); + = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia); // finding the first match again means there is no match where {skip} // evaluates to zero. if (firstpos.lnum != 0 && equalpos(pos, firstpos)) { @@ -6239,7 +6234,9 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) // didn't find it or no skip argument break; } - firstpos = pos; + if (firstpos.lnum == 0) { + firstpos = pos; + } // If the skip expression matches, ignore this match. { @@ -6468,7 +6465,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // Allocate extra memory for the argument vector and the NULL pointer int argvl = argsl + 2; - char **argv = xmalloc(sizeof(char_u *) * (size_t)argvl); + char **argv = xmalloc(sizeof(char *) * (size_t)argvl); // Copy program name argv[0] = xstrdup(argvars[0].vval.v_string); @@ -6644,7 +6641,7 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } if (!error && name != NULL) { - rettv->vval.v_number = find_decl((char_u *)name, strlen(name), locally, + rettv->vval.v_number = find_decl((char *)name, strlen(name), locally, thisblock, SEARCH_KEEP) == FAIL; } } @@ -6810,7 +6807,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir .sa_tm = &tm, }; - int n = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1L, + int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, options, RE_SEARCH, &sia); if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) { // didn't find it or found the first match again: FAIL @@ -7069,11 +7066,11 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fpt return; } - char_u *const csearch = (char_u *)tv_dict_get_string(d, "char", false); + char *const csearch = tv_dict_get_string(d, "char", false); if (csearch != NULL) { int pcc[MAX_MCO]; - const int c = utfc_ptr2char((char *)csearch, pcc); - set_last_csearch(c, csearch, utfc_ptr2len((char *)csearch)); + const int c = utfc_ptr2char(csearch, pcc); + set_last_csearch(c, csearch, utfc_ptr2len(csearch)); } dictitem_T *di = tv_dict_find(d, S_LEN("forward")); @@ -7553,7 +7550,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr if (str != NULL) { // Check the argument for spelling. while (*str != NUL) { - len = spell_check(curwin, (char_u *)str, &attr, &capcol, false); + len = spell_check(curwin, (char *)str, &attr, &capcol, false); if (attr != HLF_COUNT) { word = str; break; @@ -7612,7 +7609,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr maxcount = 25; } - spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false); + spell_suggest_list(&ga, (char *)str, maxcount, need_capital, false); f_spellsuggest_return: tv_list_alloc_ret(rettv, (ptrdiff_t)ga.ga_len); @@ -7668,7 +7665,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (*str == NUL) { match = false; // Empty item at the end. } else { - match = vim_regexec_nl(®match, (char_u *)str, col); + match = vim_regexec_nl(®match, (char *)str, col); } const char *end; if (match) { @@ -7823,34 +7820,35 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // MSVC returns NULL for an invalid value of seconds. if (curtime_ptr == NULL) { rettv->vval.v_string = xstrdup(_("(Invalid)")); - } else { - vimconv_T conv; + return; + } - conv.vc_type = CONV_NONE; - char *enc = (char *)enc_locale(); - convert_setup(&conv, p_enc, enc); - if (conv.vc_type != CONV_NONE) { - p = string_convert(&conv, p, NULL); - } - char result_buf[256]; - if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) { - result_buf[0] = NUL; - } + vimconv_T conv; - if (conv.vc_type != CONV_NONE) { - xfree(p); - } - convert_setup(&conv, enc, p_enc); - if (conv.vc_type != CONV_NONE) { - rettv->vval.v_string = string_convert(&conv, result_buf, NULL); - } else { - rettv->vval.v_string = xstrdup(result_buf); - } + conv.vc_type = CONV_NONE; + char *enc = enc_locale(); + convert_setup(&conv, p_enc, enc); + if (conv.vc_type != CONV_NONE) { + p = string_convert(&conv, p, NULL); + } + char result_buf[256]; + if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) { + result_buf[0] = NUL; + } - // Release conversion descriptors. - convert_setup(&conv, NULL, NULL); - xfree(enc); + if (conv.vc_type != CONV_NONE) { + xfree(p); } + convert_setup(&conv, enc, p_enc); + if (conv.vc_type != CONV_NONE) { + rettv->vval.v_string = string_convert(&conv, result_buf, NULL); + } else { + rettv->vval.v_string = xstrdup(result_buf); + } + + // Release conversion descriptors. + convert_setup(&conv, NULL, NULL); + xfree(enc); } /// "strgetchar()" function @@ -7930,11 +7928,11 @@ static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc) { const char *s = tv_get_string(&argvars[0]); varnumber_T len = 0; - int (*func_mb_ptr2char_adv)(const char_u **pp); + int (*func_mb_ptr2char_adv)(const char **pp); func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; while (*s != NUL) { - func_mb_ptr2char_adv((const char_u **)&s); + func_mb_ptr2char_adv(&s); len++; } rettv->vval.v_number = len; @@ -8097,7 +8095,7 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) vimconv_T conv = { .vc_type = CONV_NONE, }; - char *enc = (char *)enc_locale(); + char *enc = enc_locale(); convert_setup(&conv, p_enc, enc); if (conv.vc_type != CONV_NONE) { fmt = string_convert(&conv, fmt, NULL); @@ -8654,6 +8652,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr emsg(_(e_number_exp)); return; } + int paused = (bool)tv_get_number(&argvars[1]); timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0])); if (timer != NULL) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 7c61a2f990..c298064d86 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -900,8 +900,8 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) list_T *l; bool error = false; - if (var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), - arg_errmsg, TV_TRANSLATE)) { + if (value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), + arg_errmsg, TV_TRANSLATE)) { return; } @@ -1156,7 +1156,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) semsg(_(e_listarg), sort ? "sort()" : "uniq()"); } else { list_T *const l = argvars[0].vval.v_list; - if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) { + if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) { goto theend; } tv_list_set_ret(rettv, l); @@ -1599,7 +1599,7 @@ void callback_free(Callback *callback) { switch (callback->type) { case kCallbackFuncref: - func_unref((char_u *)callback->data.funcref); + func_unref(callback->data.funcref); xfree(callback->data.funcref); break; case kCallbackPartial: @@ -1628,7 +1628,7 @@ void callback_put(Callback *cb, typval_T *tv) case kCallbackFuncref: tv->v_type = VAR_FUNC; tv->vval.v_string = xstrdup(cb->data.funcref); - func_ref((char_u *)cb->data.funcref); + func_ref(cb->data.funcref); break; case kCallbackLua: // TODO(tjdevries): Unified Callback. @@ -1654,7 +1654,7 @@ void callback_copy(Callback *dest, Callback *src) break; case kCallbackFuncref: dest->data.funcref = xstrdup(src->data.funcref); - func_ref((char_u *)src->data.funcref); + func_ref(src->data.funcref); break; case kCallbackLua: dest->data.luaref = api_new_luaref(src->data.luaref); @@ -2494,7 +2494,7 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action } else if (*action == 'f' && di2 != di1) { typval_T oldtv; - if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len) + if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len) || var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) { break; } @@ -2710,7 +2710,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) { blob_T *const b = argvars[0].vval.v_blob; - if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) { + if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) { return; } @@ -2730,7 +2730,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) } if (argvars[2].v_type == VAR_UNKNOWN) { // Remove one item, return its value. - char_u *const p = (char_u *)b->bv_ga.ga_data; + uint8_t *const p = (uint8_t *)b->bv_ga.ga_data; rettv->vval.v_number = (varnumber_T)(*(p + idx)); memmove(p + idx, p + idx + 1, (size_t)(len - idx - 1)); b->bv_ga.ga_len--; @@ -2752,9 +2752,8 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) blob->bv_ga.ga_len = (int)(end - idx + 1); ga_grow(&blob->bv_ga, (int)(end - idx + 1)); - char_u *const p = (char_u *)b->bv_ga.ga_data; - memmove((char_u *)blob->bv_ga.ga_data, p + idx, - (size_t)(end - idx + 1)); + uint8_t *const p = (uint8_t *)b->bv_ga.ga_data; + memmove(blob->bv_ga.ga_data, p + idx, (size_t)(end - idx + 1)); tv_blob_set_ret(rettv, blob); if (len - end - 1 > 0) { @@ -2902,7 +2901,7 @@ void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) if (argvars[2].v_type != VAR_UNKNOWN) { semsg(_(e_toomanyarg), "remove()"); } else if ((d = argvars[0].vval.v_dict) != NULL - && !var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) { + && !value_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) { const char *key = tv_get_string_chk(&argvars[1]); if (key != NULL) { dictitem_T *di = tv_dict_find(d, key, -1); @@ -3007,7 +3006,7 @@ void tv_blob_copy(typval_T *const from, typval_T *const to) (tv)->v_lock = VAR_UNLOCKED; \ } while (0) -static inline int _nothing_conv_func_start(typval_T *const tv, char_u *const fun) +static inline int _nothing_conv_func_start(typval_T *const tv, char *const fun) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_lock = VAR_UNLOCKED; @@ -3209,17 +3208,19 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic /// @param[in,out] tv Value to free. void tv_clear(typval_T *const tv) { - if (tv != NULL && tv->v_type != VAR_UNKNOWN) { - // WARNING: do not translate the string here, gettext is slow and function - // is used *very* often. At the current state encode_vim_to_nothing() does - // not error out and does not use the argument anywhere. - // - // If situation changes and this argument will be used, translate it in the - // place where it is used. - const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); - (void)evn_ret; - assert(evn_ret == OK); + if (tv == NULL || tv->v_type == VAR_UNKNOWN) { + return; } + + // WARNING: do not translate the string here, gettext is slow and function + // is used *very* often. At the current state encode_vim_to_nothing() does + // not error out and does not use the argument anywhere. + // + // If situation changes and this argument will be used, translate it in the + // place where it is used. + const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); + (void)evn_ret; + assert(evn_ret == OK); } //{{{3 Free @@ -3229,35 +3230,37 @@ void tv_clear(typval_T *const tv) /// @param tv Object to free. void tv_free(typval_T *tv) { - if (tv != NULL) { - switch (tv->v_type) { - case VAR_PARTIAL: - partial_unref(tv->vval.v_partial); - break; - case VAR_FUNC: - func_unref((char_u *)tv->vval.v_string); - FALLTHROUGH; - case VAR_STRING: - xfree(tv->vval.v_string); - break; - case VAR_BLOB: - tv_blob_unref(tv->vval.v_blob); - break; - case VAR_LIST: - tv_list_unref(tv->vval.v_list); - break; - case VAR_DICT: - tv_dict_unref(tv->vval.v_dict); - break; - case VAR_BOOL: - case VAR_SPECIAL: - case VAR_NUMBER: - case VAR_FLOAT: - case VAR_UNKNOWN: - break; - } - xfree(tv); + if (tv == NULL) { + return; + } + + switch (tv->v_type) { + case VAR_PARTIAL: + partial_unref(tv->vval.v_partial); + break; + case VAR_FUNC: + func_unref(tv->vval.v_string); + FALLTHROUGH; + case VAR_STRING: + xfree(tv->vval.v_string); + break; + case VAR_BLOB: + tv_blob_unref(tv->vval.v_blob); + break; + case VAR_LIST: + tv_list_unref(tv->vval.v_list); + break; + case VAR_DICT: + tv_dict_unref(tv->vval.v_dict); + break; + case VAR_BOOL: + case VAR_SPECIAL: + case VAR_NUMBER: + case VAR_FLOAT: + case VAR_UNKNOWN: + break; } + xfree(tv); } //{{{3 Copy @@ -3288,7 +3291,7 @@ void tv_copy(const typval_T *const from, typval_T *const to) if (from->vval.v_string != NULL) { to->vval.v_string = xstrdup(from->vval.v_string); if (from->v_type == VAR_FUNC) { - func_ref((char_u *)to->vval.v_string); + func_ref(to->vval.v_string); } } break; @@ -3460,12 +3463,12 @@ bool tv_check_lock(const typval_T *tv, const char *name, size_t name_len) default: break; } - return var_check_lock(tv->v_lock, name, name_len) - || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len)); + return value_check_lock(tv->v_lock, name, name_len) + || (lock != VAR_UNLOCKED && value_check_lock(lock, name, name_len)); } -/// @return true if variable "name" is locked (immutable) -bool var_check_lock(VarLockStatus lock, const char *name, size_t name_len) +/// @return true if variable "name" has a locked (immutable) value +bool value_check_lock(VarLockStatus lock, const char *name, size_t name_len) { const char *error_message = NULL; switch (lock) { diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 1ee3b5bf69..3f59cd3547 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -358,7 +358,7 @@ static inline int tv_blob_len(const blob_T *const b) return b->bv_ga.ga_len; } -static inline char_u tv_blob_get(const blob_T *b, int idx) +static inline uint8_t tv_blob_get(const blob_T *b, int idx) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; /// Get the byte at index `idx` in the blob. @@ -367,12 +367,12 @@ static inline char_u tv_blob_get(const blob_T *b, int idx) /// @param[in] idx Index in a blob. Must be valid. /// /// @return Byte value at the given index. -static inline char_u tv_blob_get(const blob_T *const b, int idx) +static inline uint8_t tv_blob_get(const blob_T *const b, int idx) { - return ((char_u *)b->bv_ga.ga_data)[idx]; + return ((uint8_t *)b->bv_ga.ga_data)[idx]; } -static inline void tv_blob_set(blob_T *b, int idx, char_u c) +static inline void tv_blob_set(blob_T *b, int idx, uint8_t c) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; /// Store the byte `c` at index `idx` in the blob. @@ -380,9 +380,9 @@ static inline void tv_blob_set(blob_T *b, int idx, char_u c) /// @param[in] b Blob to index. Cannot be NULL. /// @param[in] idx Index in a blob. Must be valid. /// @param[in] c Value to store. -static inline void tv_blob_set(blob_T *const b, int idx, char_u c) +static inline void tv_blob_set(blob_T *const b, int idx, uint8_t c) { - ((char_u *)b->bv_ga.ga_data)[idx] = c; + ((uint8_t *)b->bv_ga.ga_data)[idx] = c; } /// Initialize VimL object diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h index 939e5d0810..4615198441 100644 --- a/src/nvim/eval/typval_defs.h +++ b/src/nvim/eval/typval_defs.h @@ -337,7 +337,7 @@ struct ufunc { ///< used for s: variables int uf_refcount; ///< reference count, see func_name_refcount() funccall_T *uf_scoped; ///< l: local variables for closure - char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with + char *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with ///< "<SNR>" as a string, otherwise NULL char uf_name[]; ///< Name of function (actual size equals name); ///< can start with <SNR>123_ diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 6c931d3f88..6d29286a58 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -339,7 +339,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( tv_blob_len(tv->vval.v_blob)); break; case VAR_FUNC: - TYPVAL_ENCODE_CONV_FUNC_START(tv, (char_u *)tv->vval.v_string); + TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string); TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0); TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); TYPVAL_ENCODE_CONV_FUNC_END(tv); @@ -347,7 +347,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( case VAR_PARTIAL: { partial_T *const pt = tv->vval.v_partial; (void)pt; - TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : (char_u *)partial_name(pt))); // -V547 + TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt))); // -V547 _mp_push(*mpstack, ((MPConvStackVal) { // -V779 .type = kMPConvPartial, .tv = tv, diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index c70d56cd25..6c6dc3fa43 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -45,6 +45,7 @@ #include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/strings.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -83,7 +84,7 @@ hashtab_T *func_tbl_get(void) } /// Get function arguments. -static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int *varargs, +static int get_function_args(char **argp, char endchar, garray_T *newargs, int *varargs, garray_T *default_args, bool skip) { bool mustend = false; @@ -105,7 +106,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int // Isolate the arguments: "arg1, arg2, ...)" bool any_default = false; - while (*p != (char)endchar) { + while (*p != endchar) { if (p[0] == '.' && p[1] == '.' && p[2] == '.') { if (varargs != NULL) { *varargs = true; @@ -117,7 +118,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int while (ASCII_ISALNUM(*p) || *p == '_') { p++; } - if (arg == p || isdigit(*arg) + if (arg == p || isdigit((uint8_t)(*arg)) || (p - arg == 9 && strncmp(arg, "firstline", 9) == 0) || (p - arg == 8 && strncmp(arg, "lastline", 8) == 0)) { if (!skip) { @@ -187,14 +188,14 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int } } p = skipwhite(p); - if (mustend && *p != (char)endchar) { + if (mustend && *p != endchar) { if (!skip) { semsg(_(e_invarg2), *argp); } break; } } - if (*p != (char)endchar) { + if (*p != endchar) { goto err_ret; } p++; // skip "endchar" @@ -228,12 +229,12 @@ static void register_closure(ufunc_T *fp) } /// @return a name for a lambda. Returned in static memory. -char_u *get_lambda_name(void) +char *get_lambda_name(void) { - static char_u name[30]; + static char name[30]; static int lambda_no = 0; - snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no); + snprintf(name, sizeof(name), "<lambda>%d", ++lambda_no); return name; } @@ -307,7 +308,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) char *p; garray_T newlines; - char *name = (char *)get_lambda_name(); + char *name = get_lambda_name(); fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1); pt = xcalloc(1, sizeof(partial_T)); @@ -581,9 +582,9 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char /// Find a function by name, return pointer to it in ufuncs. /// /// @return NULL for unknown function. -ufunc_T *find_func(const char_u *name) +ufunc_T *find_func(const char *name) { - hashitem_T *hi = hash_find(&func_hashtab, (char *)name); + hashitem_T *hi = hash_find(&func_hashtab, name); if (!HASHITEM_EMPTY(hi)) { return HI2UF(hi); } @@ -759,13 +760,12 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) static bool func_remove(ufunc_T *fp) { hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp)); - - if (!HASHITEM_EMPTY(hi)) { - hash_remove(&func_hashtab, hi); - return true; + if (HASHITEM_EMPTY(hi)) { + return false; } - return false; + hash_remove(&func_hashtab, hi); + return true; } static void func_clear_items(ufunc_T *fp) @@ -1225,9 +1225,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett /// For the first we only count the name stored in func_hashtab as a reference, /// using function() does not count as a reference, because the function is /// looked up by name. -static bool func_name_refcount(const char_u *name) +static bool func_name_refcount(const char *name) { - return isdigit(*name) || *name == '<'; + return isdigit((uint8_t)(*name)) || *name == '<'; } /// Call a user function after checking the arguments. @@ -1318,7 +1318,7 @@ void free_all_functions(void) // Only free functions that are not refcounted, those are // supposed to be freed when no longer referenced. fp = HI2UF(hi); - if (func_name_refcount((char_u *)fp->uf_name)) { + if (func_name_refcount(fp->uf_name)) { skipped++; } else { changed = func_hashtab.ht_changed; @@ -1344,7 +1344,7 @@ void free_all_functions(void) // Only free functions that are not refcounted, those are // supposed to be freed when no longer referenced. fp = HI2UF(hi); - if (func_name_refcount((char_u *)fp->uf_name)) { + if (func_name_refcount(fp->uf_name)) { skipped++; } else { func_free(fp); @@ -1381,7 +1381,7 @@ static bool builtin_function(const char *name, int len) return p == NULL; } -int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv) +int func_call(char *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv) { typval_T argv[MAX_FUNC_ARGS + 1]; int argc = 0; @@ -1403,7 +1403,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict funcexe.fe_evaluate = true; funcexe.fe_partial = partial; funcexe.fe_selfdict = selfdict; - r = call_func((char *)name, -1, rettv, argc, argv, &funcexe); + r = call_func(name, -1, rettv, argc, argv, &funcexe); func_call_skip_call: // Free the arguments. @@ -1434,30 +1434,30 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv /// Give an error message for the result of a function. /// Nothing if "error" is FCERR_NONE. -static void user_func_error(int error, const char_u *name) +static void user_func_error(int error, const char *name) FUNC_ATTR_NONNULL_ALL { switch (error) { case FCERR_UNKNOWN: - emsg_funcname(N_("E117: Unknown function: %s"), (char *)name); + emsg_funcname(N_("E117: Unknown function: %s"), name); break; case FCERR_NOTMETHOD: - emsg_funcname(N_("E276: Cannot use function as a method: %s"), (char *)name); + emsg_funcname(N_("E276: Cannot use function as a method: %s"), name); break; case FCERR_DELETED: - emsg_funcname(N_("E933: Function was deleted: %s"), (char *)name); + emsg_funcname(N_("E933: Function was deleted: %s"), name); break; case FCERR_TOOMANY: - emsg_funcname(_(e_toomanyarg), (char *)name); + emsg_funcname(_(e_toomanyarg), name); break; case FCERR_TOOFEW: - emsg_funcname(N_("E119: Not enough arguments for function: %s"), (char *)name); + emsg_funcname(N_("E119: Not enough arguments for function: %s"), name); break; case FCERR_SCRIPT: - emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), (char *)name); + emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), name); break; case FCERR_DICT: - emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), (char *)name); + emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name); break; } } @@ -1579,7 +1579,7 @@ 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((char_u *)rfname); + fp = find_func(rfname); } // Trigger FuncUndefined event, may load the function. @@ -1587,13 +1587,13 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL) && !aborting()) { // executed an autocommand, search for the function again - fp = find_func((char_u *)rfname); + fp = find_func(rfname); } // Try loading a package. if (fp == NULL && script_autoload((const char *)rfname, strlen(rfname), true) && !aborting()) { // Loaded a package, search for the function again. - fp = find_func((char_u *)rfname); + fp = find_func(rfname); } if (fp != NULL && (fp->uf_flags & FC_DELETED)) { @@ -1611,7 +1611,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t } 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((char_u *)fname, argcount, argvars, rettv, + error = call_internal_method(fname, argcount, argvars, rettv, funcexe->fe_basetv); } else { // Find the function name in the table, call its implementation. @@ -1635,7 +1635,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) ? (char_u *)name : (char_u *)funcname); + user_func_error(error, (name != NULL) ? name : funcname); } // clear the copies made from the partial @@ -1651,7 +1651,7 @@ theend: char *printable_func_name(ufunc_T *fp) { - return fp->uf_name_exp != NULL ? (char *)fp->uf_name_exp : fp->uf_name; + return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; } /// List the head of the function: "name(arg1, arg2)". @@ -1723,7 +1723,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) /// @param partial return: partial of a FuncRef /// /// @return the function name in allocated memory, or NULL for failure. -char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial) +char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial) FUNC_ATTR_NONNULL_ARG(1) { char *name = NULL; @@ -1744,7 +1744,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa && (*pp)[2] == KE_SNR) { *pp += 3; len = get_id_len((const char **)pp) + 3; - return (char_u *)xmemdupz(start, (size_t)len); + return xmemdupz(start, (size_t)len); } // A name starting with "<SID>" or "<SNR>" is local to a script. But @@ -1923,7 +1923,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa theend: clear_lval(&lv); - return (char_u *)name; + return name; } /// If the "funcname" starts with "s:" or "<SID>", then expands it to the @@ -1975,7 +1975,7 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi) CLEAR_POINTER(fudi); } } else { - saved = (char *)trans_function_name(&p, skip, flags, fudi, NULL); + saved = trans_function_name(&p, skip, flags, fudi, NULL); } *name = p; return saved; @@ -2000,8 +2000,8 @@ static void list_functions(regmatch_T *regmatch) if ((fp->uf_flags & FC_DEAD) == 0 && (regmatch == NULL ? (!message_filtered((char *)fp->uf_name) - && !func_name_refcount((char_u *)fp->uf_name)) - : (!isdigit(*fp->uf_name) + && !func_name_refcount(fp->uf_name)) + : (!isdigit((uint8_t)(*fp->uf_name)) && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) { list_func_head(fp, false, false); if (changed != func_hashtab.ht_changed) { @@ -2132,7 +2132,7 @@ void ex_function(exarg_T *eap) *p = NUL; } if (!eap->skip && !got_int) { - fp = find_func((char_u *)name); + fp = find_func(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++) { @@ -2255,7 +2255,7 @@ 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((char_u *)name) != NULL) { + } else if (name != NULL && find_func(name) != NULL) { emsg_funcname(e_funcexts, name); } } @@ -2295,7 +2295,7 @@ void ex_function(exarg_T *eap) } else { xfree(line_to_free); if (eap->getline == NULL) { - theline = (char *)getcmdline(':', 0L, indent, do_concat); + theline = getcmdline(':', 0L, indent, do_concat); } else { theline = eap->getline(':', eap->cookie, indent, do_concat); } @@ -2509,7 +2509,7 @@ void ex_function(exarg_T *eap) goto erret; } - fp = find_func((char_u *)name); + fp = find_func(name); if (fp != NULL) { // Function can be replaced with "function!" and when sourcing the // same script again, but only once. @@ -2531,7 +2531,7 @@ void ex_function(exarg_T *eap) fp = NULL; overwrite = true; } else { - char_u *exp_name = fp->uf_name_exp; + char *exp_name = fp->uf_name_exp; // redefine existing function, keep the expanded name XFREE_CLEAR(name); fp->uf_name_exp = NULL; @@ -2550,13 +2550,13 @@ void ex_function(exarg_T *eap) goto erret; } if (fudi.fd_di == NULL) { - if (var_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg, - TV_CSTRING)) { + if (value_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg, + TV_CSTRING)) { // Can't add a function to a locked dictionary goto erret; } - } else if (var_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg, - TV_CSTRING)) { + } else if (value_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg, + TV_CSTRING)) { // Can't change an existing function if it is locked goto erret; } @@ -2689,7 +2689,7 @@ bool translated_function_exists(const char *name) if (builtin_function(name, -1)) { return find_internal_func((char *)name) != NULL; } - return find_func((const char_u *)name) != NULL; + return find_func(name) != NULL; } /// Check whether function with the given name exists @@ -2707,7 +2707,7 @@ bool function_exists(const char *const name, bool no_deref) if (no_deref) { flag |= TFN_NO_DEREF; } - char *const p = (char *)trans_function_name((char **)&nm, false, flag, NULL, NULL); + char *const p = trans_function_name((char **)&nm, false, flag, NULL, NULL); nm = skipwhite(nm); // Only accept "funcname", "funcname ", "funcname (..." and @@ -2769,7 +2769,7 @@ void ex_delfunction(exarg_T *eap) { ufunc_T *fp = NULL; char *p; - char_u *name; + char *name; funcdict_T fudi; p = eap->arg; @@ -2791,7 +2791,7 @@ void ex_delfunction(exarg_T *eap) *p = NUL; } - if (isdigit(*name) && fudi.fd_dict == NULL) { + if (isdigit((uint8_t)(*name)) && fudi.fd_dict == NULL) { if (!eap->skip) { semsg(_(e_invarg2), eap->arg); } @@ -2832,7 +2832,7 @@ void ex_delfunction(exarg_T *eap) // it and the refcount is more than one, it should be kept. // A numbered function or lambda should be kept if the refcount is // one or more. - if (fp->uf_refcount > (func_name_refcount((char_u *)fp->uf_name) ? 0 : 1)) { + if (fp->uf_refcount > (func_name_refcount(fp->uf_name) ? 0 : 1)) { // Function is still referenced somewhere. Don't free it but // do remove it from the hashtable. if (func_remove(fp)) { @@ -2848,7 +2848,7 @@ void ex_delfunction(exarg_T *eap) /// Unreference a Function: decrement the reference count and free it when it /// becomes zero. -void func_unref(char_u *name) +void func_unref(char *name) { ufunc_T *fp = NULL; @@ -2857,7 +2857,7 @@ void func_unref(char_u *name) } fp = find_func(name); - if (fp == NULL && isdigit(*name)) { + if (fp == NULL && isdigit((uint8_t)(*name))) { #ifdef EXITFREE if (!entered_free_all_mem) { internal_error("func_unref()"); @@ -2890,7 +2890,7 @@ void func_ptr_unref(ufunc_T *fp) } /// Count a reference to a Function. -void func_ref(char_u *name) +void func_ref(char *name) { ufunc_T *fp; @@ -2900,7 +2900,7 @@ void func_ref(char_u *name) fp = find_func(name); if (fp != NULL) { (fp->uf_refcount)++; - } else if (isdigit(*name)) { + } else if (isdigit((uint8_t)(*name))) { // Only give an error for a numbered function. // Fail silently, when named or lambda function isn't found. internal_error("func_ref()"); @@ -3017,7 +3017,7 @@ void ex_call(exarg_T *eap) return; } - tofree = (char *)trans_function_name(&arg, false, TFN_INT, &fudi, &partial); + tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. semsg(_(e_dictkey), fudi.fd_newkey); @@ -3304,7 +3304,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. fname = fname_trans_sid(fname, fname_buf, &tofree, &error); - fp = find_func((char_u *)fname); + fp = find_func(fname); xfree(tofree); } @@ -3327,7 +3327,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) // be referenced elsewhere. if (ret_pt->pt_name != NULL) { pt->pt_name = xstrdup(ret_pt->pt_name); - func_ref((char_u *)pt->pt_name); + func_ref(pt->pt_name); } else { pt->pt_func = ret_pt->pt_func; func_ptr_ref(pt->pt_func); @@ -3348,9 +3348,9 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) } /// @return the name of the executed function. -char_u *func_name(void *cookie) +char *func_name(void *cookie) { - return (char_u *)((funccall_T *)cookie)->func->uf_name; + return ((funccall_T *)cookie)->func->uf_name; } /// @return the address holding the next breakpoint line for a funccall cookie. @@ -3609,7 +3609,7 @@ bool set_ref_in_functions(int copyID) if (!HASHITEM_EMPTY(hi)) { todo--; fp = HI2UF(hi); - if (!func_name_refcount((char_u *)fp->uf_name) + if (!func_name_refcount(fp->uf_name) && set_ref_in_func(NULL, fp, copyID)) { return true; } @@ -3635,7 +3635,7 @@ bool set_ref_in_func_args(int copyID) /// "ht_stack" is used to add hashtabs to be marked. Can be NULL. /// /// @return true if setting references failed somehow. -bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) +bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) { ufunc_T *fp = fp_in; funccall_T *fc; @@ -3649,8 +3649,8 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) } if (fp_in == NULL) { - fname = fname_trans_sid((char *)name, fname_buf, &tofree, &error); - fp = find_func((char_u *)fname); + fname = fname_trans_sid(name, fname_buf, &tofree, &error); + fp = find_func(fname); } if (fp != NULL) { for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) { @@ -3662,9 +3662,9 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) } /// Registers a luaref as a lambda. -char_u *register_luafunc(LuaRef ref) +char *register_luafunc(LuaRef ref) { - char *name = (char *)get_lambda_name(); + char *name = get_lambda_name(); ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1); fp->uf_refcount = 1; @@ -3678,5 +3678,5 @@ char_u *register_luafunc(LuaRef ref) hash_add(&func_hashtab, UF2HIKEY(fp)); // coverity[leaked_storage] - return (char_u *)fp->uf_name; + return fp->uf_name; } diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 206df03381..9ed245d6c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -106,7 +106,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd) return NULL; } *p = NUL; - if (islower(*marker)) { + if (islower((uint8_t)(*marker))) { emsg(_("E221: Marker cannot start with lower case letter")); return NULL; } @@ -208,7 +208,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const) argend--; } expr = skipwhite(argend); - if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL + if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) { // ":let" without "=": list variables if (*arg == '[') { @@ -244,7 +244,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const) op[0] = '='; op[1] = NUL; if (*expr != '=') { - if (vim_strchr("+-*/%.", *expr) != NULL) { + if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) { op[0] = *expr; // +=, -=, *=, /=, %= or .= if (expr[0] == '.' && expr[1] == '.') { // ..= expr++; @@ -590,10 +590,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo if (len == 0) { semsg(_(e_invarg2), name - 1); } else { - if (op != NULL && vim_strchr("+-*/%", *op) != NULL) { + if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { semsg(_(e_letwrong), op); } else if (endchars != NULL - && vim_strchr(endchars, *skipwhite(arg)) == NULL) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(arg))) == NULL) { emsg(_(e_letunexp)); } else if (!check_secure()) { char *tofree = NULL; @@ -629,7 +629,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo char *const p = (char *)find_option_end((const char **)&arg, &scope); if (p == NULL || (endchars != NULL - && vim_strchr(endchars, *skipwhite(p)) == NULL)) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) { emsg(_(e_letunexp)); } else { varnumber_T n = 0; @@ -716,10 +716,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo return NULL; } arg++; - if (op != NULL && vim_strchr("+-*/%", *op) != NULL) { + if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { semsg(_(e_letwrong), op); } else if (endchars != NULL - && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) { emsg(_(e_letunexp)); } else { char *s; @@ -747,7 +747,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START); if (p != NULL && lv.ll_name != NULL) { - if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) { + if (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL) { emsg(_(e_letunexp)); } else { set_var_lval(&lv, p, tv, copy, is_const, op); @@ -877,13 +877,13 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ } else if ((lp->ll_list != NULL // ll_list is not NULL when lvalue is not in a list, NULL lists // yield E689. - && var_check_lock(tv_list_locked(lp->ll_list), - lp->ll_name, - lp->ll_name_len)) + && value_check_lock(tv_list_locked(lp->ll_list), + lp->ll_name, + lp->ll_name_len)) || (lp->ll_dict != NULL - && var_check_lock(lp->ll_dict->dv_lock, - lp->ll_name, - lp->ll_name_len))) { + && value_check_lock(lp->ll_dict->dv_lock, + lp->ll_name, + lp->ll_name_len))) { return FAIL; } else if (lp->ll_range) { assert(lp->ll_list != NULL); @@ -892,9 +892,9 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ listitem_T *last_li = first_li; for (;;) { listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li); - if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock, - lp->ll_name, - lp->ll_name_len)) { + if (value_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock, + lp->ll_name, + lp->ll_name_len)) { return false; } lp->ll_li = li; @@ -976,11 +976,11 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit) dictitem_T *const di = TV_DICT_HI2DI(hi); if (var_check_fixed(di->di_flags, name, TV_CSTRING) || var_check_ro(di->di_flags, name, TV_CSTRING) - || var_check_lock(d->dv_lock, name, TV_CSTRING)) { + || value_check_lock(d->dv_lock, name, TV_CSTRING)) { return FAIL; } - if (var_check_lock(d->dv_lock, name, TV_CSTRING)) { + if (value_check_lock(d->dv_lock, name, TV_CSTRING)) { return FAIL; } @@ -1023,10 +1023,6 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap bool lock = eap->cmdidx == CMD_lockvar; int ret = OK; - if (deep == 0) { // Nothing to do. - return OK; - } - if (lp->ll_tv == NULL) { if (*lp->ll_name == '$') { semsg(_(e_lock_unlock), lp->ll_name); @@ -1050,9 +1046,13 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap } else { di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK); } - tv_item_lock(&di->di_tv, deep, lock, false); + if (deep != 0) { + tv_item_lock(&di->di_tv, deep, lock, false); + } } } + } else if (deep == 0) { + // nothing to do } else if (lp->ll_range) { listitem_T *li = lp->ll_li; @@ -1282,12 +1282,18 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, return; } - // existing variable, need to clear the value + // Check in this order for backwards compatibility: + // - Whether the variable is read-only + // - Whether the variable value is locked + // - Whether the variable is locked if (var_check_ro(v->di_flags, name, name_len) - || var_check_lock(v->di_tv.v_lock, name, name_len)) { + || value_check_lock(v->di_tv.v_lock, name, name_len) + || var_check_lock(v->di_flags, name, name_len)) { return; } + // existing variable, need to clear the value + // Handle setting internal v: variables separately where needed to // prevent changing the type. if (is_vimvarht(ht)) { @@ -1341,7 +1347,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, // Make sure dict is valid assert(dict != NULL); - v = xmalloc(sizeof(dictitem_T) + strlen(varname)); + v = xmalloc(offsetof(dictitem_T, di_key) + strlen(varname) + 1); STRCPY(v->di_key, varname); if (hash_add(ht, (char *)v->di_key) == FAIL) { xfree(v); @@ -1418,6 +1424,26 @@ bool var_check_ro(const int flags, const char *name, size_t name_len) return true; } +/// Return true if di_flags "flags" indicates variable "name" is locked. +/// Also give an error message. +bool var_check_lock(const int flags, const char *name, size_t name_len) +{ + if (!(flags & DI_FLAGS_LOCK)) { + return false; + } + + if (name_len == TV_TRANSLATE) { + name = _(name); + name_len = strlen(name); + } else if (name_len == TV_CSTRING) { + name_len = strlen(name); + } + + semsg(_("E1122: Variable is locked: %*s"), (int)name_len, name); + + return true; +} + /// Check whether variable is fixed (DI_FLAGS_FIX) /// /// Also gives an error message. @@ -1464,7 +1490,7 @@ bool var_wrong_func_name(const char *const name, const bool new_var) { // Allow for w: b: s: and t:. // Allow autoload variable. - if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':') + if (!(vim_strchr("wbst", (uint8_t)name[0]) != NULL && name[1] == ':') && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2] : name[0]) && vim_strchr(name, '#') == NULL) { semsg(_("E704: Funcref variable name must start with a capital: %s"), name); diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 4bcbc13534..f58a0c488a 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -12,6 +12,7 @@ #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" @@ -139,6 +140,8 @@ void win_findbuf(typval_T *argvars, list_T *list) /// Find window specified by "vp" in tabpage "tp". /// /// @param tp NULL for current tab page +/// @return current window if "vp" is number zero. +/// NULL if not found. win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp) { int nr = (int)tv_get_number_chk(vp, NULL); diff --git a/src/nvim/eval/window.h b/src/nvim/eval/window.h index 682a794113..995f0a55a9 100644 --- a/src/nvim/eval/window.h +++ b/src/nvim/eval/window.h @@ -2,9 +2,19 @@ #define NVIM_EVAL_WINDOW_H #include <stdbool.h> +#include <string.h> +#include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/cursor.h" #include "nvim/eval/typval_defs.h" +#include "nvim/globals.h" +#include "nvim/mark.h" +#include "nvim/option_defs.h" +#include "nvim/os/os.h" +#include "nvim/pos.h" +#include "nvim/vim.h" +#include "nvim/window.h" /// Structure used by switch_win() to pass values to restore_win() typedef struct { diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 10a09275d9..e528d21a71 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.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 <assert.h> #include <stdint.h> #include <uv.h> @@ -12,6 +13,7 @@ #include "nvim/log.h" #include "nvim/macros.h" #include "nvim/os/os.h" +#include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/libuv_process.c.generated.h" diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 9dfd6f329a..1a524a56ca 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -20,6 +20,7 @@ #include "nvim/os/shell.h" #include "nvim/os/time.h" #include "nvim/rbuffer.h" +#include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/process.c.generated.h" diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index c2af0e6986..437a05f61d 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -158,7 +158,7 @@ void do_ascii(const exarg_T *const eap) char buf2[20]; buf2[0] = NUL; - dig = (char *)get_digraph_for_char(cval); + dig = get_digraph_for_char(cval); if (dig != NULL) { iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, @@ -206,7 +206,7 @@ void do_ascii(const exarg_T *const eap) } iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len); - dig = (char *)get_digraph_for_char(c); + dig = get_digraph_for_char(c); if (dig != NULL) { iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, @@ -528,7 +528,7 @@ void ex_sort(exarg_T *eap) emsg(_(e_noprevre)); goto sortend; } - regmatch.regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC); + regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); } else { regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); } @@ -1348,7 +1348,7 @@ static char *find_pipe(const char *cmd) } if (*p == '"') { inquote = !inquote; - } else if (rem_backslash((const char_u *)p)) { + } else if (rem_backslash(p)) { p++; } } @@ -1420,7 +1420,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) #else // For shells that don't understand braces around commands, at least allow // the use of commands in a pipe. - xstrlcpy(buf, (char *)cmd, len); + xstrlcpy(buf, cmd, len); if (itmp != NULL) { // If there is a pipe, we have to put the '<' in front of it. // Don't do this when 'shellquote' is not empty, otherwise the @@ -3332,7 +3332,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T } // new pattern and substitution if (eap->cmd[0] == 's' && *cmd != NUL && !ascii_iswhite(*cmd) - && vim_strchr("0123456789cegriIp|\"", *cmd) == NULL) { + && vim_strchr("0123456789cegriIp|\"", (uint8_t)(*cmd)) == NULL) { // don't accept alphanumeric for separator if (check_regexp_delim(*cmd) == FAIL) { return 0; @@ -3343,7 +3343,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // //sub/r). "\&sub&" use last substitute pattern (like //sub/). if (*cmd == '\\') { cmd++; - if (vim_strchr("/?&", *cmd) == NULL) { + if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { emsg(_(e_backslash)); return 0; } @@ -3351,11 +3351,11 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T which_pat = RE_SEARCH; // use last '/' pattern } pat = ""; // empty search pattern - delimiter = (char_u)(*cmd++); // remember delimiter character + delimiter = (uint8_t)(*cmd++); // remember delimiter character has_second_delim = true; } else { // find the end of the regexp which_pat = RE_LAST; // use last used regexp - delimiter = (char_u)(*cmd++); // remember delimiter character + delimiter = (uint8_t)(*cmd++); // remember delimiter character pat = cmd; // remember start of search pat cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delimiter) { // end delimiter found @@ -3443,7 +3443,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T return 0; } - if (search_regcomp((char_u *)pat, NULL, RE_SUBST, which_pat, + if (search_regcomp(pat, NULL, RE_SUBST, which_pat, (cmdpreview ? 0 : SEARCH_HIS), ®match) == FAIL) { if (subflags.do_error) { emsg(_(e_invcmd)); @@ -3697,7 +3697,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T msg_putchar('\n'); xfree(prompt); if (resp != NULL) { - typed = (char_u)(*resp); + typed = (uint8_t)(*resp); xfree(resp); } else { // getcmdline_prompt() returns NULL if there is no command line to return. @@ -3895,7 +3895,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // When it fails sublen is zero. sublen = vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, - (char_u *)sub, (char_u *)sub_firstline, 0, + sub, sub_firstline, 0, REGSUB_BACKSLASH | (magic_isset() ? REGSUB_MAGIC : 0)); textlock--; @@ -3938,7 +3938,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T textlock++; (void)vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, - (char_u *)sub, (char_u *)new_end, sublen, + sub, new_end, sublen, REGSUB_COPY | REGSUB_BACKSLASH | (magic_isset() ? REGSUB_MAGIC : 0)); textlock--; @@ -4372,7 +4372,7 @@ void ex_global(exarg_T *eap) // "\&": use previous substitute pattern. if (*cmd == '\\') { cmd++; - if (vim_strchr("/?&", *cmd) == NULL) { + if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { emsg(_(e_backslash)); return; } @@ -4398,8 +4398,8 @@ void ex_global(exarg_T *eap) } } - char_u *used_pat; - if (search_regcomp((char_u *)pat, &used_pat, RE_BOTH, which_pat, + char *used_pat; + if (search_regcomp(pat, &used_pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) { emsg(_(e_invcmd)); return; @@ -4704,7 +4704,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) if (s != NULL) { *s = p + 1; } - c = (char_u)(*p); + c = (uint8_t)(*p); p = skip_regexp(p + 1, c, true); if (*p != c) { return NULL; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 68db03bd7d..c8b6ceab69 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -2387,7 +2387,7 @@ module.cmds = { }, { command='scriptnames', - flags=bit.bor(BANG, RANGE, COUNT, TRLBAR, CMDWIN, LOCK_OK), + flags=bit.bor(BANG, FILES, RANGE, COUNT, TRLBAR, CMDWIN, LOCK_OK), addr_type='ADDR_OTHER', func='ex_scriptnames', }, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e11dd0a2f6..a24e8458a6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -369,7 +369,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // Get the function or script name and the address where the next breakpoint // line and the debug tick for a function or script are stored. if (getline_is_func) { - fname = (char *)func_name(real_cookie); + fname = func_name(real_cookie); breakpoint = func_breakpoint(real_cookie); dbg_tick = func_dbg_tick(real_cookie); } else if (getline_equal(fgetline, cookie, getsourceline)) { @@ -919,7 +919,7 @@ static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) char *line; // First time inside the ":while"/":for": get line normally. if (cp->getline == NULL) { - line = (char *)getcmdline(c, 0L, indent, do_concat); + line = getcmdline(c, 0L, indent, do_concat); } else { line = cp->getline(c, cp->cookie, indent, do_concat); } @@ -2852,7 +2852,7 @@ bool checkforcmd(char **pp, const char *cmd, int len) break; } } - if (i >= len && !isalpha((*pp)[i])) { + if (i >= len && !ASCII_ISALPHA((*pp)[i])) { *pp = skipwhite(*pp + i); return true; } @@ -2877,7 +2877,7 @@ static void append_command(char *cmd) STRCAT(IObuff, ": "); d = IObuff + strlen(IObuff); while (*s != NUL && d - IObuff + 5 < IOSIZE) { - if ((char_u)s[0] == 0xc2 && (char_u)s[1] == 0xa0) { + if ((uint8_t)s[0] == 0xc2 && (uint8_t)s[1] == 0xa0) { s += 2; STRCPY(d, "<a0>"); d += 4; @@ -2890,6 +2890,33 @@ static void append_command(char *cmd) *d = NUL; } +/// Return true and set "*idx" if "p" points to a one letter command. +/// - The 'k' command can directly be followed by any character. +/// - The 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' +/// but :sre[wind] is another command, as are :scr[iptnames], +/// :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. +static int one_letter_cmd(const char *p, cmdidx_T *idx) +{ + if (*p == 'k') { + *idx = CMD_k; + return true; + } + if (p[0] == 's' + && ((p[1] == 'c' + && (p[2] == NUL + || (p[2] != 's' && p[2] != 'r' + && (p[3] == NUL + || (p[3] != 'i' && p[4] != 'p'))))) + || p[1] == 'g' + || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') + || p[1] == 'I' + || (p[1] == 'r' && p[2] != 'e'))) { + *idx = CMD_substitute; + return true; + } + return false; +} + /// Find an Ex command by its name, either built-in or user. /// Start of the name can be found at eap->cmd. /// Sets eap->cmdidx and returns a pointer to char after the command name. @@ -2900,27 +2927,8 @@ char *find_ex_command(exarg_T *eap, int *full) FUNC_ATTR_NONNULL_ARG(1) { // Isolate the command and search for it in the command table. - // Exceptions: - // - the 'k' command can directly be followed by any character. - // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' - // but :sre[wind] is another command, as are :scr[iptnames], - // :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. - // - the "d" command can directly be followed by 'l' or 'p' flag. char *p = eap->cmd; - if (*p == 'k') { - eap->cmdidx = CMD_k; - p++; - } else if (p[0] == 's' - && ((p[1] == 'c' - && (p[2] == NUL - || (p[2] != 's' && p[2] != 'r' - && (p[3] == NUL - || (p[3] != 'i' && p[4] != 'p'))))) - || p[1] == 'g' - || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') - || p[1] == 'I' - || (p[1] == 'r' && p[2] != 'e'))) { - eap->cmdidx = CMD_substitute; + if (one_letter_cmd(p, &eap->cmdidx)) { p++; } else { while (ASCII_ISALPHA(*p)) { @@ -2934,10 +2942,11 @@ char *find_ex_command(exarg_T *eap, int *full) } // check for non-alpha command - if (p == eap->cmd && vim_strchr("@!=><&~#", *p) != NULL) { + if (p == eap->cmd && vim_strchr("@!=><&~#", (uint8_t)(*p)) != NULL) { p++; } int len = (int)(p - eap->cmd); + // The "d" command can directly be followed by 'l' or 'p' flag. if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) { // Check for ":dl", ":dell", etc. to ":deletel": that's // :delete with the 'l' flag. Same for 'p'. @@ -2958,7 +2967,7 @@ char *find_ex_command(exarg_T *eap, int *full) } if (ASCII_ISLOWER(eap->cmd[0])) { - const int c1 = (char_u)eap->cmd[0]; + const int c1 = (uint8_t)eap->cmd[0]; const int c2 = len == 1 ? NUL : eap->cmd[1]; if (command_count != CMD_SIZE) { @@ -3135,9 +3144,11 @@ cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len) { cmdidx_T idx; - 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; + if (!one_letter_cmd(cmd, &idx)) { + 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; + } } } @@ -3161,7 +3172,7 @@ uint32_t excmd_get_argt(cmdidx_T idx) /// @return the "cmd" pointer advanced to beyond the range. char *skip_range(const char *cmd, int *ctx) { - while (vim_strchr(" \t0123456789.$%'/?-+,;\\", *cmd) != NULL) { + while (vim_strchr(" \t0123456789.$%'/?-+,;\\", (uint8_t)(*cmd)) != NULL) { if (*cmd == '\\') { if (cmd[1] == '?' || cmd[1] == '/' || cmd[1] == '&') { cmd++; @@ -3350,7 +3361,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int case '/': case '?': // '/' or '?' - search - c = (char_u)(*cmd++); + c = (uint8_t)(*cmd++); if (addr_type != ADDR_LINES) { addr_error(addr_type); cmd = NULL; @@ -3423,7 +3434,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int pos.coladd = 0; if (searchit(curwin, curbuf, &pos, NULL, *cmd == '?' ? BACKWARD : FORWARD, - (char_u *)"", 1L, SEARCH_MSG, i, NULL) != FAIL) { + "", 1L, SEARCH_MSG, i, NULL) != FAIL) { lnum = pos.lnum; } else { cmd = NULL; @@ -3484,7 +3495,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int if (ascii_isdigit(*cmd)) { i = '+'; // "number" is same as "+number" } else { - i = (char_u)(*cmd++); + i = (uint8_t)(*cmd++); } if (!ascii_isdigit(*cmd)) { // '+' is '+1' n = 1; @@ -3531,7 +3542,7 @@ error: /// Get flags from an Ex command argument. static void get_flags(exarg_T *eap) { - while (vim_strchr("lp#", *eap->arg) != NULL) { + while (vim_strchr("lp#", (uint8_t)(*eap->arg)) != NULL) { if (*eap->arg == 'l') { eap->flags |= EXFLAG_LIST; } else if (*eap->arg == 'p') { @@ -3699,7 +3710,7 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake || isgrep) && !grep_internal(eap->cmdidx)) { 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); + : (*curbuf->b_p_mp == NUL ? p_mp : curbuf->b_p_mp); arg = skipwhite(arg); @@ -3748,7 +3759,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) } // Quick check if this cannot be the start of a special string. // Also removes backslash before '%', '#' and '<'. - if (vim_strchr("%#<", *p) == NULL) { + if (vim_strchr("%#<", (uint8_t)(*p)) == NULL) { p++; continue; } @@ -3756,8 +3767,8 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // Try to find a match at this position. size_t srclen; int escaped; - char *repl = (char *)eval_vars((char_u *)p, (char_u *)eap->arg, &srclen, &(eap->do_ecmd_lnum), - errormsgp, &escaped, true); + char *repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum), + errormsgp, &escaped, true); if (*errormsgp != NULL) { // error detected return FAIL; } @@ -3801,8 +3812,8 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) #endif for (l = repl; *l; l++) { - if (vim_strchr((char *)ESCAPE_CHARS, *l) != NULL) { - l = vim_strsave_escaped(repl, (char *)ESCAPE_CHARS); + if (vim_strchr(ESCAPE_CHARS, (uint8_t)(*l)) != NULL) { + l = vim_strsave_escaped(repl, ESCAPE_CHARS); xfree(repl); repl = l; break; @@ -3857,7 +3868,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) backslash_halve(eap->arg); } #else - backslash_halve((char_u *)eap->arg); + backslash_halve(eap->arg); #endif if (has_wildcards) { @@ -4033,15 +4044,15 @@ char *skip_cmd_arg(char *p, int rembs) return p; } -int get_bad_opt(const char_u *p, exarg_T *eap) +int get_bad_opt(const char *p, exarg_T *eap) FUNC_ATTR_NONNULL_ALL { if (STRICMP(p, "keep") == 0) { eap->bad_char = BAD_KEEP; } else if (STRICMP(p, "drop") == 0) { eap->bad_char = BAD_DROP; - } else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) { - eap->bad_char = *p; + } else if (MB_BYTE2LEN((uint8_t)(*p)) == 1 && p[1] == NUL) { + eap->bad_char = (uint8_t)(*p); } else { return FAIL; } @@ -4118,7 +4129,7 @@ static int getargopt(exarg_T *eap) if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) { return FAIL; } - eap->force_ff = (char_u)eap->cmd[eap->force_ff]; + eap->force_ff = (uint8_t)eap->cmd[eap->force_ff]; } else if (pp == &eap->force_enc) { // Make 'fileencoding' lower case. for (char *p = eap->cmd + eap->force_enc; *p != NUL; p++) { @@ -4127,7 +4138,7 @@ static int getargopt(exarg_T *eap) } else { // Check ++bad= argument. Must be a single-byte character, "keep" or // "drop". - if (get_bad_opt((char_u *)eap->cmd + bad_char_idx, eap) == FAIL) { + if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL) { return FAIL; } } @@ -4965,8 +4976,8 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { - fname = (char *)find_file_in_path(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname); + fname = find_file_in_path(eap->arg, strlen(eap->arg), + FNAME_MESS, true, curbuf->b_ffname); if (fname == NULL) { goto theend; } @@ -4976,7 +4987,7 @@ void ex_splitview(exarg_T *eap) // Either open new tab page or split the window. if (use_tab) { if (win_new_tabpage(cmdmod.cmod_tab != 0 ? cmdmod.cmod_tab : eap->addr_count == 0 - ? 0 : (int)eap->line2 + 1, (char_u *)eap->arg) != FAIL) { + ? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) { do_exedit(eap, old_curwin); apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf); @@ -5158,15 +5169,15 @@ 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(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname); + char *fname = find_file_in_path(eap->arg, strlen(eap->arg), + FNAME_MESS, true, curbuf->b_ffname); if (eap->addr_count > 0) { // Repeat finding the file "count" times. This matters when it // appears several times in the path. linenr_T count = eap->line2; while (fname != NULL && --count > 0) { xfree(fname); - fname = (char *)find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname); + fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname); } } @@ -5238,9 +5249,9 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) old_curwin == NULL ? curwin : NULL); } else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit) || *eap->arg != NUL) { - // Can't edit another file when "curbuf->b_ro_locked" is set. Only ":edit" - // can bring us here, others are stopped earlier. - if (*eap->arg != NUL && curbuf_locked()) { + // Can't edit another file when "textlock" or "curbuf->b_ro_locked" is set. + // Only ":edit" or ":script" can bring us here, others are stopped earlier. + if (*eap->arg != NUL && text_or_buf_locked()) { return; } n = readonlymode; @@ -5961,18 +5972,18 @@ static void ex_undo(exarg_T *eap) static void ex_wundo(exarg_T *eap) { - char hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; - u_compute_hash(curbuf, (char_u *)hash); - u_write_undo(eap->arg, eap->forceit, curbuf, (char_u *)hash); + u_compute_hash(curbuf, hash); + u_write_undo(eap->arg, eap->forceit, curbuf, hash); } static void ex_rundo(exarg_T *eap) { - char hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; - u_compute_hash(curbuf, (char_u *)hash); - u_read_undo(eap->arg, (char_u *)hash, NULL); + u_compute_hash(curbuf, hash); + u_read_undo(eap->arg, hash, NULL); } /// ":redo". @@ -5991,7 +6002,7 @@ static void ex_later(exarg_T *eap) if (*p == NUL) { count = 1; - } else if (isdigit(*p)) { + } else if (isdigit((uint8_t)(*p))) { count = getdigits_long(&p, false, 0); switch (*p) { case 's': @@ -6049,7 +6060,7 @@ static void ex_redir(exarg_T *eap) close_redir(); arg++; if (valid_yank_reg(*arg, true) && *arg != '_') { - redir_reg = (char_u)(*arg++); + redir_reg = (uint8_t)(*arg++); if (*arg == '>' && arg[1] == '>') { // append arg += 2; } else { @@ -6714,8 +6725,8 @@ ssize_t find_cmdline_var(const char *src, size_t *usedlen) /// @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, const char_u *srcstart, size_t *usedlen, linenr_T *lnump, - char **errormsg, int *escaped, bool empty_is_error) +char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg, + int *escaped, bool empty_is_error) { char *result; char *resultbuf = NULL; @@ -6731,7 +6742,7 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T } // Check if there is something to do. - ssize_t spec_idx = find_cmdline_var((char *)src, usedlen); + ssize_t spec_idx = find_cmdline_var(src, usedlen); if (spec_idx < 0) { // no match *usedlen = 1; return NULL; @@ -6789,16 +6800,16 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T skip_mod = true; break; } - char *s = (char *)src + 1; + char *s = src + 1; if (*s == '<') { // "#<99" uses v:oldfiles. s++; } int i = getdigits_int(&s, false, 0); - if ((char_u *)s == src + 2 && src[1] == '-') { + if (s == src + 2 && src[1] == '-') { // just a minus sign, don't skip over it s--; } - *usedlen = (size_t)((char_u *)s - src); // length of what we expand + *usedlen = (size_t)(s - src); // length of what we expand if (src[1] == '<' && i != 0) { if (*usedlen < 2) { @@ -6834,7 +6845,7 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T break; case SPEC_CFILE: // file name under cursor - result = (char *)file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL); + result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL); if (result == NULL) { *errormsg = ""; return NULL; @@ -6844,7 +6855,7 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T case SPEC_AFILE: // file name for autocommand if (autocmd_fname != NULL - && !path_is_absolute((char_u *)autocmd_fname) + && !path_is_absolute(autocmd_fname) // For CmdlineEnter and related events, <afile> is not a path! #9348 && !strequal("/", autocmd_fname)) { // Still need to turn the fname into a full path. It was @@ -6951,7 +6962,7 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T resultlen = (size_t)(s - result); } } else if (!skip_mod) { - valid |= modify_fname((char *)src, tilde_file, usedlen, &result, + valid |= modify_fname(src, tilde_file, usedlen, &result, &resultbuf, &resultlen); if (result == NULL) { *errormsg = ""; @@ -6974,7 +6985,7 @@ char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T result = xstrnsave(result, resultlen); } xfree(resultbuf); - return (char_u *)result; + return result; } /// Expand the <sfile> string in "arg". @@ -6991,8 +7002,7 @@ 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, - true); + char *repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL, true); if (errormsg != NULL) { if (*errormsg) { emsg(errormsg); diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 6450892e39..f76e60f6c5 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -449,8 +449,8 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) // when no active try block is found, see do_cmdline(). if (type == ET_USER) { if (strncmp(value, "Vim", 3) == 0 - && (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' - || ((char_u *)value)[3] == '(')) { + && (((char *)value)[3] == NUL || ((char *)value)[3] == ':' + || ((char *)value)[3] == '(')) { emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix")); goto fail; } @@ -1150,7 +1150,7 @@ void ex_throw(exarg_T *eap) // On error or when an exception is thrown during argument evaluation, do // not throw. if (!eap->skip && value != NULL) { - if (throw_exception((char_u *)value, ET_USER, NULL) == FAIL) { + if (throw_exception(value, ET_USER, NULL) == FAIL) { xfree(value); } else { do_throw(eap->cstack); @@ -1372,8 +1372,7 @@ void ex_catch(exarg_T *eap) // prev_got_int = got_int; got_int = false; - caught = vim_regexec_nl(®match, (char_u *)current_exception->value, - (colnr_T)0); + caught = vim_regexec_nl(®match, current_exception->value, (colnr_T)0); got_int |= prev_got_int; vim_regfree(regmatch.regprog); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 72208c976f..76c3680742 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -274,7 +274,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s parse_command_modifiers(&ea, &dummy, &dummy_cmdmod, true); cmd = skip_range(ea.cmd, NULL); - if (vim_strchr("sgvl", *cmd) == NULL) { + if (vim_strchr("sgvl", (uint8_t)(*cmd)) == NULL) { goto theend; } @@ -381,7 +381,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat proftime_T tm; int skiplen, patlen; char next_char; - char_u use_last_pat; + bool use_last_pat; int search_delim; // Parsing range may already set the last search pattern. @@ -558,7 +558,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((char_u *)ccline.cmdbuff + skiplen)) { + && !pat_has_uppercase(ccline.cmdbuff + skiplen)) { *c = mb_tolower(*c); } if (*c == search_delim @@ -725,7 +725,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea if (ccline.input_fn) { s->xpc.xp_context = ccline.xp_context; s->xpc.xp_pattern = ccline.cmdbuff; - s->xpc.xp_arg = (char *)ccline.xp_arg; + s->xpc.xp_arg = ccline.xp_arg; } // Avoid scrolling when called by a recursive do_cmdline(), e.g. when @@ -773,7 +773,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea tl_ret = try_leave(&tstate, &err); if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); - msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg); + msg_scroll = true; + msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST); api_clear_error(&err); redrawcmd(); } @@ -881,7 +882,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); - semsg(e_autocmd_err, err.msg); + emsg(err.msg); did_emsg = false; api_clear_error(&err); } @@ -907,7 +908,7 @@ theend: xfree(ccline.last_colors.cmdbuff); kv_destroy(ccline.last_colors.colors); - char_u *p = (char_u *)ccline.cmdbuff; + char *p = ccline.cmdbuff; if (ui_has(kUICmdline)) { ui_call_cmdline_hide(ccline.level); @@ -922,7 +923,7 @@ theend: ccline.cmdbuff = NULL; } - return p; + return (uint8_t *)p; } static int command_line_check(VimState *state) @@ -1234,10 +1235,20 @@ static int command_line_execute(VimState *state, int key) } } + // The wildmenu is cleared if the pressed key is not used for + // navigating the wild menu (i.e. the key is not 'wildchar' or + // 'wildcharm' or Ctrl-N or Ctrl-P or Ctrl-A or Ctrl-L). + // If the popup menu is displayed, then PageDown and PageUp keys are + // also used to navigate the menu. + bool end_wildmenu = (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z + && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A + && s->c != Ctrl_L); + end_wildmenu = end_wildmenu && (!cmdline_pum_active() + || (s->c != K_PAGEDOWN && s->c != K_PAGEUP + && s->c != K_KPAGEDOWN && s->c != K_KPAGEUP)); + // free expanded names when finished walking through matches - if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z - && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A - && s->c != Ctrl_L) { + if (end_wildmenu) { command_line_end_wildmenu(s); } @@ -1368,7 +1379,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ char save; if (search_delim == ccline.cmdbuff[skiplen]) { - pat = (char *)last_search_pattern(); + pat = last_search_pattern(); if (pat == NULL) { restore_last_search_pattern(); return FAIL; @@ -1398,7 +1409,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ pat[patlen] = NUL; int found = searchit(curwin, curbuf, &t, NULL, next_match ? FORWARD : BACKWARD, - (char_u *)pat, count, search_flags, + pat, count, search_flags, RE_SEARCH, NULL); emsg_off--; pat[patlen] = save; @@ -1463,7 +1474,7 @@ static int command_line_erase_chars(CommandLineState *s) } if (s->c == K_DEL) { - ccline.cmdpos += mb_off_next((char_u *)ccline.cmdbuff, + ccline.cmdpos += mb_off_next(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos); } @@ -1546,9 +1557,9 @@ static void command_line_toggle_langmap(CommandLineState *s) if (s->b_im_ptr != NULL) { if (s->b_im_ptr == &curbuf->b_p_iminsert) { - set_iminsert_global(); + set_iminsert_global(curbuf); } else { - set_imsearch_global(); + set_imsearch_global(curbuf); } } ui_cursor_shape(); // may show different cursor shape @@ -2000,8 +2011,8 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_N: // next match case Ctrl_P: // previous match if (s->xpc.xp_numfiles > 0) { - if (nextwild(&s->xpc, (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT, - 0, s->firstc != '@') == FAIL) { + const int wild_type = (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } return command_line_not_changed(s); @@ -2016,13 +2027,26 @@ static int command_line_handle_key(CommandLineState *s) case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: - switch (command_line_browse_history(s)) { - case CMDLINE_CHANGED: - return command_line_changed(s); - case GOTO_NORMAL_MODE: - return 0; - default: + if (cmdline_pum_active() + && (s->c == K_PAGEUP || s->c == K_PAGEDOWN + || s->c == K_KPAGEUP || s->c == K_KPAGEDOWN)) { + // If the popup menu is displayed, then PageUp and PageDown + // are used to scroll the menu. + const int wild_type = + (s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN) ? WILD_PAGEDOWN : WILD_PAGEUP; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { + break; + } return command_line_not_changed(s); + } else { + switch (command_line_browse_history(s)) { + case CMDLINE_CHANGED: + return command_line_changed(s); + case GOTO_NORMAL_MODE: + return 0; + default: + return command_line_not_changed(s); + } } case Ctrl_G: // next match @@ -2141,7 +2165,7 @@ static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) { // remove trailing \v and the like while (len >= 2 && p[len - 2] == '\\' - && vim_strchr("mMvVcCZ", p[len - 1]) != NULL) { + && vim_strchr("mMvVcCZ", (uint8_t)p[len - 1]) != NULL) { len -= 2; } @@ -2521,7 +2545,8 @@ static void do_autocmd_cmdlinechanged(int firstc) bool tl_ret = try_leave(&tstate, &err); if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); - msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg); + msg_scroll = true; + msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST); api_clear_error(&err); redrawcmd(); } @@ -2600,9 +2625,9 @@ static void abandon_cmdline(void) /// /// @param count only used for incremental search /// @param indent indent for inside conditionals -char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) +char *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) { - return command_line_enter(firstc, count, indent, true); + return (char *)command_line_enter(firstc, count, indent, true); } /// Get a command line with a prompt @@ -2635,10 +2660,10 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at CLEAR_FIELD(ccline); } ccline.prompt_id = last_prompt_id++; - ccline.cmdprompt = (char_u *)prompt; + ccline.cmdprompt = (char *)prompt; ccline.cmdattr = attr; ccline.xp_context = xp_context; - ccline.xp_arg = (char_u *)xp_arg; + ccline.xp_arg = (char *)xp_arg; ccline.input_fn = (firstc == '@'); ccline.highlight_callback = highlight_callback; @@ -2662,12 +2687,6 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at return ret; } -// Return current cmdline prompt -char_u *get_cmdprompt(void) -{ - return ccline.cmdprompt; -} - /// Read the 'wildmode' option, fill wim_flags[]. int check_opt_wim(void) { @@ -2847,7 +2866,7 @@ char *getexline(int c, void *cookie, int indent, bool do_concat) (void)vgetc(); } - return (char *)getcmdline(c, 1L, indent, do_concat); + return getcmdline(c, 1L, indent, do_concat); } bool cmdline_overstrike(void) @@ -2885,7 +2904,7 @@ void realloc_cmdbuff(int len) return; // no need to resize } - char_u *p = (char_u *)ccline.cmdbuff; + char *p = 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. @@ -2897,7 +2916,7 @@ void realloc_cmdbuff(int len) && ccline.xpc->xp_pattern != NULL && ccline.xpc->xp_context != EXPAND_NOTHING && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL) { - int i = (int)((char_u *)ccline.xpc->xp_pattern - p); + int i = (int)(ccline.xpc->xp_pattern - p); // If xp_pattern points inside the old cmdbuff it needs to be adjusted // to point into the newly allocated memory. @@ -3232,10 +3251,10 @@ static void draw_cmdline(int start, int len) bool do_arabicshape = false; int mb_l; for (int i = start; i < start + len; i += mb_l) { - char_u *p = (char_u *)ccline.cmdbuff + i; + char *p = ccline.cmdbuff + i; int u8cc[MAX_MCO]; - int u8c = utfc_ptr2char_len((char *)p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len((char *)p, start + len - i); + int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); + mb_l = utfc_ptr2len_len(p, start + len - i); if (ARABIC_CHAR(u8c)) { do_arabicshape = true; break; @@ -3268,10 +3287,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 = (char_u *)ccline.cmdbuff + i; + char *p = ccline.cmdbuff + i; int u8cc[MAX_MCO]; - int u8c = utfc_ptr2char_len((char *)p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len((char *)p, start + len - i); + int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); + mb_l = utfc_ptr2len_len(p, start + len - i); if (ARABIC_CHAR(u8c)) { int pc; int pc1 = 0; @@ -3285,7 +3304,7 @@ static void draw_cmdline(int start, int len) if (i + mb_l >= start + len) { nc = NUL; } else { - nc = utf_ptr2char((char *)p + mb_l); + nc = utf_ptr2char(p + mb_l); } } else { // Displaying from left to right. @@ -3294,7 +3313,7 @@ static void draw_cmdline(int start, int len) } else { int pcc[MAX_MCO]; - pc = utfc_ptr2char_len((char *)p + mb_l, pcc, start + len - i - mb_l); + pc = utfc_ptr2char_len(p + mb_l, pcc, start + len - i - mb_l); pc1 = pcc[0]; } nc = prev_c; @@ -3344,7 +3363,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) if (cmdline_star) { content = arena_array(&arena, 1); size_t len = 0; - for (char_u *p = (char_u *)ccline.cmdbuff; *p; MB_PTR_ADV(p)) { + for (char *p = ccline.cmdbuff; *p; MB_PTR_ADV(p)) { len++; } char *buf = arena_alloc(&arena, len, false); @@ -3375,7 +3394,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) char charbuf[2] = { (char)line->cmdfirstc, 0 }; ui_call_cmdline_show(content, line->cmdpos, cstr_as_string(charbuf), - cstr_as_string((char *)(line->cmdprompt)), + cstr_as_string((line->cmdprompt)), line->cmdindent, line->level); if (line->special_char) { @@ -3657,7 +3676,7 @@ static void restore_cmdline(CmdlineInfo *ccp) static bool cmdline_paste(int regname, bool literally, bool remcr) { char *arg; - char_u *p; + char *p; bool allocated; // check for valid regname; also accept special characters for CTRL-R in @@ -3689,7 +3708,7 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate // part of the word. - p = (char_u *)arg; + p = arg; if (p_is && regname == Ctrl_W) { char *w; int len; @@ -3722,19 +3741,19 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // 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) +void cmdline_paste_str(char *s, int literally) { int c, cv; if (literally) { - put_on_cmdline((char *)s, -1, true); + put_on_cmdline(s, -1, true); } else { while (*s != NUL) { - cv = *s; + cv = (uint8_t)(*s); if (cv == Ctrl_V && s[1]) { s++; } - c = mb_cptr2char_adv((const char_u **)&s); + c = mb_cptr2char_adv((const char **)&s); if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL || c == Ctrl_L || (c == Ctrl_BSL && *s == Ctrl_N)) { @@ -3775,7 +3794,7 @@ static void redrawcmdprompt(void) msg_putchar(ccline.cmdfirstc); } if (ccline.cmdprompt != NULL) { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + msg_puts_attr(ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; // do the reverse of cmd_startcol() if (ccline.cmdfirstc != NUL) { @@ -3950,8 +3969,8 @@ char *vim_strsave_fnameescape(const char *const fname, const int what) { #ifdef BACKSLASH_IN_FILENAME # define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<" -# define BUFFER_ESC_CHARS ((char_u *)" \t\n*?[`%#'\"|!<") - char_u buf[sizeof(PATH_ESC_CHARS)]; +# define BUFFER_ESC_CHARS (" \t\n*?[`%#'\"|!<") + char buf[sizeof(PATH_ESC_CHARS)]; int j = 0; // Don't escape '[', '{' and '!' if they are in 'isfname' and for the @@ -3963,8 +3982,7 @@ char *vim_strsave_fnameescape(const char *const fname, const int what) } } buf[j] = NUL; - char *p = (char *)vim_strsave_escaped((const char_u *)fname, - (const char_u *)buf); + char *p = vim_strsave_escaped(fname, buf); #else # define PATH_ESC_CHARS " \t\n*?[{`$\\%#'\"|!<" # define SHELL_ESC_CHARS " \t\n*?[{`$\\%#'\"|!<>();&" @@ -3993,11 +4011,11 @@ 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 *p = xmalloc(strlen(*pp) + 2); p[0] = '\\'; STRCPY(p + 1, *pp); xfree(*pp); - *pp = (char *)p; + *pp = p; } /// For each file name in files[num_files]: @@ -4271,7 +4289,7 @@ char *check_cedit(void) if (*p_cedit == NUL) { cedit_key = -1; } else { - n = string_to_key((char_u *)p_cedit); + n = string_to_key(p_cedit); if (vim_isprintc(n)) { return e_invarg; } diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h index 916b695a35..61ac4b69c5 100644 --- a/src/nvim/ex_getln.h +++ b/src/nvim/ex_getln.h @@ -54,14 +54,14 @@ struct cmdline_info { int cmdspos; ///< cursor column on screen int cmdfirstc; ///< ':', '/', '?', '=', '>' or NUL int cmdindent; ///< number of spaces before cmdline - char_u *cmdprompt; ///< message in front of cmdline + char *cmdprompt; ///< message in front of cmdline int cmdattr; ///< attributes for prompt int overstrike; ///< Typing mode on the command line. Shared by ///< getcmdline() and put_on_cmdline(). expand_T *xpc; ///< struct being used for expansion, xp_pattern ///< may point into cmdbuff int xp_context; ///< type of expansion - char_u *xp_arg; ///< user-defined expansion arg + char *xp_arg; ///< user-defined expansion arg int input_fn; ///< when true Invoked for input() function unsigned prompt_id; ///< Prompt number, used to disable coloring on errors. Callback highlight_callback; ///< Callback used for coloring user input. diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index cae9c18309..3de5e1db52 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -38,7 +38,6 @@ #include "nvim/path.h" #include "nvim/pos.h" #include "nvim/runtime.h" -#include "nvim/types.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -113,40 +112,43 @@ static int ses_win_rec(FILE *fd, frame_T *fr) frame_T *frc; int count = 0; - if (fr->fr_layout != FR_LEAF) { - // Find first frame that's not skipped and then create a window for - // each following one (first frame is already there). - frc = ses_skipframe(fr->fr_child); - if (frc != NULL) { - while ((frc = ses_skipframe(frc->fr_next)) != NULL) { - // Make window as big as possible so that we have lots of room - // to split. - if (fprintf(fd, "%s%s", - "wincmd _ | wincmd |\n", - (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n")) < 0) { - return FAIL; - } - count++; + if (fr->fr_layout == FR_LEAF) { + return OK; + } + + // Find first frame that's not skipped and then create a window for + // each following one (first frame is already there). + frc = ses_skipframe(fr->fr_child); + if (frc != NULL) { + while ((frc = ses_skipframe(frc->fr_next)) != NULL) { + // Make window as big as possible so that we have lots of room + // to split. + if (fprintf(fd, "%s%s", + "wincmd _ | wincmd |\n", + (fr->fr_layout == FR_COL ? "split\n" : "vsplit\n")) < 0) { + return FAIL; } + count++; } + } - // Go back to the first window. - if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL - ? "%dwincmd k\n" : "%dwincmd h\n", count) < 0)) { - return FAIL; - } + // Go back to the first window. + if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL + ? "%dwincmd k\n" : "%dwincmd h\n", count) < 0)) { + return FAIL; + } - // Recursively create frames/windows in each window of this column or row. - frc = ses_skipframe(fr->fr_child); - while (frc != NULL) { - ses_win_rec(fd, frc); - frc = ses_skipframe(frc->fr_next); - // Go to next window. - if (frc != NULL && put_line(fd, "wincmd w") == FAIL) { - return FAIL; - } + // Recursively create frames/windows in each window of this column or row. + frc = ses_skipframe(fr->fr_child); + while (frc != NULL) { + ses_win_rec(fd, frc); + frc = ses_skipframe(frc->fr_next); + // Go to next window. + if (frc != NULL && put_line(fd, "wincmd w") == FAIL) { + return FAIL; } } + return OK; } @@ -907,12 +909,14 @@ static int makeopens(FILE *fd, char *dirnow) void ex_loadview(exarg_T *eap) { char *fname = get_view_file(*eap->arg); - if (fname != NULL) { - if (do_source(fname, false, DOSO_NONE) == FAIL) { - semsg(_(e_notopen), fname); - } - xfree(fname); + if (fname == NULL) { + return; + } + + if (do_source(fname, false, DOSO_NONE) == FAIL) { + semsg(_(e_notopen), fname); } + xfree(fname); } /// ":mkexrc", ":mkvimrc", ":mkview", ":mksession". diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index d0280b3571..a0435afd65 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -143,7 +143,7 @@ typedef struct ff_visited_list_hdr { // '**' can be expanded to several directory levels. // Set the default maximum depth. -#define FF_MAX_STAR_STAR_EXPAND ((char_u)30) +#define FF_MAX_STAR_STAR_EXPAND 30 // The search context: // ffsc_stack_ptr: the stack for the dirs to search @@ -182,7 +182,7 @@ typedef struct ff_search_ctx_T { # include "file_search.c.generated.h" #endif -static char_u e_pathtoolong[] = N_("E854: path too long for completion"); +static char e_pathtoolong[] = N_("E854: path too long for completion"); /// Initialization routine for vim_findfile(). /// @@ -302,14 +302,12 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i #ifdef BACKSLASH_IN_FILENAME // "c:dir" needs "c:" to be expanded, otherwise use current dir if (*path != NUL && path[1] == ':') { - char_u drive[3]; + char drive[3]; drive[0] = path[0]; drive[1] = ':'; drive[2] = NUL; - if (vim_FullName((const char *)drive, (char *)ff_expand_buffer, MAXPATHL, - true) - == FAIL) { + if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, true) == FAIL) { goto error_return; } path += 2; @@ -504,15 +502,15 @@ error_return: } /// @return the stopdir string. Check that ';' is not escaped. -char_u *vim_findfile_stopdir(char *buf) +char *vim_findfile_stopdir(char *buf) { - char_u *r_ptr = (char_u *)buf; + char *r_ptr = 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'. - STRMOVE(r_ptr, (char *)r_ptr + 1); + STRMOVE(r_ptr, r_ptr + 1); r_ptr++; } r_ptr++; @@ -551,7 +549,7 @@ void vim_findfile_cleanup(void *ctx) /// /// @return a pointer to an allocated file name or, /// NULL if nothing found. -char_u *vim_findfile(void *search_ctx_arg) +char *vim_findfile(void *search_ctx_arg) { char *file_path; char *rest_of_wildcards; @@ -829,7 +827,7 @@ char_u *vim_findfile(void *search_ctx_arg) verbose_leave_scroll(); } #endif - return (char_u *)file_path; + return file_path; } // Not found or found already, try next suffix. @@ -1094,7 +1092,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p } // New file/dir. Add it to the list of visited files/dirs. - vp = xmalloc(sizeof(ff_visited_T) + strlen(ff_expand_buffer)); + vp = xmalloc(offsetof(ff_visited_T, ffv_fname) + strlen(ff_expand_buffer) + 1); if (!url) { vp->file_id_valid = true; @@ -1287,13 +1285,13 @@ static int ff_path_in_stoplist(char *path, int path_len, char **stopdirs_v) /// @param rel_fname file name searching relative to /// /// @return an allocated string for the file name. NULL for error. -char_u *find_file_in_path(char *ptr, size_t len, int options, int first, char *rel_fname) +char *find_file_in_path(char *ptr, size_t len, int options, int first, char *rel_fname) { - return (char_u *)find_file_in_path_option(ptr, len, options, first, - (*curbuf->b_p_path == NUL - ? (char *)p_path - : curbuf->b_p_path), - FINDFILE_BOTH, rel_fname, curbuf->b_p_sua); + 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); } static char *ff_file_to_find = NULL; @@ -1322,10 +1320,10 @@ void free_findfile(void) /// @param rel_fname file name searching relative to /// /// @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) +char *find_directory_in_path(char *ptr, size_t len, int options, char *rel_fname) { - return (char_u *)find_file_in_path_option((char *)ptr, len, options, true, (char *)p_cdpath, - FINDFILE_DIR, (char *)rel_fname, ""); + return find_file_in_path_option(ptr, len, options, true, p_cdpath, + FINDFILE_DIR, rel_fname, ""); } /// @param ptr file name @@ -1446,7 +1444,7 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch for (;;) { if (did_findfile_init) { - file_name = (char *)vim_findfile(fdip_search_ctx); + file_name = vim_findfile(fdip_search_ctx); if (file_name != NULL) { break; } @@ -1469,7 +1467,7 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch copy_option_part(&dir, buf, MAXPATHL, " ,"); // get the stopdir string - r_ptr = (char *)vim_findfile_stopdir(buf); + r_ptr = vim_findfile_stopdir(buf); fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find, r_ptr, 100, false, find_what, fdip_search_ctx, false, rel_fname); @@ -1610,8 +1608,8 @@ int vim_chdirfile(char *fname, CdCause cause) /// Change directory to "new_dir". Search 'cdpath' for relative directory names. int vim_chdir(char *new_dir) { - char *dir_name = (char *)find_directory_in_path((char_u *)new_dir, strlen(new_dir), - FNAME_MESS, (char_u *)curbuf->b_ffname); + char *dir_name = find_directory_in_path(new_dir, strlen(new_dir), + FNAME_MESS, curbuf->b_ffname); if (dir_name == NULL) { return -1; } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 0ee547d124..fbb5c4f1fa 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -105,7 +105,7 @@ enum { // 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 + char *bw_buf; // buffer with data to be written int bw_len; // length of data #ifdef HAS_BW_FLAGS int bw_flags; // FIO_ flags @@ -113,14 +113,12 @@ struct bw_info { char_u bw_rest[CONV_RESTLEN]; // not converted bytes int bw_restlen; // nr of bytes in bw_rest[] int bw_first; // first write call - char_u *bw_conv_buf; // buffer for writing converted chars + char *bw_conv_buf; // buffer for writing converted chars size_t bw_conv_buflen; // size of bw_conv_buf int bw_conv_error; // set for conversion error linenr_T bw_conv_error_lnum; // first line with error or zero linenr_T bw_start_lnum; // line number at start of buffer -#ifdef HAVE_ICONV iconv_t bw_iconv_fd; // descriptor for iconv() or -1 -#endif }; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -248,11 +246,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, char *fenc_next = NULL; // next item in 'fencs' or NULL bool advance_fenc = false; long real_size = 0; -#ifdef HAVE_ICONV iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 bool did_iconv = false; // true when iconv() failed and trying // 'charconvert' next -#endif bool converted = false; // true if conversion done bool notconverted = false; // true if conversion wanted but it wasn't possible char conv_rest[CONV_RESTLEN]; @@ -278,7 +274,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, && fname != NULL && vim_strchr(p_cpo, CPO_FNAMER) != NULL && !(flags & READ_DUMMY)) { - if (set_rw_fname((char_u *)fname, (char_u *)sfname) == FAIL) { + if (set_rw_fname(fname, sfname) == FAIL) { return FAIL; } } @@ -779,13 +775,11 @@ retry: } } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { // aborted conversion with iconv(), close the descriptor iconv_close(iconv_fd); iconv_fd = (iconv_t)-1; } -#endif if (advance_fenc) { // Try the next entry in 'fileencodings'. @@ -835,32 +829,24 @@ retry: // appears not to handle this correctly. This works just like // conversion to UTF-8 except how the resulting character is put in // the buffer. - fio_flags = get_fio_flags((char_u *)fenc); + fio_flags = get_fio_flags(fenc); } -#ifdef HAVE_ICONV // Try using iconv() if we can't convert internally. if (fio_flags == 0 && !did_iconv) { - iconv_fd = (iconv_t)my_iconv_open((char_u *)"utf-8", (char_u *)fenc); + iconv_fd = (iconv_t)my_iconv_open("utf-8", fenc); } -#endif // 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 - && iconv_fd == (iconv_t)-1 -#endif - ) { -#ifdef HAVE_ICONV + && !read_fifo && iconv_fd == (iconv_t)-1) { did_iconv = false; -#endif // Skip conversion when it's already done (retry for wrong // "fileformat"). if (tmpname == NULL) { - tmpname = (char *)readfile_charconvert((char_u *)fname, (char_u *)fenc, &fd); + tmpname = readfile_charconvert(fname, fenc, &fd); if (tmpname == NULL) { // Conversion failed. Try another one. advance_fenc = true; @@ -874,11 +860,7 @@ retry: } } } else { - if (fio_flags == 0 -#ifdef HAVE_ICONV - && iconv_fd == (iconv_t)-1 -#endif - ) { + if (fio_flags == 0 && iconv_fd == (iconv_t)-1) { // Conversion wanted but we can't. // Try the next conversion in 'fileencodings' advance_fenc = true; @@ -961,12 +943,9 @@ retry: // ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be // multiple of 4 real_size = (int)size; -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { size = size / ICONV_MULT; - } else { -#endif - if (fio_flags & FIO_LATIN1) { + } else if (fio_flags & FIO_LATIN1) { size = size / 2; } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { size = (size * 2 / 3) & ~1; @@ -975,9 +954,7 @@ retry: } else if (fio_flags == FIO_UCSBOM) { size = size / ICONV_MULT; // worst case } -#ifdef HAVE_ICONV - } -#endif + if (conv_restlen > 0) { // Insert unconverted bytes from previous line. memmove(ptr, conv_rest, (size_t)conv_restlen); // -V614 @@ -991,13 +968,11 @@ retry: if (read_buf_lnum > from) { size = 0; } else { - int n, ni; - long tlen; - - tlen = 0; + int ni; + long tlen = 0; for (;;) { p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; - n = (int)strlen((char *)p); + int n = (int)strlen((char *)p); if ((int)tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done @@ -1049,11 +1024,7 @@ retry: // not be converted. Truncated file? // When we did a conversion report an error. - if (fio_flags != 0 -#ifdef HAVE_ICONV - || iconv_fd != (iconv_t)-1 -#endif - ) { + if (fio_flags != 0 || iconv_fd != (iconv_t)-1) { if (can_retry) { goto rewind_retry; } @@ -1074,23 +1045,17 @@ retry: // character if we were converting; if we weren't, // leave the UTF8 checking code to do it, as it // works slightly differently. - if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 -#ifdef HAVE_ICONV - || iconv_fd != (iconv_t)-1 -#endif - )) { // NOLINT(whitespace/parens) + if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 || iconv_fd != (iconv_t)-1)) { while (conv_restlen > 0) { *(--ptr) = (char)bad_char_behavior; conv_restlen--; } } fio_flags = 0; // don't convert this -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); iconv_fd = (iconv_t)-1; } -#endif } } } @@ -1107,15 +1072,15 @@ retry: || (!curbuf->b_p_bomb && tmpname == NULL && (*fenc == 'u' || *fenc == NUL)))) { - char_u *ccname; + char *ccname; int blen = 0; // no BOM detection in a short file or in binary mode if (size < 2 || curbuf->b_p_bin) { ccname = NULL; } else { - ccname = check_for_bom((char_u *)ptr, size, &blen, - fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags((char_u *)fenc)); + ccname = check_for_bom(ptr, size, &blen, + fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); } if (ccname != NULL) { // Remove BOM from the text @@ -1137,7 +1102,7 @@ retry: if (fenc_alloced) { xfree(fenc); } - fenc = (char *)ccname; + fenc = ccname; fenc_alloced = false; } // retry reading without getting new bytes or rewinding @@ -1155,7 +1120,6 @@ retry: break; } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { // Attempt conversion of the read bytes to 'encoding' using iconv(). const char *fromp = ptr; @@ -1175,7 +1139,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, (char_u *)top); + conv_error = readfile_linenr(linecnt, ptr, top); } // Deal with a bad byte and continue with the next. @@ -1193,7 +1157,7 @@ retry: if (from_size > 0) { // Some remaining characters, keep them for the next // round. - memmove(conv_rest, (char_u *)fromp, from_size); + memmove(conv_rest, fromp, from_size); conv_restlen = (int)from_size; } @@ -1202,7 +1166,6 @@ retry: memmove(line_start, buffer, (size_t)linerest); size = (top - ptr); } -#endif if (fio_flags != 0) { unsigned int u8c; @@ -1287,7 +1250,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1315,7 +1278,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1356,7 +1319,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1394,7 +1357,7 @@ retry: // an incomplete character at the end though, the next // read() will get the next bytes, we'll check it // then. - l = utf_ptr2len_len(p, todo); + l = utf_ptr2len_len((char *)p, todo); if (l > todo && !incomplete_tail) { // Avoid retrying with a different encoding when // a truncated file is more likely, or attempting @@ -1420,15 +1383,15 @@ retry: if (can_retry && !incomplete_tail) { break; } -#ifdef HAVE_ICONV + // When we did a conversion report an error. if (iconv_fd != (iconv_t)-1 && conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } -#endif + // Remember the first linenr with an illegal byte if (conv_error == 0 && illegal_byte == 0) { - illegal_byte = readfile_linenr(linecnt, (char_u *)ptr, p); + illegal_byte = readfile_linenr(linecnt, ptr, (char *)p); } // Drop, keep or replace the bad byte. @@ -1448,17 +1411,13 @@ retry: // Detected a UTF-8 error. rewind_retry: // Retry reading with another conversion. -#ifdef HAVE_ICONV if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) { // iconv() failed, try 'charconvert' did_iconv = true; } else { -#endif - // use next item from 'fileencodings' - advance_fenc = true; -#ifdef HAVE_ICONV - } -#endif + // use next item from 'fileencodings' + advance_fenc = true; + } file_rewind = true; goto retry; } @@ -1554,7 +1513,7 @@ rewind_retry: break; } if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } lnum++; if (--read_count == 0) { @@ -1610,7 +1569,7 @@ rewind_retry: break; } if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } lnum++; if (--read_count == 0) { @@ -1667,7 +1626,7 @@ failed: error = true; } else { if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } read_no_eol_lnum = ++lnum; } @@ -1683,11 +1642,9 @@ failed: if (fenc_alloced) { xfree(fenc); } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); } -#endif if (!read_buffer && !read_stdin) { close(fd); // errors are ignored @@ -1887,7 +1844,7 @@ failed: char_u hash[UNDO_HASH_SIZE]; sha256_finish(&sha_ctx, hash); - u_read_undo(NULL, hash, (char_u *)fname); + u_read_undo(NULL, hash, fname); } if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) { @@ -1958,9 +1915,9 @@ bool is_dev_fd_file(char *fname) /// @param linecnt line count before reading more bytes /// @param p start of more bytes read /// @param endp end of more bytes read -static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, const char_u *endp) +static linenr_T readfile_linenr(linenr_T linecnt, char *p, const char *endp) { - char_u *s; + char *s; linenr_T lnum; lnum = curbuf->b_ml.ml_line_count - linecnt + 1; @@ -2040,7 +1997,7 @@ static char *next_fenc(char **pp, bool *alloced) *pp = NULL; return ""; } - p = vim_strchr((*pp), ','); + p = vim_strchr(*pp, ','); if (p == NULL) { r = enc_canonize(*pp); *pp += strlen(*pp); @@ -2065,22 +2022,22 @@ static char *next_fenc(char **pp, bool *alloced) /// /// @return name of the resulting converted file (the caller should delete it after reading it). /// Returns NULL if the conversion failed ("*fdp" is not set) . -static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) +static char *readfile_charconvert(char *fname, char *fenc, int *fdp) { - char_u *tmpname; + char *tmpname; char *errmsg = NULL; - tmpname = (char_u *)vim_tempname(); + tmpname = vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { close(*fdp); // close the input file, ignore errors *fdp = -1; - if (eval_charconvert((char *)fenc, "utf-8", - (char *)fname, (char *)tmpname) == FAIL) { + if (eval_charconvert(fenc, "utf-8", + fname, tmpname) == FAIL) { errmsg = _("Conversion with 'charconvert' failed"); } - if (errmsg == NULL && (*fdp = os_open((char *)tmpname, O_RDONLY, 0)) < 0) { + if (errmsg == NULL && (*fdp = os_open(tmpname, O_RDONLY, 0)) < 0) { errmsg = _("can't read output of 'charconvert'"); } } @@ -2090,14 +2047,14 @@ static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) // another type of conversion might still work. msg(errmsg); if (tmpname != NULL) { - os_remove((char *)tmpname); // delete converted file + os_remove(tmpname); // delete converted file XFREE_CLEAR(tmpname); } } // If the input file is closed, open it (caller should check for error). if (*fdp < 0) { - *fdp = os_open((char *)fname, O_RDONLY, 0); + *fdp = os_open(fname, O_RDONLY, 0); } return tmpname; @@ -2167,7 +2124,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bool errmsg_allocated = false; char *buffer; char smallbuf[SMBUFSIZE]; - char *backup_ext; int bufsize; long perm; // file permissions int retval = OK; @@ -2233,9 +2189,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en 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. @@ -2254,7 +2208,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en && !filtering && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { - if (set_rw_fname((char_u *)fname, (char_u *)sfname) == FAIL) { + if (set_rw_fname(fname, sfname) == FAIL) { return FAIL; } buf = curbuf; // just in case autocmds made "buf" invalid @@ -2473,7 +2427,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (!filtering) { filemess(buf, #ifndef UNIX - (char_u *)sfname, + sfname, #else fname, #endif @@ -2517,7 +2471,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } #else // win32 // Check for a writable device name. - c = fname == NULL ? NODE_OTHER : os_nodetype((char *)fname); + c = fname == NULL ? NODE_OTHER : os_nodetype(fname); if (c == NODE_OTHER) { SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; @@ -2535,7 +2489,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } if (overwriting) { - os_fileinfo((char *)fname, &file_info_old); + os_fileinfo(fname, &file_info_old); } } #endif // !UNIX @@ -2566,13 +2520,13 @@ 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. if (!newfile) { - acl = os_get_acl((char_u *)fname); + acl = os_get_acl(fname); } #endif // 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)) { + if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) { dobackup = false; } @@ -2598,8 +2552,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if ((bkc & BKC_YES) || append) { // "yes" 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 @@ -2614,7 +2566,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // First find a file name that doesn't exist yet (use some // arbitrary numbers). STRCPY(IObuff, fname); - for (i = 4913;; i += 123) { + for (int i = 4913;; i += 123) { char *tail = path_tail(IObuff); size_t size = (size_t)(tail - IObuff); snprintf(tail, IOSIZE - size, "%d", i); @@ -2667,18 +2619,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } // make sure we have a valid backup extension to use - if (*p_bex == NUL) { - backup_ext = ".bak"; - } else { - backup_ext = p_bex; - } + char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; if (backup_copy) { - char *wp; int some_error = false; - char *dirp; - char *rootname; - char *p; // Try to make the backup in each directory in the 'bdir' option. // @@ -2690,11 +2634,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // // For these reasons, the existing writable file must be truncated // and reused. Creation of a backup COPY will be attempted. - dirp = p_bdir; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name, using an entry in 'bdir'. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2717,7 +2661,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = true; // out of memory goto nobackup; @@ -2753,7 +2697,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); + char *wp = backup + strlen(backup) - 1 - strlen(backup_ext); if (wp < backup) { // empty file name ??? wp = backup; } @@ -2806,7 +2750,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en (double)file_info_old.stat.st_mtim.tv_sec); #endif #ifdef HAVE_ACL - os_set_acl((char_u *)backup, acl); + os_set_acl(backup, acl); #endif SET_ERRMSG(NULL); break; @@ -2824,10 +2768,6 @@ nobackup: } SET_ERRMSG(NULL); } else { - char *dirp; - char *p; - char *rootname; - // Make a backup by renaming the original file. // If 'cpoptions' includes the "W" flag, we don't want to @@ -2841,11 +2781,11 @@ nobackup: // 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; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name and make the backup file name. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2869,7 +2809,7 @@ nobackup: } if (backup == NULL) { - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -2980,7 +2920,7 @@ nobackup: // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). // Prepare the flags for it and allocate bw_conv_buf when needed. if (converted) { - wb_flags = get_fio_flags((char_u *)fenc); + wb_flags = get_fio_flags(fenc); if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) { // Need to allocate a buffer to translate into. if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) { @@ -2996,10 +2936,9 @@ nobackup: } if (converted && wb_flags == 0) { -#ifdef HAVE_ICONV // Use iconv() conversion when conversion is needed and it's not done // internally. - write_info.bw_iconv_fd = (iconv_t)my_iconv_open((char_u *)fenc, (char_u *)"utf-8"); + write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, "utf-8"); if (write_info.bw_iconv_fd != (iconv_t)-1) { // We're going to use iconv(), allocate a buffer to convert in. write_info.bw_conv_buflen = (size_t)bufsize * ICONV_MULT; @@ -3009,28 +2948,21 @@ nobackup: } 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. - if (*p_ccv != NUL) { - 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; + // 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 = 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 -#endif && wfname == fname) { if (!forceit) { SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)")); @@ -3151,7 +3083,7 @@ restore_backup: } SET_ERRMSG(NULL); - write_info.bw_buf = (char_u *)buffer; + write_info.bw_buf = buffer; nchars = 0; // use "++bin", "++nobin" or 'binary' @@ -3164,7 +3096,7 @@ restore_backup: // Skip the BOM when appending and the file already existed, the BOM // only makes sense at the start of the file. if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) { - write_info.bw_len = make_bom((char_u *)buffer, (char_u *)fenc); + write_info.bw_len = make_bom((char_u *)buffer, fenc); if (write_info.bw_len > 0) { // don't convert write_info.bw_flags = FIO_NOCONVERT | wb_flags; @@ -3196,7 +3128,7 @@ restore_backup: // Keep it fast! 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, (uint8_t *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); } while ((c = *++ptr) != NUL) { if (c == NL) { @@ -3342,7 +3274,7 @@ restore_backup: // Probably need to set the ACL before changing the user (can't set the // ACL on a file the user doesn't own). if (!backup_copy) { - os_set_acl((char_u *)wfname, acl); + os_set_acl(wfname, acl); } #endif @@ -3551,12 +3483,10 @@ nofail: } xfree(fenc_tofree); xfree(write_info.bw_conv_buf); -#ifdef HAVE_ICONV if (write_info.bw_iconv_fd != (iconv_t)-1) { iconv_close(write_info.bw_iconv_fd); write_info.bw_iconv_fd = (iconv_t)-1; } -#endif #ifdef HAVE_ACL os_free_acl(acl); #endif @@ -3605,10 +3535,10 @@ nofail: // 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]; + uint8_t hash[UNDO_HASH_SIZE]; - sha256_finish(&sha_ctx, (char_u *)hash); - u_write_undo(NULL, false, buf, (char_u *)hash); + sha256_finish(&sha_ctx, hash); + u_write_undo(NULL, false, buf, hash); } if (!should_abort(retval)) { @@ -3652,7 +3582,7 @@ nofail: /// Set the name of the current buffer. Use when the buffer doesn't have a /// name and a ":r" or ":w" command with a file name is used. -static int set_rw_fname(char_u *fname, char_u *sfname) +static int set_rw_fname(char *fname, char *sfname) { buf_T *buf = curbuf; @@ -3670,7 +3600,7 @@ static int set_rw_fname(char_u *fname, char_u *sfname) return FAIL; } - if (setfname(curbuf, (char *)fname, (char *)sfname, false) == OK) { + if (setfname(curbuf, fname, sfname, false) == OK) { curbuf->b_flags |= BF_NOTEDITED; } @@ -3743,9 +3673,7 @@ static bool msg_add_fileformat(int eol_type) /// Append line and character count to IObuff. void msg_add_lines(int insert_space, long lnum, off_T nchars) { - char *p; - - p = IObuff + strlen(IObuff); + char *p = IObuff + strlen(IObuff); if (insert_space) { *p++ = ' '; @@ -3801,7 +3729,7 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F || file_info->stat.st_mtim.tv_sec - mtime > 1 || mtime - file_info->stat.st_mtim.tv_sec > 1; #else - || (long)file_info->stat.st_mtim.tv_sec != mtime; + || file_info->stat.st_mtim.tv_sec != mtime; #endif } @@ -3811,48 +3739,37 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F /// @return FAIL for failure, OK otherwise. static int buf_write_bytes(struct bw_info *ip) { - int wlen; - char_u *buf = ip->bw_buf; // data to write - int len = ip->bw_len; // length of data + char *buf = ip->bw_buf; // data to write + int len = ip->bw_len; // length of data #ifdef HAS_BW_FLAGS - int flags = ip->bw_flags; // extra flags + int flags = ip->bw_flags; // extra flags #endif // 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. - p = ip->bw_conv_buf; // translate to buffer - for (wlen = 0; wlen < len; wlen++) { - p += utf_char2bytes(buf[wlen], (char *)p); + char *p = ip->bw_conv_buf; // translate to buffer + for (int wlen = 0; wlen < len; wlen++) { + p += utf_char2bytes((uint8_t)buf[wlen], p); } buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { + unsigned c; + int n = 0; // 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 { - p = ip->bw_conv_buf; // translate to buffer - } - for (wlen = 0; wlen < len; wlen += n) { + // translate in-place (can only get shorter) or to buffer + char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf; + for (int wlen = 0; wlen < len; wlen += n) { 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! - l = CONV_RESTLEN - ip->bw_restlen; - if (l > len) { - l = len; - } + int l = MIN(len, CONV_RESTLEN - ip->bw_restlen); memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); - n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); + n = utf_ptr2len_len((char *)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 @@ -3892,9 +3809,9 @@ static int buf_write_bytes(struct bw_info *ip) break; } if (n > 1) { - c = (unsigned)utf_ptr2char((char *)buf + wlen); + c = (unsigned)utf_ptr2char(buf + wlen); } else { - c = buf[wlen]; + c = (uint8_t)buf[wlen]; } } @@ -3914,32 +3831,28 @@ static int buf_write_bytes(struct bw_info *ip) } } -#ifdef HAVE_ICONV if (ip->bw_iconv_fd != (iconv_t)-1) { const char *from; size_t fromlen; - char *to; size_t tolen; // Convert with iconv(). 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. fromlen = (size_t)len + (size_t)ip->bw_restlen; - fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + char *fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); memmove(fp + ip->bw_restlen, buf, (size_t)len); from = fp; tolen = ip->bw_conv_buflen - fromlen; } else { - from = (const char *)buf; + from = buf; fromlen = (size_t)len; tolen = ip->bw_conv_buflen; } - to = (char *)ip->bw_conv_buf; + char *to = ip->bw_conv_buf; if (ip->bw_first) { size_t save_len = tolen; @@ -3950,7 +3863,7 @@ static int buf_write_bytes(struct bw_info *ip) // 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; + to = ip->bw_conv_buf; tolen = save_len; } ip->bw_first = false; @@ -3971,16 +3884,15 @@ static int buf_write_bytes(struct bw_info *ip) ip->bw_restlen = (int)fromlen; buf = ip->bw_conv_buf; - len = (int)((char_u *)to - ip->bw_conv_buf); + len = (int)(to - ip->bw_conv_buf); } -#endif } if (ip->bw_fd < 0) { // Only checking conversion, which is OK if we get here. return OK; } - wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); + int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); return (wlen < len) ? FAIL : OK; } @@ -3991,11 +3903,10 @@ static int buf_write_bytes(struct bw_info *ip) /// @param flags FIO_ flags that specify which encoding to use /// /// @return true for an error, false when it's OK. -static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL +static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL { - char_u *p = *pp; + char_u *p = (char_u *)(*pp); bool error = false; - int cc; if (flags & FIO_UCS4) { if (flags & FIO_ENDIAN_L) { @@ -4018,7 +3929,7 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL if (c >= 0x100000) { error = true; } - cc = (int)(((c >> 10) & 0x3ff) + 0xd800); + int cc = (int)(((c >> 10) & 0x3ff) + 0xd800); if (flags & FIO_ENDIAN_L) { *p++ = (uint8_t)cc; *p++ = (uint8_t)(cc >> 8); @@ -4047,7 +3958,7 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL } } - *pp = p; + *pp = (char *)p; return error; } @@ -4061,7 +3972,6 @@ 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) { @@ -4070,8 +3980,8 @@ static bool need_conversion(const char *fenc) } else { // Ignore difference between "ansi" and "latin1", "ucs-4" and // "ucs-4be", etc. - enc_flags = get_fio_flags((char_u *)p_enc); - fenc_flags = get_fio_flags((char_u *)fenc); + int enc_flags = get_fio_flags(p_enc); + fenc_flags = get_fio_flags(fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } if (same_encoding) { @@ -4089,14 +3999,12 @@ static bool need_conversion(const char *fenc) /// use 'encoding'. /// /// @param name string to check for encoding -static int get_fio_flags(const char_u *name) +static int get_fio_flags(const char *name) { - int prop; - if (*name == NUL) { - name = (char_u *)p_enc; + name = p_enc; } - prop = enc_canon_props((char *)name); + int prop = enc_canon_props(name); if (prop & ENC_UNICODE) { if (prop & ENC_2BYTE) { if (prop & ENC_ENDIAN_L) { @@ -4130,8 +4038,9 @@ static int get_fio_flags(const char_u *name) /// /// @return the name of the encoding and set "*lenp" to the length or, /// NULL when no BOM found. -static char_u *check_for_bom(const char_u *p, long size, int *lenp, int flags) +static char *check_for_bom(const char *p_in, long size, int *lenp, int flags) { + const uint8_t *p = (const uint8_t *)p_in; char *name = NULL; int len = 2; @@ -4167,18 +4076,15 @@ static char_u *check_for_bom(const char_u *p, long size, int *lenp, int flags) } *lenp = len; - return (char_u *)name; + return name; } /// Generate a BOM in "buf[4]" for encoding "name". /// /// @return the length of the BOM (zero when no BOM). -static int make_bom(char_u *buf, char_u *name) +static int make_bom(char_u *buf, char *name) { - int flags; - char_u *p; - - flags = get_fio_flags(name); + int flags = get_fio_flags(name); // Can't put a BOM in a non-Unicode file. if (flags == FIO_LATIN1 || flags == 0) { @@ -4191,9 +4097,9 @@ static int make_bom(char_u *buf, char_u *name) buf[2] = 0xbf; return 3; } - p = buf; + char *p = (char *)buf; (void)ucs2bytes(0xfeff, &p, flags); - return (int)(p - buf); + return (int)((char_u *)p - buf); } /// Shorten filename of a buffer. @@ -4205,20 +4111,18 @@ static int make_bom(char_u *buf, char_u *name) /// /// For buffers that have buftype "nofile" or "scratch": never change the file /// name. -void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) +void shorten_buf_fname(buf_T *buf, char *dirname, int force) { - char *p; - if (buf->b_fname != NULL && !bt_nofilename(buf) && !path_with_url(buf->b_fname) && (force || buf->b_sfname == NULL - || path_is_absolute((char_u *)buf->b_sfname))) { + || path_is_absolute(buf->b_sfname))) { if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = path_shorten_fname(buf->b_ffname, (char *)dirname); + char *p = path_shorten_fname(buf->b_ffname, dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4232,11 +4136,11 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) /// Shorten filenames for all buffers. void shorten_fnames(int force) { - char_u dirname[MAXPATHL]; + char dirname[MAXPATHL]; - os_dirname((char *)dirname, MAXPATHL); + os_dirname(dirname, MAXPATHL); FOR_ALL_BUFFERS(buf) { - shorten_buf_fname(buf, dirname, force); + shorten_buf_fname(buf, (char *)dirname, force); // Always make the swap file name a full path, a "nofile" buffer may // also have a swap file. @@ -4515,10 +4419,7 @@ int vim_rename(const char *from, const char *to) { int fd_in; int fd_out; - int n; char *errmsg = NULL; - char *buffer; - long perm; #ifdef HAVE_ACL vim_acl_T acl; // ACL from original file #endif @@ -4552,7 +4453,7 @@ int vim_rename(const char *from, const char *to) } if (use_tmp_file) { - char_u tempname[MAXPATHL + 1]; + char 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". @@ -4560,18 +4461,18 @@ int vim_rename(const char *from, const char *to) return -1; } STRCPY(tempname, from); - for (n = 123; n < 99999; n++) { - char *tail = path_tail((char *)tempname); - snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - (char *)tempname - 1)), "%d", n); + for (int n = 123; n < 99999; n++) { + char *tail = path_tail(tempname); + snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); - if (!os_path_exists((char *)tempname)) { - if (os_rename((char_u *)from, tempname) == OK) { - if (os_rename(tempname, (char_u *)to) == OK) { + if (!os_path_exists(tempname)) { + if (os_rename(from, tempname) == OK) { + if (os_rename(tempname, to) == OK) { return 0; } // Strange, the second step failed. Try moving the // file back and return failure. - (void)os_rename(tempname, (char_u *)from); + (void)os_rename(tempname, from); return -1; } // If it fails for one temp name it will most likely fail @@ -4589,15 +4490,15 @@ int vim_rename(const char *from, const char *to) os_remove((char *)to); // First try a normal rename, return if it works. - if (os_rename((char_u *)from, (char_u *)to) == OK) { + if (os_rename(from, to) == OK) { return 0; } // Rename() failed, try copying the file. - perm = os_getperm(from); + long perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. - acl = os_get_acl((char_u *)from); + acl = os_get_acl(from); #endif fd_in = os_open((char *)from, O_RDONLY, 0); if (fd_in < 0) { @@ -4620,7 +4521,7 @@ int vim_rename(const char *from, const char *to) // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim // is `preserve_exit()`ing. - buffer = try_malloc(BUFSIZE); + char *buffer = try_malloc(BUFSIZE); if (buffer == NULL) { close(fd_out); close(fd_in); @@ -4630,6 +4531,7 @@ int vim_rename(const char *from, const char *to) return -1; } + int n; while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) { if (write_eintr(fd_out, buffer, (size_t)n) != n) { errmsg = _("E208: Error writing to \"%s\""); @@ -4647,10 +4549,10 @@ int vim_rename(const char *from, const char *to) to = from; } #ifndef UNIX // For Unix os_open() already set the permission. - os_setperm((const char *)to, perm); + os_setperm(to, perm); #endif #ifdef HAVE_ACL - os_set_acl((char_u *)to, acl); + os_set_acl(to, acl); os_free_acl(acl); #endif if (errmsg != NULL) { @@ -4673,8 +4575,6 @@ static int already_warned = false; /// @return true if some message was written (screen should be redrawn and cursor positioned). int check_timestamps(int focus) { - int didit = 0; - // Don't check timestamps while system() or another low-level function may // cause us to lose and gain focus. if (no_check_timestamps > 0) { @@ -4689,6 +4589,8 @@ int check_timestamps(int focus) return false; } + int didit = 0; + if (!stuff_empty() || global_busy || !typebuf_typed() || autocmd_busy || curbuf->b_ro_locked > 0 || allbuf_lock > 0) { @@ -4732,13 +4634,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) { buf_T *tbuf = curbuf; int retval = OK; - linenr_T lnum; - char *p; // Copy the lines in "frombuf" to "tobuf". curbuf = tobuf; - for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { - p = xstrdup(ml_get_buf(frombuf, lnum, false)); + for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { + char *p = xstrdup(ml_get_buf(frombuf, lnum, false)); if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; @@ -4750,7 +4650,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) // Delete all the lines in "frombuf". if (retval != FAIL) { curbuf = frombuf; - for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { + for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { if (ml_delete(lnum, false) == FAIL) { // Oops! We could try putting back the saved lines, but that // might fail again... @@ -4774,7 +4674,6 @@ int buf_check_timestamp(buf_T *buf) FUNC_ATTR_NONNULL_ALL { int retval = 0; - char *path; char *mesg = NULL; char *mesg2 = ""; bool helpmesg = false; @@ -4789,8 +4688,6 @@ 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 *s; - char *reason; bufref_T bufref; set_bufref(&bufref, buf); @@ -4838,6 +4735,7 @@ int buf_check_timestamp(buf_T *buf) // was set, the global option value otherwise. reload = RELOAD_NORMAL; } else { + char *reason; if (!file_info_ok) { reason = "deleted"; } else if (bufIsChanged(buf)) { @@ -4864,7 +4762,7 @@ int buf_check_timestamp(buf_T *buf) if (!bufref_valid(&bufref)) { emsg(_("E246: FileChangedShell autocommand deleted buffer")); } - s = get_vim_var_str(VV_FCS_CHOICE); + char *s = get_vim_var_str(VV_FCS_CHOICE); if (strcmp(s, "reload") == 0 && *reason != 'd') { reload = RELOAD_NORMAL; } else if (strcmp(s, "edit") == 0) { @@ -4917,7 +4815,7 @@ int buf_check_timestamp(buf_T *buf) } if (mesg != NULL) { - path = home_replace_save(buf, buf->b_fname); + char *path = home_replace_save(buf, buf->b_fname); if (!helpmesg) { mesg2 = ""; } @@ -5000,8 +4898,6 @@ int buf_check_timestamp(buf_T *buf) void buf_reload(buf_T *buf, int orig_mode, bool reload_options) { exarg_T ea; - pos_T old_cursor; - linenr_T old_topline; int old_ro = buf->b_p_ro; buf_T *savebuf; bufref_T bufref; @@ -5021,8 +4917,8 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) prep_exarg(&ea, buf); } - old_cursor = curwin->w_cursor; - old_topline = curwin->w_topline; + pos_T old_cursor = curwin->w_cursor; + linenr_T old_topline = curwin->w_topline; if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { // Save all the text, so that the reload can be undone. @@ -5156,11 +5052,11 @@ void write_lnum_adjust(linenr_T offset) #if defined(BACKSLASH_IN_FILENAME) /// Convert all backslashes in fname to forward slashes in-place, /// unless when it looks like a URL. -void forward_slash(char_u *fname) +void forward_slash(char *fname) { - char_u *p; + char *p; - if (path_with_url((const char *)fname)) { + if (path_with_url(fname)) { return; } for (p = fname; *p != NUL; p++) { @@ -5317,7 +5213,7 @@ int delete_recursive(const char *name) garray_T ga; if (readdir_core(&ga, exp, NULL, NULL) == OK) { for (int i = 0; i < ga.ga_len; i++) { - vim_snprintf(NameBuff, MAXPATHL, "%s/%s", exp, ((char_u **)ga.ga_data)[i]); + vim_snprintf(NameBuff, MAXPATHL, "%s/%s", exp, ((char **)ga.ga_data)[i]); if (delete_recursive((const char *)NameBuff) != 0) { // Remember the failure but continue deleting any further // entries. @@ -5505,28 +5401,22 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, /// @param ffname full file name /// /// @return true if there was a match -bool match_file_list(char_u *list, char_u *sfname, char_u *ffname) +bool match_file_list(char *list, char *sfname, char *ffname) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { - char_u buf[100]; - char_u *tail; - char_u *regpat; - char allow_dirs; - bool match; - char *p; - - tail = (char_u *)path_tail((char *)sfname); + char *tail = path_tail(sfname); // try all patterns in 'wildignore' - p = (char *)list; + char *p = list; while (*p) { - copy_option_part(&p, (char *)buf, ARRAY_SIZE(buf), ","); - regpat = (char_u *)file_pat_to_reg_pat((char *)buf, NULL, &allow_dirs, false); + char buf[100]; + copy_option_part(&p, buf, ARRAY_SIZE(buf), ","); + char allow_dirs; + char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); if (regpat == NULL) { break; } - match = match_file_pat((char *)regpat, NULL, (char *)ffname, (char *)sfname, (char *)tail, - (int)allow_dirs); + bool match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); xfree(regpat); if (match) { return true; @@ -5549,15 +5439,10 @@ bool match_file_list(char_u *list, char_u *sfname, char_u *ffname) char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) FUNC_ATTR_NONNULL_ARG(1) { - const char *endp; - char *reg_pat; - const char *p; - int nested = 0; - bool add_dollar = true; - if (allow_dirs != NULL) { *allow_dirs = false; } + if (pat_end == NULL) { pat_end = pat + strlen(pat); } @@ -5568,7 +5453,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs size_t size = 2; // '^' at start, '$' at end. - for (p = pat; p < pat_end; p++) { + for (const char *p = pat; p < pat_end; p++) { switch (*p) { case '*': case '.': @@ -5589,7 +5474,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs break; } } - reg_pat = xmalloc(size + 1); + char *reg_pat = xmalloc(size + 1); size_t i = 0; @@ -5600,14 +5485,16 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs } else { reg_pat[i++] = '^'; } - endp = pat_end - 1; + const char *endp = pat_end - 1; + bool add_dollar = true; if (endp >= pat && *endp == '*') { while (endp - pat > 0 && *endp == '*') { endp--; } add_dollar = false; } - for (p = pat; *p && nested >= 0 && p <= endp; p++) { + int nested = 0; + for (const char *p = pat; *p && nested >= 0 && p <= endp; p++) { switch (*p) { case '*': reg_pat[i++] = '.'; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 6cb9e5c38d..7306131574 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -2873,7 +2873,7 @@ static void foldlevelIndent(fline_T *flp) // empty line or lines starting with a character in 'foldignore': level // depends on surrounding lines - if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, *s) != NULL) { + if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, (uint8_t)(*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; diff --git a/src/nvim/fold.h b/src/nvim/fold.h index 9c3a34ab31..ac1e8c9419 100644 --- a/src/nvim/fold.h +++ b/src/nvim/fold.h @@ -20,8 +20,6 @@ typedef struct foldinfo { linenr_T fi_lines; } foldinfo_T; -#define FOLDINFO_INIT { 0, 0, 0, 0 } - EXTERN int disable_fold_update INIT(= 0); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/garray.c b/src/nvim/garray.c index 0f11868031..aa9a44d410 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -173,9 +173,9 @@ char *ga_concat_strings_sep(const garray_T *gap, const char *sep) /// @param gap /// /// @returns the concatenated strings -char_u *ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET +char *ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET { - return (char_u *)ga_concat_strings_sep(gap, ","); + return ga_concat_strings_sep(gap, ","); } /// Concatenate a string to a growarray which contains characters. @@ -216,7 +216,7 @@ void ga_concat_len(garray_T *const gap, const char *restrict s, const size_t len /// /// @param gap /// @param c -void ga_append(garray_T *gap, char c) +void ga_append(garray_T *gap, uint8_t c) { - GA_APPEND(char, gap, c); + GA_APPEND(uint8_t, gap, c); } diff --git a/src/nvim/garray.h b/src/nvim/garray.h index 3e2650b410..1623c4db7b 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -27,7 +27,8 @@ typedef struct growarray { #define GA_APPEND(item_type, gap, item) \ do { \ ga_grow(gap, 1); \ - ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ + ((item_type *)(gap)->ga_data)[(gap)->ga_len] = (item); \ + (gap)->ga_len++; \ } while (0) #define GA_APPEND_VIA_PTR(item_type, gap) \ diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 96c9b21b8f..35f6bf8455 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -426,7 +426,9 @@ for _,fn in ipairs(functions) do end remote_fns.redraw = {impl_name="ui_client_redraw", fast=true} -local hashorder, hashfun = hashy.hashy_hash("msgpack_rpc_get_handler_for", vim.tbl_keys(remote_fns), function (idx) +local names = vim.tbl_keys(remote_fns) +table.sort(names) +local hashorder, hashfun = hashy.hashy_hash("msgpack_rpc_get_handler_for", names, function (idx) return "method_handlers["..idx.."].name" end) diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index a50e058e00..baed6a74c2 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -73,14 +73,13 @@ for _,fun in ipairs(metadata) do end end +local func_names = vim.tbl_keys(funcs) +table.sort(func_names) local funcsdata = io.open(funcs_file, 'w') -funcsdata:write(mpack.pack(funcs)) +funcsdata:write(mpack.pack(func_names)) funcsdata:close() - -local names = vim.tbl_keys(funcs) - -local neworder, hashfun = hashy.hashy_hash("find_internal_func", names, function (idx) +local neworder, hashfun = hashy.hashy_hash("find_internal_func", func_names, function (idx) return "functions["..idx.."].name" end) hashpipe:write("static const EvalFuncDef functions[] = {\n") diff --git a/src/nvim/generators/gen_events.lua b/src/nvim/generators/gen_events.lua index 6ee45a14af..8db7f22452 100644 --- a/src/nvim/generators/gen_events.lua +++ b/src/nvim/generators/gen_events.lua @@ -32,7 +32,9 @@ for i, event in ipairs(events) do end end -for alias, event in pairs(aliases) do +for _, v in ipairs(aliases) do + local alias = v[1] + local event = v[2] names_tgt:write(('\n {%u, "%s", EVENT_%s},'):format(#alias, alias, event:upper())) end diff --git a/src/nvim/generators/gen_keysets.lua b/src/nvim/generators/gen_keysets.lua index 633c5da184..b1c1f3e2d8 100644 --- a/src/nvim/generators/gen_keysets.lua +++ b/src/nvim/generators/gen_keysets.lua @@ -1,4 +1,3 @@ - local nvimsrcdir = arg[1] local shared_file = arg[2] local funcs_file = arg[3] @@ -38,7 +37,9 @@ local function sanitize(key) return key end -for name, keys in pairs(keysets) do +for _, v in ipairs(keysets) do + local name = v[1] + local keys = v[2] local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx) return name.."_table["..idx.."].str" end) diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index af21d44eaf..edb7dae159 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -159,7 +159,7 @@ local dump_option = function(i, o) if #o.scope == 2 then pv_name = 'OPT_BOTH(' .. pv_name .. ')' end - defines['PV_' .. varname:sub(3):upper()] = pv_name + table.insert(defines, { 'PV_' .. varname:sub(3):upper() , pv_name}) w(' .indir=' .. pv_name) end if o.enable_if then @@ -192,7 +192,7 @@ w(' [' .. ('%u'):format(#options.options) .. ']={.fullname=NULL}') w('};') w('') -for k, v in pairs(defines) do - w('#define ' .. k .. ' ' .. v) +for _, v in ipairs(defines) do + w('#define ' .. v[1] .. ' ' .. v[2]) end opt_fd:close() diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b9e3b6b902..8ed9381bca 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -151,11 +151,11 @@ void free_buff(buffheader_T *buf) /// K_SPECIAL in the returned string is escaped. /// /// @param dozero count == zero is not an error -static char_u *get_buffcont(buffheader_T *buffer, int dozero) +static char *get_buffcont(buffheader_T *buffer, int dozero) { size_t count = 0; - char_u *p = NULL; - char_u *p2; + char *p = NULL; + char *p2; // compute the total length of the string for (const buffblock_T *bp = buffer->bh_first.b_next; @@ -168,7 +168,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 = (char_u *)bp->b_str; *str;) { + for (const char *str = bp->b_str; *str;) { *p2++ = *str++; } } @@ -185,7 +185,7 @@ char_u *get_recorded(void) char *p; size_t len; - p = (char *)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 @@ -207,7 +207,7 @@ char_u *get_recorded(void) /// Return the contents of the redo buffer as a single string. /// K_SPECIAL in the returned string is escaped. -char_u *get_inserted(void) +char *get_inserted(void) { return get_buffcont(&redobuff, false); } @@ -252,7 +252,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } else { len = (size_t)slen; } - buffblock_T *p = xmalloc(sizeof(buffblock_T) + len); + buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1); buf->bh_space = len - (size_t)slen; xstrlcpy(p->b_str, s, (size_t)slen + 1); @@ -475,7 +475,7 @@ void saveRedobuff(save_redo_T *save_redo) old_redobuff.bh_first.b_next = NULL; // Make a copy, so that ":normal ." in a function works. - char *const s = (char *)get_buffcont(&save_redo->sr_redobuff, false); + char *const s = get_buffcont(&save_redo->sr_redobuff, false); if (s == NULL) { return; } @@ -538,7 +538,7 @@ void AppendToRedobuffLit(const char *str, int len) // Handle a special or multibyte character. // Composing chars separately are handled separately. - const int c = mb_cptr2char_adv((const char_u **)&s); + const int c = mb_cptr2char_adv(&s); if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^'))) { add_char_buff(&redobuff, Ctrl_V); } @@ -599,7 +599,7 @@ void stuffReadbuffSpec(const char *s) stuffReadbuffLen(s, 3); s += 3; } else { - int c = mb_cptr2char_adv((const char_u **)&s); + int c = mb_cptr2char_adv(&s); if (c == CAR || c == NL || c == ESC) { c = ' '; } @@ -640,7 +640,7 @@ void stuffescaped(const char *arg, bool literally) // stuff a single special character if (*arg != NUL) { - const int c = mb_cptr2char_adv((const char_u **)&arg); + const int c = mb_cptr2char_adv(&arg); if (literally && ((c < ' ' && c != TAB) || c == DEL)) { stuffcharReadbuff(Ctrl_V); } @@ -886,7 +886,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) // often. int newoff = MAXMAPLEN + 4; int extra = addlen + newoff + 4 * (MAXMAPLEN + 4); - if (typebuf.tb_len > 2147483674 - extra) { + if (typebuf.tb_len > INT_MAX - extra) { // string is getting too long for 32 bit int emsg(_(e_toocompl)); // also calls flush_buffers setcursor(); @@ -2526,10 +2526,12 @@ static int vgetorpeek(bool advance) // move cursor left, if possible if (curwin->w_cursor.col != 0) { if (curwin->w_wcol > 0) { - if (did_ai) { - // We are expecting to truncate the trailing - // white-space, so find the last non-white - // character -- webb + // After auto-indenting and no text is following, + // we are expecting to truncate the trailing + // white-space, so find the last non-white + // character -- webb + if (did_ai + && *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) { curwin->w_wcol = 0; ptr = (char_u *)get_cursor_line_ptr(); chartabsize_T cts; @@ -2993,16 +2995,16 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat) ga_concat(&line_ga, "<SNR>"); } else { if (cmod != 0) { - ga_append(&line_ga, (char)K_SPECIAL); - ga_append(&line_ga, (char)KS_MODIFIER); - ga_append(&line_ga, (char)cmod); + ga_append(&line_ga, K_SPECIAL); + ga_append(&line_ga, KS_MODIFIER); + ga_append(&line_ga, (uint8_t)cmod); } if (IS_SPECIAL(c1)) { - ga_append(&line_ga, (char)K_SPECIAL); - ga_append(&line_ga, (char)K_SECOND(c1)); - ga_append(&line_ga, (char)K_THIRD(c1)); + ga_append(&line_ga, K_SPECIAL); + ga_append(&line_ga, (uint8_t)K_SECOND(c1)); + ga_append(&line_ga, (uint8_t)K_THIRD(c1)); } else { - ga_append(&line_ga, (char)c1); + ga_append(&line_ga, (uint8_t)c1); } } @@ -3038,7 +3040,7 @@ bool map_execute_lua(void) } else if (c1 == '\r' || c1 == '\n') { c1 = NUL; // end the line } else { - ga_append(&line_ga, (char)c1); + ga_append(&line_ga, (uint8_t)c1); } } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index aa8dbf6331..df4ae05522 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -494,6 +494,9 @@ EXTERN int v_dying INIT(= 0); EXTERN bool stdin_isatty INIT(= true); // is stdout a terminal? EXTERN bool stdout_isatty INIT(= true); +// is stderr a terminal? +EXTERN bool stderr_isatty INIT(= true); + /// filedesc set by embedder for reading first buffer like `cmd | nvim -` EXTERN int stdin_fd INIT(= -1); @@ -771,7 +774,7 @@ EXTERN bool g_tag_at_cursor INIT(= false); // whether the tag command comes EXTERN int replace_offset INIT(= 0); // offset for replace_push() -EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|"); // need backslash in cmd line +EXTERN char *escape_chars INIT(= " \t\\\"|"); // need backslash in cmd line EXTERN int keep_help_flag INIT(= false); // doing :ta from help file @@ -803,8 +806,8 @@ enum { extern char *default_vim_dir; extern char *default_vimruntime_dir; extern char *default_lib_dir; -extern char_u *compiled_user; -extern char_u *compiled_sys; +extern char *compiled_user; +extern char *compiled_sys; #endif // When a window has a local directory, the absolute path of the global @@ -822,7 +825,7 @@ 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 -EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); +EXTERN char no_lines_msg[] INIT(= N_("--No lines in buffer--")); // When ":global" is used to number of substitutions and changed lines is // accumulated until it's finished. @@ -999,7 +1002,6 @@ EXTERN char e_fnametoolong[] INIT(= N_("E856: Filename too long")); EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String")); EXTERN char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); -EXTERN char e_autocmd_err[] INIT(= N_("E5500: autocmd has thrown an exception: %s")); EXTERN char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>")); EXTERN char e_cmdmap_repeated[] INIT(= N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>")); diff --git a/src/nvim/grid.c b/src/nvim/grid.c index 4702e224c6..46f8a59710 100644 --- a/src/nvim/grid.c +++ b/src/nvim/grid.c @@ -142,16 +142,16 @@ void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr) /// Also return its attribute in *attrp; void grid_getbytes(ScreenGrid *grid, int row, int col, char *bytes, int *attrp) { - size_t off; - grid_adjust(&grid, &row, &col); // safety check - 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]); + if (grid->chars == NULL || row >= grid->rows || col >= grid->cols) { + return; } + + size_t off = grid->line_offset[row] + (size_t)col; + *attrp = grid->attrs[off]; + schar_copy(bytes, grid->chars[off]); } /// put string '*text' on the window grid at position 'row' and 'col', with diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c index 042cb43ce4..851e70caca 100644 --- a/src/nvim/hashtab.c +++ b/src/nvim/hashtab.c @@ -30,6 +30,7 @@ #include "nvim/hashtab.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/types.h" #include "nvim/vim.h" // Magic value for algorithm that walks through the array. @@ -87,7 +88,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(key)); } /// Like hash_find, but key is not NUL-terminated @@ -203,13 +204,13 @@ void hash_debug_results(void) /// FAIL if key already present int hash_add(hashtab_T *ht, char *key) { - hash_T hash = hash_hash((char_u *)key); + hash_T hash = hash_hash(key); hashitem_T *hi = hash_lookup(ht, key, strlen(key), hash); if (!HASHITEM_EMPTY(hi)) { internal_error("hash_add()"); return FAIL; } - hash_add_item(ht, hi, (char_u *)key, hash); + hash_add_item(ht, hi, key, hash); return OK; } @@ -220,14 +221,14 @@ int hash_add(hashtab_T *ht, char *key) /// @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. /// @param hash The precomputed hash value for the key. -void hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash) +void hash_add_item(hashtab_T *ht, hashitem_T *hi, char *key, hash_T hash) { ht->ht_used++; ht->ht_changed++; if (hi->hi_key == NULL) { ht->ht_filled++; } - hi->hi_key = (char *)key; + hi->hi_key = key; hi->hi_hash = hash; // When the space gets low may resize the array. @@ -405,9 +406,9 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems) /// run a script that uses hashtables a lot. Vim will then print statistics /// when exiting. Try that with the current hash algorithm and yours. The /// lower the percentage the better. -hash_T hash_hash(const char_u *key) +hash_T hash_hash(const char *key) { - hash_T hash = *key; + hash_T hash = (uint8_t)(*key); if (hash == 0) { return (hash_T)0; @@ -415,7 +416,7 @@ hash_T hash_hash(const char_u *key) // A simplistic algorithm that appears to do very well. // Suggested by George Reilly. - const uint8_t *p = key + 1; + const uint8_t *p = (uint8_t *)key + 1; while (*p != NUL) { HASH_CYCLE_BODY(hash, p); } diff --git a/src/nvim/help.c b/src/nvim/help.c index 0a695a0aa7..bbc552fa4c 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -412,7 +412,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // And also "\_$" and "\_^". if (arg[0] == '\\' && ((arg[1] != NUL && arg[2] == NUL) - || (vim_strchr("%_z@", arg[1]) != NULL + || (vim_strchr("%_z@", (uint8_t)arg[1]) != NULL && arg[2] != NUL))) { vim_snprintf(d, IOSIZE, "/\\\\%s", arg + 1); // Check for "/\\_$", should be "/\\_\$" @@ -471,7 +471,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // Insert '-' before and after "CTRL-X" when applicable. if (*s < ' ' || (*s == '^' && s[1] - && (ASCII_ISALPHA(s[1]) || vim_strchr("?@[\\]^", s[1]) != NULL))) { + && (ASCII_ISALPHA(s[1]) || vim_strchr("?@[\\]^", (uint8_t)s[1]) != NULL))) { if (d > IObuff && d[-1] != '_' && d[-1] != '\\') { *d++ = '_'; // prepend a '_' to make x_CTRL-x } @@ -555,7 +555,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // Sort the matches found on the heuristic number that is after the // tag name. qsort((void *)(*matches), (size_t)(*num_matches), - sizeof(char_u *), help_compare); + sizeof(char *), help_compare); // Delete more than TAG_MANY to reduce the size of the listing. while (*num_matches > TAG_MANY) { xfree((*matches)[--*num_matches]); @@ -799,7 +799,7 @@ void fix_help_buffer(void) // The text is utf-8 when a byte // above 127 is found and no // illegal byte sequence is found. - if ((char_u)(*s) >= 0x80 && this_utf != kFalse) { + if ((uint8_t)(*s) >= 0x80 && this_utf != kFalse) { this_utf = kTrue; const int l = utf_ptr2len(s); if (l == 1) { @@ -923,7 +923,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // If using the "++t" argument or generating tags for "$VIMRUNTIME/doc" // add the "help-tags" tag. - ga_init(&ga, (int)sizeof(char_u *), 100); + ga_init(&ga, (int)sizeof(char *), 100); if (add_help_tags || path_full_compare("$VIMRUNTIME/doc", dir, false, true) == kEqualFiles) { size_t s_len = 18 + strlen(tagfname); @@ -948,7 +948,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // Detect utf-8 file by a non-ASCII char in the first line. TriState this_utf8 = kNone; for (s = IObuff; *s != NUL; s++) { - if ((char_u)(*s) >= 0x80) { + if ((uint8_t)(*s) >= 0x80) { this_utf8 = kTrue; const int l = utf_ptr2len(s); if (l == 1) { @@ -974,12 +974,12 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool } if (in_example) { // skip over example; a non-white in the first column ends it - if (vim_strchr(" \t\n\r", IObuff[0])) { + if (vim_strchr(" \t\n\r", (uint8_t)IObuff[0])) { continue; } in_example = false; } - p1 = vim_strchr((char *)IObuff, '*'); // find first '*' + p1 = vim_strchr(IObuff, '*'); // find first '*' while (p1 != NULL) { p2 = strchr((const char *)p1 + 1, '*'); // Find second '*'. if (p2 != NULL && p2 > p1 + 1) { // Skip "*" and "**". @@ -994,7 +994,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool // followed by a white character or end-of-line. if (s == p2 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') - && (vim_strchr(" \t\n\r", s[1]) != NULL + && (vim_strchr(" \t\n\r", (uint8_t)s[1]) != NULL || s[1] == '\0')) { *p2 = '\0'; p1++; diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index c3a259c87d..c20eac3c28 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -649,7 +649,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through) cattrs = battrs; cattrs.rgb_fg_color = rgb_blend(ratio, battrs.rgb_fg_color, fattrs.rgb_bg_color); - if (cattrs.rgb_ae_attr & (HL_ANY_UNDERLINE)) { + if (cattrs.rgb_ae_attr & (HL_UNDERLINE_MASK)) { cattrs.rgb_sp_color = rgb_blend(ratio, battrs.rgb_sp_color, fattrs.rgb_bg_color); } else { @@ -667,7 +667,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through) } cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color, fattrs.rgb_fg_color); - if (cattrs.rgb_ae_attr & (HL_ANY_UNDERLINE)) { + if (cattrs.rgb_ae_attr & (HL_UNDERLINE_MASK)) { cattrs.rgb_sp_color = rgb_blend(ratio/2, battrs.rgb_bg_color, fattrs.rgb_sp_color); } else { @@ -825,46 +825,52 @@ void hlattrs2dict(Dictionary *dict, HlAttrs ae, bool use_rgb) Dictionary hl = *dict; int mask = use_rgb ? ae.rgb_ae_attr : ae.cterm_ae_attr; + if (mask & HL_INVERSE) { + PUT_C(hl, "reverse", BOOLEAN_OBJ(true)); + } + if (mask & HL_BOLD) { PUT_C(hl, "bold", BOOLEAN_OBJ(true)); } - if (mask & HL_STANDOUT) { - PUT_C(hl, "standout", BOOLEAN_OBJ(true)); + if (mask & HL_ITALIC) { + PUT_C(hl, "italic", BOOLEAN_OBJ(true)); } - if (mask & HL_UNDERLINE) { + switch (mask & HL_UNDERLINE_MASK) { + case HL_UNDERLINE: PUT_C(hl, "underline", BOOLEAN_OBJ(true)); - } + break; - if (mask & HL_UNDERCURL) { + case HL_UNDERCURL: PUT_C(hl, "undercurl", BOOLEAN_OBJ(true)); - } + break; - if (mask & HL_UNDERDOUBLE) { + case HL_UNDERDOUBLE: PUT_C(hl, "underdouble", BOOLEAN_OBJ(true)); - } + break; - if (mask & HL_UNDERDOTTED) { + case HL_UNDERDOTTED: PUT_C(hl, "underdotted", BOOLEAN_OBJ(true)); - } + break; - if (mask & HL_UNDERDASHED) { + case HL_UNDERDASHED: PUT_C(hl, "underdashed", BOOLEAN_OBJ(true)); + break; } - if (mask & HL_ITALIC) { - PUT_C(hl, "italic", BOOLEAN_OBJ(true)); - } - - if (mask & HL_INVERSE) { - PUT_C(hl, "reverse", BOOLEAN_OBJ(true)); + if (mask & HL_STANDOUT) { + PUT_C(hl, "standout", BOOLEAN_OBJ(true)); } if (mask & HL_STRIKETHROUGH) { PUT_C(hl, "strikethrough", BOOLEAN_OBJ(true)); } + if (mask & HL_ALTFONT) { + PUT_C(hl, "altfont", BOOLEAN_OBJ(true)); + } + if (mask & HL_NOCOMBINE) { PUT_C(hl, "nocombine", BOOLEAN_OBJ(true)); } @@ -920,16 +926,17 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e m = m | flag; \ } + CHECK_FLAG(dict, mask, reverse, , HL_INVERSE); CHECK_FLAG(dict, mask, bold, , HL_BOLD); - CHECK_FLAG(dict, mask, standout, , HL_STANDOUT); + CHECK_FLAG(dict, mask, italic, , HL_ITALIC); CHECK_FLAG(dict, mask, underline, , HL_UNDERLINE); CHECK_FLAG(dict, mask, undercurl, , HL_UNDERCURL); CHECK_FLAG(dict, mask, underdouble, , HL_UNDERDOUBLE); CHECK_FLAG(dict, mask, underdotted, , HL_UNDERDOTTED); CHECK_FLAG(dict, mask, underdashed, , HL_UNDERDASHED); - CHECK_FLAG(dict, mask, italic, , HL_ITALIC); - CHECK_FLAG(dict, mask, reverse, , HL_INVERSE); + CHECK_FLAG(dict, mask, standout, , HL_STANDOUT); CHECK_FLAG(dict, mask, strikethrough, , HL_STRIKETHROUGH); + CHECK_FLAG(dict, mask, altfont, , HL_ALTFONT); if (use_rgb) { CHECK_FLAG(dict, mask, fg_indexed, , HL_FG_INDEXED); CHECK_FLAG(dict, mask, bg_indexed, , HL_BG_INDEXED); @@ -1005,13 +1012,14 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e } cterm_mask_provided = true; + CHECK_FLAG(cterm, cterm_mask, reverse, , HL_INVERSE); CHECK_FLAG(cterm, cterm_mask, bold, , HL_BOLD); - CHECK_FLAG(cterm, cterm_mask, standout, , HL_STANDOUT); + CHECK_FLAG(cterm, cterm_mask, italic, , HL_ITALIC); CHECK_FLAG(cterm, cterm_mask, underline, , HL_UNDERLINE); CHECK_FLAG(cterm, cterm_mask, undercurl, , HL_UNDERCURL); - CHECK_FLAG(cterm, cterm_mask, italic, , HL_ITALIC); - CHECK_FLAG(cterm, cterm_mask, reverse, , HL_INVERSE); + CHECK_FLAG(cterm, cterm_mask, standout, , HL_STANDOUT); CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH); + CHECK_FLAG(cterm, cterm_mask, altfont, , HL_ALTFONT); CHECK_FLAG(cterm, cterm_mask, nocombine, , HL_NOCOMBINE); } else if (dict->cterm.type == kObjectTypeArray && dict->cterm.data.array.size == 0) { // empty list from Lua API should clear all cterm attributes diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 2557a248c3..95c81ac9db 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -15,19 +15,23 @@ typedef enum { HL_INVERSE = 0x01, HL_BOLD = 0x02, HL_ITALIC = 0x04, + // The next three bits are all underline styles + HL_UNDERLINE_MASK = 0x38, HL_UNDERLINE = 0x08, HL_UNDERCURL = 0x10, - HL_UNDERDOUBLE = 0x20, - HL_UNDERDOTTED = 0x40, - HL_UNDERDASHED = 0x80, - HL_STANDOUT = 0x0100, - HL_NOCOMBINE = 0x0200, - HL_STRIKETHROUGH = 0x0400, + HL_UNDERDOUBLE = 0x18, + HL_UNDERDOTTED = 0x20, + HL_UNDERDASHED = 0x28, + // 0x30 and 0x38 spare for underline styles + HL_STANDOUT = 0x0040, + HL_STRIKETHROUGH = 0x0080, + HL_ALTFONT = 0x0100, + // 0x0200 spare + HL_NOCOMBINE = 0x0400, HL_BG_INDEXED = 0x0800, HL_FG_INDEXED = 0x1000, HL_DEFAULT = 0x2000, HL_GLOBAL = 0x4000, - HL_ANY_UNDERLINE = HL_UNDERLINE | HL_UNDERDOUBLE | HL_UNDERCURL | HL_UNDERDOTTED | HL_UNDERDASHED, } HlAttrFlags; /// Stores a complete highlighting entry, including colors and attributes diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 404835c4a9..3d91335f55 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -67,32 +67,32 @@ Map(cstr_t, int) highlight_unames = MAP_INIT; static char *(hl_name_table[]) = { "bold", "standout", "underline", "undercurl", "underdouble", "underdotted", "underdashed", - "italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" }; + "italic", "reverse", "inverse", "strikethrough", "altfont", + "nocombine", "NONE" }; static int hl_attr_table[] = { HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_UNDERDOUBLE, HL_UNDERDOTTED, HL_UNDERDASHED, - HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 }; + HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_ALTFONT, + HL_NOCOMBINE, 0 }; /// Structure that stores information about a highlight group. /// The ID of a highlight group is also called group ID. It is the index in /// the highlight_ga array PLUS ONE. typedef struct { - char_u *sg_name; ///< highlight group name - char *sg_name_u; ///< uppercase of sg_name + char *sg_name; ///< highlight group name + char *sg_name_u; ///< uppercase of sg_name bool sg_cleared; ///< "hi clear" was used int sg_attr; ///< Screen attr @see ATTR_ENTRY int sg_link; ///< link to this highlight group ID int sg_deflink; ///< default link; restored in highlight_clear() int sg_set; ///< combination of flags in \ref SG_SET sctx_T sg_deflink_sctx; ///< script where the default link was set - sctx_T sg_script_ctx; ///< script in which the group was last set - // for terminal UIs + sctx_T sg_script_ctx; ///< script in which the group was last set for terminal UIs int sg_cterm; ///< "cterm=" highlighting attr ///< (combination of \ref HlAttrFlags) int sg_cterm_fg; ///< terminal fg color number + 1 int sg_cterm_bg; ///< terminal bg color number + 1 - bool sg_cterm_bold; ///< bold attr was set for light color - // for RGB UIs + bool sg_cterm_bold; ///< bold attr was set for light color for RGB UIs int sg_gui; ///< "gui=" highlighting attributes ///< (combination of \ref HlAttrFlags) RgbValue sg_rgb_fg; ///< RGB foreground color @@ -571,7 +571,7 @@ int highlight_num_groups(void) } /// Returns the name of a highlight group. -char_u *highlight_group_name(int id) +char *highlight_group_name(int id) { return hl_table[id].sg_name; } @@ -658,8 +658,6 @@ void init_highlight(bool both, bool reset) /// @return OK for success, FAIL for failure. int load_colors(char *name) { - char_u *buf; - int retval = FAIL; static bool recursive = false; // When being called recursively, this is probably because setting @@ -671,13 +669,13 @@ int load_colors(char *name) recursive = true; size_t buflen = strlen(name) + 12; - buf = xmalloc(buflen); + char *buf = xmalloc(buflen); apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf); - snprintf((char *)buf, buflen, "colors/%s.vim", name); - retval = source_runtime((char *)buf, DIP_START + DIP_OPT); + snprintf(buf, buflen, "colors/%s.vim", name); + int retval = source_runtime(buf, DIP_START + DIP_OPT); if (retval == FAIL) { - snprintf((char *)buf, buflen, "colors/%s.lua", name); - retval = source_runtime((char *)buf, DIP_START + DIP_OPT); + snprintf(buf, buflen, "colors/%s.lua", name); + retval = source_runtime(buf, DIP_START + DIP_OPT); } xfree(buf); if (retval == OK) { @@ -873,25 +871,6 @@ update: void do_highlight(const char *line, const bool forceit, const bool init) FUNC_ATTR_NONNULL_ALL { - const char *name_end; - const char *linep; - const char *key_start; - const char *arg_start; - int off; - int len; - int attr; - int id; - int idx; - HlGroup item_before; - bool did_change = false; - bool dodefault = false; - bool doclear = false; - bool dolink = false; - bool error = false; - int color; - bool is_normal_group = false; // "Normal" group - bool did_highlight_changed = false; - // If no argument, list current highlighting. if (!init && ends_excmd((uint8_t)(*line))) { for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) { @@ -901,9 +880,11 @@ void do_highlight(const char *line, const bool forceit, const bool init) return; } + bool dodefault = false; + // Isolate the name. - name_end = (const char *)skiptowhite(line); - linep = (const char *)skipwhite(name_end); + const char *name_end = (const char *)skiptowhite(line); + const char *linep = (const char *)skipwhite(name_end); // Check for "default" argument. if (strncmp(line, "default", (size_t)(name_end - line)) == 0) { @@ -913,6 +894,9 @@ void do_highlight(const char *line, const bool forceit, const bool init) linep = (const char *)skipwhite(name_end); } + bool doclear = false; + bool dolink = false; + // Check for "clear" or "link" argument. if (strncmp(line, "clear", (size_t)(name_end - line)) == 0) { doclear = true; @@ -922,7 +906,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) // ":highlight {group-name}": list highlighting for one group. if (!doclear && !dolink && ends_excmd((uint8_t)(*linep))) { - id = syn_name2id_len(line, (size_t)(name_end - line)); + int id = syn_name2id_len(line, (size_t)(name_end - line)); if (id == 0) { semsg(_("E411: highlight group not found: %s"), line); } else { @@ -1024,11 +1008,11 @@ void do_highlight(const char *line, const bool forceit, const bool init) } // Find the group name in the table. If it does not exist yet, add it. - id = syn_check_group(line, (size_t)(name_end - line)); + int id = syn_check_group(line, (size_t)(name_end - line)); if (id == 0) { // Failed (out of memory). return; } - idx = id - 1; // Index is ID minus one. + int idx = id - 1; // Index is ID minus one. // Return if "default" was used and the group already has settings if (dodefault && hl_has_settings(idx, true)) { @@ -1036,8 +1020,8 @@ 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); + HlGroup item_before = hl_table[idx]; + bool 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)) { @@ -1047,11 +1031,16 @@ void do_highlight(const char *line, const bool forceit, const bool init) } } + bool did_change = false; + bool error = false; + char key[64]; char arg[512]; if (!doclear) { + const char *arg_start; + while (!ends_excmd((uint8_t)(*linep))) { - key_start = linep; + const char *key_start = linep; if (*linep == '=') { semsg(_("E415: unexpected equal sign: %s"), key_start); error = true; @@ -1071,7 +1060,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } memcpy(key, key_start, key_len); key[key_len] = NUL; - vim_strup((char_u *)key); + vim_strup(key); linep = (const char *)skipwhite(linep); if (strcmp(key, "NONE") == 0) { @@ -1128,12 +1117,12 @@ void do_highlight(const char *line, const bool forceit, const bool init) if (strcmp(key, "TERM") == 0 || strcmp(key, "CTERM") == 0 || strcmp(key, "GUI") == 0) { - attr = 0; - off = 0; + int attr = 0; + int off = 0; int i; while (arg[off] != NUL) { for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) { - len = (int)strlen(hl_name_table[i]); + int len = (int)strlen(hl_name_table[i]); if (STRNICMP(arg + off, hl_name_table[i], len) == 0) { attr |= hl_attr_table[i]; off += len; @@ -1183,6 +1172,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) hl_table[idx].sg_cterm_bold = false; } + int color; if (ascii_isdigit(*arg)) { color = atoi(arg); } else if (STRICMP(arg, "fg") == 0) { @@ -1203,7 +1193,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } } else { // Reduce calls to STRICMP a bit, it can be slow. - off = TOUPPER_ASC(*arg); + int off = TOUPPER_ASC(*arg); int i; for (i = ARRAY_SIZE(color_names); --i >= 0;) { if (off == color_names[i][0] @@ -1360,6 +1350,8 @@ void do_highlight(const char *line, const bool forceit, const bool init) } } + bool did_highlight_changed = false; + if (!error && is_normal_group) { // Need to update all groups, because they might be using "bg" and/or // "fg", which have been changed now. @@ -1471,7 +1463,7 @@ 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((char *)sgp->sg_name)) { + if (message_filtered(sgp->sg_name)) { return; } @@ -1505,7 +1497,7 @@ static void highlight_list_one(const int id) didh = true; msg_puts_attr("links to", HL_ATTR(HLF_D)); msg_putchar(' '); - msg_outtrans((char *)hl_table[hl_table[id - 1].sg_link - 1].sg_name); + msg_outtrans(hl_table[hl_table[id - 1].sg_link - 1].sg_name); } if (!didh) { @@ -1527,7 +1519,7 @@ Dictionary get_global_hl_defs(Arena *arena) hlattrs2dict(&attrs, syn_attr2entry(h->sg_attr), true); } else if (h->sg_link > 0) { attrs = arena_dict(arena, 1); - char *link = (char *)hl_table[h->sg_link - 1].sg_name; + char *link = hl_table[h->sg_link - 1].sg_name; PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link))); } PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs)); @@ -1544,8 +1536,6 @@ Dictionary get_global_hl_defs(Arena *arena) static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, const char *sarg, const char *const name) { - char buf[100]; - if (got_int) { return false; } @@ -1554,6 +1544,7 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg return didh; } + char buf[100]; const char *ts = buf; if (type == LIST_INT) { snprintf((char *)buf, sizeof(buf), "%d", iarg - 1); @@ -1562,12 +1553,17 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg } else { // type == LIST_ATTR buf[0] = NUL; for (int i = 0; hl_attr_table[i] != 0; i++) { - if (iarg & hl_attr_table[i]) { + if (((hl_attr_table[i] & HL_UNDERLINE_MASK) + && ((iarg & HL_UNDERLINE_MASK) == hl_attr_table[i])) + || (!(hl_attr_table[i] & HL_UNDERLINE_MASK) + && (iarg & hl_attr_table[i]))) { if (buf[0] != NUL) { xstrlcat(buf, ",", 100); } xstrlcat(buf, hl_name_table[i], 100); - iarg &= ~hl_attr_table[i]; // don't want "inverse" + if (!(hl_attr_table[i] & HL_UNDERLINE_MASK)) { + iarg &= ~hl_attr_table[i]; // don't want "inverse" + } } } } @@ -1594,19 +1590,24 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg const char *highlight_has_attr(const int id, const int flag, const int modec) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { - int attr; - if (id <= 0 || id > highlight_ga.ga_len) { return NULL; } + int attr; + if (modec == 'g') { attr = hl_table[id - 1].sg_gui; } else { attr = hl_table[id - 1].sg_cterm; } - return (attr & flag) ? "1" : NULL; + if (flag & HL_UNDERLINE_MASK) { + int ul = attr & HL_UNDERLINE_MASK; + return ul == flag ? "1" : NULL; + } else { + return (attr & flag) ? "1" : NULL; + } } /// Return color name of the given highlight group @@ -1622,7 +1623,6 @@ const char *highlight_color(const int id, const char *const what, const int mode FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { static char name[20]; - int n; bool fg = false; bool sp = false; bool font = false; @@ -1641,6 +1641,9 @@ const char *highlight_color(const int id, const char *const what, const int mode } else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) { return NULL; } + + int n; + if (modec == 'g') { if (what[2] == '#' && ui_rgb_attached()) { if (fg) { @@ -1702,7 +1705,7 @@ bool syn_list_header(const bool did_header, const int outlen, const int id, bool if (got_int) { return true; } - msg_outtrans((char *)hl_table[id - 1].sg_name); + msg_outtrans(hl_table[id - 1].sg_name); name_col = msg_col; endcol = 15; } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) { @@ -1795,7 +1798,7 @@ int syn_name2id_len(const char *name, size_t len) // Avoid alloc()/free(), these are slow too. memcpy(name_u, name, len); name_u[len] = '\0'; - vim_strup((char_u *)name_u); + vim_strup(name_u); // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. @@ -1804,10 +1807,10 @@ int syn_name2id_len(const char *name, size_t len) /// Lookup a highlight group name and return its attributes. /// Return zero if not found. -int syn_name2attr(const char_u *name) +int syn_name2attr(const char *name) FUNC_ATTR_NONNULL_ALL { - int id = syn_name2id((char *)name); + int id = syn_name2id(name); if (id != 0) { return syn_id2attr(id); @@ -1823,10 +1826,10 @@ int highlight_exists(const char *name) /// Return the name of highlight group "id". /// When not a valid ID return an empty string. -char_u *syn_id2name(int id) +char *syn_id2name(int id) { if (id <= 0 || id > highlight_ga.ga_len) { - return (char_u *)""; + return ""; } return hl_table[id - 1].sg_name; } @@ -1896,7 +1899,7 @@ static int syn_add_group(const char *name, size_t len) // Append another syntax_highlight entry. HlGroup *hlgp = GA_APPEND_VIA_PTR(HlGroup, &highlight_ga); CLEAR_POINTER(hlgp); - hlgp->sg_name = (char_u *)arena_memdupz(&highlight_arena, name, len); + hlgp->sg_name = arena_memdupz(&highlight_arena, name, len); hlgp->sg_rgb_bg = -1; hlgp->sg_rgb_fg = -1; hlgp->sg_rgb_sp = -1; @@ -1908,7 +1911,7 @@ static int syn_add_group(const char *name, size_t 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); + vim_strup(hlgp->sg_name_u); int id = highlight_ga.ga_len; // ID is index plus one @@ -2048,17 +2051,15 @@ static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int /// screen redraw after any :highlight command. void highlight_changed(void) { - int id; char userhl[30]; // use 30 to avoid compiler warning int id_S = -1; int id_SNC = 0; - int hlcnt; need_highlight_changed = false; /// 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])); + int id = syn_check_group(hlf_names[hlf], strlen(hlf_names[hlf])); if (id == 0) { abort(); } @@ -2097,7 +2098,7 @@ void highlight_changed(void) // Must to be in there simultaneously in case of table overflows in // get_attr_entry() ga_grow(&highlight_ga, 10); - hlcnt = highlight_ga.ga_len; + int hlcnt = highlight_ga.ga_len; if (id_S == -1) { // Make sure id_S is always valid to simplify code below. Use the last entry CLEAR_POINTER(&hl_table[hlcnt + 9]); @@ -2105,7 +2106,7 @@ void highlight_changed(void) } for (int i = 0; i < 9; i++) { snprintf(userhl, sizeof(userhl), "User%d", i + 1); - id = syn_name2id(userhl); + int id = syn_name2id(userhl); if (id == 0) { highlight_user[i] = 0; highlight_stlnc[i] = 0; @@ -2171,12 +2172,10 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg) /// List highlighting matches in a nice way. static void highlight_list(void) { - int i; - - for (i = 10; --i >= 0;) { + for (int i = 10; --i >= 0;) { highlight_list_two(i, HL_ATTR(HLF_D)); } - for (i = 40; --i >= 0;) { + for (int i = 40; --i >= 0;) { highlight_list_two(99, 0); } } @@ -2921,9 +2920,9 @@ color_name_table_T color_name_table[] = { /// return the hex value or -1 if could not find a correct value RgbValue name_to_color(const char *name, int *idx) { - if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2]) - && isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5]) - && isxdigit(name[6]) && name[7] == NUL) { + if (name[0] == '#' && isxdigit((uint8_t)name[1]) && isxdigit((uint8_t)name[2]) + && isxdigit((uint8_t)name[3]) && isxdigit((uint8_t)name[4]) && isxdigit((uint8_t)name[5]) + && isxdigit((uint8_t)name[6]) && name[7] == NUL) { // rgb hex string *idx = kColorIdxHex; return (RgbValue)strtol((char *)(name + 1), NULL, 16); @@ -2947,7 +2946,6 @@ RgbValue name_to_color(const char *name, int *idx) } else { // found match *idx = m; return color_name_table[m].color; - break; } } diff --git a/src/nvim/iconv.h b/src/nvim/iconv.h index 509f83c415..f5f3f25786 100644 --- a/src/nvim/iconv.h +++ b/src/nvim/iconv.h @@ -1,20 +1,18 @@ #ifndef NVIM_ICONV_H #define NVIM_ICONV_H -#include "auto/config.h" +#include <errno.h> +#include <iconv.h> -#ifdef HAVE_ICONV -# include <errno.h> -# include <iconv.h> +#include "auto/config.h" // define some missing constants if necessary -# ifndef EILSEQ -# define EILSEQ 123 -# endif -# define ICONV_ERRNO errno -# define ICONV_E2BIG E2BIG -# define ICONV_EINVAL EINVAL -# define ICONV_EILSEQ EILSEQ +#ifndef EILSEQ +# define EILSEQ 123 #endif +#define ICONV_ERRNO errno +#define ICONV_E2BIG E2BIG +#define ICONV_EINVAL EINVAL +#define ICONV_EILSEQ EILSEQ #endif // NVIM_ICONV_H diff --git a/src/nvim/indent.c b/src/nvim/indent.c index be1dfb77cf..ec6c72da6d 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -17,6 +17,7 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/extmark.h" #include "nvim/gettext.h" @@ -24,6 +25,7 @@ #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/mark.h" +#include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -386,7 +388,7 @@ int get_indent_buf(buf_T *buf, linenr_T lnum) /// Count the size (in window cells) of the indent in line "ptr", with /// 'tabstop' at "ts". /// If @param list is true, count only screen size for tabs. -int get_indent_str(const char_u *ptr, int ts, bool list) +int get_indent_str(const char *ptr, int ts, bool list) FUNC_ATTR_NONNULL_ALL { int count = 0; @@ -400,7 +402,7 @@ int get_indent_str(const char_u *ptr, int ts, bool list) } else { // In list mode, when tab is not set, count screen char width // for Tab, displays: ^I - count += ptr2cells((char *)ptr); + count += ptr2cells(ptr); } } else if (*ptr == ' ') { // Count a space for one. @@ -803,7 +805,7 @@ int get_breakindent_win(win_T *wp, char *line) { static int prev_indent = 0; // Cached indent value. static long prev_ts = 0L; // Cached tabstop value. - static const char_u *prev_line = NULL; // cached pointer to line. + static const char *prev_line = NULL; // cached pointer to line. static varnumber_T prev_tick = 0; // Changedtick of cached value. static long *prev_vts = NULL; // Cached vartabs values. static int prev_list = 0; // cached list value @@ -820,12 +822,12 @@ int get_breakindent_win(win_T *wp, char *line) // - 'tabstop' changed // - 'briopt_list changed' changed or // - 'formatlistpattern' changed - if (prev_line != (char_u *)line || prev_ts != wp->w_buffer->b_p_ts + if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts || prev_tick != buf_get_changedtick(wp->w_buffer) || prev_listopt != wp->w_briopt_list || (prev_flp == NULL || (strcmp(prev_flp, get_flp_value(wp->w_buffer)) != 0)) || prev_vts != wp->w_buffer->b_p_vts_array) { - prev_line = (char_u *)line; + prev_line = 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; @@ -850,7 +852,7 @@ int get_breakindent_win(win_T *wp, char *line) if (wp->w_briopt_list > 0) { prev_list += wp->w_briopt_list; } else { - prev_list = (int)(*regmatch.endp - *regmatch.startp); + prev_indent = (int)(*regmatch.endp - *regmatch.startp); } } vim_regfree(regmatch.regprog); @@ -869,17 +871,13 @@ int get_breakindent_win(win_T *wp, char *line) bri += win_col_off2(wp); // add additional indent for numbered lists - if (wp->w_briopt_list != 0) { - if (wp->w_briopt_list > 0) { - bri += prev_list; - } else { - bri = prev_list; - } + if (wp->w_briopt_list > 0) { + bri += prev_list; } // indent minus the length of the showbreak string if (wp->w_briopt_sbr) { - bri -= vim_strsize((char *)get_showbreak_value(wp)); + bri -= vim_strsize(get_showbreak_value(wp)); } // never indent past left window margin @@ -901,10 +899,10 @@ int get_breakindent_win(win_T *wp, char *line) // the line. int inindent(int extra) { - char_u *ptr; + char *ptr; colnr_T col; - for (col = 0, ptr = (char_u *)get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) { + for (col = 0, ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) { ptr++; } @@ -1187,7 +1185,7 @@ int get_lisp_indent(void) { pos_T *pos, realpos, paren; int amount; - char_u *that; + char *that; colnr_T col; colnr_T firsttry; int parencount; @@ -1222,7 +1220,7 @@ int get_lisp_indent(void) continue; } - for (that = (char_u *)get_cursor_line_ptr(); *that != NUL; that++) { + for (that = get_cursor_line_ptr(); *that != NUL; that++) { if (*that == ';') { while (*(that + 1) != NUL) { that++; @@ -1272,20 +1270,20 @@ int get_lisp_indent(void) curwin->w_cursor.col = pos->col; col = pos->col; - that = (char_u *)get_cursor_line_ptr(); + that = get_cursor_line_ptr(); if (vi_lisp && (get_indent() == 0)) { amount = 2; } else { - char_u *line = that; + char *line = that; chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, pos->lnum, 0, (char *)line, (char *)line); + init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, 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; + that = cts.cts_ptr; clear_chartabsize_arg(&cts); // Some keywords require "body" indenting rules (the @@ -1293,7 +1291,7 @@ int get_lisp_indent(void) // (let ((a 1)) instead (let ((a 1)) // (...)) of (...)) if (!vi_lisp && ((*that == '(') || (*that == '[')) - && lisp_match((char *)that + 1)) { + && lisp_match(that + 1)) { amount += 2; } else { if (*that != NUL) { @@ -1303,12 +1301,12 @@ int get_lisp_indent(void) firsttry = amount; init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line), - amount, (char *)line, (char *)that); + amount, line, that); while (ascii_iswhite(*cts.cts_ptr)) { cts.cts_vcol += lbr_chartabsize(&cts); cts.cts_ptr++; } - that = (char_u *)cts.cts_ptr; + that = cts.cts_ptr; amount = cts.cts_vcol; clear_chartabsize_arg(&cts); @@ -1324,9 +1322,10 @@ int get_lisp_indent(void) quotecount = 0; init_chartabsize_arg(&cts, curwin, - (colnr_T)(that - line), amount, (char *)line, (char *)that); + (colnr_T)(that - line), amount, line, that); if (vi_lisp || ((*that != '"') && (*that != '\'') - && (*that != '#') && ((*that < '0') || (*that > '9')))) { + && (*that != '#') + && (((uint8_t)(*that) < '0') || ((uint8_t)(*that) > '9')))) { while (*cts.cts_ptr && (!ascii_iswhite(*cts.cts_ptr) || quotecount || parencount) && (!((*cts.cts_ptr == '(' || *cts.cts_ptr == '[') @@ -1352,7 +1351,7 @@ int get_lisp_indent(void) cts.cts_vcol += lbr_chartabsize(&cts); cts.cts_ptr++; } - that = (char_u *)cts.cts_ptr; + that = cts.cts_ptr; amount = cts.cts_vcol; clear_chartabsize_arg(&cts); @@ -1375,7 +1374,7 @@ static int lisp_match(char *p) { char buf[LSIZE]; int len; - char *word = (char *)(*curbuf->b_p_lw != NUL ? (char_u *)curbuf->b_p_lw : p_lispwords); + char *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; while (*word != NUL) { (void)copy_option_part(&word, buf, LSIZE, ","); diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index ccf4448e93..1c771073b2 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -23,7 +23,6 @@ #include "nvim/pos.h" #include "nvim/search.h" #include "nvim/strings.h" -#include "nvim/types.h" #include "nvim/vim.h" // Find result cache for cpp_baseclass @@ -705,7 +704,7 @@ static int cin_get_equal_amount(linenr_T lnum) s = ml_get(lnum); line = s; - while (*s != NUL && vim_strchr("=;{}\"'", *s) == NULL) { + while (*s != NUL && vim_strchr("=;{}\"'", (uint8_t)(*s)) == NULL) { if (cin_iscomment(s)) { // ignore comments s = cin_skipcomment(s); } else { diff --git a/src/nvim/input.c b/src/nvim/input.c index 0f0af9d5f0..96214d45c2 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -29,7 +29,8 @@ # include "input.c.generated.h" // IWYU pragma: export #endif -/// Ask for a reply from the user, 'y' or 'n' +/// Ask for a reply from the user, a 'y' or a 'n', with prompt "str" (which +/// should have been translated already). /// /// No other characters are accepted, the message is repeated until a valid /// reply is entered or <C-c> is hit. diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index fa8e78f624..6de3b0a9d0 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -7,6 +7,7 @@ #include <limits.h> #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -597,7 +598,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Allocate wide character array for the completion and fill it. int *const wca = xmalloc((size_t)char_len * sizeof(*wca)); { - const char_u *p = (char_u *)str; + const char *p = str; for (int i = 0; i < char_len; i++) { wca[i] = mb_ptr2char_adv(&p); } @@ -605,7 +606,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Rule 1: Were any chars converted to lower? { - const char_u *p = (char_u *)compl_orig_text; + const char *p = compl_orig_text; for (int i = 0; i < min_len; i++) { const int c = mb_ptr2char_adv(&p); if (mb_islower(c)) { @@ -624,7 +625,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Rule 2: No lower case, 2nd consecutive letter converted to // upper case. if (!has_lower) { - const char_u *p = (char_u *)compl_orig_text; + const char *p = 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])) { @@ -640,7 +641,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp // Copy the original case of the part we typed. { - const char_u *p = (char_u *)compl_orig_text; + const char *p = compl_orig_text; for (int i = 0; i < min_len; i++) { const int c = mb_ptr2char_adv(&p); if (mb_islower(c)) { @@ -2257,14 +2258,14 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb) /// Invoked when the 'completefunc' option is set. The option value can be a /// name of a function (string), or function(<name>) or funcref(<name>) or a /// lambda expression. -int set_completefunc_option(void) +void set_completefunc_option(char **errmsg) { - int retval = option_set_callback_func(curbuf->b_p_cfu, &cfu_cb); - if (retval == OK) { - set_buflocal_cfu_callback(curbuf); + if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) { + *errmsg = e_invarg; + return; } - return retval; + set_buflocal_cfu_callback(curbuf); } /// Copy the global 'completefunc' callback function to the buffer-local @@ -2278,14 +2279,13 @@ void set_buflocal_cfu_callback(buf_T *buf) /// Invoked when the 'omnifunc' option is set. The option value can be a /// name of a function (string), or function(<name>) or funcref(<name>) or a /// lambda expression. -int set_omnifunc_option(void) +void set_omnifunc_option(buf_T *buf, char **errmsg) { - int retval = option_set_callback_func(curbuf->b_p_ofu, &ofu_cb); - if (retval == OK) { - set_buflocal_ofu_callback(curbuf); + if (option_set_callback_func(buf->b_p_ofu, &ofu_cb) == FAIL) { + *errmsg = e_invarg; + return; } - - return retval; + set_buflocal_ofu_callback(buf); } /// Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc' @@ -2299,7 +2299,7 @@ void set_buflocal_ofu_callback(buf_T *buf) /// Invoked when the 'thesaurusfunc' option is set. The option value can be a /// name of a function (string), or function(<name>) or funcref(<name>) or a /// lambda expression. -int set_thesaurusfunc_option(void) +void set_thesaurusfunc_option(char **errmsg) { int retval; @@ -2311,7 +2311,9 @@ int set_thesaurusfunc_option(void) retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); } - return retval; + if (retval == FAIL) { + *errmsg = e_invarg; + } } /// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with @@ -2856,7 +2858,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar // 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 + } else if (vim_strchr("buwU", (uint8_t)(*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 @@ -2950,7 +2952,7 @@ static void get_next_dict_tsr_completion(int compl_type, char *dict, int dict_f) } else { ins_compl_dictionaries(dict != NULL ? dict : (compl_type == CTRL_X_THESAURUS - ? (*curbuf->b_p_tsr == NUL ? (char *)p_tsr : curbuf->b_p_tsr) + ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr) : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)), compl_pattern, @@ -2996,7 +2998,7 @@ static void get_next_filename_completion(void) #ifdef BACKSLASH_IN_FILENAME if (curbuf->b_p_csl[0] != NUL) { for (int i = 0; i < num_matches; i++) { - char_u *ptr = matches[i]; + char *ptr = matches[i]; while (*ptr != NUL) { if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') { *ptr = '/'; @@ -3160,7 +3162,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_ compl_direction, compl_pattern); } else { found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, - NULL, compl_direction, (char_u *)compl_pattern, 1L, + NULL, compl_direction, compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); } msg_silent--; diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index a4228fcc7e..e19806e464 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -474,7 +474,7 @@ char_u *get_special_key_name(int c, int modifiers) int i, idx; int table_idx; - char_u *s; + char *s; string[0] = '<'; idx = 1; @@ -543,7 +543,7 @@ char_u *get_special_key_name(int c, int modifiers) } else { s = transchar(c); while (*s) { - string[idx++] = *s++; + string[idx++] = (uint8_t)(*s++); } } } @@ -572,7 +572,7 @@ char_u *get_special_key_name(int c, int modifiers) /// @param[out] did_simplify found <C-H>, etc. /// /// @return Number of characters added to dst, zero for no match. -unsigned int trans_special(const char **const srcp, const size_t src_len, char_u *const dst, +unsigned int trans_special(const char **const srcp, const size_t src_len, char *const dst, const int flags, const bool escape_ks, bool *const did_simplify) FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT { @@ -582,7 +582,7 @@ unsigned int trans_special(const char **const srcp, const size_t src_len, char_u return 0; } - return special_to_buf(key, modifiers, escape_ks, dst); + return special_to_buf(key, modifiers, escape_ks, (char_u *)dst); } /// Put the character sequence for "key" with "modifiers" into "dst" and return @@ -629,11 +629,11 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m const int flags, bool *const did_simplify) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { - const char_u *last_dash; - const char_u *end_of_name; - const char_u *src; - const char_u *bp; - const char_u *const end = (char_u *)(*srcp) + src_len - 1; + const char *last_dash; + const char *end_of_name; + const char *src; + const char *bp; + const char *const end = *srcp + src_len - 1; const bool in_string = flags & FSK_IN_STRING; int modifiers; int bit; @@ -645,7 +645,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m return 0; } - src = (char_u *)(*srcp); + src = *srcp; if (src[0] != '<') { return 0; } @@ -659,7 +659,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m if (*bp == '-') { last_dash = bp; if (bp + 1 <= end) { - l = utfc_ptr2len_len((char *)bp + 1, (int)(end - bp) + 1); + l = utfc_ptr2len_len(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-\"> @@ -674,7 +674,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m 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((char *)bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); + vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true); if (l == 0) { emsg(_(e_invarg)); return 0; @@ -691,7 +691,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m modifiers = 0x0; for (bp = src + 1; bp < last_dash; bp++) { if (*bp != '-') { - bit = name_to_mod_mask(*bp); + bit = name_to_mod_mask((uint8_t)(*bp)); if (bit == 0x0) { break; // Illegal modifier name } @@ -704,7 +704,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m if (STRNICMP(last_dash + 1, "char-", 5) == 0 && ascii_isdigit(last_dash[6])) { // <Char-123> or <Char-033> or <Char-0x33> - vim_str2nr((char *)last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true); + vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true); if (l == 0) { emsg(_(e_invarg)); return 0; @@ -718,12 +718,12 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m // Special case for a double-quoted string off = l = 2; } else { - l = utfc_ptr2len((char *)last_dash + 1); + l = utfc_ptr2len(last_dash + 1); } if (modifiers != 0 && last_dash[l + 1] == '>') { - key = utf_ptr2char((char *)last_dash + off); + key = utf_ptr2char(last_dash + off); } else { - key = get_special_key_code(last_dash + off); + key = get_special_key_code((char_u *)last_dash + off); if (!(flags & FSK_KEEP_X_KEY)) { key = handle_x_keys(key); } @@ -753,7 +753,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m } *modp = modifiers; - *srcp = (char *)end_of_name; + *srcp = end_of_name; return key; } // else { ELOG("unknown key: '%s'", src); } } @@ -944,7 +944,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co } } - slen = trans_special(&src, (size_t)(end - src) + 1, (char_u *)result + dlen, + slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, FSK_KEYCODE | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY), true, did_simplify); if (slen) { @@ -1059,8 +1059,8 @@ 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 *d = res; + char *res = xmalloc(strlen(p) * 4 + 1); + char_u *d = (char_u *)res; for (char_u *s = (char_u *)p; *s != NUL;) { if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) { // Copy special key unmodified. @@ -1076,7 +1076,7 @@ char *vim_strsave_escape_ks(char *p) } *d = NUL; - return (char *)res; + return res; } /// Remove escaping from K_SPECIAL characters. Reverse of diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c index 629a31c913..a9dac40731 100644 --- a/src/nvim/linematch.c +++ b/src/nvim/linematch.c @@ -9,7 +9,6 @@ #include "nvim/linematch.h" #include "nvim/macros.h" #include "nvim/memory.h" -#include "nvim/vim.h" // struct for running the diff linematch algorithm typedef struct { diff --git a/src/nvim/locale.c b/src/nvim/locale.c index 6322271073..c3cfd3bedb 100644 --- a/src/nvim/locale.c +++ b/src/nvim/locale.c @@ -294,7 +294,7 @@ static char **find_locales(void) if (locale_a == NULL) { return NULL; } - ga_init(&locales_ga, sizeof(char_u *), 20); + ga_init(&locales_ga, sizeof(char *), 20); // Transform locale_a string where each locale is separated by "\n" // into an array of locale strings. @@ -308,7 +308,7 @@ static char **find_locales(void) 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; + ((char **)locales_ga.ga_data)[locales_ga.ga_len] = NULL; return locales_ga.ga_data; } # endif diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 3c129fe7ce..6160b84485 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -391,7 +391,7 @@ nlua_pop_typval_table_processing_end: case LUA_TFUNCTION: { LuaRef func = nlua_ref_global(lstate, -1); - char *name = (char *)register_luafunc(func); + char *name = register_luafunc(func); cur.tv->v_type = VAR_FUNC; cur.tv->vval.v_string = xstrdup(name); diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 12ddbd094f..1415ceeaed 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -49,6 +49,7 @@ #include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/option_defs.h" +#include "nvim/os/fileio.h" #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/pos.h" @@ -56,7 +57,6 @@ #include "nvim/runtime.h" #include "nvim/strings.h" #include "nvim/ui.h" -#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/usercmd.h" #include "nvim/version.h" @@ -64,6 +64,7 @@ #include "nvim/window.h" static int in_fast_callback = 0; +static bool in_script = false; // Initialized in nlua_init(). static lua_State *global_lstate = NULL; @@ -133,8 +134,13 @@ static void nlua_error(lua_State *const lstate, const char *const msg) str = lua_tolstring(lstate, -1, &len); } - msg_ext_set_kind("lua_error"); - semsg_multiline(msg, (int)len, str); + if (in_script) { + os_errmsg(str); + os_errmsg("\n"); + } else { + msg_ext_set_kind("lua_error"); + semsg_multiline(msg, (int)len, str); + } lua_pop(lstate, 1); } @@ -534,7 +540,7 @@ int nlua_get_global_ref_count(void) return nlua_global_refs->ref_count; } -static void nlua_common_vim_init(lua_State *lstate, bool is_thread) +static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_standalone) FUNC_ATTR_NONNULL_ARG(1) { nlua_ref_state_t *ref_state = nlua_new_ref_state(lstate, is_thread); @@ -567,7 +573,9 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread) lua_setfield(lstate, -2, "_empty_dict_mt"); // vim.loop - if (is_thread) { + if (is_standalone) { + // do nothing, use libluv like in a standalone interpreter + } else if (is_thread) { luv_set_callback(lstate, nlua_luv_thread_cb_cfpcall); luv_set_thread(lstate, nlua_luv_thread_cfpcall); luv_set_cthread(lstate, nlua_luv_thread_cfcpcall); @@ -606,7 +614,7 @@ static int nlua_module_preloader(lua_State *lstate) return 1; } -static bool nlua_init_packages(lua_State *lstate) +static bool nlua_init_packages(lua_State *lstate, bool is_standalone) FUNC_ATTR_NONNULL_ALL { // put builtin packages in preload @@ -618,7 +626,7 @@ static bool nlua_init_packages(lua_State *lstate) lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure] lua_setfield(lstate, -2, def.name); // [package, preload] - if (nlua_disable_preload && strequal(def.name, "vim.inspect")) { + if ((nlua_disable_preload && !is_standalone) && strequal(def.name, "vim.inspect")) { break; } } @@ -769,7 +777,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_ui_detach); lua_setfield(lstate, -2, "ui_detach"); - nlua_common_vim_init(lstate, false); + nlua_common_vim_init(lstate, false, false); // patch require() (only for --startuptime) if (time_fd != NULL) { @@ -788,7 +796,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setglobal(lstate, "vim"); - if (!nlua_init_packages(lstate)) { + if (!nlua_init_packages(lstate, false)) { return false; } @@ -813,6 +821,9 @@ void nlua_init(char **argv, int argc, int lua_arg0) luaL_openlibs(lstate); if (!nlua_state_init(lstate)) { os_errmsg(_("E970: Failed to initialize builtin lua modules\n")); +#ifdef EXITFREE + nlua_common_free_all_mem(lstate); +#endif os_exit(1); } @@ -824,9 +835,28 @@ void nlua_init(char **argv, int argc, int lua_arg0) static lua_State *nlua_thread_acquire_vm(void) { + return nlua_init_state(true); +} + +void nlua_run_script(char **argv, int argc, int lua_arg0) + FUNC_ATTR_NORETURN +{ + in_script = true; + global_lstate = nlua_init_state(false); + luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem); + nlua_init_argv(global_lstate, argv, argc, lua_arg0); + bool lua_ok = nlua_exec_file(argv[lua_arg0 - 1]); +#ifdef EXITFREE + nlua_free_all_mem(); +#endif + exit(lua_ok ? 0 : 1); +} + +lua_State *nlua_init_state(bool thread) +{ // If it is called from the main thread, it will attempt to rebuild the cache. const uv_thread_t self = uv_thread_self(); - if (uv_thread_equal(&main_thread, &self)) { + if (!in_script && uv_thread_equal(&main_thread, &self)) { runtime_search_path_validate(); } @@ -835,9 +865,11 @@ static lua_State *nlua_thread_acquire_vm(void) // Add in the lua standard libraries luaL_openlibs(lstate); - // print - lua_pushcfunction(lstate, &nlua_print); - lua_setglobal(lstate, "print"); + if (!in_script) { + // print + lua_pushcfunction(lstate, &nlua_print); + lua_setglobal(lstate, "print"); + } lua_pushinteger(lstate, 0); lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.refcount"); @@ -845,18 +877,20 @@ static lua_State *nlua_thread_acquire_vm(void) // vim lua_newtable(lstate); - nlua_common_vim_init(lstate, true); + nlua_common_vim_init(lstate, thread, in_script); nlua_state_add_stdlib(lstate, true); - lua_createtable(lstate, 0, 0); - lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); - lua_setfield(lstate, -2, "nvim__get_runtime"); - lua_setfield(lstate, -2, "api"); + if (!in_script) { + lua_createtable(lstate, 0, 0); + lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime); + lua_setfield(lstate, -2, "nvim__get_runtime"); + lua_setfield(lstate, -2, "api"); + } lua_setglobal(lstate, "vim"); - nlua_init_packages(lstate); + nlua_init_packages(lstate, in_script); lua_getglobal(lstate, "package"); lua_getfield(lstate, -1, "loaded"); @@ -1440,11 +1474,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) estack_push(ETYPE_SCRIPT, name, 0); garray_T ga; - char_u *line = NULL; + char *line = NULL; - ga_init(&ga, (int)sizeof(char_u *), 10); - while ((line = (char_u *)fgetline(0, cookie, 0, false)) != NULL) { - GA_APPEND(char_u *, &ga, line); + ga_init(&ga, (int)sizeof(char *), 10); + while ((line = fgetline(0, cookie, 0, false)) != NULL) { + GA_APPEND(char *, &ga, line); } char *code = ga_concat_strings_sep(&ga, "\n"); size_t len = strlen(code); @@ -1877,7 +1911,7 @@ int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results) goto cleanup_array; } - GA_APPEND(char_u *, &result_array, (char_u *)string_to_cstr(v.data.string)); + GA_APPEND(char *, &result_array, string_to_cstr(v.data.string)); } xp->xp_pattern += prefix_len; @@ -1914,7 +1948,7 @@ bool nlua_is_table_from_lua(const typval_T *const arg) } } -char_u *nlua_register_table_as_callable(const typval_T *const arg) +char *nlua_register_table_as_callable(const typval_T *const arg) { LuaRef table_ref = LUA_NOREF; if (arg->v_type == VAR_DICT) { @@ -1950,7 +1984,7 @@ char_u *nlua_register_table_as_callable(const typval_T *const arg) LuaRef func = nlua_ref_global(lstate, -1); - char_u *name = register_luafunc(func); + char *name = register_luafunc(func); lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); @@ -1960,8 +1994,8 @@ char_u *nlua_register_table_as_callable(const typval_T *const arg) void nlua_execute_on_key(int c) { - char_u buf[NUMBUFLEN]; - size_t buf_len = special_to_buf(c, mod_mask, false, buf); + char buf[NUMBUFLEN]; + size_t buf_len = special_to_buf(c, mod_mask, false, (char_u *)buf); lua_State *const lstate = global_lstate; @@ -1977,7 +2011,7 @@ void nlua_execute_on_key(int c) luaL_checktype(lstate, -1, LUA_TFUNCTION); // [ vim, vim._on_key, buf ] - lua_pushlstring(lstate, (const char *)buf, buf_len); + lua_pushlstring(lstate, buf, buf_len); int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index 0a566b2f86..d510d25e90 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -61,7 +61,7 @@ int nlua_spell_check(lua_State *lstate) while (*str != NUL) { attr = HLF_COUNT; - len = spell_check(curwin, (char_u *)str, &attr, &capcol, false); + len = spell_check(curwin, (char *)str, &attr, &capcol, false); assert(len <= INT_MAX); if (attr != HLF_COUNT) { diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index dac96790d7..6ebca6d97e 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -40,17 +40,17 @@ # include "lua/stdlib.c.generated.h" #endif -static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) +static int regex_match(lua_State *lstate, regprog_T **prog, char *str) { regmatch_T rm; rm.regprog = *prog; rm.rm_ic = false; - bool match = vim_regexec(&rm, (char *)str, 0); + bool match = vim_regexec(&rm, str, 0); *prog = rm.regprog; if (match) { - lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - (char *)str)); - lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - (char *)str)); + lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - str)); + lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - str)); return 2; } return 0; @@ -60,7 +60,7 @@ static int regex_match_str(lua_State *lstate) { regprog_T **prog = regex_check(lstate); const char *str = luaL_checkstring(lstate, 2); - int nret = regex_match(lstate, prog, (char_u *)str); + int nret = regex_match(lstate, prog, (char *)str); if (!*prog) { return luaL_error(lstate, "regex: internal error"); @@ -116,7 +116,7 @@ static int regex_match_line(lua_State *lstate) line[end] = NUL; } - int nret = regex_match(lstate, prog, (char_u *)line + start); + int nret = regex_match(lstate, prog, line + start); if (end >= 0) { line[end] = save; @@ -198,7 +198,7 @@ static int nlua_str_utf_pos(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL size_t idx = 1; size_t clen; for (size_t i = 0; i < s1_len && s1[i] != NUL; i += clen) { - clen = (size_t)utf_ptr2len_len((const char_u *)(s1) + i, (int)(s1_len - i)); + clen = (size_t)utf_ptr2len_len(s1 + i, (int)(s1_len - i)); lua_pushinteger(lstate, (long)i + 1); lua_rawseti(lstate, -2, (int)idx); idx++; @@ -266,8 +266,7 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL use_utf16 = lua_toboolean(lstate, 3); } - ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len, - (size_t)idx, use_utf16); + ssize_t byteidx = mb_utf_index_to_bytes(s1, s1_len, (size_t)idx, use_utf16); if (byteidx == -1) { return luaL_error(lstate, "index out of range"); } @@ -483,8 +482,6 @@ 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) { @@ -503,14 +500,14 @@ static int nlua_iconv(lua_State *lstate) 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))); + char *from = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL))); + char *to = 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); + convert_setup_ext(&vimconv, from, false, to, false); - char_u *ret = (char_u *)string_convert(&vimconv, (char *)str, &str_len); + char *ret = string_convert(&vimconv, (char *)str, &str_len); convert_setup(&vimconv, NULL, NULL); @@ -520,15 +517,13 @@ static int nlua_iconv(lua_State *lstate) if (ret == NULL) { lua_pushnil(lstate); } else { - lua_pushlstring(lstate, (char *)ret, str_len); + lua_pushlstring(lstate, ret, str_len); xfree(ret); } return 1; } -#endif - void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { @@ -575,12 +570,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) 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 fecf746036..56f4daed1a 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -182,8 +182,8 @@ int tslua_add_language(lua_State *L) uv_lib_t lib; if (uv_dlopen(path, &lib)) { - snprintf(IObuff, IOSIZE, "Failed to load parser: uv_dlopen: %s", - uv_dlerror(&lib)); + snprintf(IObuff, IOSIZE, "Failed to load parser for language '%s': uv_dlopen: %s", + lang_name, uv_dlerror(&lib)); uv_dlclose(&lib); lua_pushstring(L, IObuff); return lua_error(L); diff --git a/src/nvim/main.c b/src/nvim/main.c index 6f14a00949..e26922bf8e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -10,7 +10,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #include "auto/config.h" #include "nvim/arglist.h" @@ -62,7 +61,6 @@ #include "nvim/os/fileio.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/os/pty_process.h" #include "nvim/os/stdpaths_defs.h" #include "nvim/os/time.h" #include "nvim/path.h" @@ -97,7 +95,6 @@ #include "nvim/msgpack_rpc/helpers.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/signal.h" -#include "nvim/tui/tui.h" // values for "window_layout" enum { @@ -242,6 +239,14 @@ int main(int argc, char **argv) argv0 = argv[0]; + if (argc > 1 && STRICMP(argv[1], "-ll") == 0) { + if (argc == 2) { + print_mainerr(err_arg_missing, argv[1]); + exit(1); + } + nlua_run_script(argv, argc, 3); + } + char *fname = NULL; // file name from command line mparm_T params; // various parameters passed between // main() and other functions. @@ -289,7 +294,13 @@ int main(int argc, char **argv) } } - bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode); +#ifdef MSWIN + // on windows we use CONIN special file, thus we don't know this yet. + bool has_term = true; +#else + bool has_term = (stdin_isatty || stdout_isatty || stderr_isatty); +#endif + bool use_builtin_ui = (has_term && !headless_mode && !embedded_mode && !silent_mode); // don't bind the server yet, if we are using builtin ui. // This will be done when nvim server has been forked from the ui process @@ -305,7 +316,7 @@ int main(int argc, char **argv) bool remote_ui = (ui_client_channel_id != 0); if (use_builtin_ui && !remote_ui) { - ui_client_forward_stdin = !params.input_isatty; + ui_client_forward_stdin = !stdin_isatty; uint64_t rv = ui_client_start_server(params.argc, params.argv); if (!rv) { os_errmsg("Failed to start Nvim server!\n"); @@ -362,8 +373,8 @@ int main(int argc, char **argv) debug_break_level = params.use_debug_break_level; // Read ex-commands if invoked with "-es". - if (!params.input_isatty && !params.input_istext && silent_mode && exmode_active) { - input_start(STDIN_FILENO); + if (!stdin_isatty && !params.input_istext && silent_mode && exmode_active) { + input_start(); } if (ui_client_channel_id) { @@ -542,7 +553,9 @@ 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); + if (!wp->w_arg_idx_invalid) { + diff_win_options(wp, true); + } } } @@ -579,6 +592,7 @@ int main(int argc, char **argv) if (use_builtin_ui) { os_icon_init(); } + os_title_save(); #endif // Adjust default register name for "unnamed" in 'clipboard'. Can only be @@ -640,8 +654,8 @@ void os_exit(int r) if (!event_teardown() && r == 0) { r = 1; // Exit with error if main_loop did not teardown gracefully. } - if (input_global_fd() >= 0) { - stream_set_blocking(input_global_fd(), true); // normalize stream (#2598) + if (used_stdin) { + stream_set_blocking(STDIN_FILENO, true); // normalize stream (#2598) } ILOG("Nvim exit: %d", r); @@ -760,7 +774,7 @@ void getout(int exitval) // Apply 'titleold'. if (p_title && *p_titleold != NUL) { - ui_call_set_title(cstr_as_string((char *)p_titleold)); + ui_call_set_title(cstr_as_string(p_titleold)); } if (garbage_collect_at_exit) { @@ -770,6 +784,7 @@ void getout(int exitval) #ifdef MSWIN // Restore Windows console icon before exiting. os_icon_set(NULL, NULL); + os_title_reset(); #endif os_exit(exitval); @@ -786,9 +801,9 @@ void preserve_exit(void) // Prevent repeated calls into this method. if (really_exiting) { - if (input_global_fd() >= 0) { + if (used_stdin) { // normalize stream (#2598) - stream_set_blocking(input_global_fd(), true); + stream_set_blocking(STDIN_FILENO, true); } exit(2); } @@ -796,6 +811,11 @@ void preserve_exit(void) really_exiting = true; // Ignore SIGHUP while we are already exiting. #9274 signal_reject_deadly(); + + if (ui_client_channel_id) { + os_exit(1); + } + os_errmsg(IObuff); os_errmsg("\n"); ui_flush(); @@ -880,7 +900,7 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, os_errmsg("Remote ui failed to start: "); os_errmsg(connect_error); os_errmsg("\n"); - exit(1); + os_exit(1); } ui_client_channel_id = chan; @@ -964,7 +984,7 @@ static bool edit_stdin(mparm_T *parmp) bool implicit = !headless_mode && !(embedded_mode && stdin_fd <= 0) && (!exmode_active || parmp->input_istext) - && !parmp->input_isatty + && !stdin_isatty && parmp->scriptin == NULL; // `-s -` was not given. return parmp->had_stdin_file || implicit; } @@ -1450,11 +1470,9 @@ static void init_startuptime(mparm_T *paramp) static void check_and_set_isatty(mparm_T *paramp) { - stdin_isatty - = paramp->input_isatty = os_isatty(STDIN_FILENO); - stdout_isatty - = paramp->output_isatty = os_isatty(STDOUT_FILENO); - paramp->err_isatty = os_isatty(STDERR_FILENO); + stdin_isatty = os_isatty(STDIN_FILENO); + stdout_isatty = os_isatty(STDOUT_FILENO); + stderr_isatty = os_isatty(STDERR_FILENO); TIME_MSG("window checked"); } @@ -1506,7 +1524,7 @@ static void handle_quickfix(mparm_T *paramp) set_string_option_direct("ef", -1, paramp->use_ef, OPT_FREE, SID_CARG); } vim_snprintf(IObuff, IOSIZE, "cfile %s", p_ef); - if (qf_init(NULL, (char *)p_ef, p_efm, true, IObuff, p_menc) < 0) { + if (qf_init(NULL, p_ef, p_efm, true, IObuff, p_menc) < 0) { msg_putchar('\n'); os_exit(3); } @@ -2106,6 +2124,12 @@ static int execute_env(char *env) static void mainerr(const char *errstr, const char *str) FUNC_ATTR_NORETURN { + print_mainerr(errstr, str); + os_exit(1); +} + +static void print_mainerr(const char *errstr, const char *str) +{ char *prgname = path_tail(argv0); signal_stop(); // kill us with CTRL-C here, if you like @@ -2121,8 +2145,6 @@ static void mainerr(const char *errstr, const char *str) os_errmsg(_("\nMore info with \"")); os_errmsg(prgname); os_errmsg(" -h\"\n"); - - os_exit(1); } /// Prints version information for "nvim -v" or "nvim --version". diff --git a/src/nvim/main.h b/src/nvim/main.h index 46d7217364..2d54837872 100644 --- a/src/nvim/main.h +++ b/src/nvim/main.h @@ -30,10 +30,7 @@ typedef struct { char *tagname; // tag from -t argument char *use_ef; // 'errorfile' from -q argument - bool input_isatty; // stdin is a terminal bool input_istext; // stdin is text, not executable (-E/-Es) - bool output_isatty; // stdout is a terminal - bool err_isatty; // stderr is a terminal int no_swap_file; // "-n" argument used int use_debug_break_level; diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 04a0107fe8..831d1299a8 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -5,6 +5,7 @@ #include <assert.h> #include <inttypes.h> +#include <lauxlib.h> #include <limits.h> #include <stdbool.h> #include <stdio.h> @@ -17,6 +18,7 @@ #include "nvim/ascii.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/cmdexpand.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -38,6 +40,7 @@ #include "nvim/pos.h" #include "nvim/regexp.h" #include "nvim/runtime.h" +#include "nvim/search.h" #include "nvim/strings.h" #include "nvim/vim.h" @@ -1196,7 +1199,7 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) } if (c) { - ga_append(&ga, (char)c); + ga_append(&ga, (uint8_t)c); } } ga_append(&ga, NUL); @@ -1267,93 +1270,135 @@ char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, /// Find all mapping/abbreviation names that match regexp "regmatch". /// For command line expansion of ":[un]map" and ":[un]abbrev" in all modes. /// @return OK if matches found, FAIL otherwise. -int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) +int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***matches) { - mapblock_T *mp; - int hash; - int count; - int round; - char *p; - int i; - - *num_file = 0; // return values in case of FAIL - *file = NULL; - - // round == 1: Count the matches. - // round == 2: Build the array to keep the matches. - for (round = 1; round <= 2; round++) { - count = 0; - - for (i = 0; i < 7; i++) { - if (i == 0) { - p = "<silent>"; - } else if (i == 1) { - p = "<unique>"; - } else if (i == 2) { - p = "<script>"; - } else if (i == 3) { - p = "<expr>"; - } else if (i == 4 && !expand_buffer) { - p = "<buffer>"; - } else if (i == 5) { - p = "<nowait>"; - } else if (i == 6) { - p = "<special>"; - } else { + const bool fuzzy = cmdline_fuzzy_complete(pat); + + *numMatches = 0; // return values in case of FAIL + *matches = NULL; + + garray_T ga; + if (!fuzzy) { + ga_init(&ga, sizeof(char *), 3); + } else { + ga_init(&ga, sizeof(fuzmatch_str_T), 3); + } + + // First search in map modifier arguments + for (int i = 0; i < 7; i++) { + char *p; + if (i == 0) { + p = "<silent>"; + } else if (i == 1) { + p = "<unique>"; + } else if (i == 2) { + p = "<script>"; + } else if (i == 3) { + p = "<expr>"; + } else if (i == 4 && !expand_buffer) { + p = "<buffer>"; + } else if (i == 5) { + p = "<nowait>"; + } else if (i == 6) { + p = "<special>"; + } else { + continue; + } + + bool match; + int score = 0; + if (!fuzzy) { + match = vim_regexec(regmatch, p, (colnr_T)0); + } else { + score = fuzzy_match_str(p, pat); + match = (score != 0); + } + + if (!match) { + continue; + } + + if (fuzzy) { + GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ + .idx = ga.ga_len, + .str = xstrdup(p), + .score = score, + })); + } else { + GA_APPEND(char *, &ga, xstrdup(p)); + } + } + + for (int hash = 0; hash < 256; hash++) { + mapblock_T *mp; + if (expand_isabbrev) { + if (hash > 0) { // only one abbrev list + break; // for (hash) + } + mp = first_abbr; + } else if (expand_buffer) { + mp = curbuf->b_maphash[hash]; + } else { + mp = maphash[hash]; + } + for (; mp; mp = mp->m_next) { + if (!(mp->m_mode & expand_mapmodes)) { continue; } - if (vim_regexec(regmatch, p, (colnr_T)0)) { - if (round == 1) { - count++; - } else { - (*file)[count++] = xstrdup(p); - } + char *p = (char *)translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS); + if (p == NULL) { + continue; } - } - for (hash = 0; hash < 256; hash++) { - if (expand_isabbrev) { - if (hash > 0) { // only one abbrev list - break; // for (hash) - } - mp = first_abbr; - } else if (expand_buffer) { - mp = curbuf->b_maphash[hash]; + bool match; + int score = 0; + if (!fuzzy) { + match = vim_regexec(regmatch, p, (colnr_T)0); } else { - mp = maphash[hash]; + score = fuzzy_match_str(p, pat); + match = (score != 0); } - for (; mp; mp = mp->m_next) { - if (mp->m_mode & expand_mapmodes) { - p = (char *)translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS); - if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) { - if (round == 1) { - count++; - } else { - (*file)[count++] = p; - p = NULL; - } - } - xfree(p); - } - } // for (mp) - } // for (hash) - if (count == 0) { // no match found - break; // for (round) - } + if (!match) { + xfree(p); + continue; + } - if (round == 1) { - *file = xmalloc((size_t)count * sizeof(char *)); - } - } // for (round) + if (fuzzy) { + GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ + .idx = ga.ga_len, + .str = p, + .score = score, + })); + } else { + GA_APPEND(char *, &ga, p); + } + } // for (mp) + } // for (hash) + if (ga.ga_len == 0) { + return FAIL; + } + + if (!fuzzy) { + *matches = ga.ga_data; + *numMatches = ga.ga_len; + } else { + fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, false); + *numMatches = ga.ga_len; + } + + int count = *numMatches; if (count > 1) { // Sort the matches - sort_strings(*file, count); + // Fuzzy matching already sorts the matches + if (!fuzzy) { + sort_strings(*matches, count); + } // Remove multiple entries - char **ptr1 = *file; + char **ptr1 = *matches; char **ptr2 = ptr1 + 1; char **ptr3 = ptr1 + count; @@ -1367,7 +1412,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char ***file) } } - *num_file = count; + *numMatches = count; return count == 0 ? FAIL : OK; } @@ -1806,9 +1851,9 @@ int makemap(FILE *fd, buf_T *buf) } if (putc(' ', fd) < 0 - || put_escstr(fd, (char_u *)mp->m_keys, 0) == FAIL + || put_escstr(fd, mp->m_keys, 0) == FAIL || putc(' ', fd) < 0 - || put_escstr(fd, (char_u *)mp->m_str, 1) == FAIL + || put_escstr(fd, mp->m_str, 1) == FAIL || put_eol(fd) < 0) { return FAIL; } @@ -1834,9 +1879,9 @@ int makemap(FILE *fd, buf_T *buf) // "what": 0 for :map lhs, 1 for :map rhs, 2 for :set // // return FAIL for failure, OK otherwise -int put_escstr(FILE *fd, char_u *strstart, int what) +int put_escstr(FILE *fd, char *strstart, int what) { - char_u *str = strstart; + char_u *str = (char_u *)strstart; int c; // :map xx <Nop> @@ -1913,7 +1958,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what) } } else if (c < ' ' || c > '~' || c == '|' || (what == 0 && c == ' ') - || (what == 1 && str == strstart && c == ' ') + || (what == 1 && str == (char_u *)strstart && c == ' ') || (what != 2 && c == '<')) { if (putc(Ctrl_V, fd) < 0) { return FAIL; diff --git a/src/nvim/mark.c b/src/nvim/mark.c index b98935e93d..f1a1f25e6c 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -5,6 +5,7 @@ #include <assert.h> #include <limits.h> +#include <stdint.h> #include <stdio.h> #include <string.h> @@ -39,7 +40,6 @@ #include "nvim/sign.h" #include "nvim/strings.h" #include "nvim/textobject.h" -#include "nvim/types.h" #include "nvim/undo_defs.h" #include "nvim/vim.h" @@ -1380,18 +1380,21 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c // When deleting lines, this may create duplicate marks in the // jumplist. They will be removed here for the specified window. -// When "checktail" is true, removes tail jump if it matches current position. -void cleanup_jumplist(win_T *wp, bool checktail) +// When "loadfiles" is true first ensure entries have the "fnum" field set +// (this may be a bit slow). +void cleanup_jumplist(win_T *wp, bool loadfiles) { int i; - // Load all the files from the jump list. This is - // needed to properly clean up duplicate entries, but will take some - // time. - for (i = 0; i < wp->w_jumplistlen; i++) { - if ((wp->w_jumplist[i].fmark.fnum == 0) - && (wp->w_jumplist[i].fmark.mark.lnum != 0)) { - fname2fnum(&wp->w_jumplist[i]); + if (loadfiles) { + // If specified, load all the files from the jump list. This is + // needed to properly clean up duplicate entries, but will take some + // time. + for (i = 0; i < wp->w_jumplistlen; i++) { + if ((wp->w_jumplist[i].fmark.fnum == 0) + && (wp->w_jumplist[i].fmark.mark.lnum != 0)) { + fname2fnum(&wp->w_jumplist[i]); + } } } @@ -1439,8 +1442,8 @@ void cleanup_jumplist(win_T *wp, bool checktail) // When pointer is below last jump, remove the jump if it matches the current // line. This avoids useless/phantom jumps. #9805 - if (checktail && wp->w_jumplistlen - && wp->w_jumplistidx == wp->w_jumplistlen) { + if (loadfiles // otherwise (i.e.: Shada), last entry should be kept + && wp->w_jumplistlen && wp->w_jumplistidx == wp->w_jumplistlen) { const xfmark_T *fm_last = &wp->w_jumplist[wp->w_jumplistlen - 1]; if (fm_last->fmark.fnum == curbuf->b_fnum && fm_last->fmark.mark.lnum == wp->w_cursor.lnum) { diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 2036ddd21d..77ba6e6fa4 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -1182,7 +1182,7 @@ static size_t check_node(MarkTree *b, mtnode_t *x, mtpos_t *last, bool *last_rig assert(x->ptr[i] != x->ptr[j]); } } - } else { + } else if (x->n > 0) { *last = x->key[x->n - 1].pos; } return n_keys; diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 93ac0fccfa..8b50ba719a 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -100,8 +100,8 @@ static char e_list_item_nr_cell_width_invalid[] = N_("E1112: List item %d cell width invalid"); static char e_overlapping_ranges_for_nr[] = N_("E1113: Overlapping ranges for 0x%lx"); -static char e_only_values_of_0x100_and_higher_supported[] - = N_("E1114: Only values of 0x100 and higher supported"); +static char e_only_values_of_0x80_and_higher_supported[] + = N_("E1114: Only values of 0x80 and higher supported"); // To speed up BYTELEN(); keep a lookup table to quickly get the length in // bytes of a UTF-8 character from the first byte of a UTF-8 string. Bytes @@ -406,9 +406,9 @@ int bomb_size(void) } // Remove all BOM from "s" by moving remaining text. -void remove_bom(char_u *s) +void remove_bom(char *s) { - char *p = (char *)s; + char *p = s; while ((p = strchr(p, 0xef)) != NULL) { if ((uint8_t)p[1] == 0xbb && (uint8_t)p[2] == 0xbf) { @@ -482,12 +482,16 @@ static bool intable(const struct interval *table, size_t n_items, int c) /// gen_unicode_tables.lua, which must be manually invoked as needed. int utf_char2cells(int c) { - if (c >= 0x100) { + // Use the value from setcellwidths() at 0x80 and higher, unless the + // character is not printable. + if (c >= 0x80 && vim_isprintc(c)) { int n = cw_value(c); if (n != 0) { return n; } + } + if (c >= 0x100) { if (!utf_printable(c)) { return 6; // unprintable, displays <xxxx> } @@ -540,7 +544,7 @@ int utf_ptr2cells_len(const char *p, int size) // Need to convert to a wide character. if (size > 0 && (uint8_t)(*p) >= 0x80) { - if (utf_ptr2len_len((char_u *)p, size) < utf8len_tab[(uint8_t)(*p)]) { + if (utf_ptr2len_len(p, size) < utf8len_tab[(uint8_t)(*p)]) { return 1; // truncated } c = utf_ptr2char((char *)p); @@ -566,8 +570,8 @@ size_t mb_string2cells(const char *str) { size_t clen = 0; - for (const char_u *p = (char_u *)str; *p != NUL; p += utfc_ptr2len((char *)p)) { - clen += (size_t)utf_ptr2cells((char *)p); + for (const char *p = str; *p != NUL; p += utfc_ptr2len(p)) { + clen += (size_t)utf_ptr2cells(p); } return clen; @@ -584,9 +588,9 @@ 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((char *)p, (int)size + (int)(p - (char_u *)str))) { - clen += (size_t)utf_ptr2cells((char *)p); + for (const char *p = str; *p != NUL && p < str + size; + p += utfc_ptr2len_len(p, (int)size + (int)(p - str))) { + clen += (size_t)utf_ptr2cells(p); } return clen; @@ -699,23 +703,23 @@ static int utf_safe_read_char_adv(const char_u **s, size_t *n) // 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 mb_ptr2char_adv(const char **const pp) { int c; - c = utf_ptr2char((char *)(*pp)); - *pp += utfc_ptr2len((char *)(*pp)); + c = utf_ptr2char(*pp); + *pp += utfc_ptr2len(*pp); return c; } // 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 mb_cptr2char_adv(const char **pp) { int c; - c = utf_ptr2char((char *)(*pp)); - *pp += utf_ptr2len((char *)(*pp)); + c = utf_ptr2char(*pp); + *pp += utf_ptr2len(*pp); return c; } @@ -785,7 +789,7 @@ int utfc_ptr2char_len(const char *p, int *pcc, int maxlen) int i = 0; - int len = utf_ptr2len_len((char_u *)p, maxlen); + int len = utf_ptr2len_len(p, maxlen); // Is it safe to use utf_ptr2char()? bool safe = len > 1 && len <= maxlen; int c = safe ? utf_ptr2char(p) : (uint8_t)(*p); @@ -793,7 +797,7 @@ int utfc_ptr2char_len(const char *p, int *pcc, int maxlen) // Only accept a composing char when the first char isn't illegal. if ((safe || c < 0x80) && len < maxlen && (uint8_t)p[len] >= 0x80) { for (; i < MAX_MCO; i++) { - int len_cc = utf_ptr2len_len((char_u *)p + len, maxlen - len); + int len_cc = utf_ptr2len_len(p + len, maxlen - len); safe = len_cc > 1 && len_cc <= maxlen - len; if (!safe || (pcc[i] = utf_ptr2char(p + len)) < 0x80 || !(i == 0 ? utf_composinglike(p, p + len) : utf_iscomposing(pcc[i]))) { @@ -848,13 +852,13 @@ int utf_byte2len(int b) // 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 utf_ptr2len_len(const char *p, int size) { int len; int i; int m; - len = utf8len_tab[*p]; + len = utf8len_tab[(uint8_t)(*p)]; if (len == 1) { return 1; // NUL, ascii or illegal lead byte } @@ -925,7 +929,7 @@ int utfc_ptr2len_len(const char *p, int size) } // Skip over first UTF-8 char, stopping at a NUL byte. - len = utf_ptr2len_len((char_u *)p, size); + len = utf_ptr2len_len(p, size); // Check for illegal byte and incomplete byte sequence. if ((len == 1 && (uint8_t)p[0] >= 0x80) || len > size) { @@ -944,7 +948,7 @@ int utfc_ptr2len_len(const char *p, int size) // 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); + len_next_char = utf_ptr2len_len(p + len, size - len); if (len_next_char > size - len) { break; } @@ -1462,7 +1466,7 @@ void mb_utflen(const char *s, size_t len, size_t *codepoints, size_t *codeunits) size_t count = 0, extra = 0; size_t clen; for (size_t i = 0; i < len; i += clen) { - clen = (size_t)utf_ptr2len_len((char_u *)s + i, (int)(len - i)); + clen = (size_t)utf_ptr2len_len(s + i, (int)(len - i)); // NB: gets the byte value of invalid sequence bytes. // we only care whether the char fits in the BMP or not int c = (clen > 1) ? utf_ptr2char(s + i) : (uint8_t)s[i]; @@ -1475,7 +1479,7 @@ void mb_utflen(const char *s, size_t len, size_t *codepoints, size_t *codeunits) *codeunits += count + extra; } -ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool use_utf16_units) +ssize_t mb_utf_index_to_bytes(const char *s, size_t len, size_t index, bool use_utf16_units) FUNC_ATTR_NONNULL_ALL { size_t count = 0; @@ -1487,7 +1491,7 @@ ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool us clen = (size_t)utf_ptr2len_len(s + i, (int)(len - i)); // NB: gets the byte value of invalid sequence bytes. // we only care whether the char fits in the BMP or not - int c = (clen > 1) ? utf_ptr2char((char *)s + i) : s[i]; + int c = (clen > 1) ? utf_ptr2char(s + i) : (uint8_t)s[i]; count++; if (use_utf16_units && c > 0xFFFF) { count++; @@ -1534,14 +1538,14 @@ void show_utf8(void) { int len; int rlen = 0; - char_u *line; + char *line; int clen; int i; // Get the byte length of the char under the cursor, including composing // characters. - line = (char_u *)get_cursor_pos_ptr(); - len = utfc_ptr2len((char *)line); + line = get_cursor_pos_ptr(); + len = utfc_ptr2len(line); if (len == 0) { msg("NUL"); return; @@ -1555,10 +1559,10 @@ void show_utf8(void) STRCPY(IObuff + rlen, "+ "); rlen += 2; } - clen = utf_ptr2len((char *)line + i); + clen = utf_ptr2len(line + i); } sprintf(IObuff + rlen, "%02x ", // NOLINT(runtime/printf) - (line[i] == NL) ? NUL : line[i]); // NUL is stored as NL + (line[i] == NL) ? NUL : (uint8_t)line[i]); // NUL is stored as NL clen--; rlen += (int)strlen(IObuff + rlen); if (rlen > IOSIZE - 20) { @@ -1787,7 +1791,7 @@ void mb_copy_char(const char **const fp, char **const tp) /// Return the offset from "p_in" to the first byte of a character. When "p_in" is /// at the start of a character 0 is returned, otherwise the offset to the next /// character. Can start anywhere in a stream of bytes. -int mb_off_next(const char_u *base, const char *p_in) +int mb_off_next(const char *base, const char *p_in) { const uint8_t *p = (uint8_t *)p_in; int i; @@ -1801,7 +1805,7 @@ int mb_off_next(const char_u *base, const char *p_in) for (i = 0; (p[i] & 0xc0) == 0x80; i++) {} if (i > 0) { // Check for illegal sequence. - for (j = 0; p - j > base; j++) { + for (j = 0; p - j > (uint8_t *)base; j++) { if ((p[-j] & 0xc0) != 0x80) { break; } @@ -1884,7 +1888,7 @@ void utf_find_illegal(void) char *p; int len; vimconv_T vimconv; - char_u *tofree = NULL; + char *tofree = NULL; vimconv.vc_type = CONV_NONE; if (enc_canon_props(curbuf->b_p_fenc) & ENC_8BIT) { @@ -1899,11 +1903,11 @@ void utf_find_illegal(void) p = get_cursor_pos_ptr(); if (vimconv.vc_type != CONV_NONE) { xfree(tofree); - tofree = (char_u *)string_convert(&vimconv, p, NULL); + tofree = string_convert(&vimconv, p, NULL); if (tofree == NULL) { break; } - p = (char *)tofree; + p = tofree; } while (*p != NUL) { @@ -1916,7 +1920,7 @@ void utf_find_illegal(void) } else { int l; - len = (int)(p - (char *)tofree); + len = (int)(p - tofree); for (p = get_cursor_pos_ptr(); *p != NUL && len-- > 0; p += l) { l = utf_ptr2len(p); curwin->w_cursor.col += l; @@ -2024,7 +2028,7 @@ char *mb_prevptr(char *line, char *p) /// following composing characters) counts as one. int mb_charlen(const char *str) { - const char_u *p = (char_u *)str; + const char *p = str; int count; if (p == NULL) { @@ -2032,20 +2036,20 @@ int mb_charlen(const char *str) } for (count = 0; *p != NUL; count++) { - p += utfc_ptr2len((char *)p); + p += utfc_ptr2len(p); } return count; } /// Like mb_charlen() but for a string with specified length. -int mb_charlen_len(const char_u *str, int len) +int mb_charlen_len(const char *str, int len) { - const char_u *p = str; + const char *p = str; int count; for (count = 0; *p != NUL && p < str + len; count++) { - p += utfc_ptr2len((char *)p); + p += utfc_ptr2len(p); } return count; @@ -2196,7 +2200,7 @@ static int enc_alias_search(const char *name) // Get the canonicalized encoding of the current locale. // Returns an allocated string when successful, NULL when not. -char_u *enc_locale(void) +char *enc_locale(void) { int i; char buf[50]; @@ -2232,7 +2236,7 @@ char_u *enc_locale(void) const char *p = vim_strchr(s, '.'); if (p != NULL) { if (p > s + 2 && !STRNICMP(p + 1, "EUC", 3) - && !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') { + && !isalnum((uint8_t)p[4]) && p[4] != '-' && p[-3] == '_') { // Copy "XY.EUC" to "euc-XY" to buf[10]. memmove(buf, "euc-", 4); buf[4] = (char)(ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0); @@ -2256,20 +2260,18 @@ enc_locale_copy_enc: buf[i] = NUL; } - return (char_u *)enc_canonize(buf); + return 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). -void *my_iconv_open(char_u *to, char_u *from) +void *my_iconv_open(char *to, char *from) { iconv_t fd; -# define ICONV_TESTLEN 400 - char_u tobuf[ICONV_TESTLEN]; +#define ICONV_TESTLEN 400 + char tobuf[ICONV_TESTLEN]; char *p; size_t tolen; static WorkingStatus iconv_working = kUnknown; @@ -2277,7 +2279,7 @@ 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(enc_skip((char *)to), enc_skip((char *)from)); + fd = iconv_open(enc_skip(to), enc_skip(from)); if (fd != (iconv_t)-1 && iconv_working == kUnknown) { // Do a dummy iconv() call to check if it actually works. There is a @@ -2285,7 +2287,7 @@ void *my_iconv_open(char_u *to, char_u *from) // 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; + p = tobuf; tolen = ICONV_TESTLEN; (void)iconv(fd, NULL, NULL, &p, &tolen); if (p == NULL) { @@ -2305,8 +2307,8 @@ void *my_iconv_open(char_u *to, char_u *from) // 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, const char_u *str, size_t slen, - size_t *unconvlenp, size_t *resultlenp) +static char *iconv_string(const vimconv_T *const vcp, const char *str, size_t slen, + size_t *unconvlenp, size_t *resultlenp) { const char *from; size_t fromlen; @@ -2314,11 +2316,11 @@ static char_u *iconv_string(const vimconv_T *const vcp, const char_u *str, size_ size_t tolen; size_t len = 0; size_t done = 0; - char_u *result = NULL; - char_u *p; + char *result = NULL; + char *p; int l; - from = (char *)str; + from = str; fromlen = slen; for (;;) { if (len == 0 || ICONV_ERRNO == ICONV_E2BIG) { @@ -2333,7 +2335,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, const char_u *str, size_ result = p; } - to = (char *)result + done; + to = result + done; tolen = len - done - 2; // Avoid a warning for systems with a wrong iconv() prototype by // casting the second argument to void *. @@ -2373,17 +2375,15 @@ static char_u *iconv_string(const vimconv_T *const vcp, const char_u *str, size_ break; } // Not enough room or skipping illegal sequence. - done = (size_t)(to - (char *)result); + done = (size_t)(to - result); } if (resultlenp != NULL && result != NULL) { - *resultlenp = (size_t)(to - (char *)result); + *resultlenp = (size_t)(to - result); } return result; } -#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. @@ -2408,11 +2408,9 @@ int convert_setup_ext(vimconv_T *vcp, char *from, bool from_unicode_is_utf8, cha int to_is_utf8; // Reset to no conversion. -#ifdef HAVE_ICONV if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) { iconv_close(vcp->vc_fd); } -#endif *vcp = (vimconv_T)MBYTE_NONE_CONV; // No conversion when one of the names is empty or they are equal. @@ -2448,18 +2446,15 @@ int convert_setup_ext(vimconv_T *vcp, char *from, bool from_unicode_is_utf8, cha } else if (from_is_utf8 && (to_prop & ENC_LATIN9)) { // Internal utf-8 -> latin9 conversion. vcp->vc_type = CONV_TO_LATIN9; - } -#ifdef HAVE_ICONV - else { // NOLINT(readability/braces) + } else { // Use iconv() for conversion. - 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); + vcp->vc_fd = (iconv_t)my_iconv_open(to_is_utf8 ? "utf-8" : to, + from_is_utf8 ? "utf-8" : from); if (vcp->vc_fd != (iconv_t)-1) { vcp->vc_type = CONV_ICONV; vcp->vc_factor = 4; // could be longer too... } } -#endif if (vcp->vc_type == CONV_NONE) { return FAIL; } @@ -2474,14 +2469,13 @@ int convert_setup_ext(vimconv_T *vcp, char *from, bool from_unicode_is_utf8, cha /// 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 (char *)string_convert_ext(vcp, (char_u *)ptr, lenp, NULL); + return string_convert_ext(vcp, 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. -char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp, - size_t *unconvlenp) +char *string_convert_ext(const vimconv_T *const vcp, char *ptr, size_t *lenp, size_t *unconvlenp) { char_u *retval = NULL; char_u *d; @@ -2490,12 +2484,12 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp size_t len; if (lenp == NULL) { - len = strlen((char *)ptr); + len = strlen(ptr); } else { len = *lenp; } if (len == 0) { - return (char_u *)xstrdup(""); + return xstrdup(""); } switch (vcp->vc_type) { @@ -2503,7 +2497,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp retval = xmalloc(len * 2 + 1); d = retval; for (size_t i = 0; i < len; i++) { - c = ptr[i]; + c = (uint8_t)ptr[i]; if (c < 0x80) { *d++ = (char_u)c; } else { @@ -2521,7 +2515,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp retval = xmalloc(len * 3 + 1); d = retval; for (size_t i = 0; i < len; i++) { - c = ptr[i]; + c = (uint8_t)ptr[i]; switch (c) { case 0xa4: c = 0x20ac; break; // euro @@ -2557,7 +2551,7 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp if (l == 0) { *d++ = NUL; } else if (l == 1) { - uint8_t l_w = utf8len_tab_zero[ptr[i]]; + uint8_t l_w = utf8len_tab_zero[(uint8_t)ptr[i]]; if (l_w == 0) { // Illegal utf-8 byte cannot be converted @@ -2569,9 +2563,9 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp *unconvlenp = len - i; break; } - *d++ = ptr[i]; + *d++ = (uint8_t)ptr[i]; } else { - c = utf_ptr2char((char *)ptr + i); + c = utf_ptr2char(ptr + i); if (vcp->vc_type == CONV_TO_LATIN9) { switch (c) { case 0x20ac: @@ -2623,14 +2617,12 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp } break; -#ifdef HAVE_ICONV case CONV_ICONV: // conversion with vcp->vc_fd - retval = iconv_string(vcp, ptr, len, unconvlenp, lenp); + retval = (char_u *)iconv_string(vcp, ptr, len, unconvlenp, lenp); break; -#endif } - return retval; + return (char *)retval; } /// Table set by setcellwidths(). @@ -2709,7 +2701,7 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (li_tv->v_type != VAR_LIST || li_tv->vval.v_list == NULL) { semsg(_(e_list_item_nr_is_not_list), item); - xfree(ptrs); + xfree((void *)ptrs); return; } @@ -2725,25 +2717,25 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (i == 0) { n1 = lili_tv->vval.v_number; - if (n1 < 0x100) { - emsg(_(e_only_values_of_0x100_and_higher_supported)); - xfree(ptrs); + if (n1 < 0x80) { + emsg(_(e_only_values_of_0x80_and_higher_supported)); + xfree((void *)ptrs); return; } } else if (i == 1 && lili_tv->vval.v_number < n1) { semsg(_(e_list_item_nr_range_invalid), item); - xfree(ptrs); + xfree((void *)ptrs); return; } else if (i == 2 && (lili_tv->vval.v_number < 1 || lili_tv->vval.v_number > 2)) { semsg(_(e_list_item_nr_cell_width_invalid), item); - xfree(ptrs); + xfree((void *)ptrs); return; } } if (i != 3) { semsg(_(e_list_item_nr_does_not_contain_3_numbers), item); - xfree(ptrs); + xfree((void *)ptrs); return; } @@ -2762,7 +2754,7 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const varnumber_T n1 = TV_LIST_ITEM_TV(lili)->vval.v_number; if (item > 0 && n1 <= table[item - 1].last) { semsg(_(e_overlapping_ranges_for_nr), (long)n1); - xfree(ptrs); + xfree((void *)ptrs); xfree(table); return; } @@ -2773,7 +2765,7 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) table[item].width = (char)TV_LIST_ITEM_TV(lili)->vval.v_number; } - xfree(ptrs); + xfree((void *)ptrs); cw_interval_T *const cw_table_save = cw_table; const size_t cw_table_size_save = cw_table_size; @@ -2795,6 +2787,21 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) redraw_all_later(UPD_NOT_VALID); } +/// "getcellwidths()" function +void f_getcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + tv_list_alloc_ret(rettv, (ptrdiff_t)cw_table_size); + + for (size_t i = 0; i < cw_table_size; i++) { + list_T *entry = tv_list_alloc(3); + tv_list_append_number(entry, (varnumber_T)cw_table[i].first); + tv_list_append_number(entry, (varnumber_T)cw_table[i].last); + tv_list_append_number(entry, (varnumber_T)cw_table[i].width); + + tv_list_append_list(rettv->vval.v_list, entry); + } +} + void f_charclass(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { if (tv_check_for_string_arg(argvars, 0) == FAIL diff --git a/src/nvim/mbyte_defs.h b/src/nvim/mbyte_defs.h index 53b01a211f..e913e20f9f 100644 --- a/src/nvim/mbyte_defs.h +++ b/src/nvim/mbyte_defs.h @@ -46,9 +46,7 @@ typedef enum { typedef struct { int vc_type; ///< Zero or more ConvFlags. int vc_factor; ///< Maximal expansion factor. -#ifdef HAVE_ICONV iconv_t vc_fd; ///< Value for CONV_ICONV. -#endif bool vc_fail; ///< What to do with invalid characters: if true, fail, ///< otherwise use '?'. } vimconv_T; diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 61d7893948..46be9ccea5 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -62,7 +62,6 @@ #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/pos.h" -#include "nvim/types.h" #include "nvim/vim.h" #define MEMFILE_PAGE_SIZE 4096 /// default page size diff --git a/src/nvim/memline.c b/src/nvim/memline.c index eee3b9d517..b3fc64a68c 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -149,7 +149,7 @@ struct data_block { #define DB_INDEX_MASK (~DB_MARKED) #define INDEX_SIZE (sizeof(unsigned)) // size of one db_index entry -#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) // size of data block header +#define HEADER_SIZE (offsetof(DATA_BL, db_index)) // size of data block header enum { B0_FNAME_SIZE_ORG = 900, // what it was in older versions @@ -749,7 +749,7 @@ void ml_recover(bool checkext) 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 + && vim_strchr("abcdefghijklmnopqrstuvw", TOLOWER_ASC((uint8_t)fname[len - 2])) != NULL && ASCII_ISALPHA(fname[len - 1])) { directly = true; fname_used = xstrdup(fname); // make a copy for mf_open() @@ -757,7 +757,7 @@ void ml_recover(bool checkext) directly = false; // count the number of matching swap files - len = recover_names((char_u *)fname, false, 0, NULL); + len = recover_names(fname, false, 0, NULL); if (len == 0) { // no swap files found semsg(_("E305: No swap file found for %s"), fname); goto theend; @@ -767,7 +767,7 @@ void ml_recover(bool checkext) i = 1; } else { // several swap files found, choose // list the names of the swap files - (void)recover_names((char_u *)fname, true, 0, NULL); + (void)recover_names(fname, true, 0, NULL); msg_putchar('\n'); msg_puts(_("Enter number of swap file to use (0 to quit): ")); i = get_number(false, NULL); @@ -776,7 +776,7 @@ void ml_recover(bool checkext) } } // get the swap file name that will be used - (void)recover_names((char_u *)fname, false, i, &fname_used); + (void)recover_names(fname, false, i, &fname_used); } if (fname_used == NULL) { goto theend; // user chose invalid number. @@ -1201,24 +1201,24 @@ theend: /// @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 **fname_out) +int recover_names(char *fname, int list, int nr, char **fname_out) { int num_names; char *(names[6]); - char_u *tail; + char *tail; char *p; int file_count = 0; char **files; - char_u *fname_res = NULL; + char *fname_res = NULL; #ifdef HAVE_READLINK - char_u fname_buf[MAXPATHL]; + char fname_buf[MAXPATHL]; #endif if (fname != NULL) { #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((char *)fname, (char *)fname_buf) == OK) { + if (resolve_symlink(fname, fname_buf) == OK) { fname_res = fname_buf; } else #endif @@ -1250,7 +1250,7 @@ int recover_names(char_u *fname, int list, int nr, char **fname_out) names[2] = xstrdup(".sw?"); num_names = 3; } else { - num_names = recov_file_names(names, (char *)fname_res, true); + num_names = recov_file_names(names, fname_res, true); } } else { // check directory dir_name if (fname == NULL) { @@ -1267,13 +1267,12 @@ int recover_names(char_u *fname, int list, int nr, char **fname_out) && len > 1 && p[-1] == p[-2]) { // Ends with '//', Use Full path for swap name - tail = (char_u *)make_percent_swname(dir_name, - (char *)fname_res); + tail = make_percent_swname(dir_name, fname_res); } else { - tail = (char_u *)path_tail((char *)fname_res); - tail = (char_u *)concat_fnames(dir_name, (char *)tail, true); + tail = path_tail(fname_res); + tail = concat_fnames(dir_name, tail, true); } - num_names = recov_file_names(names, (char *)tail, false); + num_names = recov_file_names(names, tail, false); xfree(tail); } } @@ -1290,11 +1289,11 @@ int recover_names(char_u *fname, int list, int nr, char **fname_out) // 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); + char *swapname = modname(fname_res, ".swp", true); if (swapname != NULL) { - if (os_path_exists((char *)swapname)) { - files = xmalloc(sizeof(char_u *)); - files[0] = (char *)swapname; + if (os_path_exists(swapname)) { + files = xmalloc(sizeof(char *)); + files[0] = swapname; swapname = NULL; num_files = 1; } @@ -1877,7 +1876,7 @@ int ml_append(linenr_T lnum, char *line, colnr_T len, bool newfile) /// @param line text of the new line /// @param len length of new line, including NUL, or 0 /// @param newfile flag, see above -int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool newfile) +int ml_append_buf(buf_T *buf, linenr_T lnum, char *line, colnr_T len, bool newfile) FUNC_ATTR_NONNULL_ARG(1) { if (buf->b_ml.ml_mfp == NULL) { @@ -1887,7 +1886,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, (char *)line, len, newfile, false); + return ml_append_int(buf, lnum, line, len, newfile, false); } /// @param lnum append after this line (can be 0) @@ -2721,7 +2720,8 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp) PTR_BL *pp = hp->bh_data; pp->pb_id = PTR_ID; pp->pb_count = 0; - pp->pb_count_max = (uint16_t)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1); + pp->pb_count_max + = (uint16_t)((mfp->mf_page_size - offsetof(PTR_BL, pb_pointer)) / sizeof(PTR_EN)); return hp; } @@ -3000,7 +3000,7 @@ int resolve_symlink(const char *fname, char *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((char_u *)buf)) { + if (path_is_absolute(buf)) { STRCPY(tmp, buf); } else { char *tail = path_tail(tmp); diff --git a/src/nvim/memory.c b/src/nvim/memory.c index aa8314b23d..5356300382 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -31,7 +31,6 @@ #include "nvim/message.h" #include "nvim/sign.h" #include "nvim/ui.h" -#include "nvim/ui_compositor.h" #include "nvim/usercmd.h" #include "nvim/vim.h" diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 0fa45ac24a..2a18b08d8d 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -6,6 +6,7 @@ #include <assert.h> #include <stdbool.h> +#include <stdint.h> #include <string.h> #include "nvim/ascii.h" diff --git a/src/nvim/message.c b/src/nvim/message.c index de4acd601f..3b3dfcd5b6 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2514,7 +2514,7 @@ static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int fin } if (s > *sb_str) { - mp = xmalloc((sizeof(msgchunk_T) + (size_t)(s - *sb_str))); + mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1); mp->sb_eol = (char)finish; mp->sb_msg_col = *sb_col; mp->sb_attr = attr; @@ -3006,7 +3006,7 @@ static int do_more_prompt(int typed_char) #if defined(MSWIN) /// Headless (no UI) error message handler. -static void do_msg(char *str, bool errmsg) +static void do_msg(const char *str, bool errmsg) { static bool did_err = false; assert(str != NULL); @@ -3026,13 +3026,13 @@ static void do_msg(char *str, bool errmsg) } } -void os_errmsg(char *str) +void os_errmsg(const char *str) { do_msg(str, true); } /// Headless (no UI) message handler. -void os_msg(char *str) +void os_msg(const char *str) { do_msg(str, false); } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index b7d15fe9af..950b025e53 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -3,6 +3,7 @@ #include <assert.h> #include <stdbool.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> @@ -85,17 +86,17 @@ static int get_mouse_class(char *p) /// Move "pos" back to the start of the word it's in. static void find_start_of_word(pos_T *pos) { - char_u *line; + char *line; int cclass; int col; - line = (char_u *)ml_get(pos->lnum); - cclass = get_mouse_class((char *)line + pos->col); + line = ml_get(pos->lnum); + cclass = get_mouse_class(line + pos->col); while (pos->col > 0) { col = pos->col - 1; - col -= utf_head_off((char *)line, (char *)line + col); - if (get_mouse_class((char *)line + col) != cclass) { + col -= utf_head_off(line, line + col); + if (get_mouse_class(line + col) != cclass) { break; } pos->col = col; @@ -106,19 +107,19 @@ static void find_start_of_word(pos_T *pos) /// When 'selection' is "exclusive", the position is just after the word. static void find_end_of_word(pos_T *pos) { - char_u *line; + char *line; int cclass; int col; - line = (char_u *)ml_get(pos->lnum); + line = ml_get(pos->lnum); if (*p_sel == 'e' && pos->col > 0) { pos->col--; - pos->col -= utf_head_off((char *)line, (char *)line + pos->col); + pos->col -= utf_head_off(line, line + pos->col); } - cclass = get_mouse_class((char *)line + pos->col); + cclass = get_mouse_class(line + pos->col); while (line[pos->col] != NUL) { - col = pos->col + utfc_ptr2len((char *)line + pos->col); - if (get_mouse_class((char *)line + col) != cclass) { + col = pos->col + utfc_ptr2len(line + pos->col); + if (get_mouse_class(line + col) != cclass) { if (*p_sel == 'e') { pos->col = col; } @@ -1539,16 +1540,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 *line = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); + char *line = ml_get_buf(wp->w_buffer, lnum, false); chartabsize_T cts; - init_chartabsize_arg(&cts, wp, lnum, 0, (char *)line, (char *)line); + init_chartabsize_arg(&cts, wp, lnum, 0, line, 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); + return (colnr_T)(cts.cts_ptr - line); } /// Set UI mouse depending on current mode and 'mouse'. @@ -1574,10 +1575,10 @@ static void set_mouse_topline(win_T *wp) static colnr_T scroll_line_len(linenr_T lnum) { colnr_T col = 0; - char_u *line = (char_u *)ml_get(lnum); + char *line = ml_get(lnum); if (*line != NUL) { for (;;) { - int numchar = win_chartabsize(curwin, (char *)line, col); + int numchar = win_chartabsize(curwin, line, col); MB_PTR_ADV(line); if (*line == NUL) { // don't count the last character break; @@ -1679,10 +1680,10 @@ 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 = (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` + char *line = ml_get(lnum); + char *ptr = line; + char *ptr_end; + char *ptr_row_offset = line; // Where we begin adjusting `ptr_end` // Find the offset where scanning should begin. int offset = wp->w_leftcol; @@ -1700,8 +1701,8 @@ 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, (char *)ptr, vcol); - ptr += utfc_ptr2len((char *)ptr); + vcol += win_chartabsize(curwin, ptr, vcol); + ptr += utfc_ptr2len(ptr); } ptr_row_offset = ptr; @@ -1711,8 +1712,8 @@ 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, (char *)ptr_end, vcol); - ptr_end += utfc_ptr2len((char *)ptr_end); + vcol += win_chartabsize(curwin, ptr_end, vcol); + ptr_end += utfc_ptr2len(ptr_end); } int matchid; @@ -1726,7 +1727,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, (char *)ptr, vcol); + cwidth = win_chartabsize(curwin, ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. @@ -1754,7 +1755,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) while (prev_matchid == matchid && *ptr != NUL) { INCR(); - ptr += utfc_ptr2len((char *)ptr); + ptr += utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); } @@ -1762,7 +1763,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) } } - ptr += utfc_ptr2len((char *)ptr); + ptr += utfc_ptr2len(ptr); } return col + nudge; diff --git a/src/nvim/move.c b/src/nvim/move.c index dc2f4b4844..3af26b910e 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -27,12 +27,14 @@ #include "nvim/eval/window.h" #include "nvim/fold.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight.h" #include "nvim/macros.h" #include "nvim/mbyte.h" #include "nvim/memline_defs.h" +#include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/option.h" @@ -758,7 +760,7 @@ void curs_columns(win_T *wp, int may_scroll) // When cursor wraps to first char of next line in Insert // mode, the 'showbreak' string isn't shown, backup to first // column - char *const sbr = (char *)get_showbreak_value(wp); + char *const sbr = get_showbreak_value(wp); if (*sbr && *get_cursor_pos_ptr() == NUL && wp->w_wcol == vim_strsize(sbr)) { wp->w_wcol = 0; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 0c23a7798c..d60e18590f 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -20,14 +20,15 @@ #include "nvim/channel.h" #include "nvim/event/defs.h" #include "nvim/event/loop.h" +#include "nvim/event/process.h" #include "nvim/event/rstream.h" #include "nvim/event/stream.h" #include "nvim/event/wstream.h" -#include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/map.h" #include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/helpers.h" diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index b1e033d9f1..1d75c208be 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -101,7 +101,7 @@ char *server_address_new(const char *name) xfree(dir); #endif if ((size_t)r >= sizeof(fmt)) { - ELOG("truncated server address"); + ELOG("truncated server address: %.40s...", fmt); } return xstrdup(fmt); } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8f4240c062..b88cfb8926 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -451,12 +451,34 @@ static int find_command(int cmdchar) /// message, return true. static bool check_text_locked(oparg_T *oap) { - if (text_locked()) { + if (!text_locked()) { + return false; + } + + if (oap != NULL) { clearopbeep(oap); - text_locked_msg(); + } + text_locked_msg(); + return true; +} + +/// If text is locked, "curbuf->b_ro_locked" or "allbuf_lock" is set: +/// Give an error message, possibly beep and return true. +/// "oap" may be NULL. +static bool check_text_or_curbuf_locked(oparg_T *oap) +{ + if (check_text_locked(oap)) { return true; } - return false; + + if (!curbuf_locked()) { + return false; + } + + if (oap != NULL) { + clearop(oap); + } + return true; } /// Normal state entry point. This is called on: @@ -1107,8 +1129,7 @@ static int normal_execute(VimState *state, int key) goto finish; } - if ((nv_cmds[s->idx].cmd_flags & NV_NCW) - && (check_text_locked(&s->oa) || curbuf_locked())) { + if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && check_text_or_curbuf_locked(&s->oa)) { // this command is not allowed now s->command_finished = true; goto finish; @@ -1505,8 +1526,7 @@ void restore_visual_mode(void) /// @param dir the direction of searching, is either FORWARD or BACKWARD /// @param *colp is in/decremented if "ptr[-dir]" should also be included. /// @param bnp points to a counter for square brackets. -static bool find_is_eval_item(const char_u *const ptr, int *const colp, int *const bnp, - const int dir) +static bool find_is_eval_item(const char *const ptr, int *const colp, int *const bnp, const int dir) { // Accept everything inside []. if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) { @@ -1614,7 +1634,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text || (find_type & FIND_IDENT)) && (!(find_type & FIND_EVAL) || prevcol == 0 - || !find_is_eval_item((char_u *)ptr + prevcol, &prevcol, &bn, BACKWARD))) { + || !find_is_eval_item(ptr + prevcol, &prevcol, &bn, BACKWARD))) { break; } col = prevcol; @@ -1657,7 +1677,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text : mb_get_class(ptr + col) != 0) || ((find_type & FIND_EVAL) && col <= (int)startcol - && find_is_eval_item((char_u *)ptr + col, &col, &bn, FORWARD)))) { + && find_is_eval_item(ptr + col, &col, &bn, FORWARD)))) { col += utfc_ptr2len(ptr + col); } @@ -1906,7 +1926,7 @@ bool add_to_showcmd(int c) } } - char *p = (char *)transchar(c); + char *p = transchar(c); if (*p == ' ') { STRCPY(p, "<20>"); } @@ -2191,17 +2211,19 @@ static void nv_addsub(cmdarg_T *cap) /// CTRL-F, CTRL-B, etc: Scroll page up or down. static void nv_page(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - if (mod_mask & MOD_MASK_CTRL) { - // <C-PageUp>: tab page back; <C-PageDown>: tab page forward - if (cap->arg == BACKWARD) { - goto_tabpage(-(int)cap->count1); - } else { - goto_tabpage((int)cap->count0); - } + if (checkclearop(cap->oap)) { + return; + } + + if (mod_mask & MOD_MASK_CTRL) { + // <C-PageUp>: tab page back; <C-PageDown>: tab page forward + if (cap->arg == BACKWARD) { + goto_tabpage(-(int)cap->count1); } else { - (void)onepage(cap->arg, cap->count1); + goto_tabpage((int)cap->count0); } + } else { + (void)onepage(cap->arg, cap->count1); } } @@ -2213,22 +2235,23 @@ static void nv_gd(oparg_T *oap, int nchar, int thisblock) size_t len; char *ptr; if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 - || !find_decl((char_u *)ptr, len, nchar == 'd', thisblock, SEARCH_START)) { + || !find_decl(ptr, len, nchar == 'd', thisblock, SEARCH_START)) { clearopbeep(oap); - } else { - if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP) { - foldOpenCursor(); - } - // clear any search statistics - if (messaging() && !msg_silent && !shortmess(SHM_SEARCHCOUNT)) { - clear_cmdline = true; - } + return; + } + + if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP) { + foldOpenCursor(); + } + // clear any search statistics + if (messaging() && !msg_silent && !shortmess(SHM_SEARCHCOUNT)) { + clear_cmdline = true; } } /// @return true if line[offset] is not inside a C-style comment or string, /// false otherwise. -static bool is_ident(const char_u *line, int offset) +static bool is_ident(const char *line, int offset) { bool incomment = false; int instring = 0; @@ -2236,11 +2259,11 @@ static bool is_ident(const char_u *line, int offset) for (int i = 0; i < offset && line[i] != NUL; i++) { if (instring != 0) { - if (prev != '\\' && line[i] == instring) { + if (prev != '\\' && (uint8_t)line[i] == instring) { instring = 0; } } else if ((line[i] == '"' || line[i] == '\'') && !incomment) { - instring = line[i]; + instring = (uint8_t)line[i]; } else { if (incomment) { if (prev == '*' && line[i] == '/') { @@ -2253,7 +2276,7 @@ static bool is_ident(const char_u *line, int offset) } } - prev = line[i]; + prev = (uint8_t)line[i]; } return incomment == false && instring == 0; @@ -2267,7 +2290,7 @@ static bool is_ident(const char_u *line, int offset) /// @param flags_arg flags passed to searchit() /// /// @return fail when not found. -bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_arg) +bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_arg) { char *pat; pos_T old_pos; @@ -2285,7 +2308,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ // Put "\V" before the pattern to avoid that the special meaning of "." // and "~" causes trouble. assert(len <= INT_MAX); - sprintf(pat, vim_iswordp((char *)ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", // NOLINT(runtime/printf) + sprintf(pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", // NOLINT(runtime/printf) (int)len, ptr); old_pos = curwin->w_cursor; save_p_ws = p_ws; @@ -2313,7 +2336,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ clearpos(&found_pos); for (;;) { t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD, - (char_u *)pat, 1L, searchflags, RE_LAST, NULL); + pat, 1L, searchflags, RE_LAST, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) { t = false; // match after start is failure too } @@ -2346,7 +2369,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ curwin->w_cursor.col = 0; continue; } - bool valid = is_ident((char_u *)get_cursor_line_ptr(), curwin->w_cursor.col); + bool valid = is_ident(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. @@ -2527,7 +2550,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) validate_virtcol(); colnr_T virtcol = curwin->w_virtcol; if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) { - virtcol -= vim_strsize((char *)get_showbreak_value(curwin)); + virtcol -= vim_strsize(get_showbreak_value(curwin)); } int c = utf_ptr2char(get_cursor_pos_ptr()); @@ -3195,44 +3218,45 @@ static void nv_colon(cmdarg_T *cap) if (VIsual_active && !is_cmdkey && !is_lua) { nv_operator(cap); - } else { - if (cap->oap->op_type != OP_NOP) { - // Using ":" as a movement is charwise exclusive. - cap->oap->motion_type = kMTCharWise; - cap->oap->inclusive = false; - } else if (cap->count0 && !is_cmdkey && !is_lua) { - // translate "count:" into ":.,.+(count - 1)" - stuffcharReadbuff('.'); - if (cap->count0 > 1) { - stuffReadbuff(",.+"); - stuffnumReadbuff(cap->count0 - 1L); - } - } + return; + } - // When typing, don't type below an old message - if (KeyTyped) { - compute_cmdrow(); + if (cap->oap->op_type != OP_NOP) { + // Using ":" as a movement is charwise exclusive. + cap->oap->motion_type = kMTCharWise; + cap->oap->inclusive = false; + } else if (cap->count0 && !is_cmdkey && !is_lua) { + // translate "count:" into ":.,.+(count - 1)" + stuffcharReadbuff('.'); + if (cap->count0 > 1) { + stuffReadbuff(",.+"); + stuffnumReadbuff(cap->count0 - 1L); } + } - if (is_lua) { - cmd_result = map_execute_lua(); - } else { - // get a command line and execute it - cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, - cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); - } + // When typing, don't type below an old message + if (KeyTyped) { + compute_cmdrow(); + } - if (cmd_result == false) { - // The Ex command failed, do not execute the operator. - clearop(cap->oap); - } 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)) - || did_emsg)) { - // The start of the operator has become invalid by the Ex command. - clearopbeep(cap->oap); - } + if (is_lua) { + cmd_result = map_execute_lua(); + } else { + // get a command line and execute it + cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, + cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); + } + + if (cmd_result == false) { + // The Ex command failed, do not execute the operator. + clearop(cap->oap); + } 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)) + || did_emsg)) { + // The start of the operator has become invalid by the Ex command. + clearopbeep(cap->oap); } } @@ -3263,14 +3287,16 @@ static void nv_ctrlh(cmdarg_T *cap) /// CTRL-L: clear screen and redraw. static void nv_clear(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - // Clear all syntax states to force resyncing. - syn_stack_free_all(curwin->w_s); - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - wp->w_s->b_syn_slow = false; - } - redraw_later(curwin, UPD_CLEAR); + if (checkclearop(cap->oap)) { + return; + } + + // Clear all syntax states to force resyncing. + syn_stack_free_all(curwin->w_s); + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + wp->w_s->b_syn_slow = false; } + redraw_later(curwin, UPD_CLEAR); } /// CTRL-O: In Select mode: switch to Visual mode for one command. @@ -3301,21 +3327,23 @@ static void nv_hat(cmdarg_T *cap) /// "Z" commands. static void nv_Zet(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - switch (cap->nchar) { - // "ZZ": equivalent to ":x". - case 'Z': - do_cmdline_cmd("x"); - break; + if (checkclearopq(cap->oap)) { + return; + } - // "ZQ": equivalent to ":q!" (Elvis compatible). - case 'Q': - do_cmdline_cmd("q!"); - break; + switch (cap->nchar) { + // "ZZ": equivalent to ":x". + case 'Z': + do_cmdline_cmd("x"); + break; - default: - clearopbeep(cap->oap); - } + // "ZQ": equivalent to ":q!" (Elvis compatible). + case 'Q': + do_cmdline_cmd("q!"); + break; + + default: + clearopbeep(cap->oap); } } @@ -3446,7 +3474,7 @@ 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 *kp = *curbuf->b_p_kp == NUL ? (char *)p_kp : curbuf->b_p_kp; // 'keywordprg' + char *kp = *curbuf->b_p_kp == NUL ? 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 @@ -3532,7 +3560,7 @@ static void nv_ident(cmdarg_T *cap) p = buf + strlen(buf); while (n-- > 0) { // put a backslash before \ and some others - if (vim_strchr(aux_ptr, *ptr) != NULL) { + if (vim_strchr(aux_ptr, (uint8_t)(*ptr)) != NULL) { *p++ = '\\'; } // When current byte is a part of multibyte character, copy all @@ -3846,13 +3874,14 @@ static void nv_up(cmdarg_T *cap) // <S-Up> is page up cap->arg = BACKWARD; nv_page(cap); - } else { - cap->oap->motion_type = kMTLineWise; - if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) { - clearopbeep(cap->oap); - } else if (cap->arg) { - beginline(BL_WHITE | BL_FIX); - } + return; + } + + cap->oap->motion_type = kMTLineWise; + if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) { + clearopbeep(cap->oap); + } else if (cap->arg) { + beginline(BL_WHITE | BL_FIX); } } @@ -3895,15 +3924,11 @@ static void nv_gotofile(cmdarg_T *cap) char *ptr; linenr_T lnum = -1; - if (check_text_locked(cap->oap)) { - return; - } - if (curbuf_locked()) { - clearop(cap->oap); + if (check_text_or_curbuf_locked(cap->oap)) { return; } - ptr = (char *)grab_file_name(cap->count1, &lnum); + ptr = grab_file_name(cap->count1, &lnum); if (ptr != NULL) { // do autowrite if necessary @@ -3972,7 +3997,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 = (char *)getcmdline(cap->cmdchar, cap->count1, 0, true); + cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, true); if (cap->searchbuf == NULL) { clearop(oap); @@ -4058,22 +4083,23 @@ static void nv_csearch(cmdarg_T *cap) cap->oap->motion_type = kMTCharWise; if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) { clearopbeep(cap->oap); - } else { - curwin->w_set_curswant = true; - // Include a Tab for "tx" and for "dfx". - if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD - && (t_cmd || cap->oap->op_type != OP_NOP)) { - colnr_T scol, ecol; + return; + } - getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); - curwin->w_cursor.coladd = ecol - scol; - } else { - curwin->w_cursor.coladd = 0; - } - adjust_for_sel(cap); - if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + curwin->w_set_curswant = true; + // Include a Tab for "tx" and for "dfx". + if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD + && (t_cmd || cap->oap->op_type != OP_NOP)) { + colnr_T scol, ecol; + + getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); + curwin->w_cursor.coladd = ecol - scol; + } else { + curwin->w_cursor.coladd = 0; + } + adjust_for_sel(cap); + if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } @@ -4395,25 +4421,28 @@ static void nv_brace(cmdarg_T *cap) cap->oap->inclusive = false; curwin->w_set_curswant = true; - if (findsent(cap->arg, cap->count1) == false) { + if (findsent(cap->arg, cap->count1) == FAIL) { clearopbeep(cap->oap); - } else { - // Don't leave the cursor on the NUL past end of line. - adjust_cursor(cap->oap); - curwin->w_cursor.coladd = 0; - if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + return; + } + + // Don't leave the cursor on the NUL past end of line. + adjust_cursor(cap->oap); + curwin->w_cursor.coladd = 0; + if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } /// "m" command: Mark a position. static void nv_mark(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - if (setmark(cap->nchar) == false) { - clearopbeep(cap->oap); - } + if (checkclearop(cap->oap)) { + return; + } + + if (setmark(cap->nchar) == false) { + clearopbeep(cap->oap); } } @@ -4427,11 +4456,12 @@ static void nv_findpar(cmdarg_T *cap) curwin->w_set_curswant = true; if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, false)) { clearopbeep(cap->oap); - } else { - curwin->w_cursor.coladd = 0; - if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + return; + } + + curwin->w_cursor.coladd = 0; + if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } @@ -4452,14 +4482,16 @@ static void nv_undo(cmdarg_T *cap) /// <Undo> command. static void nv_kundo(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - if (bt_prompt(curbuf)) { - clearopbeep(cap->oap); - return; - } - u_undo((int)cap->count1); - curwin->w_set_curswant = true; + if (checkclearopq(cap->oap)) { + return; } + + if (bt_prompt(curbuf)) { + clearopbeep(cap->oap); + return; + } + u_undo((int)cap->count1); + curwin->w_set_curswant = true; } /// Handle the "r" command. @@ -4670,15 +4702,20 @@ static void nv_Replace(cmdarg_T *cap) VIsual_mode_orig = VIsual_mode; // remember original area for gv VIsual_mode = 'V'; nv_operator(cap); - } else if (!checkclearopq(cap->oap)) { - if (!MODIFIABLE(curbuf)) { - emsg(_(e_modifiable)); - } else { - if (virtual_active()) { - coladvance(getviscol()); - } - invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); + return; + } + + if (checkclearopq(cap->oap)) { + return; + } + + if (!MODIFIABLE(curbuf)) { + emsg(_(e_modifiable)); + } else { + if (virtual_active()) { + coladvance(getviscol()); } + invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); } } @@ -4689,20 +4726,25 @@ static void nv_vreplace(cmdarg_T *cap) cap->cmdchar = 'r'; cap->nchar = cap->extra_char; nv_replace(cap); // Do same as "r" in Visual mode for now - } else if (!checkclearopq(cap->oap)) { - if (!MODIFIABLE(curbuf)) { - emsg(_(e_modifiable)); - } else { - if (cap->extra_char == Ctrl_V) { // get another character - cap->extra_char = get_literal(false); - } - stuffcharReadbuff(cap->extra_char); - stuffcharReadbuff(ESC); - if (virtual_active()) { - coladvance(getviscol()); - } - invoke_edit(cap, true, 'v', false); + return; + } + + if (checkclearopq(cap->oap)) { + return; + } + + if (!MODIFIABLE(curbuf)) { + emsg(_(e_modifiable)); + } else { + if (cap->extra_char == Ctrl_V) { // get another character + cap->extra_char = get_literal(false); + } + stuffcharReadbuff(cap->extra_char); + stuffcharReadbuff(ESC); + if (virtual_active()) { + coladvance(getviscol()); } + invoke_edit(cap, true, 'v', false); } } @@ -4903,42 +4945,44 @@ static void nv_pcmark(cmdarg_T *cap) MarkMoveRes move_res = 0; // Result from moving to the mark const bool old_KeyTyped = KeyTyped; // getting file may reset it. - if (!checkclearopq(cap->oap)) { - if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) { - if (!goto_tabpage_lastused()) { - clearopbeep(cap->oap); - } - return; - } + if (checkclearopq(cap->oap)) { + return; + } - if (cap->cmdchar == 'g') { - fm = get_changelist(curbuf, curwin, (int)cap->count1); - } else { - fm = get_jumplist(curwin, (int)cap->count1); - flags |= KMarkNoContext | kMarkJumpList; - } - // Changelist and jumplist have their own error messages. Therefore avoid - // calling nv_mark_move_to() when not found to avoid incorrect error - // messages. - if (fm != NULL) { - move_res = nv_mark_move_to(cap, flags, fm); - } else if (cap->cmdchar == 'g') { - if (curbuf->b_changelistlen == 0) { - emsg(_("E664: changelist is empty")); - } else if (cap->count1 < 0) { - emsg(_("E662: At start of changelist")); - } else { - emsg(_("E663: At end of changelist")); - } - } else { + if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) { + if (!goto_tabpage_lastused()) { clearopbeep(cap->oap); } - if (cap->oap->op_type == OP_NOP - && (move_res & kMarkSwitchedBuf || move_res & kMarkChangedLine) - && (fdo_flags & FDO_MARK) - && old_KeyTyped) { - foldOpenCursor(); + return; + } + + if (cap->cmdchar == 'g') { + fm = get_changelist(curbuf, curwin, (int)cap->count1); + } else { + fm = get_jumplist(curwin, (int)cap->count1); + flags |= KMarkNoContext | kMarkJumpList; + } + // Changelist and jumplist have their own error messages. Therefore avoid + // calling nv_mark_move_to() when not found to avoid incorrect error + // messages. + if (fm != NULL) { + move_res = nv_mark_move_to(cap, flags, fm); + } else if (cap->cmdchar == 'g') { + if (curbuf->b_changelistlen == 0) { + emsg(_("E664: changelist is empty")); + } else if (cap->count1 < 0) { + emsg(_("E662: At start of changelist")); + } else { + emsg(_("E663: At end of changelist")); } + } else { + clearopbeep(cap->oap); + } + if (cap->oap->op_type == OP_NOP + && (move_res & kMarkSwitchedBuf || move_res & kMarkChangedLine) + && (fdo_flags & FDO_MARK) + && old_KeyTyped) { + foldOpenCursor(); } } @@ -5028,9 +5072,13 @@ static void nv_visual(cmdarg_T *cap) curwin->w_curswant = MAXCOL; coladvance(MAXCOL); } else if (VIsual_mode == Ctrl_V) { + // Update curswant on the original line, that is where "col" is valid. + linenr_T lnum = curwin->w_cursor.lnum; + curwin->w_cursor.lnum = VIsual.lnum; update_curswant_force(); assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); curwin->w_curswant += resel_VIsual_vcol * (int)cap->count0 - 1; + curwin->w_cursor.lnum = lnum; coladvance(curwin->w_curswant); } else { curwin->w_set_curswant = true; @@ -5669,42 +5717,46 @@ static void nv_g_cmd(cmdarg_T *cap) /// Handle "o" and "O" commands. static void n_opencmd(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - if (cap->cmdchar == 'O') { - // Open above the first line of a folded sequence of lines - (void)hasFolding(curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); - } else { - // Open below the last line of a folded sequence of lines - (void)hasFolding(curwin->w_cursor.lnum, - NULL, &curwin->w_cursor.lnum); - } - if (u_save((linenr_T)(curwin->w_cursor.lnum - - (cap->cmdchar == 'O' ? 1 : 0)), - (linenr_T)(curwin->w_cursor.lnum + - (cap->cmdchar == 'o' ? 1 : 0))) - && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, - has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0, - 0, NULL)) { - if (win_cursorline_standout(curwin)) { - // force redraw of cursorline - curwin->w_valid &= ~VALID_CROW; - } - invoke_edit(cap, false, cap->cmdchar, true); + if (checkclearopq(cap->oap)) { + return; + } + + if (cap->cmdchar == 'O') { + // Open above the first line of a folded sequence of lines + (void)hasFolding(curwin->w_cursor.lnum, + &curwin->w_cursor.lnum, NULL); + } else { + // Open below the last line of a folded sequence of lines + (void)hasFolding(curwin->w_cursor.lnum, + NULL, &curwin->w_cursor.lnum); + } + if (u_save((linenr_T)(curwin->w_cursor.lnum - + (cap->cmdchar == 'O' ? 1 : 0)), + (linenr_T)(curwin->w_cursor.lnum + + (cap->cmdchar == 'o' ? 1 : 0))) + && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, + has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0, + 0, NULL)) { + if (win_cursorline_standout(curwin)) { + // force redraw of cursorline + curwin->w_valid &= ~VALID_CROW; } + invoke_edit(cap, false, cap->cmdchar, true); } } /// "." command: redo last change. static void nv_dot(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - // If "restart_edit" is true, the last but one command is repeated - // instead of the last command (inserting text). This is used for - // CTRL-O <.> in insert mode. - if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false) { - clearopbeep(cap->oap); - } + if (checkclearopq(cap->oap)) { + return; + } + + // If "restart_edit" is true, the last but one command is repeated + // instead of the last command (inserting text). This is used for + // CTRL-O <.> in insert mode. + if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false) { + clearopbeep(cap->oap); } } @@ -5728,10 +5780,12 @@ static void nv_redo_or_register(cmdarg_T *cap) return; } - if (!checkclearopq(cap->oap)) { - u_redo((int)cap->count1); - curwin->w_set_curswant = true; + if (checkclearopq(cap->oap)) { + return; } + + u_redo((int)cap->count1); + curwin->w_set_curswant = true; } /// Handle "U" command. @@ -5743,10 +5797,15 @@ static void nv_Undo(cmdarg_T *cap) cap->cmdchar = 'g'; cap->nchar = 'U'; nv_operator(cap); - } else if (!checkclearopq(cap->oap)) { - u_undoline(); - curwin->w_set_curswant = true; + return; } + + if (checkclearopq(cap->oap)) { + return; + } + + u_undoline(); + curwin->w_set_curswant = true; } /// '~' command: If tilde is not an operator and Visual is off: swap case of a @@ -6309,16 +6368,21 @@ static void nv_record(cmdarg_T *cap) cap->cmdchar = 'g'; cap->nchar = 'q'; nv_operator(cap); - } else if (!checkclearop(cap->oap)) { - if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') { - stuffcharReadbuff(cap->nchar); - stuffcharReadbuff(K_CMDWIN); - } else { - // (stop) recording into a named register, unless executing a - // register. - if (reg_executing == 0 && do_record(cap->nchar) == FAIL) { - clearopbeep(cap->oap); - } + return; + } + + if (checkclearop(cap->oap)) { + return; + } + + if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') { + stuffcharReadbuff(cap->nchar); + stuffcharReadbuff(K_CMDWIN); + } else { + // (stop) recording into a named register, unless executing a + // register. + if (reg_executing == 0 && do_record(cap->nchar) == FAIL) { + clearopbeep(cap->oap); } } } @@ -6360,24 +6424,29 @@ static void nv_join(cmdarg_T *cap) { if (VIsual_active) { // join the visual lines nv_operator(cap); - } else if (!checkclearop(cap->oap)) { - if (cap->count0 <= 1) { - cap->count0 = 2; // default for join is two lines! - } - if (curwin->w_cursor.lnum + cap->count0 - 1 > - curbuf->b_ml.ml_line_count) { - // can't join when on the last line - if (cap->count0 <= 2) { - clearopbeep(cap->oap); - return; - } - cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1; - } + return; + } - prep_redo(cap->oap->regname, cap->count0, - NUL, cap->cmdchar, NUL, NUL, cap->nchar); - do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true); + if (checkclearop(cap->oap)) { + return; } + + if (cap->count0 <= 1) { + cap->count0 = 2; // default for join is two lines! + } + if (curwin->w_cursor.lnum + cap->count0 - 1 > + curbuf->b_ml.ml_line_count) { + // can't join when on the last line + if (cap->count0 <= 2) { + clearopbeep(cap->oap); + return; + } + cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1; + } + + prep_redo(cap->oap->regname, cap->count0, + NUL, cap->cmdchar, NUL, NUL, cap->nchar); + do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true); } /// "P", "gP", "p" and "gp" commands. @@ -6407,117 +6476,121 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) } else { clearopbeep(cap->oap); } - } else if (bt_prompt(curbuf) && !prompt_curpos_editable()) { - clearopbeep(cap->oap); - } else { - if (fix_indent) { - dir = (cap->cmdchar == ']' && cap->nchar == 'p') - ? FORWARD : BACKWARD; - flags |= PUT_FIXINDENT; - } else { - dir = (cap->cmdchar == 'P' - || ((cap->cmdchar == 'g' || cap->cmdchar == 'z') - && cap->nchar == 'P')) ? BACKWARD : FORWARD; - } - prep_redo_cmd(cap); - if (cap->cmdchar == 'g') { - flags |= PUT_CURSEND; - } else if (cap->cmdchar == 'z') { - flags |= PUT_BLOCK_INNER; - } + return; + } - if (VIsual_active) { - // Putting in Visual mode: The put text replaces the selected - // text. First delete the selected text, then put the new text. - // Need to save and restore the registers that the delete - // overwrites if the old contents is being put. - was_visual = true; - regname = cap->oap->regname; - bool keep_registers = cap->cmdchar == 'P'; - // '+' and '*' could be the same selection - bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); - if (regname == 0 || regname == '"' || clipoverwrite - || ascii_isdigit(regname) || regname == '-') { - // The delete might overwrite the register we want to put, save it first - savereg = copy_register(regname); - } + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } - // To place the cursor correctly after a blockwise put, and to leave the - // text in the correct position when putting over a selection with - // 'virtualedit' and past the end of the line, we use the 'c' operator in - // do_put(), which requires the visual selection to still be active. - if (!VIsual_active || VIsual_mode == 'V' || regname != '.') { - // Now delete the selected text. Avoid messages here. - cap->cmdchar = 'd'; - cap->nchar = NUL; - cap->oap->regname = keep_registers ? '_' : NUL; - msg_silent++; - nv_operator(cap); - do_pending_operator(cap, 0, false); - empty = (curbuf->b_ml.ml_flags & ML_EMPTY); - msg_silent--; + if (fix_indent) { + dir = (cap->cmdchar == ']' && cap->nchar == 'p') + ? FORWARD : BACKWARD; + flags |= PUT_FIXINDENT; + } else { + dir = (cap->cmdchar == 'P' + || ((cap->cmdchar == 'g' || cap->cmdchar == 'z') + && cap->nchar == 'P')) ? BACKWARD : FORWARD; + } + prep_redo_cmd(cap); + if (cap->cmdchar == 'g') { + flags |= PUT_CURSEND; + } else if (cap->cmdchar == 'z') { + flags |= PUT_BLOCK_INNER; + } - // delete PUT_LINE_BACKWARD; - cap->oap->regname = regname; - } + if (VIsual_active) { + // Putting in Visual mode: The put text replaces the selected + // text. First delete the selected text, then put the new text. + // Need to save and restore the registers that the delete + // overwrites if the old contents is being put. + was_visual = true; + regname = cap->oap->regname; + bool keep_registers = cap->cmdchar == 'P'; + // '+' and '*' could be the same selection + bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); + if (regname == 0 || regname == '"' || clipoverwrite + || ascii_isdigit(regname) || regname == '-') { + // The delete might overwrite the register we want to put, save it first + savereg = copy_register(regname); + } + + // To place the cursor correctly after a blockwise put, and to leave the + // text in the correct position when putting over a selection with + // 'virtualedit' and past the end of the line, we use the 'c' operator in + // do_put(), which requires the visual selection to still be active. + if (!VIsual_active || VIsual_mode == 'V' || regname != '.') { + // Now delete the selected text. Avoid messages here. + cap->cmdchar = 'd'; + cap->nchar = NUL; + cap->oap->regname = keep_registers ? '_' : NUL; + msg_silent++; + nv_operator(cap); + do_pending_operator(cap, 0, false); + empty = (curbuf->b_ml.ml_flags & ML_EMPTY); + msg_silent--; - // When deleted a linewise Visual area, put the register as - // lines to avoid it joined with the next line. When deletion was - // charwise, split a line when putting lines. - if (VIsual_mode == 'V') { - flags |= PUT_LINE; - } else if (VIsual_mode == 'v') { - flags |= PUT_LINE_SPLIT; - } - if (VIsual_mode == Ctrl_V && dir == FORWARD) { - flags |= PUT_LINE_FORWARD; - } - dir = BACKWARD; - if ((VIsual_mode != 'V' - && curwin->w_cursor.col < curbuf->b_op_start.col) - || (VIsual_mode == 'V' - && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) { - // cursor is at the end of the line or end of file, put - // forward. - dir = FORWARD; - } - // May have been reset in do_put(). - VIsual_active = true; + // delete PUT_LINE_BACKWARD; + cap->oap->regname = regname; } - do_put(cap->oap->regname, savereg, dir, cap->count1, flags); - // If a register was saved, free it - if (savereg != NULL) { - free_register(savereg); - xfree(savereg); + // When deleted a linewise Visual area, put the register as + // lines to avoid it joined with the next line. When deletion was + // charwise, split a line when putting lines. + if (VIsual_mode == 'V') { + flags |= PUT_LINE; + } else if (VIsual_mode == 'v') { + flags |= PUT_LINE_SPLIT; + } + if (VIsual_mode == Ctrl_V && dir == FORWARD) { + flags |= PUT_LINE_FORWARD; + } + dir = BACKWARD; + if ((VIsual_mode != 'V' + && curwin->w_cursor.col < curbuf->b_op_start.col) + || (VIsual_mode == 'V' + && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) { + // cursor is at the end of the line or end of file, put + // forward. + dir = FORWARD; } + // May have been reset in do_put(). + VIsual_active = true; + } + do_put(cap->oap->regname, savereg, dir, cap->count1, flags); - // What to reselect with "gv"? Selecting the just put text seems to - // be the most useful, since the original text was removed. - if (was_visual) { - curbuf->b_visual.vi_start = curbuf->b_op_start; - curbuf->b_visual.vi_end = curbuf->b_op_end; - // need to adjust cursor position - if (*p_sel == 'e') { - inc(&curbuf->b_visual.vi_end); - } + // If a register was saved, free it + if (savereg != NULL) { + free_register(savereg); + xfree(savereg); + } + + // What to reselect with "gv"? Selecting the just put text seems to + // be the most useful, since the original text was removed. + if (was_visual) { + curbuf->b_visual.vi_start = curbuf->b_op_start; + curbuf->b_visual.vi_end = curbuf->b_op_end; + // need to adjust cursor position + if (*p_sel == 'e') { + inc(&curbuf->b_visual.vi_end); } + } - // When all lines were selected and deleted do_put() leaves an empty - // line that needs to be deleted now. - if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) { - ml_delete(curbuf->b_ml.ml_line_count, true); - deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); + // When all lines were selected and deleted do_put() leaves an empty + // line that needs to be deleted now. + if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) { + ml_delete(curbuf->b_ml.ml_line_count, true); + deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); - // If the cursor was in that line, move it to the end of the last - // line. - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); - } + // If the cursor was in that line, move it to the end of the last + // line. + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance(MAXCOL); } - auto_format(false, true); } + auto_format(false, true); } /// "o" and "O" commands. diff --git a/src/nvim/normal.h b/src/nvim/normal.h index 90a5c4103e..bed1a40b97 100644 --- a/src/nvim/normal.h +++ b/src/nvim/normal.h @@ -4,6 +4,7 @@ #include <stdbool.h> #include "nvim/buffer_defs.h" +#include "nvim/macros.h" #include "nvim/pos.h" // Values for find_ident_under_cursor() diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 34432c58db..435ca106ab 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -723,7 +723,7 @@ int get_expr_register(void) { char *new_line; - new_line = (char *)getcmdline('=', 0L, 0, true); + new_line = getcmdline('=', 0L, 0, true); if (new_line == NULL) { return NUL; } @@ -1006,7 +1006,7 @@ static int stuff_yank(int regname, char *p) } else { free_register(reg); set_yreg_additional_data(reg, NULL); - reg->y_array = xmalloc(sizeof(char_u *)); + reg->y_array = xmalloc(sizeof(char *)); reg->y_array[0] = p; reg->y_size = 1; reg->y_type = kMTCharWise; @@ -1028,14 +1028,14 @@ static int execreg_lastc = NUL; /// with a \. Lines that start with a comment "\ character are ignored. /// @returns the concatenated line. The index of the line that should be /// processed next is returned in idx. -static char_u *execreg_line_continuation(char **lines, size_t *idx) +static char *execreg_line_continuation(char **lines, size_t *idx) { size_t i = *idx; assert(i > 0); const size_t cmd_end = i; garray_T ga; - ga_init(&ga, (int)sizeof(char_u), 400); + ga_init(&ga, (int)sizeof(char), 400); char *p; @@ -1068,7 +1068,7 @@ static char_u *execreg_line_continuation(char **lines, size_t *idx) ga_clear(&ga); *idx = i; - return (char_u *)str; + return str; } /// Execute a yank register: copy it into the stuff buffer @@ -1118,9 +1118,9 @@ int do_execreg(int regname, int colon, int addcr, int silent) // When in Visual mode "'<,'>" will be prepended to the command. // Remove it when it's already there. if (VIsual_active && strncmp(p, "'<,'>", 5) == 0) { - retval = put_in_typebuf((char_u *)p + 5, true, true, silent); + retval = put_in_typebuf(p + 5, true, true, silent); } else { - retval = put_in_typebuf((char_u *)p, true, true, silent); + retval = put_in_typebuf(p, true, true, silent); } xfree(p); } else if (regname == '=') { @@ -1128,15 +1128,15 @@ int do_execreg(int regname, int colon, int addcr, int silent) if (p == NULL) { return FAIL; } - retval = put_in_typebuf((char_u *)p, true, colon, silent); + retval = put_in_typebuf(p, true, colon, silent); xfree(p); } else if (regname == '.') { // use last inserted text - p = (char *)get_last_insert_save(); + p = get_last_insert_save(); if (p == NULL) { emsg(_(e_noinstext)); return FAIL; } - retval = put_in_typebuf((char_u *)p, false, colon, silent); + retval = put_in_typebuf(p, false, colon, silent); xfree(p); } else { yankreg_T *reg = get_yank_register(regname, YREG_PASTE); @@ -1164,7 +1164,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) if (colon && i > 0) { p = skipwhite(str); if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')) { - str = (char *)execreg_line_continuation(reg->y_array, &i); + str = execreg_line_continuation(reg->y_array, &i); free_str = true; } } @@ -1193,18 +1193,20 @@ static void put_reedit_in_typebuf(int silent) { char_u buf[3]; - if (restart_edit != NUL) { - if (restart_edit == 'V') { - buf[0] = 'g'; - buf[1] = 'R'; - buf[2] = NUL; - } else { - buf[0] = (char_u)(restart_edit == 'I' ? 'i' : restart_edit); - buf[1] = NUL; - } - if (ins_typebuf((char *)buf, REMAP_NONE, 0, true, silent) == OK) { - restart_edit = NUL; - } + if (restart_edit == NUL) { + return; + } + + if (restart_edit == 'V') { + buf[0] = 'g'; + buf[1] = 'R'; + buf[2] = NUL; + } else { + buf[0] = (char_u)(restart_edit == 'I' ? 'i' : restart_edit); + buf[1] = NUL; + } + if (ins_typebuf((char *)buf, REMAP_NONE, 0, true, silent) == OK) { + restart_edit = NUL; } } @@ -1214,7 +1216,7 @@ static void put_reedit_in_typebuf(int silent) /// @param esc when true then it is to be taken literally: Escape K_SPECIAL /// characters and no remapping. /// @param colon add ':' before the line -static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent) +static int put_in_typebuf(char *s, bool esc, bool colon, int silent) { int retval = OK; @@ -1226,9 +1228,9 @@ static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent) char *p; if (esc) { - p = vim_strsave_escape_ks((char *)s); + p = vim_strsave_escape_ks(s); } else { - p = (char *)s; + p = s; } if (p == NULL) { retval = FAIL; @@ -1347,11 +1349,11 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) if (last_search_pat() == NULL && errmsg) { emsg(_(e_noprevre)); } - *argp = (char *)last_search_pat(); + *argp = last_search_pat(); return true; case '.': // last inserted text - *argp = (char *)get_last_insert_save(); + *argp = get_last_insert_save(); *allocated = true; if (*argp == NULL && errmsg) { emsg(_(e_noinstext)); @@ -1363,9 +1365,8 @@ bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg) if (!errmsg) { return false; } - *argp - = (char *)file_name_at_cursor(FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0), - 1L, NULL); + *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0), + 1L, NULL); *allocated = true; return true; @@ -1418,11 +1419,11 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) } for (size_t i = 0; i < reg->y_size; i++) { - cmdline_paste_str((char_u *)reg->y_array[i], literally); + cmdline_paste_str(reg->y_array[i], literally); // Insert ^M between lines, unless `remcr` is true. if (i < reg->y_size - 1 && !remcr) { - cmdline_paste_str((char_u *)"\r", literally); + cmdline_paste_str("\r", literally); } // Check for CTRL-C, in case someone tries to paste a few thousand @@ -1455,7 +1456,7 @@ int op_delete(oparg_T *oap) { int n; linenr_T lnum; - char_u *ptr; + char *ptr; char *newp, *oldp; struct block_def bd = { 0 }; linenr_T old_lcount = curbuf->b_ml.ml_line_count; @@ -1489,11 +1490,11 @@ int op_delete(oparg_T *oap) && oap->line_count > 1 && oap->motion_force == NUL && oap->op_type == OP_DELETE) { - ptr = (char_u *)ml_get(oap->end.lnum) + oap->end.col; + ptr = ml_get(oap->end.lnum) + oap->end.col; if (*ptr != NUL) { ptr += oap->inclusive; } - ptr = (char_u *)skipwhite((char *)ptr); + ptr = skipwhite(ptr); if (*ptr == NUL && inindent(0)) { oap->motion_type = kMTLineWise; } @@ -1785,10 +1786,12 @@ setmarks: /// Used for deletion. static void mb_adjust_opend(oparg_T *oap) { - if (oap->inclusive) { - char *p = ml_get(oap->end.lnum); - oap->end.col += utf_cp_tail_off(p, p + oap->end.col); + if (!oap->inclusive) { + return; } + + char *p = ml_get(oap->end.lnum); + oap->end.col += utf_cp_tail_off(p, p + oap->end.col); } /// Put character 'c' at position 'lp' @@ -2573,12 +2576,14 @@ void free_register(yankreg_T *reg) FUNC_ATTR_NONNULL_ALL { set_yreg_additional_data(reg, NULL); - if (reg->y_array != NULL) { - for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included - xfree(reg->y_array[i]); - } - XFREE_CLEAR(reg->y_array); + if (reg->y_array == NULL) { + return; + } + + for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included + xfree(reg->y_array[i]); } + XFREE_CLEAR(reg->y_array); } /// Yanks the text between "oap->start" and "oap->end" into a yank register. @@ -2738,7 +2743,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) } if (curr != reg) { // append the new block to the old block - new_ptr = xmalloc(sizeof(char_u *) * (curr->y_size + reg->y_size)); + new_ptr = xmalloc(sizeof(char *) * (curr->y_size + reg->y_size)); for (j = 0; j < curr->y_size; j++) { new_ptr[j] = curr->y_array[j]; } @@ -3081,7 +3086,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_array != NULL) { break; } - y_array = xmalloc(y_size * sizeof(char_u *)); + y_array = xmalloc(y_size * sizeof(char *)); } } else { y_size = 1; // use fake one-line yank register @@ -3146,7 +3151,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_size == 0 || y_array == NULL) { semsg(_("E353: Nothing in register %s"), - regname == 0 ? (char_u *)"\"" : transchar(regname)); + regname == 0 ? "\"" : transchar(regname)); goto end; } @@ -3711,20 +3716,23 @@ void adjust_cursor_eol(void) { unsigned int cur_ve_flags = get_ve_flags(); - if (curwin->w_cursor.col > 0 - && gchar_cursor() == NUL - && (cur_ve_flags & VE_ONEMORE) == 0 - && !(restart_edit || (State & MODE_INSERT))) { - // Put the cursor on the last character in the line. - dec_cursor(); + const bool adj_cursor = (curwin->w_cursor.col > 0 + && gchar_cursor() == NUL + && (cur_ve_flags & VE_ONEMORE) == 0 + && !(restart_edit || (State & MODE_INSERT))); + if (!adj_cursor) { + return; + } - if (cur_ve_flags == VE_ALL) { - colnr_T scol, ecol; + // Put the cursor on the last character in the line. + dec_cursor(); - // Coladd is set to the width of the last character. - getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); - curwin->w_cursor.coladd = ecol - scol + 1; - } + if (cur_ve_flags == VE_ALL) { + colnr_T scol, ecol; + + // Coladd is set to the width of the last character. + getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); + curwin->w_cursor.coladd = ecol - scol + 1; } } @@ -3884,9 +3892,9 @@ void ex_display(exarg_T *eap) // display last search pattern if (last_search_pat() != NULL && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int - && !message_filtered((char *)last_search_pat())) { + && !message_filtered(last_search_pat())) { msg_puts("\n c \"/ "); - dis_msg((char *)last_search_pat(), false); + dis_msg(last_search_pat(), false); } // display last used expression @@ -4205,11 +4213,13 @@ static bool reset_lbr(void) /// Restore 'linebreak' and take care of side effects. static void restore_lbr(bool lbr_saved) { - 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 (curwin->w_p_lbr || !lbr_saved) { + return; } + + // changing 'linebreak' may require w_virtcol to be updated + curwin->w_p_lbr = true; + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); } /// prepare a few things for block mode yank/delete/tilde @@ -4468,7 +4478,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) { int col; - char_u *buf1 = NULL; + char *buf1 = NULL; char buf2[NUMBUFLEN]; int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin static bool hexupper = false; // 0xABC @@ -4740,7 +4750,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // When there are many leading zeros it could be very long. // Allocate a bit too much. buf1 = xmalloc((size_t)length + NUMBUFLEN); - ptr = (char *)buf1; + ptr = buf1; if (negative && (!visual || was_positive)) { *ptr++ = '-'; } @@ -4792,7 +4802,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } *ptr = NUL; STRCAT(buf1, buf2); - ins_str((char *)buf1); // insert the new number + ins_str(buf1); // insert the new number endpos = curwin->w_cursor; if (curwin->w_cursor.col) { curwin->w_cursor.col--; @@ -5081,7 +5091,7 @@ void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_app // Special case: '/' search pattern if (name == '/') { - set_last_search_pat((char_u *)str, RE_SEARCH, true, true); + set_last_search_pat(str, RE_SEARCH, true, true); return; } @@ -5171,7 +5181,7 @@ 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 **ss = (char **)str; *ss != NULL; ss++) { newlines++; } } else { @@ -5193,7 +5203,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, } // Grow the register array to hold the pointers to the new lines. - char **pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(char_u *)); + char **pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(char *)); y_ptr->y_array = pp; size_t lnum = y_ptr->y_size; // The current line number. @@ -5212,12 +5222,11 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, } } else { size_t line_len; - for (const char_u *start = (char_u *)str, *end = (char_u *)str + len; + for (const char *start = str, *end = str + len; start < end + extraline; start += line_len + 1, lnum++) { assert(end - start >= 0); - line_len = (size_t)((char_u *)xmemscan(start, '\n', - (size_t)(end - start)) - start); + line_len = (size_t)((char *)xmemscan(start, '\n', (size_t)(end - start)) - start); if (line_len > maxlen) { maxlen = line_len; } @@ -5269,8 +5278,8 @@ void clear_oparg(oparg_T *oap) /// line, stopping if it encounters an end-of-line (NUL byte). In that /// case, eol_size will be added to the character count to account for /// the size of the EOL character. -static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *cc, - varnumber_T limit, int eol_size) +static varnumber_T line_count_info(char *line, varnumber_T *wc, varnumber_T *cc, varnumber_T limit, + int eol_size) { varnumber_T i; varnumber_T words = 0; @@ -5287,7 +5296,7 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *c is_word = 1; } chars++; - i += utfc_ptr2len((char *)line + i); + i += utfc_ptr2len(line + i); } if (is_word) { @@ -5312,8 +5321,8 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *c void cursor_pos_info(dict_T *dict) { char *p; - char_u buf1[50]; - char_u buf2[40]; + char buf1[50]; + char buf2[40]; linenr_T lnum; varnumber_T byte_count = 0; varnumber_T bom_count = 0; @@ -5422,7 +5431,7 @@ void cursor_pos_info(dict_T *dict) break; } if (s != NULL) { - byte_count_cursor += line_count_info((char_u *)s, &word_count_cursor, + byte_count_cursor += line_count_info(s, &word_count_cursor, &char_count_cursor, len, eol_size); if (lnum == curbuf->b_ml.ml_line_count && !curbuf->b_p_eol @@ -5437,14 +5446,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((char_u *)ml_get(lnum), &word_count_cursor, + + line_count_info(ml_get(lnum), &word_count_cursor, &char_count_cursor, (varnumber_T)curwin->w_cursor.col + 1, eol_size); } } // Add to the running totals - byte_count += line_count_info((char_u *)ml_get(lnum), &word_count, &char_count, + byte_count += line_count_info(ml_get(lnum), &word_count, &char_count, (varnumber_T)MAXCOL, eol_size); } @@ -5459,7 +5468,7 @@ void cursor_pos_info(dict_T *dict) getvcols(curwin, &min_pos, &max_pos, &min_pos.col, &max_pos.col); int64_t cols; STRICT_SUB(oparg.end_vcol + 1, oparg.start_vcol, &cols, int64_t); - vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "), + vim_snprintf(buf1, sizeof(buf1), _("%" PRId64 " Cols; "), cols); } else { buf1[0] = NUL; @@ -5490,7 +5499,7 @@ void cursor_pos_info(dict_T *dict) } else { p = get_cursor_line_ptr(); validate_virtcol(); - col_print((char *)buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, + col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); col_print((char *)buf2, sizeof(buf2), (int)strlen(p), linetabsize(p)); @@ -5500,7 +5509,7 @@ void cursor_pos_info(dict_T *dict) _("Col %s of %s; Line %" PRId64 " of %" PRId64 ";" " Word %" PRId64 " of %" PRId64 ";" " Byte %" PRId64 " of %" PRId64 ""), - (char *)buf1, (char *)buf2, + buf1, buf2, (int64_t)curwin->w_cursor.lnum, (int64_t)curbuf->b_ml.ml_line_count, (int64_t)word_count_cursor, (int64_t)word_count, @@ -5511,7 +5520,7 @@ void cursor_pos_info(dict_T *dict) " Word %" PRId64 " of %" PRId64 ";" " Char %" PRId64 " of %" PRId64 ";" " Byte %" PRId64 " of %" PRId64 ""), - (char *)buf1, (char *)buf2, + buf1, buf2, (int64_t)curwin->w_cursor.lnum, (int64_t)curbuf->b_ml.ml_line_count, (int64_t)word_count_cursor, (int64_t)word_count, @@ -5617,10 +5626,11 @@ static void op_colon(oparg_T *oap) static Callback opfunc_cb; /// Process the 'operatorfunc' option value. -/// @return OK or FAIL -int set_operatorfunc_option(void) +void set_operatorfunc_option(char **errmsg) { - return option_set_callback_func(p_opfunc, &opfunc_cb); + if (option_set_callback_func(p_opfunc, &opfunc_cb) == FAIL) { + *errmsg = e_invarg; + } } #if defined(EXITFREE) diff --git a/src/nvim/option.c b/src/nvim/option.c index 02c770e608..387b94533c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -36,6 +36,7 @@ #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" +#include "nvim/cmdexpand.h" #include "nvim/cursor_shape.h" #include "nvim/decoration_provider.h" #include "nvim/diff.h" @@ -81,6 +82,7 @@ #include "nvim/regexp.h" #include "nvim/runtime.h" #include "nvim/screen.h" +#include "nvim/search.h" #include "nvim/sign_defs.h" #include "nvim/spell.h" #include "nvim/spellfile.h" @@ -173,8 +175,6 @@ void set_init_tablocal(void) /// editor state initialized here. Do logging in set_init_2 or later. void set_init_1(bool clean_arg) { - int opt_idx; - langmap_init(); // Find default value for 'shell' option. @@ -202,7 +202,7 @@ void set_init_1(bool clean_arg) static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; #endif garray_T ga; - opt_idx = findoption("backupskip"); + int opt_idx = findoption("backupskip"); ga_init(&ga, 1, 100); for (size_t n = 0; n < ARRAY_SIZE(names); n++) { @@ -251,19 +251,14 @@ void set_init_1(bool clean_arg) } { - char *cdpath; - char *buf; - int i; - int j; - // Initialize the 'cdpath' option's default value. - cdpath = vim_getenv("CDPATH"); + char *cdpath = vim_getenv("CDPATH"); if (cdpath != NULL) { - buf = xmalloc(2 * strlen(cdpath) + 2); + char *buf = xmalloc(2 * strlen(cdpath) + 2); { buf[0] = ','; // start with ",", current dir first - j = 1; - for (i = 0; cdpath[i] != NUL; i++) { + int j = 1; + for (int i = 0; cdpath[i] != NUL; i++) { if (vim_ispathlistsep(cdpath[i])) { buf[j++] = ','; } else { @@ -274,7 +269,7 @@ void set_init_1(bool clean_arg) } } buf[j] = NUL; - opt_idx = findoption("cdpath"); + int opt_idx = findoption("cdpath"); if (opt_idx >= 0) { options[opt_idx].def_val = buf; options[opt_idx].flags |= P_DEF_ALLOCED; @@ -339,25 +334,25 @@ void set_init_1(bool clean_arg) // 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) { + for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_NO_DEF_EXP) { continue; } char *p; - if ((options[opt_idx].flags & P_GETTEXT) - && options[opt_idx].var != NULL) { - p = _(*(char **)options[opt_idx].var); + if ((opt->flags & P_GETTEXT) && opt->var != NULL) { + p = _(*(char **)opt->var); } else { p = option_expand(opt_idx, NULL); } if (p != NULL) { p = xstrdup(p); - *(char **)options[opt_idx].var = p; - if (options[opt_idx].flags & P_DEF_ALLOCED) { - xfree(options[opt_idx].def_val); + *(char **)opt->var = p; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val); } - options[opt_idx].def_val = p; - options[opt_idx].flags |= P_DEF_ALLOCED; + opt->def_val = p; + opt->flags |= P_DEF_ALLOCED; } } @@ -379,12 +374,12 @@ void set_init_1(bool clean_arg) // enc_locale() will try to find the encoding of the current locale. // This will be used when 'default' is used as encoding specifier // in 'fileencodings' - char_u *p = enc_locale(); + char *p = enc_locale(); if (p == NULL) { // use utf-8 as 'default' if locale encoding can't be detected. - p = (char_u *)xmemdupz(S_LEN("utf-8")); + p = xmemdupz(S_LEN("utf-8")); } - fenc_default = (char *)p; + fenc_default = p; #ifdef HAVE_WORKING_LIBINTL // GNU gettext 0.10.37 supports this feature: set the codeset used for @@ -400,32 +395,32 @@ void set_init_1(bool clean_arg) /// This does not take care of side effects! /// /// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL -static void set_option_default(int opt_idx, int opt_flags) +static void set_option_default(const 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 = (char_u *)get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags); - uint32_t flags = options[opt_idx].flags; + // pointer to variable for current option + vimoption_T *opt = &options[opt_idx]; + char_u *varp = (char_u *)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); + uint32_t flags = opt->flags; if (varp != NULL) { // skip hidden option, nothing to do for it if (flags & P_STRING) { // Use set_string_option_direct() for local options to handle // freeing and allocating the value. - if (options[opt_idx].indir != PV_NONE) { - set_string_option_direct(NULL, opt_idx, - options[opt_idx].def_val, opt_flags, 0); + if (opt->indir != PV_NONE) { + set_string_option_direct(NULL, opt_idx, opt->def_val, opt_flags, 0); } else { if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { free_string_option(*(char **)(varp)); } - *(char **)varp = options[opt_idx].def_val; - options[opt_idx].flags &= ~P_ALLOCED; + *(char **)varp = opt->def_val; + opt->flags &= ~P_ALLOCED; } } else if (flags & P_NUM) { - if (options[opt_idx].indir == PV_SCROLL) { + if (opt->indir == PV_SCROLL) { win_comp_scroll(curwin); } else { - long def_val = (long)options[opt_idx].def_val; + long def_val = (long)opt->def_val; if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { // 'scrolloff' and 'sidescrolloff' local values have a @@ -436,21 +431,21 @@ static void set_option_default(int opt_idx, int opt_flags) } // May also set global value for local option. if (both) { - *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = + *(long *)get_varp_scope(opt, OPT_GLOBAL) = def_val; } } } else { // P_BOOL - *(int *)varp = (int)(intptr_t)options[opt_idx].def_val; + *(int *)varp = (int)(intptr_t)opt->def_val; #ifdef UNIX // 'modeline' defaults to off for root - if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID) { + if (opt->indir == PV_ML && getuid() == ROOT_UID) { *(int *)varp = false; } #endif // May also set global value for local option. if (both) { - *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = + *(int *)get_varp_scope(opt, OPT_GLOBAL) = *(int *)varp; } } @@ -493,12 +488,13 @@ static void set_string_default(const char *name, char *val, bool allocated) { int opt_idx = findoption(name); if (opt_idx >= 0) { - if (options[opt_idx].flags & P_DEF_ALLOCED) { - xfree(options[opt_idx].def_val); + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val); } - options[opt_idx].def_val = allocated ? val : xstrdup(val); - options[opt_idx].flags |= P_DEF_ALLOCED; + opt->def_val = allocated ? val : xstrdup(val); + opt->flags |= P_DEF_ALLOCED; } } @@ -507,12 +503,12 @@ static void set_string_default(const char *name, char *val, bool allocated) static char *find_dup_item(char *origval, const char *newval, uint32_t flags) FUNC_ATTR_NONNULL_ARG(2) { - int bs = 0; - if (origval == NULL) { return NULL; } + int bs = 0; + const size_t newlen = strlen(newval); for (char *s = origval; *s != NUL; s++) { if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1))) @@ -572,11 +568,9 @@ void set_init_2(bool headless) // set in set_init_1 but logging is not allowed there ILOG("startup runtimepath/packpath value: %s", p_rtp); - int idx; - // 'scroll' defaults to half the window height. The stored default is zero, // which results in the actual value computed from the window height. - idx = findoption("scroll"); + int idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { set_option_default(idx, OPT_LOCAL); } @@ -674,23 +668,25 @@ void set_helplang_default(const char *lang) return; } int idx = findoption("hlg"); - if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - if (options[idx].flags & P_ALLOCED) { - free_string_option(p_hlg); - } - p_hlg = xmemdupz(lang, lang_len); - // zh_CN becomes "cn", zh_TW becomes "tw". - if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) { - p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); - p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); - } else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') { - // any C like setting, such as C.UTF-8, becomes "en" - p_hlg[0] = 'e'; - p_hlg[1] = 'n'; - } - p_hlg[2] = NUL; - options[idx].flags |= P_ALLOCED; + if (idx < 0 || (options[idx].flags & P_WAS_SET)) { + return; + } + + if (options[idx].flags & P_ALLOCED) { + free_string_option(p_hlg); } + p_hlg = xmemdupz(lang, lang_len); + // zh_CN becomes "cn", zh_TW becomes "tw". + if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) { + p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); + p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); + } else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') { + // any C like setting, such as C.UTF-8, becomes "en" + p_hlg[0] = 'e'; + p_hlg[1] = 'n'; + } + p_hlg[2] = NUL; + options[idx].flags |= P_ALLOCED; } /// 'title' and 'icon' only default to true if they have not been set or reset @@ -730,25 +726,181 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } +static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, const char *varp, + char **errmsg) +{ + varnumber_T 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 == '&') { + value = (int)(intptr_t)options[opt_idx].def_val; + } else if (nextchar == '<') { + // For 'autoread' -1 means to use global value. + if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL) { + value = -1; + } else { + value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + } else { + if (prefix == 2) { + value = *(int *)varp ^ 1; // ":set invopt": invert + } else { + value = prefix; // ":set opt" or ":set noopt": set or reset + } + } + + *errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); +} + +static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op, + const char *varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + varnumber_T value; + char *arg = *argp; + + // Different ways to set a number option: + // & set to default value + // < set to global value + // <xx> accept special key codes for 'wildchar' + // c accept any non-digit for 'wildchar' + // [-]0-9 set number + // other error + arg++; + if (nextchar == '&') { + value = (long)(intptr_t)options[opt_idx].def_val; + } else if (nextchar == '<') { + // For 'undolevels' NO_LOCAL_UNDOLEVEL means to + // use the global value. + if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { + value = NO_LOCAL_UNDOLEVEL; + } else { + value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + } + } else if (((long *)varp == &p_wc + || (long *)varp == &p_wcm) + && (*arg == '<' + || *arg == '^' + || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) + && !ascii_isdigit(*arg)))) { + value = string_to_key(arg); + if (value == 0 && (long *)varp != &p_wcm) { + *errmsg = e_invarg; + return; + } + } else if (*arg == '-' || ascii_isdigit(*arg)) { + int i; + // Allow negative, octal and hex numbers. + vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); + if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { + *errmsg = e_number_required_after_equal; + return; + } + } else { + *errmsg = e_number_required_after_equal; + return; + } + + if (op == OP_ADDING) { + value = *(long *)varp + value; + } + if (op == OP_PREPENDING) { + value = *(long *)varp * value; + } + if (op == OP_REMOVING) { + value = *(long *)varp - value; + } + *errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value, + errbuf, errbuflen, opt_flags); +} + +// Handle some special cases with string option values +static void munge_string_opt_val(char **varp, char **oldval, char **const origval, + char_u **const origval_l, char_u **const origval_g, + char **const argp, char *const whichwrap, size_t whichwraplen, + char **const save_argp) +{ + // Set 'keywordprg' to ":help" if an empty + // value was passed to :set by the user. + if (varp == &p_kp && (**argp == NUL || **argp == ' ')) { + *save_argp = *argp; + *argp = ":help"; + } else if (varp == &p_bs && ascii_isdigit(**(char_u **)varp)) { + // Convert 'backspace' number to string, for + // adding, prepending and removing string. + const int i = getdigits_int(varp, true, 0); + switch (i) { + case 0: + *varp = empty_option; + break; + case 1: + *varp = xstrdup("indent,eol"); + break; + case 2: + *varp = xstrdup("indent,eol,start"); + break; + case 3: + *varp = xstrdup("indent,eol,nostop"); + break; + } + xfree(*oldval); + if (*origval == *oldval) { + *origval = *varp; + } + if (*origval_l == (char_u *)(*oldval)) { + *origval_l = *(char_u **)varp; + } + if (*origval_g == (char_u *)(*oldval)) { + *origval_g = *(char_u **)varp; + } + *oldval = *varp; + } else if (varp == &p_ww && ascii_isdigit(**argp)) { + // Convert 'whichwrap' number to string, for backwards compatibility + // with Vim 3.0. + *whichwrap = NUL; + int i = getdigits_int(argp, true, 0); + if (i & 1) { + xstrlcat(whichwrap, "b,", whichwraplen); + } + if (i & 2) { + xstrlcat(whichwrap, "s,", whichwraplen); + } + if (i & 4) { + xstrlcat(whichwrap, "h,l,", whichwraplen); + } + if (i & 8) { + xstrlcat(whichwrap, "<,>,", whichwraplen); + } + if (i & 16) { + xstrlcat(whichwrap, "[,],", whichwraplen); + } + if (*whichwrap != NUL) { // remove trailing , + whichwrap[strlen(whichwrap) - 1] = NUL; + } + *save_argp = *argp; + *argp = whichwrap; + } else if (**argp == '>' && (varp == &p_dir || varp == &p_bdir)) { + // Remove '>' before 'dir' and 'bdir', for backwards compatibility with + // version 3.0 + (*argp)++; + } +} + /// 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) +static void 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 *oldval = NULL; // previous value if *varp - char *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; char whichwrap[80]; // When using ":set opt=val" for a global option @@ -760,7 +912,7 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, } // The old value is kept until we are sure that the new value is valid. - oldval = *(char **)varp; + char *oldval = *(char **)varp; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); @@ -773,6 +925,7 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, } } + char *origval; // 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)) { @@ -803,70 +956,8 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, } 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 **)varp; - } - if (origval_l == (char_u *)oldval) { - origval_l = *(char_u **)varp; - } - if (origval_g == (char_u *)oldval) { - origval_g = *(char_u **)varp; - } - oldval = *(char **)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++; - } + munge_string_opt_val((char **)varp, &oldval, &origval, &origval_l, &origval_g, &arg, + whichwrap, sizeof(whichwrap), &save_arg); // Copy the new string into allocated memory. // Can't use set_string_option_direct(), because we need to remove the @@ -995,14 +1086,14 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, // 'whichwrap' if (flags & P_ONECOMMA) { if (*s != ',' && *(s + 1) == ',' - && vim_strchr(s + 2, *s) != NULL) { + && vim_strchr(s + 2, (uint8_t)(*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) { + && vim_strchr(s + 1, (uint8_t)(*s)) != NULL) { STRMOVE(s, s + 1); continue; } @@ -1020,13 +1111,13 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, *(char_u **)(varp) = (char_u *)newval; // origval may be freed by did_set_string_option(), make a copy. - saved_origval = (origval != NULL) ? xstrdup(origval) : NULL; - saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : NULL; - saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : NULL; + char *saved_origval = (origval != NULL) ? xstrdup(origval) : NULL; + char *saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : NULL; + char *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; + char *saved_newval = (newval != NULL) ? xstrdup(newval) : NULL; { uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); @@ -1068,416 +1159,391 @@ static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, 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 -/// does not need to be expanded with option_expand(). -/// "opt_flags": -/// 0 for ":set" -/// OPT_GLOBAL for ":setglobal" -/// OPT_LOCAL for ":setlocal" and a modeline -/// OPT_MODELINE for a modeline -/// OPT_WINONLY to only set window-local options -/// OPT_NOWIN to skip setting window-local options -/// -/// @param arg option string (may be written to!) -/// +static set_op_T get_op(const char *arg) +{ + set_op_T op = OP_NONE; + if (*arg != NUL && *(arg + 1) == '=') { + if (*arg == '+') { + op = OP_ADDING; // "+=" + } else if (*arg == '^') { + op = OP_PREPENDING; // "^=" + } else if (*arg == '-') { + op = OP_REMOVING; // "-=" + } + } + return op; +} + +static int get_option_prefix(char **argp) +{ + if (strncmp(*argp, "no", 2) == 0) { + *argp += 2; + return 0; + } else if (strncmp(*argp, "inv", 3) == 0) { + *argp += 3; + return 2; + } + + return 1; +} + +/// @param[in] arg Pointer to start option name +/// @param[out] opt_idxp Option index in options[] table. +/// @param[out] keyp +/// @param[out] len Length of option name /// @return FAIL if an error is detected, OK otherwise -int do_set(char *arg, int opt_flags) +static int parse_option_name(char *arg, int *keyp, int *lenp, int *opt_idxp) { - int did_show = false; // already showed one value + // find end of name + int key = 0; + int len; + int opt_idx; - if (*arg == NUL) { - showoptions(0, opt_flags); - did_show = true; - goto theend; - } - - char errbuf[80]; - - while (*arg != NUL) { // loop to process all options - char *errmsg = NULL; - char *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. - arg += 3; - if (*arg == '&') { - arg++; - // Only for :set command set global value of local options. - set_options_default(OPT_FREE | opt_flags); - didset_options(); - didset_options2(); - ui_refresh_options(); - redraw_all_later(UPD_CLEAR); - } else { - showoptions(1, opt_flags); - did_show = true; - } + if (*arg == '<') { + opt_idx = -1; + // look out for <t_>;> + if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { + len = 5; } else { - int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name - if (strncmp(arg, "no", 2) == 0) { - prefix = 0; - arg += 2; - } else if (strncmp(arg, "inv", 3) == 0) { - prefix = 2; - arg += 3; + len = 1; + while (arg[len] != NUL && arg[len] != '>') { + len++; } - - // find end of name - int key = 0; - int len; - int opt_idx; - if (*arg == '<') { - opt_idx = -1; - // look out for <t_>;> - if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { - len = 5; - } else { - len = 1; - while (arg[len] != NUL && arg[len] != '>') { - len++; - } - } - if (arg[len] != '>') { - errmsg = e_invarg; - goto skip; - } - if (arg[1] == 't' && arg[2] == '_') { // could be term code - opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); - } + } + if (arg[len] != '>') { + return FAIL; + } + if (arg[1] == 't' && arg[2] == '_') { // could be term code + opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); + } + len++; + if (opt_idx == -1) { + key = find_key_option(arg + 1, true); + } + } else { + // The two characters after "t_" may not be alphanumeric. + if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { + len = 4; + } else { + len = 0; + while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { len++; - if (opt_idx == -1) { - key = find_key_option(arg + 1, true); - } - } else { - len = 0; - // The two characters after "t_" may not be alphanumeric. - if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { - len = 4; - } else { - while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { - len++; - } - } - opt_idx = findoption_len((const char *)arg, (size_t)len); - if (opt_idx == -1) { - key = find_key_option(arg, false); - } } + } + opt_idx = findoption_len((const char *)arg, (size_t)len); + if (opt_idx == -1) { + key = find_key_option(arg, false); + } + } - // remember character after option name - int afterchar = (uint8_t)arg[len]; + *keyp = key; + *lenp = len; + *opt_idxp = opt_idx; - // skip white space, allow ":set ai ?" - while (ascii_iswhite(arg[len])) { - len++; - } + return OK; +} - set_op_T op = OP_NONE; - if (arg[len] != NUL && arg[len + 1] == '=') { - if (arg[len] == '+') { - op = OP_ADDING; // "+=" - len++; - } else if (arg[len] == '^') { - op = OP_PREPENDING; // "^=" - len++; - } else if (arg[len] == '-') { - op = OP_REMOVING; // "-=" - len++; - } - } - char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name +static int validate_opt_idx(win_T *win, int opt_idx, int opt_flags, uint32_t flags, int prefix, + char **errmsg) +{ + // Only bools can have a prefix of 'inv' or 'no' + if (!(flags & P_BOOL) && prefix != 1) { + *errmsg = e_invarg; + return FAIL; + } - if (opt_idx == -1 && key == 0) { // found a mismatch: skip - errmsg = e_unknown_option; - goto skip; - } + // Skip all options that are not window-local (used when showing + // an already loaded buffer in a window). + if ((opt_flags & OPT_WINONLY) + && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { + return FAIL; + } - uint32_t flags; // flags for current option - char *varp = NULL; // pointer to variable for current option - - if (opt_idx >= 0) { - if (options[opt_idx].var == NULL) { // hidden option: skip - // Only give an error message when requesting the value of - // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", nextchar) == NULL - && (!(options[opt_idx].flags & P_BOOL) - || nextchar == '?')) { - errmsg = e_unsupportedoption; - } - goto skip; - } + // Skip all options that are window-local (used for :vimgrep). + if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 + && options[opt_idx].var == VAR_WIN) { + return FAIL; + } - flags = options[opt_idx].flags; - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - } else { - flags = P_STRING; - } + // Disallow changing some options from modelines. + if (opt_flags & OPT_MODELINE) { + if (flags & (P_SECURE | P_NO_ML)) { + *errmsg = e_not_allowed_in_modeline; + return FAIL; + } + if ((flags & P_MLE) && !p_mle) { + *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; + return FAIL; + } + // In diff mode some options are overruled. This avoids that + // 'foldmethod' becomes "marker" instead of "diff" and that + // "wrap" gets set. + if (win->w_p_diff + && opt_idx >= 0 // shut up coverity warning + && (options[opt_idx].indir == PV_FDM + || options[opt_idx].indir == PV_WRAP)) { + return FAIL; + } + } - // Skip all options that are not window-local (used when showing - // an already loaded buffer in a window). - if ((opt_flags & OPT_WINONLY) - && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) { - goto skip; - } + // Disallow changing some options in the sandbox + if (sandbox != 0 && (flags & P_SECURE)) { + *errmsg = e_sandbox; + return FAIL; + } - // Skip all options that are window-local (used for :vimgrep). - if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 - && options[opt_idx].var == VAR_WIN) { - goto skip; - } + return OK; +} - // Disallow changing some options from modelines. - if (opt_flags & OPT_MODELINE) { - if (flags & (P_SECURE | P_NO_ML)) { - errmsg = e_not_allowed_in_modeline; - goto skip; - } - if ((flags & P_MLE) && !p_mle) { - errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; - goto skip; - } - // In diff mode some options are overruled. This avoids that - // 'foldmethod' becomes "marker" instead of "diff" and that - // "wrap" gets set. - if (curwin->w_p_diff - && opt_idx >= 0 // shut up coverity warning - && (options[opt_idx].indir == PV_FDM - || options[opt_idx].indir == PV_WRAP)) { - goto skip; - } - } +static void do_set_option_value(int opt_idx, int opt_flags, char **argp, int prefix, int nextchar, + set_op_T op, uint32_t flags, char *varp, char *errbuf, + size_t errbuflen, char **errmsg) +{ + int value_checked = false; + if (flags & P_BOOL) { // boolean + do_set_bool(opt_idx, opt_flags, prefix, nextchar, varp, errmsg); + } else if (flags & P_NUM) { // numeric + do_set_num(opt_idx, opt_flags, argp, nextchar, op, varp, errbuf, errbuflen, errmsg); + } else if (opt_idx >= 0) { // string. + do_set_string(opt_idx, opt_flags, argp, nextchar, op, flags, varp, errbuf, + errbuflen, &value_checked, errmsg); + } else { + // key code option(FIXME(tarruda): Show a warning or something + // similar) + } - // Disallow changing some options in the sandbox - if (sandbox != 0 && (flags & P_SECURE)) { - errmsg = e_sandbox; - goto skip; - } + if (*errmsg != NULL) { + return; + } - if (vim_strchr("?=:!&<", nextchar) != NULL) { - arg += len; - if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { - if (arg[3] == 'm') { // "opt&vim": set to Vim default - arg += 3; - } else { // "opt&vi": set to Vi default - arg += 2; - } - } - if (vim_strchr("?!&<", nextchar) != NULL - && arg[1] != NUL && !ascii_iswhite(arg[1])) { - errmsg = e_trailing; - goto skip; - } - } + if (opt_idx >= 0) { + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); + } +} - // - // allow '=' and ':' as MS-DOS command.com allows only one - // '=' character per "set" command line. grrr. (jw) - // - if (nextchar == '?' - || (prefix == 1 - && vim_strchr("=:&<", nextchar) == NULL - && !(flags & P_BOOL))) { - // print value - if (did_show) { - msg_putchar('\n'); // cursor below last one - } else { - gotocmdline(true); // cursor at status line - did_show = true; // remember that we did a line - } - if (opt_idx >= 0) { - showoneopt(&options[opt_idx], opt_flags); - if (p_verbose > 0) { - // Mention where the option was last set. - if (varp == (char *)options[opt_idx].var) { - option_last_set_msg(options[opt_idx].last_set); - } else if ((int)options[opt_idx].indir & PV_WIN) { - option_last_set_msg(curwin->w_p_script_ctx[ - (int)options[opt_idx].indir & PV_MASK]); - } else if ((int)options[opt_idx].indir & PV_BUF) { - option_last_set_msg(curbuf->b_p_script_ctx[ - (int)options[opt_idx].indir & PV_MASK]); - } - } - } else { - errmsg = e_key_code_not_set; - goto skip; - } - if (nextchar != '?' - && nextchar != NUL && !ascii_iswhite(afterchar)) { - errmsg = e_trailing; - } - } else { - int value_checked = false; - varnumber_T value; +static void do_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, + size_t errbuflen, char **errmsg) +{ + // 1: nothing, 0: "no", 2: "inv" in front of name + int prefix = get_option_prefix(argp); - if (flags & P_BOOL) { // boolean - if (nextchar == '=' || nextchar == ':') { - errmsg = e_invarg; - goto skip; - } + char *arg = *argp; - // ":set opt!": invert - // ":set opt&": reset to default value - // ":set opt<": reset to global value - if (nextchar == '!') { - value = *(int *)(varp) ^ 1; - } else if (nextchar == '&') { - value = (int)(intptr_t)options[opt_idx].def_val; - } else if (nextchar == '<') { - // For 'autoread' -1 means to use global value. - if ((int *)varp == &curbuf->b_p_ar - && opt_flags == OPT_LOCAL) { - value = -1; - } else { - value = *(int *)get_varp_scope(&(options[opt_idx]), - OPT_GLOBAL); - } - } else { - // ":set invopt": invert - // ":set opt" or ":set noopt": set or reset - if (nextchar != NUL && !ascii_iswhite(afterchar)) { - errmsg = e_trailing; - goto skip; - } - if (prefix == 2) { // inv - value = *(int *)(varp) ^ 1; - } else { - value = prefix; - } - } + // find end of name + int key = 0; + int len; + int opt_idx; + if (parse_option_name(arg, &key, &len, &opt_idx) == FAIL) { + *errmsg = e_invarg; + return; + } - errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); - } else { // Numeric or string. - if (vim_strchr("=:&<", nextchar) == NULL - || prefix != 1) { - errmsg = e_invarg; - goto skip; - } + // remember character after option name + int afterchar = (uint8_t)arg[len]; - if (flags & P_NUM) { // numeric - // Different ways to set a number option: - // & set to default value - // < set to global value - // <xx> accept special key codes for 'wildchar' - // c accept any non-digit for 'wildchar' - // [-]0-9 set number - // other error - arg++; - if (nextchar == '&') { - value = (long)(intptr_t)options[opt_idx].def_val; - } else if (nextchar == '<') { - // For 'undolevels' NO_LOCAL_UNDOLEVEL means to - // use the global value. - if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { - value = NO_LOCAL_UNDOLEVEL; - } else { - value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - } - } else if (((long *)varp == &p_wc - || (long *)varp == &p_wcm) - && (*arg == '<' - || *arg == '^' - || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) - && !ascii_isdigit(*arg)))) { - value = string_to_key((char_u *)arg); - if (value == 0 && (long *)varp != &p_wcm) { - errmsg = e_invarg; - goto skip; - } - } else if (*arg == '-' || ascii_isdigit(*arg)) { - int i; - // Allow negative, octal and hex numbers. - vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); - if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { - errmsg = e_number_required_after_equal; - goto skip; - } - } else { - errmsg = e_number_required_after_equal; - goto skip; - } + // skip white space, allow ":set ai ?" + while (ascii_iswhite(arg[len])) { + len++; + } - if (op == OP_ADDING) { - value = *(long *)varp + value; - } - if (op == OP_PREPENDING) { - value = *(long *)varp * value; - } - 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. - 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; - } - break; - } - } else { - // key code option(FIXME(tarruda): Show a warning or something - // similar) - } - } + set_op_T op = get_op(arg + len); + if (op != OP_NONE) { + len++; + } - if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); - } + uint8_t nextchar = (uint8_t)arg[len]; // next non-white char after option name + + if (opt_idx == -1 && key == 0) { // found a mismatch: skip + *errmsg = e_unknown_option; + return; + } + + uint32_t flags; // flags for current option + char *varp = NULL; // pointer to variable for current option + + if (opt_idx >= 0) { + if (options[opt_idx].var == NULL) { // hidden option: skip + // Only give an error message when requesting the value of + // a hidden option, ignore setting it. + if (vim_strchr("=:!&<", nextchar) == NULL + && (!(options[opt_idx].flags & P_BOOL) + || nextchar == '?')) { + *errmsg = e_unsupportedoption; } + return; + } -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") - for (int i = 0; i < 2; i++) { - while (*arg != NUL && !ascii_iswhite(*arg)) { - if (*arg++ == '\\' && *arg != NUL) { - arg++; - } - } - arg = skipwhite(arg); - if (*arg != '=') { - break; - } + flags = options[opt_idx].flags; + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + } else { + flags = P_STRING; + } + + if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) { + return; + } + + if (vim_strchr("?=:!&<", nextchar) != NULL) { + *argp += len; + if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') { + if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default + *argp += 3; + } else { // "opt&vi": set to Vi default + *argp += 2; } } + if (vim_strchr("?!&<", nextchar) != NULL + && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { + *errmsg = e_trailing; + return; + } + } - if (errmsg != NULL) { - xstrlcpy(IObuff, _(errmsg), IOSIZE); - int i = (int)strlen(IObuff) + 2; - if (i + (arg - startarg) < IOSIZE) { - // append the argument with the error - STRCAT(IObuff, ": "); - assert(arg >= startarg); - memmove(IObuff + i, startarg, (size_t)(arg - startarg)); - IObuff[i + (arg - startarg)] = NUL; + // + // allow '=' and ':' as MS-DOS command.com allows only one + // '=' character per "set" command line. grrr. (jw) + // + if (nextchar == '?' + || (prefix == 1 + && vim_strchr("=:&<", nextchar) == NULL + && !(flags & P_BOOL))) { + // print value + if (*did_show) { + msg_putchar('\n'); // cursor below last one + } else { + gotocmdline(true); // cursor at status line + *did_show = true; // remember that we did a line + } + if (opt_idx >= 0) { + showoneopt(&options[opt_idx], opt_flags); + if (p_verbose > 0) { + // Mention where the option was last set. + if (varp == (char *)options[opt_idx].var) { + option_last_set_msg(options[opt_idx].last_set); + } else if ((int)options[opt_idx].indir & PV_WIN) { + option_last_set_msg(curwin->w_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } else if ((int)options[opt_idx].indir & PV_BUF) { + option_last_set_msg(curbuf->b_p_script_ctx[(int)options[opt_idx].indir & PV_MASK]); + } } - // make sure all characters are printable - trans_characters(IObuff, IOSIZE); + } else { + *errmsg = e_key_code_not_set; + return; + } + if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) { + *errmsg = e_trailing; + } + return; + } - no_wait_return++; // wait_return() done later - emsg(IObuff); // show error highlighted - no_wait_return--; + if (flags & P_BOOL) { + if (vim_strchr("=:", nextchar) != NULL) { + *errmsg = e_invarg; + return; + } - return FAIL; + if (vim_strchr("!&<", nextchar) == NULL && nextchar != NUL && !ascii_iswhite(afterchar)) { + *errmsg = e_trailing; + return; } + } else { + if (vim_strchr("=:&<", nextchar) == NULL) { + *errmsg = e_invarg; + return; + } + } + + do_set_option_value(opt_idx, opt_flags, argp, prefix, nextchar, op, flags, varp, + errbuf, errbuflen, errmsg); +} + +/// Parse 'arg' for option settings. +/// +/// 'arg' may be IObuff, but only when no errors can be present and option +/// does not need to be expanded with option_expand(). +/// "opt_flags": +/// 0 for ":set" +/// OPT_GLOBAL for ":setglobal" +/// OPT_LOCAL for ":setlocal" and a modeline +/// OPT_MODELINE for a modeline +/// OPT_WINONLY to only set window-local options +/// OPT_NOWIN to skip setting window-local options +/// +/// @param arg option string (may be written to!) +/// +/// @return FAIL if an error is detected, OK otherwise +int do_set(char *arg, int opt_flags) +{ + bool did_show = false; // already showed one value - arg = skipwhite(arg); + if (*arg == NUL) { + showoptions(false, opt_flags); + did_show = true; + } else { + while (*arg != NUL) { // loop to process all options + if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) + && !(opt_flags & OPT_MODELINE)) { + // ":set all" show all options. + // ":set all&" set all options to their default value. + arg += 3; + if (*arg == '&') { + arg++; + // Only for :set command set global value of local options. + set_options_default(OPT_FREE | opt_flags); + didset_options(); + didset_options2(); + ui_refresh_options(); + redraw_all_later(UPD_CLEAR); + } else { + showoptions(true, opt_flags); + did_show = true; + } + } else { + char *startarg = arg; // remember for error message + char *errmsg = NULL; + char errbuf[80]; + + do_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); + + // 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 (int i = 0; i < 2; i++) { + arg = skiptowhite_esc(arg); + arg = skipwhite(arg); + if (*arg != '=') { + break; + } + } + + if (errmsg != NULL) { + xstrlcpy(IObuff, _(errmsg), IOSIZE); + int i = (int)strlen(IObuff) + 2; + if (i + (arg - startarg) < IOSIZE) { + // append the argument with the error + STRCAT(IObuff, ": "); + assert(arg >= startarg); + memmove(IObuff + i, startarg, (size_t)(arg - startarg)); + IObuff[i + (arg - startarg)] = NUL; + } + // make sure all characters are printable + trans_characters(IObuff, IOSIZE); + + no_wait_return++; // wait_return() done later + emsg(IObuff); // show error highlighted + no_wait_return--; + + return FAIL; + } + } + + arg = skipwhite(arg); + } } -theend: if (silent_mode && did_show) { // After displaying option values in silent mode. silent_mode = false; @@ -1516,15 +1582,15 @@ 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. -int string_to_key(char_u *arg) +int string_to_key(char *arg) { if (*arg == '<') { - return find_key_option((char *)arg + 1, true); + return find_key_option(arg + 1, true); } if (*arg == '^') { - return CTRL_CHR(arg[1]); + return CTRL_CHR((uint8_t)arg[1]); } - return *arg; + return (uint8_t)(*arg); } // When changing 'title', 'titlestring', 'icon' or 'iconstring', call @@ -1597,9 +1663,9 @@ void set_options_bin(int oldval, int newval, int opt_flags) /// number, return -1. int get_shada_parameter(int type) { - char_u *p = find_shada_parameter(type); + char *p = find_shada_parameter(type); if (p != NULL && ascii_isdigit(*p)) { - return atoi((char *)p); + return atoi(p); } return -1; } @@ -1607,11 +1673,11 @@ int get_shada_parameter(int type) /// Find the parameter represented by the given character (eg ''', ':', '"', or /// '/') in the 'shada' option and return a pointer to the string after it. /// Return NULL if the parameter is not specified in the string. -char_u *find_shada_parameter(int type) +char *find_shada_parameter(int type) { for (char *p = p_shada; *p; p++) { if (*p == type) { - return (char_u *)p + 1; + return p + 1; } if (*p == 'n') { // 'n' is always the last one break; @@ -1650,7 +1716,7 @@ static char *option_expand(int opt_idx, char *val) // names. // For 'spellsuggest' expand after "file:". expand_env_esc(val, NameBuff, MAXPATHL, - (char_u **)options[opt_idx].var == &p_tags, false, + (char **)options[opt_idx].var == &p_tags, false, (char_u **)options[opt_idx].var == (char_u **)&p_sps ? "file:" : NULL); if (strcmp(NameBuff, val) == 0) { // they are the same @@ -1703,9 +1769,7 @@ static void didset_options2(void) /// Check for string options that are NULL (normally only termcap options). void check_options(void) { - int opt_idx; - - for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) { + for (int 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 **)get_varp(&(options[opt_idx]))); } @@ -1769,9 +1833,9 @@ void redraw_titles(void) 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 = (char_u *)val; *s != NUL; s++) { + for (const char *s = val; *s != NUL; s++) { if (!ASCII_ISALNUM(*s) - && vim_strchr(allowed, *s) == NULL) { + && vim_strchr(allowed, (uint8_t)(*s)) == NULL) { return false; } } @@ -1970,7 +2034,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va || (opt_flags & OPT_GLOBAL) || opt_flags == 0) && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { u_compute_hash(bp, hash); - u_read_undo(NULL, hash, (char_u *)bp->b_fname); + u_read_undo(NULL, hash, bp->b_fname); } } } @@ -2256,8 +2320,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, errmsg = e_positive; } } else if (pp == &p_ch) { - int minval = 0; - if (value < minval) { + if (value < 0) { errmsg = e_positive; } else { p_ch_was_zero = value == 0; @@ -2593,7 +2656,7 @@ 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) +void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags) { // Careful: P_RALL is a combination of other P_ flags bool all = (flags & P_RALL) == P_RALL; @@ -2607,19 +2670,24 @@ void check_redraw(uint32_t flags) } if ((flags & P_RBUF) || (flags & P_RWIN) || all) { - changed_window_setting(); + changed_window_setting_win(win); } if (flags & P_RBUF) { - redraw_curbuf_later(UPD_NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); } if (flags & P_RWINONLY) { - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } if (all) { redraw_all_later(UPD_NOT_VALID); } } +void check_redraw(uint32_t flags) +{ + check_redraw_for(curbuf, curwin, flags); +} + /// Find index for named option /// /// @param[in] arg Option to find index for. @@ -2876,7 +2944,6 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return SOPT_STRING | SOPT_GLOBAL; } - char_u *varp = NULL; int rv = 0; int opt_idx = findoption(name); if (opt_idx < 0) { @@ -2926,6 +2993,8 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return rv; } + char_u *varp = NULL; + if (opt_type == SREQ_GLOBAL) { if (p->var == VAR_WIN) { return 0; @@ -3003,58 +3072,62 @@ char *set_option_value(const char *const name, const long number, const char *co int opt_idx = findoption(name); if (opt_idx < 0) { semsg(_("E355: Unknown option: %s"), name); - } else { - uint32_t flags = options[opt_idx].flags; - // Disallow changing some options in the sandbox - if (sandbox > 0 && (flags & P_SECURE)) { - emsg(_(e_sandbox)); - return NULL; + return NULL; + } + + uint32_t flags = options[opt_idx].flags; + // Disallow changing some options in the sandbox + if (sandbox > 0 && (flags & P_SECURE)) { + emsg(_(e_sandbox)); + return NULL; + } + + if (flags & P_STRING) { + const char *s = string; + if (s == NULL || opt_flags & OPT_CLEAR) { + s = ""; } - if (flags & P_STRING) { - const char *s = string; - if (s == NULL || opt_flags & OPT_CLEAR) { - s = ""; - } - return set_string_option(opt_idx, s, opt_flags); - } - - char_u *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; - - // Either we are given a string or we are setting option - // to zero. - for (idx = 0; string[idx] == '0'; idx++) {} - if (string[idx] != NUL || idx == 0) { - // There's another character after zeros or the string - // is empty. In both cases, we are trying to set a - // num option using a string. - semsg(_("E521: Number required: &%s = '%s'"), - name, string); - return NULL; // do nothing as we hit an error - } - } - long numval = number; - if (opt_flags & OPT_CLEAR) { - if ((int *)varp == &curbuf->b_p_ar) { - numval = -1; - } else if ((long *)varp == &curbuf->b_p_ul) { - numval = NO_LOCAL_UNDOLEVEL; - } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { - numval = -1; - } else { - char *s = NULL; - (void)get_option_value(name, &numval, &s, NULL, OPT_GLOBAL); - } - } - if (flags & P_NUM) { - return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); - } - return set_bool_option(opt_idx, varp, (int)numval, opt_flags); + return set_string_option(opt_idx, s, opt_flags); + } + + char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); + if (varp == NULL) { + // hidden option is not changed + return NULL; + } + + if (number == 0 && string != NULL) { + int idx; + + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; idx++) {} + if (string[idx] != NUL || idx == 0) { + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. + semsg(_("E521: Number required: &%s = '%s'"), + name, string); + return NULL; // do nothing as we hit an error + } + } + long numval = number; + if (opt_flags & OPT_CLEAR) { + if ((int *)varp == &curbuf->b_p_ar) { + numval = -1; + } else if ((long *)varp == &curbuf->b_p_ul) { + numval = NO_LOCAL_UNDOLEVEL; + } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { + numval = -1; + } else { + char *s = NULL; + (void)get_option_value(name, &numval, &s, NULL, OPT_GLOBAL); } } - return NULL; + if (flags & P_NUM) { + return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + } + return set_bool_option(opt_idx, varp, (int)numval, opt_flags); } /// Call set_option_value() and when an error is returned report it. @@ -3086,10 +3159,10 @@ bool is_string_option(const char *name) // Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. // When "has_lt" is true there is a '<' before "*arg_arg". // Returns 0 when the key is not recognized. -int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) +int find_key_option_len(const char *arg_arg, size_t len, bool has_lt) { int key = 0; - const char *arg = (char *)arg_arg; + const char *arg = arg_arg; // Don't use get_special_key_code() for t_xx, we don't want it to call // add_termcap_entry(). @@ -3109,14 +3182,14 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) static int find_key_option(const char *arg, bool has_lt) { - return find_key_option_len((char_u *)arg, strlen(arg), has_lt); + return find_key_option_len(arg, strlen(arg), has_lt); } -/// if 'all' == 0: show changed options -/// if 'all' == 1: show all normal options +/// if 'all' == false: show changed options +/// if 'all' == true: show all normal options /// /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL -static void showoptions(int all, int opt_flags) +static void showoptions(bool all, int opt_flags) { #define INC 20 #define GAP 3 @@ -3427,12 +3500,13 @@ int makefoldset(FILE *fd) static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_t flags) { - char_u *buf = NULL; - char_u *part = NULL; - if (fprintf(fd, "%s %s=", cmd, name) < 0) { return FAIL; } + + char *buf = NULL; + char_u *part = NULL; + if (*valuep != NULL) { // Output 'pastetoggle' as key names. For other // options some characters have to be escaped with @@ -3440,7 +3514,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ if (valuep == &p_pt) { char_u *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 *)str2special((const char **)&s, false, false), 2) == FAIL) { return FAIL; } } @@ -3449,7 +3523,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ // replace home directory in the whole option value into "buf" buf = xmalloc(size); - home_replace(NULL, *valuep, (char *)buf, size, false); + home_replace(NULL, *valuep, 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 @@ -3462,7 +3536,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ if (put_eol(fd) == FAIL) { goto fail; } - char *p = (char *)buf; + char *p = buf; while (*p != NUL) { // for each comma separated option part, append value to // the option, :set rtp+=value @@ -3470,7 +3544,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ goto fail; } (void)copy_option_part(&p, (char *)part, size, ","); - if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) { + if (put_escstr(fd, (char *)part, 2) == FAIL || put_eol(fd) == FAIL) { goto fail; } } @@ -3483,7 +3557,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ return FAIL; } xfree(buf); - } else if (put_escstr(fd, (char_u *)(*valuep), 2) == FAIL) { + } else if (put_escstr(fd, *valuep, 2) == FAIL) { return FAIL; } } @@ -3499,11 +3573,10 @@ fail: static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep) { - long wc; - if (fprintf(fd, "%s %s=", cmd, name) < 0) { return FAIL; } + long wc; if (wc_use_keyname((char_u *)valuep, &wc)) { // print 'wildchar' and 'wildcharm' as a key name if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0) { @@ -3639,83 +3712,87 @@ void unset_global_local_option(char *name, void *from) } } -/// Get pointer to option variable, depending on local or global scope. -/// -/// @param scope can be OPT_LOCAL, OPT_GLOBAL or a combination. -char *get_varp_scope(vimoption_T *p, int scope) +char *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) { if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) { - return GLOBAL_WO(get_varp(p)); + return GLOBAL_WO(get_varp_from(p, buf, win)); } return (char *)p->var; } if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { switch ((int)p->indir) { case PV_FP: - return (char *)&(curbuf->b_p_fp); + return (char *)&(buf->b_p_fp); case PV_EFM: - return (char *)&(curbuf->b_p_efm); + return (char *)&(buf->b_p_efm); case PV_GP: - return (char *)&(curbuf->b_p_gp); + return (char *)&(buf->b_p_gp); case PV_MP: - return (char *)&(curbuf->b_p_mp); + return (char *)&(buf->b_p_mp); case PV_EP: - return (char *)&(curbuf->b_p_ep); + return (char *)&(buf->b_p_ep); case PV_KP: - return (char *)&(curbuf->b_p_kp); + return (char *)&(buf->b_p_kp); case PV_PATH: - return (char *)&(curbuf->b_p_path); + return (char *)&(buf->b_p_path); case PV_AR: - return (char *)&(curbuf->b_p_ar); + return (char *)&(buf->b_p_ar); case PV_TAGS: - return (char *)&(curbuf->b_p_tags); + return (char *)&(buf->b_p_tags); case PV_TC: - return (char *)&(curbuf->b_p_tc); + return (char *)&(buf->b_p_tc); case PV_SISO: - return (char *)&(curwin->w_p_siso); + return (char *)&(win->w_p_siso); case PV_SO: - return (char *)&(curwin->w_p_so); + return (char *)&(win->w_p_so); case PV_DEF: - return (char *)&(curbuf->b_p_def); + return (char *)&(buf->b_p_def); case PV_INC: - return (char *)&(curbuf->b_p_inc); + return (char *)&(buf->b_p_inc); case PV_DICT: - return (char *)&(curbuf->b_p_dict); + return (char *)&(buf->b_p_dict); case PV_TSR: - return (char *)&(curbuf->b_p_tsr); + return (char *)&(buf->b_p_tsr); case PV_TSRFU: - return (char *)&(curbuf->b_p_tsrfu); + return (char *)&(buf->b_p_tsrfu); case PV_TFU: - return (char *)&(curbuf->b_p_tfu); + return (char *)&(buf->b_p_tfu); case PV_SBR: - return (char *)&(curwin->w_p_sbr); + return (char *)&(win->w_p_sbr); case PV_STL: - return (char *)&(curwin->w_p_stl); + return (char *)&(win->w_p_stl); case PV_WBR: - return (char *)&(curwin->w_p_wbr); + return (char *)&(win->w_p_wbr); case PV_UL: - return (char *)&(curbuf->b_p_ul); + return (char *)&(buf->b_p_ul); case PV_LW: - return (char *)&(curbuf->b_p_lw); + return (char *)&(buf->b_p_lw); case PV_BKC: - return (char *)&(curbuf->b_p_bkc); + return (char *)&(buf->b_p_bkc); case PV_MENC: - return (char *)&(curbuf->b_p_menc); + return (char *)&(buf->b_p_menc); case PV_FCS: - return (char *)&(curwin->w_p_fcs); + return (char *)&(win->w_p_fcs); case PV_LCS: - return (char *)&(curwin->w_p_lcs); + return (char *)&(win->w_p_lcs); case PV_VE: - return (char *)&(curwin->w_p_ve); + return (char *)&(win->w_p_ve); } return NULL; // "cannot happen" } - return (char *)get_varp(p); + return (char *)get_varp_from(p, buf, win); } -/// Get pointer to option variable. -static char_u *get_varp(vimoption_T *p) +/// Get pointer to option variable, depending on local or global scope. +/// +/// @param scope can be OPT_LOCAL, OPT_GLOBAL or a combination. +char *get_varp_scope(vimoption_T *p, int scope) +{ + return get_varp_scope_from(p, scope, curbuf, curwin); +} + +static char_u *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) { // hidden option, always return NULL if (p->var == NULL) { @@ -3728,314 +3805,320 @@ static char_u *get_varp(vimoption_T *p) // global option with local value: use local value if it's been set case PV_EP: - return *curbuf->b_p_ep != NUL - ? (char_u *)&curbuf->b_p_ep : p->var; + return *buf->b_p_ep != NUL + ? (char_u *)&buf->b_p_ep : p->var; case PV_KP: - return *curbuf->b_p_kp != NUL - ? (char_u *)&curbuf->b_p_kp : p->var; + return *buf->b_p_kp != NUL + ? (char_u *)&buf->b_p_kp : p->var; case PV_PATH: - return *curbuf->b_p_path != NUL - ? (char_u *)&(curbuf->b_p_path) : p->var; + return *buf->b_p_path != NUL + ? (char_u *)&(buf->b_p_path) : p->var; case PV_AR: - return curbuf->b_p_ar >= 0 - ? (char_u *)&(curbuf->b_p_ar) : p->var; + return buf->b_p_ar >= 0 + ? (char_u *)&(buf->b_p_ar) : p->var; case PV_TAGS: - return *curbuf->b_p_tags != NUL - ? (char_u *)&(curbuf->b_p_tags) : p->var; + return *buf->b_p_tags != NUL + ? (char_u *)&(buf->b_p_tags) : p->var; case PV_TC: - return *curbuf->b_p_tc != NUL - ? (char_u *)&(curbuf->b_p_tc) : p->var; + return *buf->b_p_tc != NUL + ? (char_u *)&(buf->b_p_tc) : p->var; case PV_SISO: - return curwin->w_p_siso >= 0 - ? (char_u *)&(curwin->w_p_siso) : p->var; + return win->w_p_siso >= 0 + ? (char_u *)&(win->w_p_siso) : p->var; case PV_SO: - return curwin->w_p_so >= 0 - ? (char_u *)&(curwin->w_p_so) : p->var; + return win->w_p_so >= 0 + ? (char_u *)&(win->w_p_so) : p->var; case PV_BKC: - return *curbuf->b_p_bkc != NUL - ? (char_u *)&(curbuf->b_p_bkc) : p->var; + return *buf->b_p_bkc != NUL + ? (char_u *)&(buf->b_p_bkc) : p->var; case PV_DEF: - return *curbuf->b_p_def != NUL - ? (char_u *)&(curbuf->b_p_def) : p->var; + return *buf->b_p_def != NUL + ? (char_u *)&(buf->b_p_def) : p->var; case PV_INC: - return *curbuf->b_p_inc != NUL - ? (char_u *)&(curbuf->b_p_inc) : p->var; + return *buf->b_p_inc != NUL + ? (char_u *)&(buf->b_p_inc) : p->var; case PV_DICT: - return *curbuf->b_p_dict != NUL - ? (char_u *)&(curbuf->b_p_dict) : p->var; + return *buf->b_p_dict != NUL + ? (char_u *)&(buf->b_p_dict) : p->var; case PV_TSR: - return *curbuf->b_p_tsr != NUL - ? (char_u *)&(curbuf->b_p_tsr) : p->var; + return *buf->b_p_tsr != NUL + ? (char_u *)&(buf->b_p_tsr) : p->var; case PV_TSRFU: - return *curbuf->b_p_tsrfu != NUL - ? (char_u *)&(curbuf->b_p_tsrfu) : p->var; + return *buf->b_p_tsrfu != NUL + ? (char_u *)&(buf->b_p_tsrfu) : p->var; case PV_FP: - return *curbuf->b_p_fp != NUL - ? (char_u *)&(curbuf->b_p_fp) : p->var; + return *buf->b_p_fp != NUL + ? (char_u *)&(buf->b_p_fp) : p->var; case PV_EFM: - return *curbuf->b_p_efm != NUL - ? (char_u *)&(curbuf->b_p_efm) : p->var; + return *buf->b_p_efm != NUL + ? (char_u *)&(buf->b_p_efm) : p->var; case PV_GP: - return *curbuf->b_p_gp != NUL - ? (char_u *)&(curbuf->b_p_gp) : p->var; + return *buf->b_p_gp != NUL + ? (char_u *)&(buf->b_p_gp) : p->var; case PV_MP: - return *curbuf->b_p_mp != NUL - ? (char_u *)&(curbuf->b_p_mp) : p->var; + return *buf->b_p_mp != NUL + ? (char_u *)&(buf->b_p_mp) : p->var; case PV_SBR: - return *curwin->w_p_sbr != NUL - ? (char_u *)&(curwin->w_p_sbr) : p->var; + return *win->w_p_sbr != NUL + ? (char_u *)&(win->w_p_sbr) : p->var; case PV_STL: - return *curwin->w_p_stl != NUL - ? (char_u *)&(curwin->w_p_stl) : p->var; + return *win->w_p_stl != NUL + ? (char_u *)&(win->w_p_stl) : p->var; case PV_WBR: - return *curwin->w_p_wbr != NUL - ? (char_u *)&(curwin->w_p_wbr) : p->var; + return *win->w_p_wbr != NUL + ? (char_u *)&(win->w_p_wbr) : p->var; case PV_UL: - return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL - ? (char_u *)&(curbuf->b_p_ul) : p->var; + return buf->b_p_ul != NO_LOCAL_UNDOLEVEL + ? (char_u *)&(buf->b_p_ul) : p->var; case PV_LW: - return *curbuf->b_p_lw != NUL - ? (char_u *)&(curbuf->b_p_lw) : p->var; + return *buf->b_p_lw != NUL + ? (char_u *)&(buf->b_p_lw) : p->var; case PV_MENC: - return *curbuf->b_p_menc != NUL - ? (char_u *)&(curbuf->b_p_menc) : p->var; + return *buf->b_p_menc != NUL + ? (char_u *)&(buf->b_p_menc) : p->var; case PV_FCS: - return *curwin->w_p_fcs != NUL - ? (char_u *)&(curwin->w_p_fcs) : p->var; + return *win->w_p_fcs != NUL + ? (char_u *)&(win->w_p_fcs) : p->var; case PV_LCS: - return *curwin->w_p_lcs != NUL - ? (char_u *)&(curwin->w_p_lcs) : p->var; + return *win->w_p_lcs != NUL + ? (char_u *)&(win->w_p_lcs) : p->var; case PV_VE: - return *curwin->w_p_ve != NUL - ? (char_u *)&curwin->w_p_ve : p->var; + return *win->w_p_ve != NUL + ? (char_u *)&win->w_p_ve : p->var; case PV_ARAB: - return (char_u *)&(curwin->w_p_arab); + return (char_u *)&(win->w_p_arab); case PV_LIST: - return (char_u *)&(curwin->w_p_list); + return (char_u *)&(win->w_p_list); case PV_SPELL: - return (char_u *)&(curwin->w_p_spell); + return (char_u *)&(win->w_p_spell); case PV_CUC: - return (char_u *)&(curwin->w_p_cuc); + return (char_u *)&(win->w_p_cuc); case PV_CUL: - return (char_u *)&(curwin->w_p_cul); + return (char_u *)&(win->w_p_cul); case PV_CULOPT: - return (char_u *)&(curwin->w_p_culopt); + return (char_u *)&(win->w_p_culopt); case PV_CC: - return (char_u *)&(curwin->w_p_cc); + return (char_u *)&(win->w_p_cc); case PV_DIFF: - return (char_u *)&(curwin->w_p_diff); + return (char_u *)&(win->w_p_diff); case PV_FDC: - return (char_u *)&(curwin->w_p_fdc); + return (char_u *)&(win->w_p_fdc); case PV_FEN: - return (char_u *)&(curwin->w_p_fen); + return (char_u *)&(win->w_p_fen); case PV_FDI: - return (char_u *)&(curwin->w_p_fdi); + return (char_u *)&(win->w_p_fdi); case PV_FDL: - return (char_u *)&(curwin->w_p_fdl); + return (char_u *)&(win->w_p_fdl); case PV_FDM: - return (char_u *)&(curwin->w_p_fdm); + return (char_u *)&(win->w_p_fdm); case PV_FML: - return (char_u *)&(curwin->w_p_fml); + return (char_u *)&(win->w_p_fml); case PV_FDN: - return (char_u *)&(curwin->w_p_fdn); + return (char_u *)&(win->w_p_fdn); case PV_FDE: - return (char_u *)&(curwin->w_p_fde); + return (char_u *)&(win->w_p_fde); case PV_FDT: - return (char_u *)&(curwin->w_p_fdt); + return (char_u *)&(win->w_p_fdt); case PV_FMR: - return (char_u *)&(curwin->w_p_fmr); + return (char_u *)&(win->w_p_fmr); case PV_NU: - return (char_u *)&(curwin->w_p_nu); + return (char_u *)&(win->w_p_nu); case PV_RNU: - return (char_u *)&(curwin->w_p_rnu); + return (char_u *)&(win->w_p_rnu); case PV_NUW: - return (char_u *)&(curwin->w_p_nuw); + return (char_u *)&(win->w_p_nuw); case PV_WFH: - return (char_u *)&(curwin->w_p_wfh); + return (char_u *)&(win->w_p_wfh); case PV_WFW: - return (char_u *)&(curwin->w_p_wfw); + return (char_u *)&(win->w_p_wfw); case PV_PVW: - return (char_u *)&(curwin->w_p_pvw); + return (char_u *)&(win->w_p_pvw); case PV_RL: - return (char_u *)&(curwin->w_p_rl); + return (char_u *)&(win->w_p_rl); case PV_RLC: - return (char_u *)&(curwin->w_p_rlc); + return (char_u *)&(win->w_p_rlc); case PV_SCROLL: - return (char_u *)&(curwin->w_p_scr); + return (char_u *)&(win->w_p_scr); case PV_WRAP: - return (char_u *)&(curwin->w_p_wrap); + return (char_u *)&(win->w_p_wrap); case PV_LBR: - return (char_u *)&(curwin->w_p_lbr); + return (char_u *)&(win->w_p_lbr); case PV_BRI: - return (char_u *)&(curwin->w_p_bri); + return (char_u *)&(win->w_p_bri); case PV_BRIOPT: - return (char_u *)&(curwin->w_p_briopt); + return (char_u *)&(win->w_p_briopt); case PV_SCBIND: - return (char_u *)&(curwin->w_p_scb); + return (char_u *)&(win->w_p_scb); case PV_CRBIND: - return (char_u *)&(curwin->w_p_crb); + return (char_u *)&(win->w_p_crb); case PV_COCU: - return (char_u *)&(curwin->w_p_cocu); + return (char_u *)&(win->w_p_cocu); case PV_COLE: - return (char_u *)&(curwin->w_p_cole); + return (char_u *)&(win->w_p_cole); case PV_AI: - return (char_u *)&(curbuf->b_p_ai); + return (char_u *)&(buf->b_p_ai); case PV_BIN: - return (char_u *)&(curbuf->b_p_bin); + return (char_u *)&(buf->b_p_bin); case PV_BOMB: - return (char_u *)&(curbuf->b_p_bomb); + return (char_u *)&(buf->b_p_bomb); case PV_BH: - return (char_u *)&(curbuf->b_p_bh); + return (char_u *)&(buf->b_p_bh); case PV_BT: - return (char_u *)&(curbuf->b_p_bt); + return (char_u *)&(buf->b_p_bt); case PV_BL: - return (char_u *)&(curbuf->b_p_bl); + return (char_u *)&(buf->b_p_bl); case PV_CHANNEL: - return (char_u *)&(curbuf->b_p_channel); + return (char_u *)&(buf->b_p_channel); case PV_CI: - return (char_u *)&(curbuf->b_p_ci); + return (char_u *)&(buf->b_p_ci); case PV_CIN: - return (char_u *)&(curbuf->b_p_cin); + return (char_u *)&(buf->b_p_cin); case PV_CINK: - return (char_u *)&(curbuf->b_p_cink); + return (char_u *)&(buf->b_p_cink); case PV_CINO: - return (char_u *)&(curbuf->b_p_cino); + return (char_u *)&(buf->b_p_cino); case PV_CINSD: - return (char_u *)&(curbuf->b_p_cinsd); + return (char_u *)&(buf->b_p_cinsd); case PV_CINW: - return (char_u *)&(curbuf->b_p_cinw); + return (char_u *)&(buf->b_p_cinw); case PV_COM: - return (char_u *)&(curbuf->b_p_com); + return (char_u *)&(buf->b_p_com); case PV_CMS: - return (char_u *)&(curbuf->b_p_cms); + return (char_u *)&(buf->b_p_cms); case PV_CPT: - return (char_u *)&(curbuf->b_p_cpt); + return (char_u *)&(buf->b_p_cpt); #ifdef BACKSLASH_IN_FILENAME case PV_CSL: - return (char_u *)&(curbuf->b_p_csl); + return (char_u *)&(buf->b_p_csl); #endif case PV_CFU: - return (char_u *)&(curbuf->b_p_cfu); + return (char_u *)&(buf->b_p_cfu); case PV_OFU: - return (char_u *)&(curbuf->b_p_ofu); + return (char_u *)&(buf->b_p_ofu); case PV_EOF: - return (char_u *)&(curbuf->b_p_eof); + return (char_u *)&(buf->b_p_eof); case PV_EOL: - return (char_u *)&(curbuf->b_p_eol); + return (char_u *)&(buf->b_p_eol); case PV_FIXEOL: - return (char_u *)&(curbuf->b_p_fixeol); + return (char_u *)&(buf->b_p_fixeol); case PV_ET: - return (char_u *)&(curbuf->b_p_et); + return (char_u *)&(buf->b_p_et); case PV_FENC: - return (char_u *)&(curbuf->b_p_fenc); + return (char_u *)&(buf->b_p_fenc); case PV_FF: - return (char_u *)&(curbuf->b_p_ff); + return (char_u *)&(buf->b_p_ff); case PV_FT: - return (char_u *)&(curbuf->b_p_ft); + return (char_u *)&(buf->b_p_ft); case PV_FO: - return (char_u *)&(curbuf->b_p_fo); + return (char_u *)&(buf->b_p_fo); case PV_FLP: - return (char_u *)&(curbuf->b_p_flp); + return (char_u *)&(buf->b_p_flp); case PV_IMI: - return (char_u *)&(curbuf->b_p_iminsert); + return (char_u *)&(buf->b_p_iminsert); case PV_IMS: - return (char_u *)&(curbuf->b_p_imsearch); + return (char_u *)&(buf->b_p_imsearch); case PV_INF: - return (char_u *)&(curbuf->b_p_inf); + return (char_u *)&(buf->b_p_inf); case PV_ISK: - return (char_u *)&(curbuf->b_p_isk); + return (char_u *)&(buf->b_p_isk); case PV_INEX: - return (char_u *)&(curbuf->b_p_inex); + return (char_u *)&(buf->b_p_inex); case PV_INDE: - return (char_u *)&(curbuf->b_p_inde); + return (char_u *)&(buf->b_p_inde); case PV_INDK: - return (char_u *)&(curbuf->b_p_indk); + return (char_u *)&(buf->b_p_indk); case PV_FEX: - return (char_u *)&(curbuf->b_p_fex); + return (char_u *)&(buf->b_p_fex); case PV_LISP: - return (char_u *)&(curbuf->b_p_lisp); + return (char_u *)&(buf->b_p_lisp); case PV_LOP: - return (char_u *)&(curbuf->b_p_lop); + return (char_u *)&(buf->b_p_lop); case PV_ML: - return (char_u *)&(curbuf->b_p_ml); + return (char_u *)&(buf->b_p_ml); case PV_MPS: - return (char_u *)&(curbuf->b_p_mps); + return (char_u *)&(buf->b_p_mps); case PV_MA: - return (char_u *)&(curbuf->b_p_ma); + return (char_u *)&(buf->b_p_ma); case PV_MOD: - return (char_u *)&(curbuf->b_changed); + return (char_u *)&(buf->b_changed); case PV_NF: - return (char_u *)&(curbuf->b_p_nf); + return (char_u *)&(buf->b_p_nf); case PV_PI: - return (char_u *)&(curbuf->b_p_pi); + return (char_u *)&(buf->b_p_pi); case PV_QE: - return (char_u *)&(curbuf->b_p_qe); + return (char_u *)&(buf->b_p_qe); case PV_RO: - return (char_u *)&(curbuf->b_p_ro); + return (char_u *)&(buf->b_p_ro); case PV_SCBK: - return (char_u *)&(curbuf->b_p_scbk); + return (char_u *)&(buf->b_p_scbk); case PV_SI: - return (char_u *)&(curbuf->b_p_si); + return (char_u *)&(buf->b_p_si); case PV_STS: - return (char_u *)&(curbuf->b_p_sts); + return (char_u *)&(buf->b_p_sts); case PV_SUA: - return (char_u *)&(curbuf->b_p_sua); + return (char_u *)&(buf->b_p_sua); case PV_SWF: - return (char_u *)&(curbuf->b_p_swf); + return (char_u *)&(buf->b_p_swf); case PV_SMC: - return (char_u *)&(curbuf->b_p_smc); + return (char_u *)&(buf->b_p_smc); case PV_SYN: - return (char_u *)&(curbuf->b_p_syn); + return (char_u *)&(buf->b_p_syn); case PV_SPC: - return (char_u *)&(curwin->w_s->b_p_spc); + return (char_u *)&(win->w_s->b_p_spc); case PV_SPF: - return (char_u *)&(curwin->w_s->b_p_spf); + return (char_u *)&(win->w_s->b_p_spf); case PV_SPL: - return (char_u *)&(curwin->w_s->b_p_spl); + return (char_u *)&(win->w_s->b_p_spl); case PV_SPO: - return (char_u *)&(curwin->w_s->b_p_spo); + return (char_u *)&(win->w_s->b_p_spo); case PV_SW: - return (char_u *)&(curbuf->b_p_sw); + return (char_u *)&(buf->b_p_sw); case PV_TFU: - return (char_u *)&(curbuf->b_p_tfu); + return (char_u *)&(buf->b_p_tfu); case PV_TS: - return (char_u *)&(curbuf->b_p_ts); + return (char_u *)&(buf->b_p_ts); case PV_TW: - return (char_u *)&(curbuf->b_p_tw); + return (char_u *)&(buf->b_p_tw); case PV_UDF: - return (char_u *)&(curbuf->b_p_udf); + return (char_u *)&(buf->b_p_udf); case PV_WM: - return (char_u *)&(curbuf->b_p_wm); + return (char_u *)&(buf->b_p_wm); case PV_VSTS: - return (char_u *)&(curbuf->b_p_vsts); + return (char_u *)&(buf->b_p_vsts); case PV_VTS: - return (char_u *)&(curbuf->b_p_vts); + return (char_u *)&(buf->b_p_vts); case PV_KMAP: - return (char_u *)&(curbuf->b_p_keymap); + return (char_u *)&(buf->b_p_keymap); case PV_SCL: - return (char_u *)&(curwin->w_p_scl); + return (char_u *)&(win->w_p_scl); case PV_WINHL: - return (char_u *)&(curwin->w_p_winhl); + return (char_u *)&(win->w_p_winhl); case PV_WINBL: - return (char_u *)&(curwin->w_p_winbl); + return (char_u *)&(win->w_p_winbl); case PV_STC: - return (char_u *)&(curwin->w_p_stc); + return (char_u *)&(win->w_p_stc); default: iemsg(_("E356: get_varp ERROR")); } // always return a valid pointer to avoid a crash! - return (char_u *)&(curbuf->b_p_wm); + return (char_u *)&(buf->b_p_wm); +} + +/// Get pointer to option variable. +static inline char_u *get_varp(vimoption_T *p) +{ + return get_varp_from(p, curbuf, curwin); } /// Get the value of 'equalprg', either the buffer-local one or the global one. -char_u *get_equalprg(void) +char *get_equalprg(void) { if (*curbuf->b_p_ep == NUL) { return p_ep; } - return (char_u *)curbuf->b_p_ep; + return curbuf->b_p_ep; } /// Copy options from one window to another. @@ -4221,7 +4304,7 @@ static void init_buf_opt_idx(void) void buf_copy_options(buf_T *buf, int flags) { int should_copy = true; - char_u *save_p_isk = NULL; // init for GCC + char *save_p_isk = NULL; // init for GCC int did_isk = false; // Skip this when the option defaults have not been set yet. Happens when @@ -4254,7 +4337,7 @@ void buf_copy_options(buf_T *buf, int flags) // (jumping back to a help file with CTRL-T or CTRL-O) bool 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 = (char_u *)buf->b_p_isk; + save_p_isk = buf->b_p_isk; buf->b_p_isk = NULL; } // Always free the allocated strings. If not already initialized, @@ -4449,7 +4532,7 @@ void buf_copy_options(buf_T *buf, int flags) // 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 = (char *)save_p_isk; + buf->b_p_isk = 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 { @@ -4504,15 +4587,15 @@ void reset_modifiable(void) } /// Set the global value for 'iminsert' to the local value. -void set_iminsert_global(void) +void set_iminsert_global(buf_T *buf) { - p_iminsert = curbuf->b_p_iminsert; + p_iminsert = buf->b_p_iminsert; } /// Set the global value for 'imsearch' to the local value. -void set_imsearch_global(void) +void set_imsearch_global(buf_T *buf) { - p_imsearch = curbuf->b_p_imsearch; + p_imsearch = buf->b_p_imsearch; } static int expand_option_idx = -1; @@ -4522,11 +4605,6 @@ static int expand_option_flags = 0; /// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) { - uint32_t flags = 0; // init for GCC - int opt_idx = 0; // init for GCC - char *p; - int is_term_option = false; - expand_option_flags = opt_flags; xp->xp_context = EXPAND_SETTINGS; @@ -4534,7 +4612,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) xp->xp_pattern = arg; return; } - p = arg + strlen(arg) - 1; + char *p = arg + strlen(arg) - 1; if (*p == ' ' && *(p - 1) != '\\') { xp->xp_pattern = p + 1; return; @@ -4566,6 +4644,9 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) arg = p; char nextchar; + uint32_t flags = 0; + int opt_idx = 0; + int is_term_option = false; if (*arg == '<') { while (*p != '>') { @@ -4696,13 +4777,56 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) } } -int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file) +/// Returns true if "str" either matches "regmatch" or fuzzy matches "pat". +/// +/// If "test_only" is true and "fuzzy" is false and if "str" matches the regular +/// expression "regmatch", then returns true. Otherwise returns false. +/// +/// If "test_only" is false and "fuzzy" is false and if "str" matches the +/// regular expression "regmatch", then stores the match in matches[idx] and +/// returns true. +/// +/// If "test_only" is true and "fuzzy" is true and if "str" fuzzy matches +/// "fuzzystr", then returns true. Otherwise returns false. +/// +/// If "test_only" is false and "fuzzy" is true and if "str" fuzzy matches +/// "fuzzystr", then stores the match details in fuzmatch[idx] and returns true. +static bool match_str(char *const str, regmatch_T *const regmatch, char **const matches, + const int idx, const bool test_only, const bool fuzzy, + const char *const fuzzystr, fuzmatch_str_T *const fuzmatch) +{ + if (!fuzzy) { + if (vim_regexec(regmatch, str, (colnr_T)0)) { + if (!test_only) { + matches[idx] = xstrdup(str); + } + return true; + } + } else { + const int score = fuzzy_match_str(str, fuzzystr); + if (score != 0) { + if (!test_only) { + fuzmatch[idx].idx = idx; + fuzmatch[idx].str = xstrdup(str); + fuzmatch[idx].score = score; + } + return true; + } + } + return false; +} + +int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numMatches, + char ***matches, const bool can_fuzzy) { int num_normal = 0; // Nr of matching non-term-code settings int count = 0; static char *(names[]) = { "all" }; int ic = regmatch->rm_ic; // remember the ignore-case flag + fuzmatch_str_T *fuzmatch = NULL; + const bool fuzzy = can_fuzzy && cmdline_fuzzy_complete(fuzzystr); + // do this loop twice: // loop == 0: count the number of matching options // loop == 1: copy the matching options into allocated memory @@ -4712,11 +4836,12 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi if (xp->xp_context != EXPAND_BOOL_SETTINGS) { for (match = 0; match < (int)ARRAY_SIZE(names); match++) { - if (vim_regexec(regmatch, names[match], (colnr_T)0)) { + if (match_str(names[match], regmatch, *matches, + count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { if (loop == 0) { num_normal++; } else { - (*file)[count++] = xstrdup(names[match]); + count++; } } } @@ -4731,42 +4856,54 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi && !(options[opt_idx].flags & P_BOOL)) { continue; } - match = false; - if (vim_regexec(regmatch, str, (colnr_T)0) - || (options[opt_idx].shortname != NULL - && vim_regexec(regmatch, - options[opt_idx].shortname, - (colnr_T)0))) { - match = true; - } - if (match) { + if (match_str(str, regmatch, *matches, count, (loop == 0), + fuzzy, fuzzystr, fuzmatch)) { + if (loop == 0) { + num_normal++; + } else { + count++; + } + } else if (!fuzzy && options[opt_idx].shortname != NULL + && vim_regexec(regmatch, options[opt_idx].shortname, (colnr_T)0)) { + // Compare against the abbreviated option name (for regular + // expression match). Fuzzy matching (previous if) already + // matches against both the expanded and abbreviated names. if (loop == 0) { num_normal++; } else { - (*file)[count++] = xstrdup(str); + (*matches)[count++] = xstrdup(str); } } } if (loop == 0) { if (num_normal > 0) { - *num_file = num_normal; + *numMatches = num_normal; } else { return OK; } - *file = xmalloc((size_t)(*num_file) * sizeof(char *)); + if (!fuzzy) { + *matches = xmalloc((size_t)(*numMatches) * sizeof(char *)); + } else { + fuzmatch = xmalloc((size_t)(*numMatches) * sizeof(fuzmatch_str_T)); + } } } + + if (fuzzy) { + fuzzymatches_to_strmatches(fuzmatch, matches, count, false); + } + return OK; } -void ExpandOldSetting(int *num_file, char ***file) +void ExpandOldSetting(int *numMatches, char ***matches) { char *var = NULL; - *num_file = 0; - *file = xmalloc(sizeof(char_u *)); + *numMatches = 0; + *matches = xmalloc(sizeof(char *)); // For a terminal key code expand_option_idx is < 0. if (expand_option_idx < 0) { @@ -4783,7 +4920,7 @@ void ExpandOldSetting(int *num_file, char ***file) // A backslash is required before some characters. This is the reverse of // what happens in do_set(). - char_u *buf = (char_u *)vim_strsave_escaped(var, (char *)escape_chars); + char *buf = vim_strsave_escaped(var, escape_chars); #ifdef BACKSLASH_IN_FILENAME // For MS-Windows et al. we don't double backslashes at the start and @@ -4799,8 +4936,8 @@ void ExpandOldSetting(int *num_file, char ***file) } #endif - *file[0] = (char *)buf; - *num_file = 1; + *matches[0] = buf; + *numMatches = 1; } /// Get the value for the numeric or string option///opp in a nice format into @@ -4817,7 +4954,7 @@ static void option_value2string(vimoption_T *opp, int scope) if (wc_use_keyname((char_u *)varp, &wc)) { xstrlcpy(NameBuff, (char *)get_special_key_name((int)wc, 0), sizeof(NameBuff)); } else if (wc != 0) { - xstrlcpy(NameBuff, (char *)transchar((int)wc), sizeof(NameBuff)); + xstrlcpy(NameBuff, transchar((int)wc), sizeof(NameBuff)); } else { snprintf(NameBuff, sizeof(NameBuff), @@ -5035,10 +5172,11 @@ bool option_was_set(const char *name) void reset_option_was_set(const char *name) { const int idx = findoption(name); - - if (idx >= 0) { - options[idx].flags &= ~P_WAS_SET; + if (idx < 0) { + return; } + + options[idx].flags &= ~P_WAS_SET; } /// fill_breakat_flags() -- called when 'breakat' changes value. @@ -5199,16 +5337,16 @@ unsigned int get_ve_flags(void) /// /// @param win If not NULL, the window to get the local option from; global /// otherwise. -char_u *get_showbreak_value(win_T *const win) +char *get_showbreak_value(win_T *const win) FUNC_ATTR_WARN_UNUSED_RESULT { if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { - return (char_u *)p_sbr; + return p_sbr; } if (strcmp(win->w_p_sbr, "NONE") == 0) { - return (char_u *)empty_option; + return empty_option; } - return (char_u *)win->w_p_sbr; + return win->w_p_sbr; } /// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. @@ -5327,9 +5465,9 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars if (*p == '.') { buf[len++] = *p++; } - while (*p != NUL && vim_strchr(sep_chars, *p) == NULL) { + while (*p != NUL && vim_strchr(sep_chars, (uint8_t)(*p)) == NULL) { // Skip backslash before a separator character and space. - if (p[0] == '\\' && vim_strchr(sep_chars, p[1]) != NULL) { + if (p[0] == '\\' && vim_strchr(sep_chars, (uint8_t)p[1]) != NULL) { p++; } if (len < maxlen - 1) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 3ffab71f22..d190fc5999 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -442,7 +442,7 @@ EXTERN unsigned bo_flags; #define BO_SPELL 0x20000 #define BO_WILD 0x40000 -EXTERN char_u *p_bsk; // 'backupskip' +EXTERN char *p_bsk; // 'backupskip' EXTERN char *p_breakat; // 'breakat' EXTERN char *p_bh; ///< 'bufhidden' EXTERN char *p_bt; ///< 'buftype' @@ -468,7 +468,7 @@ EXTERN long p_columns; // 'columns' EXTERN int p_confirm; // 'confirm' EXTERN char *p_cot; // 'completeopt' #ifdef BACKSLASH_IN_FILENAME -EXTERN char_u *p_csl; // 'completeslash' +EXTERN char *p_csl; // 'completeslash' #endif EXTERN long p_pb; // 'pumblend' EXTERN long p_ph; // 'pumheight' @@ -494,9 +494,9 @@ EXTERN int p_ed; // 'edcompatible' EXTERN char *p_ead; // 'eadirection' EXTERN int p_emoji; // 'emoji' EXTERN int p_ea; // 'equalalways' -EXTERN char_u *p_ep; // 'equalprg' +EXTERN char *p_ep; // 'equalprg' EXTERN int p_eb; // 'errorbells' -EXTERN char_u *p_ef; // 'errorfile' +EXTERN char *p_ef; // 'errorfile' EXTERN char *p_efm; // 'errorformat' EXTERN char *p_gefm; // 'grepformat' EXTERN char *p_gp; // 'grepprg' @@ -531,12 +531,12 @@ EXTERN unsigned fdo_flags; EXTERN char *p_fex; ///< 'formatexpr' EXTERN char *p_flp; ///< 'formatlistpat' EXTERN char *p_fo; ///< 'formatoptions' -EXTERN char_u *p_fp; // 'formatprg' +EXTERN char *p_fp; // 'formatprg' EXTERN int p_fs; // 'fsync' EXTERN int p_gd; // 'gdefault' EXTERN char *p_guicursor; // 'guicursor' -EXTERN char_u *p_guifont; // 'guifont' -EXTERN char_u *p_guifontwide; // 'guifontwide' +EXTERN char *p_guifont; // 'guifont' +EXTERN char *p_guifontwide; // 'guifontwide' EXTERN char *p_hf; // 'helpfile' EXTERN long p_hh; // 'helpheight' EXTERN char *p_hlg; // 'helplang' @@ -568,17 +568,17 @@ EXTERN unsigned jop_flags; #define JOP_STACK 0x01 #define JOP_VIEW 0x02 EXTERN char *p_keymap; ///< 'keymap' -EXTERN char_u *p_kp; // 'keywordprg' +EXTERN char *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 char *p_lm; // 'langmenu' EXTERN long p_lines; // 'lines' EXTERN long p_linespace; // 'linespace' EXTERN int p_lisp; ///< 'lisp' EXTERN char *p_lop; ///< 'lispoptions' -EXTERN char_u *p_lispwords; // 'lispwords' +EXTERN char *p_lispwords; // 'lispwords' EXTERN long p_ls; // 'laststatus' EXTERN long p_stal; // 'showtabline' EXTERN char *p_lcs; // 'listchars' @@ -588,7 +588,7 @@ EXTERN int p_lpl; // 'loadplugins' EXTERN int p_magic; // 'magic' EXTERN char *p_menc; // 'makeencoding' EXTERN char *p_mef; // 'makeef' -EXTERN char_u *p_mp; // 'makeprg' +EXTERN char *p_mp; // 'makeprg' EXTERN char *p_mps; ///< 'matchpairs' EXTERN long p_mat; // 'matchtime' EXTERN long p_mco; // 'maxcombine' @@ -613,13 +613,13 @@ EXTERN long p_mouset; // 'mousetime' EXTERN int p_more; // 'more' EXTERN char *p_nf; ///< 'nrformats' EXTERN char *p_opfunc; // 'operatorfunc' -EXTERN char_u *p_para; // 'paragraphs' +EXTERN char *p_para; // 'paragraphs' EXTERN int p_paste; // 'paste' EXTERN char *p_pt; // 'pastetoggle' EXTERN char *p_pex; // 'patchexpr' EXTERN char *p_pm; // 'patchmode' -EXTERN char_u *p_path; // 'path' -EXTERN char_u *p_cdpath; // 'cdpath' +EXTERN char *p_path; // 'path' +EXTERN char *p_cdpath; // 'cdpath' EXTERN int p_pi; ///< 'preserveindent' EXTERN long p_pyx; // 'pyxversion' EXTERN char *p_qe; ///< 'quoteescape' @@ -673,11 +673,11 @@ EXTERN unsigned ssop_flags; #define SSOP_SKIP_RTP 0x20000 EXTERN char *p_sh; // 'shell' -EXTERN char_u *p_shcf; // 'shellcmdflag' +EXTERN char *p_shcf; // 'shellcmdflag' EXTERN char *p_sp; // 'shellpipe' EXTERN char *p_shq; // 'shellquote' EXTERN char *p_sxq; // 'shellxquote' -EXTERN char_u *p_sxe; // 'shellxescape' +EXTERN char *p_sxe; // 'shellxescape' EXTERN char *p_srr; // 'shellredir' EXTERN int p_stmp; // 'shelltemp' #ifdef BACKSLASH_IN_FILENAME @@ -725,7 +725,7 @@ 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 *p_su; // 'suffixes' EXTERN char *p_swb; // 'switchbuf' EXTERN unsigned swb_flags; // Keep in sync with p_swb_values in optionstr.c @@ -747,7 +747,7 @@ EXTERN unsigned tc_flags; ///< flags from 'tagcase' #define TC_SMART 0x10 EXTERN long p_tl; ///< 'taglength' EXTERN int p_tr; ///< 'tagrelative' -EXTERN char_u *p_tags; ///< 'tags' +EXTERN char *p_tags; ///< 'tags' EXTERN int p_tgst; ///< 'tagstack' EXTERN int p_tbidi; ///< 'termbidi' EXTERN long p_tw; ///< 'textwidth' @@ -756,13 +756,13 @@ EXTERN int p_timeout; ///< 'timeout' EXTERN long p_tm; ///< 'timeoutlen' EXTERN int p_title; ///< 'title' EXTERN long p_titlelen; ///< 'titlelen' -EXTERN char_u *p_titleold; ///< 'titleold' +EXTERN char *p_titleold; ///< 'titleold' EXTERN char *p_titlestring; ///< 'titlestring' -EXTERN char_u *p_tsr; ///< 'thesaurus' +EXTERN char *p_tsr; ///< 'thesaurus' EXTERN int p_tgc; ///< 'termguicolors' EXTERN int p_ttimeout; ///< 'ttimeout' EXTERN long p_ttm; ///< 'ttimeoutlen' -EXTERN char_u *p_udir; ///< 'undodir' +EXTERN char *p_udir; ///< 'undodir' EXTERN int p_udf; ///< 'undofile' EXTERN long p_ul; ///< 'undolevels' EXTERN long p_ur; ///< 'undoreload' @@ -778,15 +778,15 @@ EXTERN unsigned vop_flags; ///< uses SSOP_ flags EXTERN int p_vb; ///< 'visualbell' EXTERN char *p_ve; ///< 'virtualedit' EXTERN unsigned ve_flags; -#define VE_BLOCK 5U // includes "all" -#define VE_INSERT 6U // includes "all" +#define VE_BLOCK 5U // includes "all" +#define VE_INSERT 6U // includes "all" #define VE_ALL 4U #define VE_ONEMORE 8U -#define VE_NONE 16U // "none" -#define VE_NONEU 32U // "NONE" +#define VE_NONE 16U // "none" +#define VE_NONEU 32U // "NONE" EXTERN long p_verbose; // 'verbose' #ifdef IN_OPTION_C -char_u *p_vfile = (char_u *)""; // used before options are initialized +char *p_vfile = ""; // used before options are initialized #else extern char *p_vfile; // 'verbosefile' #endif @@ -795,6 +795,7 @@ EXTERN char *p_wop; // 'wildoptions' EXTERN unsigned wop_flags; #define WOP_TAGFILE 0x01 #define WOP_PUM 0x02 +#define WOP_FUZZY 0x04 EXTERN long p_window; // 'window' EXTERN char *p_wak; // 'winaltkeys' EXTERN char *p_wig; // 'wildignore' diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index a97e9b7c7e..ca50c3ab00 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -3,6 +3,7 @@ #include <assert.h> #include <stdbool.h> +#include <stdint.h> #include <string.h> #include "nvim/api/private/helpers.h" @@ -90,7 +91,7 @@ static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vspli 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 }; +static char *(p_wop_values[]) = { "tagfile", "pum", "fuzzy", NULL }; static char *(p_wak_values[]) = { "yes", "menu", "no", NULL }; static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos", "mac", NULL }; static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL }; @@ -166,36 +167,37 @@ void trigger_optionset_string(int opt_idx, int opt_flags, char *oldval, char *ol char *oldval_g, char *newval) { // Don't do this recursively. - if (oldval != NULL - && newval != NULL - && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char buf_type[7]; + if (oldval == NULL || newval == NULL + || *get_vim_var_str(VV_OPTION_TYPE) != NUL) { + return; + } - vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", - (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_OLD, oldval, -1); - set_vim_var_string(VV_OPTION_NEW, newval, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); - } - if (opt_flags & OPT_GLOBAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - set_vim_var_string(VV_OPTION_COMMAND, "set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); - } - if (opt_flags & OPT_MODELINE) { - set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); - } - apply_autocmds(EVENT_OPTIONSET, get_option(opt_idx)->fullname, NULL, false, NULL); - reset_v_option_vars(); + char buf_type[7]; + + vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", + (opt_flags & OPT_LOCAL) ? "local" : "global"); + set_vim_var_string(VV_OPTION_OLD, oldval, -1); + set_vim_var_string(VV_OPTION_NEW, newval, -1); + set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1); } + apply_autocmds(EVENT_OPTIONSET, get_option(opt_idx)->fullname, NULL, false, NULL); + reset_v_option_vars(); } static char *illegal_char(char *errbuf, size_t errbuflen, int c) @@ -204,7 +206,7 @@ static char *illegal_char(char *errbuf, size_t errbuflen, int c) return ""; } vim_snprintf(errbuf, errbuflen, _("E539: Illegal character <%s>"), - (char *)transchar(c)); + transchar(c)); return errbuf; } @@ -612,8 +614,8 @@ char *check_stl_option(char *s) groupdepth++; continue; } - if (vim_strchr(STL_ALL, *s) == NULL) { - return illegal_char(errbuf, sizeof(errbuf), *s); + if (vim_strchr(STL_ALL, (uint8_t)(*s)) == NULL) { + return illegal_char(errbuf, sizeof(errbuf), (uint8_t)(*s)); } if (*s == '{') { bool reevaluate = (*++s == '%'); @@ -636,952 +638,1238 @@ char *check_stl_option(char *s) return NULL; } -static int shada_idx = -1; +/// 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. +static bool check_illegal_path_names(char *val, uint32_t flags) +{ + return (((flags & P_NFNAME) + && strpbrk(val, (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL) + || ((flags & P_NDNAME) + && strpbrk(val, "*?[|;&<>\r\n") != NULL)); +} -/// Handle string options that need some action to perform when changed. -/// The new value must be allocated. -/// -/// @param opt_idx index in options[] table -/// @param varp pointer to the option variable -/// @param oldval previous value of the option -/// @param errbuf buffer for errors, or NULL -/// @param errbuflen length of errors buffer -/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL -/// @param value_checked value was checked to be safe, no need to set P_INSECURE -/// -/// @return NULL for success, or an untranslated error message for an error -char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, size_t errbuflen, - int opt_flags, int *value_checked) +static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, char **errmsg) { - char *errmsg = NULL; - char *s, *p; - int did_chartab = false; - vimoption_T *opt = get_option(opt_idx); - bool free_oldval = (opt->flags & P_ALLOCED); - bool value_changed = false; + char *bkc = p_bkc; + unsigned int *flags = &bkc_flags; - // Get the global option to compare with, otherwise we would have to check - // two values for all local options. - char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL); + if (opt_flags & OPT_LOCAL) { + bkc = buf->b_p_bkc; + flags = &buf->b_bkc_flags; + } - // Disallow changing some options from secure mode - if ((secure || sandbox != 0) - && (opt->flags & P_SECURE)) { - errmsg = e_secure; - } 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 *bkc = p_bkc; - unsigned int *flags = &bkc_flags; + if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else { + if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { + *errmsg = e_invarg; + } - if (opt_flags & OPT_LOCAL) { - bkc = curbuf->b_p_bkc; - flags = &curbuf->b_bkc_flags; + if (((*flags & BKC_AUTO) != 0) + + ((*flags & BKC_YES) != 0) + + ((*flags & BKC_NO) != 0) != 1) { + // Must have exactly one of "auto", "yes" and "no". + (void)opt_strings_flags(oldval, p_bkc_values, flags, true); + *errmsg = e_invarg; } + } +} - if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else { - if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { - errmsg = e_invarg; - } +static void did_set_backupext_or_patchmode(char **errmsg) +{ + if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, + *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { + *errmsg = e_backupext_and_patchmode_are_equal; + } +} - if (((*flags & BKC_AUTO) != 0) - + ((*flags & BKC_YES) != 0) - + ((*flags & BKC_NO) != 0) != 1) { - // Must have exactly one of "auto", "yes" and "no". - (void)opt_strings_flags(oldval, p_bkc_values, flags, true); - errmsg = e_invarg; - } - } - } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode' - if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex, - *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { - errmsg = e_backupext_and_patchmode_are_equal; - } - } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt' - if (briopt_check(curwin) == FAIL) { - errmsg = e_invarg; - } - // list setting requires a redraw - if (curwin->w_briopt_list) { - redraw_all_later(UPD_NOT_VALID); - } - } else if (varp == &p_isi - || varp == &(curbuf->b_p_isk) - || varp == &p_isp - || varp == &p_isf) { - // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] - // If the new option is invalid, use old value. 'lisp' option: refill - // g_chartab[] for '-' char - if (init_chartab() == FAIL) { - did_chartab = true; // need to restore it below - errmsg = e_invarg; // error in value - } - } else if (varp == &p_hf) { // 'helpfile' - // May compute new values for $VIM and $VIMRUNTIME - if (didset_vim) { - vim_unsetenv_ext("VIM"); - } - if (didset_vimruntime) { - vim_unsetenv_ext("VIMRUNTIME"); - } - } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath' - runtime_search_path_invalidate(); - } else if (varp == &curwin->w_p_culopt - || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' - if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) { - errmsg = e_invarg; - } - } else if (varp == &curwin->w_p_cc) { // 'colorcolumn' - errmsg = check_colorcolumn(curwin); - } else if (varp == &p_hlg) { // 'helplang' - // Check for "", "ab", "ab,cd", etc. - for (s = p_hlg; *s != NUL; s += 3) { - if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { - errmsg = e_invarg; - break; - } - if (s[2] == NUL) { - break; - } - } - } else if (varp == &p_hl) { // 'highlight' - if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { - errmsg = e_unsupportedoption; - } - } else if (varp == &p_jop) { // 'jumpoptions' - if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_nf) { // 'nrformats' - if (check_opt_strings(*varp, p_nf_values, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_ssop) { // 'sessionoptions' - if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { - errmsg = e_invarg; - } - if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { - // Don't allow both "sesdir" and "curdir". - (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); - errmsg = e_invarg; - } - } else if (varp == &p_vop) { // 'viewoptions' - if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) { - errmsg = e_invarg; +static void did_set_breakindentopt(win_T *win, char **errmsg) +{ + if (briopt_check(win) == FAIL) { + *errmsg = e_invarg; + } + // list setting requires a redraw + if (win == curwin && win->w_briopt_list) { + redraw_all_later(UPD_NOT_VALID); + } +} + +static void did_set_isopt(buf_T *buf, bool *did_chartab, char **errmsg) +{ + // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // If the new option is invalid, use old value. + // 'lisp' option: refill g_chartab[] for '-' char + if (buf_init_chartab(buf, true) == FAIL) { + *did_chartab = true; // need to restore it below + *errmsg = e_invarg; // error in value + } +} + +static void did_set_helpfile(void) +{ + // May compute new values for $VIM and $VIMRUNTIME + if (didset_vim) { + vim_unsetenv_ext("VIM"); + } + if (didset_vimruntime) { + vim_unsetenv_ext("VIMRUNTIME"); + } +} + +static void did_set_cursorlineopt(win_T *win, char **varp, char **errmsg) +{ + if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_helplang(char **errmsg) +{ + // Check for "", "ab", "ab,cd", etc. + for (char *s = p_hlg; *s != NUL; s += 3) { + if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { + *errmsg = e_invarg; + break; } - } else if (varp == &p_rdb) { // 'redrawdebug' - if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { - errmsg = e_invarg; + if (s[2] == NUL) { + break; } - } else if (varp == &p_sbo) { // 'scrollopt' - if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { - errmsg = e_invarg; + } +} + +static void did_set_highlight(char **varp, char **errmsg) +{ + if (strcmp(*varp, HIGHLIGHT_INIT) != 0) { + *errmsg = e_unsupportedoption; + } +} + +static void did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list, char **errmsg) +{ + if (opt_strings_flags(val, values, flagp, list) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_opt_strings(char *val, char **values, bool list, char **errmsg) +{ + did_set_opt_flags(val, values, NULL, list, errmsg); +} + +static void did_set_sessionoptions(char *oldval, char **errmsg) +{ + if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { + *errmsg = e_invarg; + } + if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { + // Don't allow both "sesdir" and "curdir". + (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); + *errmsg = e_invarg; + } +} + +static void did_set_ambiwidth(char **errmsg) +{ + if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { + *errmsg = e_invarg; + } else { + *errmsg = check_chars_options(); + } +} + +static void did_set_background(char **errmsg) +{ + if (check_opt_strings(p_bg, p_bg_values, false) != OK) { + *errmsg = e_invarg; + return; + } + + int dark = (*p_bg == 'd'); + + init_highlight(false, false); + + if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { + // The color scheme must have set 'background' back to another + // value, that's not what we want here. Disable the color + // scheme and set the colors again. + do_unlet(S_LEN("g:colors_name"), true); + free_string_option(p_bg); + p_bg = xstrdup((dark ? "dark" : "light")); + check_string_option(&p_bg); + init_highlight(false, false); + } +} + +static void did_set_wildmode(char **errmsg) +{ + if (check_opt_wim() == FAIL) { + *errmsg = e_invarg; + } +} + +static void did_set_winaltkeys(char **errmsg) +{ + if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_eventignore(char **errmsg) +{ + if (check_ei() == FAIL) { + *errmsg = e_invarg; + } +} + +// 'encoding', 'fileencoding' and 'makeencoding' +static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flags, char **errmsg) +{ + if (gvarp == &p_fenc) { + if (!MODIFIABLE(buf) && opt_flags != OPT_GLOBAL) { + *errmsg = e_modifiable; + return; } - } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth' - if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { - errmsg = e_invarg; - } else { - errmsg = check_chars_options(); - } - } else if (varp == &p_bg) { // 'background' - if (check_opt_strings(p_bg, p_bg_values, false) == OK) { - int dark = (*p_bg == 'd'); - - init_highlight(false, false); - - if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) { - // The color scheme must have set 'background' back to another - // value, that's not what we want here. Disable the color - // scheme and set the colors again. - do_unlet(S_LEN("g:colors_name"), true); - free_string_option(p_bg); - p_bg = xstrdup((dark ? "dark" : "light")); - check_string_option(&p_bg); - init_highlight(false, false); - } - } else { - errmsg = e_invarg; - } - } else if (varp == &p_wim) { // 'wildmode' - if (check_opt_wim() == FAIL) { - errmsg = e_invarg; - } - } else if (varp == &p_wop) { // 'wildoptions' - if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_wak) { // 'winaltkeys' - if (*p_wak == NUL - || check_opt_strings(p_wak, p_wak_values, false) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_ei) { // 'eventignore' - if (check_ei() == FAIL) { - errmsg = e_invarg; - } - } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) { - // 'encoding', 'fileencoding' and 'makeencoding' - if (gvarp == &p_fenc) { - if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) { - errmsg = e_modifiable; - } else if (vim_strchr(*varp, ',') != NULL) { - // No comma allowed in 'fileencoding'; catches confusing it - // with 'fileencodings'. - errmsg = e_invarg; - } else { - // May show a "+" in the title now. - redraw_titles(); - // Add 'fileencoding' to the swap file. - ml_setflags(curbuf); - } + + if (vim_strchr(*varp, ',') != NULL) { + // No comma allowed in 'fileencoding'; catches confusing it + // with 'fileencodings'. + *errmsg = e_invarg; + return; } - if (errmsg == NULL) { - // canonize the value, so that strcmp() can be used on it - p = enc_canonize(*varp); - xfree(*varp); - *varp = p; - if (varp == &p_enc) { - // only encoding=utf-8 allowed - if (strcmp(p_enc, "utf-8") != 0) { - errmsg = e_unsupportedoption; - } else { - spell_reload(); - } - } + // May show a "+" in the title now. + redraw_titles(); + // Add 'fileencoding' to the swap file. + ml_setflags(buf); + } + + // canonize the value, so that strcmp() can be used on it + char *p = enc_canonize(*varp); + xfree(*varp); + *varp = p; + if (varp == &p_enc) { + // only encoding=utf-8 allowed + if (strcmp(p_enc, "utf-8") != 0) { + *errmsg = e_unsupportedoption; + return; } - } else if (varp == &curbuf->b_p_keymap) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - int secure_save = secure; + spell_reload(); + } +} + +static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_checked, + char **errmsg) +{ + if (!valid_filetype(*varp)) { + *errmsg = e_invarg; + return; + } - // Reset the secure flag, since the value of 'keymap' has - // been checked to be safe. - secure = 0; + int secure_save = secure; - // load or unload key mapping tables - errmsg = keymap_init(); + // Reset the secure flag, since the value of 'keymap' has + // been checked to be safe. + secure = 0; - secure = secure_save; + // load or unload key mapping tables + *errmsg = keymap_init(); - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } + secure = secure_save; - if (errmsg == NULL) { - if (*curbuf->b_p_keymap != NUL) { - // Installed a new keymap, switch on using it. - curbuf->b_p_iminsert = B_IMODE_LMAP; - if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) { - curbuf->b_p_imsearch = B_IMODE_LMAP; - } - } else { - // Cleared the keymap, may reset 'iminsert' and 'imsearch'. - if (curbuf->b_p_iminsert == B_IMODE_LMAP) { - curbuf->b_p_iminsert = B_IMODE_NONE; - } - if (curbuf->b_p_imsearch == B_IMODE_LMAP) { - curbuf->b_p_imsearch = B_IMODE_USE_INSERT; - } - } - if ((opt_flags & OPT_LOCAL) == 0) { - set_iminsert_global(); - set_imsearch_global(); + // Since we check the value, there is no need to set P_INSECURE, + // even when the value comes from a modeline. + *value_checked = true; + + if (*errmsg == NULL) { + if (*buf->b_p_keymap != NUL) { + // Installed a new keymap, switch on using it. + buf->b_p_iminsert = B_IMODE_LMAP; + if (buf->b_p_imsearch != B_IMODE_USE_INSERT) { + buf->b_p_imsearch = B_IMODE_LMAP; } - status_redraw_curbuf(); - } - } else if (gvarp == &p_ff) { // 'fileformat' - if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) { - errmsg = e_modifiable; - } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { - errmsg = e_invarg; } else { - redraw_titles(); - // update flag in swap file - ml_setflags(curbuf); - // 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(UPD_NOT_VALID); + // Cleared the keymap, may reset 'iminsert' and 'imsearch'. + if (buf->b_p_iminsert == B_IMODE_LMAP) { + buf->b_p_iminsert = B_IMODE_NONE; + } + if (buf->b_p_imsearch == B_IMODE_LMAP) { + buf->b_p_imsearch = B_IMODE_USE_INSERT; } } - } else if (varp == &p_ffs) { // 'fileformats' - if (check_opt_strings(p_ffs, p_ff_values, true) != OK) { - errmsg = e_invarg; + if ((opt_flags & OPT_LOCAL) == 0) { + set_iminsert_global(buf); + set_imsearch_global(buf); } - } else if (gvarp == &p_mps) { // 'matchpairs' - for (p = *varp; *p != NUL; p++) { - int x2 = -1; - int x3 = -1; + status_redraw_buf(buf); + } +} + +static void did_set_fileformat(buf_T *buf, char **varp, const char *oldval, int opt_flags, + char **errmsg) +{ + if (!MODIFIABLE(buf) && !(opt_flags & OPT_GLOBAL)) { + *errmsg = e_modifiable; + } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { + *errmsg = e_invarg; + } else { + redraw_titles(); + // update flag in swap file + ml_setflags(buf); + // Redraw needed when switching to/from "mac": a CR in the text + // will be displayed differently. + if (get_fileformat(buf) == EOL_MAC || *oldval == 'm') { + redraw_buf_later(buf, UPD_NOT_VALID); + } + } +} + +static void did_set_matchpairs(char **varp, char **errmsg) +{ + for (char *p = *varp; *p != NUL; p++) { + int x2 = -1; + int x3 = -1; + p += utfc_ptr2len(p); + if (*p != NUL) { + x2 = (unsigned char)(*p++); + } + if (*p != NUL) { + x3 = utf_ptr2char(p); p += utfc_ptr2len(p); - if (*p != NUL) { - x2 = (unsigned char)(*p++); - } - if (*p != NUL) { - x3 = utf_ptr2char(p); - p += utfc_ptr2len(p); - } - if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { - errmsg = e_invarg; - break; - } - if (*p == NUL) { - break; - } } - } else if (gvarp == &p_com) { // 'comments' - for (s = *varp; *s;) { - while (*s && *s != ':') { - if (vim_strchr(COM_ALL, *s) == NULL - && !ascii_isdigit(*s) && *s != '-') { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - s++; - } - if (*s++ == NUL) { - errmsg = N_("E524: Missing colon"); - } else if (*s == ',' || *s == NUL) { - errmsg = N_("E525: Zero length string"); - } - if (errmsg != NULL) { + if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { + *errmsg = e_invarg; + break; + } + if (*p == NUL) { + break; + } + } +} + +static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + for (char *s = *varp; *s;) { + while (*s && *s != ':') { + if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL + && !ascii_isdigit(*s) && *s != '-') { + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); break; } - while (*s && *s != ',') { - if (*s == '\\' && s[1] != NUL) { - s++; - } + s++; + } + if (*s++ == NUL) { + *errmsg = N_("E524: Missing colon"); + } else if (*s == ',' || *s == NUL) { + *errmsg = N_("E525: Zero length string"); + } + if (*errmsg != NULL) { + break; + } + while (*s && *s != ',') { + if (*s == '\\' && s[1] != NUL) { s++; } - s = skip_to_option_part(s); - } - } 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) { - // 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(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. - 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(UPD_NOT_VALID); + s++; } - } else if (varp == &curwin->w_p_lcs) { // local 'listchars' - errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &curwin->w_p_fcs) { // local 'fillchars' - errmsg = set_chars_option(curwin, varp, true); - } else if (varp == &p_cedit) { // 'cedit' - errmsg = check_cedit(); - } else if (varp == &p_vfile) { // 'verbosefile' - verbose_stop(); - if (*p_vfile != NUL && verbose_open() == FAIL) { - errmsg = e_invarg; - } - } else if (varp == &p_shada) { // 'shada' - // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo - // option. - 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 = (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); - break; - } - if (*s == 'n') { // name is always last one - break; - } else if (*s == 'r') { // skip until next ',' - while (*++s && *s != ',') {} - } else if (*s == '%') { - // optional number - while (ascii_isdigit(*++s)) {} - } else if (*s == '!' || *s == 'h' || *s == 'c') { - s++; // no extra chars - } else { // must have a number - while (ascii_isdigit(*++s)) {} - - if (!ascii_isdigit(*(s - 1))) { - if (errbuf != NULL) { - vim_snprintf(errbuf, errbuflen, - _("E526: Missing number after <%s>"), - transchar_byte((uint8_t)(*(s - 1)))); - errmsg = errbuf; - } else { - errmsg = ""; - } - break; - } + s = skip_to_option_part(s); + } +} + +static void did_set_global_listfillchars(win_T *win, char **varp, int opt_flags, char **errmsg) +{ + char **local_ptr = varp == &p_lcs ? &win->w_p_lcs : &win->w_p_fcs; + // only apply the global value to "win" when it does not have a local value + *errmsg = set_chars_option(win, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); + if (*errmsg == NULL) { + // 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(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. + 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); } - if (*s == ',') { - s++; - } else if (*s) { + } + redraw_all_later(UPD_NOT_VALID); + } +} + +static void did_set_verbosefile(char **errmsg) +{ + verbose_stop(); + if (*p_vfile != NUL && verbose_open() == FAIL) { + *errmsg = e_invarg; + } +} + +static int shada_idx = -1; + +static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf, + size_t errbuflen, char **errmsg) +{ + // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo + // option. + *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 = ((*opt)->flags & P_ALLOCED); + for (char *s = p_shada; *s;) { + // Check it's a valid character + if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); + break; + } + if (*s == 'n') { // name is always last one + break; + } else if (*s == 'r') { // skip until next ',' + while (*++s && *s != ',') {} + } else if (*s == '%') { + // optional number + while (ascii_isdigit(*++s)) {} + } else if (*s == '!' || *s == 'h' || *s == 'c') { + s++; // no extra chars + } else { // must have a number + while (ascii_isdigit(*++s)) {} + + if (!ascii_isdigit(*(s - 1))) { if (errbuf != NULL) { - errmsg = N_("E527: Missing comma"); + vim_snprintf(errbuf, errbuflen, + _("E526: Missing number after <%s>"), + transchar_byte((uint8_t)(*(s - 1)))); + *errmsg = errbuf; } else { - errmsg = ""; + *errmsg = ""; } break; } } - if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) { - errmsg = N_("E528: Must specify a ' value"); - } - } else if (gvarp == &p_sbr) { // 'showbreak' - for (s = *varp; *s;) { - if (ptr2cells(s) != 1) { - errmsg = e_showbreak_contains_unprintable_or_wide_character; + if (*s == ',') { + s++; + } else if (*s) { + if (errbuf != NULL) { + *errmsg = N_("E527: Missing comma"); + } else { + *errmsg = ""; } - MB_PTR_ADV(s); + break; } - } else if (varp == &p_guicursor) { // 'guicursor' - errmsg = parse_shape_opt(SHAPE_CURSOR); - } else if (varp == &p_langmap) { // 'langmap' - langmap_set(); - } else if (varp == &p_breakat) { // 'breakat' - fill_breakat_flags(); - } else if (varp == &p_titlestring || varp == &p_iconstring) { - // 'titlestring' and 'iconstring' - int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; + } + if (*p_shada && *errmsg == NULL && get_shada_parameter('\'') < 0) { + *errmsg = N_("E528: Must specify a ' value"); + } +} - // NULL => statusline syntax - if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { - stl_syntax |= flagval; - } else { - stl_syntax &= ~flagval; +static void did_set_showbreak(char **varp, char **errmsg) +{ + for (char *s = *varp; *s;) { + if (ptr2cells(s) != 1) { + *errmsg = e_showbreak_contains_unprintable_or_wide_character; } - did_set_title(); - } else if (varp == &p_sel) { // 'selection' - if (*p_sel == NUL - || check_opt_strings(p_sel, p_sel_values, false) != OK) { - errmsg = e_invarg; + MB_PTR_ADV(s); + } +} + +static void did_set_titleiconstring(char **varp) +{ + // 'titlestring' and 'iconstring' + int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; + + // NULL => statusline syntax + if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { + stl_syntax |= flagval; + } else { + stl_syntax &= ~flagval; + } + did_set_title(); +} + +static void did_set_selection(char **errmsg) +{ + if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_keymodel(char **errmsg) +{ + if (check_opt_strings(p_km, p_km_values, true) != OK) { + *errmsg = e_invarg; + return; + } + km_stopsel = (vim_strchr(p_km, 'o') != NULL); + km_startsel = (vim_strchr(p_km, 'a') != NULL); +} + +static void did_set_display(char **errmsg) +{ + if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { + *errmsg = e_invarg; + return; + } + (void)init_chartab(); + msg_grid_validate(); +} + +static void did_set_spellfile(char **varp, char **errmsg) +{ + // When there is a window for this buffer in which 'spell' + // is set load the wordlists. + + if ((!valid_spellfile(*varp))) { + *errmsg = e_invarg; + } else { + *errmsg = did_set_spell_option(true); + } +} + +static void did_set_spell(char **varp, char **errmsg) +{ + // When there is a window for this buffer in which 'spell' + // is set load the wordlists. + if (!valid_spelllang(*varp)) { + *errmsg = e_invarg; + } else { + *errmsg = did_set_spell_option(false); + } +} + +static void did_set_spellcapcheck(win_T *win, char **errmsg) +{ + // When 'spellcapcheck' is set compile the regexp program. + *errmsg = compile_cap_prog(win->w_s); +} + +static void did_set_spelloptions(win_T *win, char **errmsg) +{ + if (opt_strings_flags(win->w_s->b_p_spo, p_spo_values, &(win->w_s->b_p_spo_flags), + true) != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_spellsuggest(char **errmsg) +{ + if (spell_check_sps() != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_mkspellmem(char **errmsg) +{ + if (spell_check_msm() != OK) { + *errmsg = e_invarg; + } +} + +static void did_set_buftype(buf_T *buf, win_T *win, char **errmsg) +{ + // When 'buftype' is set, check for valid value. + if ((buf->terminal && buf->b_p_bt[0] != 't') + || (!buf->terminal && buf->b_p_bt[0] == 't') + || check_opt_strings(buf->b_p_bt, p_buftype_values, false) != OK) { + *errmsg = e_invarg; + } else { + if (win->w_status_height || global_stl_height()) { + win->w_redr_status = true; + redraw_later(win, UPD_VALID); } - } else if (varp == &p_slm) { // 'selectmode' - if (check_opt_strings(p_slm, p_slm_values, true) != OK) { - errmsg = e_invarg; + buf->b_help = (buf->b_p_bt[0] == 'h'); + redraw_titles(); + } +} + +// 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' +static void did_set_statusline(win_T *win, char **varp, char **gvarp, char **errmsg) +{ + if (varp == &p_ruf) { // reset ru_wid first + ru_wid = 0; + } else if (varp == &win->w_p_stc) { + win->w_nrwidth_line_count = 0; + } + char *s = *varp; + if (varp == &p_ruf && *s == '%') { + // set ru_wid if 'ruf' starts with "%99(" + if (*++s == '-') { // ignore a '-' + s++; } - } else if (varp == &p_km) { // 'keymodel' - if (check_opt_strings(p_km, p_km_values, true) != OK) { - errmsg = e_invarg; + int wid = getdigits_int(&s, true, 0); + if (wid && *s == '(' && (*errmsg = check_stl_option(p_ruf)) == NULL) { + ru_wid = wid; } else { - km_stopsel = (vim_strchr(p_km, 'o') != NULL); - km_startsel = (vim_strchr(p_km, 'a') != NULL); + *errmsg = check_stl_option(p_ruf); } - } 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(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_ruf || s[0] != '%' || s[1] != '!') { + // check 'statusline', 'winbar', 'tabline' or 'statuscolumn' + // only if it doesn't start with "%!" + *errmsg = check_stl_option(s); + } + if (varp == &p_ruf && *errmsg == NULL) { + comp_col(); + } + // add / remove window bars for 'winbar' + if (gvarp == &p_wbr) { + set_winbar(true); + } +} + +static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, char **errmsg) +{ + // check if it is a valid value for 'complete' -- Acevedo + for (char *s = *varp; *s;) { + while (*s == ',' || *s == ' ') { + s++; } - } else if (varp == &p_spk) { // 'splitkeep' - if (check_opt_strings(p_spk, p_spk_values, false) != OK) { - errmsg = e_invarg; + if (!*s) { + break; } - } else if (varp == &p_debug) { // 'debug' - if (check_opt_strings(p_debug, p_debug_values, true) != OK) { - errmsg = e_invarg; + if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); + break; } - } else if (varp == &p_dy) { // 'display' - if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { - errmsg = e_invarg; - } else { - (void)init_chartab(); - msg_grid_validate(); - } - } else if (varp == &p_ead) { // 'eadirection' - if (check_opt_strings(p_ead, p_ead_values, false) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_cb) { // 'clipboard' - if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &(curwin->w_s->b_p_spl) // 'spell' - || varp == &(curwin->w_s->b_p_spf)) { - // When 'spelllang' or 'spellfile' is set and there is a window for this - // buffer in which 'spell' is set load the wordlists. - const bool is_spellfile = varp == &(curwin->w_s->b_p_spf); - - if ((is_spellfile && !valid_spellfile(*varp)) - || (!is_spellfile && !valid_spelllang(*varp))) { - errmsg = e_invarg; - } else { - errmsg = did_set_spell_option(is_spellfile); - } - } else if (varp == &(curwin->w_s->b_p_spc)) { - // 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 (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' - if (spell_check_sps() != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_msm) { // 'mkspellmem' - if (spell_check_msm() != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_bh) { - // When 'bufhidden' is set, check for valid value. - if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_bt) { - // When 'buftype' is set, check for valid value. - if ((curbuf->terminal && curbuf->b_p_bt[0] != 't') - || (!curbuf->terminal && curbuf->b_p_bt[0] == 't') - || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) { - errmsg = e_invarg; - } else { - if (curwin->w_status_height || global_stl_height()) { - curwin->w_redr_status = true; - redraw_later(curwin, UPD_VALID); - } - curbuf->b_help = (curbuf->b_p_bt[0] == 'h'); - redraw_titles(); - } - } else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal - || varp == &p_ruf || varp == &curwin->w_p_stc) { - // 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' - int wid; - - if (varp == &p_ruf) { // reset ru_wid first - ru_wid = 0; - } else if (varp == &curwin->w_p_stc) { - curwin->w_nrwidth_line_count = 0; - } - 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(p_ruf)) == NULL) { - ru_wid = wid; - } else { - errmsg = check_stl_option(p_ruf); - } - } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { - // check 'statusline', 'winbar', 'tabline' or 'statuscolumn' - // only if it doesn't start with "%!" - errmsg = check_stl_option(s); - } - if (varp == &p_ruf && errmsg == NULL) { - comp_col(); - } - // add / remove window bars for 'winbar' - if (gvarp == &p_wbr) { - set_winbar(true); - } - } else if (gvarp == &p_cpt) { - // check if it is a valid value for 'complete' -- Acevedo - for (s = *varp; *s;) { - while (*s == ',' || *s == ' ') { - s++; - } - if (!*s) { - break; - } - if (vim_strchr(".wbuksid]tU", *s) == NULL) { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - if (*++s != NUL && *s != ',' && *s != ' ') { - if (s[-1] == 'k' || s[-1] == 's') { - // skip optional filename after 'k' and 's' - while (*s && *s != ',' && *s != ' ') { - if (*s == '\\' && s[1] != NUL) { - s++; - } + if (*++s != NUL && *s != ',' && *s != ' ') { + if (s[-1] == 'k' || s[-1] == 's') { + // skip optional filename after 'k' and 's' + while (*s && *s != ',' && *s != ' ') { + if (*s == '\\' && s[1] != NUL) { s++; } + s++; + } + } else { + if (errbuf != NULL) { + vim_snprintf(errbuf, errbuflen, + _("E535: Illegal character after <%c>"), + *--s); + *errmsg = errbuf; } else { - if (errbuf != NULL) { - vim_snprintf(errbuf, errbuflen, - _("E535: Illegal character after <%c>"), - *--s); - errmsg = errbuf; - } else { - errmsg = ""; - } - break; + *errmsg = ""; } + break; } } - } else if (varp == &p_cot) { // 'completeopt' - if (check_opt_strings(p_cot, p_cot_values, true) != OK) { - errmsg = e_invarg; - } else { - completeopt_was_set(); - } + } +} + +static void did_set_completeopt(char **errmsg) +{ + if (check_opt_strings(p_cot, p_cot_values, true) != OK) { + *errmsg = e_invarg; + } else { + completeopt_was_set(); + } +} + #ifdef BACKSLASH_IN_FILENAME - } else if (gvarp == &p_csl) { // 'completeslash' - if (check_opt_strings(p_csl, p_csl_values, false) != OK - || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) { - errmsg = e_invarg; - } +static void did_set_completeslash(buf_T *buf, char **errmsg) +{ + if (check_opt_strings(p_csl, p_csl_values, false) != OK + || check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) { + *errmsg = e_invarg; + } +} #endif - } else if (varp == &curwin->w_p_scl) { // 'signcolumn' - if (check_signcolumn(*varp) != OK) { - errmsg = e_invarg; - } - // When changing the 'signcolumn' to or from 'number', recompute the - // width of the number column if 'number' or 'relativenumber' is set. - if (((*oldval == 'n' && *(oldval + 1) == 'u') - || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u')) - && (curwin->w_p_nu || curwin->w_p_rnu)) { - curwin->w_nrwidth_line_count = 0; - } - } else if (varp == &p_sloc) { // 'showcmdloc' - if (check_opt_strings(p_sloc, p_sloc_values, false) != OK) { - errmsg = e_invarg; - } - } 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; - } - } else if (varp == &p_pt) { - // 'pastetoggle': translate key codes like in a mapping - if (*p_pt) { - p = NULL; - (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 = p; - } - } - } else if (varp == &p_bs) { // 'backspace' - if (ascii_isdigit(*p_bs)) { - if (*p_bs > '3' || p_bs[1] != NUL) { - errmsg = e_invarg; - } - } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_bo) { - if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_tc) { // 'tagcase' - unsigned int *flags; - if (opt_flags & OPT_LOCAL) { - p = curbuf->b_p_tc; - flags = &curbuf->b_tc_flags; - } else { - p = p_tc; - flags = &tc_flags; - } +static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, char **errmsg) +{ + if (check_signcolumn(*varp) != OK) { + *errmsg = e_invarg; + } + // When changing the 'signcolumn' to or from 'number', recompute the + // width of the number column if 'number' or 'relativenumber' is set. + if (((*oldval == 'n' && *(oldval + 1) == 'u') + || (*win->w_p_scl == 'n' && *(win->w_p_scl + 1) == 'u')) + && (win->w_p_nu || win->w_p_rnu)) { + win->w_nrwidth_line_count = 0; + } +} - if ((opt_flags & OPT_LOCAL) && *p == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else if (*p == NUL - || opt_strings_flags(p, p_tc_values, flags, false) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_cmp) { // 'casemap' - if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_dip) { // 'diffopt' - if (diffopt_changed() == FAIL) { - errmsg = e_invarg; - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod' - if (check_opt_strings(*varp, p_fdm_values, false) != OK - || *curwin->w_p_fdm == NUL) { - errmsg = e_invarg; - } else { - foldUpdateAll(curwin); - if (foldmethodIsDiff(curwin)) { - newFoldLevel(); - } - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker' - p = vim_strchr(*varp, ','); - if (p == NULL) { - errmsg = N_("E536: comma required"); - } 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(*varp, "%s") == NULL) { - errmsg = N_("E537: 'commentstring' must be empty or contain %s"); - } - } else if (varp == &p_fdo) { // 'foldopen' - if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &p_fcl) { // 'foldclose' - if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore' - if (foldmethodIsIndent(curwin)) { - foldUpdateAll(curwin); - } - } else if (gvarp == &p_ve) { // 'virtualedit' - char *ve = p_ve; - unsigned int *flags = &ve_flags; +static void did_set_foldcolumn(char **varp, char **errmsg) +{ + if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) { + *errmsg = e_invarg; + } +} - if (opt_flags & OPT_LOCAL) { - ve = curwin->w_p_ve; - flags = &curwin->w_ve_flags; +static void did_set_pastetoggle(void) +{ + // 'pastetoggle': translate key codes like in a mapping + if (*p_pt) { + char *p = NULL; + (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 = p; } + } +} - if ((opt_flags & OPT_LOCAL) && *ve == NUL) { - // make the local value empty: use the global value - *flags = 0; - } else { - if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { - errmsg = e_invarg; - } else if (strcmp(p_ve, oldval) != 0) { - // Recompute cursor position in case the new 've' setting - // changes something. - validate_virtcol(); - coladvance(curwin->w_virtcol); - } +static void did_set_backspace(char **errmsg) +{ + if (ascii_isdigit(*p_bs)) { + if (*p_bs > '3' || p_bs[1] != NUL) { + *errmsg = e_invarg; } - } else if (gvarp == &p_cino) { // 'cinoptions' - // TODO(vim): recognize errors - parse_cino(curbuf); - } else if (gvarp == &p_lop) { // 'lispoptions' - if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) { - errmsg = e_invarg; - } - } else if (varp == &p_icm) { // 'inccommand' - if (check_opt_strings(p_icm, p_icm_values, false) != OK) { - errmsg = e_invarg; - } - } else if (gvarp == &p_ft) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - value_changed = strcmp(oldval, *varp) != 0; + } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { + *errmsg = e_invarg; + } +} - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } - } else if (gvarp == &p_syn) { - if (!valid_filetype(*varp)) { - errmsg = e_invarg; - } else { - value_changed = strcmp(oldval, *varp) != 0; +static void did_set_tagcase(buf_T *buf, int opt_flags, char **errmsg) +{ + unsigned int *flags; + char *p; - // Since we check the value, there is no need to set P_INSECURE, - // even when the value comes from a modeline. - *value_checked = true; - } - } else if (varp == &curwin->w_p_winhl) { - if (!parse_winhl_opt(curwin)) { - errmsg = e_invarg; - } - } else if (varp == &p_tpf) { - if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) { - errmsg = e_invarg; - } - } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop' - char *cp; + if (opt_flags & OPT_LOCAL) { + p = buf->b_p_tc; + flags = &buf->b_tc_flags; + } else { + p = p_tc; + flags = &tc_flags; + } - if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - XFREE_CLEAR(curbuf->b_p_vsts_array); - } else { - for (cp = *varp; *cp; cp++) { - if (ascii_isdigit(*cp)) { - continue; - } - if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { - continue; - } - errmsg = e_invarg; - break; - } - if (errmsg == NULL) { - long *oldarray = curbuf->b_p_vsts_array; - if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) { - xfree(oldarray); - } else { - errmsg = e_invarg; - } - } - } - } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop' - char *cp; + if ((opt_flags & OPT_LOCAL) && *p == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else if (*p == NUL + || opt_strings_flags(p, p_tc_values, flags, false) != OK) { + *errmsg = e_invarg; + } +} - if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { - XFREE_CLEAR(curbuf->b_p_vts_array); - } else { - for (cp = *varp; *cp; cp++) { - if (ascii_isdigit(*cp)) { - continue; - } - if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { - continue; - } - errmsg = e_invarg; - break; - } - if (errmsg == NULL) { - long *oldarray = curbuf->b_p_vts_array; - if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) { - xfree(oldarray); - if (foldmethodIsIndent(curwin)) { - foldUpdateAll(curwin); - } - } else { - errmsg = e_invarg; - } - } +static void did_set_diffopt(char **errmsg) +{ + if (diffopt_changed() == FAIL) { + *errmsg = e_invarg; + } +} + +static void did_set_foldmethod(win_T *win, char **varp, char **errmsg) +{ + if (check_opt_strings(*varp, p_fdm_values, false) != OK + || *win->w_p_fdm == NUL) { + *errmsg = e_invarg; + } else { + foldUpdateAll(win); + if (foldmethodIsDiff(win)) { + newFoldLevel(); } - } else if (varp == &p_dex - || varp == &curwin->w_p_fde - || varp == &curwin->w_p_fdt - || gvarp == &p_fex - || gvarp == &p_inex - || gvarp == &p_inde - || varp == &p_pex) { // '*expr' options - char **p_opt = NULL; + } +} - // If the option value starts with <SID> or s:, then replace that with - // the script identifier. +static void did_set_foldmarker(win_T *win, char **varp, char **errmsg) +{ + char *p = vim_strchr(*varp, ','); + if (p == NULL) { + *errmsg = N_("E536: comma required"); + } else if (p == *varp || p[1] == NUL) { + *errmsg = e_invarg; + } else if (foldmethodIsMarker(win)) { + foldUpdateAll(win); + } +} - if (varp == &p_dex) { // 'diffexpr' - p_opt = &p_dex; - } - if (varp == &curwin->w_p_fde) { // 'foldexpr' - p_opt = &curwin->w_p_fde; - } - if (varp == &curwin->w_p_fdt) { // 'foldtext' - p_opt = &curwin->w_p_fdt; - } - if (gvarp == &p_fex) { // 'formatexpr' - p_opt = &curbuf->b_p_fex; - } - if (gvarp == &p_inex) { // 'includeexpr' - p_opt = &curbuf->b_p_inex; - } - if (gvarp == &p_inde) { // 'indentexpr' - p_opt = &curbuf->b_p_inde; - } - if (varp == &p_pex) { // 'patchexpr' - p_opt = &p_pex; - } +static void did_set_commentstring(char **varp, char **errmsg) +{ + if (**varp != NUL && strstr(*varp, "%s") == NULL) { + *errmsg = N_("E537: 'commentstring' must be empty or contain %s"); + } +} - if (p_opt != NULL) { - char *name = get_scriptlocal_funcname(*p_opt); - if (name != NULL) { - free_string_option(*p_opt); - *p_opt = name; - } - } +static void did_set_foldignore(win_T *win) +{ + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); + } +} - if (varp == &curwin->w_p_fde && foldmethodIsExpr(curwin)) { - foldUpdateAll(curwin); - } - } else if (gvarp == &p_cfu) { // 'completefunc' - if (set_completefunc_option() == FAIL) { - errmsg = e_invarg; +static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, char **errmsg) +{ + char *ve = p_ve; + unsigned int *flags = &ve_flags; + + if (opt_flags & OPT_LOCAL) { + ve = win->w_p_ve; + flags = &win->w_ve_flags; + } + + if ((opt_flags & OPT_LOCAL) && *ve == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else { + if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) { + *errmsg = e_invarg; + } else if (strcmp(ve, oldval) != 0) { + // Recompute cursor position in case the new 've' setting + // changes something. + validate_virtcol_win(win); + // XXX: this only works when win == curwin + coladvance(win->w_virtcol); } - } else if (gvarp == &p_ofu) { // 'omnifunc' - if (set_omnifunc_option() == FAIL) { - errmsg = e_invarg; + } +} + +static void did_set_lispoptions(char **varp, char **errmsg) +{ + if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) { + *errmsg = e_invarg; + } +} + +static void did_set_filetype_or_syntax(char **varp, char *oldval, int *value_checked, + bool *value_changed, char **errmsg) +{ + if (!valid_filetype(*varp)) { + *errmsg = e_invarg; + return; + } + + *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. + *value_checked = true; +} + +static void did_set_winhl(win_T *win, char **errmsg) +{ + if (!parse_winhl_opt(win)) { + *errmsg = e_invarg; + } +} + +static void did_set_varsoftabstop(buf_T *buf, char **varp, char **errmsg) +{ + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { + XFREE_CLEAR(buf->b_p_vsts_array); + return; + } + + for (char *cp = *varp; *cp; cp++) { + if (ascii_isdigit(*cp)) { + continue; } - } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc' - if (set_thesaurusfunc_option() == FAIL) { - errmsg = e_invarg; + if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { + continue; } - } else if (varp == &p_opfunc) { // 'operatorfunc' - if (set_operatorfunc_option() == FAIL) { - errmsg = e_invarg; + *errmsg = e_invarg; + return; + } + + long *oldarray = buf->b_p_vsts_array; + if (tabstop_set(*varp, &(buf->b_p_vsts_array))) { + xfree(oldarray); + } else { + *errmsg = e_invarg; + } +} + +static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, char **errmsg) +{ + if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) { + XFREE_CLEAR(buf->b_p_vts_array); + return; + } + + for (char *cp = *varp; *cp; cp++) { + if (ascii_isdigit(*cp)) { + continue; } - } else if (varp == &p_qftf) { // 'quickfixtextfunc' - if (qf_process_qftf_option() == FAIL) { - errmsg = e_invarg; + if (*cp == ',' && cp > *varp && *(cp - 1) != ',') { + continue; } - } else if (gvarp == &p_tfu) { // 'tagfunc' - if (set_tagfunc_option() == FAIL) { - errmsg = e_invarg; + *errmsg = e_invarg; + return; + } + + long *oldarray = buf->b_p_vts_array; + if (tabstop_set(*varp, &(buf->b_p_vts_array))) { + xfree(oldarray); + if (foldmethodIsIndent(win)) { + foldUpdateAll(win); } } else { - // Options that are a list of flags. - p = NULL; - if (varp == &p_ww) { // 'whichwrap' - p = WW_ALL; - } - if (varp == &p_shm) { // 'shortmess' - p = SHM_ALL; - } else if (varp == &(p_cpo)) { // 'cpoptions' - p = CPO_VI; - } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' - p = FO_ALL; - } else if (varp == &curwin->w_p_cocu) { // 'concealcursor' - p = COCU_ALL; - } else if (varp == &p_mouse) { // 'mouse' - p = MOUSE_ALL; + *errmsg = e_invarg; + } +} + +static void did_set_optexpr(char **varp) +{ + char *name = get_scriptlocal_funcname(*varp); + if (name != NULL) { + free_string_option(*varp); + *varp = name; + } +} + +// handle option that is a list of flags. +static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size_t errbuflen, + char **errmsg) +{ + for (char *s = *varp; *s; s++) { + if (vim_strchr(flags, (uint8_t)(*s)) == NULL) { + *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s)); + break; } - if (p != NULL) { - for (s = *varp; *s; s++) { - if (vim_strchr(p, *s) == NULL) { - errmsg = illegal_char(errbuf, errbuflen, *s); - break; - } - } + } +} + +// When 'syntax' is set, load the syntax of that name +static void do_syntax_autocmd(buf_T *buf, bool value_changed) +{ + static int syn_recursive = 0; + + syn_recursive++; + // Only pass true for "force" when the value changed or not used + // recursively, to avoid endless recurrence. + apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, + value_changed || syn_recursive == 1, buf); + buf->b_flags |= BF_SYN_SET; + syn_recursive--; +} + +static void do_filetype_autocmd(buf_T *buf, char **varp, int opt_flags, bool value_changed) +{ + // 'filetype' is set, trigger the FileType autocommand + // Skip this when called from a modeline and the filetype was + // already set to this value. + if (!(opt_flags & OPT_MODELINE) || value_changed) { + static int ft_recursive = 0; + int secure_save = secure; + + // Reset the secure flag, since the value of 'filetype' has + // been checked to be safe. + secure = 0; + + ft_recursive++; + did_filetype = true; + // Only pass true for "force" when the value changed or not + // used recursively, to avoid endless recurrence. + apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, + value_changed || ft_recursive == 1, buf); + ft_recursive--; + // Just in case the old "buf" is now invalid + if (varp != &(buf->b_p_ft)) { + varp = NULL; + } + secure = secure_save; + } +} + +static void do_spelllang_source(win_T *win) +{ + char fname[200]; + char *q = win->w_s->b_p_spl; + + // Skip the first name if it is "cjk". + if (strncmp(q, "cjk,", 4) == 0) { + q += 4; + } + + // Source the spell/LANG.vim in 'runtimepath'. + // They could set 'spellcapcheck' depending on the language. + // Use the first name in 'spelllang' up to '_region' or + // '.encoding'. + char *p; + for (p = q; *p != NUL; p++) { + if (!ASCII_ISALNUM(*p) && *p != '-') { + break; } } + if (p > q) { + vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); + source_runtime(fname, DIP_ALL); + } +} + +/// Handle string options that need some action to perform when changed. +/// The new value must be allocated. +/// +/// @param opt_idx index in options[] table +/// @param varp pointer to the option variable +/// @param oldval previous value of the option +/// @param errbuf buffer for errors, or NULL +/// @param errbuflen length of errors buffer +/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL +/// @param value_checked value was checked to be safe, no need to set P_INSECURE +/// +/// @return NULL for success, or an untranslated error message for an error +static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char **varp, + char *oldval, char *errbuf, size_t errbuflen, int opt_flags, + int *value_checked) +{ + char *errmsg = NULL; + bool did_chartab = false; + 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. + char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL); - // If error detected, restore the previous value. + // Disallow changing some options from secure mode + if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) { + errmsg = e_secure; + // Check for a "normal" directory or file name in some options. + } else if (check_illegal_path_names(*varp, opt->flags)) { + errmsg = e_invarg; + } else if (gvarp == &p_bkc) { // 'backupcopy' + did_set_backupcopy(buf, oldval, opt_flags, &errmsg); + } else if (varp == &p_bex // 'backupext' + || varp == &p_pm) { // 'patchmode' + did_set_backupext_or_patchmode(&errmsg); + } else if (varp == &win->w_p_briopt) { // 'breakindentopt' + did_set_breakindentopt(win, &errmsg); + } else if (varp == &p_isi // 'isident' + || varp == &buf->b_p_isk // 'iskeyword' + || varp == &p_isp // 'isprint' + || varp == &p_isf) { // 'isfname' + did_set_isopt(buf, &did_chartab, &errmsg); + } else if (varp == &p_hf) { // 'helpfile' + did_set_helpfile(); + } else if (varp == &p_rtp // 'runtimepath' + || varp == &p_pp) { // 'packpath' + runtime_search_path_invalidate(); + } else if (gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt' + did_set_cursorlineopt(win, varp, &errmsg); + } else if (varp == &win->w_p_cc) { // 'colorcolumn' + errmsg = check_colorcolumn(win); + } else if (varp == &p_hlg) { // 'helplang' + did_set_helplang(&errmsg); + } else if (varp == &p_hl) { // 'highlight' + did_set_highlight(varp, &errmsg); + } else if (varp == &p_jop) { // 'jumpoptions' + did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg); + } else if (gvarp == &p_nf) { // 'nrformats' + did_set_opt_strings(*varp, p_nf_values, true, &errmsg); + } else if (varp == &p_ssop) { // 'sessionoptions' + did_set_sessionoptions(oldval, &errmsg); + } else if (varp == &p_vop) { // 'viewoptions' + did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg); + } else if (varp == &p_rdb) { // 'redrawdebug' + did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg); + } else if (varp == &p_sbo) { // 'scrollopt' + did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg); + } else if (varp == &p_ambw // 'ambiwidth' + || (int *)varp == &p_emoji) { // 'emoji' + did_set_ambiwidth(&errmsg); + } else if (varp == &p_bg) { // 'background' + did_set_background(&errmsg); + } else if (varp == &p_wim) { // 'wildmode' + did_set_wildmode(&errmsg); + } else if (varp == &p_wop) { // 'wildoptions' + did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg); + } else if (varp == &p_wak) { // 'winaltkeys' + did_set_winaltkeys(&errmsg); + } else if (varp == &p_ei) { // 'eventignore' + did_set_eventignore(&errmsg); + } else if (varp == &p_enc // 'encoding' + || gvarp == &p_fenc // 'fileencoding' + || gvarp == &p_menc) { // 'makeencoding' + did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg); + } else if (varp == &buf->b_p_keymap) { // 'keymap' + did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg); + } else if (gvarp == &p_ff) { // 'fileformat' + did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg); + } else if (varp == &p_ffs) { // 'fileformats' + did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg); + } else if (gvarp == &p_mps) { // 'matchpairs' + did_set_matchpairs(varp, &errmsg); + } else if (gvarp == &p_com) { // 'comments' + did_set_comments(varp, errbuf, errbuflen, &errmsg); + } else if (varp == &p_lcs // global 'listchars' + || varp == &p_fcs) { // global 'fillchars' + did_set_global_listfillchars(win, varp, opt_flags, &errmsg); + } else if (varp == &win->w_p_lcs) { // local 'listchars' + errmsg = set_chars_option(win, varp, true); + } else if (varp == &win->w_p_fcs) { // local 'fillchars' + errmsg = set_chars_option(win, varp, true); + } else if (varp == &p_cedit) { // 'cedit' + errmsg = check_cedit(); + } else if (varp == &p_vfile) { // 'verbosefile' + did_set_verbosefile(&errmsg); + } else if (varp == &p_shada) { // 'shada' + did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg); + } else if (gvarp == &p_sbr) { // 'showbreak' + did_set_showbreak(varp, &errmsg); + } else if (varp == &p_guicursor) { // 'guicursor' + errmsg = parse_shape_opt(SHAPE_CURSOR); + } else if (varp == &p_langmap) { // 'langmap' + langmap_set(); + } else if (varp == &p_breakat) { // 'breakat' + fill_breakat_flags(); + } else if (varp == &p_titlestring // 'titlestring' + || varp == &p_iconstring) { // 'iconstring' + did_set_titleiconstring(varp); + } else if (varp == &p_sel) { // 'selection' + did_set_selection(&errmsg); + } else if (varp == &p_slm) { // 'selectmode' + did_set_opt_strings(p_slm, p_slm_values, true, &errmsg); + } else if (varp == &p_km) { // 'keymodel' + did_set_keymodel(&errmsg); + } else if (varp == &p_mousem) { // 'mousemodel' + did_set_opt_strings(p_mousem, p_mousem_values, false, &errmsg); + } else if (varp == &p_mousescroll) { // 'mousescroll' + errmsg = check_mousescroll(p_mousescroll); + } else if (varp == &p_swb) { // 'switchbuf' + did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg); + } else if (varp == &p_spk) { // 'splitkeep' + did_set_opt_strings(p_spk, p_spk_values, false, &errmsg); + } else if (varp == &p_debug) { // 'debug' + did_set_opt_strings(p_debug, p_debug_values, true, &errmsg); + } else if (varp == &p_dy) { // 'display' + did_set_display(&errmsg); + } else if (varp == &p_ead) { // 'eadirection' + did_set_opt_strings(p_ead, p_ead_values, false, &errmsg); + } else if (varp == &p_cb) { // 'clipboard' + did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg); + } else if (varp == &win->w_s->b_p_spf) { // 'spellfile' + did_set_spellfile(varp, &errmsg); + } else if (varp == &win->w_s->b_p_spl) { // 'spell' + did_set_spell(varp, &errmsg); + } else if (varp == &win->w_s->b_p_spc) { // 'spellcapcheck' + did_set_spellcapcheck(win, &errmsg); + } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions' + did_set_spelloptions(win, &errmsg); + } else if (varp == &p_sps) { // 'spellsuggest' + did_set_spellsuggest(&errmsg); + } else if (varp == &p_msm) { // 'mkspellmem' + did_set_mkspellmem(&errmsg); + } else if (gvarp == &p_bh) { // 'bufhidden' + did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false, &errmsg); + } else if (gvarp == &p_bt) { // 'buftype' + did_set_buftype(buf, win, &errmsg); + } else if (gvarp == &p_stl // 'statusline' + || gvarp == &p_wbr // 'winbar' + || varp == &p_tal // 'tabline' + || varp == &p_ruf // 'rulerformat' + || varp == &win->w_p_stc) { // 'statuscolumn' + did_set_statusline(win, varp, gvarp, &errmsg); + } else if (gvarp == &p_cpt) { // 'complete' + did_set_complete(varp, errbuf, errbuflen, &errmsg); + } else if (varp == &p_cot) { // 'completeopt' + did_set_completeopt(&errmsg); +#ifdef BACKSLASH_IN_FILENAME + } else if (gvarp == &p_csl) { // 'completeslash' + did_set_completeslash(buf, &errmsg); +#endif + } else if (varp == &win->w_p_scl) { // 'signcolumn' + did_set_signcolumn(win, varp, oldval, &errmsg); + } else if (varp == &p_sloc) { // 'showcmdloc' + did_set_opt_strings(*varp, p_sloc_values, false, &errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn' + did_set_foldcolumn(varp, &errmsg); + } else if (varp == &p_pt) { // 'pastetoggle' + did_set_pastetoggle(); + } else if (varp == &p_bs) { // 'backspace' + did_set_backspace(&errmsg); + } else if (varp == &p_bo) { + did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg); + } else if (gvarp == &p_tc) { // 'tagcase' + did_set_tagcase(buf, opt_flags, &errmsg); + } else if (varp == &p_cmp) { // 'casemap' + did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg); + } else if (varp == &p_dip) { // 'diffopt' + did_set_diffopt(&errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod' + did_set_foldmethod(win, varp, &errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker' + did_set_foldmarker(win, varp, &errmsg); + } else if (gvarp == &p_cms) { // 'commentstring' + did_set_commentstring(varp, &errmsg); + } else if (varp == &p_fdo) { // 'foldopen' + did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg); + } else if (varp == &p_fcl) { // 'foldclose' + did_set_opt_strings(*varp, p_fcl_values, true, &errmsg); + } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore' + did_set_foldignore(win); + } else if (gvarp == &p_ve) { // 'virtualedit' + did_set_virtualedit(win, opt_flags, oldval, &errmsg); + } else if (gvarp == &p_cino) { // 'cinoptions' + // TODO(vim): recognize errors + parse_cino(buf); + } else if (gvarp == &p_lop) { // 'lispoptions' + did_set_lispoptions(varp, &errmsg); + } else if (varp == &p_icm) { // 'inccommand' + did_set_opt_strings(*varp, p_icm_values, false, &errmsg); + } else if (gvarp == &p_ft // 'filetype' + || gvarp == &p_syn) { // 'syntax' + did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg); + } else if (varp == &win->w_p_winhl) { // 'winhighlight' + did_set_winhl(win, &errmsg); + } else if (varp == &p_tpf) { + did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true, &errmsg); + } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop' + did_set_varsoftabstop(buf, varp, &errmsg); + } else if (varp == &buf->b_p_vts) { // 'vartabstop' + did_set_vartabstop(buf, win, varp, &errmsg); + } else if (varp == &p_dex // 'diffexpr' + || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr' + || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext' + || gvarp == &p_fex // 'formatexpr' + || gvarp == &p_inex // 'includeexpr' + || gvarp == &p_inde // 'indentexpr' + || varp == &p_pex // 'patchexpr' + || varp == &p_ccv) { // 'charconvert' + did_set_optexpr(varp); + if (varp == &win->w_p_fde && foldmethodIsExpr(win)) { + foldUpdateAll(win); + } + } else if (gvarp == &p_cfu) { // 'completefunc' + set_completefunc_option(&errmsg); + } else if (gvarp == &p_ofu) { // 'omnifunc' + set_omnifunc_option(buf, &errmsg); + } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc' + set_thesaurusfunc_option(&errmsg); + } else if (varp == &p_opfunc) { // 'operatorfunc' + set_operatorfunc_option(&errmsg); + } else if (varp == &p_qftf) { // 'quickfixtextfunc' + qf_process_qftf_option(&errmsg); + } else if (gvarp == &p_tfu) { // 'tagfunc' + set_tagfunc_option(&errmsg); + } else if (varp == &p_ww) { // 'whichwrap' + did_set_option_listflag(varp, WW_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_shm) { // 'shortmess' + did_set_option_listflag(varp, SHM_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_cpo) { // 'cpoptions' + did_set_option_listflag(varp, CPO_VI, errbuf, errbuflen, &errmsg); + } else if (varp == &buf->b_p_fo) { // 'formatoptions' + did_set_option_listflag(varp, FO_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &win->w_p_cocu) { // 'concealcursor' + did_set_option_listflag(varp, COCU_ALL, errbuf, errbuflen, &errmsg); + } else if (varp == &p_mouse) { // 'mouse' + did_set_option_listflag(varp, MOUSE_ALL, errbuf, errbuflen, &errmsg); + } else if (gvarp == &p_flp) { // 'formatlistpat' + if (win->w_briopt_list) { + // Changing Formatlistpattern when briopt includes the list setting: + // redraw + redraw_all_later(UPD_NOT_VALID); + } + } + + // If an error is detected, restore the previous value. if (errmsg != NULL) { free_string_option(*varp); *varp = oldval; // When resetting some values, need to act on it. if (did_chartab) { - (void)init_chartab(); + (void)buf_init_chartab(buf, true); } } else { // Remember where the option was set. @@ -1598,7 +1886,7 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf && (opt->indir & PV_BOTH)) { // global option with local value set to use global value; free // the local value and make it empty - p = get_varp_scope(opt, OPT_LOCAL); + char *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) { @@ -1607,65 +1895,12 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf } // Trigger the autocommand only after setting the flags. - // When 'syntax' is set, load the syntax of that name - if (varp == &(curbuf->b_p_syn)) { - static int syn_recursive = 0; - - syn_recursive++; - // Only pass true for "force" when the value changed or not used - // recursively, to avoid endless recurrence. - 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--; - } else if (varp == &(curbuf->b_p_ft)) { - // 'filetype' is set, trigger the FileType autocommand - // Skip this when called from a modeline and the filetype was - // already set to this value. - if (!(opt_flags & OPT_MODELINE) || value_changed) { - static int ft_recursive = 0; - int secure_save = secure; - - // Reset the secure flag, since the value of 'filetype' has - // been checked to be safe. - secure = 0; - - ft_recursive++; - did_filetype = true; - // Only pass true for "force" when the value changed or not - // used recursively, to avoid endless recurrence. - 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 - if (varp != &(curbuf->b_p_ft)) { - varp = NULL; - } - secure = secure_save; - } - } - if (varp == &(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) { - q += 4; - } - - // Source the spell/LANG.vim in 'runtimepath'. - // They could set 'spellcapcheck' depending on the language. - // Use the first name in 'spelllang' up to '_region' or - // '.encoding'. - for (p = q; *p != NUL; p++) { - if (!ASCII_ISALNUM(*p) && *p != '-') { - break; - } - } - if (p > q) { - vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); - source_runtime(fname, DIP_ALL); - } + if (varp == &buf->b_p_syn) { + do_syntax_autocmd(buf, value_changed); + } else if (varp == &buf->b_p_ft) { + do_filetype_autocmd(buf, varp, opt_flags, value_changed); + } else if (varp == &win->w_s->b_p_spl) { + do_spelllang_source(win); } } @@ -1673,22 +1908,23 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf setmouse(); // in case 'mouse' changed } - // Changing Formatlistpattern when briopt includes the list setting: - // redraw - if ((varp == &p_flp || varp == &(curbuf->b_p_flp)) && curwin->w_briopt_list) { - redraw_all_later(UPD_NOT_VALID); - } - - if (curwin->w_curswant != MAXCOL + if (win->w_curswant != MAXCOL && (opt->flags & (P_CURSWANT | P_RALL)) != 0) { - curwin->w_set_curswant = true; + win->w_set_curswant = true; } - check_redraw(opt->flags); + check_redraw_for(buf, win, opt->flags); return errmsg; } +char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf, size_t errbuflen, + int opt_flags, int *value_checked) +{ + return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, errbuf, errbuflen, + opt_flags, value_checked); +} + /// Check an option that can be a range of string values. /// /// @param list when true: accept a list of values diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index e1db7a8ef7..0611de14aa 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -543,7 +543,7 @@ void free_homedir(void) /// @see {expand_env} char *expand_env_save(char *src) { - return (char *)expand_env_save_opt(src, false); + return expand_env_save_opt(src, false); } /// Similar to expand_env_save() but when "one" is `true` handle the string as @@ -551,10 +551,10 @@ char *expand_env_save(char *src) /// @param src String containing environment variables to expand /// @param one Should treat as only one file name /// @see {expand_env} -char_u *expand_env_save_opt(char *src, bool one) +char *expand_env_save_opt(char *src, bool one) { - char_u *p = xmalloc(MAXPATHL); - expand_env_esc(src, (char *)p, MAXPATHL, false, one, NULL); + char *p = xmalloc(MAXPATHL); + expand_env_esc(src, p, MAXPATHL, false, one, NULL); return p; } @@ -656,7 +656,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es #endif } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) - || vim_strchr(" ,\t\n", src[1]) != NULL) { + || vim_strchr(" ,\t\n", (uint8_t)src[1]) != NULL) { var = homedir; tail = src + 1; } else { // user directory @@ -689,7 +689,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es #else // cannot expand user's home directory, so don't try var = NULL; - tail = (char_u *)""; // for gcc + tail = ""; // for gcc #endif // UNIX } @@ -697,7 +697,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es // 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 = xstrdup(var); + char *p = xstrdup(var); if (mustfree) { xfree(var); @@ -1198,7 +1198,7 @@ bool os_setenv_append_path(const char *fname) // No prescribed maximum on unix. # define MAX_ENVPATHLEN INT_MAX #endif - if (!path_is_absolute((char_u *)fname)) { + if (!path_is_absolute(fname)) { internal_error("os_setenv_append_path()"); return false; } diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index e93e1febcb..5af39555c9 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -16,6 +16,8 @@ #include "auto/config.h" #include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/log.h" #include "nvim/macros.h" #include "nvim/memory.h" #include "nvim/message.h" diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index e0449d468a..6157341ec9 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -146,11 +146,7 @@ bool os_isdir(const char *name) return false; } - if (!S_ISDIR(mode)) { - return false; - } - - return true; + return S_ISDIR(mode); } /// Check what `name` is: @@ -302,7 +298,9 @@ static bool is_executable(const char *name, char **abspath) static bool is_executable_ext(const char *name, char **abspath) FUNC_ATTR_NONNULL_ARG(1) { - const bool is_unix_shell = strstr((char *)path_tail(p_sh), "sh") != NULL; + const bool is_unix_shell = strstr(path_tail(p_sh), "powershell") == NULL + && strstr(path_tail(p_sh), "pwsh") == NULL + && strstr(path_tail(p_sh), "sh") != NULL; char *nameext = strrchr(name, '.'); size_t nameext_len = nameext ? strlen(nameext) : 0; xstrlcpy(os_buf, name, sizeof(os_buf)); @@ -328,11 +326,11 @@ static bool is_executable_ext(const char *name, char **abspath) const char *ext_end = ext; size_t ext_len = - copy_option_part(&ext_end, (char_u *)buf_end, + copy_option_part((char **)&ext_end, buf_end, sizeof(os_buf) - (size_t)(buf_end - os_buf), ENV_SEPSTR); if (ext_len != 0) { bool in_pathext = nameext_len == ext_len - && 0 == mb_strnicmp((char_u *)nameext, (char_u *)ext, ext_len); + && 0 == mb_strnicmp(nameext, ext, ext_len); if (((in_pathext || is_unix_shell) && is_executable(name, abspath)) || is_executable(os_buf, abspath)) { @@ -789,14 +787,14 @@ int os_setperm(const char *const name, int perm) // Return a pointer to the ACL of file "fname" in allocated memory. // Return NULL if the ACL is not available for whatever reason. -vim_acl_T os_get_acl(const char_u *fname) +vim_acl_T os_get_acl(const char *fname) { vim_acl_T ret = NULL; return ret; } // Set the ACL of file "fname" to "acl" (unless it's NULL). -void os_set_acl(const char_u *fname, vim_acl_T aclent) +void os_set_acl(const char *fname, vim_acl_T aclent) { if (aclent == NULL) { return; @@ -912,12 +910,11 @@ int os_file_is_writable(const char *name) /// Rename a file or directory. /// /// @return `OK` for success, `FAIL` for failure. -int os_rename(const char_u *path, const char_u *new_path) +int os_rename(const char *path, const char *new_path) FUNC_ATTR_NONNULL_ALL { int r; - RUN_UV_FS_FUNC(r, uv_fs_rename, (const char *)path, (const char *)new_path, - NULL); + RUN_UV_FS_FUNC(r, uv_fs_rename, path, new_path, NULL); return (r == kLibuvSuccess ? OK : FAIL); } @@ -1380,7 +1377,7 @@ bool os_is_reparse_point_include(const char *path) } p = utf16_path; - if (isalpha(p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) { + if (isalpha((uint8_t)p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) { p += 3; } else if (IS_PATH_SEP(p[0]) && IS_PATH_SEP(p[1])) { p += 2; diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 5d2ac1e102..759b3cf83c 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -44,7 +44,6 @@ typedef enum { static Stream read_stream = { .closed = true }; // Input before UI starts. 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 @@ -58,25 +57,14 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -void input_global_fd_init(int fd) -{ - global_fd = fd; -} - -/// Global TTY (or pipe for "-es") input stream, before UI starts. -int input_global_fd(void) -{ - return global_fd; -} - -void input_start(int fd) +void input_start(void) { if (!read_stream.closed) { return; } - input_global_fd_init(fd); - rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE); + used_stdin = true; + rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE); rstream_start(&read_stream, input_read_cb, NULL); } @@ -266,7 +254,8 @@ size_t input_enqueue(String keys) uint8_t buf[19] = { 0 }; // Do not simplify the keys here. Simplification will be done later. unsigned int new_size - = trans_special((const char **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, true, NULL); + = trans_special((const char **)&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, + NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h index 7026781407..6f25efdc7b 100644 --- a/src/nvim/os/input.h +++ b/src/nvim/os/input.h @@ -7,6 +7,8 @@ #include "nvim/api/private/defs.h" #include "nvim/event/multiqueue.h" +EXTERN bool used_stdin INIT(= false); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.h.generated.h" #endif diff --git a/src/nvim/os/nvim.manifest b/src/nvim/os/nvim.manifest new file mode 100644 index 0000000000..8878822a5d --- /dev/null +++ b/src/nvim/os/nvim.manifest @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> + <assemblyIdentity + processorArchitecture="*" + version="0.9.0.0" + type="win32" + name="Neovim" + /> + <description>Neovim</description> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <!-- Windows 10 and Windows 11 --> + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> + <!-- Windows 8.1 --> + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> + <!-- Windows 8 --> + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> + </application> + </compatibility> +</assembly> diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index ec0f03a1dc..006e27d28f 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -10,11 +10,12 @@ # include "os/os_win_console.c.generated.h" #endif +static char origTitle[256] = { 0 }; static HWND hWnd = NULL; static HICON hOrigIconSmall = NULL; static HICON hOrigIcon = NULL; -int os_get_conin_fd(void) +int os_open_conin_fd(void) { const HANDLE conin_handle = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, @@ -30,7 +31,7 @@ int os_get_conin_fd(void) void os_replace_stdin_to_conin(void) { close(STDIN_FILENO); - const int conin_fd = os_get_conin_fd(); + const int conin_fd = os_open_conin_fd(); assert(conin_fd == STDIN_FILENO); } @@ -92,3 +93,15 @@ void os_icon_init(void) } } } + +/// Saves the original Windows console title. +void os_title_save(void) +{ + GetConsoleTitle(origTitle, sizeof(origTitle)); +} + +/// Resets the original Windows console title. +void os_title_reset(void) +{ + SetConsoleTitle(origTitle); +} diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 8177f06c64..f1e2c5440f 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -221,7 +221,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // "command" below. len++; // add space for (j = 0; pat[i][j] != NUL; j++) { - if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL) { + if (vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) { len++; // may add a backslash } len++; @@ -304,14 +304,14 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // backslash inside backticks, before a special character // and before a backtick. if (intick - || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL + || vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j + 1]) != NULL || pat[i][j + 1] == '`') { *p++ = '\\'; } j++; } else if (!intick && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$') - && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL) { + && vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) { // Put a backslash before a special character, but not // when inside ``. And not for $var when EW_KEEPDOLLAR is // set. @@ -570,7 +570,7 @@ 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((char *)p_shcf, NULL) : 0); + size_t argc = tokenize(p_sh, NULL) + (cmd ? tokenize(p_shcf, NULL) : 0); char **rv = xmalloc((argc + 4) * sizeof(*rv)); // Split 'shell' @@ -581,7 +581,7 @@ char **shell_build_argv(const char *cmd, const char *extra_args) } if (cmd) { - i += tokenize((char *)p_shcf, rv + i); // Split 'shellcmdflag' + i += tokenize(p_shcf, rv + i); // Split 'shellcmdflag' rv[i++] = shell_xescape_xquote(cmd); // Copy (and escape) `cmd`. } @@ -1332,7 +1332,7 @@ static char *shell_xescape_xquote(const char *cmd) const char *ecmd = cmd; if (*p_sxe != NUL && strcmp(p_sxq, "(") == 0) { - ecmd = vim_strsave_escaped_ext(cmd, (char *)p_sxe, '^', false); + ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', false); } size_t ncmd_size = strlen(ecmd) + strlen(p_sxq) * 2 + 1; char *ncmd = xmalloc(ncmd_size); diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index a99a8d25ce..6b07b6ef70 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -121,7 +121,7 @@ char *get_xdg_home(const XDGVarType idx) #endif #ifdef BACKSLASH_IN_FILENAME - slash_adjust((char_u *)dir); + slash_adjust(dir); #endif } return dir; diff --git a/src/nvim/path.c b/src/nvim/path.c index 9350335e54..e4c2253357 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -6,6 +6,7 @@ #include <limits.h> #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> @@ -154,7 +155,7 @@ char *path_tail_with_sep(char *fname) /// @post if `len` is not null, stores the length of the executable name. /// /// @return The position of the last path separator + 1. -const char_u *invocation_path_tail(const char *invocation, size_t *len) +const char *invocation_path_tail(const char *invocation, size_t *len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) { const char *tail = get_past_head(invocation); @@ -171,7 +172,7 @@ const char_u *invocation_path_tail(const char *invocation, size_t *len) *len = (size_t)(p - tail); } - return (char_u *)tail; + return tail; } /// Get the next path component of a path name. @@ -210,10 +211,10 @@ int path_head_length(void) /// @return /// - True if path begins with a path head /// - False otherwise -bool is_path_head(const char_u *path) +bool is_path_head(const char *path) { #ifdef MSWIN - return isalpha(path[0]) && path[1] == ':'; + return isalpha((uint8_t)path[0]) && path[1] == ':'; #else return vim_ispathsep(*path); #endif @@ -228,7 +229,7 @@ char *get_past_head(const char *path) #ifdef MSWIN // May skip "c:" - if (is_path_head((char_u *)path)) { + if (is_path_head(path)) { retval = path + 2; } #endif @@ -510,7 +511,7 @@ char *FullName_save(const char *fname, bool force) char *save_abs_path(const char *name) FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - if (!path_is_absolute((char_u *)name)) { + if (!path_is_absolute(name)) { return FullName_save(name, true); } return xstrdup(name); @@ -535,7 +536,7 @@ bool path_has_wildcard(const char *p) // Windows: const char *wildcards = "?*$[`"; #endif - if (vim_strchr(wildcards, *p) != NULL + if (vim_strchr(wildcards, (uint8_t)(*p)) != NULL || (p[0] == '~' && p[1] != NUL)) { return true; } @@ -648,7 +649,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in } s = p + 1; } else if (path_end >= path + wildoff - && (vim_strchr("*?[{~$", *path_end) != NULL + && (vim_strchr("*?[{~$", (uint8_t)(*path_end)) != NULL #ifndef MSWIN || (!p_fic && (flags & EW_ICASE) && mb_isalpha(utf_ptr2char((char *)path_end))) #endif @@ -782,8 +783,8 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in // slow, thus skip it. size_t matches = (size_t)(gap->ga_len - start_len); if (matches > 0 && !got_int) { - qsort(((char_u **)gap->ga_data) + start_len, matches, - sizeof(char_u *), pstrcmp); + qsort(((char **)gap->ga_data) + start_len, matches, + sizeof(char *), pstrcmp); } return matches; } @@ -841,11 +842,11 @@ static bool is_unique(char *maybe_unique, garray_T *gap, int i) // expanding each into their equivalent path(s). static void expand_path_option(char *curdir, garray_T *gap) { - char_u *path_option = *curbuf->b_p_path == NUL ? p_path : (char_u *)curbuf->b_p_path; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { - copy_option_part((char **)&path_option, buf, MAXPATHL, " ,"); + copy_option_part(&path_option, buf, MAXPATHL, " ,"); if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1]))) { // Relative to current buffer: @@ -870,7 +871,7 @@ static void expand_path_option(char *curdir, garray_T *gap) STRCPY(buf, curdir); // relative to current directory } else if (path_with_url(buf)) { continue; // URL can't be used here - } else if (!path_is_absolute((char_u *)buf)) { + } else if (!path_is_absolute(buf)) { // Expand relative path to their full path equivalent size_t len = strlen(curdir); if (len + strlen(buf) + 3 > MAXPATHL) { @@ -894,11 +895,11 @@ static void expand_path_option(char *curdir, garray_T *gap) // path: /foo/bar/baz // fname: /foo/bar/baz/quux.txt // returns: ^this -static char_u *get_path_cutoff(char_u *fname, garray_T *gap) +static char *get_path_cutoff(char *fname, garray_T *gap) { int maxlen = 0; - char_u **path_part = (char_u **)gap->ga_data; - char_u *cutoff = NULL; + char **path_part = gap->ga_data; + char *cutoff = NULL; for (int i = 0; i < gap->ga_len; i++) { int j = 0; @@ -984,7 +985,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) } // Shorten the filename while maintaining its uniqueness - path_cutoff = (char *)get_path_cutoff((char_u *)path, &path_ga); + path_cutoff = get_path_cutoff(path, &path_ga); // Don't assume all files can be reached without path when search // pattern starts with **/, so only remove path_cutoff @@ -1011,7 +1012,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) } } - if (path_is_absolute((char_u *)path)) { + if (path_is_absolute(path)) { // Last resort: shorten relative to curdir if possible. // 'possible' means: // 1. It is under the current directory. @@ -1127,7 +1128,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl return 0; } - char *const paths = (char *)ga_concat_strings(&path_ga); + char *const paths = ga_concat_strings(&path_ga); ga_clear_strings(&path_ga); int glob_flags = 0; @@ -1137,7 +1138,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags); + globpath(paths, pattern, gap, glob_flags, false); xfree(paths); return gap->ga_len; @@ -1145,12 +1146,12 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl /// Return true if "p" contains what looks like an environment variable. /// Allowing for escaping. -static bool has_env_var(char_u *p) +static bool has_env_var(char *p) { for (; *p; MB_PTR_ADV(p)) { if (*p == '\\' && p[1] != NUL) { p++; - } else if (vim_strchr("$", *p) != NULL) { + } else if (vim_strchr("$", (uint8_t)(*p)) != NULL) { return true; } } @@ -1161,7 +1162,7 @@ static bool has_env_var(char_u *p) // 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) +static bool has_special_wildchar(char *p) { for (; *p; MB_PTR_ADV(p)) { // Disallow line break characters. @@ -1171,13 +1172,13 @@ static bool has_special_wildchar(char_u *p) // Allow for escaping. if (*p == '\\' && p[1] != NUL && p[1] != '\r' && p[1] != '\n') { p++; - } else if (vim_strchr(SPECIAL_WILDCHAR, *p) != NULL) { + } else if (vim_strchr(SPECIAL_WILDCHAR, (uint8_t)(*p)) != NULL) { // A { must be followed by a matching }. - if (*p == '{' && vim_strchr((char *)p, '}') == NULL) { + if (*p == '{' && vim_strchr(p, '}') == NULL) { continue; } // A quote and backtick must be followed by another one. - if ((*p == '`' || *p == '\'') && vim_strchr((char *)p, *p) == NULL) { + if ((*p == '`' || *p == '\'') && vim_strchr(p, (uint8_t)(*p)) == NULL) { continue; } return true; @@ -1231,7 +1232,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i // 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]) + if (has_special_wildchar(pat[i]) && !(vim_backtick(pat[i]) && pat[i][1] == '=')) { return os_expand_wildcards(num_pat, pat, num_file, file, flags); } @@ -1258,8 +1259,8 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } } else { // First expand environment variables, "~/" and "~user/". - if ((has_env_var((char_u *)p) && !(flags & EW_NOTENV)) || *p == '~') { - p = (char *)expand_env_save_opt(p, true); + if ((has_env_var(p) && !(flags & EW_NOTENV)) || *p == '~') { + p = expand_env_save_opt(p, true); if (p == NULL) { p = pat[i]; } else { @@ -1267,7 +1268,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, 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((char_u *)p) || *p == '~') { + if (has_env_var(p) || *p == '~') { xfree(p); ga_clear_strings(&ga); i = os_expand_wildcards(num_pat, pat, num_file, file, @@ -1286,7 +1287,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i // given. if (path_has_exp_wildcard(p) || (flags & EW_ICASE)) { if ((flags & EW_PATH) - && !path_is_absolute((char_u *)p) + && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) || (p[1] == '.' @@ -1413,9 +1414,9 @@ static int expand_backtick(garray_T *gap, char *pat, int flags) /// backslash twice. /// When 'shellslash' set do it the other way around. /// When the path looks like a URL leave it unmodified. -void slash_adjust(char_u *p) +void slash_adjust(char *p) { - if (path_with_url((const char *)p)) { + if (path_with_url(p)) { return; } @@ -1428,8 +1429,8 @@ void slash_adjust(char_u *p) } while (*p) { - if (*p == (char_u)psepcN) { - *p = (char_u)psepc; + if (*p == psepcN) { + *p = psepc; } MB_PTR_ADV(p); } @@ -1460,7 +1461,7 @@ void addfile(garray_T *gap, char *f, int flags) #ifdef FNAME_ILLEGAL // if the file/dir contains illegal characters, don't add it - if (strpbrk((char *)f, FNAME_ILLEGAL) != NULL) { + if (strpbrk(f, FNAME_ILLEGAL) != NULL) { return; } #endif @@ -1477,7 +1478,7 @@ void addfile(garray_T *gap, char *f, int flags) return; } - char_u *p = xmalloc(strlen(f) + 1 + isdir); + char *p = xmalloc(strlen(f) + 1 + isdir); STRCPY(p, f); #ifdef BACKSLASH_IN_FILENAME @@ -1485,9 +1486,9 @@ void addfile(garray_T *gap, char *f, int flags) #endif // Append a slash or backslash after directory names if none is present. if (isdir && (flags & EW_ADDSLASH)) { - add_pathsep((char *)p); + add_pathsep(p); } - GA_APPEND(char_u *, gap, p); + GA_APPEND(char *, gap, p); } // Converts a file name into a canonical form. It simplifies a file name into @@ -1689,8 +1690,8 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha } if (options & FNAME_EXP) { - file_name = (char *)find_file_in_path(ptr, len, options & ~FNAME_MESS, true, - rel_fname); + file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, true, + rel_fname); // If the file could not be found in a normal way, try applying // 'includeexpr' (unless done already). @@ -1700,8 +1701,8 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha if (tofree != NULL) { ptr = tofree; len = strlen(ptr); - file_name = (char *)find_file_in_path(ptr, len, options & ~FNAME_MESS, - true, rel_fname); + file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, + true, rel_fname); } } if (file_name == NULL && (options & FNAME_MESS)) { @@ -1716,7 +1717,7 @@ char *find_file_name_in_path(char *ptr, size_t len, int options, long count, cha while (file_name != NULL && --count > 0) { xfree(file_name); file_name = - (char *)find_file_in_path(ptr, len, options, false, rel_fname); + find_file_in_path(ptr, len, options, false, rel_fname); } } else { file_name = xstrnsave(ptr, len); @@ -1767,7 +1768,7 @@ int path_with_url(const char *fname) // non-URL text. // first character must be alpha - if (!isalpha(*fname)) { + if (!ASCII_ISALPHA(*fname)) { return 0; } @@ -1776,7 +1777,7 @@ int path_with_url(const char *fname) } // check body: alpha or dash - for (p = fname + 1; (isalpha(*p) || (*p == '-')); p++) {} + for (p = fname + 1; (ASCII_ISALPHA(*p) || (*p == '-')); p++) {} // check last char is not a dash if (p[-1] == '-') { @@ -1799,7 +1800,7 @@ bool path_with_extension(const char *path, const char *extension) /// Return true if "name" is a full (absolute) path name or URL. bool vim_isAbsName(char *name) { - return path_with_url(name) != 0 || path_is_absolute((char_u *)name); + return path_with_url(name) != 0 || path_is_absolute(name); } /// Save absolute file name to "buf[len]". @@ -1823,7 +1824,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 MSWIN - slash_adjust((char_u *)buf); + slash_adjust(buf); #endif return FAIL; } @@ -1838,7 +1839,7 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force) xstrlcpy(buf, fname, len); // something failed; use the filename } #ifdef MSWIN - slash_adjust((char_u *)buf); + slash_adjust(buf); #endif return rv; } @@ -1858,7 +1859,7 @@ char *fix_fname(const char *fname) #ifdef UNIX return FullName_save(fname, true); #else - if (!vim_isAbsName((char_u *)fname) + if (!vim_isAbsName((char *)fname) || strstr(fname, "..") != NULL || strstr(fname, "//") != NULL # ifdef BACKSLASH_IN_FILENAME @@ -2075,7 +2076,7 @@ char *path_shorten_fname(char *full_path, char *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((char_u *)dir_name)) { + if (len == (size_t)path_head_length() && is_path_head(dir_name)) { return full_path + len; } @@ -2123,9 +2124,9 @@ int expand_wildcards_eval(char **pat, int *num_file, char ***file, int flags) if (is_cur_alt_file || *exp_pat == '<') { emsg_off++; - eval_pat = (char *)eval_vars((char_u *)exp_pat, (char_u *)exp_pat, &usedlen, NULL, &ignored_msg, - NULL, - true); + eval_pat = eval_vars(exp_pat, exp_pat, &usedlen, NULL, &ignored_msg, + NULL, + true); emsg_off--; if (eval_pat != NULL) { star_follows = strcmp(exp_pat + usedlen, "*") == 0; @@ -2185,15 +2186,15 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int // Remove names that match 'wildignore'. if (*p_wig) { - char_u *ffname; + char *ffname; // check all files in (*files)[] assert(*num_files == 0 || *files != NULL); for (i = 0; i < *num_files; i++) { - ffname = (char_u *)FullName_save((*files)[i], false); + ffname = FullName_save((*files)[i], false); assert((*files)[i] != NULL); assert(ffname != NULL); - if (match_file_list((char_u *)p_wig, (char_u *)(*files)[i], ffname)) { + if (match_file_list(p_wig, (*files)[i], ffname)) { // remove this matching file from the list xfree((*files)[i]); for (j = i; j + 1 < *num_files; j++) { @@ -2240,7 +2241,7 @@ int match_suffix(char *fname) size_t fnamelen = strlen(fname); size_t setsuflen = 0; - for (char *setsuf = (char *)p_su; *setsuf;) { + for (char *setsuf = p_su; *setsuf;) { setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,"); if (setsuflen == 0) { char *tail = path_tail(fname); @@ -2290,7 +2291,7 @@ int path_full_dir_name(char *directory, char *buffer, size_t len) // Path does not exist (yet). For a full path fail, // will use the path as-is. For a relative path use // the current directory and append the file name. - if (path_is_absolute((const char_u *)directory)) { + if (path_is_absolute(directory)) { // Do not return immediately since we may be in the wrong directory. retval = FAIL; } else { @@ -2360,7 +2361,7 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force) char *end_of_path = (char *)fname; // expand it if forced or not an absolute path - if (force || !path_is_absolute((char_u *)fname)) { + if (force || !path_is_absolute(fname)) { p = strrchr(fname, '/'); #ifdef MSWIN if (p == NULL) { @@ -2389,14 +2390,14 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force) /// Check if file `fname` is a full (absolute) path. /// /// @return `true` if "fname" is absolute. -int path_is_absolute(const char_u *fname) +int path_is_absolute(const char *fname) { #ifdef MSWIN if (*fname == NUL) { return false; } // A name like "d:/foo" and "//server/share" is absolute - return ((isalpha(fname[0]) && fname[1] == ':' && vim_ispathsep_nocolon(fname[2])) + return ((isalpha((uint8_t)fname[0]) && fname[1] == ':' && vim_ispathsep_nocolon(fname[2])) || (vim_ispathsep_nocolon(fname[0]) && fname[0] == fname[1])); #else // UNIX: This just checks if the file name starts with '/' or '~'. @@ -2416,7 +2417,7 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize) { const char *path = os_getenv("PATH"); - if (path == NULL || path_is_absolute((char_u *)argv0)) { + if (path == NULL || path_is_absolute(argv0)) { xstrlcpy(buf, argv0, bufsize); } else if (argv0[0] == '.' || strchr(argv0, PATHSEP)) { // Relative to CWD. diff --git a/src/nvim/plines.c b/src/nvim/plines.c index e4d1ddf8d8..5469d94800 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -23,7 +23,6 @@ #include "nvim/option.h" #include "nvim/plines.h" #include "nvim/pos.h" -#include "nvim/types.h" #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -52,7 +51,7 @@ int plines_win(win_T *wp, linenr_T lnum, bool winheight) /// @return Number of filler lines above lnum int win_get_fill(win_T *wp, linenr_T lnum) { - int virt_lines = decor_virt_lines(wp, lnum, NULL); + int virt_lines = decor_virt_lines(wp, lnum, NULL, kNone); // be quick when there are no filler lines if (diffopt_filler()) { @@ -441,7 +440,7 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) // Set *headp to the size of what we add. // Do not use 'showbreak' at the NUL after the text. added = 0; - char *const sbr = c == NUL ? empty_option : (char *)get_showbreak_value(wp); + char *const sbr = c == NUL ? empty_option : get_showbreak_value(wp); if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { colnr_T sbrlen = 0; int numberwidth = win_col_off(wp); diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po index 7d6af4d2cf..eb7879efc4 100644 --- a/src/nvim/po/tr.po +++ b/src/nvim/po/tr.po @@ -5625,9 +5625,6 @@ msgstr "$VIMRUNTIME öntanımlı konumu: \"" msgid "Nvim is open source and freely distributable" msgstr "Nvim açık kaynaklıdır ve özgürce dağıtılabilir" -msgid "https://neovim.io/#chat" -msgstr "https://neovim.io/#chat" - msgid "type :help nvim<Enter> if you are new! " msgstr "eğer yeniyseniz :help nvim<Enter> " diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index b521e37177..06f845f113 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -5550,9 +5550,6 @@ msgstr " заміна для $VIMRUNTIME: \"" msgid "Nvim is open source and freely distributable" msgstr "Nvim — це відкрита й вільно розповсюджувана програма" -msgid "https://neovim.io/#chat" -msgstr "https://neovim.io/#chat" - msgid "type :help nvim<Enter> if you are new! " msgstr ":help nvim<Enter> якщо ви вперше! " diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po index 0606adcc37..af050823d3 100644 --- a/src/nvim/po/zh_CN.UTF-8.po +++ b/src/nvim/po/zh_CN.UTF-8.po @@ -19,7 +19,7 @@ msgstr "" "Project-Id-Version: Vim(Simplified Chinese)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-11-17 08:00+0800\n" -"PO-Revision-Date: 2022-11-17 22:29+0800\n" +"PO-Revision-Date: 2023-01-24 13:00+0800\n" "Last-Translator: Sizhe Zhao <prc.zhao@outlook.com>\n" "Language-Team: Simplified Chinese <i18n-translation@lists.linux.net.cn>\n" "Language: zh_CN\n" @@ -7248,17 +7248,13 @@ msgstr " $VIMRUNTIME 预设值: \"" msgid "Nvim is open source and freely distributable" msgstr "Nvim 是可自由分发的开放源代码软件" -#: ../version.c:2806 -msgid "https://neovim.io/#chat" -msgstr "" - #: ../version.c:2808 msgid "type :help nvim<Enter> if you are new! " -msgstr "" +msgstr "输入 :help nvim<Enter> 了解 Neovim! " #: ../version.c:2809 msgid "type :checkhealth<Enter> to optimize Nvim" -msgstr "" +msgstr "输入 :checkhealth<Enter> 优化 Neovim " #: ../version.c:2810 msgid "type :q<Enter> to exit " @@ -7266,11 +7262,12 @@ msgstr "输入 :q<Enter> 退出 " #: ../version.c:2811 msgid "type :help<Enter> for help " -msgstr "" +msgstr "输入 :help<Enter> 查看帮助 " #: ../version.c:2813 -msgid "type :help news<Enter> to see changes in" -msgstr "" +#, c-format +msgid "type :help news<Enter> to see changes in v%s.%s" +msgstr "输入 :help news<Enter> 查看 v%s.%s 的变化" #: ../version.c:2816 msgid "Help poor children in Uganda!" diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 1d55b2ef31..245ce87865 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -218,11 +218,16 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i // pum above "pum_win_row" pum_above = true; - // Leave two lines of context if possible - if (curwin->w_wrow - curwin->w_cline_row >= 2) { - context_lines = 2; + if (State == MODE_CMDLINE) { + // for cmdline pum, no need for context lines + context_lines = 0; } else { - context_lines = curwin->w_wrow - curwin->w_cline_row; + // Leave two lines of context if possible + if (curwin->w_wrow - curwin->w_cline_row >= 2) { + context_lines = 2; + } else { + context_lines = curwin->w_wrow - curwin->w_cline_row; + } } if (pum_win_row >= size + context_lines) { @@ -241,13 +246,17 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i // pum below "pum_win_row" pum_above = false; - // Leave two lines of context if possible - validate_cheight(); - if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) { - context_lines = 3; + if (State == MODE_CMDLINE) { + // for cmdline pum, no need for context lines + context_lines = 0; } else { - context_lines = curwin->w_cline_row - + curwin->w_cline_height - curwin->w_wrow; + // Leave two lines of context if possible + validate_cheight(); + if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) { + context_lines = 3; + } else { + context_lines = curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow; + } } pum_row = pum_win_row + context_lines; @@ -815,7 +824,7 @@ static bool pum_set_selected(int n, int repeat) // When the preview window was resized we need to // update the view on the buffer. Only go back to // the window when needed, otherwise it will always be - // redraw. + // redrawn. if (resized) { no_u_sync++; win_enter(curwin_save, true); @@ -878,6 +887,7 @@ void pum_check_clear(void) grid_free(&pum_grid); } pum_is_drawn = false; + pum_external = false; } } diff --git a/src/nvim/profile.c b/src/nvim/profile.c index 866834fc71..fd024f2d38 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -299,7 +299,7 @@ void ex_profile(exarg_T *eap) if (len == 5 && strncmp(eap->arg, "start", 5) == 0 && *e != NUL) { xfree(profile_fname); - profile_fname = (char *)expand_env_save_opt(e, true); + profile_fname = expand_env_save_opt(e, true); do_profiling = PROF_YES; profile_set_wait(profile_zero()); set_vim_var_nr(VV_PROFILING, 1L); @@ -354,7 +354,6 @@ char *get_profile_name(expand_T *xp, int idx) switch (pexpand_what) { case PEXP_SUBCMD: return pexpand_cmds[idx]; - // case PEXP_FUNC: TODO default: return NULL; } @@ -373,13 +372,17 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg) return; } - if (end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0) { + if ((end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0) + || (end_subcmd - arg == 4 && strncmp(arg, "file", 4) == 0)) { xp->xp_context = EXPAND_FILES; xp->xp_pattern = skipwhite(end_subcmd); return; + } else if (end_subcmd - arg == 4 && strncmp(arg, "func", 4) == 0) { + xp->xp_context = EXPAND_USER_FUNC; + xp->xp_pattern = skipwhite(end_subcmd); + return; } - // TODO(tarruda): expand function names after "func" xp->xp_context = EXPAND_NOTHING; } @@ -700,17 +703,17 @@ void script_prof_save(proftime_T *tm) /// Count time spent in children after invoking another script or function. void script_prof_restore(const proftime_T *tm) { - scriptitem_T *si; + if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) { + return; + } - if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { - si = &SCRIPT_ITEM(current_sctx.sc_sid); - if (si->sn_prof_on && --si->sn_pr_nest == 0) { - si->sn_pr_child = profile_end(si->sn_pr_child); - // don't count wait time - si->sn_pr_child = profile_sub_wait(*tm, si->sn_pr_child); - si->sn_pr_children = profile_add(si->sn_pr_children, si->sn_pr_child); - si->sn_prl_children = profile_add(si->sn_prl_children, si->sn_pr_child); - } + scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); + if (si->sn_prof_on && --si->sn_pr_nest == 0) { + si->sn_pr_child = profile_end(si->sn_pr_child); + // don't count wait time + si->sn_pr_child = profile_sub_wait(*tm, si->sn_pr_child); + si->sn_pr_children = profile_add(si->sn_pr_children, si->sn_pr_child); + si->sn_prl_children = profile_add(si->sn_prl_children, si->sn_pr_child); } } @@ -784,17 +787,17 @@ static void script_dump_profile(FILE *fd) /// Dump the profiling info. void profile_dump(void) { - FILE *fd; + if (profile_fname == NULL) { + return; + } - if (profile_fname != NULL) { - fd = os_fopen(profile_fname, "w"); - if (fd == NULL) { - semsg(_(e_notopen), profile_fname); - } else { - script_dump_profile(fd); - func_dump_profile(fd); - fclose(fd); - } + FILE *fd = os_fopen(profile_fname, "w"); + if (fd == NULL) { + semsg(_(e_notopen), profile_fname); + } else { + script_dump_profile(fd); + func_dump_profile(fd); + fclose(fd); } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index c895ac16f1..5518fdfa51 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -384,9 +384,9 @@ static char *efmpat_to_regpat(const char *efmpat, char *regpat, efm_T *efminfo, return NULL; } if ((idx && idx < FMT_PATTERN_R - && vim_strchr("DXOPQ", efminfo->prefix) != NULL) + && vim_strchr("DXOPQ", (uint8_t)efminfo->prefix) != NULL) || (idx == FMT_PATTERN_R - && vim_strchr("OPQ", efminfo->prefix) == NULL)) { + && vim_strchr("OPQ", (uint8_t)efminfo->prefix) == NULL)) { semsg(_("E373: Unexpected %%%c in format string"), *efmpat); return NULL; } @@ -468,10 +468,10 @@ static char *scanf_fmt_to_regpat(const char **pefmp, const char *efm, int len, c static const char *efm_analyze_prefix(const char *efmp, efm_T *efminfo) FUNC_ATTR_NONNULL_ALL { - if (vim_strchr("+-", *efmp) != NULL) { + if (vim_strchr("+-", (uint8_t)(*efmp)) != NULL) { efminfo->flags = *efmp++; } - if (vim_strchr("DXAEWINCZGOPQ", *efmp) != NULL) { + if (vim_strchr("DXAEWINCZGOPQ", (uint8_t)(*efmp)) != NULL) { efminfo->prefix = *efmp; } else { semsg(_("E376: Invalid %%%c in format string prefix"), *efmp); @@ -510,7 +510,7 @@ static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) if (ptr == NULL) { return FAIL; } - } else if (vim_strchr("%\\.^$~[", *efmp) != NULL) { + } else if (vim_strchr("%\\.^$~[", (uint8_t)(*efmp)) != NULL) { *ptr++ = *efmp; // regexp magic characters } else if (*efmp == '#') { *ptr++ = '*'; @@ -530,7 +530,7 @@ static int efm_to_regpat(const char *efm, int len, efm_T *fmt_ptr, char *regpat) } else { // copy normal character if (*efmp == '\\' && efmp + 1 < efm + len) { efmp++; - } else if (vim_strchr(".*^$~[", *efmp) != NULL) { + } else if (vim_strchr(".*^$~[", (uint8_t)(*efmp)) != NULL) { *ptr++ = '\\'; // escape regexp atoms } if (*efmp) { @@ -868,7 +868,7 @@ static int qf_get_nextline(qfstate_T *state) #endif } - remove_bom((char_u *)state->linebuf); + remove_bom(state->linebuf); return QF_OK; } @@ -925,7 +925,7 @@ restofline: // match or no match. fields->valid = true; for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { - idx = (char_u)fmt_ptr->prefix; + idx = (uint8_t)fmt_ptr->prefix; status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields, qfl->qf_multiline, qfl->qf_multiscan, &tail); @@ -1190,13 +1190,15 @@ 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; - char *p = xmallocz(len); - - qfl->qf_title = p; - xstrlcpy(p, title, len + 1); + if (title == NULL) { + return; } + + size_t len = strlen(title) + 1; + char *p = xmallocz(len); + + qfl->qf_title = p; + xstrlcpy(p, title, len + 1); } /// The title of a quickfix/location list is set, by default, to the command @@ -1483,7 +1485,7 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc if ((idx == 'C' || idx == 'Z') && !qf_multiline) { return QF_FAIL; } - if (vim_strchr("EWIN", idx) != NULL) { + if (vim_strchr("EWIN", (uint8_t)idx) != NULL) { fields->type = idx; } else { fields->type = 0; @@ -1524,7 +1526,7 @@ static int qf_parse_match(char *linebuf, size_t linelen, efm_T *fmt_ptr, regmatc static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qffields_T *fields, int qf_multiline, int qf_multiscan, char **tail) { - if (qf_multiscan && vim_strchr("OPQ", fmt_ptr->prefix) == NULL) { + if (qf_multiscan && vim_strchr("OPQ", (uint8_t)fmt_ptr->prefix) == NULL) { return QF_FAIL; } @@ -1684,14 +1686,16 @@ int qf_stack_get_bufnr(void) static void wipe_qf_buffer(qf_info_T *qi) FUNC_ATTR_NONNULL_ALL { - if (qi->qf_bufnr != INVALID_QFBUFNR) { - buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr); - if (qfbuf != NULL && qfbuf->b_nwindows == 0) { - // If the quickfix buffer is not loaded in any window, then - // wipe the buffer. - close_buffer(NULL, qfbuf, DOBUF_WIPE, false, false); - qi->qf_bufnr = INVALID_QFBUFNR; - } + if (qi->qf_bufnr == INVALID_QFBUFNR) { + return; + } + + buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr); + if (qfbuf != NULL && qfbuf->b_nwindows == 0) { + // If the quickfix buffer is not loaded in any window, then + // wipe the buffer. + close_buffer(NULL, qfbuf, DOBUF_WIPE, false, false); + qi->qf_bufnr = INVALID_QFBUFNR; } } @@ -3168,15 +3172,15 @@ void qf_list(exarg_T *eap) // Get the attributes for the different quickfix highlight items. Note // that this depends on syntax items defined in the qf.vim syntax file - qfFileAttr = syn_name2attr((char_u *)"qfFileName"); + qfFileAttr = syn_name2attr("qfFileName"); if (qfFileAttr == 0) { qfFileAttr = HL_ATTR(HLF_D); } - qfSepAttr = syn_name2attr((char_u *)"qfSeparator"); + qfSepAttr = syn_name2attr("qfSeparator"); if (qfSepAttr == 0) { qfSepAttr = HL_ATTR(HLF_D); } - qfLineAttr = syn_name2attr((char_u *)"qfLineNr"); + qfLineAttr = syn_name2attr("qfLineNr"); if (qfLineAttr == 0) { qfLineAttr = HL_ATTR(HLF_N); } @@ -3850,10 +3854,11 @@ static buf_T *qf_find_buf(qf_info_T *qi) } /// Process the 'quickfixtextfunc' option value. -/// @return OK or FAIL -int qf_process_qftf_option(void) +void qf_process_qftf_option(char **errmsg) { - return option_set_callback_func(p_qftf, &qftf_cb); + if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL) { + *errmsg = e_invarg; + } } /// Update the w:quickfix_title variable in the quickfix/location list window in @@ -3878,59 +3883,61 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) { // Check if a buffer for the quickfix list exists. Update it. buf_T *buf = qf_find_buf(qi); - if (buf != NULL) { - linenr_T old_line_count = buf->b_ml.ml_line_count; - int qf_winid = 0; - - win_T *win; - if (IS_LL_STACK(qi)) { - if (curwin->w_llist == qi) { - win = curwin; - } else { - // Find the file window (non-quickfix) with this location list - win = qf_find_win_with_loclist(qi); - if (win == NULL) { - // File window is not found. Find the location list window. - win = qf_find_win(qi); - } - if (win == NULL) { - return; - } + if (buf == NULL) { + return; + } + + linenr_T old_line_count = buf->b_ml.ml_line_count; + int qf_winid = 0; + + win_T *win; + if (IS_LL_STACK(qi)) { + if (curwin->w_llist == qi) { + win = curwin; + } else { + // Find the file window (non-quickfix) with this location list + win = qf_find_win_with_loclist(qi); + if (win == NULL) { + // File window is not found. Find the location list window. + win = qf_find_win(qi); + } + if (win == NULL) { + return; } - qf_winid = (int)win->handle; } + qf_winid = (int)win->handle; + } - // autocommands may cause trouble - incr_quickfix_busy(); - - aco_save_T aco; + // autocommands may cause trouble + incr_quickfix_busy(); - if (old_last == NULL) { - // set curwin/curbuf to buf and save a few things - aucmd_prepbuf(&aco, buf); - } + aco_save_T aco; - qf_update_win_titlevar(qi); + if (old_last == NULL) { + // set curwin/curbuf to buf and save a few things + aucmd_prepbuf(&aco, buf); + } - qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); - buf_inc_changedtick(buf); + qf_update_win_titlevar(qi); - if (old_last == NULL) { - (void)qf_win_pos_update(qi, 0); + qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid); + buf_inc_changedtick(buf); - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - } + if (old_last == NULL) { + (void)qf_win_pos_update(qi, 0); - // 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, UPD_NOT_VALID); - } + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + } - // always called after incr_quickfix_busy() - decr_quickfix_busy(); + // 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, UPD_NOT_VALID); } + + // always called after incr_quickfix_busy() + decr_quickfix_busy(); } // Add an error line to the quickfix buffer. @@ -3959,11 +3966,11 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli // buffer. if (first_bufline && (errbuf->b_sfname == NULL - || path_is_absolute((char_u *)errbuf->b_sfname))) { + || path_is_absolute(errbuf->b_sfname))) { if (*dirname == NUL) { os_dirname(dirname, MAXPATHL); } - shorten_buf_fname(errbuf, (char_u *)dirname, false); + shorten_buf_fname(errbuf, dirname, false); } xstrlcpy(IObuff, errbuf->b_fname, IOSIZE); } @@ -3997,7 +4004,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli IObuff + len, IOSIZE - len); } - if (ml_append_buf(buf, lnum, (char_u *)IObuff, + if (ml_append_buf(buf, lnum, IObuff, (colnr_T)strlen(IObuff) + 1, false) == FAIL) { return FAIL; } @@ -4188,14 +4195,16 @@ static int qf_id2nr(const qf_info_T *const qi, const unsigned qfid) static int qf_restore_list(qf_info_T *qi, unsigned save_qfid) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (qf_get_curlist(qi)->qf_id != save_qfid) { - const int curlist = qf_id2nr(qi, save_qfid); - if (curlist < 0) { - // list is not present - return FAIL; - } - qi->qf_curlist = curlist; + if (qf_get_curlist(qi)->qf_id == save_qfid) { + return OK; + } + + const int curlist = qf_id2nr(qi, save_qfid); + if (curlist < 0) { + // list is not present + return FAIL; } + qi->qf_curlist = curlist; return OK; } @@ -5040,8 +5049,8 @@ void ex_cfile(exarg_T *eap) // first error. // :caddfile adds to an existing quickfix list. If there is no // quickfix list then a new list is created. - int res = qf_init(wp, (char *)p_ef, p_efm, (eap->cmdidx != CMD_caddfile - && eap->cmdidx != CMD_laddfile), + int res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile + && eap->cmdidx != CMD_laddfile), qf_cmdtitle(*eap->cmdlinep), enc); if (wp != NULL) { qi = GET_LOC_LIST(wp); @@ -5105,7 +5114,7 @@ static void vgr_init_regmatch(regmmatch_T *regmatch, char *s) emsg(_(e_noprevre)); return; } - regmatch->regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC); + regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC); } else { regmatch->regprog = vim_regcomp(s, RE_MAGIC); } @@ -5230,8 +5239,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp const size_t sz = sizeof(matches) / sizeof(matches[0]); // Fuzzy string match - while (fuzzy_match((char_u *)str + col, (char_u *)spat, false, &score, matches, - (int)sz) > 0) { + while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz) > 0) { // Pass the buffer number so that it gets used even for a // dummy buffer, unless duplicate_name is set, then the // buffer will be wiped out below. @@ -5737,12 +5745,14 @@ static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) // 'autochdir' option have changed it. static void unload_dummy_buffer(buf_T *buf, char *dirname_start) { - if (curbuf != buf) { // safety check - close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); - - // When autocommands/'autochdir' option changed directory: go back. - restore_start_dir(dirname_start); + if (curbuf == buf) { // safety check + return; } + + close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); + + // When autocommands/'autochdir' option changed directory: go back. + restore_start_dir(dirname_start); } /// Copy the specified quickfix entry items into a new dict and append the dict @@ -5867,32 +5877,34 @@ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) int status = FAIL; // Only a List value is supported - if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) { - char *errorformat = p_efm; - dictitem_T *efm_di; - // If errorformat is supplied then use it, otherwise use the 'efm' - // option setting - if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) { - if (efm_di->di_tv.v_type != VAR_STRING - || efm_di->di_tv.vval.v_string == NULL) { - return FAIL; - } - errorformat = efm_di->di_tv.vval.v_string; - } - - list_T *l = tv_list_alloc(kListLenMayKnow); - qf_info_T *const qi = qf_alloc_stack(QFLT_INTERNAL); + if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL) { + return FAIL; + } - if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, - true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { - (void)get_errorlist(qi, NULL, 0, 0, l); - qf_free(&qi->qf_lists[0]); + char *errorformat = p_efm; + dictitem_T *efm_di; + // If errorformat is supplied then use it, otherwise use the 'efm' + // option setting + if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) { + if (efm_di->di_tv.v_type != VAR_STRING + || efm_di->di_tv.vval.v_string == NULL) { + return FAIL; } - xfree(qi); + errorformat = efm_di->di_tv.vval.v_string; + } - tv_dict_add_list(retdict, S_LEN("items"), l); - status = OK; + list_T *l = tv_list_alloc(kListLenMayKnow); + qf_info_T *const qi = qf_alloc_stack(QFLT_INTERNAL); + + if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, + true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { + (void)get_errorlist(qi, NULL, 0, 0, l); + qf_free(&qi->qf_lists[0]); } + xfree(qi); + + tv_dict_add_list(retdict, S_LEN("items"), l); + status = OK; return status; } @@ -6935,43 +6947,45 @@ void ex_cexpr(exarg_T *eap) // Evaluate the expression. When the result is a string or a list we can // use it to fill the errorlist. typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, true) != FAIL) { - if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) - || tv.v_type == VAR_LIST) { - incr_quickfix_busy(); - int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm, - (eap->cmdidx != CMD_caddexpr - && eap->cmdidx != CMD_laddexpr), - (linenr_T)0, (linenr_T)0, - qf_cmdtitle(*eap->cmdlinep), NULL); - if (qf_stack_empty(qi)) { - decr_quickfix_busy(); - goto cleanup; - } - if (res >= 0) { - qf_list_changed(qf_get_curlist(qi)); - } - // Remember the current quickfix list identifier, so that we can - // check for autocommands changing the current quickfix list. - unsigned save_qfid = qf_get_curlist(qi)->qf_id; - if (au_name != NULL) { - apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); - } - // Jump to the first error for a new list and if autocmds didn't - // free the list. - if (res > 0 - && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) - && qflist_valid(wp, save_qfid)) { - // display the first error - qf_jump_first(qi, save_qfid, eap->forceit); - } + if (eval0(eap->arg, &tv, &eap->nextcmd, true) == FAIL) { + return; + } + + if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) + || tv.v_type == VAR_LIST) { + incr_quickfix_busy(); + int res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm, + (eap->cmdidx != CMD_caddexpr + && eap->cmdidx != CMD_laddexpr), + (linenr_T)0, (linenr_T)0, + qf_cmdtitle(*eap->cmdlinep), NULL); + if (qf_stack_empty(qi)) { decr_quickfix_busy(); - } else { - emsg(_("E777: String or List expected")); + goto cleanup; } -cleanup: - tv_clear(&tv); + if (res >= 0) { + qf_list_changed(qf_get_curlist(qi)); + } + // Remember the current quickfix list identifier, so that we can + // check for autocommands changing the current quickfix list. + unsigned save_qfid = qf_get_curlist(qi)->qf_id; + if (au_name != NULL) { + apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); + } + // Jump to the first error for a new list and if autocmds didn't + // free the list. + if (res > 0 + && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) + && qflist_valid(wp, save_qfid)) { + // display the first error + qf_jump_first(qi, save_qfid, eap->forceit); + } + decr_quickfix_busy(); + } else { + emsg(_("E777: String or List expected")); } +cleanup: + tv_clear(&tv); } // Get the location list for ":lhelpgrep" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index e396e54ced..122f3e2020 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -87,7 +87,7 @@ static int toggle_Magic(int x) #define REGMAGIC 0234 // Utility definitions. -#define UCHARAT(p) ((int)(*(char_u *)(p))) +#define UCHARAT(p) ((int)(*(uint8_t *)(p))) // Used for an error (down from) vim_regcomp(): give the error message, set // rc_did_emsg and return NULL @@ -327,7 +327,7 @@ static int reg_strict; // "[abc" is illegal // uncrustify:off // META[] is used often enough to justify turning it into a table. -static char_u META_flags[] = { +static uint8_t META_flags[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // % & ( ) * + . @@ -361,7 +361,7 @@ static int nextchr; // used for ungetchr() #define REG_NPAREN 3 // \%(\) typedef struct { - char_u *regparse; + char *regparse; int prevchr_len; int curchr; int prevchr; @@ -393,12 +393,12 @@ static int get_equi_class(char **pp) { int c; int l = 1; - char_u *p = (char_u *)(*pp); + char *p = *pp; if (p[1] == '=' && p[2] != NUL) { - l = utfc_ptr2len((char *)p + 2); + l = utfc_ptr2len(p + 2); if (p[l + 2] == '=' && p[l + 3] == ']') { - c = utf_ptr2char((char *)p + 2); + c = utf_ptr2char(p + 2); *pp += l + 4; return c; } @@ -414,12 +414,12 @@ static int get_coll_element(char **pp) { int c; int l = 1; - char_u *p = (char_u *)(*pp); + char *p = *pp; if (p[0] != NUL && p[1] == '.' && p[2] != NUL) { - l = utfc_ptr2len((char *)p + 2); + l = utfc_ptr2len(p + 2); if (p[l + 2] == '.' && p[l + 3] == ']') { - c = utf_ptr2char((char *)p + 2); + c = utf_ptr2char(p + 2); *pp += l + 4; return c; } @@ -437,7 +437,7 @@ static void get_cpo_flags(void) /// Skip over a "[]" range. /// "p" must point to the character after the '['. /// The returned pointer is on the matching ']', or the terminating NUL. -static char_u *skip_anyof(char *p) +static char *skip_anyof(char *p) { int l; @@ -456,9 +456,9 @@ static char_u *skip_anyof(char *p) MB_PTR_ADV(p); } } else if (*p == '\\' - && (vim_strchr(REGEXP_INRANGE, p[1]) != NULL + && (vim_strchr(REGEXP_INRANGE, (uint8_t)p[1]) != NULL || (!reg_cpo_lit - && vim_strchr(REGEXP_ABBR, p[1]) != NULL))) { + && vim_strchr(REGEXP_ABBR, (uint8_t)p[1]) != NULL))) { p += 2; } else if (*p == '[') { if (get_char_class(&p) == CLASS_NONE @@ -472,7 +472,7 @@ static char_u *skip_anyof(char *p) } } - return (char_u *)p; + return p; } /// Skip past regular expression. @@ -522,7 +522,7 @@ char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *droppe } if ((p[0] == '[' && mymagic >= MAGIC_ON) || (p[0] == '\\' && p[1] == '[' && mymagic <= MAGIC_OFF)) { - p = (char *)skip_anyof(p + 1); + p = skip_anyof(p + 1); if (p[0] == NUL) { break; } @@ -559,9 +559,9 @@ static int at_start; // True when on the first character static int prev_at_start; // True when on the second character // Start parsing at "str". -static void initchr(char_u *str) +static void initchr(char *str) { - regparse = (char *)str; + regparse = str; prevchr_len = 0; curchr = prevprevchr = prevchr = nextchr = -1; at_start = true; @@ -572,7 +572,7 @@ static void initchr(char_u *str) // starts in the same state again. static void save_parse_state(parse_state_T *ps) { - ps->regparse = (char_u *)regparse; + ps->regparse = regparse; ps->prevchr_len = prevchr_len; ps->curchr = curchr; ps->prevchr = prevchr; @@ -586,7 +586,7 @@ static void save_parse_state(parse_state_T *ps) // Restore a previously saved parse state. static void restore_parse_state(parse_state_T *ps) { - regparse = (char *)ps->regparse; + regparse = ps->regparse; prevchr_len = ps->prevchr_len; curchr = ps->curchr; prevchr = ps->prevchr; @@ -677,7 +677,7 @@ static int peekchr(void) // '$' is only magic as the very last char and if it's in front of // either "\|", "\)", "\&", or "\n" if (reg_magic >= MAGIC_OFF) { - char_u *p = (char_u *)regparse + 1; + uint8_t *p = (uint8_t *)regparse + 1; bool is_magic_all = (reg_magic == MAGIC_ALL); // ignore \c \C \m \M \v \V and \Z after '$' @@ -892,7 +892,7 @@ static int64_t getoctchrs(void) static int read_limits(long *minval, long *maxval) { int reverse = false; - char_u *first_char; + char *first_char; long tmp; if (*regparse == '-') { @@ -900,7 +900,7 @@ static int read_limits(long *minval, long *maxval) regparse++; reverse = true; } - first_char = (char_u *)regparse; + first_char = regparse; *minval = getdigits_long(®parse, false, 0); if (*regparse == ',') { // There is a comma. if (ascii_isdigit(*++regparse)) { @@ -938,7 +938,7 @@ static int read_limits(long *minval, long *maxval) // Sometimes need to save a copy of a line. Since alloc()/free() is very // slow, we keep one allocated piece of memory and only re-allocate it when // it's too small. It's freed in bt_regexec_both() when finished. -static char_u *reg_tofree = NULL; +static uint8_t *reg_tofree = NULL; static unsigned reg_tofreelen; // Structure used to store the execution state of the regex engine. @@ -960,8 +960,8 @@ typedef struct { regmatch_T *reg_match; regmmatch_T *reg_mmatch; - char_u **reg_startp; - char_u **reg_endp; + uint8_t **reg_startp; + uint8_t **reg_endp; lpos_T *reg_startpos; lpos_T *reg_endpos; @@ -973,8 +973,8 @@ typedef struct { // The current match-position is remembered with these variables: linenr_T lnum; ///< line number, relative to first line - char_u *line; ///< start of current line - char_u *input; ///< current input, points into "line" + uint8_t *line; ///< start of current line + uint8_t *input; ///< current input, points into "line" int need_clear_subexpr; ///< subexpressions still need to be cleared int need_clear_zsubexpr; ///< extmatch subexpressions still need to be @@ -1019,7 +1019,7 @@ static bool reg_iswordc(int c) } // Get pointer to the line "lnum", which is relative to "reg_firstlnum". -static char_u *reg_getline(linenr_T lnum) +static char *reg_getline(linenr_T lnum) { // when looking behind for a match/no-match lnum is negative. But we // can't go before line 1 @@ -1028,13 +1028,13 @@ static char_u *reg_getline(linenr_T lnum) } if (lnum > rex.reg_maxline) { // Must have matched the "\n" in the last line. - return (char_u *)""; + return ""; } - return (char_u *)ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, false); + return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, false); } -static char_u *reg_startzp[NSUBEXP]; // Workspace to mark beginning -static char_u *reg_endzp[NSUBEXP]; // and end of \z(...\) matches +static uint8_t *reg_startzp[NSUBEXP]; // Workspace to mark beginning +static uint8_t *reg_endzp[NSUBEXP]; // and end of \z(...\) matches static lpos_T reg_startzpos[NSUBEXP]; // idem, beginning pos static lpos_T reg_endzpos[NSUBEXP]; // idem, end pos @@ -1147,7 +1147,7 @@ static bool reg_match_visual(void) } // getvvcol() flushes rex.line, need to get it again - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); rex.input = rex.line + col; unsigned int cols_u = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col); @@ -1184,38 +1184,42 @@ static int prog_magic_wrong(void) // used (to increase speed). static void cleanup_subexpr(void) { - if (rex.need_clear_subexpr) { - if (REG_MULTI) { - // Use 0xff to set lnum to -1 - memset(rex.reg_startpos, 0xff, sizeof(lpos_T) * NSUBEXP); - memset(rex.reg_endpos, 0xff, sizeof(lpos_T) * NSUBEXP); - } else { - memset(rex.reg_startp, 0, sizeof(char_u *) * NSUBEXP); - memset(rex.reg_endp, 0, sizeof(char_u *) * NSUBEXP); - } - rex.need_clear_subexpr = false; + if (!rex.need_clear_subexpr) { + return; + } + + if (REG_MULTI) { + // Use 0xff to set lnum to -1 + memset(rex.reg_startpos, 0xff, sizeof(lpos_T) * NSUBEXP); + memset(rex.reg_endpos, 0xff, sizeof(lpos_T) * NSUBEXP); + } else { + memset(rex.reg_startp, 0, sizeof(char *) * NSUBEXP); + memset(rex.reg_endp, 0, sizeof(char *) * NSUBEXP); } + rex.need_clear_subexpr = false; } static void cleanup_zsubexpr(void) { - if (rex.need_clear_zsubexpr) { - if (REG_MULTI) { - // Use 0xff to set lnum to -1 - memset(reg_startzpos, 0xff, sizeof(lpos_T) * NSUBEXP); - memset(reg_endzpos, 0xff, sizeof(lpos_T) * NSUBEXP); - } else { - memset(reg_startzp, 0, sizeof(char_u *) * NSUBEXP); - memset(reg_endzp, 0, sizeof(char_u *) * NSUBEXP); - } - rex.need_clear_zsubexpr = false; + if (!rex.need_clear_zsubexpr) { + return; + } + + if (REG_MULTI) { + // Use 0xff to set lnum to -1 + memset(reg_startzpos, 0xff, sizeof(lpos_T) * NSUBEXP); + memset(reg_endzpos, 0xff, sizeof(lpos_T) * NSUBEXP); + } else { + memset(reg_startzp, 0, sizeof(char *) * NSUBEXP); + memset(reg_endzp, 0, sizeof(char *) * NSUBEXP); } + rex.need_clear_zsubexpr = false; } // Advance rex.lnum, rex.line and rex.input to the next line. static void reg_nextline(void) { - rex.line = reg_getline(++rex.lnum); + rex.line = (uint8_t *)reg_getline(++rex.lnum); rex.input = rex.line; fast_breakcheck(); } @@ -1252,7 +1256,7 @@ static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T e } // Get the line to compare with. - p = (char *)reg_getline(clnum); + p = reg_getline(clnum); assert(p); if (clnum == end_lnum) { @@ -1399,8 +1403,8 @@ static int cstrncmp(char *s1, char *s2, int *n) str2 = s2; c1 = c2 = 0; while ((int)(str1 - s1) < *n) { - c1 = mb_ptr2char_adv((const char_u **)&str1); - c2 = mb_ptr2char_adv((const char_u **)&str2); + c1 = mb_ptr2char_adv((const char **)&str1); + c2 = mb_ptr2char_adv((const char **)&str2); // decompose the character if necessary, into 'base' characters // because I don't care about Arabic, I will hard-code the Hebrew @@ -1434,21 +1438,21 @@ static int cstrncmp(char *s1, char *s2, int *n) /// @param c character to find in @a s /// /// @return NULL if no match, otherwise pointer to the position in @a s -static inline char_u *cstrchr(const char_u *const s, const int c) +static inline char *cstrchr(const char *const s, const int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE { if (!rex.reg_ic) { - return (char_u *)vim_strchr((char *)s, c); + return vim_strchr(s, c); } // Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is // expected to be highly optimized. if (c > 0x80) { const int folded_c = utf_fold(c); - for (const char_u *p = s; *p != NUL; p += utfc_ptr2len((char *)p)) { - if (utf_fold(utf_ptr2char((char *)p)) == folded_c) { - return (char_u *)p; + for (const char *p = s; *p != NUL; p += utfc_ptr2len(p)) { + if (utf_fold(utf_ptr2char(p)) == folded_c) { + return (char *)p; } } return NULL; @@ -1460,11 +1464,11 @@ static inline char_u *cstrchr(const char_u *const s, const int c) } else if (ASCII_ISLOWER(c)) { cc = TOUPPER_ASC(c); } else { - return (char_u *)vim_strchr((char *)s, c); + return vim_strchr(s, c); } char tofind[] = { (char)c, (char)cc, NUL }; - return (char_u *)strpbrk((const char *)s, tofind); + return strpbrk(s, tofind); } //////////////////////////////////////////////////////////////// @@ -1636,8 +1640,7 @@ static void clear_submatch_list(staticList10_T *sl) /// references invalid! /// /// Returns the size of the replacement, including terminating NUL. -int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, int destlen, - int flags) +int vim_regsub(regmatch_T *rmp, char *source, typval_T *expr, char *dest, int destlen, int flags) { regexec_T rex_save; bool rex_in_use_save = rex_in_use; @@ -1653,7 +1656,7 @@ int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, in rex.reg_maxline = 0; rex.reg_buf = curbuf; rex.reg_line_lbr = true; - int result = vim_regsub_both((char *)source, expr, (char *)dest, destlen, flags); + int result = vim_regsub_both(source, expr, dest, destlen, flags); rex_in_use = rex_in_use_save; if (rex_in_use) { @@ -1663,7 +1666,7 @@ int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, in return result; } -int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int destlen, +int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char *source, char *dest, int destlen, int flags) { regexec_T rex_save; @@ -1681,7 +1684,7 @@ int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *de rex.reg_firstlnum = lnum; rex.reg_maxline = curbuf->b_ml.ml_line_count - lnum; rex.reg_line_lbr = false; - int result = vim_regsub_both((char *)source, NULL, (char *)dest, destlen, flags); + int result = vim_regsub_both(source, NULL, dest, destlen, flags); rex_in_use = rex_in_use_save; if (rex_in_use) { @@ -1860,7 +1863,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen no = 0; } else if ('0' <= *src && *src <= '9') { no = *src++ - '0'; - } else if (vim_strchr("uUlLeE", *src)) { + } else if (vim_strchr("uUlLeE", (uint8_t)(*src))) { switch (*src++) { case 'u': func_one = (fptr_T)do_upper; @@ -1974,7 +1977,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen if (clnum < 0 || rex.reg_mmatch->endpos[no].lnum < 0) { s = NULL; } else { - s = (char *)reg_getline(clnum) + rex.reg_mmatch->startpos[no].col; + s = reg_getline(clnum) + rex.reg_mmatch->startpos[no].col; if (rex.reg_mmatch->endpos[no].lnum == clnum) { len = rex.reg_mmatch->endpos[no].col - rex.reg_mmatch->startpos[no].col; @@ -2005,7 +2008,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen *dst = CAR; } dst++; - s = (char *)reg_getline(++clnum); + s = reg_getline(++clnum); if (rex.reg_mmatch->endpos[no].lnum == clnum) { len = rex.reg_mmatch->endpos[no].col; } else { @@ -2099,7 +2102,7 @@ static char *reg_getline_submatch(linenr_T lnum) rex.reg_firstlnum = rsm.sm_firstlnum; rex.reg_maxline = rsm.sm_maxline; - s = (char *)reg_getline(lnum); + s = reg_getline(lnum); rex.reg_firstlnum = save_first; rex.reg_maxline = save_max; @@ -2290,7 +2293,7 @@ static regengine_T nfa_regengine = { static int regexp_engine = 0; #ifdef REGEXP_DEBUG -static char_u regname[][30] = { +static uint8_t regname[][30] = { "AUTOMATIC Regexp Engine", "BACKTRACKING Regexp Engine", "NFA Regexp Engine" @@ -2339,10 +2342,10 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags) // const int called_emsg_before = called_emsg; if (regexp_engine != BACKTRACKING_ENGINE) { - prog = nfa_regengine.regcomp((char_u *)expr, + prog = nfa_regengine.regcomp((uint8_t *)expr, re_flags + (regexp_engine == AUTOMATIC_ENGINE ? RE_AUTO : 0)); } else { - prog = bt_regengine.regcomp((char_u *)expr, re_flags); + prog = bt_regengine.regcomp((uint8_t *)expr, re_flags); } // Check for error compiling regexp with initial engine. @@ -2366,8 +2369,8 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags) // But don't try if an error message was given. if (regexp_engine == AUTOMATIC_ENGINE && called_emsg == called_emsg_before) { regexp_engine = BACKTRACKING_ENGINE; - report_re_switch((char_u *)expr); - prog = bt_regengine.regcomp((char_u *)expr, re_flags); + report_re_switch(expr); + prog = bt_regengine.regcomp((uint8_t *)expr, re_flags); } } @@ -2400,12 +2403,12 @@ void free_regexp_stuff(void) #endif -static void report_re_switch(char_u *pat) +static void report_re_switch(char *pat) { if (p_verbose > 0) { verbose_enter(); msg_puts(_("Switching to backtracking RE engine for pattern: ")); - msg_puts((char *)pat); + msg_puts(pat); verbose_leave(); } } @@ -2422,7 +2425,7 @@ static void report_re_switch(char_u *pat) /// @param nl /// /// @return true if there is a match, false if not. -static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool nl) +static bool vim_regexec_string(regmatch_T *rmp, char *line, colnr_T col, bool nl) { regexec_T rex_save; bool rex_in_use_save = rex_in_use; @@ -2445,7 +2448,7 @@ static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool rex.reg_startpos = NULL; rex.reg_endpos = NULL; - int result = rmp->regprog->engine->regexec_nl(rmp, line, col, nl); + int result = rmp->regprog->engine->regexec_nl(rmp, (uint8_t *)line, col, nl); rmp->regprog->re_in_use = false; // NFA engine aborted because it's very slow, use backtracking engine instead. @@ -2457,11 +2460,11 @@ static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool p_re = BACKTRACKING_ENGINE; vim_regfree(rmp->regprog); - report_re_switch((char_u *)pat); + report_re_switch(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); + result = rmp->regprog->engine->regexec_nl(rmp, (uint8_t *)line, col, nl); rmp->regprog->re_in_use = false; } @@ -2479,7 +2482,7 @@ static bool vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col, bool // Note: "*prog" may be freed and changed. // Return true if there is a match, false if not. -bool vim_regexec_prog(regprog_T **prog, bool ignore_case, char_u *line, colnr_T col) +bool vim_regexec_prog(regprog_T **prog, bool ignore_case, char *line, colnr_T col) { regmatch_T regmatch = { .regprog = *prog, .rm_ic = ignore_case }; bool r = vim_regexec_string(®match, line, col, false); @@ -2491,13 +2494,13 @@ bool vim_regexec_prog(regprog_T **prog, bool ignore_case, char_u *line, colnr_T // Return true if there is a match, false if not. bool vim_regexec(regmatch_T *rmp, char *line, colnr_T col) { - return vim_regexec_string(rmp, (char_u *)line, col, false); + return vim_regexec_string(rmp, line, col, false); } // Like vim_regexec(), but consider a "\n" in "line" to be a line break. // Note: "rmp->regprog" may be freed and changed. // Return true if there is a match, false if not. -bool vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col) +bool vim_regexec_nl(regmatch_T *rmp, char *line, colnr_T col) { return vim_regexec_string(rmp, line, col, true); } @@ -2549,7 +2552,7 @@ long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, p_re = BACKTRACKING_ENGINE; regprog_T *prev_prog = rmp->regprog; - report_re_switch((char_u *)pat); + report_re_switch(pat); // checking for \z misuse was already done when compiling for NFA, // allow all here reg_do_extmatch = REX_ALL; diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index f930d872b6..af3d93f7c4 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -242,17 +242,17 @@ static int prevchr_len; ///< byte length of previous char static int num_complex_braces; ///< Complex \{...} count -static char_u *regcode; ///< Code-emit pointer, or JUST_CALC_SIZE +static uint8_t *regcode; ///< Code-emit pointer, or JUST_CALC_SIZE static long regsize; ///< Code size. static int reg_toolong; ///< true when offset out of range -static char_u had_endbrace[NSUBEXP]; ///< flags, true if end of () found +static uint8_t had_endbrace[NSUBEXP]; ///< flags, true if end of () found static long brace_min[10]; ///< Minimums for complex brace repeats static long brace_max[10]; ///< Maximums for complex brace repeats static int brace_count[10]; ///< Current counts for complex brace repeats static int one_exactly = false; ///< only do one char for EXACTLY // When making changes to classchars also change nfa_classcodes. -static char_u *classchars = (char_u *)".iIkKfFpPsSdDxXoOwWhHaAlLuU"; +static uint8_t *classchars = (uint8_t *)".iIkKfFpPsSdDxXoOwWhHaAlLuU"; static int classcodes[] = { ANY, IDENT, SIDENT, KWORD, SKWORD, FNAME, SFNAME, PRINT, SPRINT, @@ -265,7 +265,7 @@ static int classcodes[] = { // When regcode is set to this value, code is not emitted and size is computed // instead. -#define JUST_CALC_SIZE ((char_u *)-1) +#define JUST_CALC_SIZE ((uint8_t *)-1) // Values for rs_state in regitem_T. typedef enum regstate_E { @@ -290,7 +290,7 @@ typedef enum regstate_E { // Also stores the length of "backpos". typedef struct { union { - char_u *ptr; // rex.input pointer, for single-line regexp + uint8_t *ptr; // rex.input pointer, for single-line regexp lpos_T pos; // rex.input pos, for multi-line regexp } rs_u; int rs_len; @@ -299,7 +299,7 @@ typedef struct { // struct to save start/end pointer/position in for \(\) typedef struct { union { - char_u *ptr; + uint8_t *ptr; lpos_T pos; } se_u; } save_se_T; @@ -320,7 +320,7 @@ typedef struct regbehind_S { typedef struct regitem_S { regstate_T rs_state; // what we are doing, one of RS_ above int16_t rs_no; // submatch nr or BEHIND/NOBEHIND - char_u *rs_scan; // current node in program + uint8_t *rs_scan; // current node in program union { save_se_T sesave; regsave_T regsave; @@ -339,7 +339,7 @@ typedef struct regstar_S { // used to store input position when a BACK was encountered, so that we now if // we made any progress since the last time. typedef struct backpos_S { - char_u *bp_scan; // "scan" where BACK was encountered + uint8_t *bp_scan; // "scan" where BACK was encountered regsave_T bp_pos; // last input position } backpos_T; @@ -411,14 +411,14 @@ static regsave_T behind_pos; // Obtain a second single-byte operand stored after a four bytes operand. #define OPERAND_CMP(p) (p)[7] -static char_u *reg(int paren, int *flagp); +static uint8_t *reg(int paren, int *flagp); #ifdef BT_REGEXP_DUMP -static void regdump(char_u *, bt_regprog_T *); +static void regdump(uint8_t *, bt_regprog_T *); #endif #ifdef REGEXP_DEBUG -static char_u *regprop(char_u *); +static uint8_t *regprop(uint8_t *); static int regnarrate = 0; #endif @@ -428,9 +428,9 @@ static int regnarrate = 0; #endif // Setup to parse the regexp. Used once to get the length and once to do it. -static void regcomp_start(char_u *expr, int re_flags) // see vim_regcomp() +static void regcomp_start(uint8_t *expr, int re_flags) // see vim_regcomp() { - initchr(expr); + initchr((char *)expr); if (re_flags & RE_MAGIC) { reg_magic = MAGIC_ON; } else { @@ -466,7 +466,7 @@ static void regc(int b) if (regcode == JUST_CALC_SIZE) { regsize++; } else { - *regcode++ = (char_u)b; + *regcode++ = (uint8_t)b; } } @@ -1453,15 +1453,15 @@ static void reg_equi_class(int c) // Emit a node. // Return pointer to generated code. -static char_u *regnode(int op) +static uint8_t *regnode(int op) { - char_u *ret; + uint8_t *ret; ret = regcode; if (ret == JUST_CALC_SIZE) { regsize += 3; } else { - *regcode++ = (char_u)op; + *regcode++ = (uint8_t)op; *regcode++ = NUL; // Null "next" pointer. *regcode++ = NUL; } @@ -1469,19 +1469,19 @@ static char_u *regnode(int op) } // Write a four bytes number at "p" and return pointer to the next char. -static char_u *re_put_uint32(char_u *p, uint32_t val) +static uint8_t *re_put_uint32(uint8_t *p, uint32_t val) { - *p++ = (char_u)((val >> 24) & 0377); - *p++ = (char_u)((val >> 16) & 0377); - *p++ = (char_u)((val >> 8) & 0377); - *p++ = (char_u)(val & 0377); + *p++ = (uint8_t)((val >> 24) & 0377); + *p++ = (uint8_t)((val >> 16) & 0377); + *p++ = (uint8_t)((val >> 8) & 0377); + *p++ = (uint8_t)(val & 0377); return p; } // regnext - dig the "next" pointer out of a node // Returns NULL when calculating size, when there is no next item and when // there is an error. -static char_u *regnext(char_u *p) +static uint8_t *regnext(uint8_t *p) FUNC_ATTR_NONNULL_ALL { int offset; @@ -1503,7 +1503,7 @@ static char_u *regnext(char_u *p) } // Set the next-pointer at the end of a node chain. -static void regtail(char_u *p, char_u *val) +static void regtail(uint8_t *p, uint8_t *val) { int offset; @@ -1512,9 +1512,9 @@ static void regtail(char_u *p, char_u *val) } // Find last node. - char_u *scan = p; + uint8_t *scan = p; for (;;) { - char_u *temp = regnext(scan); + uint8_t *temp = regnext(scan); if (temp == NULL) { break; } @@ -1532,13 +1532,13 @@ static void regtail(char_u *p, char_u *val) if (offset > 0xffff) { reg_toolong = true; } else { - *(scan + 1) = (char_u)(((unsigned)offset >> 8) & 0377); - *(scan + 2) = (char_u)(offset & 0377); + *(scan + 1) = (uint8_t)(((unsigned)offset >> 8) & 0377); + *(scan + 2) = (uint8_t)(offset & 0377); } } // Like regtail, on item after a BRANCH; nop if none. -static void regoptail(char_u *p, char_u *val) +static void regoptail(uint8_t *p, uint8_t *val) { // When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" if (p == NULL || p == JUST_CALC_SIZE @@ -1552,11 +1552,11 @@ static void regoptail(char_u *p, char_u *val) // Insert an operator in front of already-emitted operand // // Means relocating the operand. -static void reginsert(int op, char_u *opnd) +static void reginsert(int op, uint8_t *opnd) { - char_u *src; - char_u *dst; - char_u *place; + uint8_t *src; + uint8_t *dst; + uint8_t *place; if (regcode == JUST_CALC_SIZE) { regsize += 3; @@ -1570,18 +1570,18 @@ static void reginsert(int op, char_u *opnd) } place = opnd; // Op node, where operand used to be. - *place++ = (char_u)op; + *place++ = (uint8_t)op; *place++ = NUL; *place = NUL; } // Insert an operator in front of already-emitted operand. // Add a number to the operator. -static void reginsert_nr(int op, long val, char_u *opnd) +static void reginsert_nr(int op, long val, uint8_t *opnd) { - char_u *src; - char_u *dst; - char_u *place; + uint8_t *src; + uint8_t *dst; + uint8_t *place; if (regcode == JUST_CALC_SIZE) { regsize += 7; @@ -1595,7 +1595,7 @@ static void reginsert_nr(int op, long val, char_u *opnd) } place = opnd; // Op node, where operand used to be. - *place++ = (char_u)op; + *place++ = (uint8_t)op; *place++ = NUL; *place++ = NUL; assert(val >= 0 && (uintmax_t)val <= UINT32_MAX); @@ -1606,11 +1606,11 @@ static void reginsert_nr(int op, long val, char_u *opnd) // The operator has the given limit values as operands. Also set next pointer. // // Means relocating the operand. -static void reginsert_limits(int op, long minval, long maxval, char_u *opnd) +static void reginsert_limits(int op, long minval, long maxval, uint8_t *opnd) { - char_u *src; - char_u *dst; - char_u *place; + uint8_t *src; + uint8_t *dst; + uint8_t *place; if (regcode == JUST_CALC_SIZE) { regsize += 11; @@ -1624,7 +1624,7 @@ static void reginsert_limits(int op, long minval, long maxval, char_u *opnd) } place = opnd; // Op node, where operand used to be. - *place++ = (char_u)op; + *place++ = (uint8_t)op; *place++ = NUL; *place++ = NUL; assert(minval >= 0 && (uintmax_t)minval <= UINT32_MAX); @@ -1641,11 +1641,11 @@ static void reginsert_limits(int op, long minval, long maxval, char_u *opnd) static int seen_endbrace(int refnum) { if (!had_endbrace[refnum]) { - char_u *p; + uint8_t *p; // Trick: check if "@<=" or "@<!" follows, in which case // the \1 can appear before the referenced match. - for (p = (char_u *)regparse; *p != NUL; p++) { + for (p = (uint8_t *)regparse; *p != NUL; p++) { if (p[0] == '@' && p[1] == '<' && (p[2] == '!' || p[2] == '=')) { break; } @@ -1665,12 +1665,12 @@ static int seen_endbrace(int refnum) // Optimization: gobbles an entire sequence of ordinary characters so that // it can turn them into a single node, which is smaller to store and // faster to run. Don't do this when one_exactly is set. -static char_u *regatom(int *flagp) +static uint8_t *regatom(int *flagp) { - char_u *ret; + uint8_t *ret; int flags; int c; - char_u *p; + uint8_t *p; int extra = 0; int save_prev_at_start = prev_at_start; @@ -1746,7 +1746,7 @@ static char_u *regatom(int *flagp) case Magic('L'): case Magic('u'): case Magic('U'): - p = (char_u *)vim_strchr((char *)classchars, no_Magic(c)); + p = (uint8_t *)vim_strchr((char *)classchars, no_Magic(c)); if (p == NULL) { EMSG_RET_NULL(_("E63: invalid use of \\_")); } @@ -1808,17 +1808,17 @@ static char_u *regatom(int *flagp) case Magic('~'): // previous substitute pattern if (reg_prev_sub != NULL) { - char_u *lp; + uint8_t *lp; ret = regnode(EXACTLY); - lp = (char_u *)reg_prev_sub; + lp = (uint8_t *)reg_prev_sub; while (*lp != NUL) { regc(*lp++); } regc(NUL); if (*reg_prev_sub != NUL) { *flagp |= HASWIDTH; - if ((lp - (char_u *)reg_prev_sub) == 1) { + if ((lp - (uint8_t *)reg_prev_sub) == 1) { *flagp |= SIMPLE; } } @@ -1948,9 +1948,9 @@ static char_u *regatom(int *flagp) EMSG_ONE_RET_NULL; } { - char_u *lastbranch; - char_u *lastnode = NULL; - char_u *br; + uint8_t *lastbranch; + uint8_t *lastnode = NULL; + uint8_t *br; ret = NULL; while ((c = getchr()) != ']') { @@ -2072,8 +2072,8 @@ static char_u *regatom(int *flagp) if (ret == JUST_CALC_SIZE) { regsize += 2; } else { - *regcode++ = (char_u)c; - *regcode++ = (char_u)cmp; + *regcode++ = (uint8_t)c; + *regcode++ = (uint8_t)cmp; } break; } else if ((c == 'l' || c == 'c' || c == 'v') && (cur || got_digit)) { @@ -2110,7 +2110,7 @@ static char_u *regatom(int *flagp) // put the number and the optional // comparator after the opcode regcode = re_put_uint32(regcode, n); - *regcode++ = (char_u)cmp; + *regcode++ = (uint8_t)cmp; } break; } @@ -2124,11 +2124,11 @@ static char_u *regatom(int *flagp) case Magic('['): collection: { - char_u *lp; + uint8_t *lp; // If there is no matching ']', we assume the '[' is a normal // character. This makes 'incsearch' and ":help [" work. - lp = skip_anyof(regparse); + lp = (uint8_t *)skip_anyof(regparse); if (*lp == ']') { // there is a matching ']' int startc = -1; // > 0 when next '-' is a range int endc; @@ -2165,7 +2165,7 @@ collection: endc = get_coll_element(®parse); } if (endc == 0) { - endc = mb_ptr2char_adv((const char_u **)®parse); + endc = mb_ptr2char_adv((const char **)®parse); } // Handle \o40, \x20 and \u20AC style sequences @@ -2197,10 +2197,10 @@ collection: // accepts "\t", "\e", etc., but only when the 'l' flag in // 'cpoptions' is not included. else if (*regparse == '\\' - && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL + && (vim_strchr(REGEXP_INRANGE, (uint8_t)regparse[1]) != NULL || (!reg_cpo_lit && vim_strchr(REGEXP_ABBR, - regparse[1]) != NULL))) { + (uint8_t)regparse[1]) != NULL))) { regparse++; if (*regparse == 'n') { // '\n' in range: also match NL @@ -2460,11 +2460,11 @@ do_multibyte: // both the endmarker for their branch list and the body of the last branch. // It might seem that this node could be dispensed with entirely, but the // endmarker role is not redundant. -static char_u *regpiece(int *flagp) +static uint8_t *regpiece(int *flagp) { - char_u *ret; + uint8_t *ret; int op; - char_u *next; + uint8_t *next; int flags; long minval; long maxval; @@ -2597,11 +2597,11 @@ static char_u *regpiece(int *flagp) // Parse one alternative of an | or & operator. // Implements the concatenation operator. -static char_u *regconcat(int *flagp) +static uint8_t *regconcat(int *flagp) { - char_u *first = NULL; - char_u *chain = NULL; - char_u *latest; + uint8_t *first = NULL; + uint8_t *chain = NULL; + uint8_t *latest; int flags; int cont = true; @@ -2673,11 +2673,11 @@ static char_u *regconcat(int *flagp) // Parse one alternative of an | operator. // Implements the & operator. -static char_u *regbranch(int *flagp) +static uint8_t *regbranch(int *flagp) { - char_u *ret; - char_u *chain = NULL; - char_u *latest; + uint8_t *ret; + uint8_t *chain = NULL; + uint8_t *latest; int flags; *flagp = WORST | HASNL; // Tentatively. @@ -2722,11 +2722,11 @@ static char_u *regbranch(int *flagp) /// follows makes it hard to avoid. /// /// @param paren REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN -static char_u *reg(int paren, int *flagp) +static uint8_t *reg(int paren, int *flagp) { - char_u *ret; - char_u *br; - char_u *ender; + uint8_t *ret; + uint8_t *br; + uint8_t *ender; int parno = 0; int flags; @@ -2840,10 +2840,10 @@ static char_u *reg(int paren, int *flagp) // Beware that the optimization-preparation code in here knows about some // of the structure of the compiled regexp. // "re_flags": RE_MAGIC and/or RE_STRING. -static regprog_T *bt_regcomp(char_u *expr, int re_flags) +static regprog_T *bt_regcomp(uint8_t *expr, int re_flags) { - char_u *scan; - char_u *longest; + uint8_t *scan; + uint8_t *longest; int len; int flags; @@ -2862,7 +2862,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags) } // Allocate space. - bt_regprog_T *r = xmalloc(sizeof(bt_regprog_T) + (size_t)regsize); + bt_regprog_T *r = xmalloc(offsetof(bt_regprog_T, program) + (size_t)regsize); r->re_in_use = false; // Second pass: emit code. @@ -2890,7 +2890,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags) r->regflags |= RF_LOOKBH; } // Remember whether this pattern has any \z specials in it. - r->reghasz = (char_u)re_has_z; + r->reghasz = (uint8_t)re_has_z; scan = r->program + 1; // First BRANCH. if (OP(regnext(scan)) == END) { // Only one top-level choice. scan = OPERAND(scan); @@ -2908,7 +2908,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags) || OP(scan) == NOTHING || OP(scan) == MOPEN + 0 || OP(scan) == NOPEN || OP(scan) == MCLOSE + 0 || OP(scan) == NCLOSE) { - char_u *regnext_scan = regnext(scan); + uint8_t *regnext_scan = regnext(scan); if (OP(regnext_scan) == EXACTLY) { r->regstart = utf_ptr2char((char *)OPERAND(regnext_scan)); } @@ -3014,7 +3014,7 @@ static void reg_restore(regsave_T *save, garray_T *gap) // only call reg_getline() when the line number changed to save // a bit of time rex.lnum = save->rs_u.pos.lnum; - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); } rex.input = rex.line + save->rs_u.pos.col; } else { @@ -3057,7 +3057,7 @@ static void save_se_multi(save_se_T *savep, lpos_T *posp) posp->col = (colnr_T)(rex.input - rex.line); } -static void save_se_one(save_se_T *savep, char_u **pp) +static void save_se_one(save_se_T *savep, uint8_t **pp) { savep->se_u.ptr = *pp; *pp = rex.input; @@ -3067,14 +3067,14 @@ static void save_se_one(save_se_T *savep, char_u **pp) /// Advances rex.input (and rex.lnum) to just after the matched chars. /// /// @param maxcount maximum number of matches allowed -static int regrepeat(char_u *p, long maxcount) +static int regrepeat(uint8_t *p, long maxcount) { long count = 0; - char_u *opnd; + uint8_t *opnd; int mask; int testval = 0; - char_u *scan = rex.input; // Make local copy of rex.input for speed. + uint8_t *scan = rex.input; // Make local copy of rex.input for speed. opnd = OPERAND(p); switch (OP(p)) { case ANY: @@ -3385,12 +3385,12 @@ do_class: } else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p))) { scan++; } else if ((len = utfc_ptr2len((char *)scan)) > 1) { - if ((cstrchr(opnd, utf_ptr2char((char *)scan)) == NULL) == testval) { + if ((cstrchr((char *)opnd, utf_ptr2char((char *)scan)) == NULL) == testval) { break; } scan += len; } else { - if ((cstrchr(opnd, *scan) == NULL) == testval) { + if ((cstrchr((char *)opnd, *scan) == NULL) == testval) { break; } scan++; @@ -3431,7 +3431,7 @@ do_class: // Push an item onto the regstack. // Returns pointer to new item. Returns NULL when out of memory. -static regitem_T *regstack_push(regstate_T state, char_u *scan) +static regitem_T *regstack_push(regstate_T state, uint8_t *scan) { regitem_T *rp; @@ -3450,7 +3450,7 @@ static regitem_T *regstack_push(regstate_T state, char_u *scan) } // Pop an item from the regstack. -static void regstack_pop(char_u **scan) +static void regstack_pop(uint8_t **scan) { regitem_T *rp; @@ -3468,15 +3468,17 @@ static void save_subexpr(regbehind_T *bp) // When "rex.need_clear_subexpr" is set we don't need to save the values, only // remember that this flag needs to be set again when restoring. bp->save_need_clear_subexpr = rex.need_clear_subexpr; - if (!rex.need_clear_subexpr) { - for (int i = 0; i < NSUBEXP; i++) { - if (REG_MULTI) { - bp->save_start[i].se_u.pos = rex.reg_startpos[i]; - bp->save_end[i].se_u.pos = rex.reg_endpos[i]; - } else { - bp->save_start[i].se_u.ptr = rex.reg_startp[i]; - bp->save_end[i].se_u.ptr = rex.reg_endp[i]; - } + if (rex.need_clear_subexpr) { + return; + } + + for (int i = 0; i < NSUBEXP; i++) { + if (REG_MULTI) { + bp->save_start[i].se_u.pos = rex.reg_startpos[i]; + bp->save_end[i].se_u.pos = rex.reg_endpos[i]; + } else { + bp->save_start[i].se_u.ptr = rex.reg_startp[i]; + bp->save_end[i].se_u.ptr = rex.reg_endp[i]; } } } @@ -3487,15 +3489,17 @@ static void restore_subexpr(regbehind_T *bp) { // Only need to restore saved values when they are not to be cleared. rex.need_clear_subexpr = bp->save_need_clear_subexpr; - if (!rex.need_clear_subexpr) { - for (int i = 0; i < NSUBEXP; i++) { - if (REG_MULTI) { - rex.reg_startpos[i] = bp->save_start[i].se_u.pos; - rex.reg_endpos[i] = bp->save_end[i].se_u.pos; - } else { - rex.reg_startp[i] = bp->save_start[i].se_u.ptr; - rex.reg_endp[i] = bp->save_end[i].se_u.ptr; - } + if (rex.need_clear_subexpr) { + return; + } + + for (int i = 0; i < NSUBEXP; i++) { + if (REG_MULTI) { + rex.reg_startpos[i] = bp->save_start[i].se_u.pos; + rex.reg_endpos[i] = bp->save_end[i].se_u.pos; + } else { + rex.reg_startp[i] = bp->save_start[i].se_u.ptr; + rex.reg_endp[i] = bp->save_end[i].se_u.ptr; } } } @@ -3516,9 +3520,9 @@ static void restore_subexpr(regbehind_T *bp) /// just after the last matched character. /// - false when there is no match. Leaves rex.input and rex.lnum in an /// undefined state! -static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) +static bool regmatch(uint8_t *scan, proftime_T *tm, int *timed_out) { - char_u *next; // Next node. + uint8_t *next; // Next node. int op; int c; regitem_T *rp; @@ -3647,7 +3651,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) // Line may have been freed, get it again. if (REG_MULTI) { - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); rex.input = rex.line + col; } @@ -3961,7 +3965,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case EXACTLY: { int len; - char_u *opnd; + uint8_t *opnd; opnd = OPERAND(scan); // Inline the first byte, for speed. @@ -4003,7 +4007,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case ANYBUT: if (c == NUL) { status = RA_NOMATCH; - } else if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF)) { + } else if ((cstrchr((char *)OPERAND(scan), c) == NULL) == (op == ANYOF)) { status = RA_NOMATCH; } else { ADVANCE_REGINPUT(); @@ -4013,7 +4017,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) case MULTIBYTECODE: { int i, len; - const char_u *opnd = OPERAND(scan); + const uint8_t *opnd = OPERAND(scan); // Safety check (just in case 'encoding' was changed since // compiling the program). if ((len = utfc_ptr2len((char *)opnd)) < 2) { @@ -4699,8 +4703,8 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) (colnr_T)strlen((char *)rex.line); } } else { - const char_u *const line = - reg_getline(rp->rs_un.regsave.rs_u.pos.lnum); + const uint8_t *const line = + (uint8_t *)reg_getline(rp->rs_un.regsave.rs_u.pos.lnum); rp->rs_un.regsave.rs_u.pos.col -= utf_head_off((char *)line, @@ -4782,7 +4786,7 @@ static bool regmatch(char_u *scan, proftime_T *tm, int *timed_out) break; } rex.lnum--; - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); // Just in case regrepeat() didn't count right. if (rex.line == NULL) { break; @@ -4913,13 +4917,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] = - (char_u *)xstrnsave((char *)reg_getline(reg_startzpos[i].lnum) + reg_startzpos[i].col, - (size_t)(reg_endzpos[i].col - reg_startzpos[i].col)); + (uint8_t *)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] = - (char_u *)xstrnsave((char *)reg_startzp[i], (size_t)(reg_endzp[i] - reg_startzp[i])); + (uint8_t *)xstrnsave((char *)reg_startzp[i], (size_t)(reg_endzp[i] - reg_startzp[i])); } } } @@ -4935,10 +4939,10 @@ static long regtry(bt_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_o /// @param timed_out flag set on timeout or NULL /// /// @return 0 for failure, or number of lines contained in the match. -static long bt_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int *timed_out) +static long bt_regexec_both(uint8_t *line, colnr_T startcol, proftime_T *tm, int *timed_out) { bt_regprog_T *prog; - char_u *s; + uint8_t *s; colnr_T col = startcol; long retval = 0L; @@ -4962,13 +4966,13 @@ static long bt_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int if (REG_MULTI) { prog = (bt_regprog_T *)rex.reg_mmatch->regprog; - line = reg_getline((linenr_T)0); + line = (uint8_t *)reg_getline((linenr_T)0); rex.reg_startpos = rex.reg_mmatch->startpos; rex.reg_endpos = rex.reg_mmatch->endpos; } else { prog = (bt_regprog_T *)rex.reg_match->regprog; - rex.reg_startp = (char_u **)rex.reg_match->startp; - rex.reg_endp = (char_u **)rex.reg_match->endp; + rex.reg_startp = (uint8_t **)rex.reg_match->startp; + rex.reg_endp = (uint8_t **)rex.reg_match->endp; } // Be paranoid... @@ -5007,14 +5011,14 @@ static long bt_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int // This is used very often, esp. for ":global". Use two versions of // the loop to avoid overhead of conditions. if (!rex.reg_ic) { - while ((s = (char_u *)vim_strchr((char *)s, c)) != NULL) { + while ((s = (uint8_t *)vim_strchr((char *)s, c)) != NULL) { if (cstrncmp((char *)s, (char *)prog->regmust, &prog->regmlen) == 0) { break; // Found it. } MB_PTR_ADV(s); } } else { - while ((s = cstrchr(s, c)) != NULL) { + while ((s = (uint8_t *)cstrchr((char *)s, c)) != NULL) { if (cstrncmp((char *)s, (char *)prog->regmust, &prog->regmlen) == 0) { break; // Found it. } @@ -5049,7 +5053,7 @@ static long bt_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int while (!got_int) { if (prog->regstart != NUL) { // Skip until the char we know it must start with. - s = cstrchr(rex.line + col, prog->regstart); + s = (uint8_t *)cstrchr((char *)rex.line + col, prog->regstart); if (s == NULL) { retval = 0; break; @@ -5071,7 +5075,7 @@ static long bt_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int // if not currently on the first line, get it again if (rex.lnum != 0) { rex.lnum = 0; - rex.line = reg_getline((linenr_T)0); + rex.line = (uint8_t *)reg_getline((linenr_T)0); } if (rex.line[col] == NUL) { break; @@ -5141,7 +5145,7 @@ theend: /// @param col column to start looking for match /// /// @return 0 for failure, number of lines contained in the match otherwise. -static int bt_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col, bool line_lbr) +static int bt_regexec_nl(regmatch_T *rmp, uint8_t *line, colnr_T col, bool line_lbr) { rex.reg_match = rmp; rex.reg_mmatch = NULL; @@ -5178,7 +5182,7 @@ static long bt_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T } // Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL. -static int re_num_cmp(uint32_t val, char_u *scan) +static int re_num_cmp(uint32_t val, uint8_t *scan) { uint32_t n = (uint32_t)OPERAND_MIN(scan); @@ -5194,12 +5198,12 @@ static int re_num_cmp(uint32_t val, char_u *scan) #ifdef BT_REGEXP_DUMP // regdump - dump a regexp onto stdout in vaguely comprehensible form -static void regdump(char_u *pattern, bt_regprog_T *r) +static void regdump(uint8_t *pattern, bt_regprog_T *r) { - char_u *s; + uint8_t *s; int op = EXACTLY; // Arbitrary non-END op. - char_u *next; - char_u *end = NULL; + uint8_t *next; + uint8_t *end = NULL; FILE *f; # ifdef BT_REGEXP_LOG @@ -5280,7 +5284,7 @@ static void regdump(char_u *pattern, bt_regprog_T *r) #ifdef REGEXP_DEBUG // regprop - printable representation of opcode -static char_u *regprop(char_u *op) +static uint8_t *regprop(uint8_t *op) { char *p; static char buf[50]; @@ -5652,6 +5656,6 @@ static char_u *regprop(char_u *op) if (p != NULL) { STRCAT(buf, p); } - return (char_u *)buf; + return (uint8_t *)buf; } #endif // REGEXP_DEBUG diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 6e7ff31c03..ea59e7d464 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -244,10 +244,10 @@ static int nfa_classcodes[] = { NFA_UPPER, NFA_NUPPER }; -static char_u e_nul_found[] = N_("E865: (NFA) Regexp end encountered prematurely"); -static char_u e_misplaced[] = N_("E866: (NFA regexp) Misplaced %c"); -static char_u e_ill_char_class[] = N_("E877: (NFA regexp) Invalid character class: %" PRId64); -static char_u e_value_too_large[] = N_("E951: \\% value too large"); +static char e_nul_found[] = N_("E865: (NFA) Regexp end encountered prematurely"); +static char e_misplaced[] = N_("E866: (NFA regexp) Misplaced %c"); +static char e_ill_char_class[] = N_("E877: (NFA regexp) Invalid character class: %" PRId64); +static char e_value_too_large[] = N_("E951: \\% value too large"); // Since the out pointers in the list are always // uninitialized, we use the pointers themselves @@ -276,8 +276,8 @@ typedef struct { colnr_T end_col; } multi[NSUBEXP]; struct linepos { - char_u *start; - char_u *end; + uint8_t *start; + uint8_t *end; } line[NSUBEXP]; } list; colnr_T orig_start_col; // list.multi[0].start_col without \zs @@ -296,7 +296,7 @@ struct nfa_pim_S { regsubs_T subs; // submatch info, only party used union { lpos_T pos; - char_u *ptr; + uint8_t *ptr; } end; // where the match must end }; @@ -354,7 +354,7 @@ static int nfa_ll_index = 0; /// Initialize internal variables before NFA compilation. /// /// @param re_flags @see vim_regcomp() -static void nfa_regcomp_start(char_u *expr, int re_flags) +static void nfa_regcomp_start(uint8_t *expr, int re_flags) { size_t postfix_size; size_t nstate_max; @@ -519,12 +519,12 @@ static int nfa_get_regstart(nfa_state_T *start, int depth) // Figure out if the NFA state list contains just literal text and nothing // else. If so return a string in allocated memory with what must match after // regstart. Otherwise return NULL. -static char_u *nfa_get_match_text(nfa_state_T *start) +static uint8_t *nfa_get_match_text(nfa_state_T *start) { nfa_state_T *p = start; int len = 0; - char_u *ret; - char_u *s; + uint8_t *ret; + uint8_t *s; if (p->c != NFA_MOPEN) { return NULL; // just in case @@ -571,7 +571,7 @@ static void realloc_post_list(void) // to the closing brace. // Keep in mind that 'ignorecase' applies at execution time, thus [a-z] may // need to be interpreted as [a-zA-Z]. -static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl) +static int nfa_recognize_char_class(uint8_t *start, uint8_t *end, int extra_newl) { #define CLASS_not 0x80 #define CLASS_af 0x40 @@ -582,7 +582,7 @@ static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl) #define CLASS_o9 0x02 #define CLASS_underscore 0x01 - char_u *p; + uint8_t *p; int config = 0; bool newl = extra_newl == true; @@ -1788,9 +1788,9 @@ static int nfa_regatom(void) int equiclass; int collclass; int got_coll_char; - char_u *p; - char_u *endp; - char_u *old_regparse = (char_u *)regparse; + uint8_t *p; + uint8_t *endp; + uint8_t *old_regparse = (uint8_t *)regparse; int extra = 0; int emit_range; int negated; @@ -1873,7 +1873,7 @@ static int nfa_regatom(void) case Magic('L'): case Magic('u'): case Magic('U'): - p = (char_u *)vim_strchr((char *)classchars, no_Magic(c)); + p = (uint8_t *)vim_strchr((char *)classchars, no_Magic(c)); if (p == NULL) { if (extra == NFA_ADD_NL) { semsg(_(e_ill_char_class), (int64_t)c); @@ -1886,7 +1886,7 @@ static int nfa_regatom(void) // When '.' is followed by a composing char ignore the dot, so that // the composing char is matched here. if (c == Magic('.') && utf_iscomposing(peekchr())) { - old_regparse = (char_u *)regparse; + old_regparse = (uint8_t *)regparse; c = getchr(); goto nfa_do_multibyte; } @@ -1932,7 +1932,7 @@ static int nfa_regatom(void) return FAIL; case Magic('~'): { - char_u *lp; + uint8_t *lp; // Previous substitute pattern. // Generated as "\%(pattern\)". @@ -1940,9 +1940,9 @@ static int nfa_regatom(void) emsg(_(e_nopresub)); return FAIL; } - for (lp = (char_u *)reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp)) { + for (lp = (uint8_t *)reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp)) { EMIT(utf_ptr2char((char *)lp)); - if (lp != (char_u *)reg_prev_sub) { + if (lp != (uint8_t *)reg_prev_sub) { EMIT(NFA_CONCAT); } } @@ -2217,13 +2217,13 @@ collection: // - character classes NFA_CLASS_* // - ranges, two characters followed by NFA_RANGE. - p = (char_u *)regparse; - endp = skip_anyof((char *)p); + p = (uint8_t *)regparse; + endp = (uint8_t *)skip_anyof((char *)p); if (*endp == ']') { // Try to reverse engineer character classes. For example, // recognize that [0-9] stands for \d and [A-Za-z_] for \h, // and perform the necessary substitutions in the NFA. - int result = nfa_recognize_char_class((char_u *)regparse, endp, extra == NFA_ADD_NL); + int result = nfa_recognize_char_class((uint8_t *)regparse, endp, extra == NFA_ADD_NL); if (result != FAIL) { if (result >= NFA_FIRST_NL && result <= NFA_LAST_NL) { EMIT(result - NFA_ADD_NL); @@ -2255,7 +2255,7 @@ collection: } // Emit the OR branches for each character in the [] emit_range = false; - while ((char_u *)regparse < endp) { + while ((uint8_t *)regparse < endp) { int oldstartc = startc; startc = -1; got_coll_char = false; @@ -2362,10 +2362,10 @@ collection: // accepts "\t", "\e", etc., but only when the 'l' flag in // 'cpoptions' is not included. if (*regparse == '\\' - && (char_u *)regparse + 1 <= endp - && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL + && (uint8_t *)regparse + 1 <= endp + && (vim_strchr(REGEXP_INRANGE, (uint8_t)regparse[1]) != NULL || (!reg_cpo_lit - && vim_strchr(REGEXP_ABBR, regparse[1]) + && vim_strchr(REGEXP_ABBR, (uint8_t)regparse[1]) != NULL))) { MB_PTR_ADV(regparse); @@ -2927,7 +2927,7 @@ static int nfa_reg(int paren) } #ifdef REGEXP_DEBUG -static char_u code[50]; +static uint8_t code[50]; static void nfa_set_code(int c) { @@ -3275,35 +3275,37 @@ static void nfa_set_code(int c) } static FILE *log_fd; -static char_u e_log_open_failed[] = +static uint8_t e_log_open_failed[] = N_("Could not open temporary log file for writing, displaying on stderr... "); // Print the postfix notation of the current regexp. -static void nfa_postfix_dump(char_u *expr, int retval) +static void nfa_postfix_dump(uint8_t *expr, int retval) { int *p; FILE *f; f = fopen(NFA_REGEXP_DUMP_LOG, "a"); - if (f != NULL) { - fprintf(f, "\n-------------------------\n"); - if (retval == FAIL) { - fprintf(f, ">>> NFA engine failed... \n"); - } else if (retval == OK) { - fprintf(f, ">>> NFA engine succeeded !\n"); - } - fprintf(f, "Regexp: \"%s\"\nPostfix notation (char): \"", expr); - for (p = post_start; *p && p < post_ptr; p++) { - nfa_set_code(*p); - fprintf(f, "%s, ", code); - } - fprintf(f, "\"\nPostfix notation (int): "); - for (p = post_start; *p && p < post_ptr; p++) { - fprintf(f, "%d ", *p); - } - fprintf(f, "\n\n"); - fclose(f); + if (f == NULL) { + return; } + + fprintf(f, "\n-------------------------\n"); + if (retval == FAIL) { + fprintf(f, ">>> NFA engine failed... \n"); + } else if (retval == OK) { + fprintf(f, ">>> NFA engine succeeded !\n"); + } + fprintf(f, "Regexp: \"%s\"\nPostfix notation (char): \"", expr); + for (p = post_start; *p && p < post_ptr; p++) { + nfa_set_code(*p); + fprintf(f, "%s, ", code); + } + fprintf(f, "\"\nPostfix notation (int): "); + for (p = post_start; *p && p < post_ptr; p++) { + fprintf(f, "%d ", *p); + } + fprintf(f, "\n\n"); + fclose(f); } // Print the NFA starting with a root node "state". @@ -3319,7 +3321,7 @@ static void nfa_print_state(FILE *debugf, nfa_state_T *state) static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) { - char_u *p; + uint8_t *p; if (state == NULL) { return; @@ -3328,10 +3330,10 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) fprintf(debugf, "(%2d)", abs(state->id)); // Output indent - p = (char_u *)indent->ga_data; + p = (uint8_t *)indent->ga_data; if (indent->ga_len >= 3) { int last = indent->ga_len - 3; - char_u save[2]; + uint8_t save[2]; strncpy(save, &p[last], 2); // NOLINT(runtime/printf) memcpy(&p[last], "+-", 2); @@ -3356,9 +3358,9 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) // grow indent for state->out indent->ga_len -= 1; if (state->out1) { - ga_concat(indent, (char_u *)"| "); + ga_concat(indent, (uint8_t *)"| "); } else { - ga_concat(indent, (char_u *)" "); + ga_concat(indent, (uint8_t *)" "); } ga_append(indent, NUL); @@ -3366,7 +3368,7 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) // replace last part of indent for state->out1 indent->ga_len -= 3; - ga_concat(indent, (char_u *)" "); + ga_concat(indent, (uint8_t *)" "); ga_append(indent, NUL); nfa_print_state2(debugf, state->out1, indent); @@ -3381,22 +3383,24 @@ static void nfa_dump(nfa_regprog_T *prog) { FILE *debugf = fopen(NFA_REGEXP_DUMP_LOG, "a"); - if (debugf != NULL) { - nfa_print_state(debugf, prog->start); + if (debugf == NULL) { + return; + } - if (prog->reganch) { - fprintf(debugf, "reganch: %d\n", prog->reganch); - } - if (prog->regstart != NUL) { - fprintf(debugf, "regstart: %c (decimal: %d)\n", - prog->regstart, prog->regstart); - } - if (prog->match_text != NULL) { - fprintf(debugf, "match_text: \"%s\"\n", prog->match_text); - } + nfa_print_state(debugf, prog->start); - fclose(debugf); + if (prog->reganch) { + fprintf(debugf, "reganch: %d\n", prog->reganch); + } + if (prog->regstart != NUL) { + fprintf(debugf, "regstart: %c (decimal: %d)\n", + prog->regstart, prog->regstart); } + if (prog->match_text != NULL) { + fprintf(debugf, "match_text: \"%s\"\n", prog->match_text); + } + + fclose(debugf); } #endif // REGEXP_DEBUG @@ -4427,16 +4431,18 @@ static void clear_sub(regsub_T *sub) static void copy_sub(regsub_T *to, regsub_T *from) { to->in_use = from->in_use; - if (from->in_use > 0) { - // Copy the match start and end positions. - if (REG_MULTI) { - memmove(&to->list.multi[0], &from->list.multi[0], - sizeof(struct multipos) * (size_t)from->in_use); - to->orig_start_col = from->orig_start_col; - } else { - memmove(&to->list.line[0], &from->list.line[0], - sizeof(struct linepos) * (size_t)from->in_use); - } + if (from->in_use <= 0) { + return; + } + + // Copy the match start and end positions. + if (REG_MULTI) { + memmove(&to->list.multi[0], &from->list.multi[0], + sizeof(struct multipos) * (size_t)from->in_use); + to->orig_start_col = from->orig_start_col; + } else { + memmove(&to->list.line[0], &from->list.line[0], + sizeof(struct linepos) * (size_t)from->in_use); } } @@ -4446,31 +4452,35 @@ static void copy_sub_off(regsub_T *to, regsub_T *from) if (to->in_use < from->in_use) { to->in_use = from->in_use; } - if (from->in_use > 1) { - // Copy the match start and end positions. - if (REG_MULTI) { - memmove(&to->list.multi[1], &from->list.multi[1], - sizeof(struct multipos) * (size_t)(from->in_use - 1)); - } else { - memmove(&to->list.line[1], &from->list.line[1], - sizeof(struct linepos) * (size_t)(from->in_use - 1)); - } + if (from->in_use <= 1) { + return; + } + + // Copy the match start and end positions. + if (REG_MULTI) { + memmove(&to->list.multi[1], &from->list.multi[1], + sizeof(struct multipos) * (size_t)(from->in_use - 1)); + } else { + memmove(&to->list.line[1], &from->list.line[1], + sizeof(struct linepos) * (size_t)(from->in_use - 1)); } } // Like copy_sub() but only do the end of the main match if \ze is present. static void copy_ze_off(regsub_T *to, regsub_T *from) { - if (rex.nfa_has_zend) { - if (REG_MULTI) { - if (from->list.multi[0].end_lnum >= 0) { - to->list.multi[0].end_lnum = from->list.multi[0].end_lnum; - to->list.multi[0].end_col = from->list.multi[0].end_col; - } - } else { - if (from->list.line[0].end != NULL) { - to->list.line[0].end = from->list.line[0].end; - } + if (!rex.nfa_has_zend) { + return; + } + + if (REG_MULTI) { + if (from->list.multi[0].end_lnum >= 0) { + to->list.multi[0].end_lnum = from->list.multi[0].end_lnum; + to->list.multi[0].end_col = from->list.multi[0].end_col; + } + } else { + if (from->list.line[0].end != NULL) { + to->list.line[0].end = from->list.line[0].end; } } } @@ -4483,8 +4493,8 @@ static bool sub_equal(regsub_T *sub1, regsub_T *sub2) int todo; linenr_T s1; linenr_T s2; - char_u *sp1; - char_u *sp2; + uint8_t *sp1; + uint8_t *sp2; todo = sub1->in_use > sub2->in_use ? sub1->in_use : sub2->in_use; if (REG_MULTI) { @@ -4779,7 +4789,7 @@ static regsubs_T *addstate(nfa_list_T *l, nfa_state_T *state, regsubs_T *subs_ar nfa_thread_T *thread; struct multipos save_multipos; int save_in_use; - char_u *save_ptr; + uint8_t *save_ptr; int i; regsub_T *sub; regsubs_T *subs = subs_arg; @@ -5522,10 +5532,10 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T // bytes if possible. if (state->val <= 0) { if (REG_MULTI) { - rex.line = reg_getline(--rex.lnum); + rex.line = (uint8_t *)reg_getline(--rex.lnum); if (rex.line == NULL) { // can't go before the first line - rex.line = reg_getline(++rex.lnum); + rex.line = (uint8_t *)reg_getline(++rex.lnum); } } rex.input = rex.line; @@ -5533,10 +5543,10 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T if (REG_MULTI && (int)(rex.input - rex.line) < state->val) { // Not enough bytes in this line, go to end of // previous line. - rex.line = reg_getline(--rex.lnum); + rex.line = (uint8_t *)reg_getline(--rex.lnum); if (rex.line == NULL) { // can't go before the first line - rex.line = reg_getline(++rex.lnum); + rex.line = (uint8_t *)reg_getline(++rex.lnum); rex.input = rex.line; } else { rex.input = rex.line + strlen((char *)rex.line); @@ -5595,7 +5605,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T // restore position in input text rex.lnum = save_reglnum; if (REG_MULTI) { - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); } rex.input = rex.line + save_reginput_col; if (result != NFA_TOO_EXPENSIVE) { @@ -5772,7 +5782,7 @@ static int failure_chance(nfa_state_T *state, int depth) // Skip until the char "c" we know a match must start with. static int skip_to_start(int c, colnr_T *colp) { - const char_u *const s = cstrchr(rex.line + *colp, c); + const uint8_t *const s = (uint8_t *)cstrchr((char *)rex.line + *colp, c); if (s == NULL) { return FAIL; } @@ -5783,7 +5793,7 @@ static int skip_to_start(int c, colnr_T *colp) // Check for a match with match_text. // Called after skip_to_start() has found regstart. // Returns zero for no match, 1 for a match. -static long find_match_text(colnr_T *startcol, int regstart, char_u *match_text) +static long find_match_text(colnr_T *startcol, int regstart, uint8_t *match_text) { #define PTR2LEN(x) utf_ptr2len(x) @@ -5792,8 +5802,8 @@ static long find_match_text(colnr_T *startcol, int regstart, char_u *match_text) for (;;) { bool match = true; - char_u *s1 = match_text; - char_u *s2 = rex.line + col + regstart_len; // skip regstart + uint8_t *s1 = match_text; + uint8_t *s2 = rex.line + col + regstart_len; // skip regstart while (*s1) { int c1_len = PTR2LEN((char *)s1); int c1 = utf_ptr2char((char *)s1); @@ -6860,7 +6870,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm // Line may have been freed, get it again. if (REG_MULTI) { - rex.line = reg_getline(rex.lnum); + rex.line = (uint8_t *)reg_getline(rex.lnum); rex.input = rex.line + col; } @@ -7298,15 +7308,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] = - (char_u *)xstrnsave((char *)reg_getline(mpos->start_lnum) + mpos->start_col, - (size_t)(mpos->end_col - mpos->start_col)); + (uint8_t *)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] = - (char_u *)xstrnsave((char *)lpos->start, (size_t)(lpos->end - lpos->start)); + (uint8_t *)xstrnsave((char *)lpos->start, (size_t)(lpos->end - lpos->start)); } } } @@ -7325,7 +7335,7 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm, int *ti /// /// @return <= 0 if there is no match and number of lines contained in the /// match otherwise. -static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int *timed_out) +static long nfa_regexec_both(uint8_t *line, colnr_T startcol, proftime_T *tm, int *timed_out) { nfa_regprog_T *prog; long retval = 0L; @@ -7333,13 +7343,13 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm, int if (REG_MULTI) { prog = (nfa_regprog_T *)rex.reg_mmatch->regprog; - line = reg_getline((linenr_T)0); // relative to the cursor + line = (uint8_t *)reg_getline((linenr_T)0); // relative to the cursor rex.reg_startpos = rex.reg_mmatch->startpos; rex.reg_endpos = rex.reg_mmatch->endpos; } else { prog = (nfa_regprog_T *)rex.reg_match->regprog; - rex.reg_startp = (char_u **)rex.reg_match->startp; - rex.reg_endp = (char_u **)rex.reg_match->endp; + rex.reg_startp = (uint8_t **)rex.reg_match->startp; + rex.reg_endp = (uint8_t **)rex.reg_match->endp; } // Be paranoid... @@ -7454,7 +7464,7 @@ theend: // Compile a regular expression into internal code for the NFA matcher. // Returns the program in allocated space. Returns NULL for an error. -static regprog_T *nfa_regcomp(char_u *expr, int re_flags) +static regprog_T *nfa_regcomp(uint8_t *expr, int re_flags) { nfa_regprog_T *prog = NULL; int *postfix; @@ -7501,7 +7511,7 @@ static regprog_T *nfa_regcomp(char_u *expr, int re_flags) post2nfa(postfix, post_ptr, true); // allocate the regprog with space for the compiled regexp - size_t prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (size_t)(nstate - 1); + size_t prog_size = offsetof(nfa_regprog_T, state) + sizeof(nfa_state_T) * (size_t)nstate; prog = xmalloc(prog_size); state_ptr = prog->state; prog->re_in_use = false; @@ -7554,11 +7564,13 @@ fail: // Free a compiled regexp program, returned by nfa_regcomp(). static void nfa_regfree(regprog_T *prog) { - if (prog != NULL) { - xfree(((nfa_regprog_T *)prog)->match_text); - xfree(((nfa_regprog_T *)prog)->pattern); - xfree(prog); + if (prog == NULL) { + return; } + + xfree(((nfa_regprog_T *)prog)->match_text); + xfree(((nfa_regprog_T *)prog)->pattern); + xfree(prog); } /// Match a regexp against a string. @@ -7570,7 +7582,7 @@ static void nfa_regfree(regprog_T *prog) /// @param col column to start looking for match /// /// @return <= 0 for failure, number of lines contained in the match otherwise. -static int nfa_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col, bool line_lbr) +static int nfa_regexec_nl(regmatch_T *rmp, uint8_t *line, colnr_T col, bool line_lbr) { rex.reg_match = rmp; rex.reg_mmatch = NULL; diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index e009b883ca..b071e10cf9 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -9,7 +9,6 @@ #include <errno.h> #include <fcntl.h> #include <inttypes.h> -#include <stddef.h> #include <stdio.h> #include <string.h> #include <uv.h> @@ -27,6 +26,7 @@ #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" @@ -105,7 +105,7 @@ estack_T *estack_push(etype_T type, char *name, linenr_T lnum) void estack_push_ufunc(ufunc_T *ufunc, linenr_T lnum) { estack_T *entry = estack_push(ETYPE_UFUNC, - ufunc->uf_name_exp != NULL ? (char *)ufunc->uf_name_exp : ufunc->uf_name, + ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name, lnum); if (entry != NULL) { entry->es_info.ufunc = ufunc; @@ -209,29 +209,56 @@ void runtime_init(void) uv_mutex_init(&runtime_search_path_mutex); } -/// ":runtime [what] {name}" +/// Get DIP_ flags from the [where] argument of a :runtime command. +/// "*argp" is advanced to after the [where] argument. +static int get_runtime_cmd_flags(char **argp, size_t where_len) +{ + char *arg = *argp; + + if (where_len == 0) { + return 0; + } + + if (strncmp(arg, "START", where_len) == 0) { + *argp = skipwhite(arg + where_len); + return DIP_START + DIP_NORTP; + } + if (strncmp(arg, "OPT", where_len) == 0) { + *argp = skipwhite(arg + where_len); + return DIP_OPT + DIP_NORTP; + } + if (strncmp(arg, "PACK", where_len) == 0) { + *argp = skipwhite(arg + where_len); + return DIP_START + DIP_OPT + DIP_NORTP; + } + if (strncmp(arg, "ALL", where_len) == 0) { + *argp = skipwhite(arg + where_len); + return DIP_START + DIP_OPT; + } + + return 0; +} + +/// ":runtime [where] {name}" void ex_runtime(exarg_T *eap) { char *arg = eap->arg; - char *p = skiptowhite(arg); - size_t len = (size_t)(p - arg); int flags = eap->forceit ? DIP_ALL : 0; + char *p = skiptowhite(arg); + flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg)); + source_runtime(arg, flags); +} - if (strncmp(arg, "START", len) == 0) { - flags += DIP_START + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "OPT", len) == 0) { - flags += DIP_OPT + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "PACK", len) == 0) { - flags += DIP_START + DIP_OPT + DIP_NORTP; - arg = skipwhite(arg + len); - } else if (strncmp(arg, "ALL", len) == 0) { - flags += DIP_START + DIP_OPT; - arg = skipwhite(arg + len); - } +static int runtime_expand_flags; - source_runtime(arg, flags); +/// Set the completion context for the :runtime command. +void set_context_in_runtime_cmd(expand_T *xp, const char *arg) +{ + char *p = skiptowhite(arg); + runtime_expand_flags + = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0; + xp->xp_context = EXPAND_RUNTIME; + xp->xp_pattern = (char *)arg; } static void source_callback(char *fname, void *cookie) @@ -822,12 +849,14 @@ static void source_all_matches(char *pat) int num_files; char **files; - if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK) { - for (int i = 0; i < num_files; i++) { - (void)do_source(files[i], false, DOSO_NONE); - } - FreeWild(num_files, files); + if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) != OK) { + return; + } + + for (int i = 0; i < num_files; i++) { + (void)do_source(files[i], false, DOSO_NONE); } + FreeWild(num_files, files); } /// Add the package directory to 'runtimepath' @@ -1174,124 +1203,154 @@ void ex_packadd(exarg_T *eap) } } -/// Expand color scheme, compiler or filetype names. -/// Search from 'runtimepath': -/// 'runtimepath'/{dirnames}/{pat}.vim -/// When "flags" has DIP_START: search also from 'start' of 'packpath': -/// 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim -/// When "flags" has DIP_OPT: search also from 'opt' of 'packpath': -/// '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 *pat, int flags, int *num_file, char ***file, char *dirnames[]) +static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap, + char *dirnames[]) { - *num_file = 0; - *file = NULL; - 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. + // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { - 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(s, size, "%s/%s*.lua", dirnames[i], pat); - globpath(p_rtp, s, &ga, 0); + const size_t buf_len = strlen(dirnames[i]) + pat_len + 31; + char *const buf = xmalloc(buf_len); + char *const tail = buf + 15; + const size_t tail_buflen = buf_len - 15; + int glob_flags = 0; + bool expand_dirs = false; + + if (*dirnames[i] == NUL) { // empty dir used for :runtime + snprintf(tail, tail_buflen, "%s*.\\(vim\\|lua\\)", pat); + } else { + snprintf(tail, tail_buflen, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); } - xfree(s); - } - if (flags & DIP_START) { - for (int i = 0; dirnames[i] != NULL; i++) { - 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(s, size, "pack/*/start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - } - xfree(s); +expand: + if ((flags & DIP_NORTP) == 0) { + globpath(p_rtp, tail, gap, glob_flags, expand_dirs); } - for (int i = 0; dirnames[i] != NULL; i++) { - 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(s, size, "start/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - } - xfree(s); + if (flags & DIP_START) { + memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT + globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs); + memcpy(tail - 8, "start/*/", 8); // NOLINT + globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs); } - } - if (flags & DIP_OPT) { - for (int i = 0; dirnames[i] != NULL; i++) { - 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(s, size, "pack/*/opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - } - xfree(s); + if (flags & DIP_OPT) { + memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT + globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs); + memcpy(tail - 6, "opt/*/", 6); // NOLINT + globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs); } - for (int i = 0; dirnames[i] != NULL; i++) { - 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(s, size, "opt/*/%s/%s*.lua", dirnames[i], pat); // NOLINT - globpath(p_pp, s, &ga, 0); - } - xfree(s); + if (*dirnames[i] == NUL && !expand_dirs) { + // expand dir names in another round + snprintf(tail, tail_buflen, "%s*", pat); + glob_flags = WILD_ADD_SLASH; + expand_dirs = true; + goto expand; + } + + xfree(buf); + } + + int pat_pathsep_cnt = 0; + for (size_t i = 0; i < pat_len; i++) { + if (vim_ispathsep(pat[i])) { + pat_pathsep_cnt++; } } - for (int i = 0; i < ga.ga_len; i++) { - char *match = ((char **)ga.ga_data)[i]; + for (int i = 0; i < gap->ga_len; i++) { + char *match = ((char **)gap->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))) { + if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0 + || STRNICMP(e - 4, ".lua", 4) == 0)) { e -= 4; - for (s = e; s > match; MB_PTR_BACK(match, s)) { - if (vim_ispathsep(*s)) { - break; - } - } - s++; *e = NUL; + } + + int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0; + for (s = e; s > match; MB_PTR_BACK(match, s)) { + if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) { + break; + } + } + s++; + if (s != match) { assert((e - s) + 1 >= 0); memmove(match, s, (size_t)(e - s) + 1); } } - if (GA_EMPTY(&ga)) { - return FAIL; + if (GA_EMPTY(gap)) { + return; } // Sort and remove duplicates which can happen when specifying multiple // directories in dirnames. - ga_remove_duplicate_strings(&ga); + ga_remove_duplicate_strings(gap); +} + +/// Expand color scheme, compiler or filetype names. +/// Search from 'runtimepath': +/// 'runtimepath'/{dirnames}/{pat}.(vim|lua) +/// When "flags" has DIP_START: search also from "start" of 'packpath': +/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua) +/// When "flags" has DIP_OPT: search also from "opt" of 'packpath': +/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua) +/// "dirnames" is an array with one or more directory names. +int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[]) +{ + *num_file = 0; + *file = NULL; + + garray_T ga; + ga_init(&ga, (int)sizeof(char *), 10); + + ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames); + + if (GA_EMPTY(&ga)) { + return FAIL; + } *file = ga.ga_data; *num_file = ga.ga_len; return OK; } +/// Handle command line completion for :runtime command. +int expand_runtime_cmd(char *pat, int *numMatches, char ***matches) +{ + *numMatches = 0; + *matches = NULL; + + garray_T ga; + ga_init(&ga, sizeof(char *), 10); + + const size_t pat_len = strlen(pat); + char *dirnames[] = { "", NULL }; + ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames); + + // Try to complete values for [where] argument when none was found. + if (runtime_expand_flags == 0) { + char *where_values[] = { "START", "OPT", "PACK", "ALL" }; + for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) { + if (strncmp(pat, where_values[i], pat_len) == 0) { + GA_APPEND(char *, &ga, xstrdup(where_values[i])); + } + } + } + + if (GA_EMPTY(&ga)) { + return FAIL; + } + + *matches = ga.ga_data; + *numMatches = ga.ga_len; + return OK; +} + /// Expand loadplugin names: -/// 'packpath'/pack/ * /opt/{pat} +/// 'packpath'/pack/*/opt/{pat} int ExpandPackAddDir(char *pat, int *num_file, char ***file) { garray_T ga; @@ -1304,9 +1363,9 @@ int ExpandPackAddDir(char *pat, int *num_file, char ***file) size_t buflen = pat_len + 26; char *s = xmalloc(buflen); snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT - globpath(p_pp, s, &ga, 0); + globpath(p_pp, s, &ga, 0, true); snprintf(s, buflen, "opt/%s*", pat); // NOLINT - globpath(p_pp, s, &ga, 0); + globpath(p_pp, s, &ga, 0, true); xfree(s); for (int i = 0; i < ga.ga_len; i++) { @@ -2161,12 +2220,17 @@ scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx) /// ":scriptnames" void ex_scriptnames(exarg_T *eap) { - if (eap->addr_count > 0) { + if (eap->addr_count > 0 || *eap->arg != NUL) { // :script {scriptId}: edit the script - if (eap->line2 < 1 || eap->line2 > script_items.ga_len) { + if (eap->addr_count > 0 && !SCRIPT_ID_VALID(eap->line2)) { emsg(_(e_invarg)); } else { - eap->arg = SCRIPT_ITEM(eap->line2).sn_name; + if (eap->addr_count > 0) { + eap->arg = SCRIPT_ITEM(eap->line2).sn_name; + } else { + expand_env(eap->arg, NameBuff, MAXPATHL); + eap->arg = NameBuff; + } do_exedit(eap, NULL); } return; diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index de363020f8..97063b900c 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -105,7 +105,6 @@ typedef kvec_t(char *) CharVec; #define DIP_NORTP 0x20 // do not use 'runtimepath' #define DIP_NOAFTER 0x40 // skip "after" directories #define DIP_AFTER 0x80 // only use "after" directories -#define DIP_LUA 0x100 // also use ".lua" files #define DIP_DIRFILE 0x200 // find both files and directories #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b18bf7ed6a..05da6e0ef1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -295,52 +295,54 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) return false; } - { - buf_T *old_curbuf = curbuf; - win_T *old_curwin = curwin; - char *s; - - curbuf = wp->w_buffer; - curwin = wp; - STRCPY(buf, "b:keymap_name"); // must be writable - emsg_skip++; - s = p = eval_to_string(buf, NULL, false); - emsg_skip--; - curbuf = old_curbuf; - curwin = old_curwin; - if (p == NULL || *p == NUL) { - if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) { - p = wp->w_buffer->b_p_keymap; - } else { - p = "lang"; - } - } - if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) { - buf[0] = NUL; + buf_T *old_curbuf = curbuf; + win_T *old_curwin = curwin; + char *s; + + curbuf = wp->w_buffer; + curwin = wp; + STRCPY(buf, "b:keymap_name"); // must be writable + emsg_skip++; + s = p = eval_to_string(buf, NULL, false); + emsg_skip--; + curbuf = old_curbuf; + curwin = old_curwin; + if (p == NULL || *p == NUL) { + if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED) { + p = wp->w_buffer->b_p_keymap; + } else { + p = "lang"; } - xfree(s); } + if (vim_snprintf(buf, (size_t)len, fmt, p) > len - 1) { + buf[0] = NUL; + } + xfree(s); return buf[0] != NUL; } /// Prepare for 'hlsearch' highlighting. void start_search_hl(void) { - if (p_hls && !no_hlsearch) { - end_search_hl(); // just in case it wasn't called before - last_pat_prog(&screen_search_hl.rm); - // Set the time limit to 'redrawtime'. - screen_search_hl.tm = profile_setlimit(p_rdt); + if (!p_hls || no_hlsearch) { + return; } + + end_search_hl(); // just in case it wasn't called before + last_pat_prog(&screen_search_hl.rm); + // Set the time limit to 'redrawtime'. + screen_search_hl.tm = profile_setlimit(p_rdt); } /// Clean up for 'hlsearch' highlighting. void end_search_hl(void) { - if (screen_search_hl.rm.regprog != NULL) { - vim_regfree(screen_search_hl.rm.regprog); - screen_search_hl.rm.regprog = NULL; + if (screen_search_hl.rm.regprog == NULL) { + return; } + + vim_regfree(screen_search_hl.rm.regprog); + screen_search_hl.rm.regprog = NULL; } /// Check if there should be a delay. Used before clearing or redrawing the @@ -671,11 +673,13 @@ void clearmode(void) static void recording_mode(int attr) { msg_puts_attr(_("recording"), attr); - if (!shortmess(SHM_RECORDING)) { - char s[4]; - snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording); - msg_puts_attr(s, attr); + if (shortmess(SHM_RECORDING)) { + return; } + + char s[4]; + snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording); + msg_puts_attr(s, attr); } void get_trans_bufname(buf_T *buf) @@ -764,7 +768,6 @@ void comp_col(void) /// Otherwise it depends on 'numberwidth' and the line count. int number_width(win_T *wp) { - int n; linenr_T lnum; if (wp->w_p_rnu && !wp->w_p_nu) { @@ -780,17 +783,13 @@ int number_width(win_T *wp) } wp->w_nrwidth_line_count = lnum; - // make best estimate for 'statuscolumn' + // reset for 'statuscolumn' if (*wp->w_p_stc != NUL) { - char buf[MAXPATHL]; - wp->w_nrwidth_width = 0; - n = build_statuscol_str(wp, true, false, lnum, 0, 0, NUL, buf, NULL, NULL); - n = MAX(n, (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw); - wp->w_nrwidth_width = MIN(n, MAX_NUMBERWIDTH); + wp->w_nrwidth_width = (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw; return wp->w_nrwidth_width; } - n = 0; + int n = 0; do { lnum /= 10; n++; @@ -815,15 +814,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(const char_u **p) +static int get_encoded_char_adv(const char **p) { - const char *s = (const char *)(*p); + const char *s = *p; if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) { int64_t num = 0; for (int bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) { *p += 2; - int n = hexhex2nr((char *)(*p)); + int n = hexhex2nr(*p); if (n < 0) { return 0; } @@ -952,7 +951,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) if (strncmp(p, tab[i].name, len) == 0 && p[len] == ':' && p[len + 1] != NUL) { - const char_u *s = (char_u *)p + len + 1; + const char *s = p + len + 1; int c1 = get_encoded_char_adv(&s); if (c1 == 0 || char2cells(c1) > 1) { return e_invarg; @@ -983,7 +982,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) *(tab[i].cp) = c1; } } - p = (char *)s; + p = s; break; } } @@ -996,7 +995,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) && strncmp(p, "multispace", len) == 0 && p[len] == ':' && p[len + 1] != NUL) { - const char_u *s = (char_u *)p + len + 1; + const char *s = p + len + 1; if (round == 0) { // Get length of lcs-multispace string in the first round last_multispace = p; @@ -1012,7 +1011,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) // lcs-multispace cannot be an empty string return e_invarg; } - p = (char *)s; + p = s; } else { int multispace_pos = 0; while (*s != NUL && *s != ',') { @@ -1021,13 +1020,13 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) wp->w_p_lcs_chars.multispace[multispace_pos++] = c1; } } - p = (char *)s; + p = s; } } else if (is_listchars && strncmp(p, "leadmultispace", len2) == 0 && p[len2] == ':' && p[len2 + 1] != NUL) { - const char_u *s = (char_u *)p + len2 + 1; + const char *s = p + len2 + 1; if (round == 0) { // get length of lcs-leadmultispace string in first round last_lmultispace = p; @@ -1043,7 +1042,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) // lcs-leadmultispace cannot be an empty string return e_invarg; } - p = (char *)s; + p = s; } else { int multispace_pos = 0; while (*s != NUL && *s != ',') { @@ -1052,7 +1051,7 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1; } } - p = (char *)s; + p = s; } } else { return e_invarg; diff --git a/src/nvim/search.c b/src/nvim/search.c index 871d2f9a0a..eb5cc2e07f 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -133,7 +133,7 @@ typedef struct SearchedFile { /// @param regmatch return: pattern and ignore-case flag /// /// @return FAIL if failed, OK otherwise. -int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, int options, +int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch) { int magic; @@ -158,11 +158,11 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in rc_did_emsg = true; return FAIL; } - pat = (char_u *)spats[i].pat; + pat = spats[i].pat; 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, (char *)pat, true, NUL); + add_to_history(HIST_SEARCH, pat, true, NUL); } if (used_pat) { @@ -171,9 +171,9 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in xfree(mr_pattern); if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { - mr_pattern = reverse_text((char *)pat); + mr_pattern = reverse_text(pat); } else { - mr_pattern = xstrdup((char *)pat); + mr_pattern = xstrdup(pat); } // Save the currently used pattern in the appropriate place, @@ -181,17 +181,17 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in 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, (char *)pat, magic); + save_re_pat(RE_SEARCH, pat, magic); } // substitute or global command if (pat_save == RE_SUBST || pat_save == RE_BOTH) { - save_re_pat(RE_SUBST, (char *)pat, magic); + save_re_pat(RE_SUBST, pat, magic); } } - regmatch->rmm_ic = ignorecase((char *)pat); + regmatch->rmm_ic = ignorecase(pat); regmatch->rmm_maxcol = 0; - regmatch->regprog = vim_regcomp((char *)pat, magic ? RE_MAGIC : 0); + regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0); if (regmatch->regprog == NULL) { return FAIL; } @@ -206,20 +206,22 @@ char *get_search_pat(void) void save_re_pat(int idx, char *pat, int magic) { - if (spats[idx].pat != pat) { - free_spat(&spats[idx]); - spats[idx].pat = xstrdup(pat); - spats[idx].magic = magic; - spats[idx].no_scs = no_smartcase; - spats[idx].timestamp = os_time(); - spats[idx].additional_data = NULL; - last_idx = idx; - // If 'hlsearch' set and search pat changed: need redraw. - if (p_hls) { - redraw_all_later(UPD_SOME_VALID); - } - set_no_hlsearch(false); + if (spats[idx].pat == pat) { + return; + } + + free_spat(&spats[idx]); + spats[idx].pat = xstrdup(pat); + spats[idx].magic = magic; + spats[idx].no_scs = no_smartcase; + spats[idx].timestamp = os_time(); + spats[idx].additional_data = NULL; + last_idx = idx; + // If 'hlsearch' set and search pat changed: need redraw. + if (p_hls) { + redraw_all_later(UPD_SOME_VALID); } + set_no_hlsearch(false); } // Save the search patterns, so they can be restored later. @@ -228,38 +230,42 @@ static int save_level = 0; void save_search_patterns(void) { - if (save_level++ == 0) { - saved_spats[0] = spats[0]; - if (spats[0].pat != NULL) { - saved_spats[0].pat = xstrdup(spats[0].pat); - } - saved_spats[1] = spats[1]; - if (spats[1].pat != NULL) { - saved_spats[1].pat = xstrdup(spats[1].pat); - } - if (mr_pattern == NULL) { - saved_mr_pattern = NULL; - } else { - saved_mr_pattern = xstrdup(mr_pattern); - } - saved_spats_last_idx = last_idx; - saved_spats_no_hlsearch = no_hlsearch; + if (save_level++ != 0) { + return; + } + + saved_spats[0] = spats[0]; + if (spats[0].pat != NULL) { + saved_spats[0].pat = xstrdup(spats[0].pat); + } + saved_spats[1] = spats[1]; + if (spats[1].pat != NULL) { + saved_spats[1].pat = xstrdup(spats[1].pat); } + if (mr_pattern == NULL) { + saved_mr_pattern = NULL; + } else { + saved_mr_pattern = xstrdup(mr_pattern); + } + saved_spats_last_idx = last_idx; + saved_spats_no_hlsearch = no_hlsearch; } void restore_search_patterns(void) { - if (--save_level == 0) { - free_spat(&spats[0]); - spats[0] = saved_spats[0]; - set_vv_searchforward(); - free_spat(&spats[1]); - spats[1] = saved_spats[1]; - xfree(mr_pattern); - mr_pattern = saved_mr_pattern; - last_idx = saved_spats_last_idx; - set_no_hlsearch(saved_spats_no_hlsearch); + if (--save_level != 0) { + return; } + + free_spat(&spats[0]); + spats[0] = saved_spats[0]; + set_vv_searchforward(); + free_spat(&spats[1]); + spats[1] = saved_spats[1]; + xfree(mr_pattern); + mr_pattern = saved_mr_pattern; + last_idx = saved_spats_last_idx; + set_no_hlsearch(saved_spats_no_hlsearch); } static inline void free_spat(struct spat *const spat) @@ -346,9 +352,9 @@ static void restore_incsearch_state(void) search_match_lines = saved_search_match_lines; } -char_u *last_search_pattern(void) +char *last_search_pattern(void) { - return (char_u *)spats[RE_SEARCH].pat; + return spats[RE_SEARCH].pat; } /// Return true when case should be ignored for search pattern "pat". @@ -365,7 +371,7 @@ int ignorecase_opt(char *pat, int ic_in, int scs) if (ic && !no_smartcase && scs && !(ctrl_x_mode_not_default() && curbuf->b_p_inf)) { - ic = !pat_has_uppercase((char_u *)pat); + ic = !pat_has_uppercase(pat); } no_smartcase = false; @@ -373,14 +379,14 @@ int ignorecase_opt(char *pat, int ic_in, int scs) } /// Returns true if pattern `pat` has an uppercase character. -bool pat_has_uppercase(char_u *pat) +bool pat_has_uppercase(char *pat) FUNC_ATTR_NONNULL_ALL { - char *p = (char *)pat; + char *p = pat; magic_T magic_val = MAGIC_ON; // get the magicness of the pattern - (void)skip_regexp_ex((char *)pat, NUL, magic_isset(), NULL, NULL, &magic_val); + (void)skip_regexp_ex(pat, NUL, magic_isset(), NULL, NULL, &magic_val); while (*p != NUL) { const int l = utfc_ptr2len(p); @@ -431,7 +437,7 @@ int last_csearch_until(void) return last_t_cmd == true; } -void set_last_csearch(int c, char_u *s, int len) +void set_last_csearch(int c, char *s, int len) { *lastc = (char_u)c; lastc_bytelen = len; @@ -452,9 +458,9 @@ void set_csearch_until(int t_cmd) last_t_cmd = t_cmd; } -char_u *last_search_pat(void) +char *last_search_pat(void) { - return (char_u *)spats[last_idx].pat; + return spats[last_idx].pat; } // Reset search direction to forward. For "gd" and "gD" commands. @@ -466,14 +472,14 @@ void reset_search_dir(void) // 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) +void set_last_search_pat(const char *s, int idx, int magic, int setlast) { free_spat(&spats[idx]); // An empty string means that nothing should be matched. if (*s == NUL) { spats[idx].pat = NULL; } else { - spats[idx].pat = xstrdup((char *)s); + spats[idx].pat = xstrdup(s); } spats[idx].timestamp = os_time(); spats[idx].additional_data = NULL; @@ -513,7 +519,7 @@ void last_pat_prog(regmmatch_T *regmatch) return; } emsg_off++; // So it doesn't beep if bad expr - (void)search_regcomp((char_u *)"", NULL, 0, last_idx, SEARCH_KEEP, regmatch); + (void)search_regcomp("", NULL, 0, last_idx, SEARCH_KEEP, regmatch); emsg_off--; } @@ -540,7 +546,7 @@ void last_pat_prog(regmmatch_T *regmatch) /// @returns FAIL (zero) for failure, non-zero for success. /// the index of the first matching /// subpattern plus one; one if there was none. -int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char_u *pat, +int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char *pat, long count, int options, int pat_use, searchit_arg_T *extra_arg) { int found; @@ -1296,7 +1302,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, long count, i } c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD, - (char_u *)searchstr, count, + searchstr, count, (spats[0].off.end * SEARCH_END + (options & (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG @@ -2321,55 +2327,63 @@ void showmatch(int c) if ((lpos = findmatch(NULL, NUL)) == NULL) { // no match, so beep vim_beep(BO_MATCH); - } else if (lpos->lnum >= curwin->w_topline - && lpos->lnum < curwin->w_botline) { - if (!curwin->w_p_wrap) { - getvcol(curwin, lpos, NULL, &vcol, NULL); - } - if (curwin->w_p_wrap - || (vcol >= curwin->w_leftcol - && vcol < curwin->w_leftcol + curwin->w_width_inner)) { - mpos = *lpos; // save the pos, update_screen() may change it - save_cursor = curwin->w_cursor; - save_so = *so; - save_siso = *siso; - // Handle "$" in 'cpo': If the ')' is typed on top of the "$", - // stop displaying the "$". - if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) { - dollar_vcol = -1; - } - curwin->w_virtcol++; // do display ')' just before "$" - update_screen(); // show the new char first - - save_dollar_vcol = dollar_vcol; - save_state = State; - State = MODE_SHOWMATCH; - ui_cursor_shape(); // may show different cursor shape - curwin->w_cursor = mpos; // move to matching char - *so = 0; // don't use 'scrolloff' here - *siso = 0; // don't use 'sidescrolloff' here - show_cursor_info(false); - setcursor(); - ui_flush(); - // Restore dollar_vcol(), because setcursor() may call curs_rows() - // which resets it if the matching position is in a previous line - // and has a higher column number. - dollar_vcol = save_dollar_vcol; - - // 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()) { - os_delay((uint64_t)p_mat * 100L + 9, false); - } - curwin->w_cursor = save_cursor; // restore cursor position - *so = save_so; - *siso = save_siso; - State = save_state; - ui_cursor_shape(); // may show different cursor shape - } + return; + } + + if (lpos->lnum < curwin->w_topline || lpos->lnum >= curwin->w_botline) { + return; + } + + if (!curwin->w_p_wrap) { + getvcol(curwin, lpos, NULL, &vcol, NULL); + } + + bool col_visible = curwin->w_p_wrap + || (vcol >= curwin->w_leftcol + && vcol < curwin->w_leftcol + curwin->w_width_inner); + if (!col_visible) { + return; + } + + mpos = *lpos; // save the pos, update_screen() may change it + save_cursor = curwin->w_cursor; + save_so = *so; + save_siso = *siso; + // Handle "$" in 'cpo': If the ')' is typed on top of the "$", + // stop displaying the "$". + if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) { + dollar_vcol = -1; } + curwin->w_virtcol++; // do display ')' just before "$" + update_screen(); // show the new char first + + save_dollar_vcol = dollar_vcol; + save_state = State; + State = MODE_SHOWMATCH; + ui_cursor_shape(); // may show different cursor shape + curwin->w_cursor = mpos; // move to matching char + *so = 0; // don't use 'scrolloff' here + *siso = 0; // don't use 'sidescrolloff' here + show_cursor_info(false); + setcursor(); + ui_flush(); + // Restore dollar_vcol(), because setcursor() may call curs_rows() + // which resets it if the matching position is in a previous line + // and has a higher column number. + dollar_vcol = save_dollar_vcol; + + // 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()) { + os_delay((uint64_t)p_mat * 100L + 9, false); + } + curwin->w_cursor = save_cursor; // restore cursor position + *so = save_so; + *siso = save_siso; + State = save_state; + ui_cursor_shape(); // may show different cursor shape } /// Find next search match under cursor, cursor at end. @@ -2440,7 +2454,7 @@ int current_search(long count, bool forward) result = searchit(curwin, curbuf, &pos, &end_pos, (dir ? FORWARD : BACKWARD), - (char_u *)spats[last_idx].pat, i ? count : 1, + spats[last_idx].pat, i ? count : 1, SEARCH_KEEP | flags, RE_SEARCH, NULL); p_ws = old_p_ws; @@ -2527,7 +2541,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio pattern = spats[last_idx].pat; } - if (search_regcomp((char_u *)pattern, NULL, RE_SEARCH, RE_SEARCH, + if (search_regcomp(pattern, NULL, RE_SEARCH, RE_SEARCH, SEARCH_KEEP, ®match) == FAIL) { return -1; } @@ -2542,7 +2556,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio // accept a match at the cursor position flag = SEARCH_START; } - if (searchit(curwin, curbuf, &pos, NULL, direction, (char_u *)pattern, 1, + if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) { // Zero-width pattern should match somewhere, then we can check if // start and end are in the same position. @@ -2588,56 +2602,63 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh update_search_stat(dirc, pos, cursor_pos, &stat, recompute, maxcount, timeout); - if (stat.cur > 0) { - char t[SEARCH_STAT_BUF_LEN]; - - if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { - if (stat.incomplete == 1) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); - } else if (stat.cnt > maxcount && stat.cur > maxcount) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", - maxcount, maxcount); - } else if (stat.cnt > maxcount) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]", - maxcount, stat.cur); - } else { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", - stat.cnt, stat.cur); - } + if (stat.cur <= 0) { + return; + } + + char t[SEARCH_STAT_BUF_LEN]; + + if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { + if (stat.incomplete == 1) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + } else if (stat.cnt > maxcount && stat.cur > maxcount) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + maxcount, maxcount); + } else if (stat.cnt > maxcount) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]", + maxcount, stat.cur); } else { - if (stat.incomplete == 1) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); - } else if (stat.cnt > maxcount && stat.cur > maxcount) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", - maxcount, maxcount); - } else if (stat.cnt > maxcount) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]", - stat.cur, maxcount); - } else { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", - stat.cur, stat.cnt); - } + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + stat.cnt, stat.cur); } - - size_t len = strlen(t); - if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) { - memmove(t + 2, t, len); - t[0] = 'W'; - t[1] = ' '; - len += 2; + } else { + if (stat.incomplete == 1) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + } else if (stat.cnt > maxcount && stat.cur > maxcount) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + maxcount, maxcount); + } else if (stat.cnt > maxcount) { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]", + stat.cur, maxcount); + } else { + vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + stat.cur, stat.cnt); } + } - memmove(msgbuf + strlen(msgbuf) - len, t, len); - if (dirc == '?' && stat.cur == maxcount + 1) { - stat.cur = -1; - } + size_t len = strlen(t); + if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) { + memmove(t + 2, t, len); + t[0] = 'W'; + t[1] = ' '; + len += 2; + } + + size_t msgbuf_len = strlen(msgbuf); + if (len > msgbuf_len) { + len = msgbuf_len; + } + memmove(msgbuf + msgbuf_len - len, t, len); - // keep the message even after redraw, but don't put in history - msg_hist_off = true; - msg_ext_set_kind("search_count"); - give_warning(msgbuf, false); - msg_hist_off = false; + if (dirc == '?' && stat.cur == maxcount + 1) { + stat.cur = -1; } + + // keep the message even after redraw, but don't put in history + msg_hist_off = true; + msg_ext_set_kind("search_count"); + give_warning(msgbuf, false); + msg_hist_off = false; } // Add the search count information to "stat". @@ -2942,7 +2963,7 @@ typedef struct { #define FUZZY_MATCH_RECURSION_LIMIT 10 /// Compute a score for a fuzzy matched string. The matching character locations -/// are in 'matches'. +/// are in "matches". static int fuzzy_match_compute_score(const char *const str, const int strSz, const uint32_t *const matches, const int numMatches) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE @@ -3007,7 +3028,7 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz, return score; } -/// Perform a recursive search for fuzzy matching 'fuzpat' in 'str'. +/// Perform a recursive search for fuzzy matching "fuzpat" in "str". /// @return the number of matching characters. static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t strIdx, int *const outScore, const char *const strBegin, const int strLen, @@ -3107,23 +3128,23 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s /// Uses char_u for match indices. Therefore patterns are limited to /// MAX_FUZZY_MATCHES characters. /// -/// @return true if 'pat_arg' matches 'str'. Also returns the match score in -/// 'outScore' and the matching character positions in 'matches'. -bool fuzzy_match(char_u *const str, const char_u *const pat_arg, const bool matchseq, +/// @return true if "pat_arg" matches "str". Also returns the match score in +/// "outScore" and the matching character positions in "matches". +bool fuzzy_match(char *const str, const char *const pat_arg, const bool matchseq, int *const outScore, uint32_t *const matches, const int maxMatches) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_ALL { - const int len = mb_charlen((char *)str); + const int len = mb_charlen(str); bool complete = false; int numMatches = 0; *outScore = 0; - char *const save_pat = xstrdup((char *)pat_arg); + char *const save_pat = xstrdup(pat_arg); char *pat = save_pat; char *p = pat; - // Try matching each word in 'pat_arg' in 'str' + // Try matching each word in "pat_arg" in "str" while (true) { if (matchseq) { complete = true; @@ -3146,7 +3167,7 @@ bool fuzzy_match(char_u *const str, const char_u *const pat_arg, const bool matc int score = 0; int recursionCount = 0; const int matchCount - = fuzzy_match_recursive(pat, (char *)str, 0, &score, (char *)str, len, NULL, + = fuzzy_match_recursive(pat, str, 0, &score, str, len, NULL, matches + numMatches, maxMatches - numMatches, 0, &recursionCount); if (matchCount == 0) { @@ -3183,14 +3204,14 @@ static int fuzzy_match_item_compare(const void *const s1, const void *const s2) return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1; } -/// Fuzzy search the string 'str' in a list of 'items' and return the matching -/// strings in 'fmatchlist'. -/// If 'matchseq' is true, then for multi-word search strings, match all the +/// Fuzzy search the string "str" in a list of "items" and return the matching +/// strings in "fmatchlist". +/// If "matchseq" is true, then for multi-word search strings, match all the /// words in sequence. -/// If 'items' is a list of strings, then search for 'str' in the list. -/// If 'items' is a list of dicts, then either use 'key' to lookup the string -/// for each item or use 'item_cb' Funcref function to get the string. -/// If 'retmatchpos' is true, then return a list of positions where 'str' +/// If "items" is a list of strings, then search for "str" in the list. +/// If "items" is a list of dicts, then either use "key" to lookup the string +/// for each item or use "item_cb" Funcref function to get the string. +/// If "retmatchpos" is true, then return a list of positions where "str" /// matches for each item. static void fuzzy_match_in_list(list_T *const l, char *const str, const bool matchseq, const char *const key, Callback *const item_cb, @@ -3245,14 +3266,14 @@ static void fuzzy_match_in_list(list_T *const l, char *const str, const bool mat } int score; - if (itemstr != NULL && fuzzy_match((char_u *)itemstr, (char_u *)str, matchseq, &score, matches, + if (itemstr != NULL && fuzzy_match(itemstr, str, matchseq, &score, matches, MAX_FUZZY_MATCHES)) { items[match_count].idx = (int)match_count; items[match_count].item = li; items[match_count].score = score; // Copy the list of matching positions in itemstr to a list, if - // 'retmatchpos' is set. + // "retmatchpos" is set. if (retmatchpos) { items[match_count].lmatchpos = tv_list_alloc(kListLenMayKnow); int j = 0; @@ -3326,8 +3347,8 @@ static void fuzzy_match_in_list(list_T *const l, char *const str, const bool mat xfree(items); } -/// Do fuzzy matching. Returns the list of matched strings in 'rettv'. -/// If 'retmatchpos' is true, also returns the matching character positions. +/// Do fuzzy matching. Returns the list of matched strings in "rettv". +/// If "retmatchpos" is true, also returns the matching character positions. static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, const bool retmatchpos) FUNC_ATTR_NONNULL_ALL @@ -3411,6 +3432,109 @@ void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) do_fuzzymatch(argvars, rettv, true); } +/// Same as fuzzy_match_item_compare() except for use with a string match +static int fuzzy_match_str_compare(const void *const s1, const void *const s2) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +{ + const int v1 = ((fuzmatch_str_T *)s1)->score; + const int v2 = ((fuzmatch_str_T *)s2)->score; + const int idx1 = ((fuzmatch_str_T *)s1)->idx; + const int idx2 = ((fuzmatch_str_T *)s2)->idx; + + return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1; +} + +/// Sort fuzzy matches by score +static void fuzzy_match_str_sort(fuzmatch_str_T *const fm, const int sz) + FUNC_ATTR_NONNULL_ALL +{ + // Sort the list by the descending order of the match score + qsort(fm, (size_t)sz, sizeof(fuzmatch_str_T), fuzzy_match_str_compare); +} + +/// Same as fuzzy_match_item_compare() except for use with a function name +/// string match. <SNR> functions should be sorted to the end. +static int fuzzy_match_func_compare(const void *const s1, const void *const s2) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +{ + const int v1 = ((fuzmatch_str_T *)s1)->score; + const int v2 = ((fuzmatch_str_T *)s2)->score; + const int idx1 = ((fuzmatch_str_T *)s1)->idx; + const int idx2 = ((fuzmatch_str_T *)s2)->idx; + const char *const str1 = ((fuzmatch_str_T *)s1)->str; + const char *const str2 = ((fuzmatch_str_T *)s2)->str; + + if (*str1 != '<' && *str2 == '<') { + return -1; + } + if (*str1 == '<' && *str2 != '<') { + return 1; + } + return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1; +} + +/// Sort fuzzy matches of function names by score. +/// <SNR> functions should be sorted to the end. +static void fuzzy_match_func_sort(fuzmatch_str_T *const fm, const int sz) + FUNC_ATTR_NONNULL_ALL +{ + // Sort the list by the descending order of the match score + qsort(fm, (size_t)sz, sizeof(fuzmatch_str_T), fuzzy_match_func_compare); +} + +/// Fuzzy match "pat" in "str". +/// @returns 0 if there is no match. Otherwise, returns the match score. +int fuzzy_match_str(char *const str, const char *const pat) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (str == NULL || pat == NULL) { + return 0; + } + + int score = 0; + uint32_t matchpos[MAX_FUZZY_MATCHES]; + fuzzy_match(str, pat, true, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0])); + + return score; +} + +/// Copy a list of fuzzy matches into a string list after sorting the matches by +/// the fuzzy score. Frees the memory allocated for "fuzmatch". +void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches, + const int count, const bool funcsort) + FUNC_ATTR_NONNULL_ARG(2) +{ + if (count <= 0) { + return; + } + + *matches = xmalloc((size_t)count * sizeof(char *)); + + // Sort the list by the descending order of the match score + if (funcsort) { + fuzzy_match_func_sort(fuzmatch, count); + } else { + fuzzy_match_str_sort(fuzmatch, count); + } + + for (int i = 0; i < count; i++) { + (*matches)[i] = fuzmatch[i].str; + } + xfree(fuzmatch); +} + +/// Free a list of fuzzy string matches. +void fuzmatch_str_free(fuzmatch_str_T *const fuzmatch, int count) +{ + if (count <= 0 || fuzmatch == NULL) { + return; + } + while (count--) { + xfree(fuzmatch[count].str); + } + xfree(fuzmatch); +} + /// Get line "lnum" and copy it into "buf[LSIZE]". /// The copy is made because the regexp may make the line invalid when using a /// mark. @@ -3534,9 +3658,9 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool 1L, p_fname); } else { // Use text after match with 'include'. - new_fname = (char *)file_name_in_line((char_u *)incl_regmatch.endp[0], 0, - FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, (char_u *)p_fname, - NULL); + new_fname = file_name_in_line(incl_regmatch.endp[0], 0, + FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, + NULL); } already_searched = false; if (new_fname != NULL) { diff --git a/src/nvim/search.h b/src/nvim/search.h index 092098d5fd..2f140ba840 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -99,6 +99,14 @@ typedef struct searchstat { int last_maxcount; // the max count of the last search } searchstat_T; +/// Fuzzy matched string list item. Used for fuzzy match completion. Items are +/// usually sorted by "score". The "idx" member is used for stable-sort. +typedef struct { + int idx; + char *str; + int score; +} fuzmatch_str_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "search.h.generated.h" #endif diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c index 72ef74b46c..db647f3ecb 100644 --- a/src/nvim/sha256.c +++ b/src/nvim/sha256.c @@ -32,10 +32,10 @@ } #define PUT_UINT32(n, b, i) { \ - (b)[(i)] = (char_u)((n) >> 24); \ - (b)[(i) + 1] = (char_u)((n) >> 16); \ - (b)[(i) + 2] = (char_u)((n) >> 8); \ - (b)[(i) + 3] = (char_u)((n)); \ + (b)[(i)] = (uint8_t)((n) >> 24); \ + (b)[(i) + 1] = (uint8_t)((n) >> 16); \ + (b)[(i) + 2] = (uint8_t)((n) >> 8); \ + (b)[(i) + 3] = (uint8_t)((n)); \ } void sha256_start(context_sha256_T *ctx) @@ -53,7 +53,7 @@ void sha256_start(context_sha256_T *ctx) ctx->state[7] = 0x5BE0CD19; } -static void sha256_process(context_sha256_T *ctx, const char_u data[SHA256_BUFFER_SIZE]) +static void sha256_process(context_sha256_T *ctx, const uint8_t data[SHA256_BUFFER_SIZE]) { uint32_t temp1, temp2, W[SHA256_BUFFER_SIZE]; uint32_t A, B, C, D, E, F, G, H; @@ -180,7 +180,7 @@ static void sha256_process(context_sha256_T *ctx, const char_u data[SHA256_BUFFE ctx->state[7] += H; } -void sha256_update(context_sha256_T *ctx, const char_u *input, size_t length) +void sha256_update(context_sha256_T *ctx, const uint8_t *input, size_t length) { if (length == 0) { return; @@ -198,7 +198,7 @@ void sha256_update(context_sha256_T *ctx, const char_u *input, size_t length) size_t fill = SHA256_BUFFER_SIZE - left; if (left && (length >= fill)) { - memcpy((void *)(ctx->buffer + left), (void *)input, fill); + memcpy(ctx->buffer + left, input, fill); sha256_process(ctx, ctx->buffer); length -= fill; input += fill; @@ -212,22 +212,22 @@ void sha256_update(context_sha256_T *ctx, const char_u *input, size_t length) } if (length) { - memcpy((void *)(ctx->buffer + left), (void *)input, length); + memcpy(ctx->buffer + left, input, length); } } -static char_u sha256_padding[SHA256_BUFFER_SIZE] = { +static uint8_t sha256_padding[SHA256_BUFFER_SIZE] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void sha256_finish(context_sha256_T *ctx, char_u digest[SHA256_SUM_SIZE]) +void sha256_finish(context_sha256_T *ctx, uint8_t digest[SHA256_SUM_SIZE]) { uint32_t last, padn; uint32_t high, low; - char_u msglen[8]; + uint8_t msglen[8]; high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); low = (ctx->total[0] << 3); @@ -265,7 +265,7 @@ void sha256_finish(context_sha256_T *ctx, char_u digest[SHA256_SUM_SIZE]) const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uint8_t *restrict salt, size_t salt_len) { - char_u sha256sum[SHA256_SUM_SIZE]; + uint8_t sha256sum[SHA256_SUM_SIZE]; static char hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL context_sha256_T ctx; @@ -309,8 +309,8 @@ bool sha256_self_test(void) { char output[SHA256_BUFFER_SIZE + 1]; // buf size + NULL context_sha256_T ctx; - char_u buf[1000]; - char_u sha256sum[SHA256_SUM_SIZE]; + uint8_t buf[1000]; + uint8_t sha256sum[SHA256_SUM_SIZE]; const char *hexit; static bool sha256_self_tested = false; diff --git a/src/nvim/sha256.h b/src/nvim/sha256.h index a1d8f670d5..eeb4031509 100644 --- a/src/nvim/sha256.h +++ b/src/nvim/sha256.h @@ -12,7 +12,7 @@ typedef struct { uint32_t total[2]; uint32_t state[8]; - char_u buffer[SHA256_BUFFER_SIZE]; + uint8_t buffer[SHA256_BUFFER_SIZE]; } context_sha256_T; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 754139a147..90a01aaf97 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -53,7 +53,6 @@ #include "nvim/search.h" #include "nvim/shada.h" #include "nvim/strings.h" -#include "nvim/types.h" #include "nvim/version.h" #include "nvim/vim.h" @@ -1483,7 +1482,7 @@ static char *shada_filename(const char *file) if (p_shadafile != NULL && *p_shadafile != NUL) { file = p_shadafile; } else { - if ((file = (char *)find_shada_parameter('n')) == NULL || *file == NUL) { + if ((file = find_shada_parameter('n')) == NULL || *file == NUL) { file = shada_get_default_file(); } // XXX It used to be one level lower, so that whatever is in @@ -2668,8 +2667,6 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef } // Initialize jump list - setpcmark(); - cleanup_jumplist(curwin, false); wms->jumps_size = shada_init_jumps(wms->jumps, &removable_bufs); const bool search_highlighted = !(no_hlsearch @@ -4039,13 +4036,11 @@ static bool shada_removable(const char *name) static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs) { - if (!curwin->w_jumplistlen) { - return 0; - } - + // Initialize jump list size_t jumps_size = 0; const void *jump_iter = NULL; - + setpcmark(); + cleanup_jumplist(curwin, false); do { xfmark_T fm; jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm); @@ -4118,7 +4113,6 @@ void shada_encode_jumps(msgpack_sbuffer *const sbuf) khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset); find_removable_bufs(&removable_bufs); PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; - cleanup_jumplist(curwin, true); size_t jumps_size = shada_init_jumps(jumps, &removable_bufs); msgpack_packer packer; msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); diff --git a/src/nvim/sign.c b/src/nvim/sign.c index e211b0069e..00e282b76e 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -99,16 +99,16 @@ static signgroup_T *sign_group_ref(const char *groupname) hashitem_T *hi; signgroup_T *group; - hash = hash_hash((char_u *)groupname); + hash = hash_hash(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(offsetof(signgroup_T, sg_name) + strlen(groupname) + 1); STRCPY(group->sg_name, groupname); group->sg_refcount = 1; group->sg_next_sign_id = 1; - hash_add_item(&sg_table, hi, (char_u *)group->sg_name, hash); + hash_add_item(&sg_table, hi, group->sg_name, hash); } else { // existing group group = HI2SG(hi); @@ -122,17 +122,17 @@ static signgroup_T *sign_group_ref(const char *groupname) /// removed, then remove the group. static void sign_group_unref(char *groupname) { - signgroup_T *group; - hashitem_T *hi = hash_find(&sg_table, groupname); - if (!HASHITEM_EMPTY(hi)) { - group = HI2SG(hi); - group->sg_refcount--; - if (group->sg_refcount == 0) { - // All the signs in this group are removed - hash_remove(&sg_table, hi); - xfree(group); - } + if (HASHITEM_EMPTY(hi)) { + return; + } + + signgroup_T *group = HI2SG(hi); + group->sg_refcount--; + if (group->sg_refcount == 0) { + // All the signs in this group are removed + hash_remove(&sg_table, hi); + xfree(group); } } diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index 16e783aab7..7aa06ce48a 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 sg_name[1]; // sign group name + int sg_next_sign_id; ///< next sign id for this group + uint16_t sg_refcount; ///< number of signs in this group + char sg_name[1]; ///< sign group name, actually longer } signgroup_T; // Macros to get the sign group structure from the group name diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 48aed9c6de..2204cda169 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -123,7 +123,7 @@ enum { slang_T *first_lang = NULL; // file used for "zG" and "zW" -char_u *int_wordlist = NULL; +char *int_wordlist = NULL; // Structure to store info for word matching. typedef struct matchinf_S { @@ -131,9 +131,9 @@ typedef struct matchinf_S { // pointers to original text to be checked char *mi_word; // start of word being checked - char_u *mi_end; // end of matching word so far - char_u *mi_fend; // next char to be added to mi_fword - char_u *mi_cend; // char after what was used for + char *mi_end; // end of matching word so far + char *mi_fend; // next char to be added to mi_fword + char *mi_cend; // char after what was used for // mi_capflags // case-folded text @@ -161,12 +161,12 @@ typedef struct matchinf_S { // for NOBREAK int mi_result2; // "mi_result" without following word - char_u *mi_end2; // "mi_end" without following word + char *mi_end2; // "mi_end" without following word } matchinf_T; // Structure used for the cookie argument of do_in_runtimepath(). typedef struct spelload_S { - char_u sl_lang[MAXWLEN + 1]; // language name + char sl_lang[MAXWLEN + 1]; // language name slang_T *sl_slang; // resulting slang_T struct int sl_nobreak; // NOBREAK language found } spelload_T; @@ -214,7 +214,7 @@ char *repl_to = NULL; /// /// @return the length of the word in bytes, also when it's OK, so that the /// caller can skip over the word. -size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docount) +size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount) { matchinf_T mi; // Most things are put in "mi" so that it can // be passed to functions quickly. @@ -226,7 +226,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // A word never starts at a space or a control character. Return quickly // then, skipping over the character. - if (*ptr <= ' ') { + if ((uint8_t)(*ptr) <= ' ') { return 1; } @@ -242,23 +242,23 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // julifeest". if (*ptr >= '0' && *ptr <= '9') { if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) { - mi.mi_end = (char_u *)skipbin((char *)ptr + 2); + mi.mi_end = (char *)skipbin(ptr + 2); } else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { - mi.mi_end = (char_u *)skiphex((char *)ptr + 2); + mi.mi_end = skiphex(ptr + 2); } else { - mi.mi_end = (char_u *)skipdigits((char *)ptr); + mi.mi_end = skipdigits(ptr); } nrlen = (size_t)(mi.mi_end - ptr); } // Find the normal end of the word (until the next non-word character). - mi.mi_word = (char *)ptr; + mi.mi_word = ptr; mi.mi_fend = ptr; if (spell_iswordp(mi.mi_fend, wp)) { bool this_upper = false; // init for gcc if (use_camel_case) { - int c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char(mi.mi_fend); this_upper = SPELL_ISUPPER(c); } @@ -266,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; - int c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char(mi.mi_fend); this_upper = SPELL_ISUPPER(c); camel_case = !prev_upper && this_upper; } @@ -275,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. - int c = utf_ptr2char((char *)ptr); + int c = utf_ptr2char(ptr); if (!SPELL_ISUPPER(c)) { wrongcaplen = (size_t)(mi.mi_fend - ptr); } @@ -300,7 +300,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou MB_PTR_ADV(mi.mi_fend); } - (void)spell_casefold(wp, ptr, (int)(mi.mi_fend - ptr), (char_u *)mi.mi_fword, + (void)spell_casefold(wp, ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1); mi.mi_fwordlen = (int)strlen(mi.mi_fword); @@ -344,7 +344,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // Count the word in the first language where it's found to be OK. if (count_word && mi.mi_result == SP_OK) { - count_common_word(mi.mi_lp->lp_slang, (char *)ptr, + count_common_word(mi.mi_lp->lp_slang, ptr, (int)(mi.mi_end - ptr), 1); count_word = false; } @@ -366,36 +366,36 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // Check for end of sentence. regmatch.regprog = wp->w_s->b_cap_prog; regmatch.rm_ic = false; - int r = vim_regexec(®match, (char *)ptr, 0); + int r = vim_regexec(®match, ptr, 0); wp->w_s->b_cap_prog = regmatch.regprog; if (r) { - *capcol = (int)(regmatch.endp[0] - (char *)ptr); + *capcol = (int)(regmatch.endp[0] - ptr); } } - return (size_t)(utfc_ptr2len((char *)ptr)); + return (size_t)(utfc_ptr2len(ptr)); } else if (mi.mi_end == ptr) { // Always include at least one character. Required for when there // is a mixup in "midword". MB_PTR_ADV(mi.mi_end); } else if (mi.mi_result == SP_BAD && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) { - char_u *p, *fp; + char *p, *fp; int save_result = mi.mi_result; // First language in 'spelllang' is NOBREAK. Find first position // at which any word would be valid. mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, 0); if (mi.mi_lp->lp_slang->sl_fidxs != NULL) { - p = (char_u *)mi.mi_word; - fp = (char_u *)mi.mi_fword; + p = mi.mi_word; + fp = mi.mi_fword; for (;;) { MB_PTR_ADV(p); MB_PTR_ADV(fp); if (p >= mi.mi_end) { break; } - mi.mi_compoff = (int)(fp - (char_u *)mi.mi_fword); + mi.mi_compoff = (int)(fp - mi.mi_fword); find_word(&mi, FIND_COMPOUND); if (mi.mi_result != SP_BAD) { mi.mi_end = p; @@ -444,7 +444,7 @@ static void find_word(matchinf_T *mip, int mode) // Check for word with matching case in keep-case tree. ptr = mip->mi_word; flen = 9999; // no case folding, always enough bytes - byts = slang->sl_kbyts; + byts = (char_u *)slang->sl_kbyts; idxs = slang->sl_kidxs; if (mode == FIND_KEEPCOMPOUND) { @@ -455,7 +455,7 @@ static void find_word(matchinf_T *mip, int mode) // Check for case-folded in case-folded tree. ptr = mip->mi_fword; flen = mip->mi_fwordlen; // available case-folded bytes - byts = slang->sl_fbyts; + byts = (char_u *)slang->sl_fbyts; idxs = slang->sl_fidxs; if (mode == FIND_PREFIX) { @@ -575,7 +575,7 @@ static void find_word(matchinf_T *mip, int mode) if (utf_head_off(ptr, ptr + wlen) > 0) { continue; // not at first byte of character } - if (spell_iswordp((char_u *)ptr + wlen, mip->mi_win)) { + if (spell_iswordp(ptr + wlen, mip->mi_win)) { if (slang->sl_compprog == NULL && !slang->sl_nobreak) { continue; // next char is a word character } @@ -612,11 +612,11 @@ static void find_word(matchinf_T *mip, int mode) // For keep-case tree the case is always right. For prefixes we // don't bother to check. if (mode == FIND_FOLDWORD) { - if (mip->mi_cend != (char_u *)mip->mi_word + wlen) { + if (mip->mi_cend != mip->mi_word + wlen) { // mi_capflags was set for a different word length, need // to do it again. - mip->mi_cend = (char_u *)mip->mi_word + wlen; - mip->mi_capflags = captype((char_u *)mip->mi_word, mip->mi_cend); + mip->mi_cend = mip->mi_word + wlen; + mip->mi_capflags = captype(mip->mi_word, mip->mi_cend); } if (mip->mi_capflags == WF_KEEPCAP @@ -629,7 +629,7 @@ static void find_word(matchinf_T *mip, int mode) // mip->mi_prefarridx that find_prefix() filled. c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, (int)flags, - (char_u *)mip->mi_word + mip->mi_cprefixlen, slang, + mip->mi_word + mip->mi_cprefixlen, slang, false); if (c == 0) { continue; @@ -664,7 +664,7 @@ static void find_word(matchinf_T *mip, int mode) // For multi-byte chars check character length against // COMPOUNDMIN. if (slang->sl_compminlen > 0 - && mb_charlen_len((char_u *)mip->mi_word + mip->mi_compoff, + && mb_charlen_len(mip->mi_word + mip->mi_compoff, wlen - mip->mi_compoff) < slang->sl_compminlen) { continue; } @@ -687,7 +687,8 @@ static void find_word(matchinf_T *mip, int mode) } // Quickly check if compounding is possible with this flag. - if (!byte_in_str(mip->mi_complen == 0 ? slang->sl_compstartflags : slang->sl_compallflags, + if (!byte_in_str(mip->mi_complen == + 0 ? slang->sl_compstartflags : slang->sl_compallflags, (int)((unsigned)flags >> 24))) { continue; } @@ -712,7 +713,7 @@ static void find_word(matchinf_T *mip, int mode) } else { p = mip->mi_word + mip->mi_compoff; } - capflags = captype((char_u *)p, (char_u *)mip->mi_word + wlen); + capflags = captype(p, mip->mi_word + wlen); if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP && (flags & WF_FIXCAP) != 0)) { continue; @@ -724,7 +725,7 @@ static void find_word(matchinf_T *mip, int mode) // accept a no-caps word, even when the dictionary // word specifies ONECAP. MB_PTR_BACK(mip->mi_word, p); - if (spell_iswordp_nmw((char_u *)p, mip->mi_win) + if (spell_iswordp_nmw(p, mip->mi_win) ? capflags == WF_ONECAP : (flags & WF_ONECAP) != 0 && capflags != WF_ONECAP) { @@ -744,12 +745,12 @@ static void find_word(matchinf_T *mip, int mode) if (slang->sl_compsylmax < MAXWLEN) { // "fword" is only needed for checking syllables. if (ptr == mip->mi_word) { - (void)spell_casefold(mip->mi_win, (char_u *)ptr, wlen, (char_u *)fword, MAXWLEN); + (void)spell_casefold(mip->mi_win, ptr, wlen, fword, MAXWLEN); } else { xstrlcpy(fword, ptr, (size_t)endlen[endidxcnt] + 1); } } - if (!can_compound(slang, (char *)fword, mip->mi_compflags)) { + if (!can_compound(slang, fword, mip->mi_compflags)) { continue; } } else if (slang->sl_comprules != NULL @@ -767,7 +768,7 @@ static void find_word(matchinf_T *mip, int mode) if (!word_ends) { int save_result = mip->mi_result; - char_u *save_end = mip->mi_end; + char *save_end = mip->mi_end; langp_T *save_lp = mip->mi_lp; // Check that a valid word follows. If there is one and we @@ -878,16 +879,16 @@ static void find_word(matchinf_T *mip, int mode) if (nobreak_result == SP_BAD) { if (mip->mi_result2 > res) { mip->mi_result2 = res; - mip->mi_end2 = (char_u *)mip->mi_word + wlen; + mip->mi_end2 = mip->mi_word + wlen; } else if (mip->mi_result2 == res - && mip->mi_end2 < (char_u *)mip->mi_word + wlen) { - mip->mi_end2 = (char_u *)mip->mi_word + wlen; + && mip->mi_end2 < mip->mi_word + wlen) { + mip->mi_end2 = mip->mi_word + wlen; } } else if (mip->mi_result > res) { mip->mi_result = res; - mip->mi_end = (char_u *)mip->mi_word + wlen; - } else if (mip->mi_result == res && mip->mi_end < (char_u *)mip->mi_word + wlen) { - mip->mi_end = (char_u *)mip->mi_word + wlen; + mip->mi_end = mip->mi_word + wlen; + } else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen) { + mip->mi_end = mip->mi_word + wlen; } if (mip->mi_result == SP_OK) { @@ -930,15 +931,15 @@ bool match_checkcompoundpattern(char *ptr, int wlen, garray_T *gap) bool can_compound(slang_T *slang, const char *word, const uint8_t *flags) FUNC_ATTR_NONNULL_ALL { - char_u uflags[MAXWLEN * 2] = { 0 }; + char uflags[MAXWLEN * 2] = { 0 }; if (slang->sl_compprog == NULL) { return false; } // Need to convert the single byte flags to utf8 characters. - char_u *p = uflags; + char *p = uflags; for (int i = 0; flags[i] != NUL; i++) { - p += utf_char2bytes(flags[i], (char *)p); + p += utf_char2bytes(flags[i], p); } *p = NUL; p = uflags; @@ -950,7 +951,7 @@ bool can_compound(slang_T *slang, const char *word, const uint8_t *flags) // are too many syllables AND the number of compound words is above // COMPOUNDWORDMAX then compounding is not allowed. if (slang->sl_compsylmax < MAXWLEN - && count_syllables(slang, (char_u *)word) > slang->sl_compsylmax) { + && count_syllables(slang, word) > slang->sl_compsylmax) { return (int)strlen((char *)flags) < slang->sl_compmax; } return true; @@ -963,7 +964,7 @@ bool can_compound(slang_T *slang, const char *word, const uint8_t *flags) bool match_compoundrule(slang_T *slang, const char_u *compflags) { // loop over all the COMPOUNDRULE entries - for (char_u *p = slang->sl_comprules; *p != NUL; p++) { + for (char_u *p = (char_u *)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 (int i = 0;; i++) { @@ -1013,7 +1014,7 @@ bool match_compoundrule(slang_T *slang, const char_u *compflags) /// @param totprefcnt nr of prefix IDs /// @param arridx idx in sl_pidxs[] /// @param cond_req only use prefixes with a condition -int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, +int valid_word_prefix(int totprefcnt, int arridx, int flags, char *word, slang_T *slang, bool cond_req) { int prefid = (int)((unsigned)flags >> 24); @@ -1061,7 +1062,7 @@ static void find_prefix(matchinf_T *mip, int mode) int wlen = 0; slang_T *slang = mip->mi_lp->lp_slang; - char_u *byts = slang->sl_pbyts; + char_u *byts = (char_u *)slang->sl_pbyts; if (byts == NULL) { return; // array is empty } @@ -1110,8 +1111,8 @@ static void find_prefix(matchinf_T *mip, int mode) } // Case-folded length may differ from original length. - mip->mi_cprefixlen = nofold_len((char_u *)mip->mi_fword, mip->mi_prefixlen, - (char_u *)mip->mi_word); + mip->mi_cprefixlen = nofold_len(mip->mi_fword, mip->mi_prefixlen, + mip->mi_word); find_word(mip, FIND_PREFIX); if (len == 0) { @@ -1157,7 +1158,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) { - char_u *p = mip->mi_fend; + char *p = mip->mi_fend; do { MB_PTR_ADV(mip->mi_fend); } while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win)); @@ -1168,7 +1169,7 @@ static int fold_more(matchinf_T *mip) } (void)spell_casefold(mip->mi_win, p, (int)(mip->mi_fend - p), - (char_u *)mip->mi_fword + mip->mi_fwordlen, + mip->mi_fword + mip->mi_fwordlen, MAXWLEN - mip->mi_fwordlen); int flen = (int)strlen(mip->mi_fword + mip->mi_fwordlen); mip->mi_fwordlen += flen; @@ -1319,7 +1320,7 @@ 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), - (char_u *)ml_get_buf(wp->w_buffer, lnum + 1, false), + ml_get_buf(wp->w_buffer, lnum + 1, false), MAXWLEN); } char *p = buf + skip; @@ -1336,7 +1337,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // start of word attr = HLF_COUNT; - len = spell_check(wp, (char_u *)p, &attr, &capcol, false); + len = spell_check(wp, p, &attr, &capcol, false); if (attr != HLF_COUNT) { // We found a bad word. Check the attribute. @@ -1480,27 +1481,29 @@ theend: // "buf", blanking-out special characters. Copy less than "maxlen" bytes. // Keep the blanks at the start of the next line, this is used in win_line() // to skip those bytes if the word was OK. -void spell_cat_line(char *buf, char_u *line, int maxlen) +void spell_cat_line(char *buf, char *line, int maxlen) { - char_u *p = (char_u *)skipwhite((char *)line); - while (vim_strchr("*#/\"\t", *p) != NULL) { + char_u *p = (char_u *)skipwhite(line); + while (vim_strchr("*#/\"\t", (uint8_t)(*p)) != NULL) { p = (char_u *)skipwhite((char *)p + 1); } - if (*p != NUL) { - // Only worth concatenating if there is something else than spaces to - // concatenate. - int n = (int)(p - line) + 1; - if (n < maxlen - 1) { - memset(buf, ' ', (size_t)n); - xstrlcpy(buf + n, (char *)p, (size_t)(maxlen - n)); - } + if (*p == NUL) { + return; + } + + // Only worth concatenating if there is something else than spaces to + // concatenate. + int n = (int)(p - (char_u *)line) + 1; + if (n < maxlen - 1) { + memset(buf, ' ', (size_t)n); + xstrlcpy(buf + n, (char *)p, (size_t)(maxlen - n)); } } // Load word list(s) for "lang" from Vim spell file(s). // "lang" must be the language without the region: e.g., "en". -static void spell_load_lang(char_u *lang) +static void spell_load_lang(char *lang) { char fname_enc[85]; int r; @@ -1520,18 +1523,18 @@ static void spell_load_lang(char_u *lang) // autocommand may load it then. 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, + vim_snprintf(fname_enc, sizeof(fname_enc) - 5, "spell/%s.%s.spl", lang, spell_enc()); - r = do_in_runtimepath((char *)fname_enc, 0, spell_load_cb, &sl); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL) { // Try loading the ASCII version. - vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, + vim_snprintf(fname_enc, sizeof(fname_enc) - 5, "spell/%s.ascii.spl", lang); - r = do_in_runtimepath((char *)fname_enc, 0, spell_load_cb, &sl); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL && round == 1 - && apply_autocmds(EVENT_SPELLFILEMISSING, (char *)lang, + && apply_autocmds(EVENT_SPELLFILEMISSING, lang, curbuf->b_fname, false, curbuf)) { continue; } @@ -1556,7 +1559,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"); - do_in_runtimepath((char *)fname_enc, DIP_ALL, spell_load_cb, &sl); + do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl); } curbuf->b_locked--; @@ -1564,19 +1567,19 @@ static void spell_load_lang(char_u *lang) // Return the encoding used for spell checking: Use 'encoding', except that we // use "latin1" for "latin9". And limit to 60 characters (just in case). -char_u *spell_enc(void) +char *spell_enc(void) { if (strlen(p_enc) < 60 && strcmp(p_enc, "iso-8859-15") != 0) { - return (char_u *)p_enc; + return p_enc; } - return (char_u *)"latin1"; + return "latin1"; } // Get the name of the .spl file for the internal wordlist into // "fname[MAXPATHL]". -static void int_wordlist_spl(char_u *fname) +static void int_wordlist_spl(char *fname) { - vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL, + vim_snprintf(fname, MAXPATHL, SPL_FNAME_TMPL, int_wordlist, spell_enc()); } @@ -1700,18 +1703,20 @@ 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 = 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. - if (slp->sl_nobreak && slang->sl_add) { - slang->sl_nobreak = true; - } else if (slang->sl_nobreak) { - slp->sl_nobreak = true; - } + slang_T *slang = spell_load_file(fname, slp->sl_lang, NULL, false); + if (slang == NULL) { + return; + } - slp->sl_slang = slang; + // When a previously loaded file has NOBREAK also use it for the + // ".add" files. + if (slp->sl_nobreak && slang->sl_add) { + slang->sl_nobreak = true; + } else if (slang->sl_nobreak) { + slp->sl_nobreak = true; } + + slp->sl_slang = slang; } /// Add a word to the hashtable of common words. @@ -1736,14 +1741,14 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) } wordcount_T *wc; - hash_T hash = hash_hash((char_u *)p); + hash_T hash = hash_hash(p); const size_t p_len = strlen(p); 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); + wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1); memcpy(wc->wc_word, p, p_len + 1); wc->wc_count = count; - hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash); + hash_add_item(&lp->sl_wordcount, hi, (char *)wc->wc_word, hash); } else { wc = HI2WC(hi); wc->wc_count = (uint16_t)(wc->wc_count + count); @@ -1755,9 +1760,9 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) // Returns true if byte "n" appears in "str". // Like strchr() but independent of locale. -bool byte_in_str(char_u *str, int n) +bool byte_in_str(uint8_t *str, int n) { - for (char_u *p = str; *p != NUL; p++) { + for (uint8_t *p = str; *p != NUL; p++) { if (*p == n) { return true; } @@ -1798,7 +1803,7 @@ int init_syl_tab(slang_T *slang) // Count the number of syllables in "word". // When "word" contains spaces the syllables after the last space are counted. // Returns zero if syllables are not defines. -static int count_syllables(slang_T *slang, const char_u *word) +static int count_syllables(slang_T *slang, const char *word) FUNC_ATTR_NONNULL_ALL { int cnt = 0; @@ -1809,7 +1814,7 @@ static int count_syllables(slang_T *slang, const char_u *word) return 0; } - for (const char *p = (char *)word; *p != NUL; p += len) { + for (const char *p = word; *p != NUL; p += len) { // When running into a space reset counter. if (*p == ' ') { len = 1; @@ -1893,11 +1898,11 @@ char *did_set_spelllang(win_T *wp) // Loop over comma separated language names. for (splp = spl_copy; *splp != NUL;) { // Get one language name. - copy_option_part(&splp, (char *)lang, MAXWLEN, ","); + copy_option_part(&splp, lang, MAXWLEN, ","); region = NULL; len = (int)strlen(lang); - if (!valid_spelllang((char *)lang)) { + if (!valid_spelllang(lang)) { continue; } @@ -1913,7 +1918,7 @@ char *did_set_spelllang(win_T *wp) filename = true; // Locate a region and remove it from the file name. - p = vim_strchr(path_tail((char *)lang), '_'); + p = vim_strchr(path_tail(lang), '_'); if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2]) && !ASCII_ISALPHA(p[3])) { xstrlcpy(region_cp, p + 1, 3); @@ -1925,7 +1930,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, slang->sl_fname, false, true) + if (path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -1959,9 +1964,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((char *)lang, (char *)lang, NULL, false); + (void)spell_load_file(lang, lang, NULL, false); } else { - spell_load_lang((char_u *)lang); + spell_load_lang(lang); // SpellFileMissing autocommands may do anything, including // destroying the buffer we are using or closing the window. if (!bufref_valid(&bufref) || !win_valid_any_tab(wp)) { @@ -1974,12 +1979,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, slang->sl_fname, false, true) == kEqualFiles + ? path_full_compare(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, (char_u *)region); + c = find_region(slang->sl_regions, region); if (c == REGION_ALL) { if (slang->sl_add) { if (*slang->sl_regions != NUL) { @@ -2022,17 +2027,17 @@ char *did_set_spelllang(win_T *wp) if (int_wordlist == NULL) { continue; } - int_wordlist_spl((char_u *)spf_name); + int_wordlist_spl(spf_name); } else { // One entry in 'spellfile'. - copy_option_part(&spf, (char *)spf_name, MAXPATHL - 5, ","); + copy_option_part(&spf, 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++) { p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL - && path_full_compare((char *)spf_name, p, false, true) == kEqualFiles) { + && path_full_compare(spf_name, p, false, true) == kEqualFiles) { break; } } @@ -2043,7 +2048,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, slang->sl_fname, false, true) + if (path_full_compare(spf_name, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -2055,13 +2060,13 @@ char *did_set_spelllang(win_T *wp) if (round == 0) { STRCPY(lang, "internal wordlist"); } else { - xstrlcpy(lang, path_tail((char *)spf_name), MAXWLEN + 1); - p = vim_strchr((char *)lang, '.'); + xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1); + p = vim_strchr(lang, '.'); if (p != NULL) { *p = NUL; // truncate at ".encoding.add" } } - slang = spell_load_file((char *)spf_name, (char *)lang, NULL, true); + slang = spell_load_file(spf_name, lang, NULL, true); // If one of the languages has NOBREAK we assume the addition // files also have this. @@ -2073,7 +2078,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, (char_u *)use_region); + c = find_region(slang->sl_regions, use_region); if (c != REGION_ALL) { region_mask = 1 << c; } else if (*slang->sl_regions != NUL) { @@ -2185,7 +2190,7 @@ static void use_midword(slang_T *lp, win_T *wp) // Find the region "region[2]" in "rp" (points to "sl_regions"). // Each region is simply stored as the two characters of its name. // Returns the index if found (first is 0), REGION_ALL if not found. -static int find_region(const char_u *rp, const char_u *region) +static int find_region(const char *rp, const char *region) { int i; @@ -2210,10 +2215,10 @@ static int find_region(const char_u *rp, const char_u *region) /// @param[in] end End of word or NULL for NUL delimited string /// /// @returns Case type of word -int captype(char_u *word, const char_u *end) +int captype(char *word, const char *end) FUNC_ATTR_NONNULL_ARG(1) { - char_u *p; + char *p; // find first letter for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p)) { @@ -2221,7 +2226,7 @@ int captype(char_u *word, const char_u *end) return 0; // only non-word characters, illegal word } } - int c = mb_ptr2char_adv((const char_u **)&p); + int c = mb_ptr2char_adv((const char **)&p); bool allcap; bool firstcap = allcap = SPELL_ISUPPER(c); bool past_second = false; // past second word char @@ -2230,7 +2235,7 @@ int captype(char_u *word, const char_u *end) // But a word with an upper char only at start is a ONECAP. for (; end == NULL ? *p != NUL : p < end; MB_PTR_ADV(p)) { if (spell_iswordp_nmw(p, curwin)) { - c = utf_ptr2char((char *)p); + c = utf_ptr2char(p); if (!SPELL_ISUPPER(c)) { // UUl -> KEEPCAP if (past_second && allcap) { @@ -2257,13 +2262,15 @@ int captype(char_u *word, const char_u *end) // Delete the internal wordlist and its .spl file. void spell_delete_wordlist(void) { - if (int_wordlist != NULL) { - char_u fname[MAXPATHL] = { 0 }; - os_remove((char *)int_wordlist); - int_wordlist_spl(fname); - os_remove((char *)fname); - XFREE_CLEAR(int_wordlist); + if (int_wordlist == NULL) { + return; } + + char fname[MAXPATHL] = { 0 }; + os_remove(int_wordlist); + int_wordlist_spl(fname); + os_remove(fname); + XFREE_CLEAR(int_wordlist); } // Free all languages. @@ -2331,10 +2338,12 @@ buf_T *open_spellbuf(void) // Close the buffer used for spell info. void close_spellbuf(buf_T *buf) { - if (buf != NULL) { - ml_close(buf, true); - xfree(buf); + if (buf == NULL) { + return; } + + ml_close(buf, true); + xfree(buf); } // Init the chartab used for spelling for ASCII. @@ -2393,18 +2402,18 @@ void init_spell_chartab(void) /// Thus this only works properly when past the first character of the word. /// /// @param wp Buffer used. -bool spell_iswordp(const char_u *p, const win_T *wp) +bool spell_iswordp(const char *p, const win_T *wp) FUNC_ATTR_NONNULL_ALL { - const int l = utfc_ptr2len((char *)p); - const char_u *s = p; + const int l = utfc_ptr2len(p); + const char *s = p; if (l == 1) { // be quick for ASCII - if (wp->w_s->b_spell_ismw[*p]) { + if (wp->w_s->b_spell_ismw[(uint8_t)(*p)]) { s = p + 1; // skip a mid-word character } } else { - int c = utf_ptr2char((char *)p); + int c = utf_ptr2char(p); if (c < 256 ? wp->w_s->b_spell_ismw[c] : (wp->w_s->b_spell_ismw_mb != NULL @@ -2413,20 +2422,20 @@ bool spell_iswordp(const char_u *p, const win_T *wp) } } - int c = utf_ptr2char((char *)s); + int c = utf_ptr2char(s); if (c > 255) { - return spell_mb_isword_class(mb_get_class((char *)s), wp); + return spell_mb_isword_class(mb_get_class(s), wp); } return spelltab.st_isw[c]; } // Returns true if "p" points to a word character. // Unlike spell_iswordp() this doesn't check for "midword" characters. -bool spell_iswordp_nmw(const char_u *p, win_T *wp) +bool spell_iswordp_nmw(const char *p, win_T *wp) { - int c = utf_ptr2char((char *)p); + int c = utf_ptr2char(p); if (c > 255) { - return spell_mb_isword_class(mb_get_class((char *)p), wp); + return spell_mb_isword_class(mb_get_class(p), wp); } return spelltab.st_isw[c]; } @@ -2471,7 +2480,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp) // Uses the character definitions from the .spl file. // When using a multi-byte 'encoding' the length may change! // Returns FAIL when something wrong. -int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int buflen) +int spell_casefold(const win_T *wp, char *str, int len, char *buf, int buflen) FUNC_ATTR_NONNULL_ALL { if (len >= buflen) { @@ -2482,12 +2491,12 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle int outi = 0; // Fold one character at a time. - for (char_u *p = str; p < str + len;) { + for (char *p = str; p < str + len;) { if (outi + MB_MAXBYTES > buflen) { buf[outi] = NUL; return FAIL; } - int c = mb_cptr2char_adv((const char_u **)&p); + int c = mb_cptr2char_adv((const char **)&p); // Exception: greek capital sigma 0x03A3 folds to 0x03C3, except // when it is the last character in a word, then it folds to @@ -2502,7 +2511,7 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle c = SPELL_TOFOLD(c); } - outi += utf_char2bytes(c, (char *)buf + outi); + outi += utf_char2bytes(c, buf + outi); } buf[outi] = NUL; @@ -2551,7 +2560,7 @@ bool check_need_cap(linenr_T lnum, colnr_T col) char *p = line + endcol; for (;;) { MB_PTR_BACK(line, p); - if (p == line || spell_iswordp_nmw((char_u *)p, curwin)) { + if (p == line || spell_iswordp_nmw(p, curwin)) { break; } if (vim_regexec(®match, p, 0) @@ -2582,15 +2591,15 @@ void ex_spellrepall(exarg_T *eap) int addlen = (int)(strlen(repl_to) - strlen(repl_from)); size_t frompatlen = strlen(repl_from) + 7; - char_u *frompat = xmalloc(frompatlen); - snprintf((char *)frompat, frompatlen, "\\V\\<%s\\>", repl_from); + char *frompat = xmalloc(frompatlen); + snprintf(frompat, frompatlen, "\\V\\<%s\\>", repl_from); p_ws = false; sub_nsubs = 0; sub_nlines = 0; curwin->w_cursor.lnum = 0; while (!got_int) { - if (do_search(NULL, '/', '/', (char *)frompat, 1L, SEARCH_KEEP, NULL) == 0 + if (do_search(NULL, '/', '/', frompat, 1L, SEARCH_KEEP, NULL) == 0 || u_save_cursor() == FAIL) { break; } @@ -2600,11 +2609,11 @@ void ex_spellrepall(exarg_T *eap) char *line = get_cursor_line_ptr(); if (addlen <= 0 || strncmp(line + curwin->w_cursor.col, repl_to, strlen(repl_to)) != 0) { - char_u *p = xmalloc(strlen(line) + (size_t)addlen + 1); + char *p = xmalloc(strlen(line) + (size_t)addlen + 1); memmove(p, line, (size_t)curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); STRCAT(p, line + curwin->w_cursor.col + strlen(repl_from)); - ml_replace(curwin->w_cursor.lnum, (char *)p, false); + ml_replace(curwin->w_cursor.lnum, p, false); changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); if (curwin->w_cursor.lnum != prev_lnum) { @@ -2634,30 +2643,30 @@ void ex_spellrepall(exarg_T *eap) /// @param[in] word source string to copy /// @param[in,out] wcopy copied string, with case of first letter changed /// @param[in] upper True to upper case, otherwise lower case -void onecap_copy(char_u *word, char *wcopy, bool upper) +void onecap_copy(char *word, char *wcopy, bool upper) { - char_u *p = word; - int c = mb_cptr2char_adv((const char_u **)&p); + char *p = word; + int c = mb_cptr2char_adv((const char **)&p); if (upper) { c = SPELL_TOUPPER(c); } else { c = SPELL_TOFOLD(c); } int l = utf_char2bytes(c, wcopy); - xstrlcpy(wcopy + l, (char *)p, (size_t)(MAXWLEN - l)); + xstrlcpy(wcopy + l, p, (size_t)(MAXWLEN - l)); } // Make a copy of "word" with all the letters upper cased into // "wcopy[MAXWLEN]". The result is NUL terminated. -void allcap_copy(char_u *word, char_u *wcopy) +void allcap_copy(char *word, char *wcopy) { - char_u *d = wcopy; - for (char_u *s = word; *s != NUL;) { - int c = mb_cptr2char_adv((const char_u **)&s); + char_u *d = (char_u *)wcopy; + for (char *s = word; *s != NUL;) { + int c = mb_cptr2char_adv((const char **)&s); if (c == 0xdf) { c = 'S'; - if (d - wcopy >= MAXWLEN - 1) { + if (d - (char_u *)wcopy >= MAXWLEN - 1) { break; } *d++ = (char_u)c; @@ -2665,7 +2674,7 @@ void allcap_copy(char_u *word, char_u *wcopy) c = SPELL_TOUPPER(c); } - if (d - wcopy >= MAXWLEN - MB_MAXBYTES) { + if (d - (char_u *)wcopy >= MAXWLEN - MB_MAXBYTES) { break; } d += utf_char2bytes(c, (char *)d); @@ -2675,9 +2684,9 @@ void allcap_copy(char_u *word, char_u *wcopy) // Case-folding may change the number of bytes: Count nr of chars in // fword[flen] and return the byte length of that many chars in "word". -int nofold_len(char_u *fword, int flen, char_u *word) +int nofold_len(char *fword, int flen, char *word) { - char_u *p; + char *p; int i = 0; for (p = fword; p < fword + flen; MB_PTR_ADV(p)) { @@ -2690,14 +2699,14 @@ int nofold_len(char_u *fword, int flen, char_u *word) } // Copy "fword" to "cword", fixing case according to "flags". -void make_case_word(char_u *fword, char_u *cword, int flags) +void make_case_word(char *fword, char *cword, int flags) { if (flags & WF_ALLCAP) { // Make it all upper-case allcap_copy(fword, cword); } else if (flags & WF_ONECAP) { // Make the first letter upper-case - onecap_copy(fword, (char *)cword, true); + onecap_copy(fword, cword, true); } else { // Use goodword as-is. STRCPY(cword, fword); @@ -2720,9 +2729,9 @@ char *eval_soundfold(const char *const word) langp_T *const lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); if (!GA_EMPTY(&lp->lp_slang->sl_sal)) { // soundfold the word - char_u sound[MAXWLEN]; - spell_soundfold(lp->lp_slang, (char *)word, false, (char *)sound); - return xstrdup((const char *)sound); + char sound[MAXWLEN]; + spell_soundfold(lp->lp_slang, (char *)word, false, sound); + return xstrdup(sound); } } } @@ -2750,7 +2759,7 @@ void spell_soundfold(slang_T *slang, char *inword, bool folded, char *res) { if (slang->sl_sofo) { // SOFOFROM and SOFOTO used - spell_soundfold_sofo(slang, (char_u *)inword, (char_u *)res); + spell_soundfold_sofo(slang, inword, res); } else { char fword[MAXWLEN]; char *word; @@ -2758,17 +2767,17 @@ void spell_soundfold(slang_T *slang, char *inword, bool folded, char *res) if (folded) { word = inword; } else { - (void)spell_casefold(curwin, (char_u *)inword, (int)strlen(inword), (char_u *)fword, MAXWLEN); + (void)spell_casefold(curwin, inword, (int)strlen(inword), fword, MAXWLEN); word = fword; } - spell_soundfold_wsal(slang, (char_u *)word, (char_u *)res); + spell_soundfold_wsal(slang, word, res); } } // Perform sound folding of "inword" into "res" according to SOFOFROM and // SOFOTO lines. -static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) +static void spell_soundfold_sofo(slang_T *slang, char *inword, char *res) { int ri = 0; @@ -2776,8 +2785,8 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // The sl_sal_first[] table contains the translation for chars up to // 255, sl_sal the rest. - for (char_u *s = inword; *s != NUL;) { - int c = mb_cptr2char_adv((const char_u **)&s); + for (char *s = inword; *s != NUL;) { + int c = mb_cptr2char_adv((const char **)&s); if (utf_class(c) == 0) { c = ' '; } else if (c < 256) { @@ -2802,7 +2811,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) } if (c != NUL && c != prevc) { - ri += utf_char2bytes(c, (char *)res + ri); + ri += utf_char2bytes(c, res + ri); if (ri + MB_MAXBYTES > MAXWLEN) { break; } @@ -2815,7 +2824,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]". // Multi-byte version of spell_soundfold(). -static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *res) +static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) { salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN] = { 0 }; @@ -2837,8 +2846,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r // Remove accents, if wanted. We actually remove all non-word characters. // But keep white space. int wordlen = 0; - for (const char_u *s = inword; *s != NUL;) { - const char_u *t = s; + for (const char *s = (char *)inword; *s != NUL;) { + const char_u *t = (char_u *)s; int c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (utf_class(c) == 0) { @@ -2849,7 +2858,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r did_white = true; } else { did_white = false; - if (!spell_iswordp_nmw(t, curwin)) { + if (!spell_iswordp_nmw((char *)t, curwin)) { continue; } } @@ -2906,7 +2915,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r } k++; } - char_u *s = smp[n].sm_rules; + char_u *s = (char_u *)smp[n].sm_rules; pri = 5; // default priority p0 = *s; @@ -2983,7 +2992,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r } p0 = 5; - s = smp[n0].sm_rules; + s = (char_u *)smp[n0].sm_rules; while (*s == '-') { // "k0" gets NOT reduced because // "if (k0 == k)" @@ -3024,7 +3033,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r // replace string ws = smp[n].sm_to_w; - s = smp[n].sm_rules; + s = (char_u *)smp[n].sm_rules; p0 = (vim_strchr((char *)s, '<') != NULL) ? 1 : 0; if (p0 == 1 && z == 0) { // rule with '<' is used @@ -3102,7 +3111,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char_u *inword, char_u *r // Convert wide characters in "wres" to a multi-byte string in "res". int l = 0; for (int n = 0; n < reslen; n++) { - l += utf_char2bytes(wres[n], (char *)res + l); + l += utf_char2bytes(wres[n], res + l); if (l + MB_MAXBYTES > MAXWLEN) { break; } @@ -3204,7 +3213,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) if (ic) { dumpflags |= DUMPFLAG_ICASE; } else { - n = captype((char_u *)pat, NULL); + n = captype(pat, NULL); if (n == WF_ONECAP) { dumpflags |= DUMPFLAG_ONECAP; } else if (n == WF_ALLCAP @@ -3218,7 +3227,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // regions or none at all. for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - p = (char *)lp->lp_slang->sl_regions; + p = lp->lp_slang->sl_regions; if (p[0] != 0) { if (region_names == NULL) { // first language with regions region_names = p; @@ -3264,11 +3273,11 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) for (int round = 1; round <= 2; round++) { if (round == 1) { dumpflags &= ~DUMPFLAG_KEEPCASE; - byts = (char *)slang->sl_fbyts; + byts = slang->sl_fbyts; idxs = slang->sl_fidxs; } else { dumpflags |= DUMPFLAG_KEEPCASE; - byts = (char *)slang->sl_kbyts; + byts = slang->sl_kbyts; idxs = slang->sl_kidxs; } if (byts == NULL) { @@ -3319,7 +3328,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // Apply the prefix, if there is one. if (c != 0) { - lnum = dump_prefixes(slang, word, (char_u *)pat, dir, + lnum = dump_prefixes(slang, word, pat, dir, dumpflags, flags, lnum); } } @@ -3337,7 +3346,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // ignore case... assert(depth >= 0); if (depth <= patlen - && mb_strnicmp((char *)word, pat, (size_t)depth) != 0) { + && mb_strnicmp(word, pat, (size_t)depth) != 0) { depth--; } } @@ -3367,12 +3376,12 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int if ((dumpflags & DUMPFLAG_KEEPCASE) == 0 && (flags & WF_CAPMASK) != 0) { // Need to fix case according to "flags". - make_case_word((char_u *)word, (char_u *)cword, flags); + make_case_word(word, cword, flags); p = cword; } else { p = word; if ((dumpflags & DUMPFLAG_KEEPCASE) - && ((captype((char_u *)word, NULL) & WF_KEEPCAP) == 0 + && ((captype(word, NULL) & WF_KEEPCAP) == 0 || (flags & WF_FIXCAP) != 0)) { keepcap = true; } @@ -3436,8 +3445,8 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int /// @param flags flags with prefix ID /// /// @return the updated line number. -static linenr_T dump_prefixes(slang_T *slang, char *word, char_u *pat, Direction *dir, - int dumpflags, int flags, linenr_T startlnum) +static linenr_T dump_prefixes(slang_T *slang, char *word, char *pat, Direction *dir, int dumpflags, + int flags, linenr_T startlnum) { idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; @@ -3450,11 +3459,11 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char_u *pat, Direction // upper-case letter in word_up[]. int c = utf_ptr2char(word); if (SPELL_TOUPPER(c) != c) { - onecap_copy((char_u *)word, (char *)word_up, true); + onecap_copy(word, word_up, true); has_word_up = true; } - char_u *byts = slang->sl_pbyts; + char_u *byts = (char_u *)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[]. @@ -3484,10 +3493,10 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char_u *pat, Direction } curi[depth] += i - 1; - c = valid_word_prefix(i, n, flags, (char_u *)word, slang, false); + c = valid_word_prefix(i, n, flags, word, slang, false); if (c != 0) { xstrlcpy(prefix + depth, word, (size_t)(MAXWLEN - depth)); - dump_word(slang, (char *)prefix, (char *)pat, dir, dumpflags, + dump_word(slang, prefix, pat, dir, dumpflags, (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; @@ -3498,11 +3507,10 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char_u *pat, Direction // first letter is upper-case, but only if the prefix has // a condition. if (has_word_up) { - c = valid_word_prefix(i, n, flags, (char_u *)word_up, slang, - true); + c = valid_word_prefix(i, n, flags, word_up, slang, true); if (c != 0) { xstrlcpy(prefix + depth, word_up, (size_t)(MAXWLEN - depth)); - dump_word(slang, (char *)prefix, (char *)pat, dir, dumpflags, + dump_word(slang, prefix, pat, dir, dumpflags, (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; @@ -3524,9 +3532,9 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char_u *pat, Direction // Move "p" to the end of word "start". // Uses the spell-checking word characters. -char_u *spell_to_word_end(char_u *start, win_T *win) +char *spell_to_word_end(char *start, win_T *win) { - char_u *p = start; + char *p = start; while (*p != NUL && spell_iswordp(p, win)) { MB_PTR_ADV(p); @@ -3545,8 +3553,8 @@ int spell_word_start(int startcol) return startcol; } - char_u *line = (char_u *)get_cursor_line_ptr(); - char_u *p; + char *line = get_cursor_line_ptr(); + char *p; // Find a word character before "startcol". for (p = line + startcol; p > line;) { @@ -3588,7 +3596,7 @@ int expand_spelling(linenr_T lnum, char *pat, char ***matchp) { garray_T ga; - spell_suggest_list(&ga, (char_u *)pat, 100, spell_expand_need_cap, true); + spell_suggest_list(&ga, pat, 100, spell_expand_need_cap, true); *matchp = ga.ga_data; return ga.ga_len; } @@ -3624,15 +3632,16 @@ char *did_set_spell_option(bool is_spellfile) } } - if (errmsg == NULL) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == curbuf && wp->w_p_spell) { - errmsg = did_set_spelllang(wp); - break; - } - } + if (errmsg != NULL) { + return errmsg; } + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer == curbuf && wp->w_p_spell) { + errmsg = did_set_spelllang(wp); + break; + } + } return errmsg; } diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index 4d146a1706..726af7d698 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -80,11 +80,11 @@ typedef struct fromto_S { // The info is split for quick processing by spell_soundfold(). // Note that "sm_oneof" and "sm_rules" point into sm_lead. typedef struct salitem_S { - char_u *sm_lead; // leading letters - int sm_leadlen; // length of "sm_lead" - char_u *sm_oneof; // letters from () or NULL - char_u *sm_rules; // rules like ^, $, priority - char_u *sm_to; // replacement. + char *sm_lead; // leading letters + int sm_leadlen; // length of "sm_lead" + char_u *sm_oneof; // letters from () or NULL + char *sm_rules; // rules like ^, $, priority + char *sm_to; // replacement. int *sm_lead_w; // wide character copy of "sm_lead" int *sm_oneof_w; // wide character copy of "sm_oneof" int *sm_to_w; // wide character copy of "sm_to" @@ -119,17 +119,17 @@ struct slang_S { 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 + char *sl_fbyts; // case-folded word bytes long sl_fbyts_len; // length of sl_fbyts idx_T *sl_fidxs; // case-folded word indexes - char_u *sl_kbyts; // keep-case word bytes + char *sl_kbyts; // keep-case word bytes idx_T *sl_kidxs; // keep-case word indexes - char_u *sl_pbyts; // prefix tree word bytes + char *sl_pbyts; // prefix tree word bytes idx_T *sl_pidxs; // prefix tree word indexes char_u *sl_info; // infotext string or NULL - char_u sl_regions[MAXREGIONS * 2 + 1]; + char sl_regions[MAXREGIONS * 2 + 1]; // table with up to 8 region names plus NUL char_u *sl_midword; // MIDWORD string or NULL @@ -143,9 +143,9 @@ struct slang_S { garray_T sl_comppat; // CHECKCOMPOUNDPATTERN items regprog_T *sl_compprog; // COMPOUNDRULE turned into a regexp progrm // (NULL when no compounding) - char_u *sl_comprules; // all COMPOUNDRULE concatenated (or NULL) - char_u *sl_compstartflags; // flags for first compound word - char_u *sl_compallflags; // all flags for compound words + uint8_t *sl_comprules; // all COMPOUNDRULE concatenated (or NULL) + uint8_t *sl_compstartflags; // flags for first compound word + uint8_t *sl_compallflags; // all flags for compound words bool sl_nobreak; // When true: no spaces between words char_u *sl_syllable; // SYLLABLE repeatable chars or NULL garray_T sl_syl_items; // syllable items @@ -172,7 +172,7 @@ struct slang_S { // Info from the .sug file. Loaded on demand. time_t sl_sugtime; // timestamp for .sug file - char_u *sl_sbyts; // soundfolded word bytes + char *sl_sbyts; // soundfolded word bytes idx_T *sl_sidxs; // soundfolded word indexes buf_T *sl_sugbuf; // buffer with word number table bool sl_sugloaded; // true when .sug file was loaded or failed to @@ -227,7 +227,7 @@ typedef struct { extern slang_T *first_lang; // file used for "zG" and "zW" -extern char_u *int_wordlist; +extern char *int_wordlist; extern spelltab_T spelltab; extern int did_set_spelltab; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index e6257aeca1..7b124ae6b6 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -270,10 +270,6 @@ #include "nvim/undo.h" #include "nvim/vim.h" -#ifndef UNIX // it's in os/unix_defs.h for Unix -# include <time.h> -#endif - // Special byte values for <byte>. Some are only used in the tree for // postponed prefixes, some only in the other trees. This is a bit messy... enum { @@ -336,7 +332,7 @@ static char *msg_compressing = N_("Compressing word tree..."); // and .dic file. // Main structure to store the contents of a ".aff" file. typedef struct afffile_S { - char_u *af_enc; // "SET", normalized, alloc'ed string or NULL + char *af_enc; // "SET", normalized, alloc'ed string or NULL int af_flagtype; // AFT_CHAR, AFT_LONG, AFT_NUM or AFT_CAPLONG unsigned af_rare; // RARE ID for rare word unsigned af_keepcase; // KEEPCASE ID for keep-case word @@ -364,12 +360,12 @@ typedef struct afffile_S { typedef struct affentry_S affentry_T; // Affix entry from ".aff" file. Used for prefixes and suffixes. struct affentry_S { - affentry_T *ae_next; // next affix with same name/number - char *ae_chop; // text to chop off basic word (can be NULL) - char *ae_add; // text to add to basic word (can be NULL) - char_u *ae_flags; // flags on the affix (can be NULL) - char_u *ae_cond; // condition (NULL for ".") - regprog_T *ae_prog; // regexp program for ae_cond or NULL + affentry_T *ae_next; // next affix with same name/number + char *ae_chop; // text to chop off basic word (can be NULL) + char *ae_add; // text to add to basic word (can be NULL) + char *ae_flags; // flags on the affix (can be NULL) + char *ae_cond; // condition (NULL for ".") + regprog_T *ae_prog; // regexp program for ae_cond or NULL char ae_compforbid; // COMPOUNDFORBIDFLAG found char ae_comppermit; // COMPOUNDPERMITFLAG found }; @@ -724,7 +720,7 @@ slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) if (p == NULL) { goto endFAIL; } - set_map_str(lp, (char_u *)p); + set_map_str(lp, p); xfree(p); break; @@ -1004,8 +1000,8 @@ someerror: // Need to put word counts in the word tries, so that we can find // a word by its number. - tree_count_words(slang->sl_fbyts, slang->sl_fidxs); - tree_count_words(slang->sl_sbyts, slang->sl_sidxs); + tree_count_words((char_u *)slang->sl_fbyts, slang->sl_fidxs); + tree_count_words((char_u *)slang->sl_sbyts, slang->sl_sidxs); nextone: if (fd != NULL) { @@ -1054,7 +1050,7 @@ static int read_region_section(FILE *fd, slang_T *lp, int len) if (len > MAXREGIONS * 2) { return SP_FORMERROR; } - SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd,; ); // NOLINT(whitespace/parens) + SPELL_READ_NONNUL_BYTES(lp->sl_regions, (size_t)len, fd,; ); // NOLINT(whitespace/parens) lp->sl_regions[len] = NUL; return 0; } @@ -1064,12 +1060,12 @@ static int read_region_section(FILE *fd, slang_T *lp, int len) // Return SP_*ERROR flags. static int read_charflags_section(FILE *fd) { - char_u *flags; + char *flags; char_u *fol; int flagslen, follen; // <charflagslen> <charflags> - flags = read_cnt_string(fd, 1, &flagslen); + flags = (char *)read_cnt_string(fd, 1, &flagslen); if (flagslen < 0) { return flagslen; } @@ -1083,7 +1079,7 @@ static int read_charflags_section(FILE *fd) // Set the word-char flags and fill SPELL_ISUPPER() table. if (flags != NULL && fol != NULL) { - set_spell_charflags(flags, flagslen, fol); + set_spell_charflags((char_u *)flags, flagslen, (char *)fol); } xfree(flags); @@ -1219,7 +1215,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) return SP_TRUNCERROR; } p = xmalloc((size_t)ccnt + 2); - smp->sm_lead = p; + smp->sm_lead = (char *)p; // Read up to the first special char into sm_lead. int i = 0; @@ -1230,7 +1226,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) } *p++ = (char_u)c; } - smp->sm_leadlen = (int)(p - smp->sm_lead); + smp->sm_leadlen = (int)(p - (char_u *)smp->sm_lead); *p++ = NUL; // Put (abc) chars in sm_oneof, if any. @@ -1252,7 +1248,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) } // Any following chars go in sm_rules. - smp->sm_rules = p; + smp->sm_rules = (char *)p; if (i < ccnt) { // store the char we got while checking for end of sm_lead *p++ = (char_u)c; @@ -1267,7 +1263,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) *p++ = NUL; // <saltolen> <salto> - smp->sm_to = read_cnt_string(fd, 1, &ccnt); + smp->sm_to = (char *)read_cnt_string(fd, 1, &ccnt); if (ccnt < 0) { xfree(smp->sm_lead); return ccnt; @@ -1275,11 +1271,11 @@ static int read_sal_section(FILE *fd, slang_T *slang) // convert the multi-byte strings to wide char strings smp->sm_lead_w = mb_str2wide(smp->sm_lead); - smp->sm_leadlen = mb_charlen((char *)smp->sm_lead); + smp->sm_leadlen = mb_charlen(smp->sm_lead); if (smp->sm_oneof == NULL) { smp->sm_oneof_w = NULL; } else { - smp->sm_oneof_w = mb_str2wide(smp->sm_oneof); + smp->sm_oneof_w = mb_str2wide((char *)smp->sm_oneof); } if (smp->sm_to == NULL) { smp->sm_to_w = NULL; @@ -1294,12 +1290,12 @@ static int read_sal_section(FILE *fd, slang_T *slang) smp = &((salitem_T *)gap->ga_data)[gap->ga_len]; p = xmalloc(1); p[0] = NUL; - smp->sm_lead = p; + smp->sm_lead = (char *)p; smp->sm_lead_w = mb_str2wide(smp->sm_lead); smp->sm_leadlen = 0; smp->sm_oneof = NULL; smp->sm_oneof_w = NULL; - smp->sm_rules = p; + smp->sm_rules = (char *)p; smp->sm_to = NULL; smp->sm_to_w = NULL; gap->ga_len++; @@ -1348,19 +1344,19 @@ static int read_words_section(FILE *fd, slang_T *lp, int len) static int read_sofo_section(FILE *fd, slang_T *slang) { int cnt; - char_u *from, *to; + char *from, *to; int res; slang->sl_sofo = true; // <sofofromlen> <sofofrom> - from = read_cnt_string(fd, 2, &cnt); + from = (char *)read_cnt_string(fd, 2, &cnt); if (cnt < 0) { return cnt; } // <sofotolen> <sofoto> - to = read_cnt_string(fd, 2, &cnt); + to = (char *)read_cnt_string(fd, 2, &cnt); if (cnt < 0) { xfree(from); return cnt; @@ -1430,7 +1426,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) return SP_TRUNCERROR; } todo -= 2; - ga_init(gap, sizeof(char_u *), c); + ga_init(gap, sizeof(char *), c); ga_grow(gap, c); while (--c >= 0) { ((char **)(gap->ga_data))[gap->ga_len++] = (char *)read_cnt_string(fd, 1, &cnt); @@ -1451,25 +1447,25 @@ static int read_compound(FILE *fd, slang_T *slang, int len) // Conversion to utf-8 may double the size. c = todo * 2 + 7; c += todo * 2; - char_u *pat = xmalloc((size_t)c); + char *pat = xmalloc((size_t)c); // We also need a list of all flags that can appear at the start and one // for all flags. - char_u *cp = xmalloc((size_t)todo + 1); + uint8_t *cp = xmalloc((size_t)todo + 1); slang->sl_compstartflags = cp; *cp = NUL; - char_u *ap = xmalloc((size_t)todo + 1); + uint8_t *ap = xmalloc((size_t)todo + 1); slang->sl_compallflags = ap; *ap = NUL; // And a list of all patterns in their original form, for checking whether // compounding may work in match_compoundrule(). This is freed when we // encounter a wildcard, the check doesn't work then. - char_u *crp = xmalloc((size_t)todo + 1); + uint8_t *crp = xmalloc((size_t)todo + 1); slang->sl_comprules = crp; - char_u *pp = pat; + char_u *pp = (char_u *)pat; *pp++ = '^'; *pp++ = '\\'; *pp++ = '('; @@ -1538,7 +1534,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) *crp = NUL; } - slang->sl_compprog = vim_regcomp((char *)pat, RE_MAGIC + RE_STRING + RE_STRICT); + slang->sl_compprog = vim_regcomp(pat, RE_MAGIC + RE_STRING + RE_STRICT); xfree(pat); if (slang->sl_compprog == NULL) { return SP_FORMERROR; @@ -1549,10 +1545,10 @@ static int read_compound(FILE *fd, slang_T *slang, int len) // Set the SOFOFROM and SOFOTO items in language "lp". // Returns SP_*ERROR flags when there is something wrong. -static int set_sofo(slang_T *lp, char_u *from, char_u *to) +static int set_sofo(slang_T *lp, char *from, char *to) { - char_u *s; - char_u *p; + char *s; + char *p; // Use "sl_sal" as an array with 256 pointers to a list of wide // characters. The index is the low byte of the character. @@ -1567,7 +1563,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to) // First count the number of items for each list. Temporarily use // sl_sal_first[] for this. for (p = from, s = to; *p != NUL && *s != NUL;) { - const int c = mb_cptr2char_adv((const char_u **)&p); + const int c = mb_cptr2char_adv((const char **)&p); MB_CPTR_ADV(s); if (c >= 256) { lp->sl_sal_first[c & 0xff]++; @@ -1590,8 +1586,8 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to) // list. memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256); for (p = from, s = to; *p != NUL && *s != NUL;) { - const int c = mb_cptr2char_adv((const char_u **)&p); - const int i = mb_cptr2char_adv((const char_u **)&s); + const int c = mb_cptr2char_adv((const char **)&p); + const int i = mb_cptr2char_adv((const char **)&s); if (c >= 256) { // Append the from-to chars at the end of the list with // the low byte. @@ -1660,13 +1656,13 @@ static void set_sal_first(slang_T *lp) // Turn a multi-byte string into a wide character string. // Return it in allocated memory. -static int *mb_str2wide(char_u *s) +static int *mb_str2wide(char *s) { int i = 0; - int *res = xmalloc(((size_t)mb_charlen((char *)s) + 1) * sizeof(int)); - for (char_u *p = s; *p != NUL;) { - res[i++] = mb_ptr2char_adv((const char_u **)&p); + int *res = xmalloc(((size_t)mb_charlen(s) + 1) * sizeof(int)); + for (char *p = s; *p != NUL;) { + res[i++] = mb_ptr2char_adv((const char **)&p); } res[i] = NUL; @@ -1681,12 +1677,12 @@ static int *mb_str2wide(char_u *s) /// @param prefixcnt when "prefixtree" is true: prefix count /// /// @return zero when OK, SP_ value for an error. -static int spell_read_tree(FILE *fd, char_u **bytsp, long *bytsp_len, idx_T **idxsp, - bool prefixtree, int prefixcnt) +static int spell_read_tree(FILE *fd, char **bytsp, long *bytsp_len, idx_T **idxsp, bool prefixtree, + int prefixcnt) FUNC_ATTR_NONNULL_ARG(1, 2, 4) { int idx; - char_u *bp; + char *bp; idx_T *ip; // The tree size was computed when writing the file, so that we can @@ -1699,23 +1695,25 @@ static int spell_read_tree(FILE *fd, char_u **bytsp, long *bytsp_len, idx_T **id // Invalid length, multiply with sizeof(int) would overflow. return SP_FORMERROR; } - if (len > 0) { - // Allocate the byte array. - bp = xmalloc((size_t)len); - *bytsp = bp; - if (bytsp_len != NULL) { - *bytsp_len = len; - } + if (len <= 0) { + return 0; + } - // Allocate the index array. - ip = xcalloc((size_t)len, sizeof(*ip)); - *idxsp = ip; + // Allocate the byte array. + bp = xmalloc((size_t)len); + *bytsp = bp; + if (bytsp_len != NULL) { + *bytsp_len = len; + } - // Recursively read the tree and store it in the array. - idx = read_tree_node(fd, bp, ip, (int)len, 0, prefixtree, prefixcnt); - if (idx < 0) { - return idx; - } + // Allocate the index array. + ip = xcalloc((size_t)len, sizeof(*ip)); + *idxsp = ip; + + // Recursively read the tree and store it in the array. + idx = read_tree_node(fd, (char_u *)bp, ip, (int)len, 0, prefixtree, prefixcnt); + if (idx < 0) { + return idx; } return 0; } @@ -1839,15 +1837,15 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx /// Reload the spell file "fname" if it's loaded. /// /// @param added_word invoked through "zg" -static void spell_reload_one(char_u *fname, bool added_word) +static void spell_reload_one(char *fname, bool added_word) { slang_T *slang; bool didit = false; for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)fname, slang->sl_fname, false, true) == kEqualFiles) { + if (path_full_compare(fname, slang->sl_fname, false, true) == kEqualFiles) { slang_clear(slang); - if (spell_load_file((char *)fname, NULL, slang, false) == NULL) { + if (spell_load_file(fname, NULL, slang, false) == NULL) { // reloading failed, clear the language slang_clear(slang); } @@ -2007,26 +2005,27 @@ static void spell_print_node(wordnode_T *node, int depth) static void spell_print_tree(wordnode_T *root) { - if (root != NULL) { - // Clear the "wn_u1.index" fields, used to remember what has been - // done. - spell_clear_flags(root); - - // Recursively print the tree. - spell_print_node(root, 0); + if (root == NULL) { + return; } + + // Clear the "wn_u1.index" fields, used to remember what has been done. + spell_clear_flags(root); + + // Recursively print the tree. + spell_print_node(root, 0); } #endif // SPELL_PRINTTREE // Reads the affix file "fname". // Returns an afffile_T, NULL for complete failure. -static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) +static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) { FILE *fd; - char_u rline[MAXLINELEN]; - char_u *line; - char_u *pc = NULL; + char rline[MAXLINELEN]; + char *line; + char *pc = NULL; #define MAXITEMCNT 30 char *(items[MAXITEMCNT]); int itemcnt; @@ -2052,13 +2051,13 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) int compmax = 0; // COMPOUNDWORDMAX value char *compflags = NULL; // COMPOUNDFLAG and COMPOUNDRULE // concatenated - char_u *midword = NULL; // MIDWORD value - char_u *syllable = NULL; // SYLLABLE value - char_u *sofofrom = NULL; // SOFOFROM value - char_u *sofoto = NULL; // SOFOTO value + char *midword = NULL; // MIDWORD value + char *syllable = NULL; // SYLLABLE value + char *sofofrom = NULL; // SOFOFROM value + char *sofoto = NULL; // SOFOTO value // Open the file. - fd = os_fopen((char *)fname, "r"); + fd = os_fopen(fname, "r"); if (fd == NULL) { semsg(_(e_notopen), fname); return NULL; @@ -2086,7 +2085,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) hash_init(&aff->af_comp); // Read all the lines in the file one by one. - while (!vim_fgets((char *)rline, MAXLINELEN, fd) && !got_int) { + while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int) { line_breakcheck(); lnum++; @@ -2098,7 +2097,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 = (char_u *)string_convert(&spin->si_conv, (char *)rline, NULL); + pc = string_convert(&spin->si_conv, rline, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %d: %s"), fname, lnum, rline); @@ -2113,7 +2112,7 @@ 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 = (char *)line;;) { + for (p = line;;) { while (*p != NUL && (uint8_t)(*p) <= ' ') { // skip white space and CR/NL p++; } @@ -2144,9 +2143,9 @@ 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 = (char_u *)enc_canonize((char *)items[1]); + aff->af_enc = enc_canonize((char *)items[1]); if (!spin->si_ascii - && convert_setup(&spin->si_conv, (char *)aff->af_enc, p_enc) == FAIL) { + && convert_setup(&spin->si_conv, aff->af_enc, p_enc) == FAIL) { smsg(_("Conversion in %s not supported: from %s to %s"), fname, aff->af_enc, p_enc); } @@ -2191,57 +2190,47 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) STRCAT(p, items[1]); spin->si_info = p; } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) { - midword = (char_u *)getroom_save(spin, items[1]); + midword = getroom_save(spin, items[1]); } else if (is_aff_rule(items, itemcnt, "TRY", 2)) { // ignored, we look in the tree for what chars may appear } else if ((is_aff_rule(items, itemcnt, "RAR", 2) // TODO(vim): remove "RAR" later || is_aff_rule(items, itemcnt, "RARE", 2)) && aff->af_rare == 0) { - aff->af_rare = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_rare = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if ((is_aff_rule(items, itemcnt, "KEP", 2) // TODO(vim): remove "KEP" later || is_aff_rule(items, itemcnt, "KEEPCASE", 2)) && aff->af_keepcase == 0) { - aff->af_keepcase = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_keepcase = affitem2flag(aff->af_flagtype, 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, (char_u *)items[1], - fname, lnum); + aff->af_bad = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2) && aff->af_needaffix == 0) { - aff->af_needaffix = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2) && aff->af_circumfix == 0) { - aff->af_circumfix = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2) && aff->af_nosuggest == 0) { - aff->af_nosuggest = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_nosuggest = affitem2flag(aff->af_flagtype, 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, (char_u *)items[1], - fname, lnum); + aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2) && aff->af_comproot == 0) { - aff->af_comproot = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_comproot = affitem2flag(aff->af_flagtype, items[1], fname, lnum); } else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2) && aff->af_compforbid == 0) { - aff->af_compforbid = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_compforbid = affitem2flag(aff->af_flagtype, 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"), fname, lnum); } } else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2) && aff->af_comppermit == 0) { - aff->af_comppermit = affitem2flag(aff->af_flagtype, (char_u *)items[1], - fname, lnum); + aff->af_comppermit = affitem2flag(aff->af_flagtype, 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"), fname, lnum); @@ -2330,7 +2319,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } } else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2) && syllable == NULL) { - syllable = (char_u *)getroom_save(spin, items[1]); + syllable = getroom_save(spin, items[1]); } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) { spin->si_nobreak = true; } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) { @@ -2375,8 +2364,7 @@ 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, (char_u *)items[1], - fname, lnum); + cur_aff->ah_flag = affitem2flag(aff->af_flagtype, items[1], fname, lnum); if (cur_aff->ah_flag == 0 || strlen(items[1]) >= AH_KEY_LEN) { break; } @@ -2469,7 +2457,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) aff_entry->ae_add = getroom_save(spin, items[3]); // Recognize flags on the affix: abcd/XYZ - aff_entry->ae_flags = (char_u *)vim_strchr(aff_entry->ae_add, '/'); + aff_entry->ae_flags = vim_strchr(aff_entry->ae_add, '/'); if (aff_entry->ae_flags != NULL) { *aff_entry->ae_flags++ = NUL; aff_process_flags(aff, aff_entry); @@ -2484,15 +2472,15 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) cur_aff->ah_first = aff_entry; if (strcmp(items[4], ".") != 0) { - char_u buf[MAXLINELEN]; + char buf[MAXLINELEN]; - aff_entry->ae_cond = (char_u *)getroom_save(spin, items[4]); + aff_entry->ae_cond = getroom_save(spin, items[4]); if (*items[0] == 'P') { - sprintf((char *)buf, "^%s", items[4]); // NOLINT(runtime/printf) + sprintf(buf, "^%s", items[4]); // NOLINT(runtime/printf) } else { - sprintf((char *)buf, "%s$", items[4]); // NOLINT(runtime/printf) + sprintf(buf, "%s$", items[4]); // NOLINT(runtime/printf) } - aff_entry->ae_prog = vim_regcomp((char *)buf, RE_MAGIC + RE_STRING + RE_STRICT); + aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING + RE_STRICT); if (aff_entry->ae_prog == NULL) { smsg(_("Broken condition in %s line %d: %s"), fname, lnum, items[4]); @@ -2520,7 +2508,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) c_up = SPELL_TOUPPER(c); if (c_up != c && (aff_entry->ae_cond == NULL - || utf_ptr2char((char *)aff_entry->ae_cond) == c)) { + || utf_ptr2char(aff_entry->ae_cond) == c)) { p = aff_entry->ae_add + strlen(aff_entry->ae_add); MB_PTR_BACK(aff_entry->ae_add, p); if (utf_ptr2char(p) == c_up) { @@ -2532,13 +2520,13 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // actual word, thus must check for the // upper-case letter. if (aff_entry->ae_cond != NULL) { - char_u buf[MAXLINELEN]; - onecap_copy((char_u *)items[4], (char *)buf, true); - aff_entry->ae_cond = (char_u *)getroom_save(spin, (char *)buf); + char buf[MAXLINELEN]; + onecap_copy(items[4], buf, true); + aff_entry->ae_cond = getroom_save(spin, buf); if (aff_entry->ae_cond != NULL) { - sprintf((char *)buf, "^%s", aff_entry->ae_cond); // NOLINT(runtime/printf) + sprintf(buf, "^%s", aff_entry->ae_cond); // NOLINT(runtime/printf) vim_regfree(aff_entry->ae_prog); - aff_entry->ae_prog = vim_regcomp((char *)buf, RE_MAGIC + RE_STRING); + aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING); } } } @@ -2553,7 +2541,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Find a previously used condition. 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)) { + if (str_equal(p, aff_entry->ae_cond)) { break; } } @@ -2562,7 +2550,7 @@ 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 : (char_u *)getroom_save(spin, (char *)aff_entry->ae_cond); + NULL : (char_u *)getroom_save(spin, aff_entry->ae_cond); } // Add the prefix to the prefix tree. @@ -2608,7 +2596,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } else if (is_aff_rule(items, itemcnt, "REP", 2) || is_aff_rule(items, itemcnt, "REPSAL", 2)) { // Ignore REP/REPSAL count - if (!isdigit(*items[1])) { + if (!isdigit((uint8_t)(*items[1]))) { smsg(_("Expected REP(SAL) count in %s line %d"), fname, lnum); } @@ -2643,7 +2631,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) if (!found_map) { // First line contains the count. found_map = true; - if (!isdigit(*items[1])) { + if (!isdigit((uint8_t)(*items[1]))) { smsg(_("Expected MAP count in %s line %d"), fname, lnum); } @@ -2652,7 +2640,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) // Check that every character appears only once. for (p = items[1]; *p != NUL;) { - c = mb_ptr2char_adv((const char_u **)&p); + c = mb_ptr2char_adv((const char **)&p); if ((!GA_EMPTY(&spin->si_map) && vim_strchr(spin->si_map.ga_data, c) != NULL) @@ -2688,10 +2676,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } } else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2) && sofofrom == NULL) { - sofofrom = (char_u *)getroom_save(spin, items[1]); + sofofrom = getroom_save(spin, items[1]); } else if (is_aff_rule(items, itemcnt, "SOFOTO", 2) && sofoto == NULL) { - sofoto = (char_u *)getroom_save(spin, items[1]); + sofoto = getroom_save(spin, items[1]); } else if (strcmp(items[0], "COMMON") == 0) { int i; @@ -2761,8 +2749,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) } if (syllable != NULL) { - aff_check_string(spin->si_syllable, (char *)syllable, "SYLLABLE"); - spin->si_syllable = (char *)syllable; + aff_check_string(spin->si_syllable, syllable, "SYLLABLE"); + spin->si_syllable = syllable; } if (sofofrom != NULL || sofoto != NULL) { @@ -2772,16 +2760,16 @@ 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, (char *)sofofrom, "SOFOFROM"); - aff_check_string(spin->si_sofoto, (char *)sofoto, "SOFOTO"); - spin->si_sofofr = (char *)sofofrom; - spin->si_sofoto = (char *)sofoto; + aff_check_string(spin->si_sofofr, sofofrom, "SOFOFROM"); + aff_check_string(spin->si_sofoto, sofoto, "SOFOTO"); + spin->si_sofofr = sofofrom; + spin->si_sofoto = sofoto; } } if (midword != NULL) { - aff_check_string(spin->si_midword, (char *)midword, "MIDWORD"); - spin->si_midword = (char *)midword; + aff_check_string(spin->si_midword, midword, "MIDWORD"); + spin->si_midword = midword; } xfree(pc); @@ -2802,18 +2790,18 @@ static bool is_aff_rule(char **items, int itemcnt, char *rulename, int mincount) // ae_flags to ae_comppermit and ae_compforbid. static void aff_process_flags(afffile_T *affile, affentry_T *entry) { - char_u *p; + char *p; char_u *prevp; unsigned flag; if (entry->ae_flags != NULL && (affile->af_compforbid != 0 || affile->af_comppermit != 0)) { for (p = entry->ae_flags; *p != NUL;) { - prevp = p; + prevp = (char_u *)p; flag = get_affitem(affile->af_flagtype, &p); if (flag == affile->af_comppermit || flag == affile->af_compforbid) { STRMOVE(prevp, (char *)p); - p = prevp; + p = (char *)prevp; if (flag == affile->af_comppermit) { entry->ae_comppermit = true; } else { @@ -2843,10 +2831,10 @@ static bool spell_info_item(char *s) // Turn an affix flag name into a number, according to the FLAG type. // returns zero for failure. -static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum) +static unsigned affitem2flag(int flagtype, char *item, char *fname, int lnum) { unsigned res; - char_u *p = item; + char *p = item; res = get_affitem(flagtype, &p); if (res == 0) { @@ -2869,7 +2857,7 @@ static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum // Get one affix name from "*pp" and advance the pointer. // Returns ZERO_FLAG for "0". // Returns zero for an error, still advances the pointer then. -static unsigned get_affitem(int flagtype, char_u **pp) +static unsigned get_affitem(int flagtype, char **pp) { int res; @@ -2878,18 +2866,18 @@ static unsigned get_affitem(int flagtype, char_u **pp) (*pp)++; // always advance, avoid getting stuck return 0; } - res = getdigits_int((char **)pp, true, 0); + res = getdigits_int(pp, true, 0); if (res == 0) { res = ZERO_FLAG; } } else { - res = mb_ptr2char_adv((const char_u **)pp); + res = mb_ptr2char_adv((const char **)pp); if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG && res >= 'A' && res <= 'Z')) { if (**pp == NUL) { return 0; } - res = mb_ptr2char_adv((const char_u **)pp) + (res << 16); + res = mb_ptr2char_adv((const char **)pp) + (res << 16); } } return (unsigned)res; @@ -2927,13 +2915,13 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags tp = (char_u *)p + strlen(p); for (p = compflags; *p != NUL;) { - if (vim_strchr("/?*+[]", *p) != NULL) { + if (vim_strchr("/?*+[]", (uint8_t)(*p)) != NULL) { // Copy non-flag characters directly. *tp++ = (char_u)(*p++); } else { // First get the flag number, also checks validity. prevp = p; - flag = get_affitem(aff->af_flagtype, (char_u **)&p); + flag = get_affitem(aff->af_flagtype, &p); if (flag != 0) { // Find the flag in the hashtable. If it was used before, use // the existing ID. Otherwise add a new entry. @@ -2978,22 +2966,22 @@ static void check_renumber(spellinfo_T *spin) } // Returns true if flag "flag" appears in affix list "afflist". -static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) +static bool flag_in_afflist(int flagtype, char *afflist, unsigned flag) { char *p; unsigned n; switch (flagtype) { case AFT_CHAR: - return vim_strchr((char *)afflist, (int)flag) != NULL; + return vim_strchr(afflist, (int)flag) != NULL; case AFT_CAPLONG: case AFT_LONG: - for (p = (char *)afflist; *p != NUL;) { - n = (unsigned)mb_ptr2char_adv((const char_u **)&p); + for (p = afflist; *p != NUL;) { + n = (unsigned)mb_ptr2char_adv((const char **)&p); if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z')) && *p != NUL) { - n = (unsigned)mb_ptr2char_adv((const char_u **)&p) + (n << 16); + n = (unsigned)mb_ptr2char_adv((const char **)&p) + (n << 16); } if (n == flag) { return true; @@ -3002,7 +2990,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) break; case AFT_NUM: - for (p = (char *)afflist; *p != NUL;) { + for (p = afflist; *p != NUL;) { int digits = getdigits_int(&p, true, 0); assert(digits >= 0); n = (unsigned int)digits; @@ -3053,13 +3041,13 @@ static bool str_equal(char *s1, char *s2) /// They are stored case-folded. static void add_fromto(spellinfo_T *spin, garray_T *gap, char *from, char *to) { - char_u word[MAXWLEN]; + char word[MAXWLEN]; fromto_T *ftp = GA_APPEND_VIA_PTR(fromto_T, gap); - (void)spell_casefold(curwin, (char_u *)from, (int)strlen(from), word, MAXWLEN); - ftp->ft_from = getroom_save(spin, (char *)word); - (void)spell_casefold(curwin, (char_u *)to, (int)strlen(to), word, MAXWLEN); - ftp->ft_to = getroom_save(spin, (char *)word); + (void)spell_casefold(curwin, from, (int)strlen(from), word, MAXWLEN); + ftp->ft_from = getroom_save(spin, word); + (void)spell_casefold(curwin, to, (int)strlen(to), word, MAXWLEN); + ftp->ft_to = getroom_save(spin, word); } /// Converts a boolean argument in a SAL line to true or false; @@ -3103,7 +3091,7 @@ static void spell_free_aff(afffile_T *aff) // Read dictionary file "fname". // Returns OK or FAIL; -static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) +static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) { hashtab_T ht; char line[MAXLINELEN]; @@ -3128,7 +3116,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) Timestamp last_msg_time = 0; // Open the file. - fd = os_fopen((char *)fname, "r"); + fd = os_fopen(fname, "r"); if (fd == NULL) { semsg(_(e_notopen), fname); return FAIL; @@ -3229,7 +3217,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) break; } - hash = hash_hash((char_u *)dw); + hash = hash_hash(dw); hi = hash_lookup(&ht, (const char *)dw, strlen(dw), hash); if (!HASHITEM_EMPTY(hi)) { if (p_verbose > 0) { @@ -3241,7 +3229,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) } duplicate++; } else { - hash_add_item(&ht, hi, (char_u *)dw, hash); + hash_add_item(&ht, hi, dw, hash); } flags = 0; @@ -3250,43 +3238,43 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) need_affix = false; if (afflist != NULL) { // Extract flags from the affix list. - flags |= get_affix_flags(affile, afflist); + flags |= get_affix_flags(affile, (char *)afflist); if (affile->af_needaffix != 0 - && flag_in_afflist(affile->af_flagtype, afflist, + && flag_in_afflist(affile->af_flagtype, (char *)afflist, affile->af_needaffix)) { need_affix = true; } if (affile->af_pfxpostpone) { // Need to store the list of prefix IDs with the word. - pfxlen = get_pfxlist(affile, afflist, store_afflist); + pfxlen = get_pfxlist(affile, (char *)afflist, store_afflist); } if (spin->si_compflags != NULL) { // Need to store the list of compound flags with the word. // Concatenate them to the list of prefix IDs. - get_compflags(affile, afflist, store_afflist + pfxlen); + get_compflags(affile, (char *)afflist, store_afflist + pfxlen); } } // Add the word to the word tree(s). if (store_word(spin, dw, flags, spin->si_region, - store_afflist, need_affix) == FAIL) { + (char *)store_afflist, need_affix) == FAIL) { retval = FAIL; } if (afflist != NULL) { // Find all matching suffixes and add the resulting words. // Additionally do matching prefixes that combine. - if (store_aff_word(spin, dw, afflist, affile, + if (store_aff_word(spin, dw, (char *)afflist, affile, &affile->af_suff, &affile->af_pref, CONDIT_SUF, flags, (char *)store_afflist, pfxlen) == FAIL) { retval = FAIL; } // Find all matching prefixes and add the resulting words. - if (store_aff_word(spin, dw, afflist, affile, + if (store_aff_word(spin, dw, (char *)afflist, affile, &affile->af_pref, NULL, CONDIT_SUF, flags, (char *)store_afflist, pfxlen) == FAIL) { retval = FAIL; @@ -3311,7 +3299,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) // Check for affix flags in "afflist" that are turned into word flags. // Return WF_ flags. -static int get_affix_flags(afffile_T *affile, char_u *afflist) +static int get_affix_flags(afffile_T *affile, char *afflist) { int flags = 0; @@ -3350,9 +3338,9 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist) // Used for PFXPOSTPONE. // Put the resulting flags in "store_afflist[MAXWLEN]" with a terminating NUL // and return the number of affixes. -static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist) +static int get_pfxlist(afffile_T *affile, char *afflist, char_u *store_afflist) { - char_u *p; + char *p; char *prevp; int cnt = 0; int id; @@ -3360,11 +3348,11 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist hashitem_T *hi; for (p = afflist; *p != NUL;) { - prevp = (char *)p; + prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a postponed prefix flag if it appears in "af_pref" // and its ID is not zero. - xstrlcpy(key, prevp, (size_t)(p - (char_u *)prevp) + 1); + xstrlcpy(key, prevp, (size_t)(p - prevp) + 1); hi = hash_find(&affile->af_pref, (char *)key); if (!HASHITEM_EMPTY(hi)) { id = HI2AH(hi)->ah_newID; @@ -3385,19 +3373,19 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist // Get the list of compound IDs from the affix list "afflist" that are used // for compound words. // Puts the flags in "store_afflist[]". -static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_afflist) +static void get_compflags(afffile_T *affile, char *afflist, char_u *store_afflist) { - char_u *p; + char *p; char *prevp; int cnt = 0; char key[AH_KEY_LEN]; hashitem_T *hi; for (p = afflist; *p != NUL;) { - prevp = (char *)p; + prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a compound flag if it appears in "af_comp". - xstrlcpy(key, prevp, (size_t)(p - (char_u *)prevp) + 1); + xstrlcpy(key, prevp, (size_t)(p - prevp) + 1); hi = hash_find(&affile->af_comp, (char *)key); if (!HASHITEM_EMPTY(hi)) { store_afflist[cnt++] = (char_u)HI2CI(hi)->ci_newID; @@ -3426,7 +3414,7 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl /// @param pfxlen nr of flags in "pfxlist" for prefixes, rest is compound flags /// /// @return FAIL when out of memory. -static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffile_T *affile, +static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_T *affile, hashtab_T *ht, hashtab_T *xht, int condit, int flags, char *pfxlist, int pfxlen) { @@ -3437,7 +3425,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil char newword[MAXWLEN]; int retval = OK; int i, j; - char_u *p; + char *p; int use_flags; char *use_pfxlist; int use_pfxlen; @@ -3476,7 +3464,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil && (ae->ae_chop == NULL || strlen(ae->ae_chop) < wordlen) && (ae->ae_prog == NULL - || vim_regexec_prog(&ae->ae_prog, false, (char_u *)word, (colnr_T)0)) + || vim_regexec_prog(&ae->ae_prog, false, word, (colnr_T)0)) && (((condit & CONDIT_CFIX) == 0) == ((condit & CONDIT_AFF) == 0 || ae->ae_flags == NULL @@ -3490,7 +3478,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil } else { xstrlcpy(newword, ae->ae_add, MAXWLEN); } - p = (char_u *)word; + p = word; if (ae->ae_chop != NULL) { // Skip chop string. i = mb_charlen(ae->ae_chop); @@ -3504,7 +3492,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil xstrlcpy(newword, word, MAXWLEN); if (ae->ae_chop != NULL) { // Remove chop string. - p = (char_u *)newword + strlen(newword); + p = newword + strlen(newword); i = mb_charlen(ae->ae_chop); for (; i > 0; i--) { MB_PTR_BACK(newword, p); @@ -3525,16 +3513,18 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil // Extract flags from the affix list. use_flags |= get_affix_flags(affile, ae->ae_flags); - if (affile->af_needaffix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags, - affile->af_needaffix)) { + if (affile->af_needaffix != 0 + && flag_in_afflist(affile->af_flagtype, ae->ae_flags, + affile->af_needaffix)) { need_affix = true; } // When there is a CIRCUMFIX flag the other affix // must also have it and we don't add the word // with one affix. - if (affile->af_circumfix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags, - affile->af_circumfix)) { + if (affile->af_circumfix != 0 + && flag_in_afflist(affile->af_flagtype, ae->ae_flags, + affile->af_circumfix)) { use_condit |= CONDIT_CFIX; if ((condit & CONDIT_CFIX) == 0) { need_affix = true; @@ -3545,8 +3535,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil || spin->si_compflags != NULL) { if (affile->af_pfxpostpone) { // Get prefix IDS from the affix list. - use_pfxlen = get_pfxlist(affile, - ae->ae_flags, store_afflist); + use_pfxlen = get_pfxlist(affile, ae->ae_flags, store_afflist); } else { use_pfxlen = 0; } @@ -3624,7 +3613,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil // Store the modified word. if (store_word(spin, newword, use_flags, - spin->si_region, (char_u *)use_pfxlist, + spin->si_region, use_pfxlist, need_affix) == FAIL) { retval = FAIL; } @@ -3669,7 +3658,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char_u *afflist, afffil } // Read a file with a list of words. -static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) +static int spell_read_wordfile(spellinfo_T *spin, char *fname) { FILE *fd; long lnum = 0; @@ -3685,7 +3674,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) int regionmask; // Open the file. - fd = os_fopen((char *)fname, "r"); + fd = os_fopen(fname, "r"); if (fd == NULL) { semsg(_(e_notopen), fname); return FAIL; @@ -3695,7 +3684,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) spell_message(spin, IObuff); // Read all the lines in the file one by one. - while (!vim_fgets((char *)rline, MAXLINELEN, fd) && !got_int) { + while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int) { line_breakcheck(); lnum++; @@ -3866,7 +3855,7 @@ static void *getroom(spellinfo_T *spin, size_t len, bool align) if (bl == NULL || (size_t)bl->sb_used + len > SBLOCKSIZE) { // Allocate a block of memory. It is not freed until much later. - bl = xcalloc(1, (sizeof(sblock_T) + SBLOCKSIZE)); + bl = xcalloc(1, offsetof(sblock_T, sb_data) + SBLOCKSIZE + 1); bl->sb_next = spin->si_blocks; spin->si_blocks = bl; bl->sb_used = 0; @@ -3935,11 +3924,11 @@ static bool valid_spell_word(const char *word, const char *end) /// @param region supported region(s) /// @param pfxlist list of prefix ids or null /// @param need_affix only store word with affix id -static int store_word(spellinfo_T *spin, char *word, int flags, int region, const char_u *pfxlist, +static int store_word(spellinfo_T *spin, char *word, int flags, int region, const char *pfxlist, bool need_affix) { int len = (int)strlen(word); - int ct = captype((char_u *)word, (char_u *)word + len); + int ct = captype(word, word + len); char_u foldword[MAXWLEN]; int res = OK; @@ -3948,8 +3937,8 @@ static int store_word(spellinfo_T *spin, char *word, int flags, int region, cons return FAIL; } - (void)spell_casefold(curwin, (char_u *)word, len, foldword, MAXWLEN); - for (const char_u *p = pfxlist; res == OK; p++) { + (void)spell_casefold(curwin, word, len, (char *)foldword, MAXWLEN); + for (const char_u *p = (char_u *)pfxlist; res == OK; p++) { if (!need_affix || (p != NULL && *p != NUL)) { res = tree_add_word(spin, foldword, spin->si_foldroot, ct | flags, region, p == NULL ? 0 : *p); @@ -3961,7 +3950,7 @@ static int store_word(spellinfo_T *spin, char *word, int flags, int region, cons spin->si_foldwcount++; if (res == OK && (ct == WF_KEEPCAP || (flags & WF_KEEPCAP))) { - for (const char_u *p = pfxlist; res == OK; p++) { + for (const char_u *p = (char_u *)pfxlist; res == OK; p++) { if (!need_affix || (p != NULL && *p != NUL)) { res = tree_add_word(spin, (char_u *)word, spin->si_keeproot, flags, region, p == NULL ? 0 : *p); @@ -4211,31 +4200,33 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root, const char *n // Skip the root itself, it's not actually used. The first sibling is the // start of the tree. - if (root->wn_sibling != NULL) { - hash_init(&ht); - const long n = node_compress(spin, root->wn_sibling, &ht, &tot); + if (root->wn_sibling == NULL) { + return; + } + + hash_init(&ht); + const long n = node_compress(spin, root->wn_sibling, &ht, &tot); #ifndef SPELL_PRINTTREE - if (spin->si_verbose || p_verbose > 2) + if (spin->si_verbose || p_verbose > 2) #endif - { - if (tot > 1000000) { - perc = (tot - n) / (tot / 100); - } else if (tot == 0) { - perc = 0; - } else { - perc = (tot - n) * 100 / tot; - } - vim_snprintf(IObuff, IOSIZE, - _("Compressed %s of %ld nodes; %ld (%ld%%) remaining"), - name, tot, tot - n, perc); - spell_message(spin, IObuff); + { + if (tot > 1000000) { + perc = (tot - n) / (tot / 100); + } else if (tot == 0) { + perc = 0; + } else { + perc = (tot - n) * 100 / tot; } + vim_snprintf(IObuff, IOSIZE, + _("Compressed %s of %ld nodes; %ld (%ld%%) remaining"), + name, tot, tot - n, perc); + spell_message(spin, IObuff); + } #ifdef SPELL_PRINTTREE - spell_print_tree(root->wn_sibling); + spell_print_tree(root->wn_sibling); #endif - hash_clear(&ht); - } + hash_clear(&ht); } /// Compress a node, its siblings and its children, depth first. @@ -4265,7 +4256,7 @@ static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, lo compressed += node_compress(spin, child, ht, tot); // Try to find an identical child. - hash = hash_hash(child->wn_u1.hashkey); + hash = hash_hash((char *)child->wn_u1.hashkey); hi = hash_lookup(ht, (const char *)child->wn_u1.hashkey, strlen((char *)child->wn_u1.hashkey), hash); if (!HASHITEM_EMPTY(hi)) { @@ -4294,7 +4285,7 @@ static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, lo } else { // No other child has this hash value, add it to the // hashtable. - hash_add_item(ht, hi, child->wn_u1.hashkey, hash); + hash_add_item(ht, hi, (char *)child->wn_u1.hashkey, hash); } } } @@ -4901,10 +4892,12 @@ void ex_mkspell(exarg_T *eap) } // Expand all the remaining arguments (e.g., $VIMRUNTIME). - if (get_arglist_exp(arg, &fcount, &fnames, false) == OK) { - mkspell(fcount, fnames, ascii, eap->forceit, false); - FreeWild(fcount, fnames); + if (get_arglist_exp(arg, &fcount, &fnames, false) != OK) { + return; } + + mkspell(fcount, fnames, ascii, eap->forceit, false); + FreeWild(fcount, fnames); } // Create the .sug file. @@ -4974,7 +4967,7 @@ static void spell_make_sugfile(spellinfo_T *spin, char *wfname) len = (int)strlen(fname); fname[len - 2] = 'u'; fname[len - 1] = 'g'; - sug_write(spin, (char_u *)fname); + sug_write(spin, fname); theend: xfree(fname); @@ -5008,7 +5001,7 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang) // Go through the whole case-folded tree, soundfold each word and put it // in the trie. - byts = slang->sl_fbyts; + byts = (char_u *)slang->sl_fbyts; idxs = slang->sl_fidxs; arridx[0] = 0; @@ -5199,10 +5192,10 @@ static int offset2bytes(int nr, char_u *buf) } // Write the .sug file in "fname". -static void sug_write(spellinfo_T *spin, char_u *fname) +static void sug_write(spellinfo_T *spin, char *fname) { // Create the file. Note that an existing file is silently overwritten! - FILE *fd = os_fopen((char *)fname, "w"); + FILE *fd = os_fopen(fname, "w"); if (fd == NULL) { semsg(_(e_notopen), fname); return; @@ -5284,7 +5277,7 @@ theend: /// @param added_word invoked through "zg" static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool added_word) { - char_u *fname = NULL; + char *fname = NULL; char **innames; int incount; afffile_T *(afile[MAXREGIONS]); @@ -5301,9 +5294,9 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool ga_init(&spin.si_rep, (int)sizeof(fromto_T), 20); ga_init(&spin.si_repsal, (int)sizeof(fromto_T), 20); ga_init(&spin.si_sal, (int)sizeof(fromto_T), 20); - ga_init(&spin.si_map, (int)sizeof(char_u), 100); - ga_init(&spin.si_comppat, (int)sizeof(char_u *), 20); - ga_init(&spin.si_prefcond, (int)sizeof(char_u *), 50); + ga_init(&spin.si_map, (int)sizeof(char), 100); + ga_init(&spin.si_comppat, (int)sizeof(char *), 20); + ga_init(&spin.si_prefcond, (int)sizeof(char *), 50); hash_init(&spin.si_commonwords); spin.si_newcompID = 127; // start compound ID at first maximum @@ -5325,14 +5318,14 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool // For ":mkspell path/vim" output file is "path/vim.latin1.spl". incount = 1; vim_snprintf(wfname, MAXPATHL, SPL_FNAME_TMPL, - fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc()); + fnames[0], spin.si_ascii ? "ascii" : spell_enc()); } else if (len > 4 && strcmp(fnames[0] + len - 4, ".spl") == 0) { // Name ends in ".spl", use as the file name. xstrlcpy(wfname, fnames[0], MAXPATHL); } else { // Name should be language, make the file name from it. vim_snprintf(wfname, MAXPATHL, SPL_FNAME_TMPL, - fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc()); + fnames[0], spin.si_ascii ? "ascii" : spell_enc()); } // Check for .ascii.spl. @@ -5404,8 +5397,8 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool 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((char *)fname)) { + vim_snprintf(fname, MAXPATHL, "%s.aff", innames[i]); + if (os_path_exists(fname)) { // Read the .aff file. Will init "spin->si_conv" based on the // "SET" line. afile[i] = spell_read_aff(&spin, fname); @@ -5413,8 +5406,7 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool error = true; } else { // Read the .dic file and store the words in the trees. - vim_snprintf((char *)fname, MAXPATHL, "%s.dic", - innames[i]); + vim_snprintf(fname, MAXPATHL, "%s.dic", innames[i]); if (spell_read_dic(&spin, fname, afile[i]) == FAIL) { error = true; } @@ -5422,7 +5414,7 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool } else { // No .aff file, try reading the file as a word list. Store // the words in the trees. - if (spell_read_wordfile(&spin, (char_u *)innames[i]) == FAIL) { + if (spell_read_wordfile(&spin, innames[i]) == FAIL) { error = true; } } @@ -5458,7 +5450,7 @@ static void mkspell(int fcount, char **fnames, bool ascii, bool over_write, bool // If the file is loaded need to reload it. if (!error) { - spell_reload_one((char_u *)wfname, added_word); + spell_reload_one(wfname, added_word); } } @@ -5534,11 +5526,11 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) buf_T *buf = NULL; bool new_spf = false; char *fname; - char_u *fnamebuf = NULL; + char *fnamebuf = NULL; char line[MAXWLEN * 2]; long fpos, fpos_next = 0; int i; - char_u *spf; + char *spf; if (!valid_spell_word(word, word + len)) { emsg(_(e_illegal_character_in_word)); @@ -5547,12 +5539,12 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) if (idx == 0) { // use internal wordlist if (int_wordlist == NULL) { - int_wordlist = (char_u *)vim_tempname(); + int_wordlist = vim_tempname(); if (int_wordlist == NULL) { return; } } - fname = (char *)int_wordlist; + fname = int_wordlist; } else { // If 'spellfile' isn't set figure out a good default value. if (*curwin->w_s->b_p_spf == NUL) { @@ -5566,8 +5558,8 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) } fnamebuf = xmalloc(MAXPATHL); - for (spf = (char_u *)curwin->w_s->b_p_spf, i = 1; *spf != NUL; i++) { - copy_option_part((char **)&spf, (char *)fnamebuf, MAXPATHL, ","); + for (spf = curwin->w_s->b_p_spf, i = 1; *spf != NUL; i++) { + copy_option_part(&spf, fnamebuf, MAXPATHL, ","); if (i == idx) { break; } @@ -5579,7 +5571,7 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) } // Check that the user isn't editing the .add file somewhere. - buf = buflist_findname_exp((char *)fnamebuf); + buf = buflist_findname_exp(fnamebuf); if (buf != NULL && buf->b_ml.ml_mfp == NULL) { buf = NULL; } @@ -5589,7 +5581,7 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) return; } - fname = (char *)fnamebuf; + fname = fnamebuf; } if (what == SPELL_ADD_BAD || undo) { @@ -5690,82 +5682,84 @@ static void init_spellfile(void) { char *buf; int l; - char_u *fname; - char_u *rtp; - char_u *lend; + char *fname; + char *rtp; + char *lend; bool aspath = false; - 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 = (char_u *)curwin->w_s->b_p_spl; *lend != NUL - && vim_strchr(",._", *lend) == NULL; lend++) { - if (vim_ispathsep(*lend)) { - aspath = true; - lstart = lend + 1; - } + char *lstart = curbuf->b_s.b_p_spl; + + if (*curwin->w_s->b_p_spl == NUL || GA_EMPTY(&curwin->w_s->b_langp)) { + return; + } + + 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 + && vim_strchr(",._", (uint8_t)(*lend)) == NULL; lend++) { + if (vim_ispathsep(*lend)) { + aspath = true; + lstart = lend + 1; } + } - // Loop over all entries in 'runtimepath'. Use the first one where we - // are allowed to write. - rtp = (char_u *)p_rtp; - while (*rtp != NUL) { + // Loop over all entries in 'runtimepath'. Use the first one where we + // are allowed to write. + rtp = p_rtp; + while (*rtp != NUL) { + if (aspath) { + // Use directory of an entry with path, e.g., for + // "/dir/lg.utf-8.spl" use "/dir". + xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lstart - curbuf->b_s.b_p_spl)); + } else { + // Copy the path from 'runtimepath' to buf[]. + copy_option_part(&rtp, buf, MAXPATHL, ","); + } + if (os_file_is_writable(buf) == 2) { + // Use the first language name from 'spelllang' and the + // encoding used in the first loaded .spl file. if (aspath) { - // Use directory of an entry with path, e.g., for - // "/dir/lg.utf-8.spl" use "/dir". - xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lstart - (char_u *)curbuf->b_s.b_p_spl)); + xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl + 1)); } else { - // Copy the path from 'runtimepath' to buf[]. - copy_option_part((char **)&rtp, buf, MAXPATHL, ","); - } - if (os_file_is_writable(buf) == 2) { - // Use the first language name from 'spelllang' and the - // encoding used in the first loaded .spl file. - if (aspath) { - xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(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); - vim_snprintf(buf + l, MAXPATHL - (size_t)l, "/spell"); - if (os_file_is_writable(buf) != 2) { - os_mkdir(buf, 0755); - } - - l = (int)strlen(buf); - vim_snprintf(buf + l, MAXPATHL - (size_t)l, - "/%.*s", (int)(lend - lstart), lstart); + // Create the "spell" directory if it doesn't exist yet. + l = (int)strlen(buf); + vim_snprintf(buf + l, MAXPATHL - (size_t)l, "/spell"); + if (os_file_is_writable(buf) != 2) { + os_mkdir(buf, 0755); } + l = (int)strlen(buf); - fname = (char_u *)LANGP_ENTRY(curwin->w_s->b_langp, 0) - ->lp_slang->sl_fname; - vim_snprintf(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_give_err("spellfile", 0L, (const char *)buf, OPT_LOCAL); - break; + vim_snprintf(buf + l, MAXPATHL - (size_t)l, + "/%.*s", (int)(lend - lstart), lstart); } - aspath = false; + l = (int)strlen(buf); + fname = LANGP_ENTRY(curwin->w_s->b_langp, 0) + ->lp_slang->sl_fname; + vim_snprintf(buf + l, MAXPATHL - (size_t)l, ".%s.add", + ((fname != NULL + && strstr(path_tail(fname), ".ascii.") != NULL) + ? "ascii" + : (const char *)spell_enc())); + set_option_value_give_err("spellfile", 0L, buf, OPT_LOCAL); + break; } - - xfree(buf); + aspath = false; } + + xfree(buf); } /// Set the spell character tables from strings in the .spl file. /// /// @param cnt length of "flags" -static void set_spell_charflags(const char_u *flags, int cnt, char_u *fol) +static void set_spell_charflags(const char_u *flags, int cnt, char *fol) { // We build the new tables here first, so that we can compare with the // previous one. spelltab_T new_st; int i; - char_u *p = fol; + char *p = fol; int c; clear_spell_chartab(&new_st); @@ -5777,7 +5771,7 @@ static void set_spell_charflags(const char_u *flags, int cnt, char_u *fol) } if (*p != NUL) { - c = mb_ptr2char_adv((const char_u **)&p); + c = mb_ptr2char_adv((const char **)&p); new_st.st_fold[i + 128] = (char_u)c; if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) { new_st.st_upper[c] = (char_u)(i + 128); @@ -5843,9 +5837,9 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap, size_t *fwv) } // Use map string "map" for languages "lp". -static void set_map_str(slang_T *lp, char_u *map) +static void set_map_str(slang_T *lp, char *map) { - char_u *p; + char *p; int headc = 0; int c; int i; @@ -5866,7 +5860,7 @@ static void set_map_str(slang_T *lp, char_u *map) // "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and // before the same slash. For characters above 255 sl_map_hash is used. for (p = map; *p != NUL;) { - c = mb_cptr2char_adv((const char_u **)&p); + c = mb_cptr2char_adv((const char **)&p); if (c == '/') { headc = 0; } else { @@ -5888,10 +5882,10 @@ static void set_map_str(slang_T *lp, char_u *map) b[cl] = NUL; utf_char2bytes(headc, b + cl + 1); b[cl + 1 + headcl] = NUL; - hash = hash_hash((char_u *)b); + hash = hash_hash(b); 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); + hash_add_item(&lp->sl_map_hash, hi, b, hash); } else { // This should have been checked when generating the .spl // file. diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index aef26ef288..54b6f552b5 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -276,26 +276,27 @@ static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool spl int newscore; hashitem_T *hi = hash_find(&slang->sl_wordcount, (char *)word); - if (!HASHITEM_EMPTY(hi)) { - wc = HI2WC(hi); - if (wc->wc_count < SCORE_THRES2) { - bonus = SCORE_COMMON1; - } else if (wc->wc_count < SCORE_THRES3) { - bonus = SCORE_COMMON2; - } else { - bonus = SCORE_COMMON3; - } - if (split) { - newscore = score - bonus / 2; - } else { - newscore = score - bonus; - } - if (newscore < 0) { - return 0; - } - return newscore; + if (HASHITEM_EMPTY(hi)) { + return score; + } + + wc = HI2WC(hi); + if (wc->wc_count < SCORE_THRES2) { + bonus = SCORE_COMMON1; + } else if (wc->wc_count < SCORE_THRES3) { + bonus = SCORE_COMMON2; + } else { + bonus = SCORE_COMMON3; } - return score; + if (split) { + newscore = score - bonus / 2; + } else { + newscore = score - bonus; + } + if (newscore < 0) { + return 0; + } + return newscore; } /// Like captype() but for a KEEPCAP word add ONECAP if the word starts with a @@ -304,42 +305,45 @@ static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool spl static int badword_captype(char_u *word, char_u *end) FUNC_ATTR_NONNULL_ALL { - int flags = captype(word, end); + int flags = captype((char *)word, (char *)end); int c; int l, u; bool first; char_u *p; - if (flags & WF_KEEPCAP) { - // Count the number of UPPER and lower case letters. - l = u = 0; - first = false; - for (p = word; p < end; MB_PTR_ADV(p)) { - c = utf_ptr2char((char *)p); - if (SPELL_ISUPPER(c)) { - u++; - if (p == word) { - first = true; - } - } else { - l++; + if (!(flags & WF_KEEPCAP)) { + return flags; + } + + // Count the number of UPPER and lower case letters. + l = u = 0; + first = false; + for (p = word; p < end; MB_PTR_ADV(p)) { + c = utf_ptr2char((char *)p); + if (SPELL_ISUPPER(c)) { + u++; + if (p == word) { + first = true; } + } else { + l++; } + } - // If there are more UPPER than lower case letters suggest an - // ALLCAP word. Otherwise, if the first letter is UPPER then - // suggest ONECAP. Exception: "ALl" most likely should be "All", - // require three upper case letters. - if (u > l && u > 2) { - flags |= WF_ALLCAP; - } else if (first) { - flags |= WF_ONECAP; - } + // If there are more UPPER than lower case letters suggest an + // ALLCAP word. Otherwise, if the first letter is UPPER then + // suggest ONECAP. Exception: "ALl" most likely should be "All", + // require three upper case letters. + if (u > l && u > 2) { + flags |= WF_ALLCAP; + } else if (first) { + flags |= WF_ONECAP; + } - if (u >= 2 && l >= 2) { // maCARONI maCAroni - flags |= WF_MIXCAP; - } + if (u >= 2 && l >= 2) { // maCARONI maCAroni + flags |= WF_MIXCAP; } + return flags; } @@ -483,6 +487,11 @@ void spell_suggest(int count) } badlen++; end_visual_mode(); + // make sure we don't include the NUL at the end of the line + line = get_cursor_line_ptr(); + if (badlen > (int)strlen(line) - (int)curwin->w_cursor.col) { + badlen = (int)strlen(line) - (int)curwin->w_cursor.col; + } // Find the start of the badly spelled word. } else if (spell_move_to(curwin, FORWARD, true, true, NULL) == 0 || curwin->w_cursor.col > prev_cursor.col) { @@ -492,15 +501,15 @@ void spell_suggest(int count) line = get_cursor_line_ptr(); p = (char_u *)line + curwin->w_cursor.col; // Backup to before start of word. - while (p > (char_u *)line && spell_iswordp_nmw(p, curwin)) { + while (p > (char_u *)line && spell_iswordp_nmw((char *)p, curwin)) { MB_PTR_BACK(line, p); } // Forward to start of word. - while (*p != NUL && !spell_iswordp_nmw(p, curwin)) { + while (*p != NUL && !spell_iswordp_nmw((char *)p, curwin)) { MB_PTR_ADV(p); } - if (!spell_iswordp_nmw(p, curwin)) { // No word found. + if (!spell_iswordp_nmw((char *)p, curwin)) { // No word found. beep_flush(); return; } @@ -673,13 +682,13 @@ void spell_suggest(int count) /// /// @param maxcount maximum nr of suggestions /// @param need_cap 'spellcapcheck' matched -void spell_suggest_list(garray_T *gap, char_u *word, int maxcount, bool need_cap, bool interactive) +void spell_suggest_list(garray_T *gap, char *word, int maxcount, bool need_cap, bool interactive) { suginfo_T sug; suggest_T *stp; char_u *wcopy; - spell_find_suggest(word, 0, &sug, maxcount, false, need_cap, interactive); + spell_find_suggest((char_u *)word, 0, &sug, maxcount, false, need_cap, interactive); // Make room in "gap". ga_init(gap, sizeof(char_u *), sug.su_ga.ga_len + 1); @@ -733,7 +742,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma if (badlen != 0) { su->su_badlen = badlen; } else { - size_t tmplen = spell_check(curwin, (char_u *)su->su_badptr, &attr, NULL, false); + size_t tmplen = spell_check(curwin, su->su_badptr, &attr, NULL, false); assert(tmplen <= INT_MAX); su->su_badlen = (int)tmplen; } @@ -744,7 +753,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma su->su_badlen = MAXWLEN - 1; // just in case } xstrlcpy((char *)su->su_badword, su->su_badptr, (size_t)su->su_badlen + 1); - (void)spell_casefold(curwin, (char_u *)su->su_badptr, su->su_badlen, (char_u *)su->su_fbadword, + (void)spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); // TODO(vim): make this work if the case-folded text is longer than the @@ -783,7 +792,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma // for that. c = utf_ptr2char(su->su_badptr); if (!SPELL_ISUPPER(c) && attr == HLF_COUNT) { - make_case_word((char_u *)su->su_badword, (char_u *)buf, WF_ONECAP); + make_case_word((char *)su->su_badword, buf, WF_ONECAP); add_suggestion(su, &su->su_ga, (char *)buf, su->su_badlen, SCORE_ICASE, 0, true, su->su_sallang, false); } @@ -895,8 +904,8 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname) // If the suggestion doesn't have specific case duplicate the case // of the bad word. - if (captype(p, NULL) == 0) { - make_case_word(p, cword, su->su_badflags); + if (captype((char *)p, NULL) == 0) { + make_case_word((char *)p, (char *)cword, su->su_badflags); p = cword; } @@ -1016,7 +1025,7 @@ static void suggest_try_special(suginfo_T *su) // use that for the goodword too: "The the" -> "The". c = su->su_fbadword[len]; su->su_fbadword[len] = NUL; - make_case_word((char_u *)su->su_fbadword, word, su->su_badflags); + make_case_word(su->su_fbadword, (char *)word, su->su_badflags); su->su_fbadword[len] = c; // Give a soundalike score of 0, compute the score as if deleting one @@ -1085,7 +1094,7 @@ static void suggest_try_change(suginfo_T *su) STRCPY(fword, su->su_fbadword); n = (int)strlen(fword); p = su->su_badptr + su->su_badlen; - (void)spell_casefold(curwin, (char_u *)p, (int)strlen(p), (char_u *)fword + n, MAXWLEN - n); + (void)spell_casefold(curwin, p, (int)strlen(p), fword + n, MAXWLEN - n); // Make sure the resulting text is not longer than the original text. n = (int)strlen(su->su_badptr); @@ -1193,7 +1202,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun if (soundfold) { // Going through the soundfold tree. - byts = fbyts = slang->sl_sbyts; + byts = fbyts = (char_u *)slang->sl_sbyts; idxs = fidxs = slang->sl_sidxs; pbyts = NULL; pidxs = NULL; @@ -1202,9 +1211,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun } else { // When there are postponed prefixes we need to use these first. At // the end of the prefix we continue in the case-fold tree. - fbyts = slang->sl_fbyts; + fbyts = (char_u *)slang->sl_fbyts; fidxs = slang->sl_fidxs; - pbyts = slang->sl_pbyts; + pbyts = (char_u *)slang->sl_pbyts; pidxs = slang->sl_pidxs; if (pbyts != NULL) { byts = pbyts; @@ -1258,7 +1267,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun if (depth < MAXWLEN - 1 && (byts[arridx] == 0 || n == STATE_NOPREFIX)) { // Set su->su_badflags to the caps type at this position. // Use the caps type until here for the prefix itself. - n = nofold_len((char_u *)fword, sp->ts_fidx, (char_u *)su->su_badptr); + n = nofold_len(fword, sp->ts_fidx, su->su_badptr); flags = badword_captype((char_u *)su->su_badptr, (char_u *)su->su_badptr + n); su->su_badflags = badword_captype((char_u *)su->su_badptr + n, (char_u *)su->su_badptr + su->su_badlen); @@ -1276,8 +1285,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Move the prefix to preword[] with the right case // and make find_keepcap_word() works. tword[sp->ts_twordlen] = NUL; - make_case_word((char_u *)tword + sp->ts_splitoff, - (char_u *)preword + sp->ts_prewordlen, flags); + make_case_word(tword + sp->ts_splitoff, + preword + sp->ts_prewordlen, flags); sp->ts_prewordlen = (char_u)strlen(preword); sp->ts_splitoff = sp->ts_twordlen; } @@ -1305,7 +1314,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun fword_ends = (fword[sp->ts_fidx] == NUL || (soundfold ? ascii_iswhite(fword[sp->ts_fidx]) - : !spell_iswordp((char_u *)fword + sp->ts_fidx, curwin))); + : !spell_iswordp(fword + sp->ts_fidx, curwin))); tword[sp->ts_twordlen] = NUL; if (sp->ts_prefixdepth <= PFD_NOTSPECIAL @@ -1320,7 +1329,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun for (c = 0; c < len && pbyts[n + c] == 0; c++) {} if (c > 0) { c = valid_word_prefix(c, n, flags, - (char_u *)tword + sp->ts_splitoff, slang, false); + tword + sp->ts_splitoff, slang, false); if (c == 0) { break; } @@ -1359,7 +1368,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun == sp->ts_twordlen - sp->ts_splitoff && strncmp(fword + sp->ts_splitfidx, tword + sp->ts_splitoff, - sp->ts_fidx - sp->ts_splitfidx) == 0) { + (size_t)(sp->ts_fidx - sp->ts_splitfidx)) == 0) { preword[sp->ts_prewordlen] = NUL; newscore = score_wordcount_adj(slang, sp->ts_score, (char_u *)preword + sp->ts_prewordlen, @@ -1441,11 +1450,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // When appending a compound word after a word character don't // use Onecap. - if (p != NULL && spell_iswordp_nmw((char_u *)p, curwin)) { + if (p != NULL && spell_iswordp_nmw(p, curwin)) { c &= ~WF_ONECAP; } - make_case_word((char_u *)tword + sp->ts_splitoff, - (char_u *)preword + sp->ts_prewordlen, c); + make_case_word(tword + sp->ts_splitoff, + preword + sp->ts_prewordlen, c); } if (!soundfold) { @@ -1477,7 +1486,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun } if (!spell_valid_case(su->su_badflags, - captype((char_u *)preword + sp->ts_prewordlen, NULL))) { + captype(preword + sp->ts_prewordlen, NULL))) { newscore += SCORE_ICASE; } } @@ -1508,10 +1517,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // char, e.g., "thes," -> "these". p = fword + sp->ts_fidx; MB_PTR_BACK(fword, p); - if (!spell_iswordp((char_u *)p, curwin) && *preword != NUL) { + if (!spell_iswordp(p, curwin) && *preword != NUL) { p = preword + strlen(preword); MB_PTR_BACK(preword, p); - if (spell_iswordp((char_u *)p, curwin)) { + if (spell_iswordp(p, curwin)) { newscore += SCORE_NONWORD; } } @@ -1531,10 +1540,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun if (su->su_badflags & WF_MIXCAP) { // We really don't know if the word should be // upper or lower case, add both. - c = captype((char_u *)preword, NULL); + c = captype(preword, NULL); if (c == 0 || c == WF_ALLCAP) { - make_case_word((char_u *)tword + sp->ts_splitoff, - (char_u *)preword + sp->ts_prewordlen, + make_case_word(tword + sp->ts_splitoff, + preword + sp->ts_prewordlen, c == 0 ? WF_ALLCAP : 0); add_suggestion(su, &su->su_ga, (char *)preword, @@ -1673,7 +1682,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // non-word character with a space. Always skip a // character when the word ends. But only when the // good word can end. - if (((!try_compound && !spell_iswordp_nmw((char_u *)fword + if (((!try_compound && !spell_iswordp_nmw(fword + sp->ts_fidx, curwin)) || fword_ends) @@ -1705,7 +1714,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // set su->su_badflags to the caps type at this // position - n = nofold_len((char_u *)fword, sp->ts_fidx, (char_u *)su->su_badptr); + n = nofold_len(fword, sp->ts_fidx, su->su_badptr); su->su_badflags = badword_captype((char_u *)su->su_badptr + n, (char_u *)su->su_badptr + su->su_badlen); @@ -2029,7 +2038,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Don't swap if the first character is not a word character. // SWAP3 etc. also don't make sense then. - if (!soundfold && !spell_iswordp((char_u *)p, curwin)) { + if (!soundfold && !spell_iswordp(p, curwin)) { PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; @@ -2039,7 +2048,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun c = utf_ptr2char(p); if (p[n] == NUL) { c2 = NUL; - } else if (!soundfold && !spell_iswordp((char_u *)p + n, curwin)) { + } else if (!soundfold && !spell_iswordp(p + n, curwin)) { c2 = c; // don't swap non-word char } else { c2 = utf_ptr2char(p + n); @@ -2099,7 +2108,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun c = utf_ptr2char(p); fl = utf_ptr2len(p + n); c2 = utf_ptr2char(p + n); - if (!soundfold && !spell_iswordp((char_u *)p + n + fl, curwin)) { + if (!soundfold && !spell_iswordp(p + n + fl, curwin)) { c3 = c; // don't swap non-word char } else { c3 = utf_ptr2char(p + n + fl); @@ -2150,7 +2159,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun utf_char2bytes(c2, p + tl); p = p + tl; - if (!soundfold && !spell_iswordp((char_u *)p, curwin)) { + if (!soundfold && !spell_iswordp(p, curwin)) { // Middle char is not a word char, skip the rotate. First and // third char were already checked at swap and swap3. PROF_STORE(sp->ts_state) @@ -2394,7 +2403,7 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) int c; idx_T lo, hi, m; char_u *p; - char_u *byts = slang->sl_kbyts; // array with bytes of the words + char_u *byts = (char_u *)slang->sl_kbyts; // array with bytes of the words idx_T *idxs = slang->sl_kidxs; // array with indexes if (byts == NULL) { @@ -2404,7 +2413,7 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) } // Make an all-cap version of "fword". - allcap_copy((char_u *)fword, (char_u *)uword); + allcap_copy(fword, uword); // Each character needs to be tried both case-folded and upper-case. // All this gets very complicated if we keep in mind that changing case @@ -2661,7 +2670,7 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * pbad = badsound; } else { // soundfold the bad word with more characters following - (void)spell_casefold(curwin, (char_u *)su->su_badptr, stp->st_orglen, fword, MAXWLEN); + (void)spell_casefold(curwin, su->su_badptr, stp->st_orglen, (char *)fword, MAXWLEN); // When joining two words the sound often changes a lot. E.g., "t he" // sounds like "t h" while "the" sounds like "@". Avoid that by @@ -2814,15 +2823,15 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T // times with different scores. Since the following is quite slow only do // the words that have a better score than before. Use a hashtable to // remember the words that have been done. - hash = hash_hash((char_u *)goodword); + hash = hash_hash(goodword); const size_t goodword_len = strlen(goodword); hi = hash_lookup(&slang->sl_sounddone, (const char *)goodword, goodword_len, hash); if (HASHITEM_EMPTY(hi)) { - sft = xmalloc(sizeof(sftword_T) + goodword_len); + sft = xmalloc(offsetof(sftword_T, sft_word) + goodword_len + 1); sft->sft_score = (int16_t)score; memcpy(sft->sft_word, goodword, goodword_len + 1); - hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash); + hash_add_item(&slang->sl_sounddone, hi, (char *)sft->sft_word, hash); } else { sft = HI2SFT(hi); if (score >= sft->sft_score) { @@ -2846,7 +2855,7 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T // previous wordnr. orgnr += bytes2offset(&nrline); - byts = slang->sl_fbyts; + byts = (char_u *)slang->sl_fbyts; idxs = slang->sl_fidxs; // Lookup the word "orgnr" one of the two tries. @@ -2904,7 +2913,7 @@ badword: flags |= su->su_badflags; if ((flags & WF_CAPMASK) != 0) { // Need to fix case according to "flags". - make_case_word(theword, cword, flags); + make_case_word((char *)theword, (char *)cword, flags); p = cword; } else { p = theword; @@ -2984,7 +2993,7 @@ static int soundfold_find(slang_T *slang, char_u *word) idx_T *idxs; int wordnr = 0; - byts = slang->sl_sbyts; + byts = (char_u *)slang->sl_sbyts; idxs = slang->sl_sidxs; for (;;) { @@ -3220,7 +3229,7 @@ static void check_suggestions(suginfo_T *su, garray_T *gap) xstrlcpy(longword + len, su->su_badptr + stp[i].st_orglen, (size_t)(MAXWLEN - len + 1)); attr = HLF_COUNT; - (void)spell_check(curwin, (char_u *)longword, &attr, NULL, false); + (void)spell_check(curwin, longword, &attr, NULL, false); if (attr != HLF_COUNT) { // Remove this entry. xfree(stp[i].st_word); @@ -3239,13 +3248,14 @@ static void add_banned(suginfo_T *su, char *word) hash_T hash; hashitem_T *hi; - hash = hash_hash((char_u *)word); + hash = hash_hash(word); const size_t word_len = strlen(word); hi = hash_lookup(&su->su_banned, word, word_len, hash); - if (HASHITEM_EMPTY(hi)) { - s = xmemdupz(word, word_len); - hash_add_item(&su->su_banned, hi, s, hash); + if (!HASHITEM_EMPTY(hi)) { // already present + return; } + s = xmemdupz(word, word_len); + hash_add_item(&su->su_banned, hi, (char *)s, hash); } /// Recompute the score for all suggestions if sound-folding is possible. This @@ -3312,21 +3322,23 @@ static int sug_compare(const void *s1, const void *s2) static int cleanup_suggestions(garray_T *gap, int maxscore, int keep) FUNC_ATTR_NONNULL_ALL { - if (gap->ga_len > 0) { - // Sort the list. - qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); + if (gap->ga_len <= 0) { + return maxscore; + } - // Truncate the list to the number of suggestions that will be displayed. - if (gap->ga_len > keep) { - suggest_T *const stp = &SUG(*gap, 0); + // Sort the list. + qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); - for (int i = keep; i < gap->ga_len; i++) { - xfree(stp[i].st_word); - } - gap->ga_len = keep; - if (keep >= 1) { - return stp[keep - 1].st_score; - } + // Truncate the list to the number of suggestions that will be displayed. + if (gap->ga_len > keep) { + suggest_T *const stp = &SUG(*gap, 0); + + for (int i = keep; i < gap->ga_len; i++) { + xfree(stp[i].st_word); + } + gap->ga_len = keep; + if (keep >= 1) { + return stp[keep - 1].st_score; } } return maxscore; @@ -3580,12 +3592,12 @@ static int spell_edit_score(slang_T *slang, const char_u *badword, const char_u // Get the characters from the multi-byte strings and put them in an // int array for easy access. badlen = 0; - for (const char_u *p = badword; *p != NUL;) { + for (const char *p = (char *)badword; *p != NUL;) { wbadword[badlen++] = mb_cptr2char_adv(&p); } wbadword[badlen++] = 0; goodlen = 0; - for (const char_u *p = goodword; *p != NUL;) { + for (const char *p = (char *)goodword; *p != NUL;) { wgoodword[goodlen++] = mb_cptr2char_adv(&p); } wgoodword[goodlen++] = 0; @@ -3686,12 +3698,12 @@ static int spell_edit_score_limit_w(slang_T *slang, const char_u *badword, const // Get the characters from the multi-byte strings and put them in an // int array for easy access. bi = 0; - for (const char_u *p = badword; *p != NUL;) { + for (const char *p = (char *)badword; *p != NUL;) { wbadword[bi++] = mb_cptr2char_adv(&p); } wbadword[bi++] = 0; gi = 0; - for (const char_u *p = goodword; *p != NUL;) { + for (const char *p = (char *)goodword; *p != NUL;) { wgoodword[gi++] = mb_cptr2char_adv(&p); } wgoodword[gi++] = 0; diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index db3e3f91bf..6ad1f31143 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -31,12 +31,14 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/move.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/optionstr.h" #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/pos.h" #include "nvim/screen.h" +#include "nvim/sign_defs.h" #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/types.h" @@ -229,8 +231,12 @@ void stl_fill_click_defs(StlClickDefinition *click_defs, StlClickRecord *click_r }; for (int i = 0; click_recs[i].start != NULL; i++) { len += vim_strnsize(buf, (int)(click_recs[i].start - buf)); - while (col < len) { - click_defs[col++] = cur_click_def; + if (col < len) { + while (col < len) { + click_defs[col++] = cur_click_def; + } + } else { + xfree(cur_click_def.func); } buf = (char *)click_recs[i].start; cur_click_def = click_recs[i].def; @@ -240,8 +246,12 @@ void stl_fill_click_defs(StlClickDefinition *click_defs, StlClickRecord *click_r cur_click_def.type = kStlClickDisabled; } } - while (col < width) { - click_defs[col++] = cur_click_def; + if (col < width) { + while (col < width) { + click_defs[col++] = cur_click_def; + } + } else { + xfree(cur_click_def.func); } } @@ -713,7 +723,7 @@ void draw_tabline(void) int len; int attr_nosel = HL_ATTR(HLF_TP); int attr_fill = HL_ATTR(HLF_TPF); - char_u *p; + char *p; int room; int use_sep_chars = (t_colors < 8); @@ -731,6 +741,10 @@ void draw_tabline(void) return; } + // Clear tab_page_click_defs: Clicking outside of tabs has no effect. + assert(tab_page_click_defs_size >= (size_t)Columns); + stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size); + // Use the 'tabline' option if it's set. if (*p_tal != NUL) { win_redr_custom(NULL, false, false); @@ -809,16 +823,16 @@ void draw_tabline(void) get_trans_bufname(cwp->w_buffer); shorten_dir(NameBuff); len = vim_strsize(NameBuff); - p = (char_u *)NameBuff; + p = NameBuff; while (len > room) { - len -= ptr2cells((char *)p); + len -= ptr2cells(p); MB_PTR_ADV(p); } if (len > Columns - col - 1) { len = Columns - col - 1; } - grid_puts_len(&default_grid, (char *)p, (int)strlen((char *)p), 0, col, attr); + grid_puts_len(&default_grid, p, (int)strlen(p), 0, col, attr); col += len; } grid_putchar(&default_grid, ' ', 0, col++, attr); @@ -868,29 +882,30 @@ void draw_tabline(void) redraw_tabline = false; } -/// Build the 'statuscolumn' string for line "lnum". If "setnum" is true, -/// update the "lnum" and "relnum" vim-variables for a new line. +/// Build the 'statuscolumn' string for line "lnum". When "relnum" == -1, +/// the v:lnum and v:relnum variables don't have to be updated. /// /// @param hlrec HL attributes (can be NULL) /// @param stcp Status column attributes (can be NULL) /// @return The width of the built status column string for line "lnum" -int build_statuscol_str(win_T *wp, bool setnum, bool wrap, linenr_T lnum, long relnum, int maxwidth, - int fillchar, char *buf, stl_hlrec_t **hlrec, statuscol_T *stcp) +int build_statuscol_str(win_T *wp, linenr_T lnum, long relnum, int maxwidth, int fillchar, + char *buf, stl_hlrec_t **hlrec, statuscol_T *stcp) { - if (setnum) { + bool fillclick = relnum >= 0 && lnum == wp->w_topline; + + if (relnum >= 0) { set_vim_var_nr(VV_LNUM, lnum); set_vim_var_nr(VV_RELNUM, relnum); } - set_vim_var_bool(VV_WRAP, wrap); StlClickRecord *clickrec; char *stc = xstrdup(wp->w_p_stc); - int width = build_stl_str_hl(wp, buf, MAXPATHL, stc, "statuscolumn", OPT_LOCAL, - fillchar, maxwidth, hlrec, &clickrec, stcp); + int width = build_stl_str_hl(wp, buf, MAXPATHL, stc, "statuscolumn", OPT_LOCAL, fillchar, + maxwidth, hlrec, fillclick ? &clickrec : NULL, stcp); xfree(stc); - // Allocate and fill click def array if width has changed - if (wp->w_status_click_defs_size != (size_t)width) { + // Only update click definitions once per window per redraw + if (fillclick) { stl_clear_click_defs(wp->w_statuscol_click_defs, wp->w_statuscol_click_defs_size); wp->w_statuscol_click_defs = stl_alloc_click_defs(wp->w_statuscol_click_defs, width, &wp->w_statuscol_click_defs_size); @@ -1322,7 +1337,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n } stl_items[curitem].type = ClickFunc; stl_items[curitem].start = out_p; - stl_items[curitem].cmd = xmemdupz(t, (size_t)(fmt_p - t)); + stl_items[curitem].cmd = tabtab ? xmemdupz(t, (size_t)(fmt_p - t)) : NULL; stl_items[curitem].minwid = minwid; fmt_p++; curitem++; @@ -1363,7 +1378,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n // An invalid item was specified. // Continue processing on the next character of the format string. - if (vim_strchr(STL_ALL, *fmt_p) == NULL) { + if (vim_strchr(STL_ALL, (uint8_t)(*fmt_p)) == NULL) { fmt_p++; continue; } @@ -1504,13 +1519,12 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n case STL_LINE: // Overload %l with v:lnum for 'statuscolumn' if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) { - if (wp->w_p_nu) { + if (wp->w_p_nu && !get_vim_var_nr(VV_VIRTNUM)) { num = get_vim_var_nr(VV_LNUM); } } else { num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum); } - break; case STL_NUMLINES: @@ -1610,7 +1624,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n case STL_ROFLAG_ALT: // Overload %r with v:relnum for 'statuscolumn' if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) { - if (wp->w_p_rnu) { + if (wp->w_p_rnu && !get_vim_var_nr(VV_VIRTNUM)) { num = get_vim_var_nr(VV_RELNUM); } } else { @@ -1678,7 +1692,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n 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++) { - *t = (char)TOUPPER_LOC(*t); + *t = (char)TOUPPER_LOC((uint8_t)(*t)); } str = buf_tmp; } @@ -1978,6 +1992,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n // the truncation point for (int i = 0; i < itemcnt; i++) { if (stl_items[i].start > trunc_p) { + for (int j = i; j < itemcnt; j++) { + if (stl_items[j].type == ClickFunc) { + XFREE_CLEAR(stl_items[j].cmd); + } + } itemcnt = i; break; } diff --git a/src/nvim/strings.c b/src/nvim/strings.c index f0f9fbf51b..34b3c38103 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -167,7 +167,7 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli // 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 = (char_u *)string; *p != NUL; MB_PTR_ADV(p)) { + for (const char *p = string; *p != NUL; MB_PTR_ADV(p)) { #ifdef MSWIN if (!p_ssl) { if (*p == '"') { @@ -185,7 +185,7 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli length++; // insert backslash } } - if (do_special && find_cmdline_var((char *)p, &l) >= 0) { + if (do_special && find_cmdline_var(p, &l) >= 0) { length++; // insert backslash p += l - 1; } @@ -270,7 +270,7 @@ char *vim_strsave_up(const char *string) char *p1; p1 = xstrdup(string); - vim_strup((char_u *)p1); + vim_strup(p1); return p1; } @@ -280,17 +280,17 @@ char *vim_strnsave_up(const char *string, size_t len) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { char *p1 = xstrnsave(string, len); - vim_strup((char_u *)p1); + vim_strup(p1); return p1; } // ASCII lower-to-upper case translation, language independent. -void vim_strup(char_u *p) +void vim_strup(char *p) FUNC_ATTR_NONNULL_ALL { - char_u c; - while ((c = *p) != NUL) { - *p++ = (char_u)(c < 'a' || c > 'z' ? c : c - 0x20); + uint8_t c; + while ((c = (uint8_t)(*p)) != NUL) { + *p++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); } } @@ -313,7 +313,7 @@ char *strcase_save(const char *const orig, bool upper) int l = utf_ptr2len(p); if (c == 0) { // overlong sequence, use only the first byte - c = (char_u)(*p); + c = (uint8_t)(*p); l = 1; } int uc = upper ? mb_toupper(c) : mb_tolower(c); @@ -372,7 +372,7 @@ int vim_stricmp(const char *s1, const char *s2) int i; for (;;) { - i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); + i = (int)TOLOWER_LOC((uint8_t)(*s1)) - (int)TOLOWER_LOC((uint8_t)(*s2)); if (i != 0) { return i; // this character different } @@ -396,7 +396,7 @@ int vim_strnicmp(const char *s1, const char *s2, size_t len) int i; while (len > 0) { - i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); + i = (int)TOLOWER_LOC((uint8_t)(*s1)) - (int)TOLOWER_LOC((uint8_t)(*s2)); if (i != 0) { return i; // this character different } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 721cc7707a..49b63ad324 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -92,7 +92,7 @@ typedef struct syn_pattern { } synpat_T; typedef struct syn_cluster_S { - char_u *scl_name; // syntax cluster name + char *scl_name; // syntax cluster name char *scl_name_u; // uppercase of scl_name int16_t *scl_list; // IDs in this syntax cluster } syn_cluster_T; @@ -721,10 +721,12 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) static void save_chartab(char *chartab) { - if (syn_block->b_syn_isk != empty_option) { - memmove(chartab, syn_buf->b_chartab, (size_t)32); - memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, (size_t)32); + if (syn_block->b_syn_isk == empty_option) { + return; } + + memmove(chartab, syn_buf->b_chartab, (size_t)32); + memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, (size_t)32); } static void restore_chartab(char *chartab) @@ -737,22 +739,23 @@ static void restore_chartab(char *chartab) /// 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 buf_chartab[32]; - save_chartab(buf_chartab); + if (syn_block->b_syn_linecont_prog == NULL) { + return false; + } - regmatch.rmm_ic = syn_block->b_syn_linecont_ic; - regmatch.regprog = syn_block->b_syn_linecont_prog; - int r = syn_regexec(®match, lnum, (colnr_T)0, - IF_SYN_TIME(&syn_block->b_syn_linecont_time)); - syn_block->b_syn_linecont_prog = regmatch.regprog; + regmmatch_T regmatch; + // chartab array for syn iskeyword + char buf_chartab[32]; + save_chartab(buf_chartab); - restore_chartab(buf_chartab); - return r; - } - return false; + regmatch.rmm_ic = syn_block->b_syn_linecont_ic; + regmatch.regprog = syn_block->b_syn_linecont_prog; + int r = syn_regexec(®match, lnum, (colnr_T)0, + IF_SYN_TIME(&syn_block->b_syn_linecont_time)); + syn_block->b_syn_linecont_prog = regmatch.regprog; + + restore_chartab(buf_chartab); + return r; } // Prepare the current state for the start of a line. @@ -873,14 +876,16 @@ static void syn_stack_free_block(synblock_T *block) { synstate_T *p; - if (block->b_sst_array != NULL) { - for (p = block->b_sst_first; p != NULL; p = p->sst_next) { - clear_syn_state(p); - } - XFREE_CLEAR(block->b_sst_array); - block->b_sst_first = NULL; - block->b_sst_len = 0; + if (block->b_sst_array == NULL) { + return; + } + + for (p = block->b_sst_first; p != NULL; p = p->sst_next) { + clear_syn_state(p); } + XFREE_CLEAR(block->b_sst_array); + block->b_sst_first = NULL; + block->b_sst_len = 0; } // Free b_sst_array[] for buffer "buf". // Used when syntax items changed to force resyncing everywhere. @@ -1490,8 +1495,8 @@ int get_syntax_attr(const colnr_T col, bool *const can_spell, const bool keep_st static int syn_current_attr(const bool syncing, const bool displaying, bool *const can_spell, const bool keep_state) { - lpos_T endpos; // was: char_u *endp; - lpos_T hl_startpos; // was: int hl_startcol; + lpos_T endpos; + lpos_T hl_startpos; lpos_T hl_endpos; lpos_T eos_pos; // end-of-start match (start region) lpos_T eoe_pos; // end-of-end pattern @@ -3416,8 +3421,8 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) } msg_putchar(' '); if (spp->sp_sync_idx >= 0) { - msg_outtrans((char *)highlight_group_name(SYN_ITEMS(curwin->w_s) - [spp->sp_sync_idx].sp_syn.id - 1)); + msg_outtrans(highlight_group_name(SYN_ITEMS(curwin->w_s) + [spp->sp_sync_idx].sp_syn.id - 1)); } else { msg_puts("NONE"); } @@ -3430,7 +3435,7 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) (void)syn_list_header(did_header, 0, id, true); msg_puts_attr("links to", attr); msg_putchar(' '); - msg_outtrans((char *)highlight_group_name(highlight_link_id(id - 1) - 1)); + msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1)); } } @@ -3453,7 +3458,7 @@ static void syn_list_cluster(int id) // slight hack: roughly duplicate the guts of syn_list_header() msg_putchar('\n'); - msg_outtrans((char *)SYN_CLSTR(curwin->w_s)[id].scl_name); + msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name); if (msg_col >= endcol) { // output at least one space endcol = msg_col + 1; @@ -3490,9 +3495,9 @@ static void put_id_list(const char *const name, const int16_t *const list, const int scl_id = *p - SYNID_CLUSTER; msg_putchar('@'); - msg_outtrans((char *)SYN_CLSTR(curwin->w_s)[scl_id].scl_name); + msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name); } else { - msg_outtrans((char *)highlight_group_name(*p - 1)); + msg_outtrans(highlight_group_name(*p - 1)); } if (p[1]) { msg_putchar(','); @@ -3514,7 +3519,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const if (last_matchgroup == 0) { msg_outtrans("NONE"); } else { - msg_outtrans((char *)highlight_group_name(last_matchgroup - 1)); + msg_outtrans(highlight_group_name(last_matchgroup - 1)); } msg_putchar(' '); } @@ -3524,7 +3529,7 @@ 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(spp->sp_pattern, sepchars[i]) != NULL;) { + for (i = 0; vim_strchr(spp->sp_pattern, (uint8_t)sepchars[i]) != NULL;) { if (sepchars[++i] == NUL) { i = 0; // no good char found, just use the first one break; @@ -3731,7 +3736,7 @@ static void add_keyword(char *const name, const int id, const int flags, sizeof(name_folded)) : name; - keyentry_T *const kp = xmalloc(sizeof(keyentry_T) + strlen(name_ic)); + keyentry_T *const kp = xmalloc(offsetof(keyentry_T, keyword) + strlen(name_ic) + 1); STRCPY(kp->keyword, name_ic); kp->k_syn.id = (int16_t)id; kp->k_syn.inc_tag = current_syn_inc_tag; @@ -3743,7 +3748,7 @@ static void add_keyword(char *const name, const int id, const int flags, } kp->next_list = copy_id_list(next_list); - const hash_T hash = hash_hash((char_u *)kp->keyword); + const hash_T hash = hash_hash(kp->keyword); hashtab_T *const ht = (curwin->w_s->b_syn_ic) ? &curwin->w_s->b_keywtab_ic : &curwin->w_s->b_keywtab; @@ -3757,7 +3762,7 @@ static void add_keyword(char *const name, const int id, const int flags, if (HASHITEM_EMPTY(hi)) { // new keyword, add to hashtable kp->ke_next = NULL; - hash_add_item(ht, hi, (char_u *)kp->keyword, hash); + hash_add_item(ht, hi, kp->keyword, hash); } else { // keyword already exists, prepend to list kp->ke_next = HI2KE(hi); @@ -4000,7 +4005,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing) // filename to include. eap->argt |= (EX_XFILE | EX_NOSPC); separate_nextcmd(eap); - if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute((char_u *)eap->arg)) { + if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute(eap->arg)) { // For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the // file. Need to expand the file name first. In other cases // ":runtime!" is used. @@ -4634,7 +4639,7 @@ static int syn_add_cluster(char *name) syn_cluster_T *scp = GA_APPEND_VIA_PTR(syn_cluster_T, &curwin->w_s->b_syn_clusters); CLEAR_POINTER(scp); - scp->scl_name = (char_u *)name; + scp->scl_name = name; scp->scl_name_u = vim_strsave_up(name); scp->scl_list = NULL; @@ -5042,7 +5047,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list, 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)) { + if (vim_regexec(®match, highlight_group_name(i), (colnr_T)0)) { if (round == 2) { // Got more items than expected; can happen // when adding items that match: @@ -5369,34 +5374,39 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg) include_link = 0; include_default = 0; + if (*arg == NUL) { + return; + } + // (part of) subcommand already typed - if (*arg != NUL) { - const char *p = (const char *)skiptowhite(arg); - if (*p != NUL) { // Past first word. - xp->xp_pattern = skipwhite(p); - if (*skiptowhite(xp->xp_pattern) != NUL) { - xp->xp_context = EXPAND_NOTHING; - } else if (STRNICMP(arg, "case", p - arg) == 0) { - expand_what = EXP_CASE; - } else if (STRNICMP(arg, "spell", p - arg) == 0) { - 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) { - xp->xp_context = EXPAND_HIGHLIGHT; - } else { - xp->xp_context = EXPAND_NOTHING; - } + const char *p = (const char *)skiptowhite(arg); + if (*p == NUL) { + return; + } + + // past first world + xp->xp_pattern = skipwhite(p); + if (*skiptowhite(xp->xp_pattern) != NUL) { + xp->xp_context = EXPAND_NOTHING; + } else if (STRNICMP(arg, "case", p - arg) == 0) { + expand_what = EXP_CASE; + } else if (STRNICMP(arg, "spell", p - arg) == 0) { + 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) { + xp->xp_context = EXPAND_HIGHLIGHT; + } else { + xp->xp_context = EXPAND_NOTHING; } } @@ -5677,7 +5687,7 @@ static void syntime_report(void) msg_puts(profile_msg(p->average)); msg_puts(" "); msg_advance(50); - msg_outtrans((char *)highlight_group_name(p->id - 1)); + msg_outtrans(highlight_group_name(p->id - 1)); msg_puts(" "); msg_advance(69); diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 73aa6eb9ca..42618e8924 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -210,22 +210,20 @@ static Callback tfu_cb; // 'tagfunc' callback function /// Reads the 'tagfunc' option value and convert that to a callback value. /// Invoked when the 'tagfunc' option is set. The option value can be a name of /// a function (string), or function(<name>) or funcref(<name>) or a lambda. -int set_tagfunc_option(void) +void set_tagfunc_option(char **errmsg) { callback_free(&tfu_cb); callback_free(&curbuf->b_tfu_cb); if (*curbuf->b_p_tfu == NUL) { - return OK; + return; } if (option_set_callback_func(curbuf->b_p_tfu, &tfu_cb) == FAIL) { - return FAIL; + *errmsg = e_invarg; } callback_copy(&curbuf->b_tfu_cb, &tfu_cb); - - return OK; } #if defined(EXITFREE) @@ -1019,7 +1017,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) // Get the line number or the search pattern used to locate // the tag. lnum = 0; - if (isdigit(*tagp.command)) { + if (isdigit((uint8_t)(*tagp.command))) { // Line number is used to locate the tag lnum = atol(tagp.command); } else { @@ -1199,7 +1197,7 @@ static void prepare_pats(pat_T *pats, int has_re) } else { for (pats->headlen = 0; pats->head[pats->headlen] != NUL; pats->headlen++) { if (vim_strchr(magic_isset() ? ".[~*\\$" : "\\$", - pats->head[pats->headlen]) != NULL) { + (uint8_t)pats->head[pats->headlen]) != NULL) { break; } } @@ -2078,10 +2076,10 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_ // the part that matters for comparing, more bytes may // follow after it. E.g. help tags store the priority // after the NUL. - *hash = hash_hash((char_u *)mfp); + *hash = hash_hash(mfp); hi = hash_lookup(&st->ht_match[mtt], (const char *)mfp, strlen(mfp), *hash); if (HASHITEM_EMPTY(hi)) { - hash_add_item(&st->ht_match[mtt], hi, (char_u *)mfp, *hash); + hash_add_item(&st->ht_match[mtt], hi, mfp, *hash); GA_APPEND(char *, &st->ga_match[mtt], mfp); st->match_count++; } else { @@ -2563,7 +2561,7 @@ int get_tagfname(tagname_T *tnp, int first, char *buf) if (first) { // Init. We make a copy of 'tags', because autocommands may change // the value without notifying us. - tnp->tn_tags = xstrdup((*curbuf->b_p_tags != NUL) ? curbuf->b_p_tags : (char *)p_tags); + tnp->tn_tags = xstrdup((*curbuf->b_p_tags != NUL) ? curbuf->b_p_tags : p_tags); tnp->tn_np = tnp->tn_tags; } @@ -2573,7 +2571,7 @@ int get_tagfname(tagname_T *tnp, int first, char *buf) // tnp->tn_did_filefind_init == true: find next file in this part. for (;;) { if (tnp->tn_did_filefind_init) { - fname = (char *)vim_findfile(tnp->tn_search_ctx); + fname = vim_findfile(tnp->tn_search_ctx); if (fname != NULL) { break; } @@ -2593,7 +2591,7 @@ int get_tagfname(tagname_T *tnp, int first, char *buf) buf[0] = NUL; (void)copy_option_part(&tnp->tn_np, buf, MAXPATHL - 1, " ,"); - r_ptr = (char *)vim_findfile_stopdir(buf); + r_ptr = vim_findfile_stopdir(buf); // move the filename one char forward and truncate the // filepath with a NUL filename = path_tail(buf); @@ -2734,55 +2732,57 @@ static int parse_match(char *lbuf, tagptrs_T *tagp) tagp->tagline = 0; tagp->command_end = NULL; - 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 += 2; // skip ";\"" - if (*p++ == TAB) { - // Accept ASCII alphabetic kind characters and any multi-byte - // character. - while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { - if (strncmp(p, "kind:", 5) == 0) { - tagp->tagkind = 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(p + 5); - } - if (tagp->tagkind != NULL && tagp->user_data != NULL) { - break; - } + if (retval != OK) { + return retval; + } - pc = vim_strchr(p, ':'); - pt = vim_strchr(p, '\t'); - if (pc == NULL || (pt != NULL && pc > pt)) { - tagp->tagkind = p; - } - if (pt == NULL) { - break; - } - p = pt; - MB_PTR_ADV(p); + // 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 += 2; // skip ";\"" + if (*p++ == TAB) { + // Accept ASCII alphabetic kind characters and any multi-byte + // character. + while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { + if (strncmp(p, "kind:", 5) == 0) { + tagp->tagkind = 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(p + 5); + } + if (tagp->tagkind != NULL && tagp->user_data != NULL) { + break; } + + pc = vim_strchr(p, ':'); + pt = vim_strchr(p, '\t'); + if (pc == NULL || (pt != NULL && pc > pt)) { + tagp->tagkind = p; + } + if (pt == NULL) { + break; + } + p = pt; + MB_PTR_ADV(p); } } - if (tagp->tagkind != NULL) { - for (p = tagp->tagkind; - *p && *p != '\t' && *p != '\r' && *p != '\n'; - MB_PTR_ADV(p)) {} - tagp->tagkind_end = 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; - } + } + if (tagp->tagkind != NULL) { + for (p = tagp->tagkind; + *p && *p != '\t' && *p != '\r' && *p != '\n'; + MB_PTR_ADV(p)) {} + tagp->tagkind_end = 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; } return retval; } @@ -3331,86 +3331,88 @@ int get_tags(list_T *list, char *pat, char *buf_fname) ret = find_tags(pat, &num_matches, &matches, TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname); - if (ret == OK && num_matches > 0) { - for (i = 0; i < num_matches; i++) { - int parse_result = parse_match(matches[i], &tp); + if (ret != OK || num_matches <= 0) { + return ret; + } - // Avoid an unused variable warning in release builds. - (void)parse_result; - assert(parse_result == OK); + for (i = 0; i < num_matches; i++) { + int parse_result = parse_match(matches[i], &tp); - is_static = test_for_static(&tp); + // Avoid an unused variable warning in release builds. + (void)parse_result; + assert(parse_result == OK); - // Skip pseudo-tag lines. - if (strncmp(tp.tagname, "!_TAG_", 6) == 0) { - xfree(matches[i]); - continue; - } + is_static = test_for_static(&tp); + + // Skip pseudo-tag lines. + if (strncmp(tp.tagname, "!_TAG_", 6) == 0) { + xfree(matches[i]); + continue; + } + + dict = tv_dict_alloc(); + tv_list_append_dict(list, dict); - dict = tv_dict_alloc(); - 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 - || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) { - ret = FAIL; - } - - xfree(full_fname); - - if (tp.command_end != NULL) { - for (char *p = tp.command_end + 3; - *p != NUL && *p != '\n' && *p != '\r'; - MB_PTR_ADV(p)) { - if (p == tp.tagkind - || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) { - // skip "kind:<kind>" and "<kind>" - p = tp.tagkind_end - 1; - } else if (strncmp(p, "file:", 5) == 0) { - // skip "file:" (static tag) - p += 4; - } else if (!ascii_iswhite(*p)) { - char *s, *n; - int len; - - // Add extra field as a dict entry. Fields are - // separated by Tabs. - n = p; - while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') { + 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 + || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) { + ret = FAIL; + } + + xfree(full_fname); + + if (tp.command_end != NULL) { + for (char *p = tp.command_end + 3; + *p != NUL && *p != '\n' && *p != '\r'; + MB_PTR_ADV(p)) { + if (p == tp.tagkind + || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) { + // skip "kind:<kind>" and "<kind>" + p = tp.tagkind_end - 1; + } else if (strncmp(p, "file:", 5) == 0) { + // skip "file:" (static tag) + p += 4; + } else if (!ascii_iswhite(*p)) { + char *s, *n; + int len; + + // Add extra field as a dict entry. Fields are + // separated by Tabs. + n = p; + while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') { + p++; + } + len = (int)(p - n); + if (*p == ':' && len > 0) { + s = ++p; + while (*p != NUL && (uint8_t)(*p) >= ' ') { p++; } - len = (int)(p - n); - if (*p == ':' && len > 0) { - s = ++p; - while (*p != NUL && (uint8_t)(*p) >= ' ') { - p++; - } - n[len] = NUL; - if (add_tag_field(dict, n, s, p) == FAIL) { - ret = FAIL; - } - n[len] = ':'; - } else { - // Skip field without colon. - while (*p != NUL && (uint8_t)(*p) >= ' ') { - p++; - } + n[len] = NUL; + if (add_tag_field(dict, n, s, p) == FAIL) { + ret = FAIL; } - if (*p == NUL) { - break; + n[len] = ':'; + } else { + // Skip field without colon. + while (*p != NUL && (uint8_t)(*p) >= ' ') { + p++; } } + if (*p == NUL) { + break; + } } } - - xfree(matches[i]); } - xfree(matches); + + xfree(matches[i]); } + xfree(matches); return ret; } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 106e92d43c..a52a34cd66 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -435,7 +435,7 @@ bool terminal_enter(void) handle_T save_curwin = curwin->handle; bool save_w_p_cul = curwin->w_p_cul; char *save_w_p_culopt = NULL; - char_u save_w_p_culopt_flags = curwin->w_p_culopt_flags; + uint8_t 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; @@ -718,7 +718,7 @@ void terminal_paste(long count, char **y_array, size_t y_size) } vterm_keyboard_start_paste(curbuf->terminal->vt); size_t buff_len = strlen(y_array[0]); - char_u *buff = xmalloc(buff_len); + char *buff = xmalloc(buff_len); for (int i = 0; i < count; i++) { // -V756 // feed the lines to the terminal for (size_t j = 0; j < y_size; j++) { @@ -731,18 +731,18 @@ void terminal_paste(long count, char **y_array, size_t y_size) buff = xrealloc(buff, len); buff_len = len; } - char_u *dst = buff; - char_u *src = (char_u *)y_array[j]; + char *dst = buff; + char *src = y_array[j]; while (*src != '\0') { - len = (size_t)utf_ptr2len((char *)src); - int c = utf_ptr2char((char *)src); + len = (size_t)utf_ptr2len(src); + int c = utf_ptr2char(src); if (!is_filter_char(c)) { memcpy(dst, src, len); dst += len; } src += len; } - terminal_send(curbuf->terminal, (char *)buff, (size_t)(dst - buff)); + terminal_send(curbuf->terminal, buff, (size_t)(dst - buff)); } } xfree(buff); diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim index a188f7afa1..680a59006b 100644 --- a/src/nvim/testdir/check.vim +++ b/src/nvim/testdir/check.vim @@ -1,6 +1,8 @@ source shared.vim source term_util.vim +command -nargs=1 MissingFeature throw 'Skipped: ' .. <args> .. ' feature missing' + " Command to check for the presence of a feature. command -nargs=1 CheckFeature call CheckFeature(<f-args>) func CheckFeature(name) @@ -8,7 +10,7 @@ func CheckFeature(name) " throw 'Checking for non-existent feature ' .. a:name " endif if !has(a:name) - throw 'Skipped: ' .. a:name .. ' feature missing' + MissingFeature a:name endif endfunc diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh index 322265737a..3a0a94b6bf 100755 --- a/src/nvim/testdir/runnvim.sh +++ b/src/nvim/testdir/runnvim.sh @@ -30,6 +30,9 @@ main() {( . "$CI_DIR/common/suite.sh" . "$CI_DIR/common/test.sh" + # Redirect XDG_CONFIG_HOME so users local config doesn't interfere + export XDG_CONFIG_HOME="$root" + export VIMRUNTIME="$root/runtime" if ! "$nvim_prg" \ -u NONE -i NONE \ diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 704ff6ec55..83af0f6be0 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -629,6 +629,7 @@ func Test_WinScrolled_diff() \ }, event) call StopVimInTerminal(buf) + call delete('XscrollEvent') endfunc func Test_WinClosed() @@ -2918,7 +2919,7 @@ func Test_autocmd_CmdWinEnter() call term_sendkeys(buf, "q:") call term_wait(buf) call term_sendkeys(buf, ":echo b:dummy_var\<cr>") - call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 1000) + call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 2000) call term_sendkeys(buf, ":echo &buftype\<cr>") call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, ":echo winnr\<cr>") diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim index 995683c68c..2e377aa434 100644 --- a/src/nvim/testdir/test_breakindent.vim +++ b/src/nvim/testdir/test_breakindent.vim @@ -856,7 +856,7 @@ func Test_breakindent20_list() " check formatlistpat indent with different list level " showbreak and sbr - setl briopt=min:5,sbr,list:-1,shift:2 + setl briopt=min:5,sbr,list:-1 setl showbreak=> redraw! let expect = [ @@ -869,6 +869,44 @@ func Test_breakindent20_list() \ ] let lines = s:screen_lines2(1, 6, 20) call s:compare_lines(expect, lines) + + " check formatlistpat indent with different list level + " showbreak sbr and shift + setl briopt=min:5,sbr,list:-1,shift:2 + setl showbreak=> + redraw! + let expect = [ + \ "* Congress shall ", + \ "> make no law ", + \ "*** Congress shall ", + \ "> make no law ", + \ "**** Congress shall ", + \ "> make no law ", + \ ] + let lines = s:screen_lines2(1, 6, 20) + call s:compare_lines(expect, lines) + + " check breakindent works if breakindentopt=list:-1 + " for a non list content + %delete _ + call setline(1, [' Congress shall make no law', + \ ' Congress shall make no law', + \ ' Congress shall make no law']) + norm! 1gg + setl briopt=min:5,list:-1 + setl showbreak= + redraw! + let expect = [ + \ " Congress shall ", + \ " make no law ", + \ " Congress shall ", + \ " make no law ", + \ " Congress shall ", + \ " make no law ", + \ ] + let lines = s:screen_lines2(1, 6, 20) + call s:compare_lines(expect, lines) + call s:close_windows('set breakindent& briopt& linebreak& list& listchars& showbreak&') endfunc diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim index 549aa691c8..9220cc17b9 100644 --- a/src/nvim/testdir/test_buffer.vim +++ b/src/nvim/testdir/test_buffer.vim @@ -423,6 +423,12 @@ func Test_buf_pattern_invalid() vsplit 00000000000000000000000000 silent! buf [0--]\&\zs*\zs*e bwipe! + + " similar case with different code path + split 0 + edit ÿ + silent! buf [0--]\&\zs*\zs*0 + bwipe! endfunc " Test for the 'maxmem' and 'maxmemtot' options diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 74a5d99ef9..cf1d56ae38 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -151,6 +151,14 @@ func Test_complete_wildmenu() call assert_equal('"e Xdir1/Xdir2/1', @:) cunmap <F2> + " Test for canceling the wild menu by pressing <PageDown> or <PageUp>. + " After this pressing <Left> or <Right> should not change the selection. + call feedkeys(":sign \<Tab>\<PageDown>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign define', @:) + call histadd('cmd', 'TestWildMenu') + call feedkeys(":sign \<Tab>\<PageUp>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"TestWildMenu', @:) + " cleanup %bwipe call delete('Xdir1', 'rf') @@ -421,6 +429,7 @@ func Test_getcompletion() call assert_true(matchcount > 0) let matchcount = len(getcompletion('File.', 'menu')) call assert_true(matchcount > 0) + source $VIMRUNTIME/delmenu.vim endif let l = getcompletion('v:n', 'var') @@ -642,6 +651,22 @@ func Test_getcompletion() call assert_fails('call getcompletion("abc", [])', 'E475:') endfunc +" Test for getcompletion() with "fuzzy" in 'wildoptions' +func Test_getcompletion_wildoptions() + let save_wildoptions = &wildoptions + set wildoptions& + let l = getcompletion('space', 'option') + call assert_equal([], l) + let l = getcompletion('ier', 'command') + call assert_equal([], l) + set wildoptions=fuzzy + let l = getcompletion('space', 'option') + call assert_true(index(l, 'backspace') >= 0) + let l = getcompletion('ier', 'command') + call assert_true(index(l, 'compiler') >= 0) + let &wildoptions = save_wildoptions +endfunc + func Test_fullcommand() let tests = { \ '': '', @@ -2198,7 +2223,8 @@ func Test_wildmenu_dirstack() endfunc " Test for recalling newer or older cmdline from history with <Up>, <Down>, -" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <C-p>, or <C-n>. +" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <kPageUp>, <kPageDown>, <C-p>, or +" <C-n>. func Test_recalling_cmdline() CheckFeature cmdline_hist @@ -2206,17 +2232,18 @@ func Test_recalling_cmdline() cnoremap <Plug>(save-cmdline) <Cmd>let g:cmdlines += [getcmdline()]<CR> let histories = [ - \ {'name': 'cmd', 'enter': ':', 'exit': "\<Esc>"}, - \ {'name': 'search', 'enter': '/', 'exit': "\<Esc>"}, - \ {'name': 'expr', 'enter': ":\<C-r>=", 'exit': "\<Esc>\<Esc>"}, - \ {'name': 'input', 'enter': ":call input('')\<CR>", 'exit': "\<CR>"}, + \ #{name: 'cmd', enter: ':', exit: "\<Esc>"}, + \ #{name: 'search', enter: '/', exit: "\<Esc>"}, + \ #{name: 'expr', enter: ":\<C-r>=", exit: "\<Esc>\<Esc>"}, + \ #{name: 'input', enter: ":call input('')\<CR>", exit: "\<CR>"}, "\ TODO: {'name': 'debug', ...} \] let keypairs = [ - \ {'older': "\<Up>", 'newer': "\<Down>", 'prefixmatch': v:true}, - \ {'older': "\<S-Up>", 'newer': "\<S-Down>", 'prefixmatch': v:false}, - \ {'older': "\<PageUp>", 'newer': "\<PageDown>", 'prefixmatch': v:false}, - \ {'older': "\<C-p>", 'newer': "\<C-n>", 'prefixmatch': v:false}, + \ #{older: "\<Up>", newer: "\<Down>", prefixmatch: v:true}, + \ #{older: "\<S-Up>", newer: "\<S-Down>", prefixmatch: v:false}, + \ #{older: "\<PageUp>", newer: "\<PageDown>", prefixmatch: v:false}, + \ #{older: "\<kPageUp>", newer: "\<kPageDown>", prefixmatch: v:false}, + \ #{older: "\<C-p>", newer: "\<C-n>", prefixmatch: v:false}, \] let prefix = 'vi' for h in histories @@ -2331,6 +2358,11 @@ func Test_wildmenu_pum() set tabline=%!MyTabLine() set showtabline=2 endfunc + + func DoFeedKeys() + let &wildcharm = char2nr("\t") + call feedkeys(":edit $VIMRUNTIME/\<Tab>\<Left>\<C-U>ab\<Tab>") + endfunc [CODE] call writefile(commands, 'Xtest') @@ -2528,6 +2560,34 @@ func Test_wildmenu_pum() call term_sendkeys(buf, "\<Esc>") call VerifyScreenDump(buf, 'Test_wildmenu_pum_40', {}) + " popup is cleared also when 'lazyredraw' is set + call term_sendkeys(buf, ":set showtabline=1 laststatus=1 lazyredraw\<CR>") + call term_sendkeys(buf, ":call DoFeedKeys()\<CR>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {}) + call term_sendkeys(buf, "\<Esc>") + + " Pressing <PageDown> should scroll the menu downward + call term_sendkeys(buf, ":sign \<Tab>\<PageDown>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_42', {}) + call term_sendkeys(buf, "\<PageDown>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_43', {}) + call term_sendkeys(buf, "\<PageDown>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_44', {}) + call term_sendkeys(buf, "\<PageDown>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_45', {}) + call term_sendkeys(buf, "\<C-U>sign \<Tab>\<Down>\<Down>\<PageDown>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_46', {}) + + " Pressing <PageUp> should scroll the menu upward + call term_sendkeys(buf, "\<C-U>sign \<Tab>\<PageUp>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_47', {}) + call term_sendkeys(buf, "\<PageUp>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_48', {}) + call term_sendkeys(buf, "\<PageUp>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_49', {}) + call term_sendkeys(buf, "\<PageUp>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_50', {}) + call term_sendkeys(buf, "\<C-U>\<CR>") call StopVimInTerminal(buf) call delete('Xtest') @@ -2551,6 +2611,30 @@ func Test_wildmenumode_with_pum() cunmap <F2> endfunc +" Test for opening the cmdline completion popup menu from the terminal window. +" The popup menu should be positioned correctly over the status line of the +" bottom-most window. +func Test_wildmenu_pum_from_terminal() + CheckRunVimInTerminal + let python = PythonProg() + call CheckPython(python) + + %bw! + let cmds = ['set wildmenu wildoptions=pum'] + let pcmd = python .. ' -c "import sys; sys.stdout.write(sys.stdin.read())"' + call add(cmds, "call term_start('" .. pcmd .. "')") + call writefile(cmds, 'Xtest') + let buf = RunVimInTerminal('-S Xtest', #{rows: 10}) + call term_sendkeys(buf, "\r\r\r") + call term_wait(buf) + call term_sendkeys(buf, "\<C-W>:sign \<Tab>") + call term_wait(buf) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_term_01', {}) + call term_wait(buf) + call StopVimInTerminal(buf) + call delete('Xtest') +endfunc + func Test_wildmenu_pum_clear_entries() CheckRunVimInTerminal @@ -2611,6 +2695,747 @@ func Test_cmdline_complete_dlist() call assert_equal("\"dlist 10 /pat/ | chistory", @:) endfunc +" argument list (only for :argdel) fuzzy completion +func Test_fuzzy_completion_arglist() + argadd change.py count.py charge.py + set wildoptions& + call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"argdel cge', @:) + set wildoptions=fuzzy + call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"argdel change.py charge.py', @:) + %argdelete + set wildoptions& +endfunc + +" autocmd group name fuzzy completion +func Test_fuzzy_completion_autocmd() + set wildoptions& + augroup MyFuzzyGroup + augroup END + call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"augroup mfg', @:) + call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"augroup MyFuzzyGroup', @:) + set wildoptions=fuzzy + call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"augroup MyFuzzyGroup', @:) + call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"augroup My*p', @:) + augroup! MyFuzzyGroup + set wildoptions& +endfunc + +" buffer name fuzzy completion +func Test_fuzzy_completion_bufname() + set wildoptions& + " Use a long name to reduce the risk of matching a random directory name + edit SomeRandomFileWithLetters.txt + enew + call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"b SRFWL', @:) + call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"b SomeRandomFileWithLetters.txt', @:) + set wildoptions=fuzzy + call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"b SomeRandomFileWithLetters.txt', @:) + call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"b S*FileWithLetters.txt', @:) + %bw! + set wildoptions& +endfunc + +" buffer name (full path) fuzzy completion +func Test_fuzzy_completion_bufname_fullpath() + CheckUnix + set wildoptions& + call mkdir('Xcmd/Xstate/Xfile.js', 'p') + edit Xcmd/Xstate/Xfile.js + cd Xcmd/Xstate + enew + call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"b CmdStateFile', @:) + set wildoptions=fuzzy + call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match('Xcmd/Xstate/Xfile.js$', @:) + cd - + call delete('Xcmd', 'rf') + set wildoptions& +endfunc + +" :behave suboptions fuzzy completion +func Test_fuzzy_completion_behave() + set wildoptions& + call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"behave xm', @:) + call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"behave xterm', @:) + set wildoptions=fuzzy + call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"behave xterm', @:) + call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"behave xt*m', @:) + let g:Sline = '' + call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx') + call assert_equal('mswin', g:Sline) + call assert_equal('"behave win', @:) + set wildoptions& +endfunc + +" " colorscheme name fuzzy completion - NOT supported +" func Test_fuzzy_completion_colorscheme() +" endfunc + +" built-in command name fuzzy completion +func Test_fuzzy_completion_cmdname() + set wildoptions& + call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sbwin', @:) + call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sbrewind', @:) + set wildoptions=fuzzy + call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sbrewind', @:) + call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sbr*d', @:) + set wildoptions& +endfunc + +" " compiler name fuzzy completion - NOT supported +" func Test_fuzzy_completion_compiler() +" endfunc + +" :cscope suboptions fuzzy completion +func Test_fuzzy_completion_cscope() + CheckFeature cscope + set wildoptions& + call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cscope ret', @:) + call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cscope reset', @:) + set wildoptions=fuzzy + call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cscope reset', @:) + call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cscope re*t', @:) + set wildoptions& +endfunc + +" :diffget/:diffput buffer name fuzzy completion +func Test_fuzzy_completion_diff() + new SomeBuffer + diffthis + new OtherBuffer + diffthis + set wildoptions& + call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"diffget sbuf', @:) + call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"diffput sbuf', @:) + set wildoptions=fuzzy + call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"diffget SomeBuffer', @:) + call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"diffput SomeBuffer', @:) + %bw! + set wildoptions& +endfunc + +" " directory name fuzzy completion - NOT supported +" func Test_fuzzy_completion_dirname() +" endfunc + +" environment variable name fuzzy completion +func Test_fuzzy_completion_env() + set wildoptions& + call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"echo $VUT', @:) + set wildoptions=fuzzy + call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"echo $VIMRUNTIME', @:) + set wildoptions& +endfunc + +" autocmd event fuzzy completion +func Test_fuzzy_completion_autocmd_event() + set wildoptions& + call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"autocmd BWout', @:) + set wildoptions=fuzzy + call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"autocmd BufWipeout', @:) + set wildoptions& +endfunc + +" vim expression fuzzy completion +func Test_fuzzy_completion_expr() + let g:PerPlaceCount = 10 + set wildoptions& + call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"let c = ppc', @:) + set wildoptions=fuzzy + call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"let c = PerPlaceCount', @:) + set wildoptions& +endfunc + +" " file name fuzzy completion - NOT supported +" func Test_fuzzy_completion_filename() +" endfunc + +" " files in path fuzzy completion - NOT supported +" func Test_fuzzy_completion_filesinpath() +" endfunc + +" " filetype name fuzzy completion - NOT supported +" func Test_fuzzy_completion_filetype() +" endfunc + +" user defined function name completion +func Test_fuzzy_completion_userdefined_func() + set wildoptions& + call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"call Test_f_u_f', @:) + set wildoptions=fuzzy + call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"call Test_fuzzy_completion_userdefined_func()', @:) + set wildoptions& +endfunc + +" <SNR> functions should be sorted to the end +func Test_fuzzy_completion_userdefined_snr_func() + func s:Sendmail() + endfunc + func SendSomemail() + endfunc + func S1e2n3dmail() + endfunc + set wildoptions=fuzzy + call feedkeys(":call sendmail\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"call SendSomemail() S1e2n3dmail() ' + \ .. expand("<SID>") .. 'Sendmail()', @:) + set wildoptions& + delfunc s:Sendmail + delfunc SendSomemail + delfunc S1e2n3dmail +endfunc + +" user defined command name completion +func Test_fuzzy_completion_userdefined_cmd() + set wildoptions& + call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"MsFeat', @:) + set wildoptions=fuzzy + call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"MissingFeature', @:) + set wildoptions& +endfunc + +" " :help tag fuzzy completion - NOT supported +" func Test_fuzzy_completion_helptag() +" endfunc + +" highlight group name fuzzy completion +func Test_fuzzy_completion_hlgroup() + set wildoptions& + call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"highlight SKey', @:) + call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"highlight SpecialKey', @:) + set wildoptions=fuzzy + call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"highlight SpecialKey', @:) + call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"highlight Sp*Key', @:) + set wildoptions& +endfunc + +" :history suboptions fuzzy completion +func Test_fuzzy_completion_history() + set wildoptions& + call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"history dg', @:) + call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"history search', @:) + set wildoptions=fuzzy + call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"history debug', @:) + call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"history se*h', @:) + set wildoptions& +endfunc + +" :language locale name fuzzy completion +func Test_fuzzy_completion_lang() + CheckUnix + set wildoptions& + call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"lang psx', @:) + set wildoptions=fuzzy + call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"lang POSIX', @:) + set wildoptions& +endfunc + +" :mapclear buffer argument fuzzy completion +func Test_fuzzy_completion_mapclear() + set wildoptions& + call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"mapclear buf', @:) + set wildoptions=fuzzy + call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"mapclear <buffer>', @:) + set wildoptions& +endfunc + +" map name fuzzy completion +func Test_fuzzy_completion_mapname() + " test regex completion works + set wildoptions=fuzzy + call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"cnoremap <expr> <esc> \<Tab>", @:) + nmap <plug>MyLongMap :p<CR> + call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap <Plug>MyLongMap", @:) + call feedkeys(":nmap MLM \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap MLM \t", @:) + call feedkeys(":nmap <F2> one two \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap <F2> one two \t", @:) + " duplicate entries should be removed + vmap <plug>MyLongMap :<C-U>#<CR> + call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap <Plug>MyLongMap", @:) + nunmap <plug>MyLongMap + vunmap <plug>MyLongMap + call feedkeys(":nmap ABC\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap ABC\t", @:) + " results should be sorted by best match + nmap <Plug>format : + nmap <Plug>goformat : + nmap <Plug>TestFOrmat : + nmap <Plug>fendoff : + nmap <Plug>state : + nmap <Plug>FendingOff : + call feedkeys(":nmap <Plug>fo\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"nmap <Plug>format <Plug>TestFOrmat <Plug>FendingOff <Plug>goformat <Plug>fendoff", @:) + nunmap <Plug>format + nunmap <Plug>goformat + nunmap <Plug>TestFOrmat + nunmap <Plug>fendoff + nunmap <Plug>state + nunmap <Plug>FendingOff + set wildoptions& +endfunc + +" abbreviation fuzzy completion +func Test_fuzzy_completion_abbr() + set wildoptions=fuzzy + call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"iabbr <nowait>", @:) + iabbr WaitForCompletion WFC + call feedkeys(":iabbr fcl\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"iabbr WaitForCompletion", @:) + call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"iabbr a1z\t", @:) + + iunabbrev WaitForCompletion + set wildoptions& +endfunc + +" menu name fuzzy completion +func Test_fuzzy_completion_menu() + CheckFeature menu + + source $VIMRUNTIME/menu.vim + set wildoptions& + call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"menu pup', @:) + set wildoptions=fuzzy + call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"menu PopUp.', @:) + + set wildoptions& + source $VIMRUNTIME/delmenu.vim +endfunc + +" :messages suboptions fuzzy completion +func Test_fuzzy_completion_messages() + set wildoptions& + call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"messages clr', @:) + set wildoptions=fuzzy + call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"messages clear', @:) + set wildoptions& +endfunc + +" :set option name fuzzy completion +func Test_fuzzy_completion_option() + set wildoptions& + call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set brkopt', @:) + set wildoptions=fuzzy + call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set breakindentopt', @:) + set wildoptions& + call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set fixendofline', @:) + set wildoptions=fuzzy + call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set fixendofline', @:) + set wildoptions& +endfunc + +" :set <term_option> +func Test_fuzzy_completion_term_option() + throw 'Skipped: Nvim does not support term options' + set wildoptions& + call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set t_EC', @:) + call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set <t_EC>', @:) + set wildoptions=fuzzy + call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set t_EC', @:) + call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set <t_EC>', @:) + set wildoptions& +endfunc + +" " :packadd directory name fuzzy completion - NOT supported +" func Test_fuzzy_completion_packadd() +" endfunc + +" " shell command name fuzzy completion - NOT supported +" func Test_fuzzy_completion_shellcmd() +" endfunc + +" :sign suboptions fuzzy completion +func Test_fuzzy_completion_sign() + set wildoptions& + call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign ufe', @:) + set wildoptions=fuzzy + call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign undefine', @:) + set wildoptions& +endfunc + +" :syntax suboptions fuzzy completion +func Test_fuzzy_completion_syntax_cmd() + set wildoptions& + call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"syntax kwd', @:) + set wildoptions=fuzzy + call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"syntax keyword', @:) + set wildoptions& +endfunc + +" syntax group name fuzzy completion +func Test_fuzzy_completion_syntax_group() + set wildoptions& + call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"syntax list mpar', @:) + set wildoptions=fuzzy + call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx') + " Fuzzy match prefers NvimParenthesis over MatchParen + " call assert_equal('"syntax list MatchParen', @:) + call assert_equal('"syntax list NvimParenthesis', @:) + set wildoptions& +endfunc + +" :syntime suboptions fuzzy completion +func Test_fuzzy_completion_syntime() + CheckFeature profile + set wildoptions& + call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"syntime clr', @:) + set wildoptions=fuzzy + call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"syntime clear', @:) + set wildoptions& +endfunc + +" " tag name fuzzy completion - NOT supported +" func Test_fuzzy_completion_tagname() +" endfunc + +" " tag name and file fuzzy completion - NOT supported +" func Test_fuzzy_completion_tagfile() +" endfunc + +" " user names fuzzy completion - how to test this functionality? +" func Test_fuzzy_completion_username() +" endfunc + +" user defined variable name fuzzy completion +func Test_fuzzy_completion_userdefined_var() + let g:SomeVariable=10 + set wildoptions& + call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"let SVar', @:) + set wildoptions=fuzzy + call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"let SomeVariable', @:) + set wildoptions& +endfunc + +" Test for sorting the results by the best match +func Test_fuzzy_completion_cmd_sort_results() + %bw! + command T123format : + command T123goformat : + command T123TestFOrmat : + command T123fendoff : + command T123state : + command T123FendingOff : + set wildoptions=fuzzy + call feedkeys(":T123fo\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"T123format T123TestFOrmat T123FendingOff T123goformat T123fendoff', @:) + delcommand T123format + delcommand T123goformat + delcommand T123TestFOrmat + delcommand T123fendoff + delcommand T123state + delcommand T123FendingOff + %bw + set wildoptions& +endfunc + +" Test for fuzzy completion of a command with lower case letters and a number +func Test_fuzzy_completion_cmd_alnum() + command Foo2Bar : + set wildoptions=fuzzy + call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"Foo2Bar', @:) + call feedkeys(":foo\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"Foo2Bar', @:) + call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"Foo2Bar', @:) + delcommand Foo2Bar + set wildoptions& +endfunc + +" Test for command completion for a command starting with 'k' +func Test_fuzzy_completion_cmd_k() + command KillKillKill : + set wildoptions& + call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"killkill\<Tab>", @:) + set wildoptions=fuzzy + call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"KillKillKill', @:) + delcom KillKillKill + set wildoptions& +endfunc + +" Test for fuzzy completion for user defined custom completion function +func Test_fuzzy_completion_custom_func() + func Tcompl(a, c, p) + return "format\ngoformat\nTestFOrmat\nfendoff\nstate" + endfunc + command -nargs=* -complete=custom,Tcompl Fuzzy : + set wildoptions& + call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy format", @:) + call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy xy", @:) + call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy ttt", @:) + set wildoptions=fuzzy + call feedkeys(":Fuzzy \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy format goformat TestFOrmat fendoff state", @:) + call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy format TestFOrmat goformat fendoff", @:) + call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy xy", @:) + call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"Fuzzy TestFOrmat", @:) + delcom Fuzzy + set wildoptions& +endfunc + +" Test for :breakadd argument completion +func Test_cmdline_complete_breakadd() + call feedkeys(":breakadd \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr file func here", @:) + call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr", @:) + call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr", @:) + call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd here", @:) + call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd here", @:) + call feedkeys(":breakadd abc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd abc", @:) + call assert_equal(['expr', 'file', 'func', 'here'], getcompletion('', 'breakpoint')) + let l = getcompletion('not', 'breakpoint') + call assert_equal([], l) + + " Test for :breakadd file [lnum] <file> + call writefile([], 'Xscript') + call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file Xscript", @:) + call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file Xscript", @:) + call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file 20 Xscript", @:) + call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file 20 Xscript", @:) + call feedkeys(":breakadd file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file 20x Xsc\t", @:) + call feedkeys(":breakadd file 20\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file 20\t", @:) + call feedkeys(":breakadd file 20x\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file 20x\t", @:) + call feedkeys(":breakadd file Xscript \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file Xscript ", @:) + call feedkeys(":breakadd file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd file X1B2C3", @:) + call delete('Xscript') + + " Test for :breakadd func [lnum] <function> + func Xbreak_func() + endfunc + call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func Xbreak_func", @:) + call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func Xbreak_func", @:) + call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func 20 Xbreak_func", @:) + call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func 20 Xbreak_func", @:) + call feedkeys(":breakadd func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func 20x Xbr\t", @:) + call feedkeys(":breakadd func 20\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func 20\t", @:) + call feedkeys(":breakadd func 20x\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func 20x\t", @:) + call feedkeys(":breakadd func Xbreak_func \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func Xbreak_func ", @:) + call feedkeys(":breakadd func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd func X1B2C3", @:) + delfunc Xbreak_func + + " Test for :breakadd expr <expression> + let g:Xtest_var = 10 + call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr Xtest_var", @:) + call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr Xtest_var", @:) + call feedkeys(":breakadd expr Xtest_var \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr Xtest_var ", @:) + call feedkeys(":breakadd expr X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd expr X1B2C3", @:) + unlet g:Xtest_var + + " Test for :breakadd here + call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd here Xtest", @:) + call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd here Xtest", @:) + call feedkeys(":breakadd here \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakadd here ", @:) +endfunc + +" Test for :breakdel argument completion +func Test_cmdline_complete_breakdel() + call feedkeys(":breakdel \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file func here", @:) + call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file", @:) + call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file", @:) + call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel here", @:) + call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel here", @:) + call feedkeys(":breakdel abc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel abc", @:) + + " Test for :breakdel file [lnum] <file> + call writefile([], 'Xscript') + call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file Xscript", @:) + call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file Xscript", @:) + call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file 20 Xscript", @:) + call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file 20 Xscript", @:) + call feedkeys(":breakdel file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file 20x Xsc\t", @:) + call feedkeys(":breakdel file 20\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file 20\t", @:) + call feedkeys(":breakdel file 20x\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file 20x\t", @:) + call feedkeys(":breakdel file Xscript \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file Xscript ", @:) + call feedkeys(":breakdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel file X1B2C3", @:) + call delete('Xscript') + + " Test for :breakdel func [lnum] <function> + func Xbreak_func() + endfunc + call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func Xbreak_func", @:) + call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func Xbreak_func", @:) + call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func 20 Xbreak_func", @:) + call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func 20 Xbreak_func", @:) + call feedkeys(":breakdel func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func 20x Xbr\t", @:) + call feedkeys(":breakdel func 20\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func 20\t", @:) + call feedkeys(":breakdel func 20x\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func 20x\t", @:) + call feedkeys(":breakdel func Xbreak_func \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func Xbreak_func ", @:) + call feedkeys(":breakdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel func X1B2C3", @:) + delfunc Xbreak_func + + " Test for :breakdel here + call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel here Xtest", @:) + call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel here Xtest", @:) + call feedkeys(":breakdel here \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"breakdel here ", @:) +endfunc + +" Test for :scriptnames argument completion +func Test_cmdline_complete_scriptnames() + set wildmenu + call writefile(['let a = 1'], 'Xa1b2c3.vim') + source Xa1b2c3.vim + call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx') + call assert_match("\"script .*Xa1b2c3.vim$", @:) + call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx') + call assert_match("\"script .*Xa1b2c3.vim$", @:) + call feedkeys(":script b2c3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"script b2c3", @:) + call feedkeys(":script 2\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match("\"script 2\<Tab>$", @:) + call feedkeys(":script \<Tab>\<Left>\<Left> \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match("\"script .*Xa1b2c3.vim $", @:) + call feedkeys(":script \<Tab>\<Left>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"script ", @:) + call assert_match('Xa1b2c3.vim$', getcompletion('.*Xa1b2.*', 'scriptnames')[0]) + call assert_equal([], getcompletion('Xa1b2', 'scriptnames')) + new + call feedkeys(":script \<Tab>\<Left>\<Left>\<CR>", 'tx') + call assert_equal('Xa1b2c3.vim', fnamemodify(@%, ':t')) + bw! + call delete('Xa1b2c3.vim') + set wildmenu& +endfunc + " this was going over the end of IObuff func Test_report_error_with_composing() let caught = 'no' @@ -2635,6 +3460,16 @@ func Test_cmdline_complete_substitute_short() endfor endfunc +" Test for :! shell command argument completion +func Test_cmdline_complete_bang_cmd_argument() + set wildoptions=fuzzy + call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"!vim test_cmdline.vim', @:) + set wildoptions& + call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"!vim test_cmdline.vim', @:) +endfunc + func Check_completion() call assert_equal('let a', getcmdline()) call assert_equal(6, getcmdpos()) diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim index 7f19085b16..4a6c8779dd 100644 --- a/src/nvim/testdir/test_const.vim +++ b/src/nvim/testdir/test_const.vim @@ -194,6 +194,14 @@ func Test_lockvar() if 0 | lockvar x | endif let x = 'again' + + let val = [1, 2, 3] + lockvar 0 val + let val[0] = 9 + call assert_equal([9, 2, 3], val) + call add(val, 4) + call assert_equal([9, 2, 3, 4], val) + call assert_fails('let val = [4, 5, 6]', 'E1122:') endfunc diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim index 47646125db..70f39a8601 100644 --- a/src/nvim/testdir/test_cursorline.vim +++ b/src/nvim/testdir/test_cursorline.vim @@ -319,7 +319,7 @@ func Test_cursorline_cursorbind_horizontal_scroll() let lines =<< trim END call setline(1, 'aa bb cc dd ee ff gg hh ii jj kk ll mm' .. - \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz') + \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz') set nowrap " The following makes the cursor apparent on the screen dump set sidescroll=1 cursorcolumn diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim index 4609b9d2f9..f5177c8fb2 100644 --- a/src/nvim/testdir/test_debugger.vim +++ b/src/nvim/testdir/test_debugger.vim @@ -36,7 +36,7 @@ endfunc " If the expected output argument is supplied, then check for it. func RunDbgCmd(buf, cmd, ...) call term_sendkeys(a:buf, a:cmd . "\r") - call term_wait(a:buf) + call term_wait(a:buf, 20) if a:0 != 0 let options = #{match: 'equal'} diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index fd54f77ccb..89a9179e60 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -336,8 +336,23 @@ func Test_edit_11_indentexpr() endfunc set indentexpr=s:NewIndentExpr() call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr) + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr) set indentexpr=<SID>NewIndentExpr() call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr) + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr) + setlocal indentexpr= + setglobal indentexpr=s:NewIndentExpr() + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr) + call assert_equal('', &indentexpr) + new + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr) + bw! + setglobal indentexpr=<SID>NewIndentExpr() + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr) + call assert_equal('', &indentexpr) + new + call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr) + bw! set indentexpr& bw! diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index b065df68f7..88c25ab115 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -98,6 +98,7 @@ let s:filename_checks = { \ 'cabalconfig': ['cabal.config'], \ 'cabalproject': ['cabal.project', 'cabal.project.local'], \ 'calendar': ['calendar', '/.calendar/file', '/share/calendar/any/calendar.file', '/share/calendar/calendar.file', 'any/share/calendar/any/calendar.file', 'any/share/calendar/calendar.file'], + \ 'capnp': ['file.capnp'], \ 'catalog': ['catalog', 'sgml.catalogfile', 'sgml.catalog', 'sgml.catalog-file'], \ 'cdl': ['file.cdl'], \ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'], @@ -122,7 +123,7 @@ let s:filename_checks = { \ 'conaryrecipe': ['file.recipe'], \ 'conf': ['auto.master'], \ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file', 'any/etc/hostname.file'], - \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials'], + \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials', 'file.nmconnection'], \ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'], \ 'cook': ['file.cook'], \ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'], @@ -180,6 +181,7 @@ let s:filename_checks = { \ 'elixir': ['file.ex', 'file.exs', 'mix.lock'], \ 'elm': ['file.elm'], \ 'elmfilt': ['filter-rules'], + \ 'elsa': ['file.lc'], \ 'elvish': ['file.elv'], \ 'epuppet': ['file.epp'], \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'], @@ -293,13 +295,14 @@ let s:filename_checks = { \ 'jq': ['file.jq'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'], - \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', 'file.slnf'], + \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf'], \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json'], \ 'jsonnet': ['file.jsonnet', 'file.libsonnet'], \ 'jsp': ['file.jsp'], \ 'julia': ['file.jl'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'], + \ 'kdl': ['file.kdl'], \ 'kivy': ['file.kv'], \ 'kix': ['file.kix'], \ 'kotlin': ['file.kt', 'file.ktm', 'file.kts'], @@ -580,6 +583,7 @@ let s:filename_checks = { \ 'texmf': ['texmf.cnf'], \ 'text': ['file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'], \ 'tf': ['file.tf', '.tfrc', 'tfrc'], + \ 'thrift': ['file.thrift'], \ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'], \ 'tilde': ['file.t.html'], \ 'tla': ['file.tla'], @@ -653,7 +657,7 @@ let s:filename_checks = { \ 'xsd': ['file.xsd'], \ 'xslt': ['file.xsl', 'file.xslt'], \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'], - \ 'yaml': ['file.yaml', 'file.yml', '.clang-format', '.clang-tidy'], + \ 'yaml': ['file.yaml', 'file.yml', '.clangd', '.clang-format', '.clang-tidy'], \ 'yang': ['file.yang'], \ 'z8a': ['file.z8a'], \ 'zig': ['file.zig'], diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 130ad9c7e1..9014948fb4 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -1305,6 +1305,7 @@ func Test_foldexpr_scriptlocal_func() set foldmethod=expr foldexpr=s:FoldFunc() redraw! call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr) + call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr) call assert_equal(1, g:FoldLnum) set foldmethod& foldexpr= bw! @@ -1314,8 +1315,31 @@ func Test_foldexpr_scriptlocal_func() set foldmethod=expr foldexpr=<SID>FoldFunc() redraw! call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr) + call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr) call assert_equal(1, g:FoldLnum) - set foldmethod& foldexpr= + bw! + call setline(1, 'abc') + setlocal foldmethod& foldexpr& + setglobal foldmethod=expr foldexpr=s:FoldFunc() + call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr) + call assert_equal('0', &foldexpr) + enew! + call setline(1, 'abc') + redraw! + call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr) + call assert_equal(1, g:FoldLnum) + bw! + call setline(1, 'abc') + setlocal foldmethod& foldexpr& + setglobal foldmethod=expr foldexpr=<SID>FoldFunc() + call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr) + call assert_equal('0', &foldexpr) + enew! + call setline(1, 'abc') + redraw! + call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr) + call assert_equal(1, g:FoldLnum) + set foldmethod& foldexpr& delfunc s:FoldFunc bw! endfunc @@ -1329,25 +1353,53 @@ func Test_foldtext_scriptlocal_func() new | only call setline(1, range(50)) let g:FoldTextArgs = [] - set foldmethod=manual set foldtext=s:FoldText() norm! 4Gzf4j redraw! call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext) + call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext) call assert_equal([4, 8], g:FoldTextArgs) set foldtext& bw! new | only call setline(1, range(50)) let g:FoldTextArgs = [] - set foldmethod=manual set foldtext=<SID>FoldText() norm! 8Gzf4j redraw! call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext) + call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext) call assert_equal([8, 12], g:FoldTextArgs) set foldtext& bw! + call setline(1, range(50)) + let g:FoldTextArgs = [] + setlocal foldtext& + setglobal foldtext=s:FoldText() + call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext) + call assert_equal('foldtext()', &foldtext) + enew! + call setline(1, range(50)) + norm! 12Gzf4j + redraw! + call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext) + call assert_equal([12, 16], g:FoldTextArgs) + set foldtext& + bw! + call setline(1, range(50)) + let g:FoldTextArgs = [] + setlocal foldtext& + setglobal foldtext=<SID>FoldText() + call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext) + call assert_equal('foldtext()', &foldtext) + enew! + call setline(1, range(50)) + norm! 16Gzf4j + redraw! + call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext) + call assert_equal([16, 20], g:FoldTextArgs) + set foldtext& + bw! delfunc s:FoldText endfunc @@ -1483,4 +1535,17 @@ func Test_indent_with_L_command() bwipe! endfunc +" Make sure that when there is a fold at the bottom of the buffer and a newline +" character is appended to the line, the fold gets expanded (instead of the new +" line not being part of the fold). +func Test_expand_fold_at_bottom_of_buffer() + new + " create a fold on the only line + fold + execute "normal A\<CR>" + call assert_equal([1, 1], range(1, 2)->map('foldlevel(v:val)')) + + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim index e369645328..f09dbd72ce 100644 --- a/src/nvim/testdir/test_gf.vim +++ b/src/nvim/testdir/test_gf.vim @@ -234,6 +234,7 @@ func Test_includeexpr_scriptlocal_func() endfunc set includeexpr=s:IncludeFunc() call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr) + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr) new | only call setline(1, 'TestFile1') let g:IncludeFname = '' @@ -242,11 +243,35 @@ func Test_includeexpr_scriptlocal_func() bw! set includeexpr=<SID>IncludeFunc() call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr) + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr) new | only call setline(1, 'TestFile2') let g:IncludeFname = '' call assert_fails('normal! gf', 'E447:') call assert_equal('TestFile2', g:IncludeFname) + bw! + setlocal includeexpr= + setglobal includeexpr=s:IncludeFunc() + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr) + call assert_equal('', &includeexpr) + new + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr) + call setline(1, 'TestFile3') + let g:IncludeFname = '' + call assert_fails('normal! gf', 'E447:') + call assert_equal('TestFile3', g:IncludeFname) + bw! + setlocal includeexpr= + setglobal includeexpr=<SID>IncludeFunc() + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr) + call assert_equal('', &includeexpr) + new + call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr) + call setline(1, 'TestFile4') + let g:IncludeFname = '' + call assert_fails('normal! gf', 'E447:') + call assert_equal('TestFile4', g:IncludeFname) + bw! set includeexpr& delfunc s:IncludeFunc bw! diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 7a9392545e..ec1379a378 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -581,6 +581,33 @@ func Test_pum_with_folds_two_tabs() call delete('Xpumscript') endfunc +func Test_pum_with_preview_win() + CheckScreendump + + let lines =<< trim END + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] + endfunc + set omnifunc=Omni_test + set completeopt+=longest + END + + call writefile(lines, 'Xpreviewscript') + let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12}) + call term_wait(buf, 100) + call term_sendkeys(buf, "Gi\<C-X>\<C-O>") + call term_wait(buf, 200) + call term_sendkeys(buf, "\<C-N>") + call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {}) + + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) + call delete('Xpreviewscript') +endfunc + " Test for inserting the tag search pattern in insert mode func Test_ins_compl_tag_sft() call writefile([ diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 8d7bede403..9ecd83265a 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -357,7 +357,7 @@ endfunc " Locked variables func Test_list_locked_var() let expected = [ - \ [['0000-000', 'ppppppp'], + \ [['1000-000', 'ppppppF'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppppppF'], @@ -384,7 +384,7 @@ func Test_list_locked_var() exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") - call assert_equal(expected[depth][u][0], ps) + call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth) let ps = '' try let l[1][1][0] = 99 @@ -428,7 +428,7 @@ func Test_list_locked_var() catch let ps .= 'F' endtry - call assert_equal(expected[depth][u][1], ps) + call assert_equal(expected[depth][u][1], ps, 'depth: ' .. depth) endfor endfor call assert_fails("let x=islocked('a b')", 'E488:') @@ -441,7 +441,7 @@ endfunc " Unletting locked variables func Test_list_locked_var_unlet() let expected = [ - \ [['0000-000', 'ppppppp'], + \ [['1000-000', 'ppppppp'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppFppFp'], @@ -469,7 +469,7 @@ func Test_list_locked_var_unlet() exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") - call assert_equal(expected[depth][u][0], ps) + call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth) let ps = '' try unlet l[2]['6'][7] @@ -673,6 +673,9 @@ func Test_func_arg_list() call s:arg_list_test(1, 2, [3, 4], {5: 6}) endfunc +func Test_dict_item_locked() +endfunc + " Tests for reverse(), sort(), uniq() func Test_reverse_sort_uniq() let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 7c90b444e5..2aaa1ff830 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -262,6 +262,7 @@ func Test_formatexpr_scriptlocal_func() endfunc set formatexpr=s:Format() call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -270,6 +271,7 @@ func Test_formatexpr_scriptlocal_func() bw! set formatexpr=<SID>Format() call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -277,6 +279,7 @@ func Test_formatexpr_scriptlocal_func() call assert_equal([4, 2], g:FormatArgs) bw! let &formatexpr = 's:Format()' + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] @@ -284,12 +287,55 @@ func Test_formatexpr_scriptlocal_func() call assert_equal([6, 2], g:FormatArgs) bw! let &formatexpr = '<SID>Format()' + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) new | only call setline(1, range(1, 40)) let g:FormatArgs = [] normal! 8GVjgq call assert_equal([8, 2], g:FormatArgs) + bw! setlocal formatexpr= + setglobal formatexpr=s:Format() + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 10GVjgq + call assert_equal([10, 2], g:FormatArgs) + bw! + setglobal formatexpr=<SID>Format() + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 12GVjgq + call assert_equal([12, 2], g:FormatArgs) + bw! + let &g:formatexpr = 's:Format()' + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 14GVjgq + call assert_equal([14, 2], g:FormatArgs) + bw! + let &g:formatexpr = '<SID>Format()' + call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr) + call assert_equal('', &formatexpr) + new + call assert_equal(expand('<SID>') .. 'Format()', &formatexpr) + call setline(1, range(1, 40)) + let g:FormatArgs = [] + normal! 16GVjgq + call assert_equal([16, 2], g:FormatArgs) + bw! + set formatexpr= delfunc s:Format bw! endfunc diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 11c2977a4e..f51de94bac 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -1238,6 +1238,30 @@ func Test_opt_cdhome() set cdhome& endfunc +func Test_set_completion_2() + CheckOption termguicolors + + " Test default option completion + set wildoptions= + call feedkeys(":set termg\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set termguicolors', @:) + + call feedkeys(":set notermg\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set notermguicolors', @:) + + " Test fuzzy option completion + set wildoptions=fuzzy + call feedkeys(":set termg\<C-A>\<C-B>\"\<CR>", 'tx') + " Nvim doesn't have 'termencoding' + " call assert_equal('"set termguicolors termencoding', @:) + call assert_equal('"set termguicolors', @:) + + call feedkeys(":set notermg\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"set notermguicolors', @:) + + set wildoptions= +endfunc + func Test_switchbuf_reset() set switchbuf=useopen sblast diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim index fcb8b8033b..3121b3b4d1 100644 --- a/src/nvim/testdir/test_packadd.vim +++ b/src/nvim/testdir/test_packadd.vim @@ -26,7 +26,7 @@ func Test_packadd() let rtp_entries = split(rtp, ',') for entry in rtp_entries - if entry =~? '\<after\>' + if entry =~? '\<after\>' let first_after_entry = entry break endif @@ -186,15 +186,17 @@ func Test_packadd_symlink_dir2() exec "silent !rmdir" top2_dir endfunc -" Check command-line completion for 'packadd' +" Check command-line completion for :packadd func Test_packadd_completion() let optdir1 = &packpath . '/pack/mine/opt' let optdir2 = &packpath . '/pack/candidate/opt' call mkdir(optdir1 . '/pluginA', 'p') call mkdir(optdir1 . '/pluginC', 'p') + call writefile([], optdir1 . '/unrelated') call mkdir(optdir2 . '/pluginB', 'p') call mkdir(optdir2 . '/pluginC', 'p') + call writefile([], optdir2 . '/unrelated') let li = [] call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't') @@ -260,9 +262,9 @@ func Test_helptags() helptags ALL - let tags1 = readfile(docdir1 . '/tags') + let tags1 = readfile(docdir1 . '/tags') call assert_match('look-here', tags1[0]) - let tags2 = readfile(docdir2 . '/tags') + let tags2 = readfile(docdir2 . '/tags') call assert_match('look-away', tags2[0]) call assert_fails('helptags abcxyz', 'E150:') @@ -358,4 +360,78 @@ func Test_runtime() call assert_equal('runstartopt', g:sequence) endfunc +func Test_runtime_completion() + let rundir = &packpath . '/runtime/Aextra' + let startdir = &packpath . '/pack/mine/start/foo/Aextra' + let optdir = &packpath . '/pack/mine/opt/bar/Aextra' + call mkdir(rundir . '/Arunbaz', 'p') + call mkdir(startdir . '/Astartbaz', 'p') + call mkdir(optdir . '/Aoptbaz', 'p') + call writefile([], rundir . '/../Arunfoo.vim') + call writefile([], rundir . '/Arunbar.vim') + call writefile([], rundir . '/Aunrelated') + call writefile([], rundir . '/../Aunrelated') + call writefile([], startdir . '/../Astartfoo.vim') + call writefile([], startdir . '/Astartbar.vim') + call writefile([], startdir . '/Aunrelated') + call writefile([], startdir . '/../Aunrelated') + call writefile([], optdir . '/../Aoptfoo.vim') + call writefile([], optdir . '/Aoptbar.vim') + call writefile([], optdir . '/Aunrelated') + call writefile([], optdir . '/../Aunrelated') + exe 'set rtp=' . &packpath . '/runtime' + + func Check_runtime_completion(arg, arg1, res) + call feedkeys(':runtime ' .. a:arg .. "\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:) + call assert_equal(a:res, getcompletion(a:arg, 'runtime')) + endfunc + + call Check_runtime_completion('', '', + \ ['Aextra/', 'Arunfoo.vim', 'START', 'OPT', 'PACK', 'ALL']) + call Check_runtime_completion('S', '', + \ ['START']) + call Check_runtime_completion('O', '', + \ ['OPT']) + call Check_runtime_completion('P', '', + \ ['PACK']) + call Check_runtime_completion('A', '', + \ ['Aextra/', 'Arunfoo.vim', 'ALL']) + call Check_runtime_completion('Aextra/', '', + \ ['Aextra/Arunbar.vim', 'Aextra/Arunbaz/']) + + call Check_runtime_completion('START ', 'START ', + \ ['Aextra/', 'Astartfoo.vim']) + call Check_runtime_completion('START A', 'START ', + \ ['Aextra/', 'Astartfoo.vim']) + call Check_runtime_completion('START Aextra/', 'START ', + \ ['Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) + + call Check_runtime_completion('OPT ', 'OPT ', + \ ['Aextra/', 'Aoptfoo.vim']) + call Check_runtime_completion('OPT A', 'OPT ', + \ ['Aextra/', 'Aoptfoo.vim']) + call Check_runtime_completion('OPT Aextra/', 'OPT ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/']) + + call Check_runtime_completion('PACK ', 'PACK ', + \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('PACK A', 'PACK ', + \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('PACK Aextra/', 'PACK ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/', + \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) + + call Check_runtime_completion('ALL ', 'ALL ', + \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('ALL A', 'ALL ', + \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim']) + call Check_runtime_completion('ALL Aextra/', 'ALL ', + \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/', + \ 'Aextra/Arunbar.vim', 'Aextra/Arunbaz/', + \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/']) + + delfunc Check_runtime_completion +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index 4225b91bc4..9165f7bace 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -403,6 +403,47 @@ func Test_profile_completion() call feedkeys(":profile start test_prof\<C-A>\<C-B>\"\<CR>", 'tx') call assert_match('^"profile start.* test_profile\.vim', @:) + + call feedkeys(":profile file test_prof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match('"profile file test_profile\.vim', @:) + call feedkeys(":profile file test_prof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match('"profile file test_profile\.vim', @:) + call feedkeys(":profile file test_prof \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match('"profile file test_prof ', @:) + call feedkeys(":profile file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_match('"profile file X1B2C3', @:) + + func Xprof_test() + endfunc + call feedkeys(":profile func Xprof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profile func Xprof_test', @:) + call feedkeys(":profile func Xprof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profile func Xprof_test', @:) + call feedkeys(":profile func Xprof \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profile func Xprof ', @:) + call feedkeys(":profile func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profile func X1B2C3', @:) + + call feedkeys(":profdel \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel file func', @:) + call feedkeys(":profdel fu\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel func', @:) + call feedkeys(":profdel he\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel he', @:) + call feedkeys(":profdel here \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel here ', @:) + call feedkeys(":profdel file test_prof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel file test_profile.vim', @:) + call feedkeys(":profdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel file X1B2C3', @:) + call feedkeys(":profdel func Xprof\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel func Xprof_test', @:) + call feedkeys(":profdel func Xprof_test \<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel func Xprof_test ', @:) + call feedkeys(":profdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx') + call assert_equal('"profdel func X1B2C3', @:) + + delfunc Xprof_test endfunc func Test_profile_errors() diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index a9cad3ed44..885043accf 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -1377,6 +1377,22 @@ func Test_subst_word_under_cursor() set noincsearch endfunc +func Test_search_skip_all_matches() + enew + call setline(1, ['no match here', + \ 'match this line', + \ 'nope', + \ 'match in this line', + \ 'last line', + \ ]) + call cursor(1, 1) + let lnum = search('this', '', 0, 0, 'getline(".") =~ "this line"') + " Only check that no match is found. Previously it searched forever. + call assert_equal(0, lnum) + + bwipe! +endfunc + func Test_search_undefined_behaviour() CheckFeature terminal diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim index 77bd50ada2..1b2d854829 100644 --- a/src/nvim/testdir/test_search_stat.vim +++ b/src/nvim/testdir/test_search_stat.vim @@ -270,6 +270,29 @@ func Test_searchcount_fails() call assert_fails('echo searchcount({"pos" : [1, 2, []]})', 'E745:') endfunc +func Test_search_stat_narrow_screen() + " This used to crash Vim + let save_columns = &columns + try + let after =<< trim [CODE] + set laststatus=2 + set columns=16 + set shortmess-=S showcmd + call setline(1, 'abc') + call feedkeys("/abc\<CR>:quit!\<CR>") + autocmd VimLeavePre * call writefile(["done"], "Xdone") + [CODE] + + if !RunVim([], after, '--clean') + return + endif + call assert_equal("done", readfile("Xdone")[0]) + call delete('Xdone') + finally + let &columns = save_columns + endtry +endfunc + func Test_searchcount_in_statusline() CheckScreendump diff --git a/src/nvim/testdir/test_shell.vim b/src/nvim/testdir/test_shell.vim new file mode 100644 index 0000000000..8b9c7a5b12 --- /dev/null +++ b/src/nvim/testdir/test_shell.vim @@ -0,0 +1,209 @@ +" Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe', +" 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote') + +source check.vim +source shared.vim + +func Test_shell_options() + " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote', + " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells. + let shells = [] + if has('unix') + let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], + \ ['csh', '-c', '|& tee', '', '>&', '', ''], + \ ['tcsh', '-c', '|& tee', '', '>&', '', '']] + endif + if has('win32') + let shells += [['cmd', '/s /c', '>%s 2>&1', '', '>%s 2>&1', '', '"']] + endif + + " start a new Vim instance with 'shell' set to each of the supported shells + " and check the default shell option settings + let after =<< trim END + let l = [&shell, &shellcmdflag, &shellpipe, &shellquote] + let l += [&shellredir, &shellxescape, &shellxquote] + call writefile([json_encode(l)], 'Xtestout') + qall! + END + for e in shells + if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"') + call assert_equal(e, json_decode(readfile('Xtestout')[0])) + endif + endfor + + " Test shellescape() for each of the shells. + for e in shells + exe 'set shell=' .. e[0] + if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'" + elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' + let str1 = "'cmd \"arg1\" ''arg2'' !%#'" + let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'" + else + let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'" + let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'" + endif + call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%#"), e[0]) + call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%#", 1), e[0]) + + " Try running an external command with the shell. + if executable(e[0]) + " set the shell options for the current 'shell' + let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, + \ &shellxescape, &shellxquote] = e[1:6] + new + r !echo hello + call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) + bwipe! + endif + endfor + set shell& shellcmdflag& shellpipe& shellquote& + set shellredir& shellxescape& shellxquote& + call delete('Xtestout') +endfunc + +" Test for the 'shell' option +func Test_shell() + throw 'Skipped: Nvim missing :shell currently' + CheckUnix + let save_shell = &shell + set shell= + let caught_e91 = 0 + try + shell + catch /E91:/ + let caught_e91 = 1 + endtry + call assert_equal(1, caught_e91) + let &shell = save_shell +endfunc + +" Test for the 'shellquote' option +func Test_shellquote() + CheckUnix + set shellquote=# + set verbose=20 + redir => v + silent! !echo Hello + redir END + set verbose& + set shellquote& + call assert_match(': "#echo Hello#"', v) +endfunc + +" Test for the 'shellescape' option +func Test_shellescape() + let save_shell = &shell + set shell=bash + call assert_equal("'text'", shellescape('text')) + call assert_equal("'te\"xt'", 'te"xt'->shellescape()) + call assert_equal("'te'\\''xt'", shellescape("te'xt")) + + call assert_equal("'te%xt'", shellescape("te%xt")) + call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) + call assert_equal("'te#xt'", shellescape("te#xt")) + call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) + call assert_equal("'te!xt'", shellescape("te!xt")) + call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + + call assert_equal("'te\nxt'", shellescape("te\nxt")) + call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) + set shell=tcsh + call assert_equal("'te\\!xt'", shellescape("te!xt")) + call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) + call assert_equal("'te\\\nxt'", shellescape("te\nxt")) + call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) + + let &shell = save_shell +endfunc + +" Test for 'shellslash' +func Test_shellslash() + CheckOption shellslash + let save_shellslash = &shellslash + " The shell and cmdflag, and expected slash in tempname with shellslash set or + " unset. The assert checks the file separator before the leafname. + " ".*\\\\[^\\\\]*$" + let shells = [['cmd', '/c', '/', '/'], + \ ['powershell', '-Command', '/', '/'], + \ ['sh', '-c', '/', '/']] + for e in shells + exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] + set noshellslash + let file = tempname() + call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') + set shellslash + let file = tempname() + call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') + endfor + let &shellslash = save_shellslash +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 + +" Test for using the shell set in the $SHELL environment variable +func Test_set_shell() + let after =<< trim [CODE] + call writefile([&shell], "Xtestout") + quit! + [CODE] + + if has('win32') + let $SHELL = 'C:\with space\cmd.exe' + let expected = '"C:\with space\cmd.exe"' + else + let $SHELL = '/bin/with space/sh' + let expected = '"/bin/with space/sh"' + endif + + if RunVimPiped([], after, '', '') + let lines = readfile('Xtestout') + call assert_equal(expected, lines[0]) + endif + call delete('Xtestout') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index a919156066..c840e834b9 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -531,8 +531,23 @@ func Test_spellsuggest_timeout() call assert_fails('set spellsuggest=timeout:--9', 'E474:') endfunc +func Test_spellsuggest_visual_end_of_line() + let enc_save = &encoding + " set encoding=iso8859 + + " This was reading beyond the end of the line. + norm R00000000000 + sil norm 0 + sil! norm i00000) + sil! norm i00000) + call feedkeys("\<CR>") + norm z= + + let &encoding = enc_save +endfunc + func Test_spellinfo() - throw 'skipped: Nvim does not support enc=latin1' + throw 'Skipped: Nvim does not support enc=latin1' new let runtime = substitute($VIMRUNTIME, '\\', '/', 'g') diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index 54b7636f69..1ee1d0dfe3 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -725,27 +725,6 @@ func Test_read_stdin() call delete('Xtestout') endfunc -func Test_set_shell() - let after =<< trim [CODE] - call writefile([&shell], "Xtestout") - quit! - [CODE] - - if has('win32') - let $SHELL = 'C:\with space\cmd.exe' - let expected = '"C:\with space\cmd.exe"' - else - let $SHELL = '/bin/with space/sh' - let expected = '"/bin/with space/sh"' - endif - - if RunVimPiped([], after, '', '') - let lines = readfile('Xtestout') - call assert_equal(expected, lines[0]) - endif - call delete('Xtestout') -endfunc - func Test_progpath() " Tests normally run with "./vim" or "../vim", these must have been expanded " to a full path. @@ -1064,7 +1043,7 @@ func Test_io_not_a_terminal() \ 'Vim: Warning: Input is not from a terminal'], l) endfunc -" Test for --not-a-term avoiding escape codes. +" Test for not being a term avoiding escape codes. func Test_not_a_term() CheckUnix CheckNotGui @@ -1075,18 +1054,14 @@ func Test_not_a_term() let redir = &shellredir .. ' Xvimout' endif - " Without --not-a-term there are a few escape sequences. - " This will take 2 seconds because of the missing --not-a-term + " As nvim checks the environment by itself there will be no escape sequences + " This will also happen to take two (2) seconds. let cmd = GetVimProg() .. ' --cmd quit ' .. redir exe "silent !" . cmd - call assert_match("\<Esc>", readfile('Xvimout')->join()) + call assert_notmatch("\e", readfile('Xvimout')->join()) call delete('Xvimout') - " With --not-a-term there are no escape sequences. - let cmd = GetVimProg() .. ' --not-a-term --cmd quit ' .. redir - exe "silent !" . cmd - call assert_notmatch("\<Esc>", readfile('Xvimout')->join()) - call delete('Xvimout') + " --not-a-term flag has thus been deleted endfunc diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index 5fd30c7da7..c99a0d456d 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -1076,6 +1076,19 @@ func Test_sub_open_cmdline_win() call delete('Xresult') endfunc +" This was editing a script file from the expression +func Test_sub_edit_scriptfile() + new + norm o0000000000000000000000000000000000000000000000000000 + func EditScript() + silent! scr! Xfile + endfunc + s/\%')/\=EditScript() + + delfunc EditScript + bwipe! +endfunc + " Test for the 2-letter and 3-letter :substitute commands func Test_substitute_short_cmd() new diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim index bfa8a277bd..6c8373b335 100644 --- a/src/nvim/testdir/test_system.vim +++ b/src/nvim/testdir/test_system.vim @@ -142,40 +142,4 @@ func Test_system_with_shell_quote() 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_taglist.vim b/src/nvim/testdir/test_taglist.vim index 0387ef2bd8..75d28c3ec4 100644 --- a/src/nvim/testdir/test_taglist.vim +++ b/src/nvim/testdir/test_taglist.vim @@ -105,8 +105,8 @@ func Test_tagfiles() help let tf = tagfiles() " Nvim: expectation(s) based on tags in build dir (added to &rtp). - " Filter out the (non-existing) '../../../runtime/doc/tags'. - call filter(tf, 'filereadable(v:val)') + " Filter out the '../../../runtime/doc/tags'. + call filter(tf, 'v:val != "../../../runtime/doc/tags"') call assert_equal(1, len(tf)) call assert_equal(fnamemodify(expand('$BUILD_DIR/runtime/doc/tags'), ':p:gs?\\?/?'), \ fnamemodify(tf[0], ':p:gs?\\?/?')) diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim index 9146cf7ab3..e5f6d68720 100644 --- a/src/nvim/testdir/test_utf8.vim +++ b/src/nvim/testdir/test_utf8.vim @@ -167,6 +167,39 @@ func Test_setcellwidths() call assert_equal(2, strwidth("\u1339")) call assert_equal(1, strwidth("\u133a")) + for aw in ['single', 'double'] + exe 'set ambiwidth=' . aw + " Handle \u0080 to \u009F as control chars even on MS-Windows. + set isprint=@,161-255 + + call setcellwidths([]) + " Control chars + call assert_equal(4, strwidth("\u0081")) + call assert_equal(6, strwidth("\uFEFF")) + " Ambiguous width chars + call assert_equal((aw == 'single') ? 1 : 2, strwidth("\u00A1")) + call assert_equal((aw == 'single') ? 1 : 2, strwidth("\u2010")) + + call setcellwidths([[0x81, 0x81, 1], [0xA1, 0xA1, 1], + \ [0x2010, 0x2010, 1], [0xFEFF, 0xFEFF, 1]]) + " Control chars + call assert_equal(4, strwidth("\u0081")) + call assert_equal(6, strwidth("\uFEFF")) + " Ambiguous width chars + call assert_equal(1, strwidth("\u00A1")) + call assert_equal(1, strwidth("\u2010")) + + call setcellwidths([[0x81, 0x81, 2], [0xA1, 0xA1, 2], + \ [0x2010, 0x2010, 2], [0xFEFF, 0xFEFF, 2]]) + " Control chars + call assert_equal(4, strwidth("\u0081")) + call assert_equal(6, strwidth("\uFEFF")) + " Ambiguous width chars + call assert_equal(2, strwidth("\u00A1")) + call assert_equal(2, strwidth("\u2010")) + endfor + set ambiwidth& isprint& + call setcellwidths([]) call assert_fails('call setcellwidths(1)', 'E714:') @@ -199,6 +232,26 @@ func Test_setcellwidths() call setcellwidths([]) endfunc +func Test_getcellwidths() + call setcellwidths([]) + call assert_equal([], getcellwidths()) + + let widthlist = [ + \ [0x1330, 0x1330, 2], + \ [9999, 10000, 1], + \ [0x1337, 0x1339, 2], + \] + let widthlistsorted = [ + \ [0x1330, 0x1330, 2], + \ [0x1337, 0x1339, 2], + \ [9999, 10000, 1], + \] + call setcellwidths(widthlist) + call assert_equal(widthlistsorted, getcellwidths()) + + call setcellwidths([]) +endfunc + func Test_setcellwidths_dump() CheckRunVimInTerminal diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim index 2bf8c3fc77..20a5f87517 100644 --- a/src/nvim/testdir/test_virtualedit.vim +++ b/src/nvim/testdir/test_virtualedit.vim @@ -537,6 +537,19 @@ func Test_global_local_virtualedit() set virtualedit& endfunc +func Test_virtualedit_setlocal() + enew + setglobal virtualedit=all + setlocal virtualedit=all + normal! l + redraw + setlocal virtualedit=none + call assert_equal(1, wincol()) + + setlocal virtualedit& + set virtualedit& +endfunc + func Test_virtualedit_mouse() let save_mouse = &mouse set mouse=a diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 14d62089cf..1e9629c2c4 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -1319,6 +1319,17 @@ func Test_visual_block_with_substitute() endfunc func Test_visual_reselect_with_count() + enew + call setline(1, ['aaaaaa', '✗ bbbb', '✗ bbbb']) + exe "normal! 2Gw\<C-V>jed" + exe "normal! gg0lP" + call assert_equal(['abbbbaaaaa', '✗bbbb ', '✗ '], getline(1, '$')) + + exe "normal! 1vr." + call assert_equal(['a....aaaaa', '✗.... ', '✗ '], getline(1, '$')) + + bwipe! + " this was causing an illegal memory access let lines =<< trim END diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index 6d27407f82..6019cee193 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -896,6 +896,9 @@ endfunc " link to the original file. The backup file should not be modified. func Test_write_backup_symlink() CheckUnix + call mkdir('Xbackup') + let save_backupdir = &backupdir + set backupdir=.,./Xbackup call writefile(['1111'], 'Xfile') silent !ln -s Xfile Xfile.bak @@ -904,11 +907,18 @@ func Test_write_backup_symlink() write call assert_equal('link', getftype('Xfile.bak')) call assert_equal('Xfile', resolve('Xfile.bak')) + " backup file should be created in the 'backup' directory + if !has('bsd') + " This check fails on FreeBSD + call assert_true(filereadable('./Xbackup/Xfile.bak')) + endif set backup& backupcopy& backupext& - close + %bw call delete('Xfile') call delete('Xfile.bak') + call delete('Xbackup', 'rf') + let &backupdir = save_backupdir endfunc " Test for ':write ++bin' and ':write ++nobin' diff --git a/src/nvim/testing.c b/src/nvim/testing.c index edb24c6dc5..b5921b3445 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -68,61 +68,62 @@ static void prepare_assert_error(garray_T *gap) /// Append "p[clen]" to "gap", escaping unprintable characters. /// Changes NL to \n, CR to \r, etc. -static void ga_concat_esc(garray_T *gap, const char_u *p, int clen) +static void ga_concat_esc(garray_T *gap, const char *p, int clen) FUNC_ATTR_NONNULL_ALL { - char_u buf[NUMBUFLEN]; + char buf[NUMBUFLEN]; if (clen > 1) { memmove(buf, p, (size_t)clen); buf[clen] = NUL; - ga_concat(gap, (char *)buf); - } else { - switch (*p) { - case BS: - ga_concat(gap, "\\b"); break; - case ESC: - ga_concat(gap, "\\e"); break; - case FF: - ga_concat(gap, "\\f"); break; - case NL: - ga_concat(gap, "\\n"); break; - case TAB: - ga_concat(gap, "\\t"); break; - case CAR: - ga_concat(gap, "\\r"); break; - case '\\': - ga_concat(gap, "\\\\"); break; - default: - if (*p < ' ' || *p == 0x7f) { - vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); - ga_concat(gap, (char *)buf); - } else { - ga_append(gap, (char)(*p)); - } - break; + ga_concat(gap, buf); + return; + } + + switch (*p) { + case BS: + ga_concat(gap, "\\b"); break; + case ESC: + ga_concat(gap, "\\e"); break; + case FF: + ga_concat(gap, "\\f"); break; + case NL: + ga_concat(gap, "\\n"); break; + case TAB: + ga_concat(gap, "\\t"); break; + case CAR: + ga_concat(gap, "\\r"); break; + case '\\': + ga_concat(gap, "\\\\"); break; + default: + if ((uint8_t)(*p) < ' ' || *p == 0x7f) { + vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p); + ga_concat(gap, buf); + } else { + ga_append(gap, (uint8_t)(*p)); } + break; } } /// Append "str" to "gap", escaping unprintable characters. /// Changes NL to \n, CR to \r, etc. -static void ga_concat_shorten_esc(garray_T *gap, const char_u *str) +static void ga_concat_shorten_esc(garray_T *gap, const char *str) FUNC_ATTR_NONNULL_ARG(1) { - char_u buf[NUMBUFLEN]; + char buf[NUMBUFLEN]; if (str == NULL) { ga_concat(gap, "NULL"); return; } - for (const char_u *p = str; *p != NUL; p++) { + for (const char *p = str; *p != NUL; p++) { int same_len = 1; - const char_u *s = p; + const char *s = p; const int c = mb_ptr2char_adv(&s); const int clen = (int)(s - p); - while (*s != NUL && c == utf_ptr2char((char *)s)) { + while (*s != NUL && c == utf_ptr2char(s)) { same_len++; s += clen; } @@ -130,8 +131,8 @@ static void ga_concat_shorten_esc(garray_T *gap, const char_u *str) ga_concat(gap, "\\["); ga_concat_esc(gap, p, clen); ga_concat(gap, " occurs "); - vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len); - ga_concat(gap, (char *)buf); + vim_snprintf(buf, NUMBUFLEN, "%d", same_len); + ga_concat(gap, buf); ga_concat(gap, " times]"); p = s - 1; } else { @@ -141,10 +142,10 @@ static void ga_concat_shorten_esc(garray_T *gap, const char_u *str) } /// Fill "gap" with information about an assert error. -static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, +static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char *exp_str, typval_T *exp_tv_arg, typval_T *got_tv_arg, assert_type_T atype) { - char_u *tofree; + char *tofree; typval_T *exp_tv = exp_tv_arg; typval_T *got_tv = got_tv_arg; bool did_copy = false; @@ -154,8 +155,8 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s && !(opt_msg_tv->v_type == VAR_STRING && (opt_msg_tv->vval.v_string == NULL || *opt_msg_tv->vval.v_string == NUL))) { - tofree = (char_u *)encode_tv2echo(opt_msg_tv, NULL); - ga_concat(gap, (char *)tofree); + tofree = encode_tv2echo(opt_msg_tv, NULL); + ga_concat(gap, tofree); xfree(tofree); ga_concat(gap, ": "); } @@ -218,7 +219,7 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s } } - tofree = (char_u *)encode_tv2string(exp_tv, NULL); + tofree = encode_tv2string(exp_tv, NULL); ga_concat_shorten_esc(gap, tofree); xfree(tofree); } else { @@ -233,7 +234,7 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s } else { ga_concat(gap, " but got "); } - tofree = (char_u *)encode_tv2string(got_tv, NULL); + tofree = encode_tv2string(got_tv, NULL); ga_concat_shorten_esc(gap, tofree); xfree(tofree); @@ -306,7 +307,7 @@ static int assert_bool(typval_T *argvars, bool is_true) : kBoolVarFalse)))) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[1], - (char_u *)(is_true ? "True" : "False"), + is_true ? "True" : "False", NULL, &argvars[0], ASSERT_OTHER); assert_error(&ga); ga_clear(&ga); @@ -642,8 +643,8 @@ static int assert_inrange(typval_T *argvars) garray_T ga; prepare_assert_error(&ga); if (argvars[3].v_type != VAR_UNKNOWN) { - char_u *const tofree = (char_u *)encode_tv2string(&argvars[3], NULL); - ga_concat(&ga, (char *)tofree); + char *const tofree = encode_tv2string(&argvars[3], NULL); + ga_concat(&ga, tofree); xfree(tofree); } else { char msg[80]; @@ -671,7 +672,7 @@ static int assert_inrange(typval_T *argvars) vim_snprintf(msg, sizeof(msg), "range %" PRIdVARNUMBER " - %" PRIdVARNUMBER ",", lower, upper); // -V576 - fill_assert_error(&ga, &argvars[3], (char_u *)msg, NULL, &argvars[2], + fill_assert_error(&ga, &argvars[3], msg, NULL, &argvars[2], ASSERT_INRANGE); assert_error(&ga); ga_clear(&ga); diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 4af629d091..e30580a748 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -127,13 +127,13 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // 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); + char *line = get_cursor_line_ptr(); + leader_len = get_leader_len(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); + int comment_start = check_linecomment(line); if (comment_start != MAXCOL) { - leader_len = get_leader_len((char *)line + comment_start, NULL, false, true); + leader_len = get_leader_len(line + comment_start, NULL, false, true); if (leader_len != 0) { leader_len += comment_start; } @@ -477,25 +477,25 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on /// comment leader changes. static int fmt_check_par(linenr_T lnum, int *leader_len, char **leader_flags, bool do_comments) { - char_u *flags = NULL; // init for GCC - char_u *ptr; + char *flags = NULL; // init for GCC + char *ptr; - ptr = (char_u *)ml_get(lnum); + ptr = ml_get(lnum); if (do_comments) { - *leader_len = get_leader_len((char *)ptr, leader_flags, false, true); + *leader_len = get_leader_len(ptr, leader_flags, false, true); } else { *leader_len = 0; } if (*leader_len > 0) { // Search for 'e' flag in comment leader flags. - flags = (char_u *)(*leader_flags); + flags = *leader_flags; while (*flags && *flags != ':' && *flags != COM_END) { flags++; } } - return *skipwhite((char *)ptr + *leader_len) == NUL + return *skipwhite(ptr + *leader_len) == NUL || (*leader_len > 0 && *flags == COM_END) || startPS(lnum, NUL, false); } @@ -544,7 +544,8 @@ static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int return false; } if (*p == COM_START) { - if (*(ml_get(lnum) + leader1_len) == NUL) { + int line_len = (int)strlen(ml_get(lnum)); + if (line_len <= leader1_len) { return false; } if (leader2_flags == NULL || leader2_len == 0) { @@ -587,7 +588,7 @@ static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int /// false when the previous line is in the same paragraph. static bool paragraph_start(linenr_T lnum) { - char_u *p; + char *p; int leader_len = 0; // leader len of current line char *leader_flags = NULL; // flags for leader of current line int next_leader_len = 0; // leader len of next line @@ -596,7 +597,7 @@ static bool paragraph_start(linenr_T lnum) if (lnum <= 1) { return true; // start of the file } - p = (char_u *)ml_get(lnum - 1); + p = ml_get(lnum - 1); if (*p == NUL) { return true; // after empty line } @@ -735,22 +736,24 @@ 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. + if (!did_add_space) { + return; + } + + 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; - } 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; - } } } } diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index ee6c39a8ba..8e786c271c 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -4,6 +4,7 @@ // textobject.c: functions for text objects #include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <string.h> @@ -28,7 +29,6 @@ #include "nvim/search.h" #include "nvim/strings.h" #include "nvim/textobject.h" -#include "nvim/types.h" #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -273,7 +273,7 @@ bool startPS(linenr_T lnum, int para, bool both) return true; } if (*s == '.' && (inmacro(p_sections, s + 1) - || (!para && inmacro((char *)p_para, s + 1)))) { + || (!para && inmacro(p_para, s + 1)))) { return true; } return false; @@ -1078,7 +1078,7 @@ static bool in_html_tag(bool end_tag) if (inc(&pos) < 0) { return false; } - c = *ml_get_pos(&pos); + c = (uint8_t)(*ml_get_pos(&pos)); if (c == '>') { break; } diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index b837a380d5..733aa25f03 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -8,31 +8,27 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/ascii.h" -#include "nvim/autocmd.h" #include "nvim/charset.h" #include "nvim/event/defs.h" -#include "nvim/event/multiqueue.h" -#include "nvim/globals.h" #include "nvim/log.h" #include "nvim/macros.h" #include "nvim/main.h" #include "nvim/map.h" #include "nvim/memory.h" -#include "nvim/message.h" #include "nvim/option.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/tui/input.h" #include "nvim/tui/input_defs.h" #include "nvim/tui/tui.h" +#include "nvim/types.h" +#include "nvim/ui_client.h" #ifdef MSWIN # include "nvim/os/os_win_console.h" #endif #include "nvim/event/rstream.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/ui.h" #define KEY_BUFFER_SIZE 0xfff @@ -121,14 +117,6 @@ static const struct kitty_key_map_entry { static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT; -#ifndef UNIT_TESTING -typedef enum { - kIncomplete = -1, - kNotApplicable = 0, - kComplete = 1, -} HandleState; -#endif - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tui/input.c.generated.h" #endif @@ -153,19 +141,7 @@ void tinput_init(TermInput *input, Loop *loop) kitty_key_map_entry[i].name); } - // If stdin is not a pty, switch to stderr. For cases like: - // echo q | nvim -es - // ls *.md | xargs nvim -#ifdef MSWIN - if (!os_isatty(input->in_fd)) { - input->in_fd = os_get_conin_fd(); - } -#else - if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) { - input->in_fd = STDERR_FILENO; - } -#endif - input_global_fd_init(input->in_fd); + input->in_fd = STDIN_FILENO; const char *term = os_getenv("TERM"); if (!term) { @@ -174,7 +150,7 @@ void tinput_init(TermInput *input, Loop *loop) 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_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, input); termkey_start(input->tk); int curflags = termkey_get_canonflags(input->tk); @@ -600,7 +576,7 @@ static void set_bg(char *bgvalue) // ignored in the calculations. // // [1] https://en.wikipedia.org/wiki/Luma_%28video%29 -static HandleState handle_background_color(TermInput *input) +HandleState handle_background_color(TermInput *input) { if (input->waiting_for_bg_response <= 0) { return kNotApplicable; @@ -671,7 +647,7 @@ static HandleState handle_background_color(TermInput *input) bool is_dark = luminance < 0.5; char *bgvalue = is_dark ? "dark" : "light"; DLOG("bg response: %s", bgvalue); - ui_client_bg_respose = is_dark ? kTrue : kFalse; + ui_client_bg_response = is_dark ? kTrue : kFalse; set_bg(bgvalue); input->waiting_for_bg_response = 0; } else if (!done && !bad) { @@ -685,12 +661,6 @@ static HandleState handle_background_color(TermInput *input) } return kComplete; } -#ifdef UNIT_TESTING -HandleState ut_handle_background_color(TermInput *input) -{ - return handle_background_color(input); -} -#endif static void handle_raw_buffer(TermInput *input, bool force) { diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 5df108b107..d33cea6383 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -40,18 +40,14 @@ typedef struct term_input { TUIData *tui_data; } TermInput; -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "tui/input.h.generated.h" -#endif - -#ifdef UNIT_TESTING typedef enum { kIncomplete = -1, kNotApplicable = 0, kComplete = 1, } HandleState; -HandleState ut_handle_background_color(TermInput *input); +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/input.h.generated.h" #endif #endif // NVIM_TUI_INPUT_H diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index 507e9df21e..d630a34ce2 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -7,12 +7,12 @@ #include <string.h> #include <unibilium.h> +#include "klib/kvec.h" +#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/ascii.h" #include "nvim/charset.h" -#include "nvim/globals.h" #include "nvim/memory.h" -#include "nvim/message.h" -#include "nvim/option.h" #include "nvim/strings.h" #include "nvim/tui/terminfo.h" #include "nvim/tui/terminfo_defs.h" diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 44f6718039..ceda3b2076 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -16,7 +16,6 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/ascii.h" #include "nvim/cursor_shape.h" #include "nvim/event/defs.h" @@ -32,12 +31,10 @@ #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" -#include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/option.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/os/signal.h" +#include "nvim/ui_client.h" #ifdef MSWIN # include "nvim/os/os_win_console.h" #endif @@ -46,7 +43,6 @@ #include "nvim/tui/tui.h" #include "nvim/ugrid.h" #include "nvim/ui.h" -#include "nvim/vim.h" // Space reserved in two output buffers to make the cursor normal or invisible // when flushing. No existing terminal will require 32 bytes to do that. @@ -141,6 +137,7 @@ struct TUIData { int enable_bracketed_paste, disable_bracketed_paste; int enable_lr_margin, disable_lr_margin; int enter_strikethrough_mode; + int enter_altfont_mode; int set_rgb_foreground, set_rgb_background; int set_cursor_color; int reset_cursor_color; @@ -255,6 +252,7 @@ static void terminfo_start(TUIData *tui) tui->unibi_ext.enable_bracketed_paste = -1; tui->unibi_ext.disable_bracketed_paste = -1; tui->unibi_ext.enter_strikethrough_mode = -1; + tui->unibi_ext.enter_altfont_mode = -1; tui->unibi_ext.enable_lr_margin = -1; tui->unibi_ext.disable_lr_margin = -1; tui->unibi_ext.enable_focus_reporting = -1; @@ -460,7 +458,11 @@ static void tui_terminal_stop(TUIData *tui) void tui_stop(TUIData *tui) { + if (tui->stopped) { + return; + } tui_terminal_stop(tui); + stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); tui->stopped = true; signal_watcher_close(&tui->winch_handle, NULL); @@ -515,7 +517,7 @@ static bool attrs_differ(TUIData *tui, int id1, int id2, bool rgb) return a1.cterm_fg_color != a2.cterm_fg_color || a1.cterm_bg_color != a2.cterm_bg_color || a1.cterm_ae_attr != a2.cterm_ae_attr - || (a1.cterm_ae_attr & HL_ANY_UNDERLINE + || (a1.cterm_ae_attr & HL_UNDERLINE_MASK && a1.rgb_sp_color != a2.rgb_sp_color); } } @@ -535,6 +537,7 @@ static void update_attrs(TUIData *tui, int attr_id) bool reverse = attr & HL_INVERSE; bool standout = attr & HL_STANDOUT; bool strikethrough = attr & HL_STRIKETHROUGH; + bool altfont = attr & HL_ALTFONT; bool underline; bool undercurl; @@ -542,13 +545,14 @@ static void update_attrs(TUIData *tui, int attr_id) bool underdotted; bool underdashed; if (tui->unibi_ext.set_underline_style != -1) { - underline = attr & HL_UNDERLINE; - undercurl = attr & HL_UNDERCURL; - underdouble = attr & HL_UNDERDOUBLE; - underdashed = attr & HL_UNDERDASHED; - underdotted = attr & HL_UNDERDOTTED; + int ul = attr & HL_UNDERLINE_MASK; + underline = ul == HL_UNDERLINE; + undercurl = ul == HL_UNDERCURL; + underdouble = ul == HL_UNDERDOUBLE; + underdashed = ul == HL_UNDERDASHED; + underdotted = ul == HL_UNDERDOTTED; } else { - underline = attr & HL_ANY_UNDERLINE; + underline = attr & HL_UNDERLINE_MASK; undercurl = false; underdouble = false; underdotted = false; @@ -593,6 +597,9 @@ static void update_attrs(TUIData *tui, int attr_id) if (italic) { unibi_out(tui, unibi_enter_italics_mode); } + if (altfont && tui->unibi_ext.enter_altfont_mode != -1) { + unibi_out_ext(tui, tui->unibi_ext.enter_altfont_mode); + } if (strikethrough && tui->unibi_ext.enter_strikethrough_mode != -1) { unibi_out_ext(tui, tui->unibi_ext.enter_strikethrough_mode); } @@ -1342,7 +1349,7 @@ static void suspend_event(void **argv) TUIData *tui = argv[0]; bool enable_mouse = tui->mouse_enabled; tui_terminal_stop(tui); - stream_set_blocking(input_global_fd(), true); // normalize stream (#2598) + stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) kill(0, SIGTSTP); @@ -1351,7 +1358,7 @@ static void suspend_event(void **argv) if (enable_mouse) { tui_mouse_on(tui); } - stream_set_blocking(input_global_fd(), false); // libuv expects this + stream_set_blocking(tui->input.in_fd, false); // libuv expects this } #endif @@ -2041,6 +2048,11 @@ static void augment_terminfo(TUIData *tui, const char *term, long vte_version, l // to the ECMA-48 strikeout/crossed-out attributes. tui->unibi_ext.enter_strikethrough_mode = unibi_find_ext_str(ut, "smxx"); + // It should be pretty safe to always enable this, as terminals will ignore + // unrecognised SGR numbers. + tui->unibi_ext.enter_altfont_mode = (int)unibi_add_ext_str(ut, "ext.enter_altfont_mode", + "\x1b[11m"); + // Dickey ncurses terminfo does not include the setrgbf and setrgbb // capabilities, proposed by Rüdiger Sonderfeld on 2013-10-15. Adding // them here when terminfo lacks them is an augmentation, not a fixup. @@ -2238,12 +2250,12 @@ static void flush_buf(TUIData *tui) /// /// @see tmux/tty-keys.c fe4e9470bb504357d073320f5d305b22663ee3fd /// @see https://bugzilla.redhat.com/show_bug.cgi?id=142659 -static const char *tui_get_stty_erase(void) +static const char *tui_get_stty_erase(int fd) { static char stty_erase[2] = { 0 }; #if defined(HAVE_TERMIOS_H) struct termios t; - if (tcgetattr(input_global_fd(), &t) != -1) { + if (tcgetattr(fd, &t) != -1) { stty_erase[0] = (char)t.c_cc[VERASE]; stty_erase[1] = '\0'; DLOG("stty/termios:erase=%s", stty_erase); @@ -2256,9 +2268,10 @@ static const char *tui_get_stty_erase(void) /// @see TermInput.tk_ti_hook_fn static const char *tui_tk_ti_getstr(const char *name, const char *value, void *data) { + TermInput *input = data; static const char *stty_erase = NULL; if (stty_erase == NULL) { - stty_erase = tui_get_stty_erase(); + stty_erase = tui_get_stty_erase(input->in_fd); } if (strequal(name, "key_backspace")) { diff --git a/src/nvim/ui.c b/src/nvim/ui.c index b25fa04c8b..9f1cb87eb0 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -7,8 +7,8 @@ #include <stddef.h> #include <stdint.h> #include <stdlib.h> +#include <string.h> -#include "auto/config.h" #include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" @@ -17,8 +17,6 @@ #include "nvim/buffer_defs.h" #include "nvim/cursor_shape.h" #include "nvim/drawscreen.h" -#include "nvim/event/defs.h" -#include "nvim/event/loop.h" #include "nvim/ex_getln.h" #include "nvim/gettext.h" #include "nvim/globals.h" @@ -27,15 +25,14 @@ #include "nvim/highlight_defs.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/msgpack_rpc/channel.h" #include "nvim/option.h" #include "nvim/os/time.h" #include "nvim/strings.h" -#include "nvim/tui/tui.h" #include "nvim/ui.h" +#include "nvim/ui_client.h" #include "nvim/ui_compositor.h" #include "nvim/vim.h" #include "nvim/window.h" diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index ff82fd3239..378c0e4831 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -6,15 +6,18 @@ #include <stdlib.h> #include "nvim/api/private/helpers.h" +#include "nvim/channel.h" #include "nvim/eval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/event/loop.h" -#include "nvim/event/multiqueue.h" #include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/os/os_defs.h" #include "nvim/tui/tui.h" #include "nvim/ui.h" #include "nvim/ui_client.h" @@ -48,9 +51,16 @@ uint64_t ui_client_start_server(int argc, char **argv) on_err, CALLBACK_NONE, false, true, true, false, kChannelStdinPipe, NULL, 0, 0, NULL, &exit_status); + + // If stdin is not a pty, it is forwarded to the client. + // Replace stdin in the TUI process with the tty fd. if (ui_client_forward_stdin) { close(0); - dup(2); +#ifdef MSWIN + os_open_conin_fd(); +#else + dup(stderr_isatty ? STDERR_FILENO : STDOUT_FILENO); +#endif } return channel->id; @@ -74,8 +84,8 @@ void ui_client_run(bool remote_ui) if (term) { PUT(opts, "term_name", STRING_OBJ(cstr_to_string(term))); } - if (ui_client_bg_respose != kNone) { - bool is_dark = (ui_client_bg_respose == kTrue); + if (ui_client_bg_response != kNone) { + bool is_dark = (ui_client_bg_response == kTrue); PUT_C(opts, "term_background", STRING_OBJ(cstr_as_string(is_dark ? "dark" : "light"))); } PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors)); diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h index 24b8fad4cc..7e5f847039 100644 --- a/src/nvim/ui_client.h +++ b/src/nvim/ui_client.h @@ -1,11 +1,14 @@ #ifndef NVIM_UI_CLIENT_H #define NVIM_UI_CLIENT_H +#include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include "nvim/api/private/defs.h" #include "nvim/grid_defs.h" #include "nvim/macros.h" +#include "nvim/types.h" typedef struct { const char *name; @@ -28,17 +31,18 @@ EXTERN bool ui_client_attached INIT(= false); /// Whether ui client has gotten a response about the bg color of the terminal, /// kTrue=dark, kFalse=light, kNone=no response yet -EXTERN TriState ui_client_bg_respose INIT(= kNone); +EXTERN TriState ui_client_bg_response INIT(= kNone); /// The ui client should forward its stdin to the nvim process /// by convention, this uses fd=3 (next free number after stdio) EXTERN bool ui_client_forward_stdin INIT(= false); #define UI_CLIENT_STDIN_FD 3 +// uncrustify:off #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui_client.h.generated.h" - # include "ui_events_client.h.generated.h" #endif +// uncrustify:on #endif // NVIM_UI_CLIENT_H diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index ad44e2ca22..9ff9eabff8 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -24,7 +24,6 @@ #include "nvim/highlight_group.h" #include "nvim/log.h" #include "nvim/macros.h" -#include "nvim/map.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option_defs.h" diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 85e261fc39..0f12c00f15 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -624,20 +624,20 @@ int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, int re // extra fields for uhp #define UHP_SAVE_NR 1 -static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); +static char e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); /// Compute the hash for a buffer text into hash[UNDO_HASH_SIZE]. /// /// @param[in] buf The buffer used to compute the hash /// @param[in] hash Array of size UNDO_HASH_SIZE in which to store the value of /// the hash -void u_compute_hash(buf_T *buf, char_u *hash) +void u_compute_hash(buf_T *buf, uint8_t *hash) { context_sha256_T ctx; sha256_start(&ctx); for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { char *p = ml_get_buf(buf, lnum, false); - sha256_update(&ctx, (char_u *)p, (uint32_t)(strlen(p) + 1)); + sha256_update(&ctx, (uint8_t *)p, strlen(p) + 1); } sha256_finish(&ctx, hash); } @@ -677,7 +677,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) // Loop over 'undodir'. When reading find the first file that exists. // When not reading use the first directory that exists or ".". - char *dirp = (char *)p_udir; + char *dirp = p_udir; while (*dirp != NUL) { size_t dir_len = copy_option_part(&dirp, dir_name, MAXPATHL, ","); if (dir_len == 1 && dir_name[0] == '.') { @@ -765,7 +765,7 @@ static void u_free_uhp(u_header_T *uhp) /// @param hash The hash of the buffer contents // /// @returns false in case of an error. -static bool serialize_header(bufinfo_T *bi, char_u *hash) +static bool serialize_header(bufinfo_T *bi, uint8_t *hash) FUNC_ATTR_NONNULL_ALL { buf_T *buf = bi->bi_buf; @@ -788,7 +788,7 @@ static bool serialize_header(bufinfo_T *bi, char_u *hash) 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; undo_write_bytes(bi, len, 4); - if (len > 0 && !undo_write(bi, (char_u *)buf->b_u_line_ptr, len)) { + if (len > 0 && !undo_write(bi, (uint8_t *)buf->b_u_line_ptr, len)) { return false; } undo_write_bytes(bi, (uintmax_t)buf->b_u_line_lnum, 4); @@ -1053,7 +1053,7 @@ static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep) if (!undo_write_bytes(bi, len, 4)) { return false; } - if (len > 0 && !undo_write(bi, (char_u *)uep->ue_array[i], len)) { + if (len > 0 && !undo_write(bi, (uint8_t *)uep->ue_array[i], len)) { return false; } } @@ -1072,18 +1072,18 @@ static u_entry_T *unserialize_uep(bufinfo_T *bi, bool *error, const char *file_n uep->ue_lcount = undo_read_4c(bi); uep->ue_size = undo_read_4c(bi); - char_u **array = NULL; + char **array = NULL; if (uep->ue_size > 0) { - if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char_u *)) { // -V547 - array = xmalloc(sizeof(char_u *) * (size_t)uep->ue_size); - memset(array, 0, sizeof(char_u *) * (size_t)uep->ue_size); + if ((size_t)uep->ue_size < SIZE_MAX / sizeof(char *)) { // -V547 + array = xmalloc(sizeof(char *) * (size_t)uep->ue_size); + memset(array, 0, sizeof(char *) * (size_t)uep->ue_size); } } - uep->ue_array = (char **)array; + uep->ue_array = array; for (size_t i = 0; i < (size_t)uep->ue_size; i++) { int line_len = undo_read_4c(bi); - char_u *line; + char *line; if (line_len >= 0) { line = undo_read_string(bi, (size_t)line_len); } else { @@ -1150,7 +1150,7 @@ static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info) /// @param[in] buf Buffer for which undo file is written. /// @param[in] hash Hash value of the buffer text. Must have #UNDO_HASH_SIZE /// size. -void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, char_u *const hash) +void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, uint8_t *const hash) FUNC_ATTR_NONNULL_ARG(3, 4) { char *file_name; @@ -1209,7 +1209,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, } goto theend; } else { - char_u mbuf[UF_START_MAGIC_LEN]; + char mbuf[UF_START_MAGIC_LEN]; ssize_t len = read_eintr(fd, mbuf, UF_START_MAGIC_LEN); close(fd); if (len < UF_START_MAGIC_LEN @@ -1342,8 +1342,8 @@ write_error: #ifdef HAVE_ACL if (buf->b_ffname != NULL) { // For systems that support ACL: get the ACL from the original file. - vim_acl_T acl = os_get_acl((char_u *)buf->b_ffname); - os_set_acl((char_u *)file_name, acl); + vim_acl_T acl = os_get_acl(buf->b_ffname); + os_set_acl(file_name, acl); os_free_acl(acl); } #endif @@ -1359,11 +1359,11 @@ theend: /// a bit more verbose. /// Otherwise use curbuf->b_ffname to generate the undo file name. /// "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. -void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_ATTR_UNUSED) +void u_read_undo(char *name, const uint8_t *hash, const char *orig_name FUNC_ATTR_UNUSED) FUNC_ATTR_NONNULL_ARG(2) { u_header_T **uhp_table = NULL; - char_u *line_ptr = NULL; + char *line_ptr = NULL; char *file_name; if (name == NULL) { @@ -1377,7 +1377,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT // owner of the text file or equal to the current user. FileInfo file_info_orig; FileInfo file_info_undo; - if (os_fileinfo((const char *)orig_name, &file_info_orig) + if (os_fileinfo(orig_name, &file_info_orig) && os_fileinfo(file_name, &file_info_undo) && file_info_orig.stat.st_uid != file_info_undo.stat.st_uid && file_info_undo.stat.st_uid != getuid()) { @@ -1414,7 +1414,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT }; // Read the undo file header. - char_u magic_buf[UF_START_MAGIC_LEN]; + char magic_buf[UF_START_MAGIC_LEN]; if (fread(magic_buf, UF_START_MAGIC_LEN, 1, fp) != 1 || memcmp(magic_buf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) { semsg(_("E823: Not an undo file: %s"), file_name); @@ -1426,7 +1426,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT goto error; } - char_u read_hash[UNDO_HASH_SIZE]; + uint8_t read_hash[UNDO_HASH_SIZE]; if (!undo_read(&bi, read_hash, UNDO_HASH_SIZE)) { corruption_error("hash", file_name); goto error; @@ -1608,7 +1608,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 = (char *)line_ptr; + curbuf->b_u_line_ptr = line_ptr; curbuf->b_u_line_lnum = line_lnum; curbuf->b_u_line_colnr = line_colnr; curbuf->b_u_numhead = num_head; @@ -1743,10 +1743,10 @@ static bool undo_read(bufinfo_T *bi, uint8_t *buffer, size_t size) /// @param len can be zero to allocate an empty line. /// /// @returns a pointer to allocated memory or NULL in case of an error. -static uint8_t *undo_read_string(bufinfo_T *bi, size_t len) +static char *undo_read_string(bufinfo_T *bi, size_t len) { - uint8_t *ptr = xmallocz(len); - if (len > 0 && !undo_read(bi, ptr, len)) { + char *ptr = xmallocz(len); + if (len > 0 && !undo_read(bi, (uint8_t *)ptr, len)) { xfree(ptr); return NULL; } @@ -2238,7 +2238,7 @@ target_zero: /// @param do_buf_event If `true`, send buffer updates. static void u_undoredo(int undo, bool do_buf_event) { - char_u **newarray = NULL; + char **newarray = NULL; linenr_T newlnum = MAXLNUM; u_entry_T *nuep; u_entry_T *newlist = NULL; @@ -2316,13 +2316,13 @@ static void u_undoredo(int undo, bool do_buf_event) // delete the lines between top and bot and save them in newarray if (oldsize > 0) { - newarray = xmalloc(sizeof(char_u *) * (size_t)oldsize); + newarray = xmalloc(sizeof(char *) * (size_t)oldsize); // delete backwards, it goes faster in most cases long i; linenr_T lnum; for (lnum = bot - 1, i = oldsize; --i >= 0; lnum--) { // what can we do when we run out of memory? - newarray[i] = (char_u *)u_save_line(lnum); + newarray[i] = u_save_line(lnum); // remember we deleted the last line in the buffer, and a // dummy empty line will be inserted if (curbuf->b_ml.ml_line_count == 1) { @@ -2348,7 +2348,7 @@ static void u_undoredo(int undo, bool do_buf_event) } xfree(uep->ue_array[i]); } - xfree((char_u *)uep->ue_array); + xfree(uep->ue_array); } // Adjust marks @@ -2378,7 +2378,7 @@ static void u_undoredo(int undo, bool do_buf_event) u_newcount += newsize; u_oldcount += oldsize; uep->ue_size = oldsize; - uep->ue_array = (char **)newarray; + uep->ue_array = newarray; uep->ue_bot = top + newsize + 1; // insert this entry in front of the new entry list @@ -2565,11 +2565,11 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet) uhp = curbuf->b_u_newhead; } - char_u msgbuf[80]; + char msgbuf[80]; if (uhp == NULL) { *msgbuf = NUL; } else { - undo_fmt_time((char *)msgbuf, sizeof(msgbuf), uhp->uh_time); + undo_fmt_time(msgbuf, sizeof(msgbuf), uhp->uh_time); } { @@ -2935,7 +2935,7 @@ static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp) #ifdef U_DEBUG uhp->uh_magic = 0; #endif - xfree((char_u *)uhp); + xfree(uhp); buf->b_u_numhead--; } @@ -2945,11 +2945,11 @@ static void u_freeentry(u_entry_T *uep, long n) while (n > 0) { xfree(uep->ue_array[--n]); } - xfree((char_u *)uep->ue_array); + xfree(uep->ue_array); #ifdef U_DEBUG uep->ue_magic = 0; #endif - xfree((char_u *)uep); + xfree(uep); } /// invalidate the undo buffer; called when storage has already been released @@ -2985,10 +2985,12 @@ void u_saveline(linenr_T lnum) /// (this is used externally for crossing a line while in insert mode) void u_clearline(void) { - if (curbuf->b_u_line_ptr != NULL) { - XFREE_CLEAR(curbuf->b_u_line_ptr); - curbuf->b_u_line_lnum = 0; + if (curbuf->b_u_line_ptr == NULL) { + return; } + + XFREE_CLEAR(curbuf->b_u_line_ptr); + curbuf->b_u_line_lnum = 0; } /// Implementation of the "U" command. diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 883d7321d2..ef13f67e49 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -89,12 +89,15 @@ static const char *command_complete[] = { [EXPAND_SYNTIME] = "syntime", [EXPAND_SETTINGS] = "option", [EXPAND_PACKADD] = "packadd", + [EXPAND_RUNTIME] = "runtime", [EXPAND_SHELLCMD] = "shellcmd", [EXPAND_SIGN] = "sign", [EXPAND_TAGS] = "tag", [EXPAND_TAGS_LISTFILES] = "tag_listfiles", [EXPAND_USER] = "user", [EXPAND_USER_VARS] = "var", + [EXPAND_BREAKPOINT] = "breakpoint", + [EXPAND_SCRIPTNAMES] = "scriptnames", }; /// List of names of address types. Must be alphabetical for completion. @@ -1422,7 +1425,7 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar ct_NONE, } type = ct_NONE; - if ((vim_strchr("qQfF", *p) != NULL) && p[1] == '-') { + if ((vim_strchr("qQfF", (uint8_t)(*p)) != NULL) && p[1] == '-') { quote = (*p == 'q' || *p == 'Q') ? 1 : 2; p += 2; l -= 2; @@ -1430,7 +1433,7 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar l++; if (l <= 1) { - type = ct_NONE; + // type = ct_NONE; } else if (STRNICMP(p, "args>", l) == 0) { type = ct_ARGS; } else if (STRNICMP(p, "bang>", l) == 0) { diff --git a/src/nvim/version.c b/src/nvim/version.c index 92122b2523..3324ac2a94 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -29,6 +29,7 @@ #include "nvim/highlight_defs.h" #include "nvim/lua/executor.h" #include "nvim/mbyte.h" +#include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option_defs.h" #include "nvim/os/os_defs.h" @@ -63,12 +64,6 @@ static char *features[] = { "-acl", #endif -#if defined(HAVE_ICONV) - "+iconv", -#else - "-iconv", -#endif - "+tui", NULL }; @@ -800,7 +795,7 @@ static const int included_patches[] = { 1702, 1701, // 1700, - // 1699, + 1699, 1698, 1697, 1696, @@ -1366,7 +1361,7 @@ static const int included_patches[] = { // 1136, 1135, 1134, - // 1133, + 1133, 1132, 1131, 1130, @@ -1679,7 +1674,7 @@ static const int included_patches[] = { 823, 822, 821, - // 820, + 820, 819, 818, 817, @@ -2790,24 +2785,18 @@ void maybe_intro_message(void) /// @param colon true for ":intro" void intro_message(int colon) { - int i; - long row; - long blanklines; - int sponsor; - char *p; static char *(lines[]) = { N_(NVIM_VERSION_LONG), "", N_("Nvim is open source and freely distributable"), - N_("https://neovim.io/#chat"), + "https://neovim.io/#chat", "", N_("type :help nvim<Enter> if you are new! "), N_("type :checkhealth<Enter> to optimize Nvim"), N_("type :q<Enter> to exit "), N_("type :help<Enter> for help "), "", - N_("type :help news<Enter> to see changes in") - " v" STR(NVIM_VERSION_MAJOR) "." STR(NVIM_VERSION_MINOR), + N_("type :help news<Enter> to see changes in v%s.%s"), "", N_("Help poor children in Uganda!"), N_("type :help iccf<Enter> for information "), @@ -2817,7 +2806,7 @@ void intro_message(int colon) size_t lines_size = ARRAY_SIZE(lines); assert(lines_size <= LONG_MAX); - blanklines = Rows - ((long)lines_size - 1L); + long blanklines = Rows - ((long)lines_size - 1L); // Don't overwrite a statusline. Depends on 'cmdheight'. if (p_ls > 1) { @@ -2830,17 +2819,27 @@ void intro_message(int colon) // Show the sponsor and register message one out of four times, the Uganda // message two out of four times. - sponsor = (int)time(NULL); + int sponsor = (int)time(NULL); sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0); // start displaying the message lines after half of the blank lines - row = blanklines / 2; + long row = blanklines / 2; if (((row >= 2) && (Columns >= 50)) || colon) { - for (i = 0; i < (int)ARRAY_SIZE(lines); i++) { - p = lines[i]; + for (int i = 0; i < (int)ARRAY_SIZE(lines); i++) { + char *p = lines[i]; + char *mesg = NULL; + int mesg_size = 0; - if (sponsor != 0) { + if (strstr(p, "news") != NULL) { + p = _(p); + mesg_size = snprintf(NULL, 0, p, + STR(NVIM_VERSION_MAJOR), STR(NVIM_VERSION_MINOR)); + assert(mesg_size > 0); + mesg = xmallocz((size_t)mesg_size); + snprintf(mesg, (size_t)mesg_size + 1, p, + STR(NVIM_VERSION_MAJOR), STR(NVIM_VERSION_MINOR)); + } else if (sponsor != 0) { if (strstr(p, "children") != NULL) { p = sponsor < 0 ? N_("Sponsor Vim development!") @@ -2849,15 +2848,25 @@ void intro_message(int colon) p = sponsor < 0 ? N_("type :help sponsor<Enter> for information ") : N_("type :help register<Enter> for information "); - } else if (strstr(p, "Orphans") != NULL) { - p = N_("menu Help->Sponsor/Register for information "); } } - if (*p != NUL) { - do_intro_line(row, _(p), 0); + if (mesg == NULL) { + if (*p != NUL) { + mesg = _(p); + } else { + mesg = ""; + } + } + + if (*mesg != NUL) { + do_intro_line(row, mesg, 0); } row++; + + if (mesg_size > 0) { + XFREE_CLEAR(mesg); + } } } diff --git a/src/nvim/vim.h b/src/nvim/vim.h index c395eb438c..3c765f8eb2 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -154,6 +154,9 @@ enum { EXPAND_MAPCLEAR, EXPAND_ARGLIST, EXPAND_DIFF_BUFFERS, + EXPAND_BREAKPOINT, + EXPAND_SCRIPTNAMES, + EXPAND_RUNTIME, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 0b19526fa0..53224f2ee9 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1826,7 +1826,7 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no flags |= FSK_SIMPLIFY; } const size_t special_len = trans_special(&p, (size_t)(e - p), - (char_u *)v_p, flags, false, NULL); + v_p, flags, false, NULL); if (special_len != 0) { v_p += special_len; } else { @@ -2497,7 +2497,6 @@ viml_pexpr_parse_bracket_closing_error: NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral); *top_node_p = cur_node; kvi_push(ast_stack, &cur_node->children); - want_node = kENodeValue; if (cur_pt == kEPTAssignment) { // Additional assignment parse type allows to easily forbid nested // lists. diff --git a/src/nvim/window.c b/src/nvim/window.c index 2bcbef14b0..6b40ccdb84 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -11,12 +11,14 @@ #include <stdlib.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/arglist.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/decoration.h" @@ -59,6 +61,7 @@ #include "nvim/option.h" #include "nvim/optionstr.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/path.h" #include "nvim/plines.h" #include "nvim/pos.h" @@ -505,7 +508,7 @@ wingotofile: CHECK_CMDWIN; linenr_T lnum = -1; - char *ptr = (char *)grab_file_name(Prenum1, &lnum); + char *ptr = grab_file_name(Prenum1, &lnum); if (ptr != NULL) { tabpage_T *oldtab = curtab; win_T *oldwin = curwin; @@ -753,20 +756,20 @@ 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 = (char_u *)wp->w_p_fcs; + char *old = wp->w_p_fcs; wp->w_p_fcs = ((*old == NUL) ? xstrdup("eob: ") - : concat_str((char *)old, ",eob: ")); - free_string_option((char *)old); + : concat_str(old, ",eob: ")); + free_string_option(old); } // TODO(bfredl): this could use a highlight namespace directly, // and avoid peculiarities around window options - char_u *old = (char_u *)wp->w_p_winhl; + char *old = wp->w_p_winhl; wp->w_p_winhl = ((*old == NUL) ? xstrdup("EndOfBuffer:") - : concat_str((char *)old, ",EndOfBuffer:")); - free_string_option((char *)old); + : concat_str(old, ",EndOfBuffer:")); + free_string_option(old); parse_winhl_opt(wp); // signcolumn: use 'auto' @@ -2524,24 +2527,23 @@ void close_windows(buf_T *buf, bool keep_curwin) RedrawingDisabled--; } -/// Check that the specified window is the last one. -/// @param win counted even if floating -/// -/// @return true if the specified window is the only window that exists, -/// false if there is another, possibly in another tab page. +/// Check if "win" is the last non-floating window that exists. bool last_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return one_window(win) && first_tabpage->tp_next == NULL; } -/// Check if current tab page contains no more than one window other than `aucmd_win[]`. -/// @param counted_float counted even if floating, but not if it is `aucmd_win[]` -bool one_window(win_T *counted_float) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +/// Check if "win" is the only non-floating window in the current tabpage. +bool one_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { + if (win->w_floating) { + return false; + } + bool seen_one = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (!is_aucmd_win(wp) && (!wp->w_floating || wp == counted_float)) { + if (!wp->w_floating) { if (seen_one) { return false; } @@ -2597,6 +2599,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev if (!ONE_WINDOW) { return false; } + buf_T *old_curbuf = curbuf; Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL; @@ -2614,8 +2617,8 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev goto_tabpage_tp(alt_tabpage(), false, true); // save index for tabclosed event - char_u prev_idx[NUMBUFLEN]; - snprintf((char *)prev_idx, NUMBUFLEN, "%i", tabpage_index(prev_curtab)); + char prev_idx[NUMBUFLEN]; + snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(prev_curtab)); // Safety check: Autocommands may have closed the window when jumping // to the other tab page. @@ -4061,7 +4064,7 @@ void free_tabpage(tabpage_T *tp) /// tabpage in case of 0. /// @param filename Will be passed to apply_autocmds(). /// @return Was the new tabpage created successfully? FAIL or OK. -int win_new_tabpage(int after, char_u *filename) +int win_new_tabpage(int after, char *filename) { tabpage_T *old_curtab = curtab; @@ -4124,7 +4127,7 @@ int win_new_tabpage(int after, char_u *filename) apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf); - apply_autocmds(EVENT_TABNEW, (char *)filename, (char *)filename, false, curbuf); + apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf); apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf); return OK; @@ -4142,12 +4145,13 @@ int may_open_tabpage(void) { int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab; - if (n != 0) { - cmdmod.cmod_tab = 0; // reset it to avoid doing it twice - postponed_split_tab = 0; - return win_new_tabpage(n, NULL); + if (n == 0) { + return FAIL; } - return FAIL; + + cmdmod.cmod_tab = 0; // reset it to avoid doing it twice + postponed_split_tab = 0; + return win_new_tabpage(n, NULL); } // Create up to "maxcount" tabpages with empty windows. @@ -4492,11 +4496,12 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le /// @return true if the tab page is valid, false otherwise. bool goto_tabpage_lastused(void) { - if (valid_tabpage(lastused_tabpage)) { - goto_tabpage_tp(lastused_tabpage, true, true); - return true; + if (!valid_tabpage(lastused_tabpage)) { + return false; } - return false; + + goto_tabpage_tp(lastused_tabpage, true, true); + return true; } // Enter window "wp" in tab page "tp". @@ -6754,7 +6759,7 @@ 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. -char_u *grab_file_name(long count, linenr_T *file_lnum) +char *grab_file_name(long count, linenr_T *file_lnum) { int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC; if (VIsual_active) { @@ -6764,12 +6769,12 @@ char_u *grab_file_name(long count, linenr_T *file_lnum) return NULL; } // Only recognize ":123" here - if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) { + if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) { char *p = ptr + len + 1; *file_lnum = (linenr_T)getdigits_long(&p, false, 0); } - return (char_u *)find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); + return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); } return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); } @@ -6785,10 +6790,10 @@ char_u *grab_file_name(long count, linenr_T *file_lnum) // 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) +char *file_name_at_cursor(int options, long count, linenr_T *file_lnum) { - return file_name_in_line((char_u *)get_cursor_line_ptr(), - curwin->w_cursor.col, options, count, (char_u *)curbuf->b_ffname, + return file_name_in_line(get_cursor_line_ptr(), + curwin->w_cursor.col, options, count, curbuf->b_ffname, file_lnum); } @@ -6796,11 +6801,11 @@ char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum) /// @param file_lnum line number after the file name /// /// @return the name of the file under or after ptr[col]. Otherwise like file_name_at_cursor(). -char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, - linenr_T *file_lnum) +char *file_name_in_line(char *line, int col, int options, long count, char *rel_fname, + linenr_T *file_lnum) { // search forward for what could be the start of a file name - char *ptr = (char *)line + col; + char *ptr = line + col; while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) { MB_PTR_ADV(ptr); } @@ -6817,8 +6822,8 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u // 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((char *)line, ptr - 1))) > 0) { + while (ptr > line) { + if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) { ptr -= len + 1; } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { @@ -6833,7 +6838,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u len = 0; 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)) { + || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) { // After type:// we also include :, ?, & and = as valid characters, so that // http://google.com:8080?q=this&that=ok works. if ((ptr[len] >= 'A' && ptr[len] <= 'Z') @@ -6854,7 +6859,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u // 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 + if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL && ptr[len - 2] != '.') { len--; } @@ -6875,17 +6880,17 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u p = skipwhite(p); } if (*p != NUL) { - if (!isdigit(*p)) { + if (!isdigit((uint8_t)(*p))) { p++; // skip the separator } p = skipwhite(p); - if (isdigit(*p)) { + if (isdigit((uint8_t)(*p))) { *file_lnum = (linenr_T)getdigits_long(&p, false, 0); } } } - return (char_u *)find_file_name_in_path(ptr, len, options, count, (char *)rel_fname); + return find_file_name_in_path(ptr, len, options, count, rel_fname); } /// Add or remove a status line from window(s), according to the @@ -7248,11 +7253,12 @@ static void clear_snapshot(tabpage_T *tp, int idx) static void clear_snapshot_rec(frame_T *fr) { - if (fr != NULL) { - clear_snapshot_rec(fr->fr_next); - clear_snapshot_rec(fr->fr_child); - xfree(fr); + if (fr == NULL) { + return; } + clear_snapshot_rec(fr->fr_next); + clear_snapshot_rec(fr->fr_child); + xfree(fr); } /// Traverse a snapshot to find the previous curwin. diff --git a/src/nvim/window.h b/src/nvim/window.h index f348f102c9..4ab2bea60a 100644 --- a/src/nvim/window.h +++ b/src/nvim/window.h @@ -6,6 +6,7 @@ #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/macros.h" #include "nvim/mark.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" |